AkurAI Build
Menu

AkurAI-Build

public

Latest change 266a1aa21e346770b48e96f008ab6c2a5a603961 - Complete PR interfaces, isolated CI and crash-safe merge recovery by Ólafur Búi Ólafsson

# Suite production delivery policy

Defines the one machine-readable contract every active app in
`AkurAI-Framework/AKURAI_APPS.toml` must satisfy to deploy to production
through AkurAI Build. No second deploy engine: every rule below is checked
against the existing `.akurai.yml` schema (`src/config.rs::JobSpec`) and the
existing run lifecycle (`src/runner.rs`, `src/db.rs`), the same objects
AkurAI Build already parses and persists.

Scope: rules apply only to jobs that declare `environment: production`.
Non-production jobs (verify-only, PR CI, staging) are unaffected — this is
how `AkurAI-Build/.akurai.yml`'s own `verify`/`package` jobs stay unrestricted
while `deploy-production` is gated.

## Rule table

Each rule has a violation identifier (stable, for audit/error reporting),
the JobSpec/run fields it reads, and whether it is a **pre-queue/promotion**
check (static, evaluated by `config::parse` / `akurai_pipeline_validate`
before a run is queued or promoted) or a **runtime evidence** check
(evaluated from the persisted `Run`/job rows after execution — declaring
something in YAML is never accepted as proof it happened).

| ID | Requirement | Kind | Fields / evidence |
|---|---|---|---|
| SDP-001 `CANONICAL_GIT` | Queued/promoted commit is a full 40/64-hex object id that matches the hosted branch head returned by `akurai_repo_branches` at queue time. | pre-queue | `Runner::queue` commit param (`config::validate_commit`); caller must pass the exact SHA, not a floating ref, for any production-bound run. |
| SDP-002 `PIPELINE_ORDER` | Pipeline contains named jobs `verify`, `package`, and a production job (conventionally `deploy` or `deploy-production`) with `needs` forming `verify -> package -> deploy`. | pre-queue | `JobSpec.name`, `JobSpec.needs` graph from `config::parse`. |
| SDP-003 `IMMUTABLE_PACKAGE` | The `package` job is distinct from `verify` and the production job, and declares at least one `artifacts` glob. | pre-queue | `JobSpec.artifacts` non-empty on the job satisfying SDP-002's package role. |
| SDP-004 `SAME_ARTIFACT` | The production job `needs` the package job (already required by SDP-002) and its `run` text does not invoke a build command (`cargo build`, `bun build`, `npm run build`, `go build`, etc.) — it must consume the artifact `package` produced, never rebuild or ad hoc `cp`/`rsync` from an unrelated path. | pre-queue | `JobSpec.command` heuristic scan on the production job only. |
| SDP-005 `PROD_ENV_APPROVAL` | Approval is an explicit opt-in job policy; routine production deployment does not require a human gate (owner direction, 2026-09-06). Destructive operations retain their separate controls. | optional promotion | `JobSpec.approval`. |
| SDP-006 `HOST_AGENT_SAFEGUARDS` | Production deploy commands hand off to a root-owned host agent (checksum verify, bounded restart, public health gate, automatic rollback) instead of mutating the running service in place. Concretely: the job's `run` text must reference one of the sanctioned handoff paths — `deploy/service-deploy.sh`, `ec2 release`, `ec2 deploy-binary`, or an app-owned `deploy.sh`/`scripts/provision-*.sh` that itself shells out to one of those. | pre-queue (pattern) + runtime (evidence) | Static: command text pattern match. Runtime: the persisted run's job log for the production job must show the handoff command actually executed and exit 0 — a job that merely printed the intent does not satisfy this rule. |
| SDP-007 `MIGRATION_RECOVERY` | If the app's `AKURAI_APPS.toml` entry declares `db_snapshot`, the production job's `run` text must take a backup (`.backup`/`cp`/`sqlite3 ... .backup`) and verify it (`PRAGMA integrity_check` or equivalent, non-empty size check) before mutating state. | pre-queue (pattern) + runtime (evidence) | Static: command text pattern match keyed off `AKURAI_APPS.toml[app].db_snapshot`. Runtime: backup file path/size appears in the job log. |
| SDP-008 `SECRET_REDACTION` | Jobs reference secrets only via the `secrets:` list (resolved from `AKURAI_SECRET_<NAME>`); no literal secret value may appear in `run` text, artifacts, or retained logs. | pre-queue + runtime | Static: `JobSpec.secrets` names are valid env names (already enforced); reject any `run` line containing a literal value matching a currently configured secret. Runtime: log redaction already strips exact secret values — audit that no unredacted match slips through. |
| SDP-009 `PERSISTED_SUCCESS` | A production deployment is "done" only when the run's persisted status is exactly `succeeded`. `queued`, `running`, `waiting`, `canceled`, `failed`, and "verify passed"/"package built" partial states are all incomplete. | runtime | `Run.status` in `db.rs`; `waiting` additionally requires an `akurai_run_promote` event before it can reach `succeeded`. |
| SDP-010 `POST_DEPLOY_VERIFY` | The production job's `run` text includes an app-specific behavior/health check (e.g. `curl .../api/health` asserting `status: ok`, or `scripts/validate.sh`) executed after the handoff step, tied to the commit that was just deployed. | pre-queue (pattern) + runtime (evidence) | Static: command text pattern match for a health/validate invocation after the deploy handoff. Runtime: that command's exit code in the job log. |

