Skip to content

feat(cli): 2.K — engine regression harness over relavium run --json (M3)#43

Merged
cemililik merged 8 commits into
mainfrom
development
Jun 22, 2026
Merged

feat(cli): 2.K — engine regression harness over relavium run --json (M3)#43
cemililik merged 8 commits into
mainfrom
development

Conversation

@cemililik

@cemililik cemililik commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What & why

Adopts the CLI as the engine's canonical end-to-end regression harness — Phase-2
workstream 2.K, which completes the M3 spine together with 2.D + 2.F. Committed
example workflows run through the real relavium run … --json path, and the resulting
NDJSON RunEvent stream + exit code are asserted against pinned expectations. Because the
run goes through the same engine, renderer, and exit-code mapping as production, a
regression in the engine run loop, the --json machine-output contract (ADR-0049), or the
exit codes fails CI. Runs are fully offline + deterministic on every PR (non-agent
fixtures — no LLM, no provider key, no network).

Canonical home: docs/reference/cli/regression-harness.md.
The maintainer-approved scope split (2026-06-22) is recorded in
phase-2-cli.md §2.K.

The harness

5 fixtures / 7 scenarios covering every authorable non-agent node type and all three run
exit codes:

Fixture Covers Exit
sequential input → transform → output 0
fan-out parallel split + merge (fan_out/fan_in) 0
conditional (×2: n=3, n=15) condition branch + symmetric node:skipped skip-propagation (both arms) 0
human-gate human_gate pause → run:paused 3
failure throwing transform → node:failedrun:failed (downstream skipped) 1

Assertion strategy — each event is reduced to a type:nodeId signature (keyed by
node, so a wrong-branch / wrong-node regression is caught, not just a dropped/extra
event). Deterministic fixtures assert the exact ordered sequence; the one parallel
fan-out asserts the signature multiset + anchors (its branch events legitimately
interleave by async timing). Plus: gap-free sequenceNumber, per-line round-trip
RunEventSchema equality (a stray field is caught), and stderr empty on clean runs.

Real engine path — enters at the runCommand boundary → default engine + the real
createCliHost (random UUIDs, wall clock), exactly as a production invocation; in-process
(no binary spawn), inside the required ci test job.

Full argv shell — one scenario additionally drives a fixture through the entire
run(argv) CLI entry (argv → extractGlobalOptions → commander → the run <workflow>
subcommand → terminal exit code) and asserts the identical stream + exit code. It uses
conditional n=15 on purpose: a dropped/mis-parsed --input routes to lo (the no-input
default), flipping node:skipped:hinode:skipped:lo and failing — so the test has real
teeth on --input threading (a topology-flat fixture could not prove it).

Also in this PR

Review trail

  • Three independent external reviews of the harness (cd8166e): all PASS / clean to merge.
  • Their one LOW finding (§2.K fixture undercount, four vs five) → fixed in 5c99bfb.
  • Their one "no-action" observation (harness enters at runCommand, not run(argv)) →
    closed in f6c7d48 by covering the full argv shell. Adversarial self-verification of that
    post-review commit then found its --input claim was hollow on the sequential fixture
    (input-independent topology) → strengthened in 22bca51 (conditional n=15; teeth
    confirmed empirically).

Verification

  • pnpm turbo run lint typecheck test build — green (20/20 tasks).
  • apps/cli: 123 tests (harness 7), all green.
  • No new ADR, no new dependency, no @relavium/llm seam crossing; packages/core untouched.

Deferred (recorded in §2.K)

  • Gate-resume scenario (relavium gate --approve → completion) → needs 2.G + 2.H.
  • Agent fixtures via recorded-LLM replay + the nightly live-provider lane → later.

🤖 Generated with Claude Code

Summary by Sourcery

Introduce an end-to-end engine regression harness that runs committed workflow fixtures through the real relavium run … --json path and asserts NDJSON output and exit codes, while consolidating CLI test IO capture and updating roadmap/docs to mark --json CI mode as done.

New Features:

  • Add an in-process Vitest regression harness for the CLI that executes non-agent workflow fixtures via relavium run … --json and validates event streams and exit codes across success, failure, and gate-pause scenarios.
  • Define committed workflow fixtures (sequential, fan-out, conditional, human-gate, failure) to exercise all non-agent node types and all three run exit codes through the real engine path.
  • Document the engine regression harness as the canonical CLI-based end-to-end gate, including fixture format, assertions, and deferred gate-resume/agent scenarios.

Enhancements:

  • Extract shared CLI test IO capture into a reusable captureIo helper and adopt it across existing CLI and renderer tests.
  • Clarify Phase 2 CLI roadmap and project overviews to mark workstream 2.F (--json machine-output contract) as complete and position 2.K as the M3-closing harness work.

Summary by CodeRabbit

  • Documentation

    • Updated project/roadmap status and the Phase 2 CLI narrative to reflect the landed --json machine-output contract.
    • Added/expanded documentation for the engine regression harness, including fixture/scenario guidance and the “engine-first test discipline” standards.
  • Tests

    • Added an end-to-end engine regression harness that executes committed workflow fixtures via the real relavium run --json path and validates deterministic NDJSON event streams plus exit codes.
    • Refactored CLI-related tests to use a shared IO-capture helper for consistent output assertions.

cemililik and others added 5 commits June 22, 2026 19:50
PR #42 merged the CLI `--json` machine-output contract (2.F) + ADR-0049 + the 2.D-Done
bookkeeping. Flip the status surfaces now that it's on main (roadmap-done-after-merge):

