Skip to content

spec: FLOW_FAILED carries the refused write's inner refusal — an optional userMessage on AutomationResult and one declared details member { code, message } on the trigger, resume, /actions and endpoint doors (ruling B′ on #24914) #24996

Closed

Description

@objectstack-fleet

Filing gate ③ — the maintainer's 「同意」 on ruling B′ of #24914 (batch #379 item 5, the director's chat, 2026-10-20): the inner refusal of a refused flow write node reaches the client structurally, as a record save's does; the inner code takes the wire spelling (UNIQUE_VIOLATION for a unique refusal — the 2026-09-03 ruling, packages/runtime/src/http-dispatcher.ts:1204-1207). Filed by the director seat (summon #45 continuation 2, session_01Lg6GQ4xjqmvEzYv78d6H7i). ⛔ Not a claim.

Reader who acts: the domain:spec seat, first in the chain. One PR: Clause-②: yes (widening), minor, contract review at CONTRACT_REVIEW_TIER. It relaxes the #9585 two-key ceiling on /actions error.details by the maintainer's ruling (batch #379 item 5), which the PR cites. Then #24914 follows (services: the four catch arms of crud-nodes.ts, engine carriage on both terminal exits and the retry exits, serial after PR #24778; cli: the four doors, the MCP bridges and the deps.error slot, declared on #22648), and the console half is an objectui card; both are pm:blocked on this card.

Dedupe: the 19 open domain:spec cards' titles read in this act: 0 name FLOW_FAILED, userMessage or AutomationResult; #24914's own dedupe (25 hits across both repositories, none an engine refusal inside a flow node reaching the user raw) stands.

What the ruling binds (origin/main e4d604efd39f)

What done looks like

  • Schema and api-surface regenerated; a spec test shows that a FLOW_FAILED envelope carrying details.<member> = { code: 'UNIQUE_VIOLATION', message } and a top-level userMessage validates on all four doors, and that an envelope without them still validates (optional, additive).
  • Changeset @objectstack/spec minor, Clause-②: yes (widening), citing the ruling.

Related

#24914 (the ruled card: measurement 6296914512, decision 6297041774) · #9378 5321043983 · #9446 5322867819 · #9585 5339708379 · #22507 6093472708 · objectstack-ai/objectui#5210 5344182262 (userMessage rendering ruling) · #24951 (engine sub-card) · PR #24778 (same file, serial).

