ticket: use base32 project record ids
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# Clarification
|
||||
|
||||
The requested command is not a TUI attach/switch affordance. It should initiate a Pod-authoritative peer handshake between the currently attached Pod and another existing Pod.
|
||||
|
||||
The intended result is broader than one-sided `ListPods` visibility: after a successful handshake, both Pods should be mutually visible as peers and should be able to exchange messages through an explicit peer-safe tool/method. The relationship must stay distinct from spawned-child delegation: no delegated filesystem scope, no parent/child ownership, no child completion notifications, and no child output cursor authority.
|
||||
|
||||
The TUI `:` command is the human-facing control path for initiating the handshake; the durable relationship and messaging authorization belong in Pod metadata/runtime semantics, not in TUI-local state.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Delegation intent: peer Pod handshake and messaging
|
||||
|
||||
Intent:
|
||||
- Investigate the existing Pod visibility/messaging implementation, then implement a TUI-initiated peer Pod handshake and peer messaging path if no design blockers are found.
|
||||
|
||||
Requirements:
|
||||
- Start with investigation. Map current authority boundaries for `ListPods`, `RestorePod`, `SendToPod`, Pod metadata, spawned-child registry, protocol methods, and TUI `:` command handling.
|
||||
- If there are design blockers or ambiguous authority decisions, write findings to the ticket artifacts and stop for parent decision.
|
||||
- If there are no blockers, proceed with implementation in the worktree.
|
||||
- Add a TUI `:` command that initiates peer handshake from the currently attached Pod to a target Pod by name.
|
||||
- Make the peer relationship Pod-authoritative, durable where appropriate, and reciprocal by default.
|
||||
- Ensure both Pods see each other in `ListPods` as peer/known, not spawned child.
|
||||
- Add or safely broaden messaging semantics so a Pod can message a visible peer without granting spawned-child powers.
|
||||
- Record delivered peer messages through an explainable durable path; do not silently mutate hidden context.
|
||||
- Preserve explicit boundaries: no delegated filesystem scope, parent/child ownership, completion notification authority, or child output cursor authority for peer Pods.
|
||||
- Add focused tests for protocol/runtime behavior, metadata persistence/restore, reciprocal `ListPods`, peer message authorization/delivery, and TUI command parsing/help where feasible.
|
||||
- Update docs/help text for the new command and peer semantics.
|
||||
|
||||
Invariants:
|
||||
- Do not treat peer Pods as spawned children.
|
||||
- Do not reintroduce hidden context injection; model-affecting delivered messages must go through the normal committed history/event path.
|
||||
- Do not add broad relationship graph semantics beyond the minimal peer relation.
|
||||
- Do not edit the parent workspace; work only in the delegated worktree.
|
||||
- Do not read ignored secret-like file contents.
|
||||
- Do not close the ticket, merge the branch, delete worktrees, or push.
|
||||
|
||||
Non-goals:
|
||||
- Arbitrary autonomous Pod-to-Pod background chatter.
|
||||
- Replacing the multi-Pod dashboard or Pod picker.
|
||||
- Delegated scope sharing between peers.
|
||||
- E2E test framework design for real spawned processes.
|
||||
|
||||
Escalate if:
|
||||
- Reciprocal handshake cannot be made atomic enough to avoid misleading partial state.
|
||||
- Peer messaging requires changing history semantics in a way that could violate context/history invariants.
|
||||
- Existing protocol or metadata schemas need a broad migration.
|
||||
- The TUI command cannot safely deliver the runtime method while preserving current Pod authority.
|
||||
- `SendToPod` broadening would confuse spawned-child and peer semantics.
|
||||
|
||||
Validation:
|
||||
- Before implementation: write a short investigation summary in the implementation report or a separate artifact.
|
||||
- Focused tests for touched crates.
|
||||
- `./tickets.sh doctor` and `git diff --check`.
|
||||
- `nix build .#yoi` if feasible; record if skipped and why.
|
||||
- Commit the implementation in the worktree when reviewable.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Implementation report: peer Pod handshake command
|
||||
|
||||
Date: 2026-06-02
|
||||
|
||||
## Investigation
|
||||
|
||||
The current boundaries are documented in `artifacts/investigation-summary.md`. No escalation blocker was found. The main concern identified was avoiding reuse of spawned-child state (`SpawnedPodRegistry`, delegated scope, output cursors, and child completion semantics) for peer communication; the implementation therefore adds separate peer metadata and a separate peer send tool.
|
||||
|
||||
## Implemented behavior
|
||||
|
||||
- Added reciprocal peer metadata to `PodMetadata` as `peers`, separate from `spawned_children` and `reclaimed_children`.
|
||||
- Added protocol `Method::RegisterPeer { name }` and `Event::PeerRegistered { result }`.
|
||||
- Added controller handling for `RegisterPeer`, idle/paused only, validating an existing target Pod and rejecting self-handshakes.
|
||||
- Added `PodDiscovery::register_peer` that persists both metadata directions and restores the exact prior source-side peer state on ordinary second-side write failure.
|
||||
- Extended `ListPods` visibility to include `VisibilityReason::Peer`; a successful handshake makes both Pods see each other as `peer` through Pod metadata.
|
||||
- Added `SendToPeerPod` as a distinct LLM tool. It only sends to visible live peer Pods, delivers `Method::Notify` with a source label, and does not use child delegation, output cursors, parent ownership, or child completion notifications.
|
||||
- Added TUI command `:peer <pod-name>` for idle attached Pods. Success is reported through a transient actionbar notice when the controller returns `PeerRegistered`.
|
||||
- Documented peer semantics in `docs/design/pod-session-state.md` and added prompt guidance that peer Pods are not spawned children.
|
||||
|
||||
## Reviewer blocker fixes
|
||||
|
||||
- `SendToPeerPod` now reuses the existing one-shot Pod socket client path (`connect_and_send`), which drains connect-time `Alert` / `Snapshot` traffic before writing `Notify` and returns an error if method delivery fails.
|
||||
- Added a regression test where the target socket emits an alert and snapshot before reading the peer `Notify`, proving the peer send drains the prelude and still delivers the message.
|
||||
- Registration failure rollback now restores the exact prior source peer list instead of unconditionally removing `source -> target`; a target-side injected failure test verifies a pre-existing source relation is preserved.
|
||||
- Wording now describes `:peer` as metadata-level reciprocal registration rather than live target-controller consent, and documents that `SendToPeerPod` fails for non-live peers instead of auto-restoring them.
|
||||
|
||||
## Tests and validation run
|
||||
|
||||
- `cargo test -p protocol -p pod-store -p pod -p tui --lib`
|
||||
- `./tickets.sh doctor`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi`
|
||||
|
||||
## Notes
|
||||
|
||||
The two-file reciprocal metadata update is not crash-transactional because the existing Pod metadata store has no multi-record transaction boundary. The implementation avoids successful replies with one-sided state for normal validation/write failures by restoring the exact prior source-side peer list if the reciprocal write fails.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Investigation summary: peer Pod handshake
|
||||
|
||||
Date: 2026-06-02
|
||||
|
||||
## Current authority map
|
||||
|
||||
- `ListPods` / `RestorePod` are implemented in `crates/pod/src/discovery.rs` and are served both as LLM tools and protocol methods from the currently attached Pod's controller. They intentionally start from the caller Pod's visibility set rather than a host-wide Pod universe. Today the visibility set is the caller itself plus spawned children from durable Pod metadata and the live spawned-child registry.
|
||||
- Pod metadata is in `crates/pod-store/src/lib.rs` as name-keyed current state (`PodMetadata`) under the Pod-state root. `spawned_children` is durable current parent/child visibility and delegation state; session JSONL remains the durable explanation for delivered context/history.
|
||||
- The spawned-child registry (`SpawnedPodRegistry`) is runtime/current ownership state for `SpawnPod`, `SendToPod`, `ReadPodOutput`, and `StopPod`. It carries output cursors and delegated scope; it should not be reused for peer visibility.
|
||||
- `SendToPod` in `crates/pod/src/spawn/comm_tools.rs` is explicitly spawned-child scoped: it looks up only `SpawnedPodRegistry`, sends `Method::Run`, and is paired with `ReadPodOutput` cursor semantics. Broadening it would blur child vs peer semantics, so a distinct peer-safe send surface is preferable.
|
||||
- Protocol methods are in `crates/protocol/src/lib.rs`; TUI command dispatch is local parsing in `crates/tui/src/command.rs`, returning typed `Method`s that `single_pod.rs` sends to the currently attached Pod. This is suitable for a TUI command that asks the current Pod to perform authoritative metadata changes.
|
||||
- Delivered notifications already have an explainable durable path: `Method::Notify` is queued through `NotifyBuffer`, rendered as a `SystemItem`, committed as `LogEntry::SystemItem`, and then appended to model history. A peer message can reuse that receive-side path without hidden context injection.
|
||||
|
||||
## Implementation direction
|
||||
|
||||
No escalation blocker found. The minimal safe design is:
|
||||
|
||||
- Add a `peers` field to `PodMetadata`, separate from `spawned_children`, with serde defaults so no broad migration is needed.
|
||||
- Add a controller-handled `Method::RegisterPeer { name }` that validates the target Pod state exists, rejects self, and writes reciprocal peer entries to both Pod metadata records. Normal write failures roll back the first side so successful replies do not leave one-sided visibility.
|
||||
- Extend `ListPods` visibility with a `peer` reason sourced from `PodMetadata.peers`; keep spawned-child comm registry and child output cursors unchanged.
|
||||
- Add a separate `SendToPeerPod` tool backed by `PodDiscovery` visibility. It only sends to visible peers, uses the target's live/restored socket from discovery, and delivers a `Method::Notify` message labeled with the sender Pod name. It does not read output, stop Pods, grant scope, or use `SpawnedPodRegistry`.
|
||||
- Add TUI `:peer <name>` command that emits `Method::RegisterPeer { name }` to the attached Pod and shows local diagnostics; the controller returns a typed result event for success and normal `Event::Error` for failure.
|
||||
|
||||
Crash-level atomicity for two metadata files is not provided by the existing store, but the implementation can avoid misleading partial state for ordinary validation/write failures and does not require broad schema migration or hidden history changes.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Review: peer Pod handshake command
|
||||
|
||||
Reviewer Pods:
|
||||
|
||||
- Initial review: `peer-pod-handshake-reviewer-20260602`
|
||||
- Re-review: `peer-pod-handshake-rereviewer-20260602`
|
||||
|
||||
## Result
|
||||
|
||||
Approved after fixes. No remaining blockers.
|
||||
|
||||
## Initial blocker findings
|
||||
|
||||
The first reviewer found two blockers:
|
||||
|
||||
1. `SendToPeerPod` wrote `Method::Notify` directly to the target socket without draining connect-time `Alert` / `Snapshot` traffic, so a real Pod socket could fail to process the notify while the sender reported success.
|
||||
2. Reciprocal registration rollback could delete a pre-existing `source -> target` peer relation when the reciprocal `target -> source` write failed.
|
||||
|
||||
## Fix verification
|
||||
|
||||
Coder added commit `057c2ef fix: harden peer pod registration`.
|
||||
|
||||
The re-review confirmed:
|
||||
|
||||
- `SendToPeerPod` now uses the existing `connect_and_send` one-shot client path, which drains connect-time `Alert` / `Snapshot` traffic before writing `Method::Notify` and reports delivery failures.
|
||||
- A regression test covers a target socket that emits an alert/snapshot before reading the peer notify.
|
||||
- `register_peer` now snapshots the source Pod's existing peer list and restores that exact list if the target-side write fails.
|
||||
- A regression test covers an injected target-side failure where the source already had the peer relation and verifies it is preserved.
|
||||
|
||||
## Validation evidence
|
||||
|
||||
Coder reported:
|
||||
|
||||
- `cargo test -p pod discovery --lib`
|
||||
- `cargo test -p tui command --lib`
|
||||
- `cargo test -p protocol -p pod-store -p pod -p tui --lib`
|
||||
- `./tickets.sh doctor`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi`
|
||||
|
||||
Reviewer re-ran:
|
||||
|
||||
- `cargo test -p pod --lib peer`
|
||||
- `cargo test -p pod --lib connect_and_send`
|
||||
|
||||
Parent/orchestrator reran after merge:
|
||||
|
||||
- `cargo test -p pod discovery --lib`
|
||||
- `cargo test -p tui command --lib`
|
||||
- `cargo test -p protocol -p pod-store -p pod -p tui --lib`
|
||||
- `./tickets.sh doctor`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi`
|
||||
- `./result/bin/yoi pod --help`
|
||||
|
||||
## Residual risk
|
||||
|
||||
Peer registration updates two metadata files and is not crash-transactional because the current Pod metadata store has no multi-record transaction boundary. Normal write failures are handled by restoring the exact prior source peer list.
|
||||
|
||||
The implemented peer relationship is metadata-level reciprocal registration, not live target-process consent. This is documented and remains separate from spawned-child delegation, delegated scope, output cursors, parent ownership, and child completion notifications.
|
||||
Reference in New Issue
Block a user