Skip to content

Worktree Change Inspection

Kwt has a local Git change engine for the transport-neutral Go inspection service and the focused kwt changes command. It remains deliberately separate from the lightweight status collector used by list, TUI, and fleet surfaces. This note records the ownership and correctness boundaries between them.

Shared core

internal/status owns local Git change facts. CollectChanges performs one bounded git status --porcelain=v2 -z --untracked-files=all read and produces:

  • NUL-delimited per-path index and working-tree states without a secondary line or whitespace delimiter;
  • deterministic path ordering and original paths for renames and copies;
  • mutually exclusive modified, added, deleted, untracked, and conflict counts;
  • an orthogonal staged count that excludes unmerged index slots; and
  • overall clean, modified, staged, or conflicted precedence.

The collector disables optional index writes, fixes the Git locale, bounds stdout and stderr independently, and removes Kwt-protected credentials from the Git process environment. Protected names include both Kwt's built-ins and the effective global fleet.token_env value. Unknown NUL-framed porcelain records are skipped for forward compatibility; malformed recognized records still fail the snapshot. Compatible records with the same resulting path are coalesced into one file entry while preserving independent index, worktree, and original-path fields; incompatible duplicates fail the snapshot.

The Git adapter limits stdout and stderr to 1 MiB each. If an exact change list exceeds the stdout limit, inspection never returns a partial snapshot. Its safe public message is worktree change list is too large to inspect; the original limit error remains available only to the in-process caller.

The module root aliases these values and InspectionService, so an in-process consumer can use the same contract without Cobra, HTTP, or daemon ownership.

Exact identity and generation fence

An inspection begins with current authoritative repository inventory for the requested absolute path. Exactly one platform-canonical path must match, and its repository identity, path, and durable generation must be complete. Optional expected repository and generation values are compare-and-fail guards, not selectors.

The service reads the durable generation from Git administration immediately before and after collecting changes. A missing, moved, removed, or replaced worktree returns retryable registration_changed and discards the file snapshot. The fence prevents pairing a replacement checkout's files with an older inventory identity. It does not claim branch or HEAD atomicity; the result is a bounded local status observation. One five-second Git-operation budget covers the pre-read, status collection, and post-read together. Git process cleanup adds at most 100 milliseconds if a descendant retains an output descriptor. Exhausting the internal budget returns retryable inspection_failed; caller cancellation remains the caller's context error.

CLI boundary

kwt changes [path] resolves the caller's literal path to an absolute path and adapts InspectionService. The same-machine daemon supplies current inventory, but the generation reads and Git status process stay in the invoking foreground client. This preserves the foreground process's cancellation and credential boundary while keeping the daemon free of status polling or file snapshots.

Human output is for direct inspection. The JSON InspectionResult is the stable machine contract: authoritative worktree identity, canonical change summary, deterministic file records, and observation time. Clean results retain an explicit empty files array. JSON losslessly represents valid UTF-8 path strings, including embedded whitespace and newlines; it cannot preserve an ill-formed UTF-8 Unix filename byte-for-byte. Stable failures use the shared service error envelope; prose messages are not part of the machine contract.

Trust model

Ordinary Git inspection after checkout is inside Kwt's accepted local-user trust boundary. Repository content remains data, while trusted machine-level Git configuration may influence Git just as it does for a direct user command. The inspection process does not expose Kwt-managed credentials, enable optional index writes, approve repository-local Kwt configuration, or persist its result. The foreground client requires config-bearing inventory, and the inspection service fails closed before Git when effective configuration is absent. Inventory ignores untrusted repository-local Kwt configuration for this noninteractive read.

Native path comparison is platform-aware: existing symlink aliases converge on Unix-like systems, and Windows comparison normalizes separators and case. Kwt does not return a platform-specific unsupported result for inspection.

Status collector boundary

StatusCollector retains its own one-shot porcelain-v2 snapshot, parser, summary accounting, bounded workers, per-row diagnostics, remote state, and activity calculation. Filtering, sorting, CSV, table, JSON, TUI, and fleet responsibilities remain on their established paths and retain their schemas. Detailed file records and the inspection service's semantic buckets are not added to those surfaces.

The only shared integration is process isolation: every Git command owned by StatusCollector receives the same built-in and configured protected-name set from the CLI, TUI, or fleet caller. This keeps credentials out of foreground and long-lived inventory processes without changing status accounting or TUI presentation.

Non-goals

Change inspection does not:

  • fetch remotes or calculate ahead/behind state or activity;
  • calculate diff, numstat, patches, or file contents;
  • mutate the index or worktree;
  • discover or batch sibling worktrees;
  • watch, poll, cache, or persist change snapshots;
  • move Git status ownership into the daemon;
  • depend on tmux or workspace-session state; or
  • introduce consumer-specific types or presentation policy.