- phase-2-cli.md: 2.F heading → ✅ Done (PR #42); status line records it (behind
  ADR-0049) and advances the spine pointer to 2.K (the regression harness that reaches M3).
- current.md: record 2.F Done (PR #42); "Next on the spine" → 2.K.
- CLAUDE.md / README.md: status paragraphs note the `--json` CI output contract has landed.

The 2.E (ink TUI) and 2.H (durable run history) run-surface feeders remain open.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adopt the CLI as the engine's canonical end-to-end regression gate (completes M3 with
2.D + 2.F). An in-process vitest e2e suite (apps/cli/src/harness/) runs committed example
workflows through the REAL `relavium run … --json` path (the default engine over the real
createCliHost) and asserts on the NDJSON RunEvent stream + exit code — deterministic and
offline on every PR, inside the existing required `test` CI gate.

- Fixtures (apps/cli/src/harness/fixtures/, non-agent → no LLM/key/network): sequential,
  fan-out (parallel + object_merge), conditional (condition + node:skipped, both arms via
  n=3→lo and n=15→hi), human-gate (run:paused → exit 3), failure (a throwing transform →
  run:failed → exit 1). Together they cover every authorable non-agent node type and all
  three run exit codes (0/1/3).
- Assertion is keyed by a `type:nodeId` SIGNATURE (not just event type), so a wrong-branch /
  wrong-node regression is caught — exact ordered sequence for deterministic fixtures, the
  signature multiset + anchors for the `parallel` fan-out (whose branches interleave by async
  timing). Plus gap-free sequenceNumber (ADR-0036), each line round-trips to exactly a
  canonical RunEvent, and stderr is empty (the stdout-pure --json contract, ADR-0049).
- Shared captureIo extracted to apps/cli/src/test-support.ts; the three other test copies
  (run.test, commands/run.test, render/renderer.test) now import it.

No new ADR, no new dependency, no @relavium/shared change — 2.K composes ADR-0036/0047/0049
+ the @relavium/llm conformance/replay substrate + the 1.U m2-e2e-harness seed.

Docs: a new docs/reference/cli/regression-harness.md (the canonical fixture + scenario
format) + a testing.md section; the §2.K work note records the maintainer-approved scope —
the gate-RESUME scenario is deferred to 2.G+2.H and agent-replay + the nightly live lane to
later (both need the replay-provider wiring), with the run-to-gate→exit-3 half shipping now.

Also marks 2.F Done (PR #42) across the status surfaces (post-merge bookkeeping, riding along).

Refs: ADR-0036, ADR-0047, ADR-0049

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The §2.K first-cut note undercounted the harness fixtures: it omitted
failure.relavium.yaml (the run:failed / exit-1 case), so it read "four" and
undersold the "all three exit codes 0/1/3" coverage. The canonical
reference/cli/regression-harness.md already lists all five; align the roadmap note.

Refs: 2.K review

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… run

The 2.K harness enters each fixture at the `runCommand` boundary (max engine
fidelity). One review left an open observation: the argv → extractGlobalOptions →
commander → `run <workflow>` subcommand → runCommand → terminal-exit-code shell is
exercised by neither suite for a real run — run.test.ts drives the shell only for
meta-ops (--help/--version → 0) and faults (→ 2), never a workflow reaching a run
terminal (0/1/3).

Close it: re-run one representative deterministic fixture through the full
`run(argv('run', <workflow>, '--input', …, '--json'))` entry and assert it yields the
IDENTICAL NDJSON stream + exit code the runCommand-boundary harness pins. This both
covers the argv-parsing glue for a real run (positional workflow, repeatable --input,
the position-independent --json global) and validates the harness's own entry-point
choice. Refactors NDJSON parsing into a shared parseEvents() used by both paths.

Updates the canonical regression-harness.md + the harness docstring to document the
runCommand-vs-argv split and that the shell is now covered end-to-end.

apps/cli: 123 tests green (harness 7). No new ADR/dependency/seam; engine untouched.

Refs: 2.K review

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The argv-shell scenario added in f6c7d48 used the sequential fixture, but
sequential's topology is input-independent: `inputs.n * 2` yields NaN (not an
error) when n is absent, so the run reaches the same terminal with the same event
topology whether or not `--input` threaded. Verified empirically: running
sequential with `n=3` vs no input produces byte-identical NDJSON and exit 0. So the
test could not actually catch the argv→commander glue dropping `--input` — the
"covers repeatable --input" claim was hollow.

Switch it to the conditional fixture at n=15 — the one arm whose topology depends on
the input. A missing/mis-parsed `--input` makes `inputs.n >= 10` false and routes to
`lo` (the no-input default), flipping node:skipped:hi↔node:skipped:lo and failing the
assertion (n=3 also routes to lo, so only n=15 distinguishes a threaded flag from a
dropped one). The argv-shell test now genuinely exercises positional <workflow> +
repeatable --input + the --json global, end-to-end to a terminal exit.

apps/cli: 123 tests green (harness 7). Self-found via adversarial verification of the
post-review commit; no engine/seam/dependency change.

Refs: 2.K review

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Reviewer's Guide

Implements the 2.K engine regression harness by adding an in-process vitest e2e suite that drives real relavium run … --json workflows through the CLI, introduces shared IO capture test utilities, adds non-agent workflow fixtures, and updates roadmap/testing/docs to mark 2.F Done and document the harness as the canonical regression gate.

Sequence diagram for 2.K CLI engine regression harness over relavium run --json

