PAPER-2026-001

Spec-Driven Development

A Meta-Experiment in Agent Orchestration: Building NBA Live Analytics as Methodology Validation

Methodology 15 min read Advanced

Abstract

This case study covers a meta-experiment testing whether structured specifications can effectively guide agent-based development. The vehicle is an NBA Live Analytics Dashboard with three analytical views—Duo Synergy, Defensive Impact, and Shot Network. The hypothesis: spec-driven development produces both working software and methodology documentation as equally important artifacts. Through three phases of implementation (Infrastructure, Pages, Polish), we observe that explicit dependency graphs, complexity annotations, and acceptance criteria enable predictable agent execution while surfacing methodology insights that would remain hidden in ad-hoc development.

3
Phases
12
Features Delivered
0
Type Errors
3
Visualization Types

1. The Hypothesis

Central Question: Can spec-driven development be managed by agents using harness and Beads abstractions, producing both working software and methodology documentation?

Traditional development treats documentation as an afterthought—something produced after the code works. Spec-driven development inverts this: the specification precedes implementation, and the implementation validates the specification.

The Meta-Experiment: The dashboard itself is the artifact; this methodology paper is the meta-artifact. Both are equally important outputs.

This follows the hermeneutic circle (a philosophical method where understanding deepens through iterative interpretation—you understand parts through the whole, and the whole through its parts): pre-understanding (the spec) meets emergent understanding (implementation), and the gap between them reveals methodology insights.

2. Architecture

The NBA Live Analytics Dashboard demonstrates a complete vertical slice: data acquisition, processing, visualization, and documentation.

// System Architecture

┌─────────────────────────────────────────────────────────────┐
│                   packages/space (SvelteKit)                │
├─────────────────────────────────────────────────────────────┤
│  /experiments/nba-live           → Landing + game selector  │
│  /experiments/nba-live/duo-synergy      → Two-man efficiency│
│  /experiments/nba-live/defensive-impact → Matchup analysis  │
│  /experiments/nba-live/shot-network     → D3 force graph    │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│              packages/space/workers/nba-proxy               │
│  - Rate limiting (10 req/min to NBA.com)                    │
│  - KV caching (30s TTL for live data)                       │
│  - D1 for player baselines                                  │
└─────────────────────────────────────────────────────────────┘

Design Decisions

Each architectural decision was documented in the spec before implementation:

DecisionChoiceRationale
Real-time updatesPolling (30s)NBA data isn't truly streaming
VisualizationCustom + D3D3 only for force-directed graphs
Baseline dataD1 DatabaseSQL queries cleaner for comparisons
StylingCanon tokensBrand compliance, fast iteration

3. Spec Structure

The specification uses a YAML format optimized for agent consumption. Key elements that enable predictable execution:

Dependency Graph

  • • Explicit depends_on arrays
  • • Prevents premature starts
  • • Enables parallel execution
  • • Validates topological order

Complexity Annotations

  • trivial: Haiku model
  • simple: Sonnet model
  • standard: Sonnet model
  • complex: Opus model

Acceptance Criteria

  • • Observable, testable conditions
  • • Verify commands where applicable
  • • No ambiguous language
  • • Binary pass/fail

File Tracking

  • • Expected files listed per feature
  • • Enables merge conflict detection
  • • Validates isolation
  • • Supports parallel convoy work

4. Phase 1: Infrastructure

Execution: Sequential (dependencies required)

Features: Types, D1 Schema, NBA Proxy Worker, API Client, Calculations

Infrastructure must be sequential—the API client cannot exist without types, calculations cannot exist without the D1 schema. The spec enforces this:

# Dependency chain

Types (1.1)
    │
    ├─── D1 Schema (1.2)
    │         │
    ├─── NBA Proxy Worker (1.3)
    │         │
    └─── Calculations (1.5)
              │
              └─── API Client (1.4)

Key Deliverables

  • types.ts — Player, Game, Shot, PlayByPlayAction interfaces
  • 0013_nba_baselines.sql — D1 migration for player metrics
  • nba-proxy/ — Cloudflare Worker with KV caching
  • api.ts — Type-safe fetch functions with Result pattern
  • calculations.ts — PPP, defensive impact, shot zone analysis

Insight: Type Alignment

