Skip to content

Extract GlobalConfig store from WorktreeApi.fs#88

Open
0101 wants to merge 8 commits into
mainfrom
improvement-survey
Open

Extract GlobalConfig store from WorktreeApi.fs#88
0101 wants to merge 8 commits into
mainfrom
improvement-survey

Conversation

@0101

@0101 0101 commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Problem

src/Server/WorktreeApi.fs was the largest production module (870 lines) and mixed four concerns: machine-level config persistence, DashboardResponse projection, worktree actions, and IWorktreeApi wiring. Roughly 250 of those lines were the machine-level ~/.treemon/config.json read/modify/write store — and that concern already had its own test suites (ConfigWriterTests.fs, WorktreeRootsConfigTests.fs), so the boundary existed; the code just lived in the wrong module.

This is candidate #7 from the code-improvement survey on this branch (the same view/state extraction lens that drove the earlier App.fs work).

Changes

Behavior-preserving extraction — no config format, key semantics, locking, atomic-write, or IWorktreeApi response changes.

  • New src/Server/GlobalConfig.fs (263 L, module Server.GlobalConfig) — owns config.json: the single-serialized-writer lock + atomic temp-file-then-replace (updateConfigAtPath), the missing-vs-empty worktreeRoots semantics the startup resolver depends on, and the typed accessors (watched roots, canvas pane open/position, collapsed repos, last-viewed hashes, editor command/name). Module-private helpers stay private; the externally-consumed surface is internal.
  • src/Server/WorktreeApi.fs 870 → 605 lines — left with just IWorktreeApi wiring + DashboardResponse assembly, calling the moved functions via open Server.GlobalConfig.
  • src/Server/Server.fsprojGlobalConfig.fs compiles before WorktreeApi.fs.
  • Consumers retargeted in one atomic change (no compat shims): Program.fs (startup roots resolver) and the test files ConfigWriterTests.fs, WorktreeRootsConfigTests.fs, ServerStartupResolutionTests.fs, SmokeTests.fs.
  • Hardening (from focused review): updateConfigAtPath skips directory creation when the config path has no parent dir, rather than attempting-and-catching.
  • Docs kept honest: worktree-monitor.md gains a Configuration Store subsection + a GlobalConfig vs TreemonConfig decision and an updated Key Files table; code-improvements.md records the survey findings and moves Parallel startup burst + fix branch event key mismatch #7 to Done.

Tests

Full suite green on the final commit (independently re-run by the verification reviewer):

  • Build: 0 errors / 0 warnings
  • Unit: 845 / 845
  • Fast: 959 / 959
  • E2E: 342 / 342 (1 pre-existing data-conditional skip, orthogonal to this change)
  • Structural: GlobalConfig.fs holds the moved symbols; the moved definitions are gone from WorktreeApi.fs (proving a move, not a copy); line count dropped ~265.

A focused-review quality gate ran over the branch diff (19 rules + 3 concern models) — 2 actionable findings, both fixed in this PR; the rest were verbatim-move/pre-existing false-positives.

0101 added 8 commits June 23, 2026 15:59
Concretize candidate #5 (survey large modules) into two evidence-backed splits: extract a GlobalConfig store from WorktreeApi.fs (#7) and split the DashboardState slice / CanvasWatchers out of RefreshScheduler.fs (#8). Note that strict-FP smells are already clean.
Planning spec for code-improvement candidate #7: lift the ~250-line machine-level config.json read/modify/write block out of WorktreeApi.fs into a dedicated Server.GlobalConfig module. Behavior-preserving; atomic move with all consumers retargeted (no compat shims).
…retarget all consumers

Extract machine-level config.json I/O from WorktreeApi.fs into new Server.GlobalConfig module (263 lines); retarget all consumers (Program.fs 3 refs, 4 test files) in one atomic change with no compat shims. WorktreeApi.fs 870->614 lines.
…tion

