carlos / platform Public
- P1 — Run §5.2: the hold does not protect against every stop path. Blocking hibernation and new move requests leaves restart, convergence, process failure and claim handoff uncovered.
Bouncestops an awake instance without consulting such a hold (activator.go:1425); completion closes replication and forgets the entry (activator.go:2355). The separate cmd unit could continue writing after that checkpoint. Fix: register cmd as part of the instance’s writer lifecycle. Every unavoidable stop must terminate and settle cmd before closing replication, releasing ownership or replacing the database. Serialize run and move admission through the same authority.
- P2 — Run §§5.2–5.3; seeded §3.3: claim-enabled isolated execution is an unfulfilled prerequisite. Legacy start/seed/stop routes return 503 when claim control is armed (server.go:840). The claim launch implementation explicitly refuses execution until the isolated root protocol supports reservations (rolelaunch_linux.go:23). Neither a plain
/cmdnor an ordinary claim wake supplies this missing integration. Fix: name and complete the guarded root-launch dependency, including cmd reservations and producer settlement, before claiming either feature works with claims enabled.
- P2 — Run §5.2: restart’s ETag pattern can drop queued work or replay commands. Restart deliberately ignores first sight and keeps its comparison state only for the agent’s lifetime (restart.go:114, restart.go:165). Copying that behavior misses runs already queued when a box boots or acquires ownership. Replaying them instead is unsafe because
picked.jsonhas no conditional acquisition or recovery semantics. Fix: scan outstanding runs at startup and ownership changes; conditionally acquire each run against its instance incarnation. Recover a picked run through its recorded invocation or mark it interrupted; never blindly execute it again.
- P2 — Run §§5.3–5.4: successful commands never reach the specified completion condition. The permitted template differences retain
Type=oneshotandRemainAfterExit=yes(seed unit:19). Success therefore remainsactive (exited), while §5.4 waits for inactivity. The current seed handler explicitly reads the retained result and then stops the unit (server.go:431). Fix: define asynchronous start and completion explicitly: observe completion of the matching oneshot invocation, capture its result, then stop and settle it. Alternatively, specify different lifecycle directives and an appropriate runtime limit.
- P2 — Run §§5.5, 5.7: acknowledgement can delete unread output. A bounded response includes the result whenever it exists (run spec:209); receiving that result triggers deletion (run spec:235). A completed command with several pages of output loses everything beyond the first returned page. Fix: publish the result only after final chunks are durable, require the CLI to consume through the declared final sequence, and require that sequence on acknowledgement.
- P2 — Run §§5.2, 5.7: the upload directory is outside the instance’s mounted tree for long hostnames. The spec uses
/data/instances/<host>/; actual nested directories useInstanceID(host), which hashes names longer than 40 bytes (provision.go:2032). Fix: derive download,CARLOS_RUN_DIRand cleanup paths throughprovision.InstanceDiror the backend’s resolved instance paths.
- P3 — Run §4:
seedVarsdoes not supply the promised region. It strips the control variables and sets onlyCARLOS_HOST(backend_exec.go:1359). Authoritative region assignment occurs in the serving-process composer (backend_exec.go:1340). Fix: specify a cmd environment composer that sets or removesCARLOS_REGIONfrom the backend’s region before adding the run variables.
- P1 — Seeded §3.3: the shared warm-file shortcut contradicts claim restore. Consider a crash after installing the seed locally but before its first upload. Step 1 says the warm file suppresses seed installation. Claim recovery, however, never trusts that file: its empty-baseline path purges local state and writes only a generation marker (claimwakeassembly.go:252, restore.go:142). Applying the stated shared algorithm therefore removes the only installed copy without reinstalling the seed. Fix: separate the two restore algorithms. In claim mode, select the remote baseline first; if initial-seed authority remains and no baseline exists, purge and reinstall the seed under the admitted generation regardless of a local file. Preserve generation publication before retiring seed recovery state.
- P1 — Seeded §§5.4, 6.4: app-name equality does not establish the destination account for an operator-filed row. App identity is account-scoped (qualified.go:4). An operator row named
foodoes not distinguish the intendedbae/foofrom another account’sfoo. The proposed exception removes the account comparison without replacing that missing ownership evidence. Fix: retain the operator-account exception, but bind each permitted transfer to an operator-authored authorization naming the exact host, old address, destination account and app. Check that authorization during the swap.
- P2 — Seeded §5.4:
Kind == "addr"does not describe an existing route class. Registry kinds areinstance,service,staticandsidecar; TCP backing is represented separately byAddr/Addrs, andSockettakes precedence (registry.go:31). The literal predicate refuses the intended imports. Fix: define the accepted legacy route shape using the actual kind and backing fields, including empty socket, tunnel and incompatible ownership fields.
- P2 — Seeded §§5.1, 5.4: ordinary creation and reconcile cannot perform the described first claim acquisition. Console creation acquires the claim before record effects (claim_create.go:99). Reconcile then rejects an existing unclaimed row before calling its claim-install hook, and requires an existing owner to equal the installed owner (claimassembly.go:20). Fix: specify an import-specific acquisition and replacement transaction, with durable recovery between claim CAS and registry commit. Define how begin remains pending, how the exact legacy row is checked, and how a failed or interrupted swap settles its acquired claim.
- P2 — Seeded §§5.4, 6.3: the existing-row branch derives a flat replacement. Reconcile chooses
nestedfrom the existing row’s paths; it reads the box’s mint layout only when no row exists (reconcile.go:1103). An addr row consequently produces flat exec paths, which the seed’s nested-only wake must refuse. Fix: the import branch must validate current nested layout and explicitly derive the replacement’s nested paths, independently of the addr row.
- P2 — Seeded §§3.2, 5.5: the state filter makes rollback unreachable. Section 3.2 skips every state except
readyandplaced; §5.5 first changes the state toaborted, then relies on reconcile to restore the old row. Reconcile’s per-record dispatch is where this ordering must be implemented (reconcile.go:1072). Fix: dispatchabortedto an idempotent rollback path before applying the ordinary seed-admission filter.
- P2 — Seeded §5.5:
Replacescannot restore the original route exactly. The original route includes account, kind, channel, environment, gate, unit, capabilities and other fields beyond its address (registry.go:36). The proposed seed record retains none of that original state. Fix: durably journal the complete original row before replacement, compare it inside the swap transaction, and restore that exact snapshot on abort. Include ownership and associated state that the transaction changes.
- P1 — Seeded §§5.5–5.6: the abort safety condition is neither authenticated nor durably observable. Usage accounting aggregates request counts and bytes by host (usagemeter.go:36); analytics records paths and methods, but no authenticated import-verification identity (meter.go:19). An app-defined verify path cannot establish that no ordinary request has served. Fix: introduce verification authority bound to the import incarnation and a durable “ordinary traffic admitted” latch. Serialize abort against that latch before forwarding ordinary requests, so an accepted write cannot race replica deletion.
- P1 — Seeded §§3.2, 10: observing upgraded boxes does not prevent a later downgrade from consuming seed records. The current protocol is version 1 (floor.go:15). The selector’s rollback checks apply only when a floor exists (boxselect.go:92); recovery can execute
carlos.prevwhen no local floor is armed (recovery unit:29). Fix: allocate a seed-capable protocol/release floor, publish it, and require evidence that affected boxes have armed it and excluded incompatible rollback binaries before writing any seed state, includingawaiting-upload.
- P1 — Seeded §§2, 4: calling
dbGaterejects the required service credentials. Its handler explicitly requiresPrincipalUser(apidb.go:110); the DB routes independently reject all service roles (authcli.go:690). Fix: authorize the seed door through the instance-role gate, then reuse a factored source resolver containing the record, account/app, residency and versioned-claim checks. Keep the existing DB download door’s authorization unchanged.
- P2 — Seeded §4:
RestoreTocannot honor--at. Its API accepts no transaction or time target, and its restore options set only the output path (restore.go:64, restore.go:132). Fix: specify a target-aware restore API and historical planning under the pinned source view, including unavailable-history errors and the actual restored TXID.
- P2 — Seeded §§4, 5.2: the resource limits do not bound restore scratch or explain upload validation.
RestoreTodownloads complete planned LTX files before restoration finishes (restore.go:186). Checking the output against 4 GiB afterward cannot prevent disk exhaustion. Import’sCheckDBalso requires a local database file and scans its pages (check.go:42), despite the upload being described solely as streaming to the bucket. Fix: define bounded scratch for both doors, accounting for LTX files and restored output together, with disk admission, deadlines, cancellable checks and cleanup on failure, disconnect and restart.
- P2 — Seeded §5.2: multipart upload and failure cleanup require additional storage support and permissions. The existing streaming interface requires a seekable body (store.go:248); its S3 implementation makes one
PutObjectcall (store.go:799). The bucket policy grants object get/put/delete, without multipart-abort authority (main.tf:163). Fix: specify multipart initiation, part upload, completion and abort, with scoped abort permission and recovery of abandoned upload IDs. Deleting an object is not cleanup of an unfinished multipart upload.
carlos run: revise.
Seeded instances: revise.