From 18593a04afec3ef36a5bb9991796d93b4408670e Mon Sep 17 00:00:00 2001 From: CMGS Date: Mon, 2 Nov 2026 12:56:06 +0800 Subject: [PATCH 1/7] usage: state the deadline, the net lane and the end of a dropped claim A consumer could not bound an interval a crash left open: the folding rule clamps to the claim's deadline, but no event carried it, renew recorded nothing, and reconcile ended claims silently. Events that move the deadline now state it, renew records an event, and reconcile records a reap with the reason for a claim it drops or quarantines. Claim events also carry the net lane, so all three pool key axes read without the hash. --- docs/deploy.md | 2 + docs/sandboxd-api.md | 31 +++++---- sandboxd/pool/archive.go | 7 ++- sandboxd/pool/claim.go | 21 +++++-- sandboxd/pool/egress_test.go | 3 + sandboxd/pool/hibernate.go | 2 +- sandboxd/pool/reconcile.go | 23 ++++++- sandboxd/pool/telemetry.go | 1 + sandboxd/pool/telemetry_test.go | 108 +++++++++++++++++++++++++++++++- sandboxd/server/usage_test.go | 4 +- sandboxd/usage/pg/pg.go | 14 +++-- sandboxd/usage/pg/pg_test.go | 6 +- sandboxd/usage/pg/schema.sql | 2 + sandboxd/usage/usage.go | 2 + 14 files changed, 192 insertions(+), 34 deletions(-) diff --git a/docs/deploy.md b/docs/deploy.md index c6c44af5a..ae585a846 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -841,8 +841,10 @@ only; computing durations or prices stays with the consumer. vm text NOT NULL DEFAULT '', key text NOT NULL DEFAULT '', template text NOT NULL DEFAULT '', + net text NOT NULL DEFAULT '', size text NOT NULL DEFAULT '', tenant text NOT NULL DEFAULT '', + deadline timestamptz, volumes text[], volumes_rw text[], children text[], diff --git a/docs/sandboxd-api.md b/docs/sandboxd-api.md index 63f1795d3..15e531e46 100644 --- a/docs/sandboxd-api.md +++ b/docs/sandboxd-api.md @@ -1013,13 +1013,17 @@ truth is the usage journal below. Always on: every lifecycle transition appends one JSONL event to `/usage.jsonl` — `{"t": , "ev": -"claim|hibernate|wake|fork|checkpoint|promote|release|reap|archive|unarchive|archive_delete|egress|egress_bytes|vmm_exit|vmm_restart|vmm_failed", +"claim|renew|hibernate|wake|fork|checkpoint|promote|release|reap|archive|unarchive|archive_delete|egress|egress_bytes|vmm_exit|vmm_restart|vmm_failed", "id": "sb_…", "vm": "sbx-…"}` plus `key` (the pool key's stable hash, claim -events), `template` and `size` (the claim's template and size tier, claim -events, so a consumer can price a sandbox by its shape without the claim -record, which is gone after release), `tenant` (the owning tenant, on every -event of a tenant's claim), `children` (fork) and `ref` (the promoted -template / checkpoint id, the egress host, or a `vmm_failed` reason). An egress event that injected credentials names +events), `template`, `net` and `size` (the claim's template, lane and size +tier, claim events, so a consumer can price a sandbox by its shape without the +claim record, which is gone after release; `size` sets the CPU and memory, +while `template` is only a label, because a promoted template's name is the +caller's choice), `deadline` (the deadline in force after this event: `claim`, +`renew`, `wake` and `unarchive` carry the lease, `archive` the retention end, or +nothing for an archive kept forever), `tenant` (the owning tenant, on every event of a +tenant's claim), `children` (fork) and `ref` (the promoted template / checkpoint +id, the egress host, a `vmm_failed` reason, or why reconcile ended a claim). An egress event that injected credentials names them in `secret` (`gh,claim:`, never a value). An egress event routed through an [upstream proxy](egress.md#upstream-proxies) carries `upstream` (its `host:port`), and with `egress_usage_bytes` on, `egress_bytes` events add the connection's payload `tx`/`rx` bytes. A volume claim also carries @@ -1035,9 +1039,11 @@ before sandboxd runs again (a host that was down) stays billed up to that point, and `vmm_failed` is informational; hibernated storage seconds = Σ(hibernate→wake) minus the archived span; archived storage seconds = Σ(archive→unarchive/archive_delete), a cheaper store tier than a hibernated -VM's RAM. An interval left open by a crash clamps to the claim's -deadline; reconcile records nothing for the claims it drops (those whose VM -record is gone), so a restart leaves those intervals without a terminal event. The `vm` name joins +VM's RAM. An interval left open by a crash, or by a node that never returns, +clamps to the last `deadline` among the claim's events. Reconcile ends a claim +it drops with a `reap`: `ref` is `vm_gone` when the VM record is gone and +`quarantined` when it cannot re-lock the egress NIC. Its `t` is the node's +return, so clamp it the same way. The `vm` name joins cocoon's machine-level metering ledger for audit cross-checks. With `meta_store.usage`, the node also lands every line in the cell's [shared usage table](deploy.md#shared-usage-table), read through @@ -1049,12 +1055,13 @@ Auth: root only (tenant tokens get 403). Reads the raw usage events of every node of the cell from the [shared usage table](deploy.md#shared-usage-table). - `GET /v1/usage?tenant=&since=