Skip to content

service-automation: a failed tenant-settings read fails the notify run as a permanent guard refusal; the resolver contract and run setup cannot carry readFailed #28056

Closed

Description

@objectstack-fleet

domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia

Split from #27710 by the domain:server seat: the #27733 + #27710 card thread measured that this row cannot be expressed in service-automation/src/plugin.ts alone. #27710's plugin-auth leg lands in that thread's PR; this card carries the automation row. ⛔ Not a claim.

What is wrong (measured on main @ bc496bf7)

service-automation's tenant-currency resolver (plugin.ts ~L1476) returns resolveLocalizationContext(...).currency and ignores readFailed (#27257). Reading it there is not enough, because nothing downstream can act on it:

  1. Resolver contract. FlowTenantCurrencyResolver (documented in packages/services/service-automation/src/engine.ts ~L826-838) gives a throw no meaning of its own: a rejection is tolerated the same as undefined.
  2. Run setup. run-resume.ts swallows the resolver's rejection and its undefined identically (run setup ~L169-176 and withTenantCurrency ~L281-293, "Tolerated"). Nothing carries "the read failed" to the renderer, and AutomationContext (packages/spec/src/contracts/automation-service.ts) has no member for it.
  3. Refusal grade. The resulting currency-hole refusal is a FlowTextTemplateError, which builtin/template.ts brands with markGuardRefusal: permanent, not fault-routable, not retried.

So a transient sys_setting read failure fails the notify run permanently, where a retry would succeed.

Expected

As #27710 states for this caller: a failed read is treated as transient (retry, or fall back as the automation contract says), never as "the tenant has no default". A read that succeeds and finds no default keeps today's behaviour. Pins: read fault → the transient path; a real "no default" → unchanged.

For triage

Blocked-by: #27951

Activity

  1. added
    bugSomething isn't working
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    domain:serverDomain lane — seat card indexed by label:pm:seat
    and removed on Oct 30, 2026
  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 客户的语言 | none | P⑤

    Triage: p2 · domain:server · area:automation · 2026-10-30T11:59Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 30, 2026
  4. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    Claim: PM loop · 2026-10-30T12:04Z · triage first touch 6522182106
    Session: session_016WV4czcfiRnuFCuLdmegYt (card thread; seat session_016WV4d1Np3hU7RQnA13YZcL)
    Account: os-elon-musk
    Branch: claude/project-thread-kqrv4t
    Worktree: objectstack-issue-28056
    Domain: domain:server
    Seat: domain:server#4
    File surface: packages/services/service-automation/src/engine.ts (FlowTenantCurrencyResolver and the notify run's grading of a currency-hole refusal), packages/services/service-automation/src/plugin.ts, — amended before push: packages/services/service-automation/src/run-resume.ts (the two catches in resolveRunContext / withTenantCurrency that swallow the resolver's rejection; an in-package out-of-band carrier, ⛔ not AutomationContext), packages/services/service-automation/src/dag-traversal.ts (the isGuardRefusal branch of executeNode), packages/services/service-automation/src/builtin/template.ts (the placeholder-currency probe helper, as service-messaging does for #27257), their tests, .changeset/*; ⛔ no packages/spec (contracts/automation-service.ts only if an existing code fits — otherwise stop and ask), no governed path
    Container & model: M, mode:thread, model: default (TIER_DEFAULT), effort: high; no contract review expected (a permanent refusal becomes retryable after a failed read) unless the diff shows a narrowing or a new code
    Clause-②: no (a failed tenant-settings read is graded retryable instead of a permanent guard refusal; no accepted call is refused — the dev confirms the arm)
    Metadata-protocol: none
    Responsibility: a failed tenant-settings read fails the notify run as a permanent currency-hole refusal; the platform path that covers it is FlowTenantCurrencyResolver giving a read failure the retryable meaning, never undefined, as the #27257 / #27710 family does; reached by every notify run whose tenant-settings read fails.
    Thread-read: 6522182106
    Premise: holds (card at origin/main f6adf480)
    Serial constraints cleared: no open PR on service-automation/src/engine.ts right now; seat 4's #27966 and seat 3's #28016 also edit that file (other hunks) — the thread merges main before opening its PR.

  5. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4czcfiRnuFCuLdmegYt
    os-dev-report

    {
      "issue": 28056,
      "status": "done",
      "branch": "claude/project-thread-kqrv4t",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28110",
      "session": "session_016WV4czcfiRnuFCuLdmegYt",
      "premise_still_valid": true,
      "summary": "The automation plugin's tenant-currency resolver now rejects when resolveLocalizationContext answers readFailed (#27257). Run setup and a resumed segment note that rejection beside the run's context (a package-local WeakMap; AutomationContext and packages/spec untouched), and executeNode's throw arm grades a FlowTextTemplateError for such a context: when a re-render with the placeholder currency XXX succeeds, the node fails with a plain runtime Error (fault-routable, retry succeeds once the read does) naming the failed read; otherwise the guard refusal stands. A read that succeeded is unchanged. File surface per the seat's amendment (engine.ts, plugin.ts, run-resume.ts, dag-traversal.ts, builtin/template.ts, tests, changeset). No new code, no spec edit.",
      "tests": "Measured on main 5448585d (scratch test, deleted): notify + fault edge, resolver throws -> run failed, edge not taken, error blames a missing setting; under errorHandling retry maxRetries 2 the run re-ran (3 reads), every attempt refused. Pins src/builtin/notify-currency-read-fault.test.ts: 3 red on main (fault routing, resume, plugin over a throwing sys_setting read), 10/10 green on head. Ablations via scripts/ablation-replace.mjs, each restored blob == HEAD: A1 no grading in the throw arm -> 3 red; A2 plugin ignores readFailed -> 1 red; A3 resume does not note -> 1 red; A4 no probe -> 1 red; A5 run setup does not note -> 2 red. @objectstack/service-automation full vitest 228 files / 2886 tests pass; typecheck (incl. check:test-typecheck) exit 0.",
      "gates": "dispatch-gates --commands at head e62036b8 derived 62 families: 62 exit 0 (check:dual-build-cjs-loads exit 3 on the first pass, exit 0 after turbo build --filter='@objectstack/dogfood^...' --filter='@objectstack/runtime^...'); --ran reconcile: 62 derived, 62 run, 0 NOT-MEASURED, 0 UNRUN; pnpm lint exit 0. CI families: read from PR #28110 check-runs at ACCEPT.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "2 — mcp__github__issue_read (get, get_comments) on #28056; no MCP write",
      "api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls -> #28110), this comment (POST /repos/objectstack-ai/objectstack/issues/28056/comments); git push is not a REST write",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — errorHandling.strategy 'retry' re-runs a run whose node met a guard refusal (retryExecution reads only success; only FLOW_INPUT_SCHEMA_INVALID short-circuits), measured as 3 reads on main for a refused notify; unchanged here",
        "carrier: none · noted, not filed — a refusing end node's message renders outside executeNode's try (renderRefusalMessage), so a currency hole there after a failed read is not graded by this change; same seam family as #28056"
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    ACCEPT → PR #28110 comment 6523812795 · head e62036b8 · 2026-10-30T13:20Z · landing sent (no contract review owed). Closes this card.

  7. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    Landed · 2026-10-30T13:43Z

    reading value
    PR #28110 MERGED 2026-10-30T13:42Z, merge commit 86c6955d (merge queue)
    this card closed completed by Fixes #28056

    State: pm:dispatched removed in this stroke.

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

Metadata

Metadata

Assignees

Labels

area:automationbugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions