diff --git a/docs/EDITOR.md b/docs/EDITOR.md index 0685eaa61..fb2784b02 100644 --- a/docs/EDITOR.md +++ b/docs/EDITOR.md @@ -224,3 +224,12 @@ schema's entry point, even though `flows check` can also ingest it. 4. Hover `timeoutMs` and inspect completion after `type: agent`. Do not correct `identitty` to `identity` in this dialect: neither is supported. + + +`flows check --json` also reports `validation`: `mode: "daemon"` includes the +validator binary, protocol and spec version; `mode: "local"` includes a reason +why daemon acceptance is unproven. Editor/schema acceptance alone does not prove +runtime compatibility. Set `FLOWS_NO_DAEMON_CHECK=1` for spawn-free local checks, +or use `--against-daemon` to require the installed binary's stateless validator. +Authored TypeScript bodies remain local header checks. See SURFACE.md's +“What `flows check` proves about the installed runtime” for scope and old binaries. diff --git a/docs/SURFACE.md b/docs/SURFACE.md index d05071355..eaf5d5ded 100644 --- a/docs/SURFACE.md +++ b/docs/SURFACE.md @@ -2002,3 +2002,43 @@ captured, hash-verified authored source bytes at their original module URLs. Successful root output records the Node version, executable SHA256, and embedded payload SHA256 as `executionRuntime`. The payload remains part of the existing artifact hash, and completed child effects remain journal results on resume. + + +### What `flows check` proves about the installed runtime + +For declarative YAML/JSON specs, `flows check` now also pipes the compiled kernel +spec to the installed `relayflowd validate-spec` when available. This performs +`RunSpec::parse` and `validate`, just like `run.start` (and is stricter than +`event.submit`, which currently only parses). No socket is opened, run created, +or journal written. The input is the same spec value `run.start` submits, in +canonical form. + +- Default: automatic validation when the installed binary supports it; otherwise + local compile and preflight, with a reason on the `CHECK PASSED` line. +- `--against-daemon`: require a verdict; unavailable or incompatible validators + refuse with `daemon_validation_unavailable` and exit 2. +- `--no-daemon-check`: local compile and preflight only, without binary discovery. + +`FLOWS_NO_DAEMON_CHECK=1` and `FLOWS_CHECK_AGAINST_DAEMON=1` select the same modes +for an environment; explicit flags win. If both environment variables are set, +the offline opt-out wins. Watch mode preserves the selection. + +A daemon refusal uses `invalid_spec`, preserving the kernel field and step +location. A refusal on a generated gate step identifies an SDK lowering bug, +not an authoring mistake. JSON reports carry `validation` on success and refusal; +human output annotates the pass line, without adding a refusal terminator. + +The annotation names the binary that judged the spec. An already running daemon +from a different build may disagree; this check does not contact that service. +Older binaries (including 2.0.19) lack `validate-spec`: automatic mode warns +`daemon_unvalidated`, naming the binary and the unproven acceptance, while +required mode refuses. The same applies to a validator that exits nonzero or +is killed after printing an accepting verdict (`abnormal_exit`): acceptance +requires both the verdict and exit 0. A daemon refusal is reported whatever the +exit status. This catches skew going forward, not retroactively. + +Authored TypeScript bodies are not lowered until execution. Their header checks +remain local, with `authored_body` as the validation reason (required mode +refuses). This change therefore does not cover the authored-body case reported +in #489. Body capability probing and requiring daemon checks in release artifact +packaging are follow-on work. diff --git a/evidence/daemon-check/README.md b/evidence/daemon-check/README.md new file mode 100644 index 000000000..2d72382b1 --- /dev/null +++ b/evidence/daemon-check/README.md @@ -0,0 +1,93 @@ +Commands were run from the repository root unless the command includes `cd`. +All `.txt` files contain captured output, not reconstructed output. + +`cd packages/sdk && npx vitest run tests/check-daemon-validation.test.ts tests/cli.test.ts tests/cli-watch.test.ts tests/relay-cli-surface.test.ts` + +[Captured output](sdk-final.txt) + +`cd packages/sdk && npx vitest run tests/check-daemon-validation.test.ts tests/cli.test.ts tests/cli-watch.test.ts` + +[Captured output](sdk-targeted-final.txt) + +`cd packages/sdk && npx vitest run tests/relay-cli-surface.test.ts` + +[Captured output](cli-surface-final.txt) + +`cd packages/sdk && npx vitest run tests/plugin-extension.test.ts` + +[Captured output](plugin-extension-retry.txt) + +`cd packages/sdk && RELAYFLOWD_BIN=/tmp/relayflows-daemon-check-target/debug/relayflowd npx vitest run tests/live-kernel.test.ts -t 'validates the canonical ladder'` + +[Captured output](live-ladder.txt) + +`CARGO_TARGET_DIR=/tmp/relayflows-daemon-check-target CARGO_PROFILE_DEV_DEBUG=0 CARGO_PROFILE_TEST_DEBUG=0 CARGO_INCREMENTAL=0 /home/daytona/.cargo/bin/cargo test --manifest-path kernel/Cargo.toml -p relayflowd --test validate_spec` + +[Captured output](rust-targeted-final.txt) + +`CARGO_TARGET_DIR=/tmp/relayflows-daemon-check-target CARGO_PROFILE_DEV_DEBUG=0 CARGO_PROFILE_TEST_DEBUG=0 CARGO_INCREMENTAL=0 /home/daytona/.cargo/bin/cargo test --manifest-path kernel/Cargo.toml -j 2` + +[Captured output](rust-workspace-retry.txt) + +`cd packages/sdk && RELAYFLOWS_TOOLCHAIN_HOME=/tmp/daemon-check-toolchain CARGO_TARGET_DIR=/tmp/relayflows-daemon-check-target npm test` + +[Captured output](sdk-full.txt) + +`cd packages/sdk && PATH=/usr/bin:/bin /usr/local/share/nvm/versions/node/v25.6.0/bin/node node_modules/vitest/vitest.mjs run tests/check-daemon-validation.test.ts tests/cli.test.ts` + +[Captured output](sdk-minimal-path.txt) + +`node scripts/cli-package-gate.mjs` + +[Captured output](package-gate.txt) + +`node scripts/build-standalone-cli.mjs bun-linux-x64 /tmp/flows-daemon-check` + +[Captured output](standalone-build.txt) + +`RELAYFLOWD_BIN=/tmp/stub-relayflowd-check /tmp/flows-daemon-check check --against-daemon --json testdata/hello-deterministic.flow.yaml` + +[Captured output](standalone-check.txt) + +`cd packages/sdk && npm run typecheck && npm run typecheck:tests` + +[Captured output](typecheck-final.txt) + +`RELAYFLOWD_BIN=/tmp/relayflows-daemon-check-target/debug/relayflowd node packages/sdk/dist/cli.js check --against-daemon testdata/hello-agent.flow.yaml` + +[Captured output](live-cli.txt) + +`cd packages/sdk && RELAYFLOWD_BIN=/kernel/target/release/relayflowd ./node_modules/.bin/vitest run tests/live-kernel.test.ts -t 'naming the step the daemon named'` + +Mutation verification for the live skew case: `stepId` mapping removed from +`daemon-spec-validation.ts`, the test run and its failure captured, the file +restored byte-for-byte (`git diff --exit-code` clean) and the test re-run. + +[Captured output, mutated](live-skew-mutated.txt) · +[Captured output, restored](live-skew-restored.txt) + +`python3 evidence/daemon-check/mutation-run.py` + +[Captured output](mutations.txt) + +`git diff --check` + +[Captured output](diff-check.txt) + +The standalone stub consumed stdin and returned this envelope without running a flow: + +```sh +#!/bin/sh +cat >/dev/null +printf '%s\n' '{"ok":true,"protocol":0,"spec_version":"0.1.0"}' +``` + +Additional historical captures: `rust-targeted.txt` is the private-toolchain +failure; `rust-targeted-retry.txt` contains the initial incorrect test assertion +for the cwd message; `rust-workspace.txt` contains the disk-full linker failure. +`sdk-build*.txt`, `typecheck-tests-final.txt`, and `sdk-targeted.txt` are earlier +build/typecheck/targeted captures. `rustfmt-setup.txt` records tool installation. +`timing.txt` captures shell `time` for the deterministic fixture in auto mode +with RELAYFLOWD_BIN pinned to the built binary, then with --no-daemon-check. +Each `mutation-*.txt` embeds its exact command and exit status. Temporary mutation +working directories are removed by the script; the captured outputs here persist. diff --git a/evidence/daemon-check/cli-surface-final.txt b/evidence/daemon-check/cli-surface-final.txt new file mode 100644 index 000000000..54812636c --- /dev/null +++ b/evidence/daemon-check/cli-surface-final.txt @@ -0,0 +1,10 @@ + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + + ✓ tests/relay-cli-surface.test.ts (89 tests) 83ms + + Test Files 1 passed (1) + Tests 89 passed (89) + Start at 14:36:15 + Duration 3.18s (transform 1.91s, setup 23ms, collect 2.88s, tests 83ms, environment 0ms, prepare 44ms) + diff --git a/evidence/daemon-check/diff-check.txt b/evidence/daemon-check/diff-check.txt new file mode 100644 index 000000000..e69de29bb diff --git a/evidence/daemon-check/live-cli.txt b/evidence/daemon-check/live-cli.txt new file mode 100644 index 000000000..0238afa3d --- /dev/null +++ b/evidence/daemon-check/live-cli.txt @@ -0,0 +1,11 @@ +WARNING [permissions_unenforced] Step "edit" declares permissions (fileGlobs, accessPreset). This declaration is validated and recorded with the step spec; it is not currently enforced (gate 8 / #442). These permissions do not restrict file or network access. +WARNING [unprovable_effects] Step "greet" command "printf" resolves, but its effects cannot be proven before execution. +WARNING [unprovable_effects] Step "finish" command "printf" resolves, but its effects cannot be proven before execution. +WARNING [editor_schema_missing] For editor validation, add this first line: # yaml-language-server: $schema=https://schema.relayflows.dev/v0.1/flows.schema.json +GATE step "greet" exit_code+output_contains from data (kernel, journal-replayable) +GATE step "edit" output_contains from data (kernel, journal-replayable) +GATE step "finish" exit_code from data (kernel, journal-replayable) +RESOLVED step "edit" cli "./preflight/authenticated-cli" from project (/home/daytona/.relayflow-v2-supervisor/durable/repository/testdata/flows.json) model "test-model-v1" from step +REQUIRES claude (step "edit") +WARNING [agent_worker_unresolved] 1 agent step ("edit") requires an attached worker. For a local run, use `flows run --local-agent `, unless you already attach an agent worker for this daemon. `flows check` does not verify worker attachment: with no worker attached the run parks at the first agent step. +CHECK PASSED testdata/hello-agent.flow.yaml [validated by relayflowd at /tmp/relayflows-daemon-check-target/debug/relayflowd, protocol 0] diff --git a/evidence/daemon-check/live-ladder.txt b/evidence/daemon-check/live-ladder.txt new file mode 100644 index 000000000..0e04a9a51 --- /dev/null +++ b/evidence/daemon-check/live-ladder.txt @@ -0,0 +1,15 @@ + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + +stdout | tests/live-kernel.test.ts +LIVE_KERNEL relayflowd=/tmp/relayflows-daemon-check-target/debug/relayflowd +LIVE_KERNEL flows=/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/dist/cli.js + + ✓ tests/live-kernel.test.ts (33 tests | 32 skipped) 306ms + ✓ validates the canonical ladder with the built daemon without running it 303ms + + Test Files 1 passed (1) + Tests 1 passed | 32 skipped (33) + Start at 14:31:05 + Duration 4.41s (transform 2.31s, setup 62ms, collect 3.80s, tests 306ms, environment 0ms, prepare 46ms) + diff --git a/evidence/daemon-check/live-skew-mutated.txt b/evidence/daemon-check/live-skew-mutated.txt new file mode 100644 index 000000000..807e1f459 --- /dev/null +++ b/evidence/daemon-check/live-skew-mutated.txt @@ -0,0 +1,44 @@ +$ sed -i "s/const stepId = index === undefined ? undefined : submitted.steps[Number(index)]?.id;/const stepId: string | undefined = undefined;/" packages/sdk/src/daemon-spec-validation.ts +$ cd packages/sdk && RELAYFLOWD_BIN=$PWD/../../kernel/target/release/relayflowd ./node_modules/.bin/vitest run tests/live-kernel.test.ts -t "naming the step the daemon named" + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + +stdout | tests/live-kernel.test.ts +LIVE_KERNEL relayflowd=/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/target/release/relayflowd +LIVE_KERNEL flows=/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/dist/cli.js + + ❯ tests/live-kernel.test.ts (34 tests | 1 failed | 33 skipped) 61ms + × refuses a field the built daemon does not know, naming the step the daemon named 59ms + → expected { severity: 'refusal', …(3) } to match object { Object (kind, stepId) } +(3 matching properties omitted from actual) + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/live-kernel.test.ts > refuses a field the built daemon does not know, naming the step the daemon named +AssertionError: expected { severity: 'refusal', …(3) } to match object { Object (kind, stepId) } +(3 matching properties omitted from actual) + +- Expected ++ Received + + Object { + "kind": "invalid_spec", +- "stepId": "edit", + } + + ❯ tests/live-kernel.test.ts:2101:19 + 2099| // The daemon names the field and its own index; the report adds the… + 2100| // step id for that index, and claims no compiler bug for an authore… + 2101| expect(refusal).toMatchObject({ kind: 'invalid_spec', stepId: 'edit'… + | ^ + 2102| expect(refusal?.message).toContain('unknown field "from_a_newer_sdk"… + 2103| expect(refusal?.message).not.toContain('generated by this compiler'); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ + + Test Files 1 failed (1) + Tests 1 failed | 33 skipped (34) + Start at 15:16:07 + Duration 1.92s (transform 1.06s, setup 20ms, collect 1.67s, tests 61ms, environment 0ms, prepare 44ms) + +exit=1 diff --git a/evidence/daemon-check/live-skew-restored.txt b/evidence/daemon-check/live-skew-restored.txt new file mode 100644 index 000000000..ac8f2a879 --- /dev/null +++ b/evidence/daemon-check/live-skew-restored.txt @@ -0,0 +1,17 @@ +$ git checkout -- packages/sdk/src/daemon-spec-validation.ts # restored byte-for-byte; git diff --exit-code is clean +$ cd packages/sdk && RELAYFLOWD_BIN=$PWD/../../kernel/target/release/relayflowd ./node_modules/.bin/vitest run tests/live-kernel.test.ts -t "naming the step the daemon named" + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + +stdout | tests/live-kernel.test.ts +LIVE_KERNEL relayflowd=/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/target/release/relayflowd +LIVE_KERNEL flows=/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/dist/cli.js + + ✓ tests/live-kernel.test.ts (34 tests | 33 skipped) 61ms + + Test Files 1 passed (1) + Tests 1 passed | 33 skipped (34) + Start at 15:16:15 + Duration 2.59s (transform 1.45s, setup 24ms, collect 2.31s, tests 61ms, environment 0ms, prepare 50ms) + +exit=0 diff --git a/evidence/daemon-check/mutation-indices-authored-mutated.txt b/evidence/daemon-check/mutation-indices-authored-mutated.txt new file mode 100644 index 000000000..c322f9233 --- /dev/null +++ b/evidence/daemon-check/mutation-indices-authored-mutated.txt @@ -0,0 +1,66 @@ +$ 'node' '/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/node_modules/vitest/vitest.mjs' 'run' 'tests/check-daemon-validation.test.ts' '-t' 'maps authored steps following generated steps' +cwd: /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + RUN v2.1.9 /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + ❯ tests/check-daemon-validation.test.ts (20 tests | 1 failed | 19 skipped) 24ms + × maps authored steps following generated steps without blaming the compiler 23ms + → expected [ { severity: 'warning', …(3) }, …(2) ] to deep equally contain { severity: 'refusal', …(4) } + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/check-daemon-validation.test.ts > maps authored steps following generated steps without blaming the compiler +AssertionError: expected [ { severity: 'warning', …(3) }, …(2) ] to deep equally contain { severity: 'refusal', …(4) } + +- Expected: +Object { + "errors": Array [ + "unknown field \"nope\" at steps[2]", + ], + "kind": "invalid_spec", + "message": "unknown field \"nope\" at steps[2]", + "severity": "refusal", + "stepId": "second", +} + ++ Received: +Array [ + Object { + "kind": "unprovable_effects", + "message": "Step \"first\" command \"echo\" resolves, but its effects cannot be proven before execution.", + "severity": "warning", + "stepId": "first", + }, + Object { + "kind": "unprovable_effects", + "message": "Step \"second\" command \"echo\" resolves, but its effects cannot be proven before execution.", + "severity": "warning", + "stepId": "second", + }, + Object { + "errors": Array [ + "unknown field \"nope\" at steps[2]", + ], + "kind": "invalid_spec", + "message": "unknown field \"nope\" at steps[2]", + "severity": "refusal", + }, +] + + ❯ tests/check-daemon-validation.test.ts:178:38 + 176| { daemonValidation: 'required', daemonValidationDeps: deps('unknow… + 177| expect(checked.report.ok).toBe(false); + 178| expect(checked.report.diagnostics).toContainEqual({ severity: 'refus… + | ^ + 179| message: 'unknown field "nope" at steps[2]', errors: ['unknown fie… + 180| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ + + Test Files 1 failed (1) + Tests 1 failed | 19 skipped (20) + Start at 14:32:45 + Duration 2.04s (transform 1.15s, setup 17ms, collect 1.80s, tests 24ms, environment 0ms, prepare 71ms) + + +exit=1 diff --git a/evidence/daemon-check/mutation-indices-authored-restored.txt b/evidence/daemon-check/mutation-indices-authored-restored.txt new file mode 100644 index 000000000..1e960a4c2 --- /dev/null +++ b/evidence/daemon-check/mutation-indices-authored-restored.txt @@ -0,0 +1,14 @@ +$ 'node' '/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/node_modules/vitest/vitest.mjs' 'run' 'tests/check-daemon-validation.test.ts' '-t' 'maps authored steps following generated steps' +cwd: /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + RUN v2.1.9 /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + ✓ tests/check-daemon-validation.test.ts (20 tests | 19 skipped) 30ms + + Test Files 1 passed (1) + Tests 1 passed | 19 skipped (20) + Start at 14:32:50 + Duration 2.38s (transform 1.35s, setup 16ms, collect 2.02s, tests 30ms, environment 0ms, prepare 85ms) + + +exit=0 diff --git a/evidence/daemon-check/mutation-indices-generated-mutated.txt b/evidence/daemon-check/mutation-indices-generated-mutated.txt new file mode 100644 index 000000000..be45ae11e --- /dev/null +++ b/evidence/daemon-check/mutation-indices-generated-mutated.txt @@ -0,0 +1,42 @@ +$ 'node' '/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/node_modules/vitest/vitest.mjs' 'run' 'tests/check-daemon-validation.test.ts' '-t' 'maps generated-step indices' +cwd: /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + RUN v2.1.9 /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + ❯ tests/check-daemon-validation.test.ts (20 tests | 1 failed | 19 skipped) 12ms + × maps generated-step indices to submitted steps and identifies compiler bugs 11ms + → expected { severity: 'refusal', …(4) } to match object { stepId: 'first.gate', …(1) } +(3 matching properties omitted from actual) + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/check-daemon-validation.test.ts > maps generated-step indices to submitted steps and identifies compiler bugs +AssertionError: expected { severity: 'refusal', …(4) } to match object { stepId: 'first.gate', …(1) } +(3 matching properties omitted from actual) + +- Expected ++ Received + + Object { + "kind": "invalid_spec", +- "stepId": "first.gate", ++ "stepId": "second", + } + + ❯ tests/check-daemon-validation.test.ts:41:33 + 39| verification: { type: 'artifact_exists', path: 'answer.txt' } }, f… + 40| const result = validateSpecWithDaemon(gated, 'required', deps('unkno… + 41| expect(result.diagnostics[0]).toMatchObject({ stepId: 'first.gate', … + | ^ + 42| expect(result.diagnostics[0]?.message).toContain('generated by this … + 43| expect(result.diagnostics[0]?.message).toContain('Report this rather… + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ + + Test Files 1 failed (1) + Tests 1 failed | 19 skipped (20) + Start at 14:32:43 + Duration 2.09s (transform 1.18s, setup 14ms, collect 1.86s, tests 12ms, environment 0ms, prepare 84ms) + + +exit=1 diff --git a/evidence/daemon-check/mutation-indices-generated-restored.txt b/evidence/daemon-check/mutation-indices-generated-restored.txt new file mode 100644 index 000000000..8b033b548 --- /dev/null +++ b/evidence/daemon-check/mutation-indices-generated-restored.txt @@ -0,0 +1,14 @@ +$ 'node' '/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/node_modules/vitest/vitest.mjs' 'run' 'tests/check-daemon-validation.test.ts' '-t' 'maps generated-step indices' +cwd: /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + RUN v2.1.9 /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + ✓ tests/check-daemon-validation.test.ts (20 tests | 19 skipped) 6ms + + Test Files 1 passed (1) + Tests 1 passed | 19 skipped (20) + Start at 14:32:47 + Duration 2.55s (transform 1.49s, setup 14ms, collect 2.28s, tests 6ms, environment 0ms, prepare 47ms) + + +exit=0 diff --git a/evidence/daemon-check/mutation-refusal-cli-mutated.txt b/evidence/daemon-check/mutation-refusal-cli-mutated.txt new file mode 100644 index 000000000..64b5f390e --- /dev/null +++ b/evidence/daemon-check/mutation-refusal-cli-mutated.txt @@ -0,0 +1,37 @@ +$ 'node' '/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/node_modules/vitest/vitest.mjs' 'run' 'tests/check-daemon-validation.test.ts' '-t' 'real CLI refuses skew in auto and required modes' +cwd: /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + RUN v2.1.9 /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + ❯ tests/check-daemon-validation.test.ts (20 tests | 1 failed | 19 skipped) 496ms + × real CLI refuses skew in auto and required modes 495ms + → expected +0 to be 2 // Object.is equality + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/check-daemon-validation.test.ts > real CLI refuses skew in auto and required modes +AssertionError: expected +0 to be 2 // Object.is equality + +- Expected ++ Received + +- 2 ++ 0 + + ❯ tests/check-daemon-validation.test.ts:106:27 + 104| for (const flags of [[], ['--against-daemon']]) { + 105| const result = cli(f.path, f.binary, flags); + 106| expect(result.status).toBe(2); + | ^ + 107| expect(result.stderr).toContain(`REFUSED [invalid_spec] ${message}… + 108| } + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ + + Test Files 1 failed (1) + Tests 1 failed | 19 skipped (20) + Start at 14:32:34 + Duration 2.52s (transform 1.16s, setup 16ms, collect 1.80s, tests 496ms, environment 0ms, prepare 45ms) + + +exit=1 diff --git a/evidence/daemon-check/mutation-refusal-cli-restored.txt b/evidence/daemon-check/mutation-refusal-cli-restored.txt new file mode 100644 index 000000000..0d822959c --- /dev/null +++ b/evidence/daemon-check/mutation-refusal-cli-restored.txt @@ -0,0 +1,15 @@ +$ 'node' '/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/node_modules/vitest/vitest.mjs' 'run' 'tests/check-daemon-validation.test.ts' '-t' 'real CLI refuses skew in auto and required modes' +cwd: /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + RUN v2.1.9 /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + ✓ tests/check-daemon-validation.test.ts (20 tests | 19 skipped) 865ms + ✓ real CLI refuses skew in auto and required modes 864ms + + Test Files 1 passed (1) + Tests 1 passed | 19 skipped (20) + Start at 14:32:39 + Duration 3.03s (transform 1.29s, setup 47ms, collect 1.95s, tests 865ms, environment 0ms, prepare 42ms) + + +exit=0 diff --git a/evidence/daemon-check/mutation-refusal-unit-mutated.txt b/evidence/daemon-check/mutation-refusal-unit-mutated.txt new file mode 100644 index 000000000..27aa38a1b --- /dev/null +++ b/evidence/daemon-check/mutation-refusal-unit-mutated.txt @@ -0,0 +1,37 @@ +$ 'node' '/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/node_modules/vitest/vitest.mjs' 'run' 'tests/check-daemon-validation.test.ts' '-t' 'refuses package-valid daemon-invalid skew through check' +cwd: /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + RUN v2.1.9 /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + ❯ tests/check-daemon-validation.test.ts (20 tests | 1 failed | 19 skipped) 29ms + × refuses package-valid daemon-invalid skew through check 28ms + → expected true to be false // Object.is equality + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/check-daemon-validation.test.ts > refuses package-valid daemon-invalid skew through check +AssertionError: expected true to be false // Object.is equality + +- Expected ++ Received + +- false ++ true + + ❯ tests/check-daemon-validation.test.ts:31:28 + 29| const result = checkAuthoredFlow(flow, '/tmp/flow.json', undefined, + 30| { daemonValidation: 'auto', daemonValidationDeps: deps(message) }); + 31| expect(result.report.ok).toBe(false); + | ^ + 32| expect(result.report.diagnostics).toContainEqual({ severity: 'refusa… + 33| message, errors: [message], stepId: 'first' }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ + + Test Files 1 failed (1) + Tests 1 failed | 19 skipped (20) + Start at 14:32:32 + Duration 2.21s (transform 1.29s, setup 19ms, collect 1.94s, tests 29ms, environment 0ms, prepare 45ms) + + +exit=1 diff --git a/evidence/daemon-check/mutation-refusal-unit-restored.txt b/evidence/daemon-check/mutation-refusal-unit-restored.txt new file mode 100644 index 000000000..d844f1d2d --- /dev/null +++ b/evidence/daemon-check/mutation-refusal-unit-restored.txt @@ -0,0 +1,14 @@ +$ 'node' '/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/node_modules/vitest/vitest.mjs' 'run' 'tests/check-daemon-validation.test.ts' '-t' 'refuses package-valid daemon-invalid skew through check' +cwd: /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + RUN v2.1.9 /tmp/daemon-check-mutation-avim9yyh/packages/sdk + + ✓ tests/check-daemon-validation.test.ts (20 tests | 19 skipped) 23ms + + Test Files 1 passed (1) + Tests 1 passed | 19 skipped (20) + Start at 14:32:37 + Duration 2.05s (transform 1.15s, setup 35ms, collect 1.80s, tests 23ms, environment 0ms, prepare 43ms) + + +exit=0 diff --git a/evidence/daemon-check/mutation-run.py b/evidence/daemon-check/mutation-run.py new file mode 100644 index 000000000..dcccdae8e --- /dev/null +++ b/evidence/daemon-check/mutation-run.py @@ -0,0 +1,56 @@ +"""Run the reviewed mutations in an isolated copy so concurrent suites stay pristine.""" +from pathlib import Path +import hashlib +import shutil +import subprocess +import tempfile + +repo = Path(__file__).resolve().parents[2] +source = repo / 'packages/sdk' +evidence = repo / 'evidence/daemon-check' +with tempfile.TemporaryDirectory(prefix='daemon-check-mutation-') as directory: + root = Path(directory) + sdk = root / 'packages/sdk' + sdk.mkdir(parents=True) + for name in ['src', 'dist']: + shutil.copytree(source / name, sdk / name) + for name in ['package.json', 'vitest.config.ts']: + shutil.copy2(source / name, sdk / name) + (sdk / 'tests').mkdir() + for name in ['check-daemon-validation.test.ts', 'isolate-workspace.ts']: + shutil.copy2(source / 'tests' / name, sdk / 'tests' / name) + (sdk / 'node_modules').symlink_to(source / 'node_modules', target_is_directory=True) + (root / 'testdata').symlink_to(repo / 'testdata', target_is_directory=True) + files = [sdk / 'src/daemon-spec-validation.ts', sdk / 'dist/daemon-spec-validation.js'] + originals = {p: p.read_bytes() for p in files} + cases = [ + ('refusal', 'if (verdict.ok)', 'if (true)', [ + ('unit', 'refuses package-valid daemon-invalid skew through check'), + ('cli', 'real CLI refuses skew in auto and required modes'), + ]), + ('indices', 'submitted.steps[Number(index)]?.id', 'flow.steps[Number(index)]?.id', [ + ('generated', 'maps generated-step indices'), + ('authored', 'maps authored steps following generated steps'), + ]), + ] + for name, before, after, tests in cases: + for path, original in originals.items(): + text = original.decode() + assert before in text, (path, before) + path.write_text(text.replace(before, after)) + for phase in ['mutated', 'restored']: + if phase == 'restored': + for path, original in originals.items(): + path.write_bytes(original) + assert path.read_bytes() == original + for label, test in tests: + command = ['node', str(source / 'node_modules/vitest/vitest.mjs'), 'run', + 'tests/check-daemon-validation.test.ts', '-t', test] + result = subprocess.run(command, cwd=sdk, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + output = evidence / f'mutation-{name}-{label}-{phase}.txt' + output.write_text('$ ' + ' '.join(repr(arg) for arg in command) + '\n' + + f'cwd: {sdk}\n' + result.stdout + f'\nexit={result.returncode}\n') + print(f'{output.name}: exit={result.returncode}', flush=True) + assert (result.returncode != 0) if phase == 'mutated' else (result.returncode == 0) + for path, original in originals.items(): + print(f'Restored byte-for-byte: {path.relative_to(sdk)} sha256={hashlib.sha256(original).hexdigest()}', flush=True) diff --git a/evidence/daemon-check/mutations.txt b/evidence/daemon-check/mutations.txt new file mode 100644 index 000000000..9e6b22c6a --- /dev/null +++ b/evidence/daemon-check/mutations.txt @@ -0,0 +1,12 @@ +mutation-refusal-unit-mutated.txt: exit=1 +mutation-refusal-cli-mutated.txt: exit=1 +mutation-refusal-unit-restored.txt: exit=0 +mutation-refusal-cli-restored.txt: exit=0 +Restored byte-for-byte: src/daemon-spec-validation.ts sha256=3aac707c344f3b83a8cef39d47df4901635b071b5b34cecb0e06340a479eae4c +Restored byte-for-byte: dist/daemon-spec-validation.js sha256=16ff10bf6f1e3d2b3fe89000f85776d7b84d90f5c8aff81fd1ed3b3382d6f764 +mutation-indices-generated-mutated.txt: exit=1 +mutation-indices-authored-mutated.txt: exit=1 +mutation-indices-generated-restored.txt: exit=0 +mutation-indices-authored-restored.txt: exit=0 +Restored byte-for-byte: src/daemon-spec-validation.ts sha256=3aac707c344f3b83a8cef39d47df4901635b071b5b34cecb0e06340a479eae4c +Restored byte-for-byte: dist/daemon-spec-validation.js sha256=16ff10bf6f1e3d2b3fe89000f85776d7b84d90f5c8aff81fd1ed3b3382d6f764 diff --git a/evidence/daemon-check/package-gate.txt b/evidence/daemon-check/package-gate.txt new file mode 100644 index 000000000..d1a0ac78f --- /dev/null +++ b/evidence/daemon-check/package-gate.txt @@ -0,0 +1,28 @@ +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node scripts/pack-release.mjs surface /tmp/flows-cli-package-gXtQFF/tarballs +PACK_OK @relayflows/surface@2.0.42: package/dist/index.js, package/dist/index.d.ts, package/dist/runtime.js, package/dist/runtime.d.ts +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node scripts/pack-release.mjs sdk /tmp/flows-cli-package-gXtQFF/tarballs +PACK_OK @relayflows/sdk@2.0.42: package/dist/index.js, package/dist/index.d.ts, package/dist/cli.js +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node scripts/pack-release.mjs relayflows /tmp/flows-cli-package-gXtQFF/tarballs +PACK_OK relayflows@2.0.42: package/bin/flows.js +$ npm install --ignore-scripts --omit=optional --no-audit --no-fund /tmp/flows-cli-package-gXtQFF/tarballs/relayflows-2.0.42.tgz /tmp/flows-cli-package-gXtQFF/tarballs/relayflows-sdk-2.0.42.tgz /tmp/flows-cli-package-gXtQFF/tarballs/relayflows-surface-2.0.42.tgz + +added 150 packages in 10s +$ /tmp/flows-cli-package-gXtQFF/local/node_modules/.bin/flows check examples/dependency-upgrade-bot.flow.ts +REQUIRES claude (agent "upgrader") +CHECK PASSED examples/dependency-upgrade-bot.flow.ts [local only: authored body, so daemon acceptance is unproven] +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node /tmp/flows-cli-package-gXtQFF/local/node_modules/relayflows/bin/flows.js check examples/dependency-upgrade-bot.flow.ts +REQUIRES claude (agent "upgrader") +CHECK PASSED examples/dependency-upgrade-bot.flow.ts [local only: authored body, so daemon acceptance is unproven] +$ npm install -g --prefix /tmp/flows-cli-package-gXtQFF/prefix --ignore-scripts --omit=optional --no-audit --no-fund /tmp/flows-cli-package-gXtQFF/tarballs/relayflows-2.0.42.tgz /tmp/flows-cli-package-gXtQFF/tarballs/relayflows-sdk-2.0.42.tgz /tmp/flows-cli-package-gXtQFF/tarballs/relayflows-surface-2.0.42.tgz + +added 294 packages in 8s +$ npm install --ignore-scripts --omit=optional --no-audit --no-fund /tmp/flows-cli-package-gXtQFF/tarballs/relayflows-surface-2.0.42.tgz + +added 140 packages in 2s +$ /tmp/flows-cli-package-gXtQFF/prefix/bin/flows check examples/dependency-upgrade-bot.flow.ts +REQUIRES claude (agent "upgrader") +CHECK PASSED examples/dependency-upgrade-bot.flow.ts [local only: authored body, so daemon acceptance is unproven] +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node /tmp/flows-cli-package-gXtQFF/prefix/lib/node_modules/relayflows/bin/flows.js check examples/dependency-upgrade-bot.flow.ts +REQUIRES claude (agent "upgrader") +CHECK PASSED examples/dependency-upgrade-bot.flow.ts [local only: authored body, so daemon acceptance is unproven] +CLI_PACKAGE_OK: local and global installs diff --git a/evidence/daemon-check/plugin-extension-retry.txt b/evidence/daemon-check/plugin-extension-retry.txt new file mode 100644 index 000000000..d15fce1df --- /dev/null +++ b/evidence/daemon-check/plugin-extension-retry.txt @@ -0,0 +1,10 @@ + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + + ✓ tests/plugin-extension.test.ts (94 tests) 428ms + + Test Files 1 passed (1) + Tests 94 passed (94) + Start at 14:37:26 + Duration 2.84s (transform 1.47s, setup 26ms, collect 2.21s, tests 428ms, environment 0ms, prepare 44ms) + diff --git a/evidence/daemon-check/rust-targeted-final.txt b/evidence/daemon-check/rust-targeted-final.txt new file mode 100644 index 000000000..15614560c --- /dev/null +++ b/evidence/daemon-check/rust-targeted-final.txt @@ -0,0 +1,11 @@ + Compiling relayflowd v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd) + Finished `test` profile [unoptimized] target(s) in 0.19s + Running tests/validate_spec.rs (/tmp/relayflows-daemon-check-target/debug/deps/validate_spec-2e0369aa01bb2e19) + +running 3 tests +test refuses_unknown_field_with_kernel_location ... ok +test accepts_without_creating_data_directory_or_journal ... ok +test refuses_semantic_errors_and_malformed_json ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + diff --git a/evidence/daemon-check/rust-targeted-retry.txt b/evidence/daemon-check/rust-targeted-retry.txt new file mode 100644 index 000000000..d1b8ef29a --- /dev/null +++ b/evidence/daemon-check/rust-targeted-retry.txt @@ -0,0 +1,154 @@ + Compiling proc-macro2 v1.0.107 + Compiling quote v1.0.47 + Compiling unicode-ident v1.0.24 + Compiling libc v0.2.189 + Compiling cfg-if v1.0.4 + Compiling stable_deref_trait v1.2.1 + Compiling version_check v0.9.5 + Compiling autocfg v1.5.1 + Compiling serde_core v1.0.229 + Compiling num-traits v0.2.19 + Compiling getrandom v0.3.4 + Compiling zerocopy v0.8.56 + Compiling syn v3.0.4 + Compiling syn v2.0.119 + Compiling serde v1.0.229 + Compiling smallvec v1.15.2 + Compiling synstructure v0.13.2 + Compiling litemap v0.8.3 + Compiling zerofrom-derive v0.1.7 + Compiling yoke-derive v0.8.2 + Compiling zerofrom v0.1.8 + Compiling memchr v2.8.3 + Compiling yoke v0.8.3 + Compiling writeable v0.6.4 + Compiling num-integer v0.1.47 + Compiling generic-array v0.14.7 + Compiling icu_normalizer_data v2.3.0 + Compiling utf8_iter v1.0.4 + Compiling icu_properties_data v2.3.0 + Compiling parking_lot_core v0.9.12 + Compiling zmij v1.0.23 + Compiling zerovec-derive v0.11.6 + Compiling displaydoc v0.2.7 + Compiling serde_derive v1.0.229 + Compiling typenum v1.20.1 + Compiling zerotrie v0.2.5 + Compiling ref-cast v1.0.27 + Compiling zerovec v0.11.8 + Compiling ref-cast-impl v1.0.27 + Compiling num-bigint v0.4.8 + Compiling tinystr v0.8.4 + Compiling potential_utf v0.1.6 + Compiling icu_locale_core v2.3.0 + Compiling icu_collections v2.3.0 + Compiling aho-corasick v1.1.5 + Compiling icu_provider v2.3.1 + Compiling ahash v0.8.12 + Compiling regex-syntax v0.8.11 + Compiling once_cell v1.21.4 + Compiling shlex v2.0.1 + Compiling serde_json v1.0.151 + Compiling find-msvc-tools v0.1.11 + Compiling scopeguard v1.2.0 + Compiling lock_api v0.4.14 + Compiling cc v1.4.4 + Compiling icu_normalizer v2.3.0 + Compiling icu_properties v2.3.0 + Compiling num-rational v0.4.2 + Compiling regex-automata v0.4.18 + Compiling ppv-lite86 v0.2.21 + Compiling num-iter v0.1.46 + Compiling rand_core v0.9.5 + Compiling num-complex v0.4.6 + Compiling itoa v1.0.18 + Compiling pkg-config v0.3.34 + Compiling borrow-or-share v0.2.4 + Compiling bit-vec v0.8.0 + Compiling vcpkg v0.2.15 + Compiling bit-set v0.8.0 + Compiling fluent-uri v0.3.2 + Compiling num v0.4.3 + Compiling libsqlite3-sys v0.35.0 + Compiling rand_chacha v0.9.0 + Compiling idna_adapter v1.2.2 + Compiling parking_lot v0.12.5 + Compiling block-buffer v0.10.4 + Compiling crypto-common v0.1.7 + Compiling percent-encoding v2.3.2 + Compiling uuid v1.26.0 + Compiling utf8parse v0.2.2 + Compiling lazy_static v1.5.0 + Compiling foldhash v0.1.5 + Compiling thiserror v2.0.20 + Compiling bitflags v2.13.1 + Compiling vsimd v0.8.0 + Compiling outref v0.5.2 + Compiling hashbrown v0.15.5 + Compiling fraction v0.15.4 + Compiling uuid-simd v0.8.0 + Compiling anstyle-parse v1.0.0 + Compiling referencing v0.33.0 + Compiling fancy-regex v0.16.2 + Compiling regex v1.13.1 + Compiling digest v0.10.7 + Compiling rand v0.9.5 + Compiling idna v1.1.0 + Compiling email_address v0.2.9 + Compiling thiserror-impl v2.0.20 + Compiling cpufeatures v0.2.17 + Compiling is_terminal_polyfill v1.70.2 + Compiling anstyle-query v1.1.5 + Compiling num-cmp v0.1.0 + Compiling bytecount v0.6.9 + Compiling base64 v0.22.1 + Compiling colorchoice v1.0.5 + Compiling anstyle v1.0.14 + Compiling jsonschema v0.33.0 + Compiling anstream v1.0.0 + Compiling sha2 v0.10.9 + Compiling ulid v1.2.1 + Compiling hashlink v0.10.0 + Compiling ryu-js v1.0.3 + Compiling fallible-streaming-iterator v0.1.9 + Compiling fallible-iterator v0.3.0 + Compiling strsim v0.11.1 + Compiling anyhow v1.0.104 + Compiling clap_lex v1.1.0 + Compiling heck v0.5.0 + Compiling clap_builder v4.6.6 + Compiling clap_derive v4.6.4 + Compiling relayflowd-core v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd-core) + Compiling rustix v1.1.4 + Compiling getrandom v0.4.3 + Compiling clap v4.6.6 + Compiling wait-timeout v0.2.1 + Compiling linux-raw-sys v0.12.1 + Compiling fastrand v2.5.0 + Compiling tempfile v3.27.0 + Compiling rusqlite v0.37.0 + Compiling relayflowd-journal v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd-journal) + Compiling relayflowd v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd) + Finished `test` profile [unoptimized + debuginfo] target(s) in 18.85s + Running tests/validate_spec.rs (/tmp/relayflows-daemon-check-target/debug/deps/validate_spec-4ce5e52f28299220) + +running 3 tests +test refuses_unknown_field_with_kernel_location ... ok +test refuses_semantic_errors_and_malformed_json ... FAILED +test accepts_without_creating_data_directory_or_journal ... ok + +failures: + +---- refuses_semantic_errors_and_malformed_json stdout ---- + +thread 'refuses_semantic_errors_and_malformed_json' (23293) panicked at relayflowd/tests/validate_spec.rs:51:5: +assertion failed: verdict["error"]["message"].as_str().unwrap().contains("cwd") +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + +failures: + refuses_semantic_errors_and_malformed_json + +test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +error: test failed, to rerun pass `-p relayflowd --test validate_spec` diff --git a/evidence/daemon-check/rust-targeted.txt b/evidence/daemon-check/rust-targeted.txt new file mode 100644 index 000000000..2a284cb84 --- /dev/null +++ b/evidence/daemon-check/rust-targeted.txt @@ -0,0 +1,2 @@ +error: rustup could not choose a version of cargo to run, because one wasn't specified explicitly, and no default is configured. +help: run 'rustup default stable' to download the latest stable release of Rust and set it as your default toolchain. diff --git a/evidence/daemon-check/rust-workspace-retry.txt b/evidence/daemon-check/rust-workspace-retry.txt new file mode 100644 index 000000000..e6f2633d1 --- /dev/null +++ b/evidence/daemon-check/rust-workspace-retry.txt @@ -0,0 +1,673 @@ + Compiling proc-macro2 v1.0.107 + Compiling unicode-ident v1.0.24 + Compiling quote v1.0.47 + Compiling libc v0.2.189 + Compiling syn v3.0.4 + Compiling syn v2.0.119 + Compiling synstructure v0.13.2 + Compiling zerofrom-derive v0.1.7 + Compiling yoke-derive v0.8.2 + Compiling zerofrom v0.1.8 + Compiling cfg-if v1.0.4 + Compiling stable_deref_trait v1.2.1 + Compiling version_check v0.9.5 + Compiling zerovec-derive v0.11.6 + Compiling yoke v0.8.3 + Compiling autocfg v1.5.1 + Compiling num-traits v0.2.19 + Compiling displaydoc v0.2.7 + Compiling zerovec v0.11.8 + Compiling serde_core v1.0.229 + Compiling getrandom v0.3.4 + Compiling zerocopy v0.8.56 + Compiling serde v1.0.229 + Compiling smallvec v1.15.2 + Compiling tinystr v0.8.4 + Compiling serde_derive v1.0.229 + Compiling litemap v0.8.3 + Compiling memchr v2.8.3 + Compiling writeable v0.6.4 + Compiling icu_locale_core v2.3.0 + Compiling num-integer v0.1.47 + Compiling zerotrie v0.2.5 + Compiling potential_utf v0.1.6 + Compiling generic-array v0.14.7 + Compiling icu_normalizer_data v2.3.0 + Compiling utf8_iter v1.0.4 + Compiling icu_properties_data v2.3.0 + Compiling icu_collections v2.3.0 + Compiling icu_provider v2.3.1 + Compiling parking_lot_core v0.9.12 + Compiling zmij v1.0.23 + Compiling typenum v1.20.1 + Compiling ref-cast v1.0.27 + Compiling num-bigint v0.4.8 + Compiling aho-corasick v1.1.5 + Compiling ahash v0.8.12 + Compiling ref-cast-impl v1.0.27 + Compiling regex-syntax v0.8.11 + Compiling once_cell v1.21.4 + Compiling serde_json v1.0.151 + Compiling scopeguard v1.2.0 + Compiling lock_api v0.4.14 + Compiling num-rational v0.4.2 + Compiling icu_properties v2.3.0 + Compiling regex-automata v0.4.18 + Compiling icu_normalizer v2.3.0 + Compiling num-iter v0.1.46 + Compiling ppv-lite86 v0.2.21 + Compiling rand_core v0.9.5 + Compiling num-complex v0.4.6 + Compiling itoa v1.0.18 + Compiling borrow-or-share v0.2.4 + Compiling bit-vec v0.8.0 + Compiling bit-set v0.8.0 + Compiling fluent-uri v0.3.2 + Compiling num v0.4.3 + Compiling rand_chacha v0.9.0 + Compiling parking_lot v0.12.5 + Compiling idna_adapter v1.2.2 + Compiling block-buffer v0.10.4 + Compiling crypto-common v0.1.7 + Compiling outref v0.5.2 + Compiling percent-encoding v2.3.2 + Compiling uuid v1.26.0 + Compiling lazy_static v1.5.0 + Compiling thiserror v2.0.20 + Compiling vsimd v0.8.0 + Compiling fraction v0.15.4 + Compiling uuid-simd v0.8.0 + Compiling referencing v0.33.0 + Compiling digest v0.10.7 + Compiling idna v1.1.0 + Compiling rand v0.9.5 + Compiling fancy-regex v0.16.2 + Compiling regex v1.13.1 + Compiling email_address v0.2.9 + Compiling thiserror-impl v2.0.20 + Compiling cpufeatures v0.2.17 + Compiling num-cmp v0.1.0 + Compiling bytecount v0.6.9 + Compiling base64 v0.22.1 + Compiling jsonschema v0.33.0 + Compiling sha2 v0.10.9 + Compiling ulid v1.2.1 + Compiling ryu-js v1.0.3 + Compiling shlex v2.0.1 + Compiling find-msvc-tools v0.1.11 + Compiling cc v1.4.4 + Compiling pkg-config v0.3.34 + Compiling vcpkg v0.2.15 + Compiling relayflowd-core v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd-core) + Compiling libsqlite3-sys v0.35.0 + Compiling foldhash v0.1.5 + Compiling bitflags v2.13.1 + Compiling hashbrown v0.15.5 + Compiling hashlink v0.10.0 + Compiling fallible-streaming-iterator v0.1.9 + Compiling fallible-iterator v0.3.0 + Compiling utf8parse v0.2.2 + Compiling anstyle-parse v1.0.0 + Compiling anstyle v1.0.14 + Compiling colorchoice v1.0.5 + Compiling getrandom v0.4.3 + Compiling anstyle-query v1.1.5 + Compiling rustix v1.1.4 + Compiling is_terminal_polyfill v1.70.2 + Compiling anstream v1.0.0 + Compiling strsim v0.11.1 + Compiling clap_lex v1.1.0 + Compiling heck v0.5.0 + Compiling anyhow v1.0.104 + Compiling linux-raw-sys v0.12.1 + Compiling clap_derive v4.6.4 + Compiling rusqlite v0.37.0 + Compiling relayflowd-journal v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd-journal) + Compiling clap_builder v4.6.6 + Compiling fastrand v2.5.0 + Compiling tempfile v3.27.0 + Compiling wait-timeout v0.2.1 + Compiling clap v4.6.6 + Compiling relayflowd v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd) + Finished `test` profile [unoptimized] target(s) in 39.67s + Running unittests src/lib.rs (/tmp/relayflows-daemon-check-target/debug/deps/relayflowd-13dfe97f990f058a) + +running 64 tests +test engine::remote::worker_failure_detail_tests::a_non_string_output_is_rendered_rather_than_dropped ... ok +test engine::remote::worker_failure_detail_tests::a_null_or_blank_output_yields_no_detail ... ok +test engine::remote::worker_failure_detail_tests::a_string_output_is_carried_verbatim_and_trimmed ... ok +test engine::remote::worker_failure_detail_tests::an_output_at_the_boundary_is_not_truncated ... ok +test engine::boot_identity_tests::every_engine_in_this_process_shares_one_boot_id ... ok +test engine::remote::worker_failure_detail_tests::render_is_bounded_before_allocation_for_hostile_string ... ok +test engine::remote::worker_failure_detail_tests::truncation_does_not_split_a_multi_byte_char ... ok +test engine::remote::worker_failure_detail_tests::render_is_bounded_before_allocation_for_hostile_json ... ok +test engine::wake::claim_guard_tests::a_disarmed_guard_leaves_the_claim_alone ... ok +test engine::wake::claim_guard_tests::a_guard_only_releases_its_own_run ... ok +test engine::wake::claim_guard_tests::a_panic_between_claim_and_register_still_releases ... ok +test exec_det::tests::captures_deterministic_output ... ok +test exec_det::tests::failed_command_evidence_survives_completion ... ok +test engine::wake::claim_guard_tests::an_armed_guard_releases_the_claim_when_dropped ... ok +test engine::boot_identity_tests::prior_boot_registered_undriven_admission_is_recovered_by_start_retry ... ok +test exec_det::tests::timeout_has_an_explicit_completion_reason ... ok +test server::channels::tests::unknown_verb_never_falls_through_to_receive ... ok +test server::client::tests::resume_waits_while_the_heartbeat_renewed_lease_is_live ... ok +test server::liveness::tests::sweep_id_buckets_by_the_interval ... ok +test exec_det::tests::lease_override_bounds_execution_and_preserves_command_timeout ... ok +test server::liveness::tests::sweep_pass_healthy_subscription_is_a_noop ... ok +test server::liveness::tests::sweep_pass_latches_after_journaling_and_next_bucket_is_empty ... ok +test server::tests::a_lone_surrogate_in_a_request_is_refused_with_no_request_id ... ok +test engine::boot_identity_tests::failure_after_workspace_binding_releases_admission_without_exposing_effects ... ok +test server::tests::a_failed_disconnect_journal_append_is_retained_and_retried_not_dropped ... ok +test server::tests::agent::contract::a_transcript_digest_at_its_budget_rides_trajectory_tail_verbatim ... ok +test server::tests::agent::contract::an_agent_worker_attaching_without_pins_is_refused_at_attach ... ok +test server::tests::agent::contract::a_replacement_worker_that_never_reported_the_pinned_surface_is_not_dispatched_to ... ok +test server::tests::agent::contract::agent_without_a_compatible_worker_parks_without_starting ... ok +test server::tests::agent::contract::an_agent_worker_missing_a_declared_surface_parks_the_run_instead_of_erroring ... ok +test server::tests::agent::contract::an_oversized_trajectory_tail_is_refused_at_step_complete ... ok +test server::tests::agent::contract::an_llm_completion_claiming_an_effect_fails_closed_with_the_reason_journaled ... ok +test server::tests::agent::eligibility::required_streams_must_be_held_before_worker_registration ... ok +test server::tests::agent::eligibility::required_streams_keep_ordinary_steps_off_conversation_workers ... ok +test server::tests::agent::contract::human_intervention_is_durable_and_resume_requires_explicit_override ... ok +test server::tests::agent::pins::reset_worker_reporting_a_revision_other_than_its_pin_fails_closed_as_worker_error ... ok +test server::tests::agent::pins::consecutive_agent_steps_on_different_surfaces_each_start_from_their_own_pins ... ok +test server::tests::deterministic_marker_carrying_json_survives_reopen_and_refuses_changed_detail ... ok +test server::tests::dispatch_carries_the_lease_as_a_duration ... ok +test server::tests::heartbeat_cannot_revive_an_expired_assignment ... ok +test server::tests::heartbeat_carries_the_remaining_lease_as_a_duration ... ok +test server::tests::hello_enforces_protocol_version ... ok +test server::tests::run_resume_adopts_a_real_journal_whose_registry_row_is_missing ... ok +test server::tests::run_resume_asks_the_registry_instead_of_treating_an_orphan_file_as_a_run ... ok +test server::tests::run_resume_refuses_a_journal_that_never_recorded_its_run ... ok +test server::tests::run_resume_refuses_a_valid_journal_that_belongs_to_another_run ... ok +test server::tests::run_start_admission_key_recovers_the_same_run_and_refuses_spec_drift ... ok +test server::tests::run_start_fails_closed_on_an_unknown_verification_key ... ok +test server::tests::run_start_refuses_invalid_admission_keys ... ok +test server::tests::run_start_watch_replays_an_existing_admission ... ok +test exec_det::tests::timeout_kills_the_whole_process_group ... ok +test server::tests::run_start_watch_rolls_back_after_journal_creation_failure ... ok +test server::tests::run_start_watch_streams_while_the_step_is_still_blocked ... ok +test server::tests::run_start_without_watch_pushes_no_entries ... ok +test server::tests::step_wait_parks_the_attempt_and_a_human_answer_redispatches_it ... ok +test server::tests::stopped_heartbeats_past_the_deadline_journal_lease_expired_and_release_the_step ... ok +test server::tests::subscription_router::targeted_router_verbs_validate_receipts_and_preserve_wire_metadata ... ok +test socket_path::tests::deep_data_dir_produces_short_socket_path ... ok +test socket_path::tests::different_data_dirs_yield_different_sockets ... ok +test socket_path::tests::relative_and_absolute_data_dirs_agree ... ok +test socket_path::tests::same_data_dir_yields_same_socket ... ok +test server::tests::agent::pins::a_replacement_worker_at_a_different_revision_is_not_dispatched_the_stale_pins ... ok +test server::tests::an_entry_appended_during_watch_registration_is_delivered_exactly_once ... ok +test server::tests::run_start_with_watch_streams_every_entry_once_before_the_result ... ok + +test result: ok. 64 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.80s + + Running unittests src/main.rs (/tmp/relayflows-daemon-check-target/debug/deps/relayflowd-d2dbf0e59b908ab1) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/advisory_deterministic.rs (/tmp/relayflows-daemon-check-target/debug/deps/advisory_deterministic-52e5f5ab30ba37d1) + +running 2 tests +test the_same_flow_without_the_declaration_still_fails_and_never_reaches_the_dependent ... ok +test a_recorded_red_step_completes_and_hands_its_exit_code_to_the_next_step ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s + + Running tests/budget_gate.rs (/tmp/relayflows-daemon-check-target/debug/deps/budget_gate-01a7a3cdccc1d405) + +running 13 tests +test carried_metered_dollars_still_stop_the_continuing_run ... ok +test a_malformed_reported_cost_is_refused ... ok +test daily_windows_reset_and_exact_limits_do_not_refuse ... ok +test carried_prior_spend_keeps_unknown_dollar_cost_unmetered ... ok +test metering_flag_is_additive_on_the_wire ... ok +test prior_spend_metering_flag_is_additive_and_fails_closed_for_older_kernels ... ok +test a_no_model_cost_must_be_zero ... ok +test reported_cost_is_journaled_but_never_charged_to_the_budget ... ok +test crossing_completion_is_durable_and_next_step_is_refused ... ok +test unmetered_spend_is_journaled_as_unknown_and_never_crosses_a_dollar_ceiling ... ok +test deterministic_spend_and_wallclock_limit_gate_parallel_batch_starts ... ok +test unmetered_tokens_still_cross_a_token_ceiling ... ok +test unmetered_usage_may_not_claim_priced_dollars ... ok + +test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s + + Running tests/crash_resume.rs (/tmp/relayflows-daemon-check-target/debug/deps/crash_resume-5c6cdbba9e81e4b8) + +running 41 tests +test agent::resume_without_a_worker_parks_immediately_instead_of_timing_out ... ok +test agent::rung_c_sigkill_after_final_effect_replays_results_without_redispatch ... ok +test agent::rung_c_reset_sigkill_mid_edit_restores_pins_dedupes_effect_and_explains_attempts ... ok +test agent::rung_c_crash_between_effect_election_and_the_provider_call_performs_it_exactly_once ... ok +test agent::rung_c_sigkill_between_agent_completion_and_final_effect_memoizes_the_agent ... ok +test channels::channels_reject_foreign_workers_stale_attempts_and_invalid_acknowledgements ... ok +test concurrency::cancel_and_completion_race_has_one_terminal_fact ... ok +test agent::rung_c_sigkill_boundaries_resume_only_unfinished_steps_via_real_cli ... ok +test concurrency::cancel_closes_the_lease_and_rejects_a_late_completion ... ok +test concurrency::concurrent_resumes_lease_exactly_one_attempt ... ok +test concurrency::run_start_dispatches_every_independent_lane_before_any_completion ... ok +test concurrency::live_resume_leaves_an_active_lease_running ... ok +test concurrency::server_restart_recovers_every_parallel_lease_without_duplicate_success ... ok +test llm::completed_llm_output_is_memoized_when_serve_dies_during_the_next_step ... ok +test llm::failing_llm_verification_schedules_a_durable_retry_and_succeeds ... ok +test llm::llm_verification_exhaustion_is_a_declared_failure_kind ... ok +test llm::serve_plumbs_watch_events_and_replayable_stream_verbs ... ok +test llm::sigkill_after_the_final_rung_b_effect_resumes_without_redispatching_llm ... ok +test llm::sigkill_under_serve_mid_llm_releases_the_lease_and_finishes_via_cli_resume ... ok +test llm::worker_killed_while_holding_a_lease_is_explained_and_released_on_cli_resume ... ok +test channels::channels_sigkill_resume_redelivers_unacked_messages_with_exactly_once_effects ... ok +test llm::sigkill_sweep_covers_before_and_between_the_rung_b_steps ... ok +test memory::memory_sigkill_after_injection_replays_pack_and_charges_it_once ... ok +test parallel_lifecycle::overlapping_agent_conflict_survives_server_crash_and_resume ... ok +test parallel_lifecycle::terminal_failure_drains_or_explains_every_live_sibling ... ok +test parallel_lifecycle::overlapping_agent_lanes_serialize_while_disjoint_lanes_merge_in_either_order ... ok +test pin_projection::rejected_completion_cannot_forge_pins_or_trigger_a_blind_retry ... ok +test placement::declared_placement_keeps_one_source_tree_across_resume ... ok +test placement::sigkill_before_first_step_preserves_the_submitted_workspace ... ok +test protocol_admission::every_mutating_run_verb_refuses_terminal_before_changing_state ... ok +test placement::sigkill_mid_step_keeps_the_route_and_source_tree ... ok +test sigkill_after_cancel_request_resumes_to_one_canceled_fact ... ok +test sigkill_mid_step_replaces_and_explains_the_dead_attempt ... ok +test sigkill_under_serve_resumes_the_socket_started_run ... ok +test surface_identity::aliases_are_rejected_and_external_ancestors_serialize_over_real_sockets ... ok +test sigkill_sweep_covers_every_hello_step_boundary ... ok +test worker_capacity::two_workers_receive_a_deterministic_fair_capacity_bounded_batch ... ok +test worker_capacity::default_capacity_one_reopens_only_after_durable_completion_or_crash ... ok +test workspace_identity::workspace_aliases_are_refused_and_canonical_subtrees_serialize_over_real_sockets ... ok +test manual_recovery::manual_recovery_parks_a_worker_reported_loss_across_daemon_restart_until_a_human_answers ... ok +test parallel_lifecycle::renewed_parallel_leases_survive_the_original_grant_and_remain_distinct ... ok + +test result: ok. 41 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 37.28s + + Running tests/daemon_lifecycle.rs (/tmp/relayflows-daemon-check-target/debug/deps/daemon_lifecycle-a08dcc505b577e02) + +running 6 tests +test clean_shutdown_removes_advertisement_and_socket ... ok +test connection_file_is_published_only_after_the_socket_is_live ... ok +test a_second_serve_on_a_served_data_dir_refuses_and_the_first_keeps_serving ... ok +test deep_data_dir_still_binds ... ok +test sigkill_leaves_a_stale_file_with_a_dead_pid ... ok +test a_sigkilled_daemons_successor_starts_cleanly ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/event_activities.rs (/tmp/relayflows-daemon-check-target/debug/deps/event_activities-624e7d20b49b7b97) + +running 12 tests +test exact_deadline_tie_wins_and_reports_unread_range ... ok +test cancel_closes_an_open_activity_before_the_terminal_run_record ... ok +test accepted_append_is_buffered_deduplicated_and_survives_a_restart_before_next ... ok +test closing_over_a_suspended_pull_reports_closed_live_and_on_replay ... ok +test idle_wait_is_durable_and_fires_without_an_event ... ok +test immediate_event_wakes_have_durable_distinct_wait_boundaries ... ok +test normal_wake_is_not_acknowledged_until_the_following_next ... ok +test overflow_of_a_parked_next_returns_overflow_after_recovery ... ok +test prepared_open_response_replays_the_immutable_binding_snapshot ... ok +test prepared_binding_stays_invisible_across_a_crash_until_activation_then_next_suspends ... ok +test remaining_event_await_acceptance_cases_use_the_real_journal ... ok +test overflow_closes_before_the_1001st_unread_frame_and_recovery_never_reopens_it ... ok + +test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 17.53s + + Running tests/event_activity_corruption.rs (/tmp/relayflows-daemon-check-target/debug/deps/event_activity_corruption-eff5b0a2a8c71875) + +running 3 tests +test a_completed_event_range_cannot_replay_with_missing_frames ... ok +test malformed_stream_frames_fail_replay_and_future_append ... ok +test malformed_deadline_range_is_an_error_while_null_is_an_empty_range ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/event_activity_parking.rs (/tmp/relayflows-daemon-check-target/debug/deps/event_activity_parking-350e689f8f4944ae) + +running 4 tests +test replay_keeps_each_acknowledged_batch_addressable_by_body_call_ordinal ... ok +test intentional_close_cancels_the_pending_pull_without_claiming_a_timeout ... ok +test activation_and_delivery_racing_the_lease_handoff_are_not_lost ... ok +test parked_attempt_survives_restart_and_only_a_ready_subscription_redispatches_it ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.12s + + Running tests/event_wake.rs (/tmp/relayflows-daemon-check-target/debug/deps/event_wake-04f05876d87f6739) + +running 3 tests +test two_racing_deliveries_of_one_event_produce_exactly_one_run ... ok +test matching_event_wakes_once_with_fresh_context ... ok +test a_resumed_run_dispatches_the_original_wake_context ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/hn_monitor_integration.rs (/tmp/relayflows-daemon-check-target/debug/deps/hn_monitor_integration-a2744610dee58931) + +running 1 test +test hn_story_event_wakes_monitor_once_with_story_context ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s + + Running tests/input_binding.rs (/tmp/relayflows-daemon-check-target/debug/deps/input_binding-f42ebaaabfc91472) + +running 2 tests +test binding_schema_is_additive_and_fails_closed ... ok +test sigkill_before_consumer_resolves_original_journal_output_without_reexecuting_source ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s + + Running tests/invalid_schema_preflight.rs (/tmp/relayflows-daemon-check-target/debug/deps/invalid_schema_preflight-b36033d141e968b9) + +running 3 tests +test invalid_json_schema_is_refused_before_journal_or_command ... ok +test unbounded_json_schema_is_refused_before_journal_or_command ... ok +test legitimately_recursive_json_schema_still_starts ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.75s + + Running tests/late_start.rs (/tmp/relayflows-daemon-check-target/debug/deps/late_start-b29c98e96656cb46) + +running 2 tests +test a_dispatch_after_a_slow_deterministic_peer_keeps_its_full_lease ... ok +test a_start_after_a_slow_deterministic_peer_is_stamped_when_journaled ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.42s + + Running tests/manual_recovery.rs (/tmp/relayflows-daemon-check-target/debug/deps/manual_recovery-cd563a126daa15c0) + +running 2 tests +test a_park_torn_between_its_two_appends_is_repaired_on_resume ... ok +test manual_park_of_a_worker_reported_loss_survives_reopen_and_answers_to_a_human ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s + + Running tests/memoization.rs (/tmp/relayflows-daemon-check-target/debug/deps/memoization-f0f02cfb410d0ee2) + +running 3 tests +test refuses_missing_wrong_flow_and_unreadable_journal_before_creating_run ... ok +test actual_changed_input_invalidates_consumer_even_with_identical_consumer_spec ... ok +test reused_prefix_survives_restart_without_source_and_never_mutates_prior ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s + + Running tests/memory.rs (/tmp/relayflows-daemon-check-target/debug/deps/memory-0b00ea075eed4e8b) + +running 5 tests +test rejected_journal_fact_releases_reservation_and_never_dispatches ... ok +test llm_dispatch_receives_same_pack_after_resume_without_provider ... ok +test replay_and_resume_need_no_provider_and_script_receives_recorded_pack ... ok +test over_budget_and_provider_errors_fail_without_dispatch_or_charge ... ok +test semantic_retry_reuses_memory_without_a_second_charge ... ok + +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s + + Running tests/memory_epoch.rs (/tmp/relayflows-daemon-check-target/debug/deps/memory_epoch-4bcca4b86db44191) + +running 1 test +test epoch_carries_pack_and_exact_charge_and_refuses_duplicate_injection ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/parallel_driver.rs (/tmp/relayflows-daemon-check-target/debug/deps/parallel_driver-70f9e44889e2d0fb) + +running 4 tests +test stop_after_one_holds_for_an_independent_deterministic_batch ... ok +test pause_before_second_independent_step_holds_the_driver_boundary ... ok +test backpressured_or_mismatched_lane_does_not_drop_a_later_dispatch ... ok +test crash_boundaries_resume_the_real_driver_with_one_effect_per_lane ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14s + + Running tests/placement_pins.rs (/tmp/relayflows-daemon-check-target/debug/deps/placement_pins-174eccde3f6442f5) + +running 3 tests +test unsupported_local_pty_is_refused_before_an_earlier_step_can_run ... ok +test default_worker_pins_the_declared_worktree_base_commit_and_refuses_missing_source ... ok +test a_resumed_attempt_keeps_the_original_pin_after_the_worktree_head_moves ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/placement_routing.rs (/tmp/relayflows-daemon-check-target/debug/deps/placement_routing-3ea06dbd1e6c4986) + +running 3 tests +test a_failed_routing_append_never_starts_or_dispatches_work ... ok +test crash_between_routing_and_start_does_not_redecide ... ok +test worker_retry_consumes_the_original_routing_fact ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/routing_diagnostics.rs (/tmp/relayflows-daemon-check-target/debug/deps/routing_diagnostics-914a18e812529456) + +running 2 tests +test duplicate_routes_have_a_distinct_diagnostic_and_leave_the_original_fact_intact ... ok +test malformed_routes_name_the_same_field_at_append_replay_and_epoch_replay ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/spec_review_routing.rs (/tmp/relayflows-daemon-check-target/debug/deps/spec_review_routing-65bfdbb3b9e5faa8) + +running 4 tests +test attempt_scoped_route_is_rejected_at_append_and_replay ... ok +test malformed_epoch_routes_are_rejected_before_commit ... ok +test epoch_cannot_drop_or_replace_a_durable_route ... ok +test workspace_pin_peels_tags_and_refuses_non_commit_objects ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/subscription_liveness.rs (/tmp/relayflows-daemon-check-target/debug/deps/subscription_liveness-a97a9e8927d09ddc) + +running 3 tests +test submit_event_upserts_subscription_row_and_sweep_flags_it_stale_after_budget ... ok +test stale_transition_is_journaled_as_subscription_stale_entry_in_the_last_known_run ... ok +test a_fresh_arrival_re_arms_the_latch_and_the_next_silence_can_stale_again ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/subscription_router_delivery.rs (/tmp/relayflows-daemon-check-target/debug/deps/subscription_router_delivery-be595dc13bf9f1ba) + +running 5 tests +test canceling_a_run_closes_a_prepared_only_subscription_once_and_reports_it_closed ... ok +test inspect_reports_exactly_one_snapshot_per_subscription_across_its_lifecycle ... ok +test router_snapshots_keep_absolute_timers_and_overflow_fence_across_restart ... ok +test targeted_ingress_is_fenced_deduplicated_and_isolated_after_restart ... ok +test a_fence_torn_from_its_close_refuses_ingress_and_is_completed_once_on_retry_or_resume ... ok + +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.13s + + Running tests/trigger_watcher.rs (/tmp/relayflows-daemon-check-target/debug/deps/trigger_watcher-961678fadacec577) + +running 3 tests +test retains_bad_and_unregistered_events_while_consuming_filter_nonmatches ... ok +test failed_archive_retries_the_same_durable_run ... ok +test journals_payload_and_filename_key_then_archives_and_dedupes_replay ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/validate_spec.rs (/tmp/relayflows-daemon-check-target/debug/deps/validate_spec-2e0369aa01bb2e19) + +running 3 tests +test refuses_unknown_field_with_kernel_location ... ok +test refuses_semantic_errors_and_malformed_json ... ok +test accepts_without_creating_data_directory_or_journal ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running unittests src/lib.rs (/tmp/relayflows-daemon-check-target/debug/deps/relayflowd_core-d431620b728b692b) + +running 86 tests +test channel::tests::delivery_replay_and_independent_acknowledged_offsets ... ok +test channel::tests::malformed_payloads_and_invalid_new_channel_appends_leave_state_unchanged ... ok +test channel::tests::forged_deliveries_and_acknowledgements_fail_closed ... ok +test channel::tests::send_retry_is_stable_and_conflicting_content_is_rejected ... ok +test clock::tests::simulated_clock_is_explicitly_advanced ... ok +test entry::attempt_started_tests::a_pre_field_attempt_started_still_reads ... ok +test entry::attempt_started_tests::max_transport_retries_is_always_journaled ... ok +test entry::completion_reason_tests::all_covers_every_serialized_label ... ok +test entry::completion_reason_tests::every_journal_label_matches_serialized ... ok +test entry::reported_cost_tests::step_completed_without_reported_cost_round_trips_unchanged ... ok +test journal::tests::memory_journal_assigns_sequences_and_rolls_epochs ... ok +test machine::parallel_tests::every_declared_mutable_surface_participates_in_conflict_selection ... ok +test machine::parallel_tests::external_ancestor_and_descendant_paths_conflict_but_siblings_do_not ... ok +test machine::parallel_tests::crash_resume_preserves_each_parallel_lease_exactly_once ... ok +test machine::parallel_tests::disjoint_agent_lanes_merge_pins_in_either_completion_order ... ok +test machine::parallel_tests::machine_starts_every_runnable_step_in_authored_order ... ok +test machine::parallel_tests::failed_run_drains_open_siblings_before_terminal_entry ... ok +test machine::parallel_tests::overlapping_agent_surfaces_are_serialized_in_authored_order ... ok +test machine::parallel_tests::parallel_lanes_do_not_cross_the_dependency_barrier_early ... ok +test machine::parallel_tests::workspace_ancestor_and_descendant_paths_conflict_but_siblings_do_not ... ok +test machine::tests::a_retryable_worker_reported_reason_is_not_rewritten_by_the_retry_branch ... ok +test machine::recovery_tests::manual_recovery_parks_a_worker_reported_transport_loss_instead_of_redispatching ... ok +test machine::recovery_tests::recovery_journals_the_wait_human_a_torn_manual_park_never_wrote ... ok +test machine::recovery_tests::reset_recovery_still_retries_a_worker_reported_transport_loss ... ok +test machine::tests::all_backing_off_steps_return_timers ... ok +test machine::tests::cancel_request_closes_the_active_lease_before_the_terminal_fact ... ok +test machine::tests::deterministic_lease_rejects_invalid_and_foreign_fields ... ok +test machine::tests::deterministic_lease_override_and_default_are_journaled ... ok +test machine::tests::crashed_attempt_does_not_consume_an_iteration ... ok +test machine::tests::classified_transport_retry_is_bounded_and_preserves_pin_and_idempotency ... ok +test machine::tests::durable_cancel_request_outranks_crash_recovery ... ok +test machine::tests::each_failed_attempt_journals_its_own_output_beside_an_identical_verdict ... ok +test machine::tests::every_reason_label_matches_its_serialized_form ... ok +test machine::tests::failed_deterministic_completion_preserves_exit_code_and_stderr ... ok +test machine::tests::machine_starts_runnable_step_with_stable_effect_key ... ok +test machine::tests::every_failed_run_terminates_with_declared_completion_reasons ... ok +test machine::tests::ordinary_worker_error_is_not_retried_by_either_budget ... ok +test machine::tests::manual_recovery_parks_needs_human_and_never_redispatches ... ok +test machine::tests::repeated_cancel_request_is_idempotent ... ok +test machine::tests::inspect_recovery_injects_the_dirty_pin_completion_reason_and_tail ... ok +test machine::tests::refused_dispatch_is_re_elected_within_max_iterations_only ... ok +test machine::tests::successful_memo_is_never_scheduled_again ... ok +test machine::tests::the_exhaustion_label_replaces_verification_failed_over_identical_evidence ... ok +test machine::tests::worker_reported_failure_without_detail_still_records_a_verification ... ok +test machine::tests::verification_failure_schedules_a_durable_retry ... ok +test machine::tests::reset_recovery_dispatches_the_original_pinned_revision ... ok +test memory::tests::caps_compare_exact_decimals_and_each_token_dimension ... ok +test retry::tests::jitter_is_repeatable_and_bounded ... ok +test schema::tests::a_property_named_ref_is_not_a_reference ... ok +test schema::tests::in_document_uri_references_resolve_to_the_node_they_name ... ok +test schema::tests::references_the_bound_leaves_opaque_are_refused_by_the_engine ... ok +test schema::tests::refusal_names_the_cycle_it_found ... ok +test schema::tests::shared_declarations_and_boolean_schemas_are_validated ... ok +test spec::tests::a_misspelled_step_level_key_is_a_parse_error ... ok +test spec::tests::a_misspelled_verification_gate_key_is_a_parse_error_not_a_dropped_gate ... ok +test spec::tests::agent_cwd_is_carried_and_must_be_run_root_relative ... ok +test spec::tests::agent_without_cwd_hashes_as_before ... ok +test spec::tests::cli_identity_is_internal_to_provider_steps ... ok +test spec::tests::cycles_are_rejected ... ok +test spec::tests::external_surface_paths_must_have_one_canonical_spelling ... ok +test spec::tests::on_non_zero_parses_the_two_declared_policies_and_refuses_anything_else ... ok +test spec::tests::preflight_data_is_fail_closed ... ok +test schema::tests::every_accepted_corpus_schema_is_accepted ... ok +test schema::tests::every_refused_corpus_schema_compiles_but_is_refused_by_the_bound ... ok +test spec::tests::spec_version_is_semver_and_gated ... ok +test spec::tests::the_default_policy_is_absent_from_the_serialized_boundary_spec ... ok +test spec::tests::the_full_ladder_parses_in_the_one_dialect ... ok +test spec::tests::unknown_root_and_nested_fields_are_rejected ... ok +test spec::tests::workspace_mounts_and_worktrees_must_have_one_canonical_spelling ... ok +test spec::tests::zero_agent_flow_is_valid ... ok +test state::budget::tests::adds_costs_exactly_beyond_machine_decimal_precision ... ok +test state::budget::tests::overflow_and_malformed_cost_leave_total_unchanged ... ok +test state::tests::a_completion_that_omits_a_surface_does_not_drop_it_from_the_pin_chain ... ok +test state::tests::budget_decimal_strings_add_without_floats ... ok +test state::tests::end_pin_chain_is_enforced_and_a_broken_chain_is_a_hard_error ... ok +test state::tests::journal_replays_data_gate_verdict_without_rerunning_completed_code ... ok +test verify::tests::a_recorded_nonzero_exit_passes_its_gate_and_names_the_code ... ok +test verify::tests::an_unbounded_schema_in_a_journal_fails_its_gate_instead_of_aborting ... ok +test verify::tests::deterministic_output_requires_successful_exit_and_content ... ok +test verify::tests::json_schema_is_a_control_gate ... ok +test verify::tests::recording_an_exit_code_does_not_relax_a_declared_content_gate ... ok +test verify::tests::recording_does_not_absorb_a_missing_or_sentinel_exit_status ... ok +test verify::tests::the_default_policy_still_fails_a_nonzero_exit ... ok +test spec::tests::sdk_boundary_accepts_a_valid_10_000_step_reverse_chain ... ok +test spec::tests::sdk_boundary_rejects_a_10_000_step_cycle_with_a_typed_error ... ok +test schema::tests::deeply_nested_schemas_do_not_overflow_the_checker ... ok + +test result: ok. 86 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.89s + + Running tests/memoization.rs (/tmp/relayflows-daemon-check-target/debug/deps/memoization-80e876e725c6a1a4) + +running 4 tests +test distinct_large_kernel_integers_do_not_alias_through_float_rounding ... ok +test match_reuses_output_with_provenance_and_zero_cost_without_dispatch ... ok +test changed_spec_or_input_dispatches_and_legacy_or_failed_records_miss ... ok +test canonical_corpus_agrees_with_typescript_and_key_permutations ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/spec_parity.rs (/tmp/relayflows-daemon-check-target/debug/deps/spec_parity-0655a83e180272d9) + +running 18 tests +test agent_cwd_is_not_accepted_on_other_verbs_or_under_another_name ... ok +test a_non_string_agent_cwd_fails_closed_rather_than_defaulting ... ok +test agent_timeout_bounds_match_the_kernel_corpus ... ok +test an_undeclared_agent_cwd_is_not_serialized ... ok +test agent_timeout_has_identical_canonical_bytes_and_hash ... ok +test agent_cwd_declaration_acceptance_matches_the_sdk_corpus ... ok +test memory_declaration_acceptance_matches_the_sdk_corpus ... ok +test placement_requirements_have_identical_canonical_bytes_and_hash ... ok +test agent_working_directories_have_identical_canonical_bytes_and_hash ... ok +test the_kernel_parses_the_deterministic_rung_and_stamps_the_same_hash ... ok +test step_memory_has_identical_canonical_bytes_and_hash ... ok +test placement_declaration_acceptance_matches_the_sdk_corpus ... ok +test the_kernel_parses_the_event_triggered_spec_and_stamps_the_same_hash ... ok +test the_kernel_parses_the_rung_c_agent_spec_and_stamps_the_same_hash ... ok +test the_kernel_round_trips_declared_agent_transports_and_rejects_unknown_values ... ok +test the_kernel_parses_the_sdk_compiled_spec_and_stamps_the_same_hash ... ok +test the_kernel_parses_the_rung_b_spec_and_stamps_the_same_hash ... ok +test the_kernel_parses_the_advisory_repair_spec_and_stamps_the_same_hash ... ok + +test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running unittests src/lib.rs (/tmp/relayflows-daemon-check-target/debug/deps/relayflowd_journal-4910689de8b32a5a) + +running 32 tests +test channel::tests::stale_attempts_and_raw_forged_acknowledgements_cannot_change_offsets ... ok +test channel::tests::channels_cross_segment_boundaries_and_terminal_runs_reject_mutations ... ok +test registry::tests::a_pre_migration_registry_gains_boot_id_and_its_claims_are_repairable ... ok +test channel::tests::failed_channel_writes_never_expose_delivery_or_advance_acknowledged_offset ... ok +test registry::tests::a_previous_boots_claim_with_no_run_is_repaired ... ok +test registry::tests::a_registered_run_dedupes_across_boots ... ok +test registry::tests::a_same_boot_claim_with_no_run_yet_is_a_duplicate_not_wreckage ... ok +test registry::tests::concurrent_new_boot_retries_have_one_recovery_owner ... ok +test registry::tests::prior_boot_unregistered_run_admission_is_repaired ... ok +test registry::tests::concurrent_same_boot_run_admissions_have_one_owner ... ok +test registry::tests::registry_is_a_rebuildable_run_locator ... ok +test registry::tests::releasing_a_claim_lets_the_same_boot_retry ... ok +test registry::tests::releasing_is_scoped_to_the_claiming_run ... ok +test registry::tests::run_admission_reuses_registered_run_and_rejects_spec_drift ... ok +test subscriptions::tests::detect_without_latch_stays_available_for_the_next_sweep ... ok +test subscriptions::tests::last_run_for_subscription_returns_none_before_first_arrival ... ok +test subscriptions::tests::last_run_for_subscription_returns_the_lex_greatest_ulid_regardless_of_insertion ... ok +test subscriptions::tests::prune_sweep_claims_deletes_only_rows_older_than_cutoff ... ok +test subscriptions::tests::latch_is_a_no_op_if_a_fresh_event_arrived_between_detect_and_latch ... ok +test subscriptions::tests::sweep_does_not_re_emit_the_same_stale_row_on_a_later_tick ... ok +test subscriptions::tests::sweep_ignores_subscriptions_whose_silence_is_still_within_budget ... ok +test subscriptions::tests::sweep_election_gives_the_first_caller_the_result_and_second_gets_empty ... ok +test subscriptions::tests::sweep_marks_row_stale_when_silence_exceeds_budget ... ok +test subscriptions::tests::upsert_after_stale_re_arms_and_next_silence_can_re_emit ... ok +test subscriptions::tests::upsert_is_idempotent_across_bumps_and_preserves_event_type_updates ... ok +test tests::append_is_durable_and_monotonic_after_reopen ... ok +test tests::an_unconfirmed_election_is_reclaimed_by_the_next_attempt_not_treated_as_done ... ok +test tests::effects_are_deduplicated_at_the_journal_boundary ... ok +test tests::failed_commit_is_returned_not_swallowed ... ok +test tests::rollover_is_atomic_scaffolding_for_epoch_resume ... ok +test tests::terminal_run_refuses_every_later_entry_atomically ... ok +test channel::tests::independent_connections_serialize_send_receive_and_acknowledgement ... ok + +test result: ok. 32 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.28s + + Doc-tests relayflowd + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests relayflowd_core + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests relayflowd_journal + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + diff --git a/evidence/daemon-check/rust-workspace.txt b/evidence/daemon-check/rust-workspace.txt new file mode 100644 index 000000000..7c8d438b3 --- /dev/null +++ b/evidence/daemon-check/rust-workspace.txt @@ -0,0 +1,42 @@ + Compiling relayflowd-core v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd-core) + Compiling relayflowd-journal v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd-journal) + Compiling relayflowd v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd) +error: linking with `cc` failed: exit status: 1 + | + = note: "cc" "-m64" "/tmp/relayflows-daemon-check-target/debug/deps/rustcadSFU0/symbols.o" "<65 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/tmp/relayflows-daemon-check-target/debug/deps/{libtempfile-9536fa684b3153e7,libgetrandom-4b55eae43c41b808,libfastrand-c3dd370172903a25,librustix-ac99c31c323027d8,liblinux_raw_sys-6909a3bb65c2afb1}.rlib" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libtest-*,libgetopts-*,librustc_std_workspace_std-*}.rlib" "/tmp/relayflows-daemon-check-target/debug/deps/{librelayflowd-982eee23c6fa573f,libwait_timeout-d662a9a2f10eb8f0,librelayflowd_journal-732b611254b6de12,librusqlite-ab0fc325ee05c8a7,libbitflags-9100470b2f2ecebc,libhashlink-c9f6fe959c0b48b6,libhashbrown-1c2bb10fc4ea0603,libfoldhash-2b11b30984b507d4,liblibsqlite3_sys-3752f73801891bb3,libfallible_streaming_iterator-a347b7ef8b80f8d8,libfallible_iterator-27e9842272616c44,libanyhow-95160b83a69d28f1,librelayflowd_core-4dee9ff709ccce6a,libryu_js-379fee581d4e4cf6,libjsonschema-1346d624d341b04b,libbytecount-b25e5171a2633f4e,libregex-410ffc66da49fa09,libidna-e94098e37dc02e73,libidna_adapter-988b373e3ea8033e,libicu_properties-050075a714712b80,libicu_properties_data-dc1ccafdd0d637be,libicu_normalizer-63735c110f076c93,libicu_normalizer_data-33689e7acd25cef2,libicu_collections-d7a59cc03624c389,libutf8_iter-599cfec92559ec54,libpotential_utf-9887f2172f111fd9,libicu_provider-564c1d1fc8d08098,libicu_locale_core-a0a916db6ad389b8,libtinystr-38fd63dfef755d6c,liblitemap-dbf974391a511422,libwriteable-5abcc97df5a65912,libzerovec-900082f3c6916124,libzerotrie-8180931e727bd3ce,libyoke-b47f4278c3d13e58,libstable_deref_trait-bf6ee564ab40ea72,libzerofrom-f9ebfa44f9874bc4,libuuid_simd-30e6fe3a290737a1,libuuid-e8fa9dc5c3716442,liboutref-12add1ee7a41ce58,libvsimd-8588db60a425d5f5,libfancy_regex-f5424de6cb149387,libbit_set-ecbd1f809b659a1a,libbit_vec-2dde4e28e53e1e30,libregex_automata-30b727269a1ac78e,libaho_corasick-84481b7457a84fc2,libemail_address-fa9206456703cee3,libfraction-2366378c72c2df44,liblazy_static-e89dfa456fdef5b8,libnum-2b36d6f665b1efb1,libnum_iter-b45c706e3750f11b,libnum_rational-5a3e5bdb340b978b,libnum_complex-df5794162c1ed6d0,libnum_bigint-b48bf0e502f65e24,libnum_integer-ef150102445ba2a4,libnum_traits-e9cfbafadb0db7e3,libnum_cmp-e1600a8c1cfbeb5c,libregex_syntax-1e55c064ae9af1da,libbase64-6ee8ec72165049e2,libreferencing-a0b1881a1961e55a,libpercent_encoding-0afa79f3260a3d39,libparking_lot-4033cdce020a10a2,libparking_lot_core-c997a008dfcf686a,libsmallvec-a1337c150357a38d,liblock_api-052372b6b50f420c,libscopeguard-dd7e42edb450752a,libfluent_uri-dda813dd8b9adace,libborrow_or_share-a1acdbc5ba4e7ded,libref_cast-d724d1309653b4c7,libahash-1903d715d5764112,libonce_cell-428095ce5d8434a6,libulid-0df584f54db22bac,librand-16e86ffc2370eff6,librand_chacha-f382a29c59c3a926,libppv_lite86-9177260696bccdc2,libzerocopy-8345b37130afddcb,librand_core-9ca7818f42aa0237,libgetrandom-4efc230564bd55de,liblibc-cfc6bd596224c782,libsha2-fb8428613fe2c18d,libcpufeatures-c66ff8dcdd82082d,libcfg_if-3bc98562b73372be,libdigest-0a771f46afd19aae,libblock_buffer-a49e7b74df05ed56,libcrypto_common-1294f8b1d82dd2b1,libgeneric_array-d6b2188deed735b3,libtypenum-9af964a71b8f1c20,libthiserror-8da186ef68ca92fb,libserde_json-76dc87088753b61e,libmemchr-e16633741164b756,libitoa-5b56393bc94cfad5,libzmij-9d3e9e7b02b1a066,libserde-76697550497350f7,libserde_core-b468be6fa8c1f936}.rlib" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,libcfg_if-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/tmp/relayflows-daemon-check-target/debug/deps/rustcadSFU0/raw-dylibs" "-B/lib/rustlib/x86_64-unknown-linux-gnu/bin/gcc-ld" "-fuse-ld=lld" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/tmp/relayflows-daemon-check-target/debug/build/libsqlite3-sys-9c48f08c189498ba/out" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/tmp/relayflows-daemon-check-target/debug/deps/budget_gate-7247170737f0493b" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" + = note: some arguments are omitted. use `--verbose` to show all linker arguments + = note: collect2: fatal error: ld terminated with signal 7 [Bus error], core dumped + compilation terminated. + + +error: linking with `cc` failed: exit status: 1 + | + = note: "cc" "-m64" "/tmp/relayflows-daemon-check-target/debug/deps/rustc97chRG/symbols.o" "<44 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libtest-*,libgetopts-*,librustc_std_workspace_std-*}.rlib" "/tmp/relayflows-daemon-check-target/debug/deps/{libtempfile-9536fa684b3153e7,libgetrandom-4b55eae43c41b808,libfastrand-c3dd370172903a25,librustix-ac99c31c323027d8,liblinux_raw_sys-6909a3bb65c2afb1,librelayflowd-982eee23c6fa573f,libwait_timeout-d662a9a2f10eb8f0,librelayflowd_journal-732b611254b6de12,librusqlite-ab0fc325ee05c8a7,libbitflags-9100470b2f2ecebc,libhashlink-c9f6fe959c0b48b6,libhashbrown-1c2bb10fc4ea0603,libfoldhash-2b11b30984b507d4,liblibsqlite3_sys-3752f73801891bb3,libfallible_streaming_iterator-a347b7ef8b80f8d8,libfallible_iterator-27e9842272616c44,libanyhow-95160b83a69d28f1,librelayflowd_core-4dee9ff709ccce6a,libryu_js-379fee581d4e4cf6,libjsonschema-1346d624d341b04b,libbytecount-b25e5171a2633f4e,libregex-410ffc66da49fa09,libidna-e94098e37dc02e73,libidna_adapter-988b373e3ea8033e,libicu_properties-050075a714712b80,libicu_properties_data-dc1ccafdd0d637be,libicu_normalizer-63735c110f076c93,libicu_normalizer_data-33689e7acd25cef2,libicu_collections-d7a59cc03624c389,libutf8_iter-599cfec92559ec54,libpotential_utf-9887f2172f111fd9,libicu_provider-564c1d1fc8d08098,libicu_locale_core-a0a916db6ad389b8,libtinystr-38fd63dfef755d6c,liblitemap-dbf974391a511422,libwriteable-5abcc97df5a65912,libzerovec-900082f3c6916124,libzerotrie-8180931e727bd3ce,libyoke-b47f4278c3d13e58,libstable_deref_trait-bf6ee564ab40ea72,libzerofrom-f9ebfa44f9874bc4,libuuid_simd-30e6fe3a290737a1,libuuid-e8fa9dc5c3716442,liboutref-12add1ee7a41ce58,libvsimd-8588db60a425d5f5,libfancy_regex-f5424de6cb149387,libbit_set-ecbd1f809b659a1a,libbit_vec-2dde4e28e53e1e30,libregex_automata-30b727269a1ac78e,libaho_corasick-84481b7457a84fc2,libemail_address-fa9206456703cee3,libfraction-2366378c72c2df44,liblazy_static-e89dfa456fdef5b8,libnum-2b36d6f665b1efb1,libnum_iter-b45c706e3750f11b,libnum_rational-5a3e5bdb340b978b,libnum_complex-df5794162c1ed6d0,libnum_bigint-b48bf0e502f65e24,libnum_integer-ef150102445ba2a4,libnum_traits-e9cfbafadb0db7e3,libnum_cmp-e1600a8c1cfbeb5c,libregex_syntax-1e55c064ae9af1da,libbase64-6ee8ec72165049e2,libreferencing-a0b1881a1961e55a,libpercent_encoding-0afa79f3260a3d39,libparking_lot-4033cdce020a10a2,libparking_lot_core-c997a008dfcf686a,libsmallvec-a1337c150357a38d,liblock_api-052372b6b50f420c,libscopeguard-dd7e42edb450752a,libfluent_uri-dda813dd8b9adace,libborrow_or_share-a1acdbc5ba4e7ded,libref_cast-d724d1309653b4c7,libahash-1903d715d5764112,libonce_cell-428095ce5d8434a6,libulid-0df584f54db22bac,librand-16e86ffc2370eff6,librand_chacha-f382a29c59c3a926,libppv_lite86-9177260696bccdc2,libzerocopy-8345b37130afddcb,librand_core-9ca7818f42aa0237,libgetrandom-4efc230564bd55de,liblibc-cfc6bd596224c782,libsha2-fb8428613fe2c18d,libcpufeatures-c66ff8dcdd82082d,libcfg_if-3bc98562b73372be,libdigest-0a771f46afd19aae,libblock_buffer-a49e7b74df05ed56,libcrypto_common-1294f8b1d82dd2b1,libgeneric_array-d6b2188deed735b3,libtypenum-9af964a71b8f1c20,libthiserror-8da186ef68ca92fb,libserde_json-76dc87088753b61e,libmemchr-e16633741164b756,libitoa-5b56393bc94cfad5,libzmij-9d3e9e7b02b1a066,libserde-76697550497350f7,libserde_core-b468be6fa8c1f936}.rlib" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,libcfg_if-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/tmp/relayflows-daemon-check-target/debug/deps/rustc97chRG/raw-dylibs" "-B/lib/rustlib/x86_64-unknown-linux-gnu/bin/gcc-ld" "-fuse-ld=lld" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/tmp/relayflows-daemon-check-target/debug/build/libsqlite3-sys-9c48f08c189498ba/out" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/tmp/relayflows-daemon-check-target/debug/deps/late_start-412141e23ddc6467" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" + = note: some arguments are omitted. use `--verbose` to show all linker arguments + = note: collect2: fatal error: ld terminated with signal 7 [Bus error], core dumped + compilation terminated. + + +error: could not compile `relayflowd` (test "budget_gate") due to 1 previous error +warning: build failed, waiting for other jobs to finish... +error: could not compile `relayflowd` (test "late_start") due to 1 previous error +error: linking with `cc` failed: exit status: 1 + | + = note: "cc" "-m64" "/tmp/relayflows-daemon-check-target/debug/deps/rustcfHOFrQ/symbols.o" "<95 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/tmp/relayflows-daemon-check-target/debug/deps/{libtempfile-9536fa684b3153e7,libgetrandom-4b55eae43c41b808,libfastrand-c3dd370172903a25,librustix-ac99c31c323027d8,liblinux_raw_sys-6909a3bb65c2afb1}.rlib" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libtest-*,libgetopts-*,librustc_std_workspace_std-*}.rlib" "/tmp/relayflows-daemon-check-target/debug/deps/{librelayflowd-982eee23c6fa573f,libwait_timeout-d662a9a2f10eb8f0,librelayflowd_journal-732b611254b6de12,librusqlite-ab0fc325ee05c8a7,libbitflags-9100470b2f2ecebc,libhashlink-c9f6fe959c0b48b6,libhashbrown-1c2bb10fc4ea0603,libfoldhash-2b11b30984b507d4,liblibsqlite3_sys-3752f73801891bb3,libfallible_streaming_iterator-a347b7ef8b80f8d8,libfallible_iterator-27e9842272616c44,libanyhow-95160b83a69d28f1,librelayflowd_core-4dee9ff709ccce6a,libryu_js-379fee581d4e4cf6,libjsonschema-1346d624d341b04b,libbytecount-b25e5171a2633f4e,libregex-410ffc66da49fa09,libidna-e94098e37dc02e73,libidna_adapter-988b373e3ea8033e,libicu_properties-050075a714712b80,libicu_properties_data-dc1ccafdd0d637be,libicu_normalizer-63735c110f076c93,libicu_normalizer_data-33689e7acd25cef2,libicu_collections-d7a59cc03624c389,libutf8_iter-599cfec92559ec54,libpotential_utf-9887f2172f111fd9,libicu_provider-564c1d1fc8d08098,libicu_locale_core-a0a916db6ad389b8,libtinystr-38fd63dfef755d6c,liblitemap-dbf974391a511422,libwriteable-5abcc97df5a65912,libzerovec-900082f3c6916124,libzerotrie-8180931e727bd3ce,libyoke-b47f4278c3d13e58,libstable_deref_trait-bf6ee564ab40ea72,libzerofrom-f9ebfa44f9874bc4,libuuid_simd-30e6fe3a290737a1,libuuid-e8fa9dc5c3716442,liboutref-12add1ee7a41ce58,libvsimd-8588db60a425d5f5,libfancy_regex-f5424de6cb149387,libbit_set-ecbd1f809b659a1a,libbit_vec-2dde4e28e53e1e30,libregex_automata-30b727269a1ac78e,libaho_corasick-84481b7457a84fc2,libemail_address-fa9206456703cee3,libfraction-2366378c72c2df44,liblazy_static-e89dfa456fdef5b8,libnum-2b36d6f665b1efb1,libnum_iter-b45c706e3750f11b,libnum_rational-5a3e5bdb340b978b,libnum_complex-df5794162c1ed6d0,libnum_bigint-b48bf0e502f65e24,libnum_integer-ef150102445ba2a4,libnum_traits-e9cfbafadb0db7e3,libnum_cmp-e1600a8c1cfbeb5c,libregex_syntax-1e55c064ae9af1da,libbase64-6ee8ec72165049e2,libreferencing-a0b1881a1961e55a,libpercent_encoding-0afa79f3260a3d39,libparking_lot-4033cdce020a10a2,libparking_lot_core-c997a008dfcf686a,libsmallvec-a1337c150357a38d,liblock_api-052372b6b50f420c,libscopeguard-dd7e42edb450752a,libfluent_uri-dda813dd8b9adace,libborrow_or_share-a1acdbc5ba4e7ded,libref_cast-d724d1309653b4c7,libahash-1903d715d5764112,libonce_cell-428095ce5d8434a6,libulid-0df584f54db22bac,librand-16e86ffc2370eff6,librand_chacha-f382a29c59c3a926,libppv_lite86-9177260696bccdc2,libzerocopy-8345b37130afddcb,librand_core-9ca7818f42aa0237,libgetrandom-4efc230564bd55de,liblibc-cfc6bd596224c782,libsha2-fb8428613fe2c18d,libcpufeatures-c66ff8dcdd82082d,libcfg_if-3bc98562b73372be,libdigest-0a771f46afd19aae,libblock_buffer-a49e7b74df05ed56,libcrypto_common-1294f8b1d82dd2b1,libgeneric_array-d6b2188deed735b3,libtypenum-9af964a71b8f1c20,libthiserror-8da186ef68ca92fb,libserde_json-76dc87088753b61e,libmemchr-e16633741164b756,libitoa-5b56393bc94cfad5,libzmij-9d3e9e7b02b1a066,libserde-76697550497350f7,libserde_core-b468be6fa8c1f936}.rlib" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,libcfg_if-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/tmp/relayflows-daemon-check-target/debug/deps/rustcfHOFrQ/raw-dylibs" "-B/lib/rustlib/x86_64-unknown-linux-gnu/bin/gcc-ld" "-fuse-ld=lld" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/tmp/relayflows-daemon-check-target/debug/build/libsqlite3-sys-9c48f08c189498ba/out" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/tmp/relayflows-daemon-check-target/debug/deps/event_activities-756a1a69731ac806" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" + = note: some arguments are omitted. use `--verbose` to show all linker arguments + = note: rust-lld: error: failed to open /tmp/relayflows-daemon-check-target/debug/deps/event_activities-756a1a69731ac806: No space left on device + collect2: error: ld returned 1 exit status + + +error: could not compile `relayflowd` (test "event_activities") due to 1 previous error +error: linking with `cc` failed: exit status: 1 + | + = note: "cc" "-m64" "/tmp/relayflows-daemon-check-target/debug/deps/rustcj6CPUY/symbols.o" "<60 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/tmp/relayflows-daemon-check-target/debug/deps/{libtempfile-9536fa684b3153e7,libgetrandom-4b55eae43c41b808,libfastrand-c3dd370172903a25,librustix-ac99c31c323027d8,liblinux_raw_sys-6909a3bb65c2afb1}.rlib" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libtest-*,libgetopts-*,librustc_std_workspace_std-*}.rlib" "/tmp/relayflows-daemon-check-target/debug/deps/{librelayflowd_journal-732b611254b6de12,librusqlite-ab0fc325ee05c8a7,libbitflags-9100470b2f2ecebc,libhashlink-c9f6fe959c0b48b6,libhashbrown-1c2bb10fc4ea0603,libfoldhash-2b11b30984b507d4,liblibsqlite3_sys-3752f73801891bb3,libfallible_streaming_iterator-a347b7ef8b80f8d8,libfallible_iterator-27e9842272616c44,librelayflowd_core-4dee9ff709ccce6a,libryu_js-379fee581d4e4cf6,libjsonschema-1346d624d341b04b,libbytecount-b25e5171a2633f4e,libregex-410ffc66da49fa09,libidna-e94098e37dc02e73,libidna_adapter-988b373e3ea8033e,libicu_properties-050075a714712b80,libicu_properties_data-dc1ccafdd0d637be,libicu_normalizer-63735c110f076c93,libicu_normalizer_data-33689e7acd25cef2,libicu_collections-d7a59cc03624c389,libutf8_iter-599cfec92559ec54,libpotential_utf-9887f2172f111fd9,libicu_provider-564c1d1fc8d08098,libicu_locale_core-a0a916db6ad389b8,libtinystr-38fd63dfef755d6c,liblitemap-dbf974391a511422,libwriteable-5abcc97df5a65912,libzerovec-900082f3c6916124,libzerotrie-8180931e727bd3ce,libyoke-b47f4278c3d13e58,libstable_deref_trait-bf6ee564ab40ea72,libzerofrom-f9ebfa44f9874bc4,libuuid_simd-30e6fe3a290737a1,libuuid-e8fa9dc5c3716442,liboutref-12add1ee7a41ce58,libvsimd-8588db60a425d5f5,libfancy_regex-f5424de6cb149387,libbit_set-ecbd1f809b659a1a,libbit_vec-2dde4e28e53e1e30,libregex_automata-30b727269a1ac78e,libaho_corasick-84481b7457a84fc2,libemail_address-fa9206456703cee3,libfraction-2366378c72c2df44,liblazy_static-e89dfa456fdef5b8,libnum-2b36d6f665b1efb1,libnum_iter-b45c706e3750f11b,libnum_rational-5a3e5bdb340b978b,libnum_complex-df5794162c1ed6d0,libnum_bigint-b48bf0e502f65e24,libnum_integer-ef150102445ba2a4,libnum_traits-e9cfbafadb0db7e3,libnum_cmp-e1600a8c1cfbeb5c,libregex_syntax-1e55c064ae9af1da,libbase64-6ee8ec72165049e2,libreferencing-a0b1881a1961e55a,libpercent_encoding-0afa79f3260a3d39,libparking_lot-4033cdce020a10a2,libparking_lot_core-c997a008dfcf686a,libsmallvec-a1337c150357a38d,liblock_api-052372b6b50f420c,libscopeguard-dd7e42edb450752a,libfluent_uri-dda813dd8b9adace,libborrow_or_share-a1acdbc5ba4e7ded,libref_cast-d724d1309653b4c7,libahash-1903d715d5764112,libonce_cell-428095ce5d8434a6,libulid-0df584f54db22bac,librand-16e86ffc2370eff6,librand_chacha-f382a29c59c3a926,libppv_lite86-9177260696bccdc2,libzerocopy-8345b37130afddcb,librand_core-9ca7818f42aa0237,libgetrandom-4efc230564bd55de,liblibc-cfc6bd596224c782,libsha2-fb8428613fe2c18d,libcpufeatures-c66ff8dcdd82082d,libcfg_if-3bc98562b73372be,libdigest-0a771f46afd19aae,libblock_buffer-a49e7b74df05ed56,libcrypto_common-1294f8b1d82dd2b1,libgeneric_array-d6b2188deed735b3,libtypenum-9af964a71b8f1c20,libthiserror-8da186ef68ca92fb,libserde_json-76dc87088753b61e,libmemchr-e16633741164b756,libitoa-5b56393bc94cfad5,libzmij-9d3e9e7b02b1a066,libserde-76697550497350f7,libserde_core-b468be6fa8c1f936}.rlib" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,libcfg_if-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/tmp/relayflows-daemon-check-target/debug/deps/rustcj6CPUY/raw-dylibs" "-B/lib/rustlib/x86_64-unknown-linux-gnu/bin/gcc-ld" "-fuse-ld=lld" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/tmp/relayflows-daemon-check-target/debug/build/libsqlite3-sys-9c48f08c189498ba/out" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/tmp/relayflows-daemon-check-target/debug/deps/advisory_deterministic-35ee7ddbc1eb05b0" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" + = note: some arguments are omitted. use `--verbose` to show all linker arguments + = note: PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace and instructions to reproduce the bug. + Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it): + collect2: fatal error: ld terminated with signal 7 [Bus error], core dumped + compilation terminated. + + +error: could not compile `relayflowd` (test "advisory_deterministic") due to 1 previous error diff --git a/evidence/daemon-check/rustfmt-setup.txt b/evidence/daemon-check/rustfmt-setup.txt new file mode 100644 index 000000000..d3678c828 --- /dev/null +++ b/evidence/daemon-check/rustfmt-setup.txt @@ -0,0 +1 @@ +info: downloading component rustfmt diff --git a/evidence/daemon-check/sdk-build-final.txt b/evidence/daemon-check/sdk-build-final.txt new file mode 100644 index 000000000..efe21185f --- /dev/null +++ b/evidence/daemon-check/sdk-build-final.txt @@ -0,0 +1,4 @@ + +> @relayflows/sdk@2.0.42 build +> tsc && node scripts/make-cli-executable.mjs + diff --git a/evidence/daemon-check/sdk-build.txt b/evidence/daemon-check/sdk-build.txt new file mode 100644 index 000000000..efe21185f --- /dev/null +++ b/evidence/daemon-check/sdk-build.txt @@ -0,0 +1,4 @@ + +> @relayflows/sdk@2.0.42 build +> tsc && node scripts/make-cli-executable.mjs + diff --git a/evidence/daemon-check/sdk-final.txt b/evidence/daemon-check/sdk-final.txt new file mode 100644 index 000000000..d25cb99c3 --- /dev/null +++ b/evidence/daemon-check/sdk-final.txt @@ -0,0 +1,29 @@ + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + + ✓ tests/relay-cli-surface.test.ts (89 tests) 45ms + ✓ tests/check-daemon-validation.test.ts (20 tests) 2853ms + ✓ real CLI refuses skew in auto and required modes 982ms + ✓ real CLI labels daemon and offline passes, including JSON 1363ms + ✓ real CLI refuses an invalid RELAYFLOWD_BIN in required mode 418ms + ✓ tests/cli.test.ts (71 tests) 3012ms + ✓ flows check CLI > binds a checked relative wrapper to the flow directory for worker execution 484ms + ✓ flows check CLI > resolves a bare PATH-resolved claude with no declared model, in an isolated PATH 558ms + ✓ flows run/resume CLI over the journal protocol > follows a worker wait past a locally expired lease until the daemon settles it 1040ms + ✓ tests/cli-watch.test.ts (11 tests) 17841ms + ✓ flows check --watch > forwards required daemon validation through watch despite the offline test environment 979ms + ✓ flows check --watch > rechecks syntax errors, clears once, and returns the last refusal on Ctrl-C 1394ms + ✓ flows check --watch > streams JSON lines without ANSI, recovers after atomic saves, and exits zero after repair 1965ms + ✓ flows check --watch > coalesces 20 concurrent saves into at most two rechecks 1894ms + ✓ flows check --watch > watches transitive relative use imports, cycles, and nearest config changes 2492ms + ✓ flows check --watch > refreshes the import graph and notices missing imports being created 2502ms + ✓ flows check --watch > reloads authored TypeScript instead of reusing the first imported definition 1864ms + ✓ flows check --watch > detects a nearer config appearing and falls back after it is deleted 1992ms + ✓ flows check --watch > keeps watching after the target is deleted and recreated 1981ms + ✓ flows check --watch > queues changes during a slow check without overlapping checks 773ms + + Test Files 4 passed (4) + Tests 191 passed (191) + Start at 14:40:27 + Duration 20.31s (transform 1.35s, setup 40ms, collect 5.28s, tests 23.75s, environment 0ms, prepare 184ms) + diff --git a/evidence/daemon-check/sdk-full.txt b/evidence/daemon-check/sdk-full.txt new file mode 100644 index 000000000..e70b7c915 --- /dev/null +++ b/evidence/daemon-check/sdk-full.txt @@ -0,0 +1,1599 @@ + +> @relayflows/sdk@2.0.42 test +> sh scripts/test.sh + + +> @relayflows/sdk@2.0.42 test:prep +> ( cd ../../kernel && sh ../ops/cargo.sh build ) && ( [ ! -d ../../testdata/preflight ] || find ../../testdata/preflight -name '*-cli' -type f -exec chmod +x {} + ) + + Compiling proc-macro2 v1.0.107 + Compiling unicode-ident v1.0.24 + Compiling quote v1.0.47 + Compiling stable_deref_trait v1.2.1 + Compiling libc v0.2.189 + Compiling version_check v0.9.5 + Compiling autocfg v1.5.1 + Compiling cfg-if v1.0.4 + Compiling serde_core v1.0.229 + Compiling num-traits v0.2.19 + Compiling zerocopy v0.8.56 + Compiling getrandom v0.3.4 + Compiling syn v3.0.4 + Compiling syn v2.0.119 + Compiling smallvec v1.15.2 + Compiling serde v1.0.229 + Compiling synstructure v0.13.2 + Compiling memchr v2.8.3 + Compiling zerofrom-derive v0.1.7 + Compiling yoke-derive v0.8.2 + Compiling zerofrom v0.1.8 + Compiling writeable v0.6.4 + Compiling litemap v0.8.3 + Compiling num-integer v0.1.47 + Compiling yoke v0.8.3 + Compiling zerovec-derive v0.11.6 + Compiling displaydoc v0.2.7 + Compiling serde_derive v1.0.229 + Compiling zerotrie v0.2.5 + Compiling generic-array v0.14.7 + Compiling icu_normalizer_data v2.3.0 + Compiling zerovec v0.11.8 + Compiling icu_properties_data v2.3.0 + Compiling utf8_iter v1.0.4 + Compiling typenum v1.20.1 + Compiling parking_lot_core v0.9.12 + Compiling zmij v1.0.23 + Compiling ref-cast v1.0.27 + Compiling tinystr v0.8.4 + Compiling icu_locale_core v2.3.0 + Compiling potential_utf v0.1.6 + Compiling icu_collections v2.3.0 + Compiling num-bigint v0.4.8 + Compiling ref-cast-impl v1.0.27 + Compiling icu_provider v2.3.1 + Compiling aho-corasick v1.1.5 + Compiling ahash v0.8.12 + Compiling serde_json v1.0.151 + Compiling scopeguard v1.2.0 + Compiling shlex v2.0.1 + Compiling regex-syntax v0.8.11 + Compiling find-msvc-tools v0.1.11 + Compiling cc v1.4.4 + Compiling num-rational v0.4.2 + Compiling lock_api v0.4.14 + Compiling icu_normalizer v2.3.0 + Compiling regex-automata v0.4.18 + Compiling icu_properties v2.3.0 + Compiling ppv-lite86 v0.2.21 + Compiling num-iter v0.1.46 + Compiling rand_core v0.9.5 + Compiling num-complex v0.4.6 + Compiling borrow-or-share v0.2.4 + Compiling once_cell v1.21.4 + Compiling bit-vec v0.8.0 + Compiling pkg-config v0.3.34 + Compiling itoa v1.0.18 + Compiling vcpkg v0.2.15 + Compiling num v0.4.3 + Compiling bit-set v0.8.0 + Compiling libsqlite3-sys v0.35.0 + Compiling fluent-uri v0.3.2 + Compiling rand_chacha v0.9.0 + Compiling idna_adapter v1.2.2 + Compiling parking_lot v0.12.5 + Compiling block-buffer v0.10.4 + Compiling crypto-common v0.1.7 + Compiling thiserror v2.0.20 + Compiling uuid v1.26.0 + Compiling foldhash v0.1.5 + Compiling utf8parse v0.2.2 + Compiling outref v0.5.2 + Compiling percent-encoding v2.3.2 + Compiling vsimd v0.8.0 + Compiling lazy_static v1.5.0 + Compiling fraction v0.15.4 + Compiling referencing v0.33.0 + Compiling uuid-simd v0.8.0 + Compiling hashbrown v0.15.5 + Compiling anstyle-parse v1.0.0 + Compiling digest v0.10.7 + Compiling idna v1.1.0 + Compiling regex v1.13.1 + Compiling fancy-regex v0.16.2 + Compiling rand v0.9.5 + Compiling email_address v0.2.9 + Compiling thiserror-impl v2.0.20 + Compiling is_terminal_polyfill v1.70.2 + Compiling anstyle-query v1.1.5 + Compiling bytecount v0.6.9 + Compiling cpufeatures v0.2.17 + Compiling num-cmp v0.1.0 + Compiling colorchoice v1.0.5 + Compiling anstyle v1.0.14 + Compiling base64 v0.22.1 + Compiling anstream v1.0.0 + Compiling jsonschema v0.33.0 + Compiling sha2 v0.10.9 + Compiling ulid v1.2.1 + Compiling hashlink v0.10.0 + Compiling heck v0.5.0 + Compiling anyhow v1.0.104 + Compiling bitflags v2.13.1 + Compiling fallible-streaming-iterator v0.1.9 + Compiling fallible-iterator v0.3.0 + Compiling strsim v0.11.1 + Compiling ryu-js v1.0.3 + Compiling clap_lex v1.1.0 + Compiling clap_builder v4.6.6 + Compiling clap_derive v4.6.4 + Compiling relayflowd-core v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd-core) + Compiling clap v4.6.6 + Compiling wait-timeout v0.2.1 + Compiling rusqlite v0.37.0 + Compiling relayflowd-journal v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd-journal) + Compiling relayflowd v0.1.0 (/home/daytona/.relayflow-v2-supervisor/durable/repository/kernel/relayflowd) + Finished `dev` profile [unoptimized + debuginfo] target(s) in 18.04s + +> @relayflows/sdk@2.0.42 typecheck +> tsc --noEmit && tsc -p tsconfig.type-tests.json + + +> @relayflows/sdk@2.0.42 build +> tsc && node scripts/make-cli-executable.mjs + + +> @relayflows/sdk@2.0.42 typecheck:tests +> tsc -p tsconfig.tests.json + + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + +stdout | tests/live-kernel.test.ts +LIVE_KERNEL relayflowd=/tmp/relayflows-daemon-check-target/debug/relayflowd +LIVE_KERNEL flows=/home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/dist/cli.js + + ✓ tests/preflight.test.ts (70 tests) 148ms + ✓ tests/cli.test.ts (71 tests) 2895ms + ✓ flows check CLI > binds a checked relative wrapper to the flow directory for worker execution 490ms + ✓ flows check CLI > resolves a bare PATH-resolved claude with no declared model, in an isolated PATH 438ms + ✓ flows run/resume CLI over the journal protocol > follows a worker wait past a locally expired lease until the daemon settles it 1042ms + ✓ tests/cloud-read.test.ts (46 tests) 52ms +stdout | tests/live-kernel.test.ts > surface resume after a real daemon kill > resumes a three-step run with each successful completion exactly once +LIVE_KERNEL kill -9 pid=30472 run=01M48SNXMEN8Y114WDV9HZPMR2 while step=two state=Running + + ❯ tests/live-kernel.test.ts (33 tests | 8 failed) 59035ms + ✓ built flows CLI against live relayflowd > twenty-six-step reuses 25 durable completions after editing the failed final step 2368ms + ✓ built flows CLI against live relayflowd > runs rung (a), parks rung (b), and keeps JSON report-shaped 2704ms + ✓ built flows CLI against live relayflowd > allows a deterministic run to exceed the bounded request timeout 32595ms + ✓ built flows CLI against live relayflowd > follows a live worker dispatch through flows run 725ms + ✓ built flows CLI against live relayflowd > runs an agent CLI end to end through the SDK worker 618ms + ✓ built flows CLI against live relayflowd > f.agent lowers to a real agent step and dispatches through a live worker 749ms + ✓ built flows CLI against live relayflowd > can always get a parked run to a late-attaching worker 5597ms + ✓ built flows CLI against live relayflowd > reports a real manual-recovery NeedsHuman state as parked 477ms + × built flows CLI against live relayflowd > runs hn-monitor analyze-story end-to-end via a stub agent CLI (gate 2 clause 2 demo) 767ms + → expected { …(12) } to match object { output: { …(3) }, …(1) } +(22 matching properties omitted from actual) + × built flows CLI against live relayflowd > hn-monitor analyze-story FAILS verification when the CLI omits required schema fields 754ms + → expected { …(12) } to match object { …(3) } +(21 matching properties omitted from actual) + × built flows CLI against live relayflowd > agent step preserves the CliResult wrapper as output when the CLI emits non-JSON text 776ms + → expected null not to be null + × built flows CLI against live relayflowd > AgentWorker exposes wake_context to the CLI via RELAYFLOW_WAKE_CONTEXT env var (real analyzer prerequisite) 709ms + → Cannot read properties of null (reading 'story_title') + × built flows CLI against live relayflowd > AgentWorker leaves RELAYFLOW_WAKE_CONTEXT UNSET when the run has no wake_context (undefined-vs-null pin) 636ms + → Cannot read properties of null (reading 'env_present') + ✓ built flows CLI against live relayflowd > AgentWorker passes a declared model to an identified wrapper as RELAYFLOW_MODEL 967ms + ✓ built flows CLI against live relayflowd > AgentWorker refuses a nonconforming journal-submitted wrapper before exposing RELAYFLOW_MODEL 1047ms + ✓ built flows CLI against live relayflowd > AgentWorker executes the raw claude adapter with its real model flag 868ms + ✓ built flows CLI against live relayflowd > AgentWorker executes the raw codex adapter with its real model flag 595ms + × built flows CLI against live relayflowd > AgentWorker leaves RELAYFLOW_MODEL UNSET when the step declares no model 618ms + → Cannot read properties of null (reading 'story_title') + × built flows CLI against live relayflowd > hn-monitor analyze-story reaches done through the real Claude analyzer CLI 30ms + → LIVE_ANALYZER_UNAVAILABLE: "/home/daytona/.relayflow-v2-supervisor/durable/repository/testdata/preflight/analyze-story-claude-cli" does not identify as relayflows-agent-cli-v1 — failing because gate-2 acceptance requires the real analyzer to execute. Set RELAYFLOWS_ALLOW_ANALYZER_SKIP=1 only if this run is not gate evidence. + ✓ built flows CLI against live relayflowd > preflights before journaling and names an unreachable socket 887ms + ✓ built flows CLI against live relayflowd > starts exactly one daemon when two runs race for one empty data dir 593ms + ✓ subprocess_gate output capture against live relayflowd > journals the gate command output and reports both tails 1161ms + ✓ surface resume after a real daemon kill > resumes a three-step run with each successful completion exactly once 1075ms + × a relayflow can be scheduled: tick source against live relayflowd > a tick spawns a real run whose step reports the SCHEDULED instant 618ms + → expected null to deeply equal { schedule_id: 'heartbeat-1m', …(3) } + ✓ tests/cloud-live.test.ts (55 tests) 2060ms + ✓ argv and wiring > routes both live invocations through runCli, and refuses a missing run id 2005ms + ❯ tests/hosted-extension-isolation.test.ts (22 tests | 13 failed) 4020ms + × hosted extension capability isolation > executes the exact capability-only handler for a queued receipt 235ms + → Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + × hosted extension capability isolation > executes the exact capability-only handler for a duplicate receipt 232ms + → Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + × hosted extension capability isolation > launches through the captured process primitive after builtin export synchronization 224ms + → promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + × hosted extension capability isolation > ignores inherited launcher overrides and decodes manifests with the captured Buffer intrinsic 216ms + → promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + × hosted extension capability isolation > streams verified bytes when the live store is replaced and no writable staging path exists 270ms + → promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + × hosted extension capability isolation > mounts pinned private Surface bytes when the live package changes before launch 242ms + → promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + × hosted extension capability isolation > shields verified Surface files before async settlement 229ms + → promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + × hosted extension capability isolation > preserves a typed host refusal while disclosing only a fixed marker to the child 224ms + → expected Error: Hosted extension sandbox exited wi… { code: '…' } to be Error: private Cloud policy detail { code: '…' } // Object.is equality + × hosted extension capability isolation > denies ambient credentials, host files, writes, network, subprocesses, and undeclared context verbs 231ms + → Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + × hosted extension capability isolation > enforces OS address-space and data bounds on native Buffer allocation 228ms + → expected Error: Hosted extension sandbox exited wi… { code: '…' } to match object { code: 'plugin_unsupported', …(1) } + × hosted extension capability isolation > blocks extra handler fields and authority-bearing receipt fields at the parent port 224ms + → expected Error: Hosted extension sandbox exited wi… { code: '…' } to match object { code: 'plugin_event_unroutable' } + × hosted extension capability isolation > constructs adapter authority with the captured freeze intrinsic 220ms + → Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + × hosted extension capability isolation > writes the Surface manifest and protocol without inherited toJSON behavior 226ms + → promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + ✓ hosted extension capability isolation > fails closed when the handler omits or repeats the single capability call 689ms + ✓ tests/cloud-deploy.test.ts (117 tests) 5262ms + ✓ flows deploy / flows deployments > deploys and lists GitLab repositories (json=false) 323ms + ✓ flows deploy / flows deployments > deploys and lists GitLab repositories (json=true) 682ms + ✓ flows deploy / flows deployments > passes --agents and --draft through, and names a structured refusal 493ms + ✓ flows deploy / flows deployments > explains a 403 as a missing cli:auth login and exits 2 320ms + ✓ flow versions (cloud#4115) > updates a GitLab listener without adding a target integration requirement 395ms + ✓ flow versions (cloud#4115) > names an unknown or ambiguous flow 485ms + ✓ flow versions (cloud#4115) > reports the version a create-form deploy made 405ms + ✓ tests/cloud-sync.test.ts (40 tests) 2787ms + ✓ flows run --cloud --sync-code / flows sync > runs an authored flow with --input and syncs the invoking directory 402ms + ✓ tests/observer-link.test.ts (44 tests) 598ms + ✓ tests/authored-flow.test.ts (38 tests) 896ms + ❯ tests/plugin-extension.test.ts (94 tests | 11 failed) 491ms + × flows add > resolves a branch to its commit, materializes, and records flows.json plus the lockfile 113ms + → expected 2 to be +0 // Object.is equality + × flows add > keeps the digest stable across identical installs and distinct across content changes 1ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + × flows add > recovers both crash points in the flows.json and lock transaction 1ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + × flows add > refuses github:AgentWorkforce/flows@nope#examples/babysitter with plugin_source_unresolved and writes nothing 1ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + × flows add > refuses github:AgentWorkforce/flows@main#examples/babysitter with plugin_source_unresolved and writes nothing 0ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + × flows add > refuses github:AgentWorkforce/flows@feat/babysitter-v2#examples with plugin_manifest_missing and writes nothing 0ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + × flows add > refuses github:AgentWorkforce/flows@bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#examples/babysitter with plugin_source_unresolved and writes nothing 0ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + × flows add > refuses github:AgentWorkforce/flows@feat/babysitter-v2#../x with plugin_source_invalid and writes nothing 0ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + × flows add > refuses a plugin whose compat excludes this runtime 0ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + × flows add > refuses a manifest whose declared source is not where it was fetched from 1ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + × flows add > refuses a second source under an already-installed name 0ms + → ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + ✓ tests/cloud-transcript-codex.test.ts (44 tests) 19ms + ✓ tests/worker-cli.test.ts (25 tests) 29921ms + ✓ registered CLI model defaults > passes the same priced Claude default to the real provider invocation 663ms + ✓ registered CLI model defaults > uses the explicitly supplied agent environment for the provider subprocess 742ms + ✓ registered CLI model defaults > dispatches canonical generic bytes with the preflight-proved adapter identity 615ms + ✓ direct transport lifecycle evidence > classifies only the exact Codex stdin lifecycle signature as retryable 706ms + ✓ direct transport lifecycle evidence > records a signal close separately from an ordinary nonzero exit 1018ms + ✓ direct transport lifecycle evidence > records a spawn error code without treating a missing executable as transient 507ms + ✓ direct transport lifecycle evidence > journals classified lifecycle evidence and reports crashed instead of generic worker_error 811ms + ✓ step discovery environment > names the run, step, attempt and an absolute data dir for a direct agent spawn 824ms + ✓ step discovery environment > exports none of the four without a data dir, even when the worker inherited them 530ms + ✓ wrapper discovery environment > sets the four names from the dispatch and still refuses ambient values and other secrets 643ms + ✓ wrapper discovery environment > exports none of the four to a wrapper without a data dir, even when the worker inherited them 542ms + ✓ custom wrapper execution identity > passes an explicit safe environment at identification and execution 545ms + ✓ custom wrapper execution identity > refuses a wrapper symlink retarget before delivering private values 547ms + ✓ custom wrapper execution identity > bounds wrapper execution after acknowledgement 627ms + ✓ custom wrapper execution identity > bounds captured wrapper output 530ms + ✓ custom wrapper execution identity > refuses a duplicate execute protocol frame 575ms + ✓ custom wrapper execution bounds are reader-owned > resolves when a conforming wrapper leaks a stdio pipe to a background helper 801ms + ✓ custom wrapper execution bounds are reader-owned > resolves when the leaked helper inherits stderr only 716ms + ✓ custom wrapper execution bounds are reader-owned > resolves when a wrapper leaks a stdio pipe and exits before identifying 3524ms + ✓ custom wrapper execution bounds are reader-owned > journals a completionReason at the default bound when a wrapper leaks a stdio pipe 11473ms + ✓ custom wrapper execution bounds are reader-owned > accepts an execute token and an over-8KiB payload flushed in one write 552ms + ✓ custom wrapper execution bounds are reader-owned > accepts the same over-8KiB payload whether or not it coalesces with the execute token 1389ms + ✓ custom wrapper execution bounds are reader-owned > still bounds an un-terminated handshake buffer and names the bound 465ms + ✓ delivers the journaled memory pack to the real wrapper and excludes its charge from completion usage 574ms + ✓ tests/flow-extension-compose.test.ts (33 tests) 6984ms + ✓ composing flow extensions onto a base flow > appends the Babysitter handler surface after the base, in lock order, without touching the base definition 321ms + ✓ composing flow extensions onto a base flow > composes two extensions in declaration order, and the order is the lockfile order 491ms + ✓ composing flow extensions onto a base flow > flows check reports the composition and keeps the composed triggers deliverable 1014ms + ✓ composing flow extensions onto a base flow > uses extension permissions for hosted deploy preflight and the deploy body 303ms +(node:33905) ExperimentalWarning: SQLite is an experimental feature and might change at any time +(Use `node --trace-warnings ...` to show where the warning was created) + ✓ tests/cli-status.test.ts (27 tests) 1404ms + ✓ flows status > resolves the run with no arguments from inside a worker-spawned agent 1015ms + ✓ tests/run-state.test.ts (28 tests) 12ms + ✓ tests/cloud-run.test.ts (59 tests) 827ms + ❯ tests/relay-cli-surface.test.ts (87 tests | 1 failed) 43ms + × relay-cli surface: drift between `commands` and `run` > carries every declared flag on an invocation that parses 7ms + → expected [ Array(2) ] to deeply equal [] + ✓ tests/agent-transcript.test.ts (29 tests) 283ms + ❯ tests/babysitter-native-extension.test.ts (41 tests | 1 failed) 1844ms + × native Babysitter extension > runs the exact published 2.0.26 native bytes in the isolated capability path 235ms + → promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + ✓ tests/shipped-source-worker-call-forms.test.ts (1 test) 16543ms + ✓ shipped-source worker call forms > fails closed for computed keys, assertions, binds, call, and apply 16542ms +(node:34309) [FLOWS_ROOT_LEASE_LOST] Warning: authored root run_id=root-run attempt=1: lease_conflict: attempt has no active worker lease. Waiting for the kernel to retry it. +(Use `node --trace-warnings ...` to show where the warning was created) + ✓ tests/authored-root.test.ts (22 tests) 423ms + ✓ tests/authored-completion-detail.test.ts (59 tests) 208ms + ✓ tests/shipped-source-model-provenance.test.ts (1 test) 146276ms + ✓ shipped-source model provenance > does not treat mutable aliases or incomplete named agents as pinned 146275ms + ✓ tests/step-failure-diagnostic.test.ts (26 tests) 109ms + ✓ tests/stop-process-group.test.ts (11 tests) 15705ms + ✓ every stop reaches the process group, not just the direct child > exits the run after an execution-timeout stop 1212ms + ✓ every stop reaches the process group, not just the direct child > exits the run after a protocol terminate stop 755ms + ✓ every stop reaches the process group, not just the direct child > kills a SIGTERM-deaf grandchild after a protocol terminate stop 1748ms + ✓ every stop reaches the process group, not just the direct child > kills a SIGTERM-deaf grandchild after an execution-timeout stop 2339ms + ✓ every stop reaches the process group, not just the direct child > holds the loop open long enough for the escalation to run 1139ms + ✓ every stop reaches the process group, not just the direct child > bounds forced-stop confirmation when a group remains unprovable 1014ms + ✓ a wrapper that exits with no execution deadline still drains > reports the wrapper result and reaps a grandchild holding its pipes 902ms + ✓ a wrapper that exits with no execution deadline still drains > reaps a SIGTERM-deaf grandchild holding its pipes 1939ms + ✓ a wrapper that exits with no execution deadline still drains > settles on its own deadline when an escaped holder withholds close 4307ms + ✓ tests/mcp.test.ts (34 tests) 15481ms + ✓ MCP preflight and transports > flows check refuses an undeclared server with exit 2 and no daemon 1081ms + ✓ MCP preflight and transports > flows check reports a refusing server and leaves no PID 1178ms + ✓ MCP preflight and transports > kills a SIGTERM-resistant silent child after a parent-owned handshake deadline 1322ms + ✓ MCP preflight and transports > reaps a SIGTERM-resistant descendant with inherit stdio before cleanup finishes 1068ms + ✓ MCP preflight and transports > reaps a SIGTERM-resistant descendant with ignore stdio before cleanup finishes 2027ms + ✓ MCP preflight and transports > rejects close when forced group death remains unprovable 2073ms + ✓ MCP preflight and transports > cancels force escalation when close follows an exited child 1183ms + ✓ MCP preflight and transports > waits for child close when the transport cannot own a process group 1053ms + ✓ MCP preflight and transports > cancels force escalation for an already-closed child without a process group 1174ms + ✓ MCP preflight and transports > reports malformed connection configuration as config_invalid 1376ms + ✓ authored MCP effects against the real kernel > journals one MCP receipt per call with args, result, stable logical key, and a confirmed effect 313ms + ✓ authored MCP effects against the real kernel > reports a dropped tool connection as a failed CLI run 838ms + ✓ tests/step-attempt-history.test.ts (23 tests) 41ms + ✓ tests/daemon-lifecycle.test.ts (42 tests) 51ms + ❯ tests/hosted-extension-protocol.test.ts (27 tests | 8 failed) 42286ms + × hosted extension hostile protocol > uses captured JSON intrinsics for the complete parent boundary 244ms + → Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + × hosted extension hostile protocol > rejects an import-time different PR frame with zero adapter calls 223ms + → expected Error: Hosted extension sandbox exited wi… { code: '…' } to match object { code: 'plugin_event_unroutable' } + × hosted extension hostile protocol > rejects an import-time different delivery frame with zero adapter calls 265ms + → expected Error: Hosted extension sandbox exited wi… { code: '…' } to match object { code: 'plugin_event_unroutable' } + × hosted extension hostile protocol > rejects an import-time different event frame with zero adapter calls 289ms + → expected Error: Hosted extension sandbox exited wi… { code: '…' } to match object { code: 'plugin_event_unroutable' } + × hosted extension hostile protocol > rejects two forged calls after the authoritative first outcome settles 10154ms + → hostile child did not invoke the adapter + × hosted extension hostile protocol > waits for a pending adapter to reject after a forged child error 10168ms + → hostile child did not invoke the adapter + × hosted extension hostile protocol > waits for a pending adapter to resolve after a forged child error 10155ms + → hostile child did not invoke the adapter + × hosted extension hostile protocol > returns a typed adapter rejection even when the hostile child hangs 10206ms + → hostile child did not invoke the adapter + ❯ tests/authored-node-runtime.test.ts (16 tests | 16 skipped) 13ms + ✓ tests/artifact-gates.test.ts (27 tests) 252ms + ✓ tests/hosted-base-snapshot.test.ts (18 tests) 2328ms + ✓ hosted base private snapshot > stops streaming project entries at the shared count limit 2233ms + ✓ tests/close-pr-flow.test.ts (35 tests) 21545ms + ✓ close-pr journaled repair loop > reads an existing Bugbot finding, repairs in the same worktree, pushes and re-verifies before merging 2378ms + ✓ close-pr journaled repair loop > opens a PR and feeds failed CI logs into the repair agent 2531ms + ✓ close-pr journaled repair loop > pins the current generated model for codex when no override is supplied 3829ms + ✓ close-pr journaled repair loop > pins the current generated model for claude when no override is supplied 4280ms + ✓ close-pr journaled repair loop > parks after exactly three nonconverging repairs, with accumulated blockers 2423ms + ✓ close-pr journaled repair loop > can converge on the third repair 2796ms + ✓ close-pr journaled repair loop > executes the deterministic commit and force-push steps against a local Git remote, including a no-op repair 3058ms + ✓ tests/cloud-connect.test.ts (24 tests) 3497ms + ✓ hosted verbs connect before they submit > flows run --cloud submits once the prompt connected the integration 2243ms + ✓ tests/journal-client.test.ts (17 tests) 92ms + ✓ tests/authored-node-result.test.ts (45 tests) 21ms + ✓ tests/verb-field-lint.test.ts (99 tests) 592ms + ✓ tests/bundle.test.ts (26 tests) 11718ms + ✓ immutable bundles > returns exit 2 naming a byte-flipped payload and refuses to reuse corruption 683ms + ✓ immutable bundles > verifies with --verify in any position and answers --json with one object 1412ms + ✓ immutable bundles > refuses --out with --verify rather than ignoring the destination 866ms + ✓ immutable bundles > builds and verifies the canonical YAML fixture through the compiled CLI 1869ms + ✓ immutable bundles > emits the ephemeral warning on CLI stderr and uses the default output directory 851ms + ✓ immutable bundles > refuses build-provable CLI resolution errors without environment probes 438ms + ✓ immutable bundles > builds a standalone TS fixture twice with identical executable hashes 2643ms + ✓ immutable bundles > refuses to label installed dependency drift with lockfile pins 430ms + ✓ immutable bundles > refuses invalid CLI arguments %j 403ms + ✓ immutable bundles > refuses invalid CLI arguments "--out" 423ms + ✓ immutable bundles > refuses invalid CLI arguments "--verify" 397ms + ✓ immutable bundles > refuses invalid CLI arguments "--verify" 524ms + ✓ immutable bundles > refuses invalid CLI arguments "--out" 602ms + ✓ tests/validate.test.ts (68 tests) 44ms + ✓ tests/shipped-source-flow-provenance-repairs.test.ts (1 test) 36974ms + ✓ shipped-source flow provenance repairs > audits repaired writer, alias, binding, and cyclic provenance forms 36974ms + ✓ tests/agent-relay-transport.test.ts (17 tests) 2300ms + ✓ Relay completion at the journal boundary > does not complete at readiness and journals exact output, receipt, and priced accounting 1010ms + ✓ Relay completion at the journal boundary > aborts polling on rejected renewal and never writes a stale completion 1002ms + ✓ tests/tick-source.test.ts (33 tests) 22ms + ✓ tests/flow-executor-chain.test.ts (14 tests) 12534ms + ✓ flow executor LLM and output-binding chain > runs f.llm -> f.agent -> f.run with schema-verified journal output and the exact allowed model 1319ms + ✓ flow executor LLM and output-binding chain > runs a dollar-budgeted authored Claude agent with the same default used by preflight 949ms + ✓ flow executor LLM and output-binding chain > fails invalid LLM output before the next step: not JSON 327ms + ✓ flow executor LLM and output-binding chain > fails invalid LLM output before the next step: {"message":7} 398ms + ✓ flow executor LLM and output-binding chain > preserves JSON values without promoting them to process wrappers: null 371ms + ✓ flow executor LLM and output-binding chain > preserves JSON values without promoting them to process wrappers: [1,2] 330ms + ✓ flow executor LLM and output-binding chain > preserves JSON values without promoting them to process wrappers: "hello" 386ms + ✓ flow executor LLM and output-binding chain > runs the exact authored flagship f.llm -> f.agent -> f.run path through the durable CLI root 2082ms + ✓ flow executor LLM and output-binding chain > resumes an interrupted durable authored root without replaying completed flagship effects 3606ms + ✓ flow executor LLM and output-binding chain > passes a declarative verified value through an agent into a deterministic artifact 842ms + ✓ flow executor LLM and output-binding chain > flows run consumes YAML bindings and resume reuses the original journal output 1265ms + ✓ tests/authored-step-graph.test.ts (25 tests) 832ms + ✓ the authored step DAG > does not walk a long-running step's own polling chain to find its dependents' edges 309ms + ✓ tests/cloud-mirror.test.ts (14 tests) 35ms + ✓ tests/pr-review-post.test.ts (21 tests) 2163ms + ✓ tests/authored-flow-lifecycle-executor.test.ts (27 tests) 616ms + ✓ tests/authored-step-terminal-completion.test.ts (13 tests) 4884ms + ✓ readCompletedStepOutput on an adopted gated child whose gate has not started > refuses a producer success when the wait ends with the run still not terminal 2007ms + ✓ readCompletedStepOutput given a suspended known status (#441) > refuses a producer success while the child is still not terminal 2008ms + ✓ tests/step-failure-excerpt.test.ts (42 tests) 200ms + ✓ tests/cloud-mirror-step.test.ts (17 tests) 14ms +(node:44209) ExperimentalWarning: SQLite is an experimental feature and might change at any time +(Use `node --trace-warnings ...` to show where the warning was created) + ✓ tests/cli-replay.test.ts (38 tests) 1349ms + ✓ flows replay > --json is byte-identical across two CLI invocations (diff) 915ms + ✓ tests/authored-flow-slack.test.ts (7 tests) 2171ms + ✓ authored Slack helper effects > replays after SIGKILL before confirm with the same token and one successful completion 682ms + ✓ authored Slack helper effects > replays after SIGKILL before complete with the same token and one successful completion 856ms + ✓ tests/wrapper-execution-duration.test.ts (7 tests) 10841ms + ✓ keeps the handshake deadline independent of the removed execution deadline 10053ms + ✓ still lets a lease abort stop an unlimited wrapper before it produces output 519ms + ✓ tests/tick-runner.test.ts (22 tests) 2442ms + ✓ CLI argument parsing refuses coercion rather than accepting it > refuses --interval-ms fractional as an invocation error 401ms + ✓ CLI argument parsing refuses coercion rather than accepting it > refuses --interval-ms exponent notation as an invocation error 405ms + ✓ CLI argument parsing refuses coercion rather than accepting it > refuses --interval-ms hex as an invocation error 397ms + ✓ CLI argument parsing refuses coercion rather than accepting it > refuses --interval-ms trailing text as an invocation error 414ms + ✓ CLI argument parsing refuses coercion rather than accepting it > refuses --interval-ms empty as an invocation error 404ms + ✓ CLI argument parsing refuses coercion rather than accepting it > accepts an exact integer and proceeds past parsing 394ms + ✓ tests/authored-step-index.test.ts (17 tests) 18ms + ✓ tests/named-gate-diagnostics.test.ts (20 tests) 703ms + ✓ tests/authored-agent-artifacts.test.ts (5 tests) 366ms + ✓ tests/direct-input.test.ts (6 tests) 6640ms + ✓ direct .flow.ts input through the built CLI and live runtime > returns exit 3 for an authored human handoff and persists its outcome 676ms + ✓ direct .flow.ts input through the built CLI and live runtime > returns exit 1 for an authored step_failed verdict and persists its outcome 682ms + ✓ direct .flow.ts input through the built CLI and live runtime > executes inline and file JSON input through relayflowd 2736ms + ✓ direct .flow.ts input through the built CLI and live runtime > refuses missing and malformed input before contacting relayflowd 1613ms + ✓ direct .flow.ts input through the built CLI and live runtime > does not run the authored body before daemon availability 504ms + ✓ direct .flow.ts input through the built CLI and live runtime > refuses oversized file input before contacting relayflowd 427ms + ✓ tests/worker-transcript.test.ts (9 tests) 924ms + ✓ tests/gate-contract.test.ts (20 tests) 150ms +Stopped: a Linear ticket must carry its identifier (like TECH-42) so the pull request can link back. +Stopped: a Linear ticket must carry its identifier (like TECH-42) so the pull request can link back. +Stopped: invalid pull-request metadata (duplicate-linear-closing-reference). No branch was pushed and no pull request was opened. +Stopped: invalid pull-request metadata (duplicate-linear-closing-reference). No branch was pushed and no pull request was opened. +Stopped: invalid pull-request metadata (duplicate-github-closing-reference). No branch was pushed and no pull request was opened. +Stopped: invalid pull-request metadata (malformed-review-scope). No branch was pushed and no pull request was opened. +Stopped: invalid pull-request metadata (malformed-review-scope). No branch was pushed and no pull request was opened. +Stopped: could not read the reviewed head commit. Nothing was pushed. +Stopped: could not read the reviewed head commit. Nothing was pushed. +Stopped: could not read the reviewed head commit. Nothing was pushed. + ✓ tests/canonical-software-factory.test.ts (25 tests) 853ms + ✓ tests/authored-human.test.ts (13 tests) 95ms + ✓ tests/wrapper-exit-drain.test.ts (10 tests) 3531ms + ✓ reports a signalled wrapper death while a pipe is held, with its output intact 380ms + ✓ lets a lease abort outrank a successful exit still being drained 536ms + ✓ does not let a later drain overwrite abort while group confirmation is pending 637ms + ✓ tests/worker-cli-result-exit.test.ts (7 tests) 34868ms + ✓ a Claude agent step completes on its result, not only on process exit > settles a hung, successful run within the grace and stops its whole tree 32623ms + ✓ a Claude agent step completes on its result, not only on process exit > maps an error result on a hung run to a failed exit 31623ms + ✓ a Claude agent step completes on its result, not only on process exit > leaves a hang before any result to the existing stops 32015ms + ✓ an agent tree does not outlive the process that spawned it > kills the agent group when the run process is terminated by SIGTERM 801ms + ✓ an agent tree does not outlive the process that spawned it > removes a wrapper alias on host exit after group death stays unprovable 1352ms + ✓ tests/cloud-schedule.test.ts (17 tests) 5656ms + ✓ schedule lowering > marks a non-grid cron as Cloud-only rather than approximating it, with a silence budget from its own cadence 2998ms + ✓ flows check prints declared schedules > shows the lowering for a fixed interval and the Cloud-only note for a real cron 2025ms + ✓ tests/authored-run-failure-evidence.test.ts (9 tests) 981ms + ✓ the child index after the process that wrote it is gone > still names every child, with its own run id, after a daemon restart 488ms + ✓ tests/cli-hn-monitor.test.ts (16 tests) 94ms + ✓ tests/spec-parity.test.ts (46 tests) 512ms + ✓ tests/authored-activity.test.ts (16 tests) 111ms + ✓ tests/run-projection.test.ts (13 tests) 11ms + ✓ tests/agent-artifacts-live.test.ts (5 tests) 4693ms + ✓ agent artifacts and gates through the built CLI, a real daemon and the local agent > journals the files the agent wrote, including under a dot-directory, and every artifact gate passes on that journal 1321ms + ✓ agent artifacts and gates through the built CLI, a real daemon and the local agent > fails the run when the artifact_exists gate names a file the agent did not write 882ms + ✓ agent artifacts and gates through the built CLI, a real daemon and the local agent > fails the run with the author reason when a predicate gate returns false, journaling the verdict 828ms + ✓ review follow-ups > applies a predicate gate on a helper step too, and journals its verdict 930ms + ✓ review follow-ups > records predicate verdicts on the root run so a resume reuses them instead of re-running the closure 730ms + ✓ tests/daemon-lifecycle-live.test.ts (9 tests) 7184ms + ✓ flows run against a data dir with no daemon (§6 test 7) > cold start spawns exactly one daemon, the run succeeds, and the daemon outlives the CLI 490ms + ✓ flows run against a data dir with no daemon (§6 test 7) > polls, bounded, for a daemon that holds the lock before it binds 1407ms + ✓ flows run against a data dir with no daemon (§6 test 7) > attaches to a serving daemon that has not published a connection file 488ms + ✓ flows run against a data dir with no daemon (§6 test 7) > a second run attaches to the daemon the first one started, spawning nothing 1082ms + ✓ flows run against a data dir with no daemon (§6 test 7) > detects a stale connection file left by a hard kill and starts a fresh daemon 1051ms + ✓ concurrent invocations against one empty data dir (§6 test 15) > ends with exactly one daemon owning the socket, and both runs succeed 1280ms + ✓ refusals from a spawn that cannot produce a daemon > names relayflowd_not_found rather than falling through to PATH 429ms + ✓ refusals from a spawn that cannot produce a daemon > names daemon_start_failed and quotes the daemon log when startup dies 483ms + ✓ refusals from a spawn that cannot produce a daemon > refuses a daemon speaking another protocol version instead of binding over it 471ms + ✓ tests/agent-transcript-live.test.ts (4 tests) 3811ms + ✓ the transcript digest through the built CLI, a real daemon and the local agent > preserves structured agent failure details and its completed root index 1067ms + ✓ the transcript digest through the built CLI, a real daemon and the local agent > preserves structured llm failure details and its completed root index 887ms + ✓ the transcript digest through the built CLI, a real daemon and the local agent > journals the digest in trajectory_tail on a successful agent step and writes the file it points at 915ms + ✓ the transcript digest through the built CLI, a real daemon and the local agent > on a failed agent step, names the failure and the transcript in the terminal diagnostic, redacted 941ms + ✓ tests/resume-local-agent.test.ts (8 tests) 19ms +(node:47667) Warning: Transcript tail for run-9/analyze attempt 1 (stdout) could not be written; the step continues without it: EACCES: permission denied, mkdir '/tmp/transcript-tail-tdIcb8/runs/run-9/steps' +(Use `node --trace-warnings ...` to show where the warning was created) + ✓ tests/transcript-tail.test.ts (11 tests) 1842ms + ✓ direct agent spawn > tees stdout and stderr into tail files that name the dispatch 748ms + ✓ direct agent spawn > completes the step when the tail directory cannot be created 805ms + ✓ tests/advisory-outcome.test.ts (23 tests) 80ms + ✓ tests/shipped-source-cubic-regressions.test.ts (5 tests) 12584ms + ✓ shipped-source adversarial provenance regressions > retains callable writes through member mutation, spreads, this, holes, and alternate receivers 6908ms + ✓ shipped-source adversarial provenance regressions > does not manufacture intrinsic writes or comma-left callables 2491ms + ✓ shipped-source adversarial provenance regressions > treats constructor and implicit-this receiver escapes as possible worker writes 602ms + ✓ shipped-source adversarial provenance regressions > maps pure helper parameters and refuses mutations or conditional assignments as proofs 1953ms + ✓ shipped-source adversarial provenance regressions > does not apply later alias assignments retroactively to copied values 628ms + ✓ tests/agent-cwd-live.test.ts (4 tests) 3322ms + ✓ agents drive two checkouts under one run root > runs each CLI in its declared directory, and the run is not refused as an unknown field 1029ms + ✓ agents drive two checkouts under one run root > gates on an artifact path relative to the agent directory 862ms + ✓ a declaration this contract cannot honour is refused at its own edge > refuses a path that climbs out of the run root without starting a run at all 680ms + ✓ a declaration this contract cannot honour is refused at its own edge > fails the step with the reason when the directory is not there, rather than running somewhere else 749ms + ✓ tests/authored-helpers.test.ts (6 tests) 3173ms + ✓ runs every available provider through the real kernel and resumes completed effects without a second write 1689ms + ✓ replays after SIGKILL before confirm with the same token and one successful completion 590ms + ✓ replays after SIGKILL before complete with the same token and one successful completion 547ms + ✓ tests/cloud-mirror-session.test.ts (12 tests) 14ms + ✓ tests/agent-cwd.test.ts (53 tests) 49ms + ✓ tests/authored-flow-operation.test.ts (24 tests) 547ms + ✓ tests/budget-attribution.test.ts (10 tests) 9ms + ✓ tests/pty-sidechannel.test.ts (14 tests) 9271ms + ✓ view attach preserves worker completion and marks only drive 1089ms + ✓ drive attach preserves worker completion and marks only drive 590ms + ✓ passthrough attach preserves worker completion and marks only drive 1121ms + ✓ none attach preserves worker completion and marks only drive 1047ms + ✓ none subscriber lets an unattended CLI read EOF 630ms + ✓ view subscriber lets an unattended CLI read EOF 586ms + ✓ passthrough subscriber lets an unattended CLI read EOF 609ms + ✓ incomplete subscriber lets an unattended CLI read EOF 560ms + ✓ unattended Codex receives closed stdin before startup instead of entering its additional-input lifecycle 640ms + ✓ ends driven stdin when the last drive peer disconnects after spawn 669ms + ✓ rejects drive after EOF without marking human intervention 866ms + ✓ delivers all drive bytes in order across child stdin backpressure 824ms + ✓ tests/helper-reference.test.ts (30 tests) 27ms + ✓ tests/flow-requirements.test.ts (14 tests) 911ms + ✓ flows check prints REQUIRES > names the helper, the harness and the mcp server of an authored flow 620ms + ✓ tests/backlog-picker.test.ts (14 tests) 45ms + ✓ tests/plugin-store-bounds.test.ts (11 tests) 88ms + ✓ tests/cloud-mirror-live.test.ts (3 tests) 2999ms + ✓ a local run on the Cloud dashboard > registers, publishes its steps and its log, and reports terminal last 584ms + ✓ a local run on the Cloud dashboard > sends nothing at all unless it is asked to 1407ms + ✓ a local run on the Cloud dashboard > publishes a composed authored flow as one connected dashboard DAG 884ms + ✓ tests/classify-outcome.test.ts (11 tests) 5924ms + ✓ classifyOutcome > gives up and reports when a running run never becomes classifiable 2008ms + ✓ the remedy on a worker park > follows a step through a retry backoff longer than the unclassified bound 3004ms + ✓ the remedy on a worker park > follows a run.start outcome that is already running on a retried attempt 503ms + ✓ tests/authored-completion-recovery.test.ts (5 tests) 489ms + ✓ tests/backlog-picker-flow.test.ts (6 tests) 280ms + ✓ tests/hosted-extension-protocol-intrinsics.test.ts (6 tests) 14ms + ✓ tests/preflight-permissions-unenforced.test.ts (17 tests) 725ms + ✓ an authored TypeScript body is out of reach, and spec.ts says so > checks clean on a .flow.ts whose body declares permissions 677ms + ✓ tests/budget-unmetered-live.test.ts (4 tests) 1760ms + ✓ unmetered budget spend through the live kernel > runs an unpriced step under a dollar budget without tripping it, journaling unknown dollars 658ms + ✓ unmetered budget spend through the live kernel > journals an unpriced claude step's reported cost beside unchanged metered usage, and the verdict is unchanged 477ms + ✓ unmetered budget spend through the live kernel > still counts an unpriced step toward a token budget 333ms + ✓ tests/stuck-run-triage.test.ts (22 tests) 3158ms + ✓ stuck-run-triage shell text > collects tails with no GNU timeout on PATH, as on a stock macOS 3109ms + ✓ tests/hosted-extension-routing.test.ts (7 tests) 11ms + ✓ tests/webhook.test.ts (9 tests) 1641ms + ✓ webhook ingress > checks TS declarations against flows.json without invoking handlers 1320ms + ✓ tests/redact.test.ts (54 tests) 8ms + ✓ tests/cli-probe.test.ts (17 tests) 2009ms + ✓ tests/authored-advisory-run-live.test.ts (16 tests) 1105ms + ✓ tests/webhook-live.test.ts (6 tests) 10509ms + ✓ executes and deduplicates 'app_mention' only for its provider and matching payload 1642ms + ✓ executes and deduplicates 'reaction_added' only for its provider and matching payload 1613ms + ✓ executes and deduplicates 'pull_request' only for its provider and matching payload 1671ms + ✓ flows serve-webhook writes JSON before the daemon starts, then journals and archives exactly once 1552ms + ✓ replays a dropped file after SIGKILL before spawn 497ms + ✓ resumes the same journal after SIGKILL after spawn and before acknowledgement 3533ms + ✓ tests/local-agent-live.test.ts (7 tests) 42677ms + ✓ built CLI local agent against a real daemon > dispatches through the wrapper and keeps --json stdout report-shaped 957ms + ✓ built CLI local agent against a real daemon > runs beyond the initial 30-second lease without a second invocation 35972ms + ✓ built CLI local agent against a real daemon > renders actual agent completion in text output 841ms + ✓ built CLI local agent against a real daemon > returns a failed run when the agent process fails 787ms + ✓ built CLI local agent against a real daemon > prints a remedy that runs the parked authored flow to completion 1451ms + ✓ built CLI local agent against a real daemon > prints a remedy that runs, for a run started from an input file too long to be one 2000ms + ✓ built CLI local agent against a real daemon > refuses a workspace it cannot pin before invoking the agent 667ms + ✓ tests/authored-parallel-agents.test.ts (8 tests) 9354ms + ✓ authored steps under local workers with capacity > runs more concurrent f.llm calls than the worker holds side by side, never more than its capacity 1160ms + ✓ authored steps under local workers with capacity > completes more concurrent f.agent calls than the worker holds: the overflow waits for a slot instead of parking 1545ms + ✓ authored steps under local workers with capacity > runs agents in distinct working directories side by side (the kernel carries cwd) 652ms + ✓ authored steps under local workers with capacity > serializes agents whose cwd is a symlink alias of the same directory 1046ms + ✓ authored steps under local workers with capacity > serializes agents whose cwd is a directory nested inside the other 1068ms + ✓ authored steps under local workers with capacity > never starts queued agents once the body has failed 1605ms + ✓ authored steps under local workers with capacity > never starts a queued agent when the agent holding the only slot fails 1625ms + ✓ authored steps under local workers with capacity > parks the overflow when the body is not told the capacity (the defect this closes) 652ms + ✓ tests/check-daemon-validation.test.ts (20 tests) 2815ms + ✓ real CLI refuses skew in auto and required modes 923ms + ✓ real CLI labels daemon and offline passes, including JSON 1355ms + ✓ real CLI refuses an invalid RELAYFLOWD_BIN in required mode 420ms + ✓ tests/human-live.test.ts (3 tests) 7344ms + ✓ f.human against a real daemon > parks with the question, refuses wrong answers, records one, and resumes to success 4367ms + ✓ f.human against a real daemon > a "no" is a value the body branches on: declined, exit 0, no effect 1797ms + ✓ f.human against a real daemon > refuses to answer a run the daemon does not know 1179ms + ✓ tests/check-worker-surface.test.ts (11 tests) 104ms + ✓ tests/authored-step-failed.test.ts (10 tests) 41ms +(node:52746) ExperimentalWarning: SQLite is an experimental feature and might change at any time +(Use `node --trace-warnings ...` to show where the warning was created) + ✓ tests/authored-status-detail.test.ts (20 tests) 137ms + ✓ tests/budget-preflight.test.ts (25 tests) 18ms + ✓ tests/cli-watch.test.ts (11 tests) 18517ms + ✓ flows check --watch > forwards required daemon validation through watch despite the offline test environment 846ms + ✓ flows check --watch > rechecks syntax errors, clears once, and returns the last refusal on Ctrl-C 1419ms + ✓ flows check --watch > streams JSON lines without ANSI, recovers after atomic saves, and exits zero after repair 1989ms + ✓ flows check --watch > coalesces 20 concurrent saves into at most two rechecks 1958ms + ✓ flows check --watch > watches transitive relative use imports, cycles, and nearest config changes 2705ms + ✓ flows check --watch > refreshes the import graph and notices missing imports being created 2593ms + ✓ flows check --watch > reloads authored TypeScript instead of reusing the first imported definition 1982ms + ✓ flows check --watch > detects a nearer config appearing and falls back after it is deleted 2017ms + ✓ flows check --watch > keeps watching after the target is deleted and recreated 2187ms + ✓ flows check --watch > queues changes during a slow check without overlapping checks 817ms + ✓ tests/authored-retried-child-resume-live.test.ts (2 tests) 1587ms + ✓ an authored step whose child run retried an attempt > resumes after a kill mid-step and reads the terminal completion, not the crashed one 1420ms + ✓ tests/provider-trigger-contract.test.ts (7 tests) 1239ms + ✓ provider trigger contract > accepts one subscription from each of five providers and refuses a bogus event on any of them 699ms + ✓ provider trigger contract > fails `flows check` before deployment and passes once the event is real 535ms + ✓ tests/work-package-consumer.test.ts (13 tests) 147ms + ✓ tests/shipped-source-flow-header-provenance.test.ts (1 test) 3082ms + ✓ shipped-source flow header provenance > fails closed for unsafe authored and declarative headers 3081ms + ✓ tests/helpers-fanout.test.ts (96 tests) 177ms +(node:53157) ExperimentalWarning: SQLite is an experimental feature and might change at any time +(Use `node --trace-warnings ...` to show where the warning was created) + ✓ tests/authored-step-graph-live.test.ts (1 test) 972ms + ✓ the authored step DAG through the live kernel > carries labels and predecessors on every index record and journal step, ids unchanged 971ms + ✓ tests/named-gate-journal.test.ts (5 tests) 2092ms + ✓ a lowered subprocess_gate journals the gate command's streams > persists what the gate printed before a timeout killed it 844ms + ✓ a gate on an agent step > journals the command's streams and surfaces them in the authored failure 871ms + ✓ tests/yaml-local-agent-live.test.ts (9 tests) 6855ms + ✓ YAML --local-agent through the built CLI and real daemon > runs with the checked step CLI and model and journals done 725ms + ✓ YAML --local-agent through the built CLI and real daemon > runs with the checked named CLI and model and journals done 676ms + ✓ YAML --local-agent through the built CLI and real daemon > runs with the checked flow CLI and model and journals done 701ms + ✓ YAML --local-agent through the built CLI and real daemon > runs with the checked project CLI and model and journals done 661ms + ✓ YAML --local-agent through the built CLI and real daemon > still parks without --local-agent 589ms + ✓ YAML --local-agent through the built CLI and real daemon > resumes a parked spec run with --local-agent instead of parking identically again 1072ms + ✓ YAML --local-agent through the built CLI and real daemon > parks a second time with a different message when the attached worker is not eligible 1035ms + ✓ YAML --local-agent through the built CLI and real daemon > reports the agent process failure 807ms + ✓ YAML --local-agent through the built CLI and real daemon > preserves declared workspace surfaces that the local worker cannot pin 588ms + ✓ tests/generate-triggers.test.ts (7 tests) 1225ms + ✓ discovers new adapters, preserves exact event names, and prefers adapter-local mappings 411ms + ✓ tests/local-agent-remedy.test.ts (16 tests) 16ms + ✓ tests/yaml-helpers.test.ts (34 tests) 73ms + ✓ tests/direct-run-failure.test.ts (12 tests) 20ms + ✓ tests/authored-agent-permissions.test.ts (27 tests) 956ms + ✓ tests/authored-detail-live.test.ts (3 tests) 4060ms + ✓ carries done("step_failed", { detail }) into the report, the journal and flows status 2153ms + ✓ reports a detail a caller sliced through an emoji, instead of hanging on it 668ms + ✓ leaves a one-argument done("step_failed") reporting exactly as it always did 1238ms + ✓ tests/live-event-activities.test.ts (2 tests) 402ms + ❯ tests/software-garden-babysitter-composition.test.ts (6 tests | 2 failed) 988ms + × canonical Software Garden + Babysitter composition > executes the pinned composition and preserves queued/duplicate replay receipts 396ms + → Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + × canonical Software Garden + Babysitter composition > propagates capability denial without a retry or fallback 500ms + → expected Error: Hosted extension sandbox exited wi… { code: '…' } to be Error: live babysit label is absent // Object.is equality + ✓ tests/worker-lease.test.ts (7 tests) 47ms + ✓ tests/worker-lease-lost.test.ts (17 tests) 18ms + ✓ tests/webhook-hardening.test.ts (11 tests) 79ms + ✓ tests/authored-probe-cache.test.ts (5 tests) 22230ms + ✓ authored run CLI probe cache > nine calls have no expired attempts at capacity 1 7637ms + ✓ authored run CLI probe cache > nine calls have no expired attempts at capacity 4 5526ms + ✓ authored run CLI probe cache > does not serialize nine starts behind nine probes, and probes again on a new run 7258ms + ✓ authored run CLI probe cache > caches probe failures while refusing all nine calls 441ms + ✓ authored run CLI probe cache > shares probe results across agent calls too 1367ms + ✓ tests/yaml-declared-streams-live.test.ts (8 tests) 5576ms + ✓ YAML declared streams through the built CLI and real daemon > runs with the checked step CLI and model and journals done 661ms + ✓ YAML declared streams through the built CLI and real daemon > runs with the checked named CLI and model and journals done 643ms + ✓ YAML declared streams through the built CLI and real daemon > runs with the checked flow CLI and model and journals done 682ms + ✓ YAML declared streams through the built CLI and real daemon > runs with the checked project CLI and model and journals done 661ms + ✓ YAML declared streams through the built CLI and real daemon > still parks without --local-agent 589ms + ✓ YAML declared streams through the built CLI and real daemon > reports the agent process failure 673ms + ✓ YAML declared streams through the built CLI and real daemon > resumes the journaled stream declarations after the input YAML changes 1092ms + ✓ YAML declared streams through the built CLI and real daemon > preserves declared workspace surfaces that the local worker cannot pin 575ms + ✓ tests/human-to.test.ts (8 tests) 16ms + ✓ tests/worker-lease-drift-live.test.ts (3 tests) 36342ms + ✓ worker lease under clock skew between worker and daemon > renews before the daemon deadline when the worker clock runs 75s behind the daemon 36112ms +(node:56287) ExperimentalWarning: SQLite is an experimental feature and might change at any time +(Use `node --trace-warnings ...` to show where the warning was created) + ✓ tests/plugin-loader.test.ts (9 tests) 193ms + ✓ tests/authored-dispatch-live.test.ts (2 tests) 2778ms + ✓ durable child flow dispatch > runs a declared child in the parent DAG and replays it without repeating effects 1895ms + ✓ durable child flow dispatch > lowers a named gate attached to the dispatch receipt 882ms + ✓ tests/deploy.test.ts (11 tests) 5694ms + ✓ flows deploy file buckets > publishes the full signed layout byte-for-byte and redeploys as a noop 896ms + ✓ flows deploy file buckets > answers --json with one object per outcome 905ms + ✓ flows deploy file buckets > reports a refusal as JSON under --json 413ms + ✓ flows deploy file buckets > refuses a missing local bundle before creating the bucket 447ms + ✓ flows deploy file buckets > refuses an unreachable bucket before copying 441ms + ✓ flows deploy file buckets > refuses an unwritable bucket 413ms + ✓ flows deploy file buckets > refuses local tampering of spec.canonical.json 416ms + ✓ flows deploy file buckets > refuses local tampering of identity.json 415ms + ✓ flows deploy file buckets > refuses asset bundles instead of using daemon-relative files 431ms + ✓ flows deploy file buckets > never labels a corrupt existing deployment as a noop 874ms + ✓ tests/bin.test.ts (12 tests) 6549ms + ✓ built flows binary > prints the installed SDK version for --version 426ms + ✓ built flows binary > prints the installed SDK version for -V 425ms + ✓ built flows binary > keeps version flags strict when extra arguments are supplied 412ms + ✓ built flows binary > prints the installed SDK version from the standalone binary for --version 1116ms + ✓ built flows binary > prints the installed SDK version from the standalone binary for -V 1105ms + ✓ built flows binary > refuses through a symlink to the built artifact 416ms + ✓ built flows binary > refuses through a symlinked directory component 429ms + ✓ built flows binary > classifies a signal-terminated auth probe as probe_failed 936ms + ✓ built flows binary > classifies an unavailable PATH resolver as probe_failed 436ms + ✓ built flows binary > does not describe a present non-executable CLI as missing 424ms + ✓ built flows binary > runs one auth probe for three steps sharing a flow CLI 420ms + ✓ tests/babysitter-catalog-export.test.ts (14 tests) 862ms + ✓ Babysitter catalog artifact export > CLI refuses an existing output and leaves no file on validation failure 696ms + ✓ tests/communication.test.ts (10 tests) 13ms + ✓ tests/communication-review.test.ts (6 tests) 338ms + ✓ tests/transport-evidence-bounds.test.ts (7 tests) 10ms + ✓ tests/step-lease.test.ts (36 tests) 66563ms + ✓ f.run leases against the live kernel > enforces 10000 ms for 'sleep 5; printf ok' 5138ms + ✓ f.run leases against the live kernel > enforces 40000 ms for 'sleep 31; printf ok' 31090ms + ✓ f.run leases against the live kernel > enforces 30000 ms for 'sleep 31; printf ok' 30113ms + ✓ tests/typed-output.test.ts (14 tests) 293ms + ✓ tests/agent-timeout-live.test.ts (3 tests) 5179ms + ✓ journals timeout, stops the process, runs a predicate gate and publishes under a budget header 1790ms + ✓ replays timeout after killing the root and daemon, without executing the agent again 2239ms + ✓ lets an author reject timeout through a predicate gate 1149ms + ✓ tests/effect-channel.test.ts (5 tests) 620ms + ✓ tests/worker-slots.test.ts (8 tests) 7ms + ✓ tests/json-schema-bound.test.ts (71 tests) 2403ms + ✓ JSON Schema termination bound > walks a deep schema with an explicit stack rather than recursion 1957ms + ✓ tests/communication-worker.test.ts (17 tests) 1709ms + ✓ tests/cloud-mirror-transport.test.ts (5 tests) 8ms + ✓ tests/mcp-lifecycle.test.ts (4 tests) 13ms + ✓ tests/shipped-source-models.test.ts (2 tests) 65858ms + ✓ first-party shipped source model pins > gives every TypeScript agent and LLM an explicit supported pair or a pinned named-agent declaration 65814ms + ✓ tests/model-selection.test.ts (10 tests) 22ms + ✓ tests/f-memory.test.ts (7 tests) 855ms + ✓ tests/relayflowd-path.test.ts (10 tests) 6ms + ✓ tests/agent-artifacts.test.ts (9 tests) 34ms + ✓ tests/authored-plugin-effect.test.ts (6 tests) 64ms + ✓ tests/agent-timeout-worker.test.ts (9 tests) 2226ms + ✓ stops claude at its declared limit, preserving work and stopping descendants 526ms + ✓ stops codex at its declared limit, preserving work and stopping descendants 516ms + ✓ stops wrapper at its declared limit, preserving work and stopping descendants 541ms + ✓ tests/hosted-hardening.test.ts (11 tests) 14ms + ✓ tests/local-dev-ux.test.ts (8 tests) 18ms + ✓ tests/authored-preflight.test.ts (5 tests) 246ms + ✓ tests/deterministic-llm.test.ts (5 tests) 51ms + ↓ tests/relay-cli-surface-live.test.ts (3 tests | 3 skipped) + ✓ tests/authored-declined.test.ts (13 tests) 54ms + ✓ tests/resume-failure.test.ts (2 tests) 5ms + ✓ tests/dependency-validation.test.ts (6 tests) 733ms + ✓ dependency validation > accepts a valid 10,000-step reverse chain through every direct public boundary 408ms + ✓ tests/worker-lease-lost-live.test.ts (3 tests) 1159ms + ✓ reports journal success after completion rejects with lease_conflict 444ms + ✓ reports journal success after completion rejects with run_terminal 340ms + ✓ reports journal success when a renewal rejects after completion landed 376ms + ✓ tests/authored-hooks.test.ts (5 tests) 5ms + ✓ tests/input-binding.test.ts (12 tests) 229ms + ✓ tests/yaml-helper-effect.test.ts (4 tests) 77ms + ✓ tests/cloud-mirror-ledger.test.ts (7 tests) 1153ms + ✓ the mirror ledger > keeps the newest entries when the count cap bites 1142ms + ✓ tests/scope-preflight.test.ts (6 tests) 9ms + ✓ tests/run-from-digest.test.ts (6 tests) 4657ms + ✓ flows run digest input > submits the sealed canonical spec through the normal journal path without checkout 470ms + ✓ flows run digest input > uses a verified cache hit even after the bucket is removed 434ms + ✓ flows run digest input > resolves deploy.bucket from flows.json and honors explicit override 1251ms + ✓ flows run digest input > refuses an unconfigured bucket 826ms + ✓ flows run digest input > refuses tampered spec.canonical.json before creating run data 844ms + ✓ flows run digest input > refuses tampered identity.json before creating run data 831ms + ✓ tests/build-gate.test.ts (3 tests) 1219ms + ✓ flows build gates on flows check green (#318) > refuses a flow with an unresolvable named-agent CLI and leaves no artifacts 408ms + ✓ flows build gates on flows check green (#318) > --json emits one CheckReport object on stdout on refusal, exits 2, no artifacts 401ms + ✓ flows build gates on flows check green (#318) > builds the bundle on success (regression: gate must not block valid flows) 409ms + ✓ tests/scope-compiler.test.ts (25 tests) 11ms + ✓ tests/worker-cli-abort.test.ts (3 tests) 3809ms + ✓ stops claude and its process group when lease ownership is lost 1386ms + ✓ stops wrapper.mjs and its process group when lease ownership is lost 1378ms + ✓ fails closed when abort cannot prove the process group is gone 1043ms + ✓ tests/hn-poller.test.ts (6 tests) 7ms + ✓ tests/plugin-add.test.ts (7 tests) 1166ms + ✓ typechecks the augmented verb and rejects unknown namespaces 872ms + ✓ tests/authored-step-failed-exit.test.ts (3 tests) 10ms + ✓ tests/retried-step-failure.test.ts (1 test) 620ms + ✓ a retried step failing differently through the live kernel > reports both attempts and says the evidence differs 619ms + ✓ tests/dir-watcher-poller.test.ts (6 tests) 5ms + ✓ tests/subscription-report.test.ts (8 tests) 5ms + ✓ tests/model-pricing.test.ts (10 tests) 6ms + ✓ tests/authored-use-loader.test.ts (6 tests) 1233ms + ✓ authored use graph loader > refuses two direct children with the same dispatch name 322ms + ✓ tests/yaml-helper-live.test.ts (1 test) 1047ms + ✓ runs compiled YAML helpers through the built CLI and kernel effect journal 1046ms + ✓ tests/provider-trigger-executor.test.ts (4 tests) 259ms + ✓ tests/journal-client-completion.test.ts (6 tests) 103ms + ✓ tests/transcript-tail-close.test.ts (2 tests) 1779ms + ✓ a stalled transcript-tail close > does not hold the spawn open past its bounded window 867ms + ✓ a stalled tail close beside a transcript that finished > still journals the transcript pointer 911ms + ✓ tests/wrapper-artifacts-cwd.test.ts (2 tests) 107ms + ✓ tests/hello-deterministic.test.ts (5 tests) 20ms + ✓ tests/worker-lease-sweep.test.ts (4 tests) 18ms + ✓ tests/transcript-exclusion-timeout.test.ts (1 test) 297ms + ✓ tests/cli-adapter.test.ts (4 tests) 5ms + ✓ tests/communication-mixed-resume.test.ts (1 test) 195ms + ✓ tests/work-package-validator.test.ts (7 tests) 6ms + ✓ tests/activity-preflight.test.ts (10 tests) 20ms + ✓ tests/authored-declined-live.test.ts (1 test) 1773ms + ✓ runs an input guard and resumes its completed declined root without repeated effects 1773ms + ✓ tests/cli-answer.test.ts (15 tests) 10ms + ✓ tests/bundle-preflight.test.ts (4 tests) 971ms + ✓ bundle execution preflight > ignores surrounding cache configuration on a verified cache hit 469ms + ✓ bundle execution preflight > uses the built alias for a nameless flow even in a digest-only cache directory 461ms + ✓ tests/agent-timeout-outcome.test.ts (6 tests) 17ms + ✓ tests/agent-relay-hardening.test.ts (12 tests) 13ms + ✓ tests/communication-preflight.test.ts (13 tests) 39ms + ↓ tests/real-cli-adapters.test.ts (3 tests | 3 skipped) + ✓ tests/memoization.test.ts (57 tests) 67ms + ✓ tests/shipped-source-call-array-forwarding.test.ts (1 test) 3077ms + ✓ shipped-source call-array forwarding > maps rest indexes and nested same-helper actuals for workers and flows 3076ms + ✓ tests/local-agent-environment.test.ts (8 tests) 7ms + ✓ tests/fs-descriptor.test.ts (1 test) 4ms + ✓ tests/runtime-dependencies.test.ts (1 test) 235ms + ✓ tests/parse-json-output.test.ts (7 tests) 4ms + ✓ tests/reported-cost.test.ts (4 tests) 3ms + ✓ tests/journal-client-subscriptions.test.ts (1 test) 7ms + ✓ tests/authored-model-probe-kinds.test.ts (2 tests) 177ms + ✓ tests/communication-environment-preflight.test.ts (6 tests) 5ms + ✓ tests/budget-authored-live.test.ts (2 tests) 245ms + ✓ tests/adapters/codex.test.ts (7 tests) 5ms + ✓ tests/slack-writeback.test.ts (1 test) 262ms + ✓ tests/authored-surface-authority.test.ts (2 tests) 19ms + ✓ tests/adapters/claude.test.ts (7 tests) 4ms + ✓ tests/worker-cli-cwd.test.ts (2 tests) 529ms + ✓ runAgentCli — cwd propagation (flows#357) > omits cwd when not provided (inherits parent cwd) 522ms + ✓ tests/shipped-source-parameter-provenance.test.ts (1 test) 1826ms + ✓ shipped-source parameter provenance > keeps caller-supplied identifier and destructured keys unknown 1825ms + ✓ tests/slack-block-kit.test.ts (5 tests) 15ms + ✓ tests/agent-timeout.test.ts (23 tests) 38ms + ✓ tests/communication-history.test.ts (1 test) 4ms + ✓ tests/resume-worker-lease.test.ts (2 tests) 4ms + ✓ tests/adapters/registry.test.ts (4 tests) 5ms + ✓ tests/direct-run-worker-lease.test.ts (2 tests) 7ms + ✓ tests/authored-declined-report.test.ts (6 tests) 7ms + ✓ tests/promise-ancestry.test.ts (2 tests) 286ms + ✓ tests/agent-cwd-validation.test.ts (2 tests) 427ms + ✓ declarative agent cwd > is refused by `flows check` on a YAML flow before anything runs 423ms + ✓ tests/communication-refusal.test.ts (1 test) 16ms + ✓ tests/bundle-transport.test.ts (20 tests) 4383ms + ✓ digest references > accepts and deploys the build output for hello 679ms + ✓ digest references > accepts and deploys the build output for Hello 664ms + ✓ digest references > accepts and deploys the build output for hello.world 860ms + ✓ digest references > accepts and deploys the build output for hello_world 834ms + ✓ digest references > accepts and deploys the build output for 123 635ms + ✓ digest references > accepts and deploys the build output for A_b.c-1 706ms + ✓ tests/cli-cloud-mirror-flag.test.ts (4 tests) 4ms + ✓ tests/catalog-plugins.test.ts (2 tests) 3ms + ✓ tests/check-command-cwd.test.ts (1 test) 14ms + ✓ tests/communication-lazy.test.ts (1 test) 5ms + ✓ tests/cli-progress-wait.test.ts (2 tests) 4ms + ↓ tests/run-digest-live.test.ts (1 test | 1 skipped) + ✓ tests/placement.test.ts (54 tests) 22ms + ✓ tests/preflight-run-cache.test.ts (1 test) 5ms + ✓ tests/canonical-tree.test.ts (1 test) 2ms + ✓ tests/local-agent-stream-selection.test.ts (1 test) 5ms + ✓ tests/run-digest.test.ts (4 tests) 2341ms + ✓ digest run configuration refusals > reports config_invalid before fetching or starting a run for {invalid json 712ms + ✓ digest run configuration refusals > reports config_invalid before fetching or starting a run for {"deploy":{}} 575ms + ✓ digest run configuration refusals > reports config_invalid before fetching or starting a run for {"deploy":{"bucket":123}} 534ms + ✓ digest run configuration refusals > reports config_invalid before fetching or starting a run for {"deploy":{"bucket":""}} 520ms + ✓ tests/communication-tools.test.ts (1 test) 88ms + ✓ tests/authored-admission.test.ts (2 tests) 4ms + ✓ tests/memory.test.ts (18 tests) 8ms + ✓ tests/worker-platform.test.ts (1 test) 3ms +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node scripts/pack-release.mjs surface /tmp/flows-cli-package-9jWQB5/tarballs +PACK_OK @relayflows/surface@2.0.42: package/dist/index.js, package/dist/index.d.ts, package/dist/runtime.js, package/dist/runtime.d.ts +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node scripts/pack-release.mjs sdk /tmp/flows-cli-package-9jWQB5/tarballs +PACK_OK @relayflows/sdk@2.0.42: package/dist/index.js, package/dist/index.d.ts, package/dist/cli.js +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node scripts/pack-release.mjs relayflows /tmp/flows-cli-package-9jWQB5/tarballs +PACK_OK relayflows@2.0.42: package/bin/flows.js +$ npm install --ignore-scripts --omit=optional --no-audit --no-fund /tmp/flows-cli-package-9jWQB5/tarballs/relayflows-2.0.42.tgz /tmp/flows-cli-package-9jWQB5/tarballs/relayflows-sdk-2.0.42.tgz /tmp/flows-cli-package-9jWQB5/tarballs/relayflows-surface-2.0.42.tgz + +added 150 packages in 6s +$ /tmp/flows-cli-package-9jWQB5/local/node_modules/.bin/flows check examples/dependency-upgrade-bot.flow.ts +REQUIRES claude (agent "upgrader") +CHECK PASSED examples/dependency-upgrade-bot.flow.ts [local only: disabled, so daemon acceptance is unproven] +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node /tmp/flows-cli-package-9jWQB5/local/node_modules/relayflows/bin/flows.js check examples/dependency-upgrade-bot.flow.ts +REQUIRES claude (agent "upgrader") +CHECK PASSED examples/dependency-upgrade-bot.flow.ts [local only: disabled, so daemon acceptance is unproven] +$ npm install -g --prefix /tmp/flows-cli-package-9jWQB5/prefix --ignore-scripts --omit=optional --no-audit --no-fund /tmp/flows-cli-package-9jWQB5/tarballs/relayflows-2.0.42.tgz /tmp/flows-cli-package-9jWQB5/tarballs/relayflows-sdk-2.0.42.tgz /tmp/flows-cli-package-9jWQB5/tarballs/relayflows-surface-2.0.42.tgz + +added 294 packages in 4s +$ npm install --ignore-scripts --omit=optional --no-audit --no-fund /tmp/flows-cli-package-9jWQB5/tarballs/relayflows-surface-2.0.42.tgz + +added 140 packages in 2s +$ /tmp/flows-cli-package-9jWQB5/prefix/bin/flows check examples/dependency-upgrade-bot.flow.ts +REQUIRES claude (agent "upgrader") +CHECK PASSED examples/dependency-upgrade-bot.flow.ts [local only: disabled, so daemon acceptance is unproven] +$ /usr/local/share/nvm/versions/node/v25.6.0/bin/node /tmp/flows-cli-package-9jWQB5/prefix/lib/node_modules/relayflows/bin/flows.js check examples/dependency-upgrade-bot.flow.ts +REQUIRES claude (agent "upgrader") +CHECK PASSED examples/dependency-upgrade-bot.flow.ts [local only: disabled, so daemon acceptance is unproven] +CLI_PACKAGE_OK: local and global installs + ✓ tests/cli-package-gate.test.ts (1 test) 20992ms + ✓ checks authored flows with locally and globally installed release tarballs 20991ms +node:internal/modules/run_main:107 + triggerUncaughtException( + ^ + +AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + +2 !== 4 + + at expectPark (file:///home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/tests/fixtures/event-await-cli-probe.mjs:58:10) + at file:///home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/tests/fixtures/event-await-cli-probe.mjs:63:3 { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 2, + expected: 4, + operator: 'strictEqual', + diff: 'simple' +} + +Node.js v25.6.0 + ❯ tests/event-await-cli.test.ts (1 test | 1 failed) 588ms + × parks, restarts, and replays two event wakes through the actual CLI 587ms + → Command failed: /usr/local/share/nvm/versions/node/v25.6.0/bin/node /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/tests/fixtures/event-await-cli-probe.mjs /home/daytona/.relayflow-v2-supervisor/durable/repository +node:internal/modules/run_main:107 + triggerUncaughtException( + ^ + +AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + +2 !== 4 + + at expectPark (file:///home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/tests/fixtures/event-await-cli-probe.mjs:58:10) + at file:///home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/tests/fixtures/event-await-cli-probe.mjs:63:3 { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 2, + expected: 4, + operator: 'strictEqual', + diff: 'simple' +} + +Node.js v25.6.0 + + ✓ tests/authored-parallel-llm.test.ts (6 tests) 117019ms + ✓ parallel llm capacity 1 > deduplicates concurrent preflight probes 2840ms + ✓ parallel llm capacity 1 > completes nine calls without expired child leases during slow preflight 8746ms + ✓ parallel llm capacity 1 > keeps the durable root lease alive across two cold models 48478ms + ✓ parallel llm capacity 4 > deduplicates concurrent preflight probes 1652ms + ✓ parallel llm capacity 4 > completes nine calls without expired child leases during slow preflight 8096ms + ✓ parallel llm capacity 4 > keeps the durable root lease alive across two cold models 47205ms + ✓ tests/shipped-source-worker-invocations.test.ts (1 test) 654714ms + ✓ shipped-source worker invocation resolution > fails closed across direct, extracted, bound, mutable, and escaped callables 654713ms + +⎯⎯⎯⎯⎯⎯ Failed Suites 1 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/authored-node-runtime.test.ts [ tests/authored-node-runtime.test.ts ] +AssertionError: expected '1.3.6' to be '1.4.0' // Object.is equality + +Expected: "1.4.0" +Received: "1.3.6" + + ❯ tests/authored-node-runtime.test.ts:18:77 + 16| + 17| beforeAll(() => { + 18| expect(spawnSync(bun, ['--version'], { encoding: 'utf8' }).stdout.tr… + | ^ + 19| expect(existsSync(daemon), 'build the current kernel or set RELAYFLO… + 20| stage = mkdtempSync(join(tmpdir(), 'authored-standalone-build-')); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/46]⎯ + +⎯⎯⎯⎯⎯⎯ Failed Tests 45 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/babysitter-native-extension.test.ts > native Babysitter extension > runs the exact published 2.0.26 native bytes in the isolated capability path +AssertionError: promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + ❯ tests/babysitter-native-extension.test.ts:153:7 + 151| return { receiptId: `bst_${'a'.repeat(64)}`, status: 'queued' … + 152| } }, + 153| })).resolves.toEqual({ completionReason: 'success', capabilityCall… + | ^ + 154| expect(calls).toEqual([{ delivery: { + 155| deliveryId: 'gh-delivery-7', provider: 'github', eventType: 'pul… + +Caused by: Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'plugin_unsupported' } +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/46]⎯ + + FAIL tests/event-await-cli.test.ts > parks, restarts, and replays two event wakes through the actual CLI +Error: Command failed: /usr/local/share/nvm/versions/node/v25.6.0/bin/node /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/tests/fixtures/event-await-cli-probe.mjs /home/daytona/.relayflow-v2-supervisor/durable/repository +node:internal/modules/run_main:107 + triggerUncaughtException( + ^ + +AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + +2 !== 4 + + at expectPark (file:///home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/tests/fixtures/event-await-cli-probe.mjs:58:10) + at file:///home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk/tests/fixtures/event-await-cli-probe.mjs:63:3 { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 2, + expected: 4, + operator: 'strictEqual', + diff: 'simple' +} + +Node.js v25.6.0 + + ❯ expectPark tests/fixtures/event-await-cli-probe.mjs:58:10 + ❯ tests/event-await-cli.test.ts:9:18 + 7| + 8| it('parks, restarts, and replays two event wakes through the actual CL… + 9| const output = execFileSync(process.execPath, [resolve(here, 'fixtur… + | ^ + 10| resolve(here, '../../..')], { encoding: 'utf8', timeout: 90_000 }); + 11| expect(output).toContain('E2E_PASS:'); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > executes the exact capability-only handler for a queued receipt + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > executes the exact capability-only handler for a duplicate receipt + FAIL tests/hosted-extension-protocol.test.ts > hosted extension hostile protocol > uses captured JSON intrinsics for the complete parent boundary + FAIL tests/software-garden-babysitter-composition.test.ts > canonical Software Garden + Babysitter composition > executes the pinned composition and preserves queued/duplicate replay receipts +Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + 133| : new PluginError('plugin_unsupported', 'Hosted capability rejec… + 134| const refuse = (message: string) => { + 135| const error = new PluginError('plugin_unsupported', message); + | ^ + 136| CHILD_PROCESS_KILL(child, 'SIGKILL'); + 137| if (capabilityState === 'pending') { + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > launches through the captured process primitive after builtin export synchronization +AssertionError: promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + ❯ tests/hosted-extension-isolation.test.ts:283:11 + 281| input: descriptor(), + 282| babysitterTurn: { queue: async () => ({ receiptId: 'receipt-… + 283| })).resolves.toEqual({ completionReason: 'success', capability… + | ^ + 284| } finally { + 285| process.execPath = originalExecPath; + +Caused by: Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'plugin_unsupported' } +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > ignores inherited launcher overrides and decodes manifests with the captured Buffer intrinsic +AssertionError: promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + ❯ tests/hosted-extension-isolation.test.ts:373:11 + 371| input: descriptor('delivery-options'), + 372| babysitterTurn: { queue: async () => ({ receiptId: 'receipt-… + 373| })).resolves.toEqual({ completionReason: 'success', capability… + | ^ + 374| } finally { + 375| Buffer.prototype.toString = bufferToString; + +Caused by: Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'plugin_unsupported' } +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > streams verified bytes when the live store is replaced and no writable staging path exists +AssertionError: promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + ❯ tests/hosted-extension-isolation.test.ts:431:7 + 429| return { receiptId: 'receipt-1', status: 'queued' }; + 430| } }, + 431| })).resolves.toEqual({ completionReason: 'success', capabilityCall… + | ^ + 432| expect(calls).toBe(1); + 433| expect(readFileSync(join(installed.directory, 'babysitter.flow.ts'… + +Caused by: Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'plugin_unsupported' } +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > mounts pinned private Surface bytes when the live package changes before launch +AssertionError: promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + ❯ tests/hosted-extension-isolation.test.ts:456:7 + 454| return { receiptId: 'receipt-1', status: 'queued' }; + 455| } }, + 456| })).resolves.toEqual({ completionReason: 'success', capabilityCall… + | ^ + 457| expect(calls).toBe(1); + 458| expect(readFileSync(join(surfaceRoot, 'dist/flow.js'), 'utf8')).to… + +Caused by: Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'plugin_unsupported' } +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > shields verified Surface files before async settlement +AssertionError: promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + ❯ tests/hosted-extension-isolation.test.ts:532:9 + 530| surfaceRoot, + 531| babysitterTurn: { queue: async () => ({ receiptId: 'receipt-1'… + 532| })).resolves.toEqual({ completionReason: 'success', capabilityCa… + | ^ + 533| } finally { + 534| if (previous === undefined) delete (Array.prototype as { then?: … + +Caused by: Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'plugin_unsupported' } +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > preserves a typed host refusal while disclosing only a fixed marker to the child +AssertionError: expected Error: Hosted extension sandbox exited wi… { code: '…' } to be Error: private Cloud policy detail { code: '…' } // Object.is equality + +- Expected ++ Received + +- [Error: private Cloud policy detail] ++ [Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted ++ ] + + ❯ tests/hosted-extension-isolation.test.ts:560:5 + 558| provider: 'github', eventType: 'pull_request.labeled', deliveryI… + 559| }); + 560| await expect(runVerifiedNativeExtensionSandbox({ + | ^ + 561| artifact: await artifact(source), manifest: validateFlowExtensio… + 562| babysitterTurn: { queue: async () => { throw refusal; } }, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > denies ambient credentials, host files, writes, network, subprocesses, and undeclared context verbs + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > constructs adapter authority with the captured freeze intrinsic +Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + 133| : new PluginError('plugin_unsupported', 'Hosted capability rejec… + 134| const refuse = (message: string) => { + 135| const error = new PluginError('plugin_unsupported', message); + | ^ + 136| CHILD_PROCESS_KILL(child, 'SIGKILL'); + 137| if (capabilityState === 'pending') { + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[11/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > enforces OS address-space and data bounds on native Buffer allocation +AssertionError: expected Error: Hosted extension sandbox exited wi… { code: '…' } to match object { code: 'plugin_unsupported', …(1) } + +- Expected ++ Received + +- Object { ++ PluginError { + "code": "plugin_unsupported", +- "message": StringMatching /(?:Failed to allocate memory|Array buffer allocation failed)/u, + } + + ❯ tests/hosted-extension-isolation.test.ts:646:5 + 644| }); + 645| let calls = 0; + 646| await expect(runVerifiedNativeExtensionSandbox({ + | ^ + 647| artifact: installed, + 648| manifest: validateFlowExtensionManifest(manifest()), + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[12/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > blocks extra handler fields and authority-bearing receipt fields at the parent port +AssertionError: expected Error: Hosted extension sandbox exited wi… { code: '…' } to match object { code: 'plugin_event_unroutable' } + +- Expected ++ Received + +- Object { +- "code": "plugin_event_unroutable", ++ PluginError { ++ "code": "plugin_unsupported", + } + + ❯ tests/hosted-extension-isolation.test.ts:675:5 + 673| }); + 674| let calls = 0; + 675| await expect(runVerifiedNativeExtensionSandbox({ + | ^ + 676| artifact: await artifact(source), manifest: validateFlowExtensio… + 677| babysitterTurn: { queue: async () => { calls += 1; return { rece… + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[13/46]⎯ + + FAIL tests/hosted-extension-isolation.test.ts > hosted extension capability isolation > writes the Surface manifest and protocol without inherited toJSON behavior +AssertionError: promise rejected "Error: Hosted extension sandbox exited wi… { code: '…' }" instead of resolving + ❯ tests/hosted-extension-isolation.test.ts:788:11 + 786| babysitterTurn: { queue: async () => ({ receiptId: 'receipt-… + 787| timeoutMs: 3_000, + 788| })).resolves.toEqual({ completionReason: 'success', capability… + | ^ + 789| } finally { + 790| if (previous === undefined) delete (Object.prototype as { toJS… + +Caused by: Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'plugin_unsupported' } +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[14/46]⎯ + + FAIL tests/hosted-extension-protocol.test.ts > hosted extension hostile protocol > rejects an import-time different PR frame with zero adapter calls + FAIL tests/hosted-extension-protocol.test.ts > hosted extension hostile protocol > rejects an import-time different delivery frame with zero adapter calls + FAIL tests/hosted-extension-protocol.test.ts > hosted extension hostile protocol > rejects an import-time different event frame with zero adapter calls +AssertionError: expected Error: Hosted extension sandbox exited wi… { code: '…' } to match object { code: 'plugin_event_unroutable' } + +- Expected ++ Received + +- Object { +- "code": "plugin_event_unroutable", ++ PluginError { ++ "code": "plugin_unsupported", + } + + ❯ tests/hosted-extension-protocol.test.ts:447:5 + 445| ])('rejects an import-time %s frame with zero adapter calls', async … + 446| let calls = 0; + 447| await expect(runVerifiedNativeExtensionSandbox({ + | ^ + 448| artifact: await artifact(hostileImport([frame, { type: 'error', … + 449| manifest: validateFlowExtensionManifest(manifest()), dispatch: d… + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[15/46]⎯ + + FAIL tests/hosted-extension-protocol.test.ts > hosted extension hostile protocol > rejects two forged calls after the authoritative first outcome settles + FAIL tests/hosted-extension-protocol.test.ts > hosted extension hostile protocol > waits for a pending adapter to reject after a forged child error + FAIL tests/hosted-extension-protocol.test.ts > hosted extension hostile protocol > waits for a pending adapter to resolve after a forged child error + FAIL tests/hosted-extension-protocol.test.ts > hosted extension hostile protocol > returns a typed adapter rejection even when the hostile child hangs +Error: hostile child did not invoke the adapter + ❯ Timeout._onTimeout tests/hosted-extension-protocol.test.ts:135:45 + 133| async function waitForInvocation(invoked: Promise): Promise((resolve, reject) => { + 135| const timeout = setTimeout(() => reject(new Error('hostile child d… + | ^ + 136| void invoked.then(() => { clearTimeout(timeout); resolve(); }, rej… + 137| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[16/46]⎯ + + FAIL tests/live-kernel.test.ts > built flows CLI against live relayflowd > runs hn-monitor analyze-story end-to-end via a stub agent CLI (gate 2 clause 2 demo) +AssertionError: expected { …(12) } to match object { output: { …(3) }, …(1) } +(22 matching properties omitted from actual) + +- Expected ++ Received + + Object { +- "output": Object { +- "reasoning": "stub agent runtime — deterministic output for gate-2 clause-2 demo", +- "relevance_score": 5, +- "story_title": "stub", +- }, ++ "output": null, + "verification": Object { +- "gate": "json_schema", +- "verdict": "pass", ++ "gate": "execution", ++ "verdict": "fail", + }, + } + + ❯ tests/live-kernel.test.ts:657:36 + 655| && (entry as { step_id?: string }).step_id === 'analyze-story', + 656| ) as { payload: { output: unknown; verification: unknown } } | und… + 657| expect(stepCompleted?.payload).toMatchObject({ + | ^ + 658| output: { + 659| story_title: 'stub', + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[17/46]⎯ + + FAIL tests/live-kernel.test.ts > built flows CLI against live relayflowd > hn-monitor analyze-story FAILS verification when the CLI omits required schema fields +AssertionError: expected { …(12) } to match object { …(3) } +(21 matching properties omitted from actual) + +- Expected ++ Received + + Object { +- "completionReason": "retries_exhausted", ++ "completionReason": "worker_error", + "output": null, + "verification": Object { +- "gate": "json_schema", ++ "gate": "execution", + "verdict": "fail", + }, + } + + ❯ tests/live-kernel.test.ts:752:36 + 750| // its verification record names the json_schema rejection. The re… + 751| // parsed value is nulled before the completion is persisted. + 752| expect(stepCompleted?.payload).toMatchObject({ + | ^ + 753| completionReason: 'retries_exhausted', + 754| output: null, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[18/46]⎯ + + FAIL tests/live-kernel.test.ts > built flows CLI against live relayflowd > agent step preserves the CliResult wrapper as output when the CLI emits non-JSON text +AssertionError: expected null not to be null + ❯ tests/live-kernel.test.ts:823:24 + 821| // here (parseJsonOutput returned null on non-JSON stdout) and + 822| // these assertions would all fail. + 823| expect(output).not.toBeNull(); + | ^ + 824| expect(output.exit_code).toBe(0); + 825| expect(output.stdout_tail).toContain('looked at the story'); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[19/46]⎯ + + FAIL tests/live-kernel.test.ts > built flows CLI against live relayflowd > AgentWorker exposes wake_context to the CLI via RELAYFLOW_WAKE_CONTEXT env var (real analyzer prerequisite) +TypeError: Cannot read properties of null (reading 'story_title') + ❯ tests/live-kernel.test.ts:891:42 + 889| ) as { payload: { output: { story_title: string; reasoning: string… + 890| expect(stepCompleted).toBeDefined(); + 891| expect(stepCompleted!.payload.output.story_title).toBe(`echoed:${s… + | ^ + 892| expect(stepCompleted!.payload.output.reasoning).toContain(String(s… + 893| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[20/46]⎯ + + FAIL tests/live-kernel.test.ts > built flows CLI against live relayflowd > AgentWorker leaves RELAYFLOW_WAKE_CONTEXT UNSET when the run has no wake_context (undefined-vs-null pin) +TypeError: Cannot read properties of null (reading 'env_present') + ❯ tests/live-kernel.test.ts:958:38 + 956| ) as { payload: { output: { env_present: boolean } } } | undefined; + 957| expect(completed).toBeDefined(); + 958| expect(completed!.payload.output.env_present).toBe(false); + | ^ + 959| + 960| delete process.env.RELAYFLOW_WAKE_CONTEXT; + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[21/46]⎯ + + FAIL tests/live-kernel.test.ts > built flows CLI against live relayflowd > AgentWorker leaves RELAYFLOW_MODEL UNSET when the step declares no model +TypeError: Cannot read properties of null (reading 'story_title') + ❯ tests/live-kernel.test.ts:1194:38 + 1192| expect(completed).toBeDefined(); + 1193| // UNSET, not EMPTY and not the leaked parent value. + 1194| expect(completed!.payload.output.story_title).toBe('model:UNSET'); + | ^ + 1195| + 1196| delete process.env.RELAYFLOW_MODEL; + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[22/46]⎯ + + FAIL tests/live-kernel.test.ts > built flows CLI against live relayflowd > hn-monitor analyze-story reaches done through the real Claude analyzer CLI +Error: LIVE_ANALYZER_UNAVAILABLE: "/home/daytona/.relayflow-v2-supervisor/durable/repository/testdata/preflight/analyze-story-claude-cli" does not identify as relayflows-agent-cli-v1 — failing because gate-2 acceptance requires the real analyzer to execute. Set RELAYFLOWS_ALLOW_ANALYZER_SKIP=1 only if this run is not gate evidence. + ❯ tests/live-kernel.test.ts:1223:15 + 1221| const notice = `LIVE_ANALYZER_UNAVAILABLE: ${readiness.detail}`; + 1222| if (process.env['RELAYFLOWS_ALLOW_ANALYZER_SKIP'] !== '1') { + 1223| throw new Error( + | ^ + 1224| `${notice} — failing because gate-2 acceptance requires the … + 1225| + 'Set RELAYFLOWS_ALLOW_ANALYZER_SKIP=1 only if this run is … + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[23/46]⎯ + + FAIL tests/live-kernel.test.ts > a relayflow can be scheduled: tick source against live relayflowd > a tick spawns a real run whose step reports the SCHEDULED instant +AssertionError: expected null to deeply equal { schedule_id: 'heartbeat-1m', …(3) } + +- Expected: +Object { + "lag_ms": 43000, + "schedule_id": "heartbeat-1m", + "scheduled_for_ms": 1764000000000, + "slot": 29400000, +} + ++ Received: +null + + ❯ tests/live-kernel.test.ts:1739:39 + 1737| // The bound: the run reports the grid instant and its own lag, so… + 1738| // backfilled run can tell it is running for a slot from the past. + 1739| expect(completed!.payload.output).toEqual({ + | ^ + 1740| schedule_id: 'heartbeat-1m', + 1741| slot: 29_400_000, + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[24/46]⎯ + + FAIL tests/plugin-extension.test.ts > flows add > resolves a branch to its commit, materializes, and records flows.json plus the lockfile +AssertionError: expected 2 to be +0 // Object.is equality + +- Expected ++ Received + +- 0 ++ 2 + + ❯ tests/plugin-extension.test.ts:82:168 + 80| it('resolves a branch to its commit, materializes, and records flows… + 81| const gh = github(); const p = project({ cli: 'claude' }); + 82| expect(await addPlugin('github:AgentWorkforce/flows@feat/babysitte… + | ^ + 83| const config = JSON.parse(readFileSync(join(p.cwd, 'flows.json'), … + 84| expect(config).toEqual({ cli: 'claude', plugins: [REF] }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[25/46]⎯ + + FAIL tests/plugin-extension.test.ts > flows add > keeps the digest stable across identical installs and distinct across content changes +Error: ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + ❯ project tests/plugin-extension.test.ts:32:15 + 30| } + 31| function project(config: unknown = {}) { + 32| const cwd = mkdtempSync(join(tmpdir(), 'plugin-ext-')); dirs.push(cw… + | ^ + 33| writeFileSync(join(cwd, 'flows.json'), JSON.stringify(config)); + 34| const messages: string[] = []; + ❯ tests/plugin-extension.test.ts:107:36 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[26/46]⎯ + + FAIL tests/plugin-extension.test.ts > flows add > recovers both crash points in the flows.json and lock transaction +Error: ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + ❯ project tests/plugin-extension.test.ts:32:15 + 30| } + 31| function project(config: unknown = {}) { + 32| const cwd = mkdtempSync(join(tmpdir(), 'plugin-ext-')); dirs.push(cw… + | ^ + 33| writeFileSync(join(cwd, 'flows.json'), JSON.stringify(config)); + 34| const messages: string[] = []; + ❯ tests/plugin-extension.test.ts:119:17 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[27/46]⎯ + + FAIL tests/plugin-extension.test.ts > flows add > refuses github:AgentWorkforce/flows@nope#examples/babysitter with plugin_source_unresolved and writes nothing + FAIL tests/plugin-extension.test.ts > flows add > refuses github:AgentWorkforce/flows@main#examples/babysitter with plugin_source_unresolved and writes nothing + FAIL tests/plugin-extension.test.ts > flows add > refuses github:AgentWorkforce/flows@feat/babysitter-v2#examples with plugin_manifest_missing and writes nothing + FAIL tests/plugin-extension.test.ts > flows add > refuses github:AgentWorkforce/flows@bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb#examples/babysitter with plugin_source_unresolved and writes nothing + FAIL tests/plugin-extension.test.ts > flows add > refuses github:AgentWorkforce/flows@feat/babysitter-v2#../x with plugin_source_invalid and writes nothing +Error: ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + ❯ project tests/plugin-extension.test.ts:32:15 + 30| } + 31| function project(config: unknown = {}) { + 32| const cwd = mkdtempSync(join(tmpdir(), 'plugin-ext-')); dirs.push(cw… + | ^ + 33| writeFileSync(join(cwd, 'flows.json'), JSON.stringify(config)); + 34| const messages: string[] = []; + ❯ tests/plugin-extension.test.ts:153:36 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[28/46]⎯ + + FAIL tests/plugin-extension.test.ts > flows add > refuses a plugin whose compat excludes this runtime +Error: ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + ❯ project tests/plugin-extension.test.ts:32:15 + 30| } + 31| function project(config: unknown = {}) { + 32| const cwd = mkdtempSync(join(tmpdir(), 'plugin-ext-')); dirs.push(cw… + | ^ + 33| writeFileSync(join(cwd, 'flows.json'), JSON.stringify(config)); + 34| const messages: string[] = []; + ❯ tests/plugin-extension.test.ts:161:36 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[29/46]⎯ + + FAIL tests/plugin-extension.test.ts > flows add > refuses a manifest whose declared source is not where it was fetched from +Error: ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + ❯ project tests/plugin-extension.test.ts:32:15 + 30| } + 31| function project(config: unknown = {}) { + 32| const cwd = mkdtempSync(join(tmpdir(), 'plugin-ext-')); dirs.push(cw… + | ^ + 33| writeFileSync(join(cwd, 'flows.json'), JSON.stringify(config)); + 34| const messages: string[] = []; + ❯ tests/plugin-extension.test.ts:167:15 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[30/46]⎯ + + FAIL tests/plugin-extension.test.ts > flows add > refuses a second source under an already-installed name +Error: ENOSPC: no space left on device, mkdtemp '/tmp/plugin-ext-XXXXXX' + ❯ project tests/plugin-extension.test.ts:32:15 + 30| } + 31| function project(config: unknown = {}) { + 32| const cwd = mkdtempSync(join(tmpdir(), 'plugin-ext-')); dirs.push(cw… + | ^ + 33| writeFileSync(join(cwd, 'flows.json'), JSON.stringify(config)); + 34| const messages: string[] = []; + ❯ tests/plugin-extension.test.ts:172:36 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[31/46]⎯ + + FAIL tests/relay-cli-surface.test.ts > relay-cli surface: drift between `commands` and `run` > carries every declared flag on an invocation that parses +AssertionError: expected [ Array(2) ] to deeply equal [] + +- Expected ++ Received + +- Array [] ++ Array [ ++ "flows check --against-daemon", ++ "flows check --no-daemon-check", ++ ] + + ❯ tests/relay-cli-surface.test.ts:383:23 + 381| } + 382| + 383| expect(uncarried).toEqual([]); + | ^ + 384| }); + 385| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[32/46]⎯ + + FAIL tests/software-garden-babysitter-composition.test.ts > canonical Software Garden + Babysitter composition > propagates capability denial without a retry or fallback +AssertionError: expected Error: Hosted extension sandbox exited wi… { code: '…' } to be Error: live babysit label is absent // Object.is equality + +- Expected ++ Received + +- [Error: live babysit label is absent] ++ [Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted ++ ] + + ❯ tests/software-garden-babysitter-composition.test.ts:139:7 + 137| const refusal = new Error('live babysit label is absent'); + 138| let calls = 0; + 139| await expect(runHostedSoftwareGardenBabysitter({ + | ^ + 140| flowPath: installed.flowPath, + 141| dispatch: dispatch(), + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[33/46]⎯ + +⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯ + +Vitest caught 1 unhandled error during the test run. +This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected. + +⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯ +Error: Hosted extension sandbox exited without a valid completion (exit 1): bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted + + ❯ refuse src/hosted-extension-protocol.ts:135:21 + 133| : new PluginError('plugin_unsupported', 'Hosted capability rejec… + 134| const refuse = (message: string) => { + 135| const error = new PluginError('plugin_unsupported', message); + | ^ + 136| CHILD_PROCESS_KILL(child, 'SIGKILL'); + 137| if (capabilityState === 'pending') { + ❯ ChildProcess. src/hosted-extension-protocol.ts:234:21 + ❯ ChildProcess.emit node:events:520:22 + ❯ maybeClose node:internal/child_process:1084:16 + ❯ Process.ChildProcess._handle.onexit node:internal/child_process:304:5 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'plugin_unsupported' } +This error originated in "tests/hosted-extension-protocol.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +The latest test that might've caused the error is "rejects two forged calls after the authoritative first outcome settles". It might mean one of the following: +- The error was thrown, while Vitest was running this test. +- If the error occurred after the test had been completed, this was the last documented test before it was thrown. +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ + + Test Files 9 failed | 239 passed | 3 skipped (251) + Tests 45 failed | 3801 passed | 23 skipped (3869) + Errors 1 error + Start at 14:24:31 + Duration 655.90s (transform 5.84s, setup 1.28s, collect 83.28s, tests 1770.17s, environment 32ms, prepare 11.03s) + diff --git a/evidence/daemon-check/sdk-minimal-path.txt b/evidence/daemon-check/sdk-minimal-path.txt new file mode 100644 index 000000000..aece65cf1 --- /dev/null +++ b/evidence/daemon-check/sdk-minimal-path.txt @@ -0,0 +1,17 @@ + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + + ✓ tests/check-daemon-validation.test.ts (20 tests) 3104ms + ✓ real CLI refuses skew in auto and required modes 1124ms + ✓ real CLI labels daemon and offline passes, including JSON 1394ms + ✓ real CLI refuses an invalid RELAYFLOWD_BIN in required mode 420ms + ✓ tests/cli.test.ts (71 tests) 3794ms + ✓ flows check CLI > binds a checked relative wrapper to the flow directory for worker execution 1246ms + ✓ flows check CLI > resolves a bare PATH-resolved claude with no declared model, in an isolated PATH 440ms + ✓ flows run/resume CLI over the journal protocol > follows a worker wait past a locally expired lease until the daemon settles it 1045ms + + Test Files 2 passed (2) + Tests 91 passed (91) + Start at 14:31:06 + Duration 8.70s (transform 3.86s, setup 51ms, collect 9.02s, tests 6.90s, environment 0ms, prepare 210ms) + diff --git a/evidence/daemon-check/sdk-targeted-final.txt b/evidence/daemon-check/sdk-targeted-final.txt new file mode 100644 index 000000000..49cf7658a --- /dev/null +++ b/evidence/daemon-check/sdk-targeted-final.txt @@ -0,0 +1,28 @@ + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + + ✓ tests/cli.test.ts (71 tests) 4358ms + ✓ flows check CLI > binds a checked relative wrapper to the flow directory for worker execution 945ms + ✓ flows check CLI > resolves a bare PATH-resolved claude with no declared model, in an isolated PATH 699ms + ✓ flows run/resume CLI over the journal protocol > follows a worker wait past a locally expired lease until the daemon settles it 1066ms + ✓ tests/check-daemon-validation.test.ts (20 tests) 4465ms + ✓ real CLI refuses skew in auto and required modes 1449ms + ✓ real CLI labels daemon and offline passes, including JSON 2162ms + ✓ real CLI refuses an invalid RELAYFLOWD_BIN in required mode 616ms + ✓ tests/cli-watch.test.ts (11 tests) 19871ms + ✓ flows check --watch > forwards required daemon validation through watch despite the offline test environment 1371ms + ✓ flows check --watch > rechecks syntax errors, clears once, and returns the last refusal on Ctrl-C 2275ms + ✓ flows check --watch > streams JSON lines without ANSI, recovers after atomic saves, and exits zero after repair 2472ms + ✓ flows check --watch > coalesces 20 concurrent saves into at most two rechecks 1927ms + ✓ flows check --watch > watches transitive relative use imports, cycles, and nearest config changes 2580ms + ✓ flows check --watch > refreshes the import graph and notices missing imports being created 2559ms + ✓ flows check --watch > reloads authored TypeScript instead of reusing the first imported definition 1902ms + ✓ flows check --watch > detects a nearer config appearing and falls back after it is deleted 2014ms + ✓ flows check --watch > keeps watching after the target is deleted and recreated 1987ms + ✓ flows check --watch > queues changes during a slow check without overlapping checks 779ms + + Test Files 3 passed (3) + Tests 102 passed (102) + Start at 14:30:03 + Duration 22.30s (transform 1.83s, setup 58ms, collect 6.59s, tests 28.69s, environment 0ms, prepare 196ms) + diff --git a/evidence/daemon-check/sdk-targeted.txt b/evidence/daemon-check/sdk-targeted.txt new file mode 100644 index 000000000..81c527552 --- /dev/null +++ b/evidence/daemon-check/sdk-targeted.txt @@ -0,0 +1,17 @@ + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + + ✓ tests/check-daemon-validation.test.ts (16 tests) 2751ms + ✓ real CLI refuses skew in auto and required modes 944ms + ✓ real CLI labels daemon and offline passes, including JSON 1321ms + ✓ real CLI refuses an invalid RELAYFLOWD_BIN in required mode 410ms + ✓ tests/cli.test.ts (71 tests) 3028ms + ✓ flows check CLI > binds a checked relative wrapper to the flow directory for worker execution 576ms + ✓ flows check CLI > resolves a bare PATH-resolved claude with no declared model, in an isolated PATH 429ms + ✓ flows run/resume CLI over the journal protocol > follows a worker wait past a locally expired lease until the daemon settles it 1044ms + + Test Files 2 passed (2) + Tests 87 passed (87) + Start at 14:22:14 + Duration 5.02s (transform 1.47s, setup 30ms, collect 3.58s, tests 5.78s, environment 0ms, prepare 89ms) + diff --git a/evidence/daemon-check/standalone-build.txt b/evidence/daemon-check/standalone-build.txt new file mode 100644 index 000000000..53e220c27 --- /dev/null +++ b/evidence/daemon-check/standalone-build.txt @@ -0,0 +1,6 @@ +Bundled 824 modules in 64ms + + authored-node.mjs 3.54 MB (entry point) + + [421ms] bundle 779 modules + [25ms] compile /tmp/flows-daemon-check diff --git a/evidence/daemon-check/standalone-check.txt b/evidence/daemon-check/standalone-check.txt new file mode 100644 index 000000000..a2fd42bac --- /dev/null +++ b/evidence/daemon-check/standalone-check.txt @@ -0,0 +1,4 @@ +WARNING [unprovable_effects] Step "greet" command "echo" resolves, but its effects cannot be proven before execution. +WARNING [unprovable_effects] Step "shout" command "echo" resolves, but its effects cannot be proven before execution. +WARNING [editor_schema_missing] For editor validation, add this first line: # yaml-language-server: $schema=https://schema.relayflows.dev/v0.1/flows.schema.json +{"validation":{"mode":"daemon","binary":"/tmp/stub-relayflowd-check","protocol":0,"specVersion":"0.1.0"},"ok":true,"path":"testdata/hello-deterministic.flow.yaml","projectConfigPath":"/home/daytona/.relayflow-v2-supervisor/durable/repository/testdata/flows.json","gates":[{"stepId":"greet","kind":"data","checks":["exit_code","output_contains"],"evaluator":"kernel","preflightable":true,"replayable":true},{"stepId":"shout","kind":"data","checks":["exit_code","output_contains"],"evaluator":"kernel","preflightable":true,"replayable":true}],"resolutions":[],"diagnostics":[{"severity":"warning","kind":"unprovable_effects","stepId":"greet","message":"Step \"greet\" command \"echo\" resolves, but its effects cannot be proven before execution."},{"severity":"warning","kind":"unprovable_effects","stepId":"shout","message":"Step \"shout\" command \"echo\" resolves, but its effects cannot be proven before execution."},{"severity":"warning","kind":"editor_schema_missing","message":"For editor validation, add this first line: # yaml-language-server: $schema=https://schema.relayflows.dev/v0.1/flows.schema.json"}],"requirements":{"integrations":[],"harnesses":[],"harnessUses":[],"mcp":[]}} diff --git a/evidence/daemon-check/timing.txt b/evidence/daemon-check/timing.txt new file mode 100644 index 000000000..1d313925d --- /dev/null +++ b/evidence/daemon-check/timing.txt @@ -0,0 +1,20 @@ +WARNING [unprovable_effects] Step "greet" command "echo" resolves, but its effects cannot be proven before execution. +WARNING [unprovable_effects] Step "shout" command "echo" resolves, but its effects cannot be proven before execution. +WARNING [editor_schema_missing] For editor validation, add this first line: # yaml-language-server: $schema=https://schema.relayflows.dev/v0.1/flows.schema.json +GATE step "greet" exit_code+output_contains from data (kernel, journal-replayable) +GATE step "shout" exit_code+output_contains from data (kernel, journal-replayable) +CHECK PASSED testdata/hello-deterministic.flow.yaml [validated by relayflowd at /tmp/relayflows-daemon-check-target/debug/relayflowd, protocol 0] + +real 0m0.505s +user 0m0.471s +sys 0m0.126s +WARNING [unprovable_effects] Step "greet" command "echo" resolves, but its effects cannot be proven before execution. +WARNING [unprovable_effects] Step "shout" command "echo" resolves, but its effects cannot be proven before execution. +WARNING [editor_schema_missing] For editor validation, add this first line: # yaml-language-server: $schema=https://schema.relayflows.dev/v0.1/flows.schema.json +GATE step "greet" exit_code+output_contains from data (kernel, journal-replayable) +GATE step "shout" exit_code+output_contains from data (kernel, journal-replayable) +CHECK PASSED testdata/hello-deterministic.flow.yaml [local only: disabled, so daemon acceptance is unproven] + +real 0m0.491s +user 0m0.493s +sys 0m0.107s diff --git a/evidence/daemon-check/typecheck-final.txt b/evidence/daemon-check/typecheck-final.txt new file mode 100644 index 000000000..445266dd4 --- /dev/null +++ b/evidence/daemon-check/typecheck-final.txt @@ -0,0 +1,8 @@ + +> @relayflows/sdk@2.0.42 typecheck +> tsc --noEmit && tsc -p tsconfig.type-tests.json + + +> @relayflows/sdk@2.0.42 typecheck:tests +> tsc -p tsconfig.tests.json + diff --git a/evidence/daemon-check/typecheck-tests-final.txt b/evidence/daemon-check/typecheck-tests-final.txt new file mode 100644 index 000000000..1b561ede4 --- /dev/null +++ b/evidence/daemon-check/typecheck-tests-final.txt @@ -0,0 +1,4 @@ + +> @relayflows/sdk@2.0.42 typecheck:tests +> tsc -p tsconfig.tests.json + diff --git a/kernel/DAEMON-LIFECYCLE.md b/kernel/DAEMON-LIFECYCLE.md index 3d739fab2..ca0009171 100644 --- a/kernel/DAEMON-LIFECYCLE.md +++ b/kernel/DAEMON-LIFECYCLE.md @@ -382,6 +382,20 @@ Not found → exit 2, `relayflowd_not_found`, message naming both ## 4. What changes, and what is new +`flows check` does not call `ensureDaemon` or open a socket. It may invoke the +resolved binary as `relayflowd validate-spec < spec.json`, a stateless stdin / +JSON-stdout admission check dispatched before engine construction. It parses and +validates like `run.start`, writes no run or journal, and leaves the data dir +untouched. Exit 0 carries an accepting envelope; exit 2 carries an invalid-spec +envelope. An older binary's clap exit 2 is not a verdict: consumers must validate +the stdout envelope. The envelope reports `ok`, `protocol`, `spec_version`, and +on refusal `error: {code: "invalid_spec", message}`. + +Automatic mode falls back to labelled local validation when no validator answers; +`--against-daemon` requires a verdict and `--no-daemon-check` disables discovery. +This judges the resolved binary, not a different build already serving a socket. + + ### New — `packages/sdk/src/daemon-lifecycle.ts` Mirrors `../relay/packages/cli/src/cli/lib/broker-lifecycle.ts` + diff --git a/kernel/relayflowd/src/lib.rs b/kernel/relayflowd/src/lib.rs index 8cf501261..e89dfa47c 100644 --- a/kernel/relayflowd/src/lib.rs +++ b/kernel/relayflowd/src/lib.rs @@ -14,3 +14,5 @@ pub use engine::{ }; mod workspace; + +pub mod validate_spec; diff --git a/kernel/relayflowd/src/main.rs b/kernel/relayflowd/src/main.rs index 03c0050b8..5206091ce 100644 --- a/kernel/relayflowd/src/main.rs +++ b/kernel/relayflowd/src/main.rs @@ -19,6 +19,8 @@ struct Cli { #[derive(Debug, Subcommand)] enum Command { + /// Validate a kernel spec from stdin without creating a run or journal. + ValidateSpec, /// Start and execute a run spec JSON file. Run { spec: PathBuf, @@ -56,8 +58,17 @@ enum Command { fn main() -> Result<()> { let cli = Cli::parse(); + if matches!(cli.command, Command::ValidateSpec) { + let verdict = match serde_json::from_reader::<_, serde_json::Value>(std::io::stdin()) { + Ok(value) => relayflowd::validate_spec::validate_spec(&value), + Err(error) => relayflowd::validate_spec::refusal(error.to_string()), + }; + println!("{}", verdict); + std::process::exit(if verdict["ok"] == true { 0 } else { 2 }); + } let engine = Engine::new(&cli.data_dir); match cli.command { + Command::ValidateSpec => unreachable!(), Command::Run { spec, event, diff --git a/kernel/relayflowd/src/validate_spec.rs b/kernel/relayflowd/src/validate_spec.rs new file mode 100644 index 000000000..3ef3ff2aa --- /dev/null +++ b/kernel/relayflowd/src/validate_spec.rs @@ -0,0 +1,17 @@ +//! Stateless admission check: identical to run.start (parse then validate). +//! This is intentionally stricter than event.submit, which currently only parses. +use relayflowd_core::{PROTOCOL_VERSION, RunSpec, spec::SPEC_VERSION}; +use serde_json::{Value, json}; + +pub fn validate_spec(value: &Value) -> Value { + let result = RunSpec::parse(value).and_then(|spec| spec.validate()); + match result { + Ok(()) => json!({"ok": true, "protocol": PROTOCOL_VERSION, "spec_version": SPEC_VERSION}), + Err(error) => refusal(error.to_string()), + } +} + +pub fn refusal(message: String) -> Value { + json!({"ok": false, "protocol": PROTOCOL_VERSION, "spec_version": SPEC_VERSION, + "error": {"code": "invalid_spec", "message": message}}) +} diff --git a/kernel/relayflowd/tests/validate_spec.rs b/kernel/relayflowd/tests/validate_spec.rs new file mode 100644 index 000000000..f64125cfb --- /dev/null +++ b/kernel/relayflowd/tests/validate_spec.rs @@ -0,0 +1,81 @@ +use serde_json::{Value, json}; +use std::{ + io::Write, + process::{Command, Stdio}, +}; + +fn check(value: &[u8], data_dir: &std::path::Path) -> (i32, Value) { + let mut child = Command::new(env!("CARGO_BIN_EXE_relayflowd")) + .arg("--data-dir") + .arg(data_dir) + .arg("validate-spec") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .unwrap(); + child.stdin.take().unwrap().write_all(value).unwrap(); + let output = child.wait_with_output().unwrap(); + assert!(output.stderr.is_empty(), "{:?}", output); + let verdict: Value = serde_json::from_slice(&output.stdout).unwrap(); + assert!(verdict.get("run_id").is_none()); + assert_eq!(verdict["protocol"], 0); + assert_eq!(verdict["spec_version"], "0.1.0"); + (output.status.code().unwrap(), verdict) +} + +#[test] +fn accepts_without_creating_data_directory_or_journal() { + let root = tempfile::tempdir().unwrap(); + let absent = root.path().join("absent"); + let source = include_bytes!("../../../testdata/hello-agent.spec.canonical.json"); + let (code, verdict) = check(source, &absent); + assert_eq!(code, 0); + assert_eq!( + verdict, + json!({"ok": true, "protocol": 0, "spec_version": "0.1.0"}) + ); + assert!(!absent.exists()); + check(source, root.path()); + assert_eq!(std::fs::read_dir(root.path()).unwrap().count(), 0); +} + +#[test] +fn refuses_unknown_field_with_kernel_location() { + let root = tempfile::tempdir().unwrap(); + let mut spec: Value = serde_json::from_slice(include_bytes!( + "../../../testdata/hello-agent.spec.canonical.json" + )) + .unwrap(); + spec["steps"][1]["nope"] = json!(true); + let (code, verdict) = check(&serde_json::to_vec(&spec).unwrap(), root.path()); + assert_eq!(code, 2); + assert_eq!(verdict["error"]["code"], "invalid_spec"); + assert!( + verdict["error"]["message"] + .as_str() + .unwrap() + .contains("unknown field \"nope\" at steps[1]") + ); + assert_eq!(std::fs::read_dir(root.path()).unwrap().count(), 0); +} + +#[test] +fn refuses_semantic_errors_and_malformed_json() { + let root = tempfile::tempdir().unwrap(); + let mut spec: Value = serde_json::from_slice(include_bytes!( + "../../../testdata/hello-agent.spec.canonical.json" + )) + .unwrap(); + spec["steps"][1]["cwd"] = json!("/absolute"); + let (code, verdict) = check(&serde_json::to_vec(&spec).unwrap(), root.path()); + assert_eq!(code, 2); + assert!( + verdict["error"]["message"] + .as_str() + .unwrap() + .contains("working directory \"/absolute\"") + ); + assert_eq!(check(b"{", root.path()).0, 2); + assert_eq!(std::fs::read_dir(root.path()).unwrap().count(), 0); +} diff --git a/packages/sdk/src/cli-commands.ts b/packages/sdk/src/cli-commands.ts index 0c5835f45..6346f1ac8 100644 --- a/packages/sdk/src/cli-commands.ts +++ b/packages/sdk/src/cli-commands.ts @@ -146,9 +146,9 @@ export const CLI_VERBS = [ }, { name: 'check', - description: 'Compile and preflight a flow without running it, or opening a daemon socket', + description: 'Compile, preflight, and validate with the installed runtime when available; never start a run', args: [{ name: 'source', description: 'flow.ts, flow.yaml, or spec.json', required: true }], - options: [JSON_OPTION, { flags: '--watch', description: 'Re-check on every change to the flow and its imports' }, + options: [{ flags: '--against-daemon', description: 'Require acceptance by the installed relayflowd validator (FLOWS_CHECK_AGAINST_DAEMON=1)' }, { flags: '--no-daemon-check', description: 'Local compile and preflight only (FLOWS_NO_DAEMON_CHECK=1)' }, JSON_OPTION, { flags: '--watch', description: 'Re-check on every change to the flow and its imports' }, { flags: '--explain-warnings', description: 'List every unprovable-effects warning per step instead of one summary line' }], variants: ['check'], }, diff --git a/packages/sdk/src/cli-watch.ts b/packages/sdk/src/cli-watch.ts index b126d0026..a99e2b3d6 100644 --- a/packages/sdk/src/cli-watch.ts +++ b/packages/sdk/src/cli-watch.ts @@ -1,3 +1,4 @@ +import type { DaemonValidationMode } from './daemon-spec-validation.js'; import { spawn } from 'node:child_process'; import { accessSync, constants, existsSync, readFileSync, watch, type FSWatcher } from 'node:fs'; import { dirname, join, resolve, sep } from 'node:path'; @@ -15,12 +16,13 @@ export async function watchCheck( io: CliIo, /** Cancellation, owned by the caller; this function installs no signal handler. */ signal: AbortSignal, + daemonValidation: DaemonValidationMode = 'auto', ): Promise { try { return await watchChecks({ path, signal, - check: () => checkOnce(path, options, io), + check: () => checkOnce(path, { ...options, daemonValidation }, io), clear: () => { if (!options.json) io.stdout('\x1b[2J\x1b[H'); }, }); } catch (error) { @@ -140,13 +142,14 @@ function discoverWatchPaths(path: string, imports: Map): Set { +function checkOnce(path: string, options: { json: boolean; explainWarnings: boolean; daemonValidation: DaemonValidationMode }, io: CliIo): Promise { + const mode = options.daemonValidation; // Importing an authored TS file in this process again would return its stale // cached definition (including transitive imports). A fresh CLI process uses // precisely the same check pipeline and reporting as a one-shot invocation. const entry = fileURLToPath(new URL(import.meta.url.endsWith('.ts') ? './cli.ts' : './cli.js', import.meta.url)); return new Promise((resolveCode, reject) => { - const child = spawn(process.execPath, [...process.execArgv, entry, 'check', ...(options.json ? ['--json'] : []), ...(options.explainWarnings ? ['--explain-warnings'] : []), path], { + const child = spawn(process.execPath, [...process.execArgv, entry, 'check', ...(mode === 'required' ? ['--against-daemon'] : mode === 'off' ? ['--no-daemon-check'] : []), ...(options.json ? ['--json'] : []), ...(options.explainWarnings ? ['--explain-warnings'] : []), path], { stdio: ['ignore', 'pipe', 'pipe'], // Ctrl-C belongs to the watcher; let an active check finish so its report // and exit status remain a pair, then release all resources. diff --git a/packages/sdk/src/cli.ts b/packages/sdk/src/cli.ts index 086b07093..b81a77348 100644 --- a/packages/sdk/src/cli.ts +++ b/packages/sdk/src/cli.ts @@ -1,4 +1,5 @@ #!/usr/bin/env node +import { unavailableValidation, validationAnnotation, type DaemonValidationMode } from './daemon-spec-validation.js'; import { foldUnprovableEffects, type FoldOptions } from './cli/diagnostic-fold.js'; import { startDetachedRun, emitDetachedHandle } from './cli/detached-run.js'; import { takeDetachedReceipt, type DetachedReceipt } from './cli/detached-record.js'; @@ -106,7 +107,7 @@ export type ParsedArgs = | CloudScheduleArgs | { command: 'schedules'; json: boolean } | { command: 'unschedule'; scheduleId: string; json: boolean } - | { command: 'check'; json: boolean; watch: boolean; explainWarnings: boolean; value: string } + | { command: 'check'; json: boolean; watch: boolean; explainWarnings: boolean; daemonValidation: DaemonValidationMode; value: string } | { command: 'run'; detach?: boolean; bucket: string | undefined; reuseFromRunId: string | undefined; localAgent: boolean; agentCapacity: number | undefined; dataDir: string; input: string | undefined; json: boolean; spawn: boolean; noObserverLink: boolean; cloudMirror: boolean; allowHumanInfluenced: boolean; value: string } | { command: 'resume'; detach?: boolean; localAgent: boolean; agentCapacity: number | undefined; dataDir: string; json: boolean; spawn: boolean; noObserverLink: boolean; cloudMirror: boolean; allowHumanInfluenced: boolean; value: string } | { command: 'answer'; dataDir: string; json: boolean; spawn: boolean; note: string | undefined; by: string | undefined; runId: string; waitId: string; answer: boolean } @@ -139,7 +140,7 @@ const USAGE = [ 'flows unschedule [--json] ', 'flows deploy @sha256: --to ', 'flows run @sha256: [--bucket ] [--data-dir ] [--json] [--detach]', - 'flows check [--watch] [--json] [--explain-warnings] ', + 'flows check [--against-daemon|--no-daemon-check] [--watch] [--json] [--explain-warnings] ', 'flows serve-webhook --data-dir --port

[--allow [,]]', 'flows run [--json] [--no-spawn] [--no-observer-link] [--cloud-mirror] [--detach] [--data-dir

] [--local-agent [--agent-capacity ]] [--reuse-from ] ', 'flows run --cloud [--json] [--wait] [--sync-code] [--no-connect] ', @@ -311,20 +312,20 @@ export async function runCli( if (parsed.command === 'check') { if (parsed.watch) { - return withInterrupt(options.signal, (signal) => watchCheck(parsed.value, { json: parsed.json, explainWarnings: parsed.explainWarnings }, io, signal)); + return withInterrupt(options.signal, (signal) => watchCheck(parsed.value, { json: parsed.json, explainWarnings: parsed.explainWarnings }, io, signal, parsed.daemonValidation)); } - // Deliberately daemon-free (kernel/DAEMON-LIFECYCLE.md §4). `checkFlow` is - // a compile-and-preflight that opens no daemon socket, and the parser - // refuses `--data-dir` on `check`, so there is no data dir to attach to. - // `flows check` keeps working with no daemon, no relayflowd binary and no - // data directory at all -- a property worth keeping, not an omission. - // Only this invocation opts into `agent_worker_unresolved`: `flows check` - // attaches no worker and, being daemon-free, cannot see one attached - // elsewhere. The authored `.flow.ts` path checks header declarations - // without compiling steps, so it has no agent steps to count. + // Stateless binary validation opens no socket or data dir (DAEMON-LIFECYCLE §4). + // Authored bodies are only lowered at run time, so their acceptance is unproven. const checked = /\.(?:[cm]?[jt]s)$/.test(parsed.value) ? await checkAuthoredFlowComposed(parsed.value) - : checkFlow(parsed.value, { warnUnresolvedAgentWorker: true }); + : checkFlow(parsed.value, { warnUnresolvedAgentWorker: true, daemonValidation: parsed.daemonValidation }); + if (checked.report.validation === undefined) { + const unavailable = unavailableValidation(parsed.daemonValidation, + checked.report.ok ? (parsed.daemonValidation === 'off' ? 'disabled' : 'authored_body') : 'not_reached'); + checked.report.validation = unavailable.validation; + if (checked.report.ok) checked.report.diagnostics.push(...unavailable.diagnostics); + checked.report.ok = checked.report.ok && !checked.report.diagnostics.some(d => d.severity === 'refusal'); + } emitCheckReport(checked.report, parsed.json, io, parsed.explainWarnings); return checked.report.ok ? 0 : 2; } @@ -694,6 +695,7 @@ function parseArgs(args: readonly string[]): ParsedArgs | undefined { let json = false; let watch = false; + let daemonValidation: DaemonValidationMode | undefined; let explainWarnings = false; let cloud = false; let wait = false; @@ -747,6 +749,11 @@ function parseArgs(args: readonly string[]): ParsedArgs | undefined { if (!isAgentCapacity(agentCapacity)) return undefined; continue; } + if (argument === '--against-daemon' || argument === '--no-daemon-check') { + if (command !== 'check' || daemonValidation !== undefined) return undefined; + daemonValidation = argument === '--against-daemon' ? 'required' : 'off'; + continue; + } if (argument === '--explain-warnings') { if (command !== 'check' || explainWarnings) return undefined; explainWarnings = true; @@ -837,7 +844,9 @@ function parseArgs(args: readonly string[]): ParsedArgs | undefined { if (command === 'run' && input !== undefined && !isAuthoredFlowPath(positionals[0]!)) return undefined; return command === 'check' - ? { command, json, watch, explainWarnings, value: positionals[0]! } + ? { command, json, watch, explainWarnings, value: positionals[0]!, + daemonValidation: daemonValidation ?? (process.env['FLOWS_NO_DAEMON_CHECK'] === '1' ? 'off' + : process.env['FLOWS_CHECK_AGAINST_DAEMON'] === '1' ? 'required' : 'auto') } : command === 'run' ? { command, ...(detach ? { detach } : {}), bucket, reuseFromRunId, localAgent, agentCapacity, dataDir, input, json, spawn, noObserverLink, cloudMirror, allowHumanInfluenced, value: positionals[0]! } : { command, ...(detach ? { detach } : {}), localAgent, agentCapacity, dataDir, json, spawn, noObserverLink, cloudMirror, allowHumanInfluenced, value: positionals[0]! }; @@ -1159,7 +1168,7 @@ function emitCheckReport(report: CheckReport, json: boolean, io: CliIo, explainW const requires = report.requirements === undefined ? '' : describeFlowRequirements(report.requirements); if (requires) io.stdout(`REQUIRES ${requires}`); emitDiagnostics(deferred, io, foldOptions); - if (report.ok) io.stdout(`CHECK PASSED ${report.path ?? ''}`.trimEnd()); + if (report.ok) io.stdout(`CHECK PASSED ${report.path ?? ''}`.trimEnd() + validationAnnotation(report.validation)); } function emitRunReport( diff --git a/packages/sdk/src/cli/check.ts b/packages/sdk/src/cli/check.ts index cc6c42779..b49f2b6de 100644 --- a/packages/sdk/src/cli/check.ts +++ b/packages/sdk/src/cli/check.ts @@ -1,3 +1,4 @@ +import { validateSpecWithDaemon, type DaemonValidation, type DaemonValidationMode, type DaemonValidationDeps } from '../daemon-spec-validation.js'; import { communicationInstruction } from '../communication/spec.js'; import { rememberResolvedCliIdentities } from '../resolved-cli-identity.js'; import { checkCommunicationEnvironment } from '../communication/preflight.js'; @@ -44,6 +45,7 @@ export interface ProjectConfig { } export interface CheckReport { + validation?: DaemonValidation; mcpTools?: Readonly>; ok: boolean; path?: string; @@ -125,6 +127,8 @@ type CliProbeOutcomeMap = Map; * anything that depends on how the flow is about to be invoked opts in here. */ export interface CheckInvocation { + daemonValidation?: DaemonValidationMode; + daemonValidationDeps?: DaemonValidationDeps; /** Environment used only by provider executable/auth/model probes. */ environment?: NodeJS.ProcessEnv; /** @@ -159,7 +163,7 @@ export function checkFlow(path: string, invocation: CheckInvocation = {}): Check execution = checkAuthoredFlow(readFlow(source, absolutePath), path, undefined, invocation); } catch (error) { if (!(error instanceof CheckFailure)) throw error; - execution = { report: inputFailureReport(error, path) }; + execution = { report: inputFailureReport(error, path, invocation) }; } // The editor-schema hint is a documentation nudge, emitted for every // .flow.yaml without a first-line yaml-language-server comment. @@ -172,7 +176,7 @@ export function checkFlow(path: string, invocation: CheckInvocation = {}): Check const failure = error instanceof CheckFailure ? error : new CheckFailure('invalid_spec', `Flow "${path}" could not be checked as a Relayflow spec.`); - return { report: inputFailureReport(failure, path) }; + return { report: inputFailureReport(failure, path, invocation) }; } } @@ -246,14 +250,20 @@ export function checkAuthoredFlow( const workerSurface = invocation.warnUnresolvedAgentWorker === true ? agentWorkerDiagnostics(authoring) : []; + const daemon = invocation.daemonValidation === undefined ? undefined + : result.ok && flow !== undefined + ? validateSpecWithDaemon(flow, invocation.daemonValidation, invocation.daemonValidationDeps) + : { validation: { mode: 'local' as const, reason: 'not_reached' as const }, diagnostics: [] }; + if (daemon?.diagnostics.some(d => d.severity === 'refusal')) result.ok = false; return { report: { + ...(daemon === undefined ? {} : { validation: daemon.validation }), ok: result.ok, path, ...(config.path !== undefined ? { projectConfigPath: config.path } : {}), gates: result.gates, resolutions: result.resolutions, - diagnostics: [...result.diagnostics, ...workerSurface], + diagnostics: [...result.diagnostics, ...workerSurface, ...(daemon?.diagnostics ?? [])], requirements: safeRequirements(authoring, config.cli), }, ...(result.ok && flow !== undefined ? { flow } : {}), @@ -262,7 +272,7 @@ export function checkAuthoredFlow( const failure = error instanceof CheckFailure ? error : new CheckFailure('invalid_spec', `Flow "${path}" could not be checked as a Relayflow spec.`); - return { report: inputFailureReport(failure, path) }; + return { report: inputFailureReport(failure, path, invocation) }; } } @@ -335,8 +345,10 @@ export async function checkBuildableFlow(path: string): Promise export function inputFailureReport( failure: { kind: CheckFailureKind; message: string }, path?: string, + invocation: CheckInvocation = {}, ): CheckReport { return { + ...(invocation.daemonValidation === undefined ? {} : { validation: { mode: 'local' as const, reason: 'not_reached' as const } }), ok: false, ...(path !== undefined ? { path } : {}), gates: [], diff --git a/packages/sdk/src/daemon-spec-validation.ts b/packages/sdk/src/daemon-spec-validation.ts new file mode 100644 index 000000000..edeb50998 --- /dev/null +++ b/packages/sdk/src/daemon-spec-validation.ts @@ -0,0 +1,126 @@ +import { spawnSync } from 'node:child_process'; +import { canonicalize } from './canonical.js'; +import { CompileError, toKernelSpec } from './compile.js'; +import { PROTOCOL_VERSION } from './protocol.js'; +import { RelayflowdNotFoundError, resolveRelayflowdBinary } from './relayflowd-path.js'; +import type { FlowSpec } from './spec.js'; +import type { CheckReport } from './cli/check.js'; + +export type DaemonValidationMode = 'auto' | 'required' | 'off'; +type Unavailable = 'disabled' | 'not_reached' | 'authored_body' | 'relayflowd_not_found' + | 'relayflowd_bin_invalid' | 'no_verdict' | 'spawn_failed' | 'timed_out' | 'protocol_mismatch' | 'abnormal_exit'; +export interface DaemonValidation { + mode: 'daemon' | 'local'; + binary?: string; + protocol?: number; + specVersion?: string; + reason?: Unavailable; +} +export interface DaemonValidationDeps { + resolveBinary(): string; + run(binary: string, input: string): { + status: number | null; signal?: NodeJS.Signals | null; stdout: string; stderr: string; error?: Error; + }; +} +type Result = { validation: DaemonValidation; diagnostics: CheckReport['diagnostics'] }; +// Cache discovery, never verdicts. Changed resolution inputs get a fresh lookup. +const binaries = new Map(); +const defaults: DaemonValidationDeps = { + resolveBinary() { + const key = JSON.stringify([process.env['RELAYFLOWD_BIN'], process.env['PATH'], process.cwd(), process.argv[1]]); + let found = binaries.get(key); + if (found === undefined) { + try { found = resolveRelayflowdBinary(); } + catch (error) { found = error instanceof Error ? error : new Error(String(error)); } + binaries.set(key, found); + } + if (found instanceof Error) throw found; + return found; + }, + run: (binary, input) => spawnSync(binary, ['validate-spec'], { + input, encoding: 'utf8', timeout: 5000, killSignal: 'SIGKILL', maxBuffer: 1024 * 1024, + stdio: ['pipe', 'pipe', 'pipe'], + }), +}; + +export function unavailableValidation( + mode: DaemonValidationMode, reason: Unavailable, detail = '', binary?: string, +): Result { + const message = `${binary === undefined ? 'relayflowd' : `relayflowd at ${binary}`}: ${detail || reason.replaceAll('_', ' ')}. ` + + 'Daemon acceptance is unproven; an already attached daemon from another build is not checked.'; + return { + validation: { mode: 'local', reason, ...(binary === undefined ? {} : { binary }) }, + diagnostics: mode === 'required' + ? [{ severity: 'refusal', kind: 'daemon_validation_unavailable', message }] + : reason === 'disabled' || reason === 'not_reached' || reason === 'relayflowd_not_found' + ? [] : [{ severity: 'warning', kind: 'daemon_unvalidated', message }], + }; +} + +/** Same spec value run.start submits, in canonical form; no socket or run. */ +export function validateSpecWithDaemon( + flow: FlowSpec, mode: DaemonValidationMode, deps: DaemonValidationDeps = defaults, +): Result { + if (mode === 'off') return unavailableValidation(mode, 'disabled'); + let submitted: ReturnType; + let input: string; + try { submitted = toKernelSpec(flow); input = canonicalize(submitted); } + catch (error) { + // run refuses this lowering too: degrading to local would fail open. + const errors = error instanceof CompileError ? error.errors : [String(error)]; + return { validation: { mode: 'local', reason: 'not_reached' }, + diagnostics: [{ severity: 'refusal', kind: 'invalid_spec', message: errors.join('; '), errors }] }; + } + let binary: string; + try { binary = deps.resolveBinary(); } + catch (error) { + const reason = error instanceof RelayflowdNotFoundError + ? error.attempts[0]?.startsWith('RELAYFLOWD_BIN=') ? 'relayflowd_bin_invalid' : 'relayflowd_not_found' + : 'spawn_failed'; + return unavailableValidation(mode, reason, String(error)); + } + try { + const result = deps.run(binary, input); + if (result.error) return unavailableValidation(mode, + (result.error as NodeJS.ErrnoException).code === 'ETIMEDOUT' ? 'timed_out' : 'spawn_failed', result.error.message, binary); + let verdict: unknown; + try { verdict = JSON.parse(result.stdout); } catch { /* Old binaries have no envelope. */ } + if (!isVerdict(verdict)) return unavailableValidation(mode, 'no_verdict', + 'no validation verdict (the binary may predate validate-spec)', binary); + if (verdict.protocol !== PROTOCOL_VERSION) return unavailableValidation(mode, 'protocol_mismatch', + `validator protocol ${verdict.protocol}, SDK protocol ${PROTOCOL_VERSION}`, binary); + const validation: DaemonValidation = { mode: 'daemon', binary, + protocol: verdict.protocol, specVersion: verdict.spec_version }; + if (verdict.ok) { + // Acceptance is the envelope AND exit 0; a validator that fails or is + // killed after printing it has not completed validation. + if (result.status !== 0) return unavailableValidation(mode, 'abnormal_exit', + `validator ${result.status === null ? `was terminated by ${result.signal ?? 'a signal'}` : `exited ${result.status}`} after an accepting verdict`, binary); + return { validation, diagnostics: [] }; + } + // A refusal fails closed whatever the exit status, so it is reported as-is. + const message = verdict.error.message; + const index = /steps\[(\d+)\]/.exec(message)?.[1]; + const stepId = index === undefined ? undefined : submitted.steps[Number(index)]?.id; + const generated = stepId !== undefined && !flow.steps.some(step => step.id === stepId); + return { validation, diagnostics: [{ severity: 'refusal', kind: 'invalid_spec', + message: message + (generated ? `\nStep "${stepId}" is generated by this compiler's gate lowering, not declared in the flow; ` + + 'the installed relayflowd and this @relayflows/sdk disagree (SDK lowering bug). Report this rather than editing the flow.' : ''), + errors: [message], ...(stepId === undefined ? {} : { stepId }) }] }; + } catch (error) { return unavailableValidation(mode, 'spawn_failed', String(error), binary); } +} + +type Verdict = { protocol: number; spec_version: string } & + ({ ok: true } | { ok: false; error: { code: 'invalid_spec'; message: string } }); +function isVerdict(value: unknown): value is Verdict { + if (typeof value !== 'object' || value === null) return false; + const v = value as Partial; + return Number.isInteger(v.protocol) && typeof v.spec_version === 'string' + && (v.ok === true || (v.ok === false && v.error?.code === 'invalid_spec' && typeof v.error.message === 'string')); +} + +export function validationAnnotation(validation?: DaemonValidation): string { + return validation?.mode === 'daemon' + ? ` [validated by relayflowd at ${validation.binary}, protocol ${validation.protocol}]` + : ` [local only: ${(validation?.reason ?? 'not_reached').replaceAll('_', ' ')}, so daemon acceptance is unproven]`; +} diff --git a/packages/sdk/src/failure-kinds.ts b/packages/sdk/src/failure-kinds.ts index 7a05c98a2..fbc06490f 100644 --- a/packages/sdk/src/failure-kinds.ts +++ b/packages/sdk/src/failure-kinds.ts @@ -48,7 +48,9 @@ export const CHECK_INPUT_FAILURE_KINDS = [ ...SHARED_SPEC_FAILURE_KINDS, ] as const; +// run never enables daemon validation; fromCheckReport needs a mapping if that changes. export const CHECK_FAILURE_KINDS = [ + 'daemon_validation_unavailable', ...CHECK_INPUT_FAILURE_KINDS, ...PREFLIGHT_ENVIRONMENT_FAILURE_KINDS, ] as const; @@ -172,7 +174,7 @@ export const RUN_WARNING_KINDS = [ * daemon-free, can see none either — so it opts in, while `flows run`, `flows * build` and SDK submissions do not (cli/check-worker-surface.ts). */ -export const CHECK_WARNING_KINDS = ['editor_schema_missing', 'agent_worker_unresolved'] as const; +export const CHECK_WARNING_KINDS = ['editor_schema_missing', 'daemon_unvalidated', 'agent_worker_unresolved'] as const; export type CheckWarningKind = (typeof CHECK_WARNING_KINDS)[number]; export type PreflightFailureKind = (typeof PREFLIGHT_FAILURE_KINDS)[number]; diff --git a/packages/sdk/tests/check-daemon-validation.test.ts b/packages/sdk/tests/check-daemon-validation.test.ts new file mode 100644 index 000000000..6a829713b --- /dev/null +++ b/packages/sdk/tests/check-daemon-validation.test.ts @@ -0,0 +1,221 @@ +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { spawnSync } from 'node:child_process'; +import { afterEach, expect, it, vi } from 'vitest'; +import { checkAuthoredFlow } from '../src/cli/check.js'; +import { canonicalize } from '../src/canonical.js'; +import * as compiler from '../src/compile.js'; +import { toKernelSpec } from '../src/compile.js'; +import { validateSpecWithDaemon, type DaemonValidationDeps } from '../src/daemon-spec-validation.js'; +import { RelayflowdNotFoundError, defaultRelayflowdPathDeps, resolveRelayflowdBinary } from '../src/relayflowd-path.js'; +import { runCli } from '../src/cli.js'; +import type { FlowSpec } from '../src/spec.js'; + +const flow: FlowSpec = { version: '0.1.0', steps: [ + { id: 'first', type: 'deterministic', command: 'echo hello', timeoutMs: 1000 }, + { id: 'second', type: 'deterministic', command: 'echo done' }, +] }; +const message = 'unknown field "timeout_ms" at steps[0] — refusing to guess (fail closed)'; +const envelope = (error?: string) => ({ ok: error === undefined, protocol: 0, spec_version: '0.1.0', + ...(error === undefined ? {} : { error: { code: 'invalid_spec', message: error } }) }); +const deps = (error?: string): DaemonValidationDeps => ({ resolveBinary: () => '/stub/relayflowd', + run: vi.fn(() => ({ status: error ? 2 : 0, stdout: JSON.stringify(envelope(error)), stderr: '' })) }); +const roots: string[] = []; +afterEach(() => { vi.restoreAllMocks(); vi.unstubAllEnvs(); roots.splice(0).forEach(p => rmSync(p, { recursive: true, force: true })); }); + +it('refuses package-valid daemon-invalid skew through check', () => { + expect(checkAuthoredFlow(flow, '/tmp/flow.json').report.ok).toBe(true); + const result = checkAuthoredFlow(flow, '/tmp/flow.json', undefined, + { daemonValidation: 'auto', daemonValidationDeps: deps(message) }); + expect(result.report.ok).toBe(false); + expect(result.report.diagnostics).toContainEqual({ severity: 'refusal', kind: 'invalid_spec', + message, errors: [message], stepId: 'first' }); + expect(result.report.validation?.mode).toBe('daemon'); +}); + +it('maps generated-step indices to submitted steps and identifies compiler bugs', () => { + const gated: FlowSpec = { ...flow, steps: [{ ...flow.steps[0]!, + verification: { type: 'artifact_exists', path: 'answer.txt' } }, flow.steps[1]!] }; + const result = validateSpecWithDaemon(gated, 'required', deps('unknown field "nope" at steps[1]')); + expect(result.diagnostics[0]).toMatchObject({ stepId: 'first.gate', kind: 'invalid_spec' }); + expect(result.diagnostics[0]?.message).toContain('generated by this compiler'); + expect(result.diagnostics[0]?.message).toContain('Report this rather than editing the flow'); +}); + +it('submits the canonical spec value used by run.start', () => { + const transport = deps(); + expect(validateSpecWithDaemon(flow, 'required', transport).validation.mode).toBe('daemon'); + expect(transport.run).toHaveBeenCalledWith('/stub/relayflowd', canonicalize(toKernelSpec(flow))); +}); + +it('does not resolve or spawn in off mode or after local refusal', () => { + const transport = { resolveBinary: vi.fn(), run: vi.fn() }; + expect(validateSpecWithDaemon(flow, 'off', transport).validation.reason).toBe('disabled'); + checkAuthoredFlow({ ...flow, steps: [] }, '/tmp/flow.json', undefined, + { daemonValidation: 'required', daemonValidationDeps: transport }); + expect(transport.resolveBinary).not.toHaveBeenCalled(); + expect(transport.run).not.toHaveBeenCalled(); +}); + +it.each(['auto', 'required'] as const)('handles absent and invalid explicit binaries in %s', mode => { + for (const explicit of [false, true]) { + const transport = { ...deps(), resolveBinary() { + throw new RelayflowdNotFoundError(explicit ? 'RELAYFLOWD_BIN is invalid' : 'not found', explicit ? ['RELAYFLOWD_BIN=/bad'] : []); + } }; + const result = validateSpecWithDaemon(flow, mode, transport); + expect(result.validation.reason).toBe(explicit ? 'relayflowd_bin_invalid' : 'relayflowd_not_found'); + expect(result.diagnostics.length).toBe(mode === 'required' || explicit ? 1 : 0); + if (mode === 'required') expect(result.diagnostics[0]?.severity).toBe('refusal'); + else if (explicit) expect(result.diagnostics[0]?.severity).toBe('warning'); + } +}); + +it.each([ + { status: 2, stdout: '', stderr: 'unrecognized subcommand', reason: 'no_verdict' }, + { status: 0, stdout: '{}', stderr: '', reason: 'no_verdict' }, + { status: null, stdout: '', stderr: '', error: Object.assign(new Error('timeout'), { code: 'ETIMEDOUT' }), reason: 'timed_out' }, + { status: null, stdout: '', stderr: '', error: new Error('spawn'), reason: 'spawn_failed' }, + { status: 0, stdout: JSON.stringify({ ...envelope(), protocol: 99 }), stderr: '', reason: 'protocol_mismatch' }, + { status: 2, stdout: JSON.stringify(envelope()), stderr: '', reason: 'abnormal_exit' }, + { status: null, signal: 'SIGTERM' as const, stdout: JSON.stringify(envelope()), stderr: '', reason: 'abnormal_exit' }, +])('reports $reason without claiming daemon acceptance', outcome => { + for (const mode of ['auto', 'required'] as const) { + const result = validateSpecWithDaemon(flow, mode, { ...deps(), run: () => outcome }); + expect(result.validation).toMatchObject({ mode: 'local', reason: outcome.reason }); + expect(result.diagnostics[0]).toMatchObject({ severity: mode === 'auto' ? 'warning' : 'refusal' }); + expect(result.diagnostics[0]?.message).toContain('/stub/relayflowd'); + expect(result.diagnostics[0]?.message).toContain('acceptance is unproven'); + } +}); + +function fixture() { + const root = mkdtempSync(join(tmpdir(), 'daemon-check-')); roots.push(root); + const binary = join(root, 'relayflowd'); + writeFileSync(binary, `#!${process.execPath}\nlet input='';process.stdin.on('data',x=>input+=x);process.stdin.on('end',()=>{const spec=JSON.parse(input);const bad=spec.steps.some(s=>s.timeout_ms);console.log(JSON.stringify(bad?${JSON.stringify(envelope(message))}:${JSON.stringify(envelope())}));process.exitCode=bad?2:0;});\n`, { mode: 0o755 }); + const path = join(root, 'flow.json'); writeFileSync(path, JSON.stringify(flow)); + return { root, binary, path }; +} +function cli(path: string, binary: string, flags: string[] = []) { + return spawnSync(process.execPath, [resolve('dist/cli.js'), 'check', ...flags, path], { + encoding: 'utf8', env: { ...process.env, RELAYFLOWD_BIN: binary, FLOWS_NO_DAEMON_CHECK: '', FLOWS_CHECK_AGAINST_DAEMON: '' }, + }); +} +it('real CLI refuses skew in auto and required modes', () => { + const f = fixture(); + for (const flags of [[], ['--against-daemon']]) { + const result = cli(f.path, f.binary, flags); + expect(result.status).toBe(2); + expect(result.stderr).toContain(`REFUSED [invalid_spec] ${message}`); + } +}); +it('keeps a daemon refusal whatever the validator exit status', () => { + const result = validateSpecWithDaemon(flow, 'auto', { ...deps(), + run: () => ({ status: null, signal: 'SIGTERM', stdout: JSON.stringify(envelope(message)), stderr: '' }) }); + expect(result.validation.mode).toBe('daemon'); + expect(result.diagnostics).toMatchObject([{ severity: 'refusal', kind: 'invalid_spec', stepId: 'first' }]); +}); + +it.each([['exit 2', 'process.exitCode=2'], ['SIGTERM', "process.kill(process.pid,'SIGTERM')"]])( + 'real CLI does not claim daemon acceptance after an accepting verdict then %s', (_label, ending) => { + const f = fixture(); + writeFileSync(f.binary, `#!${process.execPath}\nprocess.stdin.resume();process.stdin.on('end',()=>{process.stdout.write(${JSON.stringify(JSON.stringify(envelope()) + '\n')},()=>{${ending};});});\n`, { mode: 0o755 }); + writeFileSync(f.path, JSON.stringify({ ...flow, steps: [{ id: 'a', type: 'deterministic', command: 'echo ok' }] })); + const required = cli(f.path, f.binary, ['--against-daemon', '--json']); + expect(required.status, required.stderr).toBe(2); + expect(JSON.parse(required.stdout)).toMatchObject({ ok: false, validation: { mode: 'local', reason: 'abnormal_exit' } }); + const auto = cli(f.path, f.binary, ['--json']); + expect(JSON.parse(auto.stdout)).toMatchObject({ validation: { mode: 'local', reason: 'abnormal_exit' }, + diagnostics: expect.arrayContaining([expect.objectContaining({ severity: 'warning', kind: 'daemon_unvalidated' })]) }); + }); + +it('real CLI labels daemon and offline passes, including JSON', () => { + const f = fixture(); + expect(cli(f.path, f.binary, ['--no-daemon-check']).stdout).toContain('[local only: disabled'); + writeFileSync(f.path, JSON.stringify({ ...flow, steps: [{ id: 'a', type: 'deterministic', command: 'echo ok' }] })); + const result = cli(f.path, f.binary); + expect(result.status).toBe(0); + expect(result.stdout).toContain(`[validated by relayflowd at ${f.binary}, protocol 0]`); + expect(JSON.parse(cli(f.path, f.binary, ['--json']).stdout).validation.mode).toBe('daemon'); +}); +it('real CLI refuses an invalid RELAYFLOWD_BIN in required mode', () => { + const f = fixture(); + const result = cli(f.path, join(f.root, 'missing'), ['--against-daemon']); + expect(result.status).toBe(2); + expect(result.stderr).toContain('REFUSED [daemon_validation_unavailable]'); + expect(result.stderr).toContain('RELAYFLOWD_BIN'); +}); +it('CLI refuses when no binary anchor exists in required mode', async () => { + // Exercise the real resolver and CLI with deterministic absent anchors. + vi.stubEnv('RELAYFLOWD_BIN', ''); + vi.spyOn(defaultRelayflowdPathDeps, 'isExecutable').mockReturnValue(false); + vi.spyOn(defaultRelayflowdPathDeps, 'resolveFrom').mockReturnValue(null); + vi.spyOn(defaultRelayflowdPathDeps, 'which').mockReturnValue(null); + expect(() => resolveRelayflowdBinary()).toThrow(RelayflowdNotFoundError); + const f = fixture(); const stderr: string[] = []; + expect(await runCli(['check', '--against-daemon', f.path], { stdout: () => {}, stderr: s => stderr.push(s) })).toBe(2); + expect(stderr.join('\n')).toContain('REFUSED [daemon_validation_unavailable]'); +}); +it('flags win over environment and are check-only and mutually exclusive', async () => { + const f = fixture(); vi.stubEnv('RELAYFLOWD_BIN', f.binary); vi.stubEnv('FLOWS_CHECK_AGAINST_DAEMON', '1'); + const io = { stdout: vi.fn(), stderr: vi.fn() }; + expect(await runCli(['check', '--no-daemon-check', f.path], io)).toBe(0); + for (const args of [['check', '--against-daemon', '--no-daemon-check', f.path], + ['run', '--against-daemon', f.path], ['resume', '--no-daemon-check', 'run-id']]) { + expect(await runCli(args, io)).toBe(2); + } +}); + +it('fails closed if kernel lowering throws after local preflight passes', () => { + vi.spyOn(compiler, 'toKernelSpec').mockImplementation(() => { + throw new compiler.CompileError(['cannot lower this declaration']); + }); + const transport = deps(); + const checked = checkAuthoredFlow(flow, '/tmp/flow.json', undefined, + { daemonValidation: 'auto', daemonValidationDeps: transport }); + expect(checked.report.ok).toBe(false); + expect(checked.report.diagnostics).toContainEqual({ severity: 'refusal', kind: 'invalid_spec', + message: 'cannot lower this declaration', errors: ['cannot lower this declaration'] }); + expect(transport.run).not.toHaveBeenCalled(); +}); + +it('refuses agent cwd skew accepted by package preflight', () => { + const agent: FlowSpec = { version: '0.1.0', steps: [{ id: 'edit', type: 'agent', + cli: resolve('../../testdata/preflight/authenticated-cli'), instruction: 'edit', cwd: 'worktree' }] }; + const refusal = 'unknown field "cwd" at steps[0] — refusing to guess (fail closed)'; + expect(checkAuthoredFlow(agent, '/tmp/flow.json').report.ok).toBe(true); + const checked = checkAuthoredFlow(agent, '/tmp/flow.json', undefined, + { daemonValidation: 'required', daemonValidationDeps: deps(refusal) }); + expect(checked.report.ok).toBe(false); + expect(checked.report.diagnostics).toContainEqual({ severity: 'refusal', kind: 'invalid_spec', + message: refusal, errors: [refusal], stepId: 'edit' }); +}); + +it('maps authored steps following generated steps without blaming the compiler', () => { + const gated: FlowSpec = { ...flow, steps: [{ ...flow.steps[0]!, + verification: { type: 'artifact_exists', path: 'answer.txt' } }, flow.steps[1]!] }; + const checked = checkAuthoredFlow(gated, '/tmp/flow.json', undefined, + { daemonValidation: 'required', daemonValidationDeps: deps('unknown field "nope" at steps[2]') }); + expect(checked.report.ok).toBe(false); + expect(checked.report.diagnostics).toContainEqual({ severity: 'refusal', kind: 'invalid_spec', + message: 'unknown field "nope" at steps[2]', errors: ['unknown field "nope" at steps[2]'], stepId: 'second' }); +}); + +it('memoizes binary discovery without memoizing validation verdicts', async () => { + vi.stubEnv('RELAYFLOWD_BIN', ''); + vi.stubEnv('PATH', '/missing/check-discovery'); + vi.spyOn(defaultRelayflowdPathDeps, 'isExecutable').mockReturnValue(false); + vi.spyOn(defaultRelayflowdPathDeps, 'resolveFrom').mockReturnValue(null); + const which = vi.spyOn(defaultRelayflowdPathDeps, 'which').mockReturnValue(null); + const f = fixture(); + const io = { stdout: vi.fn(), stderr: vi.fn() }; + // The local command probe needs a real absolute executable with this PATH. + writeFileSync(f.path, JSON.stringify({ ...flow, steps: [{ id: 'a', type: 'deterministic', command: '/bin/echo ok' }] })); + await runCli(['check', '--against-daemon', f.path], io); + await runCli(['check', '--against-daemon', f.path], io); + expect(which).toHaveBeenCalledTimes(1); + const transport = deps(); + validateSpecWithDaemon(flow, 'auto', transport); + validateSpecWithDaemon(flow, 'auto', transport); + expect(transport.run).toHaveBeenCalledTimes(2); +}); diff --git a/packages/sdk/tests/check-warning-summary.test.ts b/packages/sdk/tests/check-warning-summary.test.ts index 42ed291a2..0e8928bfa 100644 --- a/packages/sdk/tests/check-warning-summary.test.ts +++ b/packages/sdk/tests/check-warning-summary.test.ts @@ -58,7 +58,9 @@ describe('flows check warning presentation', () => { expect(result.stderr).toEqual([...details, unresolved]); }); it('keeps JSON byte-identical to the original report, with either text mode', async () => { - const expected = JSON.stringify(checkFlow(fixture, { warnUnresolvedAgentWorker: true }).report); + // The CLI's daemon validation mode for this offline test environment. + const daemonValidation = process.env['FLOWS_NO_DAEMON_CHECK'] === '1' ? 'off' : 'auto'; + const expected = JSON.stringify(checkFlow(fixture, { warnUnresolvedAgentWorker: true, daemonValidation }).report); for (const flags of [[], ['--explain-warnings']]) { const result = await invoke(['check', '--json', ...flags, fixture]); expect(result.code).toBe(0); diff --git a/packages/sdk/tests/cli-watch.test.ts b/packages/sdk/tests/cli-watch.test.ts index cce83e005..b43c7966f 100644 --- a/packages/sdk/tests/cli-watch.test.ts +++ b/packages/sdk/tests/cli-watch.test.ts @@ -40,11 +40,11 @@ async function project(): Promise<{ directory: string; path: string }> { return { directory, path }; } -function start(path: string, json = false) { +function start(path: string, json = false, flags: string[] = [], environment: NodeJS.ProcessEnv = {}) { // The package's flows binary is produced by the ordinary SDK build. - const child = spawn(process.env['BUN_BIN'] ?? 'bun', ['run', 'flows', 'check', '--watch', ...(json ? ['--json'] : []), path], { + const child = spawn(process.env['BUN_BIN'] ?? 'bun', ['run', 'flows', 'check', '--watch', ...flags, ...(json ? ['--json'] : []), path], { cwd: sdk, - env: { ...process.env, PATH: `${bin}:${process.env['PATH']}` }, + env: { ...process.env, ...environment, PATH: `${bin}:${process.env['PATH']}` }, }); children.push(child); let stdout = ''; @@ -71,6 +71,16 @@ async function touch(path: string): Promise { } describe('flows check --watch', () => { + it('forwards required daemon validation through watch despite the offline test environment', async () => { + const { path } = await project(); + // The test environment selects offline; an explicit flag must survive the child. + const running = start(path, true, ['--against-daemon'], { RELAYFLOWD_BIN: '/missing/watch-relayflowd' }); + await until(() => running.reports().length > 0); + expect(running.reports()[0].ok).toBe(false); + expect(running.reports()[0].validation.reason).toBe('relayflowd_bin_invalid'); + await stop(running.child); + }); + it('rechecks syntax errors, clears once, and returns the last refusal on Ctrl-C', async () => { const { path } = await project(); const output = start(path); diff --git a/packages/sdk/tests/cli.test.ts b/packages/sdk/tests/cli.test.ts index c8b6138ad..bc13755e8 100644 --- a/packages/sdk/tests/cli.test.ts +++ b/packages/sdk/tests/cli.test.ts @@ -666,6 +666,7 @@ steps: expect(pass.code).toBe(0); expect(JSON.parse(pass.stdout.join('\n')) as CheckReport).toEqual({ ok: true, + validation: { mode: 'local', reason: 'disabled' }, path: passPath, projectConfigPath: configPath, gates: [{ @@ -688,6 +689,7 @@ steps: const report = JSON.parse(refusal.stdout.join('\n')) as CheckReport; expect(report).toEqual({ ok: false, + validation: { mode: 'local', reason: 'not_reached' }, path: refusalPath, projectConfigPath: configPath, gates: [{ diff --git a/packages/sdk/tests/live-kernel.test.ts b/packages/sdk/tests/live-kernel.test.ts index a51786f17..469b420ad 100644 --- a/packages/sdk/tests/live-kernel.test.ts +++ b/packages/sdk/tests/live-kernel.test.ts @@ -2057,3 +2057,48 @@ function isObject(value: unknown): value is Record { function delay(ms: number): Promise { return new Promise((resolveDelay) => setTimeout(resolveDelay, ms)); } + + +it('validates the canonical ladder with the built daemon without running it', () => { + for (const name of ['hello-deterministic', 'hello-llm', 'hello-agent']) { + const checked = checkFlow(join(TESTDATA, `${name}.flow.yaml`), { + daemonValidation: 'required', + daemonValidationDeps: { + resolveBinary: () => RELAYFLOWD, + run: (binary, input) => spawnSync(binary, ['validate-spec'], { input, encoding: 'utf8' }), + }, + }); + expect(checked.report.ok, JSON.stringify(checked.report)).toBe(true); + expect(checked.report.validation?.mode).toBe('daemon'); + } +}); + +it('refuses a field the built daemon does not know, naming the step the daemon named', () => { + // The skew this gate exists for: packages that emit a field the installed + // relayflowd predates (#489's `cwd`). No such field exists at this commit — + // both halves ship from it — so inject one into the submitted JSON and let + // the REAL binary judge it. check-daemon-validation.test.ts pins the + // diagnostic shaping against a stub; this pins that the installed + // validator's own refusal is what reaches `flows check`. + const checked = checkFlow(join(TESTDATA, 'hello-agent.flow.yaml'), { + daemonValidation: 'required', + daemonValidationDeps: { + resolveBinary: () => RELAYFLOWD, + run: (binary, input) => { + const submitted = JSON.parse(input) as { steps: Record[] }; + submitted.steps[1]!['from_a_newer_sdk'] = true; + return spawnSync(binary, ['validate-spec'], { + input: JSON.stringify(submitted), encoding: 'utf8', + }); + }, + }, + }); + expect(checked.report.ok, JSON.stringify(checked.report)).toBe(false); + expect(checked.report.validation?.mode).toBe('daemon'); + const refusal = checked.report.diagnostics.find((entry) => entry.severity === 'refusal'); + // The daemon names the field and its own index; the report adds the authored + // step id for that index, and claims no compiler bug for an authored step. + expect(refusal).toMatchObject({ kind: 'invalid_spec', stepId: 'edit' }); + expect(refusal?.message).toContain('unknown field "from_a_newer_sdk" at steps[1]'); + expect(refusal?.message).not.toContain('generated by this compiler'); +}); diff --git a/packages/sdk/tests/relay-cli-surface.test.ts b/packages/sdk/tests/relay-cli-surface.test.ts index 9eefa8ac1..814df656c 100644 --- a/packages/sdk/tests/relay-cli-surface.test.ts +++ b/packages/sdk/tests/relay-cli-surface.test.ts @@ -77,6 +77,8 @@ const INVOCATIONS: readonly { verb: string; argv: readonly string[]; variant: Pa { verb: 'build', argv: ['build', '--verify', '--json', BUNDLE_DIR], variant: 'build' }, { verb: 'build', argv: ['build', BUNDLE_DIR, '--verify'], variant: 'build' }, { verb: 'check', argv: ['check', 'flow.yaml'], variant: 'check' }, + { verb: 'check', argv: ['check', '--against-daemon', 'flow.yaml'], variant: 'check' }, + { verb: 'check', argv: ['check', '--no-daemon-check', 'flow.yaml'], variant: 'check' }, { verb: 'check', argv: ['check', '--explain-warnings', 'flow.yaml'], variant: 'check' }, { verb: 'check', argv: ['check', '--watch', '--json', 'flow.yaml'], variant: 'check' }, // Both `deploy` forms: the positional decides which variant the verb produces. diff --git a/packages/sdk/tsconfig.tests.json b/packages/sdk/tsconfig.tests.json index 773c991c6..3390d6f8f 100644 --- a/packages/sdk/tsconfig.tests.json +++ b/packages/sdk/tsconfig.tests.json @@ -12,6 +12,7 @@ "include": [ "src/**/*.ts", "tests/isolate-workspace.ts", + "tests/check-daemon-validation.test.ts", "tests/runtime-dependencies.test.ts", "tests/cli-package-gate.test.ts", "tests/run-projection.test.ts", diff --git a/packages/sdk/vitest.config.ts b/packages/sdk/vitest.config.ts index 04c7db2fc..965ae127a 100644 --- a/packages/sdk/vitest.config.ts +++ b/packages/sdk/vitest.config.ts @@ -3,6 +3,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { environment: 'node', + env: { FLOWS_NO_DAEMON_CHECK: '1' }, include: ['tests/**/*.test.ts'], globals: false, setupFiles: ['tests/isolate-workspace.ts'],