Routine deployment approval is optional. A configured `approval: true` is still
honored by the runner; it is no longer required merely for production jobs.

## Conforming example

`AkurAI-Build/.akurai.yml` already satisfies SDP-002/003/004/006/009/010 by
construction (see file for full text); its `deploy-production` job is the
canonical example of a production job that hands off to the host agent:

```yaml
- name: deploy-production
  needs: [package]
  executor: native
  branches: [main]
  environment: production
  run: H=${AKURAI_BUILD_HOME:-...}; AKURAI_HOST_BIN=$H/.local/bin sh deploy/service-deploy.sh
```

`deploy/service-deploy.sh` stages the artifact for `deploy/host/akurai-deploy-agent.sh`
(root-owned, systemd-triggered), which checksums, installs, restarts,
health-gates on `/api/health`, and rolls back to `$bin.previous` automatically
on failure — this is the SDP-006 reference implementation every other app's
deploy step should match or delegate to.

## Integration points (for the enforcement task)

No new engine or schema is introduced. Enforcement extends the existing
parse/queue/audit surfaces:

- `src/config.rs::parse` / `validate_job` — add SDP-002..005, 007, 008, 010
  as additional `ensure!` checks gated on `job.environment.as_deref() ==
  Some("production")`, returning a `{rule_id}: {detail}` message so callers
  can surface the exact violation identifier. Non-production jobs skip these
  checks entirely (preserves existing CI use).
- `src/mcp.rs::validate_pipeline` — already the pre-queue path
  (`akurai_pipeline_validate`); once `config::parse` enforces the rules above,
  this tool rejects non-conforming production pipelines before `akurai_run_queue`
  with no additional code.
- `src/runner.rs::queue` — already validates ref/commit (SDP-001); no change
  needed beyond ensuring the fleet-audit caller always passes an exact commit
  for production runs rather than a floating branch name.
- `src/db.rs` (`Run.status`, job log rows) — the source of truth for SDP-006/007/009/010
  runtime evidence; a new fleet-audit command reads `AKURAI_APPS.toml`, resolves
  each app's registered repository, calls the existing pipeline-validate and
  run-history queries, and reports per-app violations plus missing runtime
  evidence without adding a persistence layer.
- `AkurAI-Framework/AKURAI_APPS.toml` — existing `db_snapshot` field is the
  input SDP-007 keys off; no new field required.

## Baseline findings (13 registered apps)

Reviewed each app's registered `.akurai.yml` against the rule table above.
"Needs verification" means the referenced `deploy.sh`/script content was not
inspected line-by-line in this pass — the fleet-audit command (t_8eac946c)
should confirm SDP-006/010 runtime evidence, not just the static pattern.

