# URS-40 — Self-Validation / Validation-Automation Engine — Engineering Build Specification

| Field | Value |
|---|---|
| Document | URS-40 Engineering Build Specification (consolidated, build-ready) |
| Version | v0.4-harness-grade — **DRAFT for engineering build** |
| Date | 2026-06-05 |
| Owner | Engineering (build) · Head of QA (disposition) · CSV/CSA (validation strategy) |
| Code baseline | `Verixaai/Verixa` · branch `dev-vimal-audit-2` · commit `3bd2fe47ba703301ffea4abd3d4bc4a8f12d2df4` |
| Source artefacts (controlled masters) | `URS-40_Self-Validation-Validation-Automation-Engine.Target-State.md` (requirements) · `URS-40_Drift_Register_and_Corrected_Spec.md` (current-state delta + corrective spec + Appendix A code evidence) · `self_validation_workflow_CORRECTED.html` (lifecycle) |
| Regulatory class | GAMP 5 Category 5 (custom) · 21 CFR Part 11 (predicate-scoped) · EU Annex 11 · EU GMP Annex 22 (DRAFT, anticipatory) · EU AI Act (classification pending) · FDA CSA |
| **Status** | **DRAFT — blockers open — NOT executed — NOT approved — NOT validation-ready.** This is a build specification, **not** a validation claim. No statement of Part 11 / Annex 11 / Annex 22 / EU AI Act *compliance* is made or implied. |

> **How to use this document.** This is the single consolidated, build-ready engineering specification for URS-40 — a build guide **derived from** the controlled masters named in the header, which remain authoritative. It **consolidates and brings to full implementation-grade** the previously summary-level requirements: **SV-COR-001…029 are now all full implementation-grade PECRA** (Problem → Evidence → Corrective requirement → Acceptance), plus the three independent-verification additions **ADD-VER-01…03**. Every current-state claim is line-pinned to commit `3bd2fe47`. Build in the order given in §6. Each requirement's **Acceptance** is by **executed OQ on a test tenant** with QA/Validation disposition — automated unit tests are **not** OQ evidence (SV-COR-029). Do **not** mark any item done on code review alone.

---

## 0A. v0.4 corrective note — ARCH-AI-001 supplied, approval still blocked
This v0.4 build specification incorporates the supplied architecture record **ARCH-AI-001 "AI Optionality and Manual Continuity" v1.0 (DRAFT)**. URS-40 binds to AC-5 / AC-6 / AC-7 only. The reference is now pinned for engineering traceability, but ARCH-AI-001 is not approved. Engineering shall treat ARCH-AI-001 approval and filing as a freeze gate, not as a closed compliance item.

## 1. Intended behaviour (what the engine does)

The engine watches for a validation-relevant change → classifies it (risk-based) → generates an IQ/OQ/PQ plan from an approved protocol library → runs an **advisory** dual-model AI cross-check (Claude + GPT, via the URS-32 Gateway) → requires a **human e-signature** → executes **real** IQ/OQ/PQ and captures objective evidence → assembles an **evidence-derived** package → routes to **human disposition** (VALIDATED / CONDITIONAL / REJECTED) → archives immutably for the retention period → publishes a **readiness signal** to formal change control (URS-13). It never authorises its own release.

**Non-negotiable invariants (regulatory):**

