Skip to content

feat: 5-layer defense against worktree isolation type divergence#18

Open
andyzengmath wants to merge 61 commits intomasterfrom
ql/progressive-materialization
Open

feat: 5-layer defense against worktree isolation type divergence#18
andyzengmath wants to merge 61 commits intomasterfrom
ql/progressive-materialization

Conversation

@andyzengmath
Copy link
Owner

Summary

  • Problem: Parallel worktree execution causes type divergence (70% of post-merge issues), destructive merges (20%), and as any bypasses (10%) because isolated agents cannot see each other's work. Documented in the March 18 post-mortem.
  • Solution: 5-layer Progressive Materialization defense system — prevention (L1+L2), resolution (L3), and detection (L4+L5) with a self-healing feedback loop.
  • Scope: 22 stories, 5,144 lines across 13 files, 191 passing tests.

The 5 Layers

Layer What File
L1: Structural contracts ql-plan generates type shapes + definitions, not just names skills/ql-plan/SKILL.md, references/contract-shapes.md
L2: Contract materialization Writes real interface files before each wave so agents can import them lib/materialize.sh (new, 541 lines)
L3: Merge conflict escalation Fails story on conflict instead of silent data loss lib/monitor.sh (enhanced)
L4: Post-merge typecheck gate Runs project-wide typecheck after each merge, reverts on regression lib/monitor.sh (new function)
L5: Wave-end type audit Grep-based duplicate scan → agent consolidation → feedback to L2 lib/type-audit.sh (new, 365 lines), agents/type-auditor.md (new)

Key Design Decisions

  • Language-agnostic from day one — auto-detects TS/Python/Go from project files
  • Escalate-on-conflict — fails stories on merge conflict instead of smart merging; retry with full context
  • Self-healing feedback loop — L5 discovers missed types at wave-end, L2 materializes them for the next wave
  • Backward compatible — all new quantum.json fields are optional; existing files work unchanged

Test plan

  • 73 tests for lib/materialize.sh (detect_language, infer_shared_types_dir, generate_definition_file, materialize_contracts)
  • 14 tests for merge escalation (lib/monitor.sh)
  • 21 tests for typecheck gate (lib/monitor.sh)
  • 83 tests for type audit (lib/type-audit.sh)
  • All 191 tests passing
  • End-to-end validation on a real project with deliberate type divergence traps

🤖 Generated with Claude Code

andyzengmath and others added 30 commits March 18, 2026 17:11
…nership fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ontracts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ation

# Conflicts:
#	skills/ql-plan/SKILL.md
…ns()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ation

# Conflicts:
#	lib/materialize.sh
#	tests/test_materialize.sh
…baseline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… feedback loop

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
andyzengmath and others added 29 commits March 18, 2026 17:42
…ion_file()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d typecheck gate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ation

# Conflicts:
#	lib/materialize.sh
#	tests/test_merge_escalation.sh
#	tests/test_typecheck_gate.sh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ation

# Conflicts:
#	tests/test_materialize.sh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… Python patterns

- C-1: Add @DataClass pattern to grep_duplicate_definitions() for Python support
- C-2: audit_wave_types() accepts base_sha parameter instead of hardcoded HEAD~1
- I-1: Language-aware error counting in post_merge_typecheck() (TS/Py/Go patterns)
- I-2: generate_definition_file() falls back to infer_shared_types_dir() when no definitionFile
- I-3: Python typecheck auto-detect checks config files before command availability
- I-4: update_contracts_for_next_wave() includes consumers field for L5→L2 feedback
- S-2: Go code generation infers package name from definitionFile path
- S-5: Step 4C pseudocode uses dict assignment (shared_types is object, not array)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e, shell quality

