Skip to content

docs(qa): re-word three v18 checklist clauses the 18.0 QA sweep found mis-asserted - #24592

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-24567-checklist-v18-sweep-clauses
Oct 19, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-24567-checklist-v18-sweep-clauses

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24543
Refs #24567 (rows 1–2)
Clause-②: no

What this changes

Three platform-checklist clauses that the 18.0 QA sweep scored fail are assertion defects: the product is right and the clause is wrong. This PR re-words the three clauses, and nothing else: no product code, no test, no pin. Each item gets revision 1 → 2 and one history entry that names its QA source. The entry's ref is this PR, set by a one-token follow-up commit once the number existed.

item fields edited revision QA source
platform-core.v18-boot-refusals acceptance[2] (clause, verify, evidence), steps[0] 1 → 2 QA run #24556, acceptance[2], P0; card #24567 row 1
access-security.security-catalog-one-holder-and-boot-report acceptance[1] (clause, verify, evidence), title (install-local parenthetical) 1 → 2 QA run #24558, acceptance[1]; card #24567 row 2 (folded from #24568)
approvals.act-door-and-admin-rescue-slate acceptance[1] (clause, verify, evidence), title (PUT leg) 1 → 2 QA run #24542, clause 1; card #24543

Files: docs/qa/platform-checklist/areas/platform-core.json, docs/qa/platform-checklist/areas/access-security.json, docs/qa/platform-checklist/areas/approvals.json.

1 · platform-core.v18-boot-refusals acceptance[2] (rev 2)

Before:

clause:   the refused boot did not alter the database
verify:   checksum before == after
evidence: the two checksums
steps[0]: checksum the v17 DB; run `os serve` (v18) against it with -d file:COPY.db; read the output and exit code; checksum again

After:

clause:   the refused boot wrote no row and ran no D10 step: every table the v17 copy held keeps every row and every value in the columns it held (no row added, deleted or changed — so no column dropped, no mirror row deleted, no organization_id attributed), every table the boot created is empty, and `sys_migration` holds no `adr-0131-organization-ownership` marker. The additive schema sync the engine runs before the guard judges (new tables, new columns, new indexes) is expected and is not a failure
verify:   a row-level diff of the two SQLite snapshots from steps[0], read through SQLite so the `-wal` is included: for each table present before, its pre-existing columns compared row by row (ordered by primary key) — no difference; for each table present only after, its row count — 0; `SELECT id FROM sys_migration WHERE id = 'adr-0131-organization-ownership'` — no row. ⛔ Not a file checksum: in WAL mode the boot's DDL can sit in COPY.db-wal with the main file's hash unchanged, and the additive sync changes the hash with no row written, so a checksum answers neither question
evidence: per-table row counts before and after, the (empty) row diff over the pre-existing columns, the tables the boot created with their row counts, and the sys_migration read
steps[0]: snapshot the v17 copy through SQLite — its schema (`sqlite_master`, `pragma_table_info` per table) and every table's rows, read with the sqlite3 CLI or node:sqlite so a `-wal` file is included (copy the v17 DB together with its `-wal`, or checkpoint the original before copying); run `os serve` (v18) against the copy with `OS_DATABASE_URL=file:COPY.db` (`os serve` has no `-d` flag); read the output and exit code; snapshot again and diff the two

Why the new clause is true of the code, re-measured against the source at this PR's base:

  • packages/runtime/src/organization-ownership-boot-guard.ts (module doc, "When it judges"): the guard judges in its own start(), ordered after the engine, whose start() connects the drivers and runs the additive schema sync, and ahead of every plugin that writes at start. The doc also says the ceremony's boot "must write nothing before it is refused". So schema additions on a refused boot are the design, and rows written would be the defect. The new clause asserts exactly that.
  • docs/adr/0131-total-organization-ownership-no-null-organization-id.md D10: the four fates (column dropped, mirror deleted, attributed, reported) are the ceremony's. D10 item 5 says the refusing runtime "never auto-migrates". Nothing in D10 forbids additive sync. Each fate is visible in the row diff as a lost column, a lost row or a changed organization_id. The ceremony's completion marker is ORGANIZATION_OWNERSHIP_MIGRATION_ID = 'adr-0131-organization-ownership' in DATA_MIGRATION_FLAG_OBJECT = 'sys_migration' (packages/spec/src/system/migration.zod.ts).
  • steps[0]: os serve declares only port/dev/ui/console/server/prebuilt/preset/log-level/verbose/cert/key (packages/cli/src/commands/serve.ts, Serve.flags). There is no -d flag, so the old step is an invocation error. The QA run booted with OS_DATABASE_URL. The step had to change anyway, because it was the checksum procedure the old verify read. The -d correction rides along; see Deviations.

