{
  "schema_version": "0.1",
  "id": "PRD-002",
  "title": "PRD Plugin MCP server (validated state tools)",
  "status": "approved",
  "source_request_id": "REQ-052",
  "source_brainstorm_id": null,
  "created_at": "2026-07-02",
  "updated_at": "2026-07-13",
  "summary": "A stdio MCP server shipped inside the prd-plugin npm package exposing eighteen validated state tools so agents avoid routine .prd_plugin JSON reads and writes, including branch-first parallel tracking with serialized canonical promotion. Validation-at-write; the commit gate remains the deterministic backstop.",
  "requirements": [
    {
      "id": "PRD-REQ-009",
      "priority": "must",
      "summary": "State CRUD tools: status, next_id, open_goal, update_goal, close_goal, file_request, record_evidence, record_decision, log_change, validate.",
      "source": [
        "REQ-052"
      ],
      "acceptance_criteria": [
        "PRD-ACC-009"
      ]
    },
    {
      "id": "PRD-REQ-010",
      "priority": "must",
      "summary": "Server-side UTC timestamps on every write; caller-supplied timestamps are rejected/ignored.",
      "source": [
        "REQ-052"
      ],
      "acceptance_criteria": [
        "PRD-ACC-010"
      ]
    },
    {
      "id": "PRD-REQ-011",
      "priority": "must",
      "summary": "IDs allocated only via the registry with atomic, lock-guarded counter bumps; callers never compute IDs.",
      "source": [
        "REQ-052"
      ],
      "acceptance_criteria": [
        "PRD-ACC-011"
      ]
    },
    {
      "id": "PRD-REQ-012",
      "priority": "must",
      "summary": "Schema-validate every record pre-write with actionable rejection messages; enforce one status vocabulary (open/active/complete/resolved/deferred/parked/superseded) with legacy mapping on read.",
      "source": [
        "REQ-052"
      ],
      "acceptance_criteria": [
        "PRD-ACC-012"
      ]
    },
    {
      "id": "PRD-REQ-013",
      "priority": "must",
      "summary": "Atomic, minimal-diff writes: temp-file+rename, preserve the file's existing indentation, never reformat unrelated records.",
      "source": [
        "REQ-052"
      ],
      "acceptance_criteria": [
        "PRD-ACC-013"
      ]
    },
    {
      "id": "PRD-REQ-014",
      "priority": "must",
      "summary": "prd-install wires the server into the target repo's .mcp.json idempotently (preserving existing servers) and ships the server file with the payload.",
      "source": [
        "REQ-052"
      ],
      "acceptance_criteria": [
        "PRD-ACC-013"
      ]
    },
    {
      "id": "PRD-REQ-015",
      "priority": "should",
      "summary": "Gate/guard alignment: gate errors point offenders at the tools; stop-guard treats deferred/parked as closed; status/report code normalizes legacy statuses.",
      "source": [
        "REQ-052"
      ],
      "acceptance_criteria": [
        "PRD-ACC-012"
      ]
    },
    {
      "id": "PRD-REQ-021",
      "priority": "must",
      "summary": "Bounded find and get tools return relevant records without agents scanning state files.",
      "source": ["REQ-085"],
      "acceptance_criteria": ["PRD-ACC-021"]
    },
    {
      "id": "PRD-REQ-022",
      "priority": "must",
      "summary": "Create, update, and link tools manage supported record-backed IDs through schema-limited locked operations.",
      "source": ["REQ-085"],
      "acceptance_criteria": ["PRD-ACC-022", "PRD-ACC-023"]
    },
    {
      "id": "PRD-REQ-023",
      "priority": "must",
      "summary": "Record creation owns allocation and cannot create a duplicate even when the registry counter is stale or writers are concurrent.",
      "source": ["REQ-085"],
      "acceptance_criteria": ["PRD-ACC-024"]
    },
    {
      "id": "PRD-REQ-024",
      "priority": "must",
      "summary": "Parallel agents update distinct pre-created DBR tracking branches without mutating canonical tracking or the registry; the lead promotes merged branches serially with conflict checks and canonical ID allocation.",
      "source": ["REQ-087", "REQ-088", "DBR-001", "HLT-009"],
      "acceptance_criteria": ["PRD-ACC-025", "PRD-ACC-026", "PRD-ACC-027", "PRD-ACC-028"]
    }
  ],
  "non_functional_requirements": [
    {
      "id": "PRD-NFR-005",
      "category": "portability",
      "summary": "CommonJS, no top-level await, zero runtime npm dependencies; Node >=18; repo-generic via CWD or PRD_PLUGIN_ROOT."
    },
    {
      "id": "PRD-NFR-006",
      "category": "compatibility",
      "summary": "No regression for hand-editing repos: the commit gate still catches everything it caught before."
    },
    {
      "id": "PRD-NFR-007",
      "category": "reliability",
      "summary": "Tool descriptions teach WHEN to use each tool playbook-style; adoption must not depend on having read the skills."
    },
    {
      "id": "PRD-NFR-011",
      "category": "simplicity",
      "summary": "Reuse the existing CommonJS server, JSON files, lock, schemas, and atomic writer; add no database, secondary index, reservation subsystem, or runtime dependency."
    },
    {
      "id": "PRD-NFR-012",
      "category": "concurrency",
      "summary": "Use one committed branch file per worker, centrally enforce the configured worker boundary, and retain direct tools for lead/single-writer compatibility; add no network coordinator, distributed lock, secondary branch index, or worker-side numeric allocation."
    }
  ],
  "acceptance_criteria": [
    {
      "id": "PRD-ACC-009",
      "criterion": "End-to-end: fresh temp repo -> prd-install -> server starts -> open_goal -> file_request -> record_evidence -> close_goal -> validate clean -> gate passes with zero manual JSON edits."
    },
    {
      "id": "PRD-ACC-010",
      "criterion": "A tools/call injecting a future or caller-supplied timestamp cannot land one on disk."
    },
    {
      "id": "PRD-ACC-011",
      "criterion": "Concurrent next_id allocations return distinct sequential IDs and the registry counter never lags or skips."
    },
    {
      "id": "PRD-ACC-012",
      "criterion": "Schema violations are rejected with actionable messages; legacy status values remain readable via mapping."
    },
    {
      "id": "PRD-ACC-013",
      "criterion": "A write into a file with foreign (4-space) indentation produces a minimal diff; .mcp.json merge preserves pre-existing servers and is idempotent."
    },
    {
      "id": "PRD-ACC-021",
      "criterion": "Agents can find bounded records by kind, status, linked ID, or text and fetch one exact ID without reading state JSON."
    },
    {
      "id": "PRD-ACC-022",
      "criterion": "prd_create allocates and writes supported record types in one lock; prd_update rejects unknown or immutable fields."
    },
    {
      "id": "PRD-ACC-023",
      "criterion": "prd_link verifies both records exist and adds symmetric links without duplication."
    },
    {
      "id": "PRD-ACC-024",
      "criterion": "Concurrent creation and a registry counter behind existing records always yield unique IDs; duplicate supplied or discovered IDs are rejected."
    },
    {
      "id": "PRD-ACC-025",
      "criterion": "Two isolated worktree copies update different pre-created tracking branch files while canonical tracking and registry bytes remain unchanged, then lead promotion produces distinct TRK IDs without lost notes or links."
    },
    {
      "id": "PRD-ACC-026",
      "criterion": "Tracking branch promotion is idempotent on retry, rejects wrong owners and overlapping non-additive field changes, and records DBR/DBR-DELTA/DBR-MERGE provenance visible to state consistency and the traceability graph."
    },
    {
      "id": "PRD-ACC-027",
      "criterion": "With tracking.branching.require_for_parallel_agents enabled and the lead-provided worker environment set, every canonical state or registry write is rejected while prd_update_tracking_branch succeeds only for the assigned DBR and owner."
    },
    {
      "id": "PRD-ACC-028",
      "criterion": "A default downstream install includes state_consistency_check.py, prd_validate fails for invalid promoted branch state, and prd_status/prd_find/prd_get expose tracking branches without file scanning."
    }
  ],
  "dependencies": [],
  "open_questions": [],
  "risks": []
}
