Skip to content

docs(spec-sessions-composition-pipeline): sessions composition pipeline — shared gate, split composers, single-round wire - #529

Closed
gominimal-aw-bot[bot] wants to merge 1 commit into
mainfrom
spec/sessions-composition-pipeline-a8892b22530571c6
Closed

docs(spec-sessions-composition-pipeline): sessions composition pipeline — shared gate, split composers, single-round wire#529
gominimal-aw-bot[bot] wants to merge 1 commit into
mainfrom
spec/sessions-composition-pipeline-a8892b22530571c6

Conversation

@gominimal-aw-bot

@gominimal-aw-bot gominimal-aw-bot Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Derived spec for PR #528, authored retrospectively from the implemented code.

The spec covers:

  • Unit 1 — Shared core::compose gate pipeline (Contribution, Composable, gate_vars, gate_patches, compose_contribution)
  • Unit 2 — Client UserComposer (loadout accumulation → WireContribution)
  • Unit 3 — Daemon SessionComposer (seeded from wire, daemon composables, extend_from_wire)
  • Unit 4 — Wire protocol single-round-trip (WireContribution, ContributionResponse without round/complete, SessionStep::Response, Abort/AbortReason)
  • Unit 5 — Policy gate semantics and vocabulary (deny before user-origin auto-allow, DenyOnce removal, module restructuring, COMPOSITION.md)

Each unit has 1–3 proof artifacts (test-based or file-based, all pass against the current tree).

Gap Analysis documents four gaps:

  1. Phases 2–4 not wired (daemon ContributionResponse and client Phase 3 verdict handler are absent)
  2. Contribution::merge conflict detection absent (Conflict enum uninhabited)
  3. No test for var-name collision across the wire boundary
  4. ItemDecision::DenyOnce removal is a breaking hook-API change without a migration note

Refs #528

Generated by sdd-derive for PR #528 · sonnet46

Generated by sdd-derive ·

Summary by CodeRabbit

  • Documentation
    • Added comprehensive specification for the sessions composition pipeline, including wire protocol definitions, policy semantics with explicit precedence rules, updated hook behavior, module vocabulary reorganization, formal end-to-end invariants, design and security considerations, and implementation gap analysis.

@gominimal-aw-bot

gominimal-aw-bot Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

sdd-validate — spec boundary

Boundary resolved: Spec — docs/specs/05-spec-sessions-composition-pipeline/05-spec-sessions-composition-pipeline.md was added under docs/specs/, matching *-spec-*.md. Spec gate set applied (5 gates). No plan:provided marker on linked PR; standard spec gates apply.


Gate 1 — Acceptance criteria testable ✅ Pass

All R-ID statements describe observable behaviours that can be verified as pass/fail. Every criterion is tied to at least one named proof artifact (test name or file assertion). No vague aspirational statements were found among the R-IDs.

Gate 2 — No implementation leakage ⚠️ Warning

R-IDs throughout all five units name internal symbols — function names, type names, module paths, and call-site parameter values — where a behavioural statement would be sufficient. A retrospectively derived spec carries the code's vocabulary by nature, but the gate still applies. Representative instances:

  • 05-spec-sessions-composition-pipeline.md Unit 1 intro: "The composition pipeline lives in crates/sessions/src/core/compose.rs" — a file path where a sentence about the shared gate module would stand alone.
  • R1.3–R1.4: name gate_vars, VarsPolicy::check, hooks.on_var_unapproved, NeedsApproval, expand_patch_sources, PatchFile as subjects of behavioural statements. A restatement focused on the observable 3-pass algorithm and per-file fan-out removes the leakage.
  • R2.2: "calls compose_contribution with hooks = None, uses the process environment as home_fallback" — prescribes an internal call site and a named parameter value. Behavioural form: "the client composer runs without hook callbacks; patch expansion uses the process environment for home-directory resolution."
  • R2.4: "with_env(StoredEnv) replaces the default std::env::var lookup for tests" — prescribes the test-helper method name and parameter type.
  • R3.1: "SessionComposer::new(client: WireContribution)" — prescribes the constructor signature.

The Repository Standards section prescribes coding conventions that belong in CLAUDE.md, not in a feature spec: "100% docstring coverage per the pre-merge check", "Error types use #[derive(Debug, thiserror::Error)]", "#[allow(clippy::unnecessary_wraps)] on Contribution::merge includes a reason comment". None of these carries an R-ID and none is covered by a proof artifact. The section could be dropped from the spec without loss of behavioural specification.

Advisory: future revisions can reframe R-IDs as behavioural statements and leave symbol names to the implementation. This leakage does not prevent shipping the spec.

Gate 3 — Assumptions explicit i️ Info