The NBA API's field naming diverged from our initial assumptions. personId became id, assistPersonId became assistPlayerId. This gap between spec and reality surfaced during implementation, validating the hermeneutic circle principle: understanding emerges through practice.

5. Phase 2: Pages

Execution: Parallel convoy (after Infrastructure)

Features: Landing, Duo Synergy, Defensive Impact, Shot Network

Once infrastructure exists, pages can be built in parallel. The spec identifies file isolation—each page touches distinct routes and components:

FeatureRouteComponentComplexity
Landing/nba-live/GameSelectorstandard
Duo Synergy/duo-synergy/DuoChartstandard
Defensive Impact/defensive-impact/DefensiveHeatmapstandard
Shot Network/shot-network/ShotNetwork (D3)complex

Tufte Principles Applied

All visualizations follow Edward Tufte's principles—maximizing data-ink ratio, avoiding chartjunk, using direct labeling. The Shot Network component demonstrates this:

  • Node size encodes shot creation + attempts (proportional ink)
  • Edge thickness encodes assist frequency
  • Direct labels on nodes (no legend hover)
  • Minimal chrome—no gridlines, no decorative elements

6. Phase 3: Polish

Execution: Sequential (after Pages)

Features: Experiment Registration, Methodology Documentation

The final phase integrates the work into the larger system:

  • Experiment Registration: Entry in fileBasedExperiments.ts with principle mappings
  • Methodology Documentation: This paper—the meta-artifact that validates the spec-driven approach

Principle Mappings

The experiment tests specific Rams and Heidegger principles:

Rams Principles

  • Principle 2: Useful — delivers analytical value
  • Principle 4: Understandable — clear methodology
  • Principle 8: Thorough — complete coverage

Heidegger Concepts

  • Zuhandenheit: Infrastructure disappears
  • Hermeneutic Circle: Spec ↔ Implementation
  • Dwelling: Analytics enable understanding

7. Observations

What Worked

  • Dependency graphs prevent premature execution. The API client couldn't start until types existed. This eliminated a class of errors where agents guess at interfaces.
  • Complexity annotations guide model selection. The Shot Network (D3 force-directed) was correctly identified as complex, receiving more thorough treatment.
  • Acceptance criteria enable verification. "Nodes represent players with shots or assists" is testable; "visualization should be nice" is not.
  • File tracking prevents conflicts. Parallel convoy work on isolated routes succeeded without merge conflicts.

What the Spec Didn't Predict

  • API field naming divergence. The NBA API uses personId in some contexts and playerId in others. The spec assumed consistency.
  • D3 integration complexity. Svelte 5 runes ($props()) interact differently with D3's mutation-based model than Svelte 4 reactivity.
  • Shot type enumeration. The spec assumed 2pt/3pt action types; reality uses shot with shotType property.

These gaps validate the hermeneutic principle: the spec is pre-understanding; implementation reveals truth. The value isn't in predicting everything—it's in making the gaps visible.

8. Spec-Driven vs Ad-Hoc Development

DimensionSpec-DrivenAd-Hoc
Upfront CostHigherLower
PredictabilityHighVariable
Parallel WorkEnabledRisky
Methodology CaptureAutomaticManual
Gap VisibilityExplicitHidden
Best ForComplex, multi-file featuresQuick fixes, exploration

Key insight: The upfront cost of spec creation is offset by reduced rework and automatic methodology capture. For complex features, spec-driven development pays for itself.

9. How to Apply This

This section translates the methodology into actionable steps. Whether you're building a dashboard, API, or full-stack feature, spec-driven development follows the same process.

Step-by-Step Process

Step 1: Write the Spec Before Code (Human)
Create a YAML specification with:
- Project title and complexity annotation
- Features grouped into phases
- Explicit dependency graphs (depends_on arrays)
- Acceptance criteria (testable, observable)
- File paths for each feature

Step 2: Identify Execution Strategy (Human)
Determine which phases run:
- Sequential (dependencies required)
- Parallel convoy (isolated files, shared infrastructure)
- Mark complexity: trivial, simple, standard, complex

Step 3: Create Feature Issues (Agent)
Use Beads to create issues from spec:
`bd mol spawn <spec-file> --property <value>`
Each feature becomes an issue with:
- Dependencies enforced
- Complexity-based model selection
- Acceptance criteria as checklist

