Repository navigation
REQ-CONFIG-004: key cohort population genesis reconciliation by typed region identity - #471
Conversation
… region identity POPULATION_ENDOWMENT records carry the cohort's Region typed, but genesis reconciliation keyed cohort population by owner alone. A record naming the wrong Region therefore still reconciled, because the comparison never read the typed location it carried. Key both sides of the population comparison by cohort owner plus Region: the expected side from the record's own `regionId`, the actual side from the cohort's Region resolved through the region registry, so `sourceSeedKey` stays provenance only (Handoff/03 section 20). Add a negative control that changes only `POPULATION_ENDOWMENT.regionId` while owner, source key, amount and aggregate population are unchanged, and proves reconciliation fails. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… PR #471 Keeps REQ-CONFIG-004 PARTIAL: #455 (ProductionUnit GOOD_ENDOWMENT INPUT/OUTPUT/INVESTMENT bucket identity) is still open, so the requirement is not yet provable at full typed-identity granularity. MERGE_COMMIT stays empty; scripts/backfill_merge_commits.py fills it after this pull request merges. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AUTHOR note: one superseded
|
ACCEPTOR verdict: ACCEPTJudged head revision: 1. Every required check is measured green at the head revisionRead from the checks tab at
On the two 2. Every acceptance criterion is met, with the evidence I observed
Independent re-execution at The claimed requirement ID is implemented, not merely mentioned: 3. The diff is confined to the declared scopeFour files, every one named in the handoff and every one inside Issue #452's
No path under The highest-risk area the body nominated — hoisting 4. No invariant and no test was weakenedThe test file is 5. No secret, credential, personal data or local machine path
6. The handoff record is completeAll nine required elements are present, and the evidence separates measured from assumed rather than blurring them: the "Not checked" section names the sensitivity limitation, the un-reported forge checks at writing time, and the un-run Pages build; the assumptions section marks the "population is not deliberately Region-blind" reading as an assumption and names the right remedy if it is wrong (a spec question, not a revert). That is the distinction this gate exists to judge, and it is drawn honestly. Note on the open sibling
Merging at |
Every typed-identity defect named by the row's own PARTIAL rationale is now closed: cohort owner identity (#459), capital-good identity (#461), GOOD_ENDOWMENT region identity (#467), RESOURCE_ENDOWMENT typed region/good identity (#469), POPULATION_ENDOWMENT region identity (#471) and, with this pull request, ProductionUnit inventory-bucket identity (#455). No further REQ-CONFIG-004 Issue is open. MERGE_COMMIT is left blank for scripts/backfill_merge_commits.py, which fills it once the squash commit exists. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ucket (#473) * REQ-CONFIG-004: key ProductionUnit genesis goods by typed inventory bucket Handoff/03 section 20 (spec changelog HANDOFF-REPAIR-017) makes the ProductionUnit inventory bucket part of canonical stock identity: opening goods must reconcile by ProductionUnit + region + inventoryBucket + goodId, not by a unit-wide aggregate, and sourceSeedKey is provenance only. Before this change the three inventories were emitted as three GOOD_ENDOWMENT records distinguished only by their sourceSeedKey text, and both sides of reconciliation summed them into one owner+region+good bucket. A same-quantity INPUT<->OUTPUT<->INVESTMENT relocation therefore reconciled cleanly. The baseline scenario makes this reachable rather than theoretical: the iron mine holds `good:iron` as both INPUT (80) and OUTPUT (300). - genesisLedger.ts: add the InventoryBucket type and split GOOD_ENDOWMENT into a ProductionUnit-owned member that requires inventoryBucket and a member for every other owner that may not carry one. A Cohort holds one householdInventory and a State one publicInventory, neither of which is an INPUT/OUTPUT/INVESTMENT container, so the requirement and the prohibition are both structural rather than a runtime check. - worldState.ts: emit INPUT / OUTPUT / INVESTMENT for the three ProductionUnit opening inventories. - genesisReconciliation.ts: build one goodStockKey(owner, region, bucket, good) used by the expected and both actual projections. The reported diagnostic key now names the bucket, so a failing stock distinguishes INPUT from OUTPUT from INVESTMENT. Proving tests (genesisReconciliation.test.ts): a cross-bucket split that holds the owner+region+good aggregate exactly constant, asserted before the failure assertion; a bucket relabel on the iron mine's INPUT iron, which the unit's OUTPUT iron already covers; and a positive test that each opening inventory is recorded under its own bucket, asserting all three buckets appear so it is not vacuous. Confirmed sensitive by collapsing the bucket key segment: exactly the two new negative controls fail (2 failed | 31 passed) and restoring returns 33/33. Closes #455 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger: record REQ-CONFIG-004 as IMPLEMENTED via PR #473 Every typed-identity defect named by the row's own PARTIAL rationale is now closed: cohort owner identity (#459), capital-good identity (#461), GOOD_ENDOWMENT region identity (#467), RESOURCE_ENDOWMENT typed region/good identity (#469), POPULATION_ENDOWMENT region identity (#471) and, with this pull request, ProductionUnit inventory-bucket identity (#455). No further REQ-CONFIG-004 Issue is open. MERGE_COMMIT is left blank for scripts/backfill_merge_commits.py, which fills it once the squash commit exists. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Closes #452
Achieved outcome
Cohort opening population is now reconciled by canonical cohort owner plus typed Region identity, so a
POPULATION_ENDOWMENTrecord naming the wrong Region can no longer pass genesis reconciliation on an unchanged owner, source key and amount. Before this change the expected side keyed population onPOP:<owner>alone and the actual side rebuilt the same owner-only key, so the Region the record carried typed and required was never read; the comparison proved who held the population but not where it was.sourceSeedKeyremains provenance only, as Handoff/03 section 20 requires.Tested revision
a8349336310508cbb6896d082893cb89f08923b4(branch head; every check below was re-run at this revision after the ledger commit).Changed artifacts
git diff --name-only origin/master...HEAD:src/simulation/genesisReconciliation.ts— population key on both sides becomesPOP:<owner>:<region>. The expected side reads the record's own typedregionId; the actual side resolves the cohort's Region through the existingregionIdByRegionKeyregistry map fromCohortSeed.regionKey(the same canonical cohort/region relation and the same lookup the goods projection already uses), hoisted above the population block so both cohort projections share one resolution. Header contract comment updated to state the population key. No behavior outside population reconciliation changes.src/simulation/genesisReconciliation.test.ts— one new negative control plus atotalPopulationhelper used by it.docs/spec/implementation_status.csv—REQ-CONFIG-004row updated in place (one row per requirement):ISSUE451 → 452,PR469 → 471,MERGE_COMMITcleared (unknowable before merge;scripts/backfill_merge_commits.pyfills it),EVIDENCEextended to name this pull request alongside the prior contributing ones.STATUSstaysPARTIAL.docs/spec/IMPLEMENTATION_STATUS.md— regenerated bypython scripts/implementation_status.py, never hand-edited.Acceptance criteria
POPULATION_ENDOWMENTreconciliation verifies canonical cohort owner and typed Region identity, not onlysourceSeedKey. Both sides key onPOP:${serializeOwner(...)}:${serializeRegion(...)}. Neither side readssourceSeedKey(population reconciliation stopped doing so in PR REQ-CONFIG-004: attribute cohort opening money/goods/population to the cohort, not its Clan #459; this adds the location half).genesisReconciliation.test.ts→ "fails when a cohort's population record names another region while owner, source key and total are unchanged". It asserts the unmodified genesis reconciles, asserts the relabelled record'sowner,sourceSeedKeyandamountare identical to the original, asserts total recorded population is unchanged, and only then assertssuccess === falsewithdetails.category === "POPULATION". Sensitivity was proved by stashinggenesisReconciliation.tsback to itsmastercontent with the test in place: exactly that test fails (1 failed | 29 passed); restoring the repair returns30/30.baseline-multistate-v1ledger reconcilestrue; the full suite is green (590/590), and no positive test regressed.11bd421), which made population owner-bound asPOP:${serializeOwner(...)}. This change extends that same key with a region segment and reuses the sameserializeOwner/serializeRegionhelpers and the same region registry lookup the goods path uses — no parallel convention was introduced.docs/spec/implementation_status.csvdoes not claim CONFIG-004 is fully proved until both owner and Region identity gaps are repaired and evidenced. The row staysPARTIALand states plainly that sibling defect REQ-CONFIG-004: preserve ProductionUnit GOOD_ENDOWMENT inventory-bucket identity #455 (ProductionUnitGOOD_ENDOWMENTINPUT/OUTPUT/INVESTMENT bucket identity) is still open, so the requirement is not yet provable at full typed-identity granularity.Checks
npm cinpm run typechecktsc --noEmit, no outputnpm testnpm run builddist/canonical.jsbuiltdotnet restoredotnet build --configuration Releasedotnet test --configuration Releasepython scripts/implementation_status.py --checkpython scripts/status_lint.py --self 471 --base masterpython scripts/policy_guard.py --base masterOutcome is exactly one of
passed,failed,not_run,unavailable.Not checked
genesisReconciliation.tsonly; I did not separately neutralize the region segment alone, so the test is proved sensitive to this whole repair rather than to the region segment in isolation. Residual risk: low — the owner half of the key already existed onmaster, so the only behavior the test can be reacting to is the added region segment.typescript,build-and-test,policy-guard,mergeability) had not reported at the time this body was written; the outcomes above are from local runs at the tested revision.Assumptions and unknowns
POPULATION_ENDOWMENTdeclaresregionId: RegionIdas required insrc/domain/genesisLedger.ts, andbuildInitialWorldstep 8 is the only site that emits one, always fromidMap.regionIds.get(cohortSeed.regionKey).regionId?: RegionIdonGenesisRecordand states thatsourceSeedKeyis provenance only and must never substitute for typed stock identity.GOOD_ENDOWMENT(HANDOFF-REPAIR-017) but not separately forPOPULATION_ENDOWMENT; I read the typed-identity principle as general, consistent with how PRs REQ-CONFIG-004: key good genesis reconciliation by region identity #467 and REQ-CONFIG-004: key resource genesis reconciliation by typed region/good identity #469 treated goods and resources. If the researcher intends population to be deliberately Region-blind, this repair is wrong and the correct remedy is a spec question, not a code revert.CohortSeed.regionKey, a production divergence is not reachable from seed data alone today; the defect this closes is that a ledger record carrying a wrong Region was unobservable. That is exactly what the Issue describes, and it is why the negative control mutates the record rather than the seed.regionKeydoes not resolve in the region registry is possible aftervalidateScenarioContent(which rejectsa cohort with invalid regionKey). If it were, the actual side keys it asNO_REGIONand reconciliation fails loudly rather than silently — the safe direction.Highest-risk area for review
src/simulation/genesisReconciliation.tslines around the cohort loop:cohortRegionIdwas hoisted from the goods block to above the population block. Confirm the goods projection still resolves the identical value (it is the same expression, now computed once) and that no other consumer of that variable was reordered.Remaining gate
No mandatory work remains for Issue #452.
REQ-CONFIG-004deliberately staysPARTIAL: sibling Issue #455 (ProductionUnitGOOD_ENDOWMENTINPUT/OUTPUT/INVESTMENT bucket identity) is open and out of this Issue's scope by its own Non-goals, and #455's own scope likewise excludes this repair. Merging is the ACCEPTOR's decision; this run neither approves nor merges.🤖 Generated with Claude Code