Document opcode 0x1a2 compatibility debt

This commit is contained in:
gamer147
2026-07-20 13:13:38 -04:00
parent c8303babf5
commit 188315e66b
5 changed files with 31 additions and 4 deletions

View File

@@ -169,6 +169,17 @@ and pinning the *real* handler via the dispatch table above corrects two layers
call-script / script-load dispatch (`name-resolution.md §1`), the next target for this loop (now call-script / script-load dispatch (`name-resolution.md §1`), the next target for this loop (now
armed with the dispatch table to resolve the call-script handler directly). armed with the dispatch table to resolve the call-script handler directly).
**Port audit consequence (2026-07-20): `0x1a2` is not faithfully implemented.** The VM still dispatches
the opcode through its legacy `gfx-cmd-register` label to `GfxState.Register(Read(a[0]))`. That method adds
only the operand's current numeric value to `_operandRegistry`, a `HashSet<long>`; it does not retain the
lvalue descriptor key used by AGE. `IsRegistered` has no runtime callers, so the set currently has no
gameplay or rendering effect (and its removal during gfx-object erase is likewise inert). Therefore this
mistake does **not** invalidate the completed retained-object, animation, History, or ADV work, whose
semantics came from independent workers/fields/traces. It does mean the opcode table's syntactic `impl`
classification overstates compatibility for `0x1a2`: keep it as explicit follow-up debt until the native
descriptor table's consumer is identified, then move the model out of `GfxState` and preserve descriptor→value
semantics in the appropriate VM/service subsystem.
**Lesson:** never analyze a native op by its Kelebek `u00XXXXXX` VA directly — always resolve the real **Lesson:** never analyze a native op by its Kelebek `u00XXXXXX` VA directly — always resolve the real
handler through the dispatch table (`ctx[0x26c93 + op]`). The raw VA is off by whole functions. handler through the dispatch table (`ctx[0x26c93 + op]`). The raw VA is off by whole functions.

View File

