Repository navigation
Description
domain:devx#1 · os-warren · session_01JQwxbWBtYWqaV8NhvUrShB
Filed by the dispatching PM seat session for the W4-C3a runner session_01JQwxbZsvATYMNMArStUo2M, whose own write was refused by its session permissions (RUNNER rule 2: staged text, posted verbatim through the same door).
Part of #27377 (wave 4, W4-C3a)
QA run record for the 18.3.0 release-candidate sweep, wave 4, card W4-C3a: the unpinned P1 set (plus unpinned v18.x P2) on the api · cli · build surface. Every clause was driven live over REST, CLI, MCP or a build, on a fresh showcase boot (or a scratch app) per item.
Result: 44 of 44 items judged. 41 PASS, 2 PARTIAL, 1 FAIL, 0 BLOCKED, 0 NOT-RUN. The one FAIL is ai.mcp-run-action-exposure-gate, with two failing clauses: one stale spec and one product defect. All five owed retests hold. Off-clause probes found six further product defects, extracted at close-out through the pm-dispatch filing gate; a seventh observation did not pass the gate and is kept in the notes below. One off-clause security observation was reported privately to the dispatching PM session and is not described here.
The per-clause verdict table (370 rows) is too long for one issue body. It is posted in the three comments directly below this body, grouped by runner, in the same column shape as wave 3.
Environment fingerprint
-
Framework:
objectstack-ai/objectstack@7fa9873f38f7a0158e3ce17338dcc0f446b113e3(detached), which includesui/. Its push CI (incl. Dogfood Regression Gate) and Lint were green. -
Build:
npm_config_nodedir=/opt/node22 pnpm install --frozen-lockfile(23 s), thenpnpm exec turbo run build --concurrency=2underscripts/pm/os-verify-lock.sh(16m12s, exit 0).node scripts/check-dev-prereqs.mjsgreen (106 package artifacts). The console was not built: no item has a browser surface. -
Boot, per item:
OS_PORT=PORT OS_STORAGE_LOCAL_ROOT=RUN/uploads setsid pnpm -C examples/app-showcase exec objectstack dev --ui --seed-admin --no-compile --no-watch -p PORT -d file:RUN/data.db, stopped by process group.examples/app-showcase/dist/objectstack.jsonwas compiled once by the build and never rewritten (mtime and md5 unchanged at the end).- Items that install packages, compile or build an app, write the external datasource, or need an edited app booted from a scratch copy of the app (tar, node_modules symlinked back) or a scratch
create-objectstack -t blankscaffold. examples/app-showcase/.objectstack/installed-packages/was never created in the tree.git statuswas clean at the end. Every tree boot creates the git-ignored.objectstack/data/showcase_external.db(the RUNNER environment fact); it was left in place.
- Items that install packages, compile or build an app, write the external datasource, or need an edited app booted from a scratch copy of the app (tar, node_modules symlinked back) or a scratch
-
Ports 41300–41439, one file DB per boot. Execution was parallel: seven runner subagents (5–7 items each, grouped by area), one boot at a time per runner. Their verdicts were accepted after the coordinator cross-checked every runner's clause rows against each item's acceptance and negative counts, and re-read the FAIL against the item history and the rulings it cites.
-
Seed: stock showcase plus
--seed-admin(admin@objectos.ai). Personas: the demo personas (password showcase123); members minted by invite then sign-up, or by admin create-user; thesearch:qa-contributor-bound-memberrecipe. Each persona's identity was proven withGET /api/v1/auth/get-sessionbefore its cells. -
Special boots:
OS_AUTH_TWO_FACTOR=truefor the four two-factor items (one boot, run as one sequence as backup-codes fixtures.requires[0] prescribes);OS_METADATA_WRITABLE=objectfor the second leg of owd-save-gate,OS_METADATA_WRITABLE=agentfor a retired-def-refusal leg;OS_CLOUD_URL=offfor marketplace-install-local-lifecycle boot B and the runtime-config offline arm;- a scratch copy with the MCP upstream moved away for connector-degraded-recovery, with the dispatch proven to land on that boot (ping uptime 21.16 s against /health 24.31 s three seconds later), and a config-fault twin booted with compile from its own scratch copy;
os servewithOS_AUTH_SECRETandOS_SECRET_KEYfor fresh-install-migrate-apply-first.
OS_AUTOMATION_SCHEDULED_WORK_ENABLEDwas unset; no clause in this set is clock-driven. -
Timestamps (UTC, 2026-11-02): preparation 03:33, build 03:34–03:50, runners 03:51–04:17, coordinator verification and close-out drafting from 04:17.
Scope
The selector is release-18.3.0-w4-c3a: the W4-C3a id list of anchor #27377's wave 4, computed from the ledger at 7fa9873. Revisions are the ones node scripts/checklist-select.mjs ID --json reported at 7fa9873. All 44 items are runnable and none is planned.
access-security.scope-depth-asymmetry r5 · access-security.sharing-rules-widen r4 · access-security.record-share-grant-revoke r8 · access-security.owd-save-gate r7 · access-security.packaged-flow-write-door-parity r4 · ai.agent-tool-skill-metadata-roundtrip r8 · ai.mcp-run-action-exposure-gate r6 · api-backend.batch-transactional-discovery r8 · api-backend.formula-gates r3 · api-backend.enforce-or-remove-authoring-gates r7 · api-backend.error-envelope-ledger r8 · api-backend.filter-comparand-conformance r4 · api-backend.retired-def-refusal r4 · api-backend.aggregate-contract-matrix r7 · api-backend.api-methods-verb-gate r4 · approvals.decision-only-via-service r5 · approvals.approver-resolution-matrix r9 · attachments-storage.field-accept-maxsize-server-enforced r7 · automation.trigger-status-contract r11 · automation.packaged-flow-subflow-disable-refusal r11 · cli.build-own-contract r9 · cli.migrate-plan-apply-json r8 · cli.verify-verdict-exit-mapping r3 · cli.qa-suite-execution r11 · cli.migrate-meta-codemod r7 · cli.doctor-health-report r5 · cli.migrate-duplicates-inventory r10 · cli.hook-body-extraction-gates r8 · cli.fresh-install-migrate-apply-first r3 · identity-auth.self-service-password-reset r5 · identity-auth.two-factor-enrollment-reveal r5 · identity-auth.two-factor-verify-to-activate r5 · identity-auth.two-factor-backup-codes r6 · identity-auth.two-factor-disable-lifecycle r3 · integration-system.connector-degraded-recovery r6 · integration-system.external-datasource-federated-read r5 · platform-core.docs-audience-gate r4 · platform-core.manifest-install-contract r8 · platform-core.marketplace-install-local-lifecycle r9 · platform-core.runtime-config-boot-read r5 · platform-core.seed-mode-matrix r6 · records-forms.validation-rule-type-matrix r7 · search.rls-both-personas r8 · studio-authoring.removed-key-save-door-refusal r4
No automated.ref pin scored a clause in this set. Supporting pins that were run are cited with their layer in the clause evidence.
Comparison with wave 3 (#27392, at c4c515a)
25 of the 44 items were in #27392; 19 are new to this card.
- Deltas on the 25 shared items:
ai.mcp-run-action-exposure-gater5 → r6: PARTIAL → FAIL. Clause 1's permitted half, blocked in wave 3, now passes on theqa_ai_gatedrecipe added by r6 (its first live proof). Clause 4 fails as a stale spec and negative 1 as a product defect (see FAIL).platform-core.docs-audience-gater3 → r4: PARTIAL → PARTIAL, the same gap (clause 2's unknown-future-shape half has no pin and is unreachable live).- The other 23: PASS → PASS. Revisions moved on 14 of them (record-share-grant-revoke r7→r8, agent-tool-skill-metadata-roundtrip r7→r8, aggregate-contract-matrix r6→r7, api-methods-verb-gate r3→r4, error-envelope-ledger r7→r8, packaged-flow-subflow-disable-refusal r10→r11, trigger-status-contract r8→r11, fresh-install-migrate-apply-first r2→r3, hook-body-extraction-gates r7→r8, qa-suite-execution r10→r11, two-factor-disable-lifecycle r2→r3, two-factor-enrollment-reveal r3→r5, manifest-install-contract r7→r8, removed-key-save-door-refusal r2→r4).
- New to this card (19): 18 PASS and 1 PARTIAL (
cli.verify-verdict-exit-mapping). The new items are access-security.scope-depth-asymmetry, access-security.sharing-rules-widen, api-backend.formula-gates, api-backend.enforce-or-remove-authoring-gates, api-backend.filter-comparand-conformance, api-backend.retired-def-refusal, cli.build-own-contract, cli.migrate-plan-apply-json, cli.verify-verdict-exit-mapping, cli.migrate-meta-codemod, cli.doctor-health-report, cli.migrate-duplicates-inventory, identity-auth.self-service-password-reset, identity-auth.two-factor-verify-to-activate, identity-auth.two-factor-backup-codes, integration-system.external-datasource-federated-read, platform-core.marketplace-install-local-lifecycle, platform-core.runtime-config-boot-read, records-forms.validation-rule-type-matrix. Two of them carried a FAIL or PARTIAL in their last record (identity-auth.two-factor-backup-codesFAIL at QA run · surface:api (89/89) · 251a7dd4 · 2026-10-04 · 68 PASS / 7 PARTIAL / 14 FAIL / 0 BLOCKED / 0 NOT-RUN #21720,cli.migrate-plan-apply-jsonPARTIAL at QA run · area:cli (17/17) · 94114c1f · 2026-10-16 · 16 PASS / 0 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #23921); both PASS here.
Derived item verdicts
PASS (41): every item in Scope except the three below.
PARTIAL (2):
cli.verify-verdict-exit-mapping: clause 3's "a hole fails the run" leg is blocked(fixture). A hole is a real RLS bypass and cannot be staged on a healthy build. The RLS stack, the rls section and the staged fail side (fidelity-gap, create-failed, needs-fixture → exit 1, hardFailures 2) all passed.platform-core.docs-audience-gate: clause 2's unknown-future-audience-shape half is blocked(fixture): no pin, and the save door refuses that shape with 422 so it cannot be planted live (knownGaps[2]). The other half passes on the spec pinbook.test.ts(45/45, pure schema layer).
FAIL (1):
ai.mcp-run-action-exposure-gate: acceptance[4] (stale spec) and negative[1] (product defect). Clauses 0–3 and negative[0] pass.
FAIL — reproduction rules and dispositions
ai.mcp-run-action-exposure-gate · acceptance[4] — disposition: stale spec
The clause pins the pre-#27681 wholesale refusal of every sys_* action. Maintainer ruling 6513869839 on #27681 (letter B) and the ADR-0011 addendum "the platform identity actions an agent may reach" (ruling 6523087116 on #27900, amended by 6540309323) replaced it with a per-action ai.exposed opt-in, implemented by systemObjectActionExposureError (packages/runtime/src/action-execution.ts) and isListableAction (packages/mcp/src/mcp-http-tools.ts). Item r6 (2026-10-31) changed only the clause-1 fixture and kept this clause.
Reproduction (three fresh stock boots, 41325–41327): admin osk_ key from POST /api/v1/keys {"name":"k"}; MCP Streamable HTTP on /api/v1/mcp (initialize, then tools/call).
list_actions {}→totalCount37, of which 36 have asys_*objectName (sys_user, sys_session, sys_api_key, sys_organization, sys_member, sys_invitation, sys_team, sys_team_member, sys_account, sys_oauth_application, sys_sso_provider). Expected by the clause: none.run_action {"actionName":"create_api_key","objectName":"sys_api_key","params":{"name":"x"}}→ refused, nothing created, but with 'Action "create_api_key" on system object "sys_api_key" is not exposed via MCP: a system object's action is reachable only when its author exposed it to AI (ai.exposed) and list_actions lists it for you'. Expected: 'Object "sys_api_key" is a system object and its actions are not exposed via MCP'.- The same call without objectName → "Action 'create_api_key' is on a system object ('sys_api_key') and is not exposed via MCP — a system object's action is reachable here only when its author declares
ai: { exposed: true, description: … }on it". Expected: "Action 'create_api_key' is on a system object and is not exposed via MCP". run_action {"actionName":"revoke_api_key","objectName":"sys_api_key","recordId":ID}passes the guard and meets the next gate, 428 ACTION_CONFIRMATION_REQUIRED. Expected by the clause: the guard refuses it.
Product side is correct (non-exposed system actions are refused with zero side effects). The clause, step 6 and acceptance[1].verify ("showcase_portfolio_snapshot is the one exposed action") need re-pointing. Carried by the wave anchor #27377 §1 ("Re-point — red rows this anchor owns"), the way wave 3's stale-spec row was; under the pm-dispatch filing gate a ledger re-point is not a card of its own (close-out Parked-on: line).
ai.mcp-run-action-exposure-gate · negative[1] — disposition: product defect
The negative forbids list_actions advertising an action that run_action then refuses. Reproduced on three fresh boots (41325, 41326, 41327):
- Fresh stock boot. Admin (session):
POST /api/v1/keys {"name":"r2-repro"}→ key K;POST /api/v1/keys {"name":"throwaway"}→ id T. - MCP on
/api/v1/mcpwithAuthorization: Bearer K(initialize,notifications/initialized). list_actions {}:revoke_api_key(objectNamesys_api_key, requiresConfirmation true) carries NOunavailablekey, while every identity-route action in the same list carriesunavailable: {code: UNAUTHENTICATED, reason: "…accepts a signed-in session only, and this request was authenticated with an API key…"}.run_action {"actionName":"revoke_api_key","objectName":"sys_api_key","recordId":T,"confirm":true}→ isError{"code":"PERMISSION_DENIED","status":403,"message":"PERMISSION_DENIED: Changing an API key requires a signed-in session. … a request authenticated with an API key cannot revoke, restore or change API keys."}. AdminGET /api/v1/data/sys_api_keyshows Trevoked: false.
- Expected: either the listing marks revoke_api_key
unavailablefor an API-key caller, or the run succeeds. - Actual: listed as runnable, then refused 403; nothing changed.
- Control: the same run_action through MCP with the admin's session bearer →
ok: true, T readsrevoked: true.
Self-check: the osk_ key is valid (the same MCP session ran showcase_portfolio_snapshot); Mei's key shows the same listing (not wrong-persona); the refusal text names the credential kind (not a driver artifact). Mechanism: apiForwardCredentialRefusal classes revoke_api_key's target PATCH /api/v1/data/sys_api_key/{id} as the data door, which its table says accepts api_key, while packages/core/src/security/api-key-management-credential.ts refuses API-key-authenticated changes to sys_api_key. The refusal holds and nothing changes, so this is a listing-honesty defect, not an authorization hole.
Retests (anchor #27377 §4 and SKILL §5 trigger 2)
node scripts/qa/retest-owed.mjs at 7fa9873 listed five owed rows on this card's items. All five hold.
platform-core.seed-mode-matrix, fix metadata-protocol: when one seed in a publish-drafts batch fails, the seedApplied receipt reports inserted 0 / updated 0 although earlier seeds wrote rows, and later seeds are published but never applied #27393: holds. The card's literal repro now reportsseedApplied {success:false, inserted:2, updated:0, error:"seed apply stopped at the seed for object 'seedrepro_nope': …"}, matching the rows written; an update variant reportsinserted:1, updated:2, also matching. Two independent boots and DBs. Unchanged on purpose (stop-at-failure is kept by the fix): a good seed sorting after the failing one is published but not applied; it is now flagged by aseed_not_appliedprobe.automation.packaged-flow-subflow-disable-refusal, fix install-local: uninstalling a package (DELETE /api/v1/marketplace/install-local/ID) leaves its flows registered and triggerable in the automation engine until an unrelated metadata reload #27395: holds. AfterDELETE /api/v1/marketplace/install-local/IDthe uninstalled package's flows answer 404 from the engine and a packaged record-trigger stops firing. R7 independently saw the crm flow leave/automation/_statuson DELETE.approvals.approver-resolution-matrix, fix approvals: auserapprover naming a nonexistent user id opens a request on a phantom slot with no warning and no onEmptyApprovers fork, so the request is stuck pending forever #27397: holds. Auserapprover naming a nonexistent user id now logs an "expanded to nobody" warning and the request routes to the administrators (admin_rescue).attachments-storage.field-accept-maxsize-server-enforced, fix service-storage: sys_file lifecycle columns (status, size, mime_type) are writable through the data door, so a never-uploaded file can be marked committed and then claimed by a file field #27399: holds. The data door dropsstatus,size,mime_type,keyandetagon sys_file as readonly; a never-uploaded file stays pending and the file field refuses it.records-forms.validation-rule-type-matrix, fix objectql(validation): an unevaluable severity:'warning' rule logs "write rejected: … fails closed" twice while the write is accepted 201 and persists #24782: holds. The card's recipe answers 201; exactly one log line namesqa_unevaluable_warnand says "write proceeded", none says "write rejected" or "fails closed"; the error-severity control still answers 400 and writes no row.
Wave 3's two off-clause retests on this card's items were re-confirmed: #26478 (cli.hook-body-extraction-gates: five builds — first, rebuild, other cwd, other checkout path, fresh copy with no dist — emit the same bundle, sha256 11daba63…, with no absolute path in the bundle or its decoded sourcemap) and #26480 (platform-core.manifest-install-contract: ^19, >18, engines.platform ^19, legacy ^19.0.0 and ^20 each answer 422 OS_PROTOCOL_INCOMPATIBLE with no migrateCommand and leave no row; the older direction still offers migrate meta --from 17).
Off-clause probes (RUNNER rule 8)
Probes took about 60 runner-minutes across the 44 items. Doors probed: every door the clauses drove, plus /api/v1/analytics/dataset/query, the createMany/batch doors, the sys_two_factor and sys_record_share data doors, the encoded-path install-local doors, and os test / os migrate / os build argument edges. Personas: admin, the demo personas, minted members, the contributor-bound member, anonymous, a garbage or rotated bearer, and osk_ keys. Boundary classes: empty string, null, missing and unknown id or name, case variants, encoded ..%2F segments, oversize and malformed codes, opposite severity and posture (info/warning/error, password_history_count 3 vs 0, isolated vs single), readers outside scope, a trailing slash, an inverted range.
Seven product defects were found, each reproduced at least twice on independent boots. Six pass the pm-dispatch filing gate (class ①) and are extracted at close-out; number 3 does not and stays here as a note:
- Beside
api-backend.formula-gates: the date-arithmetic gate passes bare date subtraction (record.end_date - record.start_date,today() - record.start_date); build, validate and lint exit 0, and the field reads null or{}at runtime. - Beside
api-backend.enforce-or-remove-authoring-gates:/api/v1/analytics/dataset/queryrefuses retired$regex/$optionsinruntimeFilterwith a generic "Unsupported filter operator" instead of the RETIRED prescription naming$icontains. - Beside
cli.build-own-contract:os buildreportssizeand the summary KB as UTF-16 code units, not bytes (jsonContent.lengthin compile.ts; blank scaffold 2540 reported vs 2542 on disk, showcase 743.0 KB vs 750.4 KB). Not filed: the filing gate finds no user-visible cost beyond a 0–3% misreported size that no gate or reader acts on. - Beside
cli.qa-suite-execution:os test --urlwith a trailing slash requests//api/v1/...and fails every HTTP scenario 404. - Beside
cli.migrate-meta-codemod:os migrate meta --jsonanswers an empty (--from 18) or inverted (--from 19) range exactly like a clean replay; the "replayed nothing" warning exists only on the human path. - Beside
records-forms.validation-rule-type-matrix: the showcase flowshowcase_project_escalationfails terminally (CELno such overload: dyn‹null› > int) whenever a project with no budget turns red. - Beside
platform-core.seed-mode-matrix: an upsert seed whoseexternalIdnames a field the object does not have is accepted and inserts a duplicate on every publish, silently.
Security: identity-auth.self-service-password-reset · observed beside the clauses · security finding — detail withheld, reported to PM. It moves no clause verdict.
Observations recorded and not extracted (judged by design, documented, or wording only):
/automationanswers a removed flow key with 400 VALIDATION_FAILED where/metaanswers 422 INVALID_METADATA (deliberate in the code); view refusals add a bare root "Invalid input" issue; the unknown-key hint can suggest an unrelated key (aria → areas, defaultSort → defaults, a field with no type → "Did you mean 'url'?").PUT /meta/TYPE/NAME?mode=with any value other thandraftsaves live, as documented, so a typo such as?mode=draftspublishes env-wide; the same module refuses an unknown?surface=.os testprints a stack trace and a doubled "Error: Error:" prefix on an ordinary assertion miss (seen in wave 3 too); "Config file not found" exits 1 on the human path where other load failures exit 2 (within the clause's allowed set).os migrate plan --json --database-url ''falls back to the default DB (the payload sayskind: default);os migrate duplicates --objectdoes not narrowliveConditions;os migrate organization-ownership --jsonwrites its plan file into the CWD by default.- A
fieldapprover with an empty or unknown field logs only the node-level warning; a member's write to an external object returns datasource details before the permission refusal; any signed-in member can list connectors with their degraded reasons. - Derived namespaces of two long ids sharing their first 20 characters collide, and the 422 NAMESPACE_CONFLICT does not say the namespace was derived; a catalog install on
OS_CLOUD_URL=offanswers "OS_CLOUD_URL not configured" although it is set tooff. - Two-factor: disable on an unenrolled user is a no-op 200 that still rotates the session; the challenge sign-in response carries a
set-auth-tokenheader whose token is dead.
Checklist-accuracy findings (for anchor #27377)
ai.mcp-run-action-exposure-gater6: acceptance[4], step 6 and acceptance[1].verify are stale (the FAIL above, carried by the anchor §1 re-point row). fixtures.requires[3] (qa_ai_gated) is now proven live: admin list_actions 38 includes it, Mei's 37 does not, teardown DELETE 200 then GET 404; the history's "Not yet run live" can close.api-backend.filter-comparand-conformancer4: acceptance[1].verify asks every refusal to quote the accepted-types sentence, but the array-for-scalar refusal comes from the operator-arity door (it names the path and prescribes$in/$between); acceptance[3] lists "a multiple field" in the null class, but a multiplelookupclassifies as relation and is refused 400 INVALID_FIELD; no stock task row has a null number or boolean (use start_date, or seed one).api-backend.aggregate-contract-matrixr7: knownGaps[0] still holds; one more seeded duplicate revenue row also makescount_distinct(annual_revenue)discriminating (12 vs 13).api-backend.retired-def-refusalr4: steps[2]–[4] still namemanifest.loadingas the prescription-bearing carrier; since spec: retire tombstones, conversions and migration entries older than one protocol major; a strict unknown-key refusal with an upgrade-guide link takes over (maintainer ruling D2 = A) #25767 (ADR-0087 amendment D2=A) it aged out at 18 and gets the generic refusal plus upgrade-guide pointer. Name a live carrier (thethemesstack key,manifest.extensions). Registry digits: 247 entries (53 at 17, 194 at 18).api-backend.enforce-or-remove-authoring-gatesr7: stored widget filters are served by/analytics/dataset/query; a clause leg there would have caught probe defect 2.cli.verify-verdict-exit-mappingr3: acceptance[3].verify citesrls.summary.holes, but verify.ts sumsrls.totals.holesplusrls.probe.degradedplusrls.positionCoverage.notRun.length; acceptance[1]'s hardFailures formula omits those and the five opt-in checks; steps[4] could say a bare walled posture fails loudly withWALLED_MEMBERSHIP_POLICY_UNDECLARED.cli.build-own-contractr9, acceptance[3]: a plain thrown Error at load carries nocodeon either command; only coded throws do. Wording only.cli.hook-body-extraction-gatesr8: CAPABILITY_PATTERNS has a fifth shape,.title(…)→api.read, that steps[2] does not probe.cli.migrate-duplicates-inventoryr10: acceptance[3] "three entries from two migrations" is now four entries from three (sys_setting and notification-preference identity indexes added); steps[1]'s NULLorganization_idrow cannot be inserted on a freshly synced DB (column NOT NULL) without rebuilding the table to the nullable shape.cli.migrate-plan-apply-jsonr8, steps[8]:metaneeds--fromthough its USAGE shows it optional;record-currency-codeshas no stock success path (no record-mode currency field) unless the scratch config adds one.cli.migrate-meta-codemodr7: negative[6] should read "while schema refusals remain after the chain", since the 448 step-18 advisories always print beside "schema-valid"; planting the data key onCategoryis refused[shared](also referenced by a seed) whilePrivateNotewrites cleanly.records-forms.validation-rule-type-matrixr7, acceptance[1]: script and conditional rules without a declared field target_record, which the clause prose ("not a bare object-level failure") would read as a fail.identity-auth.two-factor-backup-codesr6, fixtures.requires[2]: names the DB file only for a--freshboot, not the-dpath of the canonical boot.identity-auth.two-factor-enrollment-revealr5, acceptance[4].verify: "the pre-verify bearer answers 401" holds only after verify-totp rotated the session.identity-auth.self-service-password-resetr5, steps[0]: theforgetPassword: '/forget-password'divergence inpackages/spec/src/api/auth-endpoints.zod.tsis still unfiled.automation.trigger-status-contractr11: acceptance[5]'s "node edited away under a live pause" exit no longer answers 404, because a paused run pins its flow body (resolveResumeTarget, run-resume.ts) and resumes on it (200); only the deregistered-flow exit is drivable, and the clause was scored on it. 409 RESUME_CHILD_PENDING (clause 4) has no step; it is drivable with a map parent over a screen child.attachments-storage.field-accept-maxsize-server-enforcedr7, fixtures.requires[2] / steps[7] / clause 5: since service-storage: sys_file lifecycle columns (status, size, mime_type) are writable through the data door, so a never-uploaded file can be marked committed and then claimed by a file field #27399 the admin data-door PATCH no longer clearsmime_type/size; the working channel is an out-of-process write to the boot's file DB (or a system-context engine write).approvals.decision-only-via-servicer5, steps[4]: the dev admin fills both slots of the unanimous slate, so one approve satisfies it and a second answers 409 INVALID_STATE.integration-system.external-datasource-federated-readr5, steps[1]:GET /api/v1/metaanswers only types and entries; the federated objects are confirmed throughGET /api/v1/meta/object.GET /api/v1/datasources/showcase_externalcarries nostatus(only the list does).access-security.record-share-grant-revoker8: the last step assigns the position through the Setup UI; the API doorPOST /api/v1/data/sys_user_positionmakes it replayable without a browser.access-security.sharing-rules-widenr4, acceptance[4]: the re-enabled rule's share gets a new id; the clause (same id after the second restart) is right.platform-core.seed-mode-matrixr6, steps[0]: an unprefixed object's publish answers HTTP 200 withoutcome:"refused"and code NAMESPACE_PREFIX, not 422; discarding a draft takes?state=draft(?mode=draft→ 400).platform-core.manifest-install-contractr8: steps[0] reads the protocol version from the boot banner orGET /api/v1/meta, which carry none (discoveryversionis the runtime's 18.2.0); steps7 needs a SECOND package claiming the same shareable namespace to discriminate the exemption (this run drovebaseandsystwice each, both 201).- RUNNER environment-fact candidate: an
os dev --no-compile --no-watchboot still hot-reloadsdist/objectstack.jsonwhen another process rewrites it and syncs the new schema into its DB within about 3 s, so on a shared tree any rebuild ofexamples/app-showcase/distchanges every other runner's live boot.
Fixture gaps
cli.verify-verdict-exit-mappingclause 3: no stageablerls-hole(the PARTIAL above); clause 2 has no lever for a 5xx create (a throwing hook answers 400 HOOK_ABORTED), staged instead with a mutating hook, a throwing hook and an always-false validation on a scratch scaffold.platform-core.docs-audience-gateclause 2: unknown-shape half has no pin (knownGaps[2], the PARTIAL above). The stock showcase still has no permissionSet-gated book or orphan doc; the run authored them in a scratch package and discarded them.api-backend.aggregate-contract-matrix: 5 showcase_account rows seeded at runtime (null revenue, Monday/Sunday, ISO-year boundary, duplicate revenue), plus the contributor-bound member and 2 own invoices.api-backend.filter-comparand-conformance: 1 showcase_task with null fields seeded.api-backend.api-methods-verb-gate: scratch objects authored throughPUT /meta/object, as the item's knownGap prescribes.ai.agent-tool-skill-metadata-roundtrip: the AI trio and 11 probes authored only in a scratch app copy (no stock AI seeds).cli.migrate-plan-apply-json/cli.migrate-duplicates-inventory: no record-mode currency field and no second org-scoped identifier in the stock showcase; both added in scratch configs. The duplicates mongodb branch remains unverified (knownGaps).access-security.sharing-rules-widen: the stock seed has no org-stampedsys_business_unit_memberrows (boot WARN "expands to NO recipients"); the runtime BU member that fixtures.requires prescribes resolves it.
Timing
Wall clock, cold tree to last runner verdict: 44 min.
- Environment: about 17 min wall (install 23 s, full build 16m12s), plus about 50 runner-minutes of boots, scratch copies and persona and fixture minting inside the runner window.
- Testing: 26 min wall (03:51–04:17) for seven parallel runners; about 60 runner-minutes of that were off-clause probes.
- The wall ratio of environment to testing is roughly 1 : 1.5.
Generated by Claude Code
Activity
objectstack-fleet commentedon Nov 2, 2026
domain:devx#1 · os-warren · session_01JQwxbWBtYWqaV8NhvUrShB
Filed by the dispatching PM seat session for the W4-C3a runner
session_01JQwxbZsvATYMNMArStUo2M, whose own write was refused by its session permissions (RUNNER rule 2: staged text, posted verbatim through the same door).Per-clause verdicts, part 1 of 3 (access-security, search, studio-authoring, api-backend, ai, build-surface cli). Clause numbers are acceptance indices;
neg/negNare the item'snegativelist. Evidence is text oracle output only.aud list / aud by-id / out by-id / rule shares / ledger: baseline 1 [KmsAj…] / 200 / 404 / [shr_89666f92…] / no row. off (POST /security/_activation/… {enabled:false} → 200) 0 / 404 / 404 / [] / active false, updated_at 03:56:06.944Z. restart 0 / 404 / 404 / [] / active false, same 03:56:06.944Z. on ({enabled:true} → 200) 1 / 200 / 404 / exactly one [shr_f51231fc…] / active true, 03:56:35.322Z. restart 1 / 200 / 404 / [shr_f51231fc…] (same id) / active true, same 03:56:35.322Z. PATCH sys_record_share/‹id> → 405 OBJECT_API_METHOD_NOT_ALLOWEDobject.externalSharingModelwas removed in @objectstack/spec 18 … Delete the key." The ?mode=draft twin gives the identical 422. The plain GET → 404 RESOURCE_NOT_FOUND and the ?state=draft GET → 404 NO_DRAFT. A GET with ?mode= → 400 (unsupported param). The same 422 appeared on the OS_METADATA_WRITABLE=object bootcmpclean, sha256 3a525e021c170c78…) on both bootsmanage_metadatacapability". The two tiers are distinctrefreshIntervalSecondsin @objectstack/spec 17"). 22 aged-out keys (unrecognized_keys at the PARENT path, e.g.fields.title,config, or root; message names the key and carries the upgrade-guide sentence). Run twice, 33/33 both timeszzz_junk_key…"), object, page and dashboard. No stored draft contains the keymessagebesideerroros migrate meta… https://objectstack.ai/docs/protocol-upgrade.); median → 400 "expected one of count|sum|avg|min|max|count_distinct" with no tail; no 500upsert: declare ['create','update'] … ⚠ After stripping, this whitelist is EMPTY —[]means DENY-ALL" + [Registry] per-object line; ['get','history'] PUT 200 + "history: declare ['get'] withenable.trackHistory: true", runtime 405 allowed [get] and get → 404 RECORD_NOT_FOUND (passes the gate)objectstack compileexit 0 with the expected agent-authoring-withdrawn warning on qa_probe_agent. 11 probes each exit 2 with no artifact: tool.permissions/active/category/builtIn/requiresConfirmation → unrecognized_keys + per-key guidance (permissions: "promised a capability gate on tool invocation that nothing ever enforced"); agent.tools, agent.knowledge, skill.triggerPhrases → "Unrecognized key(s)…‹key>… see the protocol upgrade guide: https://objectstack.ai/docs/protocol-upgrade"; agent.lifecycle → "removed in @objectstack/spec 17.7.0… Runos migrate meta --from 17"; skill.permissions and skill.trigger → their guidance sentences + the guide pointerai: { exposed: true, description: … }"; REST re-read status, done, progress and updated_at are unchangedobjectName"): showcase_mark_done absent, showcase_portfolio_snapshot present. Staged qa_ai_gated (requires manage_metadata) is present for admin (totalCount 38) and absent for Mei (37), while the snapshot is in both. The permitted half is discriminated, and this is the first live proof of the rev-6 recipeunavailablemarker (the 35 identity-route actions carry unavailable UNAUTHENTICATED). run_action revoke_api_key + confirm:true then refuses: 403 PERMISSION_DENIED "Changing an API key requires a signed-in session… a request authenticated with an API key cannot revoke, restore or change API keys", and the key stays unrevoked. Reproduced on 3 fresh boots@objectstack/formula→/home/claude/objectstack/packages/formula/dist/index.js(dist; no src newer than dist).celEngine.evaluate:record.due_date == today()→ true for '2026-11-02', false for '2026-11-01' (now=2026-11-02);record.flag ? record.x : null→ 42 / null;floor(3.7)→3,ceil(3.2)→4,floor(-3.2)→-4. ALL PASSqa_doctor_time_off, formulaqa_days_span=… ? (record.end_date - record.start_date) + 1 : null.os buildexit 1: "✗ Author-time rules failed (1 issue)"object 'qa_doctor_time_off' · field 'qa_days_span' expression: date arithmetic \google.protobuf.Duration + int` — `record.start_date` is a date … Use `daysBetween(a, b)` …, ruleexpression-invalid`os buildexit 0, "✓ Build complete", 65 author-time warnings, artifact 743.0 KB. The onlytoday()use is predicate-matrix.action.ts:523record.f_date < today()dist/{index,data,api}/index.js) safeParse rejectsquery.cursor,query.joins,query.distinct,query.windowFunctionsandEnhancedApiError.fieldErrors(eachinvalid_typeat its path);routes.includeObjectsis rejected too. The controlfieldsparses clean. Filter registry: a widgetfilter: { name: { $regex: 'acme' } }in ops-dashboard (scratch) builds exit 0 and is stored verbatim;FilterConditionSchemaparses$regex/$optionsclean. LivePOST /api/v1/data/showcase_project/query {"where":{"name":{"$regex":"acme"}}}→ 400code: INVALID_FILTER"Filter operator "$regex" on field "name" is RETIRED … Write "$icontains" instead …" ($regex+$optionsand$optionsalone are refused the same way; the$icontainscontrol → 200).os migrate meta --from 16prints⚠ [protocol 17] data.filter $regex / $options — …;--jsontodos[].id includesfilter-regex-options-retiredwherepredicate on your sort key —where: { created_at: { $gt: … } }"; joins → "read throughexpand"; fieldErrors → "renamed tofields"; includeObjects → "enable.apiEnabled/enable.apiMethods"; $regex → "Write "$icontains" instead … or$contains" (registryto: '$icontains')RestServerConfigSchema.safeParse({routes:{someUnknownKey:1}})→ success, routes reads back{}. RouteGenerationConfigSchema docblock (rest-server.zod.ts:648–665): "an authored key is refused with its prescription instead of being silently stripped (the schemas are not.strict())". The same sub-object'sincludeObjectsfails with "routes.includeObjectswas removed in @objectstack/spec 17 …"manifest.loading), automation/StateMachine (agents[].lifecycle), ui/Theme (themesstack key). No green buildqaInventedFamily→ "(root): Unrecognized key(s) on this stack definition … see the protocol upgrade guide". Carriers that authored a prescription differ from the control and name the successor:agent.lifecycle→ "removed in 17.7.0 … skill … Flow …state_machinevalidation rule";themes→ "removed in 17.1 … setapp.branding.primaryColor". Route-3 / zero-consumer defs (ExternalDataSource, ScheduleState, ApiKey) get the generic module refusal "does not provide an export named …", which is correct per knownGaps[0].manifest.loadinggets the generic strict "Unrecognized key(s) on this package manifest:loading… see the protocol upgrade guide". Its 16.x kit aged out at 18 under the #25767 ruling (ADR-0087 amendment D2=A), and the prescription now lives in content/docs/protocol-upgrade/17.md, so the generic answer is the correct one (see Checklist-accuracy). json-schema/{data/ExternalDataSource, automation/ScheduleState, automation/StateMachine, kernel/PluginLoadingConfig, ui/Theme, identity/ApiKey}.json are absent; data/ has 174 other filesPUT /meta/agent/qa_agentwith lifecycle → 403 NOT_CREATABLE "code-only".PUT /meta/manifest/…,/meta/external_data_source/…,/meta/schedule_state/…,/meta/api_key/…,/meta/theme/…and invented/meta/qa_invented_family/…→ 400 INVALID_REQUEST "'X' is not a metadata type", the same as the control.POST /meta/external_data_source→ 405./meta/typeslists none of them. UnderOS_METADATA_WRITABLE=agent(41342), an agent without lifecycle → 200, and with lifecycle → 422 INVALID_METADATA carrying the build's exact prescription; the GET answers 404 (not stored). No door disagrees with the buildos buildexit 0; summary "Data: 1 Objects 2 Fields … Artifact: dist/objectstack.json (2.5 KB)"; the artifact parses.--jsonexit 0 carries success:true, output, size:2540, stats{…}, warnings:[], conversions:[], duration (plus bodyExtractionWarnings, handlersBundled, runtimeModule, protocolVersionGap)qa_doctor_brokenwith fieldbodyand no type. Human run: exit 2, "✗ defineStack validation failed (1 issue): ✗ objects.1.fields.body.type: Invalid field type ''…".--jsonrun: exit 1,{success:false, error:…objects.1.fields.body.type…, code:"STACK_SCHEMA_INVALID"}record.owner ==,record.title &&) exits 1 on both paths and reports "✗ Author-time rules failed (2 issues)" in one run. Each finding has where / message / hint / ruleapproval-expression-invalid/ pathflows[0].nodes[1|2].config.approvers[0].value--jsonpayloads were paired per fixture and diffed on [warnings, conversions]; they are IDENTICAL for clean, schema (both carry code STACK_SCHEMA_INVALID), rule (buildissues, validateerrors) and load-throw. Live conversion: withNODE_OPTIONS=--import …/live-conversion-probe.mjsand aprobe_old_calloutnode, both payloads carry the same record{code:OS_METADATA_CONVERTED, conversionId:cli-live-conversion-probe, from:probe_old_callout, to:http, path:flows[0].nodes[1].type, …}throw new Errorin config) human 2/2, json 1/1. No other code was seen.os compilegives the same codes and payloads (JSON identical without duration; human output identical without timing lines)extra.visibleWhen = {dialect:'cel', source:…, qaUndeclared:1}underdefineStack(…, {strict:false}): the block "⚠ Undeclared authoring keys (1) — dropped at load; reported here, never refused" prints, exit 0, and the artifact visibleWhen is{"dialect":"cel","source":"record.title != null"}(key gone). The--jsonwarnings array carries the same line. Under the default defineStack only the one-linedefineStack:warning prints, with exit 0--strict-bodyexits 1 with "✗ --strict-body: 13 callable(s) lack a metadata body" and one line per hook quoting its own reason (fetch and import: "declare a Connector recipe instead"; each host member names itself and its alternative, e.g..create(→ "Spell the same payload.insert({ … })", ctx.ql → "ctx.api.object(name)", ctx.transaction → "ctx.api.transaction(fn)").--jsonexits 1 with{success:false, error:"strict-body: missing body", issues:[13 × {origin,kind,reason,freeIdentifiers}]}const api = ctx.api) ["api.read"]// @capabilities api.write, log) ships ["api.read"] only. qa_d_comment (data body whose source string keeps the comment, no capabilities) ships [] with the source intact. The build exits 0 and prints nothing about either{body:null, handler:"qa_free_helper"}, bundleobjectstack-runtime.2283156a1d78c903.mjsemitted.--strict-body: exit 1, same message;--jsonfreeIdentifiers ["helperFn"]objectstack-runtime.11daba633880d173.mjswas placed in dist, then the all-body-only config built: "→ Skipping legacy runtime bundle (all 8 callables are body-only)". dist then holds only objectstack.json, and runtimeModule is null--jsonexit 0 with success true, bodyExtractionWarnings 13 records and warnings []. jq shows all 13 hooks body:null with a handler ref-vruns both exit 0 and carry rows Node.js, pnpm, TypeScript, Dependencies, Git, Environment files, NODE_ENV (unset → row; absent when NODE_ENV=development), and Package-authored scheduled work OFF. No@objectstack/specrow in the scaffold (0 hits). The monorepo-root run has "✓ @objectstack/spec Built". Tenancy posture appears only onisolatd(1 hit; 0 on clean and valid-isolated runs). Installed packages appears only with broken.json present (0 otherwise). The config block opens "✓ Platform protocol Declared engines.protocol covers the installed platform".-vadds only detail lines (diff = the indented → lines).env=OS_TENANCY_POSTURE=isolatd, nothing in the shell: the ✗ Tenancy posture finding fires (exit 1); "✓ Environment files .env (node_env=production) … — OS_TENANCY_POSTURE from .env";-v"• OS_TENANCY_POSTURE from .env". Supporting pin doctor-env-provenance.test.ts passed (unit layer, part of the 69 passed)OS_TENANCY_POSTURE=isolatd: "✗ Tenancy posture OS_TENANCY_POSTURE="isolatd" is not a recognized tenancy posture" with the allowed set, then the Test coverage/Deprecations rows and the whole config block still print; "❌ Some critical issues found"; exit 1-vadds "→ Looked for /tmp/w4c3a/R3/doctor/qa-doctor/packages/spec/src and found nothing to walk. …" under each.ls packages/spec/src→ No such file. There are no ✓ lines for these scans and no "→ Checking for missing test files" step, and the baseline summary is driven only by the Object usage ⚠. Monorepo root: "→ Checking for missing test files..." with ⚠ Missing test rows, and "→ Scanning for @deprecated usage..." with ⚠ Deprecated rowsverify --jsonexit 0: 24 results, statuses {verified 15, needs-fixture 1, skipped 8}, nothing out of vocabulary. The staged fail app adds fidelity-gaps and create-failed. The --rls and isolated reports have the same vocabulary"code":"VALIDATION_FAILED", on an exit-0 run. qa_doctor_strict (400 VALIDATION_FAILED) → needs-fixture and is excluded from the 2 hard failures. A non-validation create (400 HOOK_ABORTED) → create-failed and counted. TheisValidationbranch (verify.ts:110) sends everything that is not a 400 VALIDATION_FAILED, a 5xx included, to create-failed. A live 5xx was not staged (see Fixture gaps)--rls --jsonexit 0 carries anrlssection (totals 264 objects, 38 PROVEN, 0 holes, 10/10 positions). Separate stack: the --rls stderr shows 2 server starts and 2 graceful shutdowns, against 1 and 1 for a bare run. The recomputed sum with the rls terms matches report.hardFailures. Not observed: a hole → exit 1OS_TENANCY_POSTURE=isolated verify --json→ exit 1,{error:"✖ FATAL: tenancy posture 'isolated' is walled, but this deployment never declared a membership policy…", code:"WALLED_MEMBERSHIP_POLICY_UNDECLARED"}(group gives the same). WithOS_AUTH_MEMBERSHIP_POLICY=invite-only OS_PLATFORM_OWNER_EMAIL=admin@objectos.ai→ exit 0, multiTenant:true, the same 15/1/8 summary. There was never a quiet single-org runGenerated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:devx#1 · os-warren · session_01JQwxbWBtYWqaV8NhvUrShB
Filed by the dispatching PM seat session for the W4-C3a runner
session_01JQwxbZsvATYMNMArStUo2M, whose own write was refused by its session permissions (RUNNER rule 2: staged text, posted verbatim through the same door).Per-clause verdicts, part 2 of 3 (cli migrate and qa suite, identity-auth, records-forms). Clause numbers are acceptance indices;
neg/negNare the item'snegativelist. Evidence is text oracle output only.qa_r4_notewas added toshowcase_category, thenos build, then bareos migratetwice. Both exited 0. The report sections are byte-identical except the elapsed-ms line, and both plan+ showcase_category [add_columns: qa_r4_note]plus the 7 lifecyclecreate_tableentries (7 table(s) to create, 1 column(s) to add). DB digests taken before, between and after are identical:sqlite_master 422 a242576e…, rows71f0365e…, sequencese60816a2….os migrate plan --jsonexits 0. stdout is one JSON document with keyschanges, composition, database, databaseSource, duration, managedTables(76), nullableTenantColumns, pending(8: the add_columns plus 7 create_table), total(0), unmanagedTables.os migrate --helplists 22 subcommands: account-issuer, activity-changed-fields, apply, audit-key-material, audit-mail-bodies, audit-metadata-bodies, comment-parent-pair, comment-reactions, duplicates, files-to-references, meta, multi-value-columns, organization-ownership, packageless-overlays, plan, record-currency-codes, recorded-by, resume, security-catalog-overlays, summary-nulls, unmapped-columns and value-shapes. Every successful--jsonrun printed one JSON document and exited 0: plan; apply--json --yes(×4); recorded-by; resume; account-issuer; activity-changed-fields; audit-key-material; audit-mail-bodies; audit-metadata-bodies; comment-parent-pair; comment-reactions; files-to-references; multi-value-columns; organization-ownership; packageless-overlays; security-catalog-overlays; summary-nulls;unmapped-columns --object showcase_category; value-shapes;meta --from 17;record-currency-codes --object showcase_category --field qa_amount --code USD(with a record-mode currency field added to the scratch, see the fixture gaps); andduplicatesrun bare. Two invocations exited 1, and both were refusals rather than successes: baremeta --json(missing_from_major) andrecord-currency-codeson the stockshowcase_project.budget(INVALID_FIELD: not a record-mode field). DB digests were identical before and after the sweep.apply --yesprinted✗ showcase_category.qa_r4_note [drop_column]and⚠ 1 destructive change(s) will be SKIPPED (re-run with --allow-destructive to include them)., and the column was still present.apply --allow-destructive --yesprinted✓ Applied 1 change(s)., and the column was gone. The JSON twin onqa_r4_b:skipped:[drop_column qa_r4_b]with messagenothing_safe_to_applyand exit 0, thenapplied:[drop_column qa_r4_b]with exit 0.planprinted⚠ No drift over the 76 object(s) this plan examined — but 2 of 78 declared object(s) were NOT examined … This is a PARTIAL plan.apply --json --yesgave{applied:[],skipped:[],created:[],message:"in_sync_partial",composition.coverage:{registeredObjects:78,examinedObjects:76,unexaminedObjects:2,reasons:{federated:2,…}}}and exit 0.os devholding the DB (pid 22919),apply --yesexited 1 with✗ …/migrate.db is in use — it is open in pid 22919 (node) (migrate.db-wal, migrate.db-shm present).and the--forcehint. The JSON form exited 1 with{error:"database_busy",signal:"file_open"}.planexited 0 with⚠ … is in use … The plan below is still accurate — it writes no row or tableand listed the pending+ showcase_category [add_columns: qa_r4_d]. The column was still absent after the refused apply.add_columns qa_r4_b, thenapply --jsonwithout--yes, gave{…,pending:[add_columns qa_r4_b],message:"confirmation_required",hint:"pass --yes"}with exit 1 (a refusal, not a success). DB digest unchanged, and a follow-upplan --jsonstill listed the pending add.--allow-destructive: the column was still insqlite_masterafter the first apply.--jsonrun in the sweep exited nonzero.report.jsonparses as one document. Top level:report:"duplicate-identifiers",reportVersion:2,generatedAt,database:"/tmp/w4c3a/R4/dup/dup.db",globalPartition:"__global__",filter:null,counters:{table:"_objectstack_sequences",status:"read"}, plusscanned[2],skipped[],duplicates[1],liveConditions[1]andruntimeIndexPreflight[4].summary{objectsScanned:1,fieldsScanned:2,duplicateValues:1,duplicateRows:2,liveConditions:1,runtimeIndexesBlocked:1,runtimeIndexBlockingRows:2}. The duplicate carries object, field, value,holderCount:2and partitions, and each holder carries id, organization (null for the NULL-org row), partition and createdAt. Theduplicates.contract.test.tspin is green (3 files, 18 tests, in-process command over a real sqlite seam).f_autonumber0001is held byqa_null_org_row(organization NULL, partition__global__) andCsjtAD5_…(org_mvyqf398…), and it is reported with both partitions. Within-partition:qa_auto20002is held twice inorg_mvyqf398…afteruniq_showcase_field_zoo_organization_id_qa_auto2was dropped, and it appears nowhere in.duplicates.140afd47…/140afd47…, rows1937e602…/1937e602…,_objectstack_sequences6a00d596…/6a00d596…. Whole-file md5 ofdup.db,-waland-shmwas also identical. Theduplicates.pre-repair.test.tspin is green.UNIQUE (type,name,package_id,bundle_member), so no swap was needed. Two activeviewrowsqa_dup_viewwere seeded with null package_id and bundle_member and body{name,label,object,list:{columns:['name']}}..runtimeIndexPreflightshowsidx_sys_metadata_overlay_activestatus:"blocked",groups:[{key:{type:"view",name:"qa_dup_view",package_id_key:"",bundle_member_key:""},rowCount:2}]. No entry names sys_view_definition. The same DB'splan --json(exit 0) has 0 hits foridx_sys_metadata_overlay_activeorqa_dup_viewon stdout. stderr carriesOverwriting view: qa_dup_view×1 andRegistered view: qa_dup_view×2. Matched control: plan does report the within-partition repeat asindex_mismatchuniq_showcase_field_zoo_organization_id_qa_auto2,actual "(absent)", BLOCKED with× 2 rows. ⚠ The preflight now has 4 entries from 3 kernel:ready migrations (overlay_active and overlay_draft,uniq_sys_setting_…,uniq_sys_notification_preference_…), not the clause's "three, two migrations" (see the checklist-accuracy findings).liveConditions:[{object:"showcase_field_zoo",field:"f_autonumber",globalLastValue:5,organizationCounters:[{organization:"org_mvyqf398…",lastValue:2}]}]. After deleting the org counter row:liveConditions:[]and.duplicatesunchanged (jq -S diff empty). With the sequences table renamed away:counters.status:"absent", and the duplicates inventory was still 1 (complete)..filterreadnullon the full run,{object:"showcase_field_zoo"}on the filtered run (1 duplicate), and{object:"showcase_category"}on the no-findings object (scanned 0, duplicates 0).--database-url file:…/dup.dbwithOS_DATABASE_URLunset gavedatabase:"/tmp/w4c3a/R4/dup/dup.db", and its duplicates are identical to the env-var run's. With columnqa_auto2renamed away,.skipped:[{object:"showcase_field_zoo",field:"qa_auto2",reason:"duplicate probe failed: The database refused to run a raw statement…"}].duplicates.null-seam.test.tspassed (in-process command over a seam double, which is the item's prescribed evidence). Live:os migrate duplicates --database-url memory://qaexited 1 with{error:"boot_failed",detail:"[StandaloneStack] A database URL with the \"memory://\" scheme selects the in-memory (mingo) engine, which is no longer a boot store…"}.planleft the digest unchanged.qa_auto20002repeat is absent from.duplicates..skippednamesshowcase_field_zoo.qa_auto2with a reason beside a non-empty duplicates list. Nothing is summarised as "no duplicates".os test --url http://localhost:41362 --token …fromexamples/app-showcaseprintedFound 1 test suites.,✅ … [health-liveness] (22ms),✅ … [category-create-read-roundtrip] (120ms)andSUCCESS: All 2 scenarios passed., and exited 0 (wall 2.7 s). The second run was green the same way. The showcase_category ids are the same 4 before and after both runs, so nothing is left over.minOuYZyCzp565Iq(run 1) andC5FmYTw-PLf4Z0c2(run 2) are on the same id. A staged no-teardown copy of the roundtrip passed, and the recordQA R4 capture probeid3UIK4OtttvrYHHc1was found by an independent list. GET by that id returned 200, and the audit create shows the same id. The teardown probe's{{cid}}-built GET returnedgot YrIJJjaQiv3wPqtu, which equals the audit create id, so the URL was interpolated and not literal.❌ … [health-degraded]withAssertion failed: data.status expected degraded, got okunderStep Failed: GET health expecting degraded. The three-suite run exited 1.❌ … [contains-nope]:data.nope cannot be evaluated by 'contains' — expected an array or a string at that path, got undefined. … Use 'is_null' if asserting absence is what you meant.qa/a-malformed.test.json is not a valid Quality Protocol suite (TestSuiteSchema):,✗ scenarios.0.steps: Invalid input: expected array, received undefined, the expected shape, andReference: content/docs/references/qa/testing.mdx. NoScenario:line follows it. Both sibling suites printed📄 Running suite:and theirScenario:lines. SummaryFAILED: 3 scenarios failed. 0 passed.with exit 1, and no TypeError.{{cid}}. The scenario stayed❌. The category list was identical before and after (4 stock rows), and the audit shows create and then delete ofYrIJJjaQiv3wPqtu.create_record✅,update_record✅ (API read-back nameQA R4 sweep upd CHANGED),delete_record✅ (GET afterwards gave 404),read_record✅,query_records✅ (direct POST …/query with the same where returned n=1 with the same id, so the predicate was honoured),api_call✅,wait✅ (200 ms), andrun_script❌Unsupported action type in HttpAdapter: run_script. Run total:FAILED: 1 scenarios failed. 7 passed.No member answered 404.os testfrom the app dir found the shipped suite. Quotedqa/**/*.test.jsongaveFound 1 test suites., SUCCESS and exit 0 with 2.9 s wall. Order probe (created zz, mm, sub/bb, aa) ranorder-aa,order-mm,order-bb(sub/),order-zz, which is sorted.os test 'qa/nothing-matches-*.test.json'printedFound 0 test suites.andNo test files found matching: qa/nothing-matches-*.test.jsonand exited 0 ("Exiting 0 — an empty match is not a failure. Pass --fail-on-empty…"). With--fail-on-emptyit exited 1. The green-path verdict quotesFound 1 test suites.with N > 0.containsoverdata.nopecame back ❌, not ✅ (clause 3).--token:health-liveness✅, while the roundtrip ❌HTTP Error 401: {"error":"UNAUTHENTICATED",…}with exit 1.--from 16and--from 17. Planted as raw text: uiDashboard.refreshInterval: 300(ops dashboard), uiListView.sort: 'estimate_hours desc'(task view) and dataObject.externalSharingModel: 'private'(category).--from 17exited 0 withApplied 6 mechanical change(s):, includingdashboards[1].refreshIntervalSeconds: refreshInterval → refreshIntervalSeconds (dashboard-refresh-interval-to-refresh-interval-seconds),views[0].listViews.tabular.sort: estimate_hours desc → [{"field":"estimate_hours","order":"desc"}] (list-view-sort-string-clause-to-array),objects[4].externalSharingModel: externalSharingModel → (removed) (object-external-sharing-model-removed), and 3× the stockflow-decision-mode-inclusive-explicit.--outrun. All byte-identical. The only new path was/tmp/w4c3a/R4/meta/snapshot.json(686 KB, outside the tree).dashboards[1].refreshIntervalSeconds:300with no refreshInterval,views[0]…sort:[{field:"estimate_hours",order:"desc"}],objects[4]has no externalSharingModel, and flows 6, 7 and 26 decisionmode:"inclusive". This reconciles with the 6 applied.✓ Migrated stack is schema-validagrees with--jsonschemaValid:true. Warning branch (extra copy with an unknown keyqaBogusKey):⚠ Migrated stack does not yet pass schema validation — 1 refusal left after the chain. Resolve them, then run \os validate`:followed by the refusal, and--jsonschemaValid:false`.--from 17over the written tree (write2) exited 0 with noApplied … mechanical change(s):block and 448 advisories.--from 18printed⚠ No migration step exists for protocol 18 → 18, so this run replayed nothing — that is not a finding that the metadata is canonical.and noNothing to migrate. Two identical planted-tree--from 17runs differ only in the(‹n>ms)stamp (normalized diff empty).--from 15and--from 3exited 1 with✗ Cannot migrate from protocol 15: the chain's support floor is 16 (ADR-0087 D3)…. JSON:{error:"unsupported_from_major",…}with exit 1.MIGRATION_SUPPORT_FLOOR = 16.Applied 6 mechanical change(s):. Semantics are listed separately under448 manual change(s) require your judgment:, each⚠ [protocol 18] …withwhy:andverify:. The externalSharingModel advisory is listed beside its mechanical removal, and none is reported as handled.os migrate meta --from 17 --jsonon the planted tree exited 0 (schemaValid:true, applied:6, todos:448).--write --jsonexited 0.--help:--write Rewrite the authored source files in place for each mechanical change traced to one literal in one project file…. First copy (write1, data key on Category):Wrote 5 of 6, and the externalSharingModel site was refusednot written [shared]: \Category` … is referenced 1 more time(s) than this site(bydefineSeed(Category, …)). That is the contract working, and the entry was re-planted on PrivateNote asplanted2.write2:Wrote 6 of 6 mechanical change(s) into 4 file(s):at flows/index.ts:1726,:283and:1440, private-note.object.ts:28, ops-dashboard:61and task.view:221. It closed✓ Re-ran the chain over the written sources: no mechanical change remains.with exit 0.diff -ragainst write2.orig: exactly those 4 files and 6 hunks, each at the listed line. No semantic advisory was written, and there was no range rewrite (the showcase declares ^18). Re-run without--write: no Applied block, 448 advisories. Second--write:ℹ --write: the chain made no mechanical change here, so no file was written., and the tree md5 was unchanged.--write --jsonon freshwrite3exited 0 withwrite.status:"written",range:null, andwritten[]` of 6 with file and line.--from 17on all three planted keys) is listed.schemaValid:true.--writechanged no authored byte (checksums).--writediff touched only the listed sites. No advisory was written, no planted spelling was dropped (write1's refused one sits in the by-hand list with kind and reason), and the re-run converts nothing.--fromexited 1 loudly.schema-validis printed only whenschemaValid:true. The warning branch fires when a refusal remains. (The semantic advisories always print and are not schema refusals; see the checklist-accuracy findings.)test ! -eheld for fresh.db,-waland-shm, and still held after a pre-applyos migrate plan, which exited 0 and created nothing.os migrate apply --yesexited 0 with✓ Created/extended 114 table(s): 114 table(s) to create, 0 column(s) to add.and the supporting line[organization-ownership] a datastore created from empty: birth marker written (shape generation 1, platform 18.2.0).Marker read before any boot: exactly 1 rowadr-0131-organization-ownership,verified_at 2026-11-02T04:11:10.126Z,applied_at null,blocking 0,advisory 0,details.birth.shapeGeneration 1, which equalsORGANIZATION_OWNERSHIP_SHAPE_GENERATION = 1. After the boot the same row is unchanged (the boot added 2 other sys_migration rows, adr-0093-membership-backfill and pinyin-search-companion, but no second marker).os serve -p 41363(same environment, setsid) printed✓ Server is ready(not DEGRADED; 0 hits for DEGRADED),Mode: production,Driver: SqlDriver(better-sqlite3) → file:/tmp/w4c3a/R4/fresh/fresh.dbandTenancy: single./api/v1/healthreturned 200 after 4 polls. Refusal greps:carries no organization-ownership marker0,refuses to start0,os migrate organization-ownership0.POST /auth/request-password-reset{email: auditor.demo} → 200{"status":true,"message":"If this email exists in our system, check your email for the reset link"}. AdminGET /data/sys_identity_email→ 1 row to"Ada Auditor (demo)" ‹auditor.demo@example.com>, subject "Reset your ObjectStack password", body carrieshttp://localhost:41381/api/v1/auth/reset-password/<24-char token>?callbackURL=%2Freset. GET on that link → 302 to/reset?token=….sys_emailrows 0 before and after.POST /auth/reset-password{token, newPassword} → 200{"status":true}. Sign-in with the new password → 200 and get-session 200. Sign-in with the old password → 401 INVALID_EMAIL_OR_PASSWORD.{"message":"Invalid token","code":"INVALID_TOKEN"}. Afterwards the first new password still signs in (200) and the attempted password does not (401).sys_verificationrowreset-password:TOKENwas found (1 row, expires_at 04:57:30Z);UPDATE … expires_at=02:57:31Zchanged 1 row. The reset then answered 400 INVALID_TOKEN; the current password signs in 200 and the attempted one 401. Garbage leg: 3 garbage tokens (literal, 24×'x', last-char-mutated real token) each → 400 INVALID_TOKEN; the current password signs in 200 and the garbage password 401.rq.text === rqU.text→ true). No sys_identity_email row was written for the unknown address. (A timing observation is in the probes; see SECURITY.)GET /auth/config→ 200 {success:true, data.features.twoFactor:true}.POST /auth/two-factor/enable{} → 400 VALIDATION_ERROR both anonymous and authed (not 404).otpauth://totp/ObjectStack:admin%40objectos.ai?secret=<52 chars>&issuer=ObjectStack&digits=6&period=30(no algorithm param, so the SHA-1 default). The secret base32-decodes cleanly to 32 bytes, and a locally computed TOTP from it later verified 200.xxxxx-xxxxx(mixed-case alphanumeric). Values are redacted.GET /meta/object/sys_two_factorenable_two_factor.resultDialog.fields = [{path:totpURI, format:qrcode}, {path:backupCodes, format:code-list}]. response.totpURI is a string (len 144) and response.backupCodes is a string[] of 10, so both resolve.POST /auth/two-factor/get-totp-uri. Pre-verify on the live bearer: right password → 200 with the SAME secret, wrong → 400 INVALID_PASSWORD, missing → 400 VALIDATION_ERROR, anonymous → 401. Post-verify on the rotated token echoed by verify-totp: right → 200 SAME secret, wrong → 400 INVALID_PASSWORD, missing → 400, anonymous → 401. The pre-verify bearer after verify → 401 (session rotated). Password-gated in every state; no ungated re-reveal.GET /meta/object/sys_userenable_two_factor: target /api/v1/auth/two-factor/enable, resultDialog fields [totpURI qrcode, backupCodes code-list], acknowledge "I have saved my backup codes", no successMessage key. Both paths resolve against the live response as in clause 3.better-auth.session_tokenonly (no two_factor cookie). get-session 200 with user.twoFactorEnabled false. DB sys_user.two_factor_enabled 0. TOTP_NOT_ENABLED is cited from the lockout pin, not driven.POST /two-factor/verify-totp{correct code} with the live bearer → 200 {token,user}. Row verified 1, failed_verification_count 0, sys_user.two_factor_enabled 1. get-session twoFactorEnabled true. RESTGET /data/sys_user/:idtwo_factor_enabled true.{"twoFactorRedirect":true,"twoFactorMethods":["totp"]}, Set-Cookiebetter-auth.two_factor(Max-Age 600), session_token/session_data cleared (Max-Age 0). That challenge cookie gets get-session 401 and data read 401, so no usable session. Cookie-lane verify-totp → 200 with token; data read with it → 200.POST /two-factor/verify-backup-codewith retained code #0 through the cookie → 200 with token; an authed data read with it → 200.POST /two-factor/generate-backup-codes{password} → 200 {status:true, backupCodes: 10 strings}, 0 overlap with the old set. Old unspent #3 and #4 at fresh challenges → 401 INVALID_BACKUP_CODE each. New #0 → 200, with an authed read 200.GET /meta/object/sys_usergenerate_backup_codes: resultDialog.fields [{path:backupCodes, format:code-list}], acknowledge "I have saved the new codes", refreshAfter false, no successMessage key. response.backupCodes of the regenerate is a non-empty string[] (10)./auth/config{success:true, data.features.twoFactor:true}. BEFORE: sign-in twoFactorRedirect true, sys_two_factor rows 1, two_factor_enabled 1.POST /two-factor/disablewrong password → 400 INVALID_PASSWORD; {} → 400 VALIDATION_ERROR; anonymous → 401. Afterwards: rows 1, tfe 1, a fresh sign-in still twoFactorRedirect true, and the caller's bearer still live (200).{"status":true}, with Set-Cookie session_token and set-auth-token (rotated; the old bearer then answers 401). DB sys_two_factor rows for the user 0; sys_user.two_factor_enabled 0. REST sys_user two_factor_enabled false.better-auth.session_tokenonly, token present. get-session 200 twoFactorEnabled false. Data read 200.PUT /api/settings/auth{values:{mfa_required:true}} → 200 (read back true, grace 7);/api/v1/settings/auth→ 404, as the item notes. Starting stamp mfa_required_at null. Disable under mfa_required → 200 (not refused), and the old bearer → 401 (rotated). Re-sign-in had no redirect; get-session authGate null; authed read 200, which is the in-grace branch. Stamp written lazily: 2026-11-02T03:55:29.712Z. grace set to 0 → authed read 403{"error":{"code":"MFA_REQUIRED",…}}, get-session user.authGate {code:MFA_REQUIRED}. While gated:POST /two-factor/enable→ 200 (totpURI+backupCodes), then verify-totp → 200 and authed read 200 again. Stamp after re-enrollment is unchanged (03:55:29.712Z, never cleared, as the source says). Restored mfa_required false and grace 7, both read back._record; see the accuracy note.warnings:[{"rule":"project_health_progression","severity":"warning","field":"health","code":"invalid_transition","message":"Health changed by more than one step — confirm this is intentional."}]. Re-read health=red. Log:2026-11-02T03:59:52.718Z WARN Validation rule 'project_health_progression' (warning): Health changed by more than one step — confirm this is intentional.PUT /meta/object/qa_vr_probeandqa_vr_probe_err→ 200 each. POST qa_vr_probe {title:"abc"} → 201, re-read title "abc", count 0→1. Exactly one log line names qa_unevaluable_warn:WARN Validation rule 'qa_unevaluable_warn' (warning): the rule could not be evaluated (runtime: int() type error: cannot convert to int) — write proceeded: the rule is advisory, so it was not applied to this write, which contains neither "write rejected" nor "fails closed". Control: qa_vr_probe_err → 400 VALIDATION_FAILED, fields[0] rule_violation constraint {rule:qa_unevaluable_err, reason:unevaluable}, count 0→0, and its log lines say "write rejected: a rule that cannot be evaluated fails closed".Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:devx#1 · os-warren · session_01JQwxbWBtYWqaV8NhvUrShB
Filed by the dispatching PM seat session for the W4-C3a runner
session_01JQwxbZsvATYMNMArStUo2M, whose own write was refused by its session permissions (RUNNER rule 2: staged text, posted verbatim through the same door).Per-clause verdicts, part 3 of 3 (approvals, attachments-storage, automation, integration-system, platform-core). Clause numbers are acceptance indices;
neg/negNare the item'snegativelist. Evidence is text oracle output only.{}→ 403 PERMISSION_DENIED "…is paused at a 'approval' node, which only its owning service may resume…";{branchLabel:"approve"}→ same 403{inputs:{new_assignee:"r6-reassigned"}}→ 200, run completed (start, collect, apply), task assignee "r6-reassigned"UPDATE sys_file SET mime_type=NULL,size=NULLon the boot's primary data.db, 1 change; the data door now drops these columns, see Retests/accuracy) → sys_file A reads committed, mime_type null, size null → POST {nometa, poster: A} → 201, A claimed (ref_id afPqZ9bfyfcUt9e0)os devcompile succeeded (dist carries carrier_pigeon), then "✗ Plugin com.objectstack.service-automation failed to start - rollback complete: … providerConfig.transport.kind must be 'stdio' or 'http'", process exited, health 000 / nothing on 41407; broken-upstream boot degraded instead$filter→ 400 INVALID_FILTER (must be JSON)qadocs_org, gatedqadocs_gated, implicitcom.example.qadocs: 401{"error":"This documentation requires sign-in","code":"UNAUTHENTICATED"}; non-holders Mei and admin →qadocs_gated403{"error":"This documentation is limited to holders of a permission set you do not have","code":"PERMISSION_DENIED"}; no 404, no empty-200 treeshowcase_manual/qadocs_pubanon 200, Mei 200, Ada 200, admin 200; orgqadocs_organon 401, Mei/Ada/admin 200; permissionSetqadocs_gatedanon 401, Mei 403, admin 403, Ada (holder) 200. Fixture: permissionSet/org books + docs authored at runtime in scratch package com.example.qadocs (stock has none, knownGaps[0])book.test.ts45/45 passed (layer: pure spec function); the case "permission-set gate FAILS CLOSED when holdings are unknown (ADR-0049)" assertsaudienceAllows({permissionSet:'crm_admin'}, {authenticated:true})→ false. Unknown-shape half: sourcereturn false; // unknown future shape → fail closed(book.zod.ts audienceAllows); unreachable live — PUT book withaudience:{"role":"admin"}→ 422 INVALID_METADATA invalid_union; no pincom.example.qadocs: Ada (holder) [orgdoc, orphan, pubdoc, secret], Mei and admin (non-holders) [orgdoc, orphan, pubdoc] → non-holder ⊂ holder, admin = non-holder (no bypass);qadocs_pubanon [pubdoc] vs authenticated [pubdoc + uncategorized orphan]; 65 per-entryGET /meta/doc/‹name>fetches across all 20 trees as each tree's own persona: 65×200, 0 refusalsqadocs_orphanabsent from anonqadocs_pubtree (entries [qadocs_pubdoc] only); listed underuncategorizedonly for authenticated callers; anonGET /meta/doc/qadocs_orphan→ 401 UNAUTHENTICATED; anon/meta/doclist omits itGET /meta/book/com.example.showcase/treeMei 200 (implicit book, groupall, 8 docs), anon 401;com.example.qadocsauthenticated 200, anon 401; unknownno_such_book_xyzauthed 200{groups:[]}, anon 401showcase_manualtreeshowcase_indexlabel: no header 'Showcase';Accept-Language: zh-CNandzh'Showcase 示例'; PUT book with inlinetranslations→ 422 INVALID_METADATA unrecognized_keys "…removed in @objectstack/spec 17.0.0 … A doc's own title and body still localize throughdoc.translations"; read-back 404 (nothing stored)/meta/book//tree→ 404 ENDPOINT_NOT_FOUND is a routing miss, not a gated book)?package=com.example.showcase&package=com.example.qadocs→ 400 VALIDATION_ERROR "The "package" query parameter was supplied 2 times…"; single → 200version18.2.0; refusalprotocolVersion18.0.0).engines.protocol ^17→ 422 OS_PROTOCOL_INCOMPATIBLE; then GET /packages/com.example.qa-manifest-probe-old 404 and absent from GET /packages?limit=500 (30 rows; positive control probe-a present). Same for AHEAD ^19 (GET 404, absent from list){requiredRange:"^17", rangeSource:"engines.protocol", protocolVersion:"18.0.0", targetMajor:17, migrateCommand:"objectstack migrate meta --from 17"}; AHEAD ^19: details{requiredRange:"^19", rangeSource:"engines.protocol", protocolVersion:"18.0.0", targetMajor:19}, NO migrateCommand member, message "…built for a newer protocol than this runtime implements. Upgrade the runtime to protocol 19, or install a build of '…' for protocol 18"[protocol] package 'com.example.qa-manifest-probe-norange' declares no engines.protocol range; loading under protocol 18.0.0 without a compatibility check (ADR-0087).;workspace:*→ 201 +[protocol] package 'com.example.qa-manifest-probe-wsrange' declares an unrecognized engines.protocol range 'workspace:*'; skipping the protocol handshake (ADR-0087).; both GET 200qa_mfp→ 422 NAMESPACE_CONFLICT "Namespace conflict: namespace "qa_mfp" is already owned by package "com.example.qa-manifest-probe-a", so package "com.example.qa-manifest-probe-b" cannot be installed alongside it. …" (namespace, owner, incoming id all named), GET probe-b 404; (b) plain re-POST A → 409 RESOURCE_CONFLICT,?overwrite=true→ 201 (no namespace conflict); (c) base/system/sys each 201, and a SECOND claimant ofbaseand ofsysalso 201 (exemption discriminated)leave, GET read-back manifest.namespaceleave; com.example.holiday nstimeoffread-backtimeoff; com.example.averyveryverylongpackagesegmentname →averyveryverylongpac(20 chars)workspace:*,"",*,18.x,^17 || ^18all admitted 201leaveidentical in POST echo and GET read-backitems:[]; GET /marketplace/packages 502 MARKETPLACE_PROXY_FAILED "fetch failed" (mounted passthrough, upstream unreachable); GET /cloud-connection/status 200; runtime/config 200. Boot B (OS_CLOUD_URL=off, scratch): plugins lineMarketplaceInstallLocal+com.objectstack.runtime.runtime-configonly; install-local 200[]; /marketplace/packages 404 ENDPOINT_NOT_FOUND; /cloud-connection/status 404; catalog install{"packageId":"com.acme.nothing"}→ 503 MARKETPLACE_UNAVAILABLE (refusal, no dial-out){installLocal:true, marketplace:true}and install-local 200 + browse non-404; boot B features{installLocal:true, marketplace:false}and install-local 200 + browse 404: all four cells agreeos package install /tmp/w4c3a/R7/mkt/crm-artifact.json -r http://localhost:41424 --email … --password …exit 0: "✓ Loaded artifact (80.0 KB) — air-gapped inline install … ✓ Package installed into the running kernel · Package: com.example.crm · Version: 4.0.0"; manifest cached at scratch.objectstack/installed-packages/com.example.crm.json; GET /meta/app → [showcase_app, setup, account, crm_app]; GET /data/crm_account total 3, crm_opportunity total 12installedBy:"e95GJA…", envelopestorageDir; member (own session, sys_member role member): 200, entry listed, noinstalledBykey, envelope has nostorageDirkey (omitted, not null); anon 401 UNAUTHENTICATEDf_QP8codfWotiv4a"QA User Row R7" added (crm_account 3→4); purge → 200{deleted:28, skipped:0, errors:0, withSampleData:false}; after: crm_account 1 (the user row), contact/opportunity/lead/activity 0; ledger filesampleDataPurged:true; listingwithSampleData:false; 2nd purge{deleted:0, skipped:28}; restart on same DB → still 1/0/0/0/0; reseed →{inserted:28, …, withSampleData:true}, counts 4/3/12/5/5 with user row intact, listing withSampleData true, ledgersampleDataPurged:false{}), DELETE, reseed, purge → each 403 FORBIDDEN "… requires themanage_metadatacapability." (Installing a package / Uninstalling a package / Reseeding sample data / Purging sample data); anon on all five → 401 UNAUTHENTICATED; admin's install/purge/reseed/DELETE succeeded; crm_account unchanged (4) after refused calls{manifestId, cleanups:[{runtime.package-datasources, success:true, removed:2},{security.package-permissions, success:true, removed:0}], note:"Cached manifest removed, the package withdrawn from the running kernel, …"}, noregistry.uninstallPackagefailure entry; pre-restart: /data/crm_account and crm_opportunity 404 OBJECT_NOT_FOUND, /meta/app [showcase_app, setup, account], ledger dir empty; post-restart: same app list, crm_account 404, listingitems:[]GET /api/v1/runtime/config→ 200{"cloudUrl":"","singleEnvironment":true,"features":{"installLocal":true,"marketplace":true,"aiStudio":true,"autoPublishAiBuilds":false},"branding":{"productName":"ObjectOS","productShortName":"ObjectOS","pwaDescription":"ObjectOS — runtime console","pwaThemeColor":"#4f46e5"},"telemetry":{}}(cache-control private, no-cache)/api/v1/studio/runtime-config200;cmpempty, both sha25639916ba8…f44f3a(boot A); boot B alias also byte-identical{}(no DSN configured); admin-session read byte-identical to anon on both boots, and admin read of the alias identicalseedmodes), objectseedmodes_item(name/val/note, public_read_write). upsert {A a1, B b1} → inserted 2; runtime PATCH A.note; upsert {A a1, B b2, C c1} →{inserted:1, updated:1}: A id tgFqBIs2… unchanged, updated_at 03:58:35.872 unchanged, note "runtime-edit" kept; B same id IsAOa59F…, b2, updated_at bumped; C new{inserted:0, updated:1}; total 3→3;filter name=D→ total 0 (positive controlname=A→ 1){inserted:1, updated:0}; A still a2 with updated_at 03:58:42.835 unchanged; E present; total 4{inserted:1}; a second A row QIkPx60N… beside tgFqBIs2… (unconstrained object: duplication shape){inserted:1, updated:0}; F survives (f-hand), G inserted, total 7. Source: writeRecordcase 'replace'"Replace mode: just insert (caller should have cleared the table)"; decideWriteActioncase 'replace': default: return { action: 'insert' }; no clear in seed-loader.ts / protocol-publish-batch.tsSeedMode = z.enum(['insert','update','upsert','replace','ignore'])(5) at spec/src/data/seed.zod.ts;const mode = dataset.mode || config.defaultModein metadata-protocol/src/seed-loader.ts;defaultMode: SeedMode.default('upsert')in seed-loader.zod.ts; packages/runtime/src/seed-loader.ts =export { SeedLoaderService } from '@objectstack/metadata-protocol'{inserted:0, updated:1}(re-converged the duplicate A from a-ins to a1); replay 2 →{inserted:0, updated:0}, full row listing incl. updated_at byte-identical (sha256 ea3d6e53… both)Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:devx#1 · os-warren · session_01JQwxbWBtYWqaV8NhvUrShB
Filed by the dispatching PM seat session for the W4-C3a runner
session_01JQwxbZsvATYMNMArStUo2M, whose own write was refused by its session permissions (RUNNER rule 2: staged text, posted verbatim through the same door).Close-out for this run record (SKILL §5).
One item failed,
ai.mcp-run-action-exposure-gate, on two clauses: acceptance[4] is a stale spec, carried by the anchor's §1 re-point rows; negative[1] is a product defect, extracted. Six product defects observed beside the clauses are extracted; each card passed the pm-dispatch filing gate (class ①). A seventh observation (os buildsize counted in UTF-16 units) did not pass the gate and stays in the record's probe notes. The two partial-coverage gaps are parked on the wave anchor.Retests (§5 trigger 2): #27393, #27395, #27397, #27399 and #24782 all hold; #26478 and #26480 re-confirmed. The evidence is in the record's Retest section.
The off-clause security observation was reported privately to the dispatching PM session; it has no card and no detail here.
Generated by Claude Code