R3-C round of the #9296 wave. Scope is 5 of the area's 10 runnable items — this is NOT a full-area run. The 5 unreached items are listed as not-run at the bottom. No product defects found.
Environment fingerprint
| reading | value |
|---|
| framework sha (subject, unmoved) | e4e5c6e3c608b1b807c83a0d5b734f213eb1a1dd |
.objectui-sha pin | 665661ab093263f39f2e660a295ea615dbcee35a (console dist stamp matches — check:console-sha ✓) |
| checklist spec | origin/main post-#9309 — 190 items, 30 kinds, 0 waived |
| app / port / db | showcase · 3401 · file:/tmp/qa-r3c/api-backend-filter.db |
| seed | --seed-admin → admin@objectos.ai; com.example.showcase 130 rows |
| clock / TZ | 2026-08-17T14:1xZ · UTC |
Scope — selector and per-item revision
node scripts/checklist-select.mjs area:automation --json → 10 runnable, 1 hidden blocked (automation.rollup-summary-filter, excluded by the resolver by design).
| # | item | rev | pri | surface | verdict |
|---|
| 1 | flow-toggle-kill-switch | 1 | P2 | api | pass |
| 2 | durable-suspend-restart | 1 | P1 | api | partial |
| 3 | flow-node-type-matrix | 3 | P1 | mixed | partial |
| 4 | trigger-type-matrix | 1 | P1 | mixed | partial |
| 5 | screen-flow-roundtrip | 2 | P1 | browser | blocked(dependency) |
Per-clause verdicts
1. flow-toggle-kill-switch (rev 1, P2) — pass · 4/4
Driven live against the running hono server (the item's dispatcher-vs-hono-route trap: oracle is a live server trace, never a simulated dispatch). Run counts are deltas computed per step, never absolute.
| clause | verdict | oracle evidence (text) |
|---|
| 0 baseline: an urgent task fires the flow exactly once | pass | POST /api/v1/data/showcase_task {priority:'urgent'} → 201; GET /api/v1/automation/showcase_urgent_task_alert/runs 2 → 3, delta = 1 |
| 1 toggle OFF is a real kill switch | pass | after POST /api/v1/automation/showcase_urgent_task_alert/toggle {enabled:false} → 200, a second urgent task produced runs 3 → 3, delta = 0 |
| 2 runtime state mirrors the toggle | pass | GET /api/v1/automation/_status while off: {enabled:false, bound:false, status:"active", triggerType:"record_change", object:"showcase_task"}; while on: {enabled:true, bound:true, …}. The record_change trigger is genuinely unbound, not merely flagged |
| 3 toggle ON restores firing | pass | after {enabled:true} → 200, a third urgent task produced runs 3 → 4, delta = 1 |
Negative probe (unknown flow): POST /api/v1/automation/does_not_exist/toggle {enabled:false} → 404{"success":false,"error":{"code":"RESOURCE_NOT_FOUND","message":"Flow 'does_not_exist' not found","httpStatus":404}}, no state change.
Automation self-check (RUNNER rule 2) — caught one instrumentation bug before it became a false fail. My first pass parsed the runs list with a generic record extractor and read 0 at every step, including the baseline, which would have been recorded as "the flow never fires". The runs envelope is {success, data:{runs:[], hasMore}} — data is an object, not a row array. Re-driven with the correct path; all four clauses then behaved. Nothing was recorded from the broken pass.
2. durable-suspend-restart (rev 1, P1) — partial · 3 pass, 2 not covered
automated.ref = packages/qa/dogfood/test/flow-durable-suspend.dogfood.test.ts. Per RUNNER rule 6 the pin is the evidence: 11/11 tests passed.
| clause | verdict | oracle evidence (text) |
|---|
| 0 each suspend persists a paused row carrying rehydration state | pass | pin: "precondition: sys_automation_run really exists — the table #4420 was missing" · "suspends at the screen node and PERSISTS the pause as a paused row" · "the durable row is what a rehydration would read — the whole SuspendedRun round-trips" |
| 1 paused rows + ordinary records survive a literal cold boot | pass | pin: "ordinary business rows survive the restart — stop() returning means DURABLE" · "the paused row survives the restart with its continuation intact" · "the resumed result is itself durable — a THIRD boot still reads it" |
| 2 the timer wait resumes without intervention after restart | not covered | the pin exercises a screen-node resume across a cold boot ("the cold kernel RE-FETCHES the screen … RESUMES the run and takes the right branch"), not the timer/PT1M wait path this clause names. Not re-driven by hand this round |
| 3 nested pause: child at approval, parent at subflow, one decision completes both | not covered | no assertion in the pin addresses the linked parent/child run correlation or the approval bubbling |
| 4 resume consumes the paused row, leaving run history | pass | pin: "the suspension is CONSUMED from the durable store on resume — no zombie row is left behind" |
3. flow-node-type-matrix (rev 3, P1) — partial · pin covers a slice of the matrix
automated.ref = packages/qa/dogfood/test/flow-node.dogfood.test.ts → 2/2 passed: "precondition: the automation service is wired and the flow is registered"; "runs the update_record node and wires the input variable into the filter".
The item is a node-type matrix with 6 clauses; the pin proves one node type (update_record) plus variable wiring end-to-end. The remaining node types in the matrix were not driven this round, so the item cannot be scored pass — recorded partial rather than promoting a one-node pin to matrix-wide coverage.
4. trigger-type-matrix (rev 1, P1) — partial · conformance ledger proven, per-trigger firing not driven
automated.ref = packages/qa/dogfood/test/flow-trigger-conformance.test.ts → 2/2 passed: "ADR-0060 D5 — flow trigger-type conformance ledger is a sound conformance ledger + ratchet, every flow type has a runtime + proof"; "sanity: discovery finds the known flow types".
That is strong evidence for the ledger/ratchet clauses — every declared flow type has a runtime and a proof, enforced by the ratchet. It is not evidence that each trigger type fires live on this build; the item's clauses that name live firing per trigger type were not driven. Recorded partial.
Corroborating live reading from the boot log (not a clause verdict): Flows: 29 flow(s) 22 bound to triggers (record_change, schedule, time_relative, api) · 7 draft.
5. screen-flow-roundtrip (rev 2, P1) — blocked(dependency)
automated.ref = objectui e2e/live/screen-flow.spec.ts — the pin lives in objectstack-ai/objectui, which is not checked out in this session, so the declared oracle cannot be consulted from here. The console dist is built and stamped at the pin, so this is not an environment failure; it is a cross-repo dependency. Recorded blocked(dependency, objectui e2e suite not available in this checkout) rather than substituting a hand-driven browser pass for the pin the item names.
Not run — 5 of 10 items
| item | rev | pri | surface |
|---|
flow-run-step-nesting | 2 | P1 | mixed |
time-relative-trigger | 2 | P2 | mixed |
flow-error-handling | 2 | P1 | mixed |
connector-dispatch-matrix | 1 | P2 | mixed |
flow-runs-page-test-trigger | 1 | P2 | mixed |
Also excluded by the resolver, by design: automation.rollup-summary-filter (blocked, fixture).
Findings
No product defects. No fail verdicts, so no defect reproduction rule is owed.
Environment note carried from #9333 (same round, same tree): the dispatched setup recipe omits @objectstack/cli, so objectstack dev is unavailable until a full pnpm exec turbo run build runs. Also relevant to this area's fixtures — stock showcase seeds carry only admin@objectos.ai, auditor.demo@example.com, phone.demo@example.com, with no credentialed non-admin persona for gate-both-sides clauses.
Boot diagnostics observed (recorded, not scored — none is a clause oracle here): the showcase boot logs 3 warnings, two of which touch this area's neighbourhood — SharingServicePlugin: boot rule backfill failed for share_open_tasks_with_manager and share_red_projects_with_execs, both SHARING_NOT_ENABLED because the target object is under a public sharing model or lacks owner_id. Flagged for whoever owns access-security.
Parent: #9296.
R3-C round of the #9296 wave. Scope is 5 of the area's 10 runnable items — this is NOT a full-area run. The 5 unreached items are listed as
not-runat the bottom. No product defects found.Environment fingerprint
e4e5c6e3c608b1b807c83a0d5b734f213eb1a1dd.objectui-shapin665661ab093263f39f2e660a295ea615dbcee35a(console dist stamp matches —check:console-sha✓)origin/mainpost-#9309 — 190 items, 30 kinds, 0 waivedfile:/tmp/qa-r3c/api-backend-filter.db--seed-admin→admin@objectos.ai;com.example.showcase130 rowsScope — selector and per-item revision
node scripts/checklist-select.mjs area:automation --json→ 10 runnable, 1 hidden blocked (automation.rollup-summary-filter, excluded by the resolver by design).flow-toggle-kill-switchdurable-suspend-restartflow-node-type-matrixtrigger-type-matrixscreen-flow-roundtripPer-clause verdicts
1.
flow-toggle-kill-switch(rev 1, P2) — pass · 4/4Driven live against the running hono server (the item's
dispatcher-vs-hono-routetrap: oracle is a live server trace, never a simulated dispatch). Run counts are deltas computed per step, never absolute.POST /api/v1/data/showcase_task {priority:'urgent'}→ 201;GET /api/v1/automation/showcase_urgent_task_alert/runs2 → 3, delta = 1POST /api/v1/automation/showcase_urgent_task_alert/toggle {enabled:false}→ 200, a second urgent task produced runs 3 → 3, delta = 0GET /api/v1/automation/_statuswhile off:{enabled:false, bound:false, status:"active", triggerType:"record_change", object:"showcase_task"}; while on:{enabled:true, bound:true, …}. The record_change trigger is genuinely unbound, not merely flagged{enabled:true}→ 200, a third urgent task produced runs 3 → 4, delta = 1Negative probe (unknown flow):
POST /api/v1/automation/does_not_exist/toggle {enabled:false}→ 404{"success":false,"error":{"code":"RESOURCE_NOT_FOUND","message":"Flow 'does_not_exist' not found","httpStatus":404}}, no state change.Automation self-check (RUNNER rule 2) — caught one instrumentation bug before it became a false fail. My first pass parsed the runs list with a generic record extractor and read
0at every step, including the baseline, which would have been recorded as "the flow never fires". The runs envelope is{success, data:{runs:[], hasMore}}—datais an object, not a row array. Re-driven with the correct path; all four clauses then behaved. Nothing was recorded from the broken pass.2.
durable-suspend-restart(rev 1, P1) — partial · 3 pass, 2 not coveredautomated.ref=packages/qa/dogfood/test/flow-durable-suspend.dogfood.test.ts. Per RUNNER rule 6 the pin is the evidence: 11/11 tests passed.sys_automation_runreally exists — the table #4420 was missing" · "suspends at the screen node and PERSISTS the pause as apausedrow" · "the durable row is what a rehydration would read — the whole SuspendedRun round-trips"stop()returning means DURABLE" · "thepausedrow survives the restart with its continuation intact" · "the resumed result is itself durable — a THIRD boot still reads it"3.
flow-node-type-matrix(rev 3, P1) — partial · pin covers a slice of the matrixautomated.ref=packages/qa/dogfood/test/flow-node.dogfood.test.ts→ 2/2 passed: "precondition: the automation service is wired and the flow is registered"; "runs theupdate_recordnode and wires the input variable into the filter".The item is a node-type matrix with 6 clauses; the pin proves one node type (
update_record) plus variable wiring end-to-end. The remaining node types in the matrix were not driven this round, so the item cannot be scoredpass— recordedpartialrather than promoting a one-node pin to matrix-wide coverage.4.
trigger-type-matrix(rev 1, P1) — partial · conformance ledger proven, per-trigger firing not drivenautomated.ref=packages/qa/dogfood/test/flow-trigger-conformance.test.ts→ 2/2 passed: "ADR-0060 D5 — flow trigger-type conformance ledger is a sound conformance ledger + ratchet, every flow type has a runtime + proof"; "sanity: discovery finds the known flow types".That is strong evidence for the ledger/ratchet clauses — every declared flow type has a runtime and a proof, enforced by the ratchet. It is not evidence that each trigger type fires live on this build; the item's clauses that name live firing per trigger type were not driven. Recorded
partial.Corroborating live reading from the boot log (not a clause verdict):
Flows: 29 flow(s) 22 bound to triggers (record_change, schedule, time_relative, api) · 7 draft.5.
screen-flow-roundtrip(rev 2, P1) — blocked(dependency)automated.ref=objectui e2e/live/screen-flow.spec.ts— the pin lives inobjectstack-ai/objectui, which is not checked out in this session, so the declared oracle cannot be consulted from here. The console dist is built and stamped at the pin, so this is not an environment failure; it is a cross-repo dependency. Recordedblocked(dependency, objectui e2e suite not available in this checkout)rather than substituting a hand-driven browser pass for the pin the item names.Not run — 5 of 10 items
flow-run-step-nestingtime-relative-triggerflow-error-handlingconnector-dispatch-matrixflow-runs-page-test-triggerAlso excluded by the resolver, by design:
automation.rollup-summary-filter(blocked, fixture).Findings
No product defects. No
failverdicts, so no defect reproduction rule is owed.Environment note carried from #9333 (same round, same tree): the dispatched setup recipe omits
@objectstack/cli, soobjectstack devis unavailable until a fullpnpm exec turbo run buildruns. Also relevant to this area's fixtures — stock showcase seeds carry onlyadmin@objectos.ai,auditor.demo@example.com,phone.demo@example.com, with no credentialed non-admin persona for gate-both-sides clauses.Boot diagnostics observed (recorded, not scored — none is a clause oracle here): the showcase boot logs 3 warnings, two of which touch this area's neighbourhood —
SharingServicePlugin: boot rule backfill failedforshare_open_tasks_with_managerandshare_red_projects_with_execs, bothSHARING_NOT_ENABLEDbecause the target object is under a public sharing model or lacksowner_id. Flagged for whoever ownsaccess-security.Parent: #9296.