Skip to content

Commit 47f6355

Browse files
docs(qa): park the 24 partial-coverage gaps of the 17.7 pre-release runs — 2 recipes, 9 pins, 6 re-pointed clauses, 7 recorded knownGaps (#22029)
Fixes #22017 Clause-②: no ## What this does The four 17.7 pre-release `qa-run` records (#21720, #21721, #21782, #21784) parked 24 partial-coverage gaps on #22017. Each row now ends in exactly one disposition on its checklist item: a fixture recipe, a pin, a re-pointed clause or a recorded knownGap. The work follows `checklist-author`'s item conventions. - 26 items across 12 area files are edited (rows 9 and 10 each cover two items). No row is dropped and no `not-run` leg is added. - Each edited item bumps `revision` by exactly one. Its new `history` entry cites its record and #22017 (`ref: "#22017"`). - Docs only: `docs/qa/platform-checklist/areas/*.json`. There is no product code, no new test and no `coverage.json` change. - Every `automated.ref` I added names a test that already exists. I read each one and checked its quoted test title verbatim, at framework `1fb274e61c`, or at objectui `0abd4f9f8769` (the `.objectui-sha` pin) for objectui pins. Each row's reason was re-checked against `main` and the current objectui pin, not copied from its record. Five premises turned out false or stale, and the table says which (rows 1, 4, 14, 21, 22). ## The 24 rows | # | item · leg (record) | disposition | evidence | rev | |---|---|---|---|---| | 1 | `identity-auth.phone-signin-surfaces` A2 / A3 (#21782) | fixture recipe: boot switch | The premise "no runtime setting" holds for Settings, but the plugin has a documented boot switch, `OS_AUTH_PHONE_NUMBER_ENABLED=true`. `packages/cli/src/commands/serve.ts` maps it to the injected AuthPlugin's `plugins.phoneNumber`, `os dev` forwards env to its serve child, and `features.phoneNumber` mirrors it (`auth-manager.ts` getPublicConfig). Run #21784 used it on `os dev`. | 2 → 3 | | 2 | `records-forms.crud-roundtrip` A7 readonly half (#21782) | pin | `metadata-protocol/src/protocol.readonly-insert.test.ts` ("cloneData forwards the copied row AND the caller overrides whole …") pins the delegation. `objectql/src/engine-insert-static-readonly-strip.test.ts` pins the real-engine strip and the defaultValue fallback. | 8 → 9 | | 3 | `records-forms.import-wizard-encoding-and-hints` A3 (#21782) | pin (pin-only by design) | The objectui `importLegacyReferenceGuard.test.tsx` is present at `0abd4f9f8769`. No live server reaches the legacy path: the console's ObjectStackAdapter always has `importRecords`. | 4 → 5 | | 4 | `records-forms.gantt-interactions` A2 / A3 (#21782) | pin | Premise false: `lockField`, `dependenciesField` and `parentField` are all `GanttConfigSchema` keys (`packages/spec/src/ui/view.zod.ts`, also at the run's subject `316be321`), so no clause needed a re-point. The objectui pins are named per clause: `GanttView.autoscheduledlg`, `countinterp.i18n`, `scheduling.selfextent` and `GanttView.dnd`. One residual sub-leg, a direct drag on a locked leaf, is recorded blocked(fixture). | 2 → 3 | | 5 | `search.command-palette-navigation` A5 (#21782) | fixture recipe | The smallest fixture is a scratch-copy showcase nav with two leaves, `visible: 'false'` and `visible: 'true'`. It is authored from source and not yet run-proven. The clause named `visibleOn`, which a nav item refuses as a near-miss (`app.zod.ts` NAV_ITEM_ALIASES), so it now names `visible` only. | 1 → 2 | | 6 | `records-forms.grid-personalization` A1 reorder / pin (#21782) | re-pointed clause | `reorderableColumns` is an `ObjectGridPropsSchema` prop (`component.zod.ts`) that ObjectGrid defaults false, never a ListView key. Pin is the author-declared `ListColumnSchema.pinned`. The persisted columnState holds widths and order only. | 2 → 3 | | 7 | `records-forms.action-location-matrix` A3 url / api (#21782) | recorded knownGap + card owed | Revision 7 (#21797) already scores the legs blocked(fixture) with record_more. The fix is an `examples/app-showcase` change that no card carries (#21797 breach B-1, unfiled). It is reported below for the seat to file. | 7 → 8 | | 8 | `i18n.surface-matrix` A6 confirm half (#21782) | pin | No showcase action declares a `confirmText` at all. The objectui pins `page-header-action-i18n.test.tsx` and `record-quick-actions.actionText-i18n.test.tsx` resolve the confirm body from `_actions` zh-CN through the real ActionRunner. | 5 → 6 | | 9a | `platform-core.keyboard-shortcut-surface` A5 (#21782) | recorded knownGap (environment) | ⌘⇧O / ⌘⇧S live on the AI chat page, which exists only where an agent catalog serves an agent (Cloud/Enterprise `service-ai`). CI has no such deployment. The verdict is reclassified blocked(environment). | 1 → 2 | | 9b | `ai.console-ai-surface-gating` A2 entitled side (#21782) | recorded knownGap (environment) | Same environment, and CI lacks it. The objectui hook pins are named as mechanism-only. | 2 → 3 | | 10a | `platform-core.builtin-apps-nav-render` catalog (#21782) | recorded knownGap (environment) | The leg needs a boot that reaches `DEFAULT_CLOUD_URL` (`packages/cloud-connection/src/cloud-url.ts`) or a reachable `OS_CLOUD_URL`. No CI job drives it. | 4 → 5 | | 10b | `platform-core.marketplace-console-honesty` boot A catalog (#21782) | recorded knownGap (environment) | Same environment as 10a. | 2 → 3 | | 11 | `access-security.rls-both-sides` A6 (#21720) | recorded knownGap | The D11 spot-check needs the maintainer's private write-up and its private remediation card (#7463 ruling), which no public record or CI carries. The skipped-object half stays scoreable. The text is non-disclosing. | 5 → 6 | | 12 | `access-security.write-path-guards` N2 (#21720) | pin | `objectql/src/engine-insert-static-readonly-strip.test.ts` ("isSystem seeds the readonly column …") covers INSERT, and `engine-readonly-strip-caller-values.test.ts` ("an isSystem caller is untouched by any of this") covers UPDATE. Both use a real engine. | 3 → 4 | | 13 | `api-backend.declarative-endpoint-execution` A3 (#21720) | re-pointed clause | No public door serves a script / proxy endpoint. `api` is code-only (#5488, `allowRuntimeCreate` false), and the stack schema refuses both types (`endpoint-publish-gate.ts` validateApiEndpointDeclarations). A3 now asserts the authoring refusal (oracle build). The runtime 501 is pinned by `endpoint-executor.test.ts` and `apis-publish-gates.test.ts` gate (a). | 1 → 2 | | 14 | `records-forms.predicate-relationship-traversal` A4 (#21720) | re-pointed clause | The knownGap was false: `showcase_member_default` grants `showcase_account` read to every member (`examples/app-showcase/src/security/permission-sets.ts`), and grants are additive, so the persona cannot exist on stock. A4 is scored from `objectql/src/engine-predicate-relationship.test.ts` (related read under SYSTEM authority; accept / refuse on the real write path), or live on the scratch-object substitute #21720 measured. | 1 → 2 | | 15 | `identity-auth.admin-lifecycle-operations` A4–A6 (#21784) | re-pointed clause | set-role is ruled (#9968, ruled B); revoke-user-sessions and remove-user are ruled (#9969, not_planned). A4–A6 now assert the ruled 403s with their vendor codes and a no-effect read, pinned by `admin-platform-admin-standing.dogfood.test.ts`. The cascade exemption is scored from plugin-security's "[#3023]" test. Step 2 (list-users) follows the same ruling. | 6 → 7 | | 16 | `studio-authoring.expression-editors` A8 (#21784) | pin (environment named) | The objectui `celAuthoring.test.ts` "graceful degradation" is present at `0abd4f9f8769`. The leg is pin-only by clause design. The knownGap names the environment, an objectui checkout at the pin. | 2 → 3 | | 17 | `studio-authoring.metadata-diagnostics-sweep` A7 (#21784) | recorded knownGap (environment) | The leg needs a store already holding a stale row. A stock environment never holds one, by design, and no CI job builds one. The producer pin (`metadata-diagnostics.union-issues.test.ts`) is named as mechanism-only. | 1 → 2 | | 18 | `integration-system.datasource-credential-refusal-matrix` A2 / A7 (#21784) | recorded knownGap (already, #21932 rev 3) | This was already parked today by #21932. This PR adds whether CI has the database: postgres and mysql exist only in the Temporal Conformance job, which runs no checklist item, and there is no mongo. It also adds the record citation. | 3 → 4 | | 19 | `approvals.decision-action-matrix` A10 (#21784) | pin | `plugin-approvals/src/approval-service.test.ts` describe "org-filtered read-back refuses loudly (#12769)". The api-trigger candidate is refuted, since the run found it org-stamped. The wire-envelope half stays unobserved on stock. | 3 → 4 | | 20 | `identity-auth.auth-method-matrix` A1 SSO / device + N3 (#21784) | recorded knownGap | `serve.ts` injects AuthPlugin with four env-mapped plugins and no `deviceAuthorization` or `oidcProviders`. SSO has the `OS_SSO_ENABLED` switch but needs a registered provider behind a reachable IdP. N3's dependency, objectui#4179, closed not_planned on 2026-09-24. | 5 → 6 | | 21 | `integration-system.external-schema-browser-ui` A7 (#21784) | re-pointed clause | Stale expected-fail. At objectui `0abd4f9f8769`, objectui#11628 (PR #11640) maps the server's `SERVICE_UNAVAILABLE` 503 envelope to `ExternalServiceUnavailableError`, pinned by `api.test.ts`. The run's console `2e818d0b51ec` predates the fix. A7 is now a positive assertion scored from the pin; the live render still needs an unwired boot. | 1 → 2 | | 22 | `records-forms.encrypted-field-behavior` A4 (#21784) | pin (pin-only of necessity) | `objectql/src/secret-fields.test.ts` ("fail-closed: writing a secret field with no CryptoProvider throws"). The knownGap's "production boot without OS_SECRET_KEY" path was wrong: that boot refuses to start (`serve.ts` rethrows). | 1 → 2 | | 23 | `cli.flag-command-error-ux` A4 (#21721) | re-pointed clause | 33 variants: 20 command files and 12 topic directories in `packages/cli/src/commands`, plus generate's `static aliases = ['g']`. `secret`, `storage` and `g` are added, and A4's count is now derived per run. | 2 → 3 | | 24 | `cli.datasource-introspect-codegen` A1 narrowing half (#21721) | pin | `rest/src/remote-tables-twin.equivalence.test.ts` covers `?schema=` narrowing and the empty set on the federation route the CLI calls. `external-datasource-service.test.ts` adds "filters by requested schema", and `envelope-unwrap.test.ts` adds the "no remote tables" print. SQLite tables carry no schema, so `listRemoteTables` never filters them. | 3 → 4 | Tally: 2 fixture recipes · 9 pins · 6 re-pointed clauses · 7 recorded knownGaps (counted by row; rows 9 and 10 cover two items each). ## For the seat (not filed here) - **Card owed (row 7):** "showcase: host record_header / record_more / record_related surfaces for showcase_task". It needs a showcase_task page that composes a record header, and a parent record page that renders the synthesized Tasks related list. Evidence: `examples/app-showcase/src/ui/pages/task-detail.page.ts` is `kind: 'full'` with no record header node, and `project-detail.page.ts` replaces the related strip with `record:line_items`. #21797 named it breach B-1 and left it unfiled. `records-forms.action-location-matrix` A1's three variants and A3's url / api legs park on it. ## Acceptance notes - **Two recipes are not run-proven.** Row 1's boot switch was booted by run #21784 for another item. Row 5's scratch-copy nav is authored from source only. Both items say so, and neither claims coverage. - **Residuals named inside a disposition:** - row 4: a direct drag on a locked leaf; - row 19: the wire envelope; - row 21: the live render on an unwired boot; - row 24: the CLI's `--schema` to `?schema=` forwarding. Each is written into its item as blocked or unpinned, never as a pass. - **Not fixed here (same items, outside the 24 rows):** - `external-schema-browser-ui` requires text still says "5 columns each"; the runs measured `columnCount` 7. #21797 listed it as unparked. - RUNNER.md's standing fact counts "23 items" whose `automated.ref` is objectui-only; the ledger has 28 at base, and this PR adds two more (rows 8 and 21), for 30. Carrier for both: none. - **Framework pins were read, not run locally.** They live in packages this PR does not touch and run in CI's required suites on `main`. objectui pins were checked at the pinned revision by `git show`. ## Verification Gate list derived by `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths, merge-base) at head `25b451177`: 13 commands, all `exit 0`, and `--ran` reconciled "13 derived, 13 run, 0 NOT-MEASURED (a DERIVED zero)". - `check:platform-checklist`: OK — 276 items. Symbol anchors are 709/719 resolved (base 697/707, +12, all resolving), and 0 line citations survive. - `check:doc-formula-expressions` first exited 3 (prerequisite not met: lint/formula not built). That run was NOT MEASURED. After `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint`, it exited 0. - The other 11: `check-ci-filter-parity`, `check-closing-keyword-parity` (and `--self-test`), `check-comment-mask-corpus`, `cross-package-test-inputs`, `doc-authoring`, `driver-memory-census`, `gitlink-declared`, `nul-bytes`, `refd-timer-probe` and `watch-hint-literal` all exited 0. - A semantic diff against base: exactly the 26 intended items changed, each by revision +1 with one appended history entry citing its record. No other item and no top-level key moved. Changeset: none. `docs/qa/**` ships in no package's `files[]`, so this is `skip-changeset`. --- _Generated by [Claude Code](https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 289ff6d commit 47f6355

12 files changed

Lines changed: 271 additions & 115 deletions

‎docs/qa/platform-checklist/areas/access-security.json‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"title": "Row-level security: restricted member sees only their rows; admin sees all",
1010
"since": "v15",
1111
"status": "active",
12-
"revision": 5,
12+
"revision": 6,
1313
"priority": "P0",
1414
"surface": "api",
1515
"personas": [
@@ -21,6 +21,9 @@
2121
"requires": [
2222
"showcase_private_note (OWD private, member_default grants create/read/edit)",
2323
"two fresh sign-ups, e.g. rls-a@verify.test / rls-b@verify.test"
24+
],
25+
"knownGaps": [
26+
"acceptance[5]'s D11 spot-check can be scored only by a runner holding the PRIVATE D11 write-up and its private fix card (maintainer-held, #7463 ruling). The environment this leg needs is that maintainer channel; no public run record, CI job or checkout carries it, by design. Without it, score the D11 spot-check blocked(dependency) (QA run #21720, parked on #22017 row 11), and still score the clause's other half, every skipped object in the verify report explained by its detail line, which needs nothing private. Never restate the defect to justify the verdict"
2427
]
2528
},
2629
"steps": [
@@ -115,6 +118,12 @@
115118
"date": "2026-10-01",
116119
"change": "checklist-accuracy findings of QA run #21056. The private handle D11 collided with the public D11 row FOLLOW-UPS.md §7c later assigned to an unrelated two-factor defect; clause 5 and the naming-collision negative now say so (FOLLOW-UPS §7c carries the same note), still non-disclosing. Numbering, for every cross-reference here and in this item's history: \"clause N\" counts from 0 (acceptance[N]); run records number clauses from 1, so clause 5 here is a run record's A6. steps[0] mints A and B invite-first under the invite_only default",
117120
"ref": "#21060"
121+
},
122+
{
123+
"revision": 6,
124+
"date": "2026-10-06",
125+
"change": "partial-coverage gap of QA run #21720 parked on #22017 (row 11). A6 was blocked(dependency): the clause forbids ticking it without the private D11 write-up. Disposition: recorded knownGap. The item gains a knownGap naming the environment the D11 spot-check needs (the maintainer's private write-up and fix card, which no public record or CI carries by design) and separating the skipped-object half, which a public run can still score. Non-disclosing, as the clause requires",
126+
"ref": "#22017"
118127
}
119128
]
120129
},
@@ -123,7 +132,7 @@
123132
"title": "Write-path guards: readonly strip, owner_id forge/transfer denied, bulk validation",
124133
"since": "v16",
125134
"status": "active",
126-
"revision": 3,
135+
"revision": 4,
127136
"priority": "P0",
128137
"surface": "api",
129138
"personas": [
@@ -193,11 +202,11 @@
193202
],
194203
"negative": [
195204
"run the forge/transfer clauses as ADMIN too and confirm they SUCCEED where legitimately privileged — the guard must gate on privilege, not break the admin path (wrong-persona trap, both sides)",
196-
"isSystem writes must still set readonly fields (A1's isSystem carve-out): verify via an objectql write with context {isSystem:true} that lead_score IS settable system-side"
205+
"isSystem writes must still set readonly fields (A1's isSystem carve-out): verify via an objectql write with context {isSystem:true} that lead_score IS settable system-side. No REST door reaches an in-process isSystem write, by design, so score this from the two objectql pins `automated` names for it (the exemption is one engine function, gated on isSystem, for every object)"
197206
],
198207
"automated": {
199208
"kind": "dogfood",
200-
"ref": "packages/qa/dogfood/test/owner-anchor-and-bulk-writes.dogfood.test.ts (+ showcase-static-readonly.dogfood.test.ts, showcase-readonly-when-parent.dogfood.test.ts)"
209+
"ref": "packages/qa/dogfood/test/owner-anchor-and-bulk-writes.dogfood.test.ts (+ showcase-static-readonly.dogfood.test.ts, showcase-readonly-when-parent.dogfood.test.ts); negative[1] (the isSystem exemption, which no REST door reaches by design) by packages/objectql/src/engine-insert-static-readonly-strip.test.ts ('isSystem seeds the readonly column — the exemption the ruling names', the INSERT path) + packages/objectql/src/engine-readonly-strip-caller-values.test.ts ('an isSystem caller is untouched by any of this', the UPDATE path on a static readonly column), both on a real engine"
201210
},
202211
"traps": [
203212
"wrong-persona"
@@ -228,6 +237,12 @@
228237
"date": "2026-10-01",
229238
"change": "checklist-accuracy findings of QA run #21056. acceptance[5] said a bulk update touching a locked row drops the field for the batch; updateMany runs engine.update per row with its own drop listener (metadata-protocol updateManyData), so only the locked row loses the field and the report is per row, results[i].droppedFields. steps[0] mints the members invite-first under the invite_only default",
230239
"ref": "#21060"
240+
},
241+
{
242+
"revision": 4,
243+
"date": "2026-10-06",
244+
"change": "partial-coverage gap of QA run #21720 parked on #22017 (row 12). N2 was not runnable: there is no REST door for an in-process isSystem write, and no pin targeted it. Disposition: pin. engine-insert-static-readonly-strip.test.ts and engine-readonly-strip-caller-values.test.ts already prove the isSystem exemption on a real engine, on INSERT and UPDATE. `automated` names them for negative[1], and the negative says to score it from them",
245+
"ref": "#22017"
231246
}
232247
]
233248
},

