Skip to content

Share one Log inventory capture across Command observations - #1248

Merged
JacobStephens2 merged 4 commits into
mainfrom
issue-1246
Oct 24, 2026
Merged

JacobStephens2 merged 4 commits into
mainfrom
issue-1246

Conversation

@JacobStephens2

@JacobStephens2 JacobStephens2 commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

A Snapshot now captures the Log inventory once. Everything that used to walk the log folder again now reads that capture: Command-record loading, historical recovery, every Command's Session query, and the Logs listing.

 Snapshot::load(root)
+  Inventory::capture(Files)      # owner → repository → commands → kind folders, listed once
   read_records(folder)           # captured regular files
   history::read(repo)            # captured candidates
-    read_dir(commands/*) again
 Observation::sessions()
   explicit stage/current references
-  read_dir(log folder) + sidecar read + metadata, per Command
+  index[(subject, SessionOwner)] # decoded, Model evidence read once per capture
+  ordered()                      # one modification-time lookup per Session path
 catalog::load
-  Snapshot::load, then read_dir every folder again
+  catalog::list(snapshot)        # the Snapshot's own captured files
src/logs/reading/
├── inventory.rs        # new: Files seam (Native adapter), Inventory, Folder, Candidate index
├── inventory_tests.rs  # new: counting adapter through Snapshot/Session/detail/Trace/Logs
├── reading.rs          # Snapshot holds Arc<Inventory>; Commands keep a private handle
├── selection.rs        # Session membership = references ∪ indexed candidates
├── history.rs          # Session-only recovery over captured candidates
└── catalog.rs          # listing projected from the capture
src/logs/owner.rs       # SessionOwner: evidence over filename identity (replaces session_matches)

What is unchanged:

  • Readers (reader.rs, still_listed) still check eligibility and writer lifetime on every read.
  • A folder that a query names outside the listed layout is enumerated on demand, once per capture. It is never listed.
  • The glossary now defines Log inventory, and docs/code-navigation.md points at its new owner.

Seams under test: the Snapshot interface and the projections built on it (Observation::sessions/session/details, trace::ancestry::of, catalog::list). They run over a temporary filesystem through the internal Files seam, with a counting adapter wrapped around Native.

Evidence

  • Before:

    • At a593009e, each Observation::sessions() listed its Command's folder and re-read its sidecars and metadata.
    • catalog::load then listed every folder again.
    • The old code had no seam, so this cannot be shown as a failing test.

    After: cargo test --bin thirdshift logs::reading::tests passes 22/22. It includes two new tests:

    one_capture_serves_every_session_projection_without_discovering_again
      fixture: Pickup run → dispatched Spec run → child Ticket, plus Runs #7 and #8, all in one folder
      assert listed folders == [root, acme, acme/widgets/commands, …/issue]
      3 rounds of: sessions(), details(), ancestry::of(), catalog::list()
        assert every Session list equals literal expectations:
          references, mtime tie broken by path, missing reference first (UNIX_EPOCH),
          evidenced tokenless Session attached, unevidenced tokenless and
          disjoint-token Sessions recovered as history
        assert the unowned notes.log is listed and the missing reference is not
      assert calls(round 1) == calls(round 3)          # projections add no discovery
      assert every list/metadata/read happened exactly once
      assert 9 Model-evidence reads, one per Session candidate
    
    a_fresh_capture_observes_added_removed_and_retargeted_sessions_and_revised_evidence
      old capture: unchanged after add/remove/symlink/evidence edit (coherent)
      fresh capture: sees the added Resume; drops the removed Session and the symlinked Repair
        (from Sessions and from the Logs listing); revised evidence detaches the tokenless Session
    
  • Suite: the full Rust suite, from scripts/affected-tests origin/main plus cargo test --no-fail-fast: 2604 passed, 0 failed across 62 test binaries at bbc78a62.

    • This host's global git config sets tag.gpgsign true. That breaks 3 worktree::synchronization_tests, which create lightweight tags, on any branch.
    • The full suite was therefore run with GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=tag.gpgsign GIT_CONFIG_VALUE_0=false.

Merge Danger

Door: two-way

It is a refactor with no new file format, cache or setting, so a revert restores the old discovery loops exactly.

Blast Radius: logs

These all read the capture: status, show, logs, the Console Inbox, the Logs page, Trace export and Waterfall, Stop and Dismiss. If ownership, ordering or eligibility drifted, it would show up there. The retained regressions in tests/show_logs.rs, tests/status.rs, tests/console.rs and reader_tests.rs pin those.

Review

  • Fixed point: origin/main, because the local main ref was stale.
  • Reports: Standards and Spec, both run with thirdshift-code-review.
  • Changed files left unread:
    • console/README.md joined the diff after review. It is a one-line wording fix for a Standards finding: "Session inventory" became "Session traces". The Standards axis had read that line; the Spec axis left it unread.
    • No other changed file went unread on either axis.

Unaddressed findings

Standards

  • Data Clump: &Arc<Inventory> threaded through tree/children/Command::new/history::read and stored on each Command. Declined, per plan Decision 2: "The Snapshot and its Command/history observations retain a private shared handle to the captured inventory; their Session queries use that handle." Existing callers such as Inbox rows, details and Trace ancestry keep calling command.sessions() with no new parameter (src/logs/reading/selection.rs, Observation::sessions).
  • Feature Envy: Inventory::sessions/candidates work on Folder data. Declined, as a judgement call. Moving them onto Folder would make every Folder carry the Files adapter. Keeping them on Inventory sends every discovery effect through the one owner that the counting test observes (src/logs/reading/inventory.rs, Inventory::sessions).
  • Data Clump: catalog::list(snapshot, root, …) passes root beside the Snapshot. Declined. The on-demand capture used by Stop's retained_work has no root. The listing's root is the configured logs_dir, which its caller already holds and which Reader::within needs anyway (src/logs/reading/catalog.rs, load).
  • No _Avoid_ line for "Session inventory" under Log inventory. Declined. The remaining uses were reworded. "Session inventory" was never a competing name for the Log inventory, and _Avoid_ is optional in this glossary.

Spec

  • Decision 11 cases (aliases, Record/Activity/Session-only precedence) are pinned only by existing tests. No change: the reviewer judged this acceptable under "Retain meaningful … regressions". reader_tests::configured_root_and_commands_aliases_stay_readable and the history cases in src/logs/reading/tests.rs and tests/status.rs are kept unchanged and pass.

Security

  • None. The security review of ce8b4bbe...bbc78a62 found no introduced finding. These are unchanged: physical-only Logs eligibility, the symlink exclusions for owner, repository, kind and file entries, Model-evidence reads, and the per-read still_listed and writer checks in Readers. Every capture is request-scoped.

Closes #1246

Built with claude · claude-opus-5-5 · high

Security review outcome

No unaddressed introduced findings.

A Snapshot now captures owner, repository, commands and kind folders once
behind a Files adapter. Command-record loading, historical recovery,
Session queries and the Logs listing consume that capture; Session
candidates are decoded, their Model evidence read and their modification
times looked up once per capture, and indexed by folder, subject and
effective owner.
…ntries

Point the Session selection index row at Session membership, share the
repository name and owned Session identity, rename the entry kind and
on-demand capture, and check that a fresh capture and Logs listing drop
an entry retargeted to a symlink.
@JacobStephens2
JacobStephens2 merged commit c7676aa into main Oct 24, 2026
18 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-1246 branch October 24, 2026 13:15
This was referenced Oct 24, 2026
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.

Deepen Log inventory so Command observations share one Session discovery pass

1 participant