Files
orca/.ciagent/IDEATION_v0.9.md
T
Jon Chery 8631a698ce docs(P00): ideate v0.9 — 30 ideas (REQ-061..090), 3 tiers, 7 phase-reorder flags
Generates 30 ideation ideas across mechanical (12), backend-enriched (12),
and cross-cutting (6) tiers, all accepted at >=0.60 confidence. Mapped to
REQ-061..REQ-090. Highest-impact: I-C-001 (migration ordering, 0.88) and
I-C-006 (dual-write window, 0.86) reshape v0.9 execution strategy. Highest
blast radius: I-M-010 (path resolver, 0.84) touches every adaptable package.
Most under-specified by PRD: I-B-003 (lead applier execution model, 0.78).
Seven phase-reordering flags against PRD section 23: add v0.9-P00 deprecation
pre-phase, split P0a into P0a1/P0a2, design SSH-push before P01, fold emitter
into P0c, add txn-design spike in P0.9-P00, bootstrap test infra in P00,
fold persona reactivation + doc banners into P00.

---ci---
project: orca
phase: 0
milestone: v0.9
status: ideate
---/ci---
2026-08-05 16:01:28 +00:00

46 KiB
Raw Blame History

Ideation v0.9 — Re-architecture Foundation

Project: orca (single-project mode) | Milestone: v0.9/v1.0 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)

Context

The v0.8 codebase (REQ-001..060, all Complete) is a daemon-based, mTLS, HCL, single-namespace orchestration engine. The adopted PRD supersedes this 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 under-specifies the deprecation mechanics, the SSH-push transport design, the lead-applier execution model, several adapter/bridge layers, and the migration ordering risk.

This ideation produced 30 ideas across three tiers, all accepted at ≥0.60 confidence, mapped to REQ-061..REQ-090. Seven phase-reordering flags against the PRD §23 plan are listed at the end.

Tier 1 — Mechanical (Codebase-Observable Gaps & Hygiene)

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.
  • 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
  • Confidence: 0.82
  • Accept/Defer: accept

I-M-002 — Coverage follow-ups: 3 zero-test packages + internal/cli to 70%

  • Tier: mechanical
  • Description: v0.8 P01 (REQ-057) raised 6 packages to ≥70% and added first tests for internal/audit, internal/certpaths, cmd/orca at a 50% toe-hold. The v0.9 re-architecture will replace several of these packages, but the adaptable ones (internal/store, internal/doctor, internal/cli) must keep their 70% floor through the refactor. Once daemon.go is deprecated/removed (I-M-001), the exclusion reason disappears and the floor applies to the whole package. Add a coverage-gate assertion in the v0.9 P0X ship phase that internal/cli ≥ 70% including all new subcommand files (ns, txn, pve, secrets, volume, cache, backup).
  • Rationale: The PRD §23 does not mention coverage. The config.json policy says 70% floor for new packages, 50% minimum. The 8 net-new subsystems will need 70% floors from their first phase. Without an explicit gate, the v0.7/v0.8 "toe-hold at 50% then defer" pattern will repeat.
  • Proposed REQ ID: REQ-062
  • Proposed phase placement: v0.9-P0X (ship+audit) + each net-new package's first phase
  • Confidence: 0.88
  • Accept/Defer: accept

I-M-003 — known_hosts flock concurrency gap (deferred P1 from REVIEW_v0.8 A2)

  • Tier: mechanical
  • Description: REVIEW_v0.8 flagged A2 (P1): TOFUHostKeyCallback capture path (bootstrap.go:290-302) and ResetHostKey (bootstrap.go:479-523) both do read-modify-write on known_hosts with no lock. The review said "Defer to v0.9." This is now load-bearing because the SSH-push transport (R-001) will do many more concurrent SSH operations than v0.8 did. Add a flock-style advisory lock (stdlib syscall.Flock wrapper) around the RMW in both paths. Lock file is cluster/known_hosts.lock (multi-namespace layout, R-002).
  • Rationale: The v0.8 single-operator mitigation is weaker under v0.9's parallel SSH fan-out. The PRD doesn't mention this, but the SSH-push transport makes the race more likely.
  • Proposed REQ ID: REQ-063
  • Proposed phase placement: v0.9-P0a1 (path resolver, since it establishes cluster/ layout)
  • Confidence: 0.74
  • Accept/Defer: accept

