Parent: atrinik/atrinik#357
Completed migration evidence: #113, #137, #139, #154
Downstream order: atrinik/atrinik#358 → atrinik/classic#170 and atrinik/playtester#2 → atrinik/github-settings#64
Outcome
Make atrinik/content@main the sole mutable authored source. Reconcile the final Classic behavior onto main, publish a deterministic explicit Classic target from main, and retire branch-specific authoring/release machinery only after every consumer has cut over. Preserve all historical tags, releases, assets, checksums, licenses, attribution, and reachable history.
The completed #137 ledger and #139 semantic audit are bounded migration evidence, not a permanent dual-line workflow and not a substitute for the exact equality gates below.
Frozen migration baseline — 2026-08-12
| Coordinate |
Revision |
Tree |
Fork (v1.8.1) |
01b1fdb65c2243df4bafe9c8109fc93229df0121 |
— |
main (v2.13.1) |
3beec723be15d9f58d6321f728f5d73d33a00013 |
ecbb60b15202300421f93af76ce46e357281dcdc |
1.x (v1.8.18) |
0032e319dde316c2076832066fb5381177b34f42 |
30e4ef7218c97b8bcd4d11f8a8e76820234bda48 |
These are the certified #154 migration inputs. Independent 1.x feature delivery is frozen. Any authorized reconciliation change that moves an input requires a newly recorded exact coordinate and rerun comparison before cutover.
The lines contain 31 main-only and 34 1.x-only commits and 43 direct tip-tree differences. The completed audit classifies all 43 with zero pending outcomes, but classification does not satisfy this issue's exact authored-tree or Classic-payload gate.
The authored reconciliation roots contain 11 changed paths:
- two semantically equal forcefield files whose fields differ only in order;
- nine map-domain paths containing the complete Incuna apartment behavior/tests and
maps/light-source-review.json.
Media plus editor/, contracts/, schemas/, and prototypes/ are identical. No open PR targets 1.x.
Exact-head runtime builds currently differ in 12 paths. main still emits a generic schema-1 manifest with no Classic target; 1.x emits the schema-2 Classic compatibility contract and retains the working Incuna apartment adapters. Pointing Classic directly at main is therefore unsupported until this issue is delivered.
Scope
1. Reconcile authored and Classic behavior
- Port the complete Classic Incuna apartment adapter, event bindings, and tests to
main: idempotent/retry-safe grant, owner gating, private-map persistence/reload, portal return, save-bed behavior, and ordered one-time quest completion.
- Retain typed property intent and replacement-consumer boundaries. Co-location does not authorize a replacement implementation to execute or copy Classic-only GPL Python.
- Normalize the two forcefield files and select one canonical
maps/light-source-review.json result so the final authored trees compare exactly.
- Preserve provenance and authorship commit-by-commit. Do not merge branch histories wholesale or copy generated runtime output.
- Never restore
maps/light-source-evidence/**, its manifest, proof scene, capture tooling/tests, or capture-bound views/evidence_focus fields.
2. Publish an explicit Classic target from main
Generalize the content-owned publisher with a target contract equivalent to:
python3 tools/build_runtime.py \
--target classic \
--source-commit SHA \
--output DIRECTORY
The Classic target must:
- identify
atrinik/content, source.branch == "main", and the exact clean commit;
- preserve
classic-ads-v1 and the current Classic runtime artifact contract while ADS remains canonical;
- identify supported Classic consumers and version range;
- emit deterministic schema-2 compatibility metadata accepted by the wrapper;
- bind every payload and applicable license/attribution file by size and SHA-256;
- remain
replacement_ready: false and unambiguous from replacement artifacts;
- fail closed on dirty/mismatched coordinates, unsafe output, incomplete licenses, or nondeterminism.
Future whole-corpus format translation remains content #8/#11 and content-toolkit #6/#9; it is not required merely to unify the current ADS source.
3. Hand off consumer cutover and branch retirement
After the reviewed Classic target is published through normal Semantic Release:
Never create, move, replace, or delete a tag/release manually.
Acceptance criteria
Integration gate
Validation
python3 tools/validate.py
python3 tools/build_runtime.py --target classic --source-commit SHA --output build/classic-runtime
git diff --check
Also run the direct final tree/catalog comparison, both exact-head Classic target builds, package checksum verification, the wrapper Classic build, the isolated content-main-cutover scenario, and current GitHub checks at every recorded coordinate.
Rollback and non-goals
The immutable rollback anchor is v1.8.18@0032e319dde316c2076832066fb5381177b34f42 with its published archives and SHA256SUMS. Until consumer cutover, a reviewed rollback may repin that artifact. Never rewrite a tag, release asset, branch history, or mutable server state.
This issue does not implement the future whole-corpus format migration, retire Classic support, relicense content, delete historical releases, or preserve 1.x as a second authoring source.
Parent: atrinik/atrinik#357
Completed migration evidence: #113, #137, #139, #154
Downstream order: atrinik/atrinik#358 → atrinik/classic#170 and atrinik/playtester#2 → atrinik/github-settings#64
Outcome
Make
atrinik/content@mainthe sole mutable authored source. Reconcile the final Classic behavior ontomain, publish a deterministic explicit Classic target frommain, and retire branch-specific authoring/release machinery only after every consumer has cut over. Preserve all historical tags, releases, assets, checksums, licenses, attribution, and reachable history.The completed #137 ledger and #139 semantic audit are bounded migration evidence, not a permanent dual-line workflow and not a substitute for the exact equality gates below.
Frozen migration baseline — 2026-08-12
v1.8.1)01b1fdb65c2243df4bafe9c8109fc93229df0121main(v2.13.1)3beec723be15d9f58d6321f728f5d73d33a00013ecbb60b15202300421f93af76ce46e357281dcdc1.x(v1.8.18)0032e319dde316c2076832066fb5381177b34f4230e4ef7218c97b8bcd4d11f8a8e76820234bda48These are the certified #154 migration inputs. Independent
1.xfeature delivery is frozen. Any authorized reconciliation change that moves an input requires a newly recorded exact coordinate and rerun comparison before cutover.The lines contain 31
main-only and 341.x-only commits and 43 direct tip-tree differences. The completed audit classifies all 43 with zero pending outcomes, but classification does not satisfy this issue's exact authored-tree or Classic-payload gate.The authored reconciliation roots contain 11 changed paths:
maps/light-source-review.json.Media plus
editor/,contracts/,schemas/, andprototypes/are identical. No open PR targets1.x.Exact-head runtime builds currently differ in 12 paths.
mainstill emits a generic schema-1 manifest with no Classic target;1.xemits the schema-2 Classic compatibility contract and retains the working Incuna apartment adapters. Pointing Classic directly atmainis therefore unsupported until this issue is delivered.Scope
1. Reconcile authored and Classic behavior
main: idempotent/retry-safe grant, owner gating, private-map persistence/reload, portal return, save-bed behavior, and ordered one-time quest completion.maps/light-source-review.jsonresult so the final authored trees compare exactly.maps/light-source-evidence/**, its manifest, proof scene, capture tooling/tests, or capture-boundviews/evidence_focusfields.2. Publish an explicit Classic target from
mainGeneralize the content-owned publisher with a target contract equivalent to:
The Classic target must:
atrinik/content,source.branch == "main", and the exact clean commit;classic-ads-v1and the current Classic runtime artifact contract while ADS remains canonical;replacement_ready: falseand unambiguous from replacement artifacts;Future whole-corpus format translation remains content #8/#11 and content-toolkit #6/#9; it is not required merely to unify the current ADS source.
3. Hand off consumer cutover and branch retirement
After the reviewed Classic target is published through normal Semantic Release:
1.xrelease configuration and dual-line guidance only after all consumers have cut over;Never create, move, replace, or delete a tag/release manually.
Acceptance criteria
git diff --exit-code FINAL_1X FINAL_MAIN -- arch maps editor contracts schemas prototypesis empty at recorded cutover candidates.python3 tools/validate.pyandgit diff --check.lib/,maps/, andattribution/path sets and SHA-256 values, excluding only enumerated source-coordinate manifest fields.mainClassic target is deterministic, schema-2, checksum/license bound, consumer-compatible, and explicitly not replacement-ready.mainreproduces from its recorded tag/commit andSHA256SUMS.1.xbefore retirement.Integration gate
mainClassic target and builds the full Classic profile from one physical content checkout.v1.xreleases remain downloadable and verifiable after eventual branch deletion.Validation
Also run the direct final tree/catalog comparison, both exact-head Classic target builds, package checksum verification, the wrapper Classic build, the isolated
content-main-cutoverscenario, and current GitHub checks at every recorded coordinate.Rollback and non-goals
The immutable rollback anchor is
v1.8.18@0032e319dde316c2076832066fb5381177b34f42with its published archives andSHA256SUMS. Until consumer cutover, a reviewed rollback may repin that artifact. Never rewrite a tag, release asset, branch history, or mutable server state.This issue does not implement the future whole-corpus format migration, retire Classic support, relicense content, delete historical releases, or preserve
1.xas a second authoring source.