| App | 002 order | 003 pkg | 004 no-rebuild | 005 approval | 006 host-agent | 007 migration | 009/010 | Notes |
|---|---|---|---|---|---|---|---|---|
| akurai-platform | ok | ok | ok | ok | ok (`ec2 deploy-binary`) | n/a | health curl present | catalog `deploy` field still names raw `akurai-ec2 release` (t_b6961691 scope) |
| akurai-notes | ok | ok | ok | ok | ok (backup+install via `ec2 ssh`) | ok (`.backup` + rollback on health-check failure) | health + `/mcp` 405 check | reference-quality migration handling |
| akurai-crm | ok | ok | ok | ok | ok (`ec2 release`) | n/a | `validate.sh` | catalog deploy field stale |
| akurai-passvault | ok | ok | ok | ok | ok (`ec2 release`) | n/a | `validate.sh` | catalog deploy field stale |
| akurai-vpn-site | ok | ok | ok | ok | ok (`ec2 ship`+`ssh rsync`) | n/a | curl health + content check | epic notes claimed this app had no `.akurai.yml`; it now does — stale note, not a current violation |
| akurai-tasks | ok | ok | ok | ok | ok (`ec2 release` w/ sha256) | n/a | `validate.sh --live` | catalog deploy field stale |
| akurai-idp | ok | ok | ok | ok | ok (`./deploy.sh publish`) | ok (sqlite `.backup` + integrity_check) | `validate.sh` | — |
| akurai-router | ok | ok | ok | ok | needs verification (`./deploy.sh`) | n/a | needs verification | deploy.sh not inspected in this pass |
| akurai-dns | ok | ok | ok | ok | needs verification (`./deploy.sh --publish-only`) | n/a | needs verification | deploy.sh not inspected in this pass |
| akurai-vpn-control | ok | ok | ok | ok | needs verification (`./deploy.sh ec2`) | n/a | needs verification | deploy.sh not inspected in this pass; approval is deliberate here (mesh criticality) |
| rust-monitor | ok | ok | ok | ok | needs verification (`akurai-ec2 release`) | n/a | `validate.sh` | epic notes claimed missing `environment: production`; pipeline already declares it — stale note |
| akurai-mail-api | ok | ok | ok | ok | ok (`ec2 ssh` backup+config, `ec2 release` w/ sha256) | ok (`tar` snapshot of app+config to timestamped backup) | `validate.sh` | epic notes claimed no distinct package job; pipeline already has one — stale note |
| akurai-drive-api | ok | ok | ok | ok | ok (`./deploy.sh publish` x2, sha256-checked) | ok (sqlite `.backup` + integrity_check) | `validate.sh` | multi-binary (backend + Framework + desktop) release, most complex conforming example |

Fleet-wide: all 13 apps satisfy SDP-002/003/004/005 as written today. The one
suite-wide gap the epic notes still call correctly is **SDP-006 evidence, not
declaration**: every app's `AKURAI_APPS.toml` `deploy` field still names a
direct `akurai-ec2 release ...` command rather than an AkurAI Build
run/promotion reference. That field is informational/manual-fallback tooling
today, not something Build enforcement reads — but it invites bypassing Build
by hand, so t_b6961691 should still replace it. The three "needs
verification" rows (router, dns, vpn-control) are the fleet audit's first
job: confirm their `deploy.sh` scripts satisfy SDP-006/010 with the same
rigor as the reference apps above, and note the discrepancies from this
document if any of the three "stale note" findings turn out to be wrong on
closer inspection.

## t_b6961691 catalog fix (2026-09-06)

Confirmed against the live `.akurai.yml` for all 13 apps and `AKURAI_APPS.toml`
before changing anything:

- AkurAI-VPNSite already has `.akurai.yml` (verify -> package -> deploy,
  `environment: production`, `approval: true`) — the epic's "missing config"
  note was stale, no file added.
- AkurAI-MailAPI already has a distinct `package` job with its own
  `artifacts:` list, separate from `verify` and `deploy` — the epic's
  "lacks a distinct immutable package job" note was stale, no job added.
- AkurAI-Monitor's `deploy` job already declares `environment: production`
  and `approval: true` — the epic's note was stale, no change made.
- No other SDP-002..010 violation found across the 13 `.akurai.yml` files on
  this pass (see rule table above); AkurAI-Router, AkurAI-DNS, and
  AkurAI-VPN's `deploy.sh` still carry the "needs verification" flag for
  SDP-006/010 runtime evidence — that inspection is fleet-audit scope
  (t_8eac946c/t_713bfb09), not re-litigated here.
- Replaced the one confirmed real violation: every one of the 13
  `AKURAI_APPS.toml` `deploy` fields named a raw `akurai-ec2 release ...`
  command. All 13 now read:
  `akurai-build: akurai_repo_sync <repo> -> akurai_run_queue(commit=<hosted-sha>) -> akurai_run_promote(id, environment=production) -> require status=succeeded`.
  This is the manual-fallback/informational field only — Build enforcement
  never reads it — so this is a docs/catalog edit, no pipeline or engine
  change, and every app's `.akurai.yml` verify/package/deploy jobs,
  artifact format, approval gate, host-agent handoff, migration recovery,
  and post-deploy checks are untouched.
- Published: commit `8816e77` on `AkurAI-Framework` branch `master`, pushed
  to hosted Git and confirmed present at hosted `refs/heads/master` via
  `git ls-remote`. AkurAI-Framework carries its own `.akurai.yml`
  (verify -> package -> deploy for the `akurai` binary), so this push
  auto-queues that pipeline's `verify`/`package` on hosted `master` per the
  push-triggered CI contract; this catalog edit does not touch source under
  test, so no separate app-level behavior change to verify beyond that run
  reaching `verify`/`package` success (its `deploy` stage ships the
  `akurai` binary itself, unrelated to this doc-data edit).
- Do not read this as fleet conformance: SDP-006/010 runtime evidence for
  router/dns/vpn-control remains unverified, and this pass only checked the
  13 `.akurai.yml` static text, not persisted run history. The fleet audit
  (t_8eac946c) is the authority for a conformance claim.

## Enforcement + fleet audit (t_8eac946c, 2026-09-06)

Implemented as specified, no new engine:

- `src/config.rs::validate_production_policy` runs inside `config::parse`
  (called by both `mcp.rs::validate_pipeline`/`akurai_pipeline_validate`
  before queue/promotion, and `runner.rs::execute_claimed` at run time) and
  checks SDP-002..006/010 as static `run:`/`needs`/`artifacts` pattern
  rules, scoped to `environment: production` jobs only — non-production
  jobs (this repo's own `verify`/`package`, any staging job) are untouched,
  so existing CI keeps working. A non-conforming production pipeline now
  fails `config::parse`, which rejects it before `akurai_run_queue` can
  even create a run row.
- `akurai ec2 fleet-audit [--json]` (`src/ec2/host.rs::fleet_audit`) reads
  `AKURAI_APPS.toml`, resolves each active app's exact hosted commit via
  `git rev-parse HEAD` on its registered checkout, runs the same
  `config::parse` against its local `.akurai.yml`, and reports precise
  violations plus the runtime-evidence categories (SDP-006/007/009/010)
  it cannot itself observe from the filesystem — it never claims a
  deployment succeeded, only that the pipeline text is (or isn't)
  conformant. Verified live: all 13 registered apps report `OK` with their
  real hosted commit SHA and the expected missing-evidence list (extra
  SDP-007 entry only for the two apps with `db_snapshot` set).
- 9 new `src/config.rs` unit tests cover the conforming pipeline and each
  failing shape: missing package dependency (SDP-002), package job without
  artifacts (SDP-003), rebuild instead of consuming the artifact (SDP-004),
  optional approval (SDP-005),
  missing host-agent handoff (SDP-006), and missing post-deploy health
  check (SDP-010); a non-production job is confirmed unaffected.
- Verified: `cargo fmt --all -- --check`, `cargo clippy --all-targets
  --all-features -- -D warnings`, `cargo test` (269/270 pass; the one
  failure, `git_process::tests::errors_on_non_repository`, reproduces
  identically on the pre-existing `5d92bd1` baseline with this diff
  stashed out — unrelated to this change).