Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 88e2389a95 | |||
| a0c363c063 | |||
| bbfcbcc4d3 | |||
| e1dc59ba79 | |||
| c629809d75 | |||
| 05efb014d6 | |||
| 9ee1cc8925 | |||
| 48a769ced0 | |||
| 45423c33ae | |||
| 1faf4b560f | |||
| 8f62cfdbe7 | |||
| f28aed2f55 | |||
| 6b410d9ab4 | |||
| d019a1c4c4 |
@@ -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
@@ -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
@@ -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.1–v1.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
@@ -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 17–22: "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.
|
||||
@@ -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`
|
||||
|
||||
@@ -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
@@ -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
@@ -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 2 — archive 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 0 — CodeArtifact 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 3 — archive 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 4 — CodeArtifact + 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 424–431 —
|
||||
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 2 — fix 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 1 — dual-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 3 — wire 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 2 — local 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 4 — fix 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 3 — attestations 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 1 — review
|
||||
- **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 3 — auth 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 2 — audit
|
||||
- **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 4 — CAP-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 (J1–J4) 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
@@ -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
@@ -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
@@ -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 17–22) + 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 424–431): 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 129–768) | 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
@@ -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.0–v1.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
@@ -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)
|
||||
|
||||
|
||||
@@ -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.0–v1.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.0–v1.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
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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,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
|
||||
|
||||
Reference in New Issue
Block a user