Skip to content

refactor(git): kolu-git owns the resolve+watch compose loop#613

Merged
srid merged 1 commit intomasterfrom
refactor/git-subscribe-extraction
Apr 17, 2026
Merged

refactor(git): kolu-git owns the resolve+watch compose loop#613
srid merged 1 commit intomasterfrom
refactor/git-subscribe-extraction

Conversation

@srid
Copy link
Copy Markdown
Member

@srid srid commented Apr 17, 2026

The git integration now owns its resolve + .git/HEAD watch + re-resolve loop as a single subscribeGitInfo(cwd, onChange) => {setCwd, stop} export from kolu-git. The server's meta/git.ts shrinks to a thin adapter that wires the cwd: channel into watcher.setCwd and forwards onChange to the metadata publish + git: channel fan-out.

This closes the last remaining slice of item 4 in #601 — the companion piece to #603's AgentProvider unification. Before this, kolu-git exposed pure primitives (resolveGitInfo, watchGitHead, hasGitDir, gitInfoEqual) that the server composed by hand into a stateful reconcile loop, while the agent integrations had already been standardized behind a single contract. The compose loop was integration-domain logic leaking into a server adapter.

AgentProvider deliberately stays different from subscribeGitInfo — agents have a first-class session-identity axis (replace the watcher when sessionKey changes) that git doesn't have, so a unified ValueWatcher<Deps, Output> would be false reuse. A focused Hickey+Lowy review (re-run on the concrete sketch before implementation) both landed on this conclusion.

Behavior-preserving. No schema changes, no user-visible output changes, no e2e-contract changes. The adapter's onChange fires exactly when the old server code would have published. meta/github.ts is untouched — its lastBranch/lastRepoRoot dedup uses a narrower equality key than gitInfoEqual (branch+repoRoot vs branch+repoRoot+worktreePath), so the cache still earns its keep.

hasGitDir-based git init detection moves inside subscribeGitInfo — the server no longer imports it. All four existing primitives stay exported for tests and future consumers; the extraction is purely additive at the public-API layer.

Try it locally

nix run github:juspay/kolu/refactor/git-subscribe-extraction

Move the combined "resolve, watch .git/HEAD, re-resolve on change, dedup
via gitInfoEqual" loop out of `server/src/meta/git.ts` and into
`kolu-git` as a new `subscribeGitInfo(cwd, onChange) => {setCwd, stop}`
export. The server file is now a thin adapter wiring the `cwd:` channel
to `watcher.setCwd` and forwarding `onChange` to `trackRecentRepo` +
`updateServerMetadata` + `publishForTerminal("git", …)`.

Closes item 4 (remainder) of #601. Companions the #603 agent-integration
unification — kolu-git was the last integration with its compose loop
leaked out into the server. `AgentProvider` stays unchanged; git has no
session-identity axis, so a narrower cwd-driven shape is the honest
contract (per focused hickey+lowy review).

hasGitDir-based `git init` detection moves inside `subscribeGitInfo`;
server no longer imports it. `meta/github.ts` is untouched — its
lastBranch/lastRepoRoot dedup uses a narrower equality than gitInfoEqual
(branch+repoRoot vs branch+repoRoot+worktreePath) so the cache still
earns its keep.

No behavior change. Zero public-API removal (resolveGitInfo,
watchGitHead, gitInfoEqual, hasGitDir all stay exported for tests and
future consumers).
@srid
Copy link
Copy Markdown
Member Author

srid commented Apr 17, 2026

Hickey/Lowy Analysis

Two parallel reviews were run during the planning phase (on the concrete sketch), with both landing on ship as planned.

Hickey: the extraction is a net simplification — one compose loop, one module owns it. Notes two follow-up candidates (not in scope here): (F1) dissolve the null → non-null HEAD-watcher-restart rule by making watchGitHead self-manage via a .git-appearance poll, and (F2) decouple "cwd changed" from "git initialized" as independent signals. Both would further collapse the accidental-complexity surface around git-init detection. Filed-forward candidates; this PR intentionally preserves those rules verbatim.

Lowy: subscribeGitInfo correctly encapsulates git's volatility axes (cwd-driven re-resolution as the sequence axis, HEAD-watch mechanism as the activity axis). The contract insulates the server from a future inotify-backed watchGitHead swap. The AgentProvider/subscribeGitInfo asymmetry is justified — session-identity is a real axis for agents that git doesn't have; collapsing them would be false reuse. Initial concern about hasGitDir leaking into the server was resolved by re-reading the sketch (it's already inside subscribeGitInfo).

Both "Fix in this PR" actions were verified in the diff: hasGitDir lives inside subscribeGitInfo; server adapter doesn't import it. Deferred F1/F2 remain candidates for a future pass.

@srid
Copy link
Copy Markdown
Member Author

srid commented Apr 17, 2026

/do results

Step Status Duration Verification
sync 1s git fetch ok; forge=github; noGit=false
research 2m 2s confirmed Option B plan; meta/git.ts consumers: resolveGitInfo/watchGitHead/gitInfoEqual/hasGitDir; meta/github.ts dedup stays (branch+repoRoot is narrower than gitInfoEqual's branch+repoRoot+worktreePath)
hickey+lowy 2m 20s both reviewers: ship as planned. Hickey flagged F1/F2 (dissolve null→non-null restart rule via self-polling watchGitHead) as deferrable follow-ups. Lowy misread — hasGitDir already planned inside subscribeGitInfo.
branch 3s on branch refactor/git-subscribe-extraction
implement 40s added subscribeGitInfo to kolu-git (~60 LOC); rewrote meta/git.ts as thin adapter (~50 LOC, down from ~100)
check 10s pnpm typecheck clean across 10 projects
docs 19s kolu-git README updated with subscribeGitInfo in modules table and refreshed server-integration section
police 1m 38s all 3 passes clean; hickey/lowy in-scope findings addressed (hasGitDir moved inside subscribeGitInfo)
fmt 7s fmt applied table realignment in kolu-git README; no other changes
commit 24s commit c5b420b pushed; branch refactor/git-subscribe-extraction tracks origin
test 47s 18 scenarios / 214 steps passed (git-context, cwd, recent-repos, worktree)
create-pr 59s PR #613 opened as draft; hickey/lowy analysis posted as comment
ci 2m 22s all 10 contexts green on c5b420b
Total 14m 36s

Slowest step: ci (2m 22s)

Optimization suggestions

  • ci is dominated by the two e2e jobs (67s linux + 81s darwin, running in parallel). Both are at steady-state; no CI-side speedup available. For retry-only cases, /do --from ci-only skips everything up to ci.
  • hickey+lowy ran 2m 20s in parallel — that's the floor for two full structural reviews. A second round on the implementation diff would be cheap to skip if the planning-phase findings have already been addressed (as they were here).
  • police took 1m 38s for a ~170-LOC diff with zero findings. For pure-refactor PRs with tight scope, consider trusting the planning-phase review and running police only after implement (not as a separate skill invocation).
  • research (2m 2s) spent most of its time re-reading files already read in the earlier talk-mode turn. Pre-loading the talk-mode findings into the research prompt would trim this.

Workflow completed at 2026-04-17.

@srid srid marked this pull request as ready for review April 17, 2026 21:35
@srid srid merged commit 34b4d7f into master Apr 17, 2026
12 checks passed
@srid srid deleted the refactor/git-subscribe-extraction branch April 17, 2026 21:35
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.

1 participant