Skip to content

Deepen the Command reader around selection and ownership #793

Closed

Description

@JacobStephens2

What to build

Make status, show, logs and Stop consume one deep Command reader module. It owns discovery, historical recovery, exact-parent trees, name resolution, Session inventory and the relationship between a selected Run and its owning Command. Callers format observations or perform their existing effects without reconstructing ownership.

This is a standalone, single-session Ticket: migrate the existing behavior together and delete the superseded caller logic. The commands' output and behavior remain compatible.

Acceptance criteria

  • One reader interface supplies the machine-wide Command list, a resolved Command/Run with its ownership information, Session selection, and retained resources for a captured Command record. Reading does not print, signal, write Stop requests or mutate records.
  • status and show preserve their version 1 JSON fields, text, sorting, recent/all filtering, idle Passes, current stages, partial historical facts and bounded latest-event reads. Existing record/history precedence and malformed/unsupported-record handling survive.
  • Name resolution preserves Issue URLs, short and qualified repository names, Pass names, case handling, ambiguity errors, live-first selection and newest-first fallback. show, logs and Stop use the same resolution.
  • Exact parent-record and parent-dispatch matching stays inside the reader implementation. Child Runs remain under the correct dispatched Run, including multiple Security dispatches containing the same child issue number.
  • A resolved selection supplies its outer Command's record/process identity for log following and eligible Stop requests, plus the enclosing Run/Spec name for child-Run refusal. Neither logs nor Stop searches the tree again or uses pointer equality to recover an owner.
  • Stop on an embedded dispatched Run still stops its outer Command. Stop on a child-owned Run is refused with the enclosing Command/Run name and sends no signal or Stop request. Existing durable-outcome and process-identity checks immediately before signaling remain in place.
  • logs --follow keeps draining final bytes until the captured outer process identity disappears, even after an outcome is recorded or the selected child ends. status still reports a durable outcome as ended immediately.
  • Session inventory preserves stage/current references, current-layout filename discovery, Resume and numbered Repair selection, duplicate removal and existing ordering. History does not invent liveness, stages or metadata.
  • Stop's ending reloads retained work through the reader, includes child-owned and dispatched Runs belonging to that exact Command, and preserves distinct, sorted branch/PR output. It cannot report another Command's or sibling dispatch's work.
  • Existing status, show/logs and Stop CLI tests pass. Add focused coverage at the reader interface for the ownership matrix below; remove superseded helper-level tests only when their behavior is covered there. No parallel ownership implementation remains in the presentation modules.
  • Update the domain-to-code navigation entries for Command records, naming, Session selection and Stop to point to the new ownership. No glossary or ADR change is required: the reader is an implementation module for existing Command vocabulary.

Blocked by

None (can start immediately).

Decisions

