docs: map existing codebase
This commit is contained in:
250
.planning/codebase/CONCERNS.md
Normal file
250
.planning/codebase/CONCERNS.md
Normal file
@@ -0,0 +1,250 @@
|
||||
# Codebase Concerns
|
||||
|
||||
**Analysis Date:** 2026-03-27
|
||||
|
||||
## Silent Error Handling (Critical)
|
||||
|
||||
**Widespread use of empty catch blocks:**
|
||||
- Files: `/.claude/hooks/gsd-prompt-guard.js`, `/.claude/hooks/gsd-context-monitor.js`, `/.claude/hooks/gsd-workflow-guard.js`, `/.claude/hooks/gsd-statusline.js`, `/.claude/hooks/gsd-check-update.js`
|
||||
- Issue: 14+ catch blocks across hooks swallow errors silently with `catch (e) {}` or `catch (e) { // comment }` without logging
|
||||
- Impact: Failures in hook execution go undetected, making debugging difficult. When files are corrupted, config fails to parse, or file system errors occur, no indication is provided to users or developers
|
||||
- Current mitigation: Comments explain intent (e.g., "Silent fail -- bridge is best-effort", "don't break statusline on parse errors"), but no logging mechanism exists
|
||||
- Recommendation: Implement optional debug logging to stderr (only when hooks are invoked in debug mode) without breaking normal operation. Use environment variable like `GSD_HOOK_DEBUG=1` to enable error logging
|
||||
|
||||
---
|
||||
|
||||
## Fragile Hook Timeout Architecture
|
||||
|
||||
**Context-Monitor Hook (`.claude/hooks/gsd-context-monitor.js`)**:
|
||||
- Issue: 10-second stdin timeout (line 35) is tight for slow systems. On Windows/Git Bash, pipe delays can exceed this
|
||||
- Files: `/.claude/hooks/gsd-context-monitor.js` (line 35: `setTimeout(() => process.exit(0), 10000)`)
|
||||
- Current mitigation: Comments reference issues #775, #1162 indicating this was a known problem
|
||||
- Risk: On systems with slow I/O, the hook exits prematurely without reading input, potentially leaving metrics unprocessed
|
||||
- Safe modification: Consider detecting platform and adjusting timeout accordingly, or make timeout configurable via environment variable
|
||||
|
||||
---
|
||||
|
||||
## Hardcoded Buffer Percentage
|
||||
|
||||
**Status Line Hook Context Normalization**:
|
||||
- Issue: 16.5% buffer hardcoded for Claude Code autocompact (line 29)
|
||||
- Files: `/.claude/hooks/gsd-statusline.js` (line 29: `const AUTO_COMPACT_BUFFER_PCT = 16.5`)
|
||||
- Impact: If Claude Code changes autocompact behavior or other models have different buffers, context calculations become inaccurate
|
||||
- Recommendation: Make this configurable via `.planning/config.json` with sensible defaults per model (Claude, Gemini, OpenCode)
|
||||
|
||||
---
|
||||
|
||||
## Stale Hook Version Tracking
|
||||
|
||||
**Hook Version Header Validation**:
|
||||
- Issue: Version detection depends on comment headers in JavaScript files (line 78 in `gsd-check-update.js`)
|
||||
- Files: `/.claude/hooks/gsd-check-update.js` (lines 73-92)
|
||||
- Risk: If hook files are minified, reformatted, or copied incorrectly, version headers can be lost, making stale hook detection fail silently
|
||||
- Current state: Detects "unknown" version if header is missing, but this doesn't prevent the hook from running with wrong version
|
||||
- Recommendation: Add a checksum or content hash validation in addition to version headers to detect unintended hook modifications
|
||||
|
||||
---
|
||||
|
||||
## Process Detachment on Windows
|
||||
|
||||
**Check-Update Hook Background Process**:
|
||||
- Issue: Uses `spawn()` with `detached: true` (line 111 in `gsd-check-update.js`)
|
||||
- Files: `/.claude/hooks/gsd-check-update.js` (lines 108-114)
|
||||
- Impact: Background npm process can hang on Windows if not properly detached. Blocks are prevented by `unref()` (line 114), but edge cases remain if process fails
|
||||
- Current state: `windowsHide: true` flag added, `stdio: 'ignore'` set
|
||||
- Recommendation: Add timeout to background spawn, return immediately after unref, and consider writing to log file instead of silently ignoring errors
|
||||
|
||||
---
|
||||
|
||||
## Config File Parsing Without Validation
|
||||
|
||||
**Multiple Hooks Read `.planning/config.json`**:
|
||||
- Issue: Config files are parsed with `JSON.parse()` but no schema validation exists
|
||||
- Files: `/.claude/hooks/gsd-context-monitor.js` (line 53), `/.claude/hooks/gsd-workflow-guard.js` (line 65)
|
||||
- Risk: Malformed JSON or missing expected fields cause silent failures. If config structure changes, old configs won't error but silently ignore new fields
|
||||
- Recommendation: Implement a simple schema validation utility (even lightweight: check for required keys and types) and log warnings when config doesn't match expected shape
|
||||
|
||||
---
|
||||
|
||||
## Race Conditions in Metrics Bridge
|
||||
|
||||
**Context Metrics Between Statusline and Monitor Hooks**:
|
||||
- Issue: Two separate hooks read/write to `/tmp/claude-ctx-{sessionId}.json` without file locking
|
||||
- Files: `/.claude/hooks/gsd-statusline.js` (line 40-47 writes), `/.claude/hooks/gsd-context-monitor.js` (line 63-70 reads)
|
||||
- Risk: On high-frequency tool use, write and read can race, causing monitor hook to read stale metrics or corrupted JSON
|
||||
- Current mitigation: Both have try-catch around JSON.parse(), stale metrics are detected by timestamp (line 74)
|
||||
- Recommendation: Use atomic writes (write-to-temp-then-rename pattern) for metrics file, or switch to a simpler shared state mechanism
|
||||
|
||||
---
|
||||
|
||||
## Missing Logging Infrastructure
|
||||
|
||||
**No Structured Logging**:
|
||||
- Issue: Hooks only log to stdout via process.stdout.write() for hook outputs. No persistent logs for troubleshooting
|
||||
- Files: All hook files (`/.claude/hooks/*.js`)
|
||||
- Impact: When hooks fail silently, no audit trail exists to debug issues. Users cannot see what hooks detected or why they exited
|
||||
- Recommendation: Create optional debug logs in `.planning/hooks-debug.log` (only when env var `GSD_DEBUG=1`), append structured JSON records with timestamp, hook name, and outcome
|
||||
|
||||
---
|
||||
|
||||
## Unbounded Memory in Warning State File
|
||||
|
||||
**Context Monitor Warning Debounce**:
|
||||
- Issue: Warning state tracked in `/tmp/claude-ctx-{sessionId}-warned.json` accumulates indefinitely
|
||||
- Files: `/.claude/hooks/gsd-context-monitor.js` (lines 87-117)
|
||||
- Risk: Temporary directory might not clean this up, causing stale state from previous sessions to affect new sessions
|
||||
- Current mitigation: State is per-session (uses sessionId), so scope is limited
|
||||
- Recommendation: Add timestamp to warning state and treat state older than 1 hour as stale (auto-reset)
|
||||
|
||||
---
|
||||
|
||||
## Regex Pattern Complexity in Prompt Guard
|
||||
|
||||
**Prompt Injection Detection Patterns**:
|
||||
- Issue: 12 regex patterns for injection detection (lines 18-32 in `gsd-prompt-guard.js`) are not anchored and may be fragile
|
||||
- Files: `/.claude/hooks/gsd-prompt-guard.js` (lines 18-32)
|
||||
- Risk: Some patterns (e.g., `/you\s+are\s+now\s+/i`) could match benign documentation text about "You are now ready to..." and trigger false warnings
|
||||
- Impact: While warnings are advisory-only, frequent false positives degrade user experience
|
||||
- Recommendation: Review patterns for false positive risk, consider context (e.g., only in code blocks, not in comments), or add allowlist for common false positives
|
||||
|
||||
---
|
||||
|
||||
## Inconsistent Hook Version Across Environments
|
||||
|
||||
**Multi-Environment Hook Duplication**:
|
||||
- Issue: Identical hooks duplicated across `.claude/`, `.agent/`, `.gemini/`, `.opencode/` directories
|
||||
- Files: 4x each of `gsd-prompt-guard.js`, `gsd-context-monitor.js`, `gsd-workflow-guard.js`, `gsd-statusline.js`, `gsd-check-update.js`
|
||||
- Risk: If one environment's hooks are updated, others can drift out of sync. Version check in `gsd-check-update.js` detects this (line 81-82) but doesn't auto-fix
|
||||
- Impact: Users with multiple agent environments may see inconsistent behavior
|
||||
- Recommendation: Consolidate hooks to a shared location or implement auto-sync mechanism in installer
|
||||
|
||||
---
|
||||
|
||||
## Resource Leaks in Timeouts
|
||||
|
||||
**Stdin Timeout Cleanup**:
|
||||
- Issue: `setTimeout()` created for stdin timeout in all hooks, relies on `clearTimeout()` to clean up
|
||||
- Files: `/.claude/hooks/gsd-prompt-guard.js`, `/.claude/hooks/gsd-context-monitor.js`, `/.claude/hooks/gsd-workflow-guard.js`, `/.claude/hooks/gsd-statusline.js`
|
||||
- Risk: If process exits before reaching `process.stdin.on('end')`, timeout continues running until expiry (3-10 seconds)
|
||||
- Current state: Process exits on timeout with code 0, but spawned processes inherit this timeout
|
||||
- Recommendation: Add `unref()` call on timeout timers so they don't keep process alive
|
||||
|
||||
---
|
||||
|
||||
## Platform-Specific Path Separator
|
||||
|
||||
**Windows Path Handling in Guards**:
|
||||
- Issue: Guards check for both `/` and `\\` in file paths (e.g., line 52 in `gsd-prompt-guard.js`)
|
||||
- Files: `/.claude/hooks/gsd-prompt-guard.js` (line 52), `/.claude/hooks/gsd-workflow-guard.js` (line 43)
|
||||
- Risk: Mixing separators when checking `.planning/` paths may not catch all variations on Windows (e.g., mixed slashes)
|
||||
- Recommendation: Normalize paths using `path.normalize()` before comparison, or use `path.sep` for platform detection
|
||||
|
||||
---
|
||||
|
||||
## Missing Config Directory Override Documentation
|
||||
|
||||
**CLAUDE_CONFIG_DIR Environment Variable**:
|
||||
- Issue: Support for `CLAUDE_CONFIG_DIR` environment variable is implemented (line 18 in `gsd-check-update.js`, line 73 in `gsd-statusline.js`) but not documented
|
||||
- Files: `/.claude/hooks/gsd-check-update.js` (line 18), `/.claude/hooks/gsd-statusline.js` (line 73)
|
||||
- Impact: Users with custom config directories won't know this variable exists, potentially breaking hook functionality
|
||||
- Recommendation: Document in copilot-instructions.md or add reference in hook comments
|
||||
|
||||
---
|
||||
|
||||
## Temporary File Cleanup Strategy
|
||||
|
||||
**Metric Files Never Cleaned**:
|
||||
- Issue: `/tmp/claude-ctx-{sessionId}.json` and `/tmp/claude-ctx-{sessionId}-warned.json` are never deleted
|
||||
- Files: `/.claude/hooks/gsd-statusline.js` (writes), `/.claude/hooks/gsd-context-monitor.js` (reads)
|
||||
- Risk: On long-running systems, /tmp fills up with stale session files
|
||||
- Recommendation: Implement cleanup logic to delete temp files older than 7 days, or hook into session cleanup to delete files on logout
|
||||
|
||||
---
|
||||
|
||||
## Package.json Missing Dependencies
|
||||
|
||||
**Minimal Configuration**:
|
||||
- Issue: `.claude/package.json` only contains `{"type":"commonjs"}`, no dependencies listed
|
||||
- Files: `/.claude/package.json`
|
||||
- Risk: Hooks use built-in Node modules (fs, path, os, child_process), so this is correct, but appears incomplete
|
||||
- Current state: This is intentional (all hooks use only Node builtins), but unclear to maintainers
|
||||
- Recommendation: Add comment in package.json explaining that hooks intentionally use no external dependencies for portability
|
||||
|
||||
---
|
||||
|
||||
## Potential Memory Bloat in Large Outputs
|
||||
|
||||
**No Stream Processing in Hooks**:
|
||||
- Issue: All hooks read entire stdin into memory before processing (`let input = ''; process.stdin.on('data', chunk => input += chunk)`)
|
||||
- Files: All hook files
|
||||
- Risk: If a tool call writes gigabytes of content (e.g., massive file read), the hook process could run out of memory
|
||||
- Current mitigation: Only tool writes/edits are inspected, and these are typically small
|
||||
- Recommendation: For hooks processing large content (especially prompt injection guard), implement streaming regex matching or line-by-line processing
|
||||
|
||||
---
|
||||
|
||||
## Test Coverage Gaps
|
||||
|
||||
**No Unit Tests for Hooks**:
|
||||
- What's not tested: None of the 5 hook files have automated tests
|
||||
- Files: `/.claude/hooks/*.js` (all of them)
|
||||
- Risk: Changes to hook logic have no regression protection. Timeout tweaks, path logic, or regex patterns could break without detection
|
||||
- Impact: Hook failures are silent (by design), so broken hooks go unnoticed until users report issues
|
||||
- Priority: High — hooks are critical path for agent context management
|
||||
|
||||
---
|
||||
|
||||
## Missing Error Recovery in Executor
|
||||
|
||||
**Deviation Rule Priority Conflicts**:
|
||||
- Issue: Executor auto-applies Rules 1-3 without clear priority when multiple rules could apply
|
||||
- Files: `/.github/agents/gsd-executor.agent.md` (line 150 mentions "RULE PRIORITY:")
|
||||
- Risk: When a task has multiple issues (e.g., bug AND missing critical functionality), executor might fix bug first, missing that missing-function blocking task completion
|
||||
- Recommendation: Clarify priority order: blocking issues (Rule 3) > missing critical functionality (Rule 2) > bugs (Rule 1)
|
||||
|
||||
---
|
||||
|
||||
## Subprocess Error Propagation in Background Checks
|
||||
|
||||
**npm view Command Failure Silent**:
|
||||
- Issue: `execSync('npm view get-shit-done-cc version')` wrapped in try-catch, timeout 10s (line 96 in `gsd-check-update.js`)
|
||||
- Files: `/.claude/hooks/gsd-check-update.js` (lines 95-97)
|
||||
- Risk: If npm is not installed, offline, or slow, fails silently. Users won't know update check failed
|
||||
- Impact: Latest version is set to "unknown", update check becomes unreliable
|
||||
- Recommendation: Log to file when update check fails (optional debug log), or retry with exponential backoff
|
||||
|
||||
---
|
||||
|
||||
## Missing Instrumentation for Decision Points
|
||||
|
||||
**No Audit Trail for Hook Decisions**:
|
||||
- Issue: When context monitor injects critical warning or workflow guard injects advisory, no record of decision
|
||||
- Files: `/.claude/hooks/gsd-context-monitor.js` (lines 125-142), `/.claude/hooks/gsd-workflow-guard.js` (lines 78-87)
|
||||
- Risk: If user behavior doesn't match warning, no way to audit what warning was shown or when
|
||||
- Recommendation: Write decision logs to `.planning/hooks-audit.log` with timestamp, hook name, decision, and reason (only in GSD active mode)
|
||||
|
||||
---
|
||||
|
||||
## Scalability of Hook Frequency
|
||||
|
||||
**Hooks Run on Every Tool Use**:
|
||||
- Issue: Context monitor (PostToolUse) runs after EVERY tool call, reads file, parses JSON, checks thresholds
|
||||
- Files: `/.claude/hooks/gsd-context-monitor.js`
|
||||
- Risk: On high-frequency tool sessions (100+ tools), accumulated overhead could impact performance
|
||||
- Current mitigation: Debounce warnings (line 108), stale metric detection (line 74)
|
||||
- Recommendation: Profile hook execution time under load, consider batching metrics or reducing check frequency
|
||||
|
||||
---
|
||||
|
||||
## Unclear Behavior on Missing Files
|
||||
|
||||
**Graceful Degradation Assumptions**:
|
||||
- Issue: When `.planning/STATE.md`, `.planning/config.json`, or todo files don't exist, hooks silently skip functionality
|
||||
- Files: All hooks that check for optional files
|
||||
- Risk: Unclear to users whether missing files are "normal" or indicate misconfiguration
|
||||
- Example: Statusline shows "no task" if todos not found, but user might think todos are lost
|
||||
- Recommendation: Distinguish between "feature not enabled" (e.g., no .planning/ = not a GSD project) vs. "feature broken" (e.g., config.json exists but unparseable)
|
||||
|
||||
---
|
||||
|
||||
*Concerns audit: 2026-03-27*
|
||||
Reference in New Issue
Block a user