I-M-004 — HCL→Markdown jobspec adapter/bridge layer

  • Tier: mechanical
  • Description: R-013 says the Markdown parser is canonical; .yaml and .hcl are "accepted by parser dispatcher." But internal/jobspec/spec.go (69 LOC) is an HCL-only parser with a flat Spec{Job, Tasks} schema — no kind: (R-012), runtime blocks, or body preservation (R-014/R-015). The "dispatcher" implies the new parser detects file extension and dispatches. Proposal: keep internal/jobspec/spec.go as the 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). The dispatcher returns a unified *WorkloadSpec that the legacy parser populates via an adapter. Preserves orca job run old-spec.hcl during the migration window.
  • Rationale: R-013 explicitly accepts .hcl, so a dispatcher is required. §23 v0.9-P0b says "parser dispatcher" but doesn't specify the adapter.
  • Proposed REQ ID: REQ-064
  • Proposed phase placement: v0.9-P0b (Markdown jobspec parser)
  • Confidence: 0.85
  • Accept/Defer: accept

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}, <ns>/{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.
  • Proposed REQ ID: REQ-065
  • Proposed phase placement: v1.0-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.
  • 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)
  • 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.
  • 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
  • Confidence: 0.78
  • Accept/Defer: accept

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 <spec.hcl>. 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.
  • Proposed REQ ID: REQ-068
  • Proposed phase placement: v0.9-P0X (ship) + v1.0-P13 (ns subcommands, when CLI surface is finalized)
  • Confidence: 0.72
  • Accept/Defer: accept

I-M-009 — internal/config/config.go HCL config demotion via adapter

  • Tier: mechanical
  • Description: internal/config/config.go (127 LOC) parses HCL config with keys db_path, listen_addr, ca_path, server_cert_path, server_key_path, node_capacity. The PRD replaces this with Markdown-frontmatter config (R-014) + per-namespace .env/.env.secrets (R-011). The listen_addr and server_*_path keys are daemon-specific (deprecated by R-001). The root.go PersistentPreRunE calls config.Load(configPath) on every command — must be repointed to the new Markdown config loader. Proposal: keep internal/config/ as legacy_config.go with // Deprecated; add internal/config/markdown.go for the new loader; root.go dispatches on file extension (.hcl→legacy, .md→new). The --config flag semantics change: .hcl is read-only legacy, .md is canonical.
  • Rationale: R-014 makes Markdown canonical but .hcl must still parse during migration. The existing config.Load is called unconditionally in root.go:42-47.
  • Proposed REQ ID: REQ-069
  • Proposed phase placement: v0.9-P0a1 (path resolver + config demotion)
  • Confidence: 0.76
  • Accept/Defer: accept

I-M-010 — internal/certpaths/ replacement with multi-namespace path resolver

  • Tier: mechanical
  • Description: internal/certpaths/certpaths.go (64 LOC) returns flat paths: Dir() = $ORCA_HOME, CACertPath() = Dir/ca.crt, DBPath() = Dir/orca.db. R-002 requires multi-namespace layout: ORCA_HOME/<ns>/db/, ORCA_HOME/cluster/{ca,master.key,peers,pve,txns}, ORCA_HOME/_defaults/. The package is imported by doctor, proxmox, store, cli — changing it is cross-cutting. Proposal: replace certpaths with a new internal/paths package: paths.NamespaceDir(ns), paths.ClusterDir(), paths.CacheDB(), paths.MasterKey(), paths.NSDb(ns), paths.NSEnv(ns), paths.NSSecrets(ns). Keep certpaths as a thin shim that calls paths with the default namespace for v0.8 compat, then remove the shim post-v1.0.
  • Rationale: R-002 is foundational and certpaths is the single source of path truth. Every adaptable package (store.Open, doctor, proxmox) imports it. Highest-blast-radius mechanical change.
  • Proposed REQ ID: REQ-070
  • Proposed phase placement: v0.9-P0a1 (must come first)
  • Confidence: 0.84
  • Accept/Defer: accept

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 (<ns>/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.
  • 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)
  • Confidence: 0.80
  • Accept/Defer: accept

I-M-012 — internal/transport/ deletion + SSH-push package introduction

  • Tier: mechanical
  • 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
  • Confidence: 0.68
  • Accept/Defer: accept (defer deletion to v1.0-P14 to keep dual-write window open)

Tier 2 — Backend-Enriched (Structural / Architectural)

I-B-001 — SSH-push transport layer design

  • Tier: backend-enriched
  • Description: The PRD replaces internal/transport/ (mTLS HTTP) with SSH-push but §23 never specifies the transport's internal design. Key decisions: (1) Connection pooling: reuse *ssh.Client per peer across multiple SCP/exec operations within a single CLI invocation. (2) Idempotency: SCP of a config file is idempotent if content hash matches — use content-addressed filename (/run/orca/<hash>.unit) and skip if present. (3) Retry: reuse v0.8's exponential backoff (100ms start, ×2, cap 5s, max 5 attempts) applied to SSH dial/exec failures. (4) Timeout: per-operation context.WithTimeout (default 30s SCP, 10s exec). (5) Fan-out: errgroup.Group with bounded concurrency for N-peer ops (default 8). (6) known_hosts: reuse proxmox.TOFUHostKeyCallback for all peers, not just Proxmox.
  • Rationale: Load-bearing replacement for the entire v0.8 transport layer. §23 assumes it but never designs it. Without connection pooling, every CLI operation re-dials SSH.
  • Proposed REQ ID: REQ-073
  • Proposed phase placement: v0.9-P01 (first phase needing SSH-push) — design in v0.9-P0a1
  • Confidence: 0.86
  • Accept/Defer: accept

I-B-002 — Emitter template system (Layer 4)

  • Tier: backend-enriched
  • Description: The PRD §5 describes a 4-layer architecture where Layer 4 is "emitters" that render systemd units, Traefik dynamic config, Syncthing config, etc. from the workload spec. §23 never specifies the emitter interface. Proposal: an internal/emitter/ package with Emitter interface: Render(spec *WorkloadSpec, node *Node) ([]File, error) where File{Path, Content, Mode}. Implementations: systemdEmitter, traefikEmitter, syncthingEmitter, socketEmitter. The SSH-push transport SCPs the []File atomically (write-to-tmp + rename). Emitters registered per workload kind + runtime.
  • Rationale: The emitter layer is the bridge between the declarative spec and the server-side files. Without a defined interface, each phase (P02 service, P04 hooks, P08 sockets, P09 storage) will invent its own rendering.
  • Proposed REQ ID: REQ-074
  • Proposed phase placement: v0.9-P0c (schemas + emitter interface)
  • Confidence: 0.82
  • Accept/Defer: accept

I-B-003 — Lead applier execution model: pure bash + systemd timer vs CLI-invoked

  • Tier: backend-enriched
  • 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/<txn-id>/; (3) the lead's systemd timer runs /run/orca/txns/<txn-id>/apply.sh which idempotently applies and runs verify; (4) the CLI polls the lead for txn status via SSH (cat /run/orca/txns/<txn-id>/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
  • Confidence: 0.78
  • Accept/Defer: accept

I-B-004 — step-ca integration: provisioning, CA bootstrap, cert signing API, SVID minting

  • Tier: backend-enriched
  • 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/<ns>/<workload>/<instance>) 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)
  • 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-<ns>-<svc>.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).
  • 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)
  • Confidence: 0.80
  • Accept/Defer: accept

I-B-006 — Runtime abstraction interface (5 backends: wasm/podman/process/pve-vm/pve-ct)

  • Tier: backend-enriched
  • Description: v0.8's internal/engine/executor.go (211 LOC) is os/exec only. R-004/R-007 require 5 runtime backends. §23 puts this in v0.9-P07. Proposal: a Runtime interface in internal/runtime/: Prepare(ctx, spec, node) (*Alloc, error), Start(ctx, alloc) (pid/unit, error), Stop(ctx, alloc) error, Status(ctx, alloc) (State, error). Implementations: processRuntime (wraps existing executor.go — directly reusable), wasmRuntime (wasmtime via CLI SSH exec), podmanRuntime (podman run via SSH), pveVMRuntime (qm create/qm start via v0.8 proxmox SSH session), pveCTRuntime (pct create/pct start). Each registered in a runtimeRegistry keyed by the runtime: frontmatter value. R-004 (migration with runtime change) means the Alloc carries a runtime field that can change on migration — Prepare re-runs with the new runtime.
  • Rationale: The 5 backends are the largest net-new implementation surface. §23 lists them as one phase (P07) but under-specifies the interface contract. The existing executor.go is a good starting point for the processRuntime adapter.
  • Proposed REQ ID: REQ-078
  • Proposed phase placement: v0.9-P07a/P07b/P07c (split per grill PC-10)
  • Confidence: 0.82
  • Accept/Defer: accept

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 (<txn-id> = sha256(desired-state.json)) and stored in cluster/txns/<txn-id>/. 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
  • 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 <ns> <key> <value> appends an encrypted line; orca secrets get <ns> <key> 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=<ns>)) 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)
  • Confidence: 0.84
  • Accept/Defer: accept

I-B-009 — Syncthing config rendering and folder-ID content-addressing

  • Tier: backend-enriched
  • Description: R-005 requires storage replication via per-namespace Syncthing. §23 puts this in v0.9-P09. Design: (1) each namespace gets a Syncthing folder orca-<ns> with a content-addressed folder ID (sha256(ns + master-key-fingerprint)). (2) The CLI renders config.xml for each peer's Syncthing instance, including the folder, devices (all peers in the namespace), and the path (<ns>/alloc/<alloc-id>/). (3) Syncthing runs as a systemd unit (emitted by the systemd emitter, I-B-002). (4) The CLI discovers peers via cluster/peers/ and adds their Syncthing device IDs (each peer's Syncthing generates its own device key on first run, reported back via SSH). (5) R-005 says "a Service's count replicas share one runtime block" — the Syncthing folder is shared across the Service's alloc instances so all replicas see the same data. Migration (R-004) works because the new node joins the Syncthing folder and syncs before the workload starts. Gated by grill C-02 (Syncthing feasibility spike) and C-14 (deterministic conflict-resolution policy + forced-divergence integration test).
  • Rationale: Syncthing is net-new. §23 lists it in P09 but doesn't specify config rendering, folder-ID scheme, or device discovery.
  • Proposed REQ ID: REQ-081
  • Proposed phase placement: v0.9-P09 (storage replication) — spike in v0.9-P00
  • Confidence: 0.72
  • Accept/Defer: accept

I-B-010 — Namespace inheritance resolver algorithm

  • Tier: backend-enriched
  • Description: v0.9-P0a2 requires a "parent walker, cycle detection" for namespace inheritance. Each ns.md has a parent: field in frontmatter. The resolver walks up the parent chain, merging inherited values (constraints, env, runtime defaults). Cycle detection: DFS with a visited set; if a namespace is revisited, return a cycle error. The resolver returns a flattened ResolvedNamespace struct. The _defaults/ namespace is the implicit root (always exists, has no parent). Inheritance semantics: child overrides parent for scalar fields; arrays (e.g., constraints) are unioned (child adds to parent, not replaces). The resolver is pure (no I/O) — it takes a map of nsName → *NSConfig and returns nsName → *ResolvedNS. This makes it trivially testable.
  • Rationale: §23 mentions "parent walker, cycle detection" but not the merge semantics (override vs union) or the resolver's purity for testing. Getting merge semantics wrong breaks constraint inheritance (P05).
  • Proposed REQ ID: REQ-082
  • Proposed phase placement: v0.9-P0a2 (namespace CRUD + inheritance)
  • Confidence: 0.86
  • Accept/Defer: accept

I-B-011 — Bin-packing scheduler redesign (CLI-side, runtime-compatibility scoring)

  • Tier: backend-enriched
  • Description: v0.8's internal/engine/scheduler.go (117 LOC) does best-fit bin-packing by CPU+memory. The v0.9 scheduler must: (1) run CLI-side (not on a daemon), (2) score nodes by runtime compatibility (a wasm workload can only go to a node with wasmtime installed; a pve-vm workload can only go to Proxmox nodes), (3) respect constraints/affinity (CEL over node attributes, P05), (4) handle the 3 kinds differently (Job = one-shot, Service = count replicas spread across nodes, DaemonSet = one per node). The existing scheduler.go is a good skeleton but the scoring function changes entirely. Proposal: Score(node, workload) (score int, fits bool) where fits checks runtime compatibility + constraints, and score is the bin-packing score (most free capacity = highest score). For Services, the scheduler picks count distinct nodes (anti-affinity by default). For DaemonSets, it picks all matching nodes.
  • Rationale: The scheduler moves from daemon-side to CLI-side (R-001) and gains runtime-awareness. §23 scatters this across P05 (constraints), P06 (task groups), P07 (runtime), P10 (migration) but never designs the scheduler itself.
  • Proposed REQ ID: REQ-083
  • Proposed phase placement: v0.9-P05 (constraints & affinity — scheduler needs constraints to be meaningful) — skeleton in P0c
  • Confidence: 0.80
  • Accept/Defer: accept

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).
  • 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)
  • Confidence: 0.78
  • Accept/Defer: accept

Tier 3 — Cross-Cutting (Risk & Multi-Phase)

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.
  • 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
  • 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.
  • 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)
  • 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.
  • 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
  • Confidence: 0.80
  • Accept/Defer: accept

I-C-004 — Security-engineer + network-engineer persona reactivation for new attack surfaces

  • Tier: cross-cutting
  • 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)
  • 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.
  • 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)
  • 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 <spec.md> 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-<alloc>.service) while the daemon uses orca-<job>.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)
  • Confidence: 0.86
  • Accept/Defer: accept

Summary Table

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-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-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-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-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-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-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-C-006 C Dual-write window decision REQ-090 v0.9-P00 0.86 accept

Phase Reordering / Addition Flags (against PRD §23)

  1. I-C-001 / I-C-006 (dual-write + migration ordering) — require a decision in v0.9-P00 (before any execution phase). Recommendation: add v0.9-P00 deprecation/migration-ordering pre-phase. Most important structural addition.
  2. I-M-010 / I-M-011 / I-M-009 / I-M-003 — all land in v0.9-P0a. P0a may be overloaded. Recommendation: split P0a into P0a1 (path/layout resolver + config demotion) and P0a2 (namespace CRUD + inheritance). Path resolver is prerequisite for everything; highest blast radius.
  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.

Cross-Reference Against Existing Decisions

  • AD-009 (Internal CA, no external PKI) — Superseded by D-101 (step-ca). I-B-004, I-M-006 implement the reversal.
  • AD-010 (Roll-our-own CA) — Superseded by D-101. I-C-005 documents the supersession. No re-litigation — the PRD has decided; the override justification records the evidence basis.
  • AD-007 (HCL for job specs) — Demoted by R-013 (Markdown canonical, HCL accepted). I-M-004 implements the adapter. Not a full reversal — HCL still parses.
  • AD-001 (Single binary with subcommands) — Still holds. The CLI is the single binary; no orca on servers (R-001) refines this.
  • AD-015 (Best-fit bin-packing) — Extended, not reversed. I-B-011 adds runtime-compatibility scoring.
  • D-035 (TOFU host-key) — Still holds for non-Proxmox peers. I-M-003 hardens the concurrency. I-B-001 reuses TOFUHostKeyCallback.
  • D-046 (key-reset is local-only) — Still holds. I-M-003 adds the lock.
  • D-047 (tiered coverage floor) — Extended by I-M-002 to cover new packages.

No accepted idea re-litigates a settled decision. All reversals (AD-009, AD-010, SPIFFE, no-container, no-multi-tenancy, HCL-canonical, daemon-on-every-node) are explicitly mandated by the PRD and justified by the recorded override justification.

Final Notes

  • Total ideas: 30 (12 mechanical, 12 backend-enriched, 6 cross-cutting).
  • Highest-confidence, highest-impact: I-C-001 (migration ordering, 0.88) and I-C-006 (dual-write window, 0.86) — these shape the entire v0.9 execution strategy.
  • Highest-blast-radius mechanical: I-M-010 (path resolver, 0.84) — touches every adaptable package.
  • Most under-specified by PRD: I-B-003 (lead applier execution model, 0.78) — R-001 + R-010 create a tension the PRD doesn't resolve.