Skip to content

QA run · release-18.3.0-w5-p0 (23/23) · 589049b0 · 2026-11-03 · 20 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #29877

Open

Description

@objectstack-fleet

domain:devx#1 · os-warren · session_01JQwxbWT669ynWFKZjqFyNF
Part of #27377 (18.3.0 pre-cut re-check, wave 5, card W5-P0: the standing priority:P0 smoke at the wave-5 subject)

This run re-judges every P0 item at the wave-5 subject 589049b0, 463 commits after the wave-4 subject 7fa9873f, and compares each item with the wave-4 P0 record #28927.

Result: all 23 runnable items have a verdict: 20 PASS, 2 PARTIAL, 1 FAIL, 0 BLOCKED, 0 NOT-RUN.

Against #28927 (21 PASS / 2 PARTIAL / 0 FAIL), one verdict moved:

Today's breaking tightenings (clause that reached each):

Other findings: the off-clause probes produced four product cards and re-checked the five wave-4 probe cards, all of which no longer reproduce (below). No security finding.

Environment fingerprint

  • Framework: 589049b023d82c94508bf9fce752ea19069279e5 (main, merge of fix(metadata-protocol)!: an object saved back from a translated /meta read stores its source labels, and one the registry would refuse is refused at save and at publish #29790), a detached checkout including ui/. git status was clean before and after the run.
  • CI on the subject: push run 41600797636 re-read after testing: completed, conclusion success (every battery job and every shard).
  • Build (cold tree, in this checkout):
    • pnpm install --frozen-lockfile, exit 0 (27 s);
    • pnpm exec turbo run build --concurrency=2, 119/119 tasks, exit 0, 15m04s (08:25:26Z–08:40:59Z);
    • pnpm console:build --concurrency=2, exit 0: ✓ @objectstack/console dist ready (83252 KB) from ui/apps/console, with the tracked sdui.manifest.json;
    • node scripts/check-dev-prereqs.mjs green (106 artifacts).
  • Stale console bundle, ruled out: every boot served /_console/ entry assets/index-DxniAR88.js, the same file as packages/console/dist/assets; R5 and R6 compared the bytes with cmp, identical. The FAIL was also reproduced against the console from source through vite.
  • Toolchain: Node 22.23.4, pnpm 10.31.0. Playwright 1.63.0 resolves chromium build 1243, which /opt/pw-browsers holds.
  • App: examples/app-showcase. One dispatcher compile boot (port 44001) wrote dist/objectstack.json at 08:41Z; every later boot used --no-compile --no-watch (its mtime was unchanged at the end). Items that install, compile, write the external datasource, run verify --rls, os start or the ceremony, or touch a v17 / 18.0 pre-release DB booted from scratch copies (tar, node_modules symlinked). After the run examples/app-showcase/.objectstack/ holds only data/ (no installed-packages/).
  • Boot line: OS_PORT=PORT OS_STORAGE_LOCAL_ROOT=RUN/uploads OS_HOME=RUN/home setsid pnpm -C … exec objectstack dev --ui --seed-admin --no-compile --no-watch -p PORT -d file:RUN/ITEM.db, with --log-level info where an item asks. Seed: Seeds: com.example.showcase 132 rows. /api/v1/health reports version 18.2.0, the unreleased line.
  • Ports: 44001 (dispatcher), 44101–44103 (R1), 44201–44203 (R2), 44301–44304 (R3), 44401–44419 (R4), 44501–44502 (R5), 44601–44602 (R6), 44701–44709 + 44719 PostgreSQL (R7), 44801–44803 (verifier). Each item ran on its own file DB. Every server was stopped by process group; every port was empty at the end.
  • Walled leg: os dev with OS_TENANCY_POSTURE=isolated, OS_PLATFORM_OWNER_EMAIL=admin@objectos.ai, OS_AUTH_MEMBERSHIP_POLICY=invite-only: banner Tenancy: isolated, Organizations mounted, no DEGRADED; /auth/config multiOrgEnabled true, degradedTenancy false.
  • v17-shaped DB: npm create-objectstack@17.7.0 (--skip-install --skip-skills, npm install --legacy-peer-deps, cli/runtime 17.7.0), booted once by its own os dev: 69 tables, 61 rows. 18.0 pre-release DB: the cli-18-prerelease-db restore (born under @objectstack/cli@18.0.0-next.5). Only copies were used, with a checksum or row diff around every step.
  • Scratch PostgreSQL 16: 127.0.0.1:44719, scram-sha-256, data dir under /tmp per the item's knownGaps[2].
  • Timestamps (2026-11-03): prep 08:25Z–08:42Z; runners 08:42Z–09:17Z; rule-7 verifier 09:09Z–09:17Z.

Execution

Parallel, per SKILL §2: seven runner subagents (R1–R7) plus one rule-7 verifier, each at effort high on the default tier (dispatch-gates --tier: 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 on R5, R6, R7, one browser each. Vitest pins ran under scripts/pm/os-verify-lock.sh at --maxWorkers=1. The dispatcher checked each runner's verdicts against the evidence it returned.

Scope: selector priority:P0, 23 runnable items

checklist-select.mjs priority:P0 reported 23 runnable items and 1 blocked item, hidden: access-security.no-active-org-session-semantics. No item is planned. Every revision at the subject equals the one in the wave-5 items file.

item revision surface runner #28927 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 13 api R3 PASS (r11) PASS
approvals.account-app-entry 8 browser R6 PASS PASS
automation.packaged-flow-disable-durable 10 api R3 PASS (r8) 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 FAIL
studio-authoring.first-run-loop 11 mixed R7 PASS (r10) PASS

Revisions moved since #28927: packaged-action-disabled-dispatch 11→13 (remedy sentence now names Setup › Packaged Actions; measured verbatim), packaged-flow-disable-durable 8→10 (refusal now points to the package's Automations in Studio; measured verbatim), first-run-loop 10→11 (both locale legs on-clause; the zh-CN leg now passes, see accuracy notes).

Per-clause verdicts

Layer note (RUNNER rule 6): 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. "live x2" = reproduced twice.

item · clause verdict text oracle evidence
access-security.rls-both-sides · acceptance[0] pass live x2, members by invite + sign-up (sys_member member, 0 set grants): A's list n=2 both A, no B id; B n=1 only B. Pin showcase-private-owd 8/8 [HTTP]
access-security.rls-both-sides · acceptance[1] pass live x2: A GET /data/showcase_private_note/B_ID → 404 RECORD_NOT_FOUND, 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, same as unknown id; admin re-read identical (body, title, updated_at, owner_id)
access-security.rls-both-sides · acceptance[3] pass live x2: admin list holds every id the run created (3, then 6)
access-security.rls-both-sides · acceptance[4] pass objectstack verify --rls (scratch copy) x2 exit 0. Per-persona line 21 PROVEN (21 consistent, 0 HOLES) · 3 NOT PROVEN; total line all personas: 38 PROVEN (38 consistent, 0 HOLES) · 226 NOT PROVEN … [unit: one object × persona probe]; 10 of 10 positions. Bare-verify control 15 verified, 0 gaps, 0 FAILED, 1 needs-fixture, 8 skipped, no PROVEN line
access-security.rls-both-sides · acceptance[5] blocked {by: dependency, ref: knownGaps[0] / #22017 row 11}; public half holds x2: 3 benign skips; member spot-check project_membership 403/403/403, ext_* GET 403 / PATCH 403 EXTERNAL_WRITE_FORBIDDEN
access-security.rls-both-sides · negative[0]–[2] pass forged PATCH 404, re-read unchanged (x2 + pin); D11 verdict carried on acceptance[5] only
access-security.write-path-guards · acceptance[0] pass live x2: POST showcase_contact {lead_score:10} → 201, header X-ObjectStack-Dropped-Fields: lead_score;reason=readonly, body droppedFields, read-back null. Pin static-readonly 9/9 [HTTP]
access-security.write-path-guards · acceptance[1] pass live x2: PATCH {lead_score:99} → 200 with the same header; null before and after
access-security.write-path-guards · acceptance[2] pass live x2 member: POST note {owner_id:Bob} → 403 PERMISSION_DENIED (system-managed, needs transfer grant); 0 planted rows
access-security.write-path-guards · acceptance[3] pass live x2: self insert 201 owner Alice; PATCH owner_id=Bob and =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 12/12 [HTTP]
access-security.write-path-guards · acceptance[5] pass live x2: paid invoice PATCH tax_rate → 200, header tax_rate;reason=readonly_when, value unchanged; line qty/unit_price/product all readonly_when, unchanged; mixed updateMany: paid row droppedFields, open row moved 2→5. Pin readonly-when-parent 9/9
access-security.write-path-guards · acceptance[6] pass live x2: continueOnError [3,-1,3] → 3/2/1, codes [ok, VALIDATION_FAILED, ok], re-read [3,2,3]; default stop → [ok, VALIDATION_FAILED, NOT_ATTEMPTED], re-read [4,2,2]
access-security.write-path-guards · negative[0] pass live x2 admin: forge-insert 201 owner Bob; transfer 200; disown 200
access-security.write-path-guards · negative[1] pass engine layer: engine-insert-static-readonly-strip + engine-readonly-strip-caller-values 55/55
access-security.crud-permission-matrix · acceptance[0] pass live REST sweep x2: all 87 allow cells of 164 answered <300, effect proven by admin re-read; pin crud-persona-matrix 49/49 [HTTP]
access-security.crud-permission-matrix · acceptance[1] pass live x2: all 77 deny cells → 403 PERMISSION_DENIED; delegate sys_user create/delete 405 with admin control 405/405. #29845 arm driven beside it (see top)
access-security.crud-permission-matrix · acceptance[2] pass live x2: admin marker scan after each of 17 denied creates → 0 rows
access-security.crud-permission-matrix · acceptance[3] pass live x2: auditor reads foreign note/inquiry/invoice/line 200 (by id and lists); contributor 404 by id, absent from lists
access-security.crud-permission-matrix · acceptance[4] pass live x2: ops PATCH admin's announcement 200, persisted; member_default 403, unchanged
access-security.crud-permission-matrix · acceptance[5] blocked {by: dependency, ref: #23267}: PUT /meta/position/guest naming showcase_guest_portal → 403 NOT_OVERRIDABLE; suggested-bindings lists only showcase_member_default@everyone; anonymous 401/401
access-security.crud-permission-matrix · acceptance[6] pass 45 rows recounted; 164 cells + 16/16 delegate cells x2; rev-12 grant steps POST /data/sys_user_permission_set 201 ×7, sys_business_unit_member 201, delegate sys_user_position 201/200/200/200
access-security.crud-permission-matrix · negative[0]–[1] pass first denied cell of each of 8 sets as admin → 2xx; 0 withheld cells answered 2xx
access-security.owd-sharing-matrix · acceptance[0] pass live x2: B list 0 rows, GET 404, PATCH 404, admin re-read "orig"; A GET 200, PATCH 200 persisted. Pin showcase-private-owd [HTTP]
access-security.owd-sharing-matrix · acceptance[1] pass live x2: B lists and GETs the announcement 200; forged PATCH 403 PERMISSION_DENIED, unchanged. Pin public-read-owd
access-security.owd-sharing-matrix · acceptance[2] pass live x2: ops PATCH 200, persisted. Pin crud-persona-matrix
access-security.owd-sharing-matrix · acceptance[3] pass live x2: project created with rev-9 body 201; contributor GET 200, PATCH 200 persisted; A's PATCH 403, unchanged
access-security.owd-sharing-matrix · acceptance[4] pass live x2: C1 invoice + line 201; C2 list 0 / GET 404 / PATCH 404, re-read unchanged; C1 200/200 (qty 1→2). Pins invoice-line-contributor-pair, controlled-by-parent, invoice-cbp
access-security.owd-sharing-matrix · acceptance[5] pass live x2: auditor lists and GETs C1's line 200
access-security.owd-sharing-matrix · acceptance[6] pass procedural: all four models per persona and verb, two rounds
access-security.owd-sharing-matrix · negative[0]–[1] pass forged PATCH 403 unchanged x2; C1 controls contained/200/200
access-security.anonymous-deny-surfaces · acceptance[0] pass live x2, no header or cookie: 401 from data, meta, actions, automation/_status, batch, security/explain, analytics query/sql/meta. Pin showcase-anonymous-deny-surfaces [HTTP]
access-security.anonymous-deny-surfaces · acceptance[1] pass live x2: anonymous POST /actions/showcase_task/showcase_mark_done/anon-probe-id → 401; member → 404 RECORD_NOT_FOUND
access-security.anonymous-deny-surfaces · acceptance[2] pass each body in exactly one family (pin predicates): rest-flat data/meta/batch/explain; dispatcher-wrapper actions/automation/analytics
access-security.anonymous-deny-surfaces · acceptance[3] pass live x2: anonymous analytics 401 incl. malformed; member query 200, sql 200, meta 200, malformed 400 VALIDATION_FAILED
access-security.anonymous-deny-surfaces · acceptance[4] pass live x2: member GET /data/showcase_private_note 200, GET /meta 200
access-security.anonymous-deny-surfaces · acceptance[5] pass live x2: anonymous GET /api/v1/forms/contact-us → 200 serving showcase_inquiry
access-security.anonymous-deny-surfaces · acceptance[6] pass procedural: 7 families live, twice
access-security.anonymous-deny-surfaces · negative[0] pass live x2: anonymous DELETE /automation/showcase_reassign_wizard → 401; admin GET after → 200
access-security.walled-environment-metadata-operator-only · acceptance[0] pass pins under the lock: rest meta-migrate-stored-walled-refusal 6/6 (unit); runtime packages-walled-write-refusal 32/32, automation-walled-definition-write 12/12, meta-walled-catalog-refusal 19/19 (dispatcher-domain); dogfood wall-* three files in a 10-file run 212/212 [HTTP]
access-security.walled-environment-metadata-operator-only · acceptance[1] pass live x2 isolated boot, org owner O (not platform admin, holds manage_metadata; pre-grant control answered the capability 403, post-grant the posture 403): object PUT 403 (read-back 404), permission PUT 403, view publish 403, package DELETE 403, set clone 403, _migrate-stored 403 ×2, POST /automation 403 (then 404); every message names the isolated posture
access-security.walled-environment-metadata-operator-only · acceptance[2] pass walled operator PUT/read/DELETE/read 200/200/200/404 x2; single admin same x2
access-security.walled-environment-metadata-operator-only · negative[0] pass no org-owner environment-metadata write landed: 7 clause doors x2 + 12 probe doors, read-backs absent or unchanged
identity-auth.default-organization-boot-invariant · acceptance[0] pass plugin-auth ensure-default-organization 57/57 (plugin unit); runtime identity-objects-default-organization.pin 4/4 (engine)
identity-auth.default-organization-boot-invariant · acceptance[1] pass --log-level info: [default-org] created the Default Organization 08:43:42.453Z before Dev admin seeded 08:43:49Z; DB agrees (org 08:43:42.447Z, first user 08:43:48.831Z)
identity-auth.default-organization-boot-invariant · acceptance[2] pass live x2: sys_member admin owner, each created user member, in the default org; get-session activeOrganizationId = default org for admin and member
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: 108 tables, 65 with organization_id, 165 rows, 0 NULL / 0 empty (166 after probes); stock.db 197 and walled.db 435 rows, 0 NULL
ai.mcp-stdio-fail-closed · acceptance[0] pass os start, stdio enabled, no key: exit 1, stdout 0 B, health 000, "[MCP] … OS_MCP_STDIO_API_KEY is not set … Refusing to start an unscoped stdio server (ADR-0101)". Pins plugin.test + plugin-execution-context 24/24 (plugin unit)
ai.mcp-stdio-fail-closed · acceptance[1] pass osk_unknown: exit 1, 0 B, "did not resolve to a valid identity …"; revoked key: exit 1, 0 B, "refused (API_KEY_REVOKED)"
ai.mcp-stdio-fail-closed · acceptance[2] pass info log "stdio transport principal-bound to OS_MCP_STDIO_API_KEY identity ID (RLS/FLS/tenant applied)" = the contributor's sys_user id; liaison boot printed the liaison's
ai.mcp-stdio-fail-closed · acceptance[3] pass contributor: MCP query_records 1 row = REST 1 row, same 19 fields; INV-1003 MCP "not found" / REST 404 (admin 13 rows, 200). Liaison project: budget/spent/budget_remaining absent on MCP and REST alike
ai.mcp-stdio-fail-closed · acceptance[4] pass member MCP count by status [{draft,1}] = REST POST /data/showcase_invoice/query [{draft,1}]; admin 3/5/5
ai.mcp-stdio-fail-closed · acceptance[5] pass liaison sum/groupBy/count_distinct/min on budget, spent → isError 403 "Field read denied: not permitted to aggregate [budget]…", no number; REST same; controls equal
ai.mcp-stdio-fail-closed · acceptance[6] pass same stdio session: 1 row; admin-session revoke 200 (API-key PATCH 403 needs a session); next query_records/get_record/aggregate_records → API_KEY_REVOKED 403, 0 rows
ai.mcp-stdio-fail-closed · acceptance[7] pass os start, no stdio env: health 200, stdout 0 B, "[MCP] Transport not auto-started …"
ai.mcp-stdio-fail-closed · negative[0]–[4] pass unset, " ", osk_, unknown, revoked, Bearer osk_… never served; member 1 row vs admin 13; masked aggregates refused; post-revoke API_KEY_REVOKED
api-backend.query-contract-matrix · acceptance[0] pass live: 29 variants × 3 doors (POST $-body, POST AST, GET $filter) = 87 calls, every id set equals the set computed from the unfiltered baseline (0 diffs); all 22 operators; infix compound refused POST 400 / GET 400
api-backend.query-contract-matrix · acceptance[1] pass $orderby=name&$top=3&$skip=2 → Fabrikam, Globex, Hooli; windows match local slices; POST limit/offset and top/skip agree
api-backend.query-contract-matrix · acceptance[2] pass $select=name,status and POST fields → 14 rows keys exactly {name,status}; fields:['account.name'] → 400 INVALID_FIELD naming expand
api-backend.query-contract-matrix · acceptance[3] pass annual_revenue asc/desc both doors = local order; no_such_field → 400 INVALID_SORT both doors
api-backend.query-contract-matrix · acceptance[4] pass recipe contributor (get-session proven): direct contact read 403; body/list/by-id expand leave contact raw; admin gets {name:"Prospect 18"}. Pin showcase-expand-crud-gate [HTTP]
api-backend.query-contract-matrix · acceptance[5] pass {status:{$nin:'done'}} → 400 VALIDATION_FAILED at query.where.status.$nin; AST twin 400; GET 400 INVALID_FILTER; no rows
api-backend.query-contract-matrix · acceptance[6] pass ?$pageSize=5 → 400 UNSUPPORTED_QUERY_PARAM listing 9 params; unknown field via GET/POST → 400 INVALID_FIELD
api-backend.query-contract-matrix · acceptance[7] pass $in:[] 0 of 10, $nin:[] 10 of 10, both 200; twins agree
api-backend.query-contract-matrix · acceptance[8] pass one row per variant; $count true/false, $search, $expand covered
api-backend.query-contract-matrix · negative[0]–[1] pass {limit:"ten"} 400; unknown key 400; blank/garbled $select/select/fields/$count/count all 400 naming the spelling; controls 200. Rest pins request-schema-gate + data-empty-projection-count-door 21 green (route-handler)
api-backend.packaged-action-disabled-dispatch · acceptance[0] pass flip 200, exactly 1 ledger row (no organization_id); mark_done bogus and real id → 409 ACTION_DISABLED with the rev-13 sentence "…Setup › Packaged Actions…"; tasks unchanged. Live dogfood pin green
api-backend.packaged-action-disabled-dispatch · acceptance[1] pass live x2: disabled gallery {bogus_key:1} → 409; re-enabled → 400 "Invalid action params" naming both keys
api-backend.packaged-action-disabled-dispatch · acceptance[2] pass disabled 409s with no-such-record-0000 read and wrote nothing; enabled controls 404
api-backend.packaged-action-disabled-dispatch · acceptance[3] pass live x2: showcase_zoo_perm_missing 403 "requires capability [showcase.restricted_ops]" enabled and disabled, byte-identical
api-backend.packaged-action-disabled-dispatch · acceptance[4] pass live x2: POST /api/v1/mcp run_action on disabled portfolio_snapshot → isError {code:ACTION_DISABLED,status:409}, message string-equal to REST; re-enabled ok
api-backend.packaged-action-disabled-dispatch · acceptance[5] pass cold restart: info "Activation ledger: 3 packaged action(s) are switched off …"; still 409; re-enable 200, real id 200 done/100; same ledger row id, active true, updated_at moved
api-backend.packaged-action-disabled-dispatch · acceptance[6] pass live x2: disabled bulk_reassign 409 with or without recordId; reassign_wizard 0 runs before and after
api-backend.packaged-action-disabled-dispatch · negative[0]–[2] pass no disabled call got the param 400 or a record answer; stock answers with 0 rows; 403 wins over 409; anonymous 401
automation.packaged-flow-disable-durable · acceptance[0] pass baseline urgent create 201, runs 0→1; toggle off 200; exactly 1 row (flow, showcase_urgent_task_alert, active false, no organization_id); no "IN PROCESS ONLY" warning
automation.packaged-flow-disable-durable · acceptance[1] pass trigger → 409 FLOW_DISABLED x2, message exactly the rev-10 sentence (package's Automations in Studio)
automation.packaged-flow-disable-durable · acceptance[2] pass cold restart: _status enabled false, bound false; info "Activation ledger: 1 packaged flow(s) are switched off … left unbound"
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; bound true; create → runs 1→2
automation.packaged-flow-disable-durable · negative[0]–[3] pass row written, restart did not re-arm, row kept on re-enable, refusal never the bare status sentence
cli.dev-boot-contract · acceptance[0] pass scratch copy default boot: health 200 after 10 s; /api/v1/ready 200 ready/running
cli.dev-boot-contract · acceptance[1] pass admin123 sign-in 200; restart with --admin-password changed99: admin123 200, changed99 401
cli.dev-boot-contract · acceptance[2] pass Database line for -d file:, OS_DATABASE_URL, :memory:, nothing chosen (.objectstack/data/objectstack.db), config default datasource (qa_home.db, no objectstack.db), legacy dev.db with the one ⚠ migrate line
cli.dev-boot-contract · acceptance[3] pass --fresh: "🧪 Fresh OS_HOME: /tmp/objectstack-dev-…"; SIGINT 130 / SIGTERM 143, tempdir gone both times
cli.dev-boot-contract · acceptance[4] pass port held: "⚠ Port 44406 is in use — serving on 44407 instead." + "↪ server bound to port 44407"; health 200
cli.dev-boot-contract · acceptance[5] pass touched src then --no-compile: "⚠ dist/objectstack.json is OLDER than your sources …"; no compile, ready, dist sha unchanged
cli.dev-boot-contract · acceptance[6] pass empty dir: exit 1 "✗ Config file not found …" + remedy line
cli.dev-boot-contract · acceptance[7] pass screenshot first: login page at /_console/login; form sign-in reached /_console/home, get-session 200
cli.dev-boot-contract · negative[0]–[3] pass marker table survived reboot; --database-driver memory exit 2 INVOCATION ERROR; OS_DATABASE_DRIVER=memory/mingo/in-memory exit 1 naming --fresh/:memory:; memory:///mingo:// exit 1, not ready; legacy read created no objectstack.db
cli.organization-ownership-ceremony · acceptance[0] pass engine/SQLite integration: packages/cli 8 ceremony files 184/184; runtime boot-guard + kernel 32/32
cli.organization-ownership-ceremony · acceptance[1] pass v17 copy production: plan exit 0 "no row or table … changed", sha unchanged, row diff 0, 144 table entries; --apply without plan exit 1 (apply_refused/plan-file-required); --dev copy same, telemetry unchanged
cli.organization-ownership-ceremony · acceptance[2] pass --apply --plan-file --backup-taken: exit 0, complete, blocking 0, 13/13 steps; marker shapeGeneration 1
cli.organization-ownership-ceremony · acceptance[3] pass unmigrated production serve: exit 1, no ready line, marker sentence, 9 tables, commands without --dev, 0 "17.x release"/"fresh installs only"; migrated copy ready, health 200; --dev refusal spells --dev
cli.organization-ownership-ceremony · acceptance[4] pass comment-reactions without --yes exit 1, with --yes 0 twice; migrate apply --allow-destructive --yes --json exit 1 refused_organization_ownership_unmigrated naming 9 tables, applied []; sha unchanged
cli.organization-ownership-ceremony · acceptance[5] pass 18.0 pre-release restore: boot refused naming sys_flow_credential/sys_secret with --dev; reviewed apply exit 0 complete; boot 2 ready; identity mails in sys_identity_email (0 diffs over 24 cols at apply), global audit 8/8 moved, mail jobs re-pointed; old passwords 200, moved reset token resets; one task PATCH → 1 sys_http_delivery declared:showcase_task_changed
cli.organization-ownership-ceremony · negative[0] pass no refusing or plan arm changed a checksum or a pre-existing row
integration-system.datasource-credential-refusal-matrix · acceptance[0] pass build door os compile: 19 datasource probes + 5 connector probes exit 2 at their paths, naming external.credentialsRef / credentialRef and the OS_DATASOURCE_ route; controls exit 0. Runtime: POST /datasources 400 on all 19, PUT /meta/connector 422 on all connector doors; 0 cleartext
integration-system.datasource-credential-refusal-matrix · acceptance[1] pass PG16 POST /datasources with top-level secret 201 ok; /test ok, remote-tables lists r7_widgets; no-secret control 201 status error
integration-system.datasource-credential-refusal-matrix · acceptance[2] pass full-body grep of admin, meta and /data/sys_metadata?type=datasource: 0 planted values (only the ruled apiSecret); admin config = meta config on all 10
integration-system.datasource-credential-refusal-matrix · acceptance[3] pass hasSecret true / false; legacy rows' redactedConfigKeys name each withheld key
integration-system.datasource-credential-refusal-matrix · acceptance[4] pass 7 rows planted with the server stopped; after re-boot listed with metadata_spec_invalid, each key in redactedConfigKeys, 0 values on any door or log
integration-system.datasource-credential-refusal-matrix · acceptance[5] pass acme-plugin-db 201; redactedConfigKeys authToken, passwd, password, url; url served acme://u@h/db; apiSecret as written
integration-system.datasource-credential-refusal-matrix · acceptance[6] pass PUT 405 Allow: DELETE, GET, HEAD, PATCH; echoed PATCH {config} 200, /test ok, credentialsRef unchanged
integration-system.datasource-credential-refusal-matrix · acceptance[7] pass auditor.demo, phone.demo, plain member, manage_metadata-only: 403 on all 24 read URLs; anonymous 401 on all; manage_platform_settings-only reads with 0 leaks
integration-system.datasource-credential-refusal-matrix · negative[0]–[6] pass no cleartext; build = runtime; PATCH password / userinfo / top-level 400; same keys redacted on both doors; no mask literal; every refusal names its replacement
platform-core.boot-health · acceptance[0] pass health 200 {status:ok, version 18.2.0} 15.1 s after launch
platform-core.boot-health · acceptance[1] pass /api/v1/ready 200 ready/running as the first non-health request
platform-core.boot-health · acceptance[2] pass boot window (51 lines): Flows: 32 flow(s) 19 bound … · 8 draft; two ℹ deployment-policy lines; 0 ⚠, 0 ERROR; Seeds: com.example.showcase 132 rows
platform-core.boot-health · acceptance[3] pass meta/app?id=showcase_app 200 {type,items}; unfiltered [showcase_app, setup, account]; _diagnostics.valid: true
platform-core.boot-health · acceptance[4] pass 51 authored nav_* ids = 51 served (diff empty); grp_data 12 objects
platform-core.boot-health · acceptance[5] pass /_console/ 200 text/html, entry byte-identical to dist
platform-core.boot-health · negative[0]–[1] pass no SeedLoader rejection, 0 ERROR lines
platform-core.console-login · acceptance[0] pass form sign-in 200 ×3 → /_console/home (screenshot: header + launcher); cookie and localStorage token both set
platform-core.console-login · acceptance[1] pass reload stays on /home; first authed calls all 200; in-page meta/app?id=showcase_app 200, 1 item
platform-core.console-login · acceptance[2] pass live x3: server sign-out 200, same bearer → 401 on meta/app, get-session, data
platform-core.console-login · acceptance[3] pass full nav → /_console/login?redirect=…showcase_task x3; client-side nav → "Sign in required" state, no stale rows
platform-core.console-login · acceptance[4] pass re-login returns to showcase_task (10 records); read 200, write 201
platform-core.console-login · negative[0]–[1] pass wrong password 401 INVALID_EMAIL_OR_PASSWORD, no cookie or token; alert shown; 0 page errors
platform-core.nav-surfaces-render · acceptance[0] pass e2e/showcase-smoke.spec.ts against this boot (browser over live HTTP): 50 passed / 0 failed on the full re-run. The first run lost 3 to "Target crashed" at 13.6 GB used (browser process, environment); those 3 then passed alone and the full suite passed
platform-core.nav-surfaces-render · acceptance[1] pass 51 served entries = 50 leaves + 1 separator; diff with the 50 SURFACES empty both ways
platform-core.nav-surfaces-render · acceptance[2] pass bad route in 2 fresh contexts: header and 50 sidebar items stay; main "Object Not Found …"; 0 page errors
platform-core.nav-surfaces-render · acceptance[3] pass no render failure in the sweep; ErrorBoundary fallback unexercised (existing knownGap)
platform-core.nav-surfaces-render · negative[0]–[3] pass no blank main; splash wait held on 50; charts passed the boundingBox poll; shell kept on bad route
platform-core.builtin-apps-nav-render · acceptance[0] pass admin walk, screenshot first: Setup 46/46 and Account 8/8 render, 0 page errors; only "failed to load" is the knownGap marketplace (502 MARKETPLACE_PROXY_FAILED, egress); 11 settings namespaces render
platform-core.builtin-apps-nav-render · acceptance[1] pass setup requiredPermissions [setup.access], 9 groups, 46 leaves = source contributions minus nav_organizations / nav_sso_providers; account 8 leaves in 3 groups; ?id=studio {items:[]}
platform-core.builtin-apps-nav-render · acceptance[2] pass member phone.demo: Setup, sys_user route and settings/mail → "You don't have access to this app" without shell; Account Profile and My Sessions open
platform-core.builtin-apps-nav-render · acceptance[3] pass member ?id=setup {items:[]}, GET meta/app/setup 403; member list [showcase_app, account]
platform-core.builtin-apps-nav-render · acceptance[4] pass account nav 8 = 8 for admin and member
platform-core.builtin-apps-nav-render · acceptance[5] pass single posture: nav_organizations absent (multiOrgEnabled:false); nav_business_units present, object and data 200 (5 units)
platform-core.builtin-apps-nav-render · acceptance[6] pass no jwks/sso/verification/device_code entries; sso:false; sys_jwks 404 OBJECT_API_DISABLED, sys_verification / sys_device_code 405
platform-core.builtin-apps-nav-render · negative[0]–[3] pass member /api/settings/NS 403 SETTINGS_FORBIDDEN for all 11 (admin 200); no "All reports" row
platform-core.seed-integrity · acceptance[0] pass expected counts re-derived through tsx from ShowcaseSeedData: 19 datasets, 132 rows; $top=1 totals and list lengths match 19/19
platform-core.seed-integrity · acceptance[1] pass "Specimen — Full" 37/37 fields; lookups resolve; f_time '14:30:00'; f_password masked
platform-core.seed-integrity · acceptance[2] pass banner Seeds: com.example.showcase 132 rows plain; [Seeder] … {"inserted":132,…,"errored":0}
platform-core.seed-integrity · acceptance[3] pass restart on the same DB: sweep JSON byte-identical; {"inserted":0,"updated":0,"skipped":132,"errored":0}
platform-core.seed-integrity · acceptance[4] pass f_user, f_users, f_secret present and null; task.cover null on 10
platform-core.seed-integrity · negative[0]–[1] pass no seeded object counts 0; no growth on restart
platform-core.v18-boot-refusals · acceptance[0] pass runtime boot-guard + kernel 32/32 (unit + kernel); plugin-security authz-identity-objects-boot-refusal 3/3
platform-core.v18-boot-refusals · acceptance[1] pass production os serve over v17 copy: exit 1, no ready line, marker sentence, 9 tables, no --dev; --dev copy 13 tables, commands carry --dev
platform-core.v18-boot-refusals · acceptance[2] pass node:sqlite row diff: production 69 tables / 61 rows, 0 differences, created tables empty, 0 marker rows; dev copy 0 differences, telemetry unchanged
platform-core.v18-boot-refusals · acceptance[3] pass live rig (SecurityPlugin without auth, os serve --dev --no-server --preset minimal): exit 1 "✗ SecurityPlugin cannot boot: … mount AuthPlugin, or … createIdentityObjectsPlugin()"; never listened
platform-core.v18-boot-refusals · negative[0] pass every v18 boot over a v17 copy (production, --dev, os start) refused; rows unchanged
approvals.account-app-entry · acceptance[0] pass build layer: console:build at this subject; served entry byte-identical to dist; entry registers approvals:inbox "Approvals Inbox" (1 hit)
approvals.account-app-entry · acceptance[1] pass non-admin approver X: avatar › Profile › Inbox › Approvals → /_console/apps/com.objectstack.account/component/approvals/inbox; tabs My Pending 6 / Submitted by me / All, 6 rows
approvals.account-app-entry · acceptance[2] pass X meta/app [showcase_app, account] with nav_account_approvals; ?id=setup {items:[]}, meta/app/setup 403; same session renders the inbox
approvals.account-app-entry · acceptance[3] pass live x2 per decision: Approve → Confirm approval_approve 200, 0/2 → 1/2, X leaves pending; Reject 200, status rejected, invoice back to draft; Request info 200, row appended; Reply approval_comment 200. Non-participant N: every REST and action door 404 REQUEST_NOT_FOUND, forged actorId 403, request unchanged; X after acting 403 / 409
approvals.account-app-entry · acceptance[4] pass cold load …/approvals/inbox?request=ID → the request's record page with the decision panel; history replaced; alias /apps/account/… lands on the same page
approvals.account-app-entry · acceptance[5] pass row link /_console/apps/com.objectstack.account/showcase_invoice/record/ID, renders; X GET /data/showcase_invoice/ID 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, no missing-component state; entry present for X, setup refused 403
records-forms.crud-roundtrip · acceptance[0] pass UI Create → POST /data/showcase_account {"industry":"retail","status":"active","sales_region":"amer","name":"os-qa-r6w5"} 201; filtered GET equal on all keys, website null
records-forms.crud-roundtrip · acceptance[1] pass UI Update → PATCH …/ID {"annual_revenue":4321000} 200; only annual_revenue and updated_at differ over 24 keys
records-forms.crud-roundtrip · acceptance[2] pass record page ⋯ › Delete › confirm → DELETE 200; filtered GET 0, by id 404
records-forms.crud-roundtrip · acceptance[3] pass reloaded list shows the row after create (15 records), absent after delete
records-forms.crud-roundtrip · acceptance[4] fail live x3 (R6) + x2 (verifier), fresh loads, 1440×900: Activity tab / ?related=timeline, Changes chip pressed → only the two sys_activity lines; page request timeline.fieldChanges:false, no GET sys_audit_log, while sys_audit_log holds 2 rows and the drawer (?recordId=) draws them. Pin ui/e2e/live/record-history-display.spec.ts (console from source via vite, own ports): 1 failed at L116 toContain(other.name). Reproduction rule below
records-forms.crud-roundtrip · acceptance[5] pass UI create os-qa-r6w5-华宁 201, re-read hex-identical; $search=华宁 2 rows; list quick-search 2 rows
records-forms.crud-roundtrip · acceptance[6] pass admin clone 201, diffs only id / timestamps / overridden name; member clone of admin zoo row: owner/created_by = member, autonumber 0001 → 0003, f_password not carried; planted lead_score 42 → clone header lead_score;reason=readonly, value null
records-forms.crud-roundtrip · acceptance[7] pass recipe search:qa-contributor-bound-member: member sees 0 of 12 seeded invoices; INV-1003 GET 404, clone 404 ×3, admin count 13 → 13; own-row clone 201
records-forms.crud-roundtrip · negative[0]–[3] pass empty name: inline required, no POST; clone re-derives id/audit/autonumber, drops readonly; API missing name 400 required; tax_id 123456789 400 invalid_format, control 201
studio-authoring.first-run-loop · acceptance[0] pass by hand, en and zh-CN legs: chip "New in Studio" / 在 Studio 中新建 → package com.example.repairs, namespace repairs; POST /api/v1/packages 201; switcher lists it Writable / 可写; in-page marker survived (no reload)
studio-authoring.first-run-loop · acceptance[1] pass Publish all → publish-drafts 200 outcome:published, publishedCount 1; GET /meta/object/repairs_repair_ticket 200 with the status options. Both legs
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. Both legs (the zh-CN leg passes; knownGaps[3] is stale)
studio-authoring.first-run-loop · acceptance[3] pass /meta/app lists repair_center with its nav entry; Home tile "Repair Center"; end-user list row with chip "In Repair", raw wip 0 times. Both legs
studio-authoring.first-run-loop · acceptance[4] pass one Server is ready per leg; listener PIDs unchanged through each loop
studio-authoring.first-run-loop · acceptance[5] pass forged as admin x2 per leg: object into showcase 422 WRITABLE_PACKAGE_REQUIRED, field on showcase_account 403 ITEM_LOCKED, plain PUT 403 NOT_OVERRIDABLE, app 422, showcase publish nothing_to_publish; nothing landed
studio-authoring.first-run-loop · negative[0]–[2] pass no silent acceptance; label chip renders; every clause held on both legs

Reproduction rule for the FAIL

records-forms.crud-roundtrip · acceptance[4] (P0; rule-7 verifier agreed; disposition: product defect, regression from a932270 / #29846, extracted)

  1. Boot the stock showcase; sign in as admin through the form at /_console/login.
  2. Accounts › New: Account Name os-qa-x, Industry Retail, Lifecycle Active › Create → POST /api/v1/data/showcase_account 201.
  3. Record page › Edit › Annual Revenue 4321000 › Update → PATCH 200. Server truth: GET /api/v1/data/sys_audit_log?filter=[["record_id","=","ID"]] → total 2.
  4. Fresh load /_console/apps/com.example.showcase/showcase_account/record/ID at 1440×900; click the Activity tab (URL gains ?related=timeline), then the Changes chip (aria-pressed="true").
  5. Expected: the audit lines with display values, e.g. Annual Revenue — → $4,321,000.00 · Dev Admin and Owner — → Dev Admin; Account Name — → os-qa-x; Industry — → Retail; Lifecycle — → Active; Sales Region — → AMER · Dev Admin (as at QA run · priority:P0 (23/23) · 7fa9873f · 2026-11-02 · 21 PASS / 2 PARTIAL / 0 FAIL / 0 BLOCKED / 0 NOT-RUN #28927, and as the drawer shows).
  6. Actual: only Updated Account "os-qa-x": Annual Revenue · Dev Admin and Created Account "os-qa-x" · Dev Admin (sys_activity). Network: the record-page request carries "timeline":{"discussion":true,"activity":true,"fieldChanges":false}; no GET /api/v1/data/sys_audit_log; object reads are GET /api/v1/meta/object?package=com.example.showcase plus by-name sys_organization, sys_user, sys_business_unit, sys_comment_reaction.
  7. Control: /_console/apps/com.example.showcase/showcase_account?recordId=ID sends fieldChanges:true, reads sys_audit_log 200, draws both audit lines.
  • Self-check: the decisive signal (fieldChanges:false) is fixed when the page is composed, before any click; role-targeted clicks only; screenshot before every DOM read; served bundle byte-identical to dist and reproduced on the source console; traps hydration-race, automation-input, stale-console-bundle and wrong-panel ruled out.

Derived item verdicts and gaps

Off-clause probes (RUNNER rule 8)

About 45 runner-minutes in total, after the clauses had verdicts, on the same boots and as the same personas: R1 7, R2 6, R3 6, R4 6, R5 6, R6 6, R7 8.

Doors: data by-id, list, query, bulk create/update/delete, clone; sys_user_permission_set, sys_user_position, ext_customer; analytics; walled /meta, /packages, /automation siblings; actions, _activation, automation toggle/trigger/runs/_status, MCP over HTTP and stdio; approvals list, request, actions and decision doors; datasource admin PATCH/GET and the federation routes; Studio metadata write and publish (incl. a zh-CN translated-read save-back); meta/app query and path forms, /api/settings/:ns, sign-in/out; the ceremony apply refusals, os dev flags, os start over a v17 DB.

Personas: admin, walled operator and org owner, plain members, contributor, auditor, ops, field_ops_delegate, liaison, a non-admin approver and a non-participant, demo personas, manage_metadata-only and manage_platform_settings-only personas, API keys, anonymous, bogus/empty bearer.

Boundary classes: hidden vs missing ids on by-id, bulk and clone doors (with and without If-Match); empty, whitespace, encoded (%2F, %00, %2e%2e), 300-char and unknown ids and names; blank and malformed query values; unknown enum values; owner forge through createMany/updateMany/clone overrides; FLS-masked fields in filter/sort/aggregate; empty/whitespace/wrong secrets; the opposite posture (walled vs single) and the opposite credential (API key vs session); missing flag values, foreign/missing plan files, no backup flag, re-apply on a certified DB.

Findings, each in its own card (listed in the close-out comment):

  • integration-system.datasource-credential-refusal-matrix · observed beside the clauses: a datasource PATCH whose new secret fails to connect (wrong, or whitespace-only) answers "the new configuration is NOT in force" but stores it, so the datasource fails at the next restart.
  • approvals.account-app-entry · observed beside the clauses: GET /api/v1/approvals/requests?status=bogus answers 200 [] instead of refusing an unknown status value.
  • api-backend.packaged-action-disabled-dispatch · observed beside the clauses: a per-record flow action with no recordId runs the flow and answers 400 FLOW_FAILED naming an internal node, not a refusal naming recordId.
  • cli.organization-ownership-ceremony · observed beside the clauses: the v17 refusal os start prints leads to a ceremony that blocks (security plugin not composed) because it does not name the auth secret os start keeps in its home.

Wave-4 probe cards re-checked — none reproduces at this subject: #28928 (PATCH {"secret":""} now 400, credential kept), #28930 (?id[]=setup now 400 VALIDATION_ERROR), #28931 (os dev -d now prints the INVOCATION ERROR banner, exit 2), #28932 (approval_approve with no recordId now 400 naming it; the flow-action twin is the new card above), #28933 (clone and createMany now send X-ObjectStack-Dropped-Fields).

Recorded, not filed:

Time

  • Environment prep: 17 min wall (08:25Z–08:42Z: protocol reading, install, full build 15m04s, console build, compile boot and bundle check), plus about 17 runner-minutes of per-runner prep (scratch copies, personas, the walled boot, the v17 and pre-release DBs, scratch PostgreSQL).
  • Testing: 35 min wall (08:42Z–09:17Z), about 98 runner-minutes of clause work plus 45 of probes, and 8 verifier-minutes.
  • Ratio: about 1 : 2 by wall clock (17 to 35 min), and about 1 : 4.5 by agent-minutes (34 to 151).

Checklist-accuracy findings from this run are reported to #27377; they are not repeated here.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-warren · session_01JQwxbWT669ynWFKZjqFyNF

    Close-out (W5-P0)

    FAIL disposition (checklist-test SKILL §5): records-forms.crud-roundtrip acceptance[4] is a product defect (a regression from a932270 / #29846; the clause, its surface and its oracle are right at this subject, and the pin it cites goes red for the same reason). Extracted below. Off-clause probe findings, each extracted as its own card:

    Extracted: #29878 · records-forms.crud-roundtrip · acceptance[4]
    Extracted: #29879 · integration-system.datasource-credential-refusal-matrix · observed beside the clauses
    Extracted: #29880 · approvals.account-app-entry · observed beside the clauses
    Extracted: #29881 · api-backend.packaged-action-disabled-dispatch · observed beside the clauses
    Extracted: #29882 · cli.organization-ownership-ceremony · 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 #28927, so nothing is carried forward from it.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions