Skip to content

docs(qa): P0 sweep follow-through — re-point query-contract-matrix, correct the run's checklist findings, extend two pins - #21111

Merged
objectstack-fleet[bot] merged 17 commits into
mainfrom
claude/issue-21060-p0-sweep-checklist
Oct 1, 2026
Merged

objectstack-fleet[bot] merged 17 commits into
mainfrom
claude/issue-21060-p0-sweep-checklist

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #21060
Clause-②: no

This finishes QA run #21056 (the 2026-10-01 P0 release sweep). It re-points the one stale red row and corrects the run's checklist-accuracy findings, citing source or a local measurement for each one. It also brings two pins up to date. No product code changes. The run's product defects stay on their own cards: #21052, #21057, #21058, objectstack-ai/objectui#11326 and objectstack-ai/objectui#11327.

1. The re-point: api-backend.query-contract-matrix (rev 2 → 3)

where old new evidence
acceptance[5] scalar $nin on POST /query answers 400 INVALID_FILTER in both spellings POST, both spellings: 400 VALIDATION_FAILED with a located fields[] entry (query.where.status.$nin for the object body, query.where for the AST). GET $filter: 400 INVALID_FILTER. Never a 500, never a widened 200. A GET twin probe is added to step 8 FilterConditionSchema.superRefine(checkFilterConditionComparands) and lowerFoldedTransportValues (spec). The POST door answers a FindDataRequestSchema failure as VALIDATION_FAILED + fields[] (rest-server.ts). Local parse of both bodies refused at exactly those two paths. The POST-door posture is pinned by rest-server-repeated-filter-param.test.ts and analytics-filter-refusal-envelope.test.ts
acceptance[2], step 5 dotted fields: ['account.name'] counted as narrowing refused 400 INVALID_FIELD by design, with the message naming expand protocol.ts#assertProjectionFieldsExist
negative[0] probe the widening with {"filter": …} filter is a declared transport spelling of where, so it is served. The probes are now a mistyped clause (400 VALIDATION_FAILED) and an undeclared key (400 INVALID_FIELD) QueryTransportParamsSchema; protocol.ts#assertQueryParamsAreFields; request-schema-gate.conformance.test.ts