Step 4: Execute Infrastructure First (Agent)
Sequential implementation of foundational features:
- Types before clients
- Database schema before queries
- Worker/server before calculations
Validate each with acceptance criteria before proceeding.

Step 5: Execute Features in Parallel (Agent)
For convoy-eligible features:
- Confirm file isolation (no overlaps)
- Run parallel sessions (different agents or sequential with context switch)
- Merge when all features reach code-complete

Step 6: Document Gaps (Human + Agent)
After implementation, capture:
- What the spec didn't predict
- Why gaps occurred (API changes, integration complexity)
- How understanding evolved
This becomes the methodology artifact (like this paper).

Real-World Example: E-Commerce Cart Feature

Let's say you're adding a shopping cart to an existing e-commerce site:

title: Shopping Cart with Checkout Flow
property: shop
complexity: standard

features:
  - title: Cart types and schema
    priority: 1
    complexity: simple
    files:
      - packages/shop/src/types/cart.ts
      - packages/shop/migrations/0015_cart_table.sql
    acceptance:
      - test: CartItem interface has product_id, quantity, price
        verify: pnpm --filter=shop exec tsc --noEmit
      - D1 migration creates cart_items table

  - title: Cart API (add, remove, update)
    priority: 1
    complexity: standard
    depends_on:
      - Cart types and schema
    files:
      - packages/shop/src/routes/api/cart/+server.ts
      - packages/shop/src/lib/cart.ts
    acceptance:
      - POST /api/cart/add returns 200 with updated cart
      - DELETE /api/cart/remove/:id removes item
      - Cart persists across sessions (D1)

  - title: Cart UI component
    priority: 2
    complexity: simple
    depends_on:
      - Cart API (add, remove, update)
    files:
      - packages/shop/src/components/Cart.svelte
      - packages/shop/src/components/CartItem.svelte
    acceptance:
      - Cart displays items with quantity controls
      - Total price updates on quantity change
      - Empty state shows "Your cart is empty"

  - title: Checkout flow
    priority: 2
    complexity: complex
    depends_on:
      - Cart API (add, remove, update)
    files:
      - packages/shop/src/routes/checkout/+page.svelte
      - packages/shop/src/routes/checkout/+page.server.ts
      - packages/shop/src/lib/payment.ts
    acceptance:
      - Checkout validates cart not empty
      - Stripe payment intent created
      - Order confirmation email sent
      - Cart cleared after successful payment

Execution strategy:

  • Phase 1 (Sequential): Cart types → Cart API
  • Phase 2 (Parallel): Cart UI and Checkout flow can run simultaneously—isolated files
  • Validation: Each feature has testable acceptance criteria
  • Complexity: Checkout marked complex for Opus model (Stripe integration, email)

When to Use Spec-Driven Development

Use this approach when:

  • Multi-file features: 3+ files that need coordination
  • Clear dependencies: Infrastructure → Features → Polish structure exists
  • Agent execution: Work will be done by AI agents (harness, Claude Code)
  • Methodology capture: You want documentation as a first-class artifact
  • Parallel work: Features can be built simultaneously by different agents

Don't use for:

  • Quick fixes or single-file changes
  • Exploratory prototyping (unknown requirements)
  • Hotfixes or emergency patches
  • Refactoring where behavior doesn't change

The upfront cost of spec creation pays off through reduced rework, automatic issue creation, and methodology documentation. For complex features, spec-driven development produces both working code and lasting understanding.

10. Conclusion

This meta-experiment validates the hypothesis: spec-driven development produces both working software and methodology documentation. The NBA Live Analytics Dashboard demonstrates:

  • Three analytical views with Tufte-compliant visualizations
  • Complete infrastructure (Worker, D1, KV caching)
  • Zero TypeScript errors at completion
  • Methodology documentation as a first-class artifact

The gaps between spec and implementation—field naming, D3 integration, enumeration values—are not failures. They are the hermeneutic circle in action: pre-understanding meeting reality, with the gap itself producing insight.

The Spec-Driven Principle

Specify
before implementing
Implement
to reveal gaps
Document
the understanding

"The specification becomes the session. The dashboard is the artifact. This paper is the meta-artifact. All three serve the whole."