The gap
A drive environment has exactly one storage-measurement writer: the provision-time baseline wired at envStorageMeasureSeam (packages/lib/src/services/drive-envs/env-storage-measure.ts), fired by ensureSpriteHolderSandbox on the create arm only.
That single write is not retried. If it fails — an exec throw, a du timeout, unparseable output, or a recordStorageMeasurement rejection — drive_envs.storageMeasuredBytes stays NULL, and nothing ever writes it again.
The storage reconcile then does exactly what it is designed to do, which makes the loss permanent rather than deferred: it bills the never-measured 0 floor and advances the watermark anyway (sandbox-storage-reconcile.ts, the costDollars <= 0 branch). Advancing unconditionally is deliberate and correct — freezing the watermark would let a later measurement retroactively over-bill the entire frozen span — but it means each skipped window is discarded for good. Once the warm path lands, there is no backfill: the env simply starts billing correctly from that point on, and everything before it was free.
Same shape, worse consequence, for a rebuild: revivedDriveEnvColumns re-stamps storageLastBilledAt but leaves storageMeasuredBytes at the previous generation's value. The baseline measurement on the fresh (empty) disk is what corrects it; if that write fails, the env keeps billing the dead generation's footprint — an over-bill, on a real payer, indefinitely.
Sessions have the same single-write hole in principle, but three writers in practice (provision, the bash path's post-op measureStorage, the git path's), so a dropped measurement self-corrects on the next real work. An env has none of those until env-bound sessions exist.
Why it wasn't fixed in #2440
The natural retry point is a re-measure on the resume arm of ensureSpriteHolderSandbox — but that is the holder-neutral provisioning core shared with sessions, so changing it there would alter session provisioning behaviour inside a PR whose whole premise is that folding envs in changes nothing about the existing meter. #2441 (pu/env-sessions) owns the env ensure path and is the natural home.
What #2440 did instead
Made the failure observable rather than silent:
- every failure path in the seam now logs with the env's id;
- the reconcile counts
neverMeasured — live rows with no reading at all;
measurementHealth splits that per persistence unit, so an env-side hole is visible separately from a session-side one.
A metric is not a fix, which is why this issue exists.
Options
- Re-measure on resume when the row has no reading. Cheapest and self-healing: fire the seam on the
resume arm when storageMeasuredBytes IS NULL, so the next person to open the env repairs it. Needs a decision about whether sessions get the same treatment.
- Warm refresh from env sessions (the planned path). Fixes the steady state and incidentally repairs a failed baseline on first real work. Does not help an env nobody opens.
- A backfill sweep for rows that have been
neverMeasured across N ticks. Most thorough, most machinery, and it must still never wake a paused Sprite — so it can only measure envs that happen to be awake.
Option 1 plus 2 probably covers it. Option 3 only if neverMeasured proves non-transient in practice.
Acceptance
- A provision-time measurement failure is repaired without human intervention.
- A rebuilt env cannot keep billing the previous generation's footprint.
neverMeasured returns to ~0 in steady state, so it stays usable as a signal.
The gap
A drive environment has exactly one storage-measurement writer: the provision-time baseline wired at
envStorageMeasureSeam(packages/lib/src/services/drive-envs/env-storage-measure.ts), fired byensureSpriteHolderSandboxon thecreatearm only.That single write is not retried. If it fails — an exec throw, a
dutimeout, unparseable output, or arecordStorageMeasurementrejection —drive_envs.storageMeasuredBytesstays NULL, and nothing ever writes it again.The storage reconcile then does exactly what it is designed to do, which makes the loss permanent rather than deferred: it bills the never-measured 0 floor and advances the watermark anyway (
sandbox-storage-reconcile.ts, thecostDollars <= 0branch). Advancing unconditionally is deliberate and correct — freezing the watermark would let a later measurement retroactively over-bill the entire frozen span — but it means each skipped window is discarded for good. Once the warm path lands, there is no backfill: the env simply starts billing correctly from that point on, and everything before it was free.Same shape, worse consequence, for a rebuild:
revivedDriveEnvColumnsre-stampsstorageLastBilledAtbut leavesstorageMeasuredBytesat the previous generation's value. The baseline measurement on the fresh (empty) disk is what corrects it; if that write fails, the env keeps billing the dead generation's footprint — an over-bill, on a real payer, indefinitely.Sessions have the same single-write hole in principle, but three writers in practice (provision, the bash path's post-op
measureStorage, the git path's), so a dropped measurement self-corrects on the next real work. An env has none of those until env-bound sessions exist.Why it wasn't fixed in #2440
The natural retry point is a re-measure on the resume arm of
ensureSpriteHolderSandbox— but that is the holder-neutral provisioning core shared with sessions, so changing it there would alter session provisioning behaviour inside a PR whose whole premise is that folding envs in changes nothing about the existing meter. #2441 (pu/env-sessions) owns the env ensure path and is the natural home.What #2440 did instead
Made the failure observable rather than silent:
neverMeasured— live rows with no reading at all;measurementHealthsplits that per persistence unit, so an env-side hole is visible separately from a session-side one.A metric is not a fix, which is why this issue exists.
Options
resumearm whenstorageMeasuredBytes IS NULL, so the next person to open the env repairs it. Needs a decision about whether sessions get the same treatment.neverMeasuredacross N ticks. Most thorough, most machinery, and it must still never wake a paused Sprite — so it can only measure envs that happen to be awake.Option 1 plus 2 probably covers it. Option 3 only if
neverMeasuredproves non-transient in practice.Acceptance
neverMeasuredreturns to ~0 in steady state, so it stays usable as a signal.