feat: mirror the fleet board contract, and model SessionInfo.role (P5.0) - #38
Open
saucam wants to merge 2 commits into
Open
feat: mirror the fleet board contract, and model SessionInfo.role (P5.0)#38saucam wants to merge 2 commits into
saucam wants to merge 2 commits into
Conversation
Lockstep half of the daemon's goal-blackboard slice 1. CONTRIBUTING requires
this crate to move with the daemon's packages/protocol.
- `reads` / `writes` on CollaborationRole: the artifact kinds a role may read
and write on the goal blackboard (`spec`, `research`, `adr`, `task-list`,
`diff`, `findings`, or `extra/<key>`).
`None` means "use the daemon's default profile for this role name", which is
NOT the same as an empty list ("read/write nothing") — the daemon distinguishes
them, so these stay Option<Vec<String>> rather than defaulting to an empty vec
here. Collapsing the two would silently strip every default profile.
Kept as plain strings, not an enum: the artifact vocabulary has a fixed core
plus an `extra/<key>` escape hatch, so an enum here would reject a valid kind a
newer daemon accepts.
The wire_format review role now carries populated lists rather than None, so
the recursive camelCase walker actually visits them and a future rename of
either field fails the wire test.
cargo build + clippy + test green: 354 tests; clippy warnings unchanged
(7 before, 7 after on codeoid-protocol, verified by stashing).
The daemon has carried `role` on SessionInfo since the conductor shipped; this crate never modelled it, so the TUI could not so much as badge a conductor. That was the stated prerequisite for the fleet views (codeoid docs/conductor-frontends-design.md §10-§11). Adds SessionRole and mirrors the new read+subscribe surface: ClientMessage::FleetSubscribe / FleetUnsubscribe DaemonMessage::FleetSnapshotResult / FleetUpdate FleetSnapshot, FleetTask, FleetEvent, FleetUsage, FleetDelta Every new enum — SessionRole, FleetTaskKind/Shape/Status — carries #[serde(other)] Unknown. This is a client talking to a daemon that may be NEWER than it: a role or status it has never heard of must degrade to an unrendered node, never fail deserialization of the whole SessionInfo and blank the session list. The wire tests parse JSON CAPTURED from the running TS daemon rather than hand-written fixtures. This crate is a hand-maintained mirror of a TS contract and the failure mode is silent field drop on one side, so a fixture written from the same assumption as the code proves nothing. The TUI accepts the two new frames and logs them: it never sends fleet.subscribe, so receiving one means a stray broadcast rather than a client bug, and it must not be reported as a forward-compat drop. The board UI is P5.2. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to highflame-ai/codeoid#294.
The prerequisite
The daemon has carried
roleonSessionInfosince the conductor shipped. This crate never modelled it — 22 fields, norole— so the TUI could not so much as badge a conductor.conductor-frontends-design.md§10 flagged exactly this: "The RustSessionInfois missing therolefield entirely; add it first."What lands
SessionRole+SessionInfo.roleClientMessage::FleetSubscribe/FleetUnsubscribeDaemonMessage::FleetSnapshotResult/FleetUpdateFleetSnapshot,FleetTask,FleetEvent,FleetUsage,FleetDeltaForward-compat is load-bearing here
Every new enum —
SessionRole,FleetTaskKind/Shape/Status— carries#[serde(other)] Unknown. This is a client talking to a daemon that may be newer than it. A role or status it has never heard of must degrade to an unrendered node, never fail deserialization of the wholeSessionInfoand blank the session list. There's a test for precisely that.On the tests
The wire tests parse JSON captured from the running TS daemon, not hand-written fixtures. This crate is a hand-maintained mirror of a TS contract and the failure mode is silent field drop on one side — a fixture written from the same assumption as the code would prove nothing. If the daemon's projection changes shape, these stop deserializing.
TUI
Accepts the two new frames and logs them at debug. It never sends
fleet.subscribe, so receiving one means a stray broadcast rather than a client bug, and it must not be reported as a forward-compat drop. The board UI is P5.2.Verification
cargo build,cargo test(7 suites, 10 protocol tests incl. 4 new),cargo fmt --check,cargo clippy— all clean. SixSessionInfotest fixtures updated for the new field; the compiler's exhaustiveness checking caught all of them plus twomatchsites incodeoid-client.