Skip to content

bug(sdd): SDD workflow does not enforce TDD, verify, or task completion β€” sub-agents report "done" with incomplete implementationsΒ #262

Description

@iBuitron

Pre-flight Checklist

  • I have searched existing issues and this is not a duplicate
  • I understand that PRs will be rejected if the linked issue does not have status:approved

πŸ“ Bug Description

Summary

Three enforcement gaps in the SDD workflow combine to produce incomplete, unverified implementations that the orchestrator accepts as "done":

  1. Strict TDD Mode is ignored β€” sdd-init enables it, sdd-apply never enforces it
  2. Verify phase is silently skipped β€” nothing gates the next SDD on the current one's verification
  3. Sub-agents report "done" without checking the spec β€” "tests pass" β‰  "spec satisfied"

These are not three independent bugs. They are three symptoms of one design flaw: the SDD workflow has no enforcement mechanism between phases β€” it relies entirely on sub-agent self-reporting.


The Evidence

A session implemented 7 SDDs (235 tasks) with Strict TDD Mode: enabled. After all 7 were marked "complete" by the orchestrator, formal verify was run for the first time. Results:

SDD Session Order Agent Said Verify Found
Circuit Breaker 1st "44 tests pass" 0 CRITICAL β€” genuinely complete
Infrastructure 2nd "All checks passed" 0 CRITICAL β€” genuinely complete
Plugin Architecture 4th "Tests pass, 0 FAIL rules" 5 CRITICAL β€” entire phase (constructor injection on 7 files) never executed
Repository+UoW 5th "261 tests pass, 29 rules pass" 2 CRITICAL β€” method name mismatch between components (enqueue vs store), repository scaffolded but never wired
Code Quality 6th "31 PASS, 0 FAIL" 3 CRITICAL β€” feature flag registry never built, store LOC caps violated, test ratio target missed
Specification+API 7th "74 tests pass, 31 rules pass" 7 CRITICAL β€” function spec said to delete still active, replacement has zero production callers, architecture rule regex bug (silent no-op), 4 features never built
Outbox+Saga 6th "255 tests pass" (verify pending)

Pattern: The first 2 SDDs (smallest, freshest context) were complete. The last 5 (larger, degraded context) had 17+ CRITICALs combined.


What Went Wrong β€” Detailed Analysis

Problem 1: TDD Not Enforced

sdd-init detects testing capabilities and outputs Strict TDD Mode: enabled. This flag is stored but never read by sdd-apply. Sub-agents receive "Follow STRICT TDD" as text in their prompt, but:

  • There's no mechanism to verify a test file was committed BEFORE the implementation
  • The agent self-reports compliance β€” nobody checks
  • As context pressure grows (SDD # 5, # 6, # 7), agents write tests and code together or skip tests entirely

Why this matters: Test-first development would have caught the method mismatch (enqueue vs store) because the test would have imported and called the real interface before the implementation existed.

Nuance: Not all tasks benefit from test-first. Moving a file between packages, updating import paths, or creating Dockerfiles don't have natural "write test first" entry points. The workflow doesn't distinguish between:

  • BEHAVIORAL tasks (new logic) β€” TDD is valuable and should be enforced
  • STRUCTURAL tasks (file moves, import rewiring) β€” existing tests are the safety net
  • INFRASTRUCTURE tasks (config files, CI) β€” not unit-testable

Problem 2: Verify Phase Skipped

The SDD pipeline defines: apply β†’ VERIFY β†’ archive. In automatic mode with multiple SDDs, what happens:

SDD-A: apply β†’ "done" β†’ SDD-B: apply β†’ "done" β†’ SDD-C: apply β†’ ... β†’ verify never runs

Nothing in the orchestrator blocks proceeding without verify. The state machine has no transition requiring verified before the next SDD starts.

Why this matters: Verify reads the spec document and checks EACH requirement against the actual code. It catches things that tests and linters cannot:

  • "This function was supposed to be deleted but it's still there with callers"
  • "This architecture rule has a regex bug β€” it matches nothing"
  • "4 features from the spec have zero corresponding code"

These are invisible to pytest (no test fails for a feature that doesn't exist) and invisible to linters (correct code that's simply missing isn't a lint violation).

Problem 3: "Tests Pass" β‰  "Spec Satisfied"

This is the core insight. Apply agents run pytest and ./check rules after each phase. Both verify CODE CORRECTNESS. Neither verifies SPEC COMPLETENESS.

  • A function that should be deleted but wasn't β†’ tests pass (function still works)
  • A method name mismatch between two new components β†’ tests pass (they're never called together in tests)
  • An entire phase skipped β†’ tests pass (no new tests exist for the skipped work)
  • A regex bug in an architecture rule β†’ rule reports PASS (matches nothing, so no violations found)

The spec defines WHAT SHOULD EXIST. Tests verify WHAT DOES EXIST WORKS. The gap between "what should exist" and "what does exist" is only caught by verify.

Problem 4: Context Degradation in Long Sessions

Sub-agents for later SDDs operate with compressed context from earlier phases. The agent knows "Phase 1-3 are done" abstractly but has lost the detailed task descriptions. When it runs final tests and they pass, it genuinely believes it's complete.

Evidence: strict correlation between session order and CRITICAL count. SDDs implemented first (fresh context, full attention) were complete. SDDs implemented last (compressed context, throughput pressure) had the most gaps.

Problem 5: Cross-SDD Integration Is Nobody's Job

When SDD-3 creates UnitOfWork.commit() calling self._outbox.enqueue(), and SDD-2 creates OutboxWriter.store(), the method name mismatch is invisible to both agents. Each only sees its own spec. The orchestrator doesn't verify integration points between SDDs.


Proposed Fixes

Fix 1: Mandatory verify gate (highest priority)

After each apply, the orchestrator MUST launch verify and block on 0 CRITICAL before proceeding. No exceptions in automatic mode.

SDD-A: apply β†’ verify (0 CRITICAL?) β†’ next SDD
                  ↓ (has CRITICALs)
              fix β†’ re-verify β†’ (0 CRITICAL?) β†’ next SDD

Fix 2: Task classification in sdd-tasks

Each task gets a type: behavioral (TDD mandatory), structural (existing tests sufficient), infra (build validation). Apply agents enforce TDD only for behavioral tasks, eliminating the impractical "test-first for file moves" problem.

Fix 3: Task completion tracking

Apply agents use a structured tracker, not mental checkboxes. After returning, the orchestrator can see: "Completed 32/37 tasks. Skipped: T3.2, T3.5, T3.8, T4.1, T4.3" instead of just "done."

Fix 4: Executable acceptance criteria

Each task's AC (grep command, file existence check, test assertion) runs automatically after the task. Not just the global test suite β€” the SPECIFIC check for THAT task.

Fix 5: Session budget

Maximum N SDDs per session (default: 3). After N, save state and require a new session. Each session starts with fresh context. Prevents the quality gradient from session-order degradation.

Fix 6: Cross-SDD integration spec

When SDDs have dependencies, generate integration points: shared interfaces, method signatures, expected callers. The later SDD's verify checks these integration points against the earlier SDD's actual code.


πŸ”„ Steps to Reproduce

βœ… Expected Behavior

.

❌ Actual Behavior

.

Gentle AI Version

.

Operating System

macOS

AI Agent / Client

Claude Code

πŸ“‹ Affected Area

CLI (commands, flags)

πŸ’‘ Logs / Error Output

Additional Context

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status:approvedApproved for implementation β€” PRs can now be openedtype:bugBug fix

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions