Files
tdkpin/original/C_RECONSTRUCTION_FINAL_AUDIT.md
ddidderr 7633ef9990 fix(attract): restore all remainder-driven cycles
The same raw Div32 pattern used by the item animation appears in every nested
idle phase: after division by 32, 40, or 16, the binary copies the remainder
from CX:BX before the second division. Readable C and Rust used quotients for
targets, word quads, the record strip, and the four-point chase, turning short
repeating chases into slow one-shot progressions.

Use `%32/2`, `%32/4`, `%40/4`, and `%16/4` for those cycles alongside the
already corrected `%144/8` items. Preserve the first-cycle phase-zero delay,
then repeat each incremental overlay state exactly. Add C and Rust coverage at
phase activation, reversal, deactivation, and wrap boundaries.

Test Plan:
- raw instruction review at `1000:01b7-063b` -- all remainder transfers confirmed
- `cargo test --workspace --all-targets --all-features` -- 125 passed
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` -- passed
- `bash original/tools/test_reconstructed_c.sh` -- passed
- `python3 original/tools/audit_reconstruction.py --require-complete` -- passed with zero incomplete or unclassified units
- `cargo run -- --simulate attract --step 145 --screenshot /tmp/tdkpin-attract-remainder.png` -- passed; visually inspected at 640x460
- `rumdl check --flavor commonmark RECONSTRUCTION.md CHANGELOG.md` -- passed
- `git diff --cached --check` -- passed
2026-08-23 20:53:12 +02:00

116 lines
6.9 KiB
Markdown

# TDKPIN.EXE C reconstruction final audit
Audit target:
```text
a9022f1894e3e6e21fc42e8f6c932f7c549ca77f63aaa0c488bb9d55d9d0174c TDKPIN.EXE
987a47580ba5c92fa071c989bdaeddf138e285d2b07106c5909a4acbc3e27088 TDKPIN_GHIDRA_RAW.c
```
The vendor source is unavailable. “Faithful C” therefore means an
address-traceable semantic reconstruction whose claims are closed by image
bytes, disassembly, relocation/reference data, typed Win16/Borland behavior,
and focused runtime evidence. It does not mean a byte-identical rebuild with
the original Borland compiler.
## Requirement audit
1. **Immutable evidence:** `TDKPIN_GHIDRA_RAW.c` retains its sealed hash.
Regenerated complete raw evidence is separate and never used as readable C.
2. **Executable bytes:** all 93,064 executable-segment bytes are classified.
93,062 have non-overlapping Ghidra code/data units. The remaining two are
individually explained in `UNEXPLAINED.tsv` as an overlapping-entry opcode
at `1020:0666` and an alignment NOP at `1020:0dea`; zero bytes are
unclassified.
3. **Functions:** 391 ordinary in-image functions and all six overlapping/shared
entries are `verified`. Every ordinary function row names its exact address,
readable C symbol, source module, disassembly evidence, and semantic result.
No row is raw, partial, restored, unknown, or blocked.
4. **Readable C:** the authoritative deliverable is the 63 strict-C11 units
under `reconstructed/`. Historical partial `TDKPIN_*_RESTORED.c` files are
explicitly marked superseded and are not completion artifacts.
5. **Imports and ABI:** all 292 NE import slots are verified. The 137 called
slots have reviewed Win16 prototypes and call-site effects; 155 duplicate,
data-only, or unused slots have explicit zero-CALL accounting. Segment/offset
far pointers, PASCAL stack cleanup, 16-bit widths/wrap, and intentionally
retained register bytes are represented in the C model.
6. **Runtime library:** every in-image Borland routine is reconstructed or
identified through its exact implementation role. Real48 conversion,
arithmetic, comparison, transcendental tables, rounding, overflow/error
behavior, heap, files, strings, objects, and startup/shutdown paths are
address-linked rather than silently omitted.
7. **Data:** all 19,770 DGROUP bytes are covered by 744 non-overlapping verified
ranges and 219 verified semantic objects. All 455 referenced DGROUP addresses
and all 18 code-embedded objects (282 bytes) are verified. The complete
175-record collision/rule table and all indirect dispatch/VMT/procedure
tables are represented.
8. **Callbacks and indirect control flow:** all six callback registrations are
verified with target, thunk/instance lifetime, and invocation behavior. All
301 NE entry points, 2,434 relocation sites, VMT dispatches, bound thunks,
function pointers, and shared/overlapping entries are inventoried.
9. **Resources:** all 63 NE resources round-trip byte-for-byte from the target
and have decoded derivatives where applicable. `RESOURCE_RECONSTRUCTION.tsv`
has 63 verified rows. The semantic C catalog in `tdkpin_resources.c` records
every type/ID, file offset, flags, allocated/meaningful size, dimensions or
sample rate, disposition, and role. Four Borland File Open/Save templates are
explicitly `linked-unused`; ICON 1 and VERSION 1 are Windows-resolved rather
than falsely assigned image-code callers. WAV 2022 is loaded/freed by the
generic loop but has no in-image playback selector.
10. **Companion timer:** `MMTIMER.DLL` is sealed as
`f1d9ac980c7bfba5dc53eaa9e7cb2c3cd9b82f879ee8962ad40bf863d641bb49`.
TDKPIN's sole ordinal-1 relocation/call, the DLL's timer callback, message
`0x0580`, returned timer ID, and `timeKillEvent` lifetime are mapped.
11. **Behavioral validation:** every reconstructed C unit is compiled with
strict warnings by `tools/test_reconstructed_c.sh`; 89 focused harness
units cover normal, boundary, error, ownership, ABI, rendering, persistence,
resource, physics, callback, and lifecycle paths. The resource verifier
proves all 63 raw hashes and derivatives. `probe_real48_reference.sh`
matches a real 16-bit Borland reference stream bit-for-bit. Documented
Wine 11.15 probes cover original startup/input, timer gravity/substeps,
claw terminals, moving flippers, collision types 1..4, target/rule effects,
multiball, and scoring. Static/host evidence is not mislabeled as Wine.
12. **Phase boundary:** no Rust source or Cargo manifest/lockfile was modified.
Post-audit evidence correction (2026-08-23): raw `1000:9b69` reads predicted
DGROUP coordinates `1028:07db/07df`, not current `07d3/07d7`. The readable
helper and its harness now reflect that distinction; the complete C test and
ledger gates below still pass. Raw `1000:c79c` also confirms that the response
reads fixed candidate slot 1 at `SS:...d8a2`; later nearer candidates are stored
in subsequent 0x34-byte slots but do not replace the applied record. A focused
two-candidate harness now seals that record-order behavior.
Raw `1000:531e` further corrects the Pascal-order BitBlt interpretation: the
DAT994 progress strip is drawn at `(202,328)` with height 13 and width
`(stage-1)*7`, rather than the impossible historical 328x202 read from a
237x13 bitmap. The focused loading-stage harness seals stages 1, 35, and 0.
Live one-substep rail/circle probes further correct the response transform.
The binary's standard dot-product tangent
`tv=(vx*normal_x + vy*normal_y)/length` drives
`spin_delta=tv*0.02*response_tangent`. The current tangential response opposes
the sign of `tv` with magnitude
`abs(normal_velocity)*response_tangent` (negative when `tv==0`) and is added to
retained `spin*0.4`. The documented horizontal drain
`(0,3015)->(-302,-1809)`, ordinary circle/bumper transitions, and stopped
Wine record-57 transition `(75530,354765)/(3000,15)` to
`(77369,356597)/(1839,1832)` with exact Real48 spin `-5.28`, plus record 72
`(235348,356825)/(-3000,15)` to `(233253,358494)/(-2095,1669)` with spin
`+5.46`, seal both paths and both relative slingshot chains.
Raw `1000:01b7-063b` further distinguishes the DOS divide outputs throughout
the idle animation: each nested phase copies the first division's remainder
from `CX:BX` before its second division. The readable C and focused timer
harness therefore use target `%32/2`, word-quad `%32/4`, record-strip `%40/4`,
four-point `%16/4`, and item `%144/8` cycles. This produces the repeating
animation rather than the previously inferred unbounded quotients.
## Reproducible gates
```sh
bash original/tools/test_reconstructed_c.sh
bash original/tools/probe_real48_reference.sh
python3 original/tools/audit_reconstruction.py --require-complete
git diff -- '*.rs' Cargo.toml Cargo.lock
```
The final ledger gate requires every function, import, data range/object,
resource, callback, and shared entry to be `verified`, plus zero unclassified
executable ranges. At this audit all required incomplete-status counts are zero.