2 · access-security.security-catalog-one-holder-and-boot-report acceptance[1] (rev 2)

Before:

clause:   install-local of a package redeclaring a catalog name → 422 NAMESPACE_CONFLICT (or PLUGIN_REGISTER_FAILED) with conflicts[], and nothing is recorded as installed
verify:   status + code + conflicts; package list unchanged
evidence: refusal body + the list
title:    … two packages declaring one permission-set / position name refuse boot (422 NAMESPACE_CONFLICT on install-local), …

After:

clause:   install-local of an inline manifest (a `{ manifest }` body) whose package redeclares a catalog name → 422 PLUGIN_REGISTER_FAILED whose message names each conflicting name and its holder, and nothing is recorded as installed
verify:   status + error.code + error.message: every redeclared catalog name (permission set, position or capability) appears in the message with the package, environment or built-in that already holds it; GET /api/v1/packages lists the same packages before and after. ⛔ No `conflicts[]` is expected on this door: it answers its own registered PLUGIN_REGISTER_FAILED and interpolates only the register error's message (that route's entry in packages/spec/src/api/error-code-ledger.zod.ts); the structured `conflicts` ride the thrown SecurityCatalogNameConflictError, which the boot-refusal pins in automated.ref assert
evidence: the refusal body + the package list before and after
title:    … two packages declaring one permission-set / position name refuse boot (on install-local, 422 PLUGIN_REGISTER_FAILED naming each name and its holder), …