The spec surfaces key assumptions in Context, Design Considerations, Security Considerations, Gap Analysis, and Open Questions. One implicit assumption was not fully stated:

R4.4 asserts the "kind" serde tag is a "stable discriminator" for SessionStep and R4.6 asserts serde_json round-tripping holds without data loss, but the spec does not state whether this serialised wire format is a stable versioned API contract (safe for external callers to store or forward) or a test-scope assertion about the current tree. Callers who serialise and route SessionStep messages over a persistent transport need to know. A single sentence in Design Considerations would resolve this — e.g., "The wire format is a process-internal protocol between a client binary and its local daemon; no stability guarantee is offered to external consumers."

Gate 4 — Proof artifacts present and behavioral ✅ Pass

All five demoable units carry 2–3 proof artifacts (Unit 1: 3 Tests; Units 2–3: 2 Tests each; Unit 4: 2 Tests; Unit 5: 1 Test + 1 File). Every artifact names a specific cargo test -p sessions '<test-path>' command or a file-existence assertion with expected headings. None would pass against an empty pull request — the named tests and the named file do not exist until the implementation code and documentation are present.

Gate 5 — Demoable unit sized to a reviewable PR ✅ Pass

Unit 1 (core::compose) covers the core gate pipeline and is clearly well above the 400-line floor. Units 2–5 are individually narrower but each is separated from its neighbours by a genuine dependency edge (Units 2 and 3 both depend on Unit 1's compose_contribution; Unit 4 defines the WireContribution wire boundary that Units 2 and 3 cross; Unit 5 supplies the policy types that Unit 1 gates on). No unit forms a strict produce/consume chain with a cohesive sibling that has no other consumer. All five splits are exempt from the under-sized finding.


Result

No Blockers. needs-human not applied.

# Gate Severity Finding
1 Gate 2 — No implementation leakage Warning R-IDs throughout all five units name internal symbols where behavioural statements belong; "Repository Standards" section prescribes coding conventions rather than behavioural requirements
2 Gate 3 — Assumptions explicit Info Wire format stability assumption (R4.4, R4.6) not stated — reader cannot determine whether the serde_json shape is a stable API contract or a test-scope assertion

Gates 1, 4, and 5 pass clean. No lifecycle label move: the spec boundary does not advance the tracking issue lifecycle.

Generated by sdd-validate for issue #529 ·

Rebuild the spec PR as docs-only. The sdd-spec derivation committed a large
sessions-composition code refactor and several reverts alongside the spec
document; a spec PR must change only the spec under docs/specs/. Reset every
code and non-spec-doc file to current main (161b763), keeping just the
derived spec so the PR no longer reverts merged work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0143kv2BRrRqGxmVwwHskQtS
@norrietaylor
norrietaylor force-pushed the spec/sessions-composition-pipeline-a8892b22530571c6 branch from c39d194 to 5698f51 Compare June 22, 2026 21:42
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

A new retrospective specification document is added at docs/specs/05-spec-sessions-composition-pipeline/. It defines the sessions composition pipeline as shipped: the core::compose policy gate, split UserComposer/SessionComposer roles, a reshaped single-round wire protocol, policy/module vocabulary changes, design and security considerations, repository standards, gap analysis, and open questions.

Changes

Sessions Composition Pipeline Specification

Layer / File(s) Summary
Document metadata and overview
docs/specs/05-spec-sessions-composition-pipeline/05-spec-sessions-composition-pipeline.md
Front matter (identifier, title, kind/status, supersedes/tracking fields) and overview section describing retrospective derivation, referenced PR/branch, and high-level refactor and wire-protocol simplification claims.
Demoable units of work: composers and wire protocol
docs/specs/05-spec-sessions-composition-pipeline/05-spec-sessions-composition-pipeline.md
Units 1–4 document the shared core::compose gate pipeline, UserComposer client-only gating, SessionComposer daemon-side reconstitution and HOME/tilde asymmetry, and the single-round wire protocol with reshaped request/response/verdict/abort types and serde proof artifacts.
Policy semantics and module vocabulary
docs/specs/05-spec-sessions-composition-pipeline/05-spec-sessions-composition-pipeline.md
Unit 5 documents deny precedence over user-loadout auto-allow, removal of DenyOnce in favor of session-wide Abort, relocation of client::enumerate/client::hooks into core, and resolve/gate/compose vocabulary definitions.
Design and security considerations
docs/specs/05-spec-sessions-composition-pipeline/05-spec-sessions-composition-pipeline.md
Describes hooks as client-only, home_fallback asymmetry, contribution merge assumptions, end-to-end Source propagation, atomic wire extension, deny precedence security framing, trust model for client wire items, daemon tilde non-expansion, and symlink policy checks.
Repository standards, gap analysis, and open questions
docs/specs/05-spec-sessions-composition-pipeline/05-spec-sessions-composition-pipeline.md
Repository standards (rustdoc, error derivation, clippy allowance, Send + Sync assertions), gap analysis (absent Phase 2–4 wiring, missing conflict-detection, missing collision tests, absent DenyOnce migration note), and open questions on Phase 2–4 timing and variable collision resolution.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Poem

🐇 A spec hops in, fresh from the warren,
With composers split and wire reborn,
deny takes precedence, DenyOnce is gone,
HOME stays asymmetric from dusk until dawn.
The gaps are noted, the questions remain—
This rabbit wrote it all down in the lane! 📜

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main addition: a specification document for the sessions composition pipeline covering the shared gate, split composers, and single-round wire protocol.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.


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

@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: 1

🤖 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
`@docs/specs/05-spec-sessions-composition-pipeline/05-spec-sessions-composition-pipeline.md`:
- Line 5: The status field is currently set to `planned`, but this specification
documents already-implemented work from PR `#528` that has already shipped on the
`evan/split03` branch. Change the `status` field value from `planned` to
`published` or `stable` to correctly reflect that this specification documents
shipped, published work with transparent gap analysis, rather than future
planned work.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 65bccdfc-cbe0-4513-aa09-87212073d306

📥 Commits

Reviewing files that changed from the base of the PR and between 161b763 and 5698f51.

📒 Files selected for processing (1)
  • docs/specs/05-spec-sessions-composition-pipeline/05-spec-sessions-composition-pipeline.md

id: spec-sessions-composition-pipeline
title: "sessions composition pipeline — shared policy gate, split client/daemon composers, single-round wire"
kind: spec
status: planned

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the status field — this spec documents already-implemented work, not planned work.

Per the PR objectives, this specification was derived retrospectively from PR #528, which shipped code on the evan/split03 branch. Setting status: planned misleads readers into thinking the spec describes future work. Since the pipeline is already implemented and the spec documents the shipped behavior (with transparent gap analysis for incomplete phases), use a status value that reflects published/documented work — published, stable, or similar.

🤖 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/specs/05-spec-sessions-composition-pipeline/05-spec-sessions-composition-pipeline.md`
at line 5, The status field is currently set to `planned`, but this
specification documents already-implemented work from PR `#528` that has already
shipped on the `evan/split03` branch. Change the `status` field value from
`planned` to `published` or `stable` to correctly reflect that this
specification documents shipped, published work with transparent gap analysis,
rather than future planned work.

@norrietaylor

Copy link
Copy Markdown
Member

Closing as deferred while @evanspearman completes loadouts

@norrietaylor
norrietaylor deleted the spec/sessions-composition-pipeline-a8892b22530571c6 branch June 23, 2026 15:16
@norrietaylor
norrietaylor restored the spec/sessions-composition-pipeline-a8892b22530571c6 branch June 23, 2026 15:16
@norrietaylor
norrietaylor deleted the spec/sessions-composition-pipeline-a8892b22530571c6 branch June 26, 2026 07:17
norrietaylor added a commit that referenced this pull request Jul 29, 2026
)

