Lane: run the project check legs AND the preview roll, not one or the other #120

Open
iggy wants to merge 1 commit from agent/lane-compose-legs into agent/lane-stages
Contributor

LegPlan was a single exclusive value, and profile was consumed only in the InProcess arm. The live lane sets CARGOLESS_LANE_PREVIEW_SLOT=lane, so it took the Preview arm and ProfileLegRunner never ran.

Six tier: lane legs were therefore dead code in production — lane-csr, lane-lib-test, lane-vsock and siblings — each added after a real outage (a csr-cone E0382 pinned the site ~6h; the cfg(test) cone hid 5.5 weeks of unit-test rot; the vsock cone froze isolation bakes for 8 days).

Confirmed against production, not only source: /workspace/cargoless-state/lane-runs.log on cargoless-lane-shadow contains only id=preview:lane leg lines — no profile leg has ever run. All 6 reds it has ever produced carried diagnostics=1, the synthetic preview.red stub anchored at cargoless.checks.yaml:1:1, which nobody touches — so every red so far was Unattributed and ejected the entire roster.

The change

ComposedLegRunner runs the profile legs, and only on green rolls the preview. LegPlan::Preview gains a profile field; empty keeps today's behaviour exactly.

  • Ordering — cheap compile legs first. The profile legs emit cargo JSON with real file paths so a red is attributable; a preview red is free text and holds the whole queue. Also: the preview roll is 20-45 min (observed up to 89), and a red preview after a red compile cannot exonerate anything while still costing the slot.
  • Plan shape — a field, not a LegPlan::Composed variant. LegPlan answers "WHERE do the legs run", and composing does not change the destination. A Composed variant would make the enum answer two questions and need every pair spelled out. Every LegPlan match is exhaustive with no _ arm, so all three sites failed to compile until updated.
  • Diagnostics — a first-runner red returns its LegOutcome verbatim, so the cargo-JSON diagnostics cannot be dropped in transit. An Err propagates as infra.
  • Legs — both runners' LegReports appear, the first's prepended, so LaneDriver::record_legs writes both halves to the durable trail. Note: LaneSnapshot / GET /lane carries phase, queue depth, in-flight ids and ejections — no legs — so the trail is today the only place per-leg evidence outlives the candidate worktree.

Observability (the half that let this survive)

The boot line printed the raw CARGOLESS_LANE_PROFILE beside the destination, announcing profile=lane where=preview:lane while running no profile leg. profile= and where= are now derived from the constructed plan, so advertising a profile the plan cannot use is unrepresentable; Dispatch reports none and warns loudly if one was configured.

Rollout note

This changes the meaning of the deployed shape: the lane sets both env vars today, so the first candidate after the roll runs six legs that have never executed in production, cold (the lane sets no warm CARGO_TARGET_DIR). See the commit message for the budget analysis.

Tests

Six tests in crates/cargoless-core/tests/lane_real_io.rs, each pinning one property: both-run, red-short-circuits-with-diagnostics, empty-profile-unchanged, dispatch-advertises-no-profile, infra-never-reaches-preview, artifact-from-last-runner.

Logic validated against a Rust-faithful Python port before commit (no local cargo by design).

🤖 Generated with Claude Code

`LegPlan` was a single exclusive value, and `profile` was consumed only in the `InProcess` arm. The live lane sets `CARGOLESS_LANE_PREVIEW_SLOT=lane`, so it took the `Preview` arm and `ProfileLegRunner` never ran. Six `tier: lane` legs were therefore dead code in production — `lane-csr`, `lane-lib-test`, `lane-vsock` and siblings — each added after a real outage (a csr-cone E0382 pinned the site ~6h; the cfg(test) cone hid 5.5 weeks of unit-test rot; the vsock cone froze isolation bakes for 8 days). **Confirmed against production**, not only source: `/workspace/cargoless-state/lane-runs.log` on `cargoless-lane-shadow` contains only `id=preview:lane` leg lines — no profile leg has ever run. All 6 reds it has ever produced carried `diagnostics=1`, the synthetic `preview.red` stub anchored at `cargoless.checks.yaml:1:1`, which nobody touches — so every red so far was `Unattributed` and ejected the entire roster. ## The change `ComposedLegRunner` runs the profile legs, and only on green rolls the preview. `LegPlan::Preview` gains a `profile` field; empty keeps today's behaviour exactly. * **Ordering** — cheap compile legs first. The profile legs emit cargo JSON with real file paths so a red is *attributable*; a preview red is free text and holds the whole queue. Also: the preview roll is 20-45 min (observed up to 89), and a red preview after a red compile cannot exonerate anything while still costing the slot. * **Plan shape** — a field, not a `LegPlan::Composed` variant. `LegPlan` answers "WHERE do the legs run", and composing does not change the destination. A `Composed` variant would make the enum answer two questions and need every pair spelled out. Every `LegPlan` match is exhaustive with no `_` arm, so all three sites failed to compile until updated. * **Diagnostics** — a first-runner red returns its `LegOutcome` verbatim, so the cargo-JSON diagnostics cannot be dropped in transit. An `Err` propagates as infra. * **Legs** — both runners' `LegReport`s appear, the first's prepended, so `LaneDriver::record_legs` writes both halves to the durable trail. Note: `LaneSnapshot` / `GET /lane` carries phase, queue depth, in-flight ids and ejections — no legs — so the trail is today the only place per-leg evidence outlives the candidate worktree. ## Observability (the half that let this survive) The boot line printed the raw `CARGOLESS_LANE_PROFILE` beside the destination, announcing `profile=lane where=preview:lane` while running no profile leg. `profile=` and `where=` are now derived from the **constructed plan**, so advertising a profile the plan cannot use is unrepresentable; `Dispatch` reports none and warns loudly if one was configured. ## Rollout note This changes the meaning of the **deployed** shape: the lane sets both env vars today, so the first candidate after the roll runs six legs that have never executed in production, cold (the lane sets no warm `CARGO_TARGET_DIR`). See the commit message for the budget analysis. ## Tests Six tests in `crates/cargoless-core/tests/lane_real_io.rs`, each pinning one property: both-run, red-short-circuits-with-diagnostics, empty-profile-unchanged, dispatch-advertises-no-profile, infra-never-reaches-preview, artifact-from-last-runner. Logic validated against a Rust-faithful Python port before commit (no local cargo by design). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
`LegPlan` was a single exclusive value, and `profile` was consumed only in
the `InProcess` arm. The live lane sets `CARGOLESS_LANE_PREVIEW_SLOT=lane`,
so it took the `Preview` arm and `ProfileLegRunner` never ran.

Six `tier: lane` legs were therefore dead code in production. Each was added
after a real outage, and each covers a cfg-cone nothing else compiles:

  lane-csr       an E0382 in a #[cfg(any(csr,hydrate))] fn pinned the site
                 ~6h while the SSR witness returned SUCCESS on every sha
  lane-lib-test  neither `cargo check` nor `cargo build` builds the cfg(test)
                 target — 5.5 weeks of silent portal unit-test rot
  lane-vsock     a cfg-gated borrow error froze every isolation bake for 8 days

A preview roll is genuinely stronger than a compile — it proves the tree
BOOTS AND ANSWERS — but it compiles nothing itself, so a cone its own build
does not exercise is simply unchecked. The two claims are complementary, so
compose them instead of choosing.

Design decisions, and why:

* ORDERING — cheap compile legs first. Three reasons, the first load-bearing:
  the profile legs emit cargo JSON, so their diagnostics carry real file paths
  and the attribution ladder can name the member who broke it; a preview red
  is free text with no spans, is correctly unattributable, and therefore holds
  the WHOLE queue. Running the attributable check first means the lane learns
  whose fault it is whenever it can. Then: a preview roll is 20-45 minutes, so
  re-discovering a type error there is pure latency for everyone queued behind;
  and a red preview after a red compile cannot exonerate the compile red while
  still costing the slot the next candidate needs. The converse order was
  considered and rejected — it inverts the first reason for no gain.

