---
name: project-index-progress
description: "PROJECT-INDEX milestone — triage @e5f053f (ADR-0037, 5 REQs, JIT docs/PROJECT-INDEX-TRIAGE.md); W1 DISPATCHED to todlando 2026-07-15; doyle gates per wave; hertz field-verify partner"
metadata: 
  node_type: memory
  type: project
  originSessionId: 5d3eec33-6de0-42f8-8c63-740485dc0d39
---

**✅ MILESTONE CLOSED 2026-07-16 — hertz field verdict 6/6 PASS on HFENDULEAM v0.33.0 live home.** Verdict detail: list 90.6ms human / 34.4ms json (was 15-18s); attribution truth all known endpoints (no dashes); index health clean (stale_reads 0 throughout, stall-evict flat 17, 1 enum/cycle, organic mid-verify branch move scanned exactly 1); whoami 11-13ms x10 + clean {id:null}/exit-1 unbound leg; cold path = brain refresh sufficed (broker N-1 posture accepted); controlled freshness via fork todlando→hertz-verify3 + purge — EXACT N=2 scan symmetry both rounds, three readers consistent, no ghost row post-purge, probes cleaned. Both the bundle-03 latency class AND the 2026-07-15 delivery-correctness class closed on the live home under release posture.

PROJECT-INDEX milestone (operator-picked at the v0.32.0 boundary, dispatched 2026-07-15).

**Triage on main @e5f053f** (bs-core + mirror): `docs/PROJECT-INDEX-TRIAGE.md` (JIT) + ADR-0037 (materialized project index) + CONTEXT.md glossary entry + 5 REQs registry-first (all `required_stages=[]`, flip per-wave). Canonical design: `.claude/reports/2026-07-10-hertz-session/03-cli-project-index-latency-rca.md` — shape operator-agreed, NOT re-litigated at build.

**Root:** list-shaped reads spawn 100+ sequential git children (`cmd_endpoint_list` → `latest_project_ref` fanout, cli.rs ~2954 / picker/data.rs ~456-518; O(P×B+C), 29–35s @13 perches×7 branches). Promoted from latency to CORRECTNESS by the 2026-07-15 bodies-vanish incident (whoami aliases the full list → hook 30s ceiling → delivery black-hole).

**MANUAL LATENCY ACCEPTANCE ✅ PASS (todlando 2026-07-16, doyle ACCEPTED):** synthetic 13-perch/7-branch A/B on HFENDULEAM, live home untouched — OLD v0.32.0 list --json 15373/17971/9125ms vs NEW @648e4f8 96/192/76ms (+endpoint-info 51ms), ~100x, sub-second met, attribution REAL (remote-URL-derived ids, 13 rows). Baseline 9-18s vs 30s RCA = fewer commits/branch in synthetic store, cost class identical. **RULED: hertz field-verify RIDES THE RELEASE — no pre-release daemon swap on live home** (live infra; release path is part of what verify proves). hertz briefed + LOCKED 6-point verify list (hertz added 5+6): (1) sub-second live list/picker, (2) attribution truth not dashes, (3) daemon status project_index counters sane, (4) UPS symptom class stays closed, (5) cold-path bounded + COMPLETE attribution on first request after the release-managed daemon restart (not warm-only timings), (6) controlled-change freshness — one endpoint metadata/project change → next cycle updates list+picker+endpoint-info consistently, exactly the expected changed-branch scan, no stale_reads climb. (Transport gotcha en route: long INLINE send drained EMPTY, file resend intact — [[send-body-from-file-not-inline]] extended.) **✅ v0.33.0 PUBLISHED counter 60 (deployah 2026-07-16, PR #12 @21a46d5, first-try clean ceremony)** — bs-releases, 11 assets verified (short names UNCHANGED — deployah's "win-msvc" wording was shorthand, docs stand), signed rel-primary-2026. **APPLIED ON HFENDULEAM same day: bare spt update + daemon refresh → CLI+brain 0.33.0, broker deliberately 0.32.0 (N-1 posture, swaps at next full bounce; docs server also waits on that).** First live index cycle: 46ms, 10 endpoints/4 projects, counters {1,0,0}, 0 stale/0 repairs; live-home list timings 85ms human/177ms json (was 15-18s). claude-spt adapter post-step now prints VERIFIED (perri shipped verify-then-notify). **HERTZ GO SENT (6-point verify), with notes: brain-refresh = the cold-start event for check 5 (full-bounce flavor available via operator if hertz insists); stall-evict baseline 15 (from today's two refreshes incl deployah zombie recovery — watch it flat, not zero). MILESTONE CLOSES on hertz verdict.** (Same-day op note: deployah endpoint was WEDGED pre-release — zombie hosted session, stop/run trap — recovered via scoped tree reap + daemon refresh + fresh run; seeded REQ-ENDPOINT-CYCLE-HONEST in [[spt-core-findings-backlog]].)

**Waves:**
- **W1 (DISPATCHED todlando 2026-07-15, off main @e5f053f):** REQ-WHOAMI-IDENTITY-ONLY (F-040 opener: session→endpoint|null resolver, no list/git/network; whoami de-aliased; endpoint-info disqualified as carrier) + REQ-PROJECT-INDEX-STORE (versioned format + read path, reader contract: never git, last-known-good, offline reads). W1 alone closes the hook-deadline class.
- **W2:** REQ-PROJECT-INDEX-WRITER (daemon sole single-flight writer, load-at-start, ready-without-warm, O(P+B+F+C) batched, atomic replace, observability — presence≠health) + REQ-PROJECT-INDEX-INVALIDATION (event-driven, branch-tip fingerprints + debounce/coalesce; generation counter REJECTED — nothing maintains it).
- **W3:** REQ-PROJECT-INDEX-READER-CUTOVER (list/picker/endpoint-info on index, behavioral parity binding: session-cwd → origin-cwd → context-recency + rendered names unchanged; counters = CI gate) + manual latency acceptance (13-perch/7-branch fixture, ~30s → sub-second) + hertz field-verify on HFENDULEAM.

**Pre-made gate rulings (binding):** complexity COUNTERS are the CI gate, wall-clock = manual acceptance ONLY (shared-runner flake class); cold-start ready-before-warm + warm-start no-scan-on-unchanged-generation; degradation legs keep fast reads; new daemon-tree e2es → HEAVY group AT BIRTH (FLAKE-LEDGER #15).

**Out of scope:** MESH-RECOVERY (sibling candidate, separate contract); precedence/name semantics changes; adapter-side work (perri consumes the W1 verb — comms at W1 ship).

**W1 CLOSED: MERGED @e457327 (PR #6), mirror-pushed, branch deleted. W2 DISPATCHED todlando 2026-07-16** (writer + invalidation off main @e457327; dispatch brief = registry titles + W1 seams write_index/source_generation/GIT_SPAWNS + pre-made rulings incl HEAVY-at-birth for daemon-tree int legs; branch suggestion build/project-index-w2-daemon-writer). **W1 GATE PASS (doyle 2026-07-16): PR #6 @13bf7a2 APPROVED TO MERGE.** Gate ledger: CI run 29463969954 SUCCESS both platforms (wan_arrival exoneration adjudicated by CI green); isolated worktree-of-sha + throwaway CARGO_TARGET_DIR — clippy workspace -D warnings clean, projindex 5/5, whoami legs 4/4 (poisoned-PATH e2e zero-git, resolver census, parse, json_emit endpoint|null); traceable exit 0; REQ-WHOAMI-1 retitle ACCEPTED (INSTALL-1/5 precedent); rig cleaned. Gate gotcha: nextest positional filter + -E don't mix — positional silently won, whoami legs skipped first run; rerun with pure -E. NEXT: W2 (daemon writer + invalidation) dispatch after merge. Original preflight: full workspace 1810/1811 (sole red = inject_control_wedge wan_arrival, standing box-anchored, reproduced on clean main worktree same box = diff exonerated) + clippy/traceable/xtask/mdbook green. Build detail:
- spt-store: NEW projindex.rs (schema=1 JSON @ `$SPT_HOME/index/project-index.json`; `IndexRead::Snapshot|Absent{Missing|Unreadable|SchemaMismatch}`; `join_roster` roster-authoritative — ghost index ids never resurrect rows; atomic `write_index` lives with the format, W2 daemon = sole prod caller; 5 units incl zero-git census) + **gitrun `GIT_SPAWNS` census seam** (`git_spawn_count()` at the store's SINGLE git choke point — reusable for every future no-git gate).
- spt cli: `cmd_whoami` de-aliased → identity-only (`detect_self_id` + single-perch reads + shared `render_self_pin`; unresolved = `NO_PERCH`/`{"id":null}` exit 1); `WhoamiJson` committed shape `{id,state?,ready?,alive?,unbound?,description?}`; **REQ-WHOAMI-1 RETITLED** (alias premise superseded; pin-render evidence stands).
- Tests: roster unit `detect_self_id_resolves_identity_with_zero_git_spawns`; `whoami_identity_e2e` (**POISONED git shim on PATH** via `git_fixture` [[bin]] — logs + fails every git call; LIGHT class, no daemon tree); `json_emit` updated off the old whoami-exit-0-list-DTO assertion.
- Docs: api.md Introspection identity-verb section; json-shapes.md whoami row split; integration-checklist note; STORAGE.md `index/` section; reference regen. CONTEXT.md tag pre-landed in triage.
- Disclose at gate: whoami human output = SELF pin only (was full list); `--json` = new identity DTO (was list DTO); unresolved exit 1 (was 0).

**W3 CLOSED: GATE PASS + MERGED @648e4f8 (PR #10 @d88fec6, todlando 2026-07-16), branch deleted, mirror-pushed (9bf6d11..648e4f8).** Gate ledger (doyle): CI 29479766061 SUCCESS both boxes; isolated worktree battery — clippy clean, nextest 29/29 (parity-vs-legacy-oracle incl slug-vs-display hard case, reader e2e + writer e2e + whoami zero-git regression); traceable 497/497; "strongest wave of the three". DISCLOSED-ACCEPTED: fresh-endpoint picker visibility lags bind by debounce window (bounded, documented). Sync-path ruling LANDED: sync.rs pull path nudges ONE Global per applied p-* branch (fingerprint gates, debounce coalesces); spt-live reconcile raw commit noted, periodic backstop covers; CONTEXT avoid-list names un-nudged p-* mutation an anti-pattern. Shipped: EndpointProject.refs (full precedence-ordered history, additive schema-1) + ProjectIndex.cwds (writer cwd→{id,display} cache, resume-row titles); readers ONE index read each (list json+human, picker gather, endpoint-info, resume rows); retired latest_project_ref/project_refs_for/project_history_for DELETED; projindex_reader_e2e HEAVY at birth (poisoned-git shim, maintenance + deleted-index degradation legs). Battery gotchas: reader-e2e fixture bug (ep2 'membership only' asserted, slice never committed — reader exonerated); REQ-PICKER-HISTORY-FRESH impl tag died with retired picker wiring → re-homed at projderive origin-cwd union leg; two scoped EPERM sweeps of leaked target spt.exe mid-battery. **MANUAL LATENCY ACCEPTANCE: PASS 2026-07-16** (todlando, synthetic 13-perch/7-branch fixture, live daemon untouched): OLD v0.32.0 list --json 15373/17971/9125 ms → NEW @648e4f8 96/192/76 ms, endpoint-info 51 ms (~100x, attribution verified real not degraded); numbers SENT doyle. ACCEPTANCE ACCEPTED by doyle 2026-07-16 + RULING: hertz field-verify RIDES THE NEXT RELEASE (v0.33.0, deployah=doyle after their docs PR #11 lands) — NO pre-release swap of the live daemon (live infra: doyle/todlando/flynn perches on this box; release path itself is part of what field-verify proves). Milestone closes on hertz's post-update live-home verify. todlando lane DONE all three waves ("outstanding job across all three waves" — doyle). Original W3 dispatch brief: (reader cutover off main @e0387e6; branch suggestion build/project-index-w3-reader-cutover; brief: registry title = gate text, parity suite drives OLD projderive kernel vs NEW index-backed render on one fixture, int leg = daemon-maintained index + zero-reader-git proof (census/poison), HEAVY at birth again, raw-BranchStore un-nudged question = builder assesses + states finding in PR, manual latency + hertz field-verify post-gate, doyle coordinates hertz after merge). **W2 CLOSED: MERGED @e0387e6 (PR #7, todlando 2026-07-15), branch deleted, mirror-pushed (SaberMage/spt-core e457327..e0387e6).** **W2 GATE PASS (doyle 2026-07-16): PR #7 @1a68900 APPROVED TO MERGE, verdict SENT to todlando (todlando merges + mirror-pushes).** Gate ledger: CI 29466867872 SUCCESS both boxes; isolated worktree + throwaway target — clippy clean, nextest 19/19 (8 projwriter units incl counters-hold + warm-no-scan + last-known-good, 3 projinval, 3 projderive, fingerprint, branchstore single-spawn, status-line, HEAVY e2e 9.3s vs live daemon); traceable exit 0; projderive kernel VERBATIM-verified vs removed picker code (parity holds, only additive SourceLeg). **Carried to W3:** raw-BranchStore sync paths un-nudged (periodic backstop covers) — re-examine at reader cutover; W3 = READER-CUTOVER + parity suite + counters-as-CI-gate + manual latency acceptance (13-perch/7-branch fixture) + hertz field-verify. Gate gotcha: own shell cwd inside worktree = Permission-denied on remove; cd out first. Build detail:
- spt-daemon NEW `projwriter.rs`: WriterEngine (explicit-path WriterPaths — units run env-free on temp trees) + `spawn_index_writer` thread in brainproc run_brain (livehost pattern, AFTER write_ready = ready-without-warm by construction). Fingerprint skip → warm no-scan; branch membership cached by tip; cwd cache stamped on `.git/config`/gitfile marker (pure fs walk, no git) → ordinary commits no-op. Stats sidecar `index/project-index-stats.json` + `daemon status` project_index block (--json, typed via IndexWriterStats) — counters = the CI-gate surface. Env valves: SPT_PROJINDEX_{DISABLE,POLL_MS,DEBOUNCE_MS,PERIODIC_MS} (test rigs only).
- spt-store NEW `projinval.rs` (drop-dir queue: nudge/drain/coalesce; store mutators use root-derived path — NEVER ambient env, so test-rooted stores nudge their own temp tree) + NEW `projderive.rs` (**project_refs_from kernel MOVED verbatim from picker/data.rs** + SourceLeg; picker delegates — parity by construction) + `branch_tips_by_recency` (one for-each-ref = recency+tips) + `fingerprint_tips` (p-* only, a-* blind, order-insensitive).
- Nudge seams: ContextStore commit_project/rename/fork/remove (funnel-level, all callers covered); bind (api/startup) / boundary (api/reporting) / ready-bind (spt-msg) / purge (cli). Raw-BranchStore sync paths NOT nudged — periodic backstop covers (5 min); note for W3/doyle.
- e2e `projindex_writer_e2e` HEAVY AT BIRTH (nextest.toml + BOTH ci.yml -E strings — keep 3 in sync): cold publish, warm-restart {1,0,0}+byte-identical, session/context/rename/fork/purge legs vs live daemon. Fork leg = store funnel + minted perch (CLI fork needs subnet rig).
- Gotchas hit: leaked target\debug\spt.exe EPERM on rebuild (scoped Get-CimInstance kill by ExecutablePath); seedmap 2-test red under bare full-parallel `cargo test -p spt-daemon --lib` = KNOWN starvation class (isolated pass, module untouched); repo NOT fmt-clean and CI has NO fmt gate — never run cargo fmt wholesale.

Gate-cycle note: v0.32.0 release merge had NOT been mirror-pushed (deployah miss) — caught up + tag backfilled @e5f053f push; watch merge-time mirror discipline on release PRs.

Kin: [[spt-core-findings-backlog]] (the promoted candidate + F-040 + incident seed), [[the-forkening-plan]] (predecessor milestone), [[v0320-published]].
