Files
Cesarus85--ringfall-mjolnir-vr/docs/shape_transfer_executor_strategy.md
T

9.8 KiB

Exact-shape transfer candidate executor

Scope and invariants

This branch productionizes only candidate generation and review-packet emission. The executor is deliberately unable to apply a patch, invoke a compiler, update a matching ledger, edit configuration, commit, merge, or integrate.

The repository is read-only from the executor's point of view. Output must be a new directory outside the repository. A successful run emits an unapplied patch, a standalone candidate fragment, and review metadata. A refusal emits no candidate.

The input atlas is evidence to recheck, not an authority for text replacement. The executor derives the ordered substitution events from the donor and recipient January target COFF relocations and requires the atlas events to match exactly. It refuses:

  • unsafe or incomplete proof records;
  • stubs with a meaningful size of 16 bytes or less;
  • unequal padded/meaningful sizes, normalized bytes, relocation count/order/type, storage class, or prologue;
  • non-injective substitutions;
  • relocation addend changes, non-symbol substitutions, and constant symbols;
  • donor source that is missing, ambiguous, recursive, or not a real definition;
  • missing, ambiguous, or incompatible recipient prototypes/inline definitions, including return type and every parameter type;
  • stale/wrong-callee atlas events;
  • a transformed symbol that is not present exactly as often as the donor target relocates it;
  • missing recipient declarations unless a single unambiguous declaration can be copied verbatim from a repository header (the packet pins that header hash); an optional manifest can pin the same operation explicitly; and
  • a recipient function already defined in source.

Text generation is token substitution only. It changes the donor function name and the relocation-proven symbol identifiers; it cannot synthesize a body, change constants, reorder statements, or retry a refusal with heuristics.

Acceptance boundary

CANDIDATE_GENERATED_NOT_ACCEPTED is the strongest possible executor result. Exact acceptance remains exclusively:

  1. the hardened cross-name tools.coff_compare.section_infos_equal comparison;
  2. a zero-regression whole-translation-unit manifest comparison; and
  3. unchanged whole-object data/BSS/ownership fingerprints.

Those gates must be run in a disposable build worktree by a human review lane. The executor neither runs them nor converts their future results into matching credit.

Operator usage

Invoke the tool from a clean campaign worktree. --target-root is the directory whose children mirror the atlas unit names and contain the January target objects. --output-dir must be a new directory outside the repository.