* PLAN SHAPE — `LegPlan::Preview` gains a `profile` field rather than adding a
  `LegPlan::Composed` variant. `LegPlan` answers "WHERE do the legs run", and
  composition does not change the destination: this is still a preview lane,
  still one slot, still the same landing semantics. A `Composed` variant would
  make the enum answer two questions at once and would need every combination
  spelled out (Composed{InProcess,Preview}, Composed{InProcess,Dispatch}, …)
  to stay honest. Empty `profile` is exactly today's behaviour, so the field
  reads as "and also run these legs first", which is what it means. Every
  `LegPlan` match is exhaustive with no `_` arm (the same discipline
  `transport/unix.rs` documents for verbs), so all three sites — `describe`,
  `profile`, `into_runner` — failed to compile until updated; there are no
  other matches in the tree.

* DIAGNOSTICS — a first-runner red returns its `LegOutcome` VERBATIM rather
  than being rebuilt, so the cargo-JSON diagnostics that make it attributable
  cannot be dropped in transit. That is most of the value of running these
  legs at all. An `Err` propagates as infrastructure: rolling a preview after
  the legs could not even be launched would let a green preview become the
  only verdict on a candidate whose compile legs never ran.

* LEGS — both runners' `LegReport`s appear, the first's PREPENDED, so `/lane`
  and the trail show what actually ran in the order it ran.

Observability, the half that let this survive: the boot line printed the raw
`CARGOLESS_LANE_PROFILE` beside the destination, so a preview lane announced
`profile=lane where=preview:lane` while running no profile leg at all. The
config was not wrong and the daemon agreed with it. `profile=` and `where=`
are now both derived from the CONSTRUCTED plan, so a line that advertises a
profile the plan cannot use is unrepresentable; `Dispatch` reports none and
gets a loud WARNING if one was configured anyway.

ROLLOUT NOTE — this changes the meaning of the DEPLOYED shape. The lane sets
both `CARGOLESS_LANE_PROFILE=lane` and `CARGOLESS_LANE_PREVIEW_SLOT=lane`
today, so the first candidate after the roll runs six legs that have never
executed in production, on a cold per-candidate target dir (the lane sets no
warm `CARGO_TARGET_DIR`). The tf-mv `lane` profile is `max_parallel: 1` under
a single 90-minute profile-wide budget, and cold serial ssr+hydrate+bindgen+
csr+lib-test+vsock plausibly exceeds it — a profile-timeout reds every leg
that had not started, on a healthy tree. Watch the first run and raise
`timeout_ms` or warm the target dir if it bites.

Tests (crates/cargoless-core/tests/lane_real_io.rs), each pinning one property:
  a_profile_and_a_preview_slot_both_run_… — THE GAP: with both configured,
      both execute, reports prepended in execution order
  a_profile_leg_red_short_circuits_the_preview_and_keeps_its_diagnostics —
      preview never rolled, and the cargo-JSON file path + span survive
  an_empty_profile_still_yields_a_preview_only_lane — today's config is
      byte-identical, including the boot line
  a_dispatch_plan_reports_no_profile_… — the boot line cannot advertise legs
      that will never run
  an_infra_failure_in_the_profile_legs_never_reaches_the_preview
  the_composed_artifact_comes_from_the_last_runner — a preview publishes
      nothing locally, so no stale profile-leg file can be promoted

Logic validated against a Rust-faithful Python port before commit (no local
cargo by design).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin agent/lane-compose-legs:agent/lane-compose-legs
git switch agent/lane-compose-legs

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch agent/lane-stages
git merge --no-ff agent/lane-compose-legs
git switch agent/lane-compose-legs
git rebase agent/lane-stages
git switch agent/lane-stages
git merge --ff-only agent/lane-compose-legs
git switch agent/lane-compose-legs
git rebase agent/lane-stages
git switch agent/lane-stages
git merge --no-ff agent/lane-compose-legs
git switch agent/lane-stages
git merge --squash agent/lane-compose-legs
git switch agent/lane-stages
git merge --ff-only agent/lane-compose-legs
git switch agent/lane-stages
git merge agent/lane-compose-legs
git push origin agent/lane-stages
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
triform/cargoless!120
No description provided.