carlos / platform Public

self-serve timings: a copy whose seal was not read has unknown bytes, no sample (final review F16)

sealed_at is marked only when the seal was read at the sealed observation,
with its final copied bytes; a seal absent or rejected there leaves the
bytes unknown (logged), so the finished move gives no copy timing and its
duration never enters the copy's fixed-part samples as a zero-byte copy.

Witness: TestUnknownSealBytesAreNoCopySample (e2e; faultStore.hidden hides
the seal for the sealing phase, then the move finishes).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev f1e096353a6e39be59fc7b96cc61e7f6953b47a1 parent 748dec8
4 files changed, +56 −5
  • internal/console/selfserve_estimate.go +3 −1
  • internal/console/selfserve_job.go +7 −3
  • internal/e2e/selfserve/job_world_test.go +8 −1
  • internal/e2e/selfserve/seal_bytes_test.go +38 −0
diff --git a/internal/console/selfserve_estimate.go b/internal/console/selfserve_estimate.go
index 5403cabc9..53dfd8a7e 100644
--- a/internal/console/selfserve_estimate.go
+++ b/internal/console/selfserve_estimate.go
@@ -322,7 +322,9 @@ ORDER BY at DESC, id DESC LIMIT ?`, q...)
// landing and the replica always carry some); its seconds are a whole
// transfer and would otherwise fall under the rate floor and pass for the
// land or promote term's fixed part. A final copy that carried nothing is
-// a true fixed-part sample, so copy needs none.
+// a true fixed-part sample, so copy needs none: sealed_at is marked only
+// with the seal's byte count read, so a copy whose bytes are unknown has
+// no end mark and gives no row (final review F16).
var selfServeTimingPhases = []struct {
phase, from, to, bytes string
needBytes bool
diff --git a/internal/console/selfserve_job.go b/internal/console/selfserve_job.go
index 48b90322b..8d93663ff 100644
--- a/internal/console/selfserve_job.go
+++ b/internal/console/selfserve_job.go
@@ -1875,11 +1875,15 @@ func (s *Server) selfServeSealing(ctx context.Context, t *leaseToken, row *SelfS
}
switch mv.State {
case provision.OfflineSealed:
- var copied int64
+ // sealed_at carries the final copy's bytes, read from the seal at
+ // this observation. A seal absent or rejected here leaves them
+ // unknown, which is not a zero-byte copy: no mark, so the move
+ // gives no copy timing (final review F16).
if ev.seal != nil {
- copied = ev.seal.FinalCopiedBytes
+ s.selfServeMark(row, "sealed_at", now, ev.seal.FinalCopiedBytes)
+ } else {
+ log.Printf("console: self-serve move %s (%s): sealed, the seal not read: the copy's bytes are unknown (no copy timing)", row.ID, row.Host)
}
- s.selfServeMark(row, "sealed_at", now, copied)
TestHooks.point("advance:sealing->landing")
_, err := s.store.AdvanceSelfServe(row.ID, ssSealing, ssLanding, "", selfServePhaseDeadline(row, ssLanding, now), time.Time{}, "", now)
return err
diff --git a/internal/e2e/selfserve/job_world_test.go b/internal/e2e/selfserve/job_world_test.go
index 91a9c798b..cd8374bbf 100644
--- a/internal/e2e/selfserve/job_world_test.go
+++ b/internal/e2e/selfserve/job_world_test.go
@@ -8,6 +8,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "os"
"path/filepath"
"strings"
"sync"
@@ -54,6 +55,9 @@ type faultStore struct {
seen func(ctx context.Context, key string)
// serialFailing fails every serial bump while set.
serialFailing bool
+ // hidden, when set, answers a console read of any key it holds as
+ // absent (an object the console cannot see for a while).
+ hidden map[string]bool
}
type putFault int
@@ -121,11 +125,14 @@ func (f *faultStore) Put(ctx context.Context, key string, body []byte, ifMatch s
// be read), and forwards every other read.
func (f *faultStore) Get(ctx context.Context, key string) ([]byte, string, error) {
f.mu.Lock()
- unreadable := f.unreadable
+ unreadable, hidden := f.unreadable, f.hidden[key]
f.mu.Unlock()
if unreadable && provision.IsRecordKey(key) {
return nil, "", errUnreadable
}
+ if hidden {
+ return nil, "", os.ErrNotExist
+ }
return f.Store.Get(ctx, key)
}
diff --git a/internal/e2e/selfserve/seal_bytes_test.go b/internal/e2e/selfserve/seal_bytes_test.go
new file mode 100644
index 000000000..2b7b11e64
--- /dev/null
+++ b/internal/e2e/selfserve/seal_bytes_test.go
@@ -0,0 +1,38 @@
+//go:build e2e
+
+package selfserve
+
+import (
+ "testing"
+
+ "github.com/carlosframework/platform/internal/console"
+ "github.com/carlosframework/platform/internal/host"
+ "github.com/carlosframework/platform/internal/moves"
+)
+
+// TestUnknownSealBytesAreNoCopySample (final review F16): the copy's bytes
+// are the seal's, read at the sealed observation. A seal the console
+// cannot see at that observation (absent for it, then restored) leaves the
+// copy's bytes unknown, never a true zero: the finished move gives no copy
+// timing, so its duration never enters the copy's fixed-part samples.
+func TestUnknownSealBytesAreNoCopySample(t *testing.T) {
+ w := newJobWorld(t)
+ r := w.cutTo("sealing")
+ seal := moves.OfflineSealKey(host.E2EHost, r.ID)
+ w.fs.mu.Lock()
+ w.fs.hidden = map[string]bool{seal: true}
+ w.fs.mu.Unlock()
+ w.run(60, "past the seal", r.ID, func(r2 *console.SelfServeMove) bool { return r2.Phase != "sealing" || r2.Outcome != "" })
+ w.fs.mu.Lock()
+ w.fs.hidden = nil
+ w.fs.mu.Unlock()
+ if d := w.done(r.ID); d.Outcome != "done" {
+ t.Fatalf("finished %s", describe(d))
+ }
+ if got, _ := w.cst.MoveTimings("", host.E2ETargetRegion, "copy", 20); len(got) != 0 {
+ t.Fatalf("a copy whose bytes were never read became a timing sample: %+v", got)
+ }
+ if got, _ := w.cst.MoveTimings("", host.E2ETargetRegion, "stop", 20); len(got) != 1 {
+ t.Fatalf("the move's other timings: stop %+v", got)
+ }
+}