`_deriveStateImpl` (used when no gsd.db exists) lacked the SUMMARY-based
reconciliation added to `deriveStateFromDb` in 0e7a01f4. Heading-style
tasks (`### T01:`) are always parsed as `done=false` by `parsePlan`
because the heading syntax has no checkbox. When the agent writes a
SUMMARY file but the plan heading has no checkbox, the task appears
incomplete forever, causing infinite re-dispatch.
Now checks each non-done task for a SUMMARY file on disk after
`parsePlan()`, mirroring the DB reconciliation logic.
Root cause: `parsePlan()` recognizes two task formats:
1. `- [x] **T01: Title**` → done from checkbox state
2. `### T01: Title` → always done=false (no checkbox to read)
The DB path (deriveStateFromDb) was already fixed in 0e7a01f4 to
reconcile via SUMMARY files. This commit applies the same fix to
the filesystem path used by projects without gsd.db.
Consolidate two separate imports from files.js into one to resolve
TS2300 duplicate identifier error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MilestoneRow and SliceRow interfaces don't have index signatures,
so they can't be assigned to Record<string, unknown>. Using
Record<string, any> allows the helper to accept any typed row object.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract syncDirFiles() helper to eliminate duplicated iterate/filter/copy/catch
logic across three directory levels (milestone root, slices, tasks). Reduces
maximum nesting depth from 4 to 2.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ErrorContext interface to UnitResult so error information (provider
errors, timeouts, idle watchdog kills) is no longer discarded at the
resolve boundary. The four call sites that previously threw away context
now attach typed error metadata with category, message, and transience.
Downstream consumers (stuck detection in phases.ts, journal unit-end
events) use the structured errorContext field directly instead of
fragile regex heuristics on message content.
The same ~20-line cleanup sequence (merge abort / squash msg unlink /
hard reset) appeared twice in reconcileMergeState(). Extract into a
private abortAndResetMerge() helper to eliminate the duplication.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deduplicate near-identical "has any non-empty field" checks for milestone
and slice planning state into a shared hasNonEmptyFields() helper with
field-name arrays, reducing 8 repeated String(row.field||"").trim() calls
to 2 declarative one-liners.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each health check function (git, runtime, global, engine) moves to its
own file with only the imports it needs. doctor-checks.ts becomes a
re-export barrel for backward compatibility.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Embed 6 new quality questions (Q3-Q8) into the GSD lifecycle so
consumer projects get adversarial, failure, load, and operational
coverage by default. All sections are opt-out ("OMIT ENTIRELY") for
simple slices.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract verdict extraction, normalization, and schema validation into a
single verdict-parser.ts module. This fixes inconsistent normalization
where `passed` was normalized to `pass` in state.ts but not in
auto-dispatch.ts or auto-prompts.ts, and centralizes scattered verdict
schema definitions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Consolidate all worktree sync, resource staleness, stale worktree escape,
and stale runtime unit cleanup into auto-worktree.ts. Extract shared
ROOT_STATE_FILES constant and isSamePath helper to eliminate triple
duplication of the rootFiles array and copy-pasted symlink checks.
Replace inline 26-line stale-unit cleanup in auto-start.ts with a call
to cleanStaleRuntimeUnits().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove duplicate resolveExpectedArtifactPath() and diagnoseExpectedArtifact()
from auto-recovery.ts, making auto-artifact-paths.ts the single source of truth.
auto-recovery.ts re-exports both functions for backward compatibility.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
guided-flow.ts has its own local implementation; the exported version
in auto-recovery.ts was never imported anywhere. Removes 35 lines of
dead code, the unused clearUnitRuntimeRecord import, and associated
tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
session-forensics.ts is a general-purpose JSONL parser that had a direct
import of getAutoWorktreePath from auto-worktree.ts, creating tight
coupling. getDeepDiagnostic now accepts an optional worktreePath parameter
instead of resolving it internally. The caller (auto.ts) resolves the
worktree path via readActiveMilestoneId + getAutoWorktreePath and passes
it in.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove basePath and unitId from RunVerificationGateOptions — they were
defined in the interface and passed by callers but never read by
runVerificationGate(). This eliminates false coupling where callers
compute values that have zero effect.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete unused resource-version.ts (functions duplicated in auto-worktree-sync.ts
with zero imports). Remove GitServiceImpl.git() private method with no call sites.
Clean up orphaned section headers and dangling JSDoc in git-service.ts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SLICE_BRANCH_RE, QUICK_BRANCH_RE, and WORKFLOW_BRANCH_RE were scattered
across worktree.ts and git-service.ts. Extract all three into
branch-patterns.ts as the single source of truth. Both original modules
re-export for backward compatibility — no consumer changes needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The lock acquisition had a primary path and a retry path with identical
28-line onCompromised callbacks and 6-line state assignment blocks (68 lines
of copy-paste). Extract into createLockCompromisedHandler() and
assignLockState() helpers so bug fixes only need to be applied once.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The doctor-environment and doctor-git tests used assertTrue and assertEq
which are not defined — they should be assert.ok and assert.equal from
the imported node:assert/strict module.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These test files imported `assert` from node:assert/strict but used
assertTrue/assertEq (from test-helpers.ts createTestContext) without
importing them, breaking typecheck:extensions on main and all PRs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The GSD extension only listened for session_start, not session_switch.
When /resume switched to a previous session, GSD's write-gate, loop guard,
discussion flow, service tier, and tool API keys were never re-initialized,
leaving GSD in stale state from the prior session.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the free-form parameter listing in step 7 of complete-milestone.md
with structured, typed parameter definitions that match the tool schema in
db-tools.ts. Parameters are grouped into required and optional sections with
explicit types (marking arrays as arrays, booleans as booleans) to prevent
LLM validation failures when calling gsd_complete_milestone.
Fixes#2581
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>