Skip to content

docs(qa): 18.0 sweep anchor round 13 — QA round 3 surface:cli findings in cli.json, plus three carried items - #24850

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-24579-v18-sweep-round13
Oct 20, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-24579-v18-sweep-round13

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Refs #24579

Clause-②: no

Round 13 of the 18.0 sweep's wave anchor (claim 6288038866, PM loop round 22). It covers QA round 3's surface:cli checklist-accuracy findings C1–C9 (QA record #24786) and B6 (QA record #24787) in cli.json, plus three items carried on the anchor. Only checklist text changes. Twelve items in three area files (cli.json 9, access-security.json 2, approvals.json 1) each take one revision bump and one history row naming the record and the finding. There is no product code, test, pin, changeset text or RUNNER.md change.

Every finding was re-read in the code at base 7697ddcf94 before it was written, and all of them hold. Every source cited below is byte-identical at the merged origin/main 5cb6e6e0aa. A scripted textual editor made the edits: it re-parses each area file and asserts that only the target items changed, and in each of them only the declared fields, plus revision (+1) and one appended history row. The raw file is never re-serialized.

Changes

finding item field old → new code anchor or pin (read at 7697ddcf94)
#24786 C1 cli.migrate-duplicates-inventory acceptance[3].verify "plan's stdout carries '[Registry] Registered view: NAME'" → under --json, stdout is the plan document alone and every boot line goes to stderr; only the human path prints the registry lines on stdout packages/cli/src/utils/json-stdout.ts#reserveStdoutForJson, taken by bootSchemaStack when jsonOutput is set; the objectql registry logs through console.log; the [metadata_spec_invalid] lines are console.error / console.warn
#24786 C2 cli.migrate-duplicates-inventory fixtures.requires[1] appended: the stock showcase has one org-scoped identifier (showcase_field_zoo.f_autonumber), so declare a second one; drop uniq_OBJ_organization_id_FIELD before seeding the repeat; plan then reports that drop as index_mismatch packages/drivers/driver-sql/src/schema-drift.ts#buildIndexName, and the declared-index-missing arm there (index_mismatch, actual (absent)); the autonumber default unique: 'organization'
#24786 C3 cli.dev-boot-contract fixtures.requires[2] (new) none → the console leg needs pnpm objectui:build; on an unbuilt tree /_console/ answers 503 "The ObjectStack Console is not built …", recorded blocked(environment) packages/cli/src/utils/console.ts#createConsoleNotBuiltPlugin; scripts/build-console.sh
#24786 C4 cli.dev-boot-contract variants[6] appended: the scratch stack's object must declare sharingModel, or the compile fails on security-owd-unset and os dev exits 1 packages/lint/src/validate-security-posture.ts#SECURITY_OWD_UNSET (severity error); dev.ts "Compile failed — fix errors above before starting dev server", then process.exit(1)
#24786 C5 cli.migrate-meta-codemod steps[6] "… resolve the manual changes above, then run os validate" → "Migrated stack does not yet pass schema validation — N refusal(s) left after the chain. Resolve them, then run os validate:", then each refusal packages/cli/src/commands/migrate/meta.ts#printSchemaVerdict
#24786 C6 cli.doctor-health-report acceptance[0].clause, acceptance[0].verify, steps[0] six unconditional rows → seven (adds Package-authored scheduled work, ON or OFF), plus the config block's Platform protocol row; the verify names the rows by their push sites and checks instead of a count packages/cli/src/commands/doctor.ts#scheduledWorkCheck; the run body's unguarded results.push calls; checkProtocolVersionGap in the config block
#24786 C7 cli.hook-body-extraction-gates acceptance[6].verify "the forbidden seven" → one hook per FORBIDDEN_PATTERNS entry, with no number (and the warning block lists at most 20) packages/cli/src/utils/extract-hook-body.ts#FORBIDDEN_PATTERNS, 14 entries at base
#24786 C8 cli.validate-v18-authoring-verdicts automated.ref a bare list of seven pins → narrowed to acceptance[0] ONLY; acceptance[1] and acceptance[2] are named as needing the CLI the seven spec, formula and lint unit files, none of which runs os validate or os build
#24786 C8 cli.verify-derived-proof-families automated.ref a bare list of five pins → acceptance[0] for all five, and acceptance[2] via the delete-behaviors negative control; acceptance[1] (on the showcase) needs the live run packages/cli/test/verify-delete-behaviors.test.ts "NEGATIVE CONTROL: reports a cascade a hook undid, counts it, and exits 1" (it spawns the CLI and asserts exit 1, contradicted, contradicted 1, hardFailures 1); every pin uses its own fixture stack
#24786 C9 cli.qa-suite-execution fixtures.requires[0] appended: the boot needs a built workspace and no console build scripts/check-console-sha.mjs "ℹ No console dist … skipping SHA check", exit 0; scripts/check-dev-prereqs.mjs runs first in the root dev chain
#24787 B6 cli.build-own-contract acceptance[3].clause, acceptance[3].verify, fixtures.knownGaps[0] (new) "the failure payload is { success: false, … issues }" → each command's payload: the rule failure is build success/error/issues against validate valid/errors; the load-time refusal is error + code (STACK_SCHEMA_INVALID) with no finding list on both; the judged parity stays warnings and conversions the emitJson payloads in compile.ts and validate.ts; packages/cli/src/utils/format.ts#errorCodeFields copies code and httpStatus only. The governing-text gap: no spec docblock or ADR states either command's --json shape (only the conversions element, packages/spec/src/stack-provenance.ts#stackConversionsOf)
carried 11 access-security.no-active-org-session-semantics fixtures.knownGaps[3] sharpened with ADR-0131 D7's reading (below) ADR-0131 D7 and D9; packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts (systemFields: { tenant: false }, tenant_id docblock, defaultRowScope sys_audit_log_org)
carried 12 access-security.owd-save-gate acceptance[0].verify, acceptance[0].evidence "a follow-up GET finds no qa_owd_probe" → that GET plus the draft read GET …/qa_owd_probe?state=draft for the ?mode=draft leg; the evidence names both reads packages/rest/src/meta-item-read-gate.ts#META_ITEM_READ_PARAMS (state, never mode)
carried 13 approvals.email-action-token-door automated.ref "Full clauses: acceptance[0]–[3] only." → acceptance[0]–[3] and negative[2] action-page-member.integration.test.ts "a dead link — unknown, expired, consumed — is told on the page with 200, through GET and POST alike": each page byte-equal to renderResultPage(kind) with no request, which renders the summary rows only when handed one (packages/plugins/plugin-approvals/src/action-link-pages.ts#renderResultPage); the file's two parity cases hold the self-hosted mount to the same bytes

Carried item 11 — the governing-text decision

The rule applied: governing text decides a clause, and a clause is re-scoped only where an ADR, spec docblock or AGENTS.md rule states the answer. ADR-0131 D7 states the attribution reading. sys_audit_log is deployment-level state with no organization column. The organization a row is about "becomes a plain attribution field under a name the tenant-field resolver does not claim, never the tenancy anchor". Such objects "are governed by object permission, not by the wall". D9 scopes the no-NULL rule to tenant-column objects ("column ⇒ in scope"). This moves acceptance[4]'s premise: its "invisible to RLS readers" was written for #8245, when the ledger was walled. It does not answer the question, though. No ADR states that a member-less actor's audit row may carry a NULL attribution, and none states that the platform operator reads such rows. The operator's 200 and the user's 403 that QA run #24783 measured come from the implementation: the object's defaultRowScope tenant_id == current_user.organization_id, which a NULL row matches for no organization reader. So the clause stays as written, and knownGaps[3] gains the D7 reading. This falsifies the dispatch's hypothesis 2 in its conclusion: D7 does state the attribution reading, but not the two facts an alignment needs.

Items left alone, with reasons

  • access-security.no-active-org-session-semantics acceptance[4]: kept as written, by the decision above.
  • cli.hook-body-extraction-gates steps[0] and acceptance[0].verify still say "fourteen at base 9a7838e". FORBIDDEN_PATTERNS still holds 14 entries at 7697ddcf94, so both are true as dated readings.
  • cli.dev-boot-contract acceptance[0] (clause, verify, evidence): unchanged. Its console leg stands; the new requires[2] says what the leg needs and how to record it when the Console is unbuilt.
  • cli.build-own-contract acceptance[0]'s success key list: unchanged. B6 names only acceptance[3], and QA run QA run · surface:build (5/7) · 580fd4ed · 2026-10-20 · 4 PASS / 1 PARTIAL / 0 FAIL / 0 BLOCKED / 2 NOT-RUN #24787 scored acceptance[0] a pass.
  • PM hypothesis 1 (a roster constant can replace each count): it holds for C7, where FORBIDDEN_PATTERNS is a declared array and is now the anchor. It does not hold for C6: doctor has no row roster, because its rows are pushed inline in run(). That verify now names the push sites and checks, and states no count.

Gates

The derived list is node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, computed on the actual change set: 3 paths vs merge base 5cb6e6e0aa, 118 changed lines. It gives 13 commands. Each one ran at head b66554b1ad, with its exit code captured before any pipe, and each exited 0:

pnpm check:platform-checklist · pnpm check:nul-bytes · pnpm check:doc-authoring · pnpm check:cross-package-test-inputs · pnpm check:driver-memory-census · pnpm check:gitlink-declared · pnpm check:refd-timer-probe · pnpm check:watch-hint-literal · pnpm --filter @objectstack/lint run check:doc-formula-expressions (after a locked turbo run build --filter=@objectstack/lint... --concurrency=2) · node scripts/check-ci-filter-parity.mjs · node scripts/check-closing-keyword-parity.mjs · node scripts/check-closing-keyword-parity.mjs --self-test · node scripts/check-comment-mask-corpus.mjs

The --ran reconciliation reads "13 derived, 13 run, 0 NOT-MEASURED, 0 UNRUN", a derived zero because all 13 recorded an exit code. No per-PR CI job runs pnpm check:platform-checklist, so this local reading is its evidence:

reading base 7697ddcf94 head b66554b1ad
items 16 areas, 328 items 16 areas, 328 items
line citations 0 survive across 21 swept documents 0 survive across 21 swept documents
symbol anchors 954/964 resolved, 10 on the named residual, 18 file floors held 965/975 resolved, 10 on the named residual, 18 file floors held

The history rows' ref are written as this PR's number in the commit that follows this PR's creation. That commit changes only those twelve strings, and the gate readings at that final head are in the report on #24579.

Serial check: origin/main was merged before this PR was opened. None of the 14 open PRs touches cli.json, access-security.json or approvals.json, or any docs/qa/ path, so no git merge-tree probe was owed.

Changeset: docs/qa/** ships in no package. No public package's files[] names it, and the root package is private. So this PR carries skip-changeset and touches no .changeset/*.md.

Acceptance notes

  • The load-time refusal payload of os build --json and os validate --json carries the error's message and code, but not the structured zod issues. The STACK_SCHEMA_INVALID ledger row (packages/spec/src/api/error-code-ledger.zod.ts) says that error carries them, and errorCodeFields copies only code and httpStatus. The message renders those issues as text: the StackSchemaInvalidError docblock in packages/spec/src/stack.zod.ts says "the message already renders those, and the envelope's job is the machine-readable half". The CLI payload declares no issues key, so this is not a breach of a declared contract. It is recorded in cli.build-own-contract knownGaps[0] and filed nowhere (carrier: none).

Generated by Claude Code

…B6 (#24579 round 13)

Ten cli.json items take one revision bump and one history row each:
migrate-duplicates-inventory (C1, C2), dev-boot-contract (C3, C4),
migrate-meta-codemod (C5), doctor-health-report (C6),
hook-body-extraction-gates (C7), validate-v18-authoring-verdicts and
verify-derived-proof-families (C8, theme-B narrowing), qa-suite-execution
(C9) and build-own-contract (B6). Each finding re-read at base 7697ddc.

Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp
Co-authored-by: Claude <noreply@anthropic.com>
…-read (#24579 round 13)

no-active-org-session-semantics knownGaps[3] gains ADR-0131 D7's reading
of sys_audit_log.tenant_id (attribution field, object permission governs);
acceptance[4] stays, no ADR states the member-less answer.
owd-save-gate acceptance[0] re-reads the probe with ?state=draft for its
?mode=draft leg (META_ITEM_READ_PARAMS).

Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp
Co-authored-by: Claude <noreply@anthropic.com>
…[2] (#24579 round 13)

action-page-member.integration.test.ts's dead-link case compares the
invalid, expired and consumed pages byte for byte with
renderResultPage(kind) and no request, which renders no summary rows.

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 20, 2026
The twelve history rows this round appended carried the branch name as
their ref until the pull request existed; they now name it. Only those
twelve strings change.

Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Seat review

ACCEPT · domain:devx seat 1 · os-warren · session_01FM29ZqLTrnPNXxijioZwMp · 2026-10-20T10:29Z · head 19eb546d9c · card #24579, round 13 (claim 6288038866)

  • Form. Draft, base main. The first line is Refs #24579, and Clause-②: no is on line 3. Assignee os-warren, labels size/m and skip-changeset. node scripts/pm/check-governed-merges.mjs --pr 24850 → NOT governed. git merge-tree against main is clean, and no other open PR touches docs/qa/platform-checklist/.
  • Ledger invariants, parsed, merge base 5cb6e6e0aa vs head. 3 area files, 12 items: 9 in cli.json, 2 in access-security.json and 1 in approvals.json. Each has exactly one revision bump and one appended history row with ref: "#24850". No item is added, removed or reordered, and no top-level key changes.
  • Counts that will drift now name their roster.
    • C7's verify drops "the forbidden seven" for extract-hook-body.ts#FORBIDDEN_PATTERNS, which the seat counts at 14 entries on main.
    • C6's verify names doctor's unguarded results.push sites and checks (seven rows, plus the config block's Platform protocol row), with no number.
  • Clause edits against governing text.
    • B6 (build-own-contract acceptance[3]) follows compile.ts / validate.ts: build answers success + issues, validate answers valid + errors, and a load-time throw answers error + code on both. No spec docblock or ADR states either --json shape, and the new knownGaps[0] says so. That is the right shape when governing text is silent.
    • Item 11 (no-active-org-session-semantics acceptance[4]) is left, and knownGaps[3] is sharpened. The seat read ADR-0131 D7 on main: an audit row's organization "becomes a plain attribution field … never the tenancy anchor", and "such objects are governed by object permission, not by the wall". D7 states the attribution reading. It does not state that a member-less actor's row may carry a NULL attribution, or who reads such rows, so the dispatch's "otherwise" branch applies.
  • The pin additions.
    • Item 13 adds action-page-member.integration.test.ts's dead-link case for negative[2]. It compares each page byte for byte with renderResultPage(kind) called with no request, which renders no summary rows, so a leaked summary would fail it.
    • C8 narrows both refs per clause (theme-B).
    • Item 12 adds the ?state=draft re-read, the GET's own parameter (META_ITEM_READ_PARAMS).
  • Gates.
    • The seat ran node scripts/check-platform-checklist.mjs at the head. Exit 0: 16 areas, 328 items, line citations: 0 survive, symbol anchors: 965/975 resolved, 18 file floors held.
    • The dev's dispatch-gates union is 13 derived, 13 run, all exit 0; --ran reconciles.
    • Check-runs at 19eb546d9c: 40, 31 success, 9 skipped, 0 failing or pending. node scripts/pm/check-expected-skips.mjs --pr 24850 → OK. No review, no comment.
  • Noted, not filed (the dev's out-of-scope finding): the load-time --json refusal of os build and os validate drops the zod issues that the STACK_SCHEMA_INVALID ledger row says the error carries (format.ts#errorCodeFields). No declared payload key is breached, so this is an observation, recorded in knownGaps[0].

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/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants