Repository navigation
Description
domain:devx#1 · os-warren · session_01JQwxbZpHPpovxXPremPLtv
Part of #27377 (wave 4, W4-C1: the standing priority:P0 smoke for the 18.3.0 release candidate)
This run re-judges every P0 item at the wave-4 subject 7fa9873f. It compares each item against the wave-3 P0 record #28545 (at eeec88d1) and the wave-3 retest #28656 (at 6e11a929).
Result: all 23 runnable items have a verdict: 21 PASS, 2 PARTIAL, 0 FAIL, 0 BLOCKED, 0 NOT-RUN.
Against #28545 (20 PASS / 2 PARTIAL / 1 FAIL), one verdict moved:
approvals.account-app-entrywent FAIL → PASS. A non-admin pending approver now opens the request page from Account › Inbox › Approvals, sees the decision panel, and Approve → Confirm answersPOST /api/v1/actions/sys_approval_request/approval_approve200 with the request moving 0/2 → 1/2. Reject, Request info and Reply also land for the non-admin, and the?request=deep link cold-loads that request's page. This re-judges Approvals: a non-admin approver who opens an approval request from the Approvals inbox sees "You don't have access to Approval Request records" instead of the decision panel (regression from #27713) #28546 and approvals: a non-admin approver's decision from the request page answers 404 RECORD_NOT_FOUND — the action door loads sys_approval_request in the caller's data scope #28657 (PR fix(runtime): a non-admin approver's decision from the request page reaches the approvals routes instead of answering 404 #28708) at this subject.- The two PARTIALs are the same standing
blocked(dependency)clauses as at QA run · priority:P0 (23/23) · eeec88d1 · 2026-11-01 · 20 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #28545:access-security.rls-both-sidesacceptance[5] (knownGaps[0], qa(checklist): park the blocked partial-coverage gaps of the 17.7 pre-release runs (#21720, #21721, #21782, #21784) — each gets a fixture recipe, a pin, a re-pointed clause or a recorded knownGap #22017 row 11) andaccess-security.crud-permission-matrixacceptance[5] (security: no door can bind a permission set to theguestanchor — ADR-0138 D3 item 5 has no enforcer (PUT /meta/position/guestanswers 403 NOT_OVERRIDABLE; guest suggestions are refused) #23267).
Other findings:
- The off-clause probes produced five low-severity product cards (close-out comment).
- One security finding was reported privately to the PM; its detail is withheld here. Off-clause rows score nothing (RUNNER rule 8), so it moves no item verdict.
- Three wave-3 probe cards were re-checked and hold at this subject: Metadata API: GET /api/v1/meta/app?id= with an empty value ignores the filter and answers the caller's full app list #28548, Datasources: POST /api/v1/datasources accepts and silently drops a top-level password or connectionString that os compile refuses, answering 201 #28549, MCP: aggregate_records silently drops an aggregation entry's
filter, so a conditional count answers the unconditional total (REST honours it) #28550.
Environment fingerprint
- Framework:
7fa9873f38f7a0158e3ce17338dcc0f446b113e3(main, 2026-11-02 02:44Z), a detached checkout includingui/.git statuswas clean before and after the run. - Build (cold tree, in this checkout):
pnpm install --frozen-lockfile, exit 0 (24 s);pnpm build --concurrency=2underscripts/pm/os-verify-lock.sh, 117/117 tasks, exit 0, 03:34:39Z–03:47:26Z (12m47s);pnpm console:build --concurrency=2, exit 0:✓ @objectstack/console dist ready (82304 KB) from ui/apps/console, with the tracked sdui.manifest.json;node scripts/check-dev-prereqs.mjsgreen (106 artifacts).
- Stale console bundle, ruled out: the dispatcher boot and every browser runner's boot served
/_console/entryassets/index-DqtqClJh.js, the same file aspackages/console/dist/assets; R5 and R6 compared the bytes (sha256 prefix 44a80d196d2562bc), identical. - Toolchain: Node 22.23.4, pnpm 10.31.0. Playwright 1.63.0 resolves chromium build 1243, which
/opt/pw-browsersholds, so noexecutablePathoverride was needed. - App:
examples/app-showcase.- One dispatcher
os devcompile boot (port 43001) wrotedist/objectstack.jsonat 03:47:53Z; every later tree boot used--no-compile --no-watch. - Items that compile, install a package, write the external datasource or touch a v17/18.0 DB booted from scratch copies (tar,
node_modulessymlinked):verify --rls, the datasource matrix, Studio first-run, the MCPos startlegs, the dev-boot contract, the ceremony and the boot-refusal legs. - After the run
examples/app-showcase/.objectstack/holds onlydata/(noinstalled-packages/).
- One dispatcher
- Boot line:
OS_PORT=PORT OS_STORAGE_LOCAL_ROOT=RUN/uploads setsid pnpm -C … exec objectstack dev --ui --seed-admin --no-compile --no-watch -p PORT -d file:RUN/ITEM.db, with--fresh/--log-level infowhere an item asks for them.- Seed:
--seed-adminplus the showcase seed,Seeds: com.example.showcase 132 rows./api/v1/healthreports version 18.2.0, the unreleased line.
- Seed:
- Ports: 43001 (dispatcher), 43101–43103 (R1), 43201–43205 (R2), 43301–43304 (R3), 43401–43413 (R4), 43501–43504 (R5), 43601–43602 (R6), 43701–43702 + 43719 PostgreSQL (R7). Each item ran on its own file DB under its runner's scratch dir. Every server was stopped by process group, and every port was empty at the end.
- Walled leg:
os devwithOS_TENANCY_POSTURE=isolated,OS_PLATFORM_OWNER_EMAIL=admin@objectos.ai,OS_AUTH_MEMBERSHIP_POLICY=invite-only. BannerTenancy: isolated,Organizationsmounted, 0 DEGRADED lines;/auth/configmultiOrgEnabled true, degradedTenancy false. - v17-shaped DB: from npm
create-objectstack@17.7.0(--skip-install --skip-skills, thennpm install --legacy-peer-deps, cli/runtime/spec 17.7.0), a blank scaffold booted once by its ownos dev: 69 tables, 61 rows. 18.0 pre-release DB: thecli-18-prerelease-dbrestore (born under@objectstack/cli@18.0.0-next.5), recipe step 3 re-dating the token. Only copies were used, with a checksum or row diff around every step. - Scratch PostgreSQL 16: 127.0.0.1 port 43719, scram-sha-256, data dir under
/tmpper the item's knownGaps[2]. - Timestamps (2026-11-02): prep 03:33Z–03:49Z; runners 03:49Z–04:21Z.
Execution
Parallel, per SKILL §2: seven runner subagents (R1–R7), each at effort high on the default tier (dispatch-gates: no path-derived mandate), each with its own port range and file DBs.
- API and CLI items fanned out (R1–R4).
- Browser and mixed items ran on three runners (R5, R6, R7), one browser each.
- Vitest pins ran under the shared heavy-verify lock at
--maxWorkers=1.
The dispatcher checked each runner's verdicts against the evidence it returned: pin outputs, HTTP traces, boot logs and response bodies. No P0 fail was recorded, so no rule-7 verifier was owed.
Scope: selector priority:P0, 23 runnable items
checklist-select.mjs reported 23 runnable items and 1 blocked item, hidden: access-security.no-active-org-session-semantics. No item is planned.
| item | revision | surface | runner | #28545 | now |
|---|---|---|---|---|---|
| access-security.rls-both-sides | 10 | api | R1 | PARTIAL | PARTIAL |
| access-security.write-path-guards | 8 | api | R1 | PASS | PASS |
| access-security.crud-permission-matrix | 12 | api | R1 | PARTIAL | PARTIAL |
| access-security.owd-sharing-matrix | 9 | api | R2 | PASS | PASS |
| access-security.anonymous-deny-surfaces | 5 | api | R2 | PASS | PASS |
| access-security.walled-environment-metadata-operator-only | 8 | api | R2 | PASS | PASS |
| ai.mcp-stdio-fail-closed | 9 | cli | R4 | PASS | PASS |
| api-backend.query-contract-matrix | 9 | api | R3 | PASS | PASS |
| api-backend.packaged-action-disabled-dispatch | 11 | api | R3 | PASS | PASS |
| approvals.account-app-entry | 8 | browser | R6 | FAIL | PASS |
| automation.packaged-flow-disable-durable | 8 | api | R3 | PASS | PASS |
| cli.dev-boot-contract | 9 | cli | R4 | PASS | PASS |
| cli.organization-ownership-ceremony | 8 | cli | R4 | PASS | PASS |
| identity-auth.default-organization-boot-invariant | 4 | api | R2 | PASS | PASS |
| integration-system.datasource-credential-refusal-matrix | 8 | mixed | R7 | PASS | PASS |
| platform-core.boot-health | 13 | mixed | R5 | PASS | PASS |
| platform-core.seed-integrity | 6 | api | R3 | PASS | PASS |
| platform-core.console-login | 4 | browser | R5 | PASS | PASS |
| platform-core.nav-surfaces-render | 10 | browser | R5 | PASS | PASS |
| platform-core.builtin-apps-nav-render | 12 | browser | R5 | PASS | PASS |
| platform-core.v18-boot-refusals | 9 | cli | R4 | PASS | PASS |
| records-forms.crud-roundtrip | 17 | browser | R6 | PASS | PASS |
| studio-authoring.first-run-loop | 10 | mixed | R7 | PASS | PASS |
Items whose revision moved since #28545: crud-permission-matrix 11→12, owd-sharing-matrix 8→9, walled 7→8, mcp-stdio 8→9, query-contract-matrix 8→9, packaged-action-disabled-dispatch 10→11, account-app-entry 7→8, ceremony 7→8, datasource matrix 7→8, nav-surfaces-render 8→10, builtin-apps-nav-render 11→12, crud-roundtrip 16→17, first-run-loop 8→10. Each was scored at its current revision, and each runner read the new history entry.
Per-clause verdicts
Layer note (RUNNER rule 6). A clause scored from a pin names the pin's layer:
- dogfood pins are in-process HTTP over a real engine and sqlite;
- objectql pins are the engine over a mock or recording driver;
- plugin-unit and dispatcher-domain pins over stubs only corroborate.
Every clause whose oracle is a public door's answer was also driven on a live boot.
| item · clause | verdict | text oracle evidence |
|---|---|---|
| access-security.rls-both-sides · acceptance[0] | pass | live x2, members minted by invite + sign-up (sys_member role member, 0 set grants): A's list n=2 both A notes, no B id; B's list n=1 only B. Pin showcase-private-owd green [HTTP in-process] |
| access-security.rls-both-sides · acceptance[1] | pass | live x2: A GET /data/showcase_private_note/B_ID → 404 RECORD_NOT_FOUND, the same envelope as an unknown id; B→A symmetric |
| access-security.rls-both-sides · acceptance[2] | pass | live x2: A PATCH B_ID {body:'forged'} → 404; admin pre/post re-read byte-identical (body, updated_at); pin case ✓ |
| access-security.rls-both-sides · acceptance[3] | pass | live x2: admin list holds every id the run created (n=3, then 6); pin 'the admin (platform posture) lists every note' ✓ |
| access-security.rls-both-sides · acceptance[4] | pass | objectstack verify --rls on a scratch copy, exit 0. Per-persona line 21 PROVEN (21 consistent, 0 HOLES) · 3 NOT PROVEN (0 member-visible, 0 probe-blocked, 3 skipped). Total line all personas: 38 PROVEN (38 consistent, 0 HOLES) · 226 NOT PROVEN (131 member-visible, 62 probe-blocked, 33 skipped) [unit: one object × persona probe]. 10 of 10 positions. Adopted-row proof on showcase_account only. Bare-verify control (own invocation) tail 15 verified, 0 gaps, 0 FAILED, 1 needs-fixture, 8 skipped (0 mismatches), no PROVEN line |
| access-security.rls-both-sides · acceptance[5] | blocked | blocked{by: dependency, ref: knownGaps[0] / #22017 row 11}: the D11 spot-check needs the private write-up. Public half holds: 3 benign skips (project_membership no plain-text probe field; ext_customer / ext_order external read-only); member spot-check project_membership GET/PATCH 403/403, ext_* GET 403 and PATCH 403 EXTERNAL_WRITE_FORBIDDEN, admin re-reads identical |
| access-security.rls-both-sides · negative[0] | pass | forged PATCH 404, admin re-read unchanged (live x2 + pin) |
| access-security.rls-both-sides · negative[1]–[2] | pass | procedural: the D11 verdict is carried on acceptance[5] only; the record cites item and clause, never the bare handle |
| access-security.write-path-guards · acceptance[0] | pass | live x2 (admin): POST showcase_contact {lead_score:10} → 201, header X-ObjectStack-Dropped-Fields: lead_score;reason=readonly, body droppedFields, read-back null. Pin static-readonly green [HTTP] |
| access-security.write-path-guards · acceptance[1] | pass | live x2: PATCH {lead_score:99} → 200 with the dropped header; null before and after |
| access-security.write-path-guards · acceptance[2] | pass | live x2 as member Alice: POST note {owner_id:Bob} → 403 PERMISSION_DENIED ("owner_id … is system-managed"); 0 planted rows |
| access-security.write-path-guards · acceptance[3] | pass | live x2: self-owner 201; PATCH owner_id=Bob and owner_id=null → 403; owner re-reads Alice |
| access-security.write-path-guards · acceptance[4] | pass | live x2: bare-array createMany of 3 → 201, all owner Alice; {records:[…]} → 400 VALIDATION_FAILED. Pin owner-anchor-and-bulk-writes green |
| access-security.write-path-guards · acceptance[5] | pass | live x2: paid invoice PATCH tax_rate:20 → 200, header tax_rate;reason=readonly_when, re-reads 5; line quantity/unit_price/product dropped readonly_when; mixed updateMany: paid line droppedFields quantity readonly_when (re-reads 2), open line lands (7). Pin readonly-when-parent green |
| access-security.write-path-guards · acceptance[6] | pass | live x2: continueOnError [3,-1,3] → total 3 / succeeded 2 / failed 1, codes [ok, VALIDATION_FAILED, ok], re-read [3,2,3]; default stop [4,-1,4] → [ok, VALIDATION_FAILED, NOT_ATTEMPTED], re-read [4,2,3] |
| access-security.write-path-guards · negative[0] | pass | live x2 admin: forge-insert 201 owner Bob; transfer 200; disown 200 owner null; pin cases ✓ |
| access-security.write-path-guards · negative[1] | pass | engine layer (real ObjectQL over recording/fake driver, own test objects): 2 files 55/55 |
| access-security.crud-permission-matrix · acceptance[0] | pass | live REST sweep x2: 164 showcase_* cells, all 87 effective-allow cells < 300 (max 201) with the effect proven by admin re-read, bad=[]. Pin crud-persona-matrix green [HTTP] |
| access-security.crud-permission-matrix · acceptance[1] | pass | live x2: all 77 deny cells 403 with top-level code PERMISSION_DENIED; delegate sys_user create/delete 405 OBJECT_API_METHOD_NOT_ALLOWED (admin control 405 too) |
| access-security.crud-permission-matrix · acceptance[2] | pass | live x2: admin marker scan after every denied create finds 0 rows |
| access-security.crud-permission-matrix · acceptance[3] | pass | live x2: auditor by-id 200 and in both lists on foreign private_note, inquiry, invoice, line; contributor by-id 404 and absent |
| access-security.crud-permission-matrix · acceptance[4] | pass | live x2: ops PATCHes admin's announcement → 200, persisted; member_default → 403, unchanged |
| access-security.crud-permission-matrix · acceptance[5] | blocked | blocked{by: dependency, ref: #23267} per knownGaps[2]: GET /meta/position/guest 200 with no permissionSets; PUT naming showcase_guest_portal → 403 NOT_OVERRIDABLE, re-read identical; suggested-bindings lists only showcase_member_default@everyone:confirmed; anonymous inquiry POST/GET → 401 |
| access-security.crud-permission-matrix · acceptance[6] | pass | 45 rows recounted (41 showcase_* + 4 delegate × sys_*); live 164 cells (87/77/9 baseline flips, all 9 2xx) + 16/16 delegate cells. Rev-12 steps driven: POST /data/sys_user_permission_set 201 for all 7 sets x2; POST /data/sys_business_unit_member 201 |
| access-security.crud-permission-matrix · negative[0] | pass | live x2: first denied cell of each of 8 sets re-run as admin → 2xx |
| access-security.crud-permission-matrix · negative[1] | pass | no withheld cell answered 2xx (0 over 164 + 16) |
| access-security.owd-sharing-matrix · acceptance[0] | pass | HTTP live, two rounds with fresh personas (get-session proven, isPlatformAdmin false): A POST 201; B list(filter id) n=0, list(all) n=0, GET 404, PATCH 404; A GET/PATCH 200; admin re-read shows A's edit. Pin private-owd 8/8 |
| access-security.owd-sharing-matrix · acceptance[1] | pass | admin-owned announcement: B GET 200 and in list; B forged PATCH 403 PERMISSION_DENIED, unchanged. Pin public-read-owd 4/4 |
| access-security.owd-sharing-matrix · acceptance[2] | pass | ops PATCH of admin's announcement 200, re-read edited. Pin crud-persona-matrix 49/49 |
| access-security.owd-sharing-matrix · acceptance[3] | pass | admin project {name, status:'planned', account} 201 (the rev-9 body); C1 GET 200, PATCH 200 persisted; A's identical PATCH 403, row unchanged |
| access-security.owd-sharing-matrix · acceptance[4] | pass | C1 invoice + line 201; C2 excluded (list n=0, GET 404, PATCH 404, quantity unchanged); C1 contains / 200 / 200. Pin invoice-line-contributor-pair 5/5; controlled-by-parent 4/4 and invoice-cbp 4/4 beneath |
| access-security.owd-sharing-matrix · acceptance[5] | pass | auditor list(filter id) contains C1's line, by-id GET 200 |
| access-security.owd-sharing-matrix · acceptance[6] | pass | procedural: all four models driven per persona and verb, two rounds |
| access-security.owd-sharing-matrix · negative[0]–[1] | pass | B's direct forged PATCH on the public_read announcement → 403, unchanged; C2's line probes repeated as C1: contains / 200 / 200 |
| access-security.anonymous-deny-surfaces · acceptance[0] | pass | HTTP live x2, no header or cookie (anonymous get-session 401): data, meta, actions, automation/_status, batch, security/explain, analytics query/sql (valid and malformed)/meta → 401 UNAUTHENTICATED. Pin showcase-anonymous-deny-surfaces 75/75 |
| access-security.anonymous-deny-surfaces · acceptance[1] | pass | anonymous POST /actions/showcase_task/showcase_mark_done/anon-probe-id → 401; member same call → 404 RECORD_NOT_FOUND |
| access-security.anonymous-deny-surfaces · acceptance[2] | pass | each 401 body matched exactly one family: rest-flat (/data /meta /batch /security/explain), dispatcher-wrapper with httpStatus 401 (/actions /automation, analytics x5) |
| access-security.anonymous-deny-surfaces · acceptance[3] | pass | anonymous analytics → 401 incl. malformed bodies; member query 200 (count 10), sql 200, meta 200, malformed 400 VALIDATION_FAILED |
| access-security.anonymous-deny-surfaces · acceptance[4] | pass | member (not platform admin) GET /data/showcase_private_note 200, GET /meta 200 |
| access-security.anonymous-deny-surfaces · acceptance[5] | pass | anonymous GET /api/v1/forms/contact-us → 200, serving the showcase_inquiry form |
| access-security.anonymous-deny-surfaces · acceptance[6] | pass | procedural: all 7 families driven live, twice |
| access-security.anonymous-deny-surfaces · negative[0] | pass | anonymous DELETE /automation/showcase_reassign_wizard → 401; admin GET afterwards 200 (x2) |
| access-security.walled-environment-metadata-operator-only · acceptance[0] | pass | pins at 7fa9873, maxWorkers=1: rest meta-migrate-stored-walled-refusal 6/6 (unit, vi.fn transport); runtime packages-walled-write-refusal 32/32, automation-walled-definition-write 12/12, meta-walled-catalog-refusal 19/19 (dispatcher-domain units); dogfood wall-environment-metadata-refusal 23/23, wall-catalog-refusal 17/17, wall-package-doors-refusal 23/23 (in-process HTTP, CRM example) |
| access-security.walled-environment-metadata-operator-only · acceptance[1] | pass | HTTP live on the isolated boot, x2, as org owner O (isPlatformAdmin false, holds manage_metadata; pre-grant control: the same PUT answered the capability 403 before the grant, the posture 403 after): PUT /meta/object → 403 FORBIDDEN, read-back 404; PUT /meta/permission/showcase_member_default → 403, sha unchanged; view publish → 403; DELETE /packages/com.example.showcase → 403 PERMISSION_DENIED, still installed; set clone → 403, clone 404; _migrate-stored preview and apply → 403 FORBIDDEN; POST /automation → 403, flow absent. Messages name the 'isolated' posture |
| access-security.walled-environment-metadata-operator-only · acceptance[2] | pass | walled operator PUT 200 "Saved object 'qa_walled_probe' (env-wide)", read-back, DELETE 200, read-back 404 (x2); single fresh boot admin same (x2) |
| access-security.walled-environment-metadata-operator-only · negative[0] | pass | no org-owner environment-metadata write succeeded: 7 clause doors x2 + 22 probe doors; every read-back absent or unchanged |
| identity-auth.default-organization-boot-invariant · acceptance[0] | pass | plugin-auth ensure-default-organization 57/57 (plugin unit, fake ql); runtime identity-objects-default-organization.pin 4/4 (engine, reduced kernel) |
| identity-auth.default-organization-boot-invariant · acceptance[1] | pass | fresh boot --log-level info: 04:00:14.830Z INFO [default-org] created the Default Organization before 04:00:18.043Z Dev admin seeded; DB created_at order agrees (org 04:00:14.827Z, first sys_user 04:00:17.833Z) |
| identity-auth.default-organization-boot-invariant · acceptance[2] | pass | sys_member: admin owner, created user member; get-session activeOrganizationId = the default org for both |
| identity-auth.default-organization-boot-invariant · acceptance[3] | pass | sys_business_unit 5 rows, all organization_id = default org |
| identity-auth.default-organization-boot-invariant · negative[0] | pass | node:sqlite scan: 106 tables, 64 carry organization_id, 165 rows, 0 NULL / 0 empty; re-scanned after probes, 167 rows, 0 NULL |
| ai.mcp-stdio-fail-closed · acceptance[0] | pass | live os start stdio (OS_MCP_STDIO_ENABLED=true), key unset: exit 1, stdout 0 bytes, health 000, "…OS_MCP_STDIO_API_KEY is not set … Refusing to start an unscoped stdio server (ADR-0101)" |
| ai.mcp-stdio-fail-closed · acceptance[1] | pass | osk_unknown exit 1 "did not resolve to a valid identity"; revoked key exit 1 "is refused (API_KEY_REVOKED)"; health 000 both |
| ai.mcp-stdio-fail-closed · acceptance[2] | pass | --log-level info: "[MCP] stdio transport principal-bound to OS_MCP_STDIO_API_KEY identity … (RLS/FLS/tenant applied)", the contributor's user id (liaison boot printed the liaison's) |
| ai.mcp-stdio-fail-closed · acceptance[3] | pass | contributor MCP == REST (1 own invoice, identical 19-field set; INV-1003 not found / 404; admin 13 both doors); liaison project rows lack budget/spent/budget_remaining on MCP and REST lists and gets; admin REST 23 fields |
| ai.mcp-stdio-fail-closed · acceptance[4] | pass | count by status: member MCP [{draft:1}] == member REST; admin draft 3 / paid 5 / sent 5 |
| ai.mcp-stdio-fail-closed · acceptance[5] | pass | liaison sum(budget), groupBy budget, count_distinct(spent) → isError PERMISSION_DENIED 403 "[Security] Field read denied …", no number; REST same 403; controls equal on both doors |
| ai.mcp-stdio-fail-closed · acceptance[6] | pass | same stdio session: pre-revoke 1 row; revoke via admin API key → 403 "requires a signed-in session" (rev-9 note), via admin session → 200; next call isError API_KEY_REVOKED 403, no rows |
| ai.mcp-stdio-fail-closed · acceptance[7] | pass | --log-level info, no stdio env, health 200: "[MCP] Transport not auto-started (HTTP is served per-request at /api/v1/mcp regardless)…" |
| ai.mcp-stdio-fail-closed · negative[0]–[4] | pass | unset, whitespace, osk_, unknown, revoked and "Bearer osk_…" keys never serve (exit 1, health 000); member 1 vs admin 13; masked aggregates refused; post-revoke API_KEY_REVOKED |
| api-backend.query-contract-matrix · acceptance[0] | pass | HTTP live: 38 variant rows × 3 doors (POST $-body, POST AST, GET $filter) = 114 calls, id sets equal to the unfiltered local baseline, 0 diffs; $contains:'ORTH' / $startsWith:'con' case-exact (0); infix compound → POST 400 VALIDATION_FAILED, GET 400 INVALID_FILTER |
| api-backend.query-contract-matrix · acceptance[1] | pass | $top=3&$skip=2 = Fabrikam, Globex, Hooli; $top=4&$skip=9 and $top=5&$skip=12 equal the local slices; POST {limit,offset} and {top,skip} identical |
| api-backend.query-contract-matrix · acceptance[2] | pass | $select=name,status and POST fields → 14 rows, keys exactly {name,status}; POST fields:['account.name'] → 400 INVALID_FIELD naming expand |
| api-backend.query-contract-matrix · acceptance[3] | pass | annual_revenue asc/desc on both doors equal the local order; no_such_field → 400 INVALID_SORT on both |
| api-backend.query-contract-matrix · acceptance[4] | pass | contributor (recipe search:qa-contributor-bound-member, get-session proven): contact direct 403; expand via body, $expand, by-id expand → contact stays the raw id, no name/email; admin materialised. Pin showcase-expand-crud-gate green [HTTP] |
| api-backend.query-contract-matrix · acceptance[5] | pass | {status:{$nin:'done'}} → 400 VALIDATION_FAILED at query.where.status.$nin; AST → 400 at query.where; GET $filter → 400 INVALID_FILTER; no rows |
| api-backend.query-contract-matrix · acceptance[6] | pass | ?$pageSize=5 → 400 UNSUPPORTED_QUERY_PARAM listing 9 params; ?not_a_field=x and where on it ($eq, $ne, AST, GET !=) → 400 INVALID_FIELD |
| api-backend.query-contract-matrix · acceptance[7] | pass | $in:[] → 0/10; $nin:[] → 10/10; AST twins equal on POST and GET |
| api-backend.query-contract-matrix · acceptance[8] | pass | one recorded row per variant; $count true (total 14) / false (omitted), $search, $expand=account rows recorded |
| api-backend.query-contract-matrix · negative[0] | pass | {limit:"ten"} → 400 at query.limit; {not_a_query_key:…} → 400 INVALID_FIELD; no rows; control 200 |
| api-backend.query-contract-matrix · negative[1] | pass | new at rev 9 (#26644): empty $select / select / fields, $select=%20, $select=,, bad $count, by-id ?select= → 400 VALIDATION_ERROR naming the spelling; POST {fields:[]}, {select:""}, {count:"maybe"} → 400 VALIDATION_FAILED; no rows; 4 controls 200. rest pins request-schema-gate + data-empty-projection-count-door 21 green (route-handler layer) |
| api-backend.packaged-action-disabled-dispatch · acceptance[0] | pass | flip 200, exactly 1 ledger row (keys without organization_id); mark_done bogus and real id → 409 ACTION_DISABLED "This action is turned off for this deployment. An administrator can turn it on again under Setup › Packaged automation, or you can use another action."; 10 tasks unchanged |
| api-backend.packaged-action-disabled-dispatch · acceptance[1] | pass | gallery disabled + garbage params → 409; re-enabled identical → 400 VALIDATION_ERROR naming p_text and bogus_key |
| api-backend.packaged-action-disabled-dispatch · acceptance[2] | pass | every disabled 409 had the bogus recordId in play and wrote nothing; enabled control 404 RECORD_NOT_FOUND |
| api-backend.packaged-action-disabled-dispatch · acceptance[3] | pass | showcase_zoo_perm_missing → 403 PERMISSION_DENIED "requires capability [showcase.restricted_ops]", enabled and disabled, byte-identical |
| api-backend.packaged-action-disabled-dispatch · acceptance[4] | pass | live POST /api/v1/mcp tools/call run_action showcase_portfolio_snapshot disabled → isError ACTION_DISABLED 409, message string-equal to REST; re-enabled ok |
| api-backend.packaged-action-disabled-dispatch · acceptance[5] | pass | cold restart: INFO "Activation ledger: 1 packaged action(s) are switched off … 'showcase_mark_done'"; still 409; re-enable 200; real id 200 (done true, progress 100); same ledger row id |
| api-backend.packaged-action-disabled-dispatch · acceptance[6] | pass | showcase_bulk_reassign disabled → 409 ACTION_DISABLED with the turned-off sentence (rev 11); showcase_reassign_wizard no ledger row, 0 runs before and after |
| api-backend.packaged-action-disabled-dispatch · negative[0]–[2] | pass | disabled calls never got the param 400 or a record answer; 0 rows = stock answers; the 403 wins; anonymous 401 |
| automation.packaged-flow-disable-durable · acceptance[0] | pass | baseline urgent create runs 0→1 (completed); toggle off 200; exactly 1 row (flow, active false, no organization_id key); no "IN PROCESS ONLY" log |
| automation.packaged-flow-disable-durable · acceptance[1] | pass | trigger → 409 FLOW_DISABLED "This flow is turned off for this deployment. An administrator can turn it on again under Setup › Packaged automation, or copy it there under a new name." |
| automation.packaged-flow-disable-durable · acceptance[2] | pass | cold restart: _status enabled false, bound false; INFO "[Automation] Activation ledger: 1 packaged flow(s) are switched off … 'showcase_urgent_task_alert'" |
| automation.packaged-flow-disable-durable · acceptance[3] | pass | new process: urgent create 201, runs stay 1 after 8 s; trigger still 409 |
| automation.packaged-flow-disable-durable · acceptance[4] | pass | toggle on 200; same row id, active true, updated_at moved; _status bound true; final create runs 1→2 |
| automation.packaged-flow-disable-durable · negative[0]–[3] | pass | row written; restart did not re-arm; row kept; never the bare status sentence |
| platform-core.seed-integrity · acceptance[0] | pass | expected counts derived from ShowcaseSeedData source (19 datasets / 132 rows); $top=1 totals and full list lengths match 19/19 |
| platform-core.seed-integrity · acceptance[1] | pass | Specimen — Full: 37/37 fields match; lookups resolve; f_time '14:30:00'; f_password masked as declared |
| platform-core.seed-integrity · acceptance[2] | pass | banner Seeds: com.example.showcase 132 rows plain; [Seeder] … {"inserted":132,…,"errored":0}; no dropped-record line |
| platform-core.seed-integrity · acceptance[3] | pass | restart over the same DB: identical sweep; {"inserted":0,"updated":0,"skipped":132,"errored":0} |
| platform-core.seed-integrity · acceptance[4] | pass | f_user, f_users, f_secret null; task.cover null on all 10 |
| platform-core.seed-integrity · negative[0]–[1] | pass | no seeded object counts 0; counts did not grow |
| cli.dev-boot-contract · acceptance[0] | pass | scratch copy with no dist (first boot compiled): health 200 after 17 s, /ready 200 {status:ready,state:running} |
| cli.dev-boot-contract · acceptance[1] | pass | admin123 sign-in 200; restart with --admin-password changed99 on the same DB: admin123 200, changed99 401 |
| cli.dev-boot-contract · acceptance[2] | pass | Database lines: -d file: / OS_DATABASE_URL / :memory: / nothing chosen → .objectstack/data/objectstack.db / config qa_home (no objectstack.db) / legacy dev.db with notice |
| cli.dev-boot-contract · acceptance[3] | pass | "🧪 Fresh OS_HOME: /tmp/objectstack-dev-…"; SIGINT EXIT=130 and SIGTERM EXIT=143, tempdir gone both times |
| cli.dev-boot-contract · acceptance[4] | pass | "⚠ Port 43407 is in use — serving on 43408 instead." + "↪ server bound to port 43408 (requested 43407)"; health 200 |
| cli.dev-boot-contract · acceptance[5] | pass | --no-compile after a source touch: "⚠ dist/objectstack.json is OLDER than your sources …", no compile, boots |
| cli.dev-boot-contract · acceptance[6] | pass | empty dir: exit 1 with the remedy line |
| cli.dev-boot-contract · acceptance[7] | pass | screenshot first: ObjectOS "Welcome back" at /_console/login; served entry equals dist; form sign-in reaches /_console/home, get-session 200 |
| cli.dev-boot-contract · negative[0]–[3] | pass | marker survives reboot; --database-driver memory exit 2 with INVOCATION ERROR, OS_DATABASE_DRIVER=memory/mingo/in-memory and memory:// / mingo:// exit 1 naming --fresh and :memory:; legacy read creates no objectstack.db; shifted port reported |
| cli.organization-ownership-ceremony · acceptance[0] | pass | unit/integration over SQLite, no HTTP: cli 8 ceremony files 179/179; runtime boot-guard 22/22 |
| cli.organization-ownership-ceremony · acceptance[1] | pass | refused boot, then plan exit 0 "no row or table … changed", primary sha and telemetry rows unchanged; --apply without plan exit 1 (--json reason plan-file-required) |
| cli.organization-ownership-ceremony · acceptance[2] | pass | apply: exit 0, complete true, blocking 0, 13 steps done; marker shapeGeneration 1 == ORGANIZATION_OWNERSHIP_SHAPE_GENERATION |
| cli.organization-ownership-ceremony · acceptance[3] | pass | unmigrated copy: exit 1, 0 ready lines, names 9 tables and the ceremony commands; migrated copy "✓ Server is ready", health 200 |
| cli.organization-ownership-ceremony · acceptance[4] | pass | raw v17 copy: reactions conversion refused without --yes, exit 0 twice with it; migrate apply --allow-destructive --yes exit 1 refused_organization_ownership_unmigrated, sha unchanged, row diff 0 |
| cli.organization-ownership-ceremony · acceptance[5] | pass | cli-18-prerelease-db restore, all --dev: boot 1 refused (row diff 0); plan exit 0; apply complete / blocking 0 (sibling-moves 10 / jobs 2 / activity 14, column-drops 2, not-null 66); boot 2 ready; moved identity mails 0 diffs, 8 audit rows moved, 2 mail jobs re-pointed; 3 sign-ins 200 / wrong password 401; reset with the moved mail's token → 200; one task PATCH → exactly 1 sys_http_delivery row |
| cli.organization-ownership-ceremony · negative[0] | pass | no refusing or plan arm changed any checksum or row |
| platform-core.v18-boot-refusals · acceptance[0] | pass | runtime boot-guard 22/22 + kernel 10/10 (unit + kernel, no HTTP); plugin-security authz-identity-objects-boot-refusal 3/3 |
| platform-core.v18-boot-refusals · acceptance[1] | pass | production os serve over a v17 copy (secret + key set): exit 1, 0 listening lines, names 9 tables and the commands without --dev; 0 hits "17.x release"; --dev copy spells --dev |
| platform-core.v18-boot-refusals · acceptance[2] | pass | row diff: production copy 69 tables / 61 rows 0 differences, 53 created tables empty; dev copy 0 differences, telemetry sibling unchanged |
| platform-core.v18-boot-refusals · acceptance[3] | pass | live rig (serve --dev --no-server --preset minimal, SecurityPlugin + one object): exit 1 "✗ SecurityPlugin cannot boot … mount createIdentityObjectsPlugin()" |
| platform-core.v18-boot-refusals · negative[0] | pass | every v18 boot over a v17 copy refused and left pre-existing rows unchanged |
| platform-core.boot-health · acceptance[0] | pass | health 200 {status:ok, version 18.2.0}, 37.6 s from pnpm launch on a loaded shared box |
| platform-core.boot-health · acceptance[1] | pass | /api/v1/ready 200 {status:ready,state:running}, the first non-health request |
| platform-core.boot-health · acceptance[2] | pass | boot window captured to its own file: Flows: 32 flow(s) 19 bound … · 8 draft; two ℹ deployment-policy lines; 0 ⚠, 0 ERROR |
| platform-core.boot-health · acceptance[3] | pass | GET meta/app?id=showcase_app 200 {type,items}; app list [showcase_app, setup, account] |
| platform-core.boot-health · acceptance[4] | pass | 59 authored nav ids vs 59 served: diff empty; grp_data 12 objects |
| platform-core.boot-health · acceptance[5] | pass | /_console/ 200 text/html, entry index-DqtqClJh.js (byte-identical to dist) |
| platform-core.boot-health · negative[0]–[1] | pass | no seed rejection; 0 ERROR lines in the boot window |
| platform-core.console-login · acceptance[0] | pass | form sign-in 200, landed /_console/home; screenshot: header + launcher; cookie and localStorage token both set |
| platform-core.console-login · acceptance[1] | pass | reload stays on /home; get-session, discovery, i18n, meta/app 200 |
| platform-core.console-login · acceptance[2] | pass | sign-out 200; same bearer: meta/app, get-session, data → 401 UNAUTHENTICATED (both runs) |
| platform-core.console-login · acceptance[3] | pass | full navigation → /_console/login?redirect=%2Fapps%2Fcom.example.showcase%2Fshowcase_task; client nav shows the named "Sign in required" state |
| platform-core.console-login · acceptance[4] | pass | re-login 200 returns to showcase_task (10 rows); fresh reads 200, write 201 |
| platform-core.console-login · negative[0]–[1] | pass | wrong password 401 INVALID_EMAIL_OR_PASSWORD, no cookie, no token, alert shown; no stale data after expiry; 0 page errors |
| platform-core.nav-surfaces-render · acceptance[0] | pass | browser over live HTTP (port 43503): examples/app-showcase/e2e/showcase-smoke.spec.ts 50 passed, 0 failed (2.1 min), incl. the new /reports entry |
| platform-core.nav-surfaces-render · acceptance[1] | pass | 51 served leaves = 50 + nav_sep_reports separator (25 page / 17 object / 5 report / 3 dashboard) vs 50 SURFACES: diff empty, nothing hand-walked (rev 10) |
| platform-core.nav-surfaces-render · acceptance[2] | pass | bad route on 2 fresh contexts: shell alive, "Object Not Found — The object …", 0 page errors |
| platform-core.nav-surfaces-render · acceptance[3] | pass | no render failure met; the boundary fallback is unexercised (existing knownGap) |
| platform-core.nav-surfaces-render · negative[0]–[3] | pass | suite: no blank main; splash wait held on 50; bad route kept the shell; charts passed the polled boundingBox check |
| platform-core.builtin-apps-nav-render · acceptance[0] | pass | admin, every group expanded, screenshot-first walk: Setup 47/47, Account 8/8, 0 pageerror; only "failed to load" is the knownGap marketplace (wire 502 MARKETPLACE_PROXY_FAILED); 11 settings namespaces render |
| platform-core.builtin-apps-nav-render · acceptance[1] | pass | setup: requiredPermissions [setup.access], 9 groups, 47 leaves = source minus gated organizations / sso_providers; account 8 leaves / 3 groups; ?id=studio 200 empty |
| platform-core.builtin-apps-nav-render · acceptance[2] | pass | member Mei (get-session phone.demo, positions [org_member, everyone]): setup routes show "You don't have access to this app" |
| platform-core.builtin-apps-nav-render · acceptance[3] | pass | member ?id=setup → 200 {items:[]}; GET meta/app/setup → 403 PERMISSION_DENIED; member list [showcase_app, account] |
| platform-core.builtin-apps-nav-render · acceptance[4] | pass | setup unobtainable for the member; account nav admin 8 = member 8 (control) |
| platform-core.builtin-apps-nav-render · acceptance[5] | pass | nav_organizations absent (single); nav_business_units present, sys_business_unit meta and data 200 |
| platform-core.builtin-apps-nav-render · acceptance[6] | pass | no jwks / sso / verification / device_code entries; auth config sso false; data/sys_jwks 404 even for admin |
| platform-core.builtin-apps-nav-render · negative[0]–[3] | pass | no blank pages beyond the marketplace knownGap; member denied on the wire and in the UI; member /api/settings/NS → 403 SETTINGS_FORBIDDEN for all 11 namespaces (admin 200) |
| approvals.account-app-entry · acceptance[0] | pass | layer build: the dispatcher's pnpm console:build at 7fa9873 printed ✓ @objectstack/console dist ready (82304 KB) from ui/apps/console; the served entry (byte-identical to dist) registers approvals:inbox |
| approvals.account-app-entry · acceptance[1] | pass | avatar › Profile › Inbox › Approvals → /_console/apps/com.objectstack.account/component/approvals/inbox; screenshot: My Pending 4 / Submitted by me / All, 4 Pending rows |
| approvals.account-app-entry · acceptance[2] | pass | non-admin X (invite + sign-up, positions contributor + finance, isPlatformAdmin false) GET /meta/app → [showcase_app, account] with nav_account_approvals; ?id=setup empty, GET /meta/app/setup 403 |
| approvals.account-app-entry · acceptance[3] | pass | row click → …/sys_approval_request/record/AREQ renders the decision panel (Approve, Reject, Reassign, Send back, Request info, Send reminder, Recall, Reply); Approve → Confirm → POST /api/v1/actions/sys_approval_request/approval_approve 200; GET /approvals/requests/AREQ got 0/2 → 1/2, X leaves pending, can_act false; /actions gains the approve row; reproduced on a 2nd request on a fresh load. As X also: reject 200 (status rejected, invoice back to draft), request_info 200, comment 200 |
| approvals.account-app-entry · acceptance[4] | pass | cold load …/component/approvals/inbox?request=AREQ replaces itself with that request's record page showing the decision panel (history.back() skips it); alias /apps/account/…?request= lands the same |
| approvals.account-app-entry · acceptance[5] | pass | inbox row record link href /_console/apps/com.objectstack.account/showcase_invoice/record/ID (current app segment); lands and renders; persona GET 200 |
| approvals.account-app-entry · acceptance[6] | pass | Preferences › Language 中文(中国), html lang zh-CN; nav 待我审批, tabs 待我审批 / 我发起的 / 全部, badge 待审批 |
| approvals.account-app-entry · negative[0]–[1] | pass | full inbox rendered from the nav entry, no missing-component state; Approvals present for the persona, setup absent |
| records-forms.crud-roundtrip · acceptance[0] | pass | UI Create → POST showcase_account {industry:'retail',status:'active',sales_region:'amer',name:'os-qa-r6w4'} 201; filtered GET total 1, 4 keys equal |
| records-forms.crud-roundtrip · acceptance[1] | pass | Update → PATCH {annual_revenue:4321000} 200; across 24 keys only annual_revenue and updated_at differ |
| records-forms.crud-roundtrip · acceptance[2] | pass | ⋯ › Delete › confirm Delete Account "os-qa-r6w4"? → DELETE 200; filtered GET total 0; by id 404 |
| records-forms.crud-roundtrip · acceptance[3] | pass | post-reload list at create: row shown, 15 records; at delete: absent |
| records-forms.crud-roundtrip · acceptance[4] | pass | after a reload, Activity tab (?related=timeline, 1440×900), Changes: Annual Revenue — → $4,321,000.00 · Dev Admin; create line lists owner, name, industry, lifecycle, region; sys_audit_log exactly create + update, no phantom rows. Driven by hand (the live spec needs ports 3000/5180) |
| records-forms.crud-roundtrip · acceptance[5] | pass | UI create os-qa-r6w4-华宁 201, hex-identical re-read; $search=华宁 → 2 rows; list quick-search 2 |
| records-forms.crud-roundtrip · acceptance[6] | pass | admin clone 201 (new id, sourceId); contributor-bound member clone of an admin-owned zoo row → owner/created_by/updated_by the member, autonumber 0001→0003; planted readonly lead_score=42 dropped on clone (droppedFields … readonly), clone reads null |
| records-forms.crud-roundtrip · acceptance[7] | pass | recipe search:qa-contributor-bound-member; member sees 0 of 12 foreign invoices; clone of INV-1003 → 404 RECORD_NOT_FOUND three times; admin count 13→13; own-row clone control 201 |
| records-forms.crud-roundtrip · negative[0] | pass | empty Account Name: inline "Account Name is required", dialog stays, no POST, count unchanged |
| records-forms.crud-roundtrip · negative[1] | pass | id/audit/autonumber re-derived; readonly dropped; RLS-invisible clone 404 |
| records-forms.crud-roundtrip · negative[2] | pass | no name and name:"" → 400 VALIDATION_FAILED fields[{field:name,code:required}] |
| records-forms.crud-roundtrip · negative[3] | pass | tax_id 123456789 and AB-CDEFGHI → 400 code:invalid_format; control 12-3456789 201 |
| integration-system.datasource-credential-refusal-matrix · acceptance[0] | pass | build door (os compile, scratch copy): 22 probes exit 2 at their paths (pg/mysql/mongodb password, turso authToken, passwd alias, URL userinfo incl. turso syncUrl, ?password= / ?authToken=, mongodb options.auth.password, nested pool.token, placeholder host, mongo credentialsRef without user, unparseable url, turso encryptionKey remote/local, top-level password, connector authentication / auth.token); each names external.credentialsRef (connectors credentialRef) and the env-route sentence; controls exit 0. Runtime: POST /api/v1/datasources 400 DATASOURCE_ADMIN_ERROR on all 20 datasource doors; PUT /meta/connector 422 on both connector doors |
| integration-system.datasource-credential-refusal-matrix · acceptance[1] | pass | scratch PG16: POST r7pg with a bound secret → 201 status ok; /test ok, tableCount 1; remote-tables lists the out-of-band table; no-secret control fails SASL |
| integration-system.datasource-credential-refusal-matrix · acceptance[2] | pass | full-body grep of admin (list + 11), meta (list + 11) and /data/sys_metadata?type=datasource: only cleartext hit is the ruled apiSecret; admin and meta config identical |
| integration-system.datasource-credential-refusal-matrix · acceptance[3] | pass | r7pg hasSecret:true; no-secret hasSecret:false; inline legacy redactedConfigKeys:["password"] |
| integration-system.datasource-credential-refusal-matrix · acceptance[4] | pass | 7 rows planted with the server stopped (passwd/pwd, token/jwt/auth_token/authtoken, turso encryptionKey, mysql password, pg userinfo, pg ?password=, mongodb options.auth.password + pool.jwt): all listed after reboot, each key in redactedConfigKeys, 0 planted values on any door or log |
| integration-system.datasource-credential-refusal-matrix · acceptance[5] | pass | unknown driver acme-plugin-db 201 (ruled boundary); password, authToken, passwd, userinfo withheld; apiSecret served as ruled |
| integration-system.datasource-credential-refusal-matrix · acceptance[6] | pass | echoed PATCH {config} 200; PUT 405 Allow: DELETE, GET, HEAD, PATCH; /test still ok, credentialsRef unchanged; echoed PATCH kept the withheld keys |
| integration-system.datasource-credential-refusal-matrix · acceptance[7] | pass | auditor.demo and phone.demo (get-session proven) 403 PERMISSION_DENIED on all 25 read URLs; anonymous 401 |
| integration-system.datasource-credential-refusal-matrix · negative[0]–[6] | pass | no cleartext, no two-door disagreement incl. the update door (PATCH with password / userinfo / top-level password → 400), consistent redaction, all aliases redacted, plugin canonical keys withheld, mask literal in 0 bodies, every refusal names its replacement |
| studio-authoring.first-run-loop · acceptance[0] | pass | by hand (F1 live spec not run: it needs a console origin and writes ui/e2e/live/.auth into the shared tree): Home chip "New in Studio" → New package 维修中心 / com.example.repairs; POST /api/v1/packages 201; switcher "Writable"; no reload (in-page marker survived) |
| studio-authoring.first-run-loop · acceptance[1] | pass | Publish all → publish-drafts 200 publishedCount 1; GET /meta/object/repairs_repair_ticket 200 with options open / wip "In Repair" / closed |
| studio-authoring.first-run-loop · acceptance[2] | pass | Studio Add record → POST {name:"Broken pump",status:"wip"} 201; GET /data/repairs_repair_ticket total 1, status wip |
| studio-authoring.first-run-loop · acceptance[3] | pass | /meta/app includes repair_center with nav_repairs_repair_ticket; screenshots: Home "Repair Center" tile; end-user list chip "In Repair", raw "wip" 0 times |
| studio-authoring.first-run-loop · acceptance[4] | pass | one Server is ready; listener PID unchanged 04:00:15Z–04:09Z |
| studio-authoring.first-run-loop · acceptance[5] | pass | forged as admin x2: object into com.example.showcase → 422 WRITABLE_PACKAGE_REQUIRED; field on showcase_account → 403 ITEM_LOCKED; plain PUT → 403 NOT_OVERRIDABLE; app into showcase → 422; nothing landed |
| studio-authoring.first-run-loop · negative[0]–[1] | pass | no silent acceptance; the label chip renders |
Reproduction rules for fails
None: this run recorded no fail.
Pins and the Playwright smoke
- Playwright smoke:
examples/app-showcase/e2e/showcase-smoke.spec.tsgave 50 passed, 0 failed (2.1 min) against a live boot on port 43503, from a scratch copy (webServer reused the boot). objectstack verify --rlsand bareverify, separate invocations on a scratch copy: per-persona21 PROVEN (21 consistent, 0 HOLES) · 3 NOT PROVEN; totalall personas: 38 PROVEN (38 consistent, 0 HOLES) · 226 NOT PROVEN [unit: one object × persona probe]; 10 of 10 positions; bare tail15 verified, 0 gaps, 0 FAILED, 1 needs-fixture, 8 skipped.- Dogfood pins (in-process HTTP,
--maxWorkers=1, under the lock), all green:- R1: private-owd, rls-fixture, owner-anchor-and-bulk-writes, static-readonly, readonly-when-parent, crud-persona-matrix, permission-zoo, guest-grants-channel: 8 files 121/121.
- R2: private-owd 8, public-read-owd 4, invoice-line-contributor-pair 5, crud-persona-matrix 49, controlled-by-parent 4, invoice-cbp 4, anonymous-deny-surfaces 75, wall-environment-metadata-refusal 23, wall-catalog-refusal 17, wall-package-doors-refusal 23: 212/212 (twice).
- R3: showcase-expand-crud-gate, packaged-activation-ledger-reach, packaged-action-disabled-dispatch-live: 29/29.
- Engine and unit pins, all green:
- objectql: engine.test + filter-array-lowering 196; readonly strip 55.
- rest: request-schema-gate + data-empty-projection-count-door 21; meta-migrate-stored-walled-refusal 6.
- runtime: action-activation-dispatch + data-empty-projection-count 26; packages-walled 32, automation-walled 12, meta-walled-catalog 19; identity-objects-default-organization pin 4; boot-guard 22 + kernel 10.
- service-automation flow-activation-ledger 49 (corroboration; the flow item carries no
automated). - plugin-auth ensure-default-organization 57; plugin-security boot refusal 3.
- cli ceremony: 8 files 179 (+ unified-db-resolution.pin 7, corroborating).
- mcp
plugin.test.ts17: plugin unit over a mocked ctx, corroborates only; everyai.mcp-stdio-fail-closedclause was scored on liveos startstdio legs. - approvals: a non-admin approver's decision from the request page answers 404 RECORD_NOT_FOUND — the action door loads sys_approval_request in the caller's data scope #28657 fix pins, corroboration only: runtime api-action-forward 68; verify action-door-api-forward-denied-subject 3 (HTTP, booted stack).
- Not run, scored by hand instead:
ui/e2e/live/record-history-display.spec.tsand the Studio F1 live spec need the console dev server on fixed ports (3000/5180) or write into the shared tree.
Derived item verdicts and fixture gaps
approvals.account-app-entry: PASS (was FAIL at QA run · priority:P0 (23/23) · eeec88d1 · 2026-11-01 · 20 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #28545). All 9 clauses pass; the Approvals: a non-admin approver who opens an approval request from the Approvals inbox sees "You don't have access to Approval Request records" instead of the decision panel (regression from #27713) #28546 and approvals: a non-admin approver's decision from the request page answers 404 RECORD_NOT_FOUND — the action door loads sys_approval_request in the caller's data scope #28657 fixes hold at this subject.access-security.rls-both-sides: PARTIAL. acceptance[5] blocked{by: dependency, ref: knownGaps[0] / qa(checklist): park the blocked partial-coverage gaps of the 17.7 pre-release runs (#21720, #21721, #21782, #21784) — each gets a fixture recipe, a pin, a re-pointed clause or a recorded knownGap #22017 row 11}, the D11 spot-check. Unchanged from QA run · priority:P0 (23/23) · eeec88d1 · 2026-11-01 · 20 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #28545; the public half holds.access-security.crud-permission-matrix: PARTIAL. acceptance[5] blocked{by: dependency, ref: security: no door can bind a permission set to theguestanchor — ADR-0138 D3 item 5 has no enforcer (PUT /meta/position/guestanswers 403 NOT_OVERRIDABLE; guest suggestions are refused) #23267}: no door binds a set to the guest anchor. Unchanged from QA run · priority:P0 (23/23) · eeec88d1 · 2026-11-01 · 20 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #28545.- Coverage notes on passing items:
platform-core.nav-surfaces-render's ErrorBoundary fallback is still unexercised (knownGap).- The marketplace catalog content stays blocked by egress (knownGap).
- The v17 fixture is a blank-scaffold DB, not a showcase DB.
- The walled grant was a recorded fixture write outside HTTP, the item's own documented recipe (both HTTP grant doors refuse it, as fixtures.requires[2] says).
Retest of earlier QA cards met in passing
Observed on this run's boots as off-clause controls; they are not clause verdicts.
- Metadata API: GET /api/v1/meta/app?id= with an empty value ignores the filter and answers the caller's full app list #28548:
meta/app?id=with an empty value now answers 400 "Query parameter 'id' names no app". - Datasources: POST /api/v1/datasources accepts and silently drops a top-level password or connectionString that os compile refuses, answering 201 #28549: the runtime datasource door now refuses a top-level
passwordat create and at PATCH (400). - MCP: aggregate_records silently drops an aggregation entry's
filter, so a conditional count answers the unconditional total (REST honours it) #28550: MCPaggregate_recordsnow honours an aggregation'sfilter({paid:5, all:13}, equal to REST). - The QA run · priority:P0 (23/23) · eeec88d1 · 2026-11-01 · 20 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #28545 probe "
$skipwithout$topgives total = matches minus offset" is no longer seen:?$skip=5returns 9 rows with total 14.
Off-clause probes (RUNNER rule 8)
About 48 runner-minutes in total, after the clauses had verdicts, on the same boots and as the same personas: R1 5, R2 8, R3 5, R4 7, R5 8, R6 9, R7 6.
Doors:
- data CRUD, list, query, by-id, bulk create/update/delete, clone, export, search, analytics, batch;
sys_user_permission_set,sys_business_unit_member,sys_user_position,sys_metadata,sys_secret;meta/app(list,?id=variants, by name),/api/settings/:ns,/metawrites on the walled boot;- sign-in, sign-out, get-session, set-active, organization create;
- actions and activation, MCP run_action / query_records / get_record / aggregate_records over HTTP and stdio; automation toggle, trigger, runs and
_status; - approvals request, actions and decisions through the action door and the approvals routes;
- the datasource admin, test, remote-tables and meta doors; packages, metadata draft PUT and publish-drafts;
os startstdio admission, the ceremony arms, theos serveboot guard,os devflag parsing; console bad routes.
Personas: admin, walled operator, walled org owner and a non-holder, plain member, contributor, client_liaison, auditor, ops, field_ops_delegate, a non-admin approver and a non-participant, demo personas auditor.demo and phone.demo, API keys (admin, contributor, liaison, revoked), anonymous, and a bogus or empty bearer.
Boundary classes:
- empty, whitespace, unknown, encoded and trailing-slash ids and values; repeated and bracketed (
id[]) parameters; - forged owner, id, credentialsRef and overrides; self-escalation of grants and positions;
- foreign rows through the bulk doors; FLS-hidden predicates in where, orderBy and aggregation filters;
- the opposite posture (walled against single) and the opposite credential (API key against session);
- an empty or null secret; a missing recordId; a missing flag value;
- a wrong or missing plan file, no backup flag, an already-certified DB, a planted-shape DB.
Findings, each in its own card (listed in the close-out comment):
integration-system.datasource-credential-refusal-matrix· observed beside the clauses:PATCH /api/v1/datasources/:name {"secret":""}replaces the stored credential with an empty secret, and the status reason then misreports the cause.platform-core.builtin-apps-nav-render· observed beside the clauses:meta/app?id[]=setup(bracketed array spelling) ignores the filter and serves the caller's unfiltered app list.cli.dev-boot-contract· observed beside the clauses: a flag missing its value (os dev -d) exits 2 without the INVOCATION ERROR banner.approvals.account-app-entry· observed beside the clauses: anapiaction called with norecordIdanswers 404 ENDPOINT_NOT_FOUND instead of naming the missing record id.access-security.write-path-guards· observed beside the clauses: the clone and createMany doors report a readonly strip in the body'sdroppedFieldsbut send noX-ObjectStack-Dropped-Fieldsheader.
Security findings:
- approvals.account-app-entry · observed beside the clauses · security finding — detail withheld, reported to PM
Recorded, not filed:
showcase_portfolio_snapshotanswers a plain memberinvoices: 12over REST and MCP: action bodies run elevated by design (buildActionExecutionContext), so this is the specimen app disclosing an aggregate, not a platform hole.GET /automation/_statuslists every flow's name and binding state to a plain member, who can read/metaanyway.- The
enabledrefusal fornull/0on the toggle door says "not a string". - A member gets 404 UNKNOWN_NAMESPACE for an unregistered settings namespace and 403 for a registered one; the names are public in the manifests.
PUT /meta/object/X?mode=draft&package=(empty) saves an env-wide draft; an unknown package is refused 422.- An unprefixed object draft is accepted at draft time and refused at publish, which blocks the package's later publishes until it is removed.
- A clone re-applies a
current_userdefault to a field that was null on the source. - The
[sharing-rule] share_new_inquiries_with_field_ops expands to NO recipientswarning prints on every boot (as at QA run · priority:P0 (23/23) · eeec88d1 · 2026-11-01 · 20 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #28545). - An unknown view in the URL silently renders the default view (as at QA run · priority:P0 (23/23) · eeec88d1 · 2026-11-01 · 20 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #28545).
Time
- Environment prep: 16 min wall (03:33Z–03:49Z: protocol reading, install, full build 12m47s, console build, compile boot and bundle check), plus about 46 runner-minutes of per-runner prep (protocol reading, scratch copies, persona minting, the walled boot, the v17 and pre-release DBs, scratch Postgres).
- Testing: 32 min wall (03:49Z–04:21Z), or about 71 runner-minutes of clause work plus 48 of probes.
- Ratio: about 1 : 2 by wall clock (16 to 32 min), and about 1 : 1.9 by agent-minutes (62 to 119).
Checklist-accuracy findings from this run are reported to #27377 for the devx lane; they are not repeated here.
Generated by Claude Code
Activity
objectstack-fleet commentedon Nov 2, 2026
domain:devx#1 · os-warren · session_01JQwxbZpHPpovxXPremPLtv
Close-out (W4-C1)
No clause
failthis run, so no FAIL disposition is owed. Off-clause probe findings, each extracted as its own card:Extracted: #28928 · integration-system.datasource-credential-refusal-matrix · observed beside the clauses
Extracted: #28930 · platform-core.builtin-apps-nav-render · observed beside the clauses
Extracted: #28931 · cli.dev-boot-contract · observed beside the clauses
Extracted: #28932 · approvals.account-app-entry · observed beside the clauses
Extracted: #28933 · access-security.write-path-guards · observed beside the clauses
Parked-on: #27377 · access-security.rls-both-sides acceptance[5] D11 spot-check (knownGaps[0], #22017 row 11), unchanged
Parked-on: #27377 · access-security.crud-permission-matrix acceptance[5] guest anchor (#23267), unchanged
This record re-judges all 23 items of #28545, so nothing is carried forward from it.
Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:devx#1 · os-warren · session_01JQwxbWT669ynWFKZjqFyNF
Superseded-by: #29877
The wave-5 P0 run re-judged all 23 items at
589049b0(2026-11-03T09:29Z), so no verdict of this record is left uncovered (nothing carried forward).records-forms.crud-roundtripmoved PASS → FAIL there (acceptance[4], extracted as #29878). Your five probe cards (#28928, #28930, #28931, #28932, #28933) were re-checked there and none reproduces.Generated by Claude Code