Spec-Driven Development
Spec-Driven Development β€Ί Module 4: Agent Orchestration, Verification & Maintenance
Module 4: Agent Orchestration, Verification & Maintenance

Chapter 15: Preventing Spec Decay: Living Documentation and CI/CD Pipelines

By Muhammad Riaz

The Software Rot Dilemma in the Age of AI

In traditional software development, documentation is notorious for aging poorly. A team spends weeks writing detailed architecture documents or API specs during a project kickoff. Yet six months later, after dozens of hotfixes, emergency refactors, and feature additions, the code has evolved while the documentation has remained static.

This phenomenonβ€” Spec Decay β€”renders traditional documentation useless over time.

In a Spec-Driven Development ecosystem, however, spec decay is far more dangerous than simple outdated documentation. Because AI coding agents rely on your specifications, architecture plans, and system invariants as their primary context source, feeding an AI agent an outdated specification will cause it to generate code based on obsolete rules.

If your specification says /api/v1/users returns an integer ID, but a hotfix last month migrated the database to UUID strings, an AI agent reading the un-updated spec will write new integrations that break production instantly.

To make SDD sustainable at enterprise scale, specifications cannot be static, one-time launch documents. They must function as Living Documentation β€”continuously verified, updated, and synchronized with the codebase via automated CI/CD pipelines.

The Living Documentation Cycle

In a mature SDD workflow, the relationship between specification files and code changes from a one-way street into a continuous feedback loop:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       THE LIVING DOCUMENTATION CYCLE                        β”‚
β”‚                                                                             β”‚
β”‚  [ Feature Spec ]   ──> AI Agent generates Implementation Code & Tests      β”‚
β”‚                               β”‚                                             β”‚
β”‚                               β–Ό                                             β”‚
β”‚  [ Code Refactor ]  ──> Human or AI updates source code mid-sprint          β”‚
β”‚                               β”‚                                             β”‚
β”‚                               β–Ό                                             β”‚
β”‚  [ CI Verification] ──> Pipeline detects Drift between Spec and Code        β”‚
β”‚                               β”‚                                             β”‚
β”‚                               β–Ό                                             β”‚
β”‚  [ Auto-Sync Gate ] ──> PR requires Spec Update before Merge Approval       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The fundamental rule of Living Documentation is simple:

No code modification is complete until its corresponding .spec.md and .plan.md files reflect the new reality.

Three Strategies for Eliminating Spec Decay

To keep your specification repository (.specs/) perfectly synchronized with living production code, deploy these three practical strategies:

1. The Two-Way Synchronization Protocol (Spec-First Refactoring)

When modifying an existing feature, developers often make the mistake of editing the source code directly and forgetting to update the specification document.

The Two-Way Synchronization Protocol mandates that any change to business logic must begin by updating the specification file first, followed by an automated AI refactoring pass.

Practical Workflow Step-by-Step

Imagine your team needs to update an existing subscription cancellation policy from an immediate service termination model to an end-of- billing-cycle termination model.

  1. Step 1: Update the Spec ( .specs/004-cancellation.spec.md ) The developer opens the existing specification and updates the functional requirements:
   <!-- OLD REQUIREMENT (DEPRECATED) -->
   - FR-2: Submitting a cancellation request MUST set `user.status = 'CANCELLED'` immediately.

   <!-- NEW REQUIREMENT (UPDATED 2026-10-18) -->
   - FR-2: Submitting a cancellation request MUST set `user.cancel_at_period_end = true`.
   - FR-3: The user's active status MUST remain `'ACTIVE'` until `current_period_end` timestamp is reached.
  1. Step 2: Execute Sync Refactor Prompt The developer triggers their CLI agent (e.g., using GitHub Spec Kit or Cursor):
   specify sync --spec .specs/004-cancellation.spec.md

Or using an explicit agent prompt:

"Read updated .specs/004-cancellation.spec.md . Identify all services, tests, and handlers in the codebase that enforce old FR-2 and refactor them to comply with new FR-2 and FR-3 ."

  1. Step 3: Verification & Commit The AI agent updates the service logic, refactors unit test assertions, and marks the specification as current. Both the specification change and code changes are committed together in a single Pull Request.

