refactor(tooling): T-1289 — economy-db becomes reach ledger
The sole generator of systems.db moves to tooling/domains/ledger/ and is now `reach ledger import`. economy_import/ keeps its name (Rust comments in server/src cite it); the entrypoint becomes service.py; schema_version.py moves with the importer, which is where the version is defined. The stamp survived the move, which is the thing that had to hold: - generated_brands.toml is byte-identical (sha256 e748531…) before and after - `reach check systems-db-stamp` reported STALE after the move (the registry saw it) and OK after the regen - the dry-run carries every count and warning of the baseline transcript, and exit 2 — imported and stamped, coverage gate unmet — still reaches the caller through @command `make regen-db` survives as a one-line delegate, per D-263's muscle-memory clause: about fifty files name it, including the headers of generated wiki TOMLs and the remedies the push gate prints. `make economy-db` is retired; it ran `reach generate brands` before the import, which the import already does as its first step. economy_import.errors is reconciled as DOMAINS.md asked. ImportAborted stays as internal rollback control flow and never reaches a caller; the service converts it to a ReachError carrying the remedy. regenerate_brands caught cargo_binary's ReachError, printed it and raised ImportAborted, dropping the remedy. It runs before the import transaction opens, so there is nothing to roll back — it now propagates. Both sys.path bootstraps are gone; they existed only because the directory was hyphenated. The step labels ran [1/10]…[10/13]…[17/19]; one 24-step counter now drives the event phase and progress. Stale pointers fixed on the way: MIGRATION_SQL has lived in economy_import/migration.py since T-1067, but the asset-pipeline rule, DEVOPS and the schema comments still sent readers to import_economics.py; the rule and DEVOPS also still named the check scripts T-1281 retired. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -345,3 +345,61 @@ nothing prints but `console`, no `subprocess` outside `core/process`.
|
||||
|
||||
DONE 2026-09-23. reach atlas planet: ten verbs over the moved package; tooling/test_planet_router.py (in make test-tooling) fails if a router option drifts from its module''s argparse. Finishing the 2026-09-02 half-move found: (1) lazy in-function imports and all of sol_data/ still used bare sibling names that only resolved via sys.path hacks — generate/batch/sol-import would have failed on first globe render under reach; qualified, hacks removed. (2) 247 print() + a per-8KB-block stdout progress writer routed through console (report verbs -> out, progress -> event, throttled download progress). (3) Every error exit now raises ReachError with fix=. (4) TWO CHECKS THAT COULD NOT FAIL: batch --verify-determinism and import-provinces both exited 0 on detected failures; both now raise. (5) sol-import --body is action=append but the router took one value — now repeatable. (6) test_conformance only walked one level, so the nested group''s ten verbs were never checked; now recursive, proven against a mutant. Stray PNGs from the 2026-09-03 runaway test run (8 modified reliefmaps, 6 new heightmaps) parked in .cache/t1288-stray-pngs/, reliefmaps restored from HEAD. NOTE: the reliefmaps differed from the committed bake, i.e. the current renderer no longer reproduces committed reliefmap bytes — not investigated here.', NULL, '2026-09-23 14:07:42', '2026-09-23 14:07:42.675', '2026-09-23 14:07:42.675', NULL, 'b6c6d1e211eada353630e3946da96310', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G65NSJ4RG6SJ12TQE78S6TKR', 'status', 'backlog', 'done', NULL, '2026-09-23 14:07:43', '2026-09-23 14:07:43.036', '2026-09-23 14:07:43.036', NULL, 'e3329ba1f64d0a63c635d4a9049d56b6', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G65T2N1WAT491WY8SV736J3G', 'description', '`tooling/economy-db/` (17 files) + `schema_version.py` become `reach ledger`.
|
||||
|
||||
The name is deliberate and is the user''s call (D-263 amendment): reach verbs
|
||||
mirror the game''s implant-app presentation patterns. `ledger` is the player-facing
|
||||
component that will aggregate economics — browse markets, wealth, transactions —
|
||||
the way `atlas` aggregates topography. The tooling verb takes the same name so the
|
||||
CLI and the UI do not diverge into two vocabularies for one subject.
|
||||
|
||||
THIS IS THE HIGHEST-RISK PORT IN THE EPIC and the reason E5 (T-1252) exists as a
|
||||
separate epic: `import_economics` is the SOLE generator of `server/data/systems.db`,
|
||||
and its meta stamp is computed over a source-file registry. Two things bite:
|
||||
|
||||
1. `tooling/generator_sources.py` lists every stamped path. Moving a file without
|
||||
updating the registry either breaks the import (missing path) or silently
|
||||
changes the SHA. T-1286 already had to swap the retired `generate-brands`
|
||||
wrapper for `core/process.py` there and regen. Expect the same.
|
||||
2. `economy-db` is hyphenated, so it is NOT importable as a package. `brands.py`
|
||||
currently bootstraps `sys.path` with REPO_ROOT to reach `tooling.core` — see
|
||||
the comment there. That bootstrap should DISAPPEAR in this port, not be
|
||||
copied; it exists only because the directory could not be imported. Overlaps
|
||||
T-1272 (hyphen sweep) — do them together or in that order.
|
||||
|
||||
Every port of this domain ends with `make regen-db` + `reach check systems-db-stamp`
|
||||
+ a commit of `server/data/systems.db`. `generated_brands.toml` must come back
|
||||
byte-identical; if it does not, the port changed generator behaviour and that is
|
||||
a bug, not a regen.
|
||||
|
||||
Standard port acceptance as on T-1281/T-1286.', '`tooling/economy-db/` (17 files) + `schema_version.py` become `reach ledger`.
|
||||
|
||||
The name is deliberate and is the user''s call (D-263 amendment): reach verbs
|
||||
mirror the game''s implant-app presentation patterns. `ledger` is the player-facing
|
||||
component that will aggregate economics — browse markets, wealth, transactions —
|
||||
the way `atlas` aggregates topography. The tooling verb takes the same name so the
|
||||
CLI and the UI do not diverge into two vocabularies for one subject.
|
||||
|
||||
THIS IS THE HIGHEST-RISK PORT IN THE EPIC and the reason E5 (T-1252) exists as a
|
||||
separate epic: `import_economics` is the SOLE generator of `server/data/systems.db`,
|
||||
and its meta stamp is computed over a source-file registry. Two things bite:
|
||||
|
||||
1. `tooling/generator_sources.py` lists every stamped path. Moving a file without
|
||||
updating the registry either breaks the import (missing path) or silently
|
||||
changes the SHA. T-1286 already had to swap the retired `generate-brands`
|
||||
wrapper for `core/process.py` there and regen. Expect the same.
|
||||
2. `economy-db` is hyphenated, so it is NOT importable as a package. `brands.py`
|
||||
currently bootstraps `sys.path` with REPO_ROOT to reach `tooling.core` — see
|
||||
the comment there. That bootstrap should DISAPPEAR in this port, not be
|
||||
copied; it exists only because the directory could not be imported. Overlaps
|
||||
T-1272 (hyphen sweep) — do them together or in that order.
|
||||
|
||||
Every port of this domain ends with `make regen-db` + `reach check systems-db-stamp`
|
||||
+ a commit of `server/data/systems.db`. `generated_brands.toml` must come back
|
||||
byte-identical; if it does not, the port changed generator behaviour and that is
|
||||
a bug, not a regen.
|
||||
|
||||
Standard port acceptance as on T-1281/T-1286.
|
||||
|
||||
DONE 2026-09-23. tooling/economy-db/ + schema_version.py -> tooling/domains/ledger/ (economy_import/ kept by name, since server/src Rust comments cite economy_import/*.py; import_economics.py became service.py). reach ledger import [--db] [--dry-run] [--strict-specialization]. Evidence: generated_brands.toml sha256 identical before/after (e748531…); stamp gate reported STALE after the move and OK after regen; dry-run transcript carries every count and warning of the baseline; exit 2 (coverage gap, data committed) proven to relay through @command with a probe. Make: regen-db kept as a one-line delegate per D-263''s muscle-memory clause (~50 files name it, incl. generated TOML headers and gate remedies); economy-db retired (it ran generate brands, which the import already does first). Reconciled economy_import.errors (DOMAINS.md ask): ImportAborted stays internal rollback control flow, converted to ReachError at the service boundary. Also: regenerate_brands used to swallow cargo_binary''s ReachError into ImportAborted, dropping its remedy — now propagates (it runs before the transaction, nothing to roll back). Both sys.path bootstraps removed. Step labels were inconsistent ([1/10]..[10/13]..[17/19]); one 24-step counter now drives phase + progress. Stale doc pointers fixed while there: MIGRATION_SQL had lived in economy_import/migration.py since T-1067 but rules/DEVOPS still said import_economics.py; asset-pipeline rule and DEVOPS still named the check-systems-db script/target T-1281 retired.', NULL, '2026-09-23 14:18:49', '2026-09-23 14:18:49.681', '2026-09-23 14:18:49.681', NULL, '13300d7ea5bd79ae4857cd59399531a6', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G65T2N1WAT491WY8SV736J3G', 'status', 'backlog', 'done', NULL, '2026-09-23 14:18:50', '2026-09-23 14:18:50.093', '2026-09-23 14:18:50.093', NULL, '63d24743b229b1544d62104c4e68ca66', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -501,3 +501,63 @@ nothing prints but `console`, no `subprocess` outside `core/process`.
|
||||
|
||||
DONE 2026-09-23. reach atlas planet: ten verbs over the moved package; tooling/test_planet_router.py (in make test-tooling) fails if a router option drifts from its module''s argparse. Finishing the 2026-09-02 half-move found: (1) lazy in-function imports and all of sol_data/ still used bare sibling names that only resolved via sys.path hacks — generate/batch/sol-import would have failed on first globe render under reach; qualified, hacks removed. (2) 247 print() + a per-8KB-block stdout progress writer routed through console (report verbs -> out, progress -> event, throttled download progress). (3) Every error exit now raises ReachError with fix=. (4) TWO CHECKS THAT COULD NOT FAIL: batch --verify-determinism and import-provinces both exited 0 on detected failures; both now raise. (5) sol-import --body is action=append but the router took one value — now repeatable. (6) test_conformance only walked one level, so the nested group''s ten verbs were never checked; now recursive, proven against a mutant. Stray PNGs from the 2026-09-03 runaway test run (8 modified reliefmaps, 6 new heightmaps) parked in .cache/t1288-stray-pngs/, reliefmaps restored from HEAD. NOTE: the reliefmaps differed from the committed bake, i.e. the current renderer no longer reproduces committed reliefmap bytes — not investigated here.', 'done', 'high', NULL, 'tooling', 'D-263', '2026-09-02 15:57:45.382', '2026-09-23 14:07:43.036', NULL, '2a78f8f8646d915600ed55c5dc5d0993', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06GCX60QRMD7KJ1TVWTR7FWK28', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Planet renderer no longer reproduces committed reliefmap.png bytes (8 bodies differ on re-render)', 'Found during T-1288. A 2026-09-03 accidental generate run re-rendered bodies in GJ-1002, GJ-1116B, GJ-139, GJ-147, GJ-216A, GJ-234A, GJ-273, GJ-282B: every reliefmap.png came back a few hundred bytes different from HEAD, while GJ1002b''s heightmap.png came back byte-identical (so the simulation is deterministic — make test-tooling confirms — and the drift is in the reliefmap RENDER path or its PNG encoding). Copies of the re-rendered files are in .cache/t1288-stray-pngs/. Question to answer first: is this a visible change (renderer code evolved since the April bake) or encoder-level noise (zlib/Pillow version, metadata)? Pixel-diff one pair before anything else. If visible: decide whether committed reliefmaps should be re-baked. If noise: make the encode deterministic so a re-render is a no-op in git.', 'backlog', 'low', NULL, 'tooling', NULL, '2026-09-23 14:07:49.189', '2026-09-23 14:07:49.189', NULL, '215478973901c77cdd0e6b5c446ff19e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G65T2N1WAT491WY8SV736J3G', 'task', '06G1S3D0M1TQW0GMFBBPQZG3ZM', 'Port ledger — the economics pipeline under its UI name', '`tooling/economy-db/` (17 files) + `schema_version.py` become `reach ledger`.
|
||||
|
||||
The name is deliberate and is the user''s call (D-263 amendment): reach verbs
|
||||
mirror the game''s implant-app presentation patterns. `ledger` is the player-facing
|
||||
component that will aggregate economics — browse markets, wealth, transactions —
|
||||
the way `atlas` aggregates topography. The tooling verb takes the same name so the
|
||||
CLI and the UI do not diverge into two vocabularies for one subject.
|
||||
|
||||
THIS IS THE HIGHEST-RISK PORT IN THE EPIC and the reason E5 (T-1252) exists as a
|
||||
separate epic: `import_economics` is the SOLE generator of `server/data/systems.db`,
|
||||
and its meta stamp is computed over a source-file registry. Two things bite:
|
||||
|
||||
1. `tooling/generator_sources.py` lists every stamped path. Moving a file without
|
||||
updating the registry either breaks the import (missing path) or silently
|
||||
changes the SHA. T-1286 already had to swap the retired `generate-brands`
|
||||
wrapper for `core/process.py` there and regen. Expect the same.
|
||||
2. `economy-db` is hyphenated, so it is NOT importable as a package. `brands.py`
|
||||
currently bootstraps `sys.path` with REPO_ROOT to reach `tooling.core` — see
|
||||
the comment there. That bootstrap should DISAPPEAR in this port, not be
|
||||
copied; it exists only because the directory could not be imported. Overlaps
|
||||
T-1272 (hyphen sweep) — do them together or in that order.
|
||||
|
||||
Every port of this domain ends with `make regen-db` + `reach check systems-db-stamp`
|
||||
+ a commit of `server/data/systems.db`. `generated_brands.toml` must come back
|
||||
byte-identical; if it does not, the port changed generator behaviour and that is
|
||||
a bug, not a regen.
|
||||
|
||||
Standard port acceptance as on T-1281/T-1286.
|
||||
|
||||
DONE 2026-09-23. tooling/economy-db/ + schema_version.py -> tooling/domains/ledger/ (economy_import/ kept by name, since server/src Rust comments cite economy_import/*.py; import_economics.py became service.py). reach ledger import [--db] [--dry-run] [--strict-specialization]. Evidence: generated_brands.toml sha256 identical before/after (e748531…); stamp gate reported STALE after the move and OK after regen; dry-run transcript carries every count and warning of the baseline; exit 2 (coverage gap, data committed) proven to relay through @command with a probe. Make: regen-db kept as a one-line delegate per D-263''s muscle-memory clause (~50 files name it, incl. generated TOML headers and gate remedies); economy-db retired (it ran generate brands, which the import already does first). Reconciled economy_import.errors (DOMAINS.md ask): ImportAborted stays internal rollback control flow, converted to ReachError at the service boundary. Also: regenerate_brands used to swallow cargo_binary''s ReachError into ImportAborted, dropping its remedy — now propagates (it runs before the transaction, nothing to roll back). Both sys.path bootstraps removed. Step labels were inconsistent ([1/10]..[10/13]..[17/19]); one 24-step counter now drives phase + progress. Stale doc pointers fixed while there: MIGRATION_SQL had lived in economy_import/migration.py since T-1067 but rules/DEVOPS still said import_economics.py; asset-pipeline rule and DEVOPS still named the check-systems-db script/target T-1281 retired.', 'backlog', 'high', NULL, 'tooling', 'D-263', '2026-09-02 16:16:28.431', '2026-09-23 14:18:49.681', NULL, '4690f4d637a68bb49840c7a2de30801a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G65T2N1WAT491WY8SV736J3G', 'task', '06G1S3D0M1TQW0GMFBBPQZG3ZM', 'Port ledger — the economics pipeline under its UI name', '`tooling/economy-db/` (17 files) + `schema_version.py` become `reach ledger`.
|
||||
|
||||
The name is deliberate and is the user''s call (D-263 amendment): reach verbs
|
||||
mirror the game''s implant-app presentation patterns. `ledger` is the player-facing
|
||||
component that will aggregate economics — browse markets, wealth, transactions —
|
||||
the way `atlas` aggregates topography. The tooling verb takes the same name so the
|
||||
CLI and the UI do not diverge into two vocabularies for one subject.
|
||||
|
||||
THIS IS THE HIGHEST-RISK PORT IN THE EPIC and the reason E5 (T-1252) exists as a
|
||||
separate epic: `import_economics` is the SOLE generator of `server/data/systems.db`,
|
||||
and its meta stamp is computed over a source-file registry. Two things bite:
|
||||
|
||||
1. `tooling/generator_sources.py` lists every stamped path. Moving a file without
|
||||
updating the registry either breaks the import (missing path) or silently
|
||||
changes the SHA. T-1286 already had to swap the retired `generate-brands`
|
||||
wrapper for `core/process.py` there and regen. Expect the same.
|
||||
2. `economy-db` is hyphenated, so it is NOT importable as a package. `brands.py`
|
||||
currently bootstraps `sys.path` with REPO_ROOT to reach `tooling.core` — see
|
||||
the comment there. That bootstrap should DISAPPEAR in this port, not be
|
||||
copied; it exists only because the directory could not be imported. Overlaps
|
||||
T-1272 (hyphen sweep) — do them together or in that order.
|
||||
|
||||
Every port of this domain ends with `make regen-db` + `reach check systems-db-stamp`
|
||||
+ a commit of `server/data/systems.db`. `generated_brands.toml` must come back
|
||||
byte-identical; if it does not, the port changed generator behaviour and that is
|
||||
a bug, not a regen.
|
||||
|
||||
Standard port acceptance as on T-1281/T-1286.
|
||||
|
||||
DONE 2026-09-23. tooling/economy-db/ + schema_version.py -> tooling/domains/ledger/ (economy_import/ kept by name, since server/src Rust comments cite economy_import/*.py; import_economics.py became service.py). reach ledger import [--db] [--dry-run] [--strict-specialization]. Evidence: generated_brands.toml sha256 identical before/after (e748531…); stamp gate reported STALE after the move and OK after regen; dry-run transcript carries every count and warning of the baseline; exit 2 (coverage gap, data committed) proven to relay through @command with a probe. Make: regen-db kept as a one-line delegate per D-263''s muscle-memory clause (~50 files name it, incl. generated TOML headers and gate remedies); economy-db retired (it ran generate brands, which the import already does first). Reconciled economy_import.errors (DOMAINS.md ask): ImportAborted stays internal rollback control flow, converted to ReachError at the service boundary. Also: regenerate_brands used to swallow cargo_binary''s ReachError into ImportAborted, dropping its remedy — now propagates (it runs before the transaction, nothing to roll back). Both sys.path bootstraps removed. Step labels were inconsistent ([1/10]..[10/13]..[17/19]); one 24-step counter now drives phase + progress. Stale doc pointers fixed while there: MIGRATION_SQL had lived in economy_import/migration.py since T-1067 but rules/DEVOPS still said import_economics.py; asset-pipeline rule and DEVOPS still named the check-systems-db script/target T-1281 retired.', 'done', 'high', NULL, 'tooling', 'D-263', '2026-09-02 16:16:28.431', '2026-09-23 14:18:50.093', NULL, '579a9be46ac9f07e3b7a687fbe4772fe', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
|
||||
Reference in New Issue
Block a user