Repository navigation
QA run · tier1:automated-pins (77 items) · e4e5c6e3 · 2026-08-17 · 35 PASS / 39 PARTIAL / 0 FAIL #9401
Description
Round R3-T1 of the #9296 wave — Tier-1 automated-pin sweep. Scope: the 77 active, non-blocked checklist items that carry an automated.ref, run per RUNNER rule 6 ("don't re-prove what automation pins"). Verdicts below are pinned-clause verdicts only — the unpinned clauses of these items are Tier-2's, and nothing here was hand-driven.
35 PASS · 39 PARTIAL · 0 FAIL · 3 BLOCKED. No clause failed as a product defect, and no access-control hole was found. The headline is the PARTIAL column: the pins are real and green, but on 39 of 77 items the pin reaches only a subset of the item's acceptance clauses. Every gap is named in the "Coverage gaps" section — that list is the round's most reusable output.
Environment fingerprint
| framework sha (subject) | e4e5c6e3c608b1b807c83a0d5b734f213eb1a1dd (detached, tree clean, subject not moved) |
| objectui pin | .objectui-sha = 665661ab093263f39f2e660a295ea615dbcee35a |
| objectui test tree | .cache/objectui-665661ab0932 — a full checkout at the pinned sha with node_modules already installed, so objectui unit pins ran against the pin rather than against the sibling checkout (which sits at 195b9e4ab, a different sha) |
| worktree | objectstack-qa-wave |
| checklist | 190 items (190 active); 30 kinds mapped, 0 waived — check-platform-checklist: OK, working-tree sync not committed |
| item set | resolved with checklist-select.mjs area:<a> --json x 15 joined to areas/*.json for the automated object; 77 pinned+active, matching the dispatch counts exactly (records-forms 24, access-security 8, attachments-storage 8, integration-system 6, studio-authoring 6) |
| node / runners | node 22.22.2, vitest 4.1.10, @playwright/test 1.62.1 with executablePath=/opt/pw-browsers/chromium-1194/chrome-linux/chrome |
| totals executed | 76 pinned test files, 953/954 assertions green; + 35 playwright smoke; + 18/29 objectui live e2e; + 2 objectstack verify invocations |
Pin inventory was checked before running: all 35 framework refs and all 25 objectui refs resolve to real files. Two refs name companion tests by bare name only — access-security.scope-depth-asymmetry (showcase-scope-depth-write, -fallback) and records-forms.import-wizard-encoding-and-hints (importMissingRequiredHint, importLegacyReferenceGuard, which actually live in plugin-grid/src/__tests__/*.tsx). Both resolve; noting them only because a bare name costs the next runner a search.
Batch commands and real output
1 — dogfood (33 pinned files, one invocation) · packages/qa/dogfood · npx vitest run test/<33 files>
Test Files 33 passed (33)·Tests 283 passed | 1 skipped (284)·Duration 169.90s
The single skip is attachments-permission-matrix > attachments cross-tenant isolation (g), gated by describe.skipIf(!organizationsAvailable). That probe resolves the cloud-private enterprise package @objectstack/organizations through the production resolver; it is absent in this OSS workspace, so the block skips by design and loudly (OS_TEST_MULTI_ORG_ENABLED=1 turns the skip into a hard failure for runs that ship the package). This is blocked(dependency), not a defect — but it does mean every cross-tenant attachment clause is unproven here.
2 — objectql · npx vitest run src/{engine,engine-lookup-referential-integrity,engine-autonumber-runtime-owned,secret-fields,overlay-precedence}.test.ts src/validation/rule-validator.option-visibility.test.ts
262 passed, 0 failed— engine 135/135 · autonumber 32/32 · secret-fields 36/36 · overlay-precedence 26/26 · lookup-RI 13/13 · option-visibility 20/20
3 — mcp / cli / services / connectors (5 invocations, sequential)
mcp
37 passed(plugin 17, skill-prompts 12, validate-expression 8) · cli11 passed(verify-tenancy-posture 7, format.exit-code 4) · service-automation31 passed(resume-authority-gate 22, connector-descriptor-audit 9) · connector-mcp13 passed· service-datasource54 passed(admin-routes 30, envelope.conformance 24)
4 — scope-depth companions · npx vitest run test/showcase-scope-depth-{write,fallback}.dogfood.test.ts
13 passed(write 9/9, fallback 4/4)
5 — objectui unit pins (25 files, one invocation, run in the pinned-sha cache)
249 passed, 0 failed, 25 files— celAuthoring 34 · CelPredicateField 24 · importParsers 30 · UndoManager 28 · bulkAction* 30 · gantt 22 · discardGuard 14 · RecordPicker/Lookup 18 · occSave 8 · calendar dnd 8 · grid personalization 10 · PermissionMatrixEditor 10 · others
6 — objectstack verify --rls · examples/app-showcase · node packages/cli/bin/run.js verify --rls
✓ verify passed — no runtime failures
CRUD:15 verified, 0 gaps, 0 FAILED, 1 needs-fixture, 7 skipped (0 mismatches)
RLS:20 PROVEN (20 consistent, 0 HOLES) · 3 NOT PROVEN (0 member-visible, 0 probe-blocked, 3 skipped)
position personas:9 of 9 declared position(s) probed·all personas: 35 PROVEN (35 consistent, 0 HOLES)Confirms R1 finding #1 —
--rlsis a separate invocation and bareverifyemits no RLS section. The run's own⚠ 3 of 23 objects were NOT provenis a coverage caveat (2 external federated read-only objects + 1 with no plain-text probe field), not a hole. Two personas (exec,auditor) proved nothing — every object was member-visible, probe-blocked or skipped; worth a Tier-2 look, since a persona that proves nothing is indistinguishable from a persona with no policy.
7 — framework playwright smoke · examples/app-showcase · playwright test --config=/tmp/.../pw-showcase.config.ts
35 passed (2.2m)— with the pinned chromium. Confirms R1 finding #2; the scratch config lives in/tmpso the subject tree stays clean.
8 — objectui live e2e (18 pinned specs) · playwright test --config=/tmp/.../pw-live.config.ts against os serve --dev on :3000 + console vite dev on :5180
18 passed, 11 failed (7.8m)— and re-run in isolation: the same 11, deterministic, not load (#9311 ruled out).
Why the 11 live-e2e reds are NOT scored as product failures
RUNNER rule 2 (reproduce, self-check, rule out the traps) and rule 5 (severe findings are hypotheses) both point the same way here. Four independent pieces of evidence:
- objectui's own CI runs only 4 of these specs.
test:e2e:live:ciis exactlyscreen-flow · action-modal · master-detail · saved-view-filter, and all four passed in this run. The workflow header is explicit that the lane iscontinue-on-error: true, "INFORMATIONAL, NON-REQUIRED", and warns: "do not switch all 20+ live specs on at once and inherit whatever flake exists". The 14 specs outside that allowlist have never been proven green by the repo that owns them. - The pinned pairing is a published backend, not this source build.
e2e/live/ci/backend.envpinsOBJECTSTACK_VERSION=17.0.0-rc.2/OBJECTSTACK_REF=89d2a4eb…, and its own header says testing a mismatched pair "proves nothing". I ran the pinned console against source-builte4e5c6e3. - Several reds are demonstrably assertion bugs, not product bugs.
form-view-subformsandgrid-file-uploadfail with a strict-mode violation in which the locator matched two elements — one of them the real<h3>Line Items</h3>. The surface rendered; the assertion is ambiguous because a Radixsr-onlydialog description now also contains the phrase.user-filtersassertsTimelineis absent from the viz whitelist while the app offers it — a product change the spec never caught up with. - The ledger already predicted two of them.
platform-core.metadata-authoring-roundtripandstudio-authoring.record-page-roundtripboth carry astaleflag sayingstudio-record-page.spec.tsis "STALE, NOT RED — that spec fills the Object control as an input when it is now arole=comboboxbutton", with arunnerRuleof "do NOT score their failure as a FAIL of this item". This run reproduced that failure byte-for-byte:locator.fill: Error: Element is not an <input>, <textarea> or [contenteditable] element. Independent corroboration of the ledger's own note.
Additionally, meta/app on stock showcase returns exactly showcase_app, setup, account — the Studio app is not installed, confirming #9296 finding #4. That is why studio-object-designer F1 ("a new package appears in the switcher") cannot pass here, while F2/F3/F4 of the same spec do.
So these are recorded as blocked/partial with the reason, never as fail. Tier-2 should still look at them — a deterministic red is worth a matched-pairing re-run before anyone calls it clean.
Per-item verdicts
Verdict scope is the pinned clauses. Scoring rule applied: pass only where the pin's executed tests span the item's acceptance clauses; partial where the pin demonstrably reaches a subset (gap named below); blocked where the pin could not be consulted in a valid pairing.
access-security
| id | rev | verdict | evidence |
|---|---|---|---|
rls-both-sides |
3 | ✅ pass | verify --rls: 20 PROVEN / 0 HOLES over 23 objects, 9/9 position personas; showcase-private-owd 5/5 |
write-path-guards |
2 | ✅ pass | owner-anchor-and-bulk-writes 9/9 + showcase-static-readonly 3/3 + showcase-readonly-when-parent 5/5 |
record-access-explain |
2 | ✅ pass | showcase-permission-zoo 13/13 (incl. the explain vama_bypass case) |
crud-permission-matrix |
1 | 🟡 partial | verify CRUD 15 verified / 0 gaps / 0 FAILED / 0 mismatches; RLS 20 PROVEN / 0 HOLES |
owd-sharing-matrix |
2 | ✅ pass | showcase-private-owd 5/5 + public-read-owd 3/3 + controlled-by-parent 4/4 + invoice-cbp 4/4 = 16/16 |
fls-mask-and-strip |
1 | 🟡 partial | showcase-permission-zoo 13/13 (FLS budget case) |
scope-depth-asymmetry |
1 | ✅ pass | showcase-scope-depth 7/7 + -write 9/9 + -fallback 4/4 = 20/20 |
anonymous-deny-surfaces |
1 | ✅ pass | showcase-anonymous-deny-surfaces 25/25 |
ai
| id | rev | verdict | evidence |
|---|---|---|---|
mcp-http-surface |
2 | 🟡 partial | showcase-mcp-http-identity 6/6 (anonymous 401, keyed tools/call, RLS/FLS-scoped query_records + get_record) |
mcp-stdio-fail-closed |
3 | 🟡 partial | mcp plugin.test 17/17, incl. the 4-test "stdio principal admission — fail-closed (ADR-0101)" block |
mcp-validate-expression |
2 | ✅ pass | mcp-validate-expression 8/8 — sound formula, bare-field error, unknown-field did-you-mean, site-dependent binding, unknown object, system-object refusal |
skill-instructions-mcp-prompts |
1 | ✅ pass | skill-prompts 12/12 — listing, prompts/get body, no-instructions/inactive not projected, invalid-params rejection, capability withheld when metadata unreadable |
api-backend
| id | rev | verdict | evidence |
|---|---|---|---|
query-contract-matrix |
1 | 🟡 partial | objectql engine.test 135/135 |
bulk-write-contract |
1 | ✅ pass | owner-anchor-and-bulk-writes 9/9 (bulk halves) |
declarative-endpoint-execution |
1 | ✅ pass | showcase-declarative-endpoints 17/17 + declarative-endpoint-policy 8/8 = 25/25 |
approvals
| id | rev | verdict | evidence |
|---|---|---|---|
decision-only-via-service |
1 | ✅ pass | resume-authority-gate 22/22 — raw resume refused, owning service admitted, ungated pause still resumable, node-scoped across subflow/map/restart |
attachments-storage
| id | rev | verdict | evidence |
|---|---|---|---|
presigned-upload-roundtrip |
1 | 🟡 partial | attachments-permission-matrix 15/16 |
download-authz-both-sides |
2 | 🟡 partial | attachments-permission-matrix 15/16 (download requires auth AND parent read) |
read-inherits-parent-rls |
2 | 🟡 partial | attachments-permission-matrix 15/16 (member cannot list/read rows whose parent is invisible) |
attach-requires-parent-edit |
2 | 🟡 partial | attachments-permission-matrix 15/16 — ATTACHMENT_PARENT_ACCESS, server-stamped uploaded_by, delete gating, FILES_DISABLED |
sys-file-status-pipeline |
1 | 🟡 partial | attachments-permission-matrix 15/16 (shared-file survival, un-tombstone on re-attach) |
orphan-tombstone-reap |
1 | 🟡 partial | attachments-permission-matrix 15/16 — reap after the 7d window, sweep-time re-verification, committed/NULL-deleted_at rows survive |
upload-session-abort |
3 | 🟡 partial | attachments-permission-matrix 15/16 — abandoned chunked upload reaped AND its parts aborted |
inline-grid-receipt-cells |
2 | ⛔ blocked | sole pin objectui e2e/live/grid-file-upload.spec.ts red in this pairing |
automation
| id | rev | verdict | evidence |
|---|---|---|---|
flow-node-type-matrix |
3 | 🟡 partial | flow-node 2/2 |
trigger-type-matrix |
1 | 🟡 partial | flow-trigger-conformance 2/2 (ledger-driven conformance) |
screen-flow-roundtrip |
2 | ✅ pass | objectui e2e/live/screen-flow.spec.ts green — one of the 4 specs on objectui's own CI allowlist |
durable-suspend-restart |
1 | ✅ pass | flow-durable-suspend 11/11 |
cli
| id | rev | verdict | evidence |
|---|---|---|---|
migrate-plan-apply-json |
1 | 🟡 partial | format.exit-code 4/4 — emitJson/emitText leave the exit code alone on success, record a requested failure, and a duration can no longer reach the exit-code slot (#4873) |
verify-verdict-exit-mapping |
1 | 🟡 partial | verify-tenancy-posture 7/7 — OS_TENANCY_POSTURE keys the multi-tenant suite, legacy-boolean back-compat, --multi-tenant override |
scaffold-first-run |
2 | 🟡 partial | CI pin .github/workflows/scaffold-e2e.yml — last 30 runs: 4 success, 26 action_required (fork/changeset PRs never executed); the 4 green runs are all 2026-08-17 |
dashboards
| id | rev | verdict | evidence |
|---|---|---|---|
dataset-report-authoring |
1 | 🟡 partial | dashboard-designer-roundtrip 3/3 — layout-less draft saves, publishes, reads back with its widgets |
empty-null-bucket-boundaries |
1 | ✅ pass | date-bucket-parity-conformance 8/8 |
identity-auth
| id | rev | verdict | evidence |
|---|---|---|---|
auth-method-matrix |
2 | 🟡 partial | oidc-authorization-code-flow 3/3 — skip_consent code redirect, token exchange persists the access-token row, userinfo answers the signed-in subject |
invitation-scope-gates |
3 | 🟡 partial | delegated-admin-invite 4/4 — delegate may invite, the same delegate issuing admin is refused with no row left behind, org owner may provision a delegate, plain member cannot invite at all |
admin-lifecycle-operations |
3 | 🟡 partial | admin-identity-audit-trail 3/3 — create-user, set-user-password and import-users each leave the expected sys_audit_log shape |
integration-system
| id | rev | verdict | evidence |
|---|---|---|---|
connector-declarative-boot |
2 | 🟡 partial | showcase-declarative-mcp 2/2 |
connector-stdio-default-deny |
2 | ✅ pass | connector-mcp mcp-provider 13/13 |
connector-descriptor-audit |
2 | ✅ pass | connector-descriptor-audit 9/9 |
webhook-lifecycle |
4 | 🟡 partial | webhook-materialization 1/1 — the authored webhook materializes into sys_webhook |
email-template-render |
4 | 🟡 partial | email-template-materialization 2/2 — the authored template materializes and renders |
datasource-admin-lifecycle |
1 | 🟡 partial | service-datasource admin-routes 30/30 + envelope.conformance 24/24 = 54/54 |
platform-core
| id | rev | verdict | evidence |
|---|---|---|---|
nav-surfaces-render |
3 | 🟡 partial | examples/app-showcase showcase-smoke 35/35 with the pinned chromium — every nav destination renders cleanly, charts draw real SVG |
metadata-registry-serving |
2 | 🟡 partial | meta-types-create-seed 6/6 |
metadata-authoring-roundtrip |
2 | 🟡 partial | package-first-authoring 5/5 green |
records-forms
| id | rev | verdict | evidence |
|---|---|---|---|
field-type-matrix |
2 | ✅ pass | field-zoo-roundtrip 46/46 + field-zoo-value-shape 45/45 = 91/91 |
list-view-capabilities |
1 | 🟡 partial | saved-view-filter green (CI allowlist) + showcase-search 5/5 |
view-type-gallery |
1 | ✅ pass | showcase-smoke 35/35 — page-level render across every view surface (Board, Calendar, Gallery, Timeline, Map, Gantt) |
conditional-rules-header |
1 | 🟡 partial | required-when-submit + list-row-action-cel both green |
conditional-rules-grid |
1 | 🟡 partial | grid-conditional-rules + grid-parent-rules both green |
cascading-options |
1 | 🟡 partial | the SERVER clause is green — "the server rejects an out-of-set option value, and accepts an in-set one" passed |
master-detail-atomic-save |
2 | 🟡 partial | master-detail green (CI allowlist) + summary-rollup green |
related-list-server-pagination |
3 | ⛔ blocked | sole pin objectui e2e/live/detail-related-list.spec.ts red in this pairing |
action-param-widgets |
2 | ✅ pass | action-params-contract 3/3 + action-modal green (CI allowlist) |
import-wizard-encoding-and-hints |
2 | ✅ pass | importParsers 30/30 + importMissingRequiredHint 2/2 + importLegacyReferenceGuard 3/3 = 35/35 |
action-location-matrix |
4 | ✅ pass | list-row-action-cel green (row-level CEL visibility) + action-modal green (dialog dispatch) |
gantt-interactions |
1 | ✅ pass | plugin-gantt autoscheduledlg 4/4 + summaryedit 8/8 + deptypes 2/2 + scheduling.selfextent 8/8 = 22/22 |
form-dirty-guard |
1 | ✅ pass | plugin-form discardGuard 14/14 |
adhoc-filter-sort-builder |
1 | 🟡 partial | saved-view-filter green (CI allowlist) |
calendar-interactions |
1 | ✅ pass | plugin-calendar CalendarView.dnd 8/8 (move/resize/time-grid drag geometry) |
concurrent-edit-conflict |
1 | 🟡 partial | plugin-form occSave 8/8 — 409 handling + overwrite retry |
grid-personalization |
1 | ✅ pass | plugin-grid groupedPagination 7/7 + groupedBooleanLabel 2/2 + inlineEditPersistence 1/1 = 10/10 |
bulk-select-all-matching |
1 | ✅ pass | plugin-grid objectBulkActionDispatch 12/12 + BulkActionBar 7/7 + bulkActionRefresh 11/11 = 30/30 |
lookup-picker-create-new |
1 | ✅ pass | fields LookupField.dependsOn 6/6 + RecordPickerDialog.filterOptions 12/12 = 18/18 |
record-edit-undo |
1 | ✅ pass | core UndoManager 28/28 (undo/redo stack) |
object-hook-lifecycle |
1 | 🟡 partial | showcase-public-form 4/4 (beforeInsert stamp) + hook-error-format 4/4 (beforeDelete onError:abort -> REST error body) |
field-type-constraints |
1 | ✅ pass | field-zoo-roundtrip 46/46 + value-shape 45/45 + engine-lookup-referential-integrity 13/13 (reference_not_found #4441) + engine-autonumber-runtime-owned 32/32 (autonumber strip #5503) |
cascading-multilevel-and-clear |
1 | 🟡 partial | rule-validator.option-visibility 20/20 — the server WRITTEN-value gate |
encrypted-field-behavior |
1 | ✅ pass | objectql secret-fields 36/36 (encrypt/mask/fail-closed) + field-zoo-roundtrip 46/46 (masked f_secret & f_password vectors) |
search
| id | rev | verdict | evidence |
|---|---|---|---|
cross-field-object-search |
3 | ✅ pass | showcase-search 5/5 — multi-field $search returns Northwind via industry, not name (ADR-0061 verbatim) |
field-scoped-narrowing |
1 | ✅ pass | showcase-search 5/5 — $searchFields narrows and can never widen |
studio-authoring
| id | rev | verdict | evidence |
|---|---|---|---|
object-designer-roundtrip |
1 | 🟡 partial | studio-object-designer 3/4 — F2 (typed underscore survives), F3 (API name derives from label on blur), F4 (picklist + empty option row does not trip validation) all green |
record-page-roundtrip |
2 | ⛔ blocked | sole pin studio-record-page.spec.ts red — locator.fill: Element is not an <input> |
draft-publish-lifecycle |
4 | 🟡 partial | dashboard-designer-roundtrip 3/3 — draft save is staged, publish flips visibility, published body reads back |
org-override-registry-gate |
2 | ✅ pass | objectql overlay-precedence 26/26 |
expression-editors |
1 | ✅ pass | celAuthoring 34/34 + CelPredicateField 24/24 + CelTestRunDialog 6/6 + PermissionAdvancedFacets.cel 2/2 = 66/66 |
permission-matrix-editor-ux |
1 | ✅ pass | PermissionMatrixEditor.fieldBulk 3/3 + PermissionMatrixEditor.readonly 7/7 = 10/10 |
Coverage gaps — every partial / blocked, with what the pin did not reach
access-security.crud-permission-matrix(rev1, partial) — the ref itself says persona-grained cells remain manual —verifyproves object-level CRUD + cross-owner RLS, never the persona x CRUD-cell matrixaccess-security.fls-mask-and-strip(rev1, partial) — ref is explicit: write half only. The read-side clauses (masked value in the GET payload, field stripped from the response shape) have no pinai.mcp-http-surface(rev2, partial) — pin is the identity-admission block only: C0 (opted-out boot 404 on /mcp and /mcp/skill), C1 (GET /mcp/skill serves SKILL.md unauthenticated) and C2 (405 +Allow: GET) are unpinnedai.mcp-stdio-fail-closed(rev3, partial) — covers C0–C2 + C7 (keyless refusal, unresolvable key, principal binding, no key demanded when disabled). C3–C6 — member-keyed RLS/FLS read parity, aggregate_records parity, FLS aggregate fail-closed, revocation honored on next call — are unpinnedapi-backend.query-contract-matrix(rev1, partial) — the ref scopes the pin to "[Security: $expand bypasses RLS/FLS on the referenced object (data leak on lookups) #2850] expand sub-read through the secured find path" = C4 only. C0–C3 and C5–C8 (operator answer sets, $top/$skip windowing, $select narrowing, sort + INVALID_SORT, INVALID_FILTER, UNSUPPORTED_QUERY_PARAM, $in/$nin empty-list boundary) are REST-contract clauses this engine unit suite does not reach.filter-comparand-shape.tsis a source module, not a testattachments-storage.presigned-upload-roundtrip(rev1, partial) — pin reaches C4 (anonymous presign 401) and the authenticated upload. C0 (presign envelope{uploadUrl, method, fileId, expiresIn, downloadUrl}), C1 (status pending->committed on complete), C2 (GET /files/:id/urlenvelope) and C3 (302 redirect) are unpinnedattachments-storage.download-authz-both-sides(rev2, partial) — C3 (acl=public_readre-opens the stable anonymous capability URL) and C4 (browser renders friendly denial copy) are unpinned; the cross-tenant case is skipped — see the enterprise-gate noteattachments-storage.read-inherits-parent-rls(rev2, partial) — C1 (COUNT filtered identically to rows) and C3 (filter fails CLOSED on compute failure / past the 2000-row pre-scan cap) are unpinnedattachments-storage.attach-requires-parent-edit(rev2, partial) — C3 (unscoped multi-delete with neither id nor where is refused outright,installAttachmentAccessHooksdoes not authorize an UNSCOPED multi-delete: no id + nowherereads as "nothing to authorize" anddeleteManyruns over the whole table #4757) is unpinnedattachments-storage.sys-file-status-pipeline(rev1, partial) — C0 (every status enum variant), C1 (a pending file is not downloadable) and C4 (only scope=attachments committed files tombstone via these hooks) are unpinnedattachments-storage.orphan-tombstone-reap(rev1, partial) — C1 (bytes reclaimed BEFORE the row delete — the ordering, not just the outcome) is not separately assertedattachments-storage.upload-session-abort(rev3, partial) — C0 (the chunked round-trip over the real routes: init -> chunk PUTs -> progress) is unpinnedattachments-storage.inline-grid-receipt-cells(rev2, blocked) — not consultable — see the live-e2e pairing note; the spec is outside objectui's own CI allowlist and its failure is an ambiguous-locator assertion, not a product signalautomation.flow-node-type-matrix(rev3, partial) — two tests against a 6-clause node-type matrix — the pin exercises the node-type registry, not each declared node type's runtime semanticsautomation.trigger-type-matrix(rev1, partial) — two tests against 6 clauses; the ledger conformance proves declared-vs-registered parity, not each trigger type firing end-to-endcli.migrate-plan-apply-json(rev1, partial) — pin is the exit-code formatter only = C2. C0 (bareos migratenever mutates), C1 (--json shape), C3 (destructive skipped until --allow-destructive), C4 (idempotent re-run in_sync), C5 (busy-DB asymmetry), C6 (--json non-interactive confirmation_required) are unpinnedcli.verify-verdict-exit-mapping(rev1, partial) — the pin decides which SUITE runs, not how a verdict maps to an exit code; the verdict->exit clauses are only indirectly coveredcli.scaffold-first-run(rev2, partial) — the workflow cannot be executed locally (registry install + docker) and was never run against the subject sha e4e5c6e; the nightly published-package canary job has no run in the windowdashboards.dataset-report-authoring(rev1, partial) — three tests against 8 clauses; the dataset/report authoring clauses beyond save->publish->read are unpinnedidentity-auth.auth-method-matrix(rev2, partial) — C7 says outright that only the OIDC flow is pinned. C0–C6 and C9 (advertisement parity, email+password round trip, phone+password, phone-OTP NOT_SUPPORTED, login-page per-variant presence/absence, server-side refusal of a disabled method, 2FA gate, change-email/delete-user) are unpinnedidentity-auth.invitation-scope-gates(rev3, partial) — C4 (UI invite affordances, both sides), C5 (lifecycle vocabulary pending->accepted/rejected/expired, cancel/resend) and C6 (/security/my-delegable-scopeis self-scoped) are unpinnedidentity-auth.admin-lifecycle-operations(rev3, partial) — C8 is the only pinned clause. C0–C7 and C9 (ban persistence/reversal, password rotation, explicit-password-wins, set-role flipping gate outcomes, revoke-user-sessions mid-flight, owner_id FK clear on user removal, impersonation attribution + console visibility, non-admin refusal of every /admin/ route) are unpinnedintegration-system.connector-declarative-boot(rev2, partial) — two tests against 6 clauses — the declarative MCP connector boots, but the wider connector-boot matrix is unpinnedintegration-system.webhook-lifecycle(rev4, partial) — one test against 6 clauses; delivery, retry, signature and teardown clauses are unpinnedintegration-system.email-template-render(rev4, partial) — two tests against 8 clauses; requireVars fail-fast, TEMPLATE_INACTIVE, (name, locale) fallback, fromOverride/replyTo/derived bodyText, customized-row survival, stray-key alias prescription and the raw /email/send door are unpinnedintegration-system.datasource-admin-lifecycle(rev1, partial) — the ref is explicit: this pins route behavior + envelope; the LIVE-mount half is not pinned — a realos devmount of the datasource is not exercisedplatform-core.nav-surfaces-render(rev3, partial) — C2 (a bad route renders a NAMED not-found/error inside a live shell) and C3 (route-level ErrorBoundary fallback, recoverable via Try Again) have no spec in the smoke — its 35 cases are clean-render and gated-inline-def cases onlyplatform-core.metadata-registry-serving(rev2, partial) — six tests against 7 clauses — the create/seed path is pinned; the wider registry-serving surface is not fully reachedplatform-core.metadata-authoring-roundtrip(rev2, partial) — the item carries a ledgerstaleflag: itsstudio-record-page.spec.tsref is STALE, NOT RED (the Object control is now arole=combobox, not an input). This run independently reproduced exactly that —locator.fill: Element is not an <input>. Per the item's ownrunnerRulethe Studio clause (C3, thePUT /api/v1/meta/page/<name>) must be hand-driven and its spec failure must NOT be scored hererecords-forms.list-view-capabilities(rev1, partial) — theuser-filtersandinline-edit-polish-2572halves are not consultable in this pairing — see the live-e2e noterecords-forms.conditional-rules-header(rev1, partial) — thefield-conditional-ruleshalf (visibleWhen/readonlyWhen/requiredWhen reacting to Status) is not consultable in this pairingrecords-forms.conditional-rules-grid(rev1, partial) — thegrid-file-uploadhalf is not consultable in this pairingrecords-forms.cascading-options(rev1, partial) — the client half ("province options re-filter live as country changes, and the stale value clears") is not consultable in this pairingrecords-forms.master-detail-atomic-save(rev2, partial) — theform-view-subformshalf is not consultable — and note its failure is a strict-mode locator ambiguity in which theLine Itemsheading WAS found, i.e. the surface renderedrecords-forms.related-list-server-pagination(rev3, blocked) — not consultable — outside objectui's CI allowlist, unpinned backend pairingrecords-forms.adhoc-filter-sort-builder(rev1, partial) — theuser-filtershalf is not consultable in this pairingrecords-forms.concurrent-edit-conflict(rev1, partial) — theinline-edit-polish-2572half (single save bar / atomic inline save) is not consultable in this pairingrecords-forms.object-hook-lifecycle(rev1, partial) — the ref is explicit: the transition audit / over-budget warn / priority-ordering LOG oracles and the abort/log/priority SCRATCH variants are NOT dogfood-pinned and must be hand-drivenrecords-forms.cascading-multilevel-and-clear(rev1, partial) — the client clear-on-change half (cascading-options.spec.ts) is not consultable in this pairingstudio-authoring.object-designer-roundtrip(rev1, partial) — F1 ("a newly created package appears in the switcher without a reload") is red; the Studio APP is not installed on stock showcase (meta/app= showcase_app, setup, account), so the switcher clause is not scoreable herestudio-authoring.record-page-roundtrip(rev2, blocked) — the item carries a ledgerstaleflag whoserunnerRulesays outright: do NOT satisfy this item by citing these specs, and do NOT score their failure as a FAIL. This run reproduced the documented staleness exactly (the Object control is now arole=comboboxbutton). Hand-drive until objectui re-points the specstudio-authoring.draft-publish-lifecycle(rev4, partial) — three tests against 12 clauses; If-Match 409 metadata_conflict, package-wide publish-drafts atomicity, invalid-draft gate, Studio chrome badges, history/diff/rollback/audit and X-Actor inertness are unpinned
Checklist-accuracy findings (for the ledger, not for code)
- The pins are narrower than the items on 39 of 77. Not a defect in any pin — but an item scored
passon a pin that reaches 1 of 10 clauses would be a false green. The gap list above is the raw material for either tighteningautomated.refscope notes (asfls-mask-and-strip,crud-permission-matrix,datasource-admin-lifecycleandobject-hook-lifecyclealready do well) or promoting the unpinned clauses to real tests per RUNNER rule 6's reverse direction. - 11 items pin objectui
e2e/livespecs that objectui itself does not gate. Only 4 live specs are intest:e2e:live:ci; the rest are informational and unproven. The ledger should either pin to the allowlist, or record the required pairing (backend.env) so a runner knows a green needs the published backend. e2e/live/ci/backend.envviolates its own stated invariant in the pinned objectui tree:OBJECTSTACK_VERSION=17.0.0-rc.2while this repo's lock resolves@objectstack/spec ^17.0.0-rc.6, though the file says the two "MUST stay aligned … bump both in the same PR". That is an objectui repo issue, filed here only as a pointer.api-backend.query-contract-matrixcites a source module as a pin —packages/objectql/src/filter-comparand-shape.tsis not a test.- Cross-tenant clauses are structurally unprovable in the OSS workspace (
@objectstack/organizationsis cloud-private). The dogfood probe handles this honestly; the checklist should mark such clauses so runners stop rediscovering it.
Not re-derived (already known, confirmed again)
objectstack verify --rlsis a separate invocation — confirmed, 20 PROVEN / 0 HOLES / 9-of-9 personas.- Playwright needs the explicit
executablePath— confirmed, 35 passed with it. - Studio is not installed on stock showcase — confirmed via
meta/app.
Nothing landed in the repo: no commits, no PR, no screenshots. Scratch artifacts stayed in /tmp/qa-wave/**.
Parent: #9296
Activity
os-zhuang commentedon Aug 17, 2026
ACCEPT — reviewer of record: PM loop (QA wave #9296), session
session_01Ai9gUdihXjg7FumzsBNSSs.Two claims spot-checked against the tree rather than the report, both hold:
.cache/objectui-665661ab0932exists in the QA tree withnode_modulespresent. That is what let 25 objectui unit pins (249 tests) run at the exact.objectui-shapin with zero installs — the sibling/home/user/objectuiis at a different sha (195b9e4ab) and has none. Without that read, 26 items would have goneblocked(environment)on a constraint that was not actually binding. This belongs in RUNNER.md's facts section; folded into docs(qa): land the #9296 wave's environment facts in RUNNER.md and the 34 checklist-accuracy corrections in areas/*.json #9386.api-backend.query-contract-matrixcitespackages/objectql/src/filter-comparand-shape.tsas anautomated.ref. That file exists and is a source module, not a test — nothing executes it as a pin. The item carries 9 acceptance clauses, which corroborates thepartialrather thanpassscoring.The finding that changes the wave's cost model
39 of 77 pinned items are
partialbecause the pin is narrower than the item —identity-auth.admin-lifecycle-operationspins 1 of 10 clauses;api-backend.query-contract-matrix(P0) pins one expand path out of nine. Mapping each pin's executed test titles onto its acceptance clauses, and naming every gap, is the most reusable thing this round produced — more so than the 35 PASS.It also corrects a premise I dispatched on. I framed the 77 pinned items as "cheap coverage, already proven by CI". They are cheap, and 0 failed — but
automated.refpresent ≠ item covered. The honest reading is 35 items fully covered, 39 partially, and the remaining clause gaps join the hand-driving load rather than sitting outside it.Judgement calls I am endorsing
blocked/partialrather thanfail. Four independent lines of evidence, not one: only 4 live specs are on objectui's own CI allowlist (all 4 green here), the lane iscontinue-on-error, the pinned pairing is a published backend (backend.env→17.0.0-rc.2) rather than a source build, and several failures are demonstrable assertion bugs (one fails a strict-mode ambiguity in which the element it sought was found). Two are covered by explicit ledgerstalerunnerRules that forbid scoring a FAIL — and the runner reproduced the exact predicted symptom independently. Recording a red asblockedneeds this much justification, and it was supplied.objectui e2e/live/ci/backend.envviolating its own stated invariant (OBJECTSTACK_VERSION=17.0.0-rc.2while the lock resolves@objectstack/spec ^17.0.0-rc.6, where the file's own header says the two must be bumped together) is a finding at destination — it belongs inobjectstack-ai/objectui, not here. Filing it there is the right next step; it means that lane may currently be testing a pairing it declares meaningless.Carried forward
revisionbumps, not eight scattered edits.verify --rls: theexecandauditorposition personas proved NOTHING — 0 PROVEN, every object member-visible / probe-blocked / skipped. Zero HOLES overall, but as the runner put it, a persona that proves nothing is indistinguishable from a persona with no policy. That deserves its own look before the wave closes; it is not covered by any current item.Tier-2A (23 unpinned api/cli/build items) dispatched.
Generated by Claude Code
docs(qa): land the #9296 wave's item corrections and the console-sess…
os-zhuang commentedon Aug 18, 2026
Close-out — extracted. Wave #9296, executed under #9480. Nothing re-judged, nothing re-run.
No FAIL to dispose of. 0 FAIL across 77 items; no product defect and no access-control finding. The four-way disposition therefore has no input from this record, which is exactly what its PARTIAL column says: the pins are green, and the value is in what they do not reach.
What was extracted
The three security-priority coverage gaps from this record's own gap list are filed and in the queue — #9481 (the read side of FLS mask/strip, plus the persona × CRUD cell matrix
verifycannot see), #9482 (the admin-lifecycle clauses C0–C7/C9 that the single pinned audit clause leaves open), #9483 (the unpinned authorization clauses of the attachments chain). They are pin-upgrade cards, not defect cards: the property is untested, not broken.(d) invalid pairing / environment — recorded blocked, no card
Recorded here so a later reader does not mistake a red for a product signal:
e2e/livespecs red, deterministically. Not scoredfail, and correctly so: only 4 specs (screen-flow,action-modal,master-detail,saved-view-filter) are on objectui's owntest:e2e:live:ciallowlist and all four passed; the lane iscontinue-on-error: trueand warns against switching the rest on; the pinned pairing is a published backend (OBJECTSTACK_VERSION=17.0.0-rc.2ine2e/live/ci/backend.env) rather than this source build; and at least two of the reds are demonstrably assertion bugs (a strict-mode locator that matched the real<h3>Line Items</h3>twice; a whitelist assertion the product has moved past). A matched-pairing re-run remains worthwhile and is not a clean bill — that stays parked.blocked:inline-grid-receipt-cells,related-list-server-pagination,record-page-roundtrip— the last two under the ledger's ownstaleflag whoserunnerRulesays outright not to score the spec's failure as a FAIL. This run reproduced the documented staleness byte-for-byte, which is corroboration of the ledger, not a defect.@objectstack/organizationsis cloud-private and absent from the OSS workspace, so the block skips loudly by design.blocked(dependency).Everything else stays parked, by pointer
All remaining (non-security) coverage gaps in the "Coverage gaps" section above — query-contract REST clauses, presign envelope shapes, the attachments status pipeline / reap ordering / chunked session, the automation node and trigger matrices, auth-method C0–C6/C9, invitation-scope C4–C6, dashboards, webhook and email lifecycle clauses, nav error surfaces, draft-publish clauses — are parked on the wave anchor by the PM's 2026-08-18 comment. This record is the authoritative list; do not re-file from memory without reading it. The five checklist-accuracy findings join the ledger-edit PR.
Extracted: #9481 #9482 #9483
Parked-on: #9296
Generated by Claude Code
tests(access-security): pin the FLS read side and the persona x CRUD …
tests(identity): pin the admin credential clauses and a derived non-a…
tests(attachments): pin clause C3 end to end and correct the ledger t…
docs(qa): land the objectstack-ai#9296 wave's item corrections and th…
tests(access-security): pin the FLS read side and the persona x CRUD …
tests(identity): pin the admin credential clauses and a derived non-a…
tests(attachments): pin clause C3 end to end and correct the ledger t…