sequenceDiagram
    actor Vitest
    participant RegressionHarness as regression.e2e.test.ts
    participant RunCommand as runCommand
    participant RunCli as run
    participant ExtractOpts as extractGlobalOptions
    participant Commander as commander

    %% Path 1: Direct engine-fidelity entry via runCommand
    Vitest->>RegressionHarness: runFixture(scenario)
    RegressionHarness->>RunCommand: runCommand({ workflow, input }, { io, global })
    RunCommand-->>RegressionHarness: ExitCode + NDJSON stdout
    RegressionHarness->>RegressionHarness: parseEvents(stdout)
    RegressionHarness-->>Vitest: assert signatures, gap-free sequenceNumber, exit

    %% Path 2: Full argv shell via run(argv)
    Vitest->>RegressionHarness: run(argv(...), io)
    RegressionHarness->>RunCli: run(argv, io)
    RunCli->>ExtractOpts: extractGlobalOptions(argv)
    ExtractOpts-->>RunCli: GlobalOptions
    RunCli->>Commander: commander.parse(argv)
    Commander->>RunCommand: runCommand({ workflow, input }, { io, global })
    RunCommand-->>Commander: ExitCode + NDJSON stdout
    Commander-->>RunCli: ExitCode
    RunCli-->>RegressionHarness: ExitCode
    RegressionHarness->>RegressionHarness: parseEvents(stdout)
    RegressionHarness-->>Vitest: assert identical stream + exitCode to runCommand path
Loading

File-Level Changes

Change Details Files
Add engine regression harness e2e suite over relavium run … --json with multiple fixture scenarios and full-shell coverage.
  • Introduce regression.e2e.test.ts that runs committed .relavium.yaml fixtures via runCommand with --json and asserts NDJSON RunEvent streams plus exit codes.
  • Implement scenario table covering sequential, fan-out/parallel, conditional (two inputs), human-gate pause, and failure workflows, asserting per-node type:nodeId signatures.
  • Enforce additional invariants: gap-free sequenceNumber, schema round-trip equality via RunEventSchema.parse, stderr empty for clean runs, and multiset/anchor-based checks for parallel interleaving.
  • Add a test that drives the conditional n=15 fixture through the full run(argv) CLI shell and asserts identical events/exit code to prove --input/--json threading through argv parsing.
apps/cli/src/harness/regression.e2e.test.ts
Add committed non-agent workflow fixtures used by the harness to cover key node types and exit codes.
  • Create a sequential input→transform→output workflow fixture that exercises a simple success path.
  • Create a fan-out/fan-in workflow using a parallel node plus merge with object_merge to cover concurrent branches.
  • Create a conditional workflow fixture that routes to hi or lo branches based on inputs.n, enabling skip-propagation coverage in both directions.
  • Create a human-gate fixture that pauses via a human_gate node and yields run:paused with gate-paused exit code 3.
  • Create a failure fixture where a transform throws (null.boom), producing node:failed and run:failed with exit code 1.
apps/cli/src/harness/fixtures/sequential.relavium.yaml
apps/cli/src/harness/fixtures/fan-out.relavium.yaml
apps/cli/src/harness/fixtures/conditional.relavium.yaml
apps/cli/src/harness/fixtures/human-gate.relavium.yaml
apps/cli/src/harness/fixtures/failure.relavium.yaml
Factor out shared CLI IO capture utility and update existing tests to use it.
  • Introduce captureIo helper that implements CliIo and accumulates stdout/stderr into in-memory buffers for assertions.
  • Refactor run.test.ts to use the new captureIo instead of an inline makeIo helper.
  • Refactor renderer.test.ts and commands/run.test.ts to import and use the shared captureIo helper, removing duplicate implementations.
apps/cli/src/test-support.ts
apps/cli/src/run.test.ts
apps/cli/src/render/renderer.test.ts
apps/cli/src/commands/run.test.ts
Document the regression harness and update roadmap and status docs to reflect 2.F completion and 2.K scope split.
  • Add docs/reference/cli/regression-harness.md describing the harness purpose, location, assertion strategy, fixtures, and deferred items (gate-resume, agent fixtures, nightly lane).
  • Update phase-2-cli.md to mark 2.F as Done, describe 2.K first-cut implementation details, and explicitly list deferred work tied to 2.G/2.H and agent replay.
  • Update docs/roadmap/current.md, README.md, and CLAUDE.md to state that --json CI mode (2.F) is Done and that 2.K is the next M3 step.
  • Extend docs/standards/testing.md to position the engine regression harness as the canonical workflow-level test gate and reference its spec.
docs/reference/cli/regression-harness.md
docs/roadmap/phases/phase-2-cli.md
docs/roadmap/current.md
docs/standards/testing.md
CLAUDE.md
README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ad398e6a-e5bc-4a0c-85ab-7b4daafaeb94

📥 Commits

Reviewing files that changed from the base of the PR and between d67a704 and a0a739b.

📒 Files selected for processing (1)
  • docs/roadmap/phases/phase-2-cli.md

📝 Walkthrough

Walkthrough

Adds the Phase 2.K engine regression harness: five committed YAML workflow fixtures (sequential, fan-out, conditional, human-gate, failure), a Vitest e2e suite that runs them through the real relavium run --json path and validates NDJSON event streams and exit codes, a shared captureIo test helper extracted from three existing test files, and associated reference and roadmap documentation.

Changes

Engine Regression Harness (2.K)

