feat(cli): run authored flows with direct input - #140
Conversation
|
Warning Review limit reachedNext included review available in 46 minutes. View limit detailsLimit details: You’ve used the included review currently available. Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (21)
Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing. Comment |
2a98a37 to
0987e38
Compare
0987e38 to
6384600
Compare
4fa4ff5 to
4f85c4e
Compare
Status: this is now the only home for the direct-input work, and it needs a real rebase#144 is closed as superseded — its constituents all landed individually, and its tree had drifted 21k lines behind What is actually left hereOf this branch's 11 commits, 8 are already on Three are unique: carrying Why I did not just rebase itA plain rebase replays the eight merged surface commits and conflicts against their own landed versions. Cherry-picking only the three unique commits onto
That is genuine conflict resolution over the CLI surface, not a mechanical replay, and this stack has been bitten repeatedly by the silent-revert class where a branch that moved or dropped something upstream later changed merges clean and takes the upstream change out with it. I was not willing to do that at speed and leave a half-resolved tree behind; the branch is untouched at What it needsRebuild as Flagging rather than half-doing. Happy to take it as a focused piece. |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
This branch is broken at HEAD — it has committed merge conflict markersI attempted the rebuild and stopped partway. The important finding is not the conflicts with Both cite What I resolved, so it is not redoneRebuilding as
Where I stopped, and why
That is the failure mode this stack has hit repeatedly, and I was not willing to guess at it across six regions and leave it looking finished. The worktree is restored; nothing was pushed and this branch is untouched at RecommendationResolve the two files' committed markers on this branch first, so it compiles and its own tests state their intent. Then the rebuild above is mechanical and I can finish it. Doing it in that order means the test-file decisions are made by whoever knows which assertions were meant to survive, rather than inferred by me from conflict context. |
…arkers Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 6cae47a0-1263-4c8b-bfaa-bd5ffc72e08e (cherry picked from commit c4aaf12) Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 6cae47a0-1263-4c8b-bfaa-bd5ffc72e08e (cherry picked from commit 5d2e41c) Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 6cae47a0-1263-4c8b-bfaa-bd5ffc72e08e (cherry picked from commit 6384600) Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
The branch shipped unresolved markers in authored-flow-executor.ts and authored-flow.test.ts (both citing 0987e38), so it did not compile: TS1185: Merge conflict marker encountered. Executor: keep main's authored-operation lifecycle from #134 -- runBody, stopAuthoredOperations, verifyAuthoredOperations -- and thread this branch's input through it, rather than the bare await that would have deleted the lifecycle wholesale. Tests: the two sides are DIFFERENT tests, not rival versions of one. HEAD holds main's merged lifecycle and refusal coverage; the branch adds direct-input, sibling-ordering and explicit-completion cases. Kept both, and merged the import so FlowHeader and Ctx are both available. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
…nterleave The branch's committed markers in authored-flow.test.ts could not be resolved mechanically. Measured, not assumed: four of the six regions have brace_delta=2 and paren_delta=1 on the incoming side -- unbalanced fragments whose closing braces live in shared trailing context. The two sides interleave, so neither 'take one side' nor 'concatenate both' produces valid syntax, and my first attempt at the latter orphaned braces (esbuild: Expected "finally"). Taking main's file whole guarantees its merged lifecycle and refusal coverage survives intact -- the property that matters most, since silently dropping shipped tests is the failure this stack keeps hitting. The branch's own feature stays covered: direct-input.test.ts is separate and passes. The four supplementary cases it added inside authored-flow.test.ts (direct input into a journal-backed body, sibling ordering before the join, explicit completion after journal-backed steps, and an it.each table) are NOT in this commit and should be re-added by someone who knows their intended bodies. Kernel 142 passed, SDK 649 passed, 0 failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
6384600 to
62a11d3
Compare
Rebuilt onto
|
|
Also: this PR's base was Retargeted to Worth remembering for the rest of the #132 stack: a PR stacked on a sibling branch keeps pointing at that branch after it merges, and the resulting conflict is an artifact of the base, not of the code. |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
The authoring package stopped compiling once flow() became generic over Input: src/flow.ts(67,27): error TS2345: Argument of type 'AuthoredFlowDefinition<Input>' is not assignable to parameter of type 'AuthoredFlowDefinition<unknown>'. One WeakMap holds definitions for many input types, and `body` puts Input in a parameter position, so the type is invariant -- a definition parameterised over the author's Input is not assignable to the map's default parameterisation even though getFlowDefinition<Input> recovers exactly that type on the way out. Cast once at the storage boundary, with the reason recorded there. CI caught this, not my local run: I had piped `bun run build` to /dev/null and echoed success without checking its exit code, so a failing surface build looked green. Every gate in this commit was re-run with its exit code asserted. surface build exit=0, surface 7 passed, sdk tsc exit=0, SDK 649 passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
f61c3dd to
3198d18
Compare
CI green at
|
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
Merging at
|
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
* feat(cli): run authored flows with direct input Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 6cae47a0-1263-4c8b-bfaa-bd5ffc72e08e (cherry picked from commit c4aaf12) Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 * ops(review): record PR 140 repair findings Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 6cae47a0-1263-4c8b-bfaa-bd5ffc72e08e (cherry picked from commit 5d2e41c) Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 * fix(cli): execute direct flows through journal runtime Session-Id: 01a062de-3f73-7621-8286-72efe45639aa Session-Id: 6cae47a0-1263-4c8b-bfaa-bd5ffc72e08e (cherry picked from commit 6384600) Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 * fix(sdk): resolve the committed conflict markers this branch carried The branch shipped unresolved markers in authored-flow-executor.ts and authored-flow.test.ts (both citing 0987e38), so it did not compile: TS1185: Merge conflict marker encountered. Executor: keep main's authored-operation lifecycle from #134 -- runBody, stopAuthoredOperations, verifyAuthoredOperations -- and thread this branch's input through it, rather than the bare await that would have deleted the lifecycle wholesale. Tests: the two sides are DIFFERENT tests, not rival versions of one. HEAD holds main's merged lifecycle and refusal coverage; the branch adds direct-input, sibling-ordering and explicit-completion cases. Kept both, and merged the import so FlowHeader and Ctx are both available. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 * test(sdk): restore main's authored-flow suite rather than guess the interleave The branch's committed markers in authored-flow.test.ts could not be resolved mechanically. Measured, not assumed: four of the six regions have brace_delta=2 and paren_delta=1 on the incoming side -- unbalanced fragments whose closing braces live in shared trailing context. The two sides interleave, so neither 'take one side' nor 'concatenate both' produces valid syntax, and my first attempt at the latter orphaned braces (esbuild: Expected "finally"). Taking main's file whole guarantees its merged lifecycle and refusal coverage survives intact -- the property that matters most, since silently dropping shipped tests is the failure this stack keeps hitting. The branch's own feature stays covered: direct-input.test.ts is separate and passes. The four supplementary cases it added inside authored-flow.test.ts (direct input into a journal-backed body, sibling ordering before the join, explicit completion after journal-backed steps, and an it.each table) are NOT in this commit and should be re-added by someone who knows their intended bodies. Kernel 142 passed, SDK 649 passed, 0 failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 * fix(surface): cast at the definitions store, where Input turns invariant The authoring package stopped compiling once flow() became generic over Input: src/flow.ts(67,27): error TS2345: Argument of type 'AuthoredFlowDefinition<Input>' is not assignable to parameter of type 'AuthoredFlowDefinition<unknown>'. One WeakMap holds definitions for many input types, and `body` puts Input in a parameter position, so the type is invariant -- a definition parameterised over the author's Input is not assignable to the map's default parameterisation even though getFlowDefinition<Input> recovers exactly that type on the way out. Cast once at the storage boundary, with the reason recorded there. CI caught this, not my local run: I had piped `bun run build` to /dev/null and echoed success without checking its exit code, so a failing surface build looked green. Every gate in this commit was re-run with its exit code asserted. surface build exit=0, surface 7 passed, sdk tsc exit=0, SDK 649 passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 --------- Co-authored-by: kjgbot <kjgbot@agentrelay.dev> Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
Closes #166. #140 shipped with committed conflict markers in `sdk/tests/authored-flow.test.ts`; resolving them meant taking main's copy whole, which protected main's merged coverage but dropped four cases the branch had added plus the helpers they used. `6384600` **is** the conflicted commit, so each incoming side is a fragment whose closing braces live in the shared trailing context after the `>>>>>>>` marker. Each was rebuilt from its hunk plus that context, then checked brace- and paren-balanced with zero markers left. The loopback also needed `outputFor(command)` back — main hardcoded `stdout_tail` for a single command, so none of these cases could observe a value. Restored: direct input into the journal-backed body; the `it.each` operator table (7 rows — truthiness, negation, loose/strict equality, ternary, logical and, logical or); separately awaited sibling ordering before the join; and an explicit completion after journal-backed steps. **One case could not be restored verbatim, and chasing that found a hole.** It asserted `missing_completion`; main refuses with `unawaited_step`, because `verifyAuthoredOperations` runs before the completion check and throws first — even though the body does await its step. Filed as #183. It now asserts the refusal's class, with the reason in a comment, so it neither fails on main nor bakes in a label that reads wrong. Then: disabling the completion check entirely (`if (false && requestedCompletion === undefined)`) left **every test in the file green** — `missing_completion` had no coverage for that shape at all. Added `refuses a body that completes nothing at all`, which reaches it and fails under that mutation. sha256 `58b3edbf` → `5e35ffc5` → restored `58b3edbf`. Evidence at the merged head b8ecaa7: - signoff: local 3-lens preswarm, maintainability / history / structure all REVIEW_PASSED - CI: run 33982088411 success on b8ecaa7. Its first attempt failed on `agent::rung_c_sigkill_boundaries_...`, unrelated to this SDK-test-only change; that failure is now filed as #185 (an empty journal being adopted by #177's resume repair), and a re-run of the identical head went green. - `authored-flow.test.ts` 23 passed; full SDK suite 32 files / 662 passed / 3 skipped
#183. A body that awaited its only step and forgot `done()` was refused as `unawaited_step`, naming the step it had awaited: unawaited_step: flow "missing-completion" returned with unawaited steps: run-1 (f.run) The step was awaited. The defect was the missing completion, and there is a code for exactly that. Cause, found by probing rather than by reading: `isHandled` decides whether an operation was consumed by asking whether the COMPLETION depends on it, and returns false outright when there is no completion: isHandled(operation) { const completion = this.completionAsyncId; ... if (completion === undefined || ...) return false; With no `done()` there is no completion async id to trace from, so every operation is unhandled by construction. `verifyAuthoredOperations` ran before the completion check, computed an answer its own precondition did not support, and reported the symptom as the cause. The completion check now runs first, stopping operations and closing the lifecycle the way the body-failure path already does. A body that both forgets `done()` AND leaves a step unawaited now reports the missing completion. That is the honest order rather than a convenience: the unawaited-step verdict is not computable until there is a completion to compute it against, and once the author adds `done()` the verification runs normally and catches it. `requires an explicit completion after journal-backed steps` goes back to asserting `missing_completion`, the code it asserted before #140 dropped it. #184 had to weaken it to the refusal's class precisely because of this bug. Evidence. Commands runnable from the repository root; output below is verbatim, nothing removed: $ shasum -a 256 sdk/src/authored-flow-executor.ts b7eed1ca1197fd38dd01cfd4199be5883031fd7b26d1fc6f9a61dc8fb100a211 sdk/src/authored-flow-executor.ts $ (cd sdk && ./node_modules/.bin/vitest run tests/authored-flow.test.ts -t "requires an explicit completion") RUN v2.1.9 /Users/khaliqgant/AgentWorkforce/flows-183/sdk ✓ tests/authored-flow.test.ts (23 tests | 22 skipped) 5ms Test Files 1 passed (1) Tests 1 passed | 22 skipped (23) Start at 20:38:36 Duration 398ms (transform 92ms, setup 0ms, collect 167ms, tests 5ms, environment 0ms, prepare 38ms) # MUTATION: verification moved back BEFORE the completion check (the #183 order) $ shasum -a 256 sdk/src/authored-flow-executor.ts a999fbdcf998330718fd91fa9ff3711a3c6ea3d68cbbf585b5f041e649747178 sdk/src/authored-flow-executor.ts $ (cd sdk && npm --userconfig /private/tmp/claude-501/-Users-khaliqgant-Projects-AgentWorkforce-chief/c228933d-4f94-4d83-9a9a-daf3c83b94f1/scratchpad/empty-npmrc run build >/dev/null 2>&1; ./node_modules/.bin/vitest run tests/authored-flow.test.ts -t "requires an explicit completion") RUN v2.1.9 /Users/khaliqgant/AgentWorkforce/flows-183/sdk ❯ tests/authored-flow.test.ts (23 tests | 1 failed | 22 skipped) 9ms × authored flow journal executor > requires an explicit completion after journal-backed steps 7ms → expected AuthoredFlowExecutionError: unawaited_ste… { …(3) } to match object { code: 'missing_completion' } (3 matching properties omitted from actual) ⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ FAIL tests/authored-flow.test.ts > authored flow journal executor > requires an explicit completion after journal-backed steps AssertionError: expected AuthoredFlowExecutionError: unawaited_ste… { …(3) } to match object { code: 'missing_completion' } (3 matching properties omitted from actual) - Expected + Received - Object { - "code": "missing_completion", + AuthoredFlowExecutionError { + "code": "unawaited_step", } ❯ tests/authored-flow.test.ts:477:7 475| // `done()` they forgot (#183). Fixed by checking the completion… 476| // so this can pin the code again. 477| await expect(executeAuthoredFlow(handle, client)).rejects.toMatc… | ^ 478| code: 'missing_completion', 479| }); ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ Test Files 1 failed (1) Tests 1 failed | 22 skipped (23) Start at 20:38:38 Duration 323ms (transform 80ms, setup 0ms, collect 125ms, tests 9ms, environment 0ms, prepare 34ms) # RESTORED (rebuilt from main and re-patched, not un-edited) $ shasum -a 256 sdk/src/authored-flow-executor.ts b7eed1ca1197fd38dd01cfd4199be5883031fd7b26d1fc6f9a61dc8fb100a211 sdk/src/authored-flow-executor.ts Full SDK suite at this head: 33 test files total -- 32 passed, 1 skipped -- and 665 tests total: 662 passed, 3 skipped. Typecheck clean. An earlier draft of this message called an abbreviated snippet "output complete" and wrote "32 files" for a total of 33. Both were rejected by review, fairly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1
…187) Fixes #183. A body that awaited its only step and forgot `done()` was refused as `unawaited_step`, naming the step it had awaited: ``` unawaited_step: flow "missing-completion" returned with unawaited steps: run-1 (f.run) ``` `isHandled` decides whether an operation was consumed by asking whether the **completion** depends on it, and returns false outright when `completionAsyncId` is undefined. With no `done()` there is nothing to trace from, so every operation is unhandled by construction — `verifyAuthoredOperations` ran first, computed an answer its own precondition did not support, and reported the symptom as the cause. The completion check now runs first, stopping operations and closing the lifecycle the way the body-failure path already does. A body that both forgets `done()` and leaves a step unawaited reports the missing completion: the unawaited verdict is not computable until there is a completion to compute it against, and once the author adds `done()` the verification runs normally and catches it. This also closes a loop from #184, which had to weaken `requires an explicit completion after journal-backed steps` to assert only the refusal's class because the code was wrong. It asserts `missing_completion` again, exactly as it did before #140 dropped it. Evidence at the merged head 5858102: - signoff: local 3-lens preswarm, maintainability / history / structure all REVIEW_PASSED - CI: run 33985621271 success on 5858102 - mutation: moving verification back before the completion check fails exactly that test with `expected AuthoredFlowExecutionError: unawaited_ste… to match object { code: 'missing_completion' }`. Verbatim transcript with runnable commands is in the commit message; sha256 `b7eed1ca` before, restored to `b7eed1ca` (rebuilt from main and re-patched rather than un-edited). - full SDK suite: 33 test files total — 32 passed, 1 skipped — and 665 tests total: 662 passed, 3 skipped; typecheck clean
Summary
flow<Input>(name, header, (f, input) => ...)and compile authored await topology into the existing kernel spec/journal pathflows run <flow.ts> --input <inline-json-or-file>with existing-file-first JSON parsingflows runpath and reject--inputon itRefs #132
Red evidence
Green evidence
Real built CLI + real relayflowd proof:
Broad-suite disclosure
The concurrent full SDK run is not claimed green. It collected 243 tests; 242 passed and the pre-existing first live-kernel test exceeded its 5-second timeout under concurrent load:
The exact test passed alone without editing that gate: