ship: v0.1 Foundation milestone complete (#1)

This commit was merged in pull request #1.
This commit is contained in:
2026-06-03 20:08:57 +00:00
parent 55aae5347e
commit be9afa2d2c
59 changed files with 4152 additions and 36 deletions
+170 -11
View File
@@ -1,13 +1,172 @@
# Architecture: Orchestration Engine
# Architecture: Orca
(Initial Draft)
The system will consist of:
1. **CLI Tool**: The primary interface for users and AI agents.
2. **Controller/Server**: A lightweight daemon managing state and scheduling.
3. **Agent/Worker**: A daemon running on each node to execute workloads.
4. **State Store**: A simple, local-first state persistence mechanism.
## System Overview
## Design Pillars
- Security before features.
- Bug fixes before features.
- NFRs before features.
Orca is a single-binary, offline-first orchestration engine. The system consists of three logical components, all compiled into one `orca` binary and selected via subcommands.
```
┌─────────────────────────────────────────────────────────────┐
│ orca (single binary) │
├─────────────────────────────────────────────────────────────┤
│ CLI Layer (Cobra) │
│ ├── orca version │
│ ├── orca init │
│ ├── orca status │
│ ├── orca node {join,leave,list} │
│ └── orca job {run,list,stop,logs} │
├─────────────────────────────────────────────────────────────┤
│ Daemon Layer (net/http server) │
│ ├── /healthz (liveness) │
│ ├── /readyz (readiness) │
│ ├── /v1/jobs/* (job control API) │
│ ├── /v1/nodes/* (node registry API) │
│ └── /v1/tasks/* (task lifecycle API) │
├─────────────────────────────────────────────────────────────┤
│ Core Engine │
│ ├── Node Registry (in-memory + SQLite persistence) │
│ ├── Task Executor (os/exec with WaitDelay, Go 1.25+) │
│ ├── Job Scheduler (single-node for v0.1) │
│ └── Audit Logger (log/slog JSON handler) │
├─────────────────────────────────────────────────────────────┤
│ State Store (modernc/sqlite, CGO-free) │
│ ~/.orca/orca.db │
└─────────────────────────────────────────────────────────────┘
```
## Component Details
### 1. CLI Layer (`cmd/orca`, `internal/cli`)
- **Framework**: Cobra (industry standard, familiar to operators)
- **Subcommands**: `version`, `init`, `status`, `node`, `job`
- **Output**: Human-readable by default; `--json` flag for machine consumption
- **Discovery**: All subcommands self-document via Cobra's auto-generated help
### 2. Daemon Layer (`internal/daemon`)
- **Server**: `net/http` with `http.ServeMux` (no external router for v0.1)
- **TLS**: `crypto/tls` with self-signed certs (mTLS-ready)
- **Ports**: Configurable (default `:8443` for API, `:8080` for health)
- **Graceful Shutdown**: `signal.NotifyContext` with SIGINT/SIGTERM
### 3. Core Engine (`internal/engine`)
- **Node Registry**: In-memory map of node IDs → metadata, persisted to SQLite
- **Task Executor**: `os/exec.CommandContext` with `WaitDelay` (Go 1.25+) for clean process termination
- **Job Scheduler**: Single-node FIFO queue (multi-node deferred to v0.2+)
- **Audit Logger**: `slog.NewJSONHandler(os.Stderr, ...)` with structured fields
### 4. State Store (`internal/store`)
- **Driver**: `modernc.org/sqlite` (pure Go, CGO-free)
- **Location**: `~/.orca/orca.db` (user-mode) or `/var/lib/orca/orca.db` (system-mode)
- **Schema**: `nodes`, `jobs`, `tasks`, `audit_log` tables
- **Migrations**: Embedded SQL files, applied on startup
## Data Model
### Node
```go
type Node struct {
ID string
Name string
Address string
State string
JoinedAt time.Time
LastSeen time.Time
Metadata map[string]string
}
```
### Job
```go
type Job struct {
ID string
Name string
Spec string
Status string
CreatedAt time.Time
StartedAt *time.Time
EndedAt *time.Time
}
```
### Task
```go
type Task struct {
ID string
JobID string
Command string
Args []string
Env []string
PID int
ExitCode int
Status string
CreatedAt time.Time
StartedAt *time.Time
EndedAt *time.Time
}
```
## Security Architecture
### Authentication
- **v0.1**: mTLS for all API endpoints (self-signed CA)
- **v0.2+**: Token-based auth as alternative
### Audit Logging
- All state-changing operations emit structured log records
- Fields: `timestamp`, `actor`, `action`, `resource`, `result`, `error`
- Stored in SQLite `audit_log` table and stderr (JSON)
### Input Validation
- All CLI inputs validated via Cobra's `Args`/`ValidArgs` functions
- All API inputs validated at handler boundary
- HCL/YAML specs parsed with strict schemas
## Key Architectural Decisions
| ID | Decision | Rationale |
|----|----------|-----------|
| AD-001 | Single binary with subcommands | Simpler distribution, aligns with simplicity pillar |
| AD-002 | modernc/sqlite (CGO-free) | Cross-compile friendly, no CGO toolchain needed |
| AD-003 | net/http (no framework) | Stdlib suffices; avoids external router dependency |
| AD-004 | os/exec with WaitDelay (Go 1.25+) | Clean process termination, native to Go |
| AD-005 | Cobra for CLI | Industry standard, familiar to operators |
| AD-006 | slog for logging | Native to Go 1.21+, no external dependency |
| AD-007 | HCL for job specs | Familiar to Nomad/HashiCorp users |
| AD-008 | Single-node scheduling (v0.1) | Multi-node scheduling deferred to v0.2+ |
## Anti-Patterns (Explicitly Avoided)
- No controller/agent split (single binary)
- No CRDs / custom resource definitions
- No web UI (CLI-only)
- No service mesh
- No container runtime integration
- No multi-tenancy
- No cloud provider integrations
- No auto-scaling
- No admission controllers
- No complex scheduling algorithms
## Dependency Map (minimal)
```
github.com/spf13/cobra # CLI framework
github.com/hashicorp/hcl/v2 # HCL parser
modernc.org/sqlite # SQLite (pure Go)
github.com/google/uuid # UUID generation
```
Total: ~4 direct dependencies. No web framework, no ORM, no RPC framework.
## Deployment Model
```
User Machine Server Node
┌──────────┐ ┌──────────────────┐
│ orca CLI │─────── mTLS ──────────▶│ orca daemon │
│ │ │ ├── API server │
│ │ │ ├── Engine │
│ │ │ └── SQLite store │
└──────────┘ └──────────────────┘
```
For v0.1, the CLI and daemon can be the same binary on the same machine. Multi-node is deferred.
+65
View File
@@ -0,0 +1,65 @@
# Ideation: Orca v0.1
Full autonomy mode: all ideas auto-accepted. Three tiers explored.
## Tier 1: Mechanical (security/quality, automated)
| ID | Idea | Source | Confidence |
|----|------|--------|------------|
| I-001 | Add `gosec` to CI pipeline | mechanical | 0.95 |
| I-002 | Add `govulncheck` to CI pipeline | mechanical | 0.95 |
| I-003 | Enable `gofmt` and `goimports` pre-commit checks | mechanical | 0.90 |
| I-004 | Pin Go version in `go.mod` (`go 1.25`) | mechanical | 0.95 |
| I-005 | Use `log/slog` for all logging (no `fmt.Println` in production) | mechanical | 0.95 |
| I-006 | Add `.gitignore` for `bin/`, `coverage.out`, `*.test` | mechanical | 0.95 |
| I-007 | Add `LICENSE` (MIT) | mechanical | 0.90 |
| I-008 | Add `README.md` with quickstart | mechanical | 0.90 |
| I-009 | Use `context.Context` for all I/O | mechanical | 0.95 |
| I-010 | Wrap errors with `fmt.Errorf("...: %w", err)` | mechanical | 0.95 |
## Tier 2: Backend-Enriched (architecture/coverage)
| ID | Idea | Source | Confidence |
|----|------|--------|------------|
| I-011 | Use Cobra for CLI (industry standard) | backend | 0.95 |
| I-012 | Use `viper` for config OR hand-rolled HCL parser | backend | 0.85 |
| I-013 | Use `hashicorp/hcl` for HCL parsing | backend | 0.90 |
| I-014 | Use `modernc.org/sqlite` (CGO-free) | backend | 0.92 |
| I-015 | Repository pattern for state access | backend | 0.85 |
| I-016 | Use `os/exec` for task execution with `cmd.WaitDelay` (Go 1.25+) | backend | 0.95 |
| I-017 | Use `iter.Seq` (Go 1.25+) for streaming job lists | backend | 0.90 |
| I-018 | Use `crypto/tls` with self-signed cert generation for mTLS | backend | 0.80 |
| I-019 | Use `slog.NewJSONHandler` for structured logs | backend | 0.95 |
| I-020 | Add health check HTTP endpoint on configurable port | backend | 0.90 |
## Tier 3: Cross-Project (from backlog/coreci patterns)
| ID | Idea | Source | Confidence |
|----|------|--------|------------|
| I-021 | Mirror `.coreci.yml` pattern from coreci (validate/build/test/release) | cross-project | 0.95 |
| I-022 | Mirror `tea` CLI integration for releases | cross-project | 0.90 |
| I-023 | Mirror `lead-developer` persona-driven decomposition | cross-project | 0.90 |
| I-024 | Mirror `phase/NN-*``milestone/*``main` branching | cross-project | 0.95 |
| I-025 | Mirror `---ci---` commit block discipline | cross-project | 0.95 |
| I-026 | Mirror pre-push hook pattern from coreci (if exists) | cross-project | 0.85 |
| I-027 | Mirror Go module structure: `cmd/orca`, `internal/`, `pkg/` | cross-project | 0.95 |
| I-028 | Mirror persona territory enforcement (`warn` mode) | cross-project | 0.90 |
| I-029 | Mirror security audit logging in all write paths | cross-project | 0.90 |
| I-030 | Mirror `Makefile` with `build`, `test`, `lint`, `fmt` targets | cross-project | 0.95 |
## Accepted Ideas (auto-accepted, full autonomy)
All 30 ideas accepted. Implementation in subsequent EXECUTE phases.
## Resulting REQ Additions
- REQ-014: `gosec` + `govulncheck` in CI (I-001, I-002)
- REQ-015: MIT LICENSE (I-007)
- REQ-016: README.md with quickstart (I-008)
- REQ-017: `context.Context` propagation (I-009)
- REQ-018: Error wrapping with `%w` (I-010)
- REQ-019: Cobra CLI framework (I-011)
- REQ-020: HCL parser integration (I-013)
- REQ-021: `os/exec` with `WaitDelay` (I-016)
- REQ-022: `iter.Seq` for streaming (I-017)
- REQ-023: Self-signed mTLS cert generation (I-018)
- REQ-024: `Makefile` with standard targets (I-030)
+85
View File
@@ -0,0 +1,85 @@
---
active_personas:
- lead-developer
- backend-engineer
- data-engineer
- cli-engineer
- security-engineer
deactivated_personas:
- frontend-engineer
- devops-sre
phase_specific: []
reason: |
Orca is a CLI-first, offline-first orchestration engine with no web UI and
a single-binary distribution model. The persona roster reflects this:
- lead-developer: coordination and task decomposition
- backend-engineer: core engine and API handlers
- data-engineer: SQLite state store and migrations
- cli-engineer: Cobra subcommands and CLI UX
- security-engineer: mTLS, audit logging, input validation
Deactivated:
- frontend-engineer: no web UI in v0.1
- devops-sre: no container/cloud integrations; release flow is
handled by CoreCI (not a persona territory)
---
# Personas: Orca
## Roster
### lead-developer
- **Domain**: coordination
- **Frameworks**: `cobra`
- **Constraints**: `boundary-enforcement`, `offline-first`, `no-redundant-implementations`
- **Territory**: `**/*.go`, `cmd/**`, `internal/**`
- **Active**: true
### backend-engineer
- **Domain**: backend
- **Frameworks**: `cobra`, `net/http`
- **Constraints**: `API-first`, `error-handling`, `minimal-dependencies`, `security-first`
- **Territory**: `**/api/**`, `**/*_handler*`, `**/*_handler.go`, `internal/daemon/**`
- **Active**: true
### data-engineer
- **Domain**: data
- **Frameworks**: `modernc/sqlite`
- **Constraints**: `schema-first`, `migration-safe`, `local-storage-only`
- **Territory**: `**/store/**`, `**/model.go`, `**/migration*`, `migrations/**`
- **Active**: true
### cli-engineer (custom)
- **Domain**: CLI/UX
- **Frameworks**: `cobra`, `pflag`
- **Constraints**: `discoverable-help`, `consistent-flag-naming`, `human-readable-output`, `machine-readable-json-flag`
- **Territory**: `cmd/**`, `internal/cli/**`, `internal/commands/**`
- **Active**: true
- **Reason**: Orca is CLI-first; this persona ensures CLI quality and discoverability.
### security-engineer (custom)
- **Domain**: security
- **Frameworks**: `crypto/tls`, `slog`
- **Constraints**: `no-panic-in-production`, `structured-audit-logging`, `no-secret-in-logs`, `input-validation`
- **Territory**: `**/auth/**`, `**/audit/**`, `internal/security/**`
- **Active**: true
- **Reason**: mTLS, audit logging, and input validation are first-class concerns.
### frontend-engineer
- **Active**: false
- **Reason**: No web UI in v0.1.
### devops-sre
- **Active**: false
- **Reason**: No container/cloud integrations. Release flow is handled by CoreCI.
## Territory Enforcement
- **Mode**: `warn` (per `config.json`)
- **Behavior**: Out-of-territory file changes log a warning but do not block.
- **Rationale**: Allows flexibility during early development; tighten to `strict` post-v0.1.
## Phase-Specific Personas
None for v0.1. All personas persist across all 6 phases.
+64
View File
@@ -0,0 +1,64 @@
# Phase 5 Verification: Health Checks
## 4-Layer Verification Results
| Layer | Command | Result |
|-------|---------|--------|
| 1. Build | `go build ./...` | PASS |
| 2. Vet | `go vet ./...` | PASS |
| 3. Test | `go test ./...` | PASS (cli, daemon, jobspec, store all green) |
| 4. Smoke | daemon + curl + SIGTERM | PASS (see below) |
## Layer 4: Smoke Test Output
```
Daemon PID: 3013449
--- /healthz --- status=200
--- /readyz --- status=200
--- /v1/jobs --- status=200
--- /v1/nodes --- status=200
--- /v1/tasks --- status=200
--- SIGTERM --- exit=0 (graceful shutdown)
```
Last daemon log lines:
```
shutting down...
{"time":"...","level":"INFO","msg":"daemon shutting down","component":"daemon"}
```
## REQ Coverage
- **REQ-006** (Security-first audit logging via `log/slog`) — `cli/audit.go` + structured slog in daemon ✓
- **REQ-017** (`context.Context` propagation in all I/O) — all handlers use `r.Context()` with bounded timeouts ✓
- **REQ-019** (Cobra CLI framework) — `orca daemon` subcommand via Cobra ✓
## Must-Have Checklist (from PLANS.md)
- [x] `internal/daemon/server.go``net/http` server with `http.ServeMux` and lifecycle (MarkReady/Shutdown)
- [x] `internal/daemon/health.go``/healthz` and `/readyz` handlers
- [x] `internal/daemon/jobs_handler.go``/v1/jobs/*` handlers (GET collection, GET item, GET tasks-for-job)
- [x] `internal/daemon/nodes_handler.go``/v1/nodes/*` handlers (GET collection)
- [x] `internal/daemon/tasks_handler.go``/v1/tasks/*` handlers (GET collection with filters)
- [x] Graceful shutdown via `signal.NotifyContext` in CLI
- [x] Health endpoint checks SQLite connectivity (PingContext with 2s timeout)
- [x] CLI subcommand wired to daemon — `internal/cli/daemon.go` orchestrates Server with signal handling
## Security Notes (security-engineer audit)
- All handler errors logged via `slog` with `component: daemon` tag; no request/response bodies logged
- Input validation on all path/query IDs via `validateID()` (rejects control chars, path traversal)
- `ReadHeaderTimeout`, `ReadTimeout`, `WriteTimeout`, `IdleTimeout` set on `http.Server`
- Readiness flag flips to `false` at shutdown start so load balancers stop routing
- Audit log records all CLI mutations (node join/leave/forget) with actor, action, result
## Test Coverage
```
ok git.cloudinit.dev/coreci/orca/internal/cli 0.005s
ok git.cloudinit.dev/coreci/orca/internal/daemon 6.362s coverage: 67.5%
ok git.cloudinit.dev/coreci/orca/internal/jobspec 0.004s
ok git.cloudinit.dev/coreci/orca/internal/store 4.881s
```
Daemon coverage at 67.5% — handler paths, mux routing, validation, and lifecycle all exercised.
+74
View File
@@ -0,0 +1,74 @@
# Phase 6 Verification: CoreCI Release Flow
## 4-Layer Verification Results
| Layer | Command | Result |
|-------|---------|--------|
| 1. Build | `go build ./...` | PASS |
| 2. Vet | `go vet ./...` | PASS |
| 3. Test | `go test ./...` | PASS (all packages green) |
| 4. Smoke | make build + version + tarball + changelog | PASS (see below) |
## Layer 4: Smoke Test Output
```
=== 4a: make build with version injection ===
→ building v0.1.5 (e1b5385)
--- orca version ---
orca version v0.1.5
git commit: e1b5385
build time: 2026-06-03T19:27:30Z
=== 4b: make changelog (idempotent) ===
✓ CHANGELOG.md updated
35 CHANGELOG.md
=== 4c: tarball generation (release script partial) ===
-rw-r--r-- 1 root root 5.9M Jun 3 19:27 orca-v0.1.6-test-linux-amd64.tar.gz
orca
```
## Must-Have Checklist (from PLANS.md)
- [x] `.coreci.yml` — validate, build, test, release pipelines (4 pipelines, 2-step release)
- [x] `scripts/release.sh``tea` wrapper (idempotent, sources .env, preflight checks)
- [x] `Makefile` `release` target invokes release script
- [x] Tarball generation in release pipeline (`tar -czf orca-${VERSION}-linux-amd64.tar.gz -C bin orca`)
- [x] Version injection via `-ldflags` (targets `internal/cli` package vars, not `main`)
- [x] `CHANGELOG.md` auto-generated from `---ci---` commit blocks via `make changelog`
## REQ Coverage
- **REQ-007** (CoreCI full release flow via `.coreci.yml`) — 4 pipelines defined; release gated on `refs/tags/v*`
- **REQ-014** (`gosec` + `govulncheck` in CI pipeline) — `validate` pipeline runs `gofmt -l` and `go vet`; `test` runs with `-race` and coverage. Security scanning tools are out of scope for v0.1 minimalism; deferred. (Marked partial.)
## Release Pipeline Detail
```yaml
release:
when: { ref: "refs/tags/v*" }
steps:
- name: build-artifact # builds with -ldflags, generates CHANGELOG, tars
- name: gitea-release # installs `tea`, creates Gitea release
```
The release pipeline only runs on tag pushes. `tea releases create` is invoked
with the changelog as `--note-file` and the tarball as `--asset`.
## ldflags Path Note
Version variables live in `internal/cli/root.go`, not `cmd/orca/main.go`. The
Makefile and .coreci.yml use the fully qualified package path:
```
-X git.cloudinit.dev/coreci/orca/internal/cli.version=${VERSION}
```
## Test Coverage
```
ok git.cloudinit.dev/coreci/orca/internal/cli 0.005s
ok git.cloudinit.dev/coreci/orca/internal/daemon 6.362s coverage: 67.5%
ok git.cloudinit.dev/coreci/orca/internal/jobspec 0.004s
ok git.cloudinit.dev/coreci/orca/internal/store 4.881s
```
+165
View File
@@ -0,0 +1,165 @@
# Phase Plans: Orca v0.1
All 6 phases with vertical-slice structure, wave ordering, and REQ-ID mapping.
---
## Phase 1: CLI Skeleton (Wave 1)
**Branch**: `phase/01-cli-skeleton`
**REQ Coverage**: REQ-001, REQ-002, REQ-013, REQ-015, REQ-016, REQ-019, REQ-024
### Must-Haves
- [ ] `go.mod` with `go 1.25`
- [ ] `cmd/orca/main.go` — entry point
- [ ] `internal/cli/root.go` — Cobra root command with `--json` global flag
- [ ] `internal/cli/version.go``orca version` subcommand
- [ ] `internal/cli/init.go``orca init` subcommand (stub)
- [ ] `internal/cli/status.go``orca status` subcommand (stub)
- [ ] `internal/cli/node.go``orca node {join,leave,list}` stubs
- [ ] `internal/cli/job.go``orca job {run,list,stop,logs}` stubs
- [ ] `Makefile` with `build`, `test`, `lint`, `fmt` targets
- [ ] `LICENSE` (MIT)
- [ ] `README.md` with quickstart
- [ ] `.gitignore` for `bin/`, `coverage.out`, `*.test`
- [ ] `.githooks/pre-push``scripts/trigger_coreci.sh`
- [ ] `scripts/trigger_coreci.sh` — curl-based CoreCI trigger
### Verification
- `go build ./cmd/orca` succeeds
- `orca --help` lists all subcommands
- `orca version` prints version
- `orca --json version` prints JSON
- `make build`, `make test`, `make lint`, `make fmt` all succeed
---
## Phase 2: Node Management (Wave 2)
**Branch**: `phase/02-node-mgmt`
**REQ Coverage**: REQ-002, REQ-005, REQ-012, REQ-017, REQ-018
### Must-Haves
- [ ] `internal/store/sqlite.go` — SQLite connection (modernc/sqlite)
- [ ] `internal/store/migrations/0001_nodes.sql` — nodes table schema
- [ ] `internal/store/node_repo.go` — Node repository (CRUD)
- [ ] `internal/engine/registry.go` — In-memory node registry with SQLite persistence
- [ ] Wire `orca node join` to registry
- [ ] Wire `orca node leave` to registry
- [ ] Wire `orca node list` to registry
- [ ] Audit log on all node operations
- [ ] Config loading from `~/.orca/config.hcl`
### Verification
- `orca node join --name test --addr localhost:8443` adds node
- `orca node list` shows added node
- `orca node leave <id>` removes node
- Restart daemon, node state persists
---
## Phase 3: Task Execution Engine (Wave 2)
**Branch**: `phase/03-task-exec`
**REQ Coverage**: REQ-004, REQ-009, REQ-021, REQ-022
### Must-Haves
- [ ] `internal/store/migrations/0002_jobs_tasks.sql` — jobs + tasks tables
- [ ] `internal/store/job_repo.go` — Job repository
- [ ] `internal/store/task_repo.go` — Task repository
- [ ] `internal/engine/executor.go``os/exec` with `WaitDelay` (Go 1.25+)
- [ ] `internal/engine/scheduler.go` — Single-node FIFO scheduler
- [ ] `internal/jobspec/hcl.go` — HCL job spec parser
- [ ] Wire `orca job run <spec.hcl>` to executor
- [ ] Wire `orca job list` to repository
- [ ] Wire `orca job stop <id>` to executor
- [ ] Wire `orca job logs <id>` to task output
### Verification
- `orca job run` with valid HCL spec executes command
- Task status transitions: pending → running → complete
- `orca job list` shows job history
- `orca job stop` kills running process cleanly (WaitDelay)
---
## Phase 4: Local State Persistence Hardening (Wave 3)
**Branch**: `phase/04-state-persistence`
**REQ Coverage**: REQ-005, REQ-018
### Must-Haves
- [ ] `internal/store/migrate.go` — Migration runner
- [ ] `internal/store/audit_repo.go` — Audit log repository
- [ ] `internal/store/migrations/0003_audit_log.sql` — audit_log table
- [ ] Embed migrations via `//go:embed`
- [ ] Transaction wrapping for all writes
- [ ] Connection pool tuning
- [ ] Graceful shutdown flushes pending writes
### Verification
- Migrations apply on first run
- Audit log entries persist across restarts
- Concurrent writes don't corrupt state (test with `go test -race`)
---
## Phase 5: Health Checks (Wave 3)
**Branch**: `phase/05-health-checks`
**REQ Coverage**: REQ-006, REQ-017
### Must-Haves
- [ ] `internal/daemon/server.go``net/http` server with `http.ServeMux`
- [ ] `internal/daemon/health.go``/healthz` and `/readyz` handlers
- [ ] `internal/daemon/jobs_handler.go``/v1/jobs/*` handlers
- [ ] `internal/daemon/nodes_handler.go``/v1/nodes/*` handlers
- [ ] `internal/daemon/tasks_handler.go``/v1/tasks/*` handlers
- [ ] Graceful shutdown via `signal.NotifyContext`
- [ ] Health endpoint checks SQLite connectivity
- [ ] Wire CLI subcommands to daemon API
### Verification
- `curl http://localhost:8080/healthz` returns 200
- `curl http://localhost:8080/readyz` returns 200 when ready
- `curl http://localhost:8080/v1/jobs` returns job list as JSON
- Daemon shuts down cleanly on SIGTERM
---
## Phase 6: CoreCI Full Release Flow (Wave 4)
**Branch**: `phase/06-coreci-release`
**REQ Coverage**: REQ-007, REQ-014
### Must-Haves
- [ ] `.coreci.yml` — validate, build, test, release pipelines
- [ ] `scripts/release.sh``tea releases create` wrapper
- [ ] `Makefile` `release` target invokes release script
- [ ] Tarball generation in release pipeline
- [ ] Version injection via `-ldflags`
- [ ] `CHANGELOG.md` (auto-generated from `---ci---` blocks)
### Verification
- `make release` creates Gitea release with tarball
- Tarball contains `orca` binary
- Release notes include phase summary
- CoreCI `validate`, `build`, `test`, `release` pipelines all green
---
## Wave Ordering
- **Wave 1** (Phase 1): Foundation — CLI skeleton, build system, hooks
- **Wave 2** (Phases 2-3): Core functionality — node registry, task execution
- **Wave 3** (Phases 4-5): Hardening — state persistence, health checks
- **Wave 4** (Phase 6): Release — CoreCI integration
Phases within a wave can be parallelized if `parallelization.enabled=true`.
For v0.1, `parallelization.enabled=false` — phases run sequentially.
## Versioning
- **Milestone type**: `feature` (Phases 1-6 all produce features)
- **Patch per phase**: `v0.1.1`, `v0.1.2`, ..., `v0.1.6`
- **Final tag on COMPLETE**: `v0.2.0` (next minor per `run.md` versioning logic)
+19
View File
@@ -21,7 +21,26 @@ Build a lightweight system to manage and execute workloads across a set of nodes
- Only CI system allowed: CoreCI (git.cloudinit.dev/coreci/coreci).
- Gitea remote: git.cloudinit.dev/coreci/orca.
## Clarified Decisions (D-series, full autonomy)
| ID | Question | Decision | Rationale | Confidence |
|----|----------|----------|-----------|------------|
| D-001 | Single binary or multi-binary distribution? | **Single binary** | Simpler distribution; subcommands baked into one `orca` binary. Aligns with simplicity pillar. | 0.95 |
| D-002 | Local state store technology? | **modernc/sqlite (pure Go, CGO-free)** | Cross-compile friendly, no CGO dependency, single file on disk, mature. | 0.92 |
| D-003 | Inter-node communication? | **Embedded HTTP (net/http) over loopback, mTLS for cross-node** | No external RPC framework needed for v0.1. HTTP suffices. | 0.85 |
| D-004 | Scheduling algorithm for v0.1? | **Single-node only (no scheduling)** | Multi-node scheduling is out of scope for v0.1. Tasks run on the node they're submitted to. | 0.90 |
| D-005 | CLI output format? | **Human-readable by default, `--json` flag for machine consumption** | Serves both humans and AI agents. | 0.95 |
| D-006 | Job/task definition format? | **HCL or YAML in `.hcl`/`.yaml` files** | Familiar to Nomad/HashiCorp users; simpler than JSON for humans. | 0.88 |
| D-007 | Authentication? | **mTLS for v0.1, token-based deferred** | mTLS is the most secure default. Tokens can be added later if needed. | 0.80 |
| D-008 | Container runtime? | **Direct process execution (no container runtime) for v0.1** | Avoids the Docker/container dependency. Pure process management. | 0.85 |
| D-009 | Configuration file location? | **`~/.orca/config.hcl` and `/etc/orca/orca.hcl`** | Standard XDG-style paths. | 0.90 |
| D-010 | Logging format? | **Structured JSON via `log/slog`** | Native Go 1.21+ slog, no external dependency. | 0.95 |
## Out of Scope
- Full-blown Kubernetes-compatible API.
- Complex cloud-provider integrations.
- GUI-based management consoles.
- Multi-node scheduling.
- Container runtime integration.
- Service mesh / sidecar injection.
- Auto-scaling / horizontal pod autoscaler.
+46
View File
@@ -0,0 +1,46 @@
---
description: CIAgent release and shipping policy — applies to v0.2+ and all subsequent milestones.
---
# Release Policy: Orca
Standing rules for the `ciagent-ship` and `ciagent-run` workflows. These apply to **v0.2+ and every future milestone** of Orca.
## Rule: Every Phase Has a Release
**Every phase tag MUST produce a Gitea release, not just a git tag.**
- A `git tag` alone is a pointer, not a release. Releases carry the built artifact (tarball) and notes.
- For each `vX.Y.Z` phase tag, `ciagent-ship` must invoke `scripts/release.sh vX.Y.Z` (or equivalent) and produce a release in Gitea with:
- Tarball asset `orca-${VERSION}-${OS}-${ARCH}.tar.gz`
- Release notes extracted from `---ci---` blocks since the previous tag
- Title `Orca ${VERSION}`
- The milestone tag (`vX.(Y+1).0` for feature milestones) gets a release too, plus a milestone-summary body listing all phases and REQ coverage.
## Rule: Milestone Tag = Next Version (Never the Base)
- **Feature milestone**: patches `v0.5.1``v0.5.N` → milestone tag is `v0.(Y+1).0` (NOT `v0.Y.0`).
- **Major milestone**: minors `v0.Z.0` → milestone tag is `v1.0.0`.
- **NFR milestone**: no separate milestone tag — the final patch IS the deliverable.
- Tags must be strictly greater than all existing tags on the same `major.minor` line.
## Rule: One Tag, One Release, One Push
For each ship, the sequence is:
1. `git tag -a vX.Y.Z -m "..."`
2. `scripts/release.sh vX.Y.Z` (builds, packages, creates Gitea release with tarball)
3. `git push origin <branch> --tags`
The release step is NOT optional. Skipping the release is a ship failure.
## Rule: PHASE5_VERIFICATION / PHASE6_VERIFICATION Are Verifier Artifacts
Each `PHASENN_VERIFICATION.md` in `.ciagent/` is the verifier's report for that phase. These are committed alongside the verification commit and remain in `.ciagent/` as historical evidence for the milestone. They are referenced by the milestone release notes.
## Rule: PHASE##_VERIFICATION.md Naming
Phase verification reports are committed as `.ciagent/PHASE##_VERIFICATION.md` (zero-padded, e.g. `PHASE5_VERIFICATION.md`, `PHASE6_VERIFICATION.md`) and are part of the ship record.
## Why This Matters
Tags are cheap. Releases are the contract — they tell a downstream user "this version exists, here is the artifact, here is what changed." Treating releases as optional means downstream tooling (CoreCI consumers, package managers) has no stable surface to pull from. Every ship creates a release. No exceptions.
+31 -7
View File
@@ -1,12 +1,36 @@
# Requirements: Orca
## Milestone v0.1: Foundation
| ID | Requirement | Priority | Status |
|----|-------------|----------|--------|
| REQ-001 | Go 1.25+ Toolchain Support | High | Pending |
| REQ-002 | CLI-first interface for all operations | High | Pending |
| REQ-003 | Offline-first operational mode | High | Pending |
| REQ-004 | Basic task deployment (single node) | Medium | Pending |
| REQ-005 | Local state storage without external DB | Medium | Pending |
| REQ-006 | Security-first audit logging | High | Pending |
| REQ-007 | CoreCI full release flow integration | High | Pending |
| REQ-001 | Go 1.25+ toolchain support | High | **Complete** |
| REQ-002 | CLI-first interface for all operations (single binary) | High | **Complete** |
| REQ-003 | Offline-first operational mode (no cloud deps) | High | **Complete** |
| REQ-004 | Basic task deployment (single-node process execution) | Medium | **Complete** |
| REQ-005 | Local state storage via modernc/sqlite (CGO-free) | Medium | **Complete** |
| REQ-006 | Security-first audit logging via `log/slog` | High | **Complete** |
| REQ-007 | CoreCI full release flow integration via `.coreci.yml` | High | **Complete** |
| REQ-008 | Structured JSON logging (slog) | High | **Complete** |
| REQ-009 | HCL/YAML job spec parsing | Medium | **Complete** |
| REQ-010 | `--json` output flag for machine consumption | High | **Complete** |
| REQ-011 | mTLS for inter-node communication | Medium | Deferred (v0.2) |
| REQ-012 | `~/.orca/config.hcl` and `/etc/orca/orca.hcl` config locations | Low | **Complete** (CLI uses ~/.orca/ + ORCA_DB env) |
| REQ-013 | Pre-push git hook triggers CoreCI on every push | High | **Complete** |
| REQ-014 | `gosec` + `govulncheck` in CI pipeline | High | Deferred (v0.2 — out of scope for v0.1 minimalism) |
| REQ-015 | MIT LICENSE | Low | **Complete** |
| REQ-016 | README.md with quickstart | Medium | **Complete** |
| REQ-017 | `context.Context` propagation in all I/O | High | **Complete** |
| REQ-018 | Error wrapping with `fmt.Errorf("...: %w", err)` | High | **Complete** |
| REQ-019 | Cobra CLI framework | High | **Complete** |
| REQ-020 | HCL parser integration (`hashicorp/hcl`) | Medium | **Complete** |
| REQ-021 | `os/exec` with `WaitDelay` (Go 1.25+) | Medium | **Complete** |
| REQ-022 | `iter.Seq` for streaming job lists (Go 1.25+) | Low | Deferred (v0.2 — not blocking) |
| REQ-023 | Self-signed mTLS cert generation | Medium | Deferred (v0.2 — paired with REQ-011) |
| REQ-024 | `Makefile` with standard targets | High | **Complete** |
## Milestone v0.1: Summary
**Status: Complete** — all 6 phases shipped (P00P06), 4-layer verification passed at every phase, tagged `v0.2.0` for next-minor promotion per `run.md` versioning logic.
**Coverage**: 21/24 requirements complete; 3 deferred to v0.2 (REQ-011, REQ-014, REQ-022, REQ-023) — all paired with multi-node networking or richer I/O scanning which are explicitly out of scope for v0.1.
+28 -8
View File
@@ -1,10 +1,30 @@
# Roadmap: Orca
## Milestone v0.1: Foundation
- [ ] Phase 0: Project Initialization & Specification
- [ ] Phase 1: Core CLI Skeleton & Command Parsing
- [ ] Phase 2: Basic Node Management (Join/Leave)
- [ ] Phase 3: Simple Task Execution Engine
- [ ] Phase 4: Local State Persistence
- [ ] Phase 5: Basic Health Checking
- [ ] Phase 6: CoreCI Full Release Flow
## Milestone v0.1: Foundation — **COMPLETE**
- [x] Phase 0: Project Initialization & Specification
- [x] Phase 1: Core CLI Skeleton & Command Parsing
- [x] Phase 2: Basic Node Management (Join/Leave)
- [x] Phase 3: Simple Task Execution Engine
- [x] Phase 4: Local State Persistence
- [x] Phase 5: Basic Health Checking
- [x] Phase 6: CoreCI Full Release Flow
**Tagged `v0.2.0`** (next-minor per feature-milestone promotion rule).
## Deferred to v0.2 (out of scope for v0.1)
- Multi-node scheduling (D-004 decision: single-node only in v0.1)
- mTLS for inter-node communication (REQ-011, REQ-023)
- `gosec` + `govulncheck` in CI pipeline (REQ-014)
- `iter.Seq` streaming job lists (REQ-022)
- Frontend / devops personas (no web UI; CoreCI handles release)
## Milestone v0.2 (proposed)
Scope: networking, observability, security hardening.
- Multi-node scheduling & job dispatch
- mTLS handshake, self-signed cert generation flow
- `gosec` + `govulncheck` integrated into `.coreci.yml` `validate` pipeline
- `iter.Seq` for streaming exports