Document and enable global storage ownership checks

This commit is contained in:
ragnarok-clanker 2026-10-26 19:15:28 +00:00
commit 935383f431
3 changed files with 63 additions and 0 deletions

View file

@ -119,6 +119,15 @@ other contributors' agents: a function merges once "same" leads
symbol database, so the source survives new versions of the executable.
If you need a new global, vtable or string, call `td_new_symbol` and use the
returned annotation (`// GLOBAL: gl_00045`).
- **Globals have one real definition.** Put a global's stable data annotation on its owning
`.cpp` definition, not on an `extern`. Shared declarations belong in its subsystem header;
source units include that header. A symbol-database record is not a C++ definition.
Recover initialization, object extent and lifetime from the original instructions and data,
not just symbol sizes. An evidenced member address uses `owner.member`, not a separate global.
Do not invent zero initialization or replace a nontrivial constructor with raw storage.
The project enables `globalRules`: both submission types and merge-time checks enforce
new/changed declarations and removal of required definitions. Existing unrelated violations
are not automatically corrected; report evidence gaps instead of manufacturing IDs.
- **No inline assembly, `__emit`, byte arrays of code, `#pragma code_seg`,
`#pragma comment`, `#line`, or `__declspec(naked/allocate)`.** These are
rejected automatically, also when hidden behind macros.
@ -147,6 +156,29 @@ other contributors' agents: a function merges once "same" leads
Implement claimed functions and their single-caller helpers in the unit assigned by the claim;
do not split their implementation into separate helper `.cpp` files.
## Structural maintenance (maintainers)
For data ownership, annotation moves and new owner units that belong to no function task:
```sh
td maintenance submit --files Source/Owner.cpp,Source/Owner.h --notes "Evidence and reason"
td batch <batchId>
```
Name the exact locally checked payload and include all dependencies. Maintenance batches are
maintainer-only; they run the source gates, compile affected units/includers and compare effective
code with a fresh main build. A changed function uses the normal revision/review path instead.
The server registers new source units in `compile.json` on merge. A queued batch is not a merge.
The linked-code check does not validate data contents or reconstruct initialization/teardown.
Prove those separately before submitting. An offset-asserted partial layout is not evidence of a
complete object's size or constructor. Never retire a stable ID just because its address is
near another symbol: establish the member relationship from `this`-relative accesses/lifetime.
`td maintenance symbol <id> --size N --reason "binary evidence"` corrects a proven extent.
`--retire --reason "owner ID, offset and evidence"` retires a mistaken global only after its
annotation is removed from main. IDs remain reserved; unrelated symbols must not be renumbered.
## Common MSVC v142 matching tips
- Declaration order of locals affects stack layout and register allocation.

View file

@ -56,6 +56,36 @@ int g_resourceReuseDelay;
- Helper functions used only by one `.cpp` may stay `static` there, defined below the statics; they need no header
declaration.
### Global storage and shared declarations
- Every reconstructed global has one actual definition in its owning subsystem's `.cpp`, with
its stable data annotation. File-local globals stay file-local. Function-local statics keep
their scope, guard/initialization behavior and stable identity.
- Shared headers contain plain `extern` declarations. Do not repeat `GLOBAL`, `STRING` or `VTABLE`
on those declarations. A `.cpp` includes the owner header instead of declaring a second extern.
Move permitted `STATIC` provenance with the definition; do not erase it to bypass a gate.
- The definition must exist on main or in the same payload. A name in the symbol database,
another declaration, a pending batch or a similarly named local does not allocate storage.
- Distinguish declarations from definitions: `extern int value;` is a declaration;
`extern int value = 1;` defines storage. Imported SDK/DLL data is not project-owned storage.
- Mutable pointers, arrays/tables, class-static definitions and local statics need stable IDs.
Scalar constants that are folded into code need no invented address. `constexpr` alone does
not exempt an addressable table or object. Use `STRING`/`VTABLE` only for that kind of original data.
- Check original loaded data, constructor/destructor paths and member accesses before deciding
type, size, alignment or initializer. The highest observed field gives a lower bound, not a
complete size. No xrefs or missing PE relocations do not prove an initializer is zero.
- A compiler may reference `global.member` by absolute address. Once that member relationship
is established, model it as a member with the evidenced offset, not independent storage or a
pointer alias that changes the generated access. Never infer membership solely from proximity.
- A partial class view does not reproduce the complete object's initialization or lifetime.
Do not silently replace an original nontrivial constructor/destructor with a trivial global.
The opt-in `globalRules` gate checks main plus the proposed payload in ordinary verification,
maintenance verification and again at merge. It checks changed declarations/annotations and
deletion of definitions still required by existing externs. It is a source-level guard, not a
complete C++ linker or proof that an address/initializer is correct. Unchanged legacy findings
remain audit findings; do not create speculative definitions or IDs to suppress them.
### `// INLINED` for functions that exist only inlined
A function that exists only inlined has exactly one annotation, the bare line `// INLINED`, immediately above its definition:

View file

@ -11,6 +11,7 @@
"Source/**/*.inl"
],
"toolchain": "ragnarok",
"globalRules": true,
"matchPolicy": {
"reviewAt": "match_unresolved",
"maxCleanupCycles": 5,