Repository navigation
flows check refuses a Cloud-bound f.slack flow locally (helper_slack.credential_missing) before printing REQUIRES - #618
Conversation
The fix for `flows check` refusing a Cloud-bound f.slack flow is covered by
synthetic fixtures, but nothing in the suite guards the artifact the defect was
reported against. `examples/stale-issues/stale-issues.flow.ts` declares
`tools: { slack: true }` and calls `f.slack.post`, and on a machine with no
Slack mount it used to exit 2 on `helper_slack.credential_missing` before
printing `REQUIRES`.
Copy the shipped example into a staged directory the way
tests/flow-requirements.test.ts already does, and assert the three things the
report asked for: no REFUSED line, exit 0, and
`REQUIRES slack (tools.slack), claude (llm step)` on stdout with exactly one
`helper_credential_unresolved` footnote.
The copy writes its own `{"type":"module"}` boundary: `examples/` carries no
package.json, so under a checkout whose ancestry declares `"type": "commonjs"`
the authored `.flow.ts` cannot be imported at all, which is a property of the
checkout and not of the flow.
Mutation-verified in evidence/helper-check/mutation-shipped-example.md:
reverting cli.ts's `warnUnresolvedHelperCredential` opt-in fails the test on the
exact refusal from the report, and the restored file is byte-identical
(sha256 83e60fd1…).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Relayflow: the adversarial review did not pass. This branch is not approved: the flow stopped here and did not mark it ready to merge. PR #618 reviewReviewed head Changes requested: two reproducible issues remain. No FindingsF1 — P2: Preserve communication preflight when downgrading a missing helper mountLocation: A YAML flow with two communicating agents and a Slack helper, with no Slack This exceeds the intended helper-only relaxation: an unrelated environment F2 — P2: Do not recommend unsupported YAML mock modesLocation: The shared warning always recommends Keep the warning specific to the execution surface: for YAML ( Reproduction of both findingsThe self-contained script creates temporary fixtures, uses a local shell stub Command, from the repository root: bun evidence/helper-check-review/reproduce.tsCaptured output: PR discussion and checksAll three discussion endpoints were queried with pagination. Each returned an gh api --paginate repos/AgentWorkforce/flows/issues/618/commentsgh api --paginate repos/AgentWorkforce/flows/pulls/618/reviewsgh api --paginate repos/AgentWorkforce/flows/pulls/618/commentsgh pr checks 618The PR description includes historical validation and later full-suite failures. Focused verificationCommand (cwd: RELAYFLOWD_BIN="$PWD/../../kernel/target/debug/relayflowd" ./node_modules/.bin/vitest run tests/check-helper-surface.test.ts tests/check-worker-surface.test.ts tests/flow-requirements.test.ts tests/authored-flow-slack.test.ts tests/preflight.test.tsExit status: 0. Captured output: The first attempt omitted Initial command (cwd: ./node_modules/.bin/vitest run tests/check-helper-surface.test.ts tests/check-worker-surface.test.ts tests/flow-requirements.test.ts tests/authored-flow-slack.test.ts tests/preflight.test.tsExit status: 1. Captured output: Command (cwd: npm run typecheck && npm run typecheck:testsExit status: 0. Captured output: The passing focused tests cover the reported stale-issues example, warning |
…n a helper mount is missing F1: when the only refusal is a missing local helper mount that `flows check` restates as helper_credential_unresolved, still compile the flow for inspection so the communication environment refusal (RELAY_API_KEY) and the budget_unmetered warning no longer depend on whether the helper is mounted. The compiled flow is still returned only when preflight admitted it. F2: YAML execution honours a mock only for Slack; the warning no longer recommends RELAYFLOWS_LINEAR_MOCK / RELAYFLOWS_GITHUB_MOCK for YAML helpers. Authored TS helpers keep their provider-specific mock advice. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
Addressed the adversarial review in c8eb1b0:
Local: check-helper-surface, check-worker-surface, preflight, helpers-fanout, helper-reference, flow-requirements, flow-extension-compose, communication-preflight, communication-environment-preflight, budget-preflight → 321 passed; authored-flow-slack with relayflowd → 7 passed; typecheck + typecheck:tests clean. |
|
@coderabbitai review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c8eb1b051d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…text The unsupported-operation check matched any `.appendBlock` in the body — an unrelated object's method, a string, a comment — so a Notion flow with no local mount still exited 2 after its mount refusal became a warning. helperMethodsUsed reads `f.<namespace>.<method>` references with the same scoped parse as helperNamespacesUsed; only a body whose context name cannot be resolved keeps the permissive text match. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 72043aaaf1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ed f.notion
helperMethodsUsed only saw `f.notion.appendBlock`, so `const notion = f.notion`
or `const { notion } = f` followed by `notion.appendBlock(...)` passed check
while execution always rejects it. helperMemberUses also reports namespaces
that leave the context without a method (aliased, destructured, passed on) and
every member name the body accesses; when f.notion escapes, any appendBlock
access keeps the unsupported-operation refusal. Direct, non-escaping use stays
precise, so an unrelated object's appendBlock still does not refuse.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aea5c1aad8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… not hand-offs
`const { appendBlock } = f.notion` escaped detection because the method name
was a binding, not a member access, and every extra `f.notion` mention —
including `if (f.notion)` — counted as an escape. helperMemberUses now records
destructured property names as member accesses, and marks a namespace escaped
only when its value is handed on: a declaration or assignment initializer, a
call/new argument, a property value, an array element, a return, spread or
yield (through ?:, ||/??, await and parentheses).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e8d22fd760
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Enumerating hand-off shapes kept missing some (arrow expression bodies, parameter and destructuring defaults, nested destructuring). helperMemberUses now links parents once and treats a use of `f.<ns>` as safe only as a method access or a read-only check (typeof/!/comparison operand, condition); every other position escapes the namespace, and a bare `f` outside those positions escapes the whole context. Destructured keys are collected at any depth, through defaults and array patterns. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5205d7f3c5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…how to avoid it When f.notion escapes, flows check cannot attribute a later .appendBlock to it or to another object, and deliberately refuses rather than admit a flow that execution always rejects. The refusal now says so and names the remedy: call f.notion methods directly so check can tell them apart. Direct use stays precise (an unrelated doc.appendBlock with f.notion.createPage passes). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
…ng mount; destructured machinery
- With main's daemon validation merged in, a YAML flow whose only refusal was
a downgraded helper mount still skipped the daemon gate (validation keyed off
the original result.ok), so --against-daemon could pass without a kernel
verdict. The validator now runs for inspect-only flows too.
- Destructuring a prototype-machinery member (const { prototype: p } = Object,
const { toPrimitive: t } = Symbol) is detected like the member access.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a6d253d0b7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Object[d], Symbol[t] and the like with a key built at runtime may name any prototype machinery, so a computed non-literal member on an unshadowed Object/Symbol/Reflect/Function/globalThis/Proxy now makes Notion appendBlock unprovable. Dynamic indexing of ordinary values stays allowed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d1bb462099
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Computed keys (const { [d]: define } = Object) and rest elements can pick out
any machinery the literal-key check cannot name, so destructuring an unshadowed
Object/Symbol/Reflect/Function/globalThis/Proxy at all now makes Notion
appendBlock unprovable.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ac06f686ca
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…achinery member Aliasing Object/Symbol/Reflect/Function/globalThis/Proxy (const O = Object) let runtime-keyed access reach the machinery under another name. Instead of chasing alias shapes, an unshadowed use of these globals is now accepted only as the object of a static member that is not prototype machinery (Object.keys, Symbol.iterator); any other use — alias, argument, destructuring, computed key — makes Notion appendBlock unprovable. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec7b706e35
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…inery
Every member named prototype counted as helper prototype machinery, so a flow
with class Local {}; Local.prototype.flag = true was refused although it can
neither expose nor modify f.notion. X.prototype is now allowed when X is a
class or function the body defines itself (declaration or const initializer)
and never reassigns; other routes to a prototype (__proto__,
getPrototypeOf, constructor.prototype, the globals) stay refused.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f568c07cf6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… rule globalThis.Object and globalThis.Symbol are the same globals by another route; extracting them (const O = globalThis.Object) let runtime-keyed access reach prototype machinery. A globalThis member naming a prototype-bearing global is now judged like the bare global: safe only as the object of a static, non-machinery member. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 14bb42e2a0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 14bb42e. Configure here.
…ded globals Only globalThis, one level deep, was treated as a route to Object/Symbol/...; Node's global, window, self and nested chains (globalThis.globalThis.Object, globalThis.global.Symbol) were not. Global roots now follow root-to-root chains and judge a named prototype-bearing global like the bare one; any other use of a root (alias, computed key) makes Notion appendBlock unprovable. Ordinary root members (global.setTimeout) stay allowed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aaac44894f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…nery
Object.constructor, (() => {}).constructor and the like are the Function
constructor, which compiles source text the scan never sees. Any member
named constructor (and the legacy __lookupGetter__/__lookupSetter__) now
makes Notion appendBlock unprovable.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a96c88b775
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
(0, eval)(src), const run = eval and globalThis.eval(src) all run source text, but only a direct eval(...) call was refused. Any unshadowed eval identifier, and any member named eval (globalThis.eval), now makes Notion appendBlock unprovable. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Session-Id: b8262468-ea26-4a6e-bee9-d193832e77dc
|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |

Fix: let flows check report Cloud-bound helper requirements without local mounts
A laptop without Slack mounted can inspect an authored Slack flow: check reports
REQUIRES slack and helper_credential_unresolved, then passes. Local run retains
its credential refusal before daemon attachment. The same rule applies to YAML
helpers, whose requirements are now derived from compiled steps with an authoring
fallback for invalid specs.
The warning is opt-in at the check surface, emitted once after REQUIRES.
Non-.flow.* modules receive a self-contained warning without a requirements line.
Unsupported providers and Notion appendBlock remain refusals even without mounts.
Hosted submission, execution, resume, and pure preflight retain their existing
credential checks. Watch inherits the CLI behavior through its child process.
Implementation follows reviewed-plan.md Parts A and B as separate commits.
The two existing authored Slack assertions were retargeted because their check
behavior changes; their executeAuthoredFlow rejection assertions remain intact.
No quality gates or GitHub workflow files were edited.
Validation and limits:
TypeScript checks passed. Commands and literal output follow.
source change was reverted, its test failed, the source bytes were restored,
and the same test passed. Both outputs are below.
codex requirement. The use fixture is deliberately invalid; it verifies the
compile-failure fallback, not successful import expansion.
package.json module boundary. The helper script restores the checkout.
Without that boundary, this checkout's Node import fails before preflight
(example-check.txt and example-run.txt). An attempted Node module flag was
unsupported (example-*-module.txt); no loader fix is included.
The initial broader command failed direct-input.test.ts setup for the absent
binary; its literal output is in evidence/helper-check/regression.txt, alongside
an initial YAML test argument error corrected before the final run.
The authored subset skips ten daemon-dependent cases: Slack structured posts,
journaled effect, confirm/complete SIGKILL replay, and multi-call writeback;
generic helper acceptance, all-provider resume, confirm/complete SIGKILL replay,
and provider-failure journaling. Those crash gates remain unverified here.
Captured evidence (paths relative to the repository):
evidence/helper-check/build.txt
evidence/helper-check/typecheck.txt
evidence/helper-check/typecheck-tests.txt
evidence/helper-check/regression-final.txt
evidence/helper-check/authored-subset.txt
evidence/helper-check/requirements.txt
evidence/helper-check/example-module-boundary.txt
evidence/helper-check/mutation-placement-fail.txt
evidence/helper-check/mutation-placement-pass.txt
evidence/helper-check/mutation-notion-fail.txt
evidence/helper-check/mutation-notion-pass.txt
Checks
The checks fail on the base commit too, so these failures were not introduced by this change: they come from the repository itself or from the environment the checks ran in. This pull request is a draft until someone looks.
What ran (.relayflow/check.sh)
Output on this branch (last 80 lines)
Output on the base commit (last 80 lines)
What the repair agent found
Repair notes — .relayflow/check.sh on relayflow/flows-software-garden-020f6161
.relayflow/check.logrecorded 6 failed vitest files / 31 failed tests. Threedistinct causes; one was missing setup and is fixed, two are facts about this
machine that no change to the tree can remove. Fixing the first then surfaced a
fourth — a pre-existing race between two test files — reported below, not fixed.
Fixed: bun was 1.3.6, CI pins 1.4.0 (missing setup)
tests/authored-node-runtime.test.tsfailed at collection:The machine image ships bun 1.3.6 at
/usr/local/share/nvm/current/bin/bun;every workflow pins 1.4.0 (
oven-sh/setup-bun@v2,bun-version: "1.4.0"incloud-runtime-artifact.yml, surface-package.yml, schema-publish.yml,
publish.yml). The standalone artifact that test builds embeds the bun runtime,
so a different bun is a different artifact and the assertion is load-bearing.
.relayflow/check.shnow installs the pin the way setup-bun does — fromhttps://bun.sh/installinto$HOME/.bun-1.4.0, first on PATH — instead ofmerely requiring that some bun exist. Verified:
Not fixable here: bwrap cannot unshare in this container
24 of the 31 failures are
tests/hosted-extension-isolation.test.ts(13),tests/hosted-extension-protocol.test.ts(8),tests/babysitter-native-extension.test.ts(1) andtests/software-garden-babysitter-composition.test.ts(2), all with:/usr/bin/bwrapis installed. What is missing is the kernel facility:unprivileged user namespaces stay blocked because the sysctl is not writable
inside the container —
— which
.relayflow/check.shalready documents and already attempts. CI runsthese on a dedicated ephemeral VM that can clear the restriction. No tree
change affects this; left alone.
Not fixable here:
/home/daytona/package.jsondeclares"type": "commonjs"The remaining 7 failures are
tests/live-kernel.test.tsagent/tick cases.Each dispatches an agent step to one of the extensionless Node fixtures under
testdata/preflight/(analyze-story-stub-cli,analyze-story-missing-fields-cli,analyze-story-text-only-cli,analyze-story-echo-wake-cli,wake-context-probe-cli,echo-model-cli,tick-slot-report-cli— all#!/usr/bin/env node). The journal records the same shape every time:The fixtures exit 0 having written nothing, so the handshake never starts.
Cause: this checkout lives under
/home/daytona, and/home/daytona/package.json(the supervisor harness's own manifest, outside therepository) declares
"type": "commonjs". That is the nearest package.json forevery extensionless file in the tree, so Node loads these ESM fixtures as
CommonJS and they produce nothing instead of their identify token. Same bytes,
same node (v25.6.0), run from a directory with no ancestor package.json:
A GitHub runner checkout has no ancestor package.json, so CI never sees this.
Nothing in
.relayflow/check.shcan undo it: Node resolves module type fromthe file's own ancestry, not from cwd or any flag CI sets. The two ways out are
editing
/home/daytona/package.json, which belongs to the harness and not tothis repository, or committing a
testdata/preflight/package.jsonwith{"type":"module"}— a change to test fixtures that only this environmentneeds. Left alone.
Surfaced by the bun pin, pre-existing, not fixed: a race on
tests/fixtures/With bun at the CI pin,
tests/authored-node-runtime.test.tsruns for the firsttime on this machine, and the run picks up one failure
check.logdid not have:It is not that test's defect, and not this branch's.
bun build --compilewrites its intermediate output into the current working directory, mode
----------, for the length of the compile:bundle-typescript.ts:59runs that build with the flow's own directory as cwd,and
tests/bundle.test.ts:285buildspackages/sdk/tests/fixtures/build.flow.ts— so an 80 MB unreadable file exists inside the shared fixtures directory for
seconds.
tests/flow-executor-chain.test.tsconcurrently snapshots that samedirectory as an agent workspace,
walkopens the file, and the EACCES closesthe journal client and fails the run.
bun 1.3.6 does not leave that file in cwd (polled 200 times through a build; the
only artifacts were
a.tsand the outfile), which is why the pin surfaced it.CI pins 1.4.0 too, so CI is exposed to the same race.
Reproduces only under full-suite parallelism. The file alone, and the two
colliding files together, both pass:
Left unfixed, deliberately. The two candidate fixes both reach outside this
task: stage
bundle.test.ts's input in a temp directory instead of the sharedtests/fixtures/(an unrelated test), or makesnapshotWorkspaceFilesskipentries it cannot read (a change to what a workspace snapshot promises, which
RFC-0001's fail-closed rail makes a decision rather than a cleanup). Reported
here so it is a decision and not an oversight.
Also observed (not a failure)
testdata/preflight/signal-probe-cliends inkill -SEGV "$$"by design, andthis machine's
/proc/sys/kernel/core_patternis the literalcore, so runningthe suite drops an untracked
testdata/preflight/coredump beside the fixture.It is test debris, not a defect; deleted, not committed, not gitignored.
Gates that the aborted run never reached
set -estopped.relayflow/check.shat the SDK vitest step, so the threesteps after it were unverified in
check.log. All three pass here:Where the suite stands after the setup fix
Was 31 failed / 3811 passed / 20 skipped. The 16 formerly-skipped
authored-node-runtimetests now run and pass; the one new failure is thetests/fixtures/race above. The remaining 31 are the bwrap group (24, across 4 files)and the live-kernel Node-fixture group (7, 1 file) — the two environment causes.
RELAYFLOWS_ALLOW_ANALYZER_SKIP=1is set here as CI sets it, so, as.relayflow/check.shalready says, this run is not gate-2 acceptance evidence.Fixes #473
Summary by cubic
flows checkno longer refuses a Cloud-bound authored flow that usesf.slackwhen the laptop has no local helper mount: the flow passes, reports the integration underREQUIRES, and emits a singlehelper_credential_unresolvedwarning after it. Localflows runstill refuses before executing the body, and Cloud submission still checks the workspace integration at submit.RELAY_API_KEYrefusals and the budget warning no longer depend on whether the helper is mounted, though a warning path never admits the flow for execution. A YAML flow whose only refusal was the downgraded mount still runs the daemon validation gate, so--against-daemoncannot pass without a kernel verdict.appendBlock) and unknown diagnostic shapes remain refusals.appendBlockis detected from the parse via an allowlist of read-only positions: direct use stays precise, while aliased, destructured, computed, string-keyed, handed-into-a-call, run througheval/Function, or reached through the root function'sarguments(regardless of its parameter shape) keeps the refusal with an explanation; a body with no named context parameter is unprovable. Aliases are followed, so a plain alias calling only supported methods passes and guard reads (f.notion && …) do not over-refuse. Discarded reads (comma operands,${f.notion}interpolation, comparisons) do not hand the value on; a tagged template does. Any inheritedObject.prototypemember onf.notion— including one reached through a destructured binding — prototype machinery (prototype,__proto__,constructor,defineProperty,set/getPrototypeOf,toPrimitive,__lookupGetter__/__lookupSetter__,Reflect,Proxy),eval, orFunctionanywhere in the body also makes the call unprovable — except when an enclosing scope of that use binds the name, or for aprototypemember of a class or function the body defines itself and never reassigns. Static string-keyed members count like their dotted forms. An unshadowed use ofObject/Symbol/Reflect/Function/globalThis/Proxyis accepted only as a static non-machinery member (Object.keys,Symbol.iterator); any other use — alias, argument, destructuring, computed key — makes the call unprovable. Globals reached through any global-object root —globalThis,global,window,self, or nested root chains — follow the same rule, so extracting one via a root is unprovable, while dynamic indexing of ordinary values and ordinary root members (global.setTimeout) stay allowed. Any unshadowed use ofevalcounts, including indirect forms ((0, eval)(…),const run = eval,globalThis.eval)..flow.mjs,.flow.mts,.flow.js). Cloud submission refuses those sources as unsupported, andensureFlowConnectionsreturns before prompting or connecting for them;.flow.tssubmissions keep the workspace-integration check at submit.Checks
Suites fail on the base commit too; failures are environmental —
bwrapuser namespaces blocked in containers and live-kernel fixtures under a"type": "commonjs"ancestorpackage.json— plus a pre-existingtests/fixtures/race betweenbundle.test.tsandflow-executor-chain.test.tsunder the pinnedbun 1.4.0. Build, typechecks, schema, surface-package, and lens-parity gates pass locally. The helper-surface suite is split by concern across four test files with shared staging inhelper-surface-fixture.ts.Written for commit 2b03dd4. Summary will update on new commits.
Note
Medium Risk
Changes preflight/check semantics for helper credentials and adds substantial static analysis in the check path; execution and cloud submit refusals are preserved but reviewers should verify edge cases around Notion appendBlock and composed check diagnostics.
Overview
flows checkno longer exits on missing local helper mounts (e.g. Slack). It lists integrations underREQUIRES, emits a singlehelper_credential_unresolvedwarning after that line (same footnote placement asagent_worker_unresolved), and can pass. Localflows runstill refuses withhelper_slack.credential_missingbefore the body runs;schedule/deploy/run --cloudstill verify workspace integrations at submit.Mount refusals are downgraded only when check opts in via
warnUnresolvedHelperCredential(check-helper-surface.ts). YAML and authored.flow.tspaths share this behavior; check can still compile and run daemon validation when the only blocker was a downgraded mount, without admitting the flow for execution.Notion
appendBlockdetection moves from a regex to AST analysis (helper-operation-use.ts): directf.notion.appendBlockstays a refusal even without a mount; aliasing, computed access,eval/Function, prototype tampering, and similar patterns stay fail-closed. Cloud connect reads requirements from all authored flow extensions but skips connect prompts for sources Cloud will not submit (non-.flow.ts).Docs (
SLACK-HELPER,SURFACE,YAML-HELPERS) and broad vitest coverage document the new warning and refusal rules.Reviewed by Cursor Bugbot for commit a96c88b. Bugbot is set up for automated code reviews on this repo. Configure here.