Design tree, settled in dependency order; no open frontier remains:

  1. Scope → reader seam → callers. Consolidate the existing Command reading implementation under a sibling reading module of the logging module. Keep status/show text and JSON formatting, byte streaming, Stop-request writes and signaling in their callers. Reason: the architectural friction is duplicated ownership knowledge; moving printing into a larger module would not remove it. This is an internal refactor with no new command, persisted format, index, cache or Console work.

  2. Reader seam → snapshot inputs and observations. Load from an explicit configured logs root and one sampled current time. The caller loads User config and hostname; the reader owns filesystem discovery and observation building. Supply a snapshot with listing and resolution operations, and a focused retained-work read by captured record path for Stop's ending. Reason: commands can share one interpretation without requiring every caller to know directory layout, history precedence or tree assembly, and final Stop reporting must refresh facts after cleanup rather than reuse its starting snapshot.

  3. Snapshot → source fidelity and compatibility. Keep record-backed and historical observations distinct internally, and expose only the facts/projections callers need to render existing output. Move historical recovery behind the same reader seam, retaining its source precedence, unknown facts, current-layout restriction and existing error behavior. Listing applies its current recent/all rules; resolution considers all history as today. Reason: forcing history into a complete durable record would invent facts, while exposing internal recovery modules would preserve the present shallow interface.

  4. Snapshot → ownership → selection result. Assemble exact parent-record/parent-dispatch relationships once. Resolution returns the selected observation together with its outermost owning Command and, for a child-owned Run, the enclosing dispatched Run/Spec or root needed for the refusal message. Embedded dispatches retain their outer record path; separately recorded children retain their own identity. Keep tree formatting possible, but remove callers' recursive ownership searches and pointer comparisons. Reason: status, follow and Stop require different projections of the same ownership facts; their callers should not rediscover them.

  5. Ownership → process semantics. Preserve two distinct questions: whether an observation has ended for display, and whether the captured outer process has exited for follow. Reuse the existing process-identity implementation and compare both PID and process start. The resolved follow identity remains captured while its liveness is rechecked. Stop still rereads durable state and validates identity before signaling; a reader snapshot grants no lasting signaling authority. Reason: outcomes precede final summaries/notifications, and a process may end or its PID may be reused after selection.

  6. Selection → Session inventory and details. Put Session discovery, deduplication, ordering and kind selection behind the selected observation's interface. Keep the existing bounded live-event interpretation available for detailed views, computed only when needed. Reason: show text, show JSON and logs must agree on Resume/Repair inventory without each learning filenames or scanning unrelated Session bodies. Preserve the existing 64 KiB tail limit and Harness interpretation.

  7. Ownership → retained work. Reload the captured Command's folder through the reader and collect only that exact tree's resources. Return structured branch/PR facts; the Stop caller preserves the existing wording, uniqueness and display ordering. Reason: retention is an ownership observation, while the output wording belongs to the caller; a machine-wide name search after cleanup could choose a different Command.

  8. Dependencies → adapter choice. Use the real filesystem adapter with temporary-directory fixtures, and the existing process-identity implementation. Introduce no generic reader effects trait, repository abstraction or new runtime. Reason: filesystem fixtures are already local substitutes; the existing process seam is sufficient and a new single-adapter interface would add indirection without depth. Sample time explicitly so age/filter tests are deterministic.

  9. Testing → shared interface and surviving checks. Keep the current CLI tests as compatibility checks. Exercise the reader directly with temporary current-layout records/logs for (a) direct Run, (b) Pass with dispatched Spec and Ticket, (c) two dispatches with equal child issue numbers, (d) a separate Command with similar issue/stamp, and (e) historical-only selection. Assert selected facts, outer owner, child-refusal target, Session choice and retained resources through the reader interface. Retain real-process CLI checks for Stop signaling and follow's final bytes; add only gaps uncovered by this migration. Reason: the interface is the test surface; tests should survive rearranging private traversal helpers.

  10. Delivery → deletion test and documentation. Finish in one Ticket with no dependencies: the work is a bounded migration of existing behavior with existing CLI coverage. Delete obsolete selection/traversal logic rather than leave forwarding implementations or add a second set of behavior tests for each old helper. Update navigation as part of implementation. No new domain term or hard-to-reverse trade-off is introduced, so CONTEXT.md and ADRs need no edits. Reason: depth must produce caller leverage and ownership locality, not just rename private functions. Deleting the resulting reader would redistribute its rules across four callers; deleting the obsolete caller searches concentrates them in one implementation.

Overlap checked against all 76 open issue titles and bodies at review time. #776 asks the Console to reuse readers and #574 asks for visibility/Stop behavior; neither proposes this deepening. This Ticket adds no Console features and does not change their product decisions. ADRs 0011 and 0016 remain intact.

Review basis: main at de3c1ed94dc3ad78859fccf555b195b90ac76a0a. All 39 existing status, show/logs and Stop integration tests passed during this review. This validates the behavior to preserve; no implementation was made. The Mermaid blocks were checked against flowchart syntax before publication.

Architecture review

Strength: Strong · Dependencies: local-substitutable

Files: src/logs.rs; src/logs/status.rs (tree, children, retained_resources); src/logs/status/history.rs; src/logs/status/inspect.rs (records, stop_target, logs, contains); src/logs/stop.rs; src/logs/command_record.rs; src/logs/process_identity.rs; tests/status.rs; tests/show_logs.rs; tests/stop.rs; docs/code-navigation.md; proposed src/logs/reading.rs and private reader helpers.

Before

flowchart LR
  S[status] --> T[Command trees]
  I[show and logs] --> T
  X[Stop] -. name and owner .-> I
  X -. retained work .-> S
  I -. owner reconstruction .-> T
  T --> H[Command history]
  T --> F[Filesystem adapter]
  I --> F
  classDef leak stroke:#dc2626,stroke-width:2px;
  class I,X leak
Loading

After

flowchart LR
  S[status] --> R
  I[show and logs] --> R
  X[Stop] --> R
  subgraph R[Command reader module]
    T[Command trees] --> H[Command history]
  end
  R --> F[Filesystem adapter]
  classDef deep stroke-width:3px;
  class R deep
Loading

Problem: The Command reading interface is shallow because callers reconstruct ownership across the seam: tree construction, selection, Stop targeting, follow completion and retained work are spread across presentation modules.

Solution: Give the Command reader module depth by absorbing discovery, selection and ownership into one implementation behind a shared observation interface.

Wins

  • Locality: ownership rules concentrate.
  • Leverage: four callers share observations.
  • Tests cross the reader seam.
  • Delete caller ownership reconstruction.

Activity

  1. added
    needs-triageMaintainer needs to evaluate this issue
    ready-for-agentFully specified, ready for an AFK agent
    architect-planAn Architect plan: the Spec or Ticket an Architecture review published
    in-progressA Claim: thirdshift has taken this issue
    and removed
    needs-triageMaintainer needs to evaluate this issue
    ready-for-agentFully specified, ready for an AFK agent
    on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    architect-planAn Architect plan: the Spec or Ticket an Architecture review published

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions