carlos / platform Public

release: adopt honors the production flag and fast_track — Hold's ignore finally has its caller

The bake window stops being unconditional. PassFilter resolves each app's
production flag once per pass, folds it into the box's production memory
BEFORE any bake verdict is taken, and passes the resulting app-level verdict
down to adoptHost as `ignore`. Hold's override parameter, which has taken
`false` at its only call site since it was written, now carries the flag's
answer OR'd with this pointer's own fast_track waiver.

Behavior change owned explicitly: with the flag defaulting to off, a
beta/stable head with no production flag installs immediately.
TestPassStableHeldByBakeWindow is updated (not deleted) to be the
production-on case — the property survives, it just needs the flag now.

The flag read is filtered to apps with a HELD (HoldFor>0) head resolved this
pass, so the 2-3 second canary fast loop never pays a production-flag bucket
read; the hourly pass pays exactly one per (account, app). Pinned by
TestCanaryFastLoopPaysNoProductionRead, which also asserts the full pass does
read it — once, for two channels and three routes.

Two orderings are load-bearing and both are now pinned by tests:
ObserveProduction runs before this pass's verdicts, so a wiped latch
re-latches from the bucket and is honored in the SAME pass; and the Save gate
gains bake.tainted, so a corrupt clock file — which fails every held head
toward baking — is rewritten within one pass instead of surviving forever.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VioXzogWf1Xi4Rswz2B6EK
Paul Campbell 71616e9fdb0c27304b7736cf8f201df11444b2b7 parent 97456be
2 files changed, +296 −5
  • internal/release/adopt.go +71 −5
  • internal/release/adopt_test.go +225 −0