- CRITICAL: Sanitize typecheckCommand against shell metacharacters before bash -c
- Spec (US-006): Add definitionFile extension hint to detect_language() for multi-config repos
- Spec (US-010): Fix skip log message format to match PRD specification
- Important: generate_definition_file() outputs written path so inferred files get committed
- Important: Check git revert exit code, log CRITICAL on failure instead of || true
- Important: Use stashed=false pattern for revert stash logic (matches merge_worktree_branch)
- Important: Replace unquoted for-loops with while-read for safe whitespace handling
- Important: Use write_quantum_json() from json-atomic.sh instead of manual tmp+mv

All 191 tests pass (73 materialize + 14 merge + 21 typecheck + 83 type-audit).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical fixes from Soliton PR review:
- Replace typecheckCommand denylist with allowlist + array execution (no bash -c)
- Add path traversal validation for definitionFile (reject ".." patterns)
- Add --no-ff to merge_worktree_branch() + verify merge commit before revert

Important fixes:
- Baseline write uses write_quantum_json() instead of manual tmp+mv
- Check write_quantum_json() return value in materialize_contracts()
- Python error count: head -1 → tail -1 (use final summary, not per-file)
- printf '%b' → '%s' for definition content (no escape interpretation)
- Initialize tc_exit=0 explicitly
- Add json-atomic.sh to monitor.sh Requires header

Test additions:
- 6 injection tests for typecheckCommand (semicolon, pipe, redirect, backtick, newline, valid)
- 2 path traversal tests for definitionFile

All 206 tests pass (76 + 14 + 33 + 83).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@andyzengmath
Copy link
Owner Author

Soliton PR Review — ql/progressive-materialization

Risk Score: 53/100 (MEDIUM) | 16 files | 6,533 additions | AI-Authored: HIGH

Agents Dispatched

correctness, security, consistency, test-quality (4/4 completed)

Findings Summary

14 findings: 3 critical, 8 improvements, 3 nitpicks

Critical Issues (all fixed in 07704f2)

  1. 🔴 [security] Command injection via typecheckCommandlib/monitor.sh:248
    Denylist regex missed redirect operators, newlines, brace expansion. Zero test coverage for the rejection path.
    Fix: Replaced denylist with allowlist of known-safe prefixes + array-based execution (no bash -c). Added 6 injection tests.

  2. 🔴 [security] Path traversal via definitionFilelib/materialize.sh:130-196
    definitionFile from quantum.json used in mkdir -p + file write with no validation that path stays within repo root.
    Fix: Added .. pattern rejection + resolved path validation. Added 2 path traversal tests.

  3. 🔴 [correctness] git revert -m 1 fails on non-merge commitslib/monitor.sh:325-337
    merge_worktree_branch() could fast-forward (no merge commit), making the revert silently fail.
    Fix: Added --no-ff to merge + parent count check before revert + canonical argument order.

Important Fixes (also in 07704f2)

  • Baseline write now uses write_quantum_json() instead of manual tmp+mv
  • write_quantum_json() return value checked in materialize_contracts()
  • Python error count: head -1tail -1 (final summary, not per-file count)
  • printf '%b''%s' (no escape sequence interpretation on agent content)
  • tc_exit initialized to 0 explicitly
  • Header comment lists json-atomic.sh in Requires

Test Results After Fixes

Suite Tests
test_materialize.sh 76/76 ✅
test_merge_escalation.sh 14/14 ✅
test_typecheck_gate.sh 33/33 ✅
test_type_audit.sh 83/83 ✅
Total 206/206 ✅

Notable Outside-PR-Scope Findings

  • quantum-loop.sh:555testCommand executed via eval with zero sanitization (same threat model as typecheckCommand)
  • lib/spawn.sh:97 — agents spawned with --dangerously-skip-permissions (architectural risk)

Strengths

  • Comprehensive test coverage (206 tests for ~1,100 lines of production shell code)
  • Consistent atomic JSON writes via write_quantum_json()
  • Safe file generation (refuses to overwrite existing files with different content)
  • Clean 5-layer composition with correctly wired L5→L2 feedback loop
  • Defensive input validation on all public functions

🤖 Reviewed by Soliton PR Review (correctness + security + consistency + test-quality)

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.

1 participant