2. Automated Spec-Drift Detectors in CI/CD

To catch cases where a developer manually edits source code without updating the corresponding specification document, build an automated Spec-Drift Detector into your GitHub Actions or GitLab CI pipeline.

Spec-drift tools perform static analysis comparing API contracts, schema types, and exported interfaces against the markdown contract definitions inside .specs/.

# Example GitHub Actions Workflow: Spec-Drift Verification Gate
name: Spec-Drift Pipeline Gate
on: [pull_request]

jobs:
verify-spec-sync:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - name: Check for Code Changes Without Spec Updates
      run: |
        # Detect if source files were modified
        CODE_CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '^src/' || true)
        # Detect if spec files were modified
        SPEC_CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '^\.specs/' || true)

        if [ -n "$CODE_CHANGED" ] && [ -z "$SPEC_CHANGED" ]; then
           echo "   SPEC DRIFT DETECTED!"
           echo "Source files in 'src/' were modified without corresponding updates to '.specs/'."
           echo "Please update the relevant specification file or run '/speckit.sync'."
           exit 1
        fi
        echo "   Spec synchronization verified."

By failing CI builds when source code changes are pushed without spec updates, you eliminate doc decay at the pull request boundary.

3. Automated Spec Generation for Legacy Codebases ("Reverse Spec Discovery")

What if you are adopting Spec-Driven Development on a massive 5-year-old legacy codebase that has zero existing specifications?

You do not need to pause product development for months to write specifications manually for thousands of legacy files. Instead, use the Reverse Spec Discovery pattern.

Reverse Spec Discovery Execution

When tasked with touching a legacy module (e.g., src/legacy/billing_engine.py), instruct an AI agent to reverse-engineer a baseline specification document before making any modifications:

# TASK: Reverse Spec Discovery

Inspect `src/legacy/billing_engine.py` and its adjacent test files.

Generate a production-grade `.specs/legacy-billing.spec.md` capturing:
1. Current functional requirements and business logic as executed in code.
2. Implied system invariants and data validations.
3. Observed edge-case handling.

DO NOT modify the Python code yet. Output ONLY the generated specification file.

Once the agent generates legacy-billing.spec.md, a human engineer reviews the spec to verify its accuracy, edits any legacy bugs or bad rules, and commits the spec as the new Anchored Baseline for that module.

Moving forward, any future AI agent working on billing_engine.py executes against that anchored specification file.

Real-World Case Study: Eliminating Regressions in Microservice Contracts

A fintech company operating 40 microservices suffered frequent integration outages because API payload updates in one service were rarely documented in shared specs, causing dependent downstream services to crash under unexpected data types.

The SDD Living Doc Transformation

  1. The engineering team added a .specs/ directory to every microservice repository.

  2. They configured CI pipelines to run schema validation tests comparing exported TypeScript/Protobuf types against

   .specs/contracts/.
  1. If an engineer modified an API payload in code without updating the contract spec, CI automatically blocked deployment.

Results Over 6 Months

  • Microservice Contract Mismatches: Reduced by 94%.

  • Onboarding Time for New Developers: Reduced from 3 weeks to 4 days, as developers could read accurate, living .spec.md files that matched production code line-for-line.

  • AI First-Pass Code Accuracy: Increased from 45% to 89% because AI agents were provided with synchronized, up-to-date context.

Practical Exercises: Maintaining Living Documentation

  1. Audit a Recent Commit for Spec Drift: Look at the last 5 pull requests merged into your team's main repository. How many of them changed business logic or API contracts without updating project documentation?

  2. Execute a Reverse Spec Discovery Pass: Pick a complex 200-line utility function or service file in your current project. Use your AI assistant to generate a .spec.md file reverse-engineered from that code. Review the output for hidden invariants.

  3. Set Up a Local Spec Sync Check: Create a local git pre-push hook script that checks if src/ modifications have matching changes in

   .specs/.

Next Steps

Now that you know how to build living specifications that remain permanently synchronized with your codebase, we must address the final, critical piece of the puzzle: The Human Factor.

In Chapter 16, we will conclude the book with Building an AI-Native Engineering Culture β€”learning how to transform software engineering teams, redefine developer career paths, and scale Spec-Driven Development across entire organizations.