Repository navigation
Commit 5e80009
docs(qa): re-word three v18 checklist clauses the 18.0 QA sweep found mis-asserted (#24592)
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:
```text
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:
```text
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:
```text
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:
```text
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:
```text
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:
```text
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
5b14b7f de43524` exits 0. `git diff --stat 5b14b7f de43524` 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 #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 (#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 #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
#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.
- **#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](https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 5a871e4 commit 5e80009
3 files changed
Lines changed: 33 additions & 15 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3501 | 3501 | | |
3502 | 3502 | | |
3503 | 3503 | | |
3504 | | - | |
| 3504 | + | |
3505 | 3505 | | |
3506 | 3506 | | |
3507 | | - | |
| 3507 | + | |
3508 | 3508 | | |
3509 | 3509 | | |
3510 | 3510 | | |
| |||
3532 | 3532 | | |
3533 | 3533 | | |
3534 | 3534 | | |
3535 | | - | |
| 3535 | + | |
3536 | 3536 | | |
3537 | | - | |
3538 | | - | |
| 3537 | + | |
| 3538 | + | |
3539 | 3539 | | |
3540 | 3540 | | |
3541 | 3541 | | |
| |||
3576 | 3576 | | |
3577 | 3577 | | |
3578 | 3578 | | |
| 3579 | + | |
| 3580 | + | |
| 3581 | + | |
| 3582 | + | |
| 3583 | + | |
| 3584 | + | |
3579 | 3585 | | |
3580 | 3586 | | |
3581 | 3587 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1556 | 1556 | | |
1557 | 1557 | | |
1558 | 1558 | | |
1559 | | - | |
| 1559 | + | |
1560 | 1560 | | |
1561 | 1561 | | |
1562 | | - | |
| 1562 | + | |
1563 | 1563 | | |
1564 | 1564 | | |
1565 | 1565 | | |
| |||
1586 | 1586 | | |
1587 | 1587 | | |
1588 | 1588 | | |
1589 | | - | |
| 1589 | + | |
1590 | 1590 | | |
1591 | | - | |
1592 | | - | |
| 1591 | + | |
| 1592 | + | |
1593 | 1593 | | |
1594 | 1594 | | |
1595 | 1595 | | |
| |||
1614 | 1614 | | |
1615 | 1615 | | |
1616 | 1616 | | |
| 1617 | + | |
| 1618 | + | |
| 1619 | + | |
| 1620 | + | |
| 1621 | + | |
| 1622 | + | |
1617 | 1623 | | |
1618 | 1624 | | |
1619 | 1625 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2977 | 2977 | | |
2978 | 2978 | | |
2979 | 2979 | | |
2980 | | - | |
| 2980 | + | |
2981 | 2981 | | |
2982 | 2982 | | |
2983 | 2983 | | |
| |||
2991 | 2991 | | |
2992 | 2992 | | |
2993 | 2993 | | |
2994 | | - | |
| 2994 | + | |
2995 | 2995 | | |
2996 | 2996 | | |
2997 | 2997 | | |
| |||
3008 | 3008 | | |
3009 | 3009 | | |
3010 | 3010 | | |
3011 | | - | |
| 3011 | + | |
3012 | 3012 | | |
3013 | | - | |
3014 | | - | |
| 3013 | + | |
| 3014 | + | |
3015 | 3015 | | |
3016 | 3016 | | |
3017 | 3017 | | |
| |||
3043 | 3043 | | |
3044 | 3044 | | |
3045 | 3045 | | |
| 3046 | + | |
| 3047 | + | |
| 3048 | + | |
| 3049 | + | |
| 3050 | + | |
| 3051 | + | |
3046 | 3052 | | |
3047 | 3053 | | |
3048 | 3054 | | |
| |||
0 commit comments