Skip to content

Feat(ai-gov): OMB M-25-22 acquisition lifecycle (v0.11 Wave 2)#196

Merged
allenfbyrd merged 5 commits into
mainfrom
feat/w2-m2522-acquisition
Jul 15, 2026
Merged

Feat(ai-gov): OMB M-25-22 acquisition lifecycle (v0.11 Wave 2)#196
allenfbyrd merged 5 commits into
mainfrom
feat/w2-m2522-acquisition

Conversation

@allenfbyrd

Copy link
Copy Markdown
Collaborator

v0.11 Wave 2 item 3 — OMB M-25-22 AI acquisition lifecycle

Evidentia's first procurement surface (spec ratified 2026-07-14; the six §4 lifecycle phases were verified verbatim against the M-25-22 memo text before modeling). M-25-22 rescinded M-24-18 on 2025-04-03; Evidentia modelled no M-24-18 surface, so this is net-new.

What's in here

  • Model (evidentia_core/ai_governance/omb_m_25_22.py): AcquisitionPhase (6, stable string values — Identification of Requirements → Market Research & Planning → Solicitation Development → Selection and Award → Contract Administration → Contract Closeout) + status-only AcquisitionPhaseRecord (M-25-22 defines no waiver mechanism, unlike M-25-21) + AIAcquisition, which carries the §4(a) initial likely-high-impact determination in M-25-21 vocabulary (reusing HighImpactDetermination, including not_assessed open-action semantics) and an optional AI-registry link (acquisitions may precede registration).
  • Store: AIAcquisitionStore clones the registry-store pattern exactly — UUID filenames, path-traversal guard, atomic writes, trusted-directory boundary, EVIDENTIA_AI_ACQUISITION_DIR.
  • CLI: ai-gov acquisition register|list|show|set-phase with AI_ACQUISITION_REGISTERED / AI_ACQUISITION_PHASE_RECORDED audit events.
  • API mirror: POST/GET /api/ai-gov/acquisitions, GET /api/ai-gov/acquisitions/{id} (entry + progress roll-up), POST .../set-phase. Structured invalid_body 400s; bad-shape and unknown IDs normalize to not_found 404. Parity: four api-only rows with reasons (GUI screen rides the next parity pass); openapi.json + UI types regenerated.
  • acquisition_progress() mirrors the M-25-21 roll-up posture: unrecorded phases report as missing — never fabricated; lifecycle_complete requires all six recorded AND complete.

Verification

  • Full suite 4939 passed / 0 failed on the merged tree; 26 new tests (phase-value stability, roll-up, store round-trip + traversal-shaped-ID rejection + malformed-file skip, CLI happy/error paths, API 200/404/422).
  • ruff, mypy --strict-optional (292 files), consistency scope 8/8, parity, doc-counts, UI typecheck + 142 vitest — all green locally.

Note on the merge commit

The branch was deliberately stacked on the item-2 branch (same-file edits). The post-#195 merge of main resolved 10 conflicts; a follow-up commit restores two things the first resolution dropped (PR #194's CHANGELOG entry + the conmon ksi parity row) — the final diff vs main is purely additive, verified by gate re-run.

Fills the per-practice extension point reserved on
OMBHighImpactAssessment at v0.10.12 (the carried obligation the v0.11
plan lists as sequencing constraint 4). The seven practice headings and
the waiver mechanics were re-verified against the M-25-21 memo text
before modeling (§4(b) practices; §4(a)(ii) CAIO waiver — written
determination, annual re-certification, 30-day OMB report,
non-delegable).

- Model: MinimumPractice (7, stable string values) + PracticeStatus
  (implemented / in_progress / not_started / waived) +
  MinimumPracticeRecord + PracticeWaiver; a validator makes WAIVED and
  a waiver record require each other. practices rides
  OMBHighImpactAssessment as a defaulted dict, so persisted
  v0.10.12-era assessments load unchanged.
- practice_compliance() reports recorded/missing/satisfied and never
  fabricates a status for an unrecorded practice (satisfied = all 7
  recorded AND implemented-or-waived). waiver_certification_due() /
  waiver_omb_report_overdue() evaluate the memo's two waiver clocks
  against a caller-supplied today (no hidden clock reads).
- CLI `ai-gov set-practice` (requires an existing assessment; waiver
  via --waiver-* flags; prints the roll-up + a not-high-impact
  advisory) and API mirror POST
  /api/ai-gov/systems/{system_id}/set-practice (structured
  invalid_body 400s; returns entry + practice_compliance). New
  AI_SYSTEM_PRACTICE_RECORDED audit event.
- Parity: api-only with reason (the /ai-gov GUI form flip rides the
  next parity pass, v0.10.8 Wave-2 pattern); openapi.json + UI types
  regenerated; wiki CLI/API references regenerated; capability-matrix
  row 11 extended.