The pin was 9 days and 62 commits stale (c854d6b1, 2026-07-20). The
motivating change is gominimal/pkgs#534, which rebuilds microvm-rootfs
from Alpine and drops the glibc closure — but the pin is linear, so this
necessarily carries everything before it too.

Materially in range:

- microvm-rootfs from Alpine (#534) — 186 MB -> 45 MB
- two libkrun vsock fixes: RX descriptor fill (#506) and packet-count
  backpressure (#512), both on the path minvmd depends on
- rust 1.97.1 (#502) and glibc 2.44 (#529) in the build stack

The rest is routine package version bumps.

Pinned at the branch tip rather than at #534's commit: pinning
mid-history buys nothing here, and the three commits after it are a
bottom bump, a graphviz bump, and a license-metadata fix.

Verified on this host: `mip materialize --arch aarch64 minvmd-rootfs`
resolves from cache and yields a 47,212,544-byte ext4 image whose only
interpreter is /lib/ld-musl-aarch64.so.1 — no glibc. The same image has
already been booted and driven through the session e2e (cold activate
4296 ms, warm ls 16 ms, sandbox proof 8030 ms), and A/B'd for cold-boot
latency against the outgoing rootfs: median 129 ms vs 154 ms, n=10 each,
non-overlapping.

This changes the guest for macOS as well, which already ships the
payload; the VM lanes are the gate.

Co-authored-by: Claude Opus 5 <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