Kk-carrier docs

Reference

Normative wire formats, exit codes, budgets and on-disk layout. This page states what K does and requires, not why. For the reasoning, read the design; for a narrative, the guide.

Two protocols: the runner protocol on stdin and stdout, and the command controller protocol between host and controller Runner protocol Command controller protocol Callersupervisor RunnerK + adapter stdin: one JSON request stdout: one JSON response + exit code 0, 1, 2 or 3 stderr: logs actions: upgrade, recover, status HostCommandHost Controlleryour program stdin: one JSON request stdout: ok + evidence bounded to 64 KiB, 30 s actions: fence, quiesce, stop, start, probe, resume
Different protocols. Upgrade, recover and status go to the runner; fence, quiesce, stop, start, probe and resume go to the application controller.

Protocol v1

One JSON request on stdin, one response on stdout, then exit. Logs go to stderr. Decoded input is bounded to 16,384 JavaScript string code units. Unknown fields, actions or protocol versions, invalid ids or targets, and a nonboolean consented are rejected before the adapter factory runs. Request ids and target strings are nonempty, trimmed strings of at most 256 code units.

Requests

{"protocolVersion":1,"action":"upgrade","id":"job-123","targetVersion":"2.0.0","consented":true}
{"protocolVersion":1,"action":"recover"}
{"protocolVersion":1,"action":"recover","expected":{"id":"job-123","targetVersion":"2.0.0"}}
{"protocolVersion":1,"action":"status"}
consented
Records approval already obtained by an authenticated caller. It is not authorization from an untrusted client. Ownership and compatibility checks still apply.
expected
Binds automated recovery to one operation. The binding is checked under the lock before any controller action. Missing or mismatched history refuses recovery. A completed original operation replays its result even when newer work is pending. An operator recover without expected runs once against the current unfinished operation.

Actions and exit codes

ActionEffect0123
upgradeInstall the exact requested version; a mismatched source result is rejectedpromoted or up-to-datefailure or rollbackheldunresolved
recoverSettle persisted work under the same lock; never starts a new upgradesuccessful or no recorded outcomerecorded failure or rollbackheld receipt or live lock ownerunresolved, including unreadable recovery state
statusRead the current receipt without lifecycle callsreadable, including genesisunreadable

Responses

Execution replies carry protocolVersion, action, result, exitCode, operation and error. Input rejection or adapter-construction failure may return only protocolVersion, result, exitCode and error. Termination can leave no complete response; inspect persistent state and recover.

operation.kind is observed (with the operation record), genesis (no operation recorded) or unreadable.

Lock acquisition failure returns result: "busy", exit 2, and the observed state without creating a receipt for the rejected request. A supervisor may finish an initial upgrade as held after confirming that worker exited. A busy recovery worker does not settle the original interrupted request; supervision retains its recovery files and returns 3. Unreadable state returns 3 for upgrade/recover, while raw status reports the read error as 1.

Receipts and retries

operation.json holds the current operation. Before starting another, K archives a terminal receipt at receipts/<sha256(operation-id)>.json under the same lock. Archived receipts have no automatic garbage collection.

Supervisor budgets

BudgetDefaultOption
Worker execution10 minutesexecution_ms
Each recovery attempt2 minutesrecovery_ms
Recovery attempts2recovery_attempts (0 to 10)
Total14 minutes (independent of other overrides)total_ms
Exit observation after termination1 secondfixed

All budgets are positive integers. Artifact acquisition has separate transfer budgets derived from the artifact size (TransferPolicy::budgets); Downloader::download called without any budget uses the same size-derived ones. An unconfirmed worker exit forbids takeover. Exhaustion preserves state and returns exit 3 with a recovery file; it never reports success.

Engine host-call budget

Every host call, including fence, readback, resume and recovery, has a positive budget, default 120 seconds (host_budget_ms). A call whose effect is uncertain raises Error::Uncertain; the worker retains its lock until it exits. Bundled workers exit after flushing their response. An in-process caller that receives Error::Uncertain must also exit rather than reuse that worker.

Command controller protocol

CommandHost::new(command, state_dir, timeout_ms) runs an external controller via argv, without a shell.

Request on stdin:

{"protocolVersion":1,"action":"fence"}
{"protocolVersion":1,"action":"quiesce"}
{"protocolVersion":1,"action":"stop","slot":"stable","artifactPath":"<stateDir>/slots/stable/artifact.bin"}
{"protocolVersion":1,"action":"start","slot":"experiment","artifactPath":"<stateDir>/slots/experiment/artifact.bin"}
{"protocolVersion":1,"action":"probe"}
{"protocolVersion":1,"action":"resume"}

Response on stdout:

{"protocolVersion":1,"ok":true}
{"protocolVersion":1,"ok":true,"evidence":{"version":"2.0.0","pid":4242,"startId":"..."}}
{"protocolVersion":1,"ok":false,"uncertain":true}

Lock protocol

upgrade.lock has one live owner per state directory. Unique process-owned contender entries serialize creation and reclamation, including the partial-write window. Only entries of provably dead owners are reclaimed. Pid reuse conservatively refuses acquisition; age never proves that a live owner is dead. The protocol requires local atomic file creation and coherent directory reads. It is not a distributed or NFS lock.

Quarantine moves the state directory with a no-replace rename (renameat2(RENAME_NOREPLACE) on Linux). Filesystems that reject that flag (Lustre, NFS, some FUSE mounts) return EINVAL; K then checks that the destination is absent and uses a plain rename(2) under the writer lock. That fallback is only exclusive when a single host uses the state directory.

State directory layout

<stateDir>/
  upgrade.lock            live owner
  upgrade.lock.claims/    contender entries
  journal.jsonl           append-only write-ahead phase record, fsync'd per line
  operation.json          current operation receipt
  receipts/<sha256(id)>.json
  slots/stable/artifact.bin
  slots/stable/VERSION
  slots/experiment/artifact.bin
  slots/experiment/VERSION
  incoming/               staging for verified downloads before slot placement
  controllers/            recorded controller pids

Each slot holds one artifact.bin and its VERSION. Package layouts and additional install hooks need a product contract. Application data belongs outside the slots. status reads operation.json without taking the lock.

Journal entries are {seq, timestampMs, intent, detail}. The handing-over entry's detail.priorStartId records the incarnation probed before the upgrade touched anything; it is absent when nothing was live. Renames and journal appends fsync the containing directory on POSIX. Slot publication also syncs the copied artifact, VERSION file and staging directory first. A failed directory sync stops the operation. Windows directory sync is a no-op and provides no equivalent power-loss durability guarantee.

Supervisor scratch layout

<scratchDir>/k-runner-<random>/
  runner.bin (runner.exe on Windows)   verified runner (mode 0700)
  recovery.json             invocation descriptor: file, sha256, size, recover request

recovery.json is an invocation descriptor, not a transaction log. It is removed after settlement and retained on an unresolved result. supervisor::resume_runner(path) re-verifies the runner against the recorded hash before executing it.

Release metadata

{"version":"2.0.0","url":"https://.../service","sha256":"<hex>","size":123456,
 "gzip":{"url":"https://.../service.gz","sha256":"<hex>","size":45678}}

sha256 and size always describe the installed bytes. When gzip is present K downloads and verifies the compressed object, bounds decompression, then verifies the canonical size and hash. Failure of a selected gzip object is terminal; K does not fall back to the canonical URL. Resume offsets refer to the compressed object.