…v0.11 Wave 2)

First slice of the ratified M-25-22 procurement surface (spec ratified
2026-07-14; lifecycle phases verified verbatim against the memo text):
AcquisitionPhase (6, stable string values) + status-only
AcquisitionPhaseRecord (M-25-22 defines no waiver mechanism) +
AIAcquisition carrying the §4(a) initial likely-high-impact
determination in M-25-21 vocabulary and an optional AI-registry link
(acquisitions may precede registration). AIAcquisitionStore clones the
registry_store pattern (UUID filenames, path-traversal guard, atomic
writes, trusted-directory boundary, EVIDENTIA_AI_ACQUISITION_DIR).
CLI: `ai-gov acquisition register|list|show|set-phase` with
AI_ACQUISITION_REGISTERED / AI_ACQUISITION_PHASE_RECORDED audit events.

API mirror, parity rows, tests, and docs follow in the next commit.
….11 Wave 2)

Completes the ratified M-25-22 surface started in the previous commit:

- API mirror under /api/ai-gov/acquisitions: register (POST), list
  (GET), get-with-progress (GET/{id}), set-phase (POST). Structured
  invalid_body 400s; bad-shape and unknown IDs normalize to not_found
  404 (the store's traversal guard raises before any path touch).
- Parity: four api-only rows with reasons (GUI screen rides the next
  parity pass); openapi.json + UI types regenerated; wiki CLI/API
  references regenerated.
- Tests: model + store unit suite (phase-value stability, progress
  roll-up, round-trip, traversal-shaped ID rejection, malformed-file
  skip), CLI suite (register/show/set-phase/list --json, unknown
  phase/ID errors), API suite (round-trip, roll-up, 404/422). The API
  fixture now isolates EVIDENTIA_AI_ACQUISITION_DIR alongside the
  registry dir.
- CHANGELOG Unreleased entry. Capability-matrix untouched by design —
  its tables are per-release; the v0.11.0 section lands at release
  prep.
…tion

# Conflicts:
#	CHANGELOG.md
#	docs/cli-gui-parity.yaml
#	docs/wiki/6-project/changelog.md
#	packages/evidentia-api/src/evidentia_api/routers/ai_gov.py
#	packages/evidentia-core/src/evidentia_core/ai_governance/__init__.py
#	packages/evidentia-core/src/evidentia_core/audit/events.py
#	packages/evidentia-ui/openapi.json
#	packages/evidentia-ui/src/types/openapi.ts
#	packages/evidentia/src/evidentia/cli/ai_gov.py
#	tests/integration/test_api/test_ai_gov.py
#	tests/integration/test_cli/test_ai_gov_federal.py
…st in the main merge

The stacked-branch merge of origin/main resolved 10 conflicted files
as --ours; for 8 of them HEAD was a strict superset, but CHANGELOG.md
(+ its generated wiki mirror) and docs/cli-gui-parity.yaml predated
the item-2 branch's own main merge, so --ours dropped PR #194's
Unreleased entry and its `conmon ksi` exempt row. Both restored
verbatim from origin/main; wiki mirrors/references, openapi.json, and
UI types regenerated. Full battery green on the merged tree: pytest
4939, mypy 292 files, ruff, consistency 8/8, parity, doc-counts.
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
evidentia Ready Ready Preview, Comment Jul 15, 2026 4:34am

Request Review

@codspeed-hq

codspeed-hq Bot commented Jul 15, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 6 untouched benchmarks


Comparing feat/w2-m2522-acquisition (6e91466) with main (45575ac)

Open in CodSpeed

def test_delete(self, store: AIAcquisitionStore) -> None:
acquisition = AIAcquisition(name="x")
store.save(acquisition)
assert store.delete(acquisition.acquisition_id) is True
store.save(acquisition)
assert store.delete(acquisition.acquisition_id) is True
assert store.load(acquisition.acquisition_id) is None
assert store.delete(acquisition.acquisition_id) is False
for phase, rec in record.phases.items()
}

for phase in AcquisitionPhase:
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.93443% with 49 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/evidentia/src/evidentia/cli/ai_gov.py 65.87% 43 Missing ⚠️
.../evidentia-api/src/evidentia_api/routers/ai_gov.py 92.16% 4 Missing ⚠️
.../evidentia_core/ai_governance/acquisition_store.py 96.88% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@allenfbyrd
allenfbyrd added this pull request to the merge queue Jul 15, 2026
Merged via the queue into main with commit de6aa47 Jul 15, 2026
37 of 38 checks passed
@allenfbyrd
allenfbyrd deleted the feat/w2-m2522-acquisition branch July 15, 2026 04:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant