{
  "schema_version": "0.1",
  "id": "ARCH-001",
  "title": "Architecture for PRD Plugin Downstream System Test Harness",
  "status": "draft",
  "source_prd_id": "PRD-001",
  "source_request_id": "REQ-028",
  "created_at": "2026-06-17",
  "updated_at": "2026-06-17",
  "summary": "A pytest-based harness orchestrates LLM-driven agents against temporary downstream repos. The architecture separates fixture creation, agent driving, scenario orchestration, assertions, and boundary monitoring into discrete components with clear interfaces.",
  "components": [
    {
      "id": "ARCH-COMP-001",
      "name": "DownstreamFixture",
      "responsibility": "Create, install, and tear down a temporary downstream repo with PRD Plugin from the local hub source. Inject canary .env and optional fake git remote.",
      "satisfies": [
        "PRD-REQ-001",
        "PRD-REQ-006",
        "PRD-NFR-003"
      ]
    },
    {
      "id": "ARCH-COMP-002",
      "name": "LLMAgentDriver",
      "responsibility": "Load a system prompt that enforces PRD Plugin method and downstream skill selection. Send scripted user prompts, receive structured tool-use responses, and dispatch to the same file/shell/read tools available to opencode/Codex.",
      "satisfies": [
        "PRD-REQ-002",
        "PRD-NFR-001"
      ]
    },
    {
      "id": "ARCH-COMP-003",
      "name": "ScenarioOrchestrator",
      "responsibility": "Run a scenario by resetting the fixture, replaying user prompts, and collecting agent actions and repo state snapshots.",
      "satisfies": [
        "PRD-REQ-002",
        "PRD-NFR-004"
      ]
    },
    {
      "id": "ARCH-COMP-004",
      "name": "StateAssertionLibrary",
      "responsibility": "Validate .prd_plugin/state/*.json, registry counters, ID references, traceability maps, and canonical artifact JSON. Reuse existing state_consistency_check.py when installed.",
      "satisfies": [
        "PRD-REQ-003",
        "PRD-REQ-004",
        "PRD-ACC-003"
      ]
    },
    {
      "id": "ARCH-COMP-005",
      "name": "GitBoundaryChecker",
      "responsibility": "Inspect git state to assert no push/merge without consent and that commit messages reference durable IDs when commits are prepared.",
      "satisfies": [
        "PRD-REQ-005",
        "PRD-ACC-005"
      ]
    },
    {
      "id": "ARCH-COMP-006",
      "name": "SecretsMonitor",
      "responsibility": "Scan all captured stdout, stderr, logs, and persisted files for the canary token and forbidden secret patterns derived from .env.",
      "satisfies": [
        "PRD-REQ-006",
        "PRD-ACC-006"
      ]
    },
    {
      "id": "ARCH-COMP-007",
      "name": "HubBoundaryMonitor",
      "responsibility": "Record every file path and script invocation attempted by the agent and flag any reference to the prd-plugin hub repo or execution of hub-only scripts.",
      "satisfies": [
        "PRD-REQ-007",
        "PRD-ACC-007"
      ]
    }
  ],
  "interfaces": [
    {
      "id": "ARCH-IF-001",
      "between": [
        "ScenarioOrchestrator",
        "DownstreamFixture"
      ],
      "contract": "Fixture returns a Path to the repo root and a cleanup callback. Orchestrator may reset fixture state between scenarios."
    },
    {
      "id": "ARCH-IF-002",
      "between": [
        "ScenarioOrchestrator",
        "LLMAgentDriver"
      ],
      "contract": "Orchestrator passes a list of user prompts and the repo root. Driver returns a structured trace of tool calls and outputs."
    },
    {
      "id": "ARCH-IF-003",
      "between": [
        "LLMAgentDriver",
        "DownstreamFixture"
      ],
      "contract": "Driver performs file read/write, shell exec, and search operations within the fixture repo root only. All paths are logged."
    },
    {
      "id": "ARCH-IF-004",
      "between": [
        "ScenarioOrchestrator",
        "StateAssertionLibrary"
      ],
      "contract": "After prompts complete, orchestrator passes repo root to assertion library, which returns a pass/fail report with source refs."
    }
  ],
  "decisions": [
    {
      "id": "ARCH-DEC-001",
      "summary": "Use an LLM-driven simulated agent",
      "rationale": "A real LLM exercises skill selection and tool-use paths that deterministic scripts cannot replicate, giving higher confidence that the PRD Plugin method works for real agents.",
      "consequences": [
        "Requires API budget",
        "Requires flakiness controls",
        "May need retries"
      ],
      "supersedes": "BR-Q-001"
    },
    {
      "id": "ARCH-DEC-002",
      "summary": "Test against local hub source, not npm package",
      "rationale": "Testing the local source allows CI to validate changes before publish. The fixture can run the local installer with a repo-root path rather than npx from npm.",
      "consequences": [
        "CI tests changes pre-publish",
        "Fixture must invoke local scripts directly"
      ]
    },
    {
      "id": "ARCH-DEC-003",
      "summary": "Use pytest as the orchestration framework",
      "rationale": "pytest is already used for the 213 hub tests, integrates with CI, supports fixtures and parametrization, and can run retries with plugins.",
      "consequences": [
        "Familiar tooling",
        "Easy CI integration"
      ]
    }
  ],
  "risks": [
    {
      "id": "ARCH-RISK-001",
      "summary": "LLM non-determinism",
      "mitigation": "Low temperature, deterministic prompts, retries with majority voting, and acceptance criteria focused on durable outcomes rather than exact tool-call sequences.",
      "source": "BR-RISK-001"
    },
    {
      "id": "ARCH-RISK-002",
      "summary": "Cost and runtime",
      "mitigation": "Fast/cheap model for smoke tests; full scenarios run on-demand or in nightly CI; budget cap per run.",
      "source": "BR-RISK-001"
    },
    {
      "id": "ARCH-RISK-003",
      "summary": "Harness maintenance",
      "mitigation": "Keep components small and reuse existing scripts; assertions are declarative; scenario definitions are data-driven.",
      "source": "BR-RISK-003"
    }
  ]
}