diff --git a/internal/release/adopt.go b/internal/release/adopt.go
index c654bb1da..8a9e3a652 100644
--- a/internal/release/adopt.go
+++ b/internal/release/adopt.go
@@ -199,6 +199,33 @@ func PassFilter(ctx context.Context, reg *registry.Registry, s Store, pub ed2551
pointers[k] = ptr
}
+ // Resolve each app's production flag once per pass — but ONLY for apps
+ // with a HELD head resolved this pass (spec §6). That filter is a cost
+ // property, not a nicety: the canary fast loop (PassFilter with a
+ // canary/*-only extra, every 2-3 SECONDS) resolves nothing but channels
+ // whose HoldFor is 0, so it never pays a production-flag bucket read at
+ // all; the hourly pass pays exactly one read per (account, app) with a
+ // held head, not one per channel and not one per route.
+ type prodState struct {
+ flag *ProductionFlag
+ err error // non-nil: the object exists but would not read or verify
+ }
+ bakeable := map[acctApp]bool{}
+ for k, ptr := range pointers {
+ if ptr != nil && HoldFor(DefaultHolds, k.channel) > 0 {
+ bakeable[acctApp{k.acct, k.app}] = true
+ }
+ }
+ prod := map[acctApp]prodState{}
+ for ak := range bakeable {
+ // A missing flag is (nil, nil) — the default, not production. Any
+ // OTHER failure is kept as an error and fails toward baking in
+ // ProductionBake: an attacker who can corrupt but not sign must not
+ // be able to shorten a window by breaking the object.
+ f, err := GetProduction(ctx, s, pub, ak.acct, ak.app)
+ prod[ak] = prodState{flag: f, err: err}
+ }
+
// Tick the bake clock: record every channel head this box hasn't seen at
// that head before, so the supply-chain window is measured from the box's
// own first sighting, never a feed timestamp (bake.go). The clock only
@@ -213,12 +240,31 @@ func PassFilter(ctx context.Context, reg *registry.Registry, s Store, pub ed2551
// for days on a fleet that happens to see no new channel head, and the
// legacy file would look safe to delete long before it actually is (see
// LoadFirstSeenMigrating and BakeDir's doc comments, 2026-08-03 review).
- changed := bake.migrated
+ //
+ // bake.tainted forces it for a different reason: the clock file existed
+ // but did not read or parse, so every held head on this box is failing
+ // toward baking until that file is replaced (ProductionBake). Without
+ // this the corrupt file would survive every changed-gated pass and the
+ // box would bake forever; with it, one pass rewrites the file from this
+ // struct's valid in-memory content and the NEXT load starts clean.
+ changed := bake.migrated || bake.tainted
for k, ptr := range pointers {
if ptr != nil && bake.Observe(k.acct, k.app, k.channel, ptr.Version, now) {
changed = true
}
}
+ // ORDER IS LOAD-BEARING: fold this pass's verified flag reads into the
+ // box's production memory HERE, before any bake verdict below is taken.
+ // That is what makes prodMemory's "a mixed-version rollout costs at most
+ // one pass of this memory" true — a binary that wiped the latch re-latches
+ // it from the bucket and honors it in the SAME pass, never a pass later.
+ // Only err == nil reaches the memory: it must only ever tick for signed
+ // documents (a failed read is a verdict input, never an observation).
+ for ak, ps := range prod {
+ if ps.err == nil && bake.ObserveProduction(ak.acct, ak.app, ps.flag, now) {
+ changed = true
+ }
+ }
if changed {
if err := bake.Save(); err != nil {
return fmt.Errorf("record bake clock: %v", err)
@@ -229,6 +275,18 @@ func PassFilter(ctx context.Context, reg *registry.Registry, s Store, pub ed2551
// this pass — one bad build shouldn't bounce every host in turn.
poisoned := map[string]bool{}
+ // One definition of "does the window apply here", shared by the awake and
+ // hibernating loops below — the same question must not be able to be
+ // answered two ways for the same app depending on whether it sleeps.
+ //
+ // RouteAccount(rt), never the raw rt.Account column: the group and
+ // bakeable keys were built from RouteAccount output, and an unmigrated
+ // row can still carry an account NAME there, which resolves to ops.
+ bakeIgnore := func(rt registry.Route) bool {
+ ak := acctApp{RouteAccount(rt), rt.App}
+ return !bake.ProductionBake(ak.acct, ak.app, prod[ak].err, bakeable[ak], DefaultHolds, now)
+ }
+
// Awake hosts first, hibernating second: repoints have no health gate, so
// let an awake host discover (and poison) a broken build before any
// sleeper is moved onto it.
@@ -242,12 +300,12 @@ func PassFilter(ctx context.Context, reg *registry.Registry, s Store, pub ed2551
continue
}
ptr := pointers[groupKey{RouteAccount(rt), rt.App, routeChannel(rt)}]
- adoptHost(ctx, reg, s, optDir, bake, poisoned, rt, ptr, restart, now, cfg.nag)
+ adoptHost(ctx, reg, s, optDir, bake, poisoned, rt, ptr, restart, now, cfg.nag, bakeIgnore(rt))
}
for _, rt := range hibernating {
ptr := pointers[groupKey{RouteAccount(rt), rt.App, routeChannel(rt)}]
// restart=nil: hibernating hosts get the pure repoint — never woken.
- adoptHost(ctx, reg, s, optDir, bake, poisoned, rt, ptr, nil, now, cfg.nag)
+ adoptHost(ctx, reg, s, optDir, bake, poisoned, rt, ptr, nil, now, cfg.nag, bakeIgnore(rt))
}
return nil
}
@@ -300,7 +358,12 @@ func RouteAccount(rt registry.Route) string {
// nag is passConfig.nag from the call's PassOptions — nil (the ordinary
// case) means the canary-TTL nag below never fires, never even builds its
// string; see NagExpiredCanaries for who sets it and why.
-func adoptHost(ctx context.Context, reg *registry.Registry, s Store, optDir string, bake *FirstSeen, poisoned map[string]bool, rt registry.Route, ptr *ChannelPointer, restart func(host string) error, now time.Time, nag io.Writer) {
+//
+// ignore is the app-level bake verdict from ProductionBake — the production
+// flag's doing, never a publisher field. True means this app is not declared
+// production on this box, so the supply-chain window does not apply to it;
+// the caller computes it once per route from the flag it read this pass.
+func adoptHost(ctx context.Context, reg *registry.Registry, s Store, optDir string, bake *FirstSeen, poisoned map[string]bool, rt registry.Route, ptr *ChannelPointer, restart func(host string) error, now time.Time, nag io.Writer, ignore bool) {
if ptr == nil {
return
}
@@ -336,7 +399,10 @@ func adoptHost(ctx context.Context, reg *registry.Registry, s Store, optDir stri
if cur == ver {
return // up to date — stay quiet on the periodic tick
}
- if hold := Hold(bake, RouteAccount(rt), rt.App, channel, ver, DefaultHolds, false, now); hold != "" {
+ // Two independent waivers, both root-signed in origin: ignore is the
+ // app's production verdict (§2/§4), ptr.FastTrack is this ONE pointer's
+ // per-promotion waiver (§5). Either one alone releases the head.
+ if hold := Hold(bake, RouteAccount(rt), rt.App, channel, ver, DefaultHolds, ignore || ptr.FastTrack, now); hold != "" {
fmt.Printf(" %s: %s (%s) is %s\n", rt.Host, ver, channel, hold)
return
}
diff --git a/internal/release/adopt_test.go b/internal/release/adopt_test.go
index f7ffb98e1..a0bccc390 100644
--- a/internal/release/adopt_test.go
+++ b/internal/release/adopt_test.go
@@ -195,6 +195,11 @@ func TestPassStableHeldByBakeWindow(t *testing.T) {
if err := Promote(ctx, s, priv, "bab", "myapp", "stable", "v1"); err != nil {
t.Fatalf("Promote: %v", err)
}
+ // The app is DECLARED production (2026-08-04 spec §2): the window is no
+ // longer unconditional — it is what the flag buys.
+ if err := SetProduction(ctx, s, priv, "bab", "myapp", true, "test"); err != nil {
+ t.Fatalf("SetProduction: %v", err)
+ }
addRoute(t, reg, "h.example.com", "myapp", "", false) // "" = stable
if err := Pass(ctx, reg, s, pub, opt, func(string) error { return nil }); err != nil {
@@ -689,3 +694,223 @@ func withCapturedStdout(t *testing.T, buf *bytes.Buffer, fn func()) {
w.Close()
<-done
}
+
+// ---- the production flag on the adopt path (2026-08-04 spec §6) -------------
+
+// The default: no flag, no window (2026-08-04 spec §2). The whole fleet
+// runs on canary/* today, so nothing live loses protection — and a
+// rapid-iteration app's stable is just another channel.
+func TestPassNoProductionFlagInstallsImmediately(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ priv, pub := testKeys(t)
+ opt := t.TempDir()
+ reg := testRegistry(t)
+
+ shipRelease(t, s, "bab", "myapp", "v1", adoptPlatform, []byte("bin"))
+ if err := Promote(ctx, s, priv, "bab", "myapp", "stable", "v1"); err != nil {
+ t.Fatal(err)
+ }
+ addRoute(t, reg, "h.example.com", "myapp", "", false)
+
+ if err := Pass(ctx, reg, s, pub, opt, func(string) error { return nil }); err != nil {
+ t.Fatalf("Pass: %v", err)
+ }
+ if v, _ := LiveVersion(opt, "h.example.com"); v != "v1" {
+ t.Fatalf("live = %q, want v1 — no production flag means no window", v)
+ }
+}
+
+// Fast-track: a production app's held head installs the moment its pointer
+// carries the root-signed waiver (spec §5).
+func TestPassFastTrackSkipsTheWindow(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ priv, pub := testKeys(t)
+ opt := t.TempDir()
+ reg := testRegistry(t)
+
+ shipRelease(t, s, "bab", "myapp", "v1", adoptPlatform, []byte("bin"))
+ if err := Promote(ctx, s, priv, "bab", "myapp", "stable", "v1"); err != nil {
+ t.Fatal(err)
+ }
+ if err := SetProduction(ctx, s, priv, "bab", "myapp", true, "test"); err != nil {
+ t.Fatal(err)
+ }
+ addRoute(t, reg, "h.example.com", "myapp", "", false)
+
+ if err := Pass(ctx, reg, s, pub, opt, func(string) error { return nil }); err != nil {
+ t.Fatal(err)
+ }
+ if v, _ := LiveVersion(opt, "h.example.com"); v != "" {
+ t.Fatalf("live = %q, want held (production, no waiver yet)", v)
+ }
+ if _, err := FastTrack(ctx, s, priv, "bab", "myapp", "stable", "test"); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pass(ctx, reg, s, pub, opt, func(string) error { return nil }); err != nil {
+ t.Fatal(err)
+ }
+ if v, _ := LiveVersion(opt, "h.example.com"); v != "v1" {
+ t.Fatalf("live = %q, want v1 — the waiver did not skip the window", v)
+ }
+}
+
+// A production app whose flag OBJECT rots (exists, won't verify) keeps
+// baking — an attacker who can corrupt but not sign shortens nothing.
+func TestPassCorruptProductionFlagFailsTowardBaking(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ priv, pub := testKeys(t)
+ opt := t.TempDir()
+ reg := testRegistry(t)
+
+ shipRelease(t, s, "bab", "myapp", "v1", adoptPlatform, []byte("bin"))
+ if err := Promote(ctx, s, priv, "bab", "myapp", "stable", "v1"); err != nil {
+ t.Fatal(err)
+ }
+ if _, err := s.Put(ctx, ProductionKey("bab", "myapp"), []byte("not a wrapper"), ""); err != nil {
+ t.Fatal(err)
+ }
+ addRoute(t, reg, "h.example.com", "myapp", "", false)
+
+ if err := Pass(ctx, reg, s, pub, opt, func(string) error { return nil }); err != nil {
+ t.Fatalf("Pass: %v", err)
+ }
+ if v, _ := LiveVersion(opt, "h.example.com"); v != "" {
+ t.Fatalf("live = %q, want held — a corrupt flag must read as production", v)
+ }
+}
+
+// ORDERING, pinned: ObserveProduction runs BEFORE this pass's bake verdicts
+// are taken, so the bucket flag re-latches a wiped memory within ONE pass —
+// the whole basis of prodMemory's "a mixed-version rollout costs at most one
+// pass of this memory" comment. Simulates the old binary that re-marshals a
+// struct with no Production field and thereby deletes the latch.
+func TestPassReLatchesProductionMemoryInTheSamePass(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ priv, pub := testKeys(t)
+ opt := t.TempDir()
+ reg := testRegistry(t)
+
+ shipRelease(t, s, "bab", "myapp", "v1", adoptPlatform, []byte("bin"))
+ if err := Promote(ctx, s, priv, "bab", "myapp", "stable", "v1"); err != nil {
+ t.Fatal(err)
+ }
+ if err := SetProduction(ctx, s, priv, "bab", "myapp", true, "test"); err != nil {
+ t.Fatal(err)
+ }
+ addRoute(t, reg, "h.example.com", "myapp", "", false)
+
+ if err := Pass(ctx, reg, s, pub, opt, func(string) error { return nil }); err != nil {
+ t.Fatal(err)
+ }
+ st := LoadFirstSeen(FirstSeenPath(opt))
+ if len(st.Production) == 0 {
+ t.Fatalf("first pass did not latch the production memory")
+ }
+
+ // The old binary's write: every channel observation survives, the
+ // production memory (and with it the replay floor) is gone.
+ st.Production = map[string]*prodMemory{}
+ if err := st.Save(); err != nil {
+ t.Fatalf("Save wiped clock: %v", err)
+ }
+
+ if err := Pass(ctx, reg, s, pub, opt, func(string) error { return nil }); err != nil {
+ t.Fatal(err)
+ }
+ if v, _ := LiveVersion(opt, "h.example.com"); v != "" {
+ t.Fatalf("live = %q, want still held — the bucket flag must re-latch BEFORE this pass's bake verdict, not after it", v)
+ }
+ if st := LoadFirstSeen(FirstSeenPath(opt)); len(st.Production) == 0 {
+ t.Fatalf("the re-latch was not persisted")
+ }
+}
+
+// A clock file that exists but does not parse is rewritten within ONE pass,
+// even when the pass observes nothing new — the taint-forced Save. Without
+// it a corrupt file would sit there forever, and every held head on the box
+// would fail toward baking pass after pass (ProductionBake's st.tainted).
+func TestPassRewritesATaintedClockInOnePass(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ _, pub := testKeys(t)
+ opt := t.TempDir()
+ reg := testRegistry(t) // no routes: nothing new is observed this pass
+
+ if err := os.WriteFile(FirstSeenPath(opt), []byte("{not json"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if st := LoadFirstSeen(FirstSeenPath(opt)); !st.tainted {
+ t.Fatalf("setup: the corrupt clock did not read as tainted")
+ }
+
+ if err := Pass(ctx, reg, s, pub, opt, func(string) error { return nil }); err != nil {
+ t.Fatalf("Pass: %v", err)
+ }
+ if st := LoadFirstSeen(FirstSeenPath(opt)); st.tainted {
+ t.Fatalf("the pass left the clock file corrupt — a tainted clock must force its own Save")
+ }
+}
+
+// prodReadStore counts Get calls for one exact key.
+type prodReadStore struct {
+ Store
+ key string
+ n int
+}
+
+func (p *prodReadStore) Get(ctx context.Context, key string) ([]byte, string, error) {
+ if key == p.key {
+ p.n++
+ }
+ return p.Store.Get(ctx, key)
+}
+
+// The 2-3 SECOND canary fast loop must never pay a production-flag bucket
+// read: canary/* has no window (DefaultHolds), so no canary-only pass ever
+// has a HELD head to ask about. The hourly pass pays exactly one read per
+// (account, app) with a held head — not one per channel, not one per route.
+func TestCanaryFastLoopPaysNoProductionRead(t *testing.T) {
+ dir := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ priv, pub := testKeys(t)
+ opt := t.TempDir()
+ reg := testRegistry(t)
+
+ shipRelease(t, dir, "bab", "myapp", "v1", adoptPlatform, []byte("bin"))
+ for _, ch := range []string{"canary/x", "canary/y", "stable"} {
+ if err := Promote(ctx, dir, priv, "bab", "myapp", ch, "v1"); err != nil {
+ t.Fatalf("Promote %s: %v", ch, err)
+ }
+ }
+ if err := SetProduction(ctx, dir, priv, "bab", "myapp", true, "test"); err != nil {
+ t.Fatal(err)
+ }
+ addRoute(t, reg, "cx.example.com", "myapp", "canary/x", false)
+ addRoute(t, reg, "cy.example.com", "myapp", "canary/y", false)
+ addRoute(t, reg, "s.example.com", "myapp", "stable", false)
+
+ s := &prodReadStore{Store: dir, key: ProductionKey("bab", "myapp")}
+ if err := PassFilter(ctx, reg, s, pub, opt, func(string) error { return nil }, isCanaryTestRoute); err != nil {
+ t.Fatalf("PassFilter: %v", err)
+ }
+ if s.n != 0 {
+ t.Fatalf("canary-only pass read the production flag %d times, want 0 — the fast loop must not pay bucket reads for a window canary/* does not have", s.n)
+ }
+
+ // Not vacuous: the full pass, which does resolve a held head, reads it —
+ // once, for two channels and three routes.
+ if err := Pass(ctx, reg, dir, pub, opt, func(string) error { return nil }); err != nil {
+ t.Fatalf("Pass: %v", err)
+ }
+ s.n = 0
+ if err := Pass(ctx, reg, s, pub, opt, func(string) error { return nil }); err != nil {
+ t.Fatalf("Pass: %v", err)
+ }
+ if s.n != 1 {
+ t.Fatalf("full pass read the production flag %d times, want exactly 1 per (account, app)", s.n)
+ }
+}