Conversation
Adds TestModelDispatch_AllModes which exercises every mode's key dispatch path through model.Update. As a refactor these tests pass now and act as a safety net — any breakage during the handler split will surface here.
Moves all seven handle*Key functions out of model.go into dedicated files (keys_list.go, keys_detail.go, keys_search.go, keys_project.go, keys_rerun.go, keys_stats.go, keys_timeline.go). model.go shrinks from 962 to 354 lines. No behavior changes; all tests pass at 85.9% coverage.
Adds TestRenderDispatch_AllModes which calls View() for every mode and checks for non-empty, non-panicking output. Acts as a safety net for the upcoming Task 2 render.go split.
…ate files Moves all per-mode render*View/Header/Footer/*BodyLines triples out of render.go into dedicated files (render_list.go, render_detail.go, render_search.go, render_rerun.go, render_stats.go, render_timeline.go). render.go shrinks from 1029 to 308 lines. project.go already owned project-mode rendering. No behavior changes; all tests pass at 86%.
Tests nav() for all standard list keys (j/k/d/u/g/G/down/up) covering empty lists, single items, boundary clamping, half-page overshoot, and unknown keys as no-ops. Fails because nav is not yet defined.
…ocks Implements nav(key, cursor, count, halfPage) in nav.go and collapses the duplicated six-case navigation switch in keys_list, keys_detail, keys_search, keys_project, and keys_stats to a single nav() call each. Timeline handler left unchanged (different shape). Coverage 88.2%.
Tests that ensureIndex() is a no-op when m.index is already set, and that it does not panic when projectsDir is empty. Fails because ensureIndex is not yet defined.
Adds ensureIndex() to model which opens the FTS5 index on first use (no-op when already set or projectsDir empty). handleSearchEntryKey collapses to a single m.ensureIndex() call. Sets up Task 8 background sync. Coverage 88.1%.
Tests LORE_CACHE_DIR env var set/unset/empty, and that the resolved directory is created on first call. Fails because resolveCacheDir is not yet defined.
Adds resolveCacheDir() in lore.go (LORE_CACHE_DIR > os.UserCacheDir()/lore) mirroring resolveProjectsDir. index.go and bookmark.go now call resolveCacheDir() instead of os.UserCacheDir() directly. Directory is created on first use. Documented in CLAUDE.md and README.
…ail modes Tests that pressing R in list mode and detail mode calls resumeFn with the correct session ID and CWD. Fails because resumeFn field and R binding do not exist yet.
Adds resumeClaude(sessionID, cwd) in rerun.go using claude --resume. New resumeFn hook on model (injectable; defaulted to resumeClaude). R bound in list and detail modes; help overlay and footers updated. Reuses rerunDoneMsg for the return-to-list flow. Coverage 87.7%.
… rates Tests that setting LORE_PRICING_FILE to a temp JSON file makes estimateCost use the custom per-token rates. Fails because pricing file loading and resetPricingOnce are not yet implemented.
Replaces the hardcoded pricingTable slice with an embedded pricing.json loaded via go:embed. Honors LORE_PRICING_FILE env var for custom rates. sync.Once guards the table so it is parsed once per process. Existing cost calculations unchanged; new tests verify the override path.
Tests that Init() returns a non-nil batched cmd, that indexReadyMsg populates m.index and clears m.indexing, that errors clear the flag without setting the index, and that the list header shows 'indexing' only while the flag is set. Fails because indexReadyMsg and indexing do not exist.
Init() now returns tea.Batch(loadSessionsCmd, syncIndexCmd). New
indexReadyMsg{idx, err} populates m.index and clears m.indexing when
the background sync finishes. List header shows 'indexing...' while
in flight. ensureIndex() is a no-op while indexing=true. Coverage 86.7%.
Table tests for parseSearchQuery covering no prefix, project:, branch:, both prefixes, prefix at end, and only prefixes. Also tests that searchSessionsFiltered correctly restricts results to matching sessions. Fails because parseSearchQuery and searchSessionsFiltered are undefined.
Adds parseSearchQuery() that splits free text from project:/branch: prefixes. searchSessionsFiltered() runs linear-scan then post-filters by project/branch. FTS5 index hits are post-filtered the same way. Help overlay updated with syntax hint. Existing prefix-free queries are unchanged. Coverage 86.0%.
…FromJSONL Adds FuzzParseSessionMetadata in session_test.go and FuzzParseTurnsFromJSONL in detail_test.go, each seeded with valid and malformed JSONL inputs. 5-second local runs found no panics. CI fuzz job added to ci.yml as a non-blocking job (30s per target); promote to required after a week of green runs.
Adds v0.8 rows to the CLAUDE.md phasing table covering all 10 tasks (code split, background FTS5 sync, resume R key, LORE_CACHE_DIR, search prefixes, LORE_PRICING_FILE, nav() helper, fuzz CI, regression nets, and this docs commit). Bumps Version to "0.8.0". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Deletes ephemeral planning files that should not live in the repo. Updates DESIGN.md status banner to v0.8.0 and adds v0.8 rows to the phasing table; notes LORE_CACHE_DIR in the Phase 5a section. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…test -fuzz Co-Authored-By: Claude Sonnet 4.6 <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.
Summary
model.goandrender.gosplit into per-mode files (keys_*.go,render_*.go);nav()helper DRYs all cursor movement;ensureIndex()extracted as a method. Red:3c46c70/59d47b0, Green:27a91f7/c676458nav()helper (T7): 24-case table test drives the helper; all cursor handlers (including statsd/u) use it. Red:649c862, Green:771d70aensureIndex()(part of T1/T2): idempotent FTS5 open; skips if already open or indexing. Red:a769d96, Green:be5e8fbLORE_CACHE_DIRenv var (T4):resolveCacheDir()inlore.go;index.goandbookmark.goboth use it. Red:3da7c34, Green:627de11Rkey (T3):resumeClaude(id, cwd)viatea.ExecProcess;Rin list and detail modes; help overlay and footers updated. Red:07684bf, Green:82da093LORE_PRICING_FILEenv override (T6):go:embed pricing.json;sync.Onceloader with env override path. Red:c72219f, Green:842912dInit()returnstea.Batch(loadSessionsCmd, syncIndexCmd); list header showsindexing…while sync runs. Red:27142b1, Green:b2b4030parseSearchQuery()splitsproject:<name>/branch:<name>from free text; FTS5 results post-filtered; linear-scan pre-filtered. Red:67121d7, Green:61d4230FuzzParseSessionMetadata(5 seeds) andFuzzParseTurnsFromJSONL(6 seeds); non-blockingfuzzCI job runs each 30s. Red+Green:3a60459internal_split_test.go,internal_render_split_test.go,nav_test.goguard against dispatch regressions.Version = "0.8.0". Commit:5b3c86bTest plan
go test -race -cover ./...passes with ≥80% coverage per package (currently 86.2%)go vet ./...cleangofmt -l .cleantestjob passes (required)fuzzjob runs (non-blocking,continue-on-error: true)Rkey in list mode resumes the selected session viaclaude --resume <id>Rkey in detail mode resumes the current sessionindexing…briefly at startup while FTS5 sync runsproject:lore refresh tokenreturns only lore-project hitsLORE_CACHE_DIR=/tmp/test-lore ./lorewrites index and bookmarks to that dirLORE_PRICING_FILE=custom.json ./lore—Spanel uses custom rates🤖 Generated with Claude Code