Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ffcbe8283 | |||
| 5775a97388 | |||
| b3c75ccec1 | |||
| e891496163 |
@@ -58,6 +58,103 @@ traceable to a human attestation and an immutable evidence stream.
|
|||||||
boundary. The platform validates, enriches with operational standards,
|
boundary. The platform validates, enriches with operational standards,
|
||||||
and reconciles the target state.
|
and reconciles the target state.
|
||||||
|
|
||||||
|
## Scope: Nova is Downstream of PDLC
|
||||||
|
|
||||||
|
> **Promoted from Core Tenet #2 + Anti-Goal #1 (v1.18, REQ-216).** This
|
||||||
|
> is the unmissable scope statement — the PDLC is upstream, Nova is
|
||||||
|
> downstream.
|
||||||
|
|
||||||
|
The **Product Development Lifecycle (PDLC)** — product backlog, code
|
||||||
|
authorship, IDE workflows, sprint planning, application business logic —
|
||||||
|
is **upstream** of Nova. Nova never penetrates the PDLC. Nova's domain is
|
||||||
|
**infrastructure + delivery only**: environment progression, cloud
|
||||||
|
resource lifecycle, operational security/observability NFRs, policy
|
||||||
|
enforcement, immutable audit lineage, and the two consumer surfaces
|
||||||
|
(technical developer + agentic).
|
||||||
|
|
||||||
|
Integration between the PDLC and Nova is **only** through the validated,
|
||||||
|
published contract boundary (`schemas/contract.schema.json` +
|
||||||
|
`schemas/submission-readiness.schema.json`). The citizen developer's AI
|
||||||
|
coding agent, an upstream agentic SDLC platform, or any upstream
|
||||||
|
development platform may all produce submissions — the source does not
|
||||||
|
matter because all are subject to the same compliance standards (the
|
||||||
|
submission-readiness gate, D-133). Nova validates, enriches with
|
||||||
|
operational standards, and reconciles the target state. Nova never
|
||||||
|
authors application code, manages product backlogs, or provides IDE
|
||||||
|
workflows.
|
||||||
|
|
||||||
|
```
|
||||||
|
PDLC (upstream) Nova (downstream)
|
||||||
|
───────────────── ─────────────────
|
||||||
|
product backlog contract ingestion
|
||||||
|
code authorship (AI agent / IDE / SDLC) → submission-readiness gate
|
||||||
|
sprint planning → policy enforcement
|
||||||
|
application business logic → cloud resource lifecycle
|
||||||
|
→ environment progression (dev→qa→prod→dr)
|
||||||
|
→ immutable audit + attestation
|
||||||
|
```
|
||||||
|
|
||||||
|
## RACI Matrix
|
||||||
|
|
||||||
|
> **Source of truth (v1.18, REQ-215, D-139).** Three roles clarify who
|
||||||
|
> owns what across the Nova delivery lifecycle. The matrix is the
|
||||||
|
> authoritative version; `docs/raci.md` is the citizen-developer-facing
|
||||||
|
> copy.
|
||||||
|
|
||||||
|
### Roles
|
||||||
|
|
||||||
|
- **Citizen Developer (CD)** — the consumer (technical developer L3A or
|
||||||
|
non-technical L3B). Responsible for all **Functional Requirements (FRs)**
|
||||||
|
and **User Acceptance Testing (UAT)**. The FRs + UAT are produced via
|
||||||
|
the citizen developer's AI coding agent, an upstream agentic SDLC, or
|
||||||
|
an upstream development platform — **the source does not matter as all
|
||||||
|
are subject to the same compliance standards** (the submission-readiness
|
||||||
|
gate, D-133).
|
||||||
|
- **Platform** — Nova. Responsible for all **Non-Functional Requirements
|
||||||
|
(NFRs)**, **Infrastructure** (cloud resource lifecycle, state, IAM),
|
||||||
|
**QA** (the platform-side quality checks: policy, confidence, schema),
|
||||||
|
and **Production deployments to cloud** (the apply path, the pipeline,
|
||||||
|
the release).
|
||||||
|
- **Release Management (RM)** — **co-owned**. QA + SRE attestations are
|
||||||
|
required by the actual release. The attestations are performed
|
||||||
|
agentically (the platform runs the checks), but the release is
|
||||||
|
**overseen and triggered by the Citizen Developer** — the human
|
||||||
|
attestation at the stage gate (D-042, hitl_gates.py). The platform
|
||||||
|
performs; the citizen developer authorizes.
|
||||||
|
|
||||||
|
### Matrix
|
||||||
|
|
||||||
|
| Work Category | Citizen Developer | Platform | Release Management |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Functional Requirements (FRs)** | **R/A** | C | I |
|
||||||
|
| **User Acceptance Testing (UAT)** | **R/A** | C | I |
|
||||||
|
| **Non-Functional Requirements (NFRs)** | I | **R/A** | C |
|
||||||
|
| **Infrastructure (cloud, state, IAM)** | I | **R/A** | C |
|
||||||
|
| **QA (policy, confidence, schema checks)** | C | **R/A** | I |
|
||||||
|
| **Production deployment to cloud** | I | **R/A** | C |
|
||||||
|
| **Release attestation (QA + SRE sign-off)** | **A** | R | **R** |
|
||||||
|
|
||||||
|
**Key: R** = Responsible (does the work) · **A** = Accountable (owns the
|
||||||
|
outcome, sign-off) · **C** = Consulted · **I** = Informed.
|
||||||
|
|
||||||
|
**Compliance-standard equivalence note:** the citizen developer's FRs +
|
||||||
|
UAT may originate from any upstream source — an AI coding agent, an
|
||||||
|
agentic SDLC platform, or a traditional development platform. All are
|
||||||
|
subject to the same compliance standards: the submission-readiness gate
|
||||||
|
(`schemas/submission-readiness.schema.json`), the contract schema, the
|
||||||
|
policy envelope, and the immutable audit stream. The platform does not
|
||||||
|
differentiate by upstream source; it validates the submission, not the
|
||||||
|
author.
|
||||||
|
|
||||||
|
**Co-ownership of Release Management:** the release is co-owned. The
|
||||||
|
platform performs the QA + SRE attestations agentically (confidence signal,
|
||||||
|
policy checks, separation-of-duties). The citizen developer oversees and
|
||||||
|
triggers the actual release — the human attestation at the stage gate is
|
||||||
|
the citizen developer's authorization, recorded with approver identity
|
||||||
|
(D-042). The platform runs the checks; the citizen developer authorizes
|
||||||
|
the promotion. This is the "autonomy in operations, human at stage gates"
|
||||||
|
model from the NORTH_STAR.
|
||||||
|
|
||||||
## Capability Status (Re-Verified 2026-07-27)
|
## Capability Status (Re-Verified 2026-07-27)
|
||||||
|
|
||||||
> Source of truth: `.ciagent/CAPABILITY_INVENTORY.md` (Phase 54, D-093).
|
> Source of truth: `.ciagent/CAPABILITY_INVENTORY.md` (Phase 54, D-093).
|
||||||
|
|||||||
@@ -499,4 +499,23 @@ def lambda_handler(event, context):
|
|||||||
return {"statusCode": 401, "body": json.dumps({"error": str(e)})}
|
return {"statusCode": 401, "body": json.dumps({"error": str(e)})}
|
||||||
return {"statusCode": 400, "body": json.dumps({"error": str(e)})}
|
return {"statusCode": 400, "body": json.dumps({"error": str(e)})}
|
||||||
except Exception as e: # pragma: no cover - defensive top-level guard
|
except Exception as e: # pragma: no cover - defensive top-level guard
|
||||||
return {"statusCode": 500, "body": json.dumps({"error": str(e)})}
|
return {"statusCode": 500, "body": json.dumps({"error": str(e)})}
|
||||||
|
|
||||||
|
|
||||||
|
# --- CLI: --check-readiness (D-133, REQ-218) ---------------------------
|
||||||
|
# Invoked as: python3 -m core.lambda.contract_ingestor --check-readiness <submission.json>
|
||||||
|
# Delegates to core.submission_readiness.check_readiness() and prints the
|
||||||
|
# structured ReadinessResult. Exits 0 if ready, 1 if not.
|
||||||
|
if __name__ == "__main__": # pragma: no cover - CLI entry
|
||||||
|
import sys
|
||||||
|
if "--check-readiness" in sys.argv:
|
||||||
|
sys.path.insert(
|
||||||
|
0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
)
|
||||||
|
from core.submission_readiness import cli_main
|
||||||
|
|
||||||
|
# Strip the --check-readiness flag; pass the file path.
|
||||||
|
rest = [a for a in sys.argv[1:] if a != "--check-readiness"]
|
||||||
|
sys.exit(cli_main(["check-readiness"] + rest))
|
||||||
|
else:
|
||||||
|
print("Usage: python3 -m core.lambda.contract_ingestor --check-readiness <submission.json>")
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
"""core/submission_readiness.py — Nova submission-readiness validator (REQ-218).
|
||||||
|
|
||||||
|
Defines what is acceptable to start — a superset gate ABOVE
|
||||||
|
contract.schema.json validity. Invoked as
|
||||||
|
``contract_ingestor.py --check-readiness`` (D-133). Returns a structured
|
||||||
|
ReadinessResult (pass/fail per check, with reason codes). On fail → the
|
||||||
|
ingestor rejects with a citizen-developer-facing error (not a stack
|
||||||
|
trace). On pass → proceeds to existing contract ingestion.
|
||||||
|
|
||||||
|
The validator calls contract.schema.json validation first (the shape),
|
||||||
|
then the readiness checks (the gate): tags, env mandatory, policy
|
||||||
|
preconditions, profile:agentic markers, appSource.
|
||||||
|
|
||||||
|
Reason codes:
|
||||||
|
MISSING_TAGS — one or more required Nova tags are absent
|
||||||
|
ENV_MISSING_MANDATORY:<env>:<field> — a per-env mandatory field is missing
|
||||||
|
AGENTIC_MISSING_INTENT — profile=agentic but naturalLanguageIntent absent
|
||||||
|
MISSING_APP_SOURCE — appSource (repo + ref) is missing
|
||||||
|
POLICY_PRECONDITION_MISSING — a declared policy precondition is absent
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
_SCHEMA_DIR = os.path.join(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "schemas"
|
||||||
|
)
|
||||||
|
|
||||||
|
REQUIRED_TAGS = [
|
||||||
|
"nova:owner",
|
||||||
|
"nova:contract",
|
||||||
|
"nova:environment",
|
||||||
|
"nova:cost-center",
|
||||||
|
"nova:ref",
|
||||||
|
]
|
||||||
|
|
||||||
|
ENV_MANDATORY: dict[str, list[str]] = {
|
||||||
|
"dev": [], # dev requires only the base contract shape (id+environment+infrastructure)
|
||||||
|
"qa": ["validation.e2eSuite", "validation.loadTest"],
|
||||||
|
"prod": ["runbook", "dashboard", "oncall"],
|
||||||
|
"dr": ["drDrillRef"],
|
||||||
|
}
|
||||||
|
|
||||||
|
AGENTIC_REQUIRED = ["naturalLanguageIntent", "confidenceAtSubmission", "agentTrace"]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ReadinessResult:
|
||||||
|
"""Structured result of the submission-readiness gate."""
|
||||||
|
|
||||||
|
ready: bool
|
||||||
|
reason_codes: list[str] = field(default_factory=list)
|
||||||
|
contract_id: str | None = None
|
||||||
|
|
||||||
|
def to_dict(self) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"ready": self.ready,
|
||||||
|
"reason_codes": self.reason_codes,
|
||||||
|
"contractId": self.contract_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
if self.ready:
|
||||||
|
return f"READY — contract {self.contract_id} passes submission-readiness gate"
|
||||||
|
codes = "; ".join(self.reason_codes) if self.reason_codes else "unknown"
|
||||||
|
return f"NOT READY — contract {self.contract_id}: {codes}"
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_contract_schema(contract: dict[str, Any]) -> list[str]:
|
||||||
|
"""Validate the contract against contract.schema.json (the shape).
|
||||||
|
Returns a list of reason codes (empty if valid). Falls back to no-op
|
||||||
|
if jsonschema or the schema file is unavailable (the contract is
|
||||||
|
validated upstream by run_platform.sh in the normal path).
|
||||||
|
"""
|
||||||
|
codes: list[str] = []
|
||||||
|
try:
|
||||||
|
import jsonschema
|
||||||
|
|
||||||
|
schema_path = os.path.join(_SCHEMA_DIR, "contract.schema.json")
|
||||||
|
with open(schema_path) as f:
|
||||||
|
schema = json.load(f)
|
||||||
|
jsonschema.validate(instance=contract, schema=schema)
|
||||||
|
except (OSError, ImportError):
|
||||||
|
pass
|
||||||
|
except jsonschema.ValidationError as e:
|
||||||
|
codes.append(f"CONTRACT_SCHEMA_INVALID:{e.message}")
|
||||||
|
return codes
|
||||||
|
|
||||||
|
|
||||||
|
def _get_nested(data: dict[str, Any], dotted_key: str) -> Any:
|
||||||
|
parts = dotted_key.split(".")
|
||||||
|
val: Any = data
|
||||||
|
for p in parts:
|
||||||
|
if not isinstance(val, dict) or p not in val:
|
||||||
|
return None
|
||||||
|
val = val[p]
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
def check_readiness(submission: dict[str, Any]) -> ReadinessResult:
|
||||||
|
"""Run the full submission-readiness gate.
|
||||||
|
|
||||||
|
1. Validate the contract shape (contract.schema.json).
|
||||||
|
2. Validate the readiness schema (submission-readiness.schema.json).
|
||||||
|
3. Run the semantic readiness checks (tags, env mandatory, agentic, appSource, policy).
|
||||||
|
|
||||||
|
Returns a ReadinessResult. Never raises — all failures are reason codes.
|
||||||
|
"""
|
||||||
|
contract_id = submission.get("contractId") or submission.get("id", "unknown")
|
||||||
|
codes: list[str] = []
|
||||||
|
|
||||||
|
# Step 1: contract shape validation
|
||||||
|
contract_shape = {k: v for k, v in submission.items() if k in ("id", "name", "environment", "infrastructure")}
|
||||||
|
if contract_shape:
|
||||||
|
codes.extend(_validate_contract_schema(contract_shape))
|
||||||
|
|
||||||
|
# Step 2: readiness schema validation
|
||||||
|
try:
|
||||||
|
import jsonschema
|
||||||
|
|
||||||
|
schema_path = os.path.join(_SCHEMA_DIR, "submission-readiness.schema.json")
|
||||||
|
with open(schema_path) as f:
|
||||||
|
readiness_schema = json.load(f)
|
||||||
|
jsonschema.validate(instance=submission, schema=readiness_schema)
|
||||||
|
except (OSError, ImportError):
|
||||||
|
pass
|
||||||
|
except jsonschema.ValidationError as e:
|
||||||
|
codes.append(f"READINESS_SCHEMA_INVALID:{e.message}")
|
||||||
|
|
||||||
|
# Step 3: semantic checks (reason codes for citizen-developer-facing errors)
|
||||||
|
|
||||||
|
# 3a: tags
|
||||||
|
tags = submission.get("tags", {})
|
||||||
|
missing_tags = [t for t in REQUIRED_TAGS if t not in tags or not tags[t]]
|
||||||
|
if missing_tags:
|
||||||
|
codes.append(f"MISSING_TAGS:{','.join(missing_tags)}")
|
||||||
|
|
||||||
|
# 3b: env mandatory (W3.E per-env table)
|
||||||
|
env = submission.get("environment")
|
||||||
|
if env and env in ENV_MANDATORY:
|
||||||
|
for field_key in ENV_MANDATORY[env]:
|
||||||
|
val = _get_nested(submission, field_key)
|
||||||
|
if val is None:
|
||||||
|
codes.append(f"ENV_MISSING_MANDATORY:{env}:{field_key}")
|
||||||
|
|
||||||
|
# 3c: agentic profile markers
|
||||||
|
if submission.get("profile") == "agentic":
|
||||||
|
for marker in AGENTIC_REQUIRED:
|
||||||
|
if not submission.get(marker):
|
||||||
|
codes.append(f"AGENTIC_MISSING_INTENT:{marker}")
|
||||||
|
|
||||||
|
# 3d: appSource
|
||||||
|
app_source = submission.get("appSource")
|
||||||
|
if not app_source or not app_source.get("repo") or not app_source.get("ref"):
|
||||||
|
codes.append("MISSING_APP_SOURCE")
|
||||||
|
|
||||||
|
# 3e: policy preconditions (warn if declared but not enforced this milestone)
|
||||||
|
policy = submission.get("policyPreconditions", {})
|
||||||
|
if not policy:
|
||||||
|
codes.append("POLICY_PRECONDITION_MISSING")
|
||||||
|
|
||||||
|
ready = len(codes) == 0
|
||||||
|
return ReadinessResult(ready=ready, reason_codes=codes, contract_id=contract_id)
|
||||||
|
|
||||||
|
|
||||||
|
def cli_main(argv: list[str]) -> int:
|
||||||
|
"""CLI entry: python3 -m core.submission_readiness <contract.json>
|
||||||
|
|
||||||
|
Also invoked via contract_ingestor.py --check-readiness (D-133).
|
||||||
|
Prints the ReadinessResult to stdout; exits 0 if ready, 1 if not.
|
||||||
|
"""
|
||||||
|
if len(argv) < 2:
|
||||||
|
print("Usage: submission_readiness <contract.json>", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
path = argv[1]
|
||||||
|
try:
|
||||||
|
with open(path) as f:
|
||||||
|
submission = json.load(f)
|
||||||
|
except (OSError, json.JSONDecodeError) as e:
|
||||||
|
print(f"ERROR: cannot read {path}: {e}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
result = check_readiness(submission)
|
||||||
|
print(result)
|
||||||
|
print(json.dumps(result.to_dict(), indent=2))
|
||||||
|
return 0 if result.ready else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(cli_main(sys.argv))
|
||||||
@@ -34,7 +34,7 @@ style: |
|
|||||||
|
|
||||||
**Shifting from Operational Overhead to Strategic Value**
|
**Shifting from Operational Overhead to Strategic Value**
|
||||||
|
|
||||||
v1.17 — Strategic Direction, Leadership Metrics & Unified Story
|
v1.18 — Citizen Developer & Production-Grade Guidance
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ v1.17 — Strategic Direction, Leadership Metrics & Unified Story
|
|||||||
2. **Vision** — Nova's strategic direction (NORTH_STAR)
|
2. **Vision** — Nova's strategic direction (NORTH_STAR)
|
||||||
3. **How** — the pipeline, Decision Ledger, attestation gates
|
3. **How** — the pipeline, Decision Ledger, attestation gates
|
||||||
4. **Proof** — grounded metrics that make the claim defensible
|
4. **Proof** — grounded metrics that make the claim defensible
|
||||||
5. **Roadmap** — deferred metrics with unblock paths + the ask
|
5. **Roadmap** — deferred metrics with unblock paths + the ask + scope + RACI
|
||||||
|
|
||||||
**Benefit:** you leave knowing which claims are proven today, which are pipeline-ready, and which are deferred with a documented unblock path — no marketing, just grounded evidence.
|
**Benefit:** you leave knowing which claims are proven today, which are pipeline-ready, and which are deferred with a documented unblock path — no marketing, just grounded evidence.
|
||||||
|
|
||||||
@@ -301,6 +301,42 @@ From `docs/METRICS_DEFERRED_ROADMAP.md`.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Slide 17 — Scope: Downstream of PDLC
|
||||||
|
|
||||||
|
**Nova governs infrastructure + delivery. The PDLC (product backlog, code authorship, IDE) is upstream — Nova never penetrates it.**
|
||||||
|
|
||||||
|
- **The PDLC is upstream:** product backlog, code authorship (AI agent / IDE / agentic SDLC), sprint planning, application business logic
|
||||||
|
- **Nova is downstream:** contract ingestion → submission-readiness gate → policy → cloud lifecycle → environment progression → audit + attestation
|
||||||
|
- **Integration is only through the contract boundary:** the citizen developer's AI coding agent, an upstream agentic SDLC, or any dev platform may all produce submissions — the source does not matter as all are subject to the same compliance standards
|
||||||
|
- Nova validates the submission, not the author
|
||||||
|
- Cites `docs/scope.md` + `PROJECT.md` § Scope
|
||||||
|
|
||||||
|
**Benefit:** you now know the scope boundary — Nova is purpose-built for infrastructure operations, not product development; integration is through one validated contract.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slide 18 — RACI: Who Owns What
|
||||||
|
|
||||||
|
**Three roles, one matrix — the citizen developer owns FRs + UAT, the platform owns NFRs + infra + QA + prod deploy, release management is co-owned.**
|
||||||
|
|
||||||
|
| Work Category | Citizen Dev | Platform | Release Mgmt |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Functional Requirements (FRs) | **R/A** | C | I |
|
||||||
|
| User Acceptance Testing (UAT) | **R/A** | C | I |
|
||||||
|
| Non-Functional Requirements (NFRs) | I | **R/A** | C |
|
||||||
|
| Infrastructure (cloud, state, IAM) | I | **R/A** | C |
|
||||||
|
| QA (policy, confidence, schema) | C | **R/A** | I |
|
||||||
|
| Production deployment to cloud | I | **R/A** | C |
|
||||||
|
| Release attestation (QA + SRE) | **A** | R | **R** |
|
||||||
|
|
||||||
|
- **Compliance-standard equivalence:** FRs + UAT may come from any upstream source (AI agent, agentic SDLC, dev platform) — all pass the same submission-readiness gate
|
||||||
|
- **Release co-ownership:** the platform runs the attestations agentically; the citizen developer oversees and triggers the actual release (human at the stage gate)
|
||||||
|
- Cites `docs/raci.md` + `PROJECT.md` § RACI Matrix
|
||||||
|
|
||||||
|
**Benefit:** you now know exactly what you bring (FRs + UAT), what Nova provides (NFRs + infra + QA + prod deploy), and what you co-own (the release attestation).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
<!-- _class: title -->
|
<!-- _class: title -->
|
||||||
<!-- _paginate: false -->
|
<!-- _paginate: false -->
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,20 @@
|
|||||||
- "Pipeline-ready" → "production-proven" is the value proposition
|
- "Pipeline-ready" → "production-proven" is the value proposition
|
||||||
- **Key takeaway:** approve a pilot + the ledger build-out to move from pipeline-ready to production-proven
|
- **Key takeaway:** approve a pilot + the ledger build-out to move from pipeline-ready to production-proven
|
||||||
|
|
||||||
|
### Slide 17 — Scope: Downstream of PDLC
|
||||||
|
- Nova governs infra + delivery only; the PDLC (product backlog, code authorship, IDE) is upstream
|
||||||
|
- Integration is only through the validated contract boundary
|
||||||
|
- Any upstream source (AI agent, agentic SDLC, dev platform) may produce submissions — all subject to the same compliance standards
|
||||||
|
- Nova validates the submission, not the author
|
||||||
|
- **Key takeaway:** Nova is purpose-built for infrastructure operations, not product development; the scope boundary is clean
|
||||||
|
|
||||||
|
### Slide 18 — RACI: Who Owns What
|
||||||
|
- Citizen Developer owns FRs + UAT (via any upstream source — AI agent, SDLC, dev platform — all pass the same gate)
|
||||||
|
- Platform owns NFRs + infra + QA + prod deploy
|
||||||
|
- Release Management is co-owned: platform runs attestations agentically, citizen developer oversees + triggers the release (human at stage gate)
|
||||||
|
- The compliance-standard equivalence is the key: the source does not matter; the submission does
|
||||||
|
- **Key takeaway:** you bring FRs + UAT; Nova provides NFRs + infra + QA + prod deploy; the release is co-owned with you at the stage gate
|
||||||
|
|
||||||
### Appendix A1 — Metrics Glossary
|
### Appendix A1 — Metrics Glossary
|
||||||
- Reference for every metric mentioned in the deck
|
- Reference for every metric mentioned in the deck
|
||||||
- Use if the audience asks "what does X mean?"
|
- Use if the audience asks "what does X mean?"
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
|
|
||||||
<h1 id="nova--the-no-humans-infrastructure-platform">Nova — The No-Humans Infrastructure Platform</h1>
|
<h1 id="nova--the-no-humans-infrastructure-platform">Nova — The No-Humans Infrastructure Platform</h1>
|
||||||
<p><strong>Shifting from Operational Overhead to Strategic Value</strong></p>
|
<p><strong>Shifting from Operational Overhead to Strategic Value</strong></p>
|
||||||
<p>v1.17 — Strategic Direction, Leadership Metrics & Unified Story</p>
|
<p>v1.18 — Citizen Developer & Production-Grade Guidance</p>
|
||||||
<footer>Act %{page}/5 — v1.17</footer>
|
<footer>Act %{page}/5 — v1.17</footer>
|
||||||
</section>
|
</section>
|
||||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="2" data-paginate="true" data-header="Nova — The No-Humans Infrastructure Platform" data-footer="Act %{page}/5 — v1.17" data-theme="default" data-style="section {
|
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="2" data-paginate="true" data-header="Nova — The No-Humans Infrastructure Platform" data-footer="Act %{page}/5 — v1.17" data-theme="default" data-style="section {
|
||||||
@@ -92,7 +92,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-1--arc-preview">Slide 1 — Arc Preview</h2>
|
<h2 id="slide-1--arc-preview">Slide 1 — Arc Preview</h2>
|
||||||
<p><strong>This deck proves Nova is the no-humans infrastructure platform — and shows you the metrics that make the claim defensible.</strong></p>
|
<p><strong>This deck proves Nova is the no-humans infrastructure platform — and shows you the metrics that make the claim defensible.</strong></p>
|
||||||
@@ -103,7 +103,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
<li><strong>Vision</strong> — Nova's strategic direction (NORTH_STAR)</li>
|
<li><strong>Vision</strong> — Nova's strategic direction (NORTH_STAR)</li>
|
||||||
<li><strong>How</strong> — the pipeline, Decision Ledger, attestation gates</li>
|
<li><strong>How</strong> — the pipeline, Decision Ledger, attestation gates</li>
|
||||||
<li><strong>Proof</strong> — grounded metrics that make the claim defensible</li>
|
<li><strong>Proof</strong> — grounded metrics that make the claim defensible</li>
|
||||||
<li><strong>Roadmap</strong> — deferred metrics with unblock paths + the ask</li>
|
<li><strong>Roadmap</strong> — deferred metrics with unblock paths + the ask + scope + RACI</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p><strong>Benefit:</strong> you leave knowing which claims are proven today, which are pipeline-ready, and which are deferred with a documented unblock path — no marketing, just grounded evidence.</p>
|
<p><strong>Benefit:</strong> you leave knowing which claims are proven today, which are pipeline-ready, and which are deferred with a documented unblock path — no marketing, just grounded evidence.</p>
|
||||||
<footer>Act %{page}/5 — v1.17</footer>
|
<footer>Act %{page}/5 — v1.17</footer>
|
||||||
@@ -146,7 +146,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-2--the-no-humans-imperative">Slide 2 — The No-Humans Imperative</h2>
|
<h2 id="slide-2--the-no-humans-imperative">Slide 2 — The No-Humans Imperative</h2>
|
||||||
<p><strong>Why the operator is the bottleneck — and why removing them from operations (not accountability) is the imperative.</strong></p>
|
<p><strong>Why the operator is the bottleneck — and why removing them from operations (not accountability) is the imperative.</strong></p>
|
||||||
@@ -197,7 +197,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-3--novas-vision">Slide 3 — Nova's Vision</h2>
|
<h2 id="slide-3--novas-vision">Slide 3 — Nova's Vision</h2>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
@@ -248,7 +248,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-4--strategic-objectives--anti-goals">Slide 4 — Strategic Objectives + Anti-Goals</h2>
|
<h2 id="slide-4--strategic-objectives--anti-goals">Slide 4 — Strategic Objectives + Anti-Goals</h2>
|
||||||
<p><strong>4 Strategic Objectives:</strong></p>
|
<p><strong>4 Strategic Objectives:</strong></p>
|
||||||
@@ -307,7 +307,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-5--12%E2%80%9318-month-targets">Slide 5 — 12–18 Month Targets</h2>
|
<h2 id="slide-5--12%E2%80%9318-month-targets">Slide 5 — 12–18 Month Targets</h2>
|
||||||
<p><strong>Current-milestone targets (grounded/derived):</strong></p>
|
<p><strong>Current-milestone targets (grounded/derived):</strong></p>
|
||||||
@@ -421,7 +421,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-6--the-platform-pipeline">Slide 6 — The Platform Pipeline</h2>
|
<h2 id="slide-6--the-platform-pipeline">Slide 6 — The Platform Pipeline</h2>
|
||||||
<p><strong>How intent becomes verified infrastructure without an operator.</strong></p>
|
<p><strong>How intent becomes verified infrastructure without an operator.</strong></p>
|
||||||
@@ -472,7 +472,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-7--the-decision-ledger">Slide 7 — The Decision Ledger</h2>
|
<h2 id="slide-7--the-decision-ledger">Slide 7 — The Decision Ledger</h2>
|
||||||
<p><strong>Every AI decision captured with confidence, alternatives, and outcome.</strong></p>
|
<p><strong>Every AI decision captured with confidence, alternatives, and outcome.</strong></p>
|
||||||
@@ -524,7 +524,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-8--the-8-concern-attestation-matrix">Slide 8 — The 8-Concern Attestation Matrix</h2>
|
<h2 id="slide-8--the-8-concern-attestation-matrix">Slide 8 — The 8-Concern Attestation Matrix</h2>
|
||||||
<p><strong>Designed controls that keep humans at stage gates.</strong></p>
|
<p><strong>Designed controls that keep humans at stage gates.</strong></p>
|
||||||
@@ -634,7 +634,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-9--telemetry-architecture">Slide 9 — Telemetry Architecture</h2>
|
<h2 id="slide-9--telemetry-architecture">Slide 9 — Telemetry Architecture</h2>
|
||||||
<p><strong>How Nova instruments itself — CloudEvents envelope, cold store, PowerBI export.</strong></p>
|
<p><strong>How Nova instruments itself — CloudEvents envelope, cold store, PowerBI export.</strong></p>
|
||||||
@@ -684,7 +684,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-10--capability-health--confidence-distribution">Slide 10 — Capability Health + Confidence Distribution</h2>
|
<h2 id="slide-10--capability-health--confidence-distribution">Slide 10 — Capability Health + Confidence Distribution</h2>
|
||||||
<p><strong>Grounded proof: capability health and confidence distribution from real runs.</strong></p>
|
<p><strong>Grounded proof: capability health and confidence distribution from real runs.</strong></p>
|
||||||
@@ -759,7 +759,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-11--decision-ledger--attestation-coverage">Slide 11 — Decision Ledger + Attestation Coverage</h2>
|
<h2 id="slide-11--decision-ledger--attestation-coverage">Slide 11 — Decision Ledger + Attestation Coverage</h2>
|
||||||
<p><strong>Trust metrics — both 100%.</strong></p>
|
<p><strong>Trust metrics — both 100%.</strong></p>
|
||||||
@@ -811,7 +811,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-12--zero-touch-efficiency">Slide 12 — Zero-Touch Efficiency</h2>
|
<h2 id="slide-12--zero-touch-efficiency">Slide 12 — Zero-Touch Efficiency</h2>
|
||||||
<p><strong>Touchless resolution, human escalation, and MTTR.</strong></p>
|
<p><strong>Touchless resolution, human escalation, and MTTR.</strong></p>
|
||||||
@@ -862,7 +862,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-13--cost--roi">Slide 13 — Cost & ROI</h2>
|
<h2 id="slide-13--cost--roi">Slide 13 — Cost & ROI</h2>
|
||||||
<p><strong>Cost estimates and the ROI formula — with honest caveats.</strong></p>
|
<p><strong>Cost estimates and the ROI formula — with honest caveats.</strong></p>
|
||||||
@@ -913,7 +913,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-14--whats-deferred--and-why">Slide 14 — What's Deferred — and Why</h2>
|
<h2 id="slide-14--whats-deferred--and-why">Slide 14 — What's Deferred — and Why</h2>
|
||||||
<p><strong>Honesty about what isn't measured yet.</strong></p>
|
<p><strong>Honesty about what isn't measured yet.</strong></p>
|
||||||
@@ -1010,7 +1010,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-15--roadmap-to-the-north-star">Slide 15 — Roadmap to the North Star</h2>
|
<h2 id="slide-15--roadmap-to-the-north-star">Slide 15 — Roadmap to the North Star</h2>
|
||||||
<p><strong>The path from v1.17's grounded metrics to the 12–18 month targets.</strong></p>
|
<p><strong>The path from v1.17's grounded metrics to the 12–18 month targets.</strong></p>
|
||||||
@@ -1061,7 +1061,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
}
|
}
|
||||||
.badge.today { background: #c6f6d5; color: #22543d; }
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
.badge.planned { background: #fef3c7; color: #78350f; }
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
;" data-marpit-pagination-total="19">
|
;" data-marpit-pagination-total="21">
|
||||||
<header>Nova — The No-Humans Infrastructure Platform</header>
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
<h2 id="slide-16--recap--ask">Slide 16 — Recap + Ask</h2>
|
<h2 id="slide-16--recap--ask">Slide 16 — Recap + Ask</h2>
|
||||||
<p><strong>The 5-act recap + the business decision.</strong></p>
|
<p><strong>The 5-act recap + the business decision.</strong></p>
|
||||||
@@ -1077,7 +1077,163 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
<p><strong>Benefit:</strong> you leave with a clear business decision to make — approve a pilot + the ledger build-out — and the confidence that every claim in this deck is grounded, derived, or honestly deferred.</p>
|
<p><strong>Benefit:</strong> you leave with a clear business decision to make — approve a pilot + the ledger build-out — and the confidence that every claim in this deck is grounded, derived, or honestly deferred.</p>
|
||||||
<footer>Act %{page}/5 — v1.17</footer>
|
<footer>Act %{page}/5 — v1.17</footer>
|
||||||
</section>
|
</section>
|
||||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="18" data-header="Nova — The No-Humans Infrastructure Platform" data-footer="Act %{page}/5 — v1.17" data-class="title" data-theme="default" data-style="section {
|
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="18" data-paginate="true" data-header="Nova — The No-Humans Infrastructure Platform" data-footer="Act %{page}/5 — v1.17" data-theme="default" data-style="section {
|
||||||
|
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||||
|
font-size: 22px;
|
||||||
|
color: #1B1B1B;
|
||||||
|
}
|
||||||
|
h1 { color: #D6002A; font-size: 34px; margin-bottom: 0.3em; }
|
||||||
|
h2 { color: #D6002A; font-size: 26px; margin-bottom: 0.2em; }
|
||||||
|
section.title { background: #1B1B1B; color: #fff; border-top: 8px solid #D6002A; }
|
||||||
|
section.title h1 { color: #fff; }
|
||||||
|
table { font-size: 18px; width: 100%; }
|
||||||
|
th { background: #F0F0F0; }
|
||||||
|
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 20px; }
|
||||||
|
img { display: block; margin: 0 auto; max-height: 320px; }
|
||||||
|
.badge {
|
||||||
|
display: inline-block; padding: 2px 8px; border-radius: 4px;
|
||||||
|
font-size: 14px; font-weight: 600;
|
||||||
|
}
|
||||||
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
|
" lang="C" data-marpit-pagination="18" style="--paginate:true;--header:Nova — The No-Humans Infrastructure Platform;--footer:Act %{page}/5 — v1.17;--theme:default;--style:section {
|
||||||
|
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||||
|
font-size: 22px;
|
||||||
|
color: #1B1B1B;
|
||||||
|
}
|
||||||
|
h1 { color: #D6002A; font-size: 34px; margin-bottom: 0.3em; }
|
||||||
|
h2 { color: #D6002A; font-size: 26px; margin-bottom: 0.2em; }
|
||||||
|
section.title { background: #1B1B1B; color: #fff; border-top: 8px solid #D6002A; }
|
||||||
|
section.title h1 { color: #fff; }
|
||||||
|
table { font-size: 18px; width: 100%; }
|
||||||
|
th { background: #F0F0F0; }
|
||||||
|
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 20px; }
|
||||||
|
img { display: block; margin: 0 auto; max-height: 320px; }
|
||||||
|
.badge {
|
||||||
|
display: inline-block; padding: 2px 8px; border-radius: 4px;
|
||||||
|
font-size: 14px; font-weight: 600;
|
||||||
|
}
|
||||||
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
|
;" data-marpit-pagination-total="21">
|
||||||
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
|
<h2 id="slide-17--scope-downstream-of-pdlc">Slide 17 — Scope: Downstream of PDLC</h2>
|
||||||
|
<p><strong>Nova governs infrastructure + delivery. The PDLC (product backlog, code authorship, IDE) is upstream — Nova never penetrates it.</strong></p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>The PDLC is upstream:</strong> product backlog, code authorship (AI agent / IDE / agentic SDLC), sprint planning, application business logic</li>
|
||||||
|
<li><strong>Nova is downstream:</strong> contract ingestion → submission-readiness gate → policy → cloud lifecycle → environment progression → audit + attestation</li>
|
||||||
|
<li><strong>Integration is only through the contract boundary:</strong> the citizen developer's AI coding agent, an upstream agentic SDLC, or any dev platform may all produce submissions — the source does not matter as all are subject to the same compliance standards</li>
|
||||||
|
<li>Nova validates the submission, not the author</li>
|
||||||
|
<li>Cites <code>docs/scope.md</code> + <code>PROJECT.md</code> § Scope</li>
|
||||||
|
</ul>
|
||||||
|
<p><strong>Benefit:</strong> you now know the scope boundary — Nova is purpose-built for infrastructure operations, not product development; integration is through one validated contract.</p>
|
||||||
|
<footer>Act %{page}/5 — v1.17</footer>
|
||||||
|
</section>
|
||||||
|
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="19" data-paginate="true" data-header="Nova — The No-Humans Infrastructure Platform" data-footer="Act %{page}/5 — v1.17" data-theme="default" data-style="section {
|
||||||
|
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||||
|
font-size: 22px;
|
||||||
|
color: #1B1B1B;
|
||||||
|
}
|
||||||
|
h1 { color: #D6002A; font-size: 34px; margin-bottom: 0.3em; }
|
||||||
|
h2 { color: #D6002A; font-size: 26px; margin-bottom: 0.2em; }
|
||||||
|
section.title { background: #1B1B1B; color: #fff; border-top: 8px solid #D6002A; }
|
||||||
|
section.title h1 { color: #fff; }
|
||||||
|
table { font-size: 18px; width: 100%; }
|
||||||
|
th { background: #F0F0F0; }
|
||||||
|
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 20px; }
|
||||||
|
img { display: block; margin: 0 auto; max-height: 320px; }
|
||||||
|
.badge {
|
||||||
|
display: inline-block; padding: 2px 8px; border-radius: 4px;
|
||||||
|
font-size: 14px; font-weight: 600;
|
||||||
|
}
|
||||||
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
|
" lang="C" data-marpit-pagination="19" style="--paginate:true;--header:Nova — The No-Humans Infrastructure Platform;--footer:Act %{page}/5 — v1.17;--theme:default;--style:section {
|
||||||
|
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||||
|
font-size: 22px;
|
||||||
|
color: #1B1B1B;
|
||||||
|
}
|
||||||
|
h1 { color: #D6002A; font-size: 34px; margin-bottom: 0.3em; }
|
||||||
|
h2 { color: #D6002A; font-size: 26px; margin-bottom: 0.2em; }
|
||||||
|
section.title { background: #1B1B1B; color: #fff; border-top: 8px solid #D6002A; }
|
||||||
|
section.title h1 { color: #fff; }
|
||||||
|
table { font-size: 18px; width: 100%; }
|
||||||
|
th { background: #F0F0F0; }
|
||||||
|
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 20px; }
|
||||||
|
img { display: block; margin: 0 auto; max-height: 320px; }
|
||||||
|
.badge {
|
||||||
|
display: inline-block; padding: 2px 8px; border-radius: 4px;
|
||||||
|
font-size: 14px; font-weight: 600;
|
||||||
|
}
|
||||||
|
.badge.today { background: #c6f6d5; color: #22543d; }
|
||||||
|
.badge.planned { background: #fef3c7; color: #78350f; }
|
||||||
|
;" data-marpit-pagination-total="21">
|
||||||
|
<header>Nova — The No-Humans Infrastructure Platform</header>
|
||||||
|
<h2 id="slide-18--raci-who-owns-what">Slide 18 — RACI: Who Owns What</h2>
|
||||||
|
<p><strong>Three roles, one matrix — the citizen developer owns FRs + UAT, the platform owns NFRs + infra + QA + prod deploy, release management is co-owned.</strong></p>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Work Category</th>
|
||||||
|
<th>Citizen Dev</th>
|
||||||
|
<th>Platform</th>
|
||||||
|
<th>Release Mgmt</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Functional Requirements (FRs)</td>
|
||||||
|
<td><strong>R/A</strong></td>
|
||||||
|
<td>C</td>
|
||||||
|
<td>I</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>User Acceptance Testing (UAT)</td>
|
||||||
|
<td><strong>R/A</strong></td>
|
||||||
|
<td>C</td>
|
||||||
|
<td>I</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Non-Functional Requirements (NFRs)</td>
|
||||||
|
<td>I</td>
|
||||||
|
<td><strong>R/A</strong></td>
|
||||||
|
<td>C</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Infrastructure (cloud, state, IAM)</td>
|
||||||
|
<td>I</td>
|
||||||
|
<td><strong>R/A</strong></td>
|
||||||
|
<td>C</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>QA (policy, confidence, schema)</td>
|
||||||
|
<td>C</td>
|
||||||
|
<td><strong>R/A</strong></td>
|
||||||
|
<td>I</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Production deployment to cloud</td>
|
||||||
|
<td>I</td>
|
||||||
|
<td><strong>R/A</strong></td>
|
||||||
|
<td>C</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Release attestation (QA + SRE)</td>
|
||||||
|
<td><strong>A</strong></td>
|
||||||
|
<td>R</td>
|
||||||
|
<td><strong>R</strong></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Compliance-standard equivalence:</strong> FRs + UAT may come from any upstream source (AI agent, agentic SDLC, dev platform) — all pass the same submission-readiness gate</li>
|
||||||
|
<li><strong>Release co-ownership:</strong> the platform runs the attestations agentically; the citizen developer oversees and triggers the actual release (human at the stage gate)</li>
|
||||||
|
<li>Cites <code>docs/raci.md</code> + <code>PROJECT.md</code> § RACI Matrix</li>
|
||||||
|
</ul>
|
||||||
|
<p><strong>Benefit:</strong> you now know exactly what you bring (FRs + UAT), what Nova provides (NFRs + infra + QA + prod deploy), and what you co-own (the release attestation).</p>
|
||||||
|
<footer>Act %{page}/5 — v1.17</footer>
|
||||||
|
</section>
|
||||||
|
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="20" data-header="Nova — The No-Humans Infrastructure Platform" data-footer="Act %{page}/5 — v1.17" data-class="title" data-theme="default" data-style="section {
|
||||||
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
color: #1B1B1B;
|
color: #1B1B1B;
|
||||||
@@ -1197,7 +1353,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
|
|||||||
</table>
|
</table>
|
||||||
<footer>Act %{page}/5 — v1.17</footer>
|
<footer>Act %{page}/5 — v1.17</footer>
|
||||||
</section>
|
</section>
|
||||||
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="19" data-header="Nova — The No-Humans Infrastructure Platform" data-footer="Act %{page}/5 — v1.17" data-class="title" data-theme="default" data-style="section {
|
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="21" data-header="Nova — The No-Humans Infrastructure Platform" data-footer="Act %{page}/5 — v1.17" data-class="title" data-theme="default" data-style="section {
|
||||||
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
color: #1B1B1B;
|
color: #1B1B1B;
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,85 @@
|
|||||||
|
# RACI — Who Owns What
|
||||||
|
|
||||||
|
> **Source of truth:** `.ciagent/PROJECT.md` § RACI Matrix (v1.18, REQ-215,
|
||||||
|
> D-139). This page is the citizen-developer-facing copy.
|
||||||
|
|
||||||
|
Nova's delivery lifecycle has three roles. This page clarifies who owns
|
||||||
|
what — so the citizen developer knows what they bring, what the platform
|
||||||
|
provides, and what is co-owned.
|
||||||
|
|
||||||
|
## The Three Roles
|
||||||
|
|
||||||
|
### Citizen Developer (CD)
|
||||||
|
|
||||||
|
That's you — the consumer (technical developer L3A or non-technical L3B).
|
||||||
|
You are **Responsible** for all **Functional Requirements (FRs)** and
|
||||||
|
**User Acceptance Testing (UAT)**. You produce the FRs + UAT via your AI
|
||||||
|
coding agent, an upstream agentic SDLC platform, or any upstream
|
||||||
|
development platform. **The source does not matter** — all are subject
|
||||||
|
to the same compliance standards (the submission-readiness gate, the
|
||||||
|
contract schema, the policy envelope, the immutable audit stream). Nova
|
||||||
|
validates the submission, not the author.
|
||||||
|
|
||||||
|
### Platform (Nova)
|
||||||
|
|
||||||
|
Nova is **Responsible** for all **Non-Functional Requirements (NFRs)**,
|
||||||
|
**Infrastructure** (cloud resource lifecycle, state, IAM), **QA** (the
|
||||||
|
platform-side quality checks: policy enforcement, confidence scoring,
|
||||||
|
schema validation), and **Production deployments to cloud** (the apply
|
||||||
|
path, the pipeline, the release mechanics).
|
||||||
|
|
||||||
|
### Release Management (RM) — co-owned
|
||||||
|
|
||||||
|
The release is **co-owned**. The platform performs the QA + SRE
|
||||||
|
attestations agentically (it runs the confidence signal, the policy
|
||||||
|
checks, the separation-of-duties). The citizen developer **oversees and
|
||||||
|
triggers** the actual release — the human attestation at the stage gate
|
||||||
|
is your authorization. The platform runs the checks; you authorize the
|
||||||
|
promotion. This is the "autonomy in operations, human at stage gates"
|
||||||
|
model.
|
||||||
|
|
||||||
|
## The Matrix
|
||||||
|
|
||||||
|
| Work Category | Citizen Developer | Platform | Release Management |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Functional Requirements (FRs)** | **R/A** | C | I |
|
||||||
|
| **User Acceptance Testing (UAT)** | **R/A** | C | I |
|
||||||
|
| **Non-Functional Requirements (NFRs)** | I | **R/A** | C |
|
||||||
|
| **Infrastructure (cloud, state, IAM)** | I | **R/A** | C |
|
||||||
|
| **QA (policy, confidence, schema checks)** | C | **R/A** | I |
|
||||||
|
| **Production deployment to cloud** | I | **R/A** | C |
|
||||||
|
| **Release attestation (QA + SRE sign-off)** | **A** | R | **R** |
|
||||||
|
|
||||||
|
**Key:** **R** = Responsible (does the work) · **A** = Accountable (owns
|
||||||
|
the outcome, sign-off) · **C** = Consulted · **I** = Informed.
|
||||||
|
|
||||||
|
## What This Means in Practice
|
||||||
|
|
||||||
|
**You (Citizen Developer) bring:**
|
||||||
|
- Your application code + a contract that declares intent.
|
||||||
|
- Your FRs (what the application does).
|
||||||
|
- Your UAT (you accept the deployment when it meets your FRs).
|
||||||
|
|
||||||
|
**Nova (Platform) provides:**
|
||||||
|
- The NFRs (security, observability, compliance — baked into the
|
||||||
|
pipeline, not your concern).
|
||||||
|
- The infrastructure (cloud resources, state management, IAM scoping).
|
||||||
|
- The QA (policy enforcement, confidence scoring, schema validation).
|
||||||
|
- The production deployment (the apply path, the pipeline, the release).
|
||||||
|
|
||||||
|
**You co-own the release:**
|
||||||
|
- Nova runs the attestations (QA confidence, SRE operational readiness).
|
||||||
|
- You authorize the promotion at the stage gate. No promotion happens
|
||||||
|
without your recorded attestation.
|
||||||
|
|
||||||
|
## Compliance Standards Apply Equally
|
||||||
|
|
||||||
|
Your FRs + UAT may come from any source — an AI coding agent, an
|
||||||
|
agentic SDLC platform, or a traditional IDE. Nova does not
|
||||||
|
differentiate. All submissions pass through the same gate
|
||||||
|
(`schemas/submission-readiness.schema.json`): tags, environment
|
||||||
|
metadata, policy preconditions, profile markers. The compliance
|
||||||
|
standards are the same regardless of how the code was authored. This
|
||||||
|
is by design: the audit trail is the same, the policy envelope is the
|
||||||
|
same, the evidence stream is the same. The source does not matter; the
|
||||||
|
submission does.
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# Scope — Nova is Downstream of PDLC
|
||||||
|
|
||||||
|
> **Source of truth:** `.ciagent/PROJECT.md` § Scope (v1.18, REQ-216).
|
||||||
|
> This page is the citizen-developer-facing copy.
|
||||||
|
|
||||||
|
## The Boundary
|
||||||
|
|
||||||
|
The **Product Development Lifecycle (PDLC)** is **upstream** of Nova. The
|
||||||
|
PDLC includes:
|
||||||
|
|
||||||
|
- Product backlog / roadmap planning
|
||||||
|
- Code authorship (via AI coding agent, IDE, or agentic SDLC platform)
|
||||||
|
- Sprint planning / issue tracking
|
||||||
|
- Application business logic
|
||||||
|
- IDE workflows / developer experience
|
||||||
|
|
||||||
|
Nova never penetrates the PDLC. Nova's domain is **infrastructure +
|
||||||
|
delivery only**.
|
||||||
|
|
||||||
|
## What Nova Does
|
||||||
|
|
||||||
|
Nova governs the downstream half:
|
||||||
|
|
||||||
|
- **Contract ingestion** — the validated entry point
|
||||||
|
- **Submission-readiness gate** — what is acceptable to start
|
||||||
|
(`schemas/submission-readiness.schema.json`)
|
||||||
|
- **Policy enforcement** — the confidence signal, Checkov, tagging
|
||||||
|
- **Cloud resource lifecycle** — Terraform plan/apply, state, IAM
|
||||||
|
- **Environment progression** — dev (autonomous) → qa (QA attestation) →
|
||||||
|
prod (SRE attestation) → dr (SRE attestation)
|
||||||
|
- **Immutable audit + attestation** — the Decision Ledger, the evidence
|
||||||
|
stream, the HITL gates
|
||||||
|
|
||||||
|
## The Integration Point
|
||||||
|
|
||||||
|
Integration between the PDLC and Nova is **only** through the validated,
|
||||||
|
published contract boundary:
|
||||||
|
|
||||||
|
```
|
||||||
|
PDLC (upstream) Nova (downstream)
|
||||||
|
───────────────── ─────────────────
|
||||||
|
product backlog contract ingestion
|
||||||
|
code authorship (AI agent / IDE / SDLC) → submission-readiness gate
|
||||||
|
sprint planning → policy enforcement
|
||||||
|
application business logic → cloud resource lifecycle
|
||||||
|
→ environment progression (dev→qa→prod→dr)
|
||||||
|
→ immutable audit + attestation
|
||||||
|
```
|
||||||
|
|
||||||
|
The citizen developer's AI coding agent, an upstream agentic SDLC
|
||||||
|
platform, or any upstream development platform may all produce
|
||||||
|
submissions. **The source does not matter** — all are subject to the
|
||||||
|
same compliance standards. Nova validates the submission, not the
|
||||||
|
author.
|
||||||
|
|
||||||
|
## What Nova is Not
|
||||||
|
|
||||||
|
- Not an upstream development platform (no product backlogs, IDE, code
|
||||||
|
authorship).
|
||||||
|
- Not a general-purpose AI agent platform (autonomy is narrow, bounded
|
||||||
|
by policy envelopes).
|
||||||
|
- Not a legacy infrastructure bridge (no VMs/bare metal/OS).
|
||||||
|
- Not a permissive delivery highway (no escape hatches past confidence
|
||||||
|
or HITL).
|
||||||
|
- Not a mutable audit log (VCS history ≠ regulatory evidence).
|
||||||
|
|
||||||
|
These anti-goals (from `docs/vision.md` §7 and Core Tenet #2) are
|
||||||
|
promoted here from buried tenets to an unmissable scope statement.
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
# Submission Readiness — What is Acceptable to Start
|
||||||
|
|
||||||
|
> **Source of truth:** `schemas/submission-readiness.schema.json` (v1.18,
|
||||||
|
> REQ-217). The validator is `core/submission_readiness.py` (REQ-218),
|
||||||
|
> invoked as `python3 -m core.lambda.contract_ingestor --check-readiness
|
||||||
|
> <submission.json>` (D-133).
|
||||||
|
|
||||||
|
Nova's submission-readiness gate defines what is **acceptable to start**.
|
||||||
|
It is a superset gate *above* contract-schema validity: the contract schema
|
||||||
|
(`schemas/contract.schema.json`) defines the **shape** (id / name /
|
||||||
|
environment / infrastructure); the readiness schema defines the **gate**
|
||||||
|
(tags, per-env mandatory metadata, policy preconditions, profile markers,
|
||||||
|
appSource). Both must pass before ingestion proceeds.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
```
|
||||||
|
citizen developer submits
|
||||||
|
↓
|
||||||
|
contract.schema.json validation (shape) ← the existing check
|
||||||
|
↓
|
||||||
|
submission-readiness.schema.json (gate) ← the new check
|
||||||
|
├── contractId present (non-empty)
|
||||||
|
├── environment valid (dev/qa/prod/dr)
|
||||||
|
├── tags: all 5 Nova tags present (D-054)
|
||||||
|
├── policyPreconditions declared
|
||||||
|
├── profile: developer or agentic
|
||||||
|
│ └── if agentic: naturalLanguageIntent + confidenceAtSubmission + agentTrace
|
||||||
|
├── appSource: repo + ref (for runtime fetch)
|
||||||
|
└── per-env mandatory (W3.E):
|
||||||
|
dev → stack + environment
|
||||||
|
qa → + validation.e2eSuite + validation.loadTest
|
||||||
|
prod → + runbook + dashboard + oncall
|
||||||
|
dr → + drDrillRef
|
||||||
|
↓
|
||||||
|
ready → proceed to contract ingestion
|
||||||
|
not ready → reject with citizen-developer-facing error (reason code)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reason Codes
|
||||||
|
|
||||||
|
When a submission is not ready, the validator returns one or more reason
|
||||||
|
codes. These are citizen-developer-facing — no stack traces.
|
||||||
|
|
||||||
|
| Code | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| `MISSING_TAGS:<tag1>,<tag2>` | One or more required Nova tags are absent |
|
||||||
|
| `ENV_MISSING_MANDATORY:<env>:<field>` | A per-env mandatory field (W3.E) is missing |
|
||||||
|
| `AGENTIC_MISSING_INTENT:<marker>` | profile=agentic but a required marker is absent |
|
||||||
|
| `MISSING_APP_SOURCE` | appSource (repo + ref) is missing |
|
||||||
|
| `POLICY_PRECONDITION_MISSING` | No policy preconditions declared |
|
||||||
|
| `CONTRACT_SCHEMA_INVALID:<detail>` | The contract shape failed contract.schema.json |
|
||||||
|
| `READINESS_SCHEMA_INVALID:<detail>` | The submission failed the readiness schema |
|
||||||
|
|
||||||
|
## Good Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"contractId": "uuid-1234",
|
||||||
|
"id": "webapi",
|
||||||
|
"name": "Customer Web API",
|
||||||
|
"environment": "dev",
|
||||||
|
"tags": {
|
||||||
|
"nova:owner": "consumer-repo",
|
||||||
|
"nova:contract": "uuid-1234",
|
||||||
|
"nova:environment": "dev",
|
||||||
|
"nova:cost-center": "nova-default",
|
||||||
|
"nova:ref": "CHG0678912"
|
||||||
|
},
|
||||||
|
"policyPreconditions": {
|
||||||
|
"public-ingress": false,
|
||||||
|
"encryption_enabled": true,
|
||||||
|
"deletion_protection": true
|
||||||
|
},
|
||||||
|
"profile": "developer",
|
||||||
|
"appSource": {
|
||||||
|
"repo": "consumer/web-api",
|
||||||
|
"ref": "main"
|
||||||
|
},
|
||||||
|
"infrastructure": {
|
||||||
|
"static-assets": {
|
||||||
|
"inputs": {
|
||||||
|
"bucket_name": "webapi-assets"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: **READY** — passes the shape + the gate.
|
||||||
|
|
||||||
|
## Rejected Examples
|
||||||
|
|
||||||
|
### Missing Tags
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"contractId": "uuid-1234",
|
||||||
|
"environment": "dev",
|
||||||
|
"tags": {
|
||||||
|
"nova:owner": "consumer-repo"
|
||||||
|
},
|
||||||
|
"policyPreconditions": {"public-ingress": false},
|
||||||
|
"profile": "developer",
|
||||||
|
"appSource": {"repo": "consumer/repo", "ref": "main"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: `NOT READY — MISSING_TAGS:nova:contract,nova:environment,nova:cost-center,nova:ref`
|
||||||
|
|
||||||
|
### Agentic Missing Intent
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"contractId": "uuid-1234",
|
||||||
|
"environment": "qa",
|
||||||
|
"tags": { "nova:owner": "x", "nova:contract": "x", "nova:environment": "qa", "nova:cost-center": "x", "nova:ref": "x" },
|
||||||
|
"policyPreconditions": {"public-ingress": false},
|
||||||
|
"profile": "agentic",
|
||||||
|
"appSource": {"repo": "x", "ref": "x"},
|
||||||
|
"validation": {"e2eSuite": true, "loadTest": true}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: `NOT READY — AGENTIC_MISSING_INTENT:naturalLanguageIntent; AGENTIC_MISSING_INTENT:confidenceAtSubmission; AGENTIC_MISSING_INTENT:agentTrace`
|
||||||
|
|
||||||
|
### Env Missing Mandatory (prod without runbook)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"contractId": "uuid-1234",
|
||||||
|
"environment": "prod",
|
||||||
|
"tags": { "nova:owner": "x", "nova:contract": "x", "nova:environment": "prod", "nova:cost-center": "x", "nova:ref": "x" },
|
||||||
|
"policyPreconditions": {"public-ingress": false},
|
||||||
|
"profile": "developer",
|
||||||
|
"appSource": {"repo": "x", "ref": "x"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: `NOT READY — ENV_MISSING_MANDATORY:prod:runbook; ENV_MISSING_MANDATORY:prod:dashboard; ENV_MISSING_MANDATORY:prod:oncall`
|
||||||
|
|
||||||
|
## Compliance-Standard Equivalence
|
||||||
|
|
||||||
|
The submission-readiness gate applies **equally** to all upstream sources.
|
||||||
|
Whether the citizen developer's submission originated from an AI coding
|
||||||
|
agent, an agentic SDLC platform, or a traditional development platform —
|
||||||
|
the same tags, the same env mandatory, the same policy preconditions, the
|
||||||
|
same profile markers are required. The source does not matter; the
|
||||||
|
submission does. This is the RACI compliance-standard equivalence note
|
||||||
|
(`docs/raci.md`) made machine-checkable.
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://nova.dev/schemas/submission-readiness.schema.json",
|
||||||
|
"title": "Nova Submission-Readiness Gate",
|
||||||
|
"description": "Defines what is acceptable to start — a superset gate ABOVE contract.schema.json validity. The contract schema defines the SHAPE (id/name/environment/infrastructure); this schema defines the READINESS gate: required Nova tags, per-env mandatory metadata (W3.E), declared policy preconditions, profile:agentic markers, and the appSource pointer. The validator (core/submission_readiness.py, REQ-218) calls contract.schema.json validation first, then these readiness checks. On fail → citizen-developer-facing error (not a stack trace); on pass → proceeds to existing contract ingestion.",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["contractId", "environment", "tags", "policyPreconditions", "profile", "appSource"],
|
||||||
|
"properties": {
|
||||||
|
"contractId": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
"description": "The contract identifier (UUID or operational id). Non-empty."
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["dev", "qa", "prod", "dr"],
|
||||||
|
"description": "Target environment. Determines the per-env mandatory fields (allOf below)."
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "The 5 required Nova tags (D-054). References schemas/tagging-standard.json.",
|
||||||
|
"required": ["nova:owner", "nova:contract", "nova:environment", "nova:cost-center", "nova:ref"],
|
||||||
|
"properties": {
|
||||||
|
"nova:owner": {"type": "string", "minLength": 1},
|
||||||
|
"nova:contract": {"type": "string", "minLength": 1},
|
||||||
|
"nova:environment": {"type": "string", "enum": ["dev", "qa", "prod", "dr"]},
|
||||||
|
"nova:cost-center": {"type": "string", "minLength": 1},
|
||||||
|
"nova:ref": {"type": "string", "minLength": 1}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"policyPreconditions": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Declared policy expectations the platform will enforce. The citizen developer states what the platform should check; the platform enforces it at apply time. Missing a declared precondition is POLICY_PRECONDITION_MISSING.",
|
||||||
|
"properties": {
|
||||||
|
"public-ingress": {"type": "boolean", "default": false},
|
||||||
|
"encryption_enabled": {"type": "boolean", "default": true},
|
||||||
|
"deletion_protection": {"type": "boolean", "default": true}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["developer", "agentic"],
|
||||||
|
"description": "developer = L3A (technical); agentic = L3B (non-technical, requires naturalLanguageIntent + confidenceAtSubmission + agentTrace per REQ-22 / W3.E)."
|
||||||
|
},
|
||||||
|
"appSource": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Pointer to the consumer application code so the platform can fetch at run time.",
|
||||||
|
"required": ["repo", "ref"],
|
||||||
|
"properties": {
|
||||||
|
"repo": {"type": "string", "minLength": 1, "description": "Repository URL or owner/repo shorthand."},
|
||||||
|
"ref": {"type": "string", "minLength": 1, "description": "Git ref (branch, tag, or SHA)."}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"naturalLanguageIntent": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required when profile=agentic (L3B). The citizen developer's plain-language intent."
|
||||||
|
},
|
||||||
|
"confidenceAtSubmission": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 1,
|
||||||
|
"description": "Required when profile=agentic (L3B). The submitter's self-assessed confidence."
|
||||||
|
},
|
||||||
|
"agentTrace": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required when profile=agentic (L3B). The agent's trace/reasoning for the submission."
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Per-env mandatory metadata (W3.E). qa requires e2eSuite + loadTest; prod requires runbook + dashboard + oncall; dr requires drDrillRef.",
|
||||||
|
"properties": {
|
||||||
|
"e2eSuite": {"type": "boolean"},
|
||||||
|
"loadTest": {"type": "boolean"}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"runbook": {"type": "string", "description": "Required when environment=prod (W3.E)."},
|
||||||
|
"dashboard": {"type": "string", "description": "Required when environment=prod (W3.E)."},
|
||||||
|
"oncall": {"type": "string", "description": "Required when environment=prod (W3.E)."},
|
||||||
|
"drDrillRef": {"type": "string", "description": "Required when environment=dr (W3.E)."}
|
||||||
|
},
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"if": {"properties": {"environment": {"const": "qa"}}},
|
||||||
|
"then": {"required": ["validation"], "properties": {"validation": {"required": ["e2eSuite", "loadTest"]}}}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {"properties": {"environment": {"const": "prod"}}},
|
||||||
|
"then": {"required": ["runbook", "dashboard", "oncall"]}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {"properties": {"environment": {"const": "dr"}}},
|
||||||
|
"then": {"required": ["drDrillRef"]}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {"properties": {"profile": {"const": "agentic"}}},
|
||||||
|
"then": {"required": ["naturalLanguageIntent", "confidenceAtSubmission", "agentTrace"]}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalProperties": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
"""tests/test_submission_readiness.py — REQ-220.
|
||||||
|
|
||||||
|
Covers: good contract passes; missing tags fail with MISSING_TAGS;
|
||||||
|
env-missing-mandatory fails with ENV_MISSING_MANDATORY:<env>:<field>;
|
||||||
|
agentic profile missing intent fails with AGENTIC_MISSING_INTENT;
|
||||||
|
missing appSource fails with MISSING_APP_SOURCE.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
from core.submission_readiness import check_readiness, ReadinessResult
|
||||||
|
|
||||||
|
GOOD_TAGS = {
|
||||||
|
"nova:owner": "consumer-repo",
|
||||||
|
"nova:contract": "uuid-1234",
|
||||||
|
"nova:environment": "dev",
|
||||||
|
"nova:cost-center": "nova-default",
|
||||||
|
"nova:ref": "CHG0678912",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _base(**overrides):
|
||||||
|
submission = {
|
||||||
|
"contractId": "uuid-1234",
|
||||||
|
"id": "webapi",
|
||||||
|
"name": "Customer Web API",
|
||||||
|
"environment": "dev",
|
||||||
|
"tags": dict(GOOD_TAGS),
|
||||||
|
"policyPreconditions": {"public-ingress": False, "encryption_enabled": True},
|
||||||
|
"profile": "developer",
|
||||||
|
"appSource": {"repo": "consumer/repo", "ref": "main"},
|
||||||
|
"infrastructure": {
|
||||||
|
"static-assets": {"inputs": {"bucket_name": "webapi-assets"}}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
submission.update(overrides)
|
||||||
|
return submission
|
||||||
|
|
||||||
|
|
||||||
|
class TestGoodContract(unittest.TestCase):
|
||||||
|
def test_good_contract_passes(self):
|
||||||
|
result = check_readiness(_base())
|
||||||
|
self.assertTrue(result.ready, f"Expected ready, got: {result.reason_codes}")
|
||||||
|
self.assertEqual(result.contract_id, "uuid-1234")
|
||||||
|
|
||||||
|
def test_good_agentic_contract_passes(self):
|
||||||
|
submission = _base(
|
||||||
|
profile="agentic",
|
||||||
|
naturalLanguageIntent="A web API for customer data",
|
||||||
|
confidenceAtSubmission=0.85,
|
||||||
|
agentTrace="LLM generated contract from issue #42",
|
||||||
|
)
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertTrue(result.ready, f"Expected ready, got: {result.reason_codes}")
|
||||||
|
|
||||||
|
|
||||||
|
class TestMissingTags(unittest.TestCase):
|
||||||
|
def test_missing_tags_fail(self):
|
||||||
|
submission = _base()
|
||||||
|
submission["tags"] = {"nova:owner": "consumer-repo"}
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
codes = " ".join(result.reason_codes)
|
||||||
|
self.assertIn("MISSING_TAGS", codes)
|
||||||
|
self.assertIn("nova:contract", codes)
|
||||||
|
self.assertIn("nova:environment", codes)
|
||||||
|
self.assertIn("nova:cost-center", codes)
|
||||||
|
self.assertIn("nova:ref", codes)
|
||||||
|
|
||||||
|
def test_empty_tag_value_fails(self):
|
||||||
|
submission = _base()
|
||||||
|
submission["tags"]["nova:owner"] = ""
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
self.assertTrue(any("MISSING_TAGS" in c for c in result.reason_codes))
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnvMissingMandatory(unittest.TestCase):
|
||||||
|
def test_qa_missing_e2e_suite_fails(self):
|
||||||
|
submission = _base(environment="qa")
|
||||||
|
submission["tags"]["nova:environment"] = "qa"
|
||||||
|
# No validation.e2eSuite
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
codes = " ".join(result.reason_codes)
|
||||||
|
self.assertIn("ENV_MISSING_MANDATORY:qa:validation.e2eSuite", codes)
|
||||||
|
|
||||||
|
def test_prod_missing_runbook_fails(self):
|
||||||
|
submission = _base(environment="prod")
|
||||||
|
submission["tags"]["nova:environment"] = "prod"
|
||||||
|
# No runbook/dashboard/oncall
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
codes = " ".join(result.reason_codes)
|
||||||
|
self.assertIn("ENV_MISSING_MANDATORY:prod:runbook", codes)
|
||||||
|
self.assertIn("ENV_MISSING_MANDATORY:prod:dashboard", codes)
|
||||||
|
self.assertIn("ENV_MISSING_MANDATORY:prod:oncall", codes)
|
||||||
|
|
||||||
|
def test_dr_missing_drdrillref_fails(self):
|
||||||
|
submission = _base(environment="dr")
|
||||||
|
submission["tags"]["nova:environment"] = "dr"
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
codes = " ".join(result.reason_codes)
|
||||||
|
self.assertIn("ENV_MISSING_MANDATORY:dr:drDrillRef", codes)
|
||||||
|
|
||||||
|
def test_prod_with_all_mandatory_passes(self):
|
||||||
|
submission = _base(
|
||||||
|
environment="prod",
|
||||||
|
runbook="docs/runbooks/webapi.md",
|
||||||
|
dashboard="https://grafana/nova/webapi",
|
||||||
|
oncall="oncall@company.com",
|
||||||
|
)
|
||||||
|
submission["tags"]["nova:environment"] = "prod"
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertTrue(result.ready, f"Expected ready, got: {result.reason_codes}")
|
||||||
|
|
||||||
|
|
||||||
|
class TestAgenticMissingIntent(unittest.TestCase):
|
||||||
|
def test_agentic_missing_all_markers_fails(self):
|
||||||
|
submission = _base(profile="agentic")
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
codes = " ".join(result.reason_codes)
|
||||||
|
self.assertIn("AGENTIC_MISSING_INTENT:naturalLanguageIntent", codes)
|
||||||
|
self.assertIn("AGENTIC_MISSING_INTENT:confidenceAtSubmission", codes)
|
||||||
|
self.assertIn("AGENTIC_MISSING_INTENT:agentTrace", codes)
|
||||||
|
|
||||||
|
def test_agentic_missing_one_marker_fails(self):
|
||||||
|
submission = _base(
|
||||||
|
profile="agentic",
|
||||||
|
naturalLanguageIntent="A web API",
|
||||||
|
confidenceAtSubmission=0.85,
|
||||||
|
# agentTrace missing
|
||||||
|
)
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
self.assertTrue(any("agentTrace" in c for c in result.reason_codes))
|
||||||
|
|
||||||
|
|
||||||
|
class TestMissingAppSource(unittest.TestCase):
|
||||||
|
def test_missing_appsource_fails(self):
|
||||||
|
submission = _base()
|
||||||
|
del submission["appSource"]
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
self.assertTrue(any("MISSING_APP_SOURCE" in c for c in result.reason_codes))
|
||||||
|
|
||||||
|
def test_appsource_missing_ref_fails(self):
|
||||||
|
submission = _base()
|
||||||
|
submission["appSource"] = {"repo": "consumer/repo"}
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
self.assertTrue(any("MISSING_APP_SOURCE" in c for c in result.reason_codes))
|
||||||
|
|
||||||
|
|
||||||
|
class TestPolicyPreconditionMissing(unittest.TestCase):
|
||||||
|
def test_empty_policy_fails(self):
|
||||||
|
submission = _base()
|
||||||
|
submission["policyPreconditions"] = {}
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertFalse(result.ready)
|
||||||
|
self.assertTrue(any("POLICY_PRECONDITION_MISSING" in c for c in result.reason_codes))
|
||||||
|
|
||||||
|
|
||||||
|
class TestReadinessResultStructure(unittest.TestCase):
|
||||||
|
def test_result_to_dict(self):
|
||||||
|
result = check_readiness(_base())
|
||||||
|
d = result.to_dict()
|
||||||
|
self.assertIn("ready", d)
|
||||||
|
self.assertIn("reason_codes", d)
|
||||||
|
self.assertIn("contractId", d)
|
||||||
|
|
||||||
|
def test_result_str_ready(self):
|
||||||
|
result = check_readiness(_base())
|
||||||
|
self.assertIn("READY", str(result))
|
||||||
|
|
||||||
|
def test_result_str_not_ready(self):
|
||||||
|
submission = _base()
|
||||||
|
del submission["appSource"]
|
||||||
|
result = check_readiness(submission)
|
||||||
|
self.assertIn("NOT READY", str(result))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user