v0.8.0 — setup expect guard, db_ref, multi-repo auth detection
Five dogfooding findings from an external multi-repo, multi-database project. The first is a test-integrity bug; the rest are gaps that forced manual workarounds.
setup:/teardown:sqlexpect:was silently ignored — every pre-state guard was decoration.checklist_lib/setup.py_do_sql()captured the scalar and returned; it never looked atexpect:. Meanwhiletemplates/CHECKLIST.yamlandreferences/test-rigor.mdboth ship the exact form (expect: CREATED # pre-state confirmed) as the recommended way to confirm a seed landed. This is worse than having no guard: a checklist written from the template looks baseline-verified, so a wrong seed lets the test run anyway and PASS for an unrelated reason. Scalarexpect:is now a hard assertion that aborts the setup (mismatch → the test FAILs with the query and both values); dictexpect:stays descriptive, same rule as averify:block; inteardownit degrades to a warning like every other teardown failure.sql._check_scalar→sql.check_scalar(now used by two modules). Documented inreferences/checklist.md. 6 new Python tests.db_ref:— multi-database support, the DB-side twin ofbase_url_ref:.ctx["db"]was one database name for the whole run while HTTP already hadbase_urls+base_url_ref, so a feature spanning two services could only be SQL-verified on the near side; the far side had to be inferred from an HTTP side-channel (GET /{id}/status → 404), which is a weaker assertion than reading the row. Newconfig.databasesdeclares named alternates — either a plain database name (same server) or a mapping ofdatabase/host/port/user/password— anddb_ref: <name>selects one on any sql step:setup,teardown,seed, averify[]item,expect.poll, andcleanup. Fields left unset still come fromdb-creds.shdiscovery, so a second database on the same server needs only its name. An undefined ref fails rather than falling back to the default database — a silent fallback would query the wrong server and report a green PASS.db-query.shgained--host/--port/--user/--password(the existing-donly ever overrode the database name, which is why a service on another port was unreachable).lint-checklist.shnow rejects an undeclareddb_reforbase_url_refat lint time instead of mid-suite. 11 new Python tests.- Related, same class as the
expect:bug:templates/CHECKLIST.yamladvertisedconfig.db.host/port/username/password, none of which the runner reads — credentials always come fromdb-creds.sh. The template now declares onlydatabase:and says where the rest comes from. Precedence is deliberately unchanged: honouring those fields would let the template's${DB_PASS:-postgres}placeholder override a correctapplication.ymldiscovery on exactly the primary supported stack.
- Related, same class as the
detect-auth.shignoredconfig.repos, so multi-repo projects got an inverted answer. The detector ran against the cwd. In a spec-flow hub that holds only the SRS/SD while the services live in sibling repos, there is no service code to fingerprint — so a Summer/APISIX project classified as a custom-Bearer one, i.e. exactly backwards, and every generated test 401s. It now reads.spec-flow/config.json→repos, classifies each declared repo, and reconciles: one signal wins (and that repo's own hints are forwarded); repos that genuinely disagree reportCONFLICTand fall back tounknownrather than picking a scaffold that is wrong for the others; a missing repo path is reported and skipped. Single-repo projects take the unchanged path. Also fixes a latent bug this exposed —HEREwas computed aftercd "$ROOT", resolving a relative$0against the wrong directory.checklist-gentagged nearly every testsmoke. The rule wasEdge:-prefixed test-case name →regression, everything else →smoke, so an SD whose §13.2 doesn't use that naming convention (most of them) produced an all-smoke checklist:--tag smokeran the entire set and the smoke → regression escalation the skill documents stopped meaning anything. Now the first non-edge TC of each Flow is that flow's smoke test and every other TC is regression — one smoke test per user story. Suite tags reflect what their tests actually carry.- Found while testing the above:
hasApiSection(/^#{2,3}\s*9(\.\d+)?\s+API/) did not match## 9. API Design— the exact headingtemplates/sd-template.mdemits — only the### 9.2 API Endpointssubsection. An SD with §9 but no §9.x subsection silently classified asinternaland got the live-e2e scaffold instead of an HTTP stub.
- Found while testing the above:
TODO:MANUAL-REVIEWcounting had one loose copy left, and the command docs told the agent to grep by hand. 0.7.1 anchored the regex instatus-reportanddoctor, butgenSd's ownstats.todoManualReviewstill used a line-wise/TODO:MANUAL-REVIEW/— which matches the Pass-1 preamble banner it emits two lines earlier. Worse,commands/{ingest,resync}.mdjust said "count remaining markers", so the agent ran a bare grep and counted revision-history entries and sd-author'sTODO:MANUAL-REVIEW remaining: 0summary as unresolved — a clean, approved SD reported 3 outstanding TODOs and the gate blocked work that was ready. The regex now lives once, ascore.countSdTodos(), used by all four call sites; the command docs give the anchoredgrep -cE '^> \*\*TODO:MANUAL-REVIEW\*\*'and point at the reported count instead.- 780 Node tests green (2 new), 65 Python tests green (17 new).