Skip to content

feat(sync): worktree index mismatch detection — doctor check + MCP banner (closes #66 phase-4)#154

Merged
Wolfvin merged 1 commit into
mainfrom
feat/issue-66-worktree-mismatch-phase4
Jul 3, 2026
Merged

feat(sync): worktree index mismatch detection — doctor check + MCP banner (closes #66 phase-4)#154
Wolfvin merged 1 commit into
mainfrom
feat/issue-66-worktree-mismatch-phase4

Conversation

@Wolfvin

@Wolfvin Wolfvin commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Closes #66 (phase 4 only — phases 1, 2, 3, 5 remain open for other workers).

What

Add git worktree ↔ CodeLens index mismatch detection. When a user runs CodeLens inside a git worktree that does not have its own .codelens/ index, CodeLens's workspace auto-detection silently walks up and loads the main checkout's index — which was built from a different branch. Every subsequent query / trace / dataflow / taint answer is then grounded in the wrong file set, with no warning to the user or the agent.

Why

Issue #66 Phase 4 explicitly calls for this:

Worktree mismatch detection — detect git worktree nested inside main checkout. Walk-up resolves .codelens/ to parent main checkout (different branch). Warning in codelens status + banner on every MCP read tool response. Suggest codelens init -i in worktree.

This is a real correctness bug. A worktree user gets stale data with no indication anything is wrong.

How

New module scripts/sync/worktree.py with three public functions:

  • detect_worktree_index_mismatch(project_root) → structured record
  • format_worktree_warning(mismatch) → multi-line CLI warning
  • format_worktree_banner(mismatch) → single-line MCP banner

The detector shells out to git rev-parse --show-toplevel and git rev-parse --git-common-dir (max 2 subprocess calls per probe, 5s timeout each, never raises). Returns 5 reason codes:

Reason Mismatch Meaning
not_a_git_repo False git not installed, or workspace not under git
not_a_worktree False main checkout, no worktree concerns
worktree_has_own_index False worktree with its own .codelens/ (correct setup)
no_index_found False worktree, but no .codelens/ anywhere up the tree
worktree_uses_main_index True MISMATCH — worktree reading main's index

Wiring

codelens doctor — new check workspace.worktree_index_mismatch (status=warning on mismatch). Runs BEFORE _check_codelens_writable because the writable check creates .codelens/ as a side effect of probing write permissions, which would mask the mismatch.

MCP server — read-tool responses get a top-level _worktree_warning field when a mismatch is detected:

{
  "content": [...],
  "isError": false,
  "_worktree_warning": {
    "banner": "⚠️ WORKTREE INDEX MISMATCH: ...",
    "mismatch": { "mismatch": true, "reason": "worktree_uses_main_index", ... }
  }
}

Mutating commands (scan, init) skip the banner — they're the user's remediation path. The mismatch verdict is cached per workspace for the server's lifetime (probed once, reused). Cache is invalidated when scan runs (the user may have just run codelens init -i to fix the mismatch).

Why a top-level field, not a content prepend: Prepending text to the content array would corrupt the JSON payload agents parse out of the response. A top-level field keeps the JSON intact while still surfacing the warning prominently.

Critical implementation detail: early-probe

The mismatch detection runs BEFORE _execute_command, not after. Why: read commands like list / query trigger ensure_codelens_dir(workspace) as a side effect of loading the registry, which creates .codelens/ in the worktree. If we probed after execution, the worktree would appear to have its own index and the mismatch would never fire. Probing early caches the pre-execution state so the banner reflects what the user actually configured.

Tests

30 new tests across 3 files (all green):

  • tests/test_worktree.py (19 tests) — detector + formatters, covers all 5 reason codes plus robustness (None input, file path, empty string, subdirectory of worktree).
  • tests/test_doctor.py (6 new tests in TestWorktreeMismatchCheck class) — doctor integration, including an ordering test that enforces "mismatch check runs BEFORE writable check".
  • tests/test_mcp_hooks.py (5 new tests in TestWorktreeBannerAttachment class) — MCP integration, including cache-once-per-workspace and detection-never-breaks-tool-call contracts.

Test results

1404 passed, 76 skipped, 1 failed in 61.22s

The 1 failure is pre-existing and unrelated to this PR:

FAILED tests/test_codelensignore.py::TestBackwardCompat::test_actual_target_dir_is_ignored

This test was failing on origin/main before this branch was created.

Files

File Change
scripts/sync/__init__.py New — package marker with docstring
scripts/sync/worktree.py New — detector + formatters (330 lines)
scripts/commands/doctor.py Modified — added _check_worktree_mismatch, reordered _run_all_checks
scripts/mcp_server.py Modified — added _worktree_mismatch_cache, _get_worktree_mismatch, _attach_worktree_banner; wired into _handle_tools_call (read tools only)
tests/test_worktree.py New — 19 tests
tests/test_doctor.py Modified — added TestWorktreeMismatchCheck class (6 tests)
tests/test_mcp_hooks.py Modified — added TestWorktreeBannerAttachment class (5 tests)
CHANGELOG.md Updated — added [8.2.0] section for issue #66 Phase 4

Acceptance criteria (from issue #66)

  • Phase 4: worktree mismatch warning appears in codelens doctor output
  • Phase 4: banner attached to every MCP read tool response (as _worktree_warning field)
  • Phase 4: suggests codelens init -i in the worktree to build its own index

Out of scope (other phases of issue #66)

  • Phase 1: Per-file staleness banner (scripts/sync/pending.py)
  • Phase 2: Connect-time catch-up
  • Phase 3: Native file watcher (FSEvents/inotify/ReadDirectoryChangesW)
  • Phase 5: Anonymous opt-in telemetry

These phases remain open for other workers — the issue is not closed by this PR.

Findings

While implementing this, I noticed that _check_codelens_writable in doctor.py creates .codelens/ as a side effect of probing write permissions. This is intentional (it's the only way to verify write access), but it means any doctor check that depends on the pre-doctor state of .codelens/ must run BEFORE the writable check. The _check_worktree_mismatch check does this correctly, but future checks should be aware of this ordering constraint. I've added a comment in _run_all_checks documenting it.

…nner (closes #66 phase-4)

Add scripts/sync/worktree.py with detect_worktree_index_mismatch(),
format_worktree_warning(), and format_worktree_banner(). The detector
shells out to 'git rev-parse --show-toplevel' and 'git rev-parse
--git-common-dir' to identify worktrees, then walks up from the
project root to find the .codelens/ that CodeLens would actually load.

A mismatch is reported when:
  - workspace is a git worktree (worktree_root != main_checkout_root)
  - AND no .codelens/ exists in the worktree
  - AND a .codelens/ does exist in the main checkout

In that scenario CodeLens silently reads the main checkout's index —
which was built from a different branch. Every query/trace/dataflow
answer is then grounded in the wrong file set.

Wiring:
  - doctor: new check 'workspace.worktree_index_mismatch' (status=warning
    on mismatch). Runs BEFORE _check_codelens_writable because the
    writable check creates .codelens/ as a side effect, which would
    mask the mismatch.
  - mcp_server: read-tool responses get a top-level _worktree_warning
    field (banner + mismatch record) when a mismatch is detected.
    Mutating commands (scan, init) skip the banner. The mismatch
    verdict is cached per workspace (probed once, reused) and
    invalidated when scan runs.
  - The early-probe happens BEFORE _execute_command because read
    commands like 'list' / 'query' trigger ensure_codelens_dir()
    as a side effect of loading the registry.

Tests: 30 new tests across 3 files.
  - tests/test_worktree.py: 19 tests for the detector + formatters.
  - tests/test_doctor.py: 6 tests for the doctor integration,
    including an ordering test that enforces 'mismatch before writable'.
  - tests/test_mcp_hooks.py: 5 tests for the MCP integration,
    including cache-once-per-workspace and detection-never-breaks-tool-call.

Pre-existing failure unrelated to this PR:
  tests/test_codelensignore.py::TestBackwardCompat::test_actual_target_dir_is_ignored
  (was failing on origin/main before this branch)
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sonarqubecloud

sonarqubecloud Bot commented Jul 2, 2026

Copy link
Copy Markdown

@Wolfvin Wolfvin merged commit f3a1580 into main Jul 3, 2026
5 of 11 checks passed
@Wolfvin Wolfvin deleted the feat/issue-66-worktree-mismatch-phase4 branch July 3, 2026 02:14
Wolfvin added a commit that referenced this pull request Jul 3, 2026
Issue #66 Phase 1 — Per-file staleness banner. Detects when indexed
files have been edited since the last scan and surfaces a warning to
the agent before the tool's actual output.

New files:
- scripts/sync/__init__.py        — re-exports public API
- scripts/sync/pending.py         — StaleFileDetector (thread-safe,
                                    in-memory Dict[str, float] cache,
                                    5s TTL per workspace) +
                                    detect_stale_files() +
                                    format_staleness_banner()
- scripts/commands/staleness.py   — 'codelens staleness' CLI command
                                    (manual check + full list when MCP
                                    banner truncates to 10)
- tests/test_staleness.py         — 41 tests (detection, cache, thread
                                    safety, banner formatting, CLI,
                                    MCP integration)
- docs/sync/staleness-banner.md   — architecture + design decisions

Modified:
- scripts/mcp_server.py           — MCPServer._staleness_detector (lazy)
                                    + _attach_staleness_banner() prepends
                                    banner to read-tool responses
                                    (suppressed on scan/init) +
                                    _invalidate_staleness_cache() after
                                    successful scan
- README/SKILL/SKILL-QUICK/pyproject/skill.json/graph_model.py —
                                    sync'd via sync_command_count.py
                                    --apply (command count 70 -> 71)

Detection algorithm:
1. Load stored mtimes from .codelens/mtimes.json
2. For each indexed file: os.stat() compare (st_size, st_mtime_ns)
3. If mtime differs, re-compute SHA-256 (only when needed) to confirm
   content actually changed — skips false positives from  /
   M	README.md
M	SKILL-QUICK.md
M	SKILL.md
A	docs/sync/staleness-banner.md
M	pyproject.toml
A	scripts/commands/staleness.py
M	scripts/graph_model.py
M	scripts/mcp_server.py
A	scripts/sync/__init__.py
A	scripts/sync/pending.py
M	skill.json
A	tests/test_staleness.py of identical content
4. Sort by edit_age ascending (most recent edit first)
5. Return tuple of StaleFile records

Why mtimes.json (not SQLite files table) as source of truth?
  mtimes.json is written by every scan, including workspaces that use
  the legacy JSON registry (pre-v8.2). The SQLite files table is only
  populated when the persistent registry is active.

Cache: 5s TTL per workspace, thread-safe via threading.Lock. Invalidated
after successful scan so next read tool re-probes against fresh index.

Banner: plain text (not markdown), prepended to first content block's
text + structured response['_staleness'] field. Both paths ensure the
warning surfaces regardless of how agents consume tool output.

Verified:
- tests/test_staleness.py: 41 passed
- tests/test_staleness.py + test_command_count.py + test_doctor.py +
  test_cli.py + test_codelens.py + test_mcp_hooks.py: 220 passed
- sync_command_count.py --check: clean
- 'codelens staleness' smoke-tested end-to-end (text + json output)

Phase 2 (connect-time catch-up), Phase 3 (native file watcher),
Phase 5 (anonymous telemetry) deferred ke follow-up issues per issue
spec. StaleFileDetector cache + StaleFile data structure designed to
accommodate Phase 2 without API change.

Note: PR #154 (issue #66 Phase 4 — worktree mismatch) also creates
scripts/sync/__init__.py and modifies mcp_server.py. If that PR merges
first, this PR will need a small rebase to resolve the __init__.py
overlap (both add the same package marker) and the mcp_server.py
overlap (both add methods to MCPServer — different method names, no
conflict). BOS will resolve at merge time.
Wolfvin added a commit that referenced this pull request Jul 3, 2026
Issue #66 Phase 1 — Per-file staleness banner. Detects when indexed
files have been edited since the last scan and surfaces a warning to
the agent before the tool's actual output.

New files:
- scripts/sync/__init__.py        — re-exports public API
- scripts/sync/pending.py         — StaleFileDetector (thread-safe,
                                    in-memory Dict[str, float] cache,
                                    5s TTL per workspace) +
                                    detect_stale_files() +
                                    format_staleness_banner()
- scripts/commands/staleness.py   — 'codelens staleness' CLI command
                                    (manual check + full list when MCP
                                    banner truncates to 10)
- tests/test_staleness.py         — 41 tests (detection, cache, thread
                                    safety, banner formatting, CLI,
                                    MCP integration)
- docs/sync/staleness-banner.md   — architecture + design decisions

Modified:
- scripts/mcp_server.py           — MCPServer._staleness_detector (lazy)
                                    + _attach_staleness_banner() prepends
                                    banner to read-tool responses
                                    (suppressed on scan/init) +
                                    _invalidate_staleness_cache() after
                                    successful scan
- README/SKILL/SKILL-QUICK/pyproject/skill.json/graph_model.py —
                                    sync'd via sync_command_count.py
                                    --apply (command count 70 -> 71)

Detection algorithm:
1. Load stored mtimes from .codelens/mtimes.json
2. For each indexed file: os.stat() compare (st_size, st_mtime_ns)
3. If mtime differs, re-compute SHA-256 (only when needed) to confirm
   content actually changed — skips false positives from  /
   M	README.md
M	SKILL-QUICK.md
M	SKILL.md
A	docs/sync/staleness-banner.md
M	pyproject.toml
A	scripts/commands/staleness.py
M	scripts/graph_model.py
M	scripts/mcp_server.py
A	scripts/sync/__init__.py
A	scripts/sync/pending.py
M	skill.json
A	tests/test_staleness.py of identical content
4. Sort by edit_age ascending (most recent edit first)
5. Return tuple of StaleFile records

Why mtimes.json (not SQLite files table) as source of truth?
  mtimes.json is written by every scan, including workspaces that use
  the legacy JSON registry (pre-v8.2). The SQLite files table is only
  populated when the persistent registry is active.

Cache: 5s TTL per workspace, thread-safe via threading.Lock. Invalidated
after successful scan so next read tool re-probes against fresh index.

Banner: plain text (not markdown), prepended to first content block's
text + structured response['_staleness'] field. Both paths ensure the
warning surfaces regardless of how agents consume tool output.

Verified:
- tests/test_staleness.py: 41 passed
- tests/test_staleness.py + test_command_count.py + test_doctor.py +
  test_cli.py + test_codelens.py + test_mcp_hooks.py: 220 passed
- sync_command_count.py --check: clean
- 'codelens staleness' smoke-tested end-to-end (text + json output)

Phase 2 (connect-time catch-up), Phase 3 (native file watcher),
Phase 5 (anonymous telemetry) deferred ke follow-up issues per issue
spec. StaleFileDetector cache + StaleFile data structure designed to
accommodate Phase 2 without API change.

Note: PR #154 (issue #66 Phase 4 — worktree mismatch) also creates
scripts/sync/__init__.py and modifies mcp_server.py. If that PR merges
first, this PR will need a small rebase to resolve the __init__.py
overlap (both add the same package marker) and the mcp_server.py
overlap (both add methods to MCPServer — different method names, no
conflict). BOS will resolve at merge time.
Wolfvin added a commit that referenced this pull request Jul 3, 2026
Issue #66 Phase 1 — Per-file staleness banner. Detects when indexed
files have been edited since the last scan and surfaces a warning to
the agent before the tool's actual output.

New files:
- scripts/sync/__init__.py        — re-exports public API
- scripts/sync/pending.py         — StaleFileDetector (thread-safe,
                                    in-memory Dict[str, float] cache,
                                    5s TTL per workspace) +
                                    detect_stale_files() +
                                    format_staleness_banner()
- scripts/commands/staleness.py   — 'codelens staleness' CLI command
                                    (manual check + full list when MCP
                                    banner truncates to 10)
- tests/test_staleness.py         — 41 tests (detection, cache, thread
                                    safety, banner formatting, CLI,
                                    MCP integration)
- docs/sync/staleness-banner.md   — architecture + design decisions

Modified:
- scripts/mcp_server.py           — MCPServer._staleness_detector (lazy)
                                    + _attach_staleness_banner() prepends
                                    banner to read-tool responses
                                    (suppressed on scan/init) +
                                    _invalidate_staleness_cache() after
                                    successful scan
- README/SKILL/SKILL-QUICK/pyproject/skill.json/graph_model.py —
                                    sync'd via sync_command_count.py
                                    --apply (command count 70 -> 71)

Detection algorithm:
1. Load stored mtimes from .codelens/mtimes.json
2. For each indexed file: os.stat() compare (st_size, st_mtime_ns)
3. If mtime differs, re-compute SHA-256 (only when needed) to confirm
   content actually changed — skips false positives from  /
   M	README.md
M	SKILL-QUICK.md
M	SKILL.md
A	docs/sync/staleness-banner.md
M	pyproject.toml
A	scripts/commands/staleness.py
M	scripts/graph_model.py
M	scripts/mcp_server.py
A	scripts/sync/__init__.py
A	scripts/sync/pending.py
M	skill.json
A	tests/test_staleness.py of identical content
4. Sort by edit_age ascending (most recent edit first)
5. Return tuple of StaleFile records

Why mtimes.json (not SQLite files table) as source of truth?
  mtimes.json is written by every scan, including workspaces that use
  the legacy JSON registry (pre-v8.2). The SQLite files table is only
  populated when the persistent registry is active.

Cache: 5s TTL per workspace, thread-safe via threading.Lock. Invalidated
after successful scan so next read tool re-probes against fresh index.

Banner: plain text (not markdown), prepended to first content block's
text + structured response['_staleness'] field. Both paths ensure the
warning surfaces regardless of how agents consume tool output.

Verified:
- tests/test_staleness.py: 41 passed
- tests/test_staleness.py + test_command_count.py + test_doctor.py +
  test_cli.py + test_codelens.py + test_mcp_hooks.py: 220 passed
- sync_command_count.py --check: clean
- 'codelens staleness' smoke-tested end-to-end (text + json output)

Phase 2 (connect-time catch-up), Phase 3 (native file watcher),
Phase 5 (anonymous telemetry) deferred ke follow-up issues per issue
spec. StaleFileDetector cache + StaleFile data structure designed to
accommodate Phase 2 without API change.

Note: PR #154 (issue #66 Phase 4 — worktree mismatch) also creates
scripts/sync/__init__.py and modifies mcp_server.py. If that PR merges
first, this PR will need a small rebase to resolve the __init__.py
overlap (both add the same package marker) and the mcp_server.py
overlap (both add methods to MCPServer — different method names, no
conflict). BOS will resolve at merge time.
Wolfvin added a commit that referenced this pull request Jul 3, 2026
Issue #66 Phase 1 — Per-file staleness banner. Detects when indexed
files have been edited since the last scan and surfaces a warning to
the agent before the tool's actual output.

New files:
- scripts/sync/__init__.py        — re-exports public API
- scripts/sync/pending.py         — StaleFileDetector (thread-safe,
                                    in-memory Dict[str, float] cache,
                                    5s TTL per workspace) +
                                    detect_stale_files() +
                                    format_staleness_banner()
- scripts/commands/staleness.py   — 'codelens staleness' CLI command
                                    (manual check + full list when MCP
                                    banner truncates to 10)
- tests/test_staleness.py         — 41 tests (detection, cache, thread
                                    safety, banner formatting, CLI,
                                    MCP integration)
- docs/sync/staleness-banner.md   — architecture + design decisions

Modified:
- scripts/mcp_server.py           — MCPServer._staleness_detector (lazy)
                                    + _attach_staleness_banner() prepends
                                    banner to read-tool responses
                                    (suppressed on scan/init) +
                                    _invalidate_staleness_cache() after
                                    successful scan
- README/SKILL/SKILL-QUICK/pyproject/skill.json/graph_model.py —
                                    sync'd via sync_command_count.py
                                    --apply (command count 70 -> 71)

Detection algorithm:
1. Load stored mtimes from .codelens/mtimes.json
2. For each indexed file: os.stat() compare (st_size, st_mtime_ns)
3. If mtime differs, re-compute SHA-256 (only when needed) to confirm
   content actually changed — skips false positives from  /
   M	README.md
M	SKILL-QUICK.md
M	SKILL.md
A	docs/sync/staleness-banner.md
M	pyproject.toml
A	scripts/commands/staleness.py
M	scripts/graph_model.py
M	scripts/mcp_server.py
A	scripts/sync/__init__.py
A	scripts/sync/pending.py
M	skill.json
A	tests/test_staleness.py of identical content
4. Sort by edit_age ascending (most recent edit first)
5. Return tuple of StaleFile records

Why mtimes.json (not SQLite files table) as source of truth?
  mtimes.json is written by every scan, including workspaces that use
  the legacy JSON registry (pre-v8.2). The SQLite files table is only
  populated when the persistent registry is active.

Cache: 5s TTL per workspace, thread-safe via threading.Lock. Invalidated
after successful scan so next read tool re-probes against fresh index.

Banner: plain text (not markdown), prepended to first content block's
text + structured response['_staleness'] field. Both paths ensure the
warning surfaces regardless of how agents consume tool output.

Verified:
- tests/test_staleness.py: 41 passed
- tests/test_staleness.py + test_command_count.py + test_doctor.py +
  test_cli.py + test_codelens.py + test_mcp_hooks.py: 220 passed
- sync_command_count.py --check: clean
- 'codelens staleness' smoke-tested end-to-end (text + json output)

Phase 2 (connect-time catch-up), Phase 3 (native file watcher),
Phase 5 (anonymous telemetry) deferred ke follow-up issues per issue
spec. StaleFileDetector cache + StaleFile data structure designed to
accommodate Phase 2 without API change.

Note: PR #154 (issue #66 Phase 4 — worktree mismatch) also creates
scripts/sync/__init__.py and modifies mcp_server.py. If that PR merges
first, this PR will need a small rebase to resolve the __init__.py
overlap (both add the same package marker) and the mcp_server.py
overlap (both add methods to MCPServer — different method names, no
conflict). BOS will resolve at merge time.
Wolfvin added a commit that referenced this pull request Jul 3, 2026
Issue #66 Phase 1 — Per-file staleness banner. Detects when indexed
files have been edited since the last scan and surfaces a warning to
the agent before the tool's actual output.

New files:
- scripts/sync/__init__.py        — re-exports public API
- scripts/sync/pending.py         — StaleFileDetector (thread-safe,
                                    in-memory Dict[str, float] cache,
                                    5s TTL per workspace) +
                                    detect_stale_files() +
                                    format_staleness_banner()
- scripts/commands/staleness.py   — 'codelens staleness' CLI command
                                    (manual check + full list when MCP
                                    banner truncates to 10)
- tests/test_staleness.py         — 41 tests (detection, cache, thread
                                    safety, banner formatting, CLI,
                                    MCP integration)
- docs/sync/staleness-banner.md   — architecture + design decisions

Modified:
- scripts/mcp_server.py           — MCPServer._staleness_detector (lazy)
                                    + _attach_staleness_banner() prepends
                                    banner to read-tool responses
                                    (suppressed on scan/init) +
                                    _invalidate_staleness_cache() after
                                    successful scan
- README/SKILL/SKILL-QUICK/pyproject/skill.json/graph_model.py —
                                    sync'd via sync_command_count.py
                                    --apply (command count 70 -> 71)

Detection algorithm:
1. Load stored mtimes from .codelens/mtimes.json
2. For each indexed file: os.stat() compare (st_size, st_mtime_ns)
3. If mtime differs, re-compute SHA-256 (only when needed) to confirm
   content actually changed — skips false positives from  /
   M	README.md
M	SKILL-QUICK.md
M	SKILL.md
A	docs/sync/staleness-banner.md
M	pyproject.toml
A	scripts/commands/staleness.py
M	scripts/graph_model.py
M	scripts/mcp_server.py
A	scripts/sync/__init__.py
A	scripts/sync/pending.py
M	skill.json
A	tests/test_staleness.py of identical content
4. Sort by edit_age ascending (most recent edit first)
5. Return tuple of StaleFile records

Why mtimes.json (not SQLite files table) as source of truth?
  mtimes.json is written by every scan, including workspaces that use
  the legacy JSON registry (pre-v8.2). The SQLite files table is only
  populated when the persistent registry is active.

Cache: 5s TTL per workspace, thread-safe via threading.Lock. Invalidated
after successful scan so next read tool re-probes against fresh index.

Banner: plain text (not markdown), prepended to first content block's
text + structured response['_staleness'] field. Both paths ensure the
warning surfaces regardless of how agents consume tool output.

Verified:
- tests/test_staleness.py: 41 passed
- tests/test_staleness.py + test_command_count.py + test_doctor.py +
  test_cli.py + test_codelens.py + test_mcp_hooks.py: 220 passed
- sync_command_count.py --check: clean
- 'codelens staleness' smoke-tested end-to-end (text + json output)

Phase 2 (connect-time catch-up), Phase 3 (native file watcher),
Phase 5 (anonymous telemetry) deferred ke follow-up issues per issue
spec. StaleFileDetector cache + StaleFile data structure designed to
accommodate Phase 2 without API change.

Note: PR #154 (issue #66 Phase 4 — worktree mismatch) also creates
scripts/sync/__init__.py and modifies mcp_server.py. If that PR merges
first, this PR will need a small rebase to resolve the __init__.py
overlap (both add the same package marker) and the mcp_server.py
overlap (both add methods to MCPServer — different method names, no
conflict). BOS will resolve at merge time.
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.

[FEATURE] Telemetry, file watcher & worktree detection — observability + reliability

1 participant