Skip to content

feat(hooks,agents): SDD discipline gate -- AGENTS.md rule + SessionStart nudge (SDD-001)#49

Merged
mlorentedev merged 1 commit into
mainfrom
feat/SDD-001-discipline-gate
May 18, 2026
Merged

feat(hooks,agents): SDD discipline gate -- AGENTS.md rule + SessionStart nudge (SDD-001)#49
mlorentedev merged 1 commit into
mainfrom
feat/SDD-001-discipline-gate

Conversation

@mlorentedev
Copy link
Copy Markdown
Owner

@mlorentedev mlorentedev commented May 18, 2026

Summary

Tier 1+2 of a 5-layer enforcement stack instituted after a 2026-05-18 session audit found that BUG-002 (#47) and BUG-003 (#48) bypassed the SDD vault gate and spec scaffold despite meeting the trigger criteria. The discipline existed in pattern-spec-driven-development.md but was opt-in.

  • Tier 1: New ### Discipline Gate (NON-NEGOTIABLE) subsection in AGENTS.md under the existing ## Spec-Driven Development section. Trigger criteria, mandatory ordered process, banned-phrases list for vault-hygiene "later" promises.
  • Tier 2: Both SessionStart hooks (.ps1 + .sh) inject a [sdd] reminder at the START of additionalContext, unconditional, byte-anchored across OS. Refactors the claude-mem heal block to use the defensive append pattern (was an overwrite, would have wiped the reminder).

Eat-our-dog-food

This PR adds the discipline AND follows it from the first commit:

  • Vault entry: 10_projects/dotfiles/11-tasks.md SDD-001-discipline-gate (added in catch-up vault hygiene this session)
  • Spec scaffold: specs/SDD-001-discipline-gate/{proposal,tasks,verification}.md via init-spec.ps1 (vault gate passed)
  • TDD: bats tests (tests/agents-md.bats, tests/hooks.bats) written before implementation
  • Smoke: empirical green on this machine (output captured in verification.md)

Why three PRs instead of one mega-PR

Per pattern-spec-driven-development.md "one spec = one atomic PR":

  • This PR (SDD-001): Tier 1 + Tier 2 -- the rule and the per-session nudge. They are coherent (one references the other).
  • SDD-002 (next): Tier 3 -- track ~/.claude/settings.json in dotfiles for hook portability across machines (~80 LOC + deep-merge install logic; standalone scope).
  • SDD-003 (after): Tier 4 + Tier 5 -- spec-gate CI job + PR template (PR-time hard enforcement).

Test plan

  • Manual smoke .ps1 on this Windows machine: [sdd] reminder is FIRST in additionalContext; existing diagnostics (doctor, hive, specs) append correctly (no regression)
  • Manual smoke .sh (Git Bash): matching JSON shape, identical core text
  • bash -n scripts/claude-session-start.sh clean
  • PSScriptAnalyzer on claude-session-start.ps1 reports only pre-existing warnings (none introduced; script also not in CI lint-powershell scan list -- documented)
  • Bats simulated locally via grep: 16 new asserts across two test files, all green
  • CI: lint + lint-powershell + test (bats) + integration + GitGuardian
  • Post-merge: next Claude Code session in any repo will receive the [sdd] reminder at start; agent must read AGENTS.md + apply Discipline Gate before tool use

Out of scope (deferred)

  • Settings.json portability (SDD-002)
  • CI spec-gate workflow (SDD-003)
  • PR template with SDD checklist (SDD-003)
  • Adding claude-session-start.ps1 to CI lint-powershell scan + fixing the 3 pre-existing PSScriptAnalyzer warnings (separate follow-up; would be scope creep here)

Cross-references

…art nudge (SDD-001)

Tier 1+2 of a 5-layer enforcement stack instituted after a session audit
(2026-05-18) found that two recent atomic PRs (BUG-002/#47, BUG-003/#48)
bypassed the SDD vault gate and spec scaffold despite meeting trigger
criteria. The discipline existed in `pattern-spec-driven-development.md`
but was opt-in: `git checkout -b` had no frication, and the SessionStart
hook only *reported* repo specs status rather than *nudging* the agent to
*apply* SDD. This PR closes the soft-enforcement gap. Hard enforcement
(CI spec-gate + PR template) ships separately as SDD-003. Settings.json
portability for fresh-machine hook deploy ships as SDD-002.

Tier 1 (AGENTS.md):
- Add `### Discipline Gate (NON-NEGOTIABLE)` subsection under the existing
  `## Spec-Driven Development` section. Enumerates the 5 trigger criteria,
  the mandatory ordered process (vault entry -> init-spec -> proposal ->
  tasks -> code -> verification -> archive on merge), and a banned-phrases
  list for vault-hygiene "later" promises that historically compound into
  debt. ~30 lines. Links to the canonical pattern doc for full rationale.

Tier 2 (SessionStart hook injection):
- `scripts/claude-session-start.{ps1,sh}` now initialise the context buffer
  with a `[sdd]` prefixed reminder (byte-anchored same text across OS) at
  the start, unconditional, runs every session regardless of CWD/repo/vault
  state. Reminder points to `AGENTS.md` + the new gate, lists skip criteria
  inline so the agent does not need a round-trip to AGENTS.md for the common
  case.
- Refactored claude-mem heal block to use the defensive append pattern
  already used by the doctor block. Without this, the heal block would
  wipe the SDD reminder when claude-mem produced output. Fixes a latent
  pre-existing bug (heal could already wipe doctor output if ordering
  changed) while load-bearing for SDD-001 correctness.
- Removed the early-exit `if (no vault and no context) exit 0` branch in
  both scripts: now dead code because the context buffer is always
  non-empty after this PR. Kept an inline comment explaining the history.

Tests (additive):
- `tests/agents-md.bats` (new file, 8 asserts): pre-existing H2 regression
  guard + new H3 subsection + 5 trigger criteria + ordered process + banned
  phrases + Standing Order reference.
- `tests/hooks.bats` (new file, 8 asserts): both hook scripts contain the
  `[sdd]` marker + core text + AGENTS.md fallback path + skip criteria
  mention + position invariant (reminder must come before the first gated
  diagnostic block) + cross-OS parity lock on the core text.

Spec scaffolding:
- `specs/SDD-001-discipline-gate/` with proposal/tasks/verification, all
  filled with substantive content. Eat-our-dog-food: this PR adds the
  discipline gate AND follows the gate from the very first commit.

Verification (empirical, this machine, 2026-05-18):
- `.ps1` smoke: `echo '{"cwd":"C:\test","session_id":"test"}' | pwsh
  -NoProfile -File scripts/claude-session-start.ps1` -> JSON with `[sdd]`
  block FIRST in additionalContext, followed by existing diagnostics.
- `.sh` smoke: matching shape, identical core text.
- `bash -n scripts/claude-session-start.sh` clean.
- PSScriptAnalyzer on `claude-session-start.ps1` reports 3 warnings -- all
  pre-existing ($Input automatic var, BOM, Test-RepoSpecs plural) and not
  introduced by this change. The script is not in the CI lint-powershell
  scan list, so no CI fail.

Out of scope (deferred to sibling specs):
- SDD-002: track `~/.claude/settings.json` in dotfiles for hook portability
  (deep-merge install logic, ~80 LOC, requires careful merge with
  third-party hooks like claude-mem and GitGuardian).
- SDD-003: `.github/workflows/ci.yml` spec-gate job + `.github/
  PULL_REQUEST_TEMPLATE.md` with SDD checklist (PR-time enforcement).
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