| access-security.rls-both-sides |
5 |
PARTIAL |
A6 blocked(dependency: the private D11 write-up the clause requires); verify --rls 38 PROVEN · 0 HOLES · 226 NOT PROVEN, 10/10 positions; private-owd 5/5 |
| access-security.write-path-guards |
3 |
PARTIAL |
N2 not-run (needs an in-process isSystem write; no REST door, no pin); owner-anchor 9/9 · static-readonly 3/3 · readonly-when-parent 5/5 |
| access-security.crud-permission-matrix |
4 |
FAIL |
A1 fails — #21057 still reproduces (3 loads); A6 blocked(fixture); persona-matrix 46/46 · permission-zoo 13/13 |
| access-security.owd-sharing-matrix |
3 |
PASS |
public-read-owd 3 · controlled-by-parent 4 · invoice-cbp 4 · private-owd 5 |
| access-security.scope-depth-asymmetry |
2 |
PASS |
scope-depth 7/7 · scope-depth-write 9/9 · scope-depth-fallback 4/4 |
| access-security.anonymous-deny-surfaces |
3 |
PASS |
anonymous-deny-surfaces 61/61 |
| access-security.sharing-rules-widen |
1 |
PASS |
unit_and_subordinates variant; rule share source rule, survives restart |
| access-security.record-share-grant-revoke |
4 |
PASS |
grant 201 / revoke 204 / cross-record DELETE 404; evaluate source_id = row id |
| access-security.share-link-capability-tokens |
3 |
FAIL |
A5 record-gone leg: 404 INVALID_OR_EXPIRED, not 410 RECORD_GONE (fail-closed by design, #5190) — stale clause; client-liaison-fixtures 5/5 |
| access-security.suggested-binding-loop |
2 |
PASS |
stock boot reconciles one confirmed row; confirm writes the binding under the caller |
| access-security.activation-write-operator-gate |
2 |
PASS |
runtime posture-gate pins 46/46; tier gate 403 at both doors, manage_metadata holder 200 |
| access-security.packaged-flow-write-door-parity |
2 |
PASS |
all three doors 403 NOT_OVERRIDABLE / ITEM_LOCKED; write-door-parity dogfood 5/5 |
| access-security.platform-owner-email-anchor |
2 |
PASS |
core pins 65/65; unset / unverified / non-match / malformed refused; verified match → platform admin |
| access-security.me-permissions-aggregation-parity |
2 |
PASS |
hono 38/38 · plugin-security 64/64 · me-apps-baseline 6/6 |
| access-security.record-view-read-audit |
1 |
PASS |
plugin-audit 43/43; stock audits nothing, opt-in records one read row per detail view |
| ai.agent-tool-skill-metadata-roundtrip |
3 |
FAIL |
A4: draft PUT on a package-shipped skill → 403 NOT_OVERRIDABLE by design (ee58392, #6608) — assertion defect |
| ai.mcp-http-surface |
2 |
PASS |
showcase-mcp-http-identity 6/6; config-off 404, anonymous 401 + WWW-Authenticate, scope narrowing |
| ai.mcp-run-action-exposure-gate |
2 |
PASS |
unexposed action refused with the opt-in sentence, no side effect |
| ai.mcp-validate-expression |
2 |
PASS |
mcp 37/37 batch; ok / bare-reference / unknown-field match a real build |
| ai.skill-instructions-mcp-prompts |
1 |
PASS |
skill-prompts 12/12; prompts/list and prompts/get round-trip |
| ai.open-edition-honest-degradation |
1 |
PASS |
/ai/agents 200 empty; models/chat 501 with the remedy; anonymous 401 |
| ai.mcp-oauth-private-host-transport |
2 |
PASS |
plugin-auth 89/89; private origin served, public plain HTTP withheld, notices exactly once |
| api-backend.batch-transactional-discovery |
3 |
FAIL |
A5: default continueOnError:false stops at the first failure (NOT_ATTEMPTED tail, batch.zod.ts:81-84) — assertion defect |
| api-backend.server-timing-admin-gated |
2 |
FAIL |
A2/A3: the item inverts global mode vs per-request admin-gated mode (hono-plugin.ts:83-104) — assertion defect; server-timing pin 24/24 |
| api-backend.query-contract-matrix |
3 |
PASS |
objectql 208/208 · rest request-schema-gate 16/16; 16 operators × 3 spellings |
| api-backend.error-envelope-ledger |
3 |
PASS |
7 code families, fields[] with label, no fieldErrors |
| api-backend.bulk-write-contract |
1 |
PASS |
owner-anchor-and-bulk-writes 9/9 |
| api-backend.route-ledger-live-parity |
3 |
PARTIAL |
A10 console-static family not-run (frontend deferred); 18 REST families answer |
| api-backend.declarative-endpoint-execution |
1 |
PARTIAL |
A3 blocked(fixture: no live script/proxy endpoint without source edits); declarative-endpoints 17/17 · policy 8/8 |
| api-backend.package-rest-lifecycle |
2 |
PASS |
create 201 / dup 409 / PATCH / overwrite; one row per id |
| api-backend.filter-comparand-conformance |
3 |
PASS |
engine door + 5 driver suites; #21333 no longer reproduces (fixed by 9f13c94, #21372) |
| api-backend.date-range-preset-matrix |
2 |
PASS |
13 presets, all answer-discriminating, against a known clock |
| api-backend.packaged-action-disabled-dispatch |
3 |
PASS |
dogfood + runtime pins green; 409 ACTION_DISABLED on REST, MCP and after restart |
| api-backend.action-activation-door-contract |
2 |
PASS |
posture-gate 38/38; body/path/404 refusals write no row |
| api-backend.aggregate-contract-matrix |
1 |
PASS |
6 functions × 5 granularities, secured leg via search:qa-contributor-bound-member |
| api-backend.api-methods-verb-gate |
1 |
PASS |
allowed sets equal spec-dist derivation; batch refusal leaves no sibling row |
| api-backend.rest-crud-config-contract |
2 |
PASS |
rest pins 57/57 (parse-not-cast + mount table) |
| api-backend.rest-batch-config-contract |
2 |
PASS |
BATCH_TOO_LARGE on all five doors; tombstones throw |
| api-backend.rest-metadata-config-contract |
3 |
FAIL |
A4 fails — authorization class, detail withheld pending maintainer (RUNNER rule 2) |
| approvals.decision-only-via-service |
1 |
PASS |
resume-authority-gate 22/22; forged resumes 403, service approve completes the run |
| approvals.email-action-token-door |
1 |
PASS |
five refusal shapes, replay refused, token not a bearer credential |
| approvals.approver-resolution-matrix |
2 |
PASS |
all resolver types, subtree units, empty-approver policies |
| approvals.status-mirror-field |
1 |
PASS |
status-mirror-cascade 2/2; six mirror values observed |
| attachments-storage.presigned-upload-roundtrip |
1 |
PASS |
pending → committed, bytes round-trip, anonymous 401 |
| attachments-storage.read-inherits-parent-rls |
3 |
PASS |
count-parity 7/7 · scan-cap 3/3 |
| attachments-storage.attach-requires-parent-edit |
5 |
PASS |
unscoped-delete-gate 10/10 · capability-gate 12/12 |
| attachments-storage.sys-file-status-pipeline |
2 |
PASS |
full pending → committed → deleted → revived cycle |
| attachments-storage.orphan-tombstone-reap |
1 |
PASS |
attachment-lifecycle 47/47; sweep reaps T1/P1, keeps T2/T3/K1 |
| attachments-storage.upload-session-abort |
3 |
PASS |
abandoned and completed sessions reaped; 410 on an expired session |
| attachments-storage.field-accept-maxsize-server-enforced |
1 |
PASS |
accept/maxSize refused, no row (the 500 status is the known gap, extracted below) |
| automation.durable-suspend-restart |
1 |
PASS |
flow-durable-suspend 11/11; three paused runs survive a cold restart and resume |
| automation.flow-toggle-kill-switch |
2 |
PASS |
OFF → no run, ON → one run; /_status tracks |
| automation.trigger-status-contract |
1 |
FAIL |
A5/A6/A7: resume refusals carry status-derived codes (VALIDATION_ERROR / RESOURCE_NOT_FOUND) — product defect |
| automation.packaged-flow-disable-durable |
2 |
PASS |
one ledger row, 409 FLOW_DISABLED, survives restart, re-enable in place |
| automation.packaged-flow-subflow-disable-refusal |
2 |
PASS |
flow-activation-ledger 47/47; 409 DELETE_RESTRICTED naming the caller |
| automation.packaged-flow-clone-contract |
2 |
PARTIAL |
A7 Studio-reach half not-run (frontend deferred); durability half and A1–A6 pass |
| dashboards.cube-query |
3 |
PASS |
counts and sums equal /data group-by exactly |
| identity-auth.self-service-password-reset |
1 |
PASS |
reset, single-use token, no enumeration |
| identity-auth.two-factor-enrollment-reveal |
1 |
FAIL |
A6: sys_user.enable_two_factor now declares a resultDialog (266654d, #11110) — stale clause |
| identity-auth.two-factor-verify-to-activate |
1 |
PASS |
unverified factor cannot complete a sign-in; verify activates |
| identity-auth.two-factor-backup-codes |
1 |
FAIL |
A6: generate_backup_codes now declares a resultDialog (266654d, #11110) — stale clause |
| identity-auth.two-factor-disable-lifecycle |
1 |
PASS |
disable removes the factor; old secret and codes dead after re-enroll |
| integration-system.connector-declarative-boot |
2 |
PASS |
showcase-declarative-mcp + two-factor-lockout 7/7; build refusals verbatim |
| integration-system.connector-degraded-recovery |
2 |
PASS |
connector pins 59/59; backoff 5/10/20/40 s, recovers without restart |
| integration-system.external-datasource-federated-read |
2 |
PASS |
federated reads; writes 403 EXTERNAL_WRITE_FORBIDDEN |
| integration-system.datasource-admin-lifecycle |
3 |
PASS |
service-datasource pins 86/86 |
| integration-system.external-schema-introspection |
2 |
FAIL |
A1 columnCount 7 not 5 (assertion defect); A3 PK as comment, value import (4257e4e, #11073 — stale clause) |
| integration-system.connector-auth-kind-application |
1 |
PASS |
rest-connector 10/10; five auth kinds on the wire, secrets never served |
| platform-core.seed-integrity |
3 |
PASS |
19 datasets / 132 rows match; restart idempotent |
| platform-core.metadata-registry-serving |
2 |
PARTIAL |
A7 console half not-run (frontend deferred); meta-types-create-seed 6/6 |
| platform-core.docs-audience-gate |
1 |
PASS |
book.test 40/40; org / permissionSet / public gates |
| platform-core.manifest-install-contract |
2 |
FAIL |
A2: protocol-incompatible refusal answers 500 without its structured diagnostic — product defect |
| platform-core.activation-ledger-registration-home |
2 |
FAIL |
A5: "41 names" — the array holds 46 (46 already at 17.6.0) — assertion defect; pins 11 + 49 + 22 green |
| platform-core.activation-ledger-row-contract |
2 |
PASS |
action-activation 18/18; 405 on writes, no organization_id column |
| platform-core.packaged-object-extend-only |
1 |
PASS |
both doors 403; object byte-identical |
| platform-core.marketplace-install-local-lifecycle |
1 |
FAIL |
A5 purge-sample-data 500 DRIVER_UNAVAILABLE (product defect); A7 hot withdrawal since 901e7cf (#21581, stale clause) |
| platform-core.runtime-config-boot-read |
1 |
PASS |
anonymous 200, both spellings byte-identical, no secrets |
| platform-core.seed-mode-matrix |
1 |
PASS |
upsert / update / ignore / insert / replace postures |
| records-forms.validation-rule-type-matrix |
2 |
PASS |
all six codes, warning/info severities non-blocking |
| records-forms.named-import-mapping |
1 |
PASS |
mapping applied, re-import upserts, unknown name 404 |
| records-forms.field-unique-enforcement |
1 |
FAIL |
A1: SQL-family refusal names the object, not the field, by design; memory boot store retired by 9a4182a (#21598) — stale clause; pins 26/26 + 65/65 |
| records-forms.delete-behavior-matrix |
1 |
PASS |
engine-cascade-delete ×4 59/59 |
| records-forms.record-clone-contract |
1 |
PASS |
search-clone pins 26/26 + 6/6 |
| records-forms.import-transform-matrix |
2 |
PASS |
five transforms; javascript refused without a tracker number |
| records-forms.predicate-relationship-traversal |
1 |
PARTIAL |
A4 blocked(fixture: no stock persona with invoice CRUD and no account read); A1–A3 pass |
| search.cross-field-object-search |
3 |
PASS |
showcase-search 5/5 |
| search.field-scoped-narrowing |
1 |
PASS |
unknown / non-searchable / hidden fields refused 400 INVALID_FIELD |
| search.rls-both-personas |
6 |
PASS |
member search never surfaces the hidden invoice; totals do not leak the population |
| studio-authoring.org-override-registry-gate |
2 |
PASS |
overlay-precedence 26/26; view overlay 200, object 403, reset |
17.7 pre-release verification, non-browser half: every runnable
surface:apiitem againstorigin/mainas it stood when the run started, the base 17.7 will be cut from (not yet cut; packages still read 17.6.0 with the pending changesets). The browser half waits for the Console pin bump (#21696). Text only; the durable truth stays indocs/qa/platform-checklist/areas/.Environment fingerprint
objectstack-ai/objectstack251a7dd4(fix(organizations)!: a create naming an organization_id meets the Layer 0 write wall, as the update does (#21666) (#21680)), in a dedicated detached worktree:pnpm install --frozen-lockfile && pnpm build→ exit 0 (6m07s)..objectui-sha=ab187972(chore(objectui): bump the console pin to ab1879721595 (carries objectui f624f278, b0bf413c and ab187972) #21625). Every clause that can only be judged in the browser is recordednot-run (frontend deferred, #21696).RUNNER.mdandscripts/checklist-select.mjsfrom the subject tree; the revision of every item is in the table.examples/app-showcase,OS_PORT={p} objectstack dev --seed-admin -p {p} -d file:/tmp/qa1770/{lane}/{item}.db, one file DB and one port per item on disjoint lane ranges 42101–43959 (egress proxy port 41333 excluded). Two lanes deviated under load and say so: L1 drove its eight access-security items on one boot with fresh personas and probe rows per item (plus an independent fresh-DB reproduction for [finding] The delegated-admin gate resolves an EMPTY subtree on a stockobjectstack devboot — seeded business units are organization-less while every session carries an active organization, so every in-scope delegated write is refused #21057), and L6 shared one DB per item group. Members minted by admininvite-member+sign-up/email; identity proved byGET /auth/get-sessionbefore each persona cell. Scratch apps and packages lived under/tmp, never in a checkout.session_018zT8d8NpiQ1ExhuNd5TxY6, 2026-10-04 08:10–11:10Z. The box (4 CPUs, 15 GB) was badly oversubscribed in the first wave (load 60–110): some boots took 10+ min and several hit plugin-start timeouts and were re-booted on fresh DBs; batched vitest runs were SIGKILLed or timed out and every affected pin was re-run alone — every verdict rests on the clean re-run. Environment / waiting ≈ 40–55 % of runner time.Scope
node scripts/checklist-select.mjs surface:api --json→ 89 runnable items. Hidden as blocked (not run):access-security.no-active-org-session-semantics,approvals.sla-escalation. This record is one of three for the same subject; the CLI and build selectors are separate records.verify --rls38 PROVEN · 0 HOLES · 226 NOT PROVEN, 10/10 positions; private-owd 5/5isSystemwrite; no REST door, no pin); owner-anchor 9/9 · static-readonly 3/3 · readonly-when-parent 5/5rule, survives restartconfirmedrow; confirm writes the binding under the callermanage_metadataholder 200readrow per detail viewWWW-Authenticate, scope narrowingok/bare-reference/unknown-fieldmatch a real buildprompts/listandprompts/getround-trip/ai/agents200 empty; models/chat 501 with the remedy; anonymous 401continueOnError:falsestops at the first failure (NOT_ATTEMPTED tail, batch.zod.ts:81-84) — assertion defectfields[]with label, nofieldErrorssearch:qa-contributor-bound-member/_statustracks/datagroup-by exactlysys_user.enable_two_factornow declares aresultDialog(266654d, #11110) — stale clausegenerate_backup_codesnow declares aresultDialog(266654d, #11110) — stale clauseorganization_idcolumnTotals: 68 PASS / 7 PARTIAL / 14 FAIL / 0 BLOCKED / 0 NOT-RUN. Of the 14 fails, 5 carry a product defect (one known, four new) and 9 are checklist clauses whose assertion is wrong or that a deliberate change made stale. Every fail was re-derived by an independent verifier from a fresh reproduction; where a verifier changed a disposition, the verifier's is recorded.
Fails — reproduction rules and dispositions
Product defects
access-security.crud-permission-matrix A1 — known #21057, still reproduces at
251a7dd4(fails closed). Fresh boot; admin invites + signs up D and T; adminPOST /api/v1/data/sys_user_permission_set {"user_id":D,"permission_set_id":{showcase_field_ops_delegate}}→ 201 andPOST /api/v1/data/sys_business_unit_member {"business_unit_id":"bu_field_ops","user_id":D}→ 201; as DPOST /api/v1/data/sys_user_position {"user_id":T,"position":"contributor","business_unit_id":"bu_west_coast"}. Expected 2xx; actual403 PERMISSION_DENIED "… outside the delegated subtree". Seededsys_business_unitrows still readorganization_id: null; stamping the org onto them flips D's create to 201.api-backend.rest-metadata-config-contract A4 — authorization class. Detail withheld pending maintainer (RUNNER rule 2). Verifier V1: CONFIRMED (narrower: no data values cross the boundary).
automation.trigger-status-contract A5 / A6 / A7 — resume refusals put status-derived codes on the wire. Admin
POST /api/v1/automation/showcase_reassign_wizard/trigger {"recordId":{a task id}}→ 200runId; then onPOST /api/v1/automation/showcase_reassign_wizard/runs/{runId}/resume:{"inputs":{}}→ 400VALIDATION_ERROR(expectedINVALID_SCREEN_INPUT);{"inputs":{"new_assignee":"x"},"output":{"$User":{}}}→ 400VALIDATION_ERROR(expectedINVALID_SIGNAL);…/runs/run_nope/resume→ 404RESOURCE_NOT_FOUND(expectedRUN_NOT_FOUND); resuming a run whose flow was deleted → 404RESOURCE_NOT_FOUND. The run stayspausedand statuses are right; the SDK'serr.codetherefore never carries the documented codes (A7). Verifier V3: CONFIRMED.platform-core.manifest-install-contract A2 — admin
POST /api/v1/packages {"manifest":{"id":"com.example.qa-old","name":"Old","version":"1.0.0","scope":"project","type":"app","engines":{"protocol":"^16"}}}. Expected a 4xx carryingrequiredRange,rangeSource,protocolVersion,targetMajor,migrateCommand; actual500 {code:"OS_PROTOCOL_INCOMPATIBLE", message, httpStatus:500}with the fields only inside the prose. The refusal itself holds (nothing installed, A1 passes). Verifier V4: CONFIRMED.platform-core.marketplace-install-local-lifecycle A5 — boot with
OS_CLOUD_URL=offfrom a scratch copy of the showcase;os package install {examples/app-crm/dist/objectstack.json} -r http://localhost:{p}; adminPOST /api/v1/marketplace/install-local/com.example.crm/purge-sample-data {}. Expected{deleted, skipped, errors}; actual500 DRIVER_UNAVAILABLE "driver service unavailable — cannot purge.", nothing deleted. Verifier V4: CONFIRMED, and found a second fault behind it (below).Checklist clauses (no product defect)
INVALID_OR_EXPIRED, byte-identical to an unknown token (the delete cascades the link row; fail-closed so "record gone" is not readable); 410RECORD_GONEis race-onlyNOT_OVERRIDABLE; a runtime-created name drafts 200ee58392e1(#6608), predates the clause's rev 3NOT_ATTEMPTEDtail);options.continueOnError:truegives "neither blocks the other"batch.zod.tscontinueOnErrordefault,744b8f5f5(#7581)OS_SERVER_TIMING=truesends spans to every caller; env off +X-OS-Debug-Timingis admin-only; the SQL-shape detail header is admin-only in both (verified)hono-plugin.ts:83-104,300-353, #3163 / #3169sys_user.enable_two_factordeclares aresultDialog(QR + code list), nosuccessMessage266654d82e(#11110, fixes #10681)generate_backup_codesdeclares aresultDialog266654d82e(#11110)columnCountis 7 per table (the fixture'sinitObjectsaddscreated_at/updated_at)external-fixture.ts:36-45fields.{f}.primaryKey;ObjectSchemais a value import forObjectSchema.create4257e4e4e3(#11073, ruling D of #11000)platform-objectsarray holds 46 names (46 at 17.6.0 too); the one-owner assertion holdsplatform-object-names.ts901e7cf13(#21581)unique:trueis the composite(organization_id, field)and the 409 names the object, never a guessed column9a4182a75(#21598);duplicate-record-error.tsPartial-coverage gaps (named, not dropped)
access-security.rls-both-sidesA6 — blocked(dependency): the clause forbids ticking it without the private D11 write-up; the by-handproject_membershipprobe answered 403 on GET / list / PATCH.access-security.write-path-guardsN2 — no REST door for an in-processisSystemwrite and no pin targets it.api-backend.route-ledger-live-parityA10,automation.packaged-flow-clone-contractA7 (Studio half),platform-core.metadata-registry-servingA7 — browser halves, deferred to the post-chore(objectui): bump the console pin to objectui main (past 973fc20f) before the 17.7 checklist run — carries objectui#11574, #11578, #11581 and the V1 declared-node slot #21696 run.api-backend.declarative-endpoint-executionA3 — no live script/proxy endpoint without editing source (runtimeapiauthoring is code-only by design,api注册表条目声明 allowRuntimeCreate: true,但运行时创建的端点匹配器永远看不见 —— 声明的能力运行时不兑现(真实 boot 实测) #5488).records-forms.predicate-relationship-traversalA4 — no stock persona with invoice CRUD and no account read (showcase_member_defaultgrants account read; the item's knownGap says otherwise). The behaviour holds on a scratch-object substitute.Fixed since the last run
9f13c949b(fix(objectql)!: a string comparand against a boolean field is narrowed to its boolean, or refused 400, at the engine filter door #21372).Close-out (extracted cards, checklist-accuracy findings) follows in a comment.
Generated by Claude Code