singularity-forge/src
deseltrus f90c83460f fix(gsd): harden auto-mode telemetry — metrics idempotency, elapsed guard, title sanitization (#1722)
Four fixes for auto-mode telemetry and display bugs:

1. Metrics idempotency guard (metrics.ts)
   - snapshotUnitMetrics now deduplicates entries by type+id+startedAt
   - Prevents idle-watchdog from creating N duplicate entries per unit
   - On duplicate: updates existing entry in-place instead of appending
   - Observed: 31 duplicate entries for a single plan-slice unit

2. Elapsed time zero-guard (auto.ts, auto-dashboard.ts, dashboard-overlay.ts)
   - getAutoDashboardData guards against autoStartTime=0 (uninitialized)
   - formatAutoElapsed rejects negative, NaN, and >30-day values
   - Dashboard overlay adds 30-day sanity check before formatting
   - Observed: dashboard showed '492804h' (Date.now() - 0)

3. Em/en-dash title auto-fix (doctor.ts)
   - Doctor now sanitizes em/en dashes in milestone H1 titles when fix=true
   - Replaces Unicode dashes with ASCII hyphens in the roadmap file
   - Prevents state document delimiter ambiguity
   - delimiter_in_title issues are now marked fixable=true

4. Tests for all three fix areas
   - Metrics: idempotency guard, simulated watchdog duplicate pattern
   - Dashboard: negative/NaN autoStartTime handling
   - Doctor: em-dash auto-fix with fix=true and fix=false verification

Root cause analysis:
- The idle watchdog (auto-timers.ts) calls closeoutUnit every 15s when
  idle is detected. closeoutUnit calls snapshotUnitMetrics which blindly
  appended to ledger.units. Each watchdog tick created a new entry with
  identical type/id/startedAt but incremented finishedAt.
- autoStartTime defaults to 0 in the session class. If getAutoDashboardData
  is called before auto-start sets the value, elapsed = Date.now() - 0.
- Milestone titles with em-dashes (U+2014) are written by the LLM during
  roadmap creation and never sanitized, causing permanent doctor warnings.
2026-03-21 08:47:27 -06:00
..
resources fix(gsd): harden auto-mode telemetry — metrics idempotency, elapsed guard, title sanitization (#1722) 2026-03-21 08:47:27 -06:00
tests fix(search): keep loop guard armed after firing to prevent infinite loop restart (#1671) (#1674) 2026-03-21 08:35:48 -06:00
app-paths.ts feat: add GSD_HOME env var to override global ~/.gsd directory (#1566) 2026-03-20 08:29:01 -06:00
bundled-extension-paths.ts Fix packaging verification and path portability (#378) 2026-03-14 12:28:14 -06:00
bundled-resource-path.ts M001: The Minimal Machine — linear auto-loop, sole-authority state, sidecar queue, WorktreeResolver (#1419) 2026-03-19 14:56:00 -06:00
cli.ts feat: feat(ui): minimal GSD welcome screen on startup (#1584) 2026-03-20 08:11:06 -06:00
extension-discovery.ts fix: apply pi manifest opt-out to extension-discovery.ts (#1545) 2026-03-20 08:11:51 -06:00
extension-registry.ts feat: add GSD_HOME env var to override global ~/.gsd directory (#1566) 2026-03-20 08:29:01 -06:00
headless-answers.ts refactor(headless): remove duplicate jsonLine, use serializeJsonLine from pi-coding-agent (#1039) 2026-03-17 18:35:00 -06:00
headless-context.ts refactor(headless): split 772-line god file into events, UI, and context modules (#1047) 2026-03-17 18:36:20 -06:00
headless-events.ts refactor(headless): split 772-line god file into events, UI, and context modules (#1047) 2026-03-17 18:36:20 -06:00
headless-query.ts M001: The Minimal Machine — linear auto-loop, sole-authority state, sidecar queue, WorktreeResolver (#1419) 2026-03-19 14:56:00 -06:00
headless-ui.ts refactor(headless): split 772-line god file into events, UI, and context modules (#1047) 2026-03-17 18:36:20 -06:00
headless.ts fix: increase headless new-milestone timeout and limit investigation scope (#1230) 2026-03-18 13:54:34 -06:00
help-text.ts feat: add -w/--worktree CLI flag for isolated worktree sessions (#1247) 2026-03-18 14:57:25 -06:00
loader.ts feat: add extension manifest + registry for user-managed enable/disable (#1238) 2026-03-18 14:12:19 -06:00
logo.ts fix: abort squash-merge on conflict and stop auto-mode instead of looping (#merge-bug-fix) 2026-03-12 15:32:39 -06:00
mcp-server.ts feat: add VS Code extension scaffold and MCP server compiled module 2026-03-16 16:46:20 -05:00
models-resolver.ts refactor: remove unnecessary 'as any' casts, dead exports, and duplicate code (#786) 2026-03-16 21:47:04 -06:00
onboarding.ts feat: add anthropic-vertex provider for Claude on Vertex AI (#1533) 2026-03-19 23:14:13 -06:00
pi-migration.ts Merge pull request #151 from dbachelder/fix/pi-provider-reuse-and-extension-loading 2026-03-12 22:25:15 -06:00
remote-questions-config.ts feat: add GSD_HOME env var to override global ~/.gsd directory (#1566) 2026-03-20 08:29:01 -06:00
resource-loader.ts fix: remove duplicate TUI header rendered on session_start (#1663) 2026-03-21 08:34:18 -06:00
startup-timings.ts Improve startup performance with lazy extension loading (#1336) 2026-03-19 07:38:50 -06:00
tool-bootstrap.ts M001: The Minimal Machine — linear auto-loop, sole-authority state, sidecar queue, WorktreeResolver (#1419) 2026-03-19 14:56:00 -06:00
update-check.ts feat: add /gsd update slash command for in-session self-update (#964) 2026-03-17 16:13:02 -06:00
update-cmd.ts feat: add gsd update subcommand for self-update 2026-03-13 18:47:33 -03:00
welcome-screen.ts fix(splash): replace box corners with full-width bars for visual unity with auto-mode widget (#1654) 2026-03-20 15:42:18 -06:00
wizard.ts fix: Phase 1 quick wins — bug fixes, security hardening, and performance 2026-03-16 13:18:02 -05:00
worktree-cli.ts M001: The Minimal Machine — linear auto-loop, sole-authority state, sidecar queue, WorktreeResolver (#1419) 2026-03-19 14:56:00 -06:00
worktree-name-gen.ts feat: add -w/--worktree CLI flag for isolated worktree sessions (#1247) 2026-03-18 14:57:25 -06:00