1. **AI is advisory only.** Generative models (Claude/GPT) **must not** set or modify `validation_result`, `run.status`, `overall_result`, or any disposition. AI divergence/unavailability raises a separate `ai_review_status` **hold**, never a result change. (DEC-40-02; SV-REQ-008/009/030; SV-COR-004/009/018.)
2. **The decision of record is deterministic + human.** Run status derives only from executed tests against acceptance criteria; disposition is a human e-signature.
3. **CONDITIONAL is a human disposition, not a run result.** Factual run results are `passed/failed/blocked/skipped/aborted`. CONDITIONAL requires a linked, approved deviation in URS-16. (SV-REQ-034; SV-COR-015.)
4. **No false records.** No run is `passed` without real evidence; empty `details` and null evidence hashes are prohibited. (SV-COR-006.)
5. **Predicate-scoped Part 11.** Part 11 controls apply per record type only where a predicate rule applies / the record is relied upon for a regulated activity / it is submitted to FDA. Not asserted blanket. (SV-COR-028.)
6. **Annex 22 / EU AI Act are anticipatory.** Annex 22 is draft (not on EudraLex's in-force list); EU AI Act classification is pending. Neither is asserted as in-force-binding or "met". (SV-COR-025; §9.2 of the Target-State URS.)

---

## 1A. Diagrams (lifecycle · architecture · target state-machines · sequence · build order)

These are the controlled diagrams from the URS-40 Target-State module (verified-clean: factual run results `passed/failed/blocked/skipped/aborted`; CONDITIONAL on the human-disposition layer; AI as a separate advisory `ai_review_status` hold that never changes the result). The build-order flow (40-EBS-5) is this document's §6.

**Diagram 40-EBS-1 — Self-validation lifecycle (target state).**
```mermaid
stateDiagram-v2
  state "Self-Validation Lifecycle" as SVLC {
    [*] --> change_detected : F8 job / deploy / migration / config / model-or-prompt change
    change_detected --> classified : classify GAMP cat + impact + risk + scope
    classified --> plan_draft : generate validation plan (IQ/OQ/PQ test cases + acceptance criteria)
    plan_draft --> plan_agent_reviewed : dual-model AI advisory review (Claude + GPT)
    plan_agent_reviewed --> plan_pending_approval : routed to validation/QA
    plan_pending_approval --> plan_approved : approver e-signs (author != approver)
    plan_pending_approval --> plan_rejected : approver e-signs rejection (terminal)
    plan_approved --> run_running : executeValidation (real IQ/OQ/PQ)
    run_running --> run_passed : results meet acceptance criteria
    run_running --> run_failed : results fail acceptance criteria
    run_running --> run_blocked : precondition/runner error
    note right of run_running : Factual run results only (passed / failed / blocked / skipped / aborted). 'conditional' is NOT a run result — it is a human disposition (below). AI cross-check runs in parallel as an advisory ai_review_status hold and NEVER sets run state or validation_result (SV-REQ-009/018/030).
    run_passed --> package_draft : assemble package from real evidence + hash
    run_failed --> package_draft : reviewable record of failure
    run_blocked --> package_draft
    package_draft --> package_agent_reviewed : dual-model AI advisory review
    package_agent_reviewed --> package_pending_approval : routed to QA
    package_pending_approval --> disp_validated : QA e-signs VALIDATED (no mandatory failure)
    package_pending_approval --> disp_conditional : QA e-signs CONDITIONAL (linked approved deviation, URS-16)
    package_pending_approval --> package_rejected : QA e-signs rejection / not-accepted
    disp_validated --> archived : retained, immutable (package_hash)
    disp_conditional --> archived
    plan_rejected --> [*]
    package_rejected --> [*]
    archived --> [*]
  }
```

**Diagram 40-EBS-2 — Module architecture & cross-module wiring.**
```mermaid
graph LR
  subgraph M40 [Module 40 — Self-Validation / Validation-Automation Engine]
    DET[Change Detection<br/>validation-change-detection.job.ts F8 / 30 min]
    CHG[Change Register<br/>system_changes]
    CLS[Classification<br/>GAMP / impact / risk / scope]
    PLAN[Validation Plan<br/>validation_plans]
    RUN[Execution + Results<br/>validation_runs]
    EVID[Objective Evidence<br/>validation_screenshots]
    AICK[Dual-Model Cross-Check<br/>Claude + GPT - advisory]
    PKG[Validation Package + hash<br/>validation_packages]
    ESIG[HITL E-Signature Gate<br/>SoD author != approver]
    DASH[Validation Dashboard<br/>ValidationDashboard.tsx]
  end

  M35[URS-35 Infrastructure / deploy] --> DET
  M13[URS-13 Change Control] --> CHG
  DET --> CHG --> CLS --> PLAN --> RUN --> EVID
  PLAN --> AICK
  RUN --> AICK
  AICK --> PKG
  RUN --> PKG --> ESIG --> DASH
  M02[URS-02 RBAC<br/>resource: validation] --> ESIG
  M03[URS-03 Context Gate / scope] --> CHG
  M04[URS-04 Workflow / HITL / E-Sign] --> ESIG
  M05[URS-05 Authority Profiles] --> ESIG
  M06[URS-06 Audit Substrate] <-- PKG
  M32[URS-32 MIRA-AI / AI Provider Gateway<br/>llm_audit_log] --> AICK
  M30[URS-30 Notifications] --> AICK
  M22[URS-22 Inspection Readiness] <-- PKG
  M38[URS-38 Dashboards] <-- DASH
  ANNEX22[Internal Annex 22 control — GenAI advisory-only in validation evidence] -.governs.-> AICK
  ARCHAI[ARCH-AI-001 advisory-AI governance] -.governs.-> AICK
  ESIG -.decision of record.-> PKG
```

**Diagram 40-EBS-3 — Target state-machines: result / AI-review / disposition separation.**
```mermaid
stateDiagram-v2
  state "validation_plans.status" as P {
    [*] --> draft
    draft --> agent_reviewed : dual-model AI advisory
    agent_reviewed --> pending_approval
    pending_approval --> approved : e-sign (author!=approver)
    pending_approval --> rejected
    approved --> superseded : new plan version
  }
  state "validation_runs.status (factual result — TARGET)" as R {
    [*] --> pending
    pending --> running : executeValidation
    running --> passed : meets acceptance_criteria
    running --> failed : fails acceptance_criteria
    running --> blocked : precondition/runner error
    note right of running : Factual run results ONLY (passed / failed / blocked / skipped / aborted). 'conditional' is NOT a run result. migration-052's run enum currently still includes 'conditional' — a defect to be removed (SV-COR-015 / SV-REQ-018).
  }
  state "ai_review_status (separate, advisory)" as AIR {
    [*] --> ai_none
    ai_none --> ai_hold : divergence > threshold OR unavailable
    ai_hold --> ai_resolved : QA/Validation reviewer resolves, with reason + audit; e-sign if it affects disposition — validation_result unchanged (SV-REQ-009/030)
  }
  state "validation_packages — disposition (human)" as K {
    [*] --> draft
    draft --> agent_reviewed
    agent_reviewed --> pending_approval
    pending_approval --> validated : QA e-signs VALIDATED (no mandatory failure)
    pending_approval --> conditional : QA e-signs CONDITIONAL (linked approved deviation, URS-16)
    pending_approval --> rejected : QA e-signs rejection / not-accepted
  }
```

**Diagram 40-EBS-4 — Dual-model AI cross-check (advisory) sequence.**
```mermaid
sequenceDiagram
  participant ENG as Engine
  participant GW as AI Provider Gateway (URS-32)
  participant CL as Anthropic Claude
  participant GP as OpenAI GPT
  participant LOG as llm_audit_log
  participant QA as QA Approver (human)
  ENG->>GW: review(plan/run/package, acceptance_criteria)
  GW->>CL: independent review request
  GW->>GP: independent review request
  CL-->>GW: score + findings
  GP-->>GW: score + findings
  GW->>LOG: log provider, model+version, prompt version, input hash, output
  GW-->>ENG: two advisory reviews + agreement/divergence
  alt divergence > threshold OR AI unavailable
    ENG->>ENG: set ai_review_status = hold + notify (URS-30) — validation_result UNCHANGED
  end
  ENG-->>QA: advisory report (labelled) + real run evidence
  QA->>QA: human decision + e-signature (decision of record)
```

**Diagram 40-EBS-5 — Prioritised build order (this document §6).**
```mermaid
flowchart TD
  S1[1. Migration: created_by/updated_by on all 5 tables + DDL b-e<br/>ADD-VER-03 / SV-COR-020 — unblocks all service execution] --> S2[2. Real execution<br/>SV-COR-006]
  S2 --> S3[3. E-signature ceremony<br/>SV-COR-005]
  S3 --> S4[4. Pass-rate units<br/>SV-COR-027]
  S4 --> S5[5. RBAC verbs + 4 unprotected routes<br/>SV-COR-012]
  S5 --> S6[6. AI gateway inject + fail-closed audit<br/>SV-COR-004/018]
  S6 --> S7[7. FE/BE contract + shared Zod DTOs<br/>SV-COR-011]
  S7 --> S8[8. Transactional audit + service-principal UUID<br/>SV-COR-010/024 / ADD-VER-01/02]
  S8 --> S9[9. Source-state enforcement + transition history<br/>SV-COR-010]
  S9 --> S10[10. Immutable archive + ON DELETE RESTRICT<br/>SV-COR-008/019]
  S10 --> GRP[Then: detect/classify/plan 001-003; evidence-derived package 007;<br/>result/review/disposition 009/015; executable protocols 013;<br/>master-change/idempotency/baseline/reject-history/provider-DP 016/017/022/023/026; replace tests 029]
  GRP --> OWN[Close with owners: 014 independence · 028 predicate-rule map · 025 numbering]
```

---

## 2. Verified current state at `3bd2fe47` (what exists; what is defective)

**Database-backed skeleton only — NOT executed, NOT approved.** Built and holding: the F8 job (`detectChanges()`, every 30 min), five RLS-isolated tables (`system_changes`, `validation_plans`, `validation_runs`, `validation_screenshots`, `validation_packages`) with `tenant_isolation` policies, route/service scaffolding for the full lifecycle, a hash-chain-capable audit service, and a partial SoD (creator ≠ approver) check. These are legitimate regulatory foundations.

**Verified defects (line-pinned at `3bd2fe47`, module `packages/backend/src/modules/competitive/`):**

| Area | Evidence | Requirement |
|---|---|---|
| Auto-pass execution (false record) | `self-validation.service.ts` 458–460 `details:[]`, 464 `passRate = 100`, 474 `status:'passed'`, 481 `pass_rate` | SV-COR-006 |
| Hardcoded classification | 134–135 null then classify hardcodes `4b/medium/medium/partial` (161–164) | SV-COR-002 |
| Provenance nulled on registration | `registerChange()` writes `deployment_id/migration_number/git_commit_hash/git_branch/changed_files/changed_tables` empty/null | SV-COR-001/016 |
| Placeholder IQ/OQ/PQ | plan emits `iq-1/oq-1/pq-1`; `steps` are plain strings (250/258/266) | SV-COR-003/013 |
| AI review absent / gateway not injected | `submitPlanForAgentReview`/`submitPackageForAgentReview` only set status; `new SelfValidationService(t, audit)` — gateway not injected; `llmAudit?` optional | SV-COR-004/018 |
| E-signature non-functional | `approvePlan()` stores `esignature_id: null` (291); `conditionallyApprovePackage()` drops `_esignatureId` (742+); `approvePackage()` stores raw id w/o ceremony (725) | SV-COR-005 |
| Screenshot hash null | `captureScreenshot()` 548 `image_hash: null` | SV-COR-006/019 |
| Package hash over IDs only | `package_hash` covers `{runId, planId, completed_at}` (619) | SV-COR-007/019 |
| Package born VALIDATED | `generateValidationPackage()` sets `overall_result: run.status==='passed' ? 'VALIDATED' : 'FAILED'` before human disposition | SV-COR-015 |
| Archive = timestamp only | `archivePackage()` 789 sets `archived_at` only; no immutability guard | SV-COR-008/019 |
| `ON DELETE CASCADE` evidence chain | migration 052: 646/680/710/739 | SV-COR-019 |
| `created_by`/`updated_by` absent in migration 052 (all 5 tables) but service writes `created_by` | runtime-insert blocker | ADD-VER-03 / SV-COR-020 |
| `pass_rate` unit mismatch | plan `pass_rate_minimum: 0.95` vs run `pass_rate: 100` → `100 ≥ 0.95` always true | SV-COR-027 |
| RBAC under-scoped | 4 routes lack permission config (register-change POST 22, list-changes GET 33, list-plans GET 74, conditional POST 213); protected routes use `action:'create'` only | SV-COR-012 |
| Audit non-atomic / incomplete | audit written outside the mutation txn; 4 mutations unaudited (`submitPackageForAgentReview`, `conditionallyApprovePackage`, `rejectPackage`, `archivePackage`) | SV-COR-010/024 / QS-1 |
| Engine actor = string `'system'` | `detectChanges()` 190 + `submitPlanForAgentReview()` 368 `userId:'system'` (not a UUID) | ADD-VER-01 / SV-COR-020 |
| Transitions not gated | `approvePlan/rejectPlan/approvePackage/rejectPackage` don't check source state | SV-COR-010 / ADD-VER-02 |
| Rejection reason discarded | `rejectPlan` (421/`_reason` 425), `rejectPackage` (767/`_reason` 771) ignore the reason | SV-COR-023 |
| FE/BE contract broken | FE calls `POST /validation/plans`, `/plans/:id/execute`, `GET /plans/:id/runs`, `GET /packages`; BE serves `/plans/generate/:changeId`, `/runs/execute/:planId`, no `/plans/:id/runs`, no `GET /packages` | SV-COR-011 |
| Tests accept defective behaviour | unit tests assert object existence + accept `passed/100/null hash` | SV-COR-029 |

Full verbatim code excerpts: Drift Register **Appendix A** (EV-01…EV-10).

---

## 3. Build requirements — full PECRA (SV-COR-001…029 + ADD-VER-01…03)

Each requirement carries: **Current state** (verified @ `3bd2fe47`), **Requirement** (`shall`), **Acceptance** (executed OQ), **Basis** (regulatory). All P0 unless marked otherwise. Acceptance is by executed OQ on a test tenant with QA/Validation disposition.

### 3.1 Core corrective spec (SV-COR-001…008)

**SV-COR-001 — Change Detection & Registration.**
- *Current state:* `registerChange()` writes `deployment_id/migration_number/git_commit_hash/git_branch/changed_files/changed_tables` as null/empty; `detectChanges()` only lists existing unclassified rows rather than detecting source events.
- *Requirement:* The system **shall** register every validation-relevant change with attributable source, change type, affected objects, and immutable provenance (commit, branch, files, tables, deployment id, migration number, actor). No plan may generate until classified; missing provenance blocks automated classification unless manually justified. The audit row **shall** be written atomically with the change; registration fails closed if the audit write fails.
- *Acceptance:* each change source (deploy / migration / config / prompt / model / RBAC) creates exactly one attributable record + hash-chain audit entry; a registration with missing provenance cannot auto-classify.
- *Basis:* 21 CFR 11.10(a)/(e); Annex 11 §9; ALCOA+ Attributable.

**SV-COR-002 — Risk-Based Classification.**
- *Current state:* `classifyChange()` hardcodes `gamp='4b', impact='medium', risk='medium', scope='partial'` (161–164) for every change.
- *Requirement:* The system **shall** classify via approved, versioned risk rules and **shall not** hardcode `medium/partial`. Audit, e-signature, RBAC, workflow-gating, data-retention, tenant-isolation, AI-provenance, and execution changes default to **high** unless downgraded with approved rationale (high-risk downgrade requires e-sign).
- *Acceptance:* a high-risk change (e.g. RBAC or e-signature) does not classify as `medium/partial` by default; downgrade requires a signed rationale.
- *Basis:* ICH Q9(R1); GAMP 5 risk-based; Annex 11 §1.

**SV-COR-003 — IQ/OQ/PQ Plan Generation.**
- *Current state:* plan emits three placeholders `iq-1/oq-1/pq-1`; PQ case is literally "Review with business" (250/258/266).
- *Requirement:* The system **shall** generate plans from an approved protocol library mapped to affected requirement IDs, modules, routes, schemas, and risk class — including negative, boundary, RBAC, audit, e-signature, tenant-isolation, and AI-provenance tests. Placeholder-only cases are prohibited; if no protocol exists for an affected control, the plan is blocked.
- *Acceptance:* no generated plan contains placeholder-only tests; an affected control with no library protocol blocks plan generation.
- *Basis:* GAMP 5 verification; Annex 11 §4.7.

**SV-COR-004 — Advisory Dual-Model AI Review.**
- *Current state:* `submitPlanForAgentReview()`/`submitPackageForAgentReview()` only set `status='agent_reviewed'`; no model call, no audit.
- *Requirement:* The system **shall** run Claude and GPT independently through the **URS-32 AI Gateway (`/api/v1/ai/*`)**, advisory only, capturing model, version, prompt, input/output hash, findings, confidence, divergence, and human disposition to `ai_governance_events` + `llm_audit_log`. AI **cannot** approve/reject/pass/fail/change status. AI unavailable → explicit `ai_unavailable_manual` (no silent proceed); divergence > threshold blocks approval until human resolution.
- *Acceptance:* two model calls produce two audit records; divergence raises a hold; no AI path sets a status.
- *Basis:* GMLP; EU AI Act Art. 13/14 (anticipatory); Annex 22 advisory-only (anticipatory).

**SV-COR-005 — Human E-Signature Ceremony.**
- *Current state:* `approvePlan()` stores `esignature_id: null` (291); `conditionallyApprovePackage()` drops `_esignatureId` (742+); `approvePackage()` stores the raw id (725) without ceremony validation; routes accept optional/empty signature.
- *Requirement:* The system **shall** require a valid e-signature ceremony (password/MFA/challenge via the HITL/e-sign service) for plan approval, package disposition, conditional approval, and (where configured) rejection. Empty/missing `esignature_id` is rejected; the signature is linked to record ID + version + hash + signer + timestamp + meaning + outcome; it cannot be reused; a record change after signing invalidates/supersedes the signature. SoD enforced.
- *Acceptance:* missing signature, wrong user, creator self-approval, reused signature, and post-signature mutation all fail.
- *Basis:* 21 CFR 11.50/11.70; Annex 11 §14.

**SV-COR-006 — Real Execution & Evidence Capture.**
- *Current state:* `executeValidation()` hardcodes `details:[]` (458–460), `passRate = 100` (464), `status:'passed'` (474); `captureScreenshot()` stores `image_hash: null` (548).
- *Requirement:* The system **shall** execute real IQ/OQ/PQ and derive run status from actual results: per-test expected/actual, evidence file, screenshot/artifact **hash**, DB before/after, pass/fail/block reason, executor, timestamp. No run is `passed` unless all mandatory acceptance criteria are met; empty `details` prohibited; runner error → `failed`/`blocked`, never auto-pass.
- *Acceptance:* a forced failure yields `failed` (not `passed`); a captured artifact has a non-null verifiable hash; empty evidence is rejected.
- *Basis:* 21 CFR 11.10(a)/(b); ALCOA+ Accurate/Original; Annex 11 §4.7.

**SV-COR-007 — Evidence-Derived Package.**
- *Current state:* package built with empty `documents` + empty `agent_review_report`; `package_hash` covers `{runId, planId, completed_at}` only (619).
- *Requirement:* The system **shall** assemble packages only from real plan/run/evidence/audit/AI/signature records: manifest, protocol, results, failures, deviations, artifacts, audit-chain references, AI advisory review, disposition, and a `package_hash` covering the manifest + every evidence reference. Empty `documents` or empty `agent_review_report` blocks approval for AI-reviewed flows; the package feeds inspection/dashboard only after approval.
- *Acceptance:* `package_hash` changes when any included evidence changes; an empty-evidence package cannot be approved.
- *Basis:* 21 CFR 11.10(b) complete copies; Annex 11 §8.

**SV-COR-008 — Immutable Archive & Retention.**
- *Current state:* `archivePackage()` sets `archived_at` only (789); no write guard.
- *Requirement:* Approved/conditional packages **shall** be immutable (no update/delete to the package or included evidence except a controlled supersede/correction workflow with full audit + e-signature) and retrievable for the full retention period; the archive event is audited; corrections preserve the original.
- *Acceptance:* update/delete attempts on an archived package/evidence fail; the original is retrievable after a controlled supersede.
- *Basis:* 21 CFR 11.10(c); Annex 11 §17.

### 3.2 Independent-review hardening — full PECRA (SV-COR-009…018)

**SV-COR-009 — Separate deterministic result from AI review.**
- *Current state:* the engine carries no field separating the executed-test result from the AI review state; AI review and result are conflated in the lifecycle.
- *Requirement:* `validation_result` **shall** derive only from executed tests + deterministic acceptance criteria; AI review **shall not** set or modify it. AI divergence or unavailability creates a **review hold** in a distinct `ai_review_status` field (`ai_none/ai_hold/ai_resolved`), never a result change. The two fields are stored and displayed separately.
- *Acceptance:* forcing an AI divergence sets `ai_review_status='ai_hold'` and leaves `validation_result` unchanged; no code path lets AI write `validation_result`.
- *Basis:* EU Annex 22 advisory-only (anticipatory); EU AI Act Art. 14 (anticipatory); QS-21.

**SV-COR-010 — Non-bypassable lifecycle transitions.**
- *Current state:* `approvePlan/rejectPlan/approvePackage/rejectPackage` do not check the current status before transitioning; audit is written outside the mutation transaction; 4 mutations are unaudited.
- *Requirement:* Every transition **shall** validate allowed source-state + authority + evidence + signature before mutating; an append-only `validation_transition_history` table records (from_state, to_state, actor, reason, signature ref, timestamp). The audit write **shall** be in the same transaction as the business mutation; a failed audit write **shall** fail the mutation.
- *Acceptance:* approving a `draft` plan (skipping `pending_approval`) is rejected; a forced audit-write failure rolls back the business mutation; every mutation has a transition-history + audit row.
- *Basis:* Annex 11 §12; 21 CFR 11.10(e)/(f); QS-1.

**SV-COR-011 — Canonical API contract / FE↔BE wiring.**
- *Current state:* FE calls `POST /validation/plans`, `POST /plans/:id/execute`, `GET /plans/:id/runs`, `GET /packages`; BE serves `POST /plans/generate/:changeId`, `POST /runs/execute/:planId`, `GET /runs/:id`, `GET /packages/:id` — none of the FE calls match.
- *Requirement:* One **versioned** API contract **shall** be the single source of truth; the BE **shall** implement every route the FE calls (path, method, params); shared **Zod DTOs** (from `packages/shared`) **shall** validate both request and response at the boundary; field names reconciled (`change_description` vs `description`).
- *Acceptance:* an automated contract test exercises every FE-invoked route end-to-end and passes; no FE call 404s; request/response validate against the shared schema.
- *Basis:* Annex 11 §5 (data exchange integrity); QS-8/QS-18.

**SV-COR-012 — Canonical RBAC vocabulary + authority.**
- *Current state:* 4 routes lack permission config (register-change POST 22, list-changes GET 33, list-plans GET 74, conditional POST 213); all protected routes use `action:'create'`/`'read'` only — no `approve/execute/manage`.
- *Requirement:* Routes **shall** use the canonical vocabulary `validation:read | manage | execute | approve`; every route (including the four unprotected ones) **shall** carry a permission config; approval routes **shall** additionally validate effective authority + SoD (creator ≠ approver), and SoD **shall not** be bypassable when `created_by` is NULL.
- *Acceptance:* each of the four routes denies an unauthorised role; an `execute` role cannot `approve`; a NULL-`created_by` row does not bypass SoD.
- *Basis:* 21 CFR 11.10(d)/(g); Annex 11 §12; QS-7.

**SV-COR-013 — Executable protocol model + qualified harness.**
- *Current state:* test cases carry `steps: string[]` of plain prose (250/258/266) — strings that drive no automation.
- *Requirement:* Each test case **shall** carry an execution mode, runner reference, machine-evaluable assertion rule, dataset reference, DB before/after capture, evidence rule, timeout, and cleanup. Plain strings **shall not** drive automation; a runner error → `blocked`/`failed`, never `passed`. The test harness **shall** be qualified before use.
- *Acceptance:* a test case with only prose steps cannot execute; a runner timeout produces `blocked`/`failed`; harness qualification evidence exists.
- *Basis:* GAMP 5 (automated test tooling); Annex 11 §4.7.

**SV-COR-014 — Independent qualification boundary.**
- *Current state:* no independent-harness or independent-qualification evidence; the engine would be the sole evidence for its own qualification.
- *Requirement:* The engine **shall not** be the sole evidence for its own initial qualification, major-change re-qualification, protocol-library qualification, or harness qualification. An independent verification path (separate tooling, reviewer, or manual protocol) **shall** corroborate.
- *Acceptance:* the qualification package for the engine includes independent (non-self-generated) evidence.
- *Basis:* GAMP 5 independence of verification. *Owner note:* the independence **threshold** is owned by the **CSV/CSA Validation Strategy** (handoff; see §5).

**SV-COR-015 — Separate result / review / disposition / deviation.**
- *Current state:* `generateValidationPackage()` sets `overall_result: run.status==='passed' ? 'VALIDATED' : 'FAILED'` before any human disposition; conditional status is set later as free text with no deviation linkage.
- *Requirement:* Distinct fields **shall** exist for execution result, AI review state, and signed human disposition. A failed mandatory test **shall not** become `VALIDATED`. **CONDITIONAL is a human disposition** (not a run result) and **shall** link an approved `deviation_id` (owner, due date, closure e-sign) managed in **URS-16 (Deviations)**; `deviation_link` is added to the package schema (§4 DDL).
- *Acceptance:* a package with a failed mandatory test cannot be set `VALIDATED`; a CONDITIONAL disposition without a linked approved URS-16 deviation is rejected.
- *Basis:* 21 CFR 11.10(a); Annex 11 §1; QS-23. *Owner note:* deviation lifecycle owned by URS-16.

**SV-COR-016 — Platform master-change + tenant-impact model.**
- *Current state:* `system_changes` is tenant-scoped; provenance is null; a platform deploy/migration has no single canonical master record with per-tenant impact links.
- *Requirement:* Each deployment/migration/config/model/prompt change **shall** be one canonical master change with linked environment + tenant-impact records; duplicate unlinked per-tenant records are prohibited.
- *Acceptance:* a single platform migration produces one master change with N linked tenant-impact rows, not N independent rows.
- *Basis:* Annex 11 §10 (change control); QS-12.

**SV-COR-017 — Idempotency, concurrency, recovery.**
- *Current state:* no idempotency key, execution lock/lease, or recoverable-state model is evidenced.
- *Requirement:* The engine **shall** use idempotency keys + an execution lock/lease + recoverable states (`queued/running/blocked/failed/aborted`); an interrupted run **shall not** be `passed`; retries **shall not** duplicate or erase evidence.
- *Acceptance:* a killed-mid-run execution recovers to `blocked`/`failed` (never `passed`); a duplicate submit is idempotent; a retry does not create duplicate evidence.
- *Basis:* Annex 11 §4.4/§16; ALCOA+ Original/Complete.

### 3.3 Independent-review hardening — full PECRA (SV-COR-018…029)

**SV-COR-018 — Canonical dual-provider AI gateway + mandatory audit.**
- *Current state:* the competitive plugin registers **both** `azure_openai` + `anthropic` and builds `AiGatewayService` with both (`plugin.ts:70–71/111–112`), but (a) `SelfValidationService` is built `new SelfValidationService(t, audit)` — the gateway is **not injected** into it; and (b) the gateway's `llmAudit?` dependency is **optional** (`ai-gateway.service.ts:100`; `fastify.aiGovernance?.llmAudit`) — **not fail-closed**.
- *Requirement:* Claude + GPT **shall** be reached **only** via the URS-32 Gateway as two independent providers; the AI/LLM audit **shall** be **fail-closed** — a missing `llmAudit` makes the review *incomplete* (no silent proceed); the gateway **shall** be injected into `SelfValidationService`; no private/direct provider calls.
- *Acceptance:* with `llmAudit` unavailable, AI review cannot complete; the gateway is a constructor dependency of `SelfValidationService`; no provider SDK is called outside the gateway.
- *Basis:* GMLP; QS-21/QS-22; Annex 22 advisory-only (anticipatory).

**SV-COR-019 — Evidence store, manifest hashing, retention, deletion-protection.**
- *Current state:* `package_hash` covers `{runId, planId, completed_at}` only (619); screenshot `image_hash: null` (548); the evidence chain uses `ON DELETE CASCADE` (migration 052: 646/680/710/739).
- *Requirement:* `package_hash` **shall** cover the full manifest + every artifact (documents, results, screenshots, AI report, conditions, signatures). The evidence chain **shall** replace `ON DELETE CASCADE` with **`ON DELETE RESTRICT`** (block parent/tenant deletion while evidence is retained) + a retention-hold flag; tenant offboarding/legal-hold uses a controlled archive/export, never a cascade delete; an immutability guard (DB trigger or app-layer) blocks UPDATE/DELETE on approved runs/packages.
- *Acceptance:* changing any included artifact changes `package_hash`; a parent/tenant delete with retained evidence is blocked (RESTRICT); UPDATE/DELETE on an approved package fails.
- *Basis:* 21 CFR 11.10(c)/(e); Annex 11 §8/§17; ALCOA+ Original.

**SV-COR-020 — Attribution + schema/migration reconciliation.**
- *Current state:* `created_by`/`updated_by` are absent from migration 052 for all five tables, yet the service writes `created_by`; engine writes use the literal string `'system'` (see ADD-VER-01/03).
- *Requirement:* All actor fields **shall** be populated with a named identity (engine writes use a stable **service-principal UUID** that cannot approve — never NULL, never an email-in-UUID, never the literal `'system'`); migration/schema/types/runtime DB **shall** be reconciled; schema drift **shall** block release; migration verification is part of IQ.
- *Acceptance:* every engine record carries a non-null UUID actor; an IQ schema-reconciliation check fails the release on drift; no `created_by` insert targets a non-existent column.
- *Basis:* ALCOA+ Attributable; Annex 11 §2/§4.4; QS-2.

**SV-COR-021 — Change-control / release-gate integration. (OPEN DEPENDENCY — freeze blocker)**
- *Current state:* the engine has no release-authority separation; the interface to formal change control is undefined.
- *Requirement:* The engine **shall** publish a validation-readiness signal to the formal release gate and **shall not** autonomously authorise production release; failed/unsigned/missing evidence → release blocked. The **receiving release gate is URS-13 (Change Control)**; the interface (status field, event, or API route by which URS-13 receives the signal) **shall** be specified jointly in URS-13 + §7.1 of the Target-State URS **before approval**.
- *Acceptance:* the engine cannot mark a change releasable; URS-13 receives and gates on the readiness signal via the defined interface.
- *Basis:* Annex 11 §10; FDA CSA. *Status:* interface undefined — **blocks freeze** until specified with URS-13 (see §5).

**SV-COR-022 — Controlled test data + environment baseline.**
- *Current state:* a run stores results/timestamps only; no environment or dataset baseline is captured.
- *Requirement:* Each run **shall** capture a versioned environment + dataset baseline (app/commit/migration/config/feature-flag/model/prompt/dataset hashes); no production PHI/PII unless approved; baseline drift blocks or invalidates the run.
- *Acceptance:* a run records its full environment baseline; a drift between baseline and execution environment blocks/invalidates the run.
- *Basis:* GAMP 5 (test environment control); Annex 11 §4.4/§5.3 (training/test data separation, anticipatory Annex 22).

**SV-COR-023 — Rejection / correction / reopen / supersede history.**
- *Current state:* `rejectPlan` (421, `_reason` 425) and `rejectPackage` (767, `_reason` 771) accept a reason parameter but discard it (underscore = unused).
- *Requirement:* The system **shall** persist reason + actor + prior state + version for every reject/correct/reopen/supersede; a rejection without a reason **shall** fail; a signed record **shall not** return to `draft`.
- *Acceptance:* a rejection with no reason is rejected; the persisted reject record carries reason+actor+prior-state+version; a signed record cannot be reopened to draft.
- *Basis:* 21 CFR 11.10(e); Annex 11 §9; ALCOA+ Complete.

**SV-COR-024 — Operational monitoring + failure notification. [P1]**
- *Current state:* performance/observability is `Unknown` in the URS; a failed audit write does not fail the mutation.
- *Requirement:* The system **shall** monitor and alert on missed jobs, backlog, stuck runs, and evidence/audit/package/archive failures; a **failed audit write shall fail the mutation** (cross-ref SV-COR-010).
- *Acceptance:* a stuck/missed run raises an alert; an injected audit-write failure fails the originating mutation.
- *Basis:* Annex 11 §16; QS-19. *Owner note:* observability largely owned by **URS-35** — adopt advisory.

**SV-COR-025 — Document-control, numbering, regulatory-claim governance.**
- *Current state:* `DEC-39-*`/`M39`/pilot-index "URS-39" references appear inside URS-40 lineage; regulatory-claim language must be governed.
- *Requirement:* One canonical module number **shall** be used (resolve `DEC-39-*`/`M39`/pilot "URS-39" in the repo `CLAUDE.md` and any code comments to URS-40/DEC-40/M40); the system **shall not** present Annex 22 as in-force binding; **shall not** assert EU AI Act Art. 13/14 as "met" without a documented risk classification; **shall not** claim the engine eliminates customer validation.
- *Acceptance:* no `DEC-39/M39/URS-39` reference remains in URS-40-scoped artefacts; no in-force-binding claim for Annex 22 / EU AI Act exists; no "eliminates customer validation" claim exists.
- *Basis:* GDocP; QS-25 (regulatory-claim governance). *Status:* repo `CLAUDE.md` DEC-39/M39 cleanup is an **open code-side action** (the URS masters are clean — DEC-40/M40, verified 0 leakage).

**SV-COR-026 — AI provider data protection (engine-scoped parts).**
- *Current state:* the URS states "no PHI in prompts" but there is no technical enforcement.
- *Requirement:* The system **shall** redact/block PHI/PII/secrets/raw screenshots before any provider call; **no credentials in prompts/logs/exports**; approved provider + region routing; fail-closed to manual review if provider-control evidence is absent.
- *Acceptance:* an injected PHI/secret payload is redacted/blocked before the gateway call; absent provider-control evidence forces manual review.
- *Basis:* QS-19/QS-26; Annex 11 §7. *Owner note:* DPA / residency / subprocessor / supplier-qualification owned by **Security/Privacy + Supplier-Quality** (handoff).

**SV-COR-027 — Acceptance-criteria & pass-rate unit integrity.**
- *Current state:* the plan stores `pass_rate_minimum: 0.95` (fraction) while the run writes `pass_rate: 100` (percent); a naive `100 ≥ 0.95` is always true.
- *Requirement:* Pass-rate units **shall** be fixed and validated; `pass_rate_minimum` and `pass_rate` **shall** use the same unit; the run **shall** be evaluated against the plan's criteria in matching units at evaluation time.
- *Acceptance:* a catastrophically failed run fails the acceptance-criteria check; a unit-mismatch is caught by validation, not silently passed.
- *Basis:* 21 CFR 11.10(a); ALCOA+ Accurate.

**SV-COR-028 — Part 11 applicability / predicate-rule map. (before approval)**
- *Current state:* the URS applies Part 11 / Annex 11 / ALCOA+ to all records without a per-record predicate-rule determination.
- *Requirement:* The documentation **shall** record, per record type, whether each electronic record is required by a predicate rule, relied upon for a regulated activity, or submitted to FDA, and apply Part 11 controls accordingly. Part 11 **shall not** be asserted for every record without this determination. (Starter map exists in §10.1 of the Target-State URS — owner: Head of QA / DI Lead.)
- *Acceptance:* a completed, QA/DI-signed predicate-rule applicability map exists for each of the five record types.
- *Basis:* 21 CFR Part 11 scope; FDA CSA. *Status:* map is a **starter draft** — must be QA/DI/Legal-confirmed before any compliance statement.

**SV-COR-029 — Validation tests vs executed OQ.**
- *Current state:* unit tests assert object existence and accept `passed`/`pass_rate:100`/empty evidence/null hashes/empty documents — i.e. they are regression tests for the defective behaviour.
- *Requirement:* Existing unit tests that accept defective behaviour **shall** be replaced; automated unit tests **shall not** be presented as executed OQ evidence; OQ **shall** include forced-false-pass, empty-evidence, null-hash, wrong-role, and cross-tenant negative cases.
- *Acceptance:* the test suite fails on a forced false-pass / null-hash / empty-evidence; OQ evidence is distinct from the unit suite and includes the negative cases.
- *Basis:* GAMP 5 verification; 21 CFR 11.10(a) system validation; QS-15/QS-16.

### 3.4 Independent-verification additions (ADD-VER-01…03)

**ADD-VER-01 — Service-principal identity, not string `'system'`.**
- *Current state:* `detectChanges()` (190) and `submitPlanForAgentReview()` (368) write `userId: 'system'` (a string literal).
- *Requirement:* The F8 job and all engine-initiated writes **shall** use a stable service-principal **UUID** (least-privilege, cannot approve), never the literal `'system'`. (Strengthens SV-COR-020.)
- *Acceptance:* no engine write persists `'system'`; the actor is a resolvable UUID.
- *Basis:* ALCOA+ Attributable; QS-2.

**ADD-VER-02 — Source-state guard + audit on agent-review transitions.**
- *Current state:* `submitPackageForAgentReview` (687–698) transitions with no source-state guard and no `audit.log`; an "AI-reviewed" state can be set silently and out of sequence.
- *Requirement:* Agent-review transitions **shall** validate source state and **shall** write an audit + transition-history row in-transaction (consistent with SV-COR-010).
- *Acceptance:* an out-of-sequence agent-review transition is rejected; every agent-review transition is audited.
- *Basis:* Annex 11 §12; QS-1.

**ADD-VER-03 — `created_by`/`updated_by` migration (runtime-insert blocker, P0).**
- *Current state:* the service comment "schema aligned to migration 052" is incorrect — the service writes `created_by` to `validation_plans`/`validation_packages`, but migration 052 defines no such columns on any of the five tables; the service cannot run without a runtime insert error.
- *Requirement:* A new migration **shall** add `created_by`/`updated_by` (UUID) to **all five** tables (`system_changes`, `validation_plans`, `validation_runs`, `validation_screenshots`, `validation_packages`) before any service execution; `validation_runs` attribution **shall** also be populated.
- *Acceptance:* the service inserts succeed with non-null UUID attribution on all five tables; the IQ schema check confirms column presence.
- *Basis:* ALCOA+ Attributable; Annex 11 §4.4. *Status:* **P0 — unblocks all service execution; build first (§6 step 1).**

---

## 4. Target schema / migration (design spec — Architect + Data Integrity ratify before build)

New fields/tables required by the Critical requirements (SV-REQ-023/030/034; SV-COR-009/010/015/019/020). This is a **draft design specification** ratified by the Product/Engineering Architect + Data Integrity owner before build; it follows migration-052 conventions (idempotent, RLS, rollback). Exact migration number assigned at build time.

```sql
-- ROLLBACK: drop the columns/tables/policies added below.
-- (a) ALCOA+ attribution (SV-REQ-023 / SV-COR-020 / ADD-VER-03) — service-principal UUID, never NULL post-backfill
ALTER TABLE validation_plans       ADD COLUMN IF NOT EXISTS created_by UUID, ADD COLUMN IF NOT EXISTS updated_by UUID;
ALTER TABLE validation_runs        ADD COLUMN IF NOT EXISTS created_by UUID, ADD COLUMN IF NOT EXISTS updated_by UUID;
ALTER TABLE validation_packages    ADD COLUMN IF NOT EXISTS created_by UUID, ADD COLUMN IF NOT EXISTS updated_by UUID;
ALTER TABLE validation_screenshots ADD COLUMN IF NOT EXISTS created_by UUID, ADD COLUMN IF NOT EXISTS updated_by UUID;
ALTER TABLE system_changes         ADD COLUMN IF NOT EXISTS created_by UUID, ADD COLUMN IF NOT EXISTS updated_by UUID;

-- (b) Deterministic run result separated from AI review (SV-REQ-018/030, SV-COR-009) — 'conditional' REMOVED from run layer
ALTER TABLE validation_runs ADD COLUMN IF NOT EXISTS validation_result VARCHAR(10)
  CHECK (validation_result IN ('passed','failed','blocked','skipped','aborted'));
ALTER TABLE validation_runs ADD COLUMN IF NOT EXISTS ai_review_status VARCHAR(20)
  CHECK (ai_review_status IN ('ai_none','ai_hold','ai_resolved'));
ALTER TABLE validation_runs ADD COLUMN IF NOT EXISTS ai_review_resolution TEXT;
ALTER TABLE validation_runs ADD COLUMN IF NOT EXISTS ai_review_resolved_by UUID;     -- QA/Validation reviewer
ALTER TABLE validation_runs ADD COLUMN IF NOT EXISTS ai_review_resolved_at TIMESTAMPTZ;
-- migration to correct the legacy run enum: drop 'conditional' from validation_runs.status after data fix (separate controlled change).

-- (c) Human disposition layer (SV-REQ-034, SV-COR-015) — CONDITIONAL lives here, with a linked URS-16 deviation
ALTER TABLE validation_packages ADD COLUMN IF NOT EXISTS disposition VARCHAR(12)
  CHECK (disposition IN ('validated','conditional','rejected'));
ALTER TABLE validation_packages ADD COLUMN IF NOT EXISTS deviation_link UUID;          -- FK → URS-16 deviation (conditional only)
ALTER TABLE validation_packages ADD COLUMN IF NOT EXISTS release_readiness VARCHAR(16)
  CHECK (release_readiness IN ('not_ready','ready','blocked'));

-- (d) Append-only transition history (SV-COR-010/023)
CREATE TABLE IF NOT EXISTS validation_transition_history (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE RESTRICT,
  entity_type VARCHAR(20) NOT NULL CHECK (entity_type IN ('change','plan','run','package')),
  entity_id UUID NOT NULL,
  record_version INTEGER,
  from_state VARCHAR(30), to_state VARCHAR(30) NOT NULL,
  reason TEXT, transitioned_by UUID NOT NULL, transitioned_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  signature_id UUID, evidence_snapshot_hash VARCHAR(64)
);  -- append-only: no UPDATE/DELETE (enforce by grant + trigger)
ALTER TABLE validation_transition_history ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON validation_transition_history
  USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

-- (e) Evidence deletion protection (SV-COR-019) — replace CASCADE with RESTRICT on the evidence chain
--     (rebuild the child FKs from validation_plans/runs/screenshots/packages → parent as ON DELETE RESTRICT;
--      tenant offboarding / legal hold uses controlled archive-export, never cascade delete.)
```

**Architect / DI ratification items (resolve before build):** exact migration number; backfill plan for `created_by` on existing rows; `VARCHAR+CHECK` (shown) vs native ENUM for `validation_result`/`disposition`; immutability-guard mechanism (DB trigger vs app-layer) for approved runs/packages; the data-fix sequence to drop `conditional` from the legacy `validation_runs.status` enum; and whether `system_changes.triggered_by` (the actor who *caused* the change) and the new `created_by` (the actor who *created the database row* — the engine's service-principal where the row is written on behalf of a deployment event) are both retained — they carry different ALCOA+ Attributable semantics and should not be conflated.

---

## 5. Open dependencies & freeze blockers

These **must** be closed before URS-40 can be frozen/approved. They are not engineering-internal — each needs a named owner outside the build team.

| # | Dependency | Owner | Blocks |
|---|---|---|---|
| D-1 | **URS-13 release-gate interface** (SV-COR-021) — the status field / event / API by which Change Control receives the engine's readiness signal is undefined. | Engineering + URS-13 owner | Freeze |
| D-2 | **URS-16 deviation linkage** (SV-COR-015) — CONDITIONAL disposition must link an approved `deviation_id` (owner, due date, closure e-sign). | URS-16 (Deviations) owner | Approval of CONDITIONAL path |
| D-3 | **Predicate-rule / Part 11 applicability map** (SV-COR-028) — starter map in Target-State §10.1 must be completed and signed. | Head of QA / DI Lead (+ Legal where flagged) | Any Part 11 compliance statement |
| D-4 | **ARCH-AI-001 controlled-document pin** (§6.7) — supplied as `ARCH-AI-001 "AI Optionality and Manual Continuity" v1.0`, target QMS path `docs/architecture/ARCH-AI-001_AI-Optionality-and-Manual-Continuity.md`, status `DRAFT — not approved`. | AI Governance / Document Control | Freeze remains blocked until ARCH-AI-001 is approved and filed. |
| D-5 | **BCDR retention/backup-restore** (ALCOA+ Enduring) — retention period + backup/restore of the five tables owned by **URS-35**; period TBD by QA/DI. | URS-35 (Infrastructure) + QA/DI | Freeze |
| D-6 | **CSV/CSA Validation Strategy annex** (SV-COR-014) — independence threshold + claim wording for self-validation. | Validation Lead / Head of QA | Approval |
| D-7 | **Full PECRA depth: substantially closed** — 27 of 29 corrective requirements are implementation-grade in §3 (this document closes FDA-INS-017 for those). **SV-COR-021 (pending D-1) and SV-COR-014 (pending D-6) are written but cannot pass OQ until their external inputs exist** — they are not yet acceptance-testable. | Engineering (this doc) | 021 ↔ D-1; 014 ↔ D-6 |
| D-8 | **Repo `CLAUDE.md` DEC-39/M39 cleanup** (SV-COR-025) — code-side numbering action; URS masters are clean (DEC-40/M40). | Engineering | Document-control closure |

---

## 6. Prioritised build order

Dependency- and criticality-ordered. Each step's exit criterion is **executed OQ** (§7), not code review.

1. **Migration first (ADD-VER-03 / SV-COR-020):** add `created_by`/`updated_by` to all five tables (+ §4 DDL b–e). *Unblocks all service execution.*
2. **Real execution (SV-COR-006) + replace defective tests (SV-COR-029, in parallel):** replace the `executeValidation()` auto-pass stub with a real runner; evidence-derived results; failure path; non-null artifact hashes (SV-COR-019 hashing). **In the same step, replace the existing regression tests** (which accept `passed`/`pass_rate:100`/null-hash/empty-evidence) with negative tests **before** step 2 is considered complete — otherwise the suite stays green against a half-corrected implementation and OQ cannot run against it.
3. **E-signature ceremony (SV-COR-005):** `approvePlan`/`approvePackage`/`conditionallyApprovePackage` **persist and validate** the signature (link to record+version+hash+meaning; re-auth; non-reuse; SoD non-bypassable on NULL `created_by`).
4. **Pass-rate units (SV-COR-027):** unify `pass_rate`/`pass_rate_minimum` to one unit; evaluate at evaluation time.
5. **RBAC (SV-COR-012):** add `approve`/`execute`/`manage` verbs; add permission config to the four unprotected routes.
6. **AI gateway (SV-COR-004/018):** inject the URS-32 Gateway into `SelfValidationService`; implement dual-model calls; **fail-closed** `llm_audit_log`.
7. **FE/BE contract (SV-COR-011):** align route paths, methods, and shared Zod DTOs; contract test.
8. **Transactional audit (SV-COR-010/024 / ADD-VER-02):** wrap audit in the mutation transaction; cover the four unaudited mutations; service-principal UUID actor (ADD-VER-01).
9. **Source-state enforcement (SV-COR-010):** gate all lifecycle transitions on allowed source-state + authority + signature; write transition-history.
10. **Immutable archive (SV-COR-008/019):** immutability guard (trigger + `ON DELETE RESTRICT`); retention/retrieval.

Then: SV-COR-001/002/003 (detect/classify/plan), 007 (evidence-derived package), 009/015 (result/review/disposition separation), 013 (executable protocols), 016/017/022/023/026 (master-change, idempotency, baselines, reject history, provider data-protection). 014/028/025 close with their owners (§5). *(SV-COR-029 is pulled forward into step 2 — see above.)*

---

## 7. Acceptance gate — executed OQ (not unit tests)

No requirement is "done" on code review. Each closes only on **executed OQ on a test tenant** with QA/Validation disposition. The OQ suite **shall** include, at minimum, these negative cases (SV-COR-029):

- **Forced false-pass:** a run with a real failure yields `failed`, and the package cannot become `VALIDATED`.
- **Empty evidence / null hash:** rejected at capture and at package assembly.
- **Wrong role / missing permission:** each of the four previously-unprotected routes denies an unauthorised role; `execute` cannot `approve`.
- **Self-approval / SoD:** creator cannot approve; NULL `created_by` does not bypass SoD.
- **Missing / reused / post-mutation signature:** all fail.
- **Out-of-sequence transition:** approving a `draft` (skipping `pending_approval`) is rejected.
- **Cross-tenant:** tenant A cannot read/act on tenant B's records.
- **AI advisory boundary:** no AI path writes `validation_result`/`disposition`; divergence raises `ai_hold`; `llmAudit` unavailable blocks review completion.
- **Cascade protection:** a parent/tenant delete with retained evidence is blocked (RESTRICT).
- **Audit atomicity:** an injected audit-write failure rolls back the business mutation.

`Unknown — evidence required` until produced: executed OQ results, QA/Validation disposition, runtime DB migration state, deployed feature-flag state, production route-guard behaviour, actual AI Gateway governance records.

---

## 8. Traceability & sign-off

**Requirement → source trace.** SV-REQ-001…034 (Target-State URS §8/§8.1) → SV-COR-001…029 + ADD-VER-01…03 (this document §3) → OQ cases (§7). Verified current-state evidence: Drift Register §2/§8/§9/§9A + Appendix A (EV-01…EV-10), all at `3bd2fe47`.

**Disposition.** This specification is build-ready for engineering. It does **not** authorise release and makes **no** compliance claim. Status: **DRAFT — blockers open (§5 D-1…D-6) — not executed — not approved — not validation-ready.**

| Role | Name | Decision | Date |
|---|---|---|---|
| Product/Engineering Architect | — | Ratify §4 DDL | — |
| Data Integrity Lead | — | Ratify §4 + §5 D-3/D-5 | — |
| AI Validation & Governance | — | Confirm §1 invariants + ARCH-AI-001 AC-5/AC-6/AC-7 binding and approval status | — |
| CSV/CSA Validation Lead | — | §5 D-6 independence + claim wording | — |
| Head of QA | — | Final risk acceptance + release disposition | — |

*Do not claim:* URS-40 is built · self-validation executes IQ/OQ/PQ · dual-model AI review exists · Part 11 e-signature support for this module · packages are evidence-derived or immutable · external validation cost is eliminated — until each is closed by executed OQ + QA disposition.


---

# Harness-Grade Engineering Build Addendum — v1.2-harness-grade

| Field | Value |
|---|---|
| Addendum ID | URS-40-EBS-HARDENING-001 |
| Version | v1.2-harness-grade — DRAFT for engineering build review |
| Applies to | URS-40 Engineering Build Specification v0.1 |
| Rule | This addendum extends the build specification to match the Claude Verixa GxP Validation Harness control rigor. It does not waive existing SV-COR-001…029 or ADD-VER-01…03. |

## B0. Build objective

Build Module 40 as an executable validation harness with deterministic control gates. The implementation shall not depend on model judgment for enforcement. AI may draft/review only within advisory fields. Deterministic backend gates, database constraints, transaction rules, evidence hashes, and human e-signature remain the control authority.

## B1. New required build components

### B1.1 Backend services / modules
- `RunReadinessService` — validates run intent, environment lock, source hashes, synthetic-data policy, jurisdictions, connected-service scope, tool qualification, external signing status, protocol-library version, and approvals.
- `ValidationExecutionService` — executes IQ/OQ/PQ cases; no auto-pass; produces result details and evidence refs.
- `EvidenceManifestService` — records artifact paths, SHA-256, evidence type, source, collector, timestamp, and retention status.
- `ComplianceClaimGuardService` — blocks prohibited claims unless executed evidence + human approval exist.
- `ExternalSignatureVerificationService` — verifies release/package signatures or records signed QA waiver.
- `ToolRunLogService` — logs model/tool/agent/prompt/input/output hashes for generated artifacts.
- `AiGovernanceValidationService` — maintains AI inventory, intended-use, risk class, model/prompt/version register, adversarial test results, HITL disposition, and drift metrics.
- `ConnectorPrivacyCrosswalkService` — maps connector ID to DPDP/GDPR/privacy/supplier fields.
- `SourceLibraryService` — tracks regulatory source files, versions, paths, checksums, and citation status.

### B1.2 Database tables / registers
Add new tables or controlled JSONB-backed registers for:
- `validation_run_readiness`
- `validation_environment_lock`
- `validation_source_document_hashes`
- `validation_evidence_index`
- `validation_tool_run_log`
- `validation_compliance_claims`
- `validation_release_signatures`
- `validation_connector_privacy_crosswalk`
- `validation_source_library_filing`
- `validation_ai_feature_inventory`
- `validation_ai_intended_use`
- `validation_ai_risk_classification`
- `validation_ai_model_prompt_versions`
- `validation_ai_adversarial_results`
- `validation_ai_monitoring_metrics`
- `validation_ai_allowed_prohibited_use`

All tables shall be tenant-scoped where tenant data is present, RLS-enabled, attributable, audit-logged, and covered by migration IQ.

### B1.3 Deterministic gates
Implement gates as backend guards and/or CLI scripts invoked by CI and pre-disposition workflow:

| Gate | Blocks when |
|---|---|
| `inspect-run-readiness` | missing run intent, env lock, source hashes, synthetic data policy, jurisdiction, connector scope, approvals, TQ status |
| `inspect-environment-lock` | Node/npm/Postgres/browser/Playwright/OS/commit/migration/seed hash/version missing or mismatched |
| `inspect-tool-run-log` | model/tool/prompt/input/output metadata missing for generated artifacts |
| `inspect-evidence-index` | evidence path missing, hash missing, hash mismatch, unapproved evidence type |
| `inspect-compliance-claims` | prohibited claim appears without approved evidence and human sign-off |
| `inspect-ai-governance` | AI feature missing inventory/intended-use/risk/model version/advisory boundary |
| `inspect-ai-adversarial` | required AI adversarial test cases missing or unresolved |
| `inspect-connector-privacy-crosswalk` | connector privacy/supplier fields missing for any active connector |
| `inspect-source-library` | regulatory source marked applicable but source path/hash missing |
| `inspect-external-signature` | package/release signature missing, unverified, or waiver absent |
| `inspect-test-architect-handoff` | executable test case lacks numbered steps, synthetic data, measurable expected results, linked controls, evidence required, actual result blank, BLOCKED status |

Each gate must have at least one failing fixture proving the block works.

## B2. Execution-level test authoring standard

Every generated IQ/OQ/PQ test case shall include:

- Test Case ID
- Scenario ID
- Module
- Validation trigger
- Risk level
- Linked URS / FS / DS / control ID
- GxP / Part 11 / Annex 11 / Schedule M / CSA mapping
- Preconditions
- Synthetic test data
- Role / tenant / user
- Numbered execution steps
- Expected UI result
- Expected API result
- Expected database / record-layer result
- Expected audit-trail result
- Expected e-signature result
- Expected negative-path result
- Evidence required
- Actual result = `Unknown — evidence required` until execution
- Pass / Fail / Blocked = `BLOCKED — evidence required` until execution
- Deviation ID
- Retest requirement
- QA reviewer
- Validation Lead reviewer
- System Owner reviewer

The build shall include detailed draft test cases for at least: CAPA, Deviation, Change Control, Complaint, OOS/OOT, Document Control, Training, Supplier Quality, Batch/MBR/EBR, Audit Management, Stability, plus Module 40 self-validation.

## B3. AI governance implementation acceptance

Before any AI review can complete:

1. AI feature exists in inventory.
2. Intended-use record exists and is approved or explicitly BLOCKED.
3. Model/provider/prompt/version row exists.
4. Allowed/prohibited-use matrix classifies the requested operation.
5. Prompt/input/output hashes are logged.
6. PHI/PII/secret redaction status is recorded.
7. Two independent provider calls are logged where dual review is required.
8. Divergence/unavailability creates `ai_review_status` hold/incomplete.
9. Human reviewer disposition is recorded before any AI finding influences the package.
10. AI output never changes deterministic result or disposition.

## B4. Updated build order

Add the following after the existing migration/schema-attribution step and before real execution:

1. Build run-readiness tables + service + gate.
2. Build environment-lock + source-document-hash + tool-run-log tables.
3. Build evidence-index with SHA-256 verification.
4. Build compliance-claim guard.
5. Build AI governance registers and AI adversarial test scaffolds.
6. Build connector privacy crosswalk + source-library filing registers.
7. Build external-signature verification scaffold.
8. Then proceed to real execution, e-signature, AI gateway, package hashing, immutable archive, and dashboard.

No runner may execute before readiness and baseline gates pass.

## B5. Engineering verification command set

The final PR shall provide commands or CI jobs equivalent to:

```bash
npm run typecheck
npm run lint
npm run test
npm run test:e2e
npm run validation:inspect-run-readiness
npm run validation:inspect-evidence-index
npm run validation:inspect-ai-governance
npm run validation:inspect-compliance-claims
npm run validation:inspect-connector-privacy
npm run validation:inspect-source-library
npm run validation:inspect-external-signature
```

If any command is not yet available, the PR is not complete. If a command is intentionally deferred, it must remain `BLOCKED — evidence required` with owner/date/rationale.

## B6. Done definition

A build item is not done when code compiles. It is done only when:

1. Migration IQ passes.
2. Unit and integration tests pass.
3. Deterministic gate passes.
4. Negative gate fixture proves the prohibited path is blocked.
5. Executed OQ evidence exists on a test tenant.
6. Evidence hash verifies.
7. Audit row exists.
8. E-signature / SoD applies where required.
9. Human QA/Validation disposition is recorded where required.
10. Compliance-claim gate finds no unauthorized claim.

## B7. Remaining hard blockers

This addendum does not close the existing external dependencies. The following still block URS freeze or validation approval: URS-13 release-gate interface, URS-16 deviation linkage, predicate-rule map, ARCH-AI-001 approval and filing, BCDR/retention owner, CSV/CSA independence annex, code-side DEC-39/M39 cleanup, and external signature execution.



---

# v0.3 QA Corrective Engineering Addendum — Harness-Hardened v1.2

## B8. Scope of this corrective build-spec release
This addendum closes the QA review defects CG-1…CG-8 from the Head of QA review of Harness-Hardened v1.1. It does **not** claim URS-40 is built, validated, compliant, approved, released, audit-ready, inspection-ready, or secure. It is build-planning input only until executed OQ and human disposition exist.

## B9. Corrected build inputs
Engineering shall treat the following as required build inputs before any implementation starts:

1. URS-40 Harness-Hardened v1.2.
2. This Engineering Build Spec Harness-Hardened v0.3.
3. RTM rows for SV-REQ-035…056 / SV-COR-030…051.
4. §H6 harness-register DDL ratified by Product/Engineering Architect + Data Integrity.
5. D-1…D-9 dependency register, including external signing key management.
6. Controlled-source register for India and AI regulatory sources.

## B10. Additional build order for SV-COR-030…051
Build after SV-COR-001…029 foundational schema/execution controls unless a dependency explicitly requires earlier implementation.

1. Implement harness-register migration from §H6 with RLS, attribution, rollback, and `ON DELETE RESTRICT`.
2. Implement `RunReadinessService` and `inspect-run-readiness` gate.
3. Implement `ToolRunLogService` and environment/source hash capture.
4. Implement `ComplianceClaimGuardService` with context-aware allowlist.
5. Implement `ExternalSignatureVerificationService`; do not mark signing complete without external signature evidence.
6. Implement `SourceLibraryService` and India/source citation gating.
7. Implement `ConnectorPrivacyCrosswalkService`; consume approved Legal/Security/Supplier values only.
8. Implement `AiGovernanceValidationService` registers and adversarial OQ cases.
9. Implement deterministic gate runner for every register and negative fixture.
10. Execute OQ-HARNESS-030…051 and attach evidence before claiming any requirement complete.

## B11. Deterministic gate acceptance
The build shall include gates equivalent to:

```text
inspect-run-readiness
inspect-environment-lock
inspect-tool-run-log
inspect-evidence-index
inspect-compliance-claims
inspect-ai-governance
inspect-ai-adversarial
inspect-connector-privacy-crosswalk
inspect-source-library
inspect-external-signature
inspect-test-architect-handoff
inspect-harness-register-ddl
```

Each gate shall have positive and negative fixtures. A negative fixture that passes is a release blocker.

## B12. OQ acceptance for harness controls
For each SV-COR-030…051:

```text
Actual result: Unknown — evidence required until executed.
Status before execution: BLOCKED — evidence required.
Completion evidence: OQ-HARNESS-### result, gate output, evidence hash, reviewer identity, QA/Validation disposition.
```

The implementation is not complete if it only compiles, only has unit tests, or only produces scaffold files. Completion requires executed OQ on a test tenant with evidence and QA/Validation disposition.

## B13. Ownership boundaries
- Security/Privacy + Legal own DPDP/GDPR legal basis and cross-border transfer adequacy.
- Supplier Quality owns supplier qualification.
- The engine consumes approved crosswalk values and blocks if missing.
- Security / Platform Release Owner owns external signing key lifecycle.
- Head of QA / Data Integrity / Legal own predicate-rule applicability.
- CSV/CSA Validation Lead owns independence threshold and self-validation claim wording.

## B14. Version correction
This build spec is v0.3. Any reference in retained sections to v0.1/v0.2 as the active addendum version is superseded by this B14 statement.
