fix(service-automation): trigger-fired-run failure log keeps the AutomationResult.error envelope in meta, not the message (#6587) - #6623
Merged
os-project-manager merged 1 commit intoAug 8, 2026
Conversation
…lope in meta, not the message (#6587) activateFlowTrigger's trigger callback spliced AutomationResult.error — which carries a failing node's / driver's text verbatim (#5912) — into the logger.error MESSAGE, the one same-class site PR #6568's residual sweep left on the fired-run path. The message now stays one physical line with the controlled facts (flow name, trigger type, consequence) and the envelope rides the structured meta slot, matching the family shape (#6499/#6568, site-12 envelope treatment). Per-site #4632 verdict: stays `error` on its own reasoning — the fired-run path has no caller holding the result envelope, so the failure would otherwise look normal from the outside; pinned by three new tests in engine-residual-log-cause.test.ts (level + stream + one-line + envelope-in-meta + error-slot layout). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01USNUyHEr7uaU6MoEWXitei
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 5 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-project-manager
marked this pull request as ready for review
August 8, 2026 08:45
os-project-manager
deleted the
claude/issue-6587-trigger-run-envelope-splice
branch
August 8, 2026 09:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #6587
The site
activateFlowTrigger's trigger callback logged a failed trigger-fired run asTrigger-fired run of flow '…' failed: ${result.error ?? 'unknown error'}atlogger.error— splicing theAutomationResult.errorenvelope, which carries a failing node's / driver's text verbatim (#5912), into the log MESSAGE. This is the one same-class site PR #6568's residual sweep reported and left (it was outside #6499's list of 13), on the fired-run path — the identical class as that PR's site 12 (bubbleToParent's envelope branch), with the same downstream harm:ObjectLogger.write()emits one timestamp+level head per call, so foreign newlines shred ONE record into several physical lines of which only the first is greppable.The fix (the family shape, not re-derived)
Message and cause separated per the merged family idiom (#6498/#6568): the message stays one physical line and carries only controlled facts — the flow name, the trigger type (
resolved.triggerType), and the consequence — keeping its originalTrigger-fired run of flow '…' failedlead phrase so existing greps still match. The envelope rides the logger's structured meta slot ({ error: result.error ?? 'unknown error' }), passed THIRD in theerror(message, error?, meta?)contract with the Error slot deliberately empty (#5575). This is the same treatment #6568 gave site 12's string envelope — notdescribeThrownForLog, which renders THROWN values; the envelope here is already a string, so it maps straight onto the meta'serrorfield.Per-site #4632 verdict
Stays
error— on its own reasoning, not inertia. The judgment question answers YES here: after the failure the system looks normal from the outside — the triggering event was handled, NO caller holds this result envelope (fire-and-forget path), and nothing retries the run — while the flow's declared effects never landed. The only other trace is the passive run-history row (the 2026-07-17 eval preserved in the site comment: a failing record-change flow produced zero output; the failure lived only in that row). That stderr survives the CLI's boot-quiet stdout window is stream mechanics, not the verdict. The verdict is pinned by test becausecheck:durability-log-leveldoes not reach this package.Tests
Three new pins appended to
engine-residual-log-cause.test.ts(the #6568 file), in its exact idiom — real bytes off a realObjectLogger, both streams captured, the family's byte-identical multi-line driver fixture. The seam is driven the way a real trigger plugin drives it: the test'sFlowTrigger.startcaptures the engine-built callback and fires it once; the flow's work node THROWS the driver text, soexecute()'s catch lands it inresult.errorverbatim, un-prefixed (the #5912-preserved shape).error, exactly one stderr line, message one line leaking no driver fact, the whole envelope inrecord.error(meta spread proves the slot), stdout silent. Behaviour-unchanged assert: the callback resolves (nothing thrown back at the trigger plugin) and the failed run still lands in run history withstatus: 'failed'.fail()也是${err.message}单行插值,同 #5048 的类别、另一个接缝 #5575).Reverse verification (direction predicted before running)
Predicted: re-splicing the site turns exactly the 3 new pins red — the JSON pin inside
expectOneLineWithCause(msg gains the newlines + driver text,record.errorvanishes), the pretty pin'stoHaveLength(1)(one record becomes 3 physical lines, the driver's first line concatenating onto the message line), the slot pin's message-one-line assert — and the 18 pre-existing pins stay green. Observed: exactly that, 3 failed / 18 passed, each failing on the predicted assertion (the pretty pin reportedexpected [ …(3) ] to have a length of 1 but got 3). Restored: 21/21 green.Local runs
pnpm --filter @objectstack/service-automation test: 70 files, 847 tests, all passed.tsc --noEmitin the package: 3 errors, all pre-existing innested-region-parity.test.ts— the same 3 fix(service-automation): engine.ts residual log-splice sweep — 13 foreign-text seams + the self-authored 14th, per-site #4632 verdicts (#6499) #6568 ledgered; my files contribute 0.eslinton both touched files: clean.node scripts/check-nul-bytes.mjs: OK; control-byte self-scan of touched files: clean.Scope
ONE site, per the dispatch. Explicitly untouched: the name-shaped tail (
engine.ts:2719,:3365,:3598,:4209,:4899— a different class; the PM splits it into its own finding at review),evaluateCondition,validateFlowExpressions' fatalfailuresarray, and everything #6568 already fixed. A user-visible log-shape change, so a patch changeset rides along.🤖 Generated with Claude Code
https://claude.ai/code/session_01USNUyHEr7uaU6MoEWXitei
Generated by Claude Code