‎docs/qa/platform-checklist/areas/ai.json‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@
596596
"title": "Console AI affordances gate on the access-filtered agent catalog: an agent-less boot hides FAB / chat dock / ⌘⇧I / top-bar link and redirects a stale /ai bookmark without flash — with the ungated bare system/ai-approvals route pinned as an expected-fail probe",
597597
"since": "v16",
598598
"status": "active",
599-
"revision": 2,
599+
"revision": 3,
600600
"priority": "P2",
601601
"surface": "browser",
602602
"personas": ["admin (form sign-in — the pending-actions poll sends the COOKIE half only, credentials:'include' with no bearer header, so an injected-token session reads as anonymous there)"],
@@ -608,7 +608,7 @@
608608
"a REAL form sign-in (not an injected localStorage token): the AI Approvals page's poll authenticates by cookie only (usePendingActions call() sends credentials:'include' and no Authorization header), so without the cookie half the poll answers 401 AUTH_REQUIRED instead of the 501 this item pins (RUNNER.md console-session fact)"
609609
],
610610
"knownGaps": [
611-
"the ENTITLED side of the gate (catalog >= 1 agent ⇒ FAB/dock/link/route all appear) has NO open-framework fixture: service-ai is Cloud/EE and no stock agent-serving harness exists. The only lever is the VITE_AI_BASE_URL opt-in pointing the catalog fetch at an external AI server (useAiSurface.ts resolveAiApiBase), which needs a console REBUILD plus such a server — score those clauses blocked(fixture), never inferred from the hook's source",
611+
"the ENTITLED side of the gate (catalog >= 1 agent ⇒ FAB/dock/link/route all appear) has NO open-framework fixture: service-ai is Cloud/EE and no stock agent-serving harness exists. The only lever is the VITE_AI_BASE_URL opt-in pointing the catalog fetch at an external AI server (useAiSurface.ts resolveAiApiBase), which needs a console REBUILD plus such a server — score those clauses blocked(environment), never inferred from the hook's source. The environment this side needs is a deployment whose agent catalog serves at least one agent to the admin: the Cloud/Enterprise @objectstack/service-ai, or the VITE_AI_BASE_URL rebuild above. Neither exists in the open framework, by design, and CI has neither (QA run #21782, parked on #22017 row 9). objectui unit-pins the signal's mechanism (packages/app-shell/src/hooks/__tests__/useAiSurface.test.ts, 'is enabled when the catalog serves at least one agent'; packages/app-shell/src/console/__tests__/RequireAiSurface.test.tsx, 'renders the AI surface when the server serves agents'). Those pin the hook, not the affordance sweep, so they do not score the entitled side",
612612
"the PER-SEAT half of the signal (ai_seat holder sees agents, seat-less user gets an empty catalog on the SAME deployment — ADR-0068, the objectui#1992 revert) is equally cloud-only: on an open boot the catalog is empty for every principal, so per-seat differentiation is unobservable here",
613613
"the /_console bundle is vendored and may be stale — verify affordance absence against current objectui app-shell or a fresh build before scoring (stale-console-bundle)"
614614
]
@@ -632,7 +632,7 @@
632632
"evidence": "the catalog request/response trace"
633633
},
634634
{
635-
"clause": "every gated affordance is ABSENT on the empty catalog: no FAB, no chat dock (⌘⇧I inert — the listener is not armed), no top-bar AI entry, no Home AI CTAs — hidden-during-load is the designed flash-free behavior, so a settled screenshot precedes every DOM read. The ENTITLED side (>= 1 agent ⇒ all of them appear) is blocked(fixture) on the open framework — record it blocked, never ticked from the hook's source",
635+
"clause": "every gated affordance is ABSENT on the empty catalog: no FAB, no chat dock (⌘⇧I inert — the listener is not armed), no top-bar AI entry, no Home AI CTAs — hidden-during-load is the designed flash-free behavior, so a settled screenshot precedes every DOM read. The ENTITLED side (>= 1 agent ⇒ all of them appear) is blocked(environment) on the open framework (fixtures.knownGaps names the environment) — record it blocked, never ticked from the hook's source",
636636
"oracle": "screenshot",
637637
"verify": "settled screenshots of shell chrome + Home show none of the affordances; post-screenshot DOM reads confirm; ⌘⇧I produces no mount (ConsoleLayout.tsx gates the listener on dockEnabled = the same signal)",
638638
"evidence": "the region screenshots + the ⌘⇧I non-event"
@@ -681,7 +681,8 @@
681681
],
682682
"history": [
683683
{ "revision": 1, "date": "2026-08-30", "change": "new item (sweep 2026-08-30, cross-angle hit 1+4): the console-side AI gating had no coverage — the catalog-signal design (useAiSurfaceEnabled) hides FAB/dock/⌘⇧I/header/Home affordances and no-flash-redirects /ai on an agent-less boot, while SystemHubPage's 'AI Approvals' card is built ungated and its page polls the dead /ai/pending-actions endpoint every 5s (501) rendering a fake empty queue beside the error alert. Authored as a NEW browser sibling of ai.open-edition-honest-degradation (which keeps the API half) rather than extending it, so neither surface double-covers the other; the two K2 defect clauses are expected-fail probes, the defect row itself is the sweep's FOLLOW-UPS entry", "ref": "#sweep-2026-08-30" },
684-
{ "revision": 2, "date": "2026-10-05", "change": "clause 4, steps 6-7, negative 3, the title and the source re-pointed (stale, #21782 VF4). objectui 9eea12a2b (objectui#10507, fixing objectui#3743) removed SystemHubPage and its 'AI Approvals' card before 17.6.0, so K2's card half is moot. The clause now asserts that no console surface advertises the entry (verifier's wording). The route half of K2 remains: system/ai-approvals is still registered ungated (AppContent systemRoutes), so steps 6-7 reach it by URL and clause 6 keeps its expected-fail scoring. Negative 3 names clause 6 only. Re-read at objectui 9dfaca6543: unchanged", "ref": "#21797" }
684+
{ "revision": 2, "date": "2026-10-05", "change": "clause 4, steps 6-7, negative 3, the title and the source re-pointed (stale, #21782 VF4). objectui 9eea12a2b (objectui#10507, fixing objectui#3743) removed SystemHubPage and its 'AI Approvals' card before 17.6.0, so K2's card half is moot. The clause now asserts that no console surface advertises the entry (verifier's wording). The route half of K2 remains: system/ai-approvals is still registered ungated (AppContent systemRoutes), so steps 6-7 reach it by URL and clause 6 keeps its expected-fail scoring. Negative 3 names clause 6 only. Re-read at objectui 9dfaca6543: unchanged", "ref": "#21797" },
685+
{ "revision": 3, "date": "2026-10-06", "change": "partial-coverage gap of QA run #21782 parked on #22017 (row 9). A2's entitled side was blocked(fixture) as the clause prescribed. Disposition: recorded knownGap. The side cannot be reached in the open framework by design (service-ai is Cloud/Enterprise). The knownGap names the environment it needs, says CI lacks it, and reclassifies the verdict blocked(environment); A2's clause follows. It also names the objectui hook pins as mechanism-only", "ref": "#22017" }
685686
]
686687
},
687688
{

‎docs/qa/platform-checklist/areas/api-backend.json‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,7 @@
873873
"title": "Metadata-authored `api` endpoints mount as real URLs with their declared auth/cache policy",
874874
"since": "v17",
875875
"status": "active",
876-
"revision": 1,
876+
"revision": 2,
877877
"priority": "P1",
878878
"surface": "api",
879879
"personas": [
@@ -891,13 +891,13 @@
891891
"flow target — delegates to a flow",
892892
"policy: authRequired (default true)",
893893
"policy: cacheTtlSeconds → Cache-Control",
894-
"script/proxy target — answer 501 in the open framework"
894+
"script/proxy target — refused at authoring, never served; the runtime's 501 is a second door, pinned"
895895
],
896896
"steps": [
897897
"boot showcase isolated; sign in as admin",
898898
"GET /api/v1/apps/showcase/tasks authed; capture status, body, and response headers",
899899
"GET the same endpoint unauthenticated; capture status",
900-
"author a script-target endpoint shape in a scratch package and hit it; capture the 501",
900+
"a script / proxy target cannot be authored into a live server. `api` is code-only (#5488: allowRuntimeCreate false, so no scratch package can hold one), and the stack schema refuses `type: 'script'` / `'proxy'`. Author one in a scratch config and run `os validate` (or `os build`); capture the refusal naming the endpoint, the type and the flow prescription. Do not attempt a live 501",
901901
"GET /apps/showcase/nope (no matching declaration); capture the transport 404"
902902
],
903903
"acceptance": [
@@ -914,10 +914,10 @@
914914
"evidence": "the response"
915915
},
916916
{
917-
"clause": "a script/proxy target answers 501 in the open framework (declared ≠ delivered surfaces honestly, not a fake 200)",
918-
"oracle": "api",
919-
"verify": "the 501 envelope",
920-
"evidence": "the response"
917+
"clause": "a script / proxy target is never served (declared ≠ delivered, refused loudly, never a fake 200). Authoring refuses it: the stack schema's `apis:` gate (packages/spec/src/api/endpoint-publish-gate.ts#validateApiEndpointDeclarations) rejects `type: 'script'` and `'proxy'`, naming the endpoint and the fix, and runtime authoring of `api` is withdrawn (#5488). The runtime keeps its own refusal for a declaration that reaches the store some other way: 501 NOT_IMPLEMENTED with a hint (packages/runtime/src/endpoint-executor.ts#planEndpointTarget)",
918+
"oracle": "build",
919+
"verify": "the scratch-config `os validate` / `os build` refusal for a script and a proxy endpoint; the runtime half from the pins in `automated` (packages/runtime/src/endpoint-executor.test.ts, '%s answers 501 NOT_IMPLEMENTED with a hint'; packages/spec/src/api/apis-publish-gates.test.ts, gate (a))",
920+
"evidence": "the two refusals + the pin output"
921921
},
922922
{
923923
"clause": "an unmatched path under /apps/** falls through to the transport 404 — the notFound seam does not swallow it",
@@ -931,22 +931,29 @@
931931
],
932932
"automated": {
933933
"kind": "dogfood",
934-
"ref": "packages/qa/dogfood/test/showcase-declarative-endpoints.dogfood.test.ts + declarative-endpoint-policy.dogfood.test.ts"
934+
"ref": "packages/qa/dogfood/test/showcase-declarative-endpoints.dogfood.test.ts + declarative-endpoint-policy.dogfood.test.ts; acceptance[2] (script / proxy never served) by packages/runtime/src/endpoint-executor.test.ts ('an unsupported declaration gets a structured 501, never invented semantics') + packages/spec/src/api/apis-publish-gates.test.ts ('gate (a) — the supported subset')"
935935
},
936936
"traps": [
937937
"dispatcher-vs-hono-route"
938938
],
939939
"source": [
940940
"examples/app-showcase/src/system/apis/index.ts (the two live endpoints)",
941941
"ADR-0121 / #5040 (declarative endpoint E-series)",
942-
"packages/runtime notFound-fallback mount seam"
942+
"packages/runtime notFound-fallback mount seam",
943+
"packages/spec/src/api/endpoint-publish-gate.ts#validateApiEndpointDeclarations (the authoring refusal of script / proxy targets, run by the stack schema) + packages/spec/src/kernel/metadata-plugin.zod.ts (api is code-only: allowRuntimeCreate false, #5488) + packages/runtime/src/endpoint-executor.ts#planEndpointTarget (the runtime's 501 second door)"
943944
],
944945
"history": [
945946
{
946947
"revision": 1,
947948
"date": "2026-08-08",
948949
"change": "initial — the coverage.json `api` waiver was STALE (showcase authors two live endpoints with dogfood pins); un-waived",
949950
"ref": "claude/platform-test-checklist-ocwugl"
951+
},
952+
{
953+
"revision": 2,
954+
"date": "2026-10-06",
955+
"change": "partial-coverage gap of QA run #21720 parked on #22017 (row 13), re-pointed clause. A3 asserted a live 501 from a script / proxy endpoint authored in a scratch package, and the run found no way to author one without editing source. No public door produces one: api is code-only (#5488), and the stack schema refuses script / proxy targets (validateApiEndpointDeclarations, packages/spec/src/api/endpoint-publish-gate.ts). The runtime's 501 is a second door for a declaration that reaches the store another way, pinned by endpoint-executor.test.ts. A3 now asserts the authoring refusal (oracle build) and cites the pins; step 4, variant 5, `automated` and source follow",
956+
"ref": "#22017"
950957
}
951958
]
952959
},

0 commit comments

Comments
 (0)