Re-measured against the source:

  • packages/cloud-connection/src/marketplace-install-local-plugin.ts, register step 3: when manifestService.register throws and the body carried an inline manifest (body.manifest), the door returns 422 { error: { code: 'PLUGIN_REGISTER_FAILED', message: 'Failed to register imported manifest: ' + the error's message } } before step 4 persists anything. A cloud-fetched manifest takes the lenient path instead and IS installed (200, hotLoaded: false). That is why the clause now names the inline shape: without it, "nothing is recorded as installed" is false on the other source.
  • packages/objectql/src/registry.ts, SecurityCatalogNameConflictError: the message lists every conflict as TYPE "name" is already held by HOLDER, joined with ; . So "names each conflicting name and its holder" holds for one conflict and for several.
  • packages/spec/src/api/error-code-ledger.zod.ts documents this door answering its own PLUGIN_REGISTER_FAILED at 422 and interpolating only the message.
  • None of the six automated.ref files mentions install-local. A grep -l for install-local|installLocal|marketplace over them exits 1, and all six paths exist. The .conflicts assertions in packages/runtime/src/standalone-stack-security-catalog-one-holder.test.ts are made on the boot-refusal throw.
  • Title: the same false 422 NAMESPACE_CONFLICT on install-local sat in the title. Leaving it would have left the item contradicting its own clause; see Deviations.
  • ⛔ No conflicts[] enhancement here, as ruled.

3 · approvals.act-door-and-admin-rescue-slate acceptance[1] (rev 2)

Before:

clause:   GET renders the action page, POST redeems, PUT → 405 with Allow: GET, POST, a dead token → a 200 page (not an error envelope)
verify:   status + headers per verb
evidence: four lines
title:    … (GET renders, POST redeems, PUT 405 Allow: GET, POST, a dead link a 200 page, …)

After:

clause:   GET renders the action page, POST redeems, a dead token → a 200 page (not an error envelope), and PUT — a method neither wire door claims — is that door's ordinary miss: 404 with no Allow header, never reaching the member (ENDPOINT_NOT_FOUND on the self-hosted `os dev` boot, whose raw-app mount registers only GET and POST; ROUTE_NOT_FOUND on the hosted dispatcher door, whose `/approvals/act` domain claims only GET, HEAD and POST). 405 with Allow: GET, POST is the in-process ApprovalService.handleActionPage member's answer only, which no wire request reaches with a PUT
verify:   status + headers per verb; for the PUT also error.code and the absence of an Allow header. The member's 405 is not a wire leg: it is pinned in-process by packages/plugins/plugin-approvals/src/action-page-member.integration.test.ts, and the dispatcher's 404 miss by packages/runtime/src/domains/approvals-act.test.ts (both in automated.ref)
evidence: four lines (the PUT's with its error.code and its headers)
title:    … (GET renders, POST redeems, a PUT neither door claims an ordinary 404 miss with no Allow header, a dead link a 200 page, …)

Re-measured against the source. The two wire doors miss with different codes, and the clause names both:

  • Self-hosted (os dev / os serve, the RUNNER's boot). packages/plugins/plugin-approvals/src/approvals-plugin.ts mountActionPages puts rawApp.get and rawApp.post straight on the raw Hono app, outside the adapter's registeredRoutes. A PUT therefore reaches the adapter's notFound seam. There allowedMethodsForPath finds no registered method for the path, and unmatchedResponse answers 404 { error: { code: 'ENDPOINT_NOT_FOUND' } } with no Allow header (packages/plugins/plugin-hono-server/src/adapter.ts). That is exactly what the QA run measured, twice; DELETE and PATCH answered the same.
  • Hosted (createHonoApp catch-all, no http.server). packages/runtime/src/domains/approvals.ts declares APPROVALS_ACT_METHODS = ['GET', 'HEAD', 'POST'], and every other method "is not claimed and falls through". The item's own pin packages/runtime/src/domains/approvals-act.test.ts asserts { status: 404, code: 'ROUTE_NOT_FOUND' } for PUT, with handleActionPage never called.
  • Member. ApprovalService.handleActionPage (packages/plugins/plugin-approvals/src/approval-service.ts) returns 405 with Allow: GET, POST for any other method. action-page-member.integration.test.ts pins that in-process for PUT, DELETE, PATCH, HEAD and OPTIONS.
  • The card's text named ROUTE_NOT_FOUND, the pin's code, while the QA run on os dev saw ENDPOINT_NOT_FOUND. Both are right for their door.

Verification

  • QA subject versus this base. git merge-base --is-ancestor 5b14b7f3 de43524606 exits 0. git diff --stat 5b14b7f3 de43524606 over the eleven files these clauses rest on (the boot guard, the install-local plugin, the approvals domain, plugin and service, the hono-server adapter, the registry, the dispatcher plugin, serve.ts, both approvals pins) plus the three area files shows one changed file: packages/objectql/src/registry.ts, from fix(objectql): report a bound action named like one its target already lists, and registerAction replacing another owner's handler #24526's bound-action reporting. None of its changed lines touch SecurityCatalogNameConflictError. The QA runs' live measurements therefore stand on this base unchanged.
  • Gates. Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (change set from git: 3 paths, 48 changed lines; 13 families). All 13 ran at ad55c68f84, and every exit code was captured before any pipe:
    • node scripts/check-ci-filter-parity.mjs · exit 0
    • node scripts/check-closing-keyword-parity.mjs · exit 0
    • node scripts/check-closing-keyword-parity.mjs --self-test · exit 0
    • node scripts/check-comment-mask-corpus.mjs · exit 0
    • pnpm --filter @objectstack/lint run check:doc-formula-expressions · exit 0. The first attempt answered PREREQUISITE NOT MET (exit 3: @objectstack/formula / @objectstack/lint not built). That attempt measured nothing; it was re-run after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint, taken under the shared verify lock.
    • pnpm check:cross-package-test-inputs · exit 0
    • pnpm check:doc-authoring · exit 0
    • pnpm check:driver-memory-census · exit 0
    • pnpm check:gitlink-declared · exit 0
    • pnpm check:nul-bytes · exit 0
    • pnpm check:platform-checklist · exit 0. Its line: OK — 16 areas, 327 items …; symbol anchors: 855/865 resolved …, 18 file floors held. That is the same anchor count as on the untouched base, so no anchor was lost or added.
    • pnpm check:refd-timer-probe · exit 0
    • pnpm check:watch-hint-literal · exit 0
    • --ran reconciliation: 13 derived, 13 run, 0 NOT-MEASURED, 0 UNRUN.
  • check:platform-checklist is not per-PR CI. It runs in the daily watchdog, so the local reading above is its evidence for this PR.
  • Cross-package reader. packages/plugins/plugin-auth/src/checklist-refusal-envelope-consistency.test.ts reads every area file for its retired-convention absence regex. Run over all 5715 strings of the three edited files, the regex matches 0 times; its positive control matches. CI's Test Core runs the file itself.
  • NOT MEASURED: a live verification re-run of the three re-worded clauses against a booted showcase. Reason: it needs a full workspace build, a v17 SQLite minted from npm @objectstack/cli@17.7.0, and two showcase boots, all in a container shared with another dev agent. The dispatch asked for a source re-measurement, which is above. Each clause's verify step is concrete and runnable: the SQLite row diff (row 1), the 422 body's code and message plus the package list (row 2), and the PUT's status, code and absent Allow header (approvals checklist: act-door-and-admin-rescue-slate clause 1 pins PUT 405 Allow on the wire, but both wire doors answer 404 by design (its own pin asserts the 404) - re-word #24543).
  • Docs-only (docs/qa/** is inside no package's published files), so skip-changeset.

Deviations (each beyond the three clause texts, inside the three claimed files)

  • platform-core.v18-boot-refusals steps[0]: re-worded. It was the checksum procedure the old verify read, and it passed -d to os serve, which has no such flag. That -d was a checklist-accuracy finding of QA run QA run · priority:P0 (23/23) · 5b14b7f3 · 2026-10-19 · 17 PASS / 5 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #24556, and the fix is mechanical: the run booted with OS_DATABASE_URL.
  • access-security.security-catalog-one-holder-and-boot-report title: its install-local parenthetical carried the same false NAMESPACE_CONFLICT.
  • approvals.act-door-and-admin-rescue-slate title: its PUT leg, as the dispatch allowed.

Acceptance notes

  • Row 1's open question for the maintainer, quoted unchanged from platform-checklist + cli: three findings from the 18.0 QA sweep at 5b14b7f3 — two clauses mis-asserted against documented contracts, and a refusal that prescribes a withdrawn command (family card) #24567:

    Open question for the maintainer (not a defect on this evidence): the refusal tells the operator to keep this database on a 17.x runtime after the v18 boot has added v18 schema to it.

    This PR does not answer it. The new clause records the additive schema as expected only because the guard's own contract orders it.

  • platform-checklist + cli: three findings from the 18.0 QA sweep at 5b14b7f3 — two clauses mis-asserted against documented contracts, and a refusal that prescribes a withdrawn command (family card) #24567 row 3 remains open: the drop-gate refusal text in packages/cli/src/commands/migrate/apply.ts and the help example in organization-ownership.ts belong to the domain:cli lane. This PR leaves packages/** untouched.

  • Checklist-accuracy findings that the same QA records list for these three items, not taken here. They close out through the wave's anchor card, per RUNNER's extraction obligation; that card has no number yet.

    • platform-core.v18-boot-refusals: steps[1]'s os dev with services:{auth:false} is refused earlier on three counts; and clause 1 names the code ORGANIZATION_OWNERSHIP_MIGRATION_REQUIRED, which the CLI output does not print.
    • access-security.security-catalog-one-holder-and-boot-report: clause 4's clean-boot info line shows only with OS_LOG_LEVEL=info.
    • approvals.act-door-and-admin-rescue-slate: fixtures.requires asks for a dev mail transport capture, but the action links already sit in sys_notification.payload.actions after a remind.
  • Observation, not filed. packages/cloud-connection/src/marketplace-install-local-hot-loaded.test.ts and marketplace-install-local-convert-forward.test.ts assert PLUGIN_REGISTER_FAILED at this door. Whether either pins the catalog-conflict message, which would make it a candidate for the item's automated.ref (RUNNER rule 6, reverse direction), was not judged. ⛔ No pin was changed.


Generated by Claude Code

… mis-asserted

platform-core.v18-boot-refusals acceptance[2]: the refused boot wrote no
row and ran no D10 step, read as a row-level SQLite diff that includes
the -wal, not a file checksum (the additive schema sync before the guard
is expected). steps[0] stops passing -d to os serve.

access-security.security-catalog-one-holder-and-boot-report acceptance[1]
and title: an inline-manifest install-local answers 422
PLUGIN_REGISTER_FAILED whose message names each conflicting name and its
holder, and nothing is installed; no conflicts[] on that door.

approvals.act-door-and-admin-rescue-slate acceptance[1] and title: a PUT
neither wire door claims is the door's ordinary 404 miss with no Allow
header; 405 + Allow: GET, POST is the in-process member's answer only.

Each item: revision 1 -> 2, one history entry naming its QA source.

Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 19, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Seat review

ACCEPT · domain:devx seat 1 · os-warren · session_01FM29ZqLTrnPNXxijioZwMp · 2026-10-19T15:26Z · head 596ee73574 · cards #24567 rows 1–2 (claim 6269843213) + #24543 (claim 6269868242)

  • Form. Draft, base main, first lines Fixes #24543 / Refs #24567 (rows 1–2) / Clause-②: no, assignee os-warren, skip-changeset (docs only). node scripts/pm/check-governed-merges.mjs --pr 24592 → NOT governed; 48 changed lines.
  • Scope. 3 files under docs/qa/platform-checklist/areas/, +33 / −15. No package, test, pin or gate touched. platform-checklist + cli: three findings from the 18.0 QA sweep at 5b14b7f3 — two clauses mis-asserted against documented contracts, and a refusal that prescribes a withdrawn command (family card) #24567 row 3 (domain:cli) is untouched, as dispatched.
  • The diff, read against the ruling (assertion defects; the product is right). Each item goes revision 1 → 2 with one history row naming its QA source and ref docs(qa): re-word three v18 checklist clauses the 18.0 QA sweep found mis-asserted #24592.
    • platform-core.v18-boot-refusals acceptance[2]: "wrote no row and ran no D10 step", verified by a row-level SQLite diff that reads the -wal, with additive schema sync expected. Checked at head: the guard's module doc (packages/runtime/src/organization-ownership-boot-guard.ts) orders it after the engine's additive sync and says the ceremony's boot "must write nothing before it is refused"; Serve.flags in packages/cli/src/commands/serve.ts declares no -d.
    • access-security.security-catalog-one-holder-and-boot-report acceptance[1]: an inline-manifest install-local answers 422 PLUGIN_REGISTER_FAILED, the message naming each name and its holder, no conflicts[]. Checked at head: marketplace-install-local-plugin.ts answers { code: 'PLUGIN_REGISTER_FAILED', message: \Failed to register imported manifest: ${registerError}` }`.
    • approvals.act-door-and-admin-rescue-slate acceptance[1]: a PUT is the door's ordinary 404 miss with no Allow. Checked at head: APPROVALS_ACT_METHODS = ['GET', 'HEAD', 'POST'] in packages/runtime/src/domains/approvals.ts, and approvals-act.test.ts asserts { status: 404, code: 'ROUTE_NOT_FOUND' } for PUT; action-page-member.integration.test.ts exists and is cited in the item's automated.ref.
  • Gates. The dev's dispatch-gates union: 13 derived, 13 run, all exit 0 at 596ee73574; check:platform-checklist keeps 855/865 anchors, the base's count. Check-runs at 596ee73574: 39, all completed, 31 success, 8 skipped; node scripts/pm/check-expected-skips.mjs --pr 24592 → OK — 8 skipped check-run(s), every one in the roster (exit 0). No review, no review comment.
  • Accepted deviations. steps[0] of the boot-refusals item (it was the old verify's checksum procedure, and its -d was an invocation error); the two titles that repeated the false clause text; the inline-manifest qualifier (a cloud-fetched manifest is installed leniently, so without it the clause would be false of the code).
  • Not measured, accepted. A live re-run of the three clauses on a booted showcase. The dispatch asked for a source re-measurement, and each new verify step is concrete and runnable.
  • Carried, not filed. ApprovalService.handleActionPage's doc says it answers "exactly what the plugin's self-hosted raw-app mount answers", yet for PUT the member answers 405 and the mount 404; no wire request reaches the member with a PUT, so nothing wrong is observable. A doc-precision nit for the approvals lane; the checklist-accuracy findings in Acceptance notes ride the 18.0 wave's anchor card.
  • Open question, not answered here. Row 1's, quoted in the PR body: the refusal tells the operator to keep the database on 17.x after the v18 boot has added v18 schema to it. This seat has put it to the maintainer.

This seat readies the PR and queues it with auto-merge.


Generated by Claude Code

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