A residual for the maintainer (not a defect): the same condition answers VALIDATION_FAILED on POST and INVALID_FILTER on GET (the #8001 family).

2. Checklist-accuracy findings: what changed, old → new

  • access-security.crud-permission-matrix (3 → 4).
  • access-security.write-path-guards (2 → 3).
    • acceptance[5], old: "drops the field for the batch". New: per row. Only the locked row loses the field, reported as results[i].droppedFields. Source: updateManyData calls engine.update per row with its own drop listener.
  • access-security.rls-both-sides (4 → 5) and access-security.owd-sharing-matrix (2 → 3), plus FOLLOW-UPS.md §7c.
    • The private handle D11 is disambiguated from §7c's public D11 row (an unrelated two-factor defect). The text stays non-disclosing.
    • Clause numbering is stated: "clause N" here means acceptance[N], and a run record's A(N+1).
  • access-security.anonymous-deny-surfaces (1 → 2). automated.ref now names all six families the pin drives (see §3).
  • search recipe qa-contributor-bound-member.
    • Step 1, old: "this works on a stock dev boot". New: invite first. The undeclared audience posture is invite_only (migration entry audience-posture-default-invite-only), and an uninvited sign-up answers 403 SELF_REGISTRATION_CLOSED.
    • Step 5: point the own-row invoice at a seeded account.
  • ai.mcp-stdio-fail-closed (3 → 4).
    • Two personas: contributor for RLS, client_liaison for FLS. The only readable: false grants are client_liaison's, on public_read_write showcase_project.
    • acceptance[5] no longer expects details.forbiddenFields on the wire. REST's PERMISSION_DENIED arm answers {error, code, object}.
    • steps[0] hosts the transport with os start. Measured: os dev printed 15 banner lines to stdout, and os start printed 0.
  • api-backend.packaged-action-disabled-dispatch (2 → 3). The MCP door is drivable live: the stock banner prints MCP: …/api/v1/mcp.
  • platform-core.boot-health (5 → 6) and platform-core.seed-integrity (2 → 3).
    • The seed reads now name the Seeds: banner row. At the default warn level, a healthy boot prints no SeedLoader line (seed-summary.ts).
    • The "no ⚠" clause now names the four misauthored flow classes. Stock boots list their policy-disabled scheduled flows with ⚠ (printAutomationSummary).
  • cli.dev-boot-contract (2 → 3).
    • steps[4], [6] and [7] write into the app directory they run in, so they need an unshared one.
    • Exit codes: SIGINT ends plain dev with the child's code (0). --fresh SIGINT exits 130 (dev.ts, ServeRestartCoordinator).
    • The 🔑 Dev admin banner reprints on later boots and is not seeding evidence (maybeReportExistingSeedAdmin).
  • integration-system.datasource-credential-refusal-matrix (1 → 2).
    • The wizard cannot plant a legacy alias row. Measured: POST /api/v1/datasources with passwd answered 400 DATASOURCE_ADMIN_ERROR.
    • The admin door updates by PATCH. Measured: PUT answered 405.
    • The admin door carries hasSecret / redactedConfigKeys.
    • The metadata path is GET /api/v1/meta/datasource/NAME. Measured: 200.
    • source gains the mongo composed-branch twin and the nested-options spelling entry.
  • platform-core.console-login (3 → 4).
    • The expiry clause verifies after the server-side sign-out its own step prescribes.
    • /_console/home renders the header and the launcher, with no sidebar by design (objectui HomeLayout).
  • platform-core.builtin-apps-nav-render (3 → 4).
    • Re-measured on a stock dev boot: Setup 45 and Account 8 destinations for the admin, and Account 8 for the member. The control reads 8 vs 8; the eighth entry is nav_connect_agent.
    • The member is the seeded Mei (demo-personas.ts).
    • The marketplace catalog's cloud egress dependency is recorded as a known gap.
  • records-forms.crud-roundtrip (7 → 8).
    • The readonly-column half of the clone clause is unobservable on the stock seed. No readonly column on showcase_account, no approval_status anywhere, and lead_score is null on every seeded contact.
    • An own-row invoice pointing at the run's account turns the later delete into 409 DELETE_RESTRICTED. Cause: a required lookup turns set_null into restrict (engine.ts).
  • approvals.account-app-entry (1 → 2).
  • studio-authoring.first-run-loop (2 → 3). Each point below was grounded in objectui at the pin:
    • The object is repairs_repair_ticket, because the dialog prefixes the package namespace (prefixObjectName).
    • The New object dialog carries a pre-selected OWD choice.
    • The "zero nav items" known gap is superseded: the scaffold checkbox defaults on.
    • steps[8] is a forged request, because authoring is hidden on read-only packages.
    • acceptance[0]'s cited objectui F1 targets the testids package-id-input / package-name-input, which no source file declares at the pin.
  • RUNNER.md Environment facts.
    • The CRUD tail now reads 15 verified, 0 gaps, 0 FAILED, 1 needs-fixture, 8 skipped.
    • verify --rls probes 10 of 10 positions, and the all-personas line is unchanged.
    • Both were re-measured with objectstack verify --rls on this branch.

3. The two pins

  • showcase-anonymous-deny-surfaces.dogfood.test.ts.
  • showcase-smoke.spec.ts + playwright.config.ts.
    • SURFACES grows from 31 to all 49 destinations showcase_app serves. The 18 added ones are derived from src/ui/apps/index.ts, including the three filter slices spelled the way objectui's nav renderer builds them. Revenue Pulse and the Hours by Status chart report are chart surfaces.
    • The main-content wait now treats the boot splash ("Initializing application…") as not rendered, and the assertion refuses a surface still on it.
    • The config reads SMOKE_API_URL for baseURL and the booted server's -p. global-setup.ts already signs in against that URL. It also reads OS_TEST_CHROMIUM_EXECUTABLE_PATH for the browser. Unset, everything stays on port 3000 exactly as before (CI sets neither).

Tests (union re-run on de73aa8444, after merging origin/main)

  • pnpm check:platform-checklist. Before, on the base 6f578888a8: exit 1, with one problem, the pre-existing identity-auth #twoFactor row. After, on de73aa8444: exit 0, 15 areas, 269 items. node scripts/check-platform-checklist.mjs --self-test: exit 0 (221 assertions).
  • Dogfood pin: pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/showcase-anonymous-deny-surfaces.dogfood.test.ts. Result: 48 passed (48), on a rebuilt closure.
  • Ablation of the dogfood pin, run against the committed pin through scripts/ablation-replace.mjs. Each mutation was proven on disk, and each restore was proven by blob == HEAD:
    • Unrouting the explain probe turned exactly its 3 cases red (expected 404 to be 401, expected 404 not to be 404).
    • The same mutation on the batch probe also turned 3 red.
  • Smoke: SMOKE_API_URL=http://localhost:43871 OS_TEST_CHROMIUM_EXECUTABLE_PATH=/opt/pw-browsers/chromium pnpm exec playwright test e2e/showcase-smoke.spec.ts, against a console built at the pin (e420df310f5b). Result: 49 passed (2.6m). The server booted on 43871 and was down afterwards.
  • An instrumented run (one-off and restored) logged 29 of the 49 surfaces on the boot splash first. The old non-chart check would have passed all 29 on the splash.
  • pnpm --filter @objectstack/dogfood typecheck and pnpm --filter @objectstack/example-showcase typecheck: exit 0. Both programs include the edited files.
  • node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 55 families, all run. 54 exit 0. NOT MEASURED: check:dual-build-cjs-loads, reason "PREREQUISITE NOT MET": 8 untouched packages have no dist/ in this container. check:type-check-debt exit 0 on a clean standalone re-run; an earlier run's log was clobbered by a timed-out batch.

Card findings NOT acted on, and why

  • owd-sharing-matrix step 1 / crud persona recipe ("grant the position, not the set directly"). The reason is withheld pending the maintainer (RUNNER rule 2, [showcase][security] An owner-isolation policy in the showcase's contributor permission set does not hold for every way a member can hold the set — detail withheld pending maintainer #21052). It cannot be grounded publicly, so it is left untouched.
  • Personas, "all member-persona items". I updated the shared recipe and the P0 items this run drove. About 28 more active items mention sign-up personas, and several sit in identity-auth.json (open-PR concurrency). That sweep is left for the PM: an open question, a RUNNER fact versus a per-item sweep.
    • Patch round (db092de284): the residual items are now covered by one RUNNER "Environment facts" bullet. It states the stock invite_only posture, the 403 SELF_REGISTRATION_CLOSED refusal, and the two doors (invite-member then sign-up, or admin create-user then change-password), with search:qa-contributor-bound-member as the worked example. This follows the seat's ACCEPT on the open question, option A.
  • records-forms.crud-roundtrip "list quick-search text persists across reloads". I could not confirm this from objectui source at the pin, so it is not written as fact.
  • §3 fixture gaps and environment. These are recorded on the card. The card says no edit is needed unless chosen, and they lie outside the claimed RUNNER lines.

Acceptance notes

  • Two RUNNER lines outside the named "Environment facts" lines changed as a direct consequence of the smoke change. The Playwright fact's test count went from 31 to 49, and it now names the browser override.
  • The datasource-credential-redaction.ts docblock still says the wizard persists through a structural name/label check. A live probe refuses an alias key 400, so this is comment drift; no carrier found.
  • The URL-branch mongo entry's "Deliberately NOT refused … the composed branch" sentence reads as if the platform did not refuse that branch. Its twin does, since Composed-branch twin of #9041: external.credentialsRef bound + discrete mongo fields naming no username is the same silent no-op, unrefused #9147. This is spec registry text, outside this ledger.

Line budget

15 files changed: +375 / −130 against origin/main. Breakdown:

  • 12 checklist JSON/MD files
  • the dogfood pin (+54)
  • the smoke spec (+56) and config (+33)

Generated by Claude Code

claude added 15 commits October 1, 2026 05:32
…fusal answers

acceptance[5] expected 400 INVALID_FILTER on the POST query door for a
scalar list comparand; since the request schema took that refusal, the
POST door answers 400 VALIDATION_FAILED with a located fields[] entry in
both spellings, and only GET $filter still answers INVALID_FILTER. Also
records that a dotted fields entry is refused INVALID_FIELD by design
(prescribing expand), and moves the widening negative off `filter`, which
is a declared transport spelling of `where`.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
…/explain

The checklist item this file pins names six surface families; the batch
and security-explain families were checked only by hand. Both are REST
routes opening with enforceAuth, so they join the rest-flat rows of the
envelope classification, with a member contrast that proves each route
is registered.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
crud-permission-matrix: counts re-measured from access-matrix.json (47
rows; the pin's 164 cells, 87 allow / 77 deny), client_liaison added to
the variants, the sys_user 405 cells named, the guest intake clause
recorded unobservable on stock, and the delegate pin no longer read as
vouching for the dev boot. write-path-guards: updateMany drops a locked
field per row, reported on results[i]. rls-both-sides and
owd-sharing-matrix: the private D11 handle is disambiguated from
FOLLOW-UPS section 7c's public D11 row, and clause numbering is stated.
anonymous-deny-surfaces: automated.ref names the six families the pin
now drives. The qa-contributor-bound-member recipe and the P0 member
items mint personas invite-first under the invite_only default.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
…the boot splash

The smoke listed 31 of the 49 destinations showcase_app serves; the 18
others are added. Its non-chart check passed on the console's boot
splash, whose text is non-empty; the wait now treats the splash as
not-yet-rendered and the assertion refuses a surface stuck on it. The
config read a hard-coded :3000: SMOKE_API_URL, which global-setup
already signs in against, now also drives baseURL and the booted
server's port, and OS_TEST_CHROMIUM_EXECUTABLE_PATH lets a container
point Playwright at its installed chromium.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
Revenue Pulse draws line/column/donut/bar widgets and the Hours by Status
chart report draws a bar chart, so both take the laid-out-chart check the
other three chart surfaces take.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
… pin and verify digits

nav-surfaces-render names the 49 destinations the smoke now drives, the
boot-splash rule, and the SMOKE_API_URL / OS_TEST_CHROMIUM_EXECUTABLE_PATH
overrides. RUNNER's environment facts carry the re-measured verify
digits (15 verified, 1 needs-fixture, 8 skipped; 10 of 10 positions)
and the smoke's new test count and browser override.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
…what a stock boot prints

At the default warn level a healthy boot prints no SeedLoader success
line, so both seed reads now name the level-immune Seeds banner row.
boot-health's no-warning clause names the misauthored flow classes,
since a stock boot lists its policy-disabled scheduled flows with a
warning glyph. packaged-action-disabled-dispatch records that the MCP
endpoint is drivable live on a stock boot.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
…wire and the host command

No showcase persona carries both RLS-hidden rows and an FLS-masked field
on one object, so the item names a contributor-bound member for RLS and
a client_liaison-bound member for FLS. The aggregate refusal is scored
on its message, since neither wire serializes forbiddenFields. Step 1
hosts the transport with os start: measured on a stock boot, os dev
prints a 15-line banner to the stdout the stdio channel owns, os start
prints none.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
…t codes and the banner caveat

Three steps write into the app directory they run in, so they need one
no other runner boots. The exit-code capture now states what to expect
(SIGINT 0, --fresh SIGINT 130, no config 1), and the Dev admin banner
row is no longer readable as seeding evidence, since it reprints on
later boots while the default password still works.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
…ock boot serves

The wizard refuses an alias-spelled credential 400, so planting a legacy
row needs a stopped-server metadata write; the admin door updates by
PATCH (PUT answers 405) and is the one carrying hasSecret and
redactedConfigKeys; the metadata read path is spelled out; and the two
refusal entries the source list missed are added.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
…k boot renders

console-login: the expiry clause verifies after the server-side sign-out
its own step prescribes, and the landing page is the header plus
launcher without a sidebar by design. builtin-apps-nav-render: Setup 45
and Account 8 destinations re-measured on a stock dev boot, the member
persona is the seeded plain persona (a fresh sign-up is refused), and
the marketplace catalog's cloud egress dependency is a known gap.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
…he restricted delete

No showcase object gives the clone clause a populated readonly column,
so that half is recorded unobservable with the system-side way to make
it observable. An own-row invoice pointing at the run's account turns
the later delete into a 409, so the recipe and the delete step say to
point it at a seeded account.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
…b vocabularies and a readable row

The locale clause names the zh-CN option the showcase offers, the tab
clause lists both locales' labels, the record-link clause needs a row
the persona can read, and the fixture asks for a sign-off launched after
the persona holds its positions. The seeded personas are loginable; the
reason to provision one is their positions.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
The object is named with the package namespace prefix, the New object
dialog carries a pre-selected sharing-model choice, a new app's nav is
scaffolded by default, the read-only negative probe is a forged request
because the console hides authoring there, and the cited objectui pin
targets testids absent at the pin.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
@github-actions github-actions Bot added the size/l label Oct 1, 2026
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 1, 2026
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests labels Oct 1, 2026
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 99398542b328eb06be8dbd781200f06a5df608b0 → packageMentionDocs.

claude added 2 commits October 1, 2026 07:29
…rs that mint a member

A stock showcase declares no audience, so an uninvited sign-up answers
403 SELF_REGISTRATION_CLOSED and no item can mint a member by a fresh
sign-up. One Environment-facts bullet names the posture, the refusal
site, and the two doors (invite-member then sign-up, or admin
create-user then change-password), with the shared contributor-bound
recipe as the worked example.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
Resolves the two conflicts with the analytics anonymous-deny change by
keeping both sides: the dogfood pin carries the analytics faces and the
/batch + /security/explain cases; access-security.anonymous-deny-surfaces
keeps main's revision-2 analytics entry, takes revision 3 for this
branch's entry, and its automated.ref names all seven families.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAhu8u8QfBvRjVZDox7CP9
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 1, 2026 08:09
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 1, 2026 08:09
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit 670680e Oct 1, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants