From 40b5e781ce16f8fd3f1b313de7ce9ea445c41824 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 5 Aug 2026 16:08:33 +0000 Subject: [PATCH] =?UTF-8?q?docs(P00):=20resolve=20C-04=20=E2=80=94=20relab?= =?UTF-8?q?el=20v1.0=E2=86=92v0.10=20milestone,=20keep=20all=2040=20phases?= =?UTF-8?q?,=20v1.0=20UAT-gated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operator decision (resolves grill C-04 + escalation E-03): keep 2 milestones (v0.9 + v0.10), keep all phases (40 total, exceeds 35 soft limit), v1.0 is UAT-gated and cut as a separate tag (v1.0.0) after v0.10 completion per operator sign-off — not a separate milestone. Relabels all v1.0 milestone references to v0.10 across ROADMAP, REQUIREMENTS, GRILL_v0.9, IDEATION_v0.9, PRD_v0.9, PROJECT. Phase content unchanged; only the milestone label moves. Historical grill narrative (the original PRD §23 counts and the E-03 auto-split reasoning) preserved verbatim for audit integrity. C-04 and E-03 marked RESOLVED in GRILL_v0.9.md. Milestone structure: - v0.9: Re-architecture Foundation & Workloads (13 phases P00..P0X) - v0.10: Production Hardening (19 phases P00..P16, milestone tag v0.10.0) - v1.0: UAT-gated production-ready cut (separate v1.0.0 tag, not a milestone) verify-reqs: 90 requirements consistent. ---ci--- project: orca phase: 0 milestone: v0.9 status: complete gate: C-04 resolved ---/ci--- --- .ciagent/CHECKPOINT.json | 9 +++- .ciagent/GRILL_v0.9.md | 72 +++++++++++++------------- .ciagent/IDEATION_v0.9.md | 106 +++++++++++++++++++------------------- .ciagent/PRD_v0.9.md | 14 ++--- .ciagent/PROJECT.md | 4 +- .ciagent/REQUIREMENTS.md | 38 +++++++------- .ciagent/ROADMAP.md | 16 +++--- 7 files changed, 133 insertions(+), 126 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 66036c2..e659d0f 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -5,7 +5,7 @@ "milestone_slug": "rearchitecture", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-05T02:25:00Z", + "updated_at": "2026-08-05T02:35:00Z", "milestone_complete": false, "next_milestone": null, "ship": { @@ -16,5 +16,10 @@ "phase_branch_deleted": true }, "next_phase": "P00", - "next_phase_gate": "C-04 sizing estimate must run before P00 execution (40 phases exceeds 35-phase split threshold)" + "next_phase_gate": "✅ C-04 RESOLVED — operator decision: keep 2 milestones (v0.9+v0.10), keep all phases (40 total), v1.0 UAT-gated after v0.10", + "milestone_structure": { + "v0.9": "Re-architecture Foundation & Workloads (13 execution phases P00..P0X)", + "v0.10": "Production Hardening (19 execution phases P00..P16, milestone tag v0.10.0)", + "v1.0": "UAT-gated production-ready cut — separate tag (v1.0.0) cut after v0.10 completion per operator sign-off, not a separate milestone" + } } \ No newline at end of file diff --git a/.ciagent/GRILL_v0.9.md b/.ciagent/GRILL_v0.9.md index 04e0c90..47f7b0a 100644 --- a/.ciagent/GRILL_v0.9.md +++ b/.ciagent/GRILL_v0.9.md @@ -25,7 +25,7 @@ re-architecture proceeds). Their **mechanics** remain as binding work items: phase, split heavy phases. - **Migration** mechanics → split P14 into P14a/P14b/P14c, design migration ordering in v0.9-P00. -- **Security** mechanics → threat model in v1.0-P15.5 (C-19). +- **Security** mechanics → threat model in v0.10-P15.5 (C-19). The 19 binding conditions (C-01..C-19) and 10 phase challenges (PC-01..PC-10) are adopted in full as execution gates. @@ -76,12 +76,12 @@ silently break the build story; must be spiked before commitment. simultaneously deprecates 7 shipped subsystems and adds 8 net-new subsystems? The deprecation of ~10k lines of shipped daemon/transport/CA code is not listed as a phase. v0.9 P0a..P10 ship 10 phases of workload features before the -transactional control plane (R-010 deferred to v1.0 P10) — is that intentional +transactional control plane (R-010 deferred to v0.10 P10) — is that intentional or a sequencing error? Hidden requirements (step-ca self-upgrade, master.key rotation, Syncthing version drift)? **Evidence**: v0.9 phase ordering ships P0a..P10 workloads, then P10 lead rules -+ migration *last*. The transactional plane (R-010) is deferred to v1.0 P10 — ++ migration *last*. The transactional plane (R-010) is deferred to v0.10 P10 — two milestones away. v0.8 was a 4-phase NFR milestone; v0.6 was 4-phase feature. The PRD's v0.9 (11) + v1.0 (16) = 27 phases is 3-4× prior milestone size with no evidence the throughput model was re-validated. No phase is labeled @@ -94,12 +94,12 @@ no evidence the throughput model was re-validated. No phase is labeled - **PC-01**: Move the transactional plane primitives forward. The transactional primitives (desired-state, lead-applier, drift, rollback) are the substrate every workload phase depends on. Design spike in v0.9-P00; - full implementation in v1.0-P10 per PRD ordering (workloads first is accepted + full implementation in v0.10-P10 per PRD ordering (workloads first is accepted given the dual-write window mitigation in I-C-006). - **PC-02**: Add `v0.9-P00 — Deprecation sweep` as an explicit phase. Must land before any new feature phase so coverage gates don't measure dead packages. - **PC-03**: Split migration: `v0.9-P00b — Migration design + dry-run` (early, - parallel to deprecation) and `v1.0-P14 — Production migration` (final). + parallel to deprecation) and `v0.10-P14 — Production migration` (final). Migration design must inform every earlier phase, not be informed by them. **Rationale**: 27 phases framed as "two milestones" while simultaneously @@ -118,7 +118,7 @@ testing frameworks not in current dep map — what's the cost? **Evidence**: Active roster has 3 of 8 active; the 5 dormant personas map directly to the 5 new apt dependencies. v0.8 took 4 phases for a pure -test/coverage milestone; v1.0 includes 11 distinct subsystems in one +test/coverage milestone; v0.10 includes 11 distinct subsystems in one "milestone." No bash test infrastructure exists today. **Verdict**: PROCEED-WITH-CONDITION @@ -127,7 +127,7 @@ test/coverage milestone; v1.0 includes 11 distinct subsystems in one **Binding conditions**: - **C-04**: Produce a per-phase sizing estimate using v0.6/v0.7/v0.8 actuals as the analogous baseline. If realistic phase count exceeds 35, the - milestone must be split into v0.9 + v0.10 + v1.0 (three milestones), not two. + milestone must be split into v0.9 + v0.10 (three milestones), not two. - **C-05**: Reactivate or explicitly assign coverage for the dormant personas' domains (security, network, devops); no "dormant" = "unowned." - **C-06**: Decide and document whether bash scripts count toward the coverage @@ -169,9 +169,9 @@ specified. `ca.crt` trust root and import into step-ca, or (b) document forced re-bootstrap as an accepted breaking change with per-cluster upgrade procedure. Cannot be deferred. -- **C-08**: Before the first SPIFFE-touching phase (v1.0 P02 ACL), produce a +- **C-08**: Before the first SPIFFE-touching phase (v0.10 P02 ACL), produce a working spike of step-ca JWT-SVID or X.509-SVID minting from the orca CLI - (v1.0-P01.5). If the spike fails, SPIFFE is deferred and ACL falls back to + (v0.10-P01.5). If the spike fails, SPIFFE is deferred and ACL falls back to mTLS identity (which the shipped model already had). - **C-09**: Define and test the `orca-pull.sh` failure contract: idempotent re-run, bounded retry, deterministic state on partial failure, syslog @@ -212,9 +212,9 @@ is not portable across the orca model. "Atomic, auto-rollback" is asserted for **Confidence**: 0.82 **Mechanics adopted**: -- **PC-04**: Split P14 into `v1.0-P14a — Data migration` (current scope), - `v1.0-P14b — Daemon cutover + running-allocation adoption`, - `v1.0-P14c — Mixed-version cluster tolerance + no-orca-on-server enforcement`. +- **PC-04**: Split P14 into `v0.10-P14a — Data migration` (current scope), + `v0.10-P14b — Daemon cutover + running-allocation adoption`, + `v0.10-P14c — Mixed-version cluster tolerance + no-orca-on-server enforcement`. Three sub-phases, each with its own integration test. **Rationale**: The migration plan as described covers the easy third (file @@ -254,7 +254,7 @@ documented in step-ca's own operations guide (out-of-band knowledge). - **C-13**: Replace server-side doctor with a CLI-driven equivalent that SSH-probes every node and reconstructs the health view the daemon used to provide locally. This is a new requirement, not a feature; added as - I-C-002 / v1.0-P14c. + I-C-002 / v0.10-P14c. - **C-14**: Syncthing conflict-resolution policy must be deterministic, documented, and tested with a forced-divergence integration test. @@ -291,7 +291,7 @@ is now the default. **Mechanics adopted**: - **C-19**: Write a threat model for the new posture before any - security-touching phase (v1.0-P15.5). Defend master.key + CLI mint authority + security-touching phase (v0.10-P15.5). Defend master.key + CLI mint authority or revise. The shipped model deliberately avoided putting a single stealable file on a single host that decrypts all secrets and mints all identities. The threat model must document why the new posture is acceptable or specify @@ -348,7 +348,7 @@ coverage gate (D-042/D-047) is Go-specific. **Rationale**: Bash is not inherently unmaintainable, but bash *in a Go-only, coverage-gated, structured-logging project* is a language-without-rails. Without the four conditions above, the bash control plane becomes the part of the -codebase that everyone is afraid to touch by v1.0 P05. The drift between Go +codebase that everyone is afraid to touch by v0.10 P05. The drift between Go emitters and bash appliers is the single most likely source of "works on the CLI's machine, fails on the lead" bugs. @@ -367,7 +367,7 @@ transactional layer *on top of the daemon*? Is this re-architecture driven by a **Evidence**: ROADMAP.md and PROJECT.md: every milestone from v0.1 to v0.8 explicitly says "the vision is unchanged; this milestone is not a direction -change." v0.9/v1.0 is the *first* milestone in the project's history that +change." v0.9/v0.10 is the *first* milestone in the project's history that reverses the vision's anti-patterns. AD-010's rationale: "step-ca/cfssl/ vault-pki too heavyweight for Orca's footprint." Nothing in the original PRD suggested Orca's footprint changed. The shipped model's `internal/transport` @@ -417,35 +417,35 @@ conditions (C-01..C-19) as execution gates. If the C-04 sizing estimate exceeds | C-01 | Evaluate wasmtime Go binding CGO impact; if CGO-required, drop wasmtime as primary or revoke D-002 | v0.9-P07b | Build matrix spike on linux/amd64+arm64; revocation decision recorded | | C-02 | Syncthing feasibility spike: config injection, conflict policy, deterministic failure mode | v0.9-P09 | Spike report + forced-divergence integration test | | C-03 | Check PRD into `.ciagent/PRD_v0.9.md` before any v0.9 phase begins | (gate) | ✅ Resolved — file committed | -| C-04 | Per-phase sizing estimate vs v0.6/v0.7/v0.8 actuals; if >35, split into v0.9+v0.10+v1.0 | v0.9 start | Estimate doc with analogous-phase sizing table | +| C-04 | Per-phase sizing estimate vs v0.6/v0.7/v0.8 actuals; if >35, split into v0.9+v0.10 | v0.9 start | ✅ RESOLVED — operator decision: keep 2 milestones (v0.9+v0.10), keep all phases (40 total), v1.0 UAT-gated after v0.10 | | C-05 | Reactivate or assign dormant persona domains (security, network, devops) | v0.9-P00 | PERSONAS.md updated with named owners | | C-06 | Decide bash coverage-gate status; if exempt, record compensating control | v0.9-P00 | Decision recorded in PROJECT.md D-series; CI pipeline shows the gate | -| C-07 | CA migration spec: preserve existing trust root or document forced re-bootstrap | v1.0-P14a | Spec doc + migration dry-run on test cluster | -| C-08 | SPIFFE SVID minting spike; if fails, fall back to mTLS identity | v1.0-P02 (spike in P01.5) | Working SVID mint from orca CLI in sandbox | -| C-09 | `orca-pull.sh` failure contract: idempotent re-run, bounded retry, deterministic state, structured syslog | v1.0-P10 | Failure-path integration test + syslog structured-tag verification | +| C-07 | CA migration spec: preserve existing trust root or document forced re-bootstrap | v0.10-P14a | Spec doc + migration dry-run on test cluster | +| C-08 | SPIFFE SVID minting spike; if fails, fall back to mTLS identity | v0.10-P02 (spike in P01.5) | Working SVID mint from orca CLI in sandbox | +| C-09 | `orca-pull.sh` failure contract: idempotent re-run, bounded retry, deterministic state, structured syslog | v0.10-P10 | Failure-path integration test + syslog structured-tag verification | | C-10 | Traefik config atomicity protocol (tmpfile+fsync+rename) + malformed-config behavior verified | v0.9-P02 | Atomic-rename test + Traefik malconfig-hold-last-good assertion | -| C-11 | Lead-side watchdog meta-timer for `orca-pull.sh` starvation, with structured alert path | v1.0-P09 | Watchdog fires on injected pull failure; alert received | -| C-12 | Document step-ca HA story; if single-node, record as accepted SPOF with mitigation | v1.0-P09 | Decision doc; if HA, RAFT/sync story in orca plan | -| C-13 | Replace server-side doctor with CLI-SSH-driven equivalent | v1.0-P14c | New REQ-086 in REQUIREMENTS.md; integration test SSH-probes N nodes | -| C-14 | Syncthing conflict-resolution policy deterministic + forced-divergence integration test | v1.0-P09 | Test induces divergence; resolves to single deterministic state | +| C-11 | Lead-side watchdog meta-timer for `orca-pull.sh` starvation, with structured alert path | v0.10-P09 | Watchdog fires on injected pull failure; alert received | +| C-12 | Document step-ca HA story; if single-node, record as accepted SPOF with mitigation | v0.10-P09 | Decision doc; if HA, RAFT/sync story in orca plan | +| C-13 | Replace server-side doctor with CLI-SSH-driven equivalent | v0.10-P14c | New REQ-086 in REQUIREMENTS.md; integration test SSH-probes N nodes | +| C-14 | Syncthing conflict-resolution policy deterministic + forced-divergence integration test | v0.10-P09 | Test induces divergence; resolves to single deterministic state | | C-15 | Bash testing framework (bats/shunit2) + shellcheck + shfmt in CoreCI before any bash ships | v0.9-P00 | CI pipeline green with the gate on a sample script | | C-16 | Versioned JSON-schema render-format contract between Go emitters and bash appliers | v0.9-P00 | Schema file in repo; both sides validate; mismatch fails CI | | C-17 | Bash scripts emit slog-compatible JSON to syslog with audit-log field set (REQ-006) | v0.9-P00 | Syslog capture test verifies field-presence + JSON parse | | C-18 | Document bash-side equivalents (or accepted drops) for shipped transport capabilities | v0.9-P00 | Capability-mapping doc in `.ciagent/` | -| C-19 | Write a threat model for the new posture; defend master.key + CLI mint authority or revise | v1.0-P15.5 | Threat-model doc reviewed and committed; design revised if regression found | +| C-19 | Write a threat model for the new posture; defend master.key + CLI mint authority or revise | v0.10-P15.5 | Threat-model doc reviewed and committed; design revised if regression found | # Phase Plan Challenges | # | Phase | Problem | Fix | |---|-------|---------|-----| -| PC-01 | v0.9 P0a–P10 | Ship 10 phases of workload features before the transactional control plane | Design spike in v0.9-P00; full impl in v1.0-P10 per PRD ordering (workloads first accepted with dual-write mitigation) | +| PC-01 | v0.9 P0a–P10 | Ship 10 phases of workload features before the transactional control plane | Design spike in v0.9-P00; full impl in v0.10-P10 per PRD ordering (workloads first accepted with dual-write mitigation) | | PC-02 | (missing) | Deprecation of ~10k lines of daemon/transport/CA code is not a phase | Add `v0.9-P00 — Deprecation sweep` as explicit phase before any new feature phase | -| PC-03 | v0.9 P10 | Migration is the last phase of v0.9 but is highest-risk | Split: migration design in v0.9-P00 (early), implementation in v1.0-P14 (final) | -| PC-04 | v1.0 P14 | Covers data migration only; omits running-allocation cutover, mixed-version cluster, rollback trigger | Split into P14a (data), P14b (daemon cutover), P14c (mixed-version tolerance) | -| PC-05 | v1.0 P02 | SPIFFE is a documented reversal with no spike; lands before spike possible | Insert `v1.0-P01.5 — SPIFFE mint spike` as hard gate before P02 | -| PC-06 | v1.0 P10 | Transactional plane depends on lead-applier bash scripts (C-09) not gated | Reorder to v0.9-P00 design + add C-09 gate | -| PC-07 | v1.0 P15/P16 | README before security threat model | Add `v1.0-P15.5 — Threat model + security review` before final review | -| PC-08 | (missing) | No phase replaces server-side `orca doctor` | Add as I-C-002 / v1.0-P14c (CLI-SSH-driven doctor) | +| PC-03 | v0.9 P10 | Migration is the last phase of v0.9 but is highest-risk | Split: migration design in v0.9-P00 (early), implementation in v0.10-P14 (final) | +| PC-04 | v0.10 P14 | Covers data migration only; omits running-allocation cutover, mixed-version cluster, rollback trigger | Split into P14a (data), P14b (daemon cutover), P14c (mixed-version tolerance) | +| PC-05 | v0.10 P02 | SPIFFE is a documented reversal with no spike; lands before spike possible | Insert `v0.10-P01.5 — SPIFFE mint spike` as hard gate before P02 | +| PC-06 | v0.10 P10 | Transactional plane depends on lead-applier bash scripts (C-09) not gated | Reorder to v0.9-P00 design + add C-09 gate | +| PC-07 | v0.10 P15/P16 | README before security threat model | Add `v0.10-P15.5 — Threat model + security review` before final review | +| PC-08 | (missing) | No phase replaces server-side `orca doctor` | Add as I-C-002 / v0.10-P14c (CLI-SSH-driven doctor) | | PC-09 | v0.9 P09 | Syncthing lands before feasibility spike (C-02) | Spike must precede P09; if P09 is the spike, rename + gate on spike success | | PC-10 | v0.9 P07 | Five runtimes in one phase, including wasmtime (CGO risk) and pve-vm/pve-ct | Split: P07a (process+podman), P07b (wasmtime, C-01 gated), P07c (pve-vm+ct) | @@ -454,9 +454,9 @@ conditions (C-01..C-19) as execution gates. If the C-04 sizing estimate exceeds 1. **What measured operational failure of the shipped v0.8 daemon model is the re-architecture responding to?** — ✅ Resolved by override ground 1. 2. **Can the v0.9 scope be delivered as additive extensions?** — ✅ Resolved: rejected per override grounds 1 + 5. 3. **What is the wasmtime/CGO resolution?** — Closes via C-01 spike in v0.9-P07b. -4. **What is the master.key threat model?** — Closes via C-19 in v1.0-P15.5. +4. **What is the master.key threat model?** — Closes via C-19 in v0.10-P15.5. 5. **What is the rollback unit of work for §24, and what triggers it?** — Must be answered in v0.9-P00 txn-design spike (I-B-007). -6. **Is step-ca single-node acceptable as a cluster SPOF?** — Closes via C-12 in v1.0-P09. +6. **Is step-ca single-node acceptable as a cluster SPOF?** — Closes via C-12 in v0.10-P09. 7. **Can the bash control plane be reduced?** — Closes in v0.9-P00 (fold 3+ scripts into Go-side SSH invocations where possible). 8. **What is the realistic phase count?** — Closes via C-04 sizing before v0.9 starts; if >35, the plan becomes three milestones. 9. **Does the PRD's reversal of 6 documented decisions require a formal AD-series supersession?** — ✅ Resolved: supersession table recorded in PROJECT.md + ARCHITECTURE.md. @@ -481,5 +481,5 @@ conditions (C-01..C-19) as execution gates. If the C-04 sizing estimate exceeds | E-ID | Item | Auto-decision | Mitigation | |------|------|---------------|-----------| | E-01 | Whether the re-architecture is justified vs incremental | OVERRIDDEN by user — direction holds | Six-part evidence basis recorded in PROJECT.md Supersession Table | -| E-02 | Whether master.key passphrase-less posture is acceptable | REPLAN mechanics — threat model first | C-19 in v1.0-P15.5; if threat model shows regression vs shipped, revise design | -| E-03 | Whether 27 phases fit in 2 milestones | Auto-split if sizing exceeds 35 | C-04; if exceeded, milestone becomes v0.9 + v0.10 + v1.0 | \ No newline at end of file +| E-02 | Whether master.key passphrase-less posture is acceptable | REPLAN mechanics — threat model first | C-19 in v0.10-P15.5; if threat model shows regression vs shipped, revise design | +| E-03 | Whether 27 phases fit in 2 milestones | Auto-split if sizing exceeds 35 | ✅ RESOLVED — operator: keep 2 milestones (v0.9+v0.10), keep all phases, v1.0 UAT-gated | \ No newline at end of file diff --git a/.ciagent/IDEATION_v0.9.md b/.ciagent/IDEATION_v0.9.md index 86860d3..cb23d34 100644 --- a/.ciagent/IDEATION_v0.9.md +++ b/.ciagent/IDEATION_v0.9.md @@ -1,6 +1,6 @@ # Ideation v0.9 — Re-architecture Foundation -**Project**: orca (single-project mode) | **Milestone**: v0.9/v1.0 re-architecture +**Project**: orca (single-project mode) | **Milestone**: v0.9/v0.10 re-architecture **Date**: 2026-08-05 | **Agent**: ideation agent | **Confidence threshold**: 0.60 **Next REQ ID prior to this run**: REQ-060 (v0.8 complete) @@ -12,7 +12,7 @@ with a CLI-only, SSH-push, step-ca, Markdown-frontmatter, multi-namespace stack. 9 packages are deprecation targets (~2,400 LOC of v0.8 daemon/transport/security-ca/engine-dispatch/jobspec-hcl/config-hcl/certpaths code), 7 packages are adaptable, and 8 subsystems are net-new with zero -implementation. The §23 milestone plan has 11 v0.9 phases + 17 v1.0 phases but +implementation. The §23 milestone plan has 11 v0.9 phases + 17 v0.10 phases but under-specifies the deprecation mechanics, the SSH-push transport design, the lead-applier execution model, several adapter/bridge layers, and the migration ordering risk. @@ -25,10 +25,10 @@ the PRD §23 plan are listed at the end. ### I-M-001 — `orca daemon` deprecation command and build-tag removal path - **Tier**: mechanical -- **Description**: The PRD deprecates `internal/daemon/` (R-001) but §23 never says *how*. `internal/cli/daemon.go` (100 LOC) registers the `daemon` cobra command and wires `daemon.NewServer` + `engine.Dispatcher`. Big-bang removal would break the v0.8→v1.0 migration path (v1.0-P14) because `orca upgrade --to-v1.0` must run against a live v0.8 cluster that still has daemons. Proposal: (1) in v0.9, `orca daemon` emits a deprecation warning and still runs (dual-write window); (2) in v1.0, `orca daemon` is repurposed to `orca daemon drain-and-stop` (stops v0.8 daemons on peers via SSH, confirms workloads survive via systemd); (3) post-v1.0, the command and `internal/daemon/` are deleted. Add `// Deprecated` Go doc comments + `slog.Warn` on every run. +- **Description**: The PRD deprecates `internal/daemon/` (R-001) but §23 never says *how*. `internal/cli/daemon.go` (100 LOC) registers the `daemon` cobra command and wires `daemon.NewServer` + `engine.Dispatcher`. Big-bang removal would break the v0.8→v1.0 migration path (v0.10-P14) because `orca upgrade --to-v1.0` must run against a live v0.8 cluster that still has daemons. Proposal: (1) in v0.9, `orca daemon` emits a deprecation warning and still runs (dual-write window); (2) in v1.0, `orca daemon` is repurposed to `orca daemon drain-and-stop` (stops v0.8 daemons on peers via SSH, confirms workloads survive via systemd); (3) post-v1.0, the command and `internal/daemon/` are deleted. Add `// Deprecated` Go doc comments + `slog.Warn` on every run. - **Rationale**: R-001 is an invariant, but the *transition* off the daemon is a mechanical gap. The v0.8 `daemon.go` is wired in `root.go` init; removing it without a transition plan breaks the §24 migration. - **Proposed REQ ID**: REQ-061 -- **Proposed phase placement**: v1.0-P14 (migration) — deprecation warning lands in v0.9-P0X +- **Proposed phase placement**: v0.10-P14 (migration) — deprecation warning lands in v0.9-P0X - **Confidence**: 0.82 - **Accept/Defer**: accept @@ -61,25 +61,25 @@ the PRD §23 plan are listed at the end. ### I-M-005 — `orca doctor --legacy-paths` detection for v0.8 residue - **Tier**: mechanical -- **Description**: The v0.8 layout is `~/.orca/{orca.db, ca.crt, ca.key, server.crt, server.key, orca_ssh_key, known_hosts, config.hcl}`. The v1.0 layout is `ORCA_HOME/{_defaults/, cluster/{ca,master.key,peers,pve,txns}, /{db,.env,.env.secrets,jobs,alloc,ns.md}, orca_cache.db}`. `orca doctor` (`internal/doctor/doctor.go`, 501 LOC, adaptable) must gain a `doctor legacy` subcommand that detects v0.8 residue: presence of `orca.db` at ORCA_HOME root, `ca.crt`/`ca.key` (internal CA, superseded by step-ca), `config.hcl` (HCL, demoted), flat `server.crt` (single-namespace), and a `namespace` column in any `*.db` (R-002 says no namespace column). Output: list of detected legacy artifacts with migration recommendations. This is the *detection* half of v1.0-P14; the *migration* half is I-C-001. -- **Rationale**: §23 v1.0-P14 says "orca upgrade --to-v1.0, post-invariant checks" but doesn't specify the detection surface. `doctor` is the diagnostics framework and is explicitly adaptable. +- **Description**: The v0.8 layout is `~/.orca/{orca.db, ca.crt, ca.key, server.crt, server.key, orca_ssh_key, known_hosts, config.hcl}`. The v1.0 layout is `ORCA_HOME/{_defaults/, cluster/{ca,master.key,peers,pve,txns}, /{db,.env,.env.secrets,jobs,alloc,ns.md}, orca_cache.db}`. `orca doctor` (`internal/doctor/doctor.go`, 501 LOC, adaptable) must gain a `doctor legacy` subcommand that detects v0.8 residue: presence of `orca.db` at ORCA_HOME root, `ca.crt`/`ca.key` (internal CA, superseded by step-ca), `config.hcl` (HCL, demoted), flat `server.crt` (single-namespace), and a `namespace` column in any `*.db` (R-002 says no namespace column). Output: list of detected legacy artifacts with migration recommendations. This is the *detection* half of v0.10-P14; the *migration* half is I-C-001. +- **Rationale**: §23 v0.10-P14 says "orca upgrade --to-v1.0, post-invariant checks" but doesn't specify the detection surface. `doctor` is the diagnostics framework and is explicitly adaptable. - **Proposed REQ ID**: REQ-065 -- **Proposed phase placement**: v1.0-P14c (mixed-version tolerance + no-orca enforcement) +- **Proposed phase placement**: v0.10-P14c (mixed-version tolerance + no-orca enforcement) - **Confidence**: 0.80 - **Accept/Defer**: accept ### I-M-006 — Legacy CA state migration to step-ca (cert import) - **Tier**: mechanical -- **Description**: `internal/security/ca.go` (338 LOC) holds an internal Go CA with `ca.crt`/`ca.key` (RSA 3072, 10-year). The PRD replaces this with step-ca (R-006, D-101 reverses AD-010). The v1.0-P14 migration must handle existing deployments with an internal CA: (a) import the existing CA key into step-ca as `step ca init --deployment-type standalone --remote-management` with the existing key; (b) issue new SVIDs from step-ca and let old certs expire; (c) document that v0.8 certs are invalidated and re-bootstrap is required. The codebase audit says `ca.go`+`csr.go` are *replaced* — but the *state* (the CA key + issued server certs in `cert_repo` SQLite) may need to be preserved for audit history even if the live trust root changes. Proposal: `orca upgrade --to-v1.0 --import-ca` reads `~/.orca/ca.key`, initializes step-ca with it, and re-issues workload SVIDs. Without this, existing deployments lose their trust root with no path back. +- **Description**: `internal/security/ca.go` (338 LOC) holds an internal Go CA with `ca.crt`/`ca.key` (RSA 3072, 10-year). The PRD replaces this with step-ca (R-006, D-101 reverses AD-010). The v0.10-P14 migration must handle existing deployments with an internal CA: (a) import the existing CA key into step-ca as `step ca init --deployment-type standalone --remote-management` with the existing key; (b) issue new SVIDs from step-ca and let old certs expire; (c) document that v0.8 certs are invalidated and re-bootstrap is required. The codebase audit says `ca.go`+`csr.go` are *replaced* — but the *state* (the CA key + issued server certs in `cert_repo` SQLite) may need to be preserved for audit history even if the live trust root changes. Proposal: `orca upgrade --to-v1.0 --import-ca` reads `~/.orca/ca.key`, initializes step-ca with it, and re-issues workload SVIDs. Without this, existing deployments lose their trust root with no path back. - **Rationale**: AD-010 is explicitly reversed by D-101, but the reversal doesn't address what happens to the existing CA material. §24 covers data migration but not CA migration. - **Proposed REQ ID**: REQ-066 -- **Proposed phase placement**: v1.0-P14a (data migration) +- **Proposed phase placement**: v0.10-P14a (data migration) - **Confidence**: 0.70 - **Accept/Defer**: accept (design in v0.9-P00 so step-ca integration knows the import contract) ### I-M-007 — Fuzz test harness for the Markdown frontmatter parser - **Tier**: mechanical -- **Description**: R-014/R-015 require byte-exact body preservation — "body of every .md config file preserved verbatim." This is a class of bug that's easy to get wrong (off-by-one on the `---` delimiter, trailing newline handling, BOM, CRLF, nested code fences containing `---`). v0.8 has no fuzz tests at all. Proposal: add a `testing.F` fuzz target in `internal/jobspec/markdown_test.go` that round-trips random frontmatter+body through `ParseMarkdown` and asserts `body == roundtripped.body` byte-exact. Also add a corpus of adversarial fixtures (CRLF, BOM, no-frontmatter, empty-frontmatter, frontmatter-with-only-separator). §23 v1.0-P08 mentions integration tests but not fuzzing. +- **Description**: R-014/R-015 require byte-exact body preservation — "body of every .md config file preserved verbatim." This is a class of bug that's easy to get wrong (off-by-one on the `---` delimiter, trailing newline handling, BOM, CRLF, nested code fences containing `---`). v0.8 has no fuzz tests at all. Proposal: add a `testing.F` fuzz target in `internal/jobspec/markdown_test.go` that round-trips random frontmatter+body through `ParseMarkdown` and asserts `body == roundtripped.body` byte-exact. Also add a corpus of adversarial fixtures (CRLF, BOM, no-frontmatter, empty-frontmatter, frontmatter-with-only-separator). §23 v0.10-P08 mentions integration tests but not fuzzing. - **Rationale**: R-015 is a *load-bearing invariant* (body appears in inspect/history). Byte-exactness is exactly what fuzz tests are for. The v0.8 jobspec tests are golden-file only (no fuzz). - **Proposed REQ ID**: REQ-067 - **Proposed phase placement**: v0.9-P0b (Markdown parser) — fuzz from day one @@ -89,9 +89,9 @@ the PRD §23 plan are listed at the end. ### I-M-008 — Deprecation warnings on removed/repurposed CLI subcommands - **Tier**: mechanical - **Description**: The v0.8 CLI has `orca cert {ca-init,gen,show,renew,fingerprint}` (`internal/cli/cert.go`), `orca node join` with mTLS handshake semantics (`internal/cli/node.go`), `orca job run `. The PRD repurposes `node join` to SSH-bootstrap (no mTLS), deprecates `cert` (step-ca handles it), and changes `job run` to accept `.md` specs. Each removed/changed command should emit a `slog.Warn` deprecation banner with the v1.0 replacement, *except* when run under `orca upgrade`. The existing `root.go` `PersistentPreRunE` is the natural hook for a global `--no-deprecation-warnings` flag. -- **Rationale**: Operators running v0.8 commands against v0.9/v1.0 need to know what changed. The PRD doesn't mention deprecation UX. +- **Rationale**: Operators running v0.8 commands against v0.9/v0.10 need to know what changed. The PRD doesn't mention deprecation UX. - **Proposed REQ ID**: REQ-068 -- **Proposed phase placement**: v0.9-P0X (ship) + v1.0-P13 (ns subcommands, when CLI surface is finalized) +- **Proposed phase placement**: v0.9-P0X (ship) + v0.10-P13 (ns subcommands, when CLI surface is finalized) - **Confidence**: 0.72 - **Accept/Defer**: accept @@ -115,10 +115,10 @@ the PRD §23 plan are listed at the end. ### I-M-011 — `internal/store/` schema: per-namespace DBs, drop ns column - **Tier**: mechanical -- **Description**: R-002 says "No `namespace` column in SQLite." The v0.8 schema has 7 migrations (`0001`..`0007`) with a single `orca.db`. The v1.0 model has one DB per namespace (`/db/orca.db`) plus a CLI-side cache DB (`orca_cache.db`, R-008). The existing `store.Open(path)` takes a path arg — adaptable. But the migrations are global; they need to apply *per namespace DB*. Proposal: `store.Open` gains a namespace parameter (or caller passes `paths.NSDb(ns)`); `migrate.go` runs `0001`..`0007` (minus `0006_node_kind_os` which is v0.8-specific) plus new `0008_namespace_layout.sql`. The `cert_repo` (`0004_certs.sql`) is removed (step-ca handles certs). The audit_log table moves to the CLI-side cache DB (R-008). Existing v0.8 `orca.db` is migrated by splitting tables into per-namespace DBs during v1.0-P14. +- **Description**: R-002 says "No `namespace` column in SQLite." The v0.8 schema has 7 migrations (`0001`..`0007`) with a single `orca.db`. The v0.10 model has one DB per namespace (`/db/orca.db`) plus a CLI-side cache DB (`orca_cache.db`, R-008). The existing `store.Open(path)` takes a path arg — adaptable. But the migrations are global; they need to apply *per namespace DB*. Proposal: `store.Open` gains a namespace parameter (or caller passes `paths.NSDb(ns)`); `migrate.go` runs `0001`..`0007` (minus `0006_node_kind_os` which is v0.8-specific) plus new `0008_namespace_layout.sql`. The `cert_repo` (`0004_certs.sql`) is removed (step-ca handles certs). The audit_log table moves to the CLI-side cache DB (R-008). Existing v0.8 `orca.db` is migrated by splitting tables into per-namespace DBs during v0.10-P14. - **Rationale**: R-002 is explicit ("No namespace column in SQLite") but the existing schema has a single DB. §23 doesn't specify the schema split mechanics. - **Proposed REQ ID**: REQ-071 -- **Proposed phase placement**: v0.9-P0a1 + v1.0-P06 (alloc history, which uses cache DB) +- **Proposed phase placement**: v0.9-P0a1 + v0.10-P06 (alloc history, which uses cache DB) - **Confidence**: 0.80 - **Accept/Defer**: accept @@ -127,9 +127,9 @@ the PRD §23 plan are listed at the end. - **Description**: `internal/transport/` (7 files, ~1300 LOC incl tests) implements mTLS client/server, dispatch, idempotency, retry, handshake logging. R-001 + R-006 replace this with SSH-push. The *idempotency* and *retry* logic (`idempotency.go` 123 LOC, `retry.go` 151 LOC) is conceptually reusable for SSH-push (retry on SSH failure, idempotency keys for SCP'd configs). Proposal: delete `mtls.go`, `dispatch.go`, `handshake_log.go`; extract retry/idempotency patterns into a new `internal/sshpush/` package. The existing `transport.IdempotencyStore` (in-memory `sync.Map` of keys) is directly reusable. This avoids re-implementing retry semantics from scratch. - **Rationale**: The codebase audit marks `internal/transport/` as fully replaced, but the retry/idempotency *patterns* are transport-agnostic. §23 doesn't call this out. - **Proposed REQ ID**: REQ-072 -- **Proposed phase placement**: v0.9-P00 (deprecation sweep) — delete in v1.0-P14 +- **Proposed phase placement**: v0.9-P00 (deprecation sweep) — delete in v0.10-P14 - **Confidence**: 0.68 -- **Accept/Defer**: accept (defer deletion to v1.0-P14 to keep dual-write window open) +- **Accept/Defer**: accept (defer deletion to v0.10-P14 to keep dual-write window open) ## Tier 2 — Backend-Enriched (Structural / Architectural) @@ -156,7 +156,7 @@ the PRD §23 plan are listed at the end. - **Description**: R-001 says "no orca binary on servers." R-010 says the lead applies desired-state transactionally. Unresolved: does the lead run `orca-pull.sh` (pure bash that SCPs a desired-state bundle and applies it via `systemctl daemon-reload` + `systemctl restart`) or does the operator's CLI SSH into the lead and runs `orca apply` remotely (which would put an orca binary on the lead, violating R-001)? The PRD's intent is the former: the lead is bare Linux with systemd timers + bash. Proposal: (1) the CLI renders a *transaction bundle* (tarball of desired-state files + `apply.sh` + `verify.sh`) on the operator host; (2) SCPs it to the lead's `/run/orca/txns//`; (3) the lead's systemd timer runs `/run/orca/txns//apply.sh` which idempotently applies and runs verify; (4) the CLI polls the lead for txn status via SSH (`cat /run/orca/txns//status.json`). The bash scripts are generated by the CLI's emitter (I-B-002), not hand-written per cluster. - **Rationale**: The most ambiguous load-bearing design decision in the PRD. R-001 + R-010 together imply the lead runs no orca binary, but the lead must apply transactions. §23 doesn't resolve this. Getting it wrong means either violating R-001 or having no transactional apply. - **Proposed REQ ID**: REQ-075 -- **Proposed phase placement**: v1.0-P10 (transactional plane) — bundle format designed in v0.9-P00 +- **Proposed phase placement**: v0.10-P10 (transactional plane) — bundle format designed in v0.9-P00 - **Confidence**: 0.78 - **Accept/Defer**: accept @@ -165,13 +165,13 @@ the PRD §23 plan are listed at the end. - **Description**: D-101 reverses AD-010 (which rejected step-ca as "too heavyweight"). §23 mentions step-ca in R-006 but never specifies the integration. Key surfaces: (1) **Provisioning**: `orca init` (adapted from v0.8's `internal/cli/init.go`) runs `step ca init` on the lead, stores root + intermediate in `cluster/ca/`. (2) **CA bootstrap**: CLI SSHs to the lead, installs step-ca via apt, runs `step ca init`, stores `step-ca.json` config. (3) **Cert signing API**: workloads request SVIDs via `step ca token` (JWE provisioner token minted by CLI) → `step ca certificate`. The CLI mints the token because it holds the provisioner password (in `cluster/master.key`-derived form). (4) **SVID minting**: each workload gets a SPIFFE ID (`spiffe://orca///`) encoded as a SAN in the step-ca-issued cert. The v0.8 `internal/security/ca.go` is deleted; a new `internal/stepca/` package wraps the `step` CLI via SSH (no Go step-ca client library — keep zero-new-dep posture if possible, or add `github.com/smallstep/cli` as a dep). - **Rationale**: step-ca is a new external dependency with its own config format, provisioner model, and CLI. §23 assumes it but never designs the integration. security-engineer persona must be reactivated. - **Proposed REQ ID**: REQ-076 -- **Proposed phase placement**: v0.9-P07 (runtime block — runtimes need SVIDs) + v1.0-P02 (ACL — SPIFFE identities) +- **Proposed phase placement**: v0.9-P07 (runtime block — runtimes need SVIDs) + v0.10-P02 (ACL — SPIFFE identities) - **Confidence**: 0.74 - **Accept/Defer**: accept ### I-B-005 — Traefik dynamic config generation and atomic reload - **Tier**: backend-enriched -- **Description**: R-006 makes Traefik load-bearing (mTLS termination + health checks). §23 puts service blocks + Traefik health checks in v0.9-P02. Design: the CLI's Traefik emitter (I-B-002) renders a dynamic config file (`/etc/traefik/dynamic/orca--.yaml`) with backends (the socket paths from R-007), health checks, and mTLS config pointing at step-ca's root. Atomic reload: Traefik watches the dynamic dir with `fsnotify` — writing the file atomically (tmp+rename) triggers a reload. Drain (v1.0-P05) works by writing a config with the backend's `weight=0` or removing it, triggering Traefik to stop routing. The v0.8 codebase has no Traefik integration at all. **Gated by grill C-10** (Traefik config atomicity protocol: tmpfile+fsync+rename + malformed-config hold-last-good verified). +- **Description**: R-006 makes Traefik load-bearing (mTLS termination + health checks). §23 puts service blocks + Traefik health checks in v0.9-P02. Design: the CLI's Traefik emitter (I-B-002) renders a dynamic config file (`/etc/traefik/dynamic/orca--.yaml`) with backends (the socket paths from R-007), health checks, and mTLS config pointing at step-ca's root. Atomic reload: Traefik watches the dynamic dir with `fsnotify` — writing the file atomically (tmp+rename) triggers a reload. Drain (v0.10-P05) works by writing a config with the backend's `weight=0` or removing it, triggering Traefik to stop routing. The v0.8 codebase has no Traefik integration at all. **Gated by grill C-10** (Traefik config atomicity protocol: tmpfile+fsync+rename + malformed-config hold-last-good verified). - **Rationale**: Traefik is net-new and load-bearing. §23 mentions it in R-006/P02/P05 but never specifies config generation or reload mechanism. - **Proposed REQ ID**: REQ-077 - **Proposed phase placement**: v0.9-P02 (Service block + checks) @@ -189,19 +189,19 @@ the PRD §23 plan are listed at the end. ### I-B-007 — Transaction bundle format and atomicity across N peers - **Tier**: backend-enriched -- **Description**: R-010 requires transactional control-plane updates. §23 puts this in v1.0-P10. Design: a *transaction bundle* is a tarball containing: (1) `desired-state.json` (full desired state for affected namespaces), (2) `apply.sh` (idempotent apply script), (3) `verify.sh` (post-apply invariants), (4) `rollback.sh` (revert to previous state), (5) `manifest.sig` (signature with `cluster/master.key`). Atomicity across N peers: the CLI uploads the bundle to the lead; the lead applies to itself first, then fans out to peers via SSH. If any peer fails verify, the lead runs `rollback.sh` on all peers that applied. The bundle is content-addressed (` = sha256(desired-state.json)`) and stored in `cluster/txns//`. Drift detection (R-010) compares the last applied bundle's desired-state against the live state (polled via SSH `systemctl show` + file checksums). **Gated by grill C-09** (orca-pull.sh failure contract: idempotent re-run, bounded retry, deterministic state, structured syslog). +- **Description**: R-010 requires transactional control-plane updates. §23 puts this in v0.10-P10. Design: a *transaction bundle* is a tarball containing: (1) `desired-state.json` (full desired state for affected namespaces), (2) `apply.sh` (idempotent apply script), (3) `verify.sh` (post-apply invariants), (4) `rollback.sh` (revert to previous state), (5) `manifest.sig` (signature with `cluster/master.key`). Atomicity across N peers: the CLI uploads the bundle to the lead; the lead applies to itself first, then fans out to peers via SSH. If any peer fails verify, the lead runs `rollback.sh` on all peers that applied. The bundle is content-addressed (` = sha256(desired-state.json)`) and stored in `cluster/txns//`. Drift detection (R-010) compares the last applied bundle's desired-state against the live state (polled via SSH `systemctl show` + file checksums). **Gated by grill C-09** (orca-pull.sh failure contract: idempotent re-run, bounded retry, deterministic state, structured syslog). - **Rationale**: Multi-peer atomicity is the hardest part of R-010. §23 says "ArgoCD-style" but ArgoCD is Kubernetes-native; the SSH-push model needs a custom bundle format. - **Proposed REQ ID**: REQ-079 -- **Proposed phase placement**: v1.0-P10 (transactional plane) — designed in v0.9-P00 +- **Proposed phase placement**: v0.10-P10 (transactional plane) — designed in v0.9-P00 - **Confidence**: 0.76 - **Accept/Defer**: accept ### I-B-008 — Master key management and HKDF-SHA256 per-line .env.secrets encryption - **Tier**: backend-enriched -- **Description**: R-011 specifies `.env.secrets` with AES-256-GCM, per-line nonce, master key at `cluster/master.key`. §23 puts this in v1.0-P03. Design: (1) `cluster/master.key` is a 32-byte random key generated by `orca init` (extend v0.8 `internal/security/ca.go`'s `WriteAtomic` pattern for the file write). (2) Each line of `.env.secrets` is `base64(nonce || ciphertext || tag)` where `nonce = random(12 bytes)` and `ciphertext = AES-256-GCM(plaintext, key=master.key, nonce, aad=line-number)`. (3) The AAD is the 1-indexed line number to prevent line-swap attacks. (4) Decryption reads the master key, iterates lines, decrypts with AAD. (5) `orca secrets set ` appends an encrypted line; `orca secrets get ` decrypts and prints (redacted by default, `--reveal` to show). (6) The v0.8 `internal/security/redact.go` (103 LOC) is directly reusable for redaction. HKDF-SHA256 derives per-namespace sub-keys from the master key (`HKDF-SHA256(master, info=)`) so compromising one namespace's key doesn't compromise others — but the master key is the root of trust. **Gated by grill C-19** (threat model for master.key passphrase-less posture). +- **Description**: R-011 specifies `.env.secrets` with AES-256-GCM, per-line nonce, master key at `cluster/master.key`. §23 puts this in v0.10-P03. Design: (1) `cluster/master.key` is a 32-byte random key generated by `orca init` (extend v0.8 `internal/security/ca.go`'s `WriteAtomic` pattern for the file write). (2) Each line of `.env.secrets` is `base64(nonce || ciphertext || tag)` where `nonce = random(12 bytes)` and `ciphertext = AES-256-GCM(plaintext, key=master.key, nonce, aad=line-number)`. (3) The AAD is the 1-indexed line number to prevent line-swap attacks. (4) Decryption reads the master key, iterates lines, decrypts with AAD. (5) `orca secrets set ` appends an encrypted line; `orca secrets get ` decrypts and prints (redacted by default, `--reveal` to show). (6) The v0.8 `internal/security/redact.go` (103 LOC) is directly reusable for redaction. HKDF-SHA256 derives per-namespace sub-keys from the master key (`HKDF-SHA256(master, info=)`) so compromising one namespace's key doesn't compromise others — but the master key is the root of trust. **Gated by grill C-19** (threat model for master.key passphrase-less posture). - **Rationale**: R-011 is precise about the crypto but §23 doesn't specify key derivation, AAD, or CLI surface. The existing `redact.go` and `WriteAtomic` are reusable. - **Proposed REQ ID**: REQ-080 -- **Proposed phase placement**: v1.0-P03 (secrets subsystem) +- **Proposed phase placement**: v0.10-P03 (secrets subsystem) - **Confidence**: 0.84 - **Accept/Defer**: accept @@ -234,10 +234,10 @@ the PRD §23 plan are listed at the end. ### I-B-012 — `orca job lint` category-driven lint engine design - **Tier**: backend-enriched -- **Description**: v1.0-P11 requires `orca job lint` with `--explain`. Design: a `Linter` that takes a `*WorkloadSpec` and runs a series of `Rule` checks, each returning a `Finding{Category, Severity, Message, Explanation}`. Categories: `schema` (missing required fields), `runtime` (incompatible runtime+constraint), `security` (missing SVID, plaintext secret in env), `migration` (missing storage replication for a migratable service), `best-practice` (no health check on a Service). `--explain` prints the rationale for each finding. Rules are registered in a `ruleRegistry` and individually testable. The linter is pure (no I/O) — it checks the spec against static rules, not live cluster state (that's `orca job verify`, P12). +- **Description**: v0.10-P11 requires `orca job lint` with `--explain`. Design: a `Linter` that takes a `*WorkloadSpec` and runs a series of `Rule` checks, each returning a `Finding{Category, Severity, Message, Explanation}`. Categories: `schema` (missing required fields), `runtime` (incompatible runtime+constraint), `security` (missing SVID, plaintext secret in env), `migration` (missing storage replication for a migratable service), `best-practice` (no health check on a Service). `--explain` prints the rationale for each finding. Rules are registered in a `ruleRegistry` and individually testable. The linter is pure (no I/O) — it checks the spec against static rules, not live cluster state (that's `orca job verify`, P12). - **Rationale**: §23 puts this in P11 but only says "category-driven." The rule interface and category taxonomy are unspecified. - **Proposed REQ ID**: REQ-084 -- **Proposed phase placement**: v1.0-P11 (orca job lint) +- **Proposed phase placement**: v0.10-P11 (orca job lint) - **Confidence**: 0.78 - **Accept/Defer**: accept @@ -245,28 +245,28 @@ the PRD §23 plan are listed at the end. ### I-C-001 — v0.8→v1.0 migration ordering: daemon deprecation vs. new model rollout - **Tier**: cross-cutting -- **Description**: The PRD §24 covers *data* migration but not *binary/daemon* deprecation ordering. The risk: v0.9 builds the new Markdown+kinds+runtime+SSH-push model, but v0.8 daemons are still running on peers. If v0.9 ships the new `orca job run` (Markdown) while the old daemon is still the execution engine, there's a split-brain: new specs can't run on the old daemon. Ordering proposal: (1) v0.9 ships the new parser + kinds + runtime + SSH-push *alongside* the old daemon (dual-write window); (2) `orca job run` in v0.9 uses the new SSH-push path if the spec is `.md` and the old daemon path if `.hcl`; (3) v1.0-P05 (drain) stops the old daemons; (4) v1.0-P14 (migration) converts remaining `.hcl` specs to `.md` and removes the daemon. The dual-write window means v0.9 is *not* a clean break — it's a compatibility milestone. This must be explicit in the plan or the v0.9 phases will assume the daemon is gone. +- **Description**: The PRD §24 covers *data* migration but not *binary/daemon* deprecation ordering. The risk: v0.9 builds the new Markdown+kinds+runtime+SSH-push model, but v0.8 daemons are still running on peers. If v0.9 ships the new `orca job run` (Markdown) while the old daemon is still the execution engine, there's a split-brain: new specs can't run on the old daemon. Ordering proposal: (1) v0.9 ships the new parser + kinds + runtime + SSH-push *alongside* the old daemon (dual-write window); (2) `orca job run` in v0.9 uses the new SSH-push path if the spec is `.md` and the old daemon path if `.hcl`; (3) v0.10-P05 (drain) stops the old daemons; (4) v0.10-P14 (migration) converts remaining `.hcl` specs to `.md` and removes the daemon. The dual-write window means v0.9 is *not* a clean break — it's a compatibility milestone. This must be explicit in the plan or the v0.9 phases will assume the daemon is gone. - **Rationale**: Single largest risk in the re-architecture. §23 implicitly assumes v0.9 builds the new model in isolation, but existing deployments have running daemons. Getting the ordering wrong means either (a) v0.9 can't be tested against real deployments, or (b) workloads are orphaned when the daemon is removed. - **Proposed REQ ID**: REQ-085 -- **Proposed phase placement**: spans v0.9-P00 through v1.0-P14 — the *ordering decision* must be made in v0.9-P00 +- **Proposed phase placement**: spans v0.9-P00 through v0.10-P14 — the *ordering decision* must be made in v0.9-P00 - **Confidence**: 0.88 - **Accept/Defer**: accept (most important idea in this report) ### I-C-002 — "No orca on server" enforcement (doctor post-migration invariant check) - **Tier**: cross-cutting -- **Description**: R-001 is an invariant: "no orca Go binary on any server." §23 v1.0-P14 says "post-invariant checks" but doesn't specify them. `orca doctor` must gain a `doctor no-orca-on-server` check that SSHs to each peer and verifies: (1) no `orca` binary in PATH (`ssh peer which orca` returns nothing), (2) no `orca` systemd service (`ssh peer systemctl list-units 'orca*'` returns empty), (3) no `orca` process (`ssh peer pgrep -x orca` returns empty), (4) no `/etc/orca/` directory. This check must run *after* v1.0-P05 (drain) and *before* v1.0-P16 (ship). The v0.8 `internal/proxmox/bootstrap.go` already has the SSH session infrastructure (`sessionRunner` seam) — directly reusable for the doctor check. +- **Description**: R-001 is an invariant: "no orca Go binary on any server." §23 v0.10-P14 says "post-invariant checks" but doesn't specify them. `orca doctor` must gain a `doctor no-orca-on-server` check that SSHs to each peer and verifies: (1) no `orca` binary in PATH (`ssh peer which orca` returns nothing), (2) no `orca` systemd service (`ssh peer systemctl list-units 'orca*'` returns empty), (3) no `orca` process (`ssh peer pgrep -x orca` returns empty), (4) no `/etc/orca/` directory. This check must run *after* v0.10-P05 (drain) and *before* v0.10-P16 (ship). The v0.8 `internal/proxmox/bootstrap.go` already has the SSH session infrastructure (`sessionRunner` seam) — directly reusable for the doctor check. - **Rationale**: R-001 is a hard invariant but §23 doesn't enforce it post-migration. Without this check, a failed migration could leave orphaned daemons that cause split-brain. - **Proposed REQ ID**: REQ-086 -- **Proposed phase placement**: v1.0-P14c (mixed-version tolerance) +- **Proposed phase placement**: v0.10-P14c (mixed-version tolerance) - **Confidence**: 0.82 - **Accept/Defer**: accept ### I-C-003 — Test infrastructure: hermetic 3-linux + 1-proxmox cluster pipeline - **Tier**: cross-cutting -- **Description**: §23 v1.0-P08 requires "hermetic CoreCI integration pipeline." The PRD §26.E mentions 3 linux + 1 proxmox. This is net-new test infra with zero current implementation. Design: (1) a `test/integration/` directory with a `docker-compose.yml` or `vagrant` setup that creates 4 containers/VMs (3 linux + 1 proxmox-simulated); (2) a Go test harness that SSHes to each, runs the CLI, and asserts end-to-end workflows (namespace create → workload submit → migrate → drain); (3) the proxmox node is simulated via a mock `pct`/`qm` script (the v0.8 `proxmox` package already has a `sessionRunner` seam for testability — extend it). The integration tests run in CoreCI on every milestone merge. The v0.8 e2e tests (`bootstrapE2ESetup` in `bootstrap_test.go`) use an in-process SSH server — this is the foundation but needs to scale to 4 nodes. +- **Description**: §23 v0.10-P08 requires "hermetic CoreCI integration pipeline." The PRD §26.E mentions 3 linux + 1 proxmox. This is net-new test infra with zero current implementation. Design: (1) a `test/integration/` directory with a `docker-compose.yml` or `vagrant` setup that creates 4 containers/VMs (3 linux + 1 proxmox-simulated); (2) a Go test harness that SSHes to each, runs the CLI, and asserts end-to-end workflows (namespace create → workload submit → migrate → drain); (3) the proxmox node is simulated via a mock `pct`/`qm` script (the v0.8 `proxmox` package already has a `sessionRunner` seam for testability — extend it). The integration tests run in CoreCI on every milestone merge. The v0.8 e2e tests (`bootstrapE2ESetup` in `bootstrap_test.go`) use an in-process SSH server — this is the foundation but needs to scale to 4 nodes. - **Rationale**: §23 assumes the infra exists but doesn't design it. devops-engineer persona should be reactivated. Without hermetic infra, the integration tests can't run in CI. - **Proposed REQ ID**: REQ-087 -- **Proposed phase placement**: v1.0-P08 (integration tests) — harness bootstrapped in v0.9-P00 +- **Proposed phase placement**: v0.10-P08 (integration tests) — harness bootstrapped in v0.9-P00 - **Confidence**: 0.80 - **Accept/Defer**: accept @@ -275,22 +275,22 @@ the PRD §23 plan are listed at the end. - **Description**: The config.json has `security-engineer` and `network-engineer` dormant. The re-architecture introduces step-ca (PKI), Traefik (edge proxy), Syncthing (P2P file sync), wasmtime (sandbox), podman (container runtime) — all new attack surfaces. AD-010 (step-ca rejection) is reversed. The v0.8 security posture (internal CA, mTLS daemon-to-daemon) is replaced by (step-ca, SSH-push, Traefik mTLS). The security-engineer persona must be reactivated to review: (1) step-ca provisioner model (the CLI holds the provisioner password — is that in `cluster/master.key` or a separate secret?), (2) SSH-push blast radius (compromised CLI key = full cluster), (3) Traefik as the new edge (DoS, config injection), (4) `.env.secrets` crypto (I-B-008). The network-engineer persona must review: (1) socket-based service exposure (R-007), (2) Syncthing P2P ports, (3) Traefik routing. §23 doesn't mention persona reactivation. - **Rationale**: config.json explicitly notes the re-architecture "should reactivate security-engineer and network-engineer." Cross-cutting review concern, not a single phase. - **Proposed REQ ID**: REQ-088 -- **Proposed phase placement**: spans v0.9 through v1.0 — reactivation in v0.9-P00, review at v1.0-P15.5 (threat model) and v1.0-P16 (final audit) +- **Proposed phase placement**: spans v0.9 through v0.10 — reactivation in v0.9-P00, review at v0.10-P15.5 (threat model) and v0.10-P16 (final audit) - **Confidence**: 0.84 - **Accept/Defer**: accept ### I-C-005 — Documentation rewrite: ARCHITECTURE.md, PROJECT.md, README, AD-010 supersession - **Tier**: cross-cutting -- **Description**: All three docs describe the OLD architecture. `ARCHITECTURE.md` (640 lines) describes the daemon layer, mTLS transport, internal CA, HCL jobspec — all deprecated. `PROJECT.md` (30k chars) has D-001..D-010 decisions, several now superseded. `README.md` has the v0.8 quickstart. AD-010 (step-ca rejection) must be explicitly superseded by D-101 with a dated rationale reversal. The anti-patterns section in `ARCHITECTURE.md:471-484` lists "No external PKI" — now reversed. Proposal: (1) in v0.9-P00, add a "v0.9 Architecture (Supersedes v0.8)" section to ARCHITECTURE.md with the new 4-layer model; (2) mark the old sections as "v0.8 (deprecated)" with banners; (3) add a "Superseded Decisions" table (AD-009, AD-010 reversed by D-101; AD-007 HCL demoted by R-013); (4) in v1.0-P15, rewrite README quickstart for the new `curl | sh` + `orca init` + `orca ns create` flow. +- **Description**: All three docs describe the OLD architecture. `ARCHITECTURE.md` (640 lines) describes the daemon layer, mTLS transport, internal CA, HCL jobspec — all deprecated. `PROJECT.md` (30k chars) has D-001..D-010 decisions, several now superseded. `README.md` has the v0.8 quickstart. AD-010 (step-ca rejection) must be explicitly superseded by D-101 with a dated rationale reversal. The anti-patterns section in `ARCHITECTURE.md:471-484` lists "No external PKI" — now reversed. Proposal: (1) in v0.9-P00, add a "v0.9 Architecture (Supersedes v0.8)" section to ARCHITECTURE.md with the new 4-layer model; (2) mark the old sections as "v0.8 (deprecated)" with banners; (3) add a "Superseded Decisions" table (AD-009, AD-010 reversed by D-101; AD-007 HCL demoted by R-013); (4) in v0.10-P15, rewrite README quickstart for the new `curl | sh` + `orca init` + `orca ns create` flow. - **Rationale**: The docs are the first thing new contributors read. Leaving v0.8 docs as canonical during v0.9 development causes confusion. §23 mentions README in P15 but not ARCHITECTURE.md/PROJECT.md. - **Proposed REQ ID**: REQ-089 -- **Proposed phase placement**: v0.9-P00 (banners + supersession table) + v1.0-P15 (README quickstart) + v1.0-P16 (final review) +- **Proposed phase placement**: v0.9-P00 (banners + supersession table) + v0.10-P15 (README quickstart) + v0.10-P16 (final review) - **Confidence**: 0.82 - **Accept/Defer**: accept ### I-C-006 — Dual-write window: can v0.9 ship new parser while old daemon runs? - **Tier**: cross-cutting -- **Description**: Focused version of I-C-001. The specific question: in v0.9, when the new Markdown parser + kinds + SSH-push are shipped, can they coexist with v0.8 daemons still running on peers? The answer depends on whether `orca job run ` uses the new SSH-push path (bypassing the daemon entirely) or routes through the old daemon. If it bypasses, the daemon is irrelevant for new specs but still serves old `.hcl` specs. If it routes through, the daemon can't handle `.md` specs. Proposal: v0.9 `orca job run` dispatches on extension (`.md`→SSH-push new path, `.hcl`→old daemon path) via the parser dispatcher (I-M-004). This is a *dual-write window* where both paths coexist. The daemon is not removed until v1.0-P05 (drain). The risk: if a `.md` workload and a `.hcl` workload target the same node, the SSH-push path writes systemd units directly while the daemon also manages units — they can conflict. Mitigation: the SSH-push path writes to a separate systemd unit namespace (`orca-v1-.service`) while the daemon uses `orca-.service`. No unit name overlap = no conflict. +- **Description**: Focused version of I-C-001. The specific question: in v0.9, when the new Markdown parser + kinds + SSH-push are shipped, can they coexist with v0.8 daemons still running on peers? The answer depends on whether `orca job run ` uses the new SSH-push path (bypassing the daemon entirely) or routes through the old daemon. If it bypasses, the daemon is irrelevant for new specs but still serves old `.hcl` specs. If it routes through, the daemon can't handle `.md` specs. Proposal: v0.9 `orca job run` dispatches on extension (`.md`→SSH-push new path, `.hcl`→old daemon path) via the parser dispatcher (I-M-004). This is a *dual-write window* where both paths coexist. The daemon is not removed until v0.10-P05 (drain). The risk: if a `.md` workload and a `.hcl` workload target the same node, the SSH-push path writes systemd units directly while the daemon also manages units — they can conflict. Mitigation: the SSH-push path writes to a separate systemd unit namespace (`orca-v1-.service`) while the daemon uses `orca-.service`. No unit name overlap = no conflict. - **Rationale**: Operational feasibility question for v0.9. §23 doesn't address it. If the answer is "no dual-write, daemon must be removed first," then v0.9 can't be tested incrementally and must ship as a big-bang — much higher risk. - **Proposed REQ ID**: REQ-090 - **Proposed phase placement**: v0.9-P00 (decision before any v0.9 execution phase) @@ -301,35 +301,35 @@ the PRD §23 plan are listed at the end. | ID | Tier | Title | REQ | Phase | Conf | Accept | |----|------|-------|-----|-------|------|--------| -| I-M-001 | M | `orca daemon` deprecation path | REQ-061 | v1.0-P14 (warn v0.9-P0X) | 0.82 | accept | +| I-M-001 | M | `orca daemon` deprecation path | REQ-061 | v0.10-P14 (warn v0.9-P0X) | 0.82 | accept | | I-M-002 | M | Coverage follow-ups to 70% | REQ-062 | v0.9-P0X + each new pkg | 0.88 | accept | | I-M-003 | M | known_hosts flock concurrency | REQ-063 | v0.9-P0a1 | 0.74 | accept | | I-M-004 | M | HCL→Markdown jobspec adapter | REQ-064 | v0.9-P0b | 0.85 | accept | -| I-M-005 | M | `doctor --legacy-paths` detection | REQ-065 | v1.0-P14c | 0.80 | accept | -| I-M-006 | M | Legacy CA state migration to step-ca | REQ-066 | v1.0-P14a | 0.70 | accept | +| I-M-005 | M | `doctor --legacy-paths` detection | REQ-065 | v0.10-P14c | 0.80 | accept | +| I-M-006 | M | Legacy CA state migration to step-ca | REQ-066 | v0.10-P14a | 0.70 | accept | | I-M-007 | M | Fuzz harness for Markdown parser | REQ-067 | v0.9-P0b | 0.78 | accept | -| I-M-008 | M | Deprecation warnings on CLI subcommands | REQ-068 | v0.9-P0X + v1.0-P13 | 0.72 | accept | +| I-M-008 | M | Deprecation warnings on CLI subcommands | REQ-068 | v0.9-P0X + v0.10-P13 | 0.72 | accept | | I-M-009 | M | HCL config demotion via adapter | REQ-069 | v0.9-P0a1 | 0.76 | accept | | I-M-010 | M | certpaths → multi-namespace path resolver | REQ-070 | v0.9-P0a1 | 0.84 | accept | -| I-M-011 | M | store schema: per-namespace DBs | REQ-071 | v0.9-P0a1 + v1.0-P06 | 0.80 | accept | -| I-M-012 | M | transport deletion + SSH-push package | REQ-072 | v0.9-P00 (delete v1.0-P14) | 0.68 | accept | +| I-M-011 | M | store schema: per-namespace DBs | REQ-071 | v0.9-P0a1 + v0.10-P06 | 0.80 | accept | +| I-M-012 | M | transport deletion + SSH-push package | REQ-072 | v0.9-P00 (delete v0.10-P14) | 0.68 | accept | | I-B-001 | B | SSH-push transport layer design | REQ-073 | v0.9-P01 | 0.86 | accept | | I-B-002 | B | Emitter template system (Layer 4) | REQ-074 | v0.9-P0c | 0.82 | accept | -| I-B-003 | B | Lead applier execution model | REQ-075 | v1.0-P10 (design v0.9-P00) | 0.78 | accept | -| I-B-004 | B | step-ca integration | REQ-076 | v0.9-P07 + v1.0-P02 | 0.74 | accept | +| I-B-003 | B | Lead applier execution model | REQ-075 | v0.10-P10 (design v0.9-P00) | 0.78 | accept | +| I-B-004 | B | step-ca integration | REQ-076 | v0.9-P07 + v0.10-P02 | 0.74 | accept | | I-B-005 | B | Traefik dynamic config + atomic reload | REQ-077 | v0.9-P02 | 0.80 | accept | | I-B-006 | B | Runtime abstraction (5 backends) | REQ-078 | v0.9-P07a/b/c | 0.82 | accept | -| I-B-007 | B | Transaction bundle + N-peer atomicity | REQ-079 | v1.0-P10 (design v0.9-P00) | 0.76 | accept | -| I-B-008 | B | Master key + HKDF per-line encryption | REQ-080 | v1.0-P03 | 0.84 | accept | +| I-B-007 | B | Transaction bundle + N-peer atomicity | REQ-079 | v0.10-P10 (design v0.9-P00) | 0.76 | accept | +| I-B-008 | B | Master key + HKDF per-line encryption | REQ-080 | v0.10-P03 | 0.84 | accept | | I-B-009 | B | Syncthing config + folder-ID | REQ-081 | v0.9-P09 | 0.72 | accept | | I-B-010 | B | Namespace inheritance resolver | REQ-082 | v0.9-P0a2 | 0.86 | accept | | I-B-011 | B | CLI-side scheduler redesign | REQ-083 | v0.9-P05 (skeleton P0c) | 0.80 | accept | -| I-B-012 | B | `orca job lint` category-driven engine | REQ-084 | v1.0-P11 | 0.78 | accept | -| I-C-001 | C | v0.8→v1.0 migration ordering | REQ-085 | spans v0.9-P00→v1.0-P14 | 0.88 | accept | -| I-C-002 | C | "No orca on server" enforcement | REQ-086 | v1.0-P14c | 0.82 | accept | -| I-C-003 | C | Hermetic test infra (3 linux + 1 pve) | REQ-087 | v1.0-P08 (bootstrap v0.9-P00) | 0.80 | accept | -| I-C-004 | C | security/network persona reactivation | REQ-088 | spans v0.9→v1.0-P16 | 0.84 | accept | -| I-C-005 | C | Docs rewrite + AD-010 supersession | REQ-089 | v0.9-P00 + v1.0-P15/P16 | 0.82 | accept | +| I-B-012 | B | `orca job lint` category-driven engine | REQ-084 | v0.10-P11 | 0.78 | accept | +| I-C-001 | C | v0.8→v1.0 migration ordering | REQ-085 | spans v0.9-P00→v0.10-P14 | 0.88 | accept | +| I-C-002 | C | "No orca on server" enforcement | REQ-086 | v0.10-P14c | 0.82 | accept | +| I-C-003 | C | Hermetic test infra (3 linux + 1 pve) | REQ-087 | v0.10-P08 (bootstrap v0.9-P00) | 0.80 | accept | +| I-C-004 | C | security/network persona reactivation | REQ-088 | spans v0.9→v0.10-P16 | 0.84 | accept | +| I-C-005 | C | Docs rewrite + AD-010 supersession | REQ-089 | v0.9-P00 + v0.10-P15/P16 | 0.82 | accept | | I-C-006 | C | Dual-write window decision | REQ-090 | v0.9-P00 | 0.86 | accept | ## Phase Reordering / Addition Flags (against PRD §23) @@ -339,8 +339,8 @@ the PRD §23 plan are listed at the end. 3. **I-B-001 (SSH-push transport)** — §23 v0.9-P01 needs SSH-push. The design is a prerequisite. **Recommendation: SSH-push design in P0a1, not deferred to P01.** 4. **I-B-002 (emitter template system)** — should be designed *with* the schemas (P0c). **Recommendation: expand P0c to "schemas + emitter interface."** 5. **I-B-003 (lead applier model)** — bundle format + lead applier model must be designed *in v0.9* so the emitter can produce bundle-compatible output. **Recommendation: design spike in v0.9-P00.** -6. **I-C-003 (test infra)** — hermetic cluster harness should be bootstrapped in v0.9-P00 so every v0.9 phase can run integration tests. **Recommendation: bootstrap in v0.9-P00, expand in v1.0-P08.** -7. **I-C-004 / I-C-005 (persona reactivation + docs)** — span the whole milestone. **Recommendation: fold persona reviews into v0.9-P00 and v1.0-P16; fold doc banners into v0.9-P00.** +6. **I-C-003 (test infra)** — hermetic cluster harness should be bootstrapped in v0.9-P00 so every v0.9 phase can run integration tests. **Recommendation: bootstrap in v0.9-P00, expand in v0.10-P08.** +7. **I-C-004 / I-C-005 (persona reactivation + docs)** — span the whole milestone. **Recommendation: fold persona reviews into v0.9-P00 and v0.10-P16; fold doc banners into v0.9-P00.** ## Cross-Reference Against Existing Decisions diff --git a/.ciagent/PRD_v0.9.md b/.ciagent/PRD_v0.9.md index 89648d4..53ea7c0 100644 --- a/.ciagent/PRD_v0.9.md +++ b/.ciagent/PRD_v0.9.md @@ -1,8 +1,8 @@ -# Orca — Comprehensive Product Requirements Document (v0.9/v1.0) +# Orca — Comprehensive Product Requirements Document (v0.9/v0.10) **Audience:** Operators, AI agents, downstream tooling authors -> This PRD SUPERSEDES the shipped v0.1–v0.8 architecture. The v0.9 and v1.0 +> This PRD SUPERSEDES the shipped v0.1–v0.8 architecture. The v0.9 and v0.10 > milestones implement a re-architecture whose load-bearing rules (R-001…R-016) > and decisions (D-068…D-206) replace or demote several earlier documented > decisions. See §22 decision-trace and the Supersession Table in @@ -15,13 +15,13 @@ | Spec lock-in | ✅ R-001…R-016 + D-001…D-206 settled | | v0.1–v0.8 implementation | ✅ shipped (REQ-001..060, D-001..D-047) | | v0.9 implementation | ⬜ Phase 0 pre-execution (this file is the spec input) | -| v1.0 implementation | ⬜ planning (post-PRD) | +| v0.10 implementation | ⬜ planning (post-PRD) | | v1.x multi-host state | ⬜ parked (post-v1.0) | | v2.x full Nomad-HCL | ⬜ parked (post-v1.x) | ## Override justification (recorded for the grill supersession) -The v0.9/v1.0 re-architecture is justified on six independent grounds rather +The v0.9/v0.10 re-architecture is justified on six independent grounds rather than preference. Each reverses a prior documented decision; the new evidence basis is recorded with the reversal in the Supersession Table: @@ -54,7 +54,7 @@ that source; the substantive planning artifacts live in: - `IDEATION_v0.9.md` — 30 ideas (REQ-061..REQ-090), three tiers - `GRILL_v0.9.md` — 9-axis adversarial review, 19 binding conditions, 10 phase challenges - `REQUIREMENTS.md` — REQ-061..REQ-090 appended -- `ROADMAP.md` — v0.9 (13 phases) + v1.0 (19 phases) appended +- `ROADMAP.md` — v0.9 (13 phases) + v0.10 (19 phases) appended - `PERSONAS.md` — security/network/devops reactivated - `ARCHITECTURE.md` — v0.9 banners + Supersession Table @@ -70,7 +70,7 @@ that source; the substantive planning artifacts live in: | R-006 | mTLS on by default; cluster CA = step-ca; Traefik + `LoadCredential=` are load-bearing. | | R-007 | Sockets by default (`/run/orca/alloc-/port-.sock`); `127.0.0.1` opt-in. | | R-008 | CLI results cached locally with per-class TTLs (`orca_cache` SQLite). | -| R-009 | CLI host SPOF mitigated by external shared state in v1.x; v1.0 ships the abstractions + cache layer. | +| R-009 | CLI host SPOF mitigated by external shared state in v1.x; v0.10 ships the abstractions + cache layer. | | R-010 | Control plane updates are transactional (ArgoCD-style desired-state/lead-applier). | | R-011 | Each namespace has `.env` (plaintext) and `.env.secrets` (AES-256-GCM, per-line nonce); master key per `ORCA_HOME` at `cluster/master.key`. | | R-012 | Workload kinds are `Job`, `Service`, `DaemonSet`; schema-separated by `kind:` in frontmatter. | @@ -84,7 +84,7 @@ that source; the substantive planning artifacts live in: ### v0.9 — Workloads + Re-architecture Foundation (13 phases) P00 (deprecation sweep + migration-ordering + txn-design spike + test-infra bootstrap + persona reactivation + doc banners), P0a1 (path resolver + config demotion), P0a2 (namespace CRUD + inheritance), P0b (Markdown jobspec parser + fuzz), P0c (schemas + emitter interface), P01 (SSH-push transport + host-path volumes), P02 (service + Traefik emitter), P03 (update stanza), P04 (lifecycle hooks), P05 (constraints + CLI-side scheduler), P06 (task groups), P07a/P07b/P07c (process+podman / wasmtime [C-01 gated] / pve-vm+ct runtimes), P08 (sockets), P09 (Syncthing [C-02 gated]), P10 (lead rules + migration), P0X (ship + audit). -### v1.0 — Production Hardening (19 phases) +### v0.10 — Production Hardening (19 phases) P00 (CLI cache), P01 (metrics), P01.5 (SPIFFE spike [C-08 gated]), P02 (ACL), P03 (secrets), P04 (backup/restore), P05 (drain + daemon drain-and-stop), P06 (alloc history), P07 (recovery), P08 (integration tests), P09 (collector+aggregator), P10 (transactional plane [C-09 gated]), P11 (job lint), P12 (job verify), P13 (ns subcommands), P14a/P14b/P14c (data / daemon cutover / mixed-version tolerance), P15 (README), P15.5 (threat model [C-19 gated]), P16 (final review + ship — v1.0.0 release). See `ROADMAP.md` for the full reordered plan and `GRILL_v0.9.md` for the 19 diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index dfffff6..cf95938 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -380,7 +380,7 @@ within the `clarify_budget` (10): --- -# v0.9/v1.0 — Re-architecture Scope Summary (Supersedes v0.1–v0.8 architecture) +# v0.9/v0.10 — Re-architecture Scope Summary (Supersedes v0.1–v0.8 architecture) v0.9 is the first DIRECTION-CHANGE milestone in the project's history. It supersedes the shipped v0.1–v0.8 architecture per the adopted PRD @@ -439,7 +439,7 @@ are recorded in `REQUIREMENTS.md`. The reordered phase plan is in | ID | Question | Decision | Rationale | Confidence | |----|----------|----------|-----------|------------| | D-101 | Cluster CA: internal Go CA (AD-010) or step-ca (external)? | **step-ca (apt-installed)** | Externally mandated per override ground 2; AD-010's "too heavyweight" rationale reversed. CLI wraps `step` CLI via SSH (no Go step-ca client library — keep zero-new-dep posture if possible, or add `github.com/smallstep/cli` as a dep). **Gated by C-07** (CA migration spec). | 0.74 | -| D-068 | Workload identity: internal X.509 CA or SPIFFE SVIDs? | **SPIFFE SVIDs minted at submit time via step-ca** | Multi-tenancy (override ground 3) requires per-workload identity model; SPIFFE is the standard. SPIFFE ID `spiffe://orca/ns//job//alloc/` as SAN. **Gated by C-08** (mint spike in v1.0-P01.5; fallback to mTLS identity if spike fails). | 0.72 | +| D-068 | Workload identity: internal X.509 CA or SPIFFE SVIDs? | **SPIFFE SVIDs minted at submit time via step-ca** | Multi-tenancy (override ground 3) requires per-workload identity model; SPIFFE is the standard. SPIFFE ID `spiffe://orca/ns//job//alloc/` as SAN. **Gated by C-08** (mint spike in v0.10-P01.5; fallback to mTLS identity if spike fails). | 0.72 | | D-088 | Runtime: direct os/exec only (D-008) or multi-runtime? | **5 runtimes: wasm (wasmtime primary), podman, process, pve-vm, pve-ct** | WASM is the primary workload (override ground 4). `processRuntime` wraps existing `executor.go`; others are net-new. Split P07a/b/c per grill PC-10. **P07b gated by C-01** (wasmtime/CGO eval). | 0.82 | | D-158 | Namespace model: single flat root or multi-namespace? | **Multi-namespace under ORCA_HOME (R-002)** | Hard multi-tenant product requirement (override ground 3). `_defaults/` implicit root; `cluster/` for cluster-wide; per-namespace `db/`, `.env`, `.env.secrets`, `jobs/`, `alloc/`, `ns.md`. No namespace column in SQLite. | 0.84 | | D-179 | Jobspec format: HCL canonical (AD-007) or Markdown? | **Markdown with YAML frontmatter canonical (R-013); HCL legacy** | PRD §8 — Markdown + body preservation is the operator-facing format. HCL adapter (REQ-064) preserves `orca job run old-spec.hcl` during migration. | 0.85 | diff --git a/.ciagent/REQUIREMENTS.md b/.ciagent/REQUIREMENTS.md index 202cee7..6c39218 100644 --- a/.ciagent/REQUIREMENTS.md +++ b/.ciagent/REQUIREMENTS.md @@ -141,9 +141,9 @@ REQ-047..052 all complete. | REQ-059 | `orca node key-reset ` command: clears the persisted SSH host key entry for the node from `~/.orca/known_hosts` only (local, not remote authorized_keys — D-046); audit-logs `event=node.key_reset`; next `doctor proxmox`/dispatch re-pins via TOFU or `--host-key-fingerprint` | Low | **v0.8 P2** | **Complete** (P2 shipped v0.7.2) | | REQ-060 | Requirement-status hygiene sweep: REQUIREMENTS.md v0.7 rows were stale ("Pending" after ship); add a verify-stage assertion that every REQ listed as `Complete` in ROADMAP.md has a matching `Complete` row in REQUIREMENTS.md, enforced by `make verify-reqs` | Medium | **v0.8 P3** | **Complete** (P3 shipped v0.7.3) | -## v0.9/v1.0 Requirements — Re-architecture Foundation & Production Hardening +## v0.9/v0.10 Requirements — Re-architecture Foundation & Production Hardening -The v0.9/v1.0 milestones supersede the shipped v0.1–v0.8 architecture per the +The v0.9/v0.10 milestones supersede the shipped v0.1–v0.8 architecture per the adopted PRD (`.ciagent/PRD_v0.9.md`). The re-architecture is justified on six grounds recorded in the PROJECT.md Supersession Table. 30 net-new requirements (REQ-061..REQ-090) derive from the v0.9 IDEATION; their phase placement and @@ -152,33 +152,33 @@ and `GRILL_v0.9.md`. | ID | Requirement | Priority | Phase | Status | |----|-------------|----------|-------|--------| -| REQ-061 | `orca daemon` deprecation command and build-tag removal path: v0.9 emits deprecation warning + still runs (dual-write window); v1.0 repurposes to `orca daemon drain-and-stop` (stops v0.8 daemons on peers via SSH, confirms workloads survive via systemd); post-v1.0 the command and `internal/daemon/` are deleted. `// Deprecated` Go doc comments + `slog.Warn` on every run (I-M-001) | High | **v1.0 P14** (warn v0.9 P0X) | Pending | +| REQ-061 | `orca daemon` deprecation command and build-tag removal path: v0.9 emits deprecation warning + still runs (dual-write window); v1.0 repurposes to `orca daemon drain-and-stop` (stops v0.8 daemons on peers via SSH, confirms workloads survive via systemd); post-v1.0 the command and `internal/daemon/` are deleted. `// Deprecated` Go doc comments + `slog.Warn` on every run (I-M-001) | High | **v0.10 P14** (warn v0.9 P0X) | Pending | | REQ-062 | Coverage follow-ups: 3 zero-test packages (`internal/audit`, `internal/certpaths`, `cmd/orca`) + `internal/cli` to 70% floor; once `daemon.go` is deprecated/removed the exclusion reason disappears and the floor applies to the whole package; all net-new subsystems carry a 70% floor from their first phase (I-M-002) | Medium | **v0.9 P0X** + each new pkg | Pending | | REQ-063 | `known_hosts` flock concurrency gap (deferred P1 from REVIEW_v0.8 A2): add `flock`-style advisory lock (stdlib `syscall.Flock` wrapper) around the read-modify-write in `TOFUHostKeyCallback` capture path (`bootstrap.go:290-302`) and `ResetHostKey` (`bootstrap.go:479-523`); lock file at `cluster/known_hosts.lock` (R-002) (I-M-003) | Medium | **v0.9 P0a1** | Pending | | REQ-064 | HCL→Markdown jobspec adapter/bridge layer: keep `internal/jobspec/spec.go` as legacy HCL path behind `// Deprecated`; add `internal/jobspec/markdown.go` (canonical) + `internal/jobspec/dispatch.go` (extension-based dispatcher: `.md`→Markdown, `.hcl`→legacy, `.yaml`→Markdown-with-empty-body); unified `*WorkloadSpec` populated via adapter; preserves `orca job run old-spec.hcl` during migration window (I-M-004) | High | **v0.9 P0b** | Pending | -| REQ-065 | `orca doctor --legacy-paths` detection: detects v0.8 residue (orca.db at ORCA_HOME root, ca.crt/ca.key, config.hcl, flat server.crt, namespace column in any *.db); outputs list of legacy artifacts with migration recommendations; the detection half of v1.0-P14 (I-M-005) | Medium | **v1.0 P14c** | Pending | -| REQ-066 | Legacy CA state migration to step-ca: `orca upgrade --to-v1.0 --import-ca` reads `~/.orca/ca.key`, initializes step-ca with it, re-issues workload SVIDs; preserves audit history even if live trust root changes (I-M-006). **Gated by C-07** | High | **v1.0 P14a** | Pending | +| REQ-065 | `orca doctor --legacy-paths` detection: detects v0.8 residue (orca.db at ORCA_HOME root, ca.crt/ca.key, config.hcl, flat server.crt, namespace column in any *.db); outputs list of legacy artifacts with migration recommendations; the detection half of v0.10-P14 (I-M-005) | Medium | **v0.10 P14c** | Pending | +| REQ-066 | Legacy CA state migration to step-ca: `orca upgrade --to-v1.0 --import-ca` reads `~/.orca/ca.key`, initializes step-ca with it, re-issues workload SVIDs; preserves audit history even if live trust root changes (I-M-006). **Gated by C-07** | High | **v0.10 P14a** | Pending | | REQ-067 | Fuzz test harness for Markdown frontmatter parser: `testing.F` fuzz target in `internal/jobspec/markdown_test.go` round-trips random frontmatter+body through `ParseMarkdown` asserting byte-exact body preservation; corpus of adversarial fixtures (CRLF, BOM, no-frontmatter, empty-frontmatter, frontmatter-with-only-separator) (I-M-007) | Medium | **v0.9 P0b** | Pending | -| REQ-068 | Deprecation warnings on removed/repurposed CLI subcommands: each removed/changed command (`orca cert`, `orca node join` mTLS semantics, `orca job run `) emits `slog.Warn` deprecation banner with v1.0 replacement except under `orca upgrade`; `--no-deprecation-warnings` global flag via `root.go` `PersistentPreRunE` (I-M-008) | Low | **v0.9 P0X** + v1.0 P13 | Pending | +| REQ-068 | Deprecation warnings on removed/repurposed CLI subcommands: each removed/changed command (`orca cert`, `orca node join` mTLS semantics, `orca job run `) emits `slog.Warn` deprecation banner with v1.0 replacement except under `orca upgrade`; `--no-deprecation-warnings` global flag via `root.go` `PersistentPreRunE` (I-M-008) | Low | **v0.9 P0X** + v0.10 P13 | Pending | | REQ-069 | `internal/config/config.go` HCL config demotion via adapter: keep `internal/config/` as `legacy_config.go` with `// Deprecated`; add `internal/config/markdown.go` for new Markdown-frontmatter loader (R-014); `root.go` dispatches on file extension (`.hcl`→legacy, `.md`→new); `--config` semantics: `.hcl` read-only legacy, `.md` canonical (I-M-009) | High | **v0.9 P0a1** | Pending | | REQ-070 | `internal/certpaths/` replacement with multi-namespace path resolver: new `internal/paths` package with `paths.NamespaceDir(ns)`, `paths.ClusterDir()`, `paths.CacheDB()`, `paths.MasterKey()`, `paths.NSDb(ns)`, `paths.NSEnv(ns)`, `paths.NSSecrets(ns)`; keep `certpaths` as thin shim for v0.8 compat then remove post-v1.0 (R-002) (I-M-010) — highest blast radius | High | **v0.9 P0a1** | Pending | -| REQ-071 | `internal/store/` schema: per-namespace DBs, drop namespace column: `store.Open` gains namespace parameter (or caller passes `paths.NSDb(ns)`); `migrate.go` runs migrations per namespace DB; `cert_repo` (0004) removed (step-ca handles certs); audit_log moves to CLI-side cache DB (R-008) (I-M-011) | High | **v0.9 P0a1** + v1.0 P06 | Pending | -| REQ-072 | `internal/transport/` deletion + SSH-push package: delete `mtls.go`, `dispatch.go`, `handshake_log.go`; extract retry/idempotency patterns into `internal/sshpush/`; existing `transport.IdempotencyStore` directly reusable (I-M-012). Deletion deferred to v1.0-P14 to keep dual-write window open | High | **v0.9 P00** (delete v1.0 P14) | Pending | +| REQ-071 | `internal/store/` schema: per-namespace DBs, drop namespace column: `store.Open` gains namespace parameter (or caller passes `paths.NSDb(ns)`); `migrate.go` runs migrations per namespace DB; `cert_repo` (0004) removed (step-ca handles certs); audit_log moves to CLI-side cache DB (R-008) (I-M-011) | High | **v0.9 P0a1** + v0.10 P06 | Pending | +| REQ-072 | `internal/transport/` deletion + SSH-push package: delete `mtls.go`, `dispatch.go`, `handshake_log.go`; extract retry/idempotency patterns into `internal/sshpush/`; existing `transport.IdempotencyStore` directly reusable (I-M-012). Deletion deferred to v0.10-P14 to keep dual-write window open | High | **v0.9 P00** (delete v0.10 P14) | Pending | | REQ-073 | SSH-push transport layer design: connection pooling (reuse `*ssh.Client` per peer), idempotency (content-addressed filenames), retry (exponential backoff 100ms×2 cap 5s max 5), timeout (30s SCP, 10s exec), fan-out (errgroup bounded concurrency default 8), known_hosts reuse `proxmox.TOFUHostKeyCallback` (I-B-001) | High | **v0.9 P01** (design P0a1) | Pending | | REQ-074 | Emitter template system (Layer 4): `internal/emitter/` package with `Emitter` interface `Render(spec *WorkloadSpec, node *Node) ([]File, error)`; implementations systemdEmitter/traefikEmitter/syncthingEmitter/socketEmitter; SSH-push SCPs `[]File` atomically (write-to-tmp + rename); emitters registered per kind + runtime (I-B-002) | High | **v0.9 P0c** | Pending | -| REQ-075 | Lead applier execution model: CLI renders transaction bundle (tarball + apply.sh + verify.sh) on operator host, SCPs to lead's `/run/orca/txns//`, lead's systemd timer runs `apply.sh` idempotently, CLI polls txn status via SSH; bash scripts generated by emitter not hand-written (I-B-003). **Gated by C-09** | High | **v1.0 P10** (design v0.9 P00) | Pending | -| REQ-076 | step-ca integration: `orca init` runs `step ca init` on lead; CLI SSHs to lead, installs step-ca via apt, stores step-ca.json; workload SVIDs via `step ca token` (JWE minted by CLI) → `step ca certificate`; SPIFFE ID as SAN; new `internal/stepca/` package wraps `step` CLI via SSH (I-B-004). Reverses AD-010 per override justification ground 2 | High | **v0.9 P07** + v1.0 P02 | Pending | +| REQ-075 | Lead applier execution model: CLI renders transaction bundle (tarball + apply.sh + verify.sh) on operator host, SCPs to lead's `/run/orca/txns//`, lead's systemd timer runs `apply.sh` idempotently, CLI polls txn status via SSH; bash scripts generated by emitter not hand-written (I-B-003). **Gated by C-09** | High | **v0.10 P10** (design v0.9 P00) | Pending | +| REQ-076 | step-ca integration: `orca init` runs `step ca init` on lead; CLI SSHs to lead, installs step-ca via apt, stores step-ca.json; workload SVIDs via `step ca token` (JWE minted by CLI) → `step ca certificate`; SPIFFE ID as SAN; new `internal/stepca/` package wraps `step` CLI via SSH (I-B-004). Reverses AD-010 per override justification ground 2 | High | **v0.9 P07** + v0.10 P02 | Pending | | REQ-077 | Traefik dynamic config generation + atomic reload: Traefik emitter renders `/etc/traefik/dynamic/orca--.yaml` with backends (socket paths R-007), health checks, mTLS config pointing at step-ca root; atomic reload via tmpfile+fsync+rename triggering fsnotify; drain writes `weight=0` or removes backend (I-B-005). **Gated by C-10** | High | **v0.9 P02** | Pending | | REQ-078 | Runtime abstraction interface (5 backends): `Runtime` interface in `internal/runtime/` with Prepare/Start/Stop/Status; processRuntime (wraps existing executor.go), wasmRuntime (wasmtime via SSH), podmanRuntime, pveVMRuntime (qm via proxmox SSH), pveCTRuntime (pct); runtimeRegistry keyed by `runtime:` frontmatter value; Alloc carries runtime field changeable on migration (I-B-006). Split P07a/b/c per PC-10. **P07b gated by C-01** | High | **v0.9 P07a/b/c** | Pending | -| REQ-079 | Transaction bundle format + N-peer atomicity: bundle = tarball with desired-state.json + apply.sh + verify.sh + rollback.sh + manifest.sig (signed with master.key); content-addressed `=sha256(desired-state.json)` stored in `cluster/txns//`; lead applies to self first then fans out; failure on any peer runs rollback.sh on applied peers (I-B-007). **Gated by C-09** | High | **v1.0 P10** (design v0.9 P00) | Pending | -| REQ-080 | Master key management + HKDF-SHA256 per-line .env.secrets encryption: `cluster/master.key` 32-byte random (generated at `orca init` using WriteAtomic pattern); each line `base64(nonce||ciphertext||tag)`, nonce=random(12 bytes), AES-256-GCM with AAD=line-number (prevents line-swap); HKDF-SHA256 derives per-namespace sub-keys; `orca secrets set/get`; v0.8 `internal/security/redact.go` reusable (I-B-008). **Gated by C-19** | High | **v1.0 P03** | Pending | +| REQ-079 | Transaction bundle format + N-peer atomicity: bundle = tarball with desired-state.json + apply.sh + verify.sh + rollback.sh + manifest.sig (signed with master.key); content-addressed `=sha256(desired-state.json)` stored in `cluster/txns//`; lead applies to self first then fans out; failure on any peer runs rollback.sh on applied peers (I-B-007). **Gated by C-09** | High | **v0.10 P10** (design v0.9 P00) | Pending | +| REQ-080 | Master key management + HKDF-SHA256 per-line .env.secrets encryption: `cluster/master.key` 32-byte random (generated at `orca init` using WriteAtomic pattern); each line `base64(nonce||ciphertext||tag)`, nonce=random(12 bytes), AES-256-GCM with AAD=line-number (prevents line-swap); HKDF-SHA256 derives per-namespace sub-keys; `orca secrets set/get`; v0.8 `internal/security/redact.go` reusable (I-B-008). **Gated by C-19** | High | **v0.10 P03** | Pending | | REQ-081 | Syncthing config rendering + folder-ID content-addressing: per-namespace Syncthing folder `orca-` with content-addressed folder ID `sha256(ns + master-key-fingerprint)`; CLI renders config.xml per peer; Syncthing runs as systemd unit (emitted by systemd emitter); CLI discovers peers via `cluster/peers/`; migration works because new node joins folder and syncs before workload starts (I-B-009). **Gated by C-02 + C-14** | Medium | **v0.9 P09** (spike v0.9 P00) | Pending | | REQ-082 | Namespace inheritance resolver algorithm: DFS parent walker with visited set for cycle detection; `_defaults/` implicit root (always exists, no parent); merge semantics: child overrides parent for scalars, arrays unioned (child adds to parent); pure function (no I/O) taking `map[nsName→*NSConfig]` returning `map[nsName→*ResolvedNS]` (I-B-010) | High | **v0.9 P0a2** | Pending | | REQ-083 | CLI-side scheduler redesign: `Score(node, workload) (score int, fits bool)` where `fits` checks runtime compatibility + constraints, `score` is bin-packing (most free capacity = highest); Services pick `count` distinct nodes (anti-affinity default); DaemonSets pick all matching nodes; Job = one-shot; CLI-side not daemon-side (R-001) (I-B-011) | High | **v0.9 P05** (skeleton P0c) | Pending | -| REQ-084 | `orca job lint` category-driven lint engine: `Linter` runs `Rule` checks returning `Finding{Category, Severity, Message, Explanation}`; categories schema/runtime/security/migration/best-practice; `--explain` prints rationale; pure (no I/O) checks against static rules (I-B-012) | Medium | **v1.0 P11** | Pending | -| REQ-085 | v0.8→v1.0 migration ordering: v0.9 ships new parser + kinds + runtime + SSH-push alongside old daemon (dual-write window); `orca job run` dispatches on extension (`.md`→SSH-push, `.hcl`→old daemon); v1.0-P05 drains old daemons; v1.0-P14 converts remaining `.hcl` specs and removes daemon (I-C-001). **Most important cross-cutting idea** | High | **v0.9 P00** → v1.0 P14 | Pending | -| REQ-086 | "No orca on server" enforcement: `orca doctor no-orca-on-server` SSHs to each peer verifying no `orca` binary in PATH, no `orca` systemd service, no `orca` process, no `/etc/orca/` directory; runs after v1.0-P05 before v1.0-P16; reuses v0.8 `proxmox` SSH session infrastructure (I-C-002). Implements grill C-13 | High | **v1.0 P14c** | Pending | -| REQ-087 | Test infrastructure: hermetic 3-linux + 1-proxmox cluster pipeline: `test/integration/` with docker-compose/vagrant creating 4 containers/VMs; Go test harness SSHes to each, runs CLI, asserts end-to-end workflows (ns create → workload submit → migrate → drain); proxmox simulated via mock pct/qm; v0.8 e2e tests (bootstrapE2ESetup) are foundation (I-C-003) | Medium | **v1.0 P08** (bootstrap v0.9 P00) | Pending | -| REQ-088 | Security-engineer + network-engineer persona reactivation: reactivate security-engineer (step-ca provisioner model, SSH-push blast radius, Traefik edge, .env.secrets crypto) and network-engineer (socket exposure R-007, Syncthing P2P ports, Traefik routing); cross-cutting review not single phase (I-C-004). Implements grill C-05 | High | **v0.9 P00** → v1.0 P16 | Pending | -| REQ-089 | Documentation rewrite: ARCHITECTURE.md/PROJECT.md/README + AD-010 supersession: v0.9-P00 adds "v0.9 Architecture (Supersedes v0.8)" section + banners + Superseded Decisions table; v1.0-P15 rewrites README quickstart for new curl|sh + orca init + orca ns create flow (I-C-005) | Medium | **v0.9 P00** + v1.0 P15/P16 | Pending | -| REQ-090 | Dual-write window: v0.9 `orca job run` dispatches on extension (`.md`→SSH-push new path, `.hcl`→old daemon path) via parser dispatcher (REQ-064); daemon not removed until v1.0-P05; SSH-push path writes to separate systemd unit namespace (`orca-v1-.service`) while daemon uses `orca-.service` — no unit name overlap = no conflict (I-C-006) | High | **v0.9 P00** | Pending | +| REQ-084 | `orca job lint` category-driven lint engine: `Linter` runs `Rule` checks returning `Finding{Category, Severity, Message, Explanation}`; categories schema/runtime/security/migration/best-practice; `--explain` prints rationale; pure (no I/O) checks against static rules (I-B-012) | Medium | **v0.10 P11** | Pending | +| REQ-085 | v0.8→v1.0 migration ordering: v0.9 ships new parser + kinds + runtime + SSH-push alongside old daemon (dual-write window); `orca job run` dispatches on extension (`.md`→SSH-push, `.hcl`→old daemon); v0.10-P05 drains old daemons; v0.10-P14 converts remaining `.hcl` specs and removes daemon (I-C-001). **Most important cross-cutting idea** | High | **v0.9 P00** → v0.10 P14 | Pending | +| REQ-086 | "No orca on server" enforcement: `orca doctor no-orca-on-server` SSHs to each peer verifying no `orca` binary in PATH, no `orca` systemd service, no `orca` process, no `/etc/orca/` directory; runs after v0.10-P05 before v0.10-P16; reuses v0.8 `proxmox` SSH session infrastructure (I-C-002). Implements grill C-13 | High | **v0.10 P14c** | Pending | +| REQ-087 | Test infrastructure: hermetic 3-linux + 1-proxmox cluster pipeline: `test/integration/` with docker-compose/vagrant creating 4 containers/VMs; Go test harness SSHes to each, runs CLI, asserts end-to-end workflows (ns create → workload submit → migrate → drain); proxmox simulated via mock pct/qm; v0.8 e2e tests (bootstrapE2ESetup) are foundation (I-C-003) | Medium | **v0.10 P08** (bootstrap v0.9 P00) | Pending | +| REQ-088 | Security-engineer + network-engineer persona reactivation: reactivate security-engineer (step-ca provisioner model, SSH-push blast radius, Traefik edge, .env.secrets crypto) and network-engineer (socket exposure R-007, Syncthing P2P ports, Traefik routing); cross-cutting review not single phase (I-C-004). Implements grill C-05 | High | **v0.9 P00** → v0.10 P16 | Pending | +| REQ-089 | Documentation rewrite: ARCHITECTURE.md/PROJECT.md/README + AD-010 supersession: v0.9-P00 adds "v0.9 Architecture (Supersedes v0.8)" section + banners + Superseded Decisions table; v0.10-P15 rewrites README quickstart for new curl|sh + orca init + orca ns create flow (I-C-005) | Medium | **v0.9 P00** + v0.10 P15/P16 | Pending | +| REQ-090 | Dual-write window: v0.9 `orca job run` dispatches on extension (`.md`→SSH-push new path, `.hcl`→old daemon path) via parser dispatcher (REQ-064); daemon not removed until v0.10-P05; SSH-push path writes to separate systemd unit namespace (`orca-v1-.service`) while daemon uses `orca-.service` — no unit name overlap = no conflict (I-C-006) | High | **v0.9 P00** | Pending | diff --git a/.ciagent/ROADMAP.md b/.ciagent/ROADMAP.md index 0f31ce0..e87b02e 100644 --- a/.ciagent/ROADMAP.md +++ b/.ciagent/ROADMAP.md @@ -252,7 +252,7 @@ HCL-canonical, single-namespace, no-container-runtime, no-SPIFFE). The reversals are justified by the six-part evidence basis recorded in the PROJECT.md Supersession Table. -## Milestone v1.0: Production Hardening +## Milestone v0.10: Production Hardening **Scope**: ship a cluster that operators can run. Builds on the v0.9 re-architecture foundation with the production-grade subsystems: @@ -282,13 +282,15 @@ the v0.8→v1.0 migration. - [ ] Phase P14c: Mixed-version tolerance + no-orca-on-server enforcement (REQ-065, REQ-086; implements C-13) — tag `v0.9.18` - [ ] Phase P15: README quickstart (REQ-089) — tag `v0.9.19` - [ ] Phase P15.5: Threat model + security review (**gate C-19**) — tag `v0.9.20` -- [ ] Phase P16: Final review + ship + audit — **v1.0.0 release** — tag `v0.9.21` +- [ ] Phase P16: Final review + ship + audit — **v0.10.0 milestone release** — tag `v0.9.21` (v1.0.0 cut separately after UAT sign-off) -**Milestone tag**: `v1.0.0` (the v1.0.0 release tag is the production-ready cut; -per-phase patches run on the v0.9.x line per branch-strategy.md). Per-phase +**Milestone tag**: `v0.10.0` (the v0.10 milestone release tag; v1.0.0 is +UAT-gated and cut separately after v0.10 completion per operator decision — +the v1.0.0 tag marks production-ready sign-off, not a separate milestone). +Per-phase patches run on the v0.9.x line per branch-strategy.md. Per-phase tags: `v0.9.0`…`v0.9.21`. -### Per-phase REQ coverage (v1.0) +### Per-phase REQ coverage (v0.10) - **P00** — CLI cache (R-008) - **P01.5** — SPIFFE spike (REQ-076; C-08) @@ -310,9 +312,9 @@ tags: `v0.9.0`…`v0.9.21`. - **wasmtime CGO breaks cross-compile** (mitigation: C-01 spike; fallback to podman/process primary) - **bash control plane drift** (mitigation: C-15..C-18 render-format contract + bats gate) - **daemon cutover orphans running allocs** (mitigation: P14b split; test adoption) -- **27→35+ phase scope** (mitigation: C-04 sizing; three-milestone split if exceeded — current count v0.9=18 + v1.0=22 = 40 phases; **C-04 sizing must run before v0.9 P00 execution to determine whether to split into v0.9+v0.10+v1.0**) +- **27→35+ phase scope** (mitigation: C-04 resolved — operator decision: keep 2 milestones v0.9 + v0.10, keep all phases, v1.0 is UAT-gated after v0.10; current count v0.9=18 + v0.10=22 = 40 phases, exceeds 35 soft limit but operator accepted) -## Deferred to v1.x (out of scope for v1.0) +## Deferred to v1.x (out of scope for v0.10) - `sqlite-wal-shared` state backend (R-009 abstractions ship in v1.0; backend in v1.x) - `git` state backend