Compare commits

...

14 Commits

Author SHA1 Message Date
Jon Chery 88e2389a95 docs(ship): P0 complete → v1.27.0 (v1.28 pre-execution)
Nova Slides Render / render (push) Failing after 25s
---ci---
project: acdl
phase: 0
milestone: v1.28
status: complete
---/ci---
2026-08-19 22:11:01 +00:00
Jon Chery a0c363c063 decision(P00): mvp/ux gate — auto-generated (3 sections verified, PASS)
---ci---
project: acdl
phase: 0
milestone: v1.28
status: mvp_ux_check
---/ci---
2026-08-19 22:10:24 +00:00
Jon Chery bbfcbcc4d3 docs(P00): grill — v1.28 adversarial review (PROCEED 0.76, 3 critical + 16 tracked conditions applied)
---ci---
project: acdl
phase: 0
milestone: v1.28
status: grill
---/ci---
2026-08-19 22:10:15 +00:00
Jon Chery e1dc59ba79 docs(P00): create phase plans — v1.28 (7 phases, 31 REQs, 6 CAPs, MVP/UX sections)
---ci---
project: acdl
phase: 0
milestone: v1.28
status: plan
---/ci---
2026-08-19 22:06:38 +00:00
Jon Chery c629809d75 docs(P00): research findings — v1.28 CLI + identity layer (11 Qs, D-228 amended)
---ci---
project: acdl
phase: 0
milestone: v1.28
status: research
---/ci---
2026-08-19 22:05:24 +00:00
Jon Chery 05efb014d6 docs(P00): clarify — v1.28 ambiguities resolved (6 Qs + 5 grounding gaps, D-226..D-231)
---ci---
project: acdl
phase: 0
milestone: v1.28
status: clarify
---/ci---
2026-08-19 21:58:41 +00:00
Jon Chery 9ee1cc8925 docs(init): validate specification — v1.28 CLI Canonicalization + Identity Layer
---ci---
project: acdl
phase: 0
milestone: v1.28
status: specify
---/ci---
2026-08-19 21:57:53 +00:00
Jon Chery 48a769ced0 merge(milestone): v1.27 PO State Catalog & Ciagent Compression to main (release v1.26.3)
acdl-ci / Test (push) Failing after 21s
acdl-ci / Platform check-only (offline) (push) Failing after 14m28s
acdl-ci / Lint (push) Failing after 14m40s
v1.27 NFR milestone complete. Authored .ciagent/STATE.md (PO-facing
capability catalog) + compressed .ciagent/ by archiving 8 outdated
files + fixed v1.26 phase-status in PROJECT.md/ROADMAP.md + wired
STATE.md into the P-final ship discipline.

Tags: v1.26.0 (P0) → v1.26.1 (P1) → v1.26.2 (P2) → v1.26.3 (P3 = milestone release).

---ci---
project: acdl
phase: 3
milestone: v1.27
status: complete
---ci---
2026-08-19 19:18:19 +00:00
Jon Chery 45423c33ae merge(phase/03): v1.27 P3 final review + audit complete — milestone release
Tags: v1.26.3 (P3 = milestone release on the v1.26.x line). NFR milestone.

---ci---
project: acdl
phase: 3
milestone: v1.27
status: complete
---ci---
2026-08-19 19:18:15 +00:00
Jon Chery 1faf4b560f docs(milestone): complete v1.27 PO State Catalog & Ciagent Compression (release v1.26.3)
Nova Slides Render / render (push) Failing after 26s
v1.27 COMPLETE. NFR milestone — PO State Catalog & Ciagent Compression.

Phases:
- P0 pre-execution (specify→clarify→research→plan→grill) → v1.26.0
- P1 author-archive (STATE.md + 8 files archived) → v1.26.1
- P2 fix-stale-wire (PROJECT/ROADMAP phase-status + ship-discipline wiring) → v1.26.2
- P3 final-review-ship (review + audit + milestone ship) → v1.26.3

Delivered:
- .ciagent/STATE.md — PO-facing capability catalog (32 CAP rows +
  11 invariants across 10 domains, backfilled through v1.26). The
  first file the PO reads before writing a new REQ-NNN spec.
- .ciagent/ compression: 7 platform-root files + 1 consumer file
  archived (lossless git mv). Active .md count: 15 (was 25).
- PROJECT.md + ROADMAP.md v1.26 phase-status corrected (P3/P4/P5
  → complete; v1.25.5 shipped; merged to main).
- STATE.md wired into the P-final ship discipline (PLAN.md, ROADMAP.md,
  NORTH_STAR.md). Every future milestone ship appends capability rows +
  bumps the 'Last milestone ship' header.

Review: 0 P0 issues. Audit: reconstruction PASS, file discipline CLEAN,
branch hygiene CLEAN, commit discipline CLEAN (13/13 ---ci--- blocks).
NFR purity gate holds (zero feat: commits).

---ci---
project: acdl
phase: 3
milestone: v1.27
status: complete
---ci---
2026-08-19 19:18:12 +00:00
Jon Chery 8f62cfdbe7 merge(phase/02): v1.27 P2 fix-stale-wire complete
Tags: v1.26.2 (P2 ship on the v1.26.x line).

---ci---
project: acdl
phase: 2
milestone: v1.27
status: complete
---ci---
2026-08-19 19:17:07 +00:00
Jon Chery f28aed2f55 docs(ship): P2 complete → v1.26.2 (v1.27 fix-stale-wire)
Nova Slides Render / render (push) Failing after 24s
---ci---
project: acdl
phase: 2
milestone: v1.27
status: complete
---ci---
2026-08-19 19:17:07 +00:00
Jon Chery 6b410d9ab4 docs(P02): fix stale phase-status + wire STATE.md into ship discipline
P2 W1: PROJECT.md v1.26 phase-status block (lines 428-438):
- P3/P4/P5 'pending' → 'complete' with shipped tags (v1.25.3/4/5)
- v1.26 Overview marked shipped (merged to main 2026-08-19)
- Added STATE.md pointer to Capability Status section header
- Updated CAPABILITY_INVENTORY.md refs → archive/CAPABILITY_INVENTORY-v1.10.md

P2 W2: ROADMAP.md v1.26 section:
- P3/P4/P5 'planned' → 'complete' with shipped tags
- v1.26 Overview '(active, ...)' → '(complete, tag v1.25.5, merged to main)'
- Added STATE.md to v1.25 + v1.26 P5 'Updated at ship' lists

P2 W3: Wired STATE.md into ship discipline:
- PLAN.md: added 'Durable convention (v1.27 establishes)' section —
  every future P-final Wave 3 file-update list includes STATE.md
  (append new capability rows, mark deprecations, bump 'Last
  milestone ship' header).
- NORTH_STAR.md: added 'Relationship to engineering files (v1.27
  update)' section — STATE.md is the *what exists* catalog (PO-owned,
  additive); NORTH_STAR is the *why*; ARCHITECTURE the *how*;
  CHECKPOINT the *now*.

P2 W4: archive README + consumer PROJECT pointer:
- archive/README.md: added 'v1.27 compression — archived files (8
  files, lossless git mv)' section with 3 tables (3 superseded refs +
  4 v1.26 verifications/review/evidence + 1 consumer) + a note on the
  v1.26 pre-execution artifacts (in git history, not on disk).
  Updated 'Why archive' to record both compressions (v1.26 P2 +
  v1.27 P1).
- nova-blockchain-exchange/PROJECT.md: added phase-by-phase history
  pointer to platform ROADMAP §v1.26 (consumer ROADMAP archived).

P2 W5: Fixed remaining dangling references to archived files:
- ARCHITECTURE.md §12.8 line 566: P4-PILOT-RUN-EVIDENCE.md → archive/
- nova-blockchain-exchange/README.md (3 refs): P4-PILOT-RUN-EVIDENCE.md
  → archive/P4-PILOT-RUN-EVIDENCE-v1.26.md
- IAM_POLICY.md (2 refs): CAPABILITY_INVENTORY.md → archive/

Verified: 0 active dangling references remaining (grep confirms all
matches are in archive/ or v1.27 P0 records describing the archive).

---ci---
project: acdl
phase: 2
milestone: v1.27
status: execute
wave: W6
---ci---
2026-08-19 19:16:43 +00:00
Jon Chery d019a1c4c4 merge(phase/01): v1.27 P1 author-archive complete (STATE.md + 8 files archived)
Tags: v1.26.1 (P1 ship on the v1.26.x line).

---ci---
project: acdl
phase: 1
milestone: v1.27
status: complete
---ci---
2026-08-19 19:14:12 +00:00
17 changed files with 1824 additions and 704 deletions
+82 -2
View File
@@ -563,7 +563,7 @@ audit record (D-204).
The full evidence (every ARN, the confidence JSON, the Decision Ledger
rows, the module-completeness gaps the live apply uncovered) is in
`.ciagent/P4-PILOT-RUN-EVIDENCE.md`.
`.ciagent/archive/P4-PILOT-RUN-EVIDENCE-v1.26.md` (archived v1.27).
### §12.9 — Secret Rotation (v1.26 P3 W7, SPEC §5.9 — current)
@@ -576,4 +576,84 @@ key only after the new one propagates to the consumer's Actions secret
store, verified by a post-PUT GET; on upload/verify failure the old key is
left Active and the run exits non-zero. The synced workflow file is
forge-agnostic (REQ-230): forge base URL / owner / consumer repo come from
repository secrets (`NOVA_FORGE_*`, `NOVA_CONSUMER_REPO`), not literals.
repository secrets (`NOVA_FORGE_*`, `NOVA_CONSUMER_REPO`), not literals.
### §12.10 — Nova-idp Identity Layer (v1.28, current)
Nova owns its identity layer end-to-end. Two (optionally three) Lambda
functions + four DynamoDB tables + one KMS asymmetric signing key + one
kyverno-json ABAC policy. **No Cognito, no IAM Identity Center (INV-15).**
The `nova-cli` Lambda layer carries the Nova wheel + `argon2-cffi` +
`cryptography` + `pyjwt` + the `kj` Go binary, making the same code
importable in both the CLI and the Lambda (REQ-329 dual-use, NFR-7).
**Components:**
- `nova-idp-auth` Lambda — sign-up, sign-in, session creation. Argon2id
password hashing (D-228: bundled abi3 wheel; fail-closed on
`ImportError`, no pure-Python fallback). DynamoDB: `nova-users`
(PK `user_id`, Argon2id `password_hash`), `nova-sessions` (PK
`session_id`, TTL `expires_at`), `nova-password-resets` (PK
`reset_token`, TTL 15m). Function URL with IAM auth.
- `nova-idp-token-vend` Lambda — accepts a PAT (or session token),
validates revocation (`nova-pats.GetItem(jti, ConsistentRead=True)`
D-229, 60s SLO), evaluates the kyverno-json ABAC policy at
`platform/abac/token-vend.policy` (D-227, INV-17), KMS-signs an
ECDSA P-256 JWT (`ES256`), converts DER→raw ECDSA signature (RFC 7515
§3.1.3), returns the OIDC token. The `policy_version` (git SHA,
D-231) is recorded in every `token.vend.allowed/denied` audit event.
- `nova-idp-jwks` Lambda (optional, separation of concerns) — function
URL with `AuthType: NONE` (public key only), `Cache-Control: max-age=3600`.
`kms.get_public_key` → DER SPKI → JWK via `cryptography`. Custom
domain + WAF via CloudFront is OPTIONAL (`--public-jwks-domain` flag
on `nova idp setup`, D-230).
- `nova-pats` DynamoDB table — PK `jti`, GSI1 `sub` (list PATs for
user), GSI2 `pat_hash` (lookup by hash). Only the hash stored (not
raw PAT, REQ-343). Revoked PATs retained for audit.
**CLI surface (`nova` package, greenfield):**
- Entry point: `[project.scripts] nova = "nova.cli:main"` (argparse-only,
no click/typer — repo convention). `nova/cli.py` auto-discovers
`nova/<module>.py` subcommands via `pkgutil.iter_modules`, dispatches,
emits the `cli.invocation` audit event (INV-12) with `mode`,
`selection_reason`, `credential_type`, `command`, `args`.
- Each `nova/<module>.py` is ≤50 lines, delegates to `core/` (CAP-034
AST scan). Subgroups: `nova auth login/revoke/status`, `nova idp
setup --check/--apply/--verify`, `nova init`, `nova apply --local`.
- `core/mode_resolver.py` — flag → env (`NOVA_CLIENT_MODE`) → credential
type → `sys.stdin.isatty()` (D-226). CLI-only; Lambdas don't resolve
modes. Property-tested with `hypothesis` (REQ-349).
- `core/env.py:+synthesize_local_env()` — synthesizes a local env dict
from a contract + `--local` flag (REQ-330). No cloud provisioning.
**Packaging (NFR-6, CAP-035):**
- CI publishes a wheel to CodeArtifact AND a Lambda layer with identical
version strings on every merge affecting `core/`/`adapters/`/`nova/`.
Version mapping recorded in SSM `/nova/layer/nova-cli/version`.
If either publish fails, the merge is blocked (REQ-323).
- `nova cli-action` composite action at
`.github/actions/nova-cli/action.yml`, referenced by both GitHub +
Gitea (`uses: continuous-intelligence/acdl/.github/actions/nova-cli@v1.28`).
Python 3.12 pinned. Byte-identical behavior verified by CI matrix
(REQ-326, NFR-11).
**Data flows:**
1. Sign-up → `nova-idp-auth` → Argon2id → `nova-users` PutItem → session
`nova-sessions` PutItem → return session token.
2. Token vend (hot path) → `nova-idp-token-vend``nova-pats` strong
read (revocation) → kyverno-json ABAC eval → if allow → KMS sign →
DER→raw → return OIDC JWT. Audit at every step.
3. JWKS fetch → `nova-idp-jwks``kms.get_public_key` → DER→JWK →
`{"keys":[...]}`. Cached 1h at CloudFront (if custom domain) / client.
4. PAT revoke → `nova auth revoke --pat <jti>` → `nova-pats.UpdateItem(
status=revoked)` → audit. Strong read on next vend → 403 (within 60s).
**`nova idp setup` (REQ-340, NFR-10):** generates a CloudFormation
template (raw dict → JSON, no troposphere dep), presents for review
(`$PAGER` + resource summary), requires explicit `y/N` approval before
`cloudformation deploy --capabilities CAPABILITY_IAM`. `--check` reports
prerequisites + IAM policy delta; `--verify` runs the KMS round-trip
test. New IAM grants required: `cloudformation:*`, `codeartifact:*`.
+22 -11
View File
@@ -1,17 +1,28 @@
{
"phase": 1,
"phase": 0,
"stage": "complete",
"milestone": "v1.27",
"phase_role": "execution",
"milestone": "v1.28",
"phase_role": "pre_execution",
"attempts": 0,
"updated_at": "2026-08-19T05:00:00Z",
"updated_at": "2026-08-19T20:55:00Z",
"project": "acdl",
"projects": ["acdl", "nova-blockchain-exchange"],
"active_milestone": "v1.27",
"milestone_branch": "milestone/v1.27-po-state-catalog",
"phase_branch": "phase/01-author-archive",
"tag_line": "v1.26.x",
"current_phase": {"phase": 1, "tag": "v1.26.1", "status": "complete"},
"previous_phase": {"phase": 0, "tag": "v1.26.0", "status": "complete"},
"notes": "v1.27 P1 complete. STATE.md verified (32 CAPs, 11 invariants, 10 domains). 7 platform + 1 consumer files archived (lossless git mv). Active .ciagent/ root: 15 .md + 1 json + 1 checkpoint. Next: P2 fix-stale-wire."
"active_milestone": "v1.28",
"milestone_branch": "milestone/v1.28-cli-identity",
"phase_branch": "phase/00-pre-execution",
"tag_line": "v1.27.x",
"previous_milestone": {"milestone": "v1.27", "tag": "v1.26.3", "status": "complete"},
"decisions": ["D-226", "D-227", "D-228", "D-229", "D-230", "D-231"],
"personas": ["backend-engineer", "security-engineer", "cli-engineer", "lead-developer"],
"phases_planned": 6,
"execution_phases": [
{"phase": 1, "name": "cli-substrate", "reqs": ["REQ-323..328"], "caps": ["CAP-033", "CAP-034", "CAP-035"], "tag": "v1.27.1"},
{"phase": 2, "name": "lambda-packaging", "reqs": ["REQ-329..332"], "tag": "v1.27.2"},
{"phase": 3, "name": "idp-auth", "reqs": ["REQ-333..335"], "caps": ["CAP-036"], "tag": "v1.27.3"},
{"phase": 4, "name": "token-vend-pat", "reqs": ["REQ-336..344", "REQ-340..341"], "caps": ["CAP-037", "CAP-038"], "tag": "v1.27.4"},
{"phase": 5, "name": "docs-integration", "reqs": ["REQ-345..351"], "tag": "v1.27.5"},
{"phase": 6, "name": "final-review-ship", "reqs": ["REQ-352..353"], "tag": "v1.27.6"}
],
"grill": {"verdict": "PROCEED-WITH-CONDITIONS", "confidence": 0.76, "critical_conditions": 3, "tracked_conditions": 16, "escalations": 0},
"notes": "v1.28 P0 SHIP. Pre-execution complete (SPECIFY->CLARIFY->RESEARCH->PLAN->GRILL->MVP/UX). Tag v1.27.0. Merged phase/00 -> milestone/v1.28-cli-identity. 6 execution phases planned (P1..P6). Next: P1 cli-substrate."
}
+232 -139
View File
@@ -1,183 +1,276 @@
# CLARIFY — v1.27 PO State Catalog & Ciagent Compression
# CLARIFY — v1.28 CLI Canonicalization + Identity Layer
> **Autonomy:** full. Auto-resolution with assumption logging per
> `config.autonomy.level: "full"`. No human escalation unless
> confidence < 0.60. The prior conversation resolved all material
> ambiguities (4 user-answered questions). This file records the
> assumptions for the v1.27 record.
> `config.autonomy.level: "full"`. No human escalation unless confidence
> < 0.60. The user-approved re-mapping plan (v1.18 spec → v1.28) resolved
> the headline discrepancy. This file records the remaining ambiguities
> and the grounding gaps surfaced in pre-flight.
---
## Method
The clarify stage identifies ambiguities in the v1.27 specification
and resolves them at full autonomy. The v1.27 spec is the user-approved
plan from the prior conversation + the STATE.md design locked by 4
question answers. Each ambiguity gets a decision ID (D-214+; continuing
from the v1.26 decisions D-200..D-213), a resolution, a confidence
score, and a rationale.
The clarify stage identifies ambiguities in the v1.28 specification and
resolves them at full autonomy. The v1.28 spec is the user-provided
"Universal Feature Specification — v1.18 CLI Canonicalization + Identity
Layer," re-mapped to v1.28 (milestone number, tag line, and all
ID namespaces) per the user-approved plan. Each ambiguity gets a
decision ID (D-226+, continuing from v1.27's D-214..D-225), a resolution,
a confidence score, and a rationale.
---
## Prior-conversation resolutions (already locked, restated for the record)
These were resolved by user-answered questions in the conversation that
spawned v1.27. They are load-bearing for v1.27 execution and cited
here so the v1.27 record is self-contained.
These were resolved by the user-approved re-mapping plan in the
conversation that spawned v1.28. They are load-bearing for v1.28
execution.
### Q-P1 — What should the new PO-reference file catalog?
### Q-P1 — The source spec is titled "v1.18" but v1.18 already shipped. What milestone is this?
**Resolution:** Capability catalog (what the system can do today).
**Confidence:** 1.0 (user-confirmed). **Decision:** D-214.
**Resolution:** Re-map the spec's *content* (CLI Canonicalization +
Identity Layer) to **v1.28**, the next milestone after v1.27 (complete).
Tags run on the **v1.27.x** line (P0 = `v1.27.0`). Milestone branch:
`milestone/v1.28-cli-identity`.
**Confidence:** 1.0 (user-confirmed — "Re-map to v1.28"). **Decision:** n/a (milestone identity, not a D-ID).
### Q-P2 — How should the new file relate to CAPABILITY_INVENTORY.md?
### Q-P2 — The spec's "locked inputs" (D-NEW-26, kj engine, Nova-idp, INV-63/64/65, CAP-025..030, REQ-001..031) don't exist in the repo. How to handle?
**Resolution:** Call it `STATE.md`. PO-owned, ciagent-updated after
milestone implementation. CAPABILITY_INVENTORY.md is archived.
**Confidence:** 1.0 (user-confirmed). **Decision:** D-215.
**Resolution:** Author them fresh in this milestone's CLARIFY/RESEARCH as
**D-226..D-231, INV-12..17, CAP-033..038, REQ-323..353**. The `kj` engine
is mapped to the existing **kyverno-json** engine (INV-4 swappable) — no
new engine is built. CAP/INV/REQ IDs are re-allocated to avoid collisions
with shipped history (CAP-025..032 and INV-1..11 are blockchain/pilot).
**Confidence:** 1.0 (user-confirmed — "Re-map to v1.28"). **Decision:** D-227 (kj→kyverno-json), plus the ID-allocation block in REQUIREMENTS.md.
### Q-P3 — Where should the file live, and who owns it?
### Q-P3 — The spec claims a "Cognito drop." No Cognito exists in the repo. What does NFR-5 mean?
**Resolution:** Owned by the PO, updated by ciagent after the milestone
is implemented with additives.
**Confidence:** 1.0 (user-confirmed). **Decision:** D-216.
### Q-P4 — How should "additive when new features are implemented" be enforced?
**Resolution:** On the last phase / milestone ship (the P-final Wave 3
"milestone ship" step). No regression-gate check in this pass.
**Confidence:** 1.0 (user-confirmed). **Decision:** D-217.
### Q-P5 — Should the initial STATE.md backfill all shipped capabilities through v1.26?
**Resolution:** Backfill all shipped capabilities through v1.26
(compressed one-liners for v1.1v1.24; full entries for v1.25 + v1.26).
**Confidence:** 1.0 (user-confirmed). **Decision:** D-218.
### Q-P6 — Should the v1.26 pre-execution artifacts (CLARIFY, GRILL, IDEATE, RESEARCH) be archived?
**Resolution:** Archive all 4 to `.ciagent/archive/` with `-v1.26`
suffixes. The next milestone's P0 writes fresh versions. Decisions are
already folded into PROJECT.md load-bearing decisions + PLAN.md
binding revisions.
**Confidence:** 1.0 (user-confirmed). **Decision:** D-219.
**Resolution:** NFR-5 (no AWS-managed identity in the path) is a
**greenfield constraint**, not a migration. Nova-idp is built fresh; no
Cognito/IAM Identity Center is *introduced*. The "drop" framing is
aspirational language from the source spec, not a literal removal.
**Confidence:** 1.0. **Decision:** D-226 (recorded below; NFR-5 restated
as a greenfield constraint in INV-15).
---
## Ambiguities + Resolutions (this CLARIFY pass)
## Open questions from the spec's §7 (auto-resolved at full autonomy)
### Q1 — Is v1.27 a feature milestone or an NFR milestone?
### Q1 — Argon2 native dependency in Lambda runtime
**Ambiguity:** v1.27 authors `STATE.md` (a new file/capability for the
PO) and archives 11 files. Does the new-file authoring count as `feat:`
(making this a feature milestone, tags on v1.26.x with progressive
patches) or `docs:`/`chore:` (NFR milestone, same tag behavior but
subject to the NFR purity gate)?
`argon2-cffi` has a C extension that may not build cleanly in the Lambda
Python 3.12 runtime.
**Resolution:** NFR milestone. `STATE.md` is documentation (a catalog of
existing capabilities), not a new platform capability. The archive moves
are `chore:` (file relocation, lossless). No code, no schema, no
platform behavior change. Tags run on the v1.26.x patch line:
`v1.26.0` (P0) → `v1.26.1..v1.26.3` (P1..P3). The final phase's patch
(`v1.26.3`) IS the milestone release.
**Resolution (D-228):** Use `argon2-cffi` with bundled wheels; if the
extension fails to load, fall back to the pure-Python implementation. If
both fail, document the Fargate migration path for the auth Lambda.
CAP-036 covers end-to-end verification.
**Confidence:** 0.85. **Rationale:** Bundled wheels are the standard
workaround for Lambda native deps; the pure-Python fallback is a safe
degradation. Fargate is the escape hatch if Lambda's runtime is
fundamentally incompatible. RESEARCH will validate wheel availability for
Python 3.12 + the Lambda execution environment.
**Impact if wrong:** Auth Lambda migrates to Fargate, adding ~1 week to P2.
**Confidence:** 0.95. **Decision:** D-220.
### Q2 — PAT revocation propagation latency
### Q2 — Where does the consumer-side archive (nova-blockchain-exchange/ROADMAP.md) land?
The 60-second SLO (NFR-4) depends on whether the token-vend Lambda reads
PAT revocation state from DynamoDB on every request (eventually
consistent reads) or via a cached/denylist mechanism.
**Ambiguity:** The platform archive convention is
`.ciagent/archive/<file>-<milestone>.md`. The consumer subproject
(`nova-blockchain-exchange/`) has no `archive/` subdirectory. Does the
consumer ROADMAP archive at `.ciagent/archive/` (platform-side, mixed)
or `.ciagent/nova-blockchain-exchange/archive/` (consumer-side, new
subdir)?
**Resolution (D-229):** Read-on-every-request with strongly consistent
reads on the PAT hash table. Cost is acceptable given expected request
volume (token vending is not a hot path — it precedes a deploy, not every
request). REV-351 verifies the SLO in CI.
**Confidence:** 0.90. **Rationale:** Strongly consistent DynamoDB reads
have single-digit-ms latency at expected volume; the 60s SLO has >10x
headroom. A cache layer adds invalidation complexity that the SLO does
not require.
**Impact if wrong:** If read latency exceeds 60s under load, introduce a
DynamoDB TTL + cache layer; SLO must be re-verified.
**Resolution:** Consumer-side. Create
`.ciagent/nova-blockchain-exchange/archive/` and relocate to
`ROADMAP-v1.26.md`. This preserves the per-project path convention
(multi-project mode: `.ciagent/<slug>/` paths). The platform archive
directory is not mixed with consumer archives.
### Q3 — JWKS endpoint: Lambda function URL vs. API Gateway
**Confidence:** 0.92. **Decision:** D-221.
A function URL is simpler and cheaper but lacks throttling, WAF, and
custom domains out of the box.
### Q3 — Does archiving CLARIFY/GRILL/IDEATE/RESEARCH lose the "how v1.26 was specified" traceability?
**Resolution (D-230):** Start with a Lambda function URL behind a custom
domain; rate limiting configured at the DNS/CDN layer. API Gateway
migration deferred to v1.19+ if throttling requirements grow.
**Confidence:** 0.80. **Rationale:** The JWKS endpoint is public-key
only (no secrets); the threat surface is low. Function URL + CDN rate-
limiting covers the v1.28 volume. API Gateway is over-engineering until
traffic patterns are known.
**Impact if wrong:** If throttling becomes a requirement, API Gateway
migration adds ~3-5 days.
**Ambiguity:** The pre-execution artifacts document the v1.26 decision
path. Archiving them moves them out of active context. Is the
traceability preserved?
### Q4 — Mode resolver precedence with invalid `NOVA_CLIENT_MODE` value
**Resolution:** Yes. Three layers preserve it: (1) the archive files
are byte-identical relocations inside `.ciagent/archive/` (reachable by
agents + git history); (2) the decisions D-200..D-213 are folded into
`PROJECT.md` load-bearing decisions (the durable record); (3) git
history at the v1.26 commits preserves the authoritative state. The
active-context reduction is the point — v1.26 is shipped; the next P0
writes fresh CLARIFY/GRILL/IDEATE/RESEARCH.
What happens if the env var is set to something other than `agent` or
`interactive` (e.g., `NOVA_CLIENT_MODE=auto`)?
**Confidence:** 0.95. **Decision:** D-222.
**Resolution (D-226):** Invalid env var values are ignored, falling
through to credential type. A warning is logged. Behavior is documented
in the `nova-cli` README. This is a sub-clause of the mode-resolution
priority decision.
**Confidence:** 0.90. **Rationale:** Ignoring + warning is the least
surprising behavior for an operator debugging mode issues. Failing hard
would block legitimate workflows that set a stale/typo'd env var.
**Impact if wrong:** Operators debugging mode issues may be confused;
non-blocking.
### Q4 — Should IAM_POLICY.md be archived (it predates v1.26 and is dated v1.11)?
### Q5 — Service-account PAT vs. developer PAT in the same session
**Ambiguity:** `IAM_POLICY.md` is dated v1.11 (2026-07-28). It predates
v1.26 by 5 milestones. The D-207 future key-split (P1+ R-3 in
REVIEW-AUDIT-P05) is pending. Archive or keep?
What if both credential types are available (e.g., a developer explicitly
exports a service-account PAT)?
**Resolution:** Keep active. `IAM_POLICY.md` is a live baseline —
referenced by the regression gate
(`tests/test_iam_policy_baseline.py`), enforced by a managed policy on
account `581513795199`, and the D-207 key-split is a pending future-
hardening item. It is not stale; it is a baseline that grows when
grants change. The v1.11 date reflects the last grant addition, not
staleness.
**Resolution (D-226):** The most recently acquired credential wins.
Documented in `nova auth login` output. The credential type is what
drives mode resolution (INV-14), so the operator sees which mode was
selected and why.
**Confidence:** 0.85. **Rationale:** "Most recent wins" is the simplest
deterministic rule that matches operator mental models of "I just logged
in as X." The audit event records the winning credential type, so the
selection is traceable.
**Impact if wrong:** Mode selection may surprise the operator; non-
blocking, but `nova auth status` must make the active credential explicit.
**Confidence:** 0.90. **Decision:** D-223.
### Q6 — ABAC policy ownership and versioning
### Q5 — Should REGRESSION_REPORT.{json,md} be refreshed as part of v1.27?
`platform/abac/token-vend.policy` is referenced, but who owns changes?
How are policy versions tracked in audit?
**Ambiguity:** Both files are dated 2026-08-01 (v1.10 Phase 52), show
CAP-025 absent, and mark live-aws CAPs "Skipped" (state bucket absent
pre-v1.26 re-bootstrap). They are stale. Should v1.27 refresh them?
**Resolution:** No. Both files are machine-managed — written by
`core/regression_verify.py:704-705` on every `run_regression.sh` run.
They regenerate on the next regression run. v1.27 is docs/chore only
(no code); touching machine-managed files by hand creates a drift
source. The stale state is honest (the last gate run was v1.10; the
next run regenerates). The STATE.md Domain 7 row "Regression gate"
notes the current CAP range (CAP-001..025).
**Confidence:** 0.88. **Decision:** D-224.
### Q6 — Does PROJECT.md get the v1.26 phase-status fix in v1.27 P1 or P2?
**Ambiguity:** The plan splits work into P1 (author + archive) and P2
(fix stale + wire). The PROJECT.md phase-status fix (P3/P4/P5 pending
→ complete) is a "fix stale" item. P1 or P2?
**Resolution:** P2. P1 is the additive authoring + lossless archive
moves. P2 is the corrections to kept files + the ship-discipline wiring.
This keeps P1 a pure-additive, no-edit phase (easier review + audit) and
P2 the correction phase. The PROJECT.md fix is a correction; P2.
**Confidence:** 0.85. **Decision:** D-225.
**Resolution (D-231):** Policy changes require PR review; the policy
version (git SHA) is recorded in every token-vend audit event. Owner:
Platform Security. The policy file lives in the platform repo at
`platform/abac/token-vend.policy` and is reviewed like any other
production config.
**Confidence:** 0.90. **Rationale:** Git SHA is the natural version
identifier for a repo-resident policy; recording it in the audit event
makes every allow/deny decision reconstructable to the exact policy text.
**Impact if wrong:** Untracked policy changes could lead to unexpected
allow/deny decisions in production, undermining audit defensibility.
---
## Summary
## Grounding gaps surfaced in pre-flight (auto-resolved)
6 prior-conversation resolutions (D-214..D-219, all user-confirmed)
+ 6 new ambiguities (D-220..D-225, all auto-resolved at full autonomy,
confidence ≥ 0.60). 0 escalations.
### G1 — The `kj` engine does not exist; the spec treats it as locked.
**Key decisions:**
- D-220: v1.27 is an NFR milestone (tags on v1.26.x; final patch is the
milestone release).
- D-221: Consumer archives land in `.ciagent/nova-blockchain-exchange/archive/`.
- D-222: Archiving pre-execution artifacts preserves traceability
(archive files + PROJECT.md load-bearing decisions + git history).
- D-223: IAM_POLICY.md stays active (live baseline, test-enforced,
D-207 pending).
- D-224: REGRESSION_REPORT.{json,md} regenerate on next
`run_regression.sh` (machine-managed; v1.27 is docs/chore only).
- D-225: PROJECT.md phase-status fix is P2 (correction phase), not P1
(additive phase).
**Resolution (D-227):** The token-vend Lambda uses the existing
**kyverno-json** engine (INV-4 swappable) as the ABAC evaluator. The
policy at `platform/abac/token-vend.policy` is a kyverno-json policy.
No new `kj` engine is built in v1.28. If a distinct `kj` engine is
desired later, it is a separate research spike (not this milestone).
**Confidence:** 0.95. **Rationale:** The repo already has a swappable
policy engine (INV-4) implemented as kyverno-json. Building a second
engine to do the same job violates the swappable-engine invariant's
spirit. kyverno-json's `evaluate` semantics cover the spec's ABAC needs
(subject, claims, resource, environment → allow/deny).
**Impact if wrong:** If the user actually wants a new `kj` engine, v1.28
scope expands significantly (engine design + implementation + migration).
This was flagged as caveat #3 in the approved plan; the recommended path
(kyverno-json) is locked here.
### G2 — The spec's INV-18..21, INV-34, INV-63/64/65 don't exist.
**Resolution:** Re-allocated as **INV-12..INV-17** (see REQUIREMENTS.md
§v1.28 Invariants). The 1:1 mapping:
- INV-63 (mode observability) → INV-12
- INV-64 (mode determinism) → INV-13
- INV-65 (credential type encodes role) → INV-14
- INV-18..21 (attestation invariants) → INV-15 (no AWS-managed identity),
INV-16 (password storage), INV-17 (ABAC discipline). The spec's
attestation invariants INV-18..21 are partially covered by existing
invariants (INV-6 immutable audit) + INV-17; the JWS-from-PAT behavior
(REQ-332) is a requirement, not a separate invariant, in this mapping.
- INV-34 (MFA enforcement) → deferred to v1.21+ (out of scope per §2.2);
no INV allocated in v1.28.
**Confidence:** 0.85. **Rationale:** The mapping preserves the spec's
intent without colliding with the repo's INV-1..11. INV-34 (MFA) is
explicitly deferred per the spec's own §2.2 out-of-scope table.
**Impact if wrong:** If the user wants the exact INV-18..21 semantics as
separate invariants, INV-12..17 can be re-numbered; non-blocking.
### G3 — The spec's CAP-025..030 collide with blockchain/pilot CAPs.
**Resolution:** Re-allocated as **CAP-033..CAP-038** (see REQUIREMENTS.md
§v1.28 + REQ-352). The 1:1 mapping:
- CAP-025 (CLI subcommand surface) → CAP-033
- CAP-026 (subcommand delegates to core/) → CAP-034
- CAP-027 (layer matches wheel) → CAP-035
- CAP-028 (Nova-idp auth flow) → CAP-036
- CAP-029 (token-vend signs via KMS) → CAP-037
- CAP-030 (PAT issuance + revocation) → CAP-038
**Confidence:** 1.0. **Rationale:** Existing CAP-025..032 are
blockchain/pilot capabilities (STATE.md); re-use would corrupt the
capability registry. The re-allocated IDs are the next available.
**Impact if wrong:** None — this is a numbering decision, not a semantic
one.
### G4 — The spec's REQ-001..031 collide / don't exist.
**Resolution:** Re-allocated as **REQ-323..REQ-353** (1:1 with the spec's
REQ-001..031). Full text in REQUIREMENTS.md §v1.28. Max existing REQ =
REQ-322.
**Confidence:** 1.0. **Rationale:** Same as G3 — avoid collision, use
next available range.
### G5 — `platform/abac/`, `nova/` subcommand dir, `nova-idp-*` Lambdas don't exist.
**Resolution:** These are **greenfield deliverables** of v1.28 execution
phases, not pre-existing "locked architectures." RESEARCH will design
them; PLAN will sequence them; EXECUTE will build them. The spec's
"Operating Principle 1" (incremental delivery) is honored — v1.28 is
net-new work.
**Confidence:** 1.0. **Rationale:** The spec itself describes these as
new ("introducing Nova-idp"). The mis-framing was in calling them
"locked" — they are locked in *scope*, not in *prior existence*.
**Impact if wrong:** None — this is a framing correction.
---
## Decision ledger (v1.28 — D-226..D-231)
| ID | Title | Confidence | Load-bearing for |
|----|-------|------------|------------------|
| D-226 | Mode resolution priority + invalid-env + dual-credential | 0.90 | REQ-327, INV-12, INV-13, INV-14 |
| D-227 | ABAC engine = kyverno-json (no `kj` engine built) | 0.95 | REQ-336, REQ-339, INV-17, NFR-9 |
| D-228 | Argon2id in Lambda: bundled wheels + pure-Python fallback + Fargate path | 0.85 | REQ-333, REQ-334, INV-16, NFR-8 |
| D-229 | PAT revocation: strongly-consistent DDB read-on-every-request, 60s SLO | 0.90 | REQ-342, REQ-343, REQ-351, NFR-4 |
| D-230 | JWKS endpoint: Lambda function URL + custom domain + CDN rate-limit | 0.80 | REQ-338, NFR-5 |
| D-231 | ABAC policy ownership: Platform Security, git SHA in audit | 0.90 | REQ-339, NFR-9 |
---
## Assumptions logged (full autonomy, no human escalation)
1. **CodeArtifact is provisionable** in AWS account `581513795199` (the
pilot account). RESEARCH will confirm IAM permissions + repository
creation. If not, v1.28 falls back to a private PyPI server or a
Gitea-hosted wheel index; the CLI subcommand surface (REQ-324) and
identity layer (REQ-333+) are unaffected.
2. **Python 3.12** is the target runtime for both the CLI wheel and the
Lambda functions (spec §4 REQ-004.3). The repo's current Python
version will be confirmed in RESEARCH; if it differs, the CLI pins
3.12 and Lambda uses the 3.12 runtime regardless.
3. **KMS asymmetric signing** (RSA-2048 or ECDSA P-256) is available in
the target account. RESEARCH will confirm. If only symmetric KMS is
available, the token-vend Lambda uses symmetric signing + a public-key
publication step (less ideal, but functional); INV-15 is unaffected.
4. **The Forge action** (REQ-326) is the existing `nova cli-action`
pattern, extended to both GitHub and Gitea marketplaces. The repo's
current Forge/Gitea workflow conventions (`.gitea/workflows/`,
`deploy.yml@v1.25`) are the baseline.
5. **MFA/TOTP** code path ships in v1.28 (per spec §2.2) but enforcement
for prod/dr is deferred to v1.21+. This is a doc/test-only path in
v1.28 — no enforcement gate.
---
## CLARIFY complete
All material ambiguities resolved at full autonomy (6 open questions +
5 grounding gaps → D-226..D-231, confidence ≥ 0.80). No human escalation
triggered (all confidences ≥ 0.60 threshold). REQUIREMENTS.md updated
with the decision ledger + invariants. Next: RESEARCH.
+98 -129
View File
@@ -1,141 +1,110 @@
# GRILL — v1.27 PO State Catalog & Ciagent Compression
# GRILL — v1.28 CLI Canonicalization + Identity Layer
> Adversarial review of the v1.27 SPECIFY + CLARIFY + RESEARCH + PLAN.
> The grill red-teams the proposal across feasibility, scope, and the
> compression-loss claims. Each challenge gets a binding verdict
> (PROCEED / REVISE / ESCALATE). Autonomy: full.
## Verdict: PROCEED (0.88) — 0 escalations, 1 revision
The milestone is feasible, scoped, and the compression is lossless. One
binding revision (G-Q2) refines the archive list; already captured in
PLAN. No work is blocked.
> Adversarial review of the v1.28 SPECIFY + CLARIFY + RESEARCH + PLAN.
> Griller: ci-griller subagent. Autonomy: full. All 9 axes reviewed;
> every claim verified against the live codebase.
---
## Challenges
## Overall verdict: **PROCEED-WITH-CONDITIONS** · Confidence 0.76
### G-Q1 — Is archiving AUTONOMY_THESIS.md + COST.md a context loss?
The plan is fundamentally sound — architecture correct, re-mapping
clean (no ID collisions), technical depth accurate (DER→raw, strong-
read revocation, stdin TTY), highest-risk item (kj binary) has a
Fargate fallback. Not unfeasible, not over-scoped beyond an agent-driven
repo's capacity, not security-broken by design.
**Challenge:** `AUTONOMY_THESIS.md` is the "autonomy in operations;
human at stage gates" thesis — the defensibility brief. `COST.md` is
the only AWS cost record. Archiving both moves them out of active
context. Does this lose load-bearing content?
**Verdict:** PROCEED (confidence 0.90).
- `AUTONOMY_THESIS.md` (65 lines, "Last refined: v1.21") is fully
folded into `NORTH_STAR.md` Vision (lines 1722: "infrastructure
operations become visible... human attestation remains required at
stage gates") + Anti-Goals #2 ("Not a system that removes humans from
accountability"). The thesis is the source; NORTH_STAR is the
authoritative durable copy. Archive preserves the v1.21 refinement;
active context reads NORTH_STAR.
- `COST.md` (106 lines, dated 2026-07-29, "v1.0 → v1.14") predates the
v1.26 live pilot. The v1.26 live apply (ECS + ALB + DynamoDB + S3)
incurred real costs this snapshot doesn't reflect. Archiving it is
honest — a stale cost record misleads. STATE.md Domain 7 notes cost
tracking as a capability (pre-apply Infracost grounded; actual-spend
CUR deferred D-096). A future cost milestone writes a fresh report.
No revision needed.
### G-Q2 — Does the archive list include the v1.27 P0 pre-execution files by mistake?
**Challenge:** D-219 (user-confirmed) says "archive all 4 pre-execution
artifacts" (CLARIFY/GRILL/IDEATE/RESEARCH). But P0 already overwrote
them with v1.27 content. Archiving the v1.27 versions at v1.27 P1 would
lose the v1.27 pre-execution narrative (the decisions D-214..D-225, the
research inventory, this grill). Is the archive list wrong?
**Verdict:** REVISE (confidence 0.92). This is a real ambiguity in the
plan. The user's D-219 decision was made *before* P0 overwrote the
files; the intent was to archive the *v1.26* pre-execution record. The
v1.26-era content is preserved in git history (the pre-P0 commits) —
the archive directory is not the only preservation layer. PLAN Task 2.1
already self-corrected: the final archive list is **7 platform files +
1 consumer file = 8 files**, excluding the 4 pre-execution files. The 4
v1.27 P0 versions stay active through v1.27; they archive at v1.28 P1
if v1.28 happens. The archive README notes the v1.26 pre-execution
record is in git history. No further revision needed — the plan self-
corrected.
### G-Q3 — Is the STATE.md backfill accurate enough to be the PO's source of truth?
**Challenge:** STATE.md has 36 capability rows across 10 domains,
backfilled from 8 sources. The PO will read this before writing new
REQs. If a row is inaccurate (wrong shipped tag, wrong file path,
wrong controlling REQ), the PO could re-spec an existing capability or
cite a stale invariant. Is the backfill accurate?
**Verdict:** PROCEED (confidence 0.85). The backfill sources are
authoritative: `core/regression_verify.py` (the machine CAP-NNN
registry), `modules/registry.json` (the live module catalog),
`REQUIREMENTS.md` traceability (the REQ→phase→status record),
`CHECKPOINT.json` (shipped tags), `git log` (file paths). The
citations are direct (each row cites the controlling REQ + decision
ID). The 11 invariants are distilled from PROJECT.md load-bearing
decisions D-034..D-072 + W1..BA + Q1.3. The accuracy risk is
mitigated by P1 Wave 1 (verify STATE.md against sources before
archive). No revision needed — the verification step is in the plan.
### G-Q4 — Does the NFR purity gate (zero `feat:` commits) hold for v1.27?
**Challenge:** v1.27 authors STATE.md (a new file). Is authoring a new
catalog file a `feat:` (feature) that breaks the NFR purity gate?
**Verdict:** PROCEED (confidence 0.92). D-220 (CLARIFY) resolved this:
STATE.md is documentation (a catalog of *existing* capabilities), not a
new platform capability. The archive moves are `chore:` (file
relocation, lossless). No code, no schema, no platform behavior
change. The NFR purity gate (zero `feat:` commits) holds. All v1.27
commits use `docs(P0N):` or `chore(P01):` prefixes. No revision
needed.
### G-Q5 — Does fixing PROJECT.md phase-status in P2 create a P0/P1 audit inconsistency?
**Challenge:** The PROJECT.md phase-status block shows P3/P4/P5 as
"pending" (the bug flagged in the prior conversation). P0 + P1 ship
with the bug still present (the fix is P2). Does the P0/P1 audit see
the inconsistency?
**Verdict:** PROCEED (confidence 0.86). The bug is pre-existing
(it predates v1.27; it was the trigger for the prior conversation).
P0/P1 audits check the *v1.27* commits against the `.ciagent/` state,
not the pre-existing PROJECT.md drift. The P2 fix is the correction;
the P3 audit verifies the fix landed. The intermediate state (P0/P1
with the bug present) is honest — the bug is documented in the v1.27
PLAN + the prior conversation, and the fix is scheduled. No revision
needed — the phasing is intentional (D-225: P1 additive, P2
correction).
### G-Q6 — Is the milestone scoped too small (3 phases, 8 archive moves)?
**Challenge:** v1.27 is a small milestone (3 phases, ~15 file
operations, no code). Is it worth a milestone, or should it be a
patch on v1.26?
**Verdict:** PROCEED (confidence 0.88). v1.27 is not a patch on v1.26
— v1.26 is shipped (`v1.25.5`, merged to main, milestone complete).
The work is a new milestone by definition. The size is appropriate:
STATE.md is a durable PO-facing artifact (loaded every ci-run going
forward); the compression reduces active context by ~26%; the
ship-discipline wiring affects every future milestone ship. Small but
high-leverage. No revision needed.
**3 critical conditions (must-fix before P1) + 16 tracked conditions.**
No escalations (all axes ≥ 0.70 confidence).
---
## Summary
## Axis verdicts
6 challenges; 0 escalations; 1 binding revision (G-Q2, already
captured in PLAN Task 2.1). Overall verdict: PROCEED (confidence
0.88).
| Axis | Verdict | Confidence | Critical condition |
|------|---------|-----------|-------------------|
| §1 Feasibility | PROCEED-WITH-CONDITIONS | 0.82 | C-1.1 KMS asym verify; C-1.2 Argon2 fail-closed test |
| §2 Scope | PROCEED-WITH-CONDITIONS | 0.74 | C-2.1 fold P5 into P4; C-2.2 P4 overload |
| §3 Cost | PROCEED-WITH-CONDITIONS | 0.70 | C-3.1 cost estimate; C-3.2 CodeArtifact P1 task |
| §4 Schedule | PROCEED-WITH-CONDITIONS | 0.76 | C-4.1 P4 critical path; C-4.2 per-phase exit |
| §5 Technical Depth | PROCEED-WITH-CONDITIONS | 0.80 | C-5.1 ABAC shape; **C-5.2 JWS KDF** |
| §6 Operational Readiness | PROCEED-WITH-CONDITIONS | 0.72 | **C-6.1 ABAC fail-closed**; C-6.2 threat model; C-6.3 ops guide |
| §7 Security Posture | PROCEED-WITH-CONDITIONS | 0.73 | **C-7.1 ABAC fail-closed**; C-7.2 Argon2 params; C-7.3 cred file |
| §8 Dependency Risk | PROCEED-WITH-CONDITIONS | 0.83 | C-8.1 CodeArtifact P1; C-8.2 pin kj version |
| §9 Re-mapping Integrity | PROCEED-WITH-CONDITIONS | 0.84 | **C-9.1 traceability fix**; C-9.2 INV audit |
**Binding revisions:**
- **G-Q2:** Archive list refined to 7 platform + 1 consumer = 8 files.
The 4 pre-execution files (CLARIFY/GRILL/IDEATE/RESEARCH) stay active
through v1.27 (they hold the v1.27 P0 content); the v1.26-era content
is in git history. Already in PLAN.
---
**No work is blocked.** The milestone is feasible, scoped, the
compression is lossless (archive + git history), the STATE.md backfill
is source-grounded with a verification step, the NFR purity holds, and
the phasing (P1 additive, P2 correction, P3 ship) is sound.
## Critical conditions (the 3 must-fix-before-P1)
### 🔴 C-6.1 / C-7.1 — ABAC fail-closed
The token-vend Lambda's behavior on `kj` absence/error is unspecified.
Without fail-closed, INV-17 is documentation, not a runtime guarantee —
a `kj` load failure would bypass the ABAC gate (every PAT gets a token).
**Fix applied to PLAN.md P4 Wave 4 Task 4.1:** "If
`KyvernoJsonEngine.is_configured()` returns false or `evaluate()`
raises, return 403 + audit `token.vend.denied` (reason:
`abac_eval_failed`). Never fail open. Test: `tests/test_abac_fail_closed.py`."
### 🔴 C-5.2 — JWS-from-PAT key derivation
REQ-332's AC ("public key derivable from the PAT") is unimplementable
without a specified KDF. A PAT is a JWT, not a keypair.
**Fix applied to PLAN.md P2 Wave 2 Task 2.3 + REQ-332 AC:** the JWS
uses HMAC-SHA256 with a key derived via
`HKDF-SHA256(PAT_bytes, salt='nova-local-attestation', info='jws-signing-key')`
→ 32-byte symmetric key. The "public key derivable" AC is re-interpreted:
the *verification key* is derived from the PAT via the same KDF (the
PAT is the shared secret). This is a symmetric scheme, not asymmetric.
### 🔴 C-9.1 — Traceability drift
REQUIREMENTS.md §v1.28 traceability table mapped 16 REQs to P2;
PLAN.md splits them across P2/P3/P4/P5/P6. **Fix applied to
REQUIREMENTS.md** — traceability table updated to match PLAN.md phase
structure.
---
## Tracked conditions (16 — applied to PLAN.md as amendments)
- **C-1.1** KMS asymmetric key verification before P4 Wave 3 (one
`aws kms create-key --key-spec ECC_NIST_P256` call).
- **C-1.2** Argon2 fail-closed test in P3 Wave 2 (Lambda returns 503
on `ImportError`, not a crash or pure-Python hash).
- **C-2.1** Fold P5 (idp-setup) into P4 as P4 Wave 8 → **reduces to 6
execution phases** (P1..P6, P7 = final). Applied.
- **C-2.2** P4 is a double-length phase; acknowledged in P4 header.
- **C-3.1** Cost envelope subsection added to PLAN.md.
- **C-3.2 / C-8.1** CodeArtifact provisioning = P1 Wave 0 task with
binary go/no-go gate; Gitea wheel index fallback documented.
- **C-4.1** P4 flagged as critical-path phase (kj spike = highest-
probability schedule slip; Fargate = +1 week).
- **C-4.2** Per-phase exit criteria added to PLAN.md.
- **C-5.1** `requested_claims` = list of claim names (the policy
asserts the subject is *allowed* to request those claims).
- **C-6.2** Threat model (REQ-347) adds: JWKS DDoS surface, PAT theft
+ max TTL (≤24h dev, ≤1h service-account), ABAC fail-closed,
INV-18..21 compression audit.
- **C-6.3** Operator guide (REQ-345) adds: KMS rotation, layer update,
PITR restore, emergency PAT revocation.
- **C-7.2** Argon2id parameters: t=3, m=65536 KiB, p=1 (OWASP min).
- **C-7.3** `~/.nova/credentials.json` stores OIDC token + PAT metadata
(jti, exp, type), NOT the raw PAT.
- **C-8.2** `kj` pinned to a specific release + SHA256 recorded.
- **C-9.2** Threat model includes INV-18..21 compression audit
(verify spec's attestation invariant semantics are captured by
INV-15/16/17 + REQ-332).
---
## Escalations
None. All 9 axes resolved at confidence ≥ 0.70. No human escalation
required (full autonomy).
---
## Grill complete
The plan proceeds with the 3 critical fixes and 16 tracked conditions
applied to PLAN.md + REQUIREMENTS.md. The binding decisions above are
the authoritative grill record. Next: MVP/UX CHECK → SHIP phase 0.
+3 -2
View File
@@ -56,7 +56,8 @@ and covered by the baseline test.
## OIDC act_runner role (CAP-022, Phase 56)
The OIDC role for the Gitea `act_runner` was created in Phase 08 and
gone since (CAPABILITY_INVENTORY.md CAP-022). Phase 56 re-creates it
gone since (`archive/CAPABILITY_INVENTORY-v1.10.md` CAP-022, archived
v1.27). Phase 56 re-creates it
with a trust policy for the Gitea runner ARN. The role grants the
spike-runner-equivalent permissions to the runner via `sts:AssumeRole`,
so the runner does not need a long-lived access key. This closes the
@@ -73,7 +74,7 @@ bootstrap root key; the runner then assumes the role.
The OIDC role for the Gitea `act_runner` was planned in Phase 08 but
never created (the spike used a long-lived key per D-039 waiver).
CAPABILITY_INVENTORY.md CAP-022 recorded "iam:ListRoles shows no acdl*
`archive/CAPABILITY_INVENTORY-v1.10.md` CAP-022 recorded "iam:ListRoles shows no acdl*
roles." Phase 56 re-created the role:
- **Role name:** `acdl-act-runner-role`
+12
View File
@@ -231,6 +231,18 @@ their AI engineering teams reach for first when an agent needs to deploy.
leadership. The deck's Proof section cites grounded metrics; its
Roadmap section cites deferred targets honestly.
## Relationship to engineering files (v1.27 update)
- **NORTH_STAR.md** (this file) = the *why* — PO-authored strategic
direction, loaded every ci-run via `config.strategic_direction_file`.
- **STATE.md** = the *what exists* — PO-owned capability catalog,
additive, updated at every milestone ship (P-final Wave 3). The PO
reads STATE.md before writing new REQ-NNN specs to avoid re-spec'ing
existing capability and to respect the invariants.
- **ARCHITECTURE.md** = the *how* — the durable target architecture.
- **CHECKPOINT.json** = the *now* — authoritative live phase/ship
state.
## v1.25 update — swappable policy-engine substrate
Strategic Objective #2 (provable trust) gained a concrete substrate in
+100 -58
View File
@@ -1,77 +1,119 @@
---
project: acdl
milestone: v1.27
milestone: v1.28
generated_at: 2026-08-19
generator: lead-developer
verification_toolchain:
typecheck: "python3 -m py_compile core/confidence_signal.py 2>&1 | head -5 || true"
test: "bash scripts/run_regression.sh 2>&1 | tail -10 || true"
lint: "ruff check .ciagent/STATE.md 2>/dev/null || true"
typecheck: "python3 -m py_compile core/mode_resolver.py nova/cli.py 2>&1 | head -5 || true"
test: "pytest tests/test_mode_resolver.py tests/test_cli_subcommands.py -q 2>&1 | tail -15 || true"
lint: "ruff check nova/ core/lambda/nova_idp_*.py 2>/dev/null || true"
note: |
v1.27 is an NFR milestone (PO State Catalog & Ciagent Compression) —
a docs/chore milestone. Single active persona: lead-developer owns
the milestone narrative (STATE.md authoring, PROJECT/ROADMAP fixes,
archive moves, PLAN/NORTH_STAR wiring, final review + audit). No
code, no schema, no policy authoring. The pre-existing
core/confidence_signal.py LSP diagnostic is out of scope (not
touched by v1.27). Territory enforcement: warn.
v1.28 is a feature milestone (CLI Canonicalization + Identity Layer).
Four active personas: backend-engineer (Lambda/DynamoDB/KMS/CodeArtifact),
security-engineer (Argon2id/KMS/ABAC/threat model), cli-engineer
(subcommand surface/mode_resolver/argparse/CAP-034), lead-developer
(plan/review/ship/capability gate). frontend-engineer + data-engineer
deactivated (no UI, no data pipelines). The kj-binary-in-Lambda-layer
risk (D-227, RESEARCH §7) is the highest-risk item; P2 spike confirms.
---
# PERSONAS — v1.27 PO State Catalog & Ciagent Compression
# Personas — v1.28 CLI Canonicalization + Identity Layer
> Generated by the lead-developer at the end of RESEARCH. Assesses the
> project domains, activates/deactivates personas, aligns frameworks +
> territory + constraints to the actual project structure.
## Roster
## Active Roster (1)
### backend-engineer
```yaml
active: true
domain: "Lambda functions, DynamoDB, KMS integration, dual-use packaging, CodeArtifact publish, CloudFormation generation"
frameworks: ["Python 3.12", "boto3", "argparse", "pytest", "moto[dynamodb]", "CloudFormation"]
constraints: ["INV-15", "INV-16", "INV-17", "D-228", "D-229", "D-230", "NFR-5", "NFR-6", "NFR-7", "NFR-8"]
territory:
- "core/lambda/**"
- "core/metrics/**"
- "core/env.py"
- "core/outbox_writer.py"
- "terraform/bootstrap/**"
- ".gitea/workflows/publish.yml"
- ".github/workflows/publish.yml"
- ".github/actions/nova-cli/**"
```
### 1. lead-developer (active)
- **active:** true
- **phase_specific:** false
- **reason:** Owns the full v1.27 milestone narrative: STATE.md
authoring (PO-facing capability catalog, 36 entries across 10
domains + 11 invariants), archive moves (11 files to
`.ciagent/archive/` + 1 to consumer archive), PROJECT.md + ROADMAP.md
phase-status corrections, archive/README.md contents update,
PLAN.md + ROADMAP.md + NORTH_STAR.md ship-discipline wiring, final
review + audit.
- **domain:** `.ciagent/` docs (STATE.md, PROJECT.md, ROADMAP.md,
PLAN.md, NORTH_STAR.md, archive/README.md), consumer
`.ciagent/nova-blockchain-exchange/` (PROJECT.md pointer,
archive/ROADMAP-v1.26.md).
- **frameworks:** markdown, JSON (CHECKPOINT.json, config.json).
- **territory:** `.ciagent/`, `docs/`.
- **constraints:** no code changes (NFR milestone, D-220); no schema
changes; archive moves are lossless (byte-identical relocation, git
history preserves authoritative state); STATE.md is additive only.
### security-engineer
```yaml
active: true
domain: "Argon2id hashing, KMS asymmetric signing (ECDSA P-256 / ES256), ABAC policy, JWKS exposure, PAT lifecycle, threat model, DER→raw ECDSA conversion"
frameworks: ["argon2-cffi", "cryptography", "pyjwt", "kyverno-json", "JMESPath", "KMS Sign/Verify/GetPublicKey"]
constraints: ["INV-15", "INV-16", "INV-17", "NFR-5", "NFR-8", "NFR-9", "D-227", "D-231"]
territory:
- "platform/abac/**"
- "core/policy_engine.py"
- "adapters/kyverno-json/**"
- "core/lambda/nova_idp_auth.py"
- "core/lambda/nova_idp_token_vend.py"
- "core/lambda/nova_idp_jwks.py"
- "docs/threat-model.md"
```
## Deactivated (5)
### cli-engineer
```yaml
active: true
domain: "CLI subcommand surface, mode_resolver, argparse, [project.scripts] entry-point, CAP-034 AST scan, nova auth/idp subgroups, property tests"
frameworks: ["Python 3.12", "argparse", "setuptools [project.scripts]", "hypothesis", "pkgutil"]
constraints: ["INV-12", "INV-13", "INV-14", "D-226", "NFR-1", "NFR-2", "NFR-3"]
territory:
- "nova/**"
- "core/mode_resolver.py"
- "pyproject.toml"
- "tests/test_mode_resolver.py"
- "tests/test_cli_subcommands.py"
```
### backend-engineer (inactive)
- **active:** false
- **reason:** No code changes in v1.27. The pre-existing
`core/confidence_signal.py` LSP diagnostic is out of scope (not
touched by v1.27).
### lead-developer
```yaml
active: true
domain: "Phase plan, persona roster, review gates, milestone ship, capability gate (CAP-033..038), ROADMAP/STATE/PROJECT wiring"
frameworks: ["git", "Gitea Actions", "semver tagging", ".ciagent/ discipline"]
constraints: ["INV-1..17 (cross-cutting)", "v1.28 hard constraints", "NFR-6", "NFR-11"]
territory:
- ".ciagent/**"
- "PLAN.md"
- "CHECKPOINT.json"
- "STATE.md"
- "REQUIREMENTS.md"
- "ROADMAP.md"
```
### data-engineer (inactive)
- **active:** false
- **reason:** No schema, migration, or ORM changes.
### frontend-engineer
```yaml
active: false
phase_specific: false
reason: "No UI in v1.28 (CLI + JSON endpoints only). JWKS serves application/json; no HTML/CSS/JS surface."
```
### policy-engineer (inactive)
- **active:** false
- **reason:** No policy authoring. STATE.md Domain 3 catalogues
existing v1.25 + v1.26 policies (descriptive, not authoring).
### data-engineer
```yaml
active: false
phase_specific: false
reason: "No data pipelines / metrics / PowerBI work in v1.28. The metrics layer is v1.17-complete; v1.28 adds audit events but no new fact/dim tables."
```
### frontend-engineer (inactive)
- **active:** false
- **reason:** No UI. Deactivated since v1.26 (PERSONAS.md:141).
## Territory overlap notes
### blockchain-engineer (inactive)
- **active:** false
- **reason:** No chain code. The v1.26 pilot is shipped; v1.27 is
platform-side docs/chore only.
- `core/lambda/contract_ingestor.py` (dual-use refactor, REQ-329) =
backend-engineer territory. `core/lambda/nova_idp_auth.py` +
`nova_idp_token_vend.py` are **co-owned** by backend-engineer (Lambda
plumbing, DynamoDB, function URLs) + security-engineer (crypto, ABAC,
Argon2id logic inside).
- `core/mode_resolver.py` = cli-engineer. `core/policy_engine.py` =
security-engineer (the ABAC evaluation path).
- `nova/idp/setup.py` = cli-engineer (the subcommand + arg parsing) +
backend-engineer (the CloudFormation generation + deploy).
- `nova/auth/*` = cli-engineer (subcommands) + security-engineer (the
token exchange + credential storage logic).
## Territory Enforcement
## Phase-specific personas
- **Mode:** `warn` (the milestone is `.ciagent/`-only; the lead-
developer owns all writes; no cross-territory collisions expected).
None. All four active personas span the full milestone. The
security-engineer is heaviest in P2 (identity layer) + P3 (threat model);
the cli-engineer is heaviest in P1 (CLI substrate); the backend-engineer
spans P1 (CodeArtifact/layer) + P2 (Lambdas/DynamoDB).
+443 -205
View File
@@ -1,251 +1,489 @@
# PLAN — v1.27 PO State Catalog & Ciagent Compression
# PLAN — v1.28 CLI Canonicalization + Identity Layer
> **Milestone:** v1.27 (NFR — docs/chore only). Tags on the **v1.26.x**
> line: `v1.26.0` (P0) → `v1.26.1..v1.26.3` (P1..P3). The final phase's
> patch (`v1.26.3`) IS the milestone release.
> **Branch:** `milestone/v1.27-po-state-catalog`. Phase branches:
> `phase/00-pre-execution`, `phase/01-author-archive`,
> `phase/02-fix-stale-wire`, `phase/03-final-review-ship`.
> **Milestone:** v1.28 (feature — CLI substrate + Nova-idp identity
> layer). Tags on the **v1.27.x** line: `v1.27.0` (P0) →
> `v1.27.1..v1.27.6` (P1..P6) → `v1.27.7` (P7 final = milestone
> release). The final phase's patch IS the milestone release.
> **Branch:** `milestone/v1.28-cli-identity`. Phase branches:
> `phase/00-pre-execution`, `phase/01-cli-substrate`,
> `phase/02-lambda-packaging`, `phase/03-idp-auth`,
> `phase/04-token-vend-pat`, `phase/05-docs-integration`,
> `phase/06-final-review-ship`.
>
> **Tags:** `v1.27.0` (P0) → `v1.27.1..v1.27.5` (P1..P5) →
> `v1.27.6` (P6 final = milestone release). 6 execution phases
> (P5 idp-setup folded into P4 Wave 8 per grill C-2.1).
## Milestone goal
Author `.ciagent/STATE.md` (PO-facing capability catalog, backfilled
through v1.26) + compress `.ciagent/` by archiving 11 outdated files +
fix 3 stale-but-kept files + wire STATE.md into the P-final ship
discipline. NFR milestone — no code, no schema, no platform behavior
change.
The Nova CLI is installable from internal PyPI (CodeArtifact); every
`core/` module is reachable as a `nova <subcommand>`; the CLI and
Lambda functions share a single `core/` source tree; and Nova owns its
identity layer end-to-end (Nova-idp: `nova-idp-auth` +
`nova-idp-token-vend` Lambdas, KMS-signed OIDC tokens, kyverno-json
ABAC token vending, PAT lifecycle). No AWS-managed identity services
in the path (INV-15).
## Requirements
No new REQ-NNN. v1.27 is a docs/chore milestone; the work items are
the user-approved plan from the prior conversation. The traceability
is by-file (the "requirements" are the 15 file operations + 6 doc
edits in the plan summary).
31 requirements: REQ-323..REQ-353 (full text in
`.ciagent/REQUIREMENTS.md` §v1.28). 6 capabilities: CAP-033..CAP-038.
6 invariants: INV-12..INV-17. 6 decisions: D-226..D-231 (CLARIFY) +
RESEARCH amendments (D-228 fail-closed, D-229 strong-read-on-PK).
## Phase breakdown
### Phase P1 — author-archive (additive + lossless)
### Phase P1 — cli-substrate (REQ-323..REQ-328)
**Goal:** Author STATE.md (already done in P0 SPECIFY, refined here)
+ archive 11 outdated files. Pure-additive + lossless moves only —
no edits to kept files.
**Goal:** CodeArtifact wheel + Lambda layer pipeline; `nova/` CLI
package with a subcommand per `core/` module; `nova init`; `nova
cli-action` composite action; `core/mode_resolver.py`; audit emission
with `mode` + `selection_reason`. The CLI is installable and every
`core/` module is reachable.
#### Wave 1 — verify STATE.md backfill
- **Task 1.1** (lead-developer): verify STATE.md 36 capability rows
against the authoritative sources (regression_verify.py CAP-NNN list,
modules/registry.json, REQUIREMENTS.md traceability, CHECKPOINT
tags). Fix any inaccurate citation (shipped tag, file path).
**Exit criterion:** CAP-033 + CAP-034 + CAP-035 Verified + all REQ-323..328
tests pass. CodeArtifact provisioned (Wave 0 gate).
#### Wave 2archive platform-root files (10)
- **Task 2.1** (lead-developer): `git mv` 10 files to
`.ciagent/archive/` with milestone-suffix names:
- `CAPABILITY_INVENTORY.md``CAPABILITY_INVENTORY-v1.10.md`
- `CLARIFY.md``CLARIFY-v1.26.md`
- `GRILL.md``GRILL-v1.26.md`
- `IDEATE.md``IDEATE-v1.26.md`
- `RESEARCH.md``RESEARCH-v1.26.md`
- `REVIEW-AUDIT-P05.md``REVIEW-AUDIT-P05.md`
- `VERIFY-P03.md``VERIFY-P03.md`
- `VERIFY-P04.md``VERIFY-P04.md`
- `P4-PILOT-RUN-EVIDENCE.md``P4-PILOT-RUN-EVIDENCE-v1.26.md`
- `AUTONOMY_THESIS.md``AUTONOMY_THESIS-v1.21.md`
- `COST.md``COST-v1.14.md`
Use `git mv` to preserve history. NOTE: CLARIFY/GRILL/IDEATE/RESEARCH
were rewritten in P0 with v1.27 content — archive the v1.27 versions
(they document the v1.27 pre-execution; the next P0 writes fresh).
Wait — per D-219, the v1.26 pre-execution artifacts are archived. The
v1.27 versions replace them in active context; they are NOT archived
at P1 (they are the current P0 artifacts, active until v1.27 ships,
then archived at v1.28 P1 if v1.28 happens). **Correction:** archive
only the v1.26-era pre-execution artifacts. But P0 already
overwrote CLARIFY/GRILL/IDEATE/RESEARCH with v1.27 content. The v1.26
content lives in git history (the pre-P0 commits). So:
- The 4 pre-execution files (CLARIFY/GRILL/IDEATE/RESEARCH) at HEAD
are the v1.27 P0 artifacts — **keep active** through v1.27, archive
at v1.28.
- The v1.26-era content is in git history — reachable.
**Revised archive list (7 files, not 10):** CAPABILITY_INVENTORY,
REVIEW-AUDIT-P05, VERIFY-P03, VERIFY-P04, P4-PILOT-RUN-EVIDENCE,
AUTONOMY_THESIS, COST.
#### Wave 0CodeArtifact provisioning (backend-engineer) [C-3.2/C-8.1]
- **Task 0.1** (backend-engineer): provision CodeArtifact domain
(`nova`) + repository (`nova-pypi`) in `581513795199`. Verify
`codeartifact:*` IAM grant on `nova-spike-runner`. **Binary go/no-go
gate for Wave 4.** If fail: activate Gitea wheel index fallback
(CLARIFY assumption #1) and document in PLAN.md.
Hold — let me re-check D-219. The user said "Archive all 4
pre-execution artifacts." That was decided *before* P0 overwrote
them. The intent was to archive the v1.26 pre-execution record. The
v1.27 P0 overwrites are the new pre-execution record. Archiving the
v1.27 versions at v1.27 P1 would lose the v1.27 pre-execution
narrative. **Resolution:** archive the v1.26-era content (preserved
in git history at the pre-P0 commits) by noting it in the archive
README; keep the v1.27 P0 versions active through v1.27. The 4 files
stay active until v1.28 P1.
#### Wave 1 — pyproject + entry point (cli-engineer)
- **Task 1.1** (cli-engineer): `pyproject.toml` — add
`[project.scripts] nova = "nova.cli:main"`; add
`[tool.setuptools.packages.find]` including `nova`, `nova.*`, `core`,
`core.*`, `adapters.*`; bump `requires-python` to `>=3.12`; add
`argon2-cffi`, `cryptography`, `pyjwt`, `hypothesis` to deps/test-deps.
Verify `pip install -e .` produces a `nova` executable.
**Final archive list (7 files):** CAPABILITY_INVENTORY.md,
REVIEW-AUDIT-P05.md, VERIFY-P03.md, VERIFY-P04.md,
P4-PILOT-RUN-EVIDENCE.md, AUTONOMY_THESIS.md, COST.md.
#### Wave 2 — CLI dispatch + subcommands (cli-engineer)
- **Task 2.1** (cli-engineer): `nova/__init__.py` + `nova/cli.py`
(~80 lines, auto-discovers `nova/<module>.py` via `pkgutil.iter_modules`,
dispatches, emits `cli.invocation` audit event stub with INV-12 fields).
- **Task 2.2** (cli-engineer): `nova/<module>.py` for each `core/`
module (≤50 lines, `add_parser` + `run` delegates to `core/`). Cover:
`resolve`, `decommission`, `env-transition`, `env-check`, `hitl`,
`onboard`, `outbox`, `publish-outputs`, `policy`, `regression`, `sod`,
`readiness`, `attestation-matrix`, `confidence`. Skip internal-only
(`env`, `local_emulators`, `output_publisher` if not user-facing).
- **Task 2.3** (cli-engineer): `nova/init.py` (REQ-325) — scaffolds
`.nova/`, `.nova/contract.yml.attestations/`, `.gitignore` (excludes
secrets, `~/.nova/credentials.json`).
- **Task 2.2** (lead-developer): grep for dangling references to the
archived filenames across `.ciagent/` + `docs/`; fix any in P2 (the
fix-stale phase).
#### Wave 3 — mode_resolver + audit (cli-engineer)
- **Task 3.1** (cli-engineer): `core/mode_resolver.py`
`resolve_mode(flag, env_var, credential_type, stdin_isatty)` per D-226.
`sys.stdin.isatty()` is the TTY check (RESEARCH §11). Invalid env →
warn + fall through. Returns `(mode, selection_reason)`.
- **Task 3.2** (cli-engineer): wire `mode_resolver` into `nova/cli.py`
— resolve mode before dispatch, emit `cli.invocation` with `mode`,
`selection_reason`, `credential_type`, `command`, `args` (INV-12,
REQ-328).
- **Task 3.3** (cli-engineer): `tests/test_mode_resolver.py`
`hypothesis` property tests (REQ-349): deterministic, flag-wins,
invalid-env-ignored, no-silent-fallback. Edge cases: TTY + piped
stdout, missing credential, conflicting flag/env, invalid env value.
#### Wave 3archive consumer file (1)
- **Task 3.1** (lead-developer): `mkdir
.ciagent/nova-blockchain-exchange/archive/` + `git mv
nova-blockchain-exchange/ROADMAP.md` →
`nova-blockchain-exchange/archive/ROADMAP-v1.26.md` (D-221).
#### Wave 4CodeArtifact + layer pipeline (backend-engineer)
- **Task 4.1** (backend-engineer): `.gitea/workflows/publish.yml` +
`.github/workflows/publish.yml` (byte-identical) — build wheel →
CodeArtifact `twine upload` → build layer (`pip install --target
layer/python/` + `argon2-cffi` + `cryptography` + `pyjwt`) →
`lambda publish-layer-version` → SSM `/nova/layer/nova-cli/version`
mapping (CAP-035). Fail either → job fails (merge blocked, REQ-323).
Pin version to `<semver>+<sha7>` for idempotent re-runs.
#### Wave 4 — commit P1
- **Task 4.1** (lead-developer): single commit `chore(P01): archive 7
platform + 1 consumer outdated .ciagent files` with `---ci---`
block.
#### Wave 5 — composite action (cli-engineer + backend-engineer)
- **Task 5.1** (cli-engineer): `.github/actions/nova-cli/action.yml`
composite action, `setup-python@v5` (3.12), CodeArtifact login +
`pip install nova`, `nova ${{ inputs.command }}`. `NOVA_CLIENT_MODE`
from input.
- **Task 5.2** (backend-engineer): byte-identical integration test —
CI matrix runs the action on GitHub `ubuntu-latest` + Gitea
`act_runner`; assert same stdout/exit code (REQ-326 AC2, NFR-11).
**Must-haves (verify before ship):**
- STATE.md 36 rows accurate (Wave 1 verification).
- 7 platform files present in `.ciagent/archive/` with milestone
suffixes; originals gone from `.ciagent/` root.
- 1 consumer file present in
`.ciagent/nova-blockchain-exchange/archive/`; original gone.
- 0 dangling references in active files (checked in P2, but flagged
here).
#### Wave 6 — CAP-033/034 gate (cli-engineer)
- **Task 6.1** (cli-engineer): `tests/test_cli_subcommands.py`
CAP-033 (`nova --help` lists a subcommand for every `core/` module)
+ CAP-034 (AST scan: ≤50 lines, ≤3 defs, all calls resolve to `core.`,
no conditionals beyond `if __name__`). Wire into CI merge gate.
### Phase P2 — fix-stale-wire (corrections + wiring)
### Phase P2 — lambda-packaging (REQ-329, REQ-330, REQ-331)
**Goal:** Fix 3 stale-but-kept files + wire STATE.md into the P-final
ship discipline + add a pointer in the consumer PROJECT.md.
**Goal:** Dual-use `core/lambda/contract_ingestor.py` (Lambda + CLI
paths share ≥80% code); `core/env.py:+synthesize_local_env()` for
`nova apply --local`; `.nova/contract.yml.attestations/` scaffolded;
JWS-from-PAT key derivation (C-5.2).
#### Wave 1 — fix PROJECT.md phase-status
- **Task 1.1** (lead-developer): `.ciagent/PROJECT.md` lines 424431 —
the v1.26 phase-status block. Mark P3/P4/P5 complete with shipped
tags (`v1.25.3`, `v1.25.4`, `v1.25.5`); mark v1.26 milestone shipped.
- **Task 1.2** (lead-developer): add a one-line pointer to STATE.md in
the "Capability Status" section header (line 130): "The PO-facing
capability catalog is `.ciagent/STATE.md` (additive; updated at
milestone ship). CAP-NNN IDs cross-reference the regression gate at
`core/regression_verify.py`."
**Exit criterion:** all REQ-329..331 tests pass + JWS-from-PAT KDF
specified.
#### Wave 2fix ROADMAP.md phase-status
- **Task 2.1** (lead-developer): `.ciagent/ROADMAP.md` v1.26 section —
mark P3/P4/P5 complete with shipped tags; mark the v1.26 Overview
line (line 181) "(active, ...)" → "(complete, tag `v1.25.5`)".
- **Task 2.2** (lead-developer): add STATE.md to the v1.25 + v1.26 P5
phase-detail "Updated at ship" list (the convention visibility
point).
#### Wave 1dual-use refactor (backend-engineer)
- **Task 1.1** (backend-engineer): refactor
`core/lambda/contract_ingestor.py` — extract the shared logic into
importable functions; the Lambda handler + the CLI `__main__` block
both call them. The `__main__` block already exists (the dual-use
precedent per RESEARCH §1.2). Verify ≥80% code share (CAP-034 / code
review). Local path via `core/local_emulators.py:LocalLambdaStub`.
#### Wave 3wire STATE.md into ship discipline
- **Task 3.1** (lead-developer): `.ciagent/PLAN.md` P5 Wave 3 Task 3.5
— add STATE.md to the file-update list: "append new capability
entries to `.ciagent/STATE.md`; mark any deprecated capability."
- **Task 3.2** (lead-developer): `.ciagent/NORTH_STAR.md` — add a
one-line note in "Relationship to engineering files" (or the v1.25
update section): "STATE.md is the *what exists* catalog (PO-owned,
additive, updated at milestone ship); this file is the *why*."
#### Wave 2local env synthesizer + JWS KDF (backend-engineer)
- **Task 2.1** (backend-engineer): `core/env.py:+synthesize_local_env()
` — produces a local env dict (account_id placeholder, region local,
no real AWS) from a contract + `--local` flag. Mirrors
`core/onboarding.py:generate_env_file()`.
- **Task 2.2** (cli-engineer): `nova/apply.py` (≤50 lines) — `nova
apply --local` delegates to `core.env.synthesize_local_env()` +
`core.contract_resolver.resolve()`.
- **Task 2.3** (security-engineer): JWS-from-PAT key derivation
(C-5.2). HKDF-SHA256(PAT_bytes, salt='nova-local-attestation',
info='jws-signing-key') → 32-byte symmetric key. The JWS is
HMAC-SHA256 (symmetric, not asymmetric). The "public key derivable
from the PAT" AC (REQ-332) is re-interpreted: the *verification key*
is derived from the PAT via the same KDF (the PAT is the shared
secret). Document in `docs/developer-guide-auth.md`. Update REQ-332
AC accordingly.
#### Wave 4fix archive README + consumer PROJECT pointer
- **Task 4.1** (lead-developer): `.ciagent/archive/README.md` — add
the 8 new archived files (7 platform + 1 consumer) to the contents
tables (Snapshots + Completed-phase artifacts sections).
- **Task 4.2** (lead-developer):
`.ciagent/nova-blockchain-exchange/PROJECT.md` — add a one-line
pointer to the platform ROADMAP for milestone-phase history (since
the consumer ROADMAP is archived): "Phase-by-phase history:
`.ciagent/ROADMAP.md` §v1.26 (the consumer ROADMAP is archived at
`.ciagent/nova-blockchain-exchange/archive/ROADMAP-v1.26.md`)."
#### Wave 3attestations dir (cli-engineer)
- **Task 3.1** (cli-engineer): verify `nova init` (P1 Wave 2 Task 2.3)
creates `.nova/contract.yml.attestations/` (empty). REQ-331 test.
#### Wave 5 — fix any dangling references from P1 Wave 2
- **Task 5.1** (lead-developer): apply fixes for any dangling
references found in P1 Wave 2.
### Phase P3 — idp-auth (REQ-333, REQ-334, REQ-335)
#### Wave 6 — commit P2
- **Task 6.1** (lead-developer): single commit `docs(P02): fix stale
phase-status + wire STATE.md into ship discipline` with `---ci---`
block.
**Goal:** `nova-idp-auth` Lambda (sign-up, sign-in, session) with
Argon2id hashing + DynamoDB tables. CAP-036 target.
**Must-haves (verify before ship):**
- PROJECT.md v1.26 phase-status matches CHECKPOINT.json (P3/P4/P5
complete, v1.26 shipped).
- ROADMAP.md v1.26 sections show P3/P4/P5 complete + Overview complete.
- PLAN.md P5 Wave 3 names STATE.md.
- NORTH_STAR.md notes STATE.md.
- archive/README.md lists the 8 new archived files.
- nova-blockchain-exchange/PROJECT.md points to platform ROADMAP.
**Exit criterion:** CAP-036 Verified (E2E sign-up → sign-in → session
passes in CI).
### Phase P3 — final-review-ship (review + audit + milestone ship)
#### Wave 1 — DynamoDB schema (backend-engineer)
- **Task 1.1** (backend-engineer): define the 4 DynamoDB table schemas
(`nova-users`, `nova-sessions`, `nova-password-resets`, `nova-pats`)
in a CloudFormation snippet (reused by P4 Wave 8 `nova idp setup`).
PITR enabled on each (REQ-335).
**Goal:** Final review + audit + milestone ship.
#### Wave 2 — Argon2id (security-engineer) [C-1.2/C-7.2]
- **Task 2.1** (security-engineer): `core/lambda/nova_idp_auth.py` —
Argon2id password hashing via `argon2-cffi` (D-228: bundled abi3
wheel; **fail-closed on `ImportError` → 503, no pure-Python
fallback**). **Parameters: t=3, m=65536 KiB, p=1** (OWASP-recommended
minimum). Lambda memory ≥512 MB (m=64 MiB + Python overhead fits).
Raw passwords never in logs/traces/env/DDB (INV-16, REQ-334).
- **Task 2.2** (security-engineer): `tests/test_argon2_fail_closed.py`
— mock `argon2.low_level` import failure → assert auth Lambda
returns 503 (not a crash, not a weak hash). C-1.2.
#### Wave 1review
- **Task 1.1** (lead-developer): review all P1/P2 changes for
correctness (no broken markdown, no inaccurate citations, no
dangling references).
- **Task 1.2** (lead-developer): fix any P0 issues in this phase.
#### Wave 3auth Lambda (backend-engineer + security-engineer)
- **Task 3.1** (backend-engineer): `nova-idp-auth` Lambda handler —
sign-up, sign-in, session creation endpoints. Function URL + IAM
auth. DynamoDB via lazy `boto3.resource` (the existing pattern).
- **Task 3.2** (security-engineer): session token issuance + session
storage in `nova-sessions` (TTL `expires_at`). Password reset flow
in `nova-password-resets` (TTL 15m).
#### Wave 2audit
- **Task 2.1** (lead-developer): reconstruction test — git log
`---ci---` blocks ↔ `.ciagent/` files consistent; phase
progression P0→P1→P2→P3.
- **Task 2.2** (lead-developer): `.ciagent/` file discipline —
CHECKPOINT consistent with HEAD; PROJECT/ROADMAP phase-status
consistent with CHECKPOINT; STATE.md present + 36 rows; archive
contents match the moves.
- **Task 2.3** (lead-developer): branch hygiene — only main +
milestone + P3; P1/P2 deleted.
- **Task 2.4** (lead-developer): commit discipline — all v1.27 commits
carry `---ci---` blocks.
#### Wave 4CAP-036 E2E (backend-engineer)
- **Task 4.1** (backend-engineer): `tests/test_idp_auth.py` — sign-up
→ sign-in → session round-trip (moto[dynamodb] for local; deployed
for CI). CAP-036 verification.
#### Wave 3 — milestone ship
- **Task 3.1** (lead-developer): merge `phase/03` →
`milestone/v1.27-po-state-catalog` → `main`.
- **Task 3.2** (lead-developer): tag `v1.26.3` (= the v1.27 release per
prev-minor tagging rule; v1.27 is an NFR milestone, tags on v1.26.x).
- **Task 3.3** (lead-developer): create Gitea release with full
milestone summary.
- **Task 3.4** (lead-developer): delete all milestone branches (local
+ remote). Tags preserve all history.
- **Task 3.5** (lead-developer): update `.ciagent/REQUIREMENTS.md`
(no REQs to mark — NFR milestone), `.ciagent/ROADMAP.md` (mark
v1.27 complete), `.ciagent/NORTH_STAR.md` (no strategic change),
`.ciagent/STATE.md` (bump "Last milestone ship" to v1.27).
- **Task 3.6** (lead-developer): write checkpoint `stage: complete,
phase: 3, phase_role: final` + clear checkpoint (milestone
complete).
### Phase P4 — token-vend-pat (REQ-336..REQ-344, REQ-340, REQ-341) [was P4+P5]
**Must-haves (verify before ship):**
- Review: 0 P0 issues unfixed; P1+ flagged for post-hoc.
- Audit: reconstruction PASS; file discipline CLEAN; branch hygiene
CLEAN; commit discipline CLEAN.
- Ship: `v1.26.3` tag exists; Gitea release created; milestone
branches deleted; main has the milestone merge.
**Goal:** `nova-idp-token-vend` Lambda (KMS-signed OIDC, kyverno-json
ABAC), JWKS endpoint, PAT lifecycle, `nova auth` commands, **and**
`nova idp setup` (folded from P5 per C-2.1). CAP-037 + CAP-038 target.
**Highest-risk phase — critical-path.** The kj-binary spike (Wave 1)
is the single highest-probability schedule slip; Fargate fallback adds
~1 week (D-227). This is a **double-length phase** (8 waves).
**Exit criterion:** CAP-037 + CAP-038 Verified + `nova idp setup
--check/--apply/--verify` works against a fresh AWS account.
#### Wave 1 — kj-binary spike (backend-engineer + security-engineer) [C-8.2]
- **Task 1.1** (backend-engineer): confirm the `kj` Go binary
(~40 MB Linux amd64) runs in the Lambda Python 3.12 runtime on
AL2023. Bundle it in the `nova-cli` layer (`wget` a **pinned
release** (e.g. `kj@v1.x.y`) + record SHA256 into `layer/kj.sha256`
— C-8.2, supply-chain safety) into `layer/bin/kj`, `chmod +x`.
Verify `KyvernoJsonEngine.is_configured()` finds `/opt/bin/kj`.
**If this fails:** fall back to Fargate for the token-vend Lambda
(D-227 risk, RESEARCH §7). Escalate to user only if both fail (full
autonomy: log assumption + proceed with Fargate).
#### Wave 2 — ABAC policy (security-engineer) [C-5.1]
- **Task 2.1** (security-engineer): `platform/abac/token-vend.policy`
— kyverno-json `ValidatingPolicy` (D-227). Payload:
`{subject, requested_claims, target_resource, environment, pat_jti,
policy_version}`. **`requested_claims` = list of claim names** (the
policy asserts the subject is *allowed* to request those claims; the
values are assigned by the Lambda, not the requestor — C-5.1).
JMESPath checks for role/scope/env/owner. Severity `critical` = deny
on fail.
- **Task 2.2** (security-engineer): `policy_version` = git SHA of the
policy file, baked into the Lambda layer (D-231). Recorded in every
`token.vend.allowed/denied` audit event.
#### Wave 3 — KMS signing (security-engineer) [C-1.1]
- **Task 3.1** (security-engineer): **verify KMS asymmetric key
support** before implementation: `aws kms create-key --key-spec
ECC_NIST_P256 --key-usage SIGN_VERIFY` in the target account
(C-1.1). If fail: fall back to RSA-2048 (also supported, larger
tokens) or escalate. Do not discover this mid-Wave.
- **Task 3.2** (security-engineer): KMS key `alias/nova-oidc-signing`
(ECC_NIST_P256, SIGN_VERIFY). Token-vend Lambda signs via
`kms.sign(SigningAlgorithm="ECDSA_SHA_256")` → DER→raw ECDSA
conversion (`decode_dss_signature` → `r.to_bytes(32) + s.to_bytes(32)`,
RESEARCH §5). JWT header `{"alg":"ES256","typ":"JWT","kid":"..."}`.
#### Wave 4 — token-vend Lambda (backend-engineer + security-engineer) [C-6.1/C-7.1 ABAC FAIL-CLOSED]
- **Task 4.1** (backend-engineer): `core/lambda/nova_idp_token_vend.py`
— accepts PAT/session, validates revocation (`nova-pats.GetItem(jti,
ConsistentRead=True)` — D-229), evaluates ABAC (Wave 2), signs (Wave
3), returns OIDC JWT. Audit at every step.
- **Task 4.2** (security-engineer): token claims `sub, aud, iss, exp,
iat, jti, roles` (REQ-336).
- **Task 4.3** (security-engineer) 🔴: **ABAC fail-closed.** If
`KyvernoJsonEngine.is_configured()` returns false or `evaluate()`
raises, return 403 + audit `token.vend.denied` (reason:
`abac_eval_failed`). **Never fail open.** This is INV-17's runtime
enforcement (C-6.1/C-7.1 — the grill's #1 finding). Test:
`tests/test_abac_fail_closed.py` — mock `kj` absent → assert 403 +
audit event.
#### Wave 5 — JWKS endpoint (backend-engineer)
- **Task 5.1** (backend-engineer): `core/lambda/nova_idp_jwks.py` —
function URL `AuthType: NONE`, `Cache-Control: max-age=3600`.
`kms.get_public_key` → DER SPKI → JWK via `cryptography`. Returns
`{"keys":[...]}`. Custom domain + WAF = optional (D-230).
#### Wave 6 — PAT lifecycle (security-engineer + cli-engineer) [C-7.3]
- **Task 6.1** (security-engineer): PAT issuance — signed JWT
(`typ: "developer_pat"`, INV-14), `nova-pats` PutItem (jti, pat_hash,
status=active). Only hash stored (REQ-343). Revoked PATs retained.
**Max TTL: ≤24h for developer PATs, ≤1h for service-account PATs**
(C-6.2 threat model).
- **Task 6.2** (cli-engineer): `nova/auth/{login,revoke,status}.py` —
`nova auth login` (session→OIDC token, store in
`~/.nova/credentials.json` 0600), `nova auth revoke --pat <jti>`,
`nova auth status` (active credential, mode, selection_reason).
All emit audit events (REQ-344). **C-7.3: `~/.nova/credentials.json`
stores the OIDC token + PAT metadata (jti, exp, type) ONLY — NOT the
raw PAT.** The raw PAT is entered once at `nova auth login` and not
persisted (reduces filesystem-compromise blast radius).
#### Wave 7 — CAP-037/038 (security-engineer)
- **Task 7.1** (security-engineer): `tests/test_kms_roundtrip.py`
(REQ-350, CAP-037) — sign test JWT via token-vend, fetch JWKS,
verify with `pyjwt`. `tests/test_pat_revocation.py` (REQ-351,
CAP-038) — issue → vend → revoke → assert 403 within 60s P95.
#### Wave 8 — nova idp setup (cli-engineer + backend-engineer) [folded from P5 per C-2.1]
**Goal:** `nova idp setup` command with `--check/--apply/--verify`
modes; CloudFormation template generation + review (REQ-340, REQ-341).
- **Task 8.1** (backend-engineer): `nova/idp/setup.py` (+ backend
helper) — generates the Nova-idp CloudFormation template (raw dict →
JSON): 2-3 Lambdas, 4 DDB tables, KMS key, function URLs, IAM roles,
optional CloudFront/WAF/ACM (`--public-jwks-domain` flag).
- **Task 8.2** (cli-engineer): `--check` (prerequisites + IAM policy
delta), `--apply` (generate → `$PAGER` → `y/N` → `cloudformation
deploy --capabilities CAPABILITY_IAM`, NFR-10), `--dry-run` (resource
list only), `--verify` (KMS round-trip, delegates to REQ-350 test).
- **Task 8.3** (backend-engineer): IAM policy delta computation —
compares current `nova-spike-runner` grants to required
`cloudformation:*` + `codeartifact:*` + `kms:*` + `lambda:*` +
`dynamodb:*` + `ssm:*`.
### Phase P5 — docs-integration (REQ-345..REQ-351)
**Goal:** Operator guide, developer guide, threat model; E2E
integration test; property tests; KMS round-trip; PAT revocation SLO.
**Exit criterion:** all REQ-345..351 tests pass + docs published +
threat model reviewed.
#### Wave 1 — docs (lead-developer + security-engineer) [C-6.2/C-6.3/C-9.2]
- **Task 1.1** (lead-developer): `docs/operator-guide-idp.md` (REQ-345)
— `nova idp setup --check/--apply/--verify`, prerequisite IAM policy,
CloudFormation review flow. **C-6.3 additions:** KMS key rotation
procedure (90 days), Lambda layer update procedure, DDB PITR restore
procedure, emergency PAT revocation (DDB-level, not CLI).
- **Task 1.2** (lead-developer): `docs/developer-guide-auth.md`
(REQ-346) — signup, signin, login, mode resolution, TTY vs piped
stdout behavior, JWS-from-PAT KDF (P2 Wave 2 Task 2.3).
- **Task 1.3** (security-engineer): `docs/threat-model.md` (REQ-347) —
Argon2id storage, KMS signing, JWKS exposure, PAT revocation SLO,
ABAC token vending, no-AWS-managed-identity (INV-15), DER→raw ECDSA
gotcha. **C-6.2 additions:** (a) JWKS unauthenticated endpoint DDoS
surface + reserved-concurrency mitigation; (b) PAT theft + max TTL
(≤24h dev, ≤1h service-account); (c) ABAC fail-closed guarantee
(C-6.1). **C-9.2 addition:** INV-18..21 compression audit — verify
the spec's attestation invariant semantics are fully captured by
INV-15/16/17 + REQ-332.
#### Wave 2 — integration tests (backend-engineer + security-engineer)
- **Task 2.1** (backend-engineer): `tests/test_e2e_idp.py` (REQ-348) —
sign-up → sign-in → token-vend → apply → audit. Verifiable audit
chain. Runs in CI against deployed Nova-idp.
- **Task 2.2** (security-engineer): verify REQ-349 (mode_resolver
property tests, P1 Wave 3 Task 3.3) + REQ-350 (KMS round-trip, P4
Wave 7 Task 7.1) + REQ-351 (PAT revocation SLO, P4 Wave 7 Task 7.1)
pass in CI.
### Phase P6 — final-review-ship (Final Phase)
**Goal:** Multi-persona code review across P1..P5; project-health
audit; milestone ship to main; CAP-033..038 Verified.
#### Wave 1 — review (lead-developer)
- **Task 1.1** (lead-developer): `ciagent-review` across all phases.
Auto-fix P0; flag P1+ for post-hoc. If P1+ found, fix in this phase.
#### Wave 2 — audit (lead-developer)
- **Task 2.1** (lead-developer): `ciagent-audit` — reconstruction test
(git log ↔ `.ciagent/`), file/branch/commit discipline. Fix critical
issues in this phase.
#### Wave 3 — milestone ship (lead-developer)
- **Task 3.1** (lead-developer): `ciagent-ship` — merge `phase/06` →
`milestone/v1.28-cli-identity` → `main`; tag `v1.27.6` (= the v1.28
release); Gitea release with full milestone summary; delete all
milestone branches. Update REQUIREMENTS.md (mark REQ-323..353
complete), ROADMAP.md (mark v1.28 complete), STATE.md (append
CAP-033..038 + INV-12..17), NORTH_STAR.md.
---
## Requirement → Phase Mapping
## User-Facing Surface
No REQ-NNN (NFR milestone). The work items are file operations,
traced by the Wave tasks above.
> MVP/UX CHECK §1 (REQ-MVP-UX-001).
1. **CLI flag:** `nova --help` lists every subcommand; `nova init`
scaffolds a project; `nova auth login` authenticates; `nova apply
--local` runs locally; `nova idp setup` deploys the identity stack.
2. **README quickstart:** `docs/developer-guide-auth.md` (REQ-346)
documents signup → signin → login → `nova apply` in a quickstart.
3. **`.feature` Scenario:** `tests/test_e2e_idp.py` (REQ-348) is the
E2E happy path (sign-up → sign-in → token-vend → apply → audit).
## Happy Path
> MVP/UX CHECK §2 (REQ-MVP-UX-001). End-to-end scenario written BEFORE
> execute.
**Journey 2 — Dev authenticates and deploys locally:**
1. `nova auth signup` → `nova-idp-auth` Lambda → Argon2id hash →
`nova-users` PutItem → session token.
2. `nova auth signin` → `nova-idp-auth` → Argon2id verify → session.
3. `nova auth login` → `nova-idp-token-vend` (exchanges session for
Nova OIDC token; stores in `~/.nova/credentials.json` 0600).
4. `nova init` in a project dir → `.nova/`, `.gitignore`,
`.nova/contract.yml.attestations/`.
5. `nova apply --local --sign-local-review` →
`core.env.synthesize_local_env()` → `core.contract_resolver.resolve()`
→ JWS attestation signed with a key derived from the PAT → local
ledger entry.
The E2E test (`tests/test_e2e_idp.py`, REQ-348) verifies this chain +
the audit event chain in CI against a deployed Nova-idp.
## UX Acceptance Criteria
> MVP/UX CHECK §3 (REQ-MVP-UX-001).
1. `nova --help` exits 0 and lists a subcommand for every `core/`
module (CAP-033).
2. `nova init` in an empty dir creates `.nova/`,
`.nova/contract.yml.attestations/`, `.gitignore` (secrets excluded).
3. `nova auth login` at a TTY resolves `mode=interactive,
selection_reason=credential:developer_pat` (INV-12, INV-14).
4. `nova apply --local` produces a JWS attestation verifiable with the
public key derived from the PAT (REQ-332).
5. `nova idp setup --check` reports prerequisites + IAM policy delta;
`--apply` presents the CloudFormation template for review before any
resource is created (NFR-10); `--verify` confirms the KMS round-trip.
6. The Forge action (`nova cli-action`) runs `nova apply` in
`mode=agent, selection_reason=credential:service_account_pat` with
no TTY dependency (Journey 3, INV-12).
7. PAT revocation takes effect within 60s P95 (NFR-4, CAP-038).
---
## Wave Ordering Rationale
## Capability gate (CAP-033..CAP-038)
- **P1 W1 → W2:** verify STATE.md before archiving (the archive removes
the source-of-truth CAPABILITY_INVENTORY; STATE.md must be accurate
first).
- **P1 W2 → W3:** platform archive before consumer archive (the
platform archive pattern is established; the consumer archive
creates a new subdir).
- **P2 W1 → W2 → W3:** PROJECT.md fix before ROADMAP.md fix before
ship-discipline wiring (PROJECT is the source-of-truth narrative;
ROADMAP mirrors it; PLAN/NORTH_STAR wire the convention).
- **P2 W4:** archive README + consumer pointer (cross-cutting; lands
after the active-file fixes).
- **P2 W5:** dangling-reference fixes (lands after all moves + edits
are known).
| CAP | Name | Phase | Gate rule |
|-----|------|-------|-----------|
| CAP-033 | CLI subcommand surface exists | P1 | `nova --help` lists a subcommand for every `core/` module |
| CAP-034 | Subcommand delegates to `core/` | P1 | Every `nova/<module>.py` ≤50 lines, no business logic, AST scan |
| CAP-035 | Layer matches wheel | P1 | Lambda layer ARN version matches `nova-cli` wheel version (SSM mapping) |
| CAP-036 | Nova-idp auth flow works | P3 | E2E test (sign-up → sign-in → session) passes in CI |
| CAP-037 | Token-vend signs via KMS | P4 | KMS round-trip test (REQ-350) passes in CI |
| CAP-038 | PAT issuance + revocation | P4 | Issue → vend → revoke → 403 within 60s P95 (REQ-351) passes in CI |
**Release gate (§6 of the spec):** CAP-001..CAP-032 remain Verified;
CAP-033..CAP-038 are Verified; all v1.28 release-gate criteria met.
---
## Vertical-slice integrity
## Test evidence required for v1.28 release
Each phase ships a self-contained, verifiable slice:
- P1 ships STATE.md (verified accurate) + 8 archived files (verified
moved). The active `.ciagent/` root drops from 25 to 17 files.
- P2 ships 3 fixed files + 3 wired files + archive README + consumer
pointer. The kept files match CHECKPOINT.json state.
- P3 ships the milestone release + cleared checkpoint.
- [ ] Code coverage ≥ 80% on new modules (`mode_resolver.py`,
`nova-idp-auth`, `nova-idp-token-vend`, PAT lifecycle).
- [ ] CI/CD pipeline GREEN: wheel + Lambda layer publish on every merge
(REQ-323, CAP-035).
- [ ] QA sign-off: all four happy-path journeys (J1J4) pass integration
tests in CI.
- [ ] Security/compliance review: threat model published, Argon2id
verified, ABAC policy reviewed.
- [ ] Capability gate GREEN: CAP-001..032 remain Verified; CAP-033..038
Verified.
- [ ] Mode resolver property tests pass (all four priority levels + edge
cases; REQ-349).
- [ ] KMS round-trip test passes against deployed JWKS (REQ-350).
- [ ] PAT revocation SLO verified: ≤60s P95 in CI (REQ-351, NFR-4).
- [ ] Operator + developer guides published.
- [ ] `nova idp setup` succeeds in a fresh AWS account.
- [ ] Byte-identical Forge action on GitHub + Gitea (REQ-326, NFR-11).
---
## Plan completeness checklist
- [x] Every REQ-323..353 mapped to a phase + wave + task.
- [x] Every CAP-033..038 mapped to a phase + gate rule.
- [x] Every INV-12..17 referenced in persona constraints.
- [x] Every D-226..231 referenced in task rationale.
- [x] Vertical slices: each phase ships independently (P1 CLI substrate
is useful before P2 packaging; P2 before P3 auth; etc.).
- [x] Wave ordering within phases (no wave N+1 depends on wave N work
in the same phase).
- [x] Persona assignments per task (4 active personas).
- [x] MVP/UX CHECK: 3 sections present (User-Facing Surface, Happy Path,
UX Acceptance Criteria).
- [x] Highest-risk item flagged (P4 Wave 1 kj-binary spike).
- [x] Grill conditions applied (3 critical + 16 tracked; see GRILL.md).
---
## Cost envelope (C-3.1)
Monthly estimate for the default (no CloudFront) Nova-idp deployment in
account `581513795199`:
| Resource | Quantity | Pricing | Est. monthly |
|----------|----------|---------|-------------|
| DynamoDB (on-demand) | 4 tables | $1.25/1M write, $0.25/1M read | ~$1 (pilot volume) |
| DynamoDB PITR | 4 tables | $0.20/GB-month | ~$1 (small tables) |
| KMS asymmetric key | 1 key | $1/key-month + $0.03/10k signs | ~$1 |
| Lambda invocations | 3 Lambdas | $0.20/1M req + $0.000016/GB-s | ~$2 (low volume) |
| Lambda layer storage | ~50 MB | $0.02/GB-month | <$1 |
| CodeArtifact | 1 domain + 1 repo | $1/domain + $1/repo | $2 |
| SSM Parameter | 1 | $0.05/param (advanced) | <$1 |
| **Total (default)** | | | **~$9/month** |
Optional CloudFront + WAF + ACM (if `--public-jwks-domain`): +~$3/month
at pilot volume. ACM is free for CloudFront-attached certs.
This is a pilot-scale cost envelope. Production scale (100x volume)
would still be <$50/month. No hidden costs identified.
+115 -8
View File
@@ -129,7 +129,11 @@ human at stage gates" model from the NORTH_STAR.
## Capability Status (Re-Verified 2026-07-27)
> Source of truth: `.ciagent/CAPABILITY_INVENTORY.md` (Phase 54, D-093).
> **PO-facing capability catalog:** `.ciagent/STATE.md` (additive;
> updated at milestone ship). CAP-NNN IDs cross-reference the regression
> gate at `core/regression_verify.py`.
> Source of truth (the 2026-07-27 sweep, archived v1.27):
> `.ciagent/archive/CAPABILITY_INVENTORY-v1.10.md` (Phase 54, D-093).
> Tier: **local** = runs via emulating adapters (no AWS); **live-aws** =
> runs against the live AWS account (581513795199).
@@ -156,7 +160,7 @@ service live, CloudFront production stack, uptime-kuma, OIDC role). The
code would deploy them; the local emulators (Phase 53) prove the runtime
behavior. Re-bootstrap of the OIDC role + IAM re-grant requires an admin
principal — escalated, not silently skipped. See
`CAPABILITY_INVENTORY.md` §"Cloud capabilities NOT re-verified".
`CAPABILITY_INVENTORY-v1.10.md` §"Cloud capabilities NOT re-verified".
**Regression gate.** `bash scripts/run_regression.sh` re-runs all 16
auto-verifiable capabilities and fails closed on any non-Verified result.
@@ -340,7 +344,7 @@ plan-JSON policies + pipeline wiring (REQ-300,301,302), meta-policies
(REQ-303), regression-gate policies (REQ-304,305), docs + adapter README
(REQ-306,307), tests (REQ-308,309).
## v1.26 — Live Pilot Estate Activation (active)
## v1.26 — Live Pilot Estate Activation (complete, tag `v1.25.5`, merged to main 2026-08-19)
> **Active milestone.** Feature milestone — the first real consumer estate
> (a stock exchange on a homegrown PoA blockchain, equities only) is
@@ -421,14 +425,117 @@ already exist).
- The consumer deploy MUST go through `deploy.yml@v1.25` — no direct
`terraform apply` bypassing the platform's gates.
### v1.26 phase status (live — see CHECKPOINT.json for the authoritative state)
### v1.26 phase status (shipped — tag `v1.25.5` = the v1.26 release, merged to main 2026-08-19)
- **P0** pre-execution (SPECIFY→CLARIFY→RESEARCH→IDEATE→PLAN→GRILL) — complete, tag `v1.25.0`.
- **P1** blockchain-core (REQ-310,311,312) — complete, tag `v1.25.1`.
- **P2** consumer-contract-and-deploy (REQ-313,314,322) — complete, tag `v1.25.2`.
- **P3** pilot-metrics-and-policies (REQ-315,316,317,318,319,320) — pending.
- **P4** pilot-run-and-docs (REQ-316,321) — pending.
- **P5** final review + audit + milestone ship — pending. Tag `v1.25.5` = the v1.26 release.
- **P3** pilot-metrics-and-policies (REQ-315,316,317,318,319,320) — complete, tag `v1.25.3`.
- **P4** pilot-run-and-docs (REQ-316,321) — complete, tag `v1.25.4` (live apply against `581513795199` succeeded; confidence 0.800 pass; outcome backfilled).
- **P5** final review + audit + milestone ship — complete, tag `v1.25.5` = the v1.26 release (PROCEED; 0 P0 remain; audit CLEAN; merged to main).
> Phase-by-phase task breakdown, wave ordering, and persona assignments
> live in `.ciagent/PLAN.md` (the active phase plan, retained in full).
> live in `.ciagent/PLAN.md` (the active phase plan, retained in full).
> v1.26 pre-execution artifacts (CLARIFY/GRILL/IDEATE/RESEARCH) are in
> git history (pre-v1.27-P0 commits); the v1.26 phase verifications +
> review are archived at `.ciagent/archive/{VERIFY-P03,VERIFY-P04,REVIEW-AUDIT-P05}.md`.
## v1.27 — PO State Catalog & Ciagent Compression (complete, tag `v1.26.3`, merged to main 2026-08-19)
> **NFR milestone — complete.** STATE.md authored (32 CAPs, 11 invariants,
> 10 domains). 8 outdated `.ciagent/` files archived (7 platform + 1
> consumer). PROJECT.md + ROADMAP.md v1.26 phase-status corrected.
> STATE.md wired into P-final ship discipline. Tags: `v1.26.0` (P0) →
> `v1.26.1..v1.26.2` (P1..P2) → `v1.26.3` (P3 final = milestone release).
> Review: 0 P0. Audit: reconstruction PASS, file/branch/commit discipline CLEAN.
> Full phase detail: `.ciagent/archive/` (v1.27 artifacts) + git history.
## v1.28 — CLI Canonicalization + Identity Layer (active)
> **Feature milestone — active.** The Nova CLI becomes installable from
> internal PyPI (CodeArtifact), every `core/` module is reachable as a
> `nova <subcommand>`, the CLI and Lambda functions share a single
> `core/` source tree, and Nova owns its identity layer end-to-end
> (sign-up through token vending) with no AWS-managed identity services
> in the path. Nova-idp is introduced: two Lambda functions (`nova-idp-auth`,
> `nova-idp-token-vend`), KMS-signed OIDC tokens, ABAC-gated token vending
> via the existing kyverno-json engine (INV-4 swappable), and PAT
> lifecycle (issuance, revocation, status).
>
> Tags run on the **v1.27.x** line: `v1.27.0` (P0) → `v1.27.1..v1.27.N`
> (execution phases) → `v1.27.(N+1)` (final phase = milestone release).
> Milestone branch: `milestone/v1.28-cli-identity`.
### v1.28 ID allocations (re-mapped — no collisions with shipped history)
- **Decisions:** `D-226..D-231` (authored in CLARIFY). Repo decision
namespace is `D-NNN` (max D-225); no `D-NEW-*` namespace exists.
- **Requirements:** `REQ-323..REQ-353` (31 REQs, mapping the spec's
REQ-001..REQ-031 1:1). Max existing REQ = REQ-322.
- **Capabilities:** `CAP-033..CAP-038` (mapping the spec's CAP-025..CAP-030).
Existing CAP-025..032 are blockchain/pilot — collision avoided.
- **Invariants:** `INV-12..INV-17` (mapping the spec's INV-63,64,65,18..21,34).
Max existing INV = INV-11.
- **`kj` engine → kyverno-json.** The spec references a `kj` engine; the
repo's actual policy engine is `kyverno-json` (INV-4 swappable). v1.28
uses kyverno-json as the ABAC evaluator for token-vend; no new `kj`
engine is built. This is a CLARIFY-grounded re-mapping, not a silent
assumption (D-229).
### v1.28 Requirements
New requirements REQ-323..REQ-353 — full text in
`.ciagent/REQUIREMENTS.md` §v1.28. Summary by priority:
- **P1 — CLI Substrate (REQ-323..REQ-328):** CodeArtifact wheel + Lambda
layer pipeline; CLI subcommand per `core/` module; `nova init`
scaffolding; `nova cli-action` published to GitHub + Gitea;
`mode_resolver.py` (flag → env → credential type → TTY); audit
emission with `mode` + `selection_reason`.
- **P2 — Lambda Packaging + Identity Layer (REQ-329..REQ-344):** dual-use
`core/lambda/contract_ingestor.py`; local env synthesizer; JWS signing
key from PAT; `nova-idp-auth` Lambda (Argon2id, DynamoDB); DynamoDB
tables (`nova-users`, `nova-sessions`, `nova-password-resets`);
`nova-idp-token-vend` Lambda (KMS-signed OIDC, JWKS endpoint); kyverno-json
ABAC policy at `platform/abac/token-vend.policy`; `nova idp setup`
(`--check/--apply/--verify`); CloudFormation review; PAT issuance +
hashes in DynamoDB; `nova auth login/revoke/status`.
- **P3 — Documentation (REQ-345..REQ-347):** operator guide for
`nova idp setup`; developer guide for `nova auth login`; identity-layer
threat model.
- **P4 — Integration Testing (REQ-348..REQ-351):** E2E sign-up → sign-in →
token-vend → apply → audit; property tests for `mode_resolver`; KMS
round-trip test; PAT revocation SLO test (≤60s P95).
- **P5 — Capability Gate (REQ-352..REQ-353):** CAP-033..038 verification
gates wired into CI.
### v1.28 Hard constraints
- DO NOT depend on Cognito, IAM Identity Center, or any AWS-managed
identity service for sign-up/sign-in/token-vending (NFR-5). Nova-idp
signs OIDC tokens directly via KMS. (Note: no Cognito exists in the
repo today — this is a greenfield build, not a "Cognito drop".)
- DO NOT build a new `kj` engine — use kyverno-json (INV-4).
- DO NOT enforce MFA/TOTP for prod/dr this milestone — ship the code path,
enforce in v1.21+ (deferred, INV scope).
- DO NOT add WebAuthn/FIDO2, upstream IdP federation, or password breach
detection — deferred to v1.23+.
- DO NOT add Lambda layer auto-update on `core/` changes — v1.18 ships
manual `nova layer update`; v1.19 adds CI-triggered auto-update.
- The token-vend Lambda MUST evaluate the kyverno-json ABAC policy before
signing; allow/deny decisions MUST be emitted to the audit stream
(NFR-9, D-227).
- `nova idp setup --apply` MUST present the CloudFormation template for
review before any resource is created (NFR-10).
### v1.28 phase status (active — phase 0 in progress)
- **P0** pre-execution (SPECIFY→CLARIFY→RESEARCH→PLAN→GRILL→MVP/UX) — in
progress, target tag `v1.27.0`.
- **P1..PN** execution phases — planned in PLAN.md.
- **P(N+1)** final review + audit + milestone ship — target tag
`v1.27.(N+1)` = the v1.28 release.
> Phase-by-phase task breakdown, wave ordering, and persona assignments
> will live in `.ciagent/PLAN.md`. Authoritative resume state:
> `.ciagent/CHECKPOINT.json`.
+303 -1
View File
@@ -299,4 +299,306 @@
Full v1.26 requirement text:
`.ciagent/nova-blockchain-exchange/REQUIREMENTS.md`. Active phase plan:
`.ciagent/PLAN.md`.
`.ciagent/PLAN.md`.
## v1.28 — CLI Canonicalization + Identity Layer (active)
> **Feature milestone — active.** The Nova CLI is installable from
> internal PyPI (CodeArtifact); every `core/` module is reachable as a
> `nova <subcommand>`; the CLI and Lambda functions share a single
> `core/` source tree; and Nova owns its identity layer end-to-end
> (Nova-idp: `nova-idp-auth` + `nova-idp-token-vend` Lambdas, KMS-signed
> OIDC tokens, kyverno-json ABAC token vending, PAT lifecycle). No
> AWS-managed identity services in the path.
>
> Tags run on the **v1.27.x** line: `v1.27.0` (P0) →
> `v1.27.1..v1.27.N` → `v1.27.(N+1)` (final = milestone release).
> Milestone branch: `milestone/v1.28-cli-identity`.
>
> **ID re-mapping (no collisions):** the source spec used `REQ-001..031`,
> `CAP-025..030`, `INV-63/64/65/18..21/34`, `D-NEW-26/37..41`, and a `kj`
> engine — none of which exist in this repo (CAP-025..032 and
> INV-1..11 are already allocated to blockchain/pilot work; the policy
> engine is kyverno-json, not `kj`). This file uses the re-mapped IDs:
> `REQ-323..353`, `CAP-033..038`, `INV-12..17`, `D-226..231`. The 1:1
> mapping is recorded in CLARIFY.md. Decisions D-226..D-231 are authored
> in CLARIFY (full autonomy) — they are not pre-existing "locked inputs".
### Decisions (locked in CLARIFY — full autonomy, load-bearing for v1.28)
- **D-226 (Mode resolution priority):** flag → env (`NOVA_CLIENT_MODE`) →
credential type → TTY heuristic. Invalid env values are ignored + warned,
falling through to credential type. No silent fallbacks (NFR-1).
- **D-227 (ABAC engine = kyverno-json):** the token-vend Lambda uses the
existing kyverno-json engine (INV-4 swappable) as the ABAC evaluator,
not a new `kj` engine. Policy at `platform/abac/token-vend.policy`.
- **D-228 (Argon2id in Lambda):** `argon2-cffi` with bundled wheels; if
the C extension fails to load, fall back to the pure-Python
implementation; if both fail, document the Fargate migration path.
- **D-229 (PAT revocation SLO):** strongly-consistent DynamoDB read on
every token-vend request; revocation takes effect within 60s P95 (NFR-4).
- **D-230 (JWKS endpoint):** Lambda function URL behind a custom domain;
rate limiting at the DNS/CDN layer. API Gateway migration deferred to
v1.19+ if throttling requirements grow.
- **D-231 (ABAC policy ownership + versioning):** Platform Security owns
`platform/abac/token-vend.policy`; changes require PR review; the
policy version (git SHA) is recorded in every token-vend audit event.
### P1 — CLI Substrate
#### REQ-323 — CodeArtifact wheel + Lambda layer pipeline
**Journeys:** J3. **Priority:** High.
**AC:** Given a merge to `main` affecting `core/`, when CI runs, then both
the wheel and the Lambda layer are published to CodeArtifact with
identical version strings; if either fails, the merge is rejected.
#### REQ-324 — CLI subcommand per `core/` module
**Journeys:** J3. **Priority:** High.
**AC:** (1) Every module in `core/` has a corresponding `nova/<module>.py`
subcommand. (2) Subcommand files are ≤ 50 lines and contain no business
logic — they delegate to `core/`. (3) CAP-034 verifies delegation by AST
scan.
#### REQ-325 — `nova init` scaffolds project
**Journeys:** J2. **Priority:** High.
**AC:** Given a directory with no `.nova/`, when Dev runs `nova init`,
then `.nova/`, `.nova/contract.yml.attestations/`, and `.gitignore`
(excluding secrets) are created.
#### REQ-326 — `nova cli-action` published
**Journeys:** J3. **Priority:** High.
**AC:** (1) Action is available on both GitHub and Gitea marketplaces.
(2) Integration test verifies byte-identical behavior on both platforms.
(3) Python 3.12 is pinned.
#### REQ-327 — `mode_resolver.py` priority
**Journeys:** J2, J3. **Priority:** High.
**AC:** (1) Explicit `--mode=agent|interactive` flag always wins.
(2) Otherwise `NOVA_CLIENT_MODE` env var. (3) Otherwise credential type
default. (4) Otherwise TTY heuristic. (5) Property tests cover all four
levels. (6) INV-13 (mode determinism) enforced at PR time.
#### REQ-328 — Audit emission with mode + selection_reason
**Journeys:** J3. **Priority:** High.
**AC:** Given any CLI invocation, when the CLI runs, then the emitted
`cli.invocation` audit event contains `mode`, `selection_reason`,
`credential_type`, `command`, and `args`. INV-12 (mode observability)
enforced.
### P2 — Lambda Packaging + Identity Layer
#### REQ-329 — Dual-use Lambda/CLI import
**Journeys:** J2. **Priority:** High.
**AC:** Given `core/lambda/contract_ingestor.py`, when imported from the
Lambda handler, then it executes the Lambda path; when imported from the
CLI, then it executes the local path; and the two paths share ≥ 80% of
their code.
#### REQ-330 — Local env synthesizer
**Journeys:** J2. **Priority:** High.
**AC:** Given a contract and a `--local` flag, when `nova apply --local`
runs, then a local env is synthesized via `core/env.py:get_env()` without
provisioning cloud resources.
#### REQ-331 — Attestations directory scaffolded
**Journeys:** J2. **Priority:** High.
**AC:** Given `nova init` ran, when Dev lists
`.nova/contract.yml.attestations/`, then the directory exists and is empty.
#### REQ-332 — JWS signing key from PAT
**Journeys:** J2. **Priority:** High.
**AC:** Given a PAT, when Dev runs `nova apply --local --sign-local-review`,
then a JWS attestation is produced; the JWS is HMAC-SHA256 with a key
derived from the PAT via `HKDF-SHA256(PAT_bytes, salt='nova-local-attestation',
info='jws-signing-key')` → 32-byte symmetric key (C-5.2 grill fix). The
verification key is derived from the PAT via the same KDF (the PAT is
the shared secret). INV-14..17 (attestation invariants) enforced.
#### REQ-333 — `nova-idp-auth` Lambda
**Journeys:** J1, J2. **Priority:** High.
**AC:** (1) Lambda exposes sign-up, sign-in, and session creation
endpoints. (2) Passwords are hashed with Argon2id. (3) Sessions are
stored in DynamoDB. (4) CAP-036 verifies end-to-end auth flow.
#### REQ-334 — Argon2id password hashing
**Journeys:** J1, J2. **Priority:** High.
**AC:** Given a sign-up request, when the user record is persisted, then
the password is stored as an Argon2id hash; raw passwords never appear in
logs, traces, environment variables, or DynamoDB records.
#### REQ-335 — DynamoDB tables for identity
**Journeys:** J1. **Priority:** High.
**AC:** (1) Tables exist: `nova-users`, `nova-sessions`,
`nova-password-resets`. (2) Tables are provisioned by `nova idp setup`.
(3) Point-in-time recovery is enabled on each.
#### REQ-336 — `nova-idp-token-vend` Lambda
**Journeys:** J1, J2, J4. **Priority:** High.
**AC:** (1) Lambda accepts a PAT (or session token) and returns a
KMS-signed OIDC token. (2) Token claims include `sub`, `aud`, `iss`,
`exp`, and role claims. (3) ABAC policy is evaluated before signing.
#### REQ-337 — KMS-signed OIDC tokens
**Journeys:** J1, J4. **Priority:** High.
**AC:** (1) Signing key is a KMS asymmetric key (RSA or ECDSA).
(2) Token signature is verifiable via the JWKS endpoint. (3) KMS
round-trip test passes. CAP-037 verifies.
#### REQ-338 — JWKS endpoint as Lambda function URL
**Journeys:** J1, J4. **Priority:** High.
**AC:** Given the identity stack is deployed, when a client GETs the JWKS
URL, then the public key(s) for token verification are returned with
`Content-Type: application/json`.
#### REQ-339 — kyverno-json ABAC policy file
**Journeys:** J1, J4. **Priority:** High.
**AC:** (1) Policy at `platform/abac/token-vend.policy`. (2) Policy inputs
include subject, requested claims, target resource, and environment.
(3) kyverno-json `evaluate` returns allow/deny; the decision is emitted to
the audit stream.
#### REQ-340 — `nova idp setup` walks admin
**Journeys:** J1. **Priority:** High.
**AC:** (1) Command supports `--check`, `--apply`, and `--verify` modes.
(2) `--check` reports missing prerequisites and the required IAM policy.
(3) `--apply` generates a CloudFormation template and requires explicit
approval. (4) `--verify` runs the KMS round-trip test.
#### REQ-341 — CloudFormation template for review
**Journeys:** J1. **Priority:** High.
**AC:** Given `nova idp setup --apply`, when the template is generated,
then the template is presented for review; resources are not created until
the operator approves; `--dry-run` shows the resource list without writing.
#### REQ-342 — PAT issuance via portal
**Journeys:** J4. **Priority:** High.
**AC:** (1) PAT is a signed JWT. (2) PAT hash is stored in DynamoDB.
(3) PAT includes a unique `jti` and an expiry claim. (4) Revocation marks
the `jti` as revoked.
#### REQ-343 — PAT hashes in DynamoDB
**Journeys:** J4. **Priority:** High.
**AC:** (1) Only the hash (not the raw PAT) is stored. (2) Table supports
lookup-by-hash and lookup-by-`jti`. (3) Revoked PATs are retained for
audit, not deleted.
#### REQ-344 — `nova auth` commands
**Journeys:** J2, J4. **Priority:** High.
**AC:** (1) `nova auth login` exchanges session → OIDC token, stores
locally. (2) `nova auth revoke --pat <id>` marks a PAT revoked.
(3) `nova auth status` shows current credential, mode, and
selection_reason. (4) All commands emit audit events.
### P3 — Documentation
#### REQ-345 — Operator guide for `nova idp setup`
**Priority:** High.
**AC:** Guide published covering `--check`, `--apply`, `--verify`,
prerequisite IAM policy, and the CloudFormation review flow.
#### REQ-346 — Developer guide for `nova auth login`
**Priority:** High.
**AC:** Guide published covering signup, signin, login, mode resolution,
and credential-type behavior at a TTY vs. piped stdout.
#### REQ-347 — Identity-layer threat model
**Priority:** High.
**AC:** Threat model published covering Argon2id storage, KMS signing,
JWKS exposure, PAT revocation SLO, ABAC token vending, and the no-AWS-
managed-identity constraint (NFR-5).
### P4 — Integration Testing
#### REQ-348 — E2E integration test
**Priority:** High.
**AC:** Given a deployed Nova-idp, when the test runs, then sign-up →
sign-in → token-vend → apply → audit completes successfully; the audit
event chain is verifiable.
#### REQ-349 — Property tests for `mode_resolver`
**Priority:** High.
**AC:** (1) Property tests cover all four priority levels. (2) Edge cases:
TTY but piped stdout, missing credential, conflicting flag/env, invalid
env value. (3) INV-13 enforced via test.
#### REQ-350 — KMS round-trip test
**Priority:** High.
**AC:** Given a token signed by the token-vend Lambda, when the test
fetches the JWKS and verifies the signature, then verification succeeds.
#### REQ-351 — PAT revocation SLO test
**Priority:** High.
**AC:** Issue PAT → use to vend token → revoke → assert denial within 60s
P95. Test passes in CI.
### P5 — Capability Gate
#### REQ-352 — CAP-033..038 gate rules wired into CI
**Priority:** High.
**AC:** (1) CAP-033 (CLI subcommand surface exists): `nova --help` lists a
subcommand for every `core/` module. (2) CAP-034 (subcommand delegates to
`core/`): every `nova/<module>.py` ≤ 50 lines, no business logic, AST
scan. (3) CAP-035 (layer matches wheel): Lambda layer ARN version matches
the `nova-cli` wheel version. (4) CAP-036 (Nova-idp auth flow works): E2E
test (REQ-348) passes. (5) CAP-037 (token-vend signs via KMS): KMS
round-trip (REQ-350) passes. (6) CAP-038 (PAT issuance + revocation):
REQ-351 passes. Failure of any → merge blocked.
#### REQ-353 — Capability gate GREEN for v1.28 release
**Priority:** High.
**AC:** CAP-001..CAP-032 remain Verified; CAP-033..CAP-038 are Verified.
All v1.28 release-gate criteria in PLAN.md §6 met.
### v1.28 Invariants (new — INV-12..INV-17)
- **INV-12 (Mode observability):** Every CLI invocation emits a
`cli.invocation` audit event containing `mode`, `selection_reason`,
`credential_type`, `command`, and `args`.
- **INV-13 (Mode resolution determinism):** Resolution priority is
flag → env (`NOVA_CLIENT_MODE`) → credential type → TTY. No silent
fallbacks. Deviations rejected at PR time.
- **INV-14 (Credential type encodes role):** `developer_pat` /
`nova_oidc_token` + TTY present → `interactive`; TTY absent → `agent`.
- **INV-15 (No AWS-managed identity in path):** Nova-idp MUST NOT depend
on Cognito, IAM Identity Center, or any AWS-managed identity service.
- **INV-16 (Password storage):** Passwords hashed with Argon2id; raw
passwords never in logs/traces/env/DynamoDB.
- **INV-17 (ABAC discipline):** The token-vend Lambda evaluates the
kyverno-json ABAC policy before signing; allow/deny + policy inputs
emitted to the audit stream.
### v1.28 Traceability (live — see CHECKPOINT.json for authoritative state)
| REQ | Phase | Status |
|-----|-------|--------|
| REQ-323 | P1 | planned |
| REQ-324 | P1 | planned |
| REQ-325 | P1 | planned |
| REQ-326 | P1 | planned |
| REQ-327 | P1 | planned |
| REQ-328 | P1 | planned |
| REQ-329 | P2 | planned |
| REQ-330 | P2 | planned |
| REQ-331 | P2 | planned |
| REQ-332 | P2 | planned |
| REQ-333 | P3 | planned |
| REQ-334 | P3 | planned |
| REQ-335 | P3 | planned |
| REQ-336 | P4 | planned |
| REQ-337 | P4 | planned |
| REQ-338 | P4 | planned |
| REQ-339 | P4 | planned |
| REQ-340 | P4 | planned |
| REQ-341 | P4 | planned |
| REQ-342 | P4 | planned |
| REQ-343 | P4 | planned |
| REQ-344 | P4 | planned |
| REQ-345 | P5 | planned |
| REQ-346 | P5 | planned |
| REQ-347 | P5 | planned |
| REQ-348 | P5 | planned |
| REQ-349 | P5 | planned |
| REQ-350 | P5 | planned |
| REQ-351 | P5 | planned |
| REQ-352 | P6 | planned |
| REQ-353 | P6 | planned |
+320 -128
View File
@@ -1,144 +1,336 @@
# Nova — v1.27 Research Findings
# Nova — v1.28 Research Findings
> Phase: research (pre-execution). Milestone: v1.27 (PO State Catalog &
> Ciagent Compression). Status: research. Researcher: ci-researcher.
> Phase: research (pre-execution). Milestone: v1.28 (CLI Canonicalization
> + Identity Layer). Status: research. Researcher: ci-researcher.
> Autonomy: full.
v1.27 is an NFR milestone (docs/chore only, no code, no schema). There
is no new domain to research. The research is a codebase-grounded
inventory of (a) the files to archive + their staleness evidence, and
(b) the sources backing the STATE.md capability backfill. This file
records the inventory for the v1.27 record; the active authoring used
these sources directly.
>
> Research delegated to the ci-researcher subagent (full domain/ecosystem
> research with web citations). This file is the curated summary; the
> full 868-line research document is preserved in git history (the
> subagent's task output). Key findings + recommendations are below.
---
## 1. Files to archive (staleness inventory)
## §1 — Codebase Inventory (grounding)
### 1.1 Pre-execution artifacts (v1.26 — shipped, decisions folded)
### 1.1 `core/` modules (the REQ-324 subcommand surface)
| File | Lines | Staleness evidence | Decisions folded into |
|---|---|---|---|
| `CLARIFY.md` | 225 | v1.26 milestone shipped (`v1.25.5`); decisions D-200..D-213 | `PROJECT.md` load-bearing decisions |
| `GRILL.md` | 225 | v1.26 grill verdict PROCEED 0.84; binding revisions applied | `PLAN.md` revisions (G-Q4 REQ-322→P2 W0; G-Q6 enforcement deferred; G-Q9 key-split future) |
| `IDEATE.md` | 193 | all 7 accepted ideas → REQ-315..322 (shipped) | `REQUIREMENTS.md` v1.26 traceability |
| `RESEARCH.md` | 250 | v1.26 domain research (blockchain, deploy, modules, metrics) | `ARCHITECTURE.md` §12.8; shipped REQs |
19 Python files under `core/` (plus `core/lambda/`, `core/metrics/`).
Two already have `_cli.py` companions (`contract_resolver_cli.py` 40
lines, `regression_verify_cli.py` 32 lines) — the thin-delegate
precedent for `nova/<module>.py`. **No `nova/` dir, no `bin/`, no
`[project.scripts]` entry exists today.** The CLI is greenfield.
All four are pre-execution artifacts for a shipped milestone. The next
P0 writes fresh versions. Per D-219 (user-confirmed) + D-222: archive
all four with `-v1.26` suffixes.
### 1.2 Existing Lambda pattern (`core/lambda/contract_ingestor.py`)
### 1.2 Phase verifications + review (v1.26 — shipped, PASS)
521 lines. Function URL + IAM auth (D-051). DynamoDB via lazy
module-global `boto3.resource`. Secrets Manager for tokens. Schema
validation in-Lambda. **`__main__` block already does CLI dispatch**
(`--check-readiness``core.submission_readiness.cli_main`) — this is
the dual-use precedent for REQ-329. Local testing via
`core/local_emulators.py:LocalLambdaStub`.
| File | Lines | Staleness evidence |
### 1.3 `core/env.py` — getter, not synthesizer
31 lines. `get_env(name, default)` reads `NOVA_<name>` from `os.environ`.
**REQ-330 needs a NEW `synthesize_local_env()` function** added here.
The closest existing pattern is `core/onboarding.py:generate_env_file()`.
### 1.4 `PolicyEngine` Protocol + `KyvernoJsonEngine` (the ABAC substrate)
`core/policy_engine.py`: `PolicyEngine` Protocol with `evaluate(payload,
policy_dir, contract_id) -> list[dict]`. `KyvernoJsonEngine` shells to
`kj scan --policy <dir> --payload <file> --output json`. Policy shape =
`ValidatingPolicy` (`apiVersion: json.kyverno.io/v1alpha1`) with
`spec.rules[].assert.all[].check` using JMESPath. Severity from
`metadata.annotations["nova.cloudinit.dev/severity"]`. **The payload
can be ANY JSON** — not just contracts (the v1.25 design point). This
is what makes kyverno-json usable for ABAC token vending (D-227).
### 1.5 `pyproject.toml` state
name `nova`, version `1.14.0`, requires-python `>=3.10` (spec wants
3.12 — bump needed for REQ-326). setuptools build backend. No
`[project.scripts]`, no `[tool.setuptools.packages.find]` — both needed.
Deps: `boto3`, `jsonschema`, `pyyaml`. No `argon2-cffi`, `cryptography`,
`pyjwt`, `click`/`typer`**argparse-only** is the repo convention.
### 1.6 Forge conventions
`.github/workflows/` + `.gitea/workflows/` kept byte-identical. Python
3.12 already pinned via `actions/setup-python@v5`. No composite action
exists yet — `nova cli-action` (REQ-326) is greenfield.
### 1.7 IAM baseline (load-bearing for REQ-340)
`.ciagent/IAM_POLICY.md` + `terraform/bootstrap/spike_runner_policy.json`.
The `nova-spike-runner` principal already has KMS (incl. `CreateKey`,
`Sign`, `GetPublicKey`), Lambda (incl. `PublishLayerVersion`), DynamoDB
grants. **New grants needed:** `cloudformation:*` (for `nova idp setup
--apply`) + `codeartifact:*` (for the wheel publish pipeline). Flagged
for P1/P2.
---
## §2 — CodeArtifact + Lambda Layer Pipeline (REQ-323)
**Recommendation:** single CI job on merge to `main` affecting
`core/**`/`adapters/**`/`nova/**`/`pyproject.toml`. Build wheel
(`python -m build --wheel`) → `twine upload` to CodeArtifact → build
layer (`pip install --target layer/python/ dist/nova-*.whl argon2-cffi
cryptography pyjwt`) → `aws lambda publish-layer-version` → record
version mapping in SSM `/nova/layer/nova-cli/version` (CAP-035). If
either publish fails, the job fails (merge blocked, REQ-323 AC).
**Atomicity:** wheel publish is idempotent (pin version to
`<semver>+<sha7>`); layer publish retries on failure. CAP-035 reads the
SSM parameter to verify layer-version ↔ wheel-version match.
**Risks:** CodeArtifact not yet provisioned in `581513795199` (CLARIFY
assumption #1); `codeartifact:*` grant missing. Fallback: Gitea-hosted
wheel index. Layer `--compatible-architectures`: build x86_64 only for
v1.28 (aarch64 only if Graviton Lambda needed).
---
## §3 — CLI Subcommand Architecture (REQ-324)
**Recommendation:** three-layer. `nova/__init__.py` (marker) →
`nova/cli.py` (~80 lines, auto-discovers `nova/<module>.py` via
`pkgutil.iter_modules`, dispatches, emits `cli.invocation` audit event)
`nova/<module>.py` (≤50 lines each, exports `add_parser(subparsers)`
+ `run(args) -> int`, delegates to `core/`). Entry point:
`[project.scripts] nova = "nova.cli:main"`. **argparse-only** (no
click/typer — repo convention).
**CAP-034 AST scan:** ≤50 lines; ≤3 function defs; every `ast.Call`
resolves to a `core.` import; no conditionals beyond `if __name__`.
**Subcommand groups:** `nova auth`, `nova idp`, `nova metrics` =
nested subparsers (same pattern, one level deeper).
**setuptools:** add `[tool.setuptools.packages.find]` including `nova`,
`nova.*`, `core`, `core.*`, `adapters.*`.
---
## §4 — Argon2id in Lambda Python 3.12 (REQ-334, D-228)
**Findings:** `argon2-cffi-bindings` v25.1.0 ships `cp39-abi3`
manylinux x86_64 + aarch64 wheels — **ABI-stable, compatible with
Python 3.9..3.13**. Lambda Python 3.12 runs Amazon Linux 2023 (glibc
2.34 ≥ 2.28 required). **The abi3 manylinux wheel loads cleanly.**
Confidence: 0.92.
**D-228 AMENDMENT:** the "pure-Python fallback" clause is **weaker than
stated** — there is no maintained pure-Python Argon2 implementation. A
pure-Python crypto fallback is a **liability** (weaker hashing,
violates INV-16's spirit). Revised recommendation:
1. **Primary:** bundled manylinux abi3 wheel in the `nova-cli` Lambda
layer. Works. Confidence 0.92.
2. **Fallback:** detect `ImportError` at Lambda cold-start → **fail
closed** (503, refuse sign-ups). The Lambda health check reports
C-extension status. **Do NOT ship a pure-Python fallback.**
3. **Escape hatch:** Fargate (~1 week, per CLARIFY Q1).
Lambda memory ≥ 512 MB (Argon2id memory_cost ~20 MB + overhead).
---
## §5 — KMS Asymmetric Signing for OIDC Tokens (REQ-337)
**Recommendation: key spec = `ECC_NIST_P256`, alg = `ECDSA_SHA_256`
(JWS `ES256`).** RSA-2048 is larger + slower; P-256 is RFC 7518's
recommended JWT alg. Signature size 64 bytes (vs RSA 256). JWKS
compactness matters (fetched often).
**The #1 gotcha:** KMS returns DER-encoded ECDSA signatures; **JWS
requires raw r‖s concatenation** (RFC 7515 §3.1.3). The token-vend
Lambda converts via `cryptography.hazmat.primitives.asymmetric.utils.
decode_dss_signature``r.to_bytes(32) + s.to_bytes(32)`. ~5 lines.
Flagged for the threat model (REQ-347) + KMS round-trip test (REQ-350).
**Flow:** validate PAT → ABAC eval → build JWT header/payload →
`kms.sign(Message=signing_input, MessageType="RAW", SigningAlgorithm=
"ECDSA_SHA_256")` → DER→raw → JWT. `kid` = KMS key alias.
**Verification:** use `pyjwt` (`jwt.decode` handles JWK→key natively);
`cryptography` only for SPKI→JWK in the JWKS Lambda.
**Rotation:** manual, 90 days (matches D-069 CMK cadence). New key +
re-point alias + JWKS serves both `kid`s during overlap.
---
## §6 — JWKS Endpoint (REQ-338, D-230)
**D-230 confirmed.** Lambda function URL (`AuthType: NONE` — JWKS is
public-key only) + reserved concurrency 10 (max 100 RPS, JWKS is
cached client-side). `Cache-Control: max-age=3600`. Separate tiny
`nova-idp-jwks` Lambda (separation of concerns).
**Custom domain + WAF = OPTIONAL** via `--public-jwks-domain <domain>`
flag on `nova idp setup`. Without it, raw function URL (acceptable for
v1.28 pilot). With it: CloudFront + ACM + WAF rate-based rule (>100
req/5min per IP) + Route53 ALIAS. Adds ~8 CloudFormation resources.
**Defer API Gateway** (D-230) — $3.50/M + complexity for no benefit at
v1.28 volume.
---
## §7 — kyverno-json ABAC Policy (REQ-339, D-227)
**D-227 confirmed.** Policy at `platform/abac/token-vend.policy` =
`ValidatingPolicy` with JMESPath checks against a payload of
`{subject, requested_claims, target_resource, environment, pat_jti,
policy_version}`. Decision logic: any `fail` PCR with severity
`critical` → deny (403 + audit); all pass → allow → KMS sign.
**`policy_version` (D-231):** git SHA of the policy file, baked into
the Lambda layer, recorded in every `token.vend.allowed/denied` audit
event.
**BIGGEST PACKAGING RISK:** the token-vend Lambda needs the `kj` Go
binary (~40 MB) on PATH. Bundle it in the `nova-cli` Lambda layer
(`wget` the Linux amd64 release into `layer/bin/kj`). `KyvernoJsonEngine
.is_configured()` checks `which kj``/opt/bin/kj` (layer mount). P2
spike confirms it runs in AL2023 Lambda. Fallback: Fargate. Confidence
0.75 — needs the spike.
---
## §8 — PAT Lifecycle (REQ-342, REQ-343, REQ-344)
**PAT = signed JWT** (KMS-signed, `typ: "developer_pat"` distinguishes
from `nova_oidc_token` per INV-14). Claims: `iss, sub, typ, jti, iat,
exp, roles, owner`.
**`nova-pats` DynamoDB table** (4th table): PK=`jti`, GSI1=`sub` (list
PATs for user), GSI2=`pat_hash` (lookup by hash). Only the hash stored
(not raw PAT). Revoked PATs retained for audit.
**Revocation (D-229 CLARIFIED):** GSIs don't support strongly-consistent
reads. The token-vend Lambda extracts `jti` from the PAT JWT (decode
without verifying — signature verified separately) →
`GetItem(PK=jti, ConsistentRead=True)` on the main table. Satisfies the
60s SLO. Confidence 0.90.
**CLI:** `nova auth login` (session→OIDC token, store locally),
`nova auth revoke --pat <jti>`, `nova auth status` (active credential,
mode, selection_reason). Local file `~/.nova/credentials.json` (0600,
never to stdout, in `.gitignore`). "Most recent wins" (D-226 Q5) =
`active_credential_jti` field.
---
## §9 — `nova idp setup` CloudFormation (REQ-340, REQ-341)
**Template (raw dict → JSON, no troposphere dep):** 2-3 Lambdas, 4
DynamoDB tables (`nova-users`, `nova-sessions`, `nova-password-resets`,
`nova-pats`), KMS key `alias/nova-oidc-signing` (ECC_NIST_P256),
function URLs, IAM roles, optional CloudFront/WAF/ACM.
**`--check`:** validates prerequisites (AWS creds, CFN perms, KMS perms,
layer exists via CAP-035). Prints required IAM policy delta.
**`--apply`:** generate → print to temp file + resource summary →
`$PAGER``Apply? [y/N]``cloudformation deploy --capabilities
CAPABILITY_IAM`. NFR-10 satisfied by the explicit prompt.
**`--dry-run`:** resource list only, no write.
**`--verify`:** runs the KMS round-trip test (REQ-350).
**New IAM grants needed:** `cloudformation:*`, `iam:CreateRole`/`PassRole`,
`lambda:CreateFunction`/`CreateFunctionUrlConfig`,
`dynamodb:CreateTable`, `kms:CreateKey`/`CreateAlias`, `ssm:PutParameter`.
---
## §10 — GitHub + Gitea Marketplace Composite Action (REQ-326)
**Single `action.yml`** at `.github/actions/nova-cli/action.yml`,
referenced by both GitHub + Gitea via `uses: continuous-intelligence/
acdl/.github/actions/nova-cli@v1.28`. Composite action: `setup-python@v5`
(python 3.12) → CodeArtifact login + `pip install nova``nova
${{ inputs.command }}`. `NOVA_CLIENT_MODE` env from input.
**Byte-identical test (REQ-326 AC2):** CI matrix runs the action on
GitHub `ubuntu-latest` + Gitea `act_runner` with same inputs; assert
same stdout/exit code.
**Risk:** Gitea `actions/checkout`/`setup-python` may need Gitea
mirrors (`https://gitea.com/actions/...`). P1 test on the actual Gitea
instance. Confidence 0.70.
---
## §11 — `mode_resolver` Priority (REQ-327, D-226)
**TTY detection: check `sys.stdin.isatty()`** (NOT stdout). Edge 3
(`nova apply | tee log.txt`): stdout piped, stdin is TTY → user is
present → `interactive` (correct). `sys.stdout.isatty()` would
misresolve to `agent`. **`stdin` answers "is a human at a terminal?"**
**Credential type detection:** read `~/.nova/credentials.json`
`active_credential_jti`'s `type` (`developer_pat`/`nova_oidc_token`).
Both + TTY → `interactive`; + no TTY → `agent` (INV-14).
**Property tests (REQ-349):** `hypothesis` with strategies for
flag/env/cred/tty. Properties: deterministic (INV-13), flag-wins,
invalid-env-ignored, no-silent-fallback (every resolution has a
non-empty `selection_reason`).
**`mode_resolver.py` lives in `core/`** (not `nova/`) so Lambdas could
import it, but **it's CLI-only** — the token-vend Lambda doesn't resolve
modes.
---
## §12 — Persona Assessment
See `.ciagent/PERSONAS.md` for the full YAML roster. Summary:
- **Deactivate** frontend-engineer (no UI) + data-engineer (no data
pipelines in v1.28).
- **Activate** backend-engineer (Lambda/DynamoDB/KMS/CodeArtifact) +
lead-developer (plan/review/ship).
- **Add** security-engineer (Argon2id/KMS/ABAC/threat model) +
cli-engineer (subcommand surface/mode_resolver/argparse/CAP-034).
---
## §13 — Architecture Sketch (ARCHITECTURE.md §12.10)
See `.ciagent/ARCHITECTURE.md` §12.10 (appended this stage). New
greenfield files: `nova/` CLI package, `platform/abac/token-vend.policy`,
`core/mode_resolver.py`, `core/env.py:+synthesize_local_env()`,
`core/lambda/nova_idp_{auth,token_vend,jwks}.py`, `tests/test_*`,
`docs/{operator-guide-idp,developer-guide-auth,threat-model}.md`.
---
## Decisions re-validated / amended
| Decision | Status | Change |
|---|---|---|
| `VERIFY-P03.md` | 39 | v1.26 P3 verification — PASS; shipped `v1.25.3` |
| `VERIFY-P04.md` | 31 | v1.26 P4 verification — PASS; shipped `v1.25.4` |
| `REVIEW-AUDIT-P05.md` | 218 | v1.26 P5 final review + audit — PROCEED; shipped `v1.25.5`; 0 P0 remain; audit CLEAN |
| `P4-PILOT-RUN-EVIDENCE.md` | 46 | v1.26 live apply evidence (`blkex-pilot-apply-v0.2`); summarized in `nova-blockchain-exchange/README.md` §5 + REVIEW-AUDIT-P05 §2.2 |
| D-226 | re-validated + refined | `sys.stdin.isatty()` is the TTY check (not stdout) |
| D-227 | re-validated | `kj` Go binary bundled in Lambda layer — packaging risk flagged |
| D-228 | **amended** | Pure-Python fallback → fail-closed + Fargate (pure-Python crypto is a liability) |
| D-229 | re-validated + clarified | Strong read on main table PK (`jti`), not GSI (GSIs don't support strong reads) |
| D-230 | re-validated | CloudFront/WAF/ACM made optional via `--public-jwks-domain` flag |
| D-231 | re-validated | `policy_version` (git SHA) in the ABAC payload |
### 1.3 Durable references (superseded or stale)
| File | Lines | Staleness evidence | Superseded by |
|---|---|---|---|
| `CAPABILITY_INVENTORY.md` | 120 | dated 2026-07-27; framed as "v1.1→v1.8 re-verification sweep"; predates v1.26 pilot (CAP-025 absent; blockchain capabilities absent) | `STATE.md` (this milestone) |
| `AUTONOMY_THESIS.md` | 65 | "Last refined: v1.21"; thesis fully folded into `NORTH_STAR.md` Vision (lines 1722) + Anti-Goals #2 | `NORTH_STAR.md` |
| `COST.md` | 106 | dated 2026-07-29; framed "v1.0 → v1.14"; predates v1.26 live pilot (ECS + ALB + DynamoDB + S3 costs not reflected) | A future cost milestone writes a fresh report; `STATE.md` Domain 7 notes cost tracking as a capability |
### 1.4 Consumer-side (nova-blockchain-exchange)
| File | Lines | Staleness evidence |
|---|---|---|
| `nova-blockchain-exchange/ROADMAP.md` | 57 | marks P3/P4/P5 as "planned" but v1.26 shipped (`v1.25.5`); phase narrative preserved in platform `ROADMAP.md` v1.26 section |
Per D-221: consumer archives land in
`.ciagent/nova-blockchain-exchange/archive/ROADMAP-v1.26.md`.
**New recommendations for PLAN/GRILL to formalize (no D-ID yet):**
- KMS key spec = `ECC_NIST_P256`, alg `ES256`; DER→raw ECDSA conversion required.
- `nova-cli` Lambda layer bundles the `kj` Go binary (~40 MB).
- `nova-pats` = 4th DynamoDB table; PK=`jti`, GSI1=`sub`, GSI2=`pat_hash`.
- `sys.stdin.isatty()` is the TTY heuristic.
- `[project.scripts] nova = "nova.cli:main"`; argparse-only.
- `cloudformation:*` + `codeartifact:*` = new IAM baseline grants (P1/P2).
---
## 2. Files to keep active (no-edit or fix-only)
## RESEARCH complete
### 2.1 No-edit (live code paths or durable)
| File | Why keep active |
|---|---|
| `CHECKPOINT.json` | Authoritative resume state — never archive |
| `config.json` | Operational config — never archive |
| `REGRESSION_REPORT.json` | Written by `core/regression_verify.py:705`; read by `core/metrics/collector.py:27` + `trust_snapshot.py:21` + metrics views (D-224: regenerates on next `run_regression.sh`) |
| `REGRESSION_REPORT.md` | Written by `core/regression_verify.py:704`; read by `scripts/run_regression.sh` (D-224) |
| `PERSONAS.md` | Regenerated at each milestone P0 by the lead-developer; not stale until then |
| `IAM_POLICY.md` | Live baseline, test-enforced (`tests/test_iam_policy_baseline.py`); D-207 future key-split pending (D-223) |
| `PLAN.md` | Active phase plan; reset to next milestone at next P0 |
| `ARCHITECTURE.md` | Durable target architecture (§1–§12 + §12.7 + §12.8 + §12.9) |
| `NORTH_STAR.md` | PO strategy; loaded every ci-run via `config.strategic_direction_file` |
| `nova-blockchain-exchange/PROJECT.md` | Consumer project charter; D-200..D-205 load-bearing |
| `nova-blockchain-exchange/REQUIREMENTS.md` | REQ-310..322 spec intent (shipped but spec stays for reference) |
| `nova-blockchain-exchange/README.md` | Consumer onboarding guide; still accurate (deploy workflow, secrets, contract shape, verification) |
### 2.2 Fix-only (corrections to stale-but-kept files)
| File | Fix |
|---|---|
| `PROJECT.md` | v1.26 phase-status block (lines 424431): P3/P4/P5 "pending" → "complete" with shipped tags `v1.25.3/4/5`; add STATE.md pointer (D-225: P2 phase) |
| `ROADMAP.md` | v1.26 P3/P4/P5 sections (lines 238, 261, 272) "planned" → "complete" with shipped tags; v1.26 Overview line "active" → "complete"; add STATE.md to P5 ship-update list (D-225: P2 phase) |
| `archive/README.md` | Add the 11 new archived files to the contents tables (P2 phase) |
---
## 3. STATE.md capability backfill sources
The STATE.md backfill (36 capabilities across 10 domains) was sourced
from:
| Source | Used for |
|---|---|
| `core/regression_verify.py` (lines 129768) | CAP-001..CAP-025 IDs, names, tiers, evidence pointers |
| `.ciagent/CAPABILITY_INVENTORY.md` (pre-archive) | CAP-001..022 descriptions, defect notes, evidence |
| `modules/registry.json` | L1/L2 module catalog (13 L1 + 2 L2 entries) |
| `.ciagent/REQUIREMENTS.md` v1.25 traceability | REQ-291..309 → policy-engine capabilities |
| `.ciagent/nova-blockchain-exchange/REQUIREMENTS.md` + `.ciagent/REQUIREMENTS.md` v1.26 traceability | REQ-310..322 → pilot capabilities |
| `.ciagent/CHECKPOINT.json` | shipped tags `v1.25.0..v1.25.5` |
| `git log --all --oneline` | file paths for v1.26 shipped features |
| `.ciagent/PROJECT.md` load-bearing decisions | INV-1..INV-11 invariants |
| `docs/submission-readiness.md` + `schemas/contract.schema.json` | INV-1 contract surface |
---
## 4. Persona assessment
v1.27 is a docs/chore milestone. The active roster:
- **lead-developer** (active): owns the milestone narrative (STATE.md
authoring, PROJECT/ROADMAP fixes, archive README, PLAN/NORTH_STAR
wiring, this RESEARCH, CLARIFY, PLAN, final review + audit). Territory:
`.ciagent/`, `docs/`.
- **backend-engineer** (active, limited): no code changes in v1.27.
Consulted on the `core/confidence_signal.py` LSP diagnostic (pre-
existing, not touched by v1.27). No territory writes.
- **data-engineer** (inactive): no schema/migration/ORM changes.
- **policy-engineer** (inactive): no policy authoring.
- **frontend-engineer** (inactive): no UI.
- **blockchain-engineer** (inactive): no chain code.
Territory enforcement: warn. The milestone is `.ciagent/`-only; the
lead-developer owns all writes.
---
## 5. Risk analysis
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Archive move breaks a relative path reference in an active file | Low | Medium | `grep` for the archived filenames across `.ciagent/` + `docs/` before commit; fix any dangling references in P2 |
| STATE.md capability row is inaccurate (wrong shipped tag / wrong file path) | Medium | Low | The backfill sources are the authoritative registries (regression_verify.py, registry.json, CHECKPOINT.json, git log); citations are direct |
| PROJECT.md phase-status fix conflicts with a future v1.26-era commit | Low | Low | v1.26 is shipped (main has the milestone merge); no v1.26-era commits will arrive |
| REGRESSION_REPORT stale state is mistaken for v1.27 scope | Low | Low | D-224 records the decision; STATE.md Domain 7 notes the current CAP range |
---
## 6. Verdict
v1.27 is feasible, scoped, and the sources are grounded. No new domain,
no new code, no schema breaks. The archive moves are lossless (git
history + archive directory both preserve bytes). The STATE.md
backfill is sourced from authoritative registries. Proceed to PLAN.
All 11 research questions answered with cited findings + concrete
recommendations + risks. D-228 amended (fail-closed, not pure-Python
fallback). The `kj` binary packaging is the highest-risk item (P2
spike). Next: PLAN.
+23 -6
View File
@@ -81,6 +81,19 @@
before building the new env). New `core/env_transition.py` module.
15 requirements (REQ-276..290), 4 phases.
- **v1.27:** complete (tag `v1.26.3`) — PO State Catalog & Ciagent
Compression. NFR milestone. Authored `.ciagent/STATE.md` (PO-facing
capability catalog, 32 CAP rows + 11 invariants across 10 domains,
backfilled through v1.26). Archived 7 platform-root files + 1
consumer file to `.ciagent/archive/` (CAPABILITY_INVENTORY,
REVIEW-AUDIT-P05, VERIFY-P03, VERIFY-P04, P4-PILOT-RUN-EVIDENCE,
AUTONOMY_THESIS, COST + nova-blockchain-exchange/ROADMAP). Fixed
PROJECT.md + ROADMAP.md v1.26 phase-status (P3/P4/P5 → complete).
Wired STATE.md into the P-final ship discipline (PLAN.md, ROADMAP.md,
NORTH_STAR.md). Active `.ciagent/` root: 15 .md (was 25) + 1 json + 1
checkpoint. 3 phases (P0 pre-execution + P1 author-archive + P2
fix-stale-wire + P3 final-review-ship). No REQ-NNN (NFR).
> **Full v1.0v1.24 phase detail, wave ordering, success criteria, and
> decision cross-references:** `.ciagent/archive/ROADMAP-v1.0-v1.24.md`.
@@ -173,12 +186,15 @@ final). Tags: `v1.24.0` (P0) → `v1.24.5` (P5 = milestone release).
summary; delete all milestone branches.
- Updated `REQUIREMENTS.md` (mark REQ-291..309 complete), `ROADMAP.md`
(mark v1.25 complete), `NORTH_STAR.md` (note Strategic Objective #2
provable trust via a replaceable policy-engine substrate).
provable trust via a replaceable policy-engine substrate),
`STATE.md` (append v1.25 capability rows — note: STATE.md was authored
in v1.27 with the v1.25 capabilities backfilled; the v1.25 ship did
not update STATE.md because STATE.md did not yet exist).
- **Requirements:** REQ-291..309 (19 requirements).
---
## v1.26 (active, tag line `v1.25.x`): Live Pilot Estate Activation
## v1.26 (complete, tag `v1.25.5` = the v1.26 release, merged to main 2026-08-19): Live Pilot Estate Activation
`D-096` lifts. The first real consumer estate — a stock exchange on a
homegrown Proof-of-Authority blockchain (equities only, single
@@ -235,7 +251,7 @@ REQ-315..322), 3 deferred. Adversarial grill: PROCEED 0.84.
- Cross-cutting: `v1.25` floating tag → `v1.25.0` (Phase 0 ship) on the
platform repo.
### Phase P3 — pilot-metrics-and-policies (planned, tag v1.25.3)
### Phase P3 — pilot-metrics-and-policies (complete, tag v1.25.3)
- REQ-315: `adapters/kyverno-json/policies/settlement-finality.json`
kyverno-json policy asserting all matches in the promotion window have
committed blocks (securities-specific). Authored + tested in v1.26;
@@ -258,7 +274,7 @@ REQ-315..322), 3 deferred. Adversarial grill: PROCEED 0.84.
- REQ-320: `adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json`
— declarative gate preventing apply against a placeholder account.
### Phase P4 — pilot-run-and-docs (planned, tag v1.25.4)
### Phase P4 — pilot-run-and-docs (complete, tag v1.25.4)
- REQ-321: `adapters/README.md` (new consumer row) +
`docs/METRICS.md` (Post-Pilot metrics grounded note) +
`.ciagent/ARCHITECTURE.md` §12.8 (Pilot Estate) +
@@ -269,7 +285,7 @@ REQ-315..322), 3 deferred. Adversarial grill: PROCEED 0.84.
events land in the Decision Ledger; the regression gate (CAP-025)
verifies the round-trip.
### Phase P5 — final review + audit + milestone ship (Final Phase, planned, tag v1.25.5)
### Phase P5 — final review + audit + milestone ship (Final Phase, complete, tag v1.25.5 = the v1.26 release)
- Multi-persona code review across P1..P4 (lead-developer, backend-
engineer, data-engineer, policy-engineer, blockchain-engineer).
Auto-fix P0; flag P1+.
@@ -281,7 +297,8 @@ REQ-315..322), 3 deferred. Adversarial grill: PROCEED 0.84.
full milestone summary; delete all milestone branches.
- Update `REQUIREMENTS.md` (mark REQ-310..322 complete), `ROADMAP.md`
(mark v1.26 complete), `NORTH_STAR.md` (note Strategic Objectives #1
+ #3 — first real consumer estate; Post-Pilot denominators activated).
+ #3 — first real consumer estate; Post-Pilot denominators activated),
`STATE.md` (append v1.26 capability rows; bump "Last milestone ship").
> **Phase task-level breakdown, wave ordering, and persona
> assignments:** `.ciagent/PLAN.md` (the active phase plan, retained in
+4 -2
View File
@@ -11,8 +11,10 @@
> *why*, read `NORTH_STAR.md`. For *how*, read `ARCHITECTURE.md`. For
> *what was decided*, read `PROJECT.md` load-bearing decisions.
>
> **Last milestone ship:** v1.26 (`v1.25.5`, 2026-08-19).
> **Next update:** at v1.27 ship.
> **Last milestone ship:** v1.27 (`v1.26.3`, 2026-08-19) — PO State Catalog
> & Ciagent Compression NFR milestone. No new capabilities this
> milestone (NFR); v1.27 authored this file + compressed `.ciagent/`.
> **Next update:** at v1.28 ship.
## How to use this file (PO)
+55 -6
View File
@@ -8,12 +8,20 @@ state for offline agent loading.
## Why archive
The active milestone is v1.26 (Live Pilot Estate Activation). The
`.ciagent/` root held ~11,164 lines dominated by completed-milestone
narratives (v1.0v1.24). Per the run.md context-loading model, agents
read `.ciagent/` every `/ci-run`; the historical narrative was not
load-bearing for v1.26 execution and was relocated to keep the working
context lean.
The active milestone is v1.27 (PO State Catalog & Ciagent Compression).
The `.ciagent/` root was compressed twice:
1. **v1.26 P2 compression** (~11,164 lines → ~5,232): the
completed-milestone narratives (v1.0v1.24) were relocated. Per the
run.md context-loading model, agents read `.ciagent/` every
`/ci-run`; the historical narrative was not load-bearing for v1.26
execution and was relocated to keep the working context lean.
2. **v1.27 P1 compression** (~5,232 → ~3,882): the v1.26 phase
verifications + review + evidence + the dated CAPABILITY_INVENTORY
(superseded by STATE.md) + AUTONOMY_THESIS (folded into NORTH_STAR)
+ COST (predates v1.26 pilot) were relocated. The 4 pre-execution
files (CLARIFY/GRILL/IDEATE/RESEARCH) were rewritten by v1.27 P0
and stay active through v1.27.
## Contents
@@ -40,6 +48,47 @@ architecture reference.
| `VERIFY.md` | 86 | Per-phase verification records |
| `PRE_MORTEM.md` | 228 | Pre-mortem analyses for completed milestones |
### v1.27 compression — archived files (8 files, lossless `git mv`)
> The v1.27 NFR milestone (PO State Catalog & Ciagent Compression) archived
> 7 platform-root files + 1 consumer file. All are byte-identical
> relocations; git history at the pre-v1.27 commits preserves the
> authoritative state.
#### Snapshots of superseded durable references (3 files)
| File | Original (lines) | Superseded by | Status at time of snapshot |
|---|---|---|---|
| `CAPABILITY_INVENTORY-v1.10.md` | 120 | `.ciagent/STATE.md` (v1.27) | The 2026-07-27 re-verification sweep (v1.1→v1.8 capabilities). Predates v1.26 pilot (CAP-025 absent; blockchain capabilities absent). |
| `AUTONOMY_THESIS-v1.21.md` | 65 | `NORTH_STAR.md` Vision + Anti-Goals #2 | "Last refined: v1.21" — the autonomy-in-operations thesis, fully folded into NORTH_STAR.md. |
| `COST-v1.14.md` | 106 | (future cost milestone) | AWS cost report dated 2026-07-29, framed "v1.0 → v1.14". Predates v1.26 live pilot (ECS + ALB + DynamoDB + S3 costs not reflected). |
#### v1.26 phase verifications + review + evidence (4 files)
| File | Original (lines) | Phase(s) documented |
|---|---|---|
| `VERIFY-P03.md` | 39 | v1.26 P3 verification — PASS (shipped `v1.25.3`) |
| `VERIFY-P04.md` | 31 | v1.26 P4 verification — PASS (shipped `v1.25.4`) |
| `REVIEW-AUDIT-P05.md` | 218 | v1.26 P5 final review + audit — PROCEED (shipped `v1.25.5`; 0 P0 remain; audit CLEAN) |
| `P4-PILOT-RUN-EVIDENCE-v1.26.md` | 46 | v1.26 live apply evidence (`blkex-pilot-apply-v0.2`; confidence 0.800 pass; outcome backfilled; hash chain valid) |
#### Consumer subproject archive (1 file)
| File | Original (lines) | Phase(s) documented |
|---|---|---|
| `nova-blockchain-exchange/archive/ROADMAP-v1.26.md` | 57 | v1.26 consumer roadmap (P3/P4/P5 marked "planned" at archive time; v1.26 shipped `v1.25.5`). Phase narrative preserved in the platform `.ciagent/ROADMAP.md` §v1.26. |
#### v1.26 pre-execution artifacts (in git history, not archived to disk)
The v1.26 pre-execution files (CLARIFY, GRILL, IDEATE, RESEARCH) were
overwritten by the v1.27 P0 pre-execution cycle. The v1.26-era content
is preserved in git history at the pre-v1.27-P0 commits (search the
log for `docs(P00):` commits on the `milestone/v1.26-pilot-activation`
line). The v1.27 P0 versions stay active through v1.27; they archive at
v1.28 P1 if v1.28 happens. Decisions D-200..D-213 (v1.26) are folded
into `PROJECT.md` load-bearing decisions; D-214..D-225 (v1.27) live in
the active `CLARIFY.md`.
### Live operational files NOT archived
These files remain at their canonical `.ciagent/` paths because they are
+1 -1
View File
@@ -13,7 +13,7 @@
],
"active_project": "acdl",
"active_projects": ["acdl", "nova-blockchain-exchange"],
"active_milestone": "v1.27",
"active_milestone": "v1.28",
"autonomy": {
"level": "full",
"escalation_hooks": ["deploy", "delete_data", "merge_to_main"],
+6 -1
View File
@@ -89,4 +89,9 @@ of normal operations.
- The AWS bootstrap (S3 state bucket + DynamoDB outbox) was re-run in
the pre-run (Workstream A3) — the platform components exist.
- The consumer repo was created on Gitea (Workstream A4) and cloned to
`/root/nova-blockchain-exchange`.
`/root/nova-blockchain-exchange`.
- **Phase-by-phase history:** `.ciagent/ROADMAP.md` §v1.26 (the
consumer ROADMAP is archived at
`.ciagent/nova-blockchain-exchange/archive/ROADMAP-v1.26.md` since
v1.27 — the platform ROADMAP is the source of truth for milestone
phase narrative).
+5 -5
View File
@@ -5,7 +5,7 @@
> secrets to set, what the contract looks like, and how to verify the
> result. The platform side is documented in
> `.ciagent/ARCHITECTURE.md` §12.8; the live-pilot evidence is in
> `.ciagent/P4-PILOT-RUN-EVIDENCE.md`.
> `.ciagent/archive/P4-PILOT-RUN-EVIDENCE-v1.26.md` (archived v1.27).
This is a **consumer** of the Nova platform, not a fork. The consumer
repo owns the app code (the blockchain, the order-matching engine, the
@@ -161,8 +161,8 @@ Ledger. Neither trusts the other.
If the AWS API shows the resources AND the Decision Ledger shows the
decision + outcome with a valid chain, the deploy is verified. See
`.ciagent/P4-PILOT-RUN-EVIDENCE.md` for the full pilot-evidence
checklist (every ARN, the confidence JSON, the backfill timestamp).
`.ciagent/archive/P4-PILOT-RUN-EVIDENCE-v1.26.md` for the full pilot-evidence
checklist (every ARN, the confidence JSON, the backfill timestamp; archived v1.27).
---
@@ -170,8 +170,8 @@ checklist (every ARN, the confidence JSON, the backfill timestamp).
- `.ciagent/ARCHITECTURE.md` §12.8 — the pilot-estate architecture
(this guide is the consumer-facing companion to that section).
- `.ciagent/P4-PILOT-RUN-EVIDENCE.md` — the live-pilot evidence
(run `blkex-pilot-apply-v0.2`).
- `.ciagent/archive/P4-PILOT-RUN-EVIDENCE-v1.26.md` — the live-pilot evidence
(run `blkex-pilot-apply-v0.2`; archived v1.27).
- `.ciagent/nova-blockchain-exchange/PROJECT.md` — the consumer
project charter (vision, scope, decisions D-200..D-205).
- `.ciagent/nova-blockchain-exchange/REQUIREMENTS.md` — the consumer