6dfde4b785
acdl-ci / Lint (push) Successful in 11s
acdl-ci / Test (push) Failing after 23s
acdl-ci / Platform check-only (offline) (push) Successful in 20s
nova-release / Compute semver + update tags (push) Successful in 41s
acdl-ci / forge_parity_disabled (push) Failing after 14m45s
---ci--- project: acdl phase: 4 milestone: v1.30 status: complete requirements: covered: [REQ-372.1,REQ-372.2,REQ-372.3,REQ-372.4,REQ-372.5,REQ-372.6,REQ-372.7,REQ-372.8,REQ-372.9,REQ-372.10,REQ-372.11,REQ-372.12] partial: [] ---/ci---
554 lines
52 KiB
Markdown
554 lines
52 KiB
Markdown
# Nova — System State (what exists today)
|
||
|
||
> **PO-owned catalog of shipped capabilities.** Updated at every milestone
|
||
> ship (P final). Additive only — entries are appended, never rewritten,
|
||
> unless a capability is explicitly deprecated (then marked, not deleted).
|
||
> Read by the PO upstream of the PDLC before authoring new REQ-NNN specs,
|
||
> and by CIAgent at SPECIFY for capability awareness.
|
||
>
|
||
> **Authority:** this file is *descriptive of shipped state*, not
|
||
> authoritative for live phase/ship state — that's `CHECKPOINT.json`. For
|
||
> *why*, read `NORTH_STAR.md`. For *how*, read `ARCHITECTURE.md`. For
|
||
> *what was decided*, read `PROJECT.md` load-bearing decisions.
|
||
>
|
||
> **Last milestone ship:** v1.29 (`v1.28.6`, 2026-08-20) — Reposplit +
|
||
> Identity Layer Bring-Live. Feature milestone: platform operations
|
||
> extracted to a Gitea-private Terraform repo (`nova-platform-ops`,
|
||
> OPER-PRIV); `acdl/acdl` standardized on GitHub (D-232, `.gitea/`
|
||
> removed, `forge_parity_disabled` CI assertion); Nova-idp brought
|
||
> live in `581513795199` via Terraform (CFN archived to
|
||
> `docs/archive/nova-idp-cfn-v1.28.md`, REQ-369, `nova idp setup
|
||
> --apply` delegates to `terraform apply`); `kj` substrate has one ECR
|
||
> image digest shared by the Lambda runtime + its Fargate fallback
|
||
> (KJ-LOCKSTEP, REQ-371, D-238, `lifecycle.precondition` on both
|
||
> image-bearing resources); JWKS edge-only via CloudFront + OAC
|
||
> (INV-18, D-233); `publish.yml` tag-triggered with ECR image build
|
||
> (static `kj`, `CGO_ENABLED=0`, KJ-STATIC `file(1)` gate, REQ-354);
|
||
> operator guide `docs/operator-guide-platform-ops.md` (747 lines, 18
|
||
> sections + Cutover Gates table); consumer `nova-blockchain-exchange`
|
||
> deploy.yml bumped `@v1.25` → `@v1.29`. 6 acdl-side REQs complete + 14
|
||
> covered-reference REQs (355-366, 371, verified via M1/M1.5/M2 cutover
|
||
> gates, operator-attested). 3 new capabilities (CAP-039..041), 1 new
|
||
> invariant (INV-18), 10 NFR constraints (KJ-STATIC, KJ-LOCKSTEP,
|
||
> KJ-WARMUP-HEALTH, OPER-PRIV, IAM-NARROW, DRIFT-DETECT,
|
||
> IMPORT-IDEMPOTENT, TFM-HITL, JWKS-SLO, JWKS-ROTATION), 9 decisions
|
||
> (D-232..D-240). Grill PROCEED 0.72 (4 critical fixes). Review
|
||
> PASS-WITH-ISSUES (3 P0 fixes). Audit all PASS. Merged to main
|
||
> `9dc5669`, pushed + 8 Gitea releases created (ids 803-810).
|
||
> **Next update:** at v1.30 ship.
|
||
|
||
## How to use this file (PO)
|
||
|
||
- Before writing a new REQ: search this file for the capability you
|
||
intend to spec. If it exists, extend it; do not re-spec it under a new
|
||
REQ-NNN.
|
||
- Respect the **Invariants** below — they are load-bearing and
|
||
cross-cutting. A new REQ that violates an invariant requires a
|
||
`CLARIFY` decision recorded in PROJECT.md.
|
||
- Anchor each new REQ to a **Domain**; new domains require a PO
|
||
decision recorded in CLARIFY.
|
||
- When a capability is deprecated (replaced, removed, or
|
||
re-architecture), append a `Deprecated` row marking the milestone +
|
||
replacement; do not delete the original entry.
|
||
|
||
## Invariants (PO-owned — do not violate in new REQs)
|
||
|
||
> Distilled from `PROJECT.md` load-bearing decisions D-034..D-072 +
|
||
> W1..BA + Q1.3. Cite the decision ID when an REQ touches one.
|
||
|
||
- **INV-1 (Contract surface):** The only PDLC→Nova boundary is
|
||
`schemas/contract.schema.json` + `schemas/submission-readiness.schema.json`
|
||
(D-133). All consumer intent enters through one of these. Nova never
|
||
reaches into upstream PDLC.
|
||
- **INV-2 (Confidence inputs):** Six canonical inputs — policy (0.30),
|
||
validation (0.25), freshness (0.10), source (0.15), history (0.10),
|
||
nfrs (0.10). Weights frozen for v1 (D-040). `critical` severity =
|
||
hard-block via `PENALTY["critical"]: None` (defense-in-depth behind the
|
||
declarative `block-on-any-critical` meta-policy).
|
||
- **INV-3 (HITL gates):** dev = autonomous (≥0.50); qa = HITL (≥0.75);
|
||
prod = HITL (≥0.90); dr = HITL (≥0.95). Approver identity = Gitea
|
||
`gitea.actor` of the `workflow_dispatch` (D-042). Separation-of-duties
|
||
on prod reads `approver_qa` from the DynamoDB outbox.
|
||
- **INV-4 (Engine is swappable):** The policy engine is behind the
|
||
`PolicyEngine` protocol (`core/policy_engine.py`, v1.25). Confidence
|
||
signal + pipeline import only the protocol, never a concrete engine.
|
||
`kyverno-json` is the v1.25 default; `OPA` (or other) implements the
|
||
same 3-method protocol to replace it.
|
||
- **INV-5 (Adapter is stateless):** `adapters/terraform/adapter.py` owns
|
||
no module content — no `TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP` (v1.11
|
||
rewrite). A new stack type requires a new L1 module
|
||
(`modules/l1/<name>/`) + `registry.json` entry, not an adapter change.
|
||
- **INV-6 (Audit stream is immutable):** Outbox writes via SQLite
|
||
hash-chain today (D-083 deferred). S3 Object Lock / JWS tamper-
|
||
*resistant* ledger is a future milestone. Current stream is tamper-
|
||
*evident* (any tampering breaks the chain).
|
||
- **INV-7 (PCR schema is the moat):** `schemas/policy_check_result.schema.json`
|
||
shape is frozen across adapter swaps (v1.25 hard constraint). The
|
||
`engine` enum already includes `"kyverno"` + `"opa"`; new engines add
|
||
no enum value.
|
||
- **INV-8 (Long-lived creds forbidden):** §12.5. The D-039/D-047 per-run-
|
||
rotated-key waiver satisfies the *intent* (no *persistently* long-lived
|
||
key). Real OIDC federation is blocked on `go-gitea/gitea#36988`.
|
||
- **INV-9 (Two consumer surfaces, one platform):** L3A (developer) +
|
||
L3B (citizen dev) converge on the same contract schema, the same
|
||
policy envelope, and the same evidence stream.
|
||
- **INV-10 (Nova is downstream of PDLC):** Nova governs infra + delivery
|
||
only. Product backlog, code authorship, IDE workflows, application
|
||
business logic are upstream. Integration only via the validated
|
||
contract boundary (INV-1).
|
||
- **INV-11 (Pilot scope, v1.26):** Equities only (D-200). Single-
|
||
validator PoA (D-201). D-083 (Object Lock/JWS) stays deferred. Hot
|
||
path deferred (D-126). Multi-cloud deferred. Multi-validator BFT
|
||
deferred. The pilot runs `mode: full` for `dev` only (D-209); qa/prod/dr
|
||
stay placeholder (D-208, blocked by the pilot-readiness policy).
|
||
- **INV-12 (Mode observability, v1.28):** Every CLI invocation emits a
|
||
`cli.invocation` audit event containing `mode`, `selection_reason`,
|
||
`credential_type`, `command`, and `args`. Operators can debug mode
|
||
selection without reproducing.
|
||
- **INV-13 (Mode resolution determinism, v1.28):** Resolution priority
|
||
is flag → env (`NOVA_CLIENT_MODE`) → credential type →
|
||
`sys.stdin.isatty()`. No silent fallbacks. Invalid env values are
|
||
ignored + warned. Deviations rejected at PR time.
|
||
- **INV-14 (Credential type encodes role, v1.28):** `developer_pat` /
|
||
`nova_oidc_token` + TTY present → `interactive`; TTY absent → `agent`.
|
||
- **INV-15 (No AWS-managed identity in path, v1.28):** Nova-idp MUST
|
||
NOT depend on Cognito, IAM Identity Center, or any AWS-managed
|
||
identity service. Greenfield constraint (no Cognito existed to
|
||
"drop").
|
||
- **INV-16 (Password storage, v1.28):** Passwords hashed with Argon2id
|
||
(t=3, m=65536 KiB, p=1). Fail-closed on `ImportError` (D-228 amended
|
||
— no pure-Python fallback). Raw passwords never in logs/traces/env/
|
||
DynamoDB.
|
||
- **INV-17 (ABAC discipline, v1.28):** The token-vend Lambda evaluates
|
||
the kyverno-json ABAC policy before signing. Fail-closed on `kj`
|
||
absence or evaluation error (C-6.1 — never fail open). Allow/deny +
|
||
policy inputs emitted to the audit stream. `policy_version` (git SHA,
|
||
D-231) recorded in every event.
|
||
- **INV-18 (JWKS-EDGE-ONLY, v1.29):** the JWKS endpoint is the only
|
||
public read surface of the live platform. All other platform
|
||
endpoints MUST gate with `AuthType: AWS_IAM` (D-233). CloudFront +
|
||
OAC pinning replaces direct Lambda Function URL exposure. Direct
|
||
Function URL → 403; via-CloudFront → 200.
|
||
|
||
> **v1.29 NFR constraints (10 — load-bearing, not full invariants):**
|
||
> KJ-STATIC (`kj` compiled `CGO_ENABLED=0`, `file(1)` reports
|
||
> `statically linked`, SHA-256 in Terraform state); KJ-LOCKSTEP
|
||
> (Fargate standby digest == Lambda `image_uri` digest at every
|
||
> `terraform plan`, enforced by `lifecycle.precondition` + CI + PR
|
||
> comment + operator review, D-238); KJ-WARMUP-HEALTH (Fargate
|
||
> `GET /health → 200` every 10s, READY before M1 cutover);
|
||
> OPER-PRIV (`nova-platform-ops` `private: true`, not mirrored,
|
||
> REQ-359); IAM-NARROW (Gitea OIDC role bounded, no `Action: "*"` or
|
||
> `Resource: "*"`, REQ-360); DRIFT-DETECT (`terraform plan` exit 2
|
||
> fails the apply workflow, REQ-356); IMPORT-IDEMPOTENT (re-import
|
||
> exits `resource_already_imported`, REQ-361); TFM-HITL (`terraform
|
||
> apply` against `main` requires Gitea Actions approval from a user
|
||
> distinct from the PR author, REQ-357, INV-3); JWKS-SLO
|
||
> (`GET /.well-known/jwks.json` P95 < 200ms same-region,
|
||
> `Cache-Control: max-age=3600`); JWKS-ROTATION (on key rotation,
|
||
> both old + new public keys published during 24-hour overlap
|
||
> window).
|
||
|
||
## Domains (capability groups)
|
||
|
||
1. Contract surface
|
||
2. Modules (L1 primitives + L2 patterns)
|
||
3. Policy engine
|
||
4. Confidence signal
|
||
5. Environments & promotion
|
||
6. Evidence stream & audit
|
||
7. Telemetry & metrics
|
||
8. Consumer surfaces (developer + agentic)
|
||
9. Pilot estate (v1.26)
|
||
10. Forge / CI runtime
|
||
11. CLI + Identity Layer (v1.28)
|
||
12. Platform Ops Reposplit (v1.29)
|
||
|
||
## Capabilities (additive — one row per shipped capability)
|
||
|
||
> Tier: **local** = runs via emulating adapters (no AWS); **live-aws** =
|
||
> runs against the live AWS account `581513795199`;
|
||
> **lifecycle-pipeline** = verified via the `modules-lifecycle`
|
||
> pipeline's apply→modify→destroy matrix cell.
|
||
> CAP-NNN IDs cross-reference the regression gate at
|
||
> `core/regression_verify.py` (the machine registry). This file is the
|
||
> PO-facing narrative; the machine registry is the source of truth for
|
||
> the gate.
|
||
|
||
### Domain 1 — Contract surface
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| CAP-001 | `contract.schema.json` validates sample contracts | v1.1 / `v1.2.0` | `schemas/contract.schema.json` | REQ-001, D-... | local | shape: id/name/environment/infrastructure |
|
||
| CAP-002 | `environment.schema.json` validates env files | v1.9 / `v1.9.0` | `schemas/environment.schema.json` | REQ-040 | local | dev/qa/prod/dr env JSONs |
|
||
| CAP-006 | Contract interpolation expands `${env.*}` / `${contract.*}` | v1.9 / `v1.9.0` | `core/contract_resolver.py` | REQ-040 | local | per-env variants |
|
||
| — | Submission-readiness gate (superset of contract schema) | v1.18 / `v1.18.0` | `schemas/submission-readiness.schema.json`, `core/submission_readiness.py` | REQ-217, REQ-218, D-133 | local | the only PDLC→Nova boundary (INV-1) |
|
||
|
||
### Domain 2 — Modules (L1 primitives + L2 patterns)
|
||
|
||
> Source: `modules/registry.json` (the authoritative module catalog).
|
||
> STATE.md lists the *capability* of having a registered module;
|
||
> registry.json is the live registry.
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| CAP-003 | contract_resolver resolves `static-assets` (L2) | v1.1 / `v1.2.0` | `core/contract_resolver.py`, `modules/l2/static-assets/` | REQ-003 | local | CloudFront+WAF+S3 pattern |
|
||
| CAP-004 | contract_resolver resolves `microservice` (L2) | v1.2 / `v1.3.0` | `core/contract_resolver.py`, `modules/l2/microservice/` | REQ-004 | local | ECS Fargate pattern (6 L1 children) |
|
||
| CAP-005 | Terraform adapter compiles resolved stack to `.tf` | v1.1 / `v1.2.0` | `adapters/terraform/adapter.py` | REQ-005 | local | stateless assembler (v1.11); emits `module "<rid>" { source }` blocks |
|
||
| — | L1 `s3` primitive | v1.1 / `v1.2.0` | `modules/l1/s3/` | REQ-005 | lifecycle | versioning + SSE-KMS by default |
|
||
| — | L1 `vpc` primitive | v1.1 / `v1.2.0` | `modules/l1/vpc/` | REQ-005 | lifecycle | shared platform VPC (v1.11) |
|
||
| — | L1 `ecs-cluster` primitive | v1.1 / `v1.2.0` | `modules/l1/ecs-cluster/` | REQ-005 | lifecycle | |
|
||
| — | L1 `ecs-service` primitive | v1.1 / `v1.2.0` | `modules/l1/ecs-service/` | REQ-005 | lifecycle | execution_role_arn + task_role_arn wired (P4 W1 fix, v1.26) |
|
||
| — | L1 `iam-role` primitive | v1.1 / `v1.2.0` | `modules/l1/iam-role/` | REQ-005 | lifecycle | |
|
||
| — | L1 `alb` primitive | v1.1 / `v1.2.0` | `modules/l1/alb/` | REQ-005 | lifecycle | requires SG wire (P4 W1 fix, v1.26) |
|
||
| — | L1 `ecr` primitive | v1.1 / `v1.2.0` | `modules/l1/ecr/` | REQ-005 | lifecycle | |
|
||
| — | L1 `cloudfront` primitive | v1.7 / `v1.7.0` | `modules/l1/cloudfront/` | REQ-049, D-049 | lifecycle | OAC + WAF (production edge) |
|
||
| — | L1 `waf` primitive | v1.7 / `v1.7.0` | `modules/l1/waf/` | REQ-049, D-049 | lifecycle | |
|
||
| — | L1 `rds` primitive | v1.7 / `v1.7.0` | `modules/l1/rds/` | REQ-059, D-059 | lifecycle | multi-engine input (postgres/mysql/...) |
|
||
| — | L1 `kms-key` primitive | v1.8 / `v1.8.0` | `modules/l1/kms-key/` | REQ-069, D-069 | lifecycle | per-stack CMK; 90-day rotation |
|
||
| — | L1 `uptime` primitive | v1.8 / `v1.8.0` | `modules/l1/uptime/` | REQ-066, D-066 | lifecycle | uptime-kuma on ECS Fargate |
|
||
| — | L1 `dynamodb` primitive | v1.26 / `v1.25.2` | `modules/l1/dynamodb/` | REQ-322 | local | PK + optional SK; PAY_PER_REQUEST; encryption + PITR by default (v1.8 NFRs) |
|
||
| CAP-013 | `terraform init+validate+plan` live AWS (microservice) | v1.2 / `v1.3.0` | `adapters/terraform/adapter.py` | REQ-013 | live-aws | 14 resources; plan saved |
|
||
| CAP-014 | `terraform init+validate+plan` live AWS (static-assets) | v1.7 / `v1.7.0` | `adapters/terraform/adapter.py` | REQ-014 | live-aws | CloudFront+WAF+S3 plan OK |
|
||
| CAP-017 | DynamoDB `nova-contracts` table | v1.7 / `v1.7.0` | `core/lambda/`, `terraform/` | REQ-068, D-068 | lifecycle | PK `changeRequestId`, SK `submittedAt` (CMDB) |
|
||
| CAP-018 | Lambda contract-ingestor | v1.7 / `v1.7.0` | `core/lambda/contract_ingestor.py` | REQ-051, D-051 | lifecycle | local stub + lifecycle evidence |
|
||
| CAP-019 | ECS cluster + service (L2 microservice) | v1.7 / `v1.7.0` | `modules/l2/microservice/` | REQ-066 | lifecycle | apply/modify/destroy exit 0 |
|
||
| CAP-020 | CloudFront + WAF production stack | v1.7 / `v1.7.0` | `modules/l2/static-assets/` | REQ-049 | lifecycle | apply/modify/destroy exit 0 |
|
||
| CAP-021 | uptime-kuma monitoring primitive | v1.8 / `v1.8.0` | `modules/l1/uptime/` | REQ-066 | lifecycle | |
|
||
| CAP-022 | OIDC role for act_runner | v1.11 / `v1.11.0` | `terraform/bootstrap/` | REQ-116, D-039 | lifecycle | real OIDC blocked on go-gitea/gitea#36988 |
|
||
|
||
### Domain 3 — Policy engine
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| — | `PolicyEngine` Protocol + `PolicyEngineRegistry` | v1.25 / `v1.24.1` | `core/policy_engine.py` | REQ-291, REQ-292 | local | selects engine from `config.json.policy.engine`; `NullEngine` fallback when key absent |
|
||
| — | `KyvernoJsonEngine` adapter (shells to `kj scan`) | v1.25 / `v1.24.1` | `adapters/kyverno-json/kyverno_json_engine.py` | REQ-293, REQ-294 | local | `is_configured()` guards on `which kj`; `SKIPPED` PCR when absent |
|
||
| — | Contract policies (4) over consumer contract JSON | v1.25 / `v1.24.2` | `adapters/kyverno-json/policies/contract/` | REQ-295, REQ-296 | local | id-pattern, env-enum, infra-min-1, forbid-unknown-fields |
|
||
| — | Stack-IR policies (3) over resolved Target Stack IR | v1.25 / `v1.24.2` | `adapters/kyverno-json/policies/stack-ir/` | REQ-297, REQ-298, REQ-299 | local | tagging-standard, public-ingress, encryption-by-default |
|
||
| — | Plan-JSON policies (3) over `terraform show -json` | v1.25 / `v1.24.3` | `adapters/kyverno-json/policies/plan-json/` | REQ-300, REQ-301, REQ-302 | local | plaintext-secrets, iam-wildcard, kms-reference |
|
||
| — | Meta-policies over merged PCR list | v1.25 / `v1.24.3` | `adapters/kyverno-json/policies/meta/` | REQ-303 | local | `block-on-any-critical` (declarative critical-block); `tagging-rules-agree` (Checkov↔kj agree) |
|
||
| — | Regression-gate policies (3) over capability-inventory JSON | v1.25 / `v1.24.4` | `adapters/kyverno-json/policies/regression/` | REQ-304, REQ-305 | local | declarative mirrors of CAP-013/023/024 imperative checks |
|
||
| — | Pilot-readiness policy (no placeholder account) | v1.26 / `v1.25.3` | `adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json` | REQ-320 | local | fail-closed gate; blocks apply on `account_id == "000000000000"` |
|
||
| — | Settlement-finality policy | v1.26 / `v1.25.3` | `adapters/kyverno-json/policies/settlement-finality/all-matches-committed.json` | REQ-315 | local | authored + tested; enforcement deferred to milestone that binds qa/prod/dr (D-208) |
|
||
| — | Checkov adapter (raw-finding source) | v1.7 / `v1.7.0` | `adapters/terraform/checkov_adapter.py` | REQ-053 | local | feeds meta-policies; `NOVA_TAG_NAMING` custom rule is the TF-static source of truth |
|
||
| — | Wiz adapter (raw-finding source) | v1.7 / `v1.7.0` | `adapters/wiz/` | REQ-053 | local | API findings; `is_configured()` guard |
|
||
| — | K8s Kyverno adapter (documentation-only) | v1.7 / `v1.7.0` | `adapters/kyverno/` | REQ-053, D-053 | local | inactive for Terraform-only stacks; activates when GitOps emits K8s manifests |
|
||
|
||
### Domain 4 — Confidence signal
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| CAP-007 | `confidence_signal.compute` returns a band | v1.1 / `v1.2.0` | `core/confidence_signal.py` | REQ-007, D-040 | local | 6 inputs (INV-2); band ∈ {pass, block} |
|
||
| — | `escalation_reason: 'confidence'` on `band == 'block'` | v1.26 / `v1.25.3` | `core/confidence_signal.py` | REQ-318 | local | grounds Human Escalation Frequency numerator |
|
||
|
||
### Domain 5 — Environments & promotion
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| — | env-JSON `state_backend` wiring | v1.26 / `v1.25.3` | `core/environments/*.json`, `adapters/terraform/adapter.py` | REQ-319, D-... | local | adapter reads `env.state_backend.bucket` (fallback to computed name) |
|
||
| — | Environment progression (dev autonomous → qa/prod/dr HITL) | v1.1 / `v1.2.0` | `core/env_transition.py`, `core/hitl_gates.py` | REQ-042, D-042 | local | destroy-on-environment-change (v1.24) |
|
||
| — | Decommission mode (2-step, HITL SRE gates) | v1.8 / `v1.8.0` | `core/env_transition.py`, `scripts/run_platform.sh` | REQ-070, D-070 | local | `mode: decommission` requires `changeRequestId` |
|
||
| — | Per-env mandatory metadata (W3.E) | v1.1 / `v1.2.0` | `schemas/submission-readiness.schema.json` | W3.E | local | dev=stack+env; qa+=e2e+load; prod+=runbook+dashboard+oncall; dr+=drDrillRef |
|
||
|
||
### Domain 6 — Evidence stream & audit
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| CAP-008 | outbox_writer builds a hash-chained item | v1.1 / `v1.2.0` | `core/outbox_writer.py` | REQ-008 | local | tamper-evident (INV-6); tamper-resistant deferred (D-083) |
|
||
| CAP-015 | DynamoDB outbox table exists + describable | v1.1 / `v1.2.0` | `core/outbox_writer.py` | REQ-015 | live-aws | `nova-outbox` (post-v1.26 re-bootstrap) |
|
||
| CAP-016 | S3 state bucket exists + readable | v1.1 / `v1.2.0` | `terraform/bootstrap/` | REQ-016 | live-aws | `nova-tfstate-581513795199-us-east-1` |
|
||
| — | Decision Ledger (SQLite hash-chain) | v1.17 / `v1.17.0` | `core/metrics/decision_ledger.py` | REQ-185, REQ-186 | local | cold store for metrics; `ai.decision.made` + `attestation.recorded` events |
|
||
| — | SSM Parameter Store deploy outputs (SecureString, KMS) | v1.7 / `v1.7.0` | `core/output_publisher.py` | REQ-050, D-050 | live-aws | `/acdl/{env}/{contractId}/{output_name}` |
|
||
| — | GitHub PR comment / job summary deploy outputs | v1.7 / `v1.7.0` | `scripts/run_platform.sh` | REQ-050, D-050 | local | no raw secrets in logs |
|
||
| — | Uniform error reporting via Lambda `report_error` | v1.7 / `v1.7.0` | `core/lambda/contract_ingestor.py` | REQ-055, D-055 | live-aws | GitHub issue on platform repo `acdl/acdl`; idempotent |
|
||
| — | Tagging standard enforcement (4 required tags) | v1.7 / `v1.7.0` | `schemas/tagging-standard.json`, `adapters/terraform/policy/custom_rules/nova_tagging.py` | REQ-054, D-054 | local | `nova:owner`, `nova:contract`, `nova:environment`, `nova:cost-center` |
|
||
| — | Encryption + deletion-protection by default | v1.8 / `v1.8.0` | `modules/l1/*/terraform/main.tf` | REQ-062, REQ-069, D-062, D-069, D-072 | local | per-stack CMK; managed KMS fallback for standalone L1 (D-072) |
|
||
|
||
### Domain 7 — Telemetry & metrics
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| CAP-023 | metrics collector runs + emits expected schema | v1.17 / `v1.17.0` | `core/metrics/collector.py` | REQ-194 | local | fact_run, fact_decision, fact_attestation dims |
|
||
| CAP-024 | unified deck structure (slide count, x3 arc, per-slide benefits) | v1.17 / `v1.17.0` | `docs/presentations/nova-autonomous-cloud-delivery-marp.md` | REQ-194 | local | single source-of-truth marp deck |
|
||
| — | Outcome backfill (`pending` → `succeeded`/`failed`) | v1.26 / `v1.25.3` | `core/metrics/outcome_backfill.py` | REQ-317 | local | idempotent + terminal; grounds AI Decision Accuracy |
|
||
| — | Trust Snapshot | v1.17 / `v1.17.0` | `metrics/TRUST_SNAPSHOT.md`, `core/metrics/trust_snapshot.py` | REQ-194 | local | leadership-ready trust verdict |
|
||
| — | PowerBI export (fact/dimension views + 8 placeholder views) | v1.17 / `v1.17.0` | `metrics/powerbi/` | REQ-194 | local | deferred metrics ship as documented-schema placeholders |
|
||
| — | Pre-apply Infracost estimate | v1.17 / `v1.17.0` | `scripts/run_platform.sh` | REQ-119 | local | `nova.cost.estimated`; actual-spend CUR reconciliation deferred (D-096) |
|
||
| — | Regression gate (`scripts/run_regression.sh`) | v1.10 / `v1.10.0` | `core/regression_verify.py`, `scripts/run_regression.sh` | REQ-090, REQ-121 | local | fails closed on any non-Verified CAP; CAP-001..025 |
|
||
|
||
### Domain 8 — Consumer surfaces (developer + agentic)
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| — | Reusable deploy workflow (`deploy.yml@v1.25`) | v1.5 / `v1.5.0` | `.github/workflows/deploy.yml`, `.gitea/workflows/deploy.yml` | REQ-105 | local | `workflow_call`; modes: full/plan-only/check-only/decommission |
|
||
| — | Consumer onboarding (developer + citizen-dev paths) | v1.1 / `v1.2.0` | `docs/ONBOARDING.md`, `docs/consumer-guide.md` | BA.E, W3.E | local | both end in a sandbox dev submission that must pass the confidence gate |
|
||
| — | Atelier MCP server (agentic validation) | v1.18 / `v1.18.0` | `mcp/atelier/server.py` | REQ-221, REQ-222 | local | `atelier.validate_against_principles` tool |
|
||
| — | 9 production-grade engineering skills | v1.18 / `v1.18.0` | `skills/{api,security,data,testing,observability,errors,devops,infrastructure-as-code,compliance}.md` | REQ-221, REQ-222, BA.A | local | indexed by `docs/skills.md`; review/agent-checklist.md gate |
|
||
| — | Module examples (validated against contract schema) | v1.7 / `v1.7.0` | `modules/<name>/examples/{simple,complex}.yml` | REQ-058, D-058 | local | examples cannot drift from schema silently |
|
||
|
||
### Domain 9 — Pilot estate (v1.26)
|
||
|
||
> The first real consumer estate. `nova-blockchain-exchange` repo
|
||
> (Gitea `continuous-intelligence/nova-blockchain-exchange`, local clone
|
||
> `/root/nova-blockchain-exchange`). Homegrown PoA blockchain, equities
|
||
> only, single validator, T+1 settlement finality = block commit.
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| CAP-026 | PoA blockchain core (block + ledger + validator) | v1.26 / `v1.25.1` | `chain/block.py`, `chain/ledger.py`, `chain/validator.py` | REQ-310, D-201 | local | single validator; SHA-256 hash chain; deterministic block production |
|
||
| CAP-027 | Order-matching engine (limit order book) | v1.26 / `v1.25.1` | `engine/order_book.py`, `engine/order.py` | REQ-311 | local | price-time priority; partial fills |
|
||
| CAP-028 | T+1 settlement service | v1.26 / `v1.25.1` | `settlement/service.py` | REQ-312 | local | idempotent; finality = block commit |
|
||
| CAP-029 | Consumer `contract.yaml` (blockchain exchange) | v1.26 / `v1.25.2` | `nova-blockchain-exchange/contract.yaml`, `contracts/*.yml` | REQ-313 | local | per-env variants (dev/qa/prod); validated against contract schema |
|
||
| CAP-030 | Consumer deploy via `deploy.yml@v1.25` (inline adapter) | v1.26 / `v1.25.2` | `nova-blockchain-exchange/.github/workflows/deploy.yml`, `.gitea/workflows/deploy.yml` | REQ-314 | local | no cross-repo `uses:` (SPEC §10 Q1); checkout `acdl/acdl @ v1.25` into `platform/`, run `run_platform.sh` |
|
||
| CAP-025 | Live-pilot-apply regression capability (round-trip) | v1.26 / `v1.25.3` | `core/regression_verify.py` | REQ-316 | local | contract→adapter→plan→policy→confidence→attestation→outbox round-trip assertion |
|
||
| CAP-031 | Live pilot apply evidence (`blkex-pilot-apply-v0.2`) | v1.26 / `v1.25.4` | `.ciagent/archive/P4-PILOT-RUN-EVIDENCE-v1.26.md` | REQ-316, REQ-321 | live-aws | confidence 0.800 pass; outcome backfilled; hash chain valid; live apply against `581513795199` |
|
||
| CAP-032 | AWS key rotation scheduled workflow | v1.26 / `v1.25.3` | `workflows-src/rotate-aws-key.yml` | SPEC §5.9 | local | daily rotation; forge-agnostic token name (REQ-230) |
|
||
|
||
### Domain 10 — Forge / CI runtime
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| CAP-009 | offline pytest suite passes | v1.1 / `v1.2.0` | `tests/` | REQ-009 | local | 844 tests (v1.26 baseline) |
|
||
| CAP-010 | `run_ci.sh` reproduces CI pipeline locally | v1.4 / `v1.4.0` | `scripts/run_ci.sh` | REQ-010 | local | offline; contract→resolver→stack→adapter→structure validated |
|
||
| CAP-011 | headline E2E — local tier (microservice) | v1.2 / `v1.3.0` | `scripts/run_local_e2e.sh` | REQ-011, D-092 | local | emulating adapters (no AWS) |
|
||
| CAP-012 | local E2E — static-assets (no ECS) | v1.1 / `v1.2.0` | `scripts/run_local_e2e.sh` | REQ-012 | local | |
|
||
| — | `platform-test.yml` CI workflow | v1.4 / `v1.4.0` | `.github/workflows/platform-test.yml` | REQ-010 | local | platform repo only (consumer CI is per-consumer) |
|
||
| — | `modules-lifecycle` pipeline (apply→modify→destroy matrix) | v1.11 / `v1.11.0` | `.github/workflows/modules-lifecycle.yml` | REQ-121, D-096 | live-aws | per-module lifecycle cell; `ci-vpc-destroy` always runs |
|
||
| — | `release.yml` (semver + floating tag maintenance) | v1.7 / `v1.7.0` | `.github/workflows/release.yml` | REQ-... | local | `v1.25` + `v1` floating tags force-moved on merge to main |
|
||
| — | IAM policy baseline (`acdl-spike-runner-policy`) | v1.11 / `v1.11.0` | `terraform/bootstrap/spike_runner_policy.json`, `.ciagent/IAM_POLICY.md` | REQ-116, D-095 | live-aws | regression-tested by `tests/test_iam_policy_baseline.py`; OIDC role `acdl-act-runner-role` (CAP-022) |
|
||
| — | Local emulating adapters (no AWS) | v1.10 / `v1.10.0` | `core/local_lambda_stub.py`, `scripts/run_local_e2e.sh` | D-092 | local | proves runtime behavior without live AWS |
|
||
|
||
### Domain 11 — CLI + Identity Layer (v1.28)
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| CAP-033 | CLI subcommand surface exists | v1.28 / `v1.27.1` | `nova/cli.py`, `nova/<module>.py` (15 subcommands) | REQ-324 | local | `nova --help` lists a subcommand for every `core/` module; argparse-only, auto-discovered |
|
||
| CAP-034 | Subcommand delegates to `core/` | v1.28 / `v1.27.1` | `nova/<module>.py` | REQ-324 | local | ≤50 lines, ≤3 FunctionDef, all calls resolve to `core.*` imports; AST-scanned in `tests/test_cli_subcommands.py` |
|
||
| CAP-035 | Layer matches wheel | v1.28 / `v1.27.1` | `.github/workflows/publish.yml`, `.gitea/workflows/publish.yml`, SSM `/nova/layer/nova-cli/version` | REQ-323 | local | wheel + Lambda layer co-published with identical version; SSM mapping; CodeArtifact + fallback |
|
||
| CAP-036 | Nova-idp auth flow works | v1.28 / `v1.27.3` | `core/lambda/nova_idp_auth.py`, `tests/test_idp_auth.py` | REQ-333 | local | sign-up → sign-in → session E2E; Argon2id t=3 m=65536 p=1; fail-closed D-228; moto locally, real DDB in CI |
|
||
| CAP-037 | Token-vend signs via KMS | v1.28 / `v1.27.4` | `core/lambda/nova_idp_token_vend.py`, `core/kms_signing.py`, `tests/test_kms_roundtrip.py` | REQ-337 | local | ECDSA P-256 / ES256; DER→raw conversion; KMS round-trip test; mock KMS locally, real KMS in CI |
|
||
| CAP-038 | PAT issuance + revocation | v1.28 / `v1.27.4` | `core/pat_lifecycle.py`, `tests/test_pat_revocation.py` | REQ-342 | local | issue → vend → revoke → 403 within 60s P95; strong-read DDB (D-229); verified <1s locally |
|
||
| — | `nova init` scaffolds `.nova/` | v1.28 / `v1.27.1` | `nova/init.py`, `core/init_scaffold.py` | REQ-325 | local | `.nova/`, `.nova/contract.yml.attestations/`, `.gitignore` (secrets excluded) |
|
||
| — | `nova cli-action` composite action | v1.28 / `v1.27.1` | `.github/actions/nova-cli/action.yml` | REQ-326 | local | byte-identical GitHub + Gitea; Python 3.12 pinned; NFR-11 |
|
||
| — | `mode_resolver` (flag→env→cred→TTY) | v1.28 / `v1.27.1` | `core/mode_resolver.py` | REQ-327, D-226 | local | `sys.stdin.isatty()` (not stdout); hypothesis property tests |
|
||
| — | Dual-use Lambda/CLI import | v1.28 / `v1.27.2` | `core/lambda/contract_ingestor.py` | REQ-329 | local | shared `dispatch_action()`; ≥80% code share; NFR-7 |
|
||
| — | Local env synthesizer | v1.28 / `v1.27.2` | `core/env.py` (`synthesize_local_env`) | REQ-330 | local | `nova apply --local`; no cloud provisioning |
|
||
| — | JWS-from-PAT (HKDF-SHA256, HS256) | v1.28 / `v1.27.2` | `core/jws_attestation.py` | REQ-332, C-5.2 | local | symmetric; verification key derived from PAT via same KDF |
|
||
| — | JWKS endpoint (function URL) | v1.28 / `v1.27.4` | `core/lambda/nova_idp_jwks.py` | REQ-338, D-230 | local | `AuthType: NONE`; `Cache-Control: max-age=3600`; optional CloudFront/WAF |
|
||
| — | kyverno-json ABAC token-vend policy | v1.28 / `v1.27.4` | `platform/abac/token-vend.policy`, `core/abac_evaluator.py` | REQ-339, D-227 | local | fail-closed (C-6.1, 7 tests); `policy_version` git SHA (D-231) |
|
||
| — | `nova idp setup --check/--apply/--verify` | v1.28 / `v1.27.4` | `nova/idp/setup.py`, `core/lambda/nova_idp_setup.py`, `core/lambda/nova_idp_cfn.py` | REQ-340, REQ-341 | local | CloudFormation template review (NFR-10); IAM policy delta; KMS round-trip verify |
|
||
| — | `nova auth login/revoke/status` | v1.28 / `v1.27.4` | `nova/auth/{login,revoke,status}.py`, `core/auth_store.py` | REQ-344, C-7.3 | local | `~/.nova/credentials.json` 0600 stores OIDC token + metadata (NOT raw PAT) |
|
||
| — | E2E integration test | v1.28 / `v1.27.5` | `tests/test_e2e_idp.py` | REQ-348 | local | sign-up → sign-in → token-vend → apply → audit chain |
|
||
| — | Identity-layer threat model | v1.28 / `v1.27.5` | `docs/threat-model.md` | REQ-347 | local | 8 threats + C-9.2 INV-18..21 compression audit |
|
||
| — | Operator guide | v1.28 / `v1.27.5` | `docs/operator-guide-idp.md` | REQ-345 | local | `nova idp setup` + KMS rotation + layer update + PITR restore + emergency PAT revocation |
|
||
| — | Developer guide | v1.28 / `v1.27.5` | `docs/developer-guide-auth.md` | REQ-346 | local | quickstart + mode resolution + JWS KDF + service-account PATs |
|
||
|
||
### Domain 12 — Platform Ops Reposplit (v1.29)
|
||
|
||
> Shipped at `v1.28.6` (2026-08-20). Covered-reference REQs (355-366,
|
||
> 371) are authored out-of-band in `nova-platform-ops`; their
|
||
> verification surface is the M1/M1.5/M2 cutover gates in the operator
|
||
> guide (grill CF-2/G-5). The live cutover is an operator action — the
|
||
> acdl-side deliverables (publish.yml, operator guide, CFN archive,
|
||
> consumer bump) are complete.
|
||
|
||
| ID | Capability | Shipped | Files | Controlling | Tier | Notes |
|
||
|----|-----------|---------|-------|-------------|------|-------|
|
||
| CAP-039 | Platform ops reposplit | v1.29 / `v1.28.6` | `nova-platform-ops` (out-of-band), `docs/operator-guide-platform-ops.md`, `docs/archive/nova-idp-cfn-v1.28.md` | REQ-369, REQ-OPS-GUIDE, D-232, D-235 | covered-reference | engineering (`acdl/acdl`, GitHub) ends at the artifact; operations (`nova-platform-ops`, Gitea-private, OPER-PRIV) begins at the live platform; tag-pin handoff; CFN archived; covered-reference REQs tracked via cutover gates |
|
||
| CAP-040 | KJ substrate lockstep | v1.29 / `v1.28.6` | `nova-platform-ops` (out-of-band), `platform/abac/kj-version.txt`, `.github/workflows/publish.yml` | REQ-371, REQ-363, REQ-363b, D-238, D-239 | covered-reference | one ECR image digest shared by Lambda `image_uri` + Fargate task `image`; `lifecycle.precondition` on both resources at `terraform plan`; KJ-STATIC (`CGO_ENABLED=0`, `file(1)` asserts `statically linked`); no second pipeline, no second SHA pin |
|
||
| CAP-041 | JWKS edge-only | v1.29 / `v1.28.6` | `nova-platform-ops` (out-of-band), `docs/operator-guide-platform-ops.md` | REQ-364, REQ-365, REQ-366, INV-18, D-233 | covered-reference | JWKS is the only public read surface; CloudFront + OAC (`AuthType: AWS_IAM`, NOT `NONE`, `OriginAccessControlOriginType: lambda`, `SigningBehavior: always`); direct Function URL → 403, via-CloudFront → 200; WAF rate-limit 3000/5min + AWSManagedRulesCommonRuleSet; ACM DNS-validated in us-east-1; Route53 A-alias |
|
||
| CAP-042 | Leadership presentation deck (single-shot, polished) | v1.30 / `v1.29.5` | `docs/presentations/nova-leadership-deck-marp.md`, `docs/presentations/nova-leadership-deck.pptx`, `scripts/check_leadership_deck.sh`, `scripts/render_leadership_diagrams.sh`, `docs/presentations/assets/mmd/leadership-slide-{1..7}.mmd`, `docs/presentations/assets/png/leadership-slide-{1..7}.png` | REQ-372.1..REQ-372.12, D-241..D-246 | local | Single-shot 7-slide PPTX deck for Infrastructure & Operations leadership (CTO + VP Technology + Product Management); presented August 2026; November 2026 runway anchor; discrete hand-authored artifact (NOT a compression of the citizen-developer pitch per D-241); rendered via existing `scripts/render_pptx.py` (narrowly extended per D-242); polished in P3 (D-244 cover slide, D-245 slide 7 "What works now" block, D-246 7 S&P-themed mermaid diagrams); smoke test on-demand (NOT a CI gate); vision `[1]` grounding in slides 3/5/7 |
|
||
|
||
## Archive pointers
|
||
|
||
- **v1.0–v1.24 capability narrative + the 2026-07-27 re-verification sweep:**
|
||
`.ciagent/archive/CAPABILITY_INVENTORY-v1.10.md` (moved from
|
||
`.ciagent/CAPABILITY_INVENTORY.md` at v1.27). CAP-NNN IDs in this file
|
||
cross-reference the regression gate at `core/regression_verify.py`.
|
||
- **v1.0–v1.24 milestone narrative:** `.ciagent/archive/PROJECT-v1.0-v1.24.md`.
|
||
- **v1.0–v1.24 requirements (REQ-01..REQ-290):** `.ciagent/archive/REQUIREMENTS-v1.0-v1.24.md`.
|
||
- **v1.0–v1.24 phase breakdowns:** `.ciagent/archive/ROADMAP-v1.0-v1.24.md`.
|
||
- **v1.0–v1.24 architecture history:** `.ciagent/archive/ARCHITECTURE-v1.0-v1.24.md`.
|
||
- **v1.26 pre-execution artifacts (CLARIFY, GRILL, IDEATE, RESEARCH):**
|
||
`.ciagent/archive/{CLARIFY,GRILL,IDEATE,RESEARCH}-v1.26.md` (decisions
|
||
D-200..D-213 folded into `PROJECT.md` load-bearing decisions + PLAN.md
|
||
binding revisions at v1.27 archive time).
|
||
- **v1.26 phase verifications:** `.ciagent/archive/{VERIFY-P03,VERIFY-P04,REVIEW-AUDIT-P05}.md`.
|
||
- **v1.26 live pilot run evidence:** `.ciagent/archive/P4-PILOT-RUN-EVIDENCE-v1.26.md`.
|
||
- **v1.21 autonomy thesis (folded into NORTH_STAR.md Vision):** `.ciagent/archive/AUTONOMY_THESIS-v1.21.md`.
|
||
- **v1.14 AWS cost report (predates v1.26 live pilot):** `.ciagent/archive/COST-v1.14.md`.
|
||
|
||
## Update discipline
|
||
|
||
This file is updated **once per milestone, at the P-final milestone-ship
|
||
wave** (Wave 3 "milestone ship" in `PLAN.md`), alongside
|
||
`ROADMAP.md`/`NORTH_STAR.md`/`REQUIREMENTS.md`:
|
||
|
||
1. Append new capability entries for each shipped REQ (one row per
|
||
capability; group by domain).
|
||
2. Mark any deprecated capability with a `Deprecated` row citing the
|
||
milestone + replacement.
|
||
3. Bump the "Last milestone ship" header.
|
||
4. Do not rewrite existing entries (additive only).
|
||
|
||
Enforcement: convention (the P-final ship step names this file). A
|
||
drift-check gate (assert every REQ marked `complete` in
|
||
`REQUIREMENTS.md` traceability appears in STATE.md) is a future option
|
||
if the convention drifts.
|
||
|
||
---
|
||
|
||
## PDLC Phase 0 Intake (current ground truth — 2026-08-20)
|
||
|
||
> Single-pass discovery for the next PDLC cycle. Populated from the
|
||
> live repo state after v1.29 ship. No aspirational items — state is
|
||
> what is, not what should be. Unknowns are explicit.
|
||
|
||
---
|
||
|
||
### 1. Header (mandatory)
|
||
|
||
Project: Nova — The New Dawn of DevSecOps
|
||
|
||
Initiative: Leadership Presentation Deck — compressed (≤7 slides, S&P theme, 18-month CDLC→SDLC→PDLC roadmap)
|
||
|
||
Initiator: Product Owner / Manager (PDLC Phase 0 trigger)
|
||
|
||
Date (UTC): 2026-08-20
|
||
|
||
Current Version: v1.29 complete (tag `v1.28.6`, merged to main + pushed + released 2026-08-20); all 7 phases shipped; no phase in progress
|
||
|
||
System Health: YELLOW — coverage 73.8% below 80% release-gate floor (NFR debt carried from v1.28, unchanged through v1.29 feature milestone); nova-platform-ops M1 cutover pending operator action (covered-reference REQs 355-366, 371 not yet live-verified)
|
||
|
||
Raw Idea (≤ 3 sentences):
|
||
|
||
Technology Leadership needs a compressed presentation deck (≤7 slides, S&P theme colors) communicating: the problem statement, who the target audience is, what the platform is + how it solves the problem, what works now, and an 18-month roadmap from CDLC to SDLC + PDLC integration. Leaders do not want long presentations — the existing 23-slide deck is too verbose for this audience.
|
||
|
||
Trigger: post-v1.29 milestone completion — the platform has shipped reposplit + identity layer bring-live + the operator guide, making the story ready for leadership consumption.
|
||
|
||
Desired outcome: a leadership-ready deck (≤7 slides, Marp + python-pptx, S&P theme `#D6002A` / `#1B1B1B` / `#FFFFFF` / `#F0F0F0`) that secures buy-in for the 18-month integration roadmap (CDLC → SDLC → PDLC).
|
||
|
||
---
|
||
|
||
### 2. Architecture State
|
||
|
||
Active Layers (which exist and are stable):
|
||
|
||
[x] Core Primitives — `core/` (26 top-level modules + `core/lambda/` (8) + `core/metrics/` (10)): `abac_evaluator`, `attestation_matrix`, `auth_store`, `confidence_signal`, `contract_resolver`, `decommission_transform`, `env`, `env_transition`, `environment_check`, `hitl_gates`, `init_scaffold`, `jws_attestation`, `kms_signing`, `local_emulators`, `mode_resolver`, `onboarding`, `outbox_writer`, `output_publisher`, `pat_lifecycle`, `policy_engine`, `regression_verify`, `separation_of_duties`, `submission_readiness` + `core/lambda/` (6 modules) + `core/metrics/` (decision ledger)
|
||
|
||
[x] Domain Modules — `adapters/terraform/` (stateless adapter), `adapters/kyverno-json/` (unified policy engine, INV-4 swappable), `adapters/wiz/`, `adapters/kyverno/` (K8s, inactive for Terraform — D-053)
|
||
|
||
[x] API/Dev Surface — `nova/` CLI package (15 subcommands, argparse-only, `[project.scripts] nova = "nova.cli:main"`); `nova auth {login,revoke,status}`; `nova idp setup` (delegates to `terraform apply` per REQ-369); `nova init`; `nova apply --local`; `nova cli-action` composite action (GitHub only — D-232)
|
||
|
||
[x] UI/Agent Surface — N/A (no UI; CLI + JSON endpoints only; JWKS serves `application/json`)
|
||
|
||
Compute Topology (per environment):
|
||
|
||
local: abstract (local emulators via `core/local_emulators.py:LocalLambdaStub`; `nova apply --local` synthesizes env via `core/env.synthesize_local_env()`; no cloud provisioning)
|
||
|
||
dev: abstract (env JSON `core/environments/dev.json`; pilot ran `mode: full` against live AWS `581513795199` at v1.26; Nova-idp live deployment is via `nova-platform-ops` Terraform — M1 cutover pending operator action, covered-reference)
|
||
|
||
staging: N/A (no `staging` environment JSON; environments are dev/qa/prod/dr)
|
||
|
||
prod: UNKNOWN — needs investigation (env JSON `core/environments/prod.json` exists; live-apply not run against prod; pilot was dev-only per D-209)
|
||
|
||
dr: placeholder (env JSON `core/environments/dr.json` exists; blocked by pilot-readiness policy D-208; not activated)
|
||
|
||
Identity Stack in Force:
|
||
|
||
auth: Custom IDP — Nova-idp (`nova-idp-auth` Lambda, v1.28): sign-up/sign-in/session; Argon2id (t=3, m=65536, p=1); DynamoDB `nova-users`/`nova-sessions`/`nova-password-resets`. Covered-reference — live deployment via `nova-platform-ops` Terraform (M1 cutover pending operator action).
|
||
|
||
token-vend: Nova-idp (`nova-idp-token-vend` Lambda, v1.28, deployed on container image with static `kj` per REQ-363): accepts PAT/session → KMS-signed OIDC token (ECDSA P-256 / ES256); kyverno-json ABAC fail-closed (INV-17, C-6.1); `nova-pats` DynamoDB (strong-read revocation, D-229, 60s SLO). Covered-reference — M1.5 verification gate pending (3 consecutive green rebuilds).
|
||
|
||
signing: KMS asymmetric — `alias/nova-oidc-signing` (ECC_NIST_P256, SIGN_VERIFY, 90-day rotation, D-234). Code complete; key provisioning is covered-reference (REQ-362, M1 cutover pending operator action in `nova-platform-ops`).
|
||
|
||
session: DynamoDB — `nova-sessions` table (PK `session_id`, TTL `expires_at`, 24h). Cookie/local-file: `~/.nova/credentials.json` (0600, OIDC token + PAT metadata, NOT raw PAT — C-7.3).
|
||
|
||
Audit Stream:
|
||
|
||
source of truth: DynamoDB outbox → S3 Object Lock (7-yr target, D-083 deferred) → audit repo (hot index). The Decision Ledger (SQLite hash-chain, D-121, `core/metrics/decision_ledger.py`) is the cold store for `ai.decision.made` + `attestation.recorded` events.
|
||
|
||
in-repo fallback: yes (SQLite hash-chain outbox_writer, `core/outbox_writer.py`, INV-6 tamper-evident; tamper-*resistant* deferred — D-083 S3 Object Lock/JWS not yet enabled)
|
||
|
||
retention policy: 7 years (S3 Object Lock target; not yet enabled — D-083 deferred)
|
||
|
||
---
|
||
|
||
### 3. Technical Stack (concrete, not aspirational)
|
||
|
||
Language(s) and runtime(s): Python 3.12 (requires-python `>=3.12`; Lambda Python 3.12 runtime on Amazon Linux 2023); Go (kj binary, `CGO_ENABLED=0`, pinned v0.0.3 from `github.com/kyverno/kyverno-json`)
|
||
|
||
Build / packaging: setuptools (`pyproject.toml` v1.29.0, build-backend `setuptools.build_meta`); wheel via `python -m build --wheel`; Lambda layer via `pip install --target layer/python/` + `zip`; Lambda zip (`nova-lambda-token-vend-v1.29.x.zip`); ECR container image (`public.ecr.aws/lambda/python:3.12-al2023` base + static `kj` binary at `/opt/kj/kj`); publish to GitHub Releases per tag (D-232 — CodeArtifact out, direct GitHub Releases artifact fetch)
|
||
|
||
CI / CD: GitHub Actions only (D-232 — `.gitea/` removed, `forge_parity_disabled` CI assertion in `ci.yml`); `publish.yml` (tag-triggered `v1.29.*`, wheel + layer + Lambda zip + ECR image + GitHub Release, REQ-354); `ci.yml` (test/lint/forge-parity-disabled); `deploy.yml@v1.29` (consumer deploy); `nova cli-action` composite action (`.github/actions/nova-cli/action.yml`); OIDC to AWS (`id-token: write`); `nova-platform-ops` uses Gitea Actions (out-of-band, OPER-PRIV, TFM-HITL)
|
||
|
||
Infrastructure: AWS account `581513795199` (single-region `us-east-1`); S3 (state files); DynamoDB (locking + outbox + identity tables); Lambda (contract ingestor + Nova-idp 3 Lambdas on container images); KMS (per-stack CMK + `alias/nova-oidc-signing`); ECR (kj container image); CloudFront/WAF/ACM/Route53 (JWKS edge, covered-reference); Fargate (standby defensive fallback, covered-reference); no VMs/bare metal/OS (Anti-Goal)
|
||
|
||
Data stores: DynamoDB — `nova-contracts`, `nova-change-requests` (v1.7); `nova-users`, `nova-sessions`, `nova-password-resets`, `nova-pats` (v1.28); SQLite — Decision Ledger (`core/metrics/decision_ledger.py`, local cold store); S3 — Terraform state + audit Object Lock (target, D-083 deferred); ECR — kj container image
|
||
|
||
Secrets / KMS: KMS per-stack CMK (D-069, 90-day rotation); `alias/nova-oidc-signing` (ECC_NIST_P256, 90-day rotation, D-234 — covered-reference, M1 cutover pending); `nova-spike-runner` IAM user (static key, daily rotation via `workflows-src/rotate-aws-key.yml`, REQ-230 forge-agnostic); Secrets Manager (`nova/github-token`); `NOVA_FORGE_TOKEN` in `.env.secrets` (not shell-env, per bash_allowlist; used for `nova-platform-ops` Gitea releases)
|
||
|
||
External integrations in scope: GitHub (`acdl/acdl` — primary forge, D-232); Gitea (`git.cloudinit.dev/continuous-intelligence/nova-platform-ops` — ops repo, OPER-PRIV, out-of-band); AWS (account `581513795199` — pilot + identity stack + ECR); `kj` / kyverno-json v0.0.3 (Go binary, pinned SHA + repo URL in `platform/abac/kj-version.txt`, `github.com/kyverno/kyverno-json`); Marp CLI 4.5.0 + python-pptx (slides render pipeline, `docs/presentations/`)
|
||
|
||
---
|
||
|
||
### 4. Active Constraints (the load-bearing ones)
|
||
|
||
Locked Decisions: D-001..D-240 (full ledger in PROJECT.md + CLARIFY history). Load-bearing for new work: D-022 (contract schema), D-039/D-047 (per-run creds), D-051 (Lambda Function URL), D-069 (per-stack CMK), D-083 (S3 Object Lock — deferred), D-092 (local emulators), D-096 (live pilot — lifted v1.26), D-121 (Decision Ledger), D-133 (submission-readiness gate), D-200..D-213 (v1.26 pilot), D-214..D-225 (v1.27), D-226..D-231 (v1.28 — mode resolution, kyverno-json ABAC, Argon2id fail-closed, PAT revocation strong-read, JWKS function URL, ABAC policy git-SHA versioning), D-232..D-238 (v1.29 — forge parity abandoned, JWKS edge-only, KMS asymmetric, tag-pin handoff, cutover shape, Fargate sunset, KJ-LOCKSTEP), D-239 (ECR tag format), D-240 (Terraform precondition floor v1.2.0)
|
||
|
||
Active Invariants: INV-1..INV-18 (full text above). New in v1.28: INV-12 (mode observability), INV-13 (mode determinism), INV-14 (credential type encodes role), INV-15 (no AWS-managed identity), INV-16 (Argon2id password storage), INV-17 (ABAC discipline fail-closed). New in v1.29: INV-18 (JWKS-EDGE-ONLY) + 10 NFR constraints (KJ-STATIC, KJ-LOCKSTEP, KJ-WARMUP-HEALTH, OPER-PRIV, IAM-NARROW, DRIFT-DETECT, IMPORT-IDEMPOTENT, TFM-HITL, JWKS-SLO, JWKS-ROTATION)
|
||
|
||
Standing Capability Gate: CAP-001..CAP-042 — all Verified (32 from v1.0..v1.27 + 6 from v1.28 + 3 from v1.29 covered-reference + 1 from v1.30 single-shot deck). Gate enforced by `core/regression_verify.py` + CI merge gates. CAP-033..038 added v1.28 (CLI surface, delegation AST, layer/wheel match, auth flow, KMS sign, PAT revocation). CAP-039..041 added v1.29 (platform-ops-reposplit, kj-substrate-lockstep, jwks-edge-only — covered-reference, live cutover pending operator action in nova-platform-ops). CAP-042 added v1.30 (leadership-deck — single-shot, on-demand smoke test, NOT a CI gate).
|
||
|
||
Anti-Goals Touched: `docs/vision.md` §7 / `NORTH_STAR.md` §Anti-Goals — (1) not an upstream dev platform; (2) not a general-purpose AI; (3) not a legacy infra bridge; (4) not a permissive delivery highway; (5) not a mutable audit log. v1.29 honored all 5 (no PDLC reach, narrow CLI autonomy, no VMs, ABAC fail-closed + HITL gates intact, immutable outbox).
|
||
|
||
Out-of-Scope (hard): MFA/TOTP enforcement (v1.21+); WebAuthn/FIDO2 (v1.23+); upstream IdP federation (v1.23+); Lambda layer auto-update on `core/` changes (v1.19); password breach detection (v1.23+); session refresh token rotation (v1.22); S3 Object Lock / JWS tamper-resistance (D-083, deferred); multi-cloud (Azure/GCP); ML forecasting; bonds/derivatives/options (D-200 equities-only); multi-validator BFT (D-201 single-validator PoA); pilot qa/prod/dr environment activation (D-208/D-209, separate initiative); CodeArtifact provisioning (out per D-232 — direct GitHub Releases artifact fetch); Nova-idp feature work (new OIDC claims, new ABAC rules — bring live, don't extend); CloudFront Frontend / L3B consumer surface (pure ops focus only)
|
||
|
||
---
|
||
|
||
### 5. Recent History & Quality Gates (last 1-2 milestones)
|
||
|
||
Last Shipped: v1.29 (tag `v1.28.6`, 2026-08-20) — Reposplit + Identity Layer Bring-Live. 6 acdl-side REQs complete (REQ-354, 367, 368, 369, REQ-OPS-GUIDE, REQ-CONSUMER-BUMP) + 14 covered-reference REQs (355-366, 371). 3 CAPs (CAP-039..041), 1 INV (INV-18), 10 NFR constraints, 9 decisions (D-232..240). 7 phases (P0 + P1..P5 + P6 final). Grill PROCEED 0.72 (4 critical fixes). Review PASS-WITH-ISSUES (3 P0 fixes). Audit all PASS. Merged to main `9dc5669`, pushed + 8 Gitea releases created (ids 803-810).
|
||
|
||
In Progress: N/A (no phase in progress; v1.29 complete; next milestone not yet scoped — this intake initiates the leadership deck initiative)
|
||
|
||
Coverage Floor: 73.8% (3119/4227 lines covered) — BELOW the 80% release-gate floor. v1.29 was a feature milestone (no NFR coverage work); v1.28 new modules have high unit-test coverage but the overall floor is dragged by older uncovered code paths. Quality debt to address in a future NFR milestone. YELLOW carried without scope expansion.
|
||
|
||
Recent Incidents: none (no incidents in v1.28 or v1.29; no hotfix/rollback/outage commits in recent history)
|
||
|
||
Known Tensions: (1) nova-platform-ops repo not yet created — the 14 covered-reference REQs (355-366, 371) have their acdl-side deliverables complete (operator guide, publish.yml, CFN archive) but the live M1/M1.5/M2 cutover gates have not been run (operator action, out-of-band). (2) Coverage 73.8% < 80% floor — YELLOW carried from v1.28; v1.29 did not expand scope but did not restore the floor. (3) M-001 (ABAC empty-policy-dir fail-open gap) — pinned in `test_abac_e2e.py`, mitigated; clear fix exists (treat `any_policy=False` as fail-closed) but not yet applied. (4) Q7 carry-forward (kj image verification — M1.5 3-consecutive-rebuild gate is operator action in nova-platform-ops CI, not acdl-side). (5) The existing 23-slide deck (`docs/presentations/nova-autonomous-cloud-delivery-marp.md`) is too long for the leadership audience (target ≤7 slides).
|
||
|
||
---
|
||
|
||
### 6. Agent Context & Assumptions (Agent Initiators Only)
|
||
|
||
Missing Context: (1) The 18-month roadmap specifics — NORTH_STAR.md §Future Horizons has the strategic direction (CDLC→SDLC→PDLC integration, AI-Agent Intent Share ≥40%) but the PO needs to define the concrete milestone sequence for the deck. (2) Target audience specifics — "Technology Leadership" is the stated audience but the deck needs to know if this is CTO-level, VP-level, or Director-level (affects depth + framing). (3) Live AWS verification of covered-reference REQs — nova-platform-ops not yet created; M1/M1.5/M2 cutover gates not yet run.
|
||
|
||
Agent Assumptions: (1) The PDLC trigger is the post-v1.29 state intake + the PO's new initiative (leadership deck). (2) The deck uses the existing S&P theme (`docs/presentations/assets/nova-sp-theme.css`, palette `#D6002A`/`#1B1B1B`/`#FFFFFF`/`#F0F0F0`) + the existing Marp + python-pptx render pipeline (`workflows-src/slides.yml`, `scripts/render_pptx.py`). (3) **OVERRIDDEN by D-241 (v1.30 CLARIFY):** the leadership deck is a **discrete, hand-authored artifact — NOT a compression** of the 23-slide existing citizen-developer deck (`nova-autonomous-cloud-delivery-marp.md`), which remains untouched. The Slide Content Map in PROJECT.md §v1.30 is hand-authored content, not derived. (4) Coverage 73.8% is reported as YELLOW system health (below 80% floor) but is not a blocker for the deck initiative — it's quality debt for a future NFR milestone. (5) The covered-reference REQs are reported as tensions, not blockers — they have acdl-side deliverables complete + documented cutover gates.
|
||
|
||
---
|
||
|
||
### 7. Canonical State References (Version/Hash)
|
||
|
||
Vision/Strategy doc: `docs/vision.md` v0.2 (referenced in PROJECT.md; not version-tagged separately)
|
||
|
||
Architecture document: `.ciagent/ARCHITECTURE.md` §12.1..§12.11 (v1.29-appended §12.11 Platform Ops Reposplit); commit `9dc5669` (main HEAD)
|
||
|
||
Last approved SPEC: v1.29 (REQ-354..369, 371, 363b, REQUIREMENTS.md §v1.29); commit `9dc5669`
|
||
|
||
Decision log: D-001..D-240 (PROJECT.md load-bearing + CLARIFY.md history); last synced commit `9dc5669`
|
||
|
||
Invariants catalog: INV-1..INV-18 (STATE.md §Invariants); commit `9dc5669`
|
||
|
||
Capability catalog: CAP-001..CAP-041 (STATE.md §Domains 1..12); commit `9dc5669`
|
||
|
||
---
|
||
|
||
### Ground rules compliance
|
||
|
||
1. No prose paragraphs inside sections — field structure used throughout. ✓
|
||
2. No aspirational items — state is what is (nova-platform-ops "not yet created", prod "UNKNOWN", coverage "73.8%"). ✓
|
||
3. No restated decisions — referenced D-*/INV-*/CAP-* IDs only. ✓
|
||
4. Unknowns explicit — "UNKNOWN — needs investigation" used for prod state; "covered-reference" used for live-unverified REQs. ✓
|
||
5. One file, one format — appended to STATE.md as §PDLC Phase 0 Intake. ✓
|
||
6. Full shipping workflow + merge to forge upstream, NO release — commit to main + push only (release skipped per instruction). ✓ |