@@ -293,6 +293,8 @@ Native handler sleep_op_0xc8 @0x420ec0 is NON-BLOCKING: it arms a timer (sleep_t
- **grounding:** source=investigation, confidence=high - **grounding:** source=investigation, confidence=high
- **evidence:** Ghidra: handler 0x42d360 fetches operand 1's value and lvalue descriptor separately, formats the descriptor key, then calls FUN_0042cf70. By contrast op 0x215 passes ctx+0x46614 to gfx_object_query_source_slot@0x47f280, which searches the retained object map and returns obj+4. - **evidence:** Ghidra: handler 0x42d360 fetches operand 1's value and lvalue descriptor separately, formats the descriptor key, then calls FUN_0042cf70. By contrast op 0x215 passes ctx+0x46614 to gfx_object_query_source_slot@0x47f280, which searches the retained object map and returns obj+4.
Port status (2026-07-20): not faithfully implemented. The legacy gfx-cmd-register dispatch currently adds only the operand's numeric value to an otherwise runtime-unread HashSet in GfxState; it neither preserves the native descriptor key nor models a known consumer. Do not treat its presence in the VM switch or coverage's impl bucket as semantic completion. The native table's consumer must be identified before choosing the correct host subsystem.
### 0x1ad `mark-save-resume-frame` (mark-save-resume-frame, argc 0) ### 0x1ad `mark-save-resume-frame` (mark-save-resume-frame, argc 0)
- **summary:** Mark the current script context as the highest frame serialized by numbered-save layouts 2/3. The native serializer saves frames 0 through this boundary and strips the boundary frame's return target so loading resumes it as the top frame. This opcode performs no file I/O itself. - **summary:** Mark the current script context as the highest frame serialized by numbered-save layouts 2/3. The native serializer saves frames 0 through this boundary and strips the boundary frame's return target so loading resumes it as the top frame. This opcode performs no file I/O itself.
- **grounding:** source=investigation, confidence=high - **grounding:** source=investigation, confidence=high

View File

@@ -293,9 +293,11 @@ script-context records for gfx objects — was wrong: it observed the wrong stru
**Resolution had TWO halves** (canonical decode in `docs/engine-re.md`, op `0x215` + "The render drift's **Resolution had TWO halves** (canonical decode in `docs/engine-re.md`, op `0x215` + "The render drift's
SECOND half"; don't duplicate here): SECOND half"; don't duplicate here):
1. **Native gfx ops (b):** all 14 command-buffer ops (`0x1a2`,`0x1f7`,`0x1fa`,`0x1ff`,`0x202`,`0x203`, 1. **Native gfx ops (b):** the retained-object command-buffer ops (`0x1f7`,`0x1fa`,`0x1ff`,`0x202`,`0x203`,
`0x212`,`0x213`,`0x215``0x21a`) reversed + implemented against a host-side `GfxState` (VM execution `0x212`,`0x213`,`0x215``0x21a`) were reversed + implemented against a host-side `GfxState` (VM execution
state; `engine/Age.Engine/Model/GfxState.cs`). `0x215` now returns distinct per-object slots. state; `engine/Age.Engine/Model/GfxState.cs`). `0x215` now returns distinct per-object slots. **Correction
(2026-07-20):** `0x1a2` never belonged to this family; its current inert `GfxState` approximation is not a
faithful implementation. See `docs/engine-re.md` § op `0x1a2` for the compatibility-debt audit.
2. **Missing system-boot state (a):** the CG handle array `G[0x62455..]` is set by boot script **INIT2** 2. **Missing system-boot state (a):** the CG handle array `G[0x62455..]` is set by boot script **INIT2**
(via entrypoint `SYSTEM4.BIN`), which a cold single-scene run skips → all CGs collapsed onto object 0. (via entrypoint `SYSTEM4.BIN`), which a cold single-scene run skips → all CGs collapsed onto object 0.
Supplied via **`Age.Cli gfx --boot`** and **Godot `--boot`** (run `INITCONFIG/INIT2/INIT` through Supplied via **`Age.Cli gfx --boot`** and **Godot `--boot`** (run `INITCONFIG/INIT2/INIT` through
@@ -2004,3 +2006,13 @@ largest repeated non-persistence cluster still unclassified.
Validation: all 206 engine tests pass; opcode and EngineCtx tests/lints, vm0 RECOVER, and `git diff --check` Validation: all 206 engine tests pass; opcode and EngineCtx tests/lints, vm0 RECOVER, and `git diff --check`
are clean. SC0000 coverage deliberately remains 119/129 distinct opcodes handled (92.2%), with `0x1ad`'s are clean. SC0000 coverage deliberately remains 119/129 distinct opcodes handled (92.2%), with `0x1ad`'s
six calls retained as a gap until numbered saves serialize active execution frames. six calls retained as a gap until numbered saves serialize active execution frames.
**Follow-up audit — `0x1a2` compatibility status (2026-07-20).** Correcting the shared instruction-length
field does not invalidate any completed visible graphics/animation/UI behavior: every affected native opcode
has independent worker/field/trace evidence, and the port does not emulate `ctx+0x53d88`. The exception is
`0x1a2`, whose legacy VM case stores only a numeric value in an unread `GfxState` set instead of AGE's
lvalue-descriptor→value entry. It has no present runtime consumer, so this is latent compatibility debt rather
than a current visual regression. Coverage currently counts the case as `impl`; do not interpret that bucket
as proof of semantic completion for this opcode. Canonical details and the eventual investigation target live
in `docs/engine-re.md` and `vm-map/opcodes.toml`. Documentation validation: regenerated opcode references,
opcode build/lint and tests, and `git diff --check` are clean.

View File

@@ -47,7 +47,8 @@ separate open-addressing table. Its write of 3 at `ctx+0x53d88` is the instructi
command type. So that snippet is a **value-registration operation, not the command type. So that snippet is a **value-registration operation, not the
decision→scene dispatch**. The real decision→scene mechanism is **still unidentified** and belongs with decision→scene dispatch**. The real decision→scene mechanism is **still unidentified** and belongs with
the call-script / script-load dispatch (`name-resolution.md §1`). See `docs/engine-re.md` for the the call-script / script-load dispatch (`name-resolution.md §1`). See `docs/engine-re.md` for the
verified handler analysis and the opcode-dispatch table that will crack call-script next. verified handler analysis, including the explicit note that the port's legacy inert `GfxState` approximation
is not a faithful implementation, and the opcode-dispatch table that will crack call-script next.
## See also ## See also
- `vm-map/globals.toml` — the named globals SCJUMP switches on (chapter_mode, progress counters, flags). - `vm-map/globals.toml` — the named globals SCJUMP switches on (chapter_mode, progress counters, flags).

View File

@@ -3467,6 +3467,7 @@ abi_source = "kelebek+decode-validated"
name = "register-lvalue-value" name = "register-lvalue-value"
category = "control" category = "control"
summary = "0x1a2 (value) — register operand 1's current value under a key derived from its lvalue descriptor in the open-addressing table at ctx+0x5190. The write of 3 at ctx+0x53d88 is only this instruction's encoded dword length, not a graphics command type. This structure is separate from op 0x215's retained gfx-object map; op 0x215 does not query it. NOT save/scene." summary = "0x1a2 (value) — register operand 1's current value under a key derived from its lvalue descriptor in the open-addressing table at ctx+0x5190. The write of 3 at ctx+0x53d88 is only this instruction's encoded dword length, not a graphics command type. This structure is separate from op 0x215's retained gfx-object map; op 0x215 does not query it. NOT save/scene."
details = "Port status (2026-07-20): not faithfully implemented. The legacy gfx-cmd-register dispatch currently adds only the operand's numeric value to an otherwise runtime-unread HashSet in GfxState; it neither preserves the native descriptor key nor models a known consumer. Do not treat its presence in the VM switch or coverage's impl bucket as semantic completion. The native table's consumer must be identified before choosing the correct host subsystem."
noop_headless = false noop_headless = false
source = "investigation" source = "investigation"
confidence = "high" confidence = "high"