Files
msd-core/gsd-core/references/planner-gap-closure.md
Tom Boucher c9a5cc3e12 fix(#4683): detect cross-plan threat-ID duplicates before execution (#4828)
admin_reason: missing-secondary-reviewer — self-authored overnight sweep; two orthogonal agent reviews ran (isolated adversarial REQUEST-CHANGES with all six findings dispositioned, plus a bypass/consumer-lens APPROVE) and the sha-pinned bench passed 46362/0 on the merged head.
2026-09-17 19:06:55 -04:00

2.8 KiB

Gap Closure Mode — Planner Reference

Triggered by --gaps flag. Creates plans to address verification or UAT failures.

Important: Skip deferred items. When reading VERIFICATION.md, only the gaps: section contains actionable items that need closure plans. The deferred: section (if present) lists items explicitly addressed in later milestone phases — these are NOT gaps and must be ignored during gap closure planning. Creating plans for deferred items wastes effort on work already scheduled for future phases.

1. Find gap sources:

Use init context (from load_project_state) which provides phase_dir:

# Check for VERIFICATION.md (code verification gaps)
ls "$phase_dir"/*-VERIFICATION.md 2>/dev/null

# Check for UAT.md with diagnosed status (user testing gaps)
grep -l "status: diagnosed" "$phase_dir"/*-UAT.md 2>/dev/null

2. Parse gaps: Each gap has: truth (failed behavior), reason, artifacts (files with issues), missing (things to add/fix).

3. Load existing SUMMARYs to understand what's already built.

4. Find next plan number: If plans 01-03 exist, next is 04.

5. Group gaps into plans by: same artifact, same concern, dependency order (can't wire if artifact is stub → fix stub first).

6. Create gap closure tasks:

<task name="{fix_description}" type="auto">
  <files>{artifact.path}</files>
  <action>
    {For each item in gap.missing:}
    - {missing item}

    Reference existing code: {from SUMMARYs}
    Gap reason: {gap.reason}
  </action>
  <verify>{How to confirm gap is closed}</verify>
  <done>{Observable truth now achievable}</done>
</task>

7. Assign waves using standard dependency analysis (same as assign_waves step):

  • Plans with no dependencies → wave 1
  • Plans that depend on other gap closure plans → max(dependency waves) + 1
  • Also consider dependencies on existing (non-gap) plans in the phase

8. Write PLAN.md files:

---
phase: XX-name
plan: NN              # Sequential after existing
type: execute
wave: N               # Computed from depends_on (see assign_waves)
depends_on: [...]     # Other plans this depends on (gap or existing)
files_modified: [...]
autonomous: true
gap_closure: true     # Flag for tracking
---

9. Number threat IDs after the phase's existing registers (#4683): when security_enforcement is on, read the <threat_model> blocks of the phase's existing PLAN files and continue after their highest T-{phase}-NN — do not renumber from T-{phase}-01. Every ID already names a specific threat in an earlier plan; reusing it makes SECURITY.md rows and VALIDATION.md's Threat Ref column ambiguous. T-{phase}-SC is reserved and every plan keeps it. The execute-phase init reports any cross-plan duplicates and hard-stops on them (threat_id_duplicates), so a collision surfaces here as a failed plan check.