Docs-only spec hygiene after the GlobalConfig extraction:
- worktree-monitor.md Key Files: add GlobalConfig.fs row (config.json store +
  typed accessors), retarget WorktreeApi.fs row to IWorktreeApi wiring +
  DashboardResponse assembly.
- code-improvements.md: move candidate #7 to Done with one-line summary + spec
  link; fix the now-dangling row-5 cross-reference; keep #8's stable ID.
…-monitor parent spec (spec-hygiene)

Folded the durable config-store invariants (single serialized writer + atomic temp-file replace, never-destroy-data/corrupt-backup, typed accessors over one store) into worktree-monitor.md Expected Behavior and added a GlobalConfig vs TreemonConfig Decisions bullet. Deleted the stale extraction-plan spec global-config-store.md and repointed the code-improvements.md Done entry. Sibling task Spec: pointers retargeted in beads.
…path with no parent directory (defensive, Low)

Added a
ot (String.IsNullOrEmpty dir) guard so directory creation is skipped (rather than attempted-and-caught) when the config path has no parent directory. Trigger is unreachable for current callers; defensive hardening only per focused-review finding 2.
Copilot AI review requested due to automatic review settings June 26, 2026 15:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extracts the machine-level configuration store (~/.treemon/config.json read/modify/write) out of the oversized WorktreeApi.fs into a new dedicated src/Server/GlobalConfig.fs module. It is a behavior-preserving refactor — the config format, locking, atomic-write semantics, missing-vs-empty worktreeRoots distinction, and IWorktreeApi responses are unchanged. It fits the codebase's ongoing "view/state extraction" effort (candidate #7 from the code-improvement survey) by separating config persistence from IWorktreeApi wiring and DashboardResponse assembly.

Changes:

  • New GlobalConfig.fs owning config.json (single-writer lock, atomic temp-file replace, typed accessors); moved symbols widened from private to internal so cross-module call sites resolve.
  • WorktreeApi.fs slimmed (~870 → 605 lines) to API wiring + DashboardResponse, now open Server.GlobalConfig; Server.fsproj compiles GlobalConfig.fs before WorktreeApi.fs.
  • Consumers retargeted with no compat shims: Program.fs plus tests (ConfigWriterTests, WorktreeRootsConfigTests, ServerStartupResolutionTests, SmokeTests); a small updateConfigAtPath hardening (skip dir creation when the path has no parent); docs updated.
Show a summary per file
File Description
src/Server/GlobalConfig.fs New module owning config.json; moved accessors/writers, now internal; adds empty-dir guard in updateConfigAtPath
src/Server/WorktreeApi.fs Removes the config block, adds open Server.GlobalConfig; call sites use unqualified moved functions
src/Server/Server.fsproj Adds GlobalConfig.fs to compile order before WorktreeApi.fs
src/Server/Program.fs Retargets globalConfigDir/tryReadWorktreeRootsConfig/writeWorktreeRoots to GlobalConfig
src/Tests/ConfigWriterTests.fs open switched to Server.GlobalConfig
src/Tests/WorktreeRootsConfigTests.fs open switched to Server.GlobalConfig
src/Tests/ServerStartupResolutionTests.fs Qualified refs switched to Server.GlobalConfig
src/Tests/SmokeTests.fs Comment updated to reference GlobalConfig.globalConfigDir
docs/spec/worktree-monitor.md Adds Configuration Store section, Key Files rows, and GlobalConfig vs TreemonConfig decision
docs/spec/future/code-improvements.md Records survey findings; moves #7 to Done (one inaccurate line count)

Review details

  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Medium

- **`GlobalConfig` store extraction** — lifted the machine-level `~/.treemon/config.json`
read/modify/write (single-writer lock, atomic temp-file replace, missing-vs-empty
`worktreeRoots` semantics, plus the canvas / collapsed-repos / last-viewed-hashes / editor
accessors) out of `WorktreeApi.fs` (870 → 614 L) into `src/Server/GlobalConfig.fs`, leaving the
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.

2 participants