Layer / File(s) Summary
Shared captureIo test helper and migration
apps/cli/src/test-support.ts, apps/cli/src/run.test.ts, apps/cli/src/commands/run.test.ts, apps/cli/src/render/renderer.test.ts
New captureIo() utility in test-support.ts returns a CliIo with chunk-accumulating writeOut/writeErr and out()/err() string getters. The equivalent local helper implementations in all three existing test files are removed and replaced with an import from the shared module.
YAML workflow fixtures
apps/cli/src/harness/fixtures/sequential.relavium.yaml, apps/cli/src/harness/fixtures/fan-out.relavium.yaml, apps/cli/src/harness/fixtures/conditional.relavium.yaml, apps/cli/src/harness/fixtures/human-gate.relavium.yaml, apps/cli/src/harness/fixtures/failure.relavium.yaml
Five committed workflow fixtures: a sequential single-transform chain, a parallel fan-out/merge using object_merge, a conditional branch on inputs.n >= 10, a human-gate approval pause (gate_type: approval), and a failure-propagation workflow using a null.boom transform.
Regression e2e harness
apps/cli/src/harness/regression.e2e.test.ts
SCENARIOS list pinning fixture file, CLI inputs, expected exit code, expected event signatures, and a parallel flag. parseEvents() parses NDJSON lines and round-trip validates each against RunEventSchema. runFixture() invokes runCommand via captureIo and asserts stderr is empty. assertGapFreeSeq() checks sequenceNumber is 0..n-1. argv() constructs full CLI invocations. Parameterized loop enforces exact ordered signatures for deterministic scenarios and multiset+anchor constraints for parallel ones. Dedicated integration test drives the conditional fixture via full CLI argv with n=15.
Reference docs and roadmap/status updates
docs/reference/cli/regression-harness.md, docs/roadmap/current.md, docs/roadmap/phases/phase-2-cli.md, docs/standards/testing.md, README.md, CLAUDE.md
New regression-harness.md reference document specifies the harness contract, assertion set, fixture list, add-a-fixture procedure, and deferred scope items. Roadmap and status files mark 2.F complete (PR #42) and advance the next spine item to 2.K. docs/standards/testing.md adds a description of the engine regression harness under "Engine-first test discipline".

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • HodeTech/Relavium#42: The --json NDJSON output contract and exit-code mapping that the harness asserts against (including RunEventSchema and stderr fault-envelope behavior) was established in PR #42.
  • HodeTech/Relavium#40: The regression harness refactors CLI test IO capture helpers that were scaffolded in the CLI skeleton work in PR #40, extracting them into a shared test-support.ts module.

Poem

🐇 Hop hop, I pinned the events in a row,
Five fixtures now wired from start node to out,
captureIo shared so no helpers repeat,
The NDJSON stream validated complete,
Gap-free sequences, multisets just right —
The regression harness runs clean every night! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(cli): 2.K — engine regression harness over relavium run --json (M3)' accurately describes the main objective: introducing the 2.K engine regression harness for the CLI that executes workflows via the real relavium run --json path. It clearly references the phase workstream (2.K) and milestone (M3).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch development

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • When building fixture paths in the harness, use path.join(FIXTURES_DIR, scenario.file) instead of string concatenation (${FIXTURES_DIR}${scenario.file}) so the tests remain robust if the directory path ever changes (e.g., missing or duplicate trailing slashes).
  • The harness helpers (signature, parseEvents, assertGapFreeSeq) look generally useful for future CLI/engine tests; consider moving them into a shared test utility module (alongside captureIo) to avoid duplication as more harness cases or suites are added.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- When building fixture paths in the harness, use `path.join(FIXTURES_DIR, scenario.file)` instead of string concatenation (`${FIXTURES_DIR}${scenario.file}`) so the tests remain robust if the directory path ever changes (e.g., missing or duplicate trailing slashes).
- The harness helpers (`signature`, `parseEvents`, `assertGapFreeSeq`) look generally useful for future CLI/engine tests; consider moving them into a shared test utility module (alongside `captureIo`) to avoid duplication as more harness cases or suites are added.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the Phase 2 engine regression harness (2.K), establishing a canonical end-to-end regression gate for the CLI. It introduces a suite of offline, deterministic workflow fixtures and an in-process E2E test harness (regression.e2e.test.ts) that asserts on NDJSON event streams and exit codes. Additionally, it refactors existing tests to share a unified captureIo helper and updates relevant documentation and roadmap files. Feedback on the PR suggests improving parseEvents in the test harness to safely handle empty or whitespace-only stdout to prevent cryptic JSON parsing errors.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +174 to +184
function parseEvents(stdout: string): RunEvent[] {
return stdout
.trimEnd()
.split('\n')
.map((line) => {
const raw: unknown = JSON.parse(line);
const event = RunEventSchema.parse(raw);
expect(event).toEqual(raw);
return event;
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If stdout is empty or contains only whitespace, stdout.trimEnd().split('\\n') will produce [""]. Passing an empty string to JSON.parse will throw a cryptic SyntaxError: Unexpected end of JSON input, making test failures harder to diagnose.\n\nConsider checking if the trimmed output is empty first and returning an empty array. This allows subsequent assertions (like expect(sigs).toEqual(...)) to fail with a clear diff of expected events vs. empty array instead of a parsing crash.

Suggested change
function parseEvents(stdout: string): RunEvent[] {
return stdout
.trimEnd()
.split('\n')
.map((line) => {
const raw: unknown = JSON.parse(line);
const event = RunEventSchema.parse(raw);
expect(event).toEqual(raw);
return event;
});
}
function parseEvents(stdout: string): RunEvent[] {
const trimmed = stdout.trim();
if (!trimmed) {
return [];
}
return trimmed.split('\\n').map((line) => {
const raw: unknown = JSON.parse(line);
const event = RunEventSchema.parse(raw);
expect(event).toEqual(raw);
return event;
});
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/cli/src/harness/regression.e2e.test.ts (1)

215-220: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Tighten parallel-case assertions with causal ordering checks.

The multiset + first/last anchors can still pass when event causality is wrong (for example, combine starting before both branch completions). Add a few partial-order checks to keep interleaving flexibility while catching scheduler regressions.

Proposed test hardening
       if (scenario.parallel === true) {
         // Branch events interleave by async timing → assert the multiset + the stable anchors.
         expect(sigs[0]).toBe('run:started');
         expect(sigs.at(-1)).toBe(scenario.events.at(-1));
         expect([...sigs].sort()).toEqual([...scenario.events].sort());
+        const idx = (sig: string): number => sigs.indexOf(sig);
+        expect(idx('node:started:combine')).toBeGreaterThan(
+          Math.max(idx('node:completed:double'), idx('node:completed:triple')),
+        );
+        expect(idx('node:started:out')).toBeGreaterThan(idx('node:completed:combine'));
       } else {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cli/src/harness/regression.e2e.test.ts` around lines 215 - 220, In the
parallel test case where scenario.parallel === true, add partial-order
assertions beyond the current multiset and first/last anchor checks to validate
causal ordering of events. Specifically, add checks that verify certain event
dependencies are maintained (for example, ensuring branch-related events
complete before subsequent events like combine start), while still permitting
flexible interleaving of parallel operations. Use indexOf or similar lookups on
the sigs array to assert that events maintaining causal relationships appear in
the correct relative order.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/cli/src/harness/regression.e2e.test.ts`:
- Around line 3-4: The ESLint violations for RunEventSchema and RunEvent
indicate that the TypeScript compiler cannot properly resolve the type
definitions from the `@relavium/shared` package, resulting in unsafe member access
errors across lines 156, 175-183, and 202. Ensure that the `@relavium/shared`
package is properly built and that its type declarations are accessible by
rebuilding the shared package, verifying that the build output includes
generated type definition files, and confirming that the tsconfig.json in the
CLI project correctly references the shared package's type declarations. If the
shared package was recently modified, clean and rebuild both the shared package
and the CLI project to ensure TypeScript has access to the latest type
information.

In `@docs/roadmap/current.md`:
- Around line 45-46: The roadmap currently lists 2.K as the next item on the
spine, but since this PR already ships the 2.K engine regression harness, the
roadmap will be outdated when merged. Move 2.K from the "Next on the spine"
section to a "done" or "completed" section, and update the spine sequence to
reflect the actual next milestone that should follow 2.K (removing 2.K from the
"Next on the spine" statement and identifying what the new next priority should
be).

In `@docs/roadmap/phases/phase-2-cli.md`:
- Line 3: The status line in the phase-2-cli.md header currently lists 2.K as
the next upcoming item on the spine, but this PR contains the 2.K deliverable
(the engine regression harness). Update the status line by adding 2.K to the
completed items list (mark it as done with the PR number and date, similar to
how 2.A, 2.B, 2.D, and 2.F are marked), remove it from the "next on the spine"
callout, and update the callout to reference the actual next item after 2.K to
eliminate the contradiction between the header and the content below.

---

Nitpick comments:
In `@apps/cli/src/harness/regression.e2e.test.ts`:
- Around line 215-220: In the parallel test case where scenario.parallel ===
true, add partial-order assertions beyond the current multiset and first/last
anchor checks to validate causal ordering of events. Specifically, add checks
that verify certain event dependencies are maintained (for example, ensuring
branch-related events complete before subsequent events like combine start),
while still permitting flexible interleaving of parallel operations. Use indexOf
or similar lookups on the sigs array to assert that events maintaining causal
relationships appear in the correct relative order.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8ec46303-20ff-48b3-91ba-7ad91cff7016

📥 Commits

Reviewing files that changed from the base of the PR and between ca13ebe and 22bca51.

📒 Files selected for processing (16)
  • CLAUDE.md
  • README.md
  • apps/cli/src/commands/run.test.ts
  • apps/cli/src/harness/fixtures/conditional.relavium.yaml
  • apps/cli/src/harness/fixtures/failure.relavium.yaml
  • apps/cli/src/harness/fixtures/fan-out.relavium.yaml
  • apps/cli/src/harness/fixtures/human-gate.relavium.yaml
  • apps/cli/src/harness/fixtures/sequential.relavium.yaml
  • apps/cli/src/harness/regression.e2e.test.ts
  • apps/cli/src/render/renderer.test.ts
  • apps/cli/src/run.test.ts
  • apps/cli/src/test-support.ts
  • docs/reference/cli/regression-harness.md
  • docs/roadmap/current.md
  • docs/roadmap/phases/phase-2-cli.md
  • docs/standards/testing.md

Comment on lines +3 to +4
import { RunEventSchema, type RunEvent } from '@relavium/shared';
import { describe, expect, it } from 'vitest';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Verify shared package type exports =="
fd -i package.json packages/shared -x cat {}

echo
echo "== Verify shared package entrypoints and declarations =="
rg -n --type=json "\"name\"\\s*:\\s*\"`@relavium/shared`\"|\"exports\"|\"types\"|\"typesVersions\"|\"main\""

echo
echo "== Verify CLI TypeScript project wiring =="
fd -i "tsconfig*.json" apps/cli -x cat {}

echo
echo "== Find other imports/usages for comparison =="
rg -n --type=ts "from '`@relavium/shared`'|RunEventSchema|type RunEvent"

Repository: HodeTech/Relavium

Length of output: 18553


🏁 Script executed:

head -n 220 apps/cli/src/harness/regression.e2e.test.ts | tail -n +140

Repository: HodeTech/Relavium

Length of output: 3063


🏁 Script executed:

wc -l apps/cli/src/harness/regression.e2e.test.ts

Repository: HodeTech/Relavium

Length of output: 109


🏁 Script executed:

sed -n '150,210p' apps/cli/src/harness/regression.e2e.test.ts | cat -n

Repository: HodeTech/Relavium

Length of output: 2683


🏁 Script executed:

cd apps/cli && npx eslint --no-eslintrc -c '{"extends": "../../.eslintrc.json"}' src/harness/regression.e2e.test.ts 2>&1 || true

Repository: HodeTech/Relavium

Length of output: 280


🏁 Script executed:

cd apps/cli && npx eslint src/harness/regression.e2e.test.ts 2>&1 || true

Repository: HodeTech/Relavium

Length of output: 1577


🏁 Script executed:

head -n 10 apps/cli/src/harness/regression.e2e.test.ts | cat -n

Repository: HodeTech/Relavium

Length of output: 548


🏁 Script executed:

cat apps/cli/tsconfig.json

Repository: HodeTech/Relavium

Length of output: 465


🏁 Script executed:

cat tsconfig.base.json | head -n 50

Repository: HodeTech/Relavium

Length of output: 1506


🏁 Script executed:

cat tsconfig.base.json | grep -A 30 "references"

Repository: HodeTech/Relavium

Length of output: 43


🏁 Script executed:

cat tsconfig.json

Repository: HodeTech/Relavium

Length of output: 107


🏁 Script executed:

find . -maxdepth 2 -name "tsconfig.json" -type f | head -20

Repository: HodeTech/Relavium

Length of output: 43


🏁 Script executed:

ls -la | grep tsconfig

Repository: HodeTech/Relavium

Length of output: 204


🏁 Script executed:

cat eslint.config.js 2>/dev/null | head -n 100 || cat .eslintrc.json 2>/dev/null || echo "No eslint config found in root"

Repository: HodeTech/Relavium

Length of output: 43


🏁 Script executed:

cat apps/cli/tsconfig.json apps/cli/package.json | head -100

Repository: HodeTech/Relavium

Length of output: 1275


🏁 Script executed:

ls -la packages/shared/dist/ 2>&1 || echo "dist not found"

Repository: HodeTech/Relavium

Length of output: 145


🏁 Script executed:

cat pnpm-workspace.yaml 2>/dev/null || cat package.json | grep -A 20 "workspaces"

Repository: HodeTech/Relavium

Length of output: 3126


Resolve @typescript-eslint/no-unsafe-* violations in RunEventSchema and RunEvent usage before merge.

ESLint confirms 11 errors across lines 156, 175–183, and 202, all flagging unsafe member access and returns on unresolved types from @relavium/shared. These violations block the merge under strict TypeScript rules (**/*.ts: no unsafe patterns).

The import statement is syntactically correct and identical to usage in other CLI test files. Verify that the shared package is built and type declarations are accessible to this file's TypeScript compiler context.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cli/src/harness/regression.e2e.test.ts` around lines 3 - 4, The ESLint
violations for RunEventSchema and RunEvent indicate that the TypeScript compiler
cannot properly resolve the type definitions from the `@relavium/shared` package,
resulting in unsafe member access errors across lines 156, 175-183, and 202.
Ensure that the `@relavium/shared` package is properly built and that its type
declarations are accessible by rebuilding the shared package, verifying that the
build output includes generated type definition files, and confirming that the
tsconfig.json in the CLI project correctly references the shared package's type
declarations. If the shared package was recently modified, clean and rebuild
both the shared package and the CLI project to ensure TypeScript has access to
the latest type information.

Sources: Coding guidelines, Linters/SAST tools

Comment thread docs/roadmap/current.md
Comment on lines +45 to +46
**Next on the spine:** **2.K** (the engine regression harness) to reach **M3**, with the **2.E**
(ink TUI) and **2.H** (durable run history) run-surface feeders open. The CLI also lands the inbound MCP client (2.R,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the spine after shipping 2.K.

This still treats 2.K as the next item, but this PR already lands the 2.K harness. Move 2.K to “done” here, or the roadmap will be stale as soon as it merges.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/roadmap/current.md` around lines 45 - 46, The roadmap currently lists
2.K as the next item on the spine, but since this PR already ships the 2.K
engine regression harness, the roadmap will be outdated when merged. Move 2.K
from the "Next on the spine" section to a "done" or "completed" section, and
update the spine sequence to reflect the actual next milestone that should
follow 2.K (removing 2.K from the "Next on the spine" statement and identifying
what the new next priority should be).

Comment thread docs/roadmap/phases/phase-2-cli.md Outdated
# Phase 2 — CLI

> Status: In progress (Product Phase 1, build phase 2). **2.A** (CLI skeleton + process contract) and **2.B** (config resolution) are ✅ **Done (PR #40, 2026-06-22)**, behind [ADR-0047](../../decisions/0047-cli-framework-commander-ink-clack.md) + [ADR-0048](../../decisions/0048-toml-config-parser.md); **2.D** (`run` → engine, the M3 keystone) is ✅ **Done (PR #41, 2026-06-22)**. The global milestone in play is **M3** (reached at 2.F + 2.K); next on the spine is **2.F** (`--json` CI mode), and the **2.E** (ink TUI) + **2.H** (durable run history) run-surface feeders now open.
> Status: In progress (Product Phase 1, build phase 2). **2.A** (CLI skeleton + process contract) and **2.B** (config resolution) are ✅ **Done (PR #40, 2026-06-22)**, behind [ADR-0047](../../decisions/0047-cli-framework-commander-ink-clack.md) + [ADR-0048](../../decisions/0048-toml-config-parser.md); **2.D** (`run` → engine, the M3 keystone) is ✅ **Done (PR #41, 2026-06-22)**, and **2.F** (the `--json` CI machine-output contract) is ✅ **Done (PR #42, 2026-06-22)**, behind [ADR-0049](../../decisions/0049-cli-machine-output-contract.md). The global milestone in play is **M3** (reached at 2.F + 2.K); next on the spine is **2.K** (the engine regression harness), with the **2.E** (ink TUI) + **2.H** (durable run history) run-surface feeders open.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Mark 2.K as completed in the phase header.

This sentence still presents 2.K as upcoming, but the new harness section below is already the 2.K deliverable in this PR. Flip 2.K to done and update the next-on-spine callout so the page doesn’t contradict itself after merge.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/roadmap/phases/phase-2-cli.md` at line 3, The status line in the
phase-2-cli.md header currently lists 2.K as the next upcoming item on the
spine, but this PR contains the 2.K deliverable (the engine regression harness).
Update the status line by adding 2.K to the completed items list (mark it as
done with the PR number and date, similar to how 2.A, 2.B, 2.D, and 2.F are
marked), remove it from the "next on the spine" callout, and update the callout
to reference the actual next item after 2.K to eliminate the contradiction
between the header and the content below.

cemililik and others added 2 commits June 22, 2026 23:36
…stream guard

Address the still-valid PR #43 review findings on the 2.K harness:

- Parallel fan-out now also asserts the causal (happens-before) spine, not only the
  multiset + anchors — most importantly the fan-in barrier (the merge starts only after
  BOTH branches complete), which a pure multiset cannot catch (combine could run before
  the branches finished and the multiset would still match). Encoded as declarative
  `causalOrder` [earlier, later] pairs on the Scenario; asserted with indexOf (safe — the
  multiset check already proved every signature is present).
- Build fixture paths with path.join(FIXTURES_DIR, file) instead of string concatenation,
  robust to trailing-slash changes.
- Guard parseEvents against an empty stream → []: a missing-output regression then fails
  the signature diff (empty vs expected) instead of crashing in JSON.parse('') with a
  cryptic "Unexpected end of JSON input".

Skipped, with reason:
- The reported @relavium/shared unsafe-member-access eslint errors do not reproduce
  (eslint + tsc both exit 0); they stem from the reviewer's analyzer lacking the built
  workspace type declarations, not the source.
- Marking 2.K Done in the roadmap is deferred to the post-merge bookkeeping commit per
  roadmap-done-after-merge (as 2.D→8cf486e and 2.F→d06fb55 did); "Next on the spine: 2.K"
  is the correct in-flight status while #43 is open.
- Extracting signature/parseEvents/assertGapFreeSeq to a shared module is premature with a
  single consumer (the captureIo extraction was justified by 4 real duplicates).

apps/cli: 123 tests green; full repo gate green. No engine/seam/dependency change.

Refs: PR #43 review

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
apps/cli/src/harness/regression.e2e.test.ts (1)

194-205: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Resolve RunEventSchema type resolution before merge (blocker).

ESLint reports multiple unsafe type violations because RunEventSchema from @relavium/shared cannot be resolved by TypeScript. This violates the strict TypeScript requirement and was flagged in the previous review as requiring resolution before merge.

The empty-string guard (lines 195-198) and schema round-trip validation (line 202) are good improvements, but the underlying type-safety issue must be fixed first.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cli/src/harness/regression.e2e.test.ts` around lines 194 - 205, The
RunEventSchema used in the parseEvents function cannot be resolved by TypeScript
from the `@relavium/shared` package, causing unsafe type violations flagged by
ESLint. Verify that RunEventSchema is properly exported from the
`@relavium/shared` package and that the import statement has the correct path. If
the export is missing or the package structure has changed, either add the
missing export to `@relavium/shared`, use an alternative type definition that is
properly exported, or update the import path to correctly reference where
RunEventSchema is defined.

Sources: Coding guidelines, Linters/SAST tools

apps/cli/src/config/load.test.ts (1)

55-55: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Resolve @relavium/shared type resolution before merge.

ESLint reports GlobalConfigSchema as an unsafe argument due to unresolved types from @relavium/shared. This violates the strict TypeScript requirement. The issue affects both this file and regression.e2e.test.ts, indicating a workspace build or type export problem.

Verify that @relavium/shared is built and type declarations are accessible:

#!/bin/bash
# Description: Check shared package build artifacts and type declarations

echo "== Shared package build outputs =="
fd -t f "\.d\.ts$" packages/shared/dist 2>/dev/null | head -20 || echo "No .d.ts files found in packages/shared/dist"

echo ""
echo "== Shared package.json exports and types field =="
cat packages/shared/package.json | jq '{name, exports, types, main}'

echo ""
echo "== CLI tsconfig references to shared =="
cat apps/cli/tsconfig.json | jq '.references // "no references field"'

echo ""
echo "== Verify shared package is built =="
if [ -f "packages/shared/dist/index.d.ts" ]; then
  echo "✓ Type declarations exist"
  rg -n "RunEventSchema|GlobalConfigSchema" packages/shared/dist/index.d.ts | head -5
else
  echo "✗ Missing dist/index.d.ts - shared package may not be built"
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cli/src/config/load.test.ts` at line 55, The `GlobalConfigSchema` import
from `@relavium/shared` cannot be resolved due to missing or inaccessible type
declarations in that package. Ensure the shared package is properly built by
checking that type declaration files (.d.ts) exist in the packages/shared/dist
directory, verify that the packages/shared/package.json has the types and
exports fields correctly configured to point to the built type declarations, and
confirm that apps/cli/tsconfig.json has a proper reference to the shared
package. If the shared package is not built, run the build command for the
workspace to generate the necessary type declaration files so that
GlobalConfigSchema can be properly resolved.

Sources: Coding guidelines, Linters/SAST tools

🧹 Nitpick comments (1)
apps/cli/src/config/load.test.ts (1)

54-54: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Remove unnecessary string concatenation.

The string concatenation ('api_key' + ' = ...') produces identical runtime output to the simpler literal form ('api_key = ...') and reduces readability.

♻️ Simplify to string literals
-    writeFileSync(file, 'api_key' + ' = "should-never-be-here"\n');
+    writeFileSync(file, 'api_key = "should-never-be-here"\n');
-    writeFileSync(file, 'update_channel' + ' = "super-secret-leak-me"\n');
+    writeFileSync(file, 'update_channel = "super-secret-leak-me"\n');

Also applies to: 60-60

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cli/src/config/load.test.ts` at line 54, Remove the unnecessary string
concatenation in the writeFileSync call where 'api_key' is concatenated with ' =
"should-never-be-here"\n'. Replace this with a single string literal 'api_key =
"should-never-be-here"\n' that produces the same runtime output but is more
readable. Apply the same change to line 60 where this pattern also appears.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@apps/cli/src/config/load.test.ts`:
- Line 55: The `GlobalConfigSchema` import from `@relavium/shared` cannot be
resolved due to missing or inaccessible type declarations in that package.
Ensure the shared package is properly built by checking that type declaration
files (.d.ts) exist in the packages/shared/dist directory, verify that the
packages/shared/package.json has the types and exports fields correctly
configured to point to the built type declarations, and confirm that
apps/cli/tsconfig.json has a proper reference to the shared package. If the
shared package is not built, run the build command for the workspace to generate
the necessary type declaration files so that GlobalConfigSchema can be properly
resolved.

In `@apps/cli/src/harness/regression.e2e.test.ts`:
- Around line 194-205: The RunEventSchema used in the parseEvents function
cannot be resolved by TypeScript from the `@relavium/shared` package, causing
unsafe type violations flagged by ESLint. Verify that RunEventSchema is properly
exported from the `@relavium/shared` package and that the import statement has the
correct path. If the export is missing or the package structure has changed,
either add the missing export to `@relavium/shared`, use an alternative type
definition that is properly exported, or update the import path to correctly
reference where RunEventSchema is defined.

---

Nitpick comments:
In `@apps/cli/src/config/load.test.ts`:
- Line 54: Remove the unnecessary string concatenation in the writeFileSync call
where 'api_key' is concatenated with ' = "should-never-be-here"\n'. Replace this
with a single string literal 'api_key = "should-never-be-here"\n' that produces
the same runtime output but is more readable. Apply the same change to line 60
where this pattern also appears.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5a58a13f-fca0-4332-a246-9b072f9a23aa

📥 Commits

Reviewing files that changed from the base of the PR and between 22bca51 and d67a704.

📒 Files selected for processing (2)
  • apps/cli/src/config/load.test.ts
  • apps/cli/src/harness/regression.e2e.test.ts

…ase-2-cli)

Encode the recommended solo pickup order for the remaining Phase-2 CLI workstreams
so the maintainer never has to re-derive "what should I build next" each time.

- New "### Remaining build order" subsection at the top of Sequencing &
  parallelization (its canonical home): a status-aware queue (2.H → 2.C → 2.E → 2.G
  → 2.I → 2.L, then 2.S → 2.R → chat → 2.J) with the why + already-met blockers per
  row. It sequences only — dependency rationale stays in the Dependency matrix, the
  from-scratch plan in Ordered waves (no restatement, per the one-canonical-home rule).
- Calls out the gate-closing backbone (the six PRs that flip all 7 exit criteria),
  that 2.K fully closes at 2.G (its deferred gate-resume half), and the one judgement
  call — front-load 2.S (the long pole + lone SSRF security review; its ports are
  inherited by desktop §3.B + VS Code §4.N), never tail it.
- Header status line now points at the queue and marks 2.K in review (PR #43); it is
  NOT marked Done (roadmap-done-after-merge — that lands in the post-merge bookkeeping).

Derived from the sequencing analysis (four lenses + adversarial dependency validation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cemililik
cemililik merged commit c193349 into main Jun 22, 2026
7 of 8 checks passed
@sonarqubecloud

Copy link
Copy Markdown

cemililik added a commit that referenced this pull request Jun 23, 2026
… reached

PR #43 merged: the engine regression harness (2.K) is live in the required CI gate.
With 2.F + 2.K both Done, global milestone M3 is reached.

- phase-2-cli.md: status line + the §2.K header marked ✅ Done (PR #43, 2026-06-23);
  the "Remaining build order" status note now shows 2.K done / M3 reached / next: 2.H
  (its gate-resume + agent-replay halves stay deferred, landing with 2.G / later).
- current.md: 2.K ✅ Done, M3 reached; "Next pickup: 2.H" pointing at the build-order queue.
- CLAUDE.md + README.md: Phase-2 status sentence now records 2.K + M3 reached.

Next pickup is 2.H (durable run history) — the highest-leverage feeder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant