Documentation
¶
Overview ¶
Package stack implements the `palai` local-stack lifecycle: it initialises the .palai data layout, drives the four-service Docker Compose distribution up and down, and runs the doctor health surface. It shells out to `docker compose` (no Docker SDK dependency) and speaks the public API and the durable spine over the ports `init` minted, so the same binary an operator runs is what the e2e proof drives.
Index ¶
- func AdminDefaults() (baseURL, apiKey string, err error)
- func AuditCheckpoint(dir, signingKey string, allowEmpty bool) error
- func AuditVerify(checkpointPath, pubkey string, notOlderThan time.Duration, minAnchored int, ...) error
- func GetResponse(id string) error
- func InstallBackup(outPath string) error
- func InstallRestore(archivePath string) error
- func InstallRestoreVerify(archivePath string) error
- func ProductionDoctor(envFile string, jsonOut bool) error
- func SupportBundle(outPath string, tailLines int) error
- func Upgrade(opts UpgradeOptions) error
- func UpgradeRollback(opts RollbackOptions) error
- type BackupManifest
- type Check
- type Config
- type ReleaseManifest
- type Report
- type RollbackOptions
- type UpgradeOptions
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AdminDefaults ¶
AdminDefaults returns the base URL and the bootstrap API key of the initialised .palai stack — the last rung of the admin CLI's flag → env → .palai fallback chain. It errors only when .palai is absent, which the caller treats as fatal only when a flag/env did not already supply the value.
func AuditCheckpoint ¶
AuditCheckpoint reads the journal, folds it into a checkpoint, and writes the signed envelope into dir. signingKey is the release signing key (PALAI_AUDIT_SIGNING_KEY when the flag is empty); there is no unsigned mode, because an unsigned anchor anyone can regenerate is not an anchor.
allowEmpty (--allow-empty) is the explicit opt-in for genuinely empty journals. Without it a zero-row read is REFUSED rather than blessed with a signature — see WriteSigned.
func AuditVerify ¶
func AuditVerify(checkpointPath, pubkey string, notOlderThan time.Duration, minAnchored int, jsonOut bool) error
AuditVerify recomputes the chain from the journal rows and compares it to the signed checkpoint. It returns a non-nil error — and therefore a non-zero exit — on any alert.
notOlderThan / minAnchored are the operator's ROLLBACK policy. Compare can only say "this checkpoint's own prefix is intact", which an attacker's older-but-validly-signed copy satisfies perfectly; only the operator knows their cadence, so only they can declare the window. The report carries the checkpoint's age whether or not one is declared.
func GetResponse ¶
GetResponse retrieves a response by id and prints its NORMALIZED projection — {"id","output_text","status"} as canonical JSON — on stdout. It is the palai CLI's leg of the E16 T8 four-client parity journey: the SAME shared run, retrieved and normalized by all four clients, is asserted byte-identical. Base URL + API key resolve from PALAI_BASE_URL/PALAI_API_KEY (the journey sets these) or fall back to the .palai config. A 410 tombstone (a purged store:false response) is reported honestly: it prints {"status":410,...} and returns an error so the caller can assert the typed-gone surface. The output text is the concatenation of the response output items' text fields — the same extraction every client applies to the same retrieved bytes.
func InstallBackup ¶
InstallBackup captures the running stack into one archive at outPath (default palai-backup-<project>-<UTC>.tar.gz in the cwd). It dumps Postgres consistently (pg_dump -Fc), copies the object-store data volume, and writes a manifest of ids + checksums.
func InstallRestore ¶
InstallRestore restores an archive into a running EMPTY target stack. It REFUSES a target that already holds tenant rows (fail-closed — no data is ever overwritten), verifies the archive's member checksums, then replaces Postgres (pg_restore --clean) and the object-store volume with the writers stopped for the swap.
func InstallRestoreVerify ¶
InstallRestoreVerify proves a restored target matches its backup manifest: the archive's member checksums verify, the live migration version + tenant ids match the manifest, and the sample response is retrievable from the restored database (proving the tenant data is queryable).
func ProductionDoctor ¶
ProductionDoctor runs the health checks against the production stack described by envFile. With jsonOut it prints the Report as JSON and exits 0 (the verdict is in the body, like `local doctor`); human output prints the table and returns an error when any check FAILED.
func SupportBundle ¶
SupportBundle gathers the diagnostics for the initialised stack and writes them to outPath as a redacted tar.gz. It never fails the whole bundle on one missing input: a compose command that errors (e.g. the stack is down) records its error text as that part's content, so an operator diagnosing a broken stack still gets the doctor report and the config.
func Upgrade ¶
func Upgrade(opts UpgradeOptions) error
Upgrade runs the §48.4 N->N+1 compose sequence: backup + restore-status -> compat verify -> expand + control-plane swap -> runner drain -> new-run engine-alias roll -> smoke. Expand is folded into the control-plane swap for the single-node compose profile (the swapped control-plane applies the idempotent, advisory-locked migration chain at boot, gated by the backup marker); the separate pre-swap migration Job is the Kubernetes path (T3). The active run stays on its PINNED engine because the engine alias is rolled ONLY AFTER the runner drains — a drained run has already completed on the engine digest that was current when it started.
func UpgradeRollback ¶
func UpgradeRollback(opts RollbackOptions) error
UpgradeRollback is the §48.5 APPLICATION rollback: it swaps the control-plane (and runner) image back to N and rolls the engine alias back to N's engine for NEW runs, while the SCHEMA stays expanded (a contract's dropped shape is not re-created — a real downgrade past a contract restores from the pre-upgrade backup, spec §48.5). The N binary boots on the expanded schema because a contract only drops shapes no in-rollback-window binary reads, so the schema head equals N's chain head. It DRAINS first: the runner recreate SIGTERMs the active run, and without a drain E10 recovery would reopen that attempt on the N control-plane's N engine — silently MIGRATING a run pinned to the N+1 engine. So an active run is drained (warn-on-timeout) before the recreate; a run still active past the window then completes on N's engine, and the operator is warned (never silent).
Types ¶
type BackupManifest ¶
type BackupManifest struct {
Kind string `json:"kind"`
Version int `json:"version"`
CreatedAt time.Time `json:"created_at"`
Project string `json:"project"` // source stack project — reference only
MigrationVersion int `json:"migration_version"` // max(schema_migrations.version)
ProjectIDs []string `json:"project_ids"` // tenant ids captured (RLS-bypassed superuser read)
SampleResponseID string `json:"sample_response_id,omitempty"` // one run id verify re-retrieves
DBDumpSHA256 string `json:"db_dump_sha256"`
ObjectStoreSHA256 string `json:"object_store_sha256"`
// Objects is the per-object sha256 of the object-store copy. The packaged control-plane sets
// no PALAI_S3_ENDPOINT, so no S3 objects are wired and these are the object-store DATA VOLUME's
// files (byte-for-byte). Each entry lets a restore prove the copy is intact file-by-file.
// ponytail: the volume is tar'd LIVE — crash-consistent-enough for today's empty/idle store, but
// once artifacts are actually written to S3 a consistent copy must quiesce the store or enumerate
// S3 objects (docs/operations/backup-restore.md ceiling), and those entries become the objects.
Objects []objectChecksum `json:"objects"`
}
BackupManifest is the machine-readable index inside a backup archive. It records what the backup captured (migration version, the tenant ids — which are the PROJECT ids since A.2 Task 6, a sample response id for the run-retrieval verify) and the integrity checksums (whole-member + per-object). It holds NO secret — restore/verify treat it as the source of truth for what a healthy restore must match.
type Config ¶
type Config struct {
Project string `json:"project"`
DataDir string `json:"data_dir"`
APIPort int `json:"api_port"`
RunnerPort int `json:"runner_port"`
PgPort int `json:"pg_port"`
S3Port int `json:"s3_port"`
BaseURL string `json:"base_url"`
ControllerDNS string `json:"controller_dns"`
// ‼️ THE STACK'S OWN SETTINGS, AND THEY LIVE HERE BECAUSE .env.local IS NOT A CONFIGURATION
// SURFACE. The owner's instruction, twice: "sakın env local kullanma ... öyle bir şey olmaması
// lazım palai için deamon ve cli için."
//
// A dotfile beside a checkout is invisible to every operator who did not create it, carries no
// schema, cannot be read back, and this tree has already paid for that three times — a `$` eaten by
// dotenv expansion, a value the child process never received, and a workspace root that disagreed
// with the daemon's for an hour. This file is written by `init`, read by every command, and printed
// by `doctor`, so a setting is a thing an operator can SEE.
//
// WHAT IS NOT HERE IS AS DELIBERATE AS WHAT IS. Credentials are not: they belong in the sealed
// store behind a model connection, which is the path the console already builds. And a device's own
// numbers — capacity, concurrency, pool — are not: those are the ADMIN PLANE's, delivered by desired
// configuration to every machine at once, which is the whole point of that surface. What is left is
// exactly the set that describes THIS stack on THIS disk, which no web form can know.
WorkspaceRoot string `json:"workspace_root,omitempty"`
EngineWallTime string `json:"engine_wall_time,omitempty"`
SandboxWallTime string `json:"sandbox_wall_time,omitempty"`
}
Config is the .palai/config.json contract the CLI writes at init and the e2e harness reads: the compose project identity, the data dir, the published host ports, and the surfaces derived from them. The field names are the JSON the harness decodes.
func (Config) Setting ¶
Setting resolves one stack setting: the saved configuration first, then the process environment.
THE ORDER IS THE POINT. The variable still works — a container deployment sets these in its own environment and always has — but it is now the FALLBACK rather than the record. A value an operator saved is the one that survives a reboot, a new shell, and a launchd job that inherits nothing.
type ReleaseManifest ¶
type ReleaseManifest struct {
Version string `json:"version"`
Stamp string `json:"stamp"`
Commit string `json:"commit"`
Images struct {
ControlPlane imageRef `json:"control_plane"`
Runner imageRef `json:"runner"`
Engine imageRef `json:"engine"`
} `json:"images"`
}
ReleaseManifest is the scripts/release/build.sh output the upgrade reads: the target version stamp and the OCI image digests the swap pins. The engine digest is the alias new runs pin AFTER the roll.
type RollbackOptions ¶
type RollbackOptions struct {
To string
}
RollbackOptions drives `palai upgrade rollback`: To is the N (previous) release manifest to return to.
type UpgradeOptions ¶
type UpgradeOptions struct {
Manifest string
From string
SkipBackup bool
DrainRun string // optional response id to wait terminal before the engine-alias roll
DrainWait time.Duration // cap on the drain wait (default 90s)
}
UpgradeOptions drives `palai upgrade`. Manifest is the target (N+1) release manifest; From is the currently-running version for the compat check (defaults to the VERSION file). SkipBackup skips the pre-upgrade backup (a drill convenience — never the operator default).