Activity

  1. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 25
    Session: session_01D6F9axfoPzR7t8G1J7Ytzz
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-24996-flow-failed-inner-refusal
    Worktree: objectstack-issue-24996
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface (at origin/main 73432299c0 or later; stop on a breach and explain it in the report):

    Read on origin/main 73432299c0 at 2026-10-21T01:31Z: AutomationResult carries successMessage / errorMessage and no userMessage, and AutomationResult.code is a closed union (#9378).


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 24996,
      "status": "done",
      "branch": "claude/issue-24996-flow-failed-inner-refusal",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25037",
      "session": "session_01D6F9axfoPzR7t8G1J7Ytzz",
      "premise_still_valid": true,
      "summary": "Contract half of ruling B-prime on #24914, spec only, with one runtime docblock. AutomationResult (contracts/automation-service.ts) gains optional userMessage (ApiErrorSchema.userMessage semantics, never replaces error) and optional innerRefusal: { code, message }; TriggerFlowResponseSchema.data mirrors both, and the #13078 parity pin holds. New in @objectstack/spec/api: FlowInnerRefusalSchema, whose code is the closed ErrorCode so the wire spelling is enforced, and FlowFailureDetailsSchema, declared once as the 400 FLOW_FAILED details of the trigger, resume, /actions and endpoint doors: errorMessage?, summary?, innerRefusal?. It is non-strict like ResumeFailureDetailsSchema, whose members sit beside it on resume. Member name: innerRefusal. It is the ruling's own words, fits the existing refusal vocabulary (FlowActionRefusal, classifyFlowRefusal, FlowRefusalCode), and stays distinct from refusalMessage, which belongs to the end-node outcome. Premise correction: the issue places AutomationResult in automation/flow.zod.ts :1085. Those lines are FlowSchema's authored successMessage/errorMessage; AutomationResult is the TS interface in contracts/automation-service.ts. flow.zod.ts is untouched, and contracts/automation-service.ts plus the runtime docblock are declared additions to the claim's file surface. The #9585 ceiling lives in runtime, not in contract.zod.ts. Its docblock (action-execution.ts FlowActionRunDetails) now cites ruling B-prime. The exact-equality negative pin (actions-flow-dispatch-status.test.ts) is deliberately left alone: nothing emits innerRefusal yet, so #24914 relaxes it with the emission. message, error.code FLOW_FAILED and AutomationResult.code are unchanged, with no new ledger code. The PR body notes the CONTRACT_REVIEW_TIER review owed, with two reviewer choices named: the closed ErrorCode on the inner code, and declaring the two existing artefacts beside the new key.",
      "tests": "All at 22786c992e. Spec: pnpm --filter @objectstack/spec test: 703 files / 21382 passed, 1 todo. test:repo: 72 files / 1236 passed. typecheck exit 0 (includes check:test-typecheck, which compiles the new type pin FlowFailureInnerRefusalIsTheContracts). New suite in automation-api.zod.test.ts: for each of the four doors, an envelope with details.innerRefusal {code:'UNIQUE_VIOLATION', message} and a top-level userMessage validates via BaseResponseSchema and FlowFailureDetailsSchema, plus ResumeFailureDetailsSchema on resume. The same envelopes without either member validate. The key set is exactly the three ruled keys. An unregistered code (ER_DUP_ENTRY) is refused at ['code']. Both inner members are required. Trigger data accepts the mirror members. 66/66 in the file. check:generated --fix proved 5 artifacts stale (api-surface, export-origins, declaration-map, docs, strictness-ledger) and regenerated and re-checked them. Runtime: actions-flow-dispatch-status.test.ts (the ceiling pin) 19 passed, after building the runtime^... closure; the first attempt failed to resolve @objectstack/observability and was not measured. Runtime tsc --noEmit exit 0. Runtime check:test-typecheck exit 1 on an untouched file (organization-ownership-boot-guard.turso-remote.kernel.test.ts); the runtime diff is a docblock only, so that verdict is not attributable to this PR and CI decides. dispatch-gates --commands (stderr line 1: objectstack-ai/objectstack at 22786c992e, --repo checked) gave 113 commands, plus 6 roster families under touched dirs (changeset-fixed, meta-url-spelling, authz-resolver, error-code-casing, filter-alias-parity, route-ledger-census): 118 of 119 exit 0. Six were PREREQUISITE NOT MET on the first pass and green on re-run after the closure build: doc-formula-expressions, doc-security-posture, skill-examples, docs-transcript-drift, lean-entry-closure, type-check-debt. NOT MEASURED: check:dual-build-cjs-loads, reason: needs a full workspace build (93 packages without dist), declared to CI Build Core. NOT MEASURED: pnpm lint, which is CI-owned. --ran reconciliation not run. No ablation was run (the change is additive schema; the negative cases in the suite serve as the red leg).",
      "mcp_calls": "0",
      "api_writes": "2 relay strokes: (1) pr_create via fleet-write dispatch fw-20261021T031651Z-f1b996 = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/25037/assignees [baozhoutao], read back identical; (2) os-dev-report comment = POST /repos/objectstack-ai/objectstack/issues/24996/comments. Plus git push (not REST). label-write: zero writes, because the dispatch named no labels and skip-changeset does not apply (the PR carries a changeset).",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #24914 (services/cli emission lane) · relax the exact-equality negative pin in packages/runtime/src/actions-flow-dispatch-status.test.ts (the /actions details toEqual({ errorMessage, summary })) in the same change that emits innerRefusal; this PR leaves it unchanged on purpose · noted, not filed",
        "carrier: the issue's author seat (the director) · the issue body places AutomationResult at automation/flow.zod.ts:1085; it is contracts/automation-service.ts:387, and its Zod mirror is TriggerFlowResponseSchema.data · noted, not filed",
        "carrier: CI TypeScript Type Check on PR 25037 · runtime check:test-typecheck reported 1 type error in untouched src/organization-ownership-boot-guard.turso-remote.kernel.test.ts on this shared box, cause unverified (a stale dependency dist or main drift); no control leg was run on origin/main · noted, not filed"
      ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Close-out — landed

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

Metadata

Metadata

Assignees

Labels

area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:specpriority:p1High: required for production / M2target:18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions