Render uncommitted (dirty) changes + live-refresh the whole scene (#74)#111
Merged
Conversation
…#74) Adds the pydantic + TypedDict + TS fields, bumps the manifest cache schema to v16, and updates the hand-authored fixtures the new required fields touch (test_models.py, EMPTY_REPO_STATS, and frontend FileNode literals) so the suite stays green even though the scanner doesn't set `dirty` yet (Task A3).
Threads the dirty-paths set (Task A1's _collect_dirty_paths) from scan_tree through _build_tree into _file_node, which stamps FileNode.dirty and overrides `modified` to the working-tree mtime for dirty files (their git-history date is stale by definition).
compute_repo_stats now counts file nodes with dirty === true (media included) into RepoStats.dirtyFileCount, alongside the existing one-pass superlative accumulation.
Collapse _collect_repo_info to a single `git status --porcelain -z` call, returning the dirty-path set alongside RepoInfo so scan_tree no longer walks it twice; the signature-scan path just discards the set. Also moves test_scan_dirty.py's mid-file imports to the top (E402) and documents that a dirty file's `modified` is always the working-tree filesystem date, regardless of git history.
…e test (#74) Sort children by path before walking in computeLayoutSignature, mirroring compute_tree_signature's defensive sort in scan.py, so the hash is deterministic regardless of manifest child order. Also add a test proving the signature reflects the path SET, not just per-file size/date.
The layout-reuse gate keyed on tree_signature (paths + nesting only), so a live content edit that changes a file's size (no rename) was wrongly treated as a no-op and reused the frozen layout — streets/positions never re-solved. Swap the gate to compare computeLayoutSignature (structure + per-file size) of the new manifest against the committed one; a size change now bumps structureRevision (full re-pack), a dates-only change still reuses. applyManifestScenic.test.ts's manifest fixture lacked a `path` on its tree root; computeLayoutSignature walks the tree (unlike the old string-field compare) and needs it, so add it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ture, layout-sig media dims, stale comments, perf) (#74) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…er (#74) The right-sidebar file preview fetched content in an effect keyed only on fullPath, so a live edit to the still-selected file left stale content until a re-select. Thread the file's mtime through fileUrl/fetchFileText/fetchFileBytes as a cache-busting version param and add it to the preview effect deps, so text, font, and media previews (and the README pane) refresh on save. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rnaries (#74) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
#74) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…anup (#74) Co-Authored-By: Claude Sonnet 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e_signature (#74) Clarify the three-signature ladder on the manifest wire format: the bare `signature` field (mtime/size/dirty/repo fingerprint) is easily confused with `tree_signature`/`layout_signature`. Rename to `content_signature` and `structure_signature` respectively, document the ladder at the Manifest model/type, and bump the manifest cache schema version since the field rename changes the cached shape.
Co-Authored-By: Claude Fable 5 <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.
Closes #74.
Two workstreams under one theme: the city reflects your working tree live.
A — Dirty changes in the scan (backend)
Previously codecity rendered git's committed snapshot, so a file you'd edited but not committed showed its last-commit date, which drives building brightness: freshly-edited work rendered dim/stale, the opposite of reality. And nothing flagged which buildings were dirty.
git status --porcelain -zit already runs into a dirty-path set (single call; tracked paths that differ from HEAD, staged or unstaged; untracked/ignored excluded).modifieddate is overridden to its working-tree mtime, so it renders at its true recency (bright) through the existing brightness encoding.createdis untouched.FileNode.dirty: boolandRepoStats.dirtyFileCount: int(Pydantic + TypedDict + generated + hand TS; cache schema bumped 15→16; the dirty-path set is folded into the scan signature so per-file dirty transitions invalidate the cache).Enumeration is unchanged (
git ls-files): genuinely untracked files stay invisible until yougit addor ignore them.B — Live-refresh the whole scene on content edits (frontend)
With live updates on, a content edit kept the layout-reuse fast path (keyed on structure-only
tree_signature), which froze building positions and never rebuilt streets, and the right-sidebar panes read a stale picker snapshot.MANIFESTby path (newfindNodeByPath), so they refresh regardless of the picker snapshot.Behavior changes worth calling out
repo.dirtynarrowed: a repo dirty only with untracked files now reports clean (was: any porcelain output). No consumer relied on the old meaning; it removes a spurious re-scan on untracked-file creation and matches "untracked files are invisible."Non-goals (possible follow-ups)
Untracked-file rendering; a per-building dirty highlight/outline; per-dirty-file landmarks in the almanac; a per-file "uncommitted changes" line in the FileInfoPane.
Testing
just test-api(294),just test-app(2606),just lint,just gen-types(no-op) all green; layout golden bench byte-identical. Built TDD across 11 commits with per-task review and a whole-branch review.To try it: open a local repo with uncommitted changes vs. a clean/remote one, live updates on; edit a tracked file and watch its building brighten + the scene re-pack, the almanac count appear, and the selection pane refresh.
🤖 Generated with Claude Code