Skip to content

docs(qa): refresh cli dev-boot DB clause to unified objectstack.db; narrow build exit clause to the #4873 leak - #7712

Merged
huangyiirene merged 1 commit into
mainfrom
claude/issue-7650-7648-cli-checklist
Aug 11, 2026
Merged

huangyiirene merged 1 commit into
mainfrom
claude/issue-7650-7648-cli-checklist

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes #7650
Fixes #7648

Two checklist reconciliations from QA run #7628, both landing in docs/qa/platform-checklist/areas/cli.json and both text-only — no packages/cli behaviour changes. The product is correct as shipped in both cards; the checklist text was what had drifted.

Premise verification (re-derived at this ref, not taken from the issues)

Both premises re-confirmed on origin/main @ 21888ab (triage verified at 5823d59):

Line numbers named at filing time (cli.json:28/:45/:80/:88 and :145) all re-derived identical at this ref.

Per-card checklist

#7650 — cli.dev-boot-contract (revision 1 to 2)

Site Before After
steps (was :28) records the Database line as file:(cwd)/.objectstack/data/dev.db records it as the project-anchored unified file:(cwd)/.objectstack/data/objectstack.db; notes --fresh uses the same unified filename under its ephemeral home
steps (new) — new step exercising the legacy compat-read: a project holding a legacy dev.db and no objectstack.db must resolve to the legacy file and print the one loud notice
acceptance clause 2 (was :45) "honors the resolveDefaultDevDbUrl matrix … the PERSISTENT project-anchored sqlite file (.objectstack/data/dev.db) — never the serve default of :memory:" "honors the ONE shared resolution matrix (#6469 resolveProjectDatabaseUrl, which dev maps its flags onto via resolveDevDatabase) … the PERSISTENT project-anchored sqlite file — the unified objectstack.db — never the historical serve default of :memory: that wipes work on restart"
acceptance clause 2 verify five tiers, dev.db default six tiers named tier-for-tier, plus "dev carries no fallback filename of its own"
negative "(a regression to the :memory: serve default)" same assertion, attribution corrected to "the historical :memory: serve default"; new negative for a silent fresh objectstack.db opened beside an existing legacy dev.db, or a compat-read with no notice
variants (was :80) 5 entries, default named dev.db 7 entries: default renamed to objectstack.db, TURSO_DATABASE_URL added to the env tier, plus the config-declared default datasource and legacy compat-read tiers
source (was :88) dev.ts (resolveDefaultDevDbUrl matrix; …) dev.ts (resolveDevDatabase — dev's ONE resolution seam, carrying no fallback filename of its own; …), plus packages/runtime/src/resolve-project-database.ts (the #6469 shared matrix, state-dir order, legacy compat-read) and packages/cli/src/commands/unified-db-resolution.pin.test.ts

The load-bearing property survives verbatim in substance. This is a rename, not a weakening: nothing-chosen still defaults to a PERSISTENT project-anchored sqlite file, and :memory: is still named as the thing it must never be. The words "PERSISTENT project-anchored sqlite file" and "never … :memory: that wipes work on restart" are carried through unchanged; only the filename and the helper name moved.

The current resolution path, read out of resolve-project-database.ts rather than assumed: explicit URL (flag/config) to env (OS_DATABASE_URL / DATABASE_URL / TURSO_DATABASE_URL) to explicit memory driver to config-declared default datasource to the unified (state dir)/data/objectstack.db, with a legacy dev.db / standalone.db compat-read (probe order objectstack.db, dev.db, standalone.db) that emits one loud notice.

#7648 — cli.build-own-contract (revision 1 to 2)

Site Before After
acceptance clause 4 (was :145) "exit codes are exactly 0 or 1 (the CliExitCode union) — never a count, never a duration" "#4873 exit-code honesty: the exit code is a STATUS, never a computed value … The legitimate exits are 0 and 1 through the CliExitCode union (every emitJson/emitText caller), plus oclif's ExitError 2 when the human path (the run without --json) ends in this.error(): a config-load-time throw exiting 2 is the framework's error exit and is NOT a violation"
clause 4 verify "echo $? across all runs is only ever 0 or 1" every exit is 0, 1, or an oclif 2 from a this.error() path, and none varies with the run — with the #4873 shape spelled out concretely (timer.elapsed() in emitJson's positional exit slot made a successful run exit 531 & 0xFF = 19, a different nonzero every time)
clause 4 evidence "the collected exit codes" exit codes with the --json and human paths labelled separately, plus repeat runs showing each code is stable
steps (new) — the exit-slot pair: one config-load-time throw run both ways — human path expecting oclif 2, --json expecting 1 — and a verbatim repeat of one success and one failure, since only a repeat can see a code that moves
negative (new) — a code tracking a computed value (duration, count, finding total) is the #4873 leak: a successful run exiting nonzero, or a code differing between two identical runs, FAILS. Oclif's fixed ExitError 2 is explicitly not that leak
source "format.ts (CliExitCode = 0 or 1 — the narrowed exit-code slot)" corrected to "the narrowed emitJson/emitText exit slot, NOT a bound on oclif's own error exit"; compile.ts entry now records the human-path this.error() vs --json emitJson + this.exit(1) split; added format.exit-code.test.ts (the #4873 pin) and a cross-reference to cli.flag-command-error-ux
title "exit 0/1 only, …" "no computed value in the exit slot, …"

The narrowed clause stays load-bearing. A duration or count reaching the exit-code slot still FAILS it, by two independent tests the old wording did not have: a successful run exiting nonzero, and a code that moves between two identical runs. The old "exactly 0 or 1" phrasing could only catch the leak by accident — it would equally have failed the legitimate oclif 2 — so this narrowing makes the clause both correct and strictly more falsifiable. The collision with cli.flag-command-error-ux dissolves because both items now name the same fact: exit 2 is oclif's error exit, and that item owns it.

Verification

Both edited items carry a revision bump (1 to 2) and an appended history entry per docs/qa/platform-checklist/README.md's change protocol.

pnpm check:platform-checklist — checklist-select --self-test: 17 cases pass. The validator reports 1 problem, byte-identical to the pre-edit baseline on this same ref:

check-platform-checklist: 1 problem(s)

  ✗ coverage.json · qa: UNCLASSIFIED — the platform has this capability (liveness ledger exists) but the checklist neither tests nor waives it. Add items or a waiver with a reason.

That red is the known pre-existing #7347 qa: UNCLASSIFIED carried by the base branch — recorded, not chased, and out of this card's file surface. diff baseline after is empty: this change adds no new finding and removes none.

Reverse verification (direction predicted before running: RED, since a text-only change has no runtime behaviour to flip — the meaningful question is whether the gate actually reads the items I edited). Setting cli.dev-boot-contract's revision back to 1 while its last history entry says 2:

check-platform-checklist: 2 problem(s)

  ✗ cli.json · cli.dev-boot-contract: "revision" (1) must equal the last history entry's revision (2) — a semantic edit bumps both
  ✗ coverage.json · qa: UNCLASSIFIED — …

Restored with git checkout -- (never git stash), back to the baseline 1 problem. The gate is not blind to these items.

JSON validity — parses, 6 items, and every item's revision equals its last history entry's revision (2, 2, 1, 1, 1, 1).

pnpm check:nul-bytes — self-test 75 assertions pass; OK (scanned 7104 text file(s) … no raw ASCII control bytes). Self-scan of the edited file beyond the gate (grep -naP over the control-byte ranges) is clean.

Diff surface, 1:1 with the mandated scope:

 docs/qa/platform-checklist/areas/cli.json | 51 +++++++++++++++++++------------
 1 file changed, 32 insertions(+), 19 deletions(-)

No coverage.json, no other area file, no packages/cli code.

Changeset

None — docs-only, releases nothing. Needs the skip-changeset label.


Generated by Claude Code

…arrow build exit clause to the #4873 leak

Two checklist reconciliations in docs/qa/platform-checklist/areas/cli.json,
both text-only — no packages/cli behaviour changes.

cli.dev-boot-contract (rev 1 -> 2), Fixes #7650:
the DB-selection clause, its step, variants and sources named the retired
`resolveDefaultDevDbUrl` helper and the `.objectstack/data/dev.db` default.
Both are superseded by #6469's unified `<state dir>/data/objectstack.db`,
resolved through the shared `resolveProjectDatabaseUrl` that dev maps onto
via `resolveDevDatabase`. Re-derived from dev.ts and
resolve-project-database.ts: the config-datasource and legacy compat-read
tiers are now variants, with a step and a negative for the legacy dev.db
notice line and the pin test in sources. The load-bearing property is
unchanged in substance — nothing chosen still defaults to a PERSISTENT
project-anchored sqlite file, never `:memory:`.

cli.build-own-contract (rev 1 -> 2), Fixes #7648:
clause 4 read "exit codes are exactly 0 or 1", which also forbade oclif's
standard ExitError 2 that compile.ts's human-path `this.error()` catches
legitimately produce on a config-load-time throw — colliding with
cli.flag-command-error-ux, which asserts that same 2 is correct. The clause
is narrowed to what #4873 actually was: a computed value reaching the exit
slot, detectable as a nonzero on success or a code that moves between
identical runs. 0/1 via CliExitCode and oclif's fixed 2 on the human path
are named as legitimate. It stays load-bearing — a duration in the exit
slot still fails it — and gains a repeat-run step plus a negative to keep
it falsifiable.
@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 11, 2026 11:50am

Request Review

@huangyiirene huangyiirene added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 11, 2026 — with Claude
@huangyiirene
huangyiirene marked this pull request as ready for review August 11, 2026 12:10
@huangyiirene
huangyiirene added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit 7756490 Aug 11, 2026
24 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-7650-7648-cli-checklist branch August 11, 2026 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants