Addresses all blocking + minor items from PR #136 review.
Architectural change (T2/H3 — the review's main complaint):
generate_brands was previously a separate Rust binary that produced a TOML
artifact, with its stamp written "on behalf" by import_economics.py at the
end of its own run. Reviewers flagged the invisible coupling: two sources
of truth in a system designed to have one, and no way to tell from the
stamp that one "generator" was really a subroutine of the other.
import_economics now invokes tooling/generate-brands as the first step of
its main() flow, before opening its own DB connection. The TOML artefact
is still produced and still committed (useful for diff-review of brand
changes), but there's now one pipeline owner. The meta table carries two
rows (import_economics, generate_atlas) not three; the Rust binary's
source SHA folds into import_economics' stamp via IMPORT_ECONOMICS_SOURCES.
A MIGRATION_SQL DELETE cleans up pre-merge DBs that still have the
orphan generate_brands row.
Other review items addressed in-line:
H1 generate_atlas._write_stamp no longer commits — transaction ownership
stays with the caller (matches import_economics pattern). Stamp +
atlas data now commit atomically; a failed stamp rolls back the
atlas data rather than leaving a stamp-missing-data intermediate.
H2 _file_sha1 (in both import_economics, generate_atlas,
check-systems-db-stamp) raises FileNotFoundError on missing sources
instead of silently contributing an empty-bytes hash. A ghost-SHA
convergence could otherwise produce vacuous "fresh" passes.
H4 pre-push no-meta-table warning rephrased — was "run after next
regeneration", now "run now if this DB was generated by you".
T1 asset-pipeline.md determinism claim softened: the stamp is
deterministic (same source → same recorded SHA), the DB binary is
not (generated_at + SQLite rowids/freelist churn).
T3 asset-pipeline.md gains a "migration escape hatch" section naming
MIGRATION_SQL in import_economics.py as the only sanctioned path
for direct writes, and forbidding hand-run sqlite-exec / one-off
patch scripts / SQLite-GUI edits.
T4 Makefile regen-db now runs as a single shell with `set -e`. A
failure in one generator halts the pipeline immediately, preventing
the "stale data, fresh stamp" state where a later step stamped a
DB whose earlier step had failed. import_economics' exit code 2
(coverage gate warning) remains explicitly tolerated.
T5 pre-push stamp check now runs on a branch's first push too —
compares against origin/main instead of origin/$BRANCH, closing
the gap where a new branch could ship a stale DB via the first push.
T6 check-systems-db-stamp fails closed on unknown generator_names in
meta — a future branch adding a new generator without registering
it in GENERATOR_SOURCES will now be rejected, not silently skipped.
T7 /pr-push watch list gains a mutual cross-reference comment with
GENERATOR_SOURCES in check-systems-db-stamp, plus the missing
names.rs source file, so the two lists cannot silently drift.
Follow-up tickets created:
#887 T8 decisions-orphan-tickets CLI — surfaces tickets whose
decision_ref points at a non-existent D-record.
#888 T9 meta.schema_version monotonic semver — for savegame migration
lineage in Phase 5+ (SHA comparison can't be ordered).
Verified:
make regen-db end-to-end — OK
make check-systems-db — OK, 2 generator(s) up to date
STALE detection — OK, verified by touching generate_atlas.py
/pr-push watch list — OK, flags this branch's changed sources
decision show D-159 — OK, structured output with tickets + refs
Refs: #855#856#857#858#859 PR #136
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>