python tools\transfer_executor.py `
  --repo-root C:\path\to\campaign-worktree `
  --atlas C:\path\to\transfer_atlas_v2.json `
  --target-root C:\path\to\build\split `
  --base-root C:\path\to\untouched\build\base `
  --recipient-unit source/objects/widgets/flags `
  --recipient-function _flag_delete `
  --donor-unit source/objects/widgets/antenna `
  --donor-function _antenna_delete `
  --output-dir C:\path\outside\repo\flag-delete-review

The donor selector is optional only when the recipient selector is unique. The tool refuses an ambiguous selection. Missing declarations are copied only when one exact declaration exists in repository headers. An operator may instead pass --declaration-manifest; each entry must include symbol, verbatim text, repository-relative header source, and the SHA-256 of that header. Extra, stale, non-verbatim, or non-header declarations are refused.

A successful output directory contains:

  • candidate.c: standalone generated fragment;
  • candidate.patch: unapplied unified diff;
  • review_packet.json: hash-pinned inputs, derived events, generation checks, and all acceptance gates marked NOT_RUN_REQUIRED;
  • frozen_tu_baseline.json: the complete untouched recipient target/base function, symbol, non-code section, and ownership fingerprints plus the pre-edit strict-exact sibling set; and
  • REVIEW.md: human handoff and mandatory gate list.

Implementation and validation log

  • 2026-07-29: observed the clean canonical campaign integration HEAD at 5b61655c5e40f6964d8dd37d2db4364b0a82c07e.
  • 2026-07-29: created isolated branch codex/shape-transfer-executor and worktree work/shape-transfer-executor from that commit.
  • 2026-07-29: reviewed the fail-closed executor spec, minimum transformation language, duplicate atlas, donor/recipient map, 12-case experiment driver, atlas generator, and later production blueprint.
  • 2026-07-29: synthetic executor suite passed 22/22. The lexically first test was the requested zero-substitution, non-rasterizer class. Covered successful no-substitution and callee/data substitutions; unchanged constant relocations; explicit and automatic hash-pinned declarations; immutable and atomic packet emission; frozen pre-edit TU/object manifests; changed-input detection; review lints for donor-domain parameter names and potentially redundant generated declarations; and refusals for wrong callees/stale atlas events, non-injective maps, relocation/statement-order changes, stubs, ambiguous sources/pairs, missing declarations/baselines/prototypes, incompatible return/parameter ABIs, pre-existing recipient bodies, and source/target occurrence mismatches.
  • 2026-07-29: the complete tools/test_*.py suite passed 167/167.

Archived-artifact validation

Validation used transfer_atlas_v2.json and the archived January target objects under fable-transfer-exp/build/split. Generation read source only from this clean 5b61655c5 worktree.

The real zero-substitution non-rasterizer pair was tested first:

  • ai/actions:_set_real_vector3d <- ai/ai_debug:_set_real_point3d: REFUSED (donor-source-missing). The older donor_source_resolved flag was a regex false-positive: ai_debug.c references set_real_point3d but does not define it. The implementation is inline in another header. Header-emission donor resolution is intentionally a later resolver upgrade, not a heuristic in this executor.

The five previously exact experiment pairs then produced:

Recipient Result Detail
objects/widgets/flags:_flag_delete CANDIDATE_GENERATED_NOT_ACCEPTED Ordered target relocations derived _antenna_data -> _flag_data; unique datum_delete prototype copied verbatim from source/memory/data.h and header hash pinned.
ai/ai:_ai_dispose REFUSED No explicit ai_debug_dispose declaration in recipient context or a unique repository header.
effects/effects:_effects_dispose REFUSED No explicit effect_data declaration/definition in recipient context or a unique repository header.
objects/object_lights:_code_00129100 REFUSED No explicit light_cluster_partition declaration/definition in recipient context or a unique repository header.
objects/object_lights:_code_00129120 REFUSED Same missing light_cluster_partition evidence.

All four missing-declaration refusals occurred after the target-object structural and relocation-derived substitution checks passed. The executor did not recreate the experiment driver's hand-written declarations because the production blueprint requires real-header provenance.

Independent human review of the first flag_delete packet made two source-only cleanups that relocation evidence cannot prove: antenna_index became flag_index, and the redundant local datum_delete prototype was removed. After that cleanup the candidate passed strict comparison at 32/32 bytes and 2/2 relocations; all four pre-existing strict-exact siblings remained exact; both existing .rdata COMDAT payloads/sizes remained byte-identical; and _flag_data remained the same 4-byte COMMON symbol. This is a valid zero-regression transfer validation, not production admission: flags.obj remains incomplete at 5/16 functions, no production source was changed here, and no matching credit was granted. The executor now emits explicit REVIEW_REQUIRED lints for both classes of cleanup instead of attempting them.

An early next-packet attempt for effects/contrails:_local_random_range <- camera/bored_camera:_real_local_random_range exposed a serious false-positive class and is revoked. Relocations suggested only _real_seed_random_range -> _seed_random_range, but the donor is float(float, float) while source/math/real_math.h already defines the recipient inline as short(short, short). Their wrapper bytes happen to share a shape because both argument types consume dword stack slots and each tail-returns its own callee's native ABI. Applying the packet in an isolated review worktree failed CL with C2371 at contrails.c(162), pointing to the conflicting inline definition at real_math.h(1344).

The executor now requires a unique compatible recipient declaration or inline definition from the actual recipient include closure, with identical canonical return and parameter types, before source transformation. Missing, ambiguous, function-pointer/array-unsupported, or incompatible evidence is terminal. A synthetic regression test reproduces the real/short conflict, and the real pair now refuses as recipient-prototype-incompatible without creating output.

Re-scanning all 21 atlas entries marked donor_source_resolved under this hardened rule produced zero new candidates. Therefore the current automated candidate batch is empty. The independently validated flag_delete transfer is the sole human-reviewed result, but it is still not admitted and the hardened generator would now refuse it until a recipient prototype is sourced. The other proven experiment pairs and the zero-substitution pair stay closed until declaration, prototype, or donor-source provenance is improved without heuristics.

No production source, matching status, configuration, or ledger changed during artifact validation.