fix(workflow-executor): tell the orchestrator why an automated inbox could not read its segment - #1938
Conversation
…could not read its segment Every sweep now sends its sync, with readFailure when a segment read failed: agent-forbidden (401/403), agent-unreachable (no answer, 502-504) or segment-read-failed. The settings panel shows it instead of "running". fixes PRD-1396 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…agent A failure of the executor's own (unsignable JWT, malformed agent URL) is a segment read failure, and a status the orchestrator would refuse is not sent. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4 new issues
|
|
Coverage Impact This PR will not change total coverage. Modified Files with Diff Coverage (2)
🛟 Help
|
…ate-chunk membership failure Cover the six network codes the classification table never exercised (ECONNRESET, EAI_AGAIN, EHOSTUNREACH, ENETUNREACH, EPIPE, ETIMEDOUT), so dropping one from UNREACHABLE_AGENT_ERROR_CODES now fails a test instead of silently reclassifying a real network failure as segment-read-failed. Add a membership read whose second chunk 503s, locking in that the whole read reports the failure rather than the first chunk's partial result. Also reword the isHttpStatus comment, which conflated the customer agent's status with the orchestrator sync, and drop an unreachable `| null` from the cause cast. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ShohanRahman
left a comment
There was a problem hiding this comment.
Approved after a full multi-perspective review (code, comments, tests, silent-failure, type-design, simplify).
Verified: 110/110 tests pass · lint clean (0 errors) · error classification, instanceof boundary checks, cause extraction, and isHttpStatus boundary all hold up.
No Critical or Important issues found. The always-sync-with-classified-readFailure change is well-tested with exact-value assertions, and the mutation check in the PR body is sound.
Advisory items addressed in 5b24f3d:
- Reworded the misleading
isHttpStatuscomment (it conflated the customer agent's status with the orchestrator sync). - Dropped an unreachable
| nullfrom thecausecast. - Pinned all six previously-untested network codes (ECONNRESET, EAI_AGAIN, EHOSTUNREACH, ENETUNREACH, EPIPE, ETIMEDOUT).
- Added a late-chunk membership-failure test locking in the all-or-nothing read behavior.
Reminder (already noted in the PR body): the server side (ForestAdmin/forestadmin-server#8542) must be deployed before #1906 is released, since the orchestrator has to accept the new readFailure field.
07a06c1
into
feature/prd-1183-runtime-automation-poller
…could not read its segment (#1938)

fixes PRD-1396
Targets the integration branch
feature/prd-1183-runtime-automation-poller(#1906). Server side: ForestAdmin/forestadmin-server#8542, which must be deployed before #1906 is released.Problem
When a segment read failed, the poller only logged it, and skipped the sync when both reads failed. The orchestrator never learned it, so the settings panel kept saying "Automation is running." while no run could start.
Change
readFailure: { reason, httpStatus? }. The candidate read's failure wins over the membership read's, since that is the read that starts runs.tryReadis classified:AgentHttpError401 / 403agent-forbidden+ statusAgentHttpError502 / 503 / 504agent-unreachable+ statusAgentHttpErrorwith no usable status (outside 100-599)agent-unreachableAgentHttpErrorsegment-read-failed+ statusECONNABORTED,ECONNREFUSED,ENOTFOUND...)agent-unreachablesegment-read-failedAutomated inbox polledlog line names the failure (readFailure).SegmentRead.outcomewas only read by the "skip the sync" guard and is removed.Nothing else relied on "no sync when the agent is unreachable": the runtime watch works from the lease, and a sync with empty lists reconciles and starts nothing.
Tests
automation-poller.test.ts: the tests that asserted no sync now expect a sync with the failure. New cases: classification table (401, 403, 502, 503, 504, 500, 400, status 0, timeout, refused connection, unknown host, error of its own, record without id, unsplittable id), candidate failure over membership failure, membership failure alone, noreadFailurewhen every read succeeded, log field.agent-client-segment-reader.test.ts: the port error keeps theAgentHttpErrorstatus and the network error code as its cause, which the classification relies on.Mutation check
Each line broken on its own,
automation-poller.test.tsrun:readFailurenot sent13 / 13 killed. Sending
readFailure: undefinedinstead of omitting it was the only survivor of a first pass: identical on the wire (JSON.stringifydrops it), so the conditional spread was removed.Local replay
Executor at this PR, server at ForestAdmin/forestadmin-server#8542 (floor lowered locally, never pushed),
_exampleagent, service account with role Operations, sweeps every ~30 s:{ configured: true, active: true }.browseEnabledremoved onownerfor the role: the next sweep logsreadFailure="agent-forbidden", the status becomes{ configured: true, active: false, reason: 'agent-forbidden', httpStatus: 403 }, and the server logsautomation-inbox-read-failed.{ configured: true, active: true }.{ configured: true, active: false, reason: 'agent-unreachable' }.🤖 Generated with Claude Code
Note
Report structured read-failure reasons from automated inbox segment reads
readFailurefield to sync requests so the orchestrator learns why a segment read failed. Failures are classified asagent-forbidden(HTTP 401/403),agent-unreachable(502/503/504 and network error codes), orsegment-read-failed, with the HTTP status kept when one exists.AutomationPollerno longer skips sync when both reads fail; it always callsautomationPort.syncwith empty items plus the selected failure reason, and a candidate-read failure takes precedence over a membership-read failure.SegmentRead, replacing them with an empty item list plus a structured failure field.readFailureinstead of no sync at all; seetryReadand the inbox polling workflow in automation-poller.ts.Macroscope summarized 5b24f3d.