carlos / platform Public

provision: Reconcile and ReconcileSidecars stay whole units (scan and retire closures); census overlays re-pinned for the review fixes (#336)

The record walk and the removal phase become closures inside each pass
instead of new functions, so the census keeps its legacy-accepted units and
only their digests and basis move. Same behaviour and tests as c1d29378.

Census (all PROPOSED on #280 with the rest of this branch's overlay):
plan14 s3-change-index overlay re-pins Reconcile, ReconcileSidecars,
fastTick, fastDeps.canaryPointerGate, fastDeps.canarySettled and
telemetrySwitchesWith with updated basis; drops confirmRecordGone and
confirmSidecarGone (deleted); adds movesDirHolds (root-input, as
sweepFinalJournals) and telemetrySwitchesResolve (main's telemetrySwitches
body, J1 root-route); rewords the telemetrySwitches H3 removal; moves the
edge, host, provision and release envelopes and the seal. B8 record-write
overlay re-pins Reconcile and ReconcileSidecars (class and kinds unchanged).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 25eac78c3daa82e4f23d7feaf2a3d7d212d89f3b parent 5e0af51
5 files changed, +342 −357
  • internal/provision/plan14_root_reads_test.go +1 −1
  • internal/provision/reconcile.go +135 −143
  • internal/provision/s3_change_index_census_test.go +10 −7
  • internal/provision/sidecar_reconcile.go +174 −184
  • internal/provision/testdata/plan14-root-reads-s3-change-index.tsv +22 −22

CI cancelled — superseded by a newer push — run details

CI log
=== gate ===
.amadan/test-gate.sh

amadan: job cancelled — a newer push superseded it
diff --git a/internal/provision/plan14_root_reads_test.go b/internal/provision/plan14_root_reads_test.go
index bd1912ba9..f29eea653 100644
--- a/internal/provision/plan14_root_reads_test.go
+++ b/internal/provision/plan14_root_reads_test.go
@@ -1343,7 +1343,7 @@ func TestPlan14RootReadCensus(t *testing.T) {
if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-s3-change-index.tsv"), &inv, true); err != nil {
t.Fatal(err)
}
- seal = "7d4b63ec0135ff227f49251b6c35a88d59026073518d89a3c81be255eacdc14f"
+ seal = "1eccb15a9cc0a215c4c3addb818b6310f9dd76fc6f8aba38038254b6037dfee6"
errs := append(compareRootReads(got, inv), checkRootReadLegacy(inv, seal)...)
errs = append(errs, checkRootReadDeclarations(got, inv)...)
if len(errs) > 0 {
diff --git a/internal/provision/reconcile.go b/internal/provision/reconcile.go
index cd21e7e54..31945adc1 100644
--- a/internal/provision/reconcile.go
+++ b/internal/provision/reconcile.go
@@ -819,155 +819,147 @@ func Reconcile(ctx context.Context, s release.Store, reg *registry.Registry, cfg
if cfg.Now == nil {
cfg.Now = time.Now
}
- sc, err := scanRecords(ctx, s, cfg)
- if err != nil {
- return err
- }
- return reconcileScanned(ctx, s, reg, cfg, sc)
-}
-// recordScan is the record-collection phase of a Reconcile pass: the
-// in-scope records by host, the hosts whose record is there but cannot be
-// used (protect), and whether anything failed to read (readFailed, which
-// disables removal for the whole pass).
-type recordScan struct {
- recs map[string]Record
- protect map[string]bool
- readFailed bool
-}
-
-// scanRecords is Reconcile's record walk over s. A pass over a record view
-// snapshot that has a removal to decide runs it again over the bucket
-// (freshStore), so both judge every record by exactly these rules (S3
-// change-index design §4.4).
-func scanRecords(ctx context.Context, s release.Store, cfg ReconcileConfig) (recordScan, error) {
- known, readFailed, err := knownAccounts(ctx, s)
- if err != nil {
- return recordScan{}, err
- }
+ // scan is the record-collection phase over st: the in-scope records by
+ // host, the hosts whose record is there but cannot be used (protect),
+ // and whether anything failed to read (readFailed, which disables
+ // removal for the whole pass). The pass scans s; a pass over a record
+ // view snapshot that has a removal to decide scans the bucket too
+ // (freshStore), so both judge every record by exactly these rules (S3
+ // change-index design §4.4).
+ type recordScan struct {
+ recs map[string]Record
+ protect map[string]bool
+ readFailed bool
+ }
+ scan := func(st release.Store) (recordScan, error) {
+ known, readFailed, err := knownAccounts(ctx, st)
+ if err != nil {
+ return recordScan{}, err
+ }
- // --- collect in-scope records --------------------------------------------
- keys, partial, err := listAppSubtree(ctx, s, known, "instances/")
- if err != nil {
- return recordScan{}, fmt.Errorf("provision: list apps: %w", err)
- }
- if partial {
- readFailed = true // unseen records must not read as retired
- }
- recs := map[string]Record{} // host -> record, in-scope only
- // protect holds hosts whose record KEY parsed (ParseRecordKey succeeded)
- // but whose body could not be trusted — unparseable JSON, or a body that
- // disagrees with its own path. Such a host must NEVER be treated as "the
- // bucket retired it": a non-additive Record encoding change reaching an
- // older binary would make EVERY existing record fail exactly this way,
- // and without this guard one tick would delete every provisioned route
- // in scope. This is narrower than readFailed (which vetoes removal for
- // the WHOLE pass): only the specific host with the unusable body is held
- // back — every other record still converges/removes normally the same
- // pass.
- protect := map[string]bool{}
- var recordKeys []string
- for _, key := range keys {
- if _, _, _, ok := ParseRecordKey(key, known); ok {
- recordKeys = append(recordKeys, key)
+ // --- collect in-scope records --------------------------------------------
+ keys, partial, err := listAppSubtree(ctx, st, known, "instances/")
+ if err != nil {
+ return recordScan{}, fmt.Errorf("provision: list apps: %w", err)
}
- }
- for _, part := range chunks(recordKeys) {
- bodies := getEach(ctx, s, part)
- for _, key := range part {
- acct, app, host, _ := ParseRecordKey(key, known)
- raw, err := bodies[key].body, bodies[key].err
- if err != nil {
- log.Printf("provision: skipping record %s: read failed: %v", key, err)
- // The record's absence from recs below must not read as "the
- // bucket retired it" — a transient Get failure disables removal
- // for the whole pass, same as an unreadable account manifest.
- readFailed = true
- continue
- }
- rec, err := DecodeRecord(raw)
- if err != nil {
- log.Printf("provision: skipping record %s: malformed: %v", key, err)
- protect[host] = true
- continue
- }
- if rec.Host != host || rec.Account != acct || rec.App != app {
- log.Printf("provision: skipping record %s: disagrees with its own path (host=%q account=%q app=%q)",
- key, rec.Host, rec.Account, rec.App)
- protect[host] = true
- continue
- }
- // The record IS the authorization, and this pass turns its host into
- // a socket path and a database path (DefaultSocket/DefaultDBPath)
- // and a registry primary key. The console's create door enforces
- // this same shape — but a door is not a guarantee about what is
- // already in the bucket: anything with bucket write access, and any
- // record written by a different (older, or future) writer, arrives
- // here unexamined. Both doors hold the invariant, neither trusts
- // the other. Protected like a corrupted body, and for the same
- // reason: a record that cannot be used is not a record that was
- // retired.
- if !ValidHostShape(rec.Host) {
- log.Printf("provision: skipping record %s: host %q is not a hostname", key, rec.Host)
- protect[host] = true
- continue
- }
- // ValidateShape is the console create door's policy check — but a
- // door is not a guarantee about what is already in the bucket (the
- // same reasoning as the host-shape check just above). This pass
- // materializes whatever it finds, so a record whose Kind/Addr/Unit/
- // Environment combination is malformed must be caught here too, or
- // a bad value becomes a live route. Protected like a corrupted
- // body: the record is there, it just cannot be used.
- if err := ValidateShape(rec); err != nil {
- log.Printf("provision: skipping record %s: invalid shape: %v", key, err)
- protect[host] = true
- continue
- }
- // ValidateShape deliberately does not inspect Channel (it validates
- // shape fields, and Channel is not one), but a channel-less record
- // must not become — or converge — a route pinned to no channel:
- // that is issue #130's failure mode arriving through a different
- // door than the one Task 3 closed. Protected like a corrupted body:
- // the record is there, it just cannot be used.
- if rec.Channel == "" {
- log.Printf("provision: skipping record %s: empty channel", key)
- protect[host] = true
- continue
- }
- // Scope. For a home-boxed record this is the region/pool test it
- // always was; for a static or public-addr one the region half widens
- // to every platform box in the deployment (everywhereClass, above).
- // A replica record narrows it: it belongs ONLY to the box whose
- // placement is the record's own Region — the placement the create
- // door validated as armed — so a replica record minted on the wrong
- // region would mint a route with no mirror behind it and no lease
- // speaking to it, a process holding live order data nobody
- // authorized into that region (the residence rule, #162). Every
- // other box skips it exactly like any other out-of-scope record;
- // the replica's own box sees Region == cfg.Region through the
- // ordinary test above.
- if !cfg.inScope(rec.Region, rec.Pool, everywhereClass(rec)) {
- continue // another agent's jurisdiction, not this pass's business
+ if partial {
+ readFailed = true // unseen records must not read as retired
+ }
+ recs := map[string]Record{} // host -> record, in-scope only
+ // protect holds hosts whose record KEY parsed (ParseRecordKey succeeded)
+ // but whose body could not be trusted — unparseable JSON, or a body that
+ // disagrees with its own path. Such a host must NEVER be treated as "the
+ // bucket retired it": a non-additive Record encoding change reaching an
+ // older binary would make EVERY existing record fail exactly this way,
+ // and without this guard one tick would delete every provisioned route
+ // in scope. This is narrower than readFailed (which vetoes removal for
+ // the WHOLE pass): only the specific host with the unusable body is held
+ // back — every other record still converges/removes normally the same
+ // pass.
+ protect := map[string]bool{}
+ var recordKeys []string
+ for _, key := range keys {
+ if _, _, _, ok := ParseRecordKey(key, known); ok {
+ recordKeys = append(recordKeys, key)
}
- // Two accounts writing the same host is a collision this pass
- // cannot arbitrate silently: whichever record this listing reaches
- // FIRST wins the host, and the loser is skipped loudly rather than
- // overwriting the winner in the map with no trace of the conflict.
- if prev, dup := recs[rec.Host]; dup {
- log.Printf("provision: duplicate host %s: keeping %s, skipping %s", rec.Host,
- RecordKey(prev.Account, prev.App, prev.Host), RecordKey(rec.Account, rec.App, rec.Host))
- continue
+ }
+ for _, part := range chunks(recordKeys) {
+ bodies := getEach(ctx, st, part)
+ for _, key := range part {
+ acct, app, host, _ := ParseRecordKey(key, known)
+ raw, err := bodies[key].body, bodies[key].err
+ if err != nil {
+ log.Printf("provision: skipping record %s: read failed: %v", key, err)
+ // The record's absence from recs below must not read as "the
+ // bucket retired it" — a transient Get failure disables removal
+ // for the whole pass, same as an unreadable account manifest.
+ readFailed = true
+ continue
+ }
+ rec, err := DecodeRecord(raw)
+ if err != nil {
+ log.Printf("provision: skipping record %s: malformed: %v", key, err)
+ protect[host] = true
+ continue
+ }
+ if rec.Host != host || rec.Account != acct || rec.App != app {
+ log.Printf("provision: skipping record %s: disagrees with its own path (host=%q account=%q app=%q)",
+ key, rec.Host, rec.Account, rec.App)
+ protect[host] = true
+ continue
+ }
+ // The record IS the authorization, and this pass turns its host into
+ // a socket path and a database path (DefaultSocket/DefaultDBPath)
+ // and a registry primary key. The console's create door enforces
+ // this same shape — but a door is not a guarantee about what is
+ // already in the bucket: anything with bucket write access, and any
+ // record written by a different (older, or future) writer, arrives
+ // here unexamined. Both doors hold the invariant, neither trusts
+ // the other. Protected like a corrupted body, and for the same
+ // reason: a record that cannot be used is not a record that was
+ // retired.
+ if !ValidHostShape(rec.Host) {
+ log.Printf("provision: skipping record %s: host %q is not a hostname", key, rec.Host)
+ protect[host] = true
+ continue
+ }
+ // ValidateShape is the console create door's policy check — but a
+ // door is not a guarantee about what is already in the bucket (the
+ // same reasoning as the host-shape check just above). This pass
+ // materializes whatever it finds, so a record whose Kind/Addr/Unit/
+ // Environment combination is malformed must be caught here too, or
+ // a bad value becomes a live route. Protected like a corrupted
+ // body: the record is there, it just cannot be used.
+ if err := ValidateShape(rec); err != nil {
+ log.Printf("provision: skipping record %s: invalid shape: %v", key, err)
+ protect[host] = true
+ continue
+ }
+ // ValidateShape deliberately does not inspect Channel (it validates
+ // shape fields, and Channel is not one), but a channel-less record
+ // must not become — or converge — a route pinned to no channel:
+ // that is issue #130's failure mode arriving through a different
+ // door than the one Task 3 closed. Protected like a corrupted body:
+ // the record is there, it just cannot be used.
+ if rec.Channel == "" {
+ log.Printf("provision: skipping record %s: empty channel", key)
+ protect[host] = true
+ continue
+ }
+ // Scope. For a home-boxed record this is the region/pool test it
+ // always was; for a static or public-addr one the region half widens
+ // to every platform box in the deployment (everywhereClass, above).
+ // A replica record narrows it: it belongs ONLY to the box whose
+ // placement is the record's own Region — the placement the create
+ // door validated as armed — so a replica record minted on the wrong
+ // region would mint a route with no mirror behind it and no lease
+ // speaking to it, a process holding live order data nobody
+ // authorized into that region (the residence rule, #162). Every
+ // other box skips it exactly like any other out-of-scope record;
+ // the replica's own box sees Region == cfg.Region through the
+ // ordinary test above.
+ if !cfg.inScope(rec.Region, rec.Pool, everywhereClass(rec)) {
+ continue // another agent's jurisdiction, not this pass's business
+ }
+ // Two accounts writing the same host is a collision this pass
+ // cannot arbitrate silently: whichever record this listing reaches
+ // FIRST wins the host, and the loser is skipped loudly rather than
+ // overwriting the winner in the map with no trace of the conflict.
+ if prev, dup := recs[rec.Host]; dup {
+ log.Printf("provision: duplicate host %s: keeping %s, skipping %s", rec.Host,
+ RecordKey(prev.Account, prev.App, prev.Host), RecordKey(rec.Account, rec.App, rec.Host))
+ continue
+ }
+ recs[rec.Host] = rec
}
- recs[rec.Host] = rec
}
+ return recordScan{recs: recs, protect: protect, readFailed: readFailed}, nil
+ }
+ sc, err := scan(s)
+ if err != nil {
+ return err
}
- return recordScan{recs: recs, protect: protect, readFailed: readFailed}, nil
-}
-
-// reconcileScanned is the rest of a Reconcile pass over s, from its record
-// walk.
-func reconcileScanned(ctx context.Context, s release.Store, reg *registry.Registry, cfg ReconcileConfig, sc recordScan) error {
recs, protect, readFailed := sc.recs, sc.protect, sc.readFailed
// --- manifest seed cache, per (acct, app), lazily -------------------------
@@ -1619,7 +1611,7 @@ func reconcileScanned(ctx context.Context, s release.Store, reg *registry.Regist
// hosts matched across every key, the bucket's trash marker). Anything
// it cannot read keeps every row this pass, as in the walk.
live := freshStore(s)
- lsc, err := scanRecords(ctx, live, cfg)
+ lsc, err := scan(live)
if err != nil || lsc.readFailed {
log.Printf("provision: not removing any route this pass: the record view lacks a record or holds a trash marker, and the bucket's own walk could not be read cleanly%s", walkErrSuffix(err))
return nil
diff --git a/internal/provision/s3_change_index_census_test.go b/internal/provision/s3_change_index_census_test.go
index cc5f4b263..c59818bf5 100644
--- a/internal/provision/s3_change_index_census_test.go
+++ b/internal/provision/s3_change_index_census_test.go
@@ -12,11 +12,14 @@ package provision
// with the change index (EnableChangeIndex, NewDeploymentS3Store), a bump
// of control/changes.json (bumpAfterMutation). Still record-transport:
// they write whatever key the caller names, record keys included.
-// - Reconcile and ReconcileSidecars: a removal that a record view snapshot
-// proves by absence (record gone, or the app's trash marker) is confirmed
-// in the bucket first (confirmRecordGone, confirmSidecarGone,
-// confirmTrashed); a confirmation can only keep a row. No record write is
-// added; they stay key-site.
+// - Reconcile and ReconcileSidecars: the record walk moves unchanged into a
+// scan closure over a store argument, and the removal phase into a retire
+// closure. Over a record view snapshot, a pass that reaches a removal the
+// snapshot proves by absence (record gone, a sidecar gone or no longer
+// placeable, the app's trash marker) runs scan again over the bucket and
+// decides every removal that pass from it, by the walk's own rules
+// (final review R1, findings 2 and 4); a walk that cannot read cleanly
+// keeps every row. No record write is added; they stay key-site.
//
// New:
// - snapStore.Put, snapStore.PutFrom: the record view snapshot store
@@ -41,8 +44,8 @@ package provision
func s3ChangeIndexWriteCensusInventory() []censusEntry {
entries := append([]censusEntry(nil), plans2WriteCensusInventory()...)
repins := []censusEntry{
- {"internal/provision/reconcile.go", "Reconcile", "key-site", "key:ParseRecordKey,key:RecordKey,lit:instances", "a7d6072c888cfcf87a8eb3b4c076495ca22201e2eb2ed49e9fbc92dd20868852"},
- {"internal/provision/sidecar_reconcile.go", "ReconcileSidecars", "key-site", "key:ParseSidecarKey,key:SidecarRecordKey,lit:sidecars", "da6e3c45950cb9ebb61d49a080fcb700a3a0bf373354269f503e52abe71cb72d"},
+ {"internal/provision/reconcile.go", "Reconcile", "key-site", "key:ParseRecordKey,key:RecordKey,lit:instances", "b93306e178252e56c67dd2ed58b87250e1b3756bddaa2589c3f7392d03300832"},
+ {"internal/provision/sidecar_reconcile.go", "ReconcileSidecars", "key-site", "key:ParseSidecarKey,key:SidecarRecordKey,lit:sidecars", "cc2aa4dbcb68f06f1190ad58a37c58e2608517e7388318b5b9e0b4bad0e8b5db"},
{"internal/release/store.go", "DirStore.Put", "record-transport", "def:Put", "63c5ff8af0fd64d30502735306287c489a659863ef3fc8b3f0df48f31c25134e"},
{"internal/release/store.go", "DirStore.PutFrom", "record-transport", "def:PutFrom", "f3f61446f41f15692d7e164b1a1637a8ff213359da3eebd60f574f585b31eb6a"},
{"internal/release/store.go", "S3Store.Put", "record-transport", "def:Put", "cd2fbd84994508f0f920210d6b0b4375a2d0ea1369ef0b73160fc2e0b2de66e9"},
diff --git a/internal/provision/sidecar_reconcile.go b/internal/provision/sidecar_reconcile.go
index 45cfec6b2..4a7c6d8d6 100644
--- a/internal/provision/sidecar_reconcile.go
+++ b/internal/provision/sidecar_reconcile.go
@@ -192,201 +192,191 @@ func ReconcileSidecars(ctx context.Context, s release.Store, reg *registry.Regis
cfg.Now = time.Now
}
- sc, err := scanSidecars(ctx, s, cfg)
- if err != nil {
- return err
+ // scan is the record-collection phase over st: the placeable in-scope
+ // records by host, the hosts whose record is there but cannot be used
+ // (protect), the per-app sidecars manifest lookup the pass goes on using,
+ // and whether anything failed to read (readFailed, which disables removal
+ // for the whole pass; a manifest read that fails later in the pass sets
+ // it too). The pass scans s; a pass over a record view snapshot that has
+ // a removal to decide scans the bucket too (freshStore), so both judge
+ // every record by exactly these rules, placement against the record and
+ // the app's sidecars manifest included (S3 change-index design §4.4).
+ type sidecarScan struct {
+ recs map[string]SidecarRecord
+ protect map[string]bool
+ readFailed bool
+ manifestFor func(acct, app string) (SidecarManifest, bool)
}
- return reconcileSidecarsScanned(ctx, s, reg, cfg, sc)
-}
-
-// sidecarScan is the record-collection phase of a ReconcileSidecars pass: the
-// placeable in-scope records by host, the hosts whose record is there but
-// cannot be used (protect), the per-app sidecars manifest lookup the pass
-// goes on using, and whether anything failed to read (readFailed, which
-// disables removal for the whole pass; a manifest read that fails later in
-// the pass sets it too).
-type sidecarScan struct {
- recs map[string]SidecarRecord
- protect map[string]bool
- readFailed bool
- manifestFor func(acct, app string) (SidecarManifest, bool)
-}
-
-// scanSidecars is ReconcileSidecars' record walk over s. A pass over a record
-// view snapshot that has a removal to decide runs it again over the bucket
-// (freshStore), so both judge every record by exactly these rules,
-// placement against the record and the app's sidecars manifest included
-// (S3 change-index design §4.4).
-func scanSidecars(ctx context.Context, s release.Store, cfg ReconcileConfig) (*sidecarScan, error) {
- sc := &sidecarScan{}
- known, readFailed, err := knownAccounts(ctx, s)
- if err != nil {
- return nil, err
- }
- sc.readFailed = readFailed
-
- // --- manifest cache, per (acct, app), lazily ------------------------------
- // known=false covers BOTH "no manifest" and "the read failed", and in both
- // cases this pass declines to mint or converge: every manifest-owned
- // column (argv, the ceilings, hibernation) would otherwise be stamped from
- // a zero value — an empty argv over a working one, on a blip. This is
- // seedFor's seedKnown discipline, applied to a family where the manifest
- // carries the RUN instruction rather than a seed.
- //
- // Declared BEFORE the record scan because placement is a scope axis and
- // placement can be stated app-wide: deciding whether a record is in scope
- // needs the manifest in hand. An unknown manifest resolves placement from
- // the record alone (sidecarPlacement over a zero manifest) — and a manifest
- // whose read FAILED has already disabled the removal phase, so an
- // unknowable placement can never evacuate anything.
- manCache := map[acctApp]SidecarManifest{}
- manKnown := map[acctApp]bool{}
- manSeen := map[acctApp]bool{}
- manifestFor := func(acct, app string) (SidecarManifest, bool) {
- k := acctApp{acct, app}
- if manSeen[k] {
- return manCache[k], manKnown[k]
- }
- manSeen[k] = true
- m, err := GetSidecarManifest(ctx, s, acct, app)
+ scan := func(st release.Store) (*sidecarScan, error) {
+ sc := &sidecarScan{}
+ known, readFailed, err := knownAccounts(ctx, st)
if err != nil {
- if errors.Is(err, os.ErrNotExist) {
- // Absence IS the answer (design §3.1): sidecars are not
- // enabled for this app. Not a read failure — removal stays
- // armed for the pass — but the records themselves stay in
- // recs, so nothing of theirs is retired on it.
- log.Printf("provision: %s/%s has sidecar records but no sidecars manifest — not minting", acct, app)
- return SidecarManifest{}, false
- }
- log.Printf("provision: sidecar manifest %s/%s: read failed: %v", acct, app, err)
- sc.readFailed = true
- return SidecarManifest{}, false
+ return nil, err
}
- manCache[k], manKnown[k] = *m, true
- return manCache[k], manKnown[k]
- }
+ sc.readFailed = readFailed
- // --- collect in-scope records --------------------------------------------
- keys, partial, err := listAppSubtree(ctx, s, known, "sidecars/")
- if err != nil {
- return nil, fmt.Errorf("provision: list apps: %w", err)
- }
- if partial {
- sc.readFailed = true // unseen records must not read as retired
- }
- recs := map[string]SidecarRecord{} // host -> record, in-scope only
- // protect holds hosts whose record KEY parsed but whose body could not be
- // trusted — unparseable JSON, a body disagreeing with its own path, or a
- // shape this binary refuses. Such a host must NEVER read as "the bucket
- // retired it": a non-additive record encoding change reaching an older
- // binary would make EVERY record fail exactly this way, and one tick would
- // then delete every sidecar in scope. Narrower than readFailed (which
- // vetoes removal for the whole pass): only the unusable host is held back.
- protect := map[string]bool{}
- var recordKeys []string
- for _, key := range keys {
- if _, _, _, ok := ParseSidecarKey(key, known); ok {
- recordKeys = append(recordKeys, key)
- }
- }
- for _, part := range chunks(recordKeys) {
- bodies := getEach(ctx, s, part)
- for _, key := range part {
- acct, app, name, _ := ParseSidecarKey(key, known)
- // Derived from the KEY, never from the body: the body is what is
- // under suspicion in every branch below.
- host := SidecarHost(name, app, acct)
- raw, err := bodies[key].body, bodies[key].err
+ // --- manifest cache, per (acct, app), lazily ------------------------------
+ // known=false covers BOTH "no manifest" and "the read failed", and in both
+ // cases this pass declines to mint or converge: every manifest-owned
+ // column (argv, the ceilings, hibernation) would otherwise be stamped from
+ // a zero value — an empty argv over a working one, on a blip. This is
+ // seedFor's seedKnown discipline, applied to a family where the manifest
+ // carries the RUN instruction rather than a seed.
+ //
+ // Declared BEFORE the record scan because placement is a scope axis and
+ // placement can be stated app-wide: deciding whether a record is in scope
+ // needs the manifest in hand. An unknown manifest resolves placement from
+ // the record alone (sidecarPlacement over a zero manifest) — and a manifest
+ // whose read FAILED has already disabled the removal phase, so an
+ // unknowable placement can never evacuate anything.
+ manCache := map[acctApp]SidecarManifest{}
+ manKnown := map[acctApp]bool{}
+ manSeen := map[acctApp]bool{}
+ manifestFor := func(acct, app string) (SidecarManifest, bool) {
+ k := acctApp{acct, app}
+ if manSeen[k] {
+ return manCache[k], manKnown[k]
+ }
+ manSeen[k] = true
+ m, err := GetSidecarManifest(ctx, st, acct, app)
if err != nil {
- log.Printf("provision: skipping sidecar record %s: read failed: %v", key, err)
- // Its absence from recs below must not read as "the bucket retired
- // it" — a transient Get failure disables removal for the whole
- // pass, same as an unreadable account manifest.
+ if errors.Is(err, os.ErrNotExist) {
+ // Absence IS the answer (design §3.1): sidecars are not
+ // enabled for this app. Not a read failure — removal stays
+ // armed for the pass — but the records themselves stay in
+ // recs, so nothing of theirs is retired on it.
+ log.Printf("provision: %s/%s has sidecar records but no sidecars manifest — not minting", acct, app)
+ return SidecarManifest{}, false
+ }
+ log.Printf("provision: sidecar manifest %s/%s: read failed: %v", acct, app, err)
sc.readFailed = true
- continue
- }
- var rec SidecarRecord
- if err := json.Unmarshal(raw, &rec); err != nil {
- log.Printf("provision: skipping sidecar record %s: malformed: %v", key, err)
- protect[host] = true
- continue
- }
- if rec.Name != name || rec.Account != acct || rec.App != app {
- log.Printf("provision: skipping sidecar record %s: disagrees with its own path (name=%q account=%q app=%q)",
- key, rec.Name, rec.Account, rec.App)
- protect[host] = true
- continue
- }
- // ValidateSidecarShape is the console create door's policy check — but
- // a door is not a guarantee about what is already in the bucket:
- // anything with bucket write access, and any record written by a
- // different (older, or future) writer, arrives here unexamined. Both
- // doors hold the invariant, neither trusts the other. Protected like a
- // corrupted body, and for the same reason: a record that cannot be
- // used is not a record that was retired.
- if err := ValidateSidecarShape(rec); err != nil {
- log.Printf("provision: skipping sidecar record %s: invalid shape: %v", key, err)
- protect[host] = true
- continue
- }
- // The host is DERIVED from the identity, never taken on trust: it
- // becomes a database path and a registry primary key, and a record
- // free to state its own host could name any row on the box.
- if rec.Host != host {
- log.Printf("provision: skipping sidecar record %s: host %q is not %q", key, rec.Host, host)
- protect[host] = true
- continue
- }
- // ValidateSidecarShape deliberately does not inspect Channel (it
- // validates shape fields, and Channel is not one), but a channel-less
- // record must not become — or converge — a route pinned to no channel:
- // such a row resolves no release, so it has no build to exec, and the
- // worker boot pass would try to run it against a symlink that does not
- // exist. The console stamps a channel at create, so a record without
- // one is malformed. Protected like a corrupted body: the record is
- // there, it just cannot be used.
- if rec.Channel == "" {
- log.Printf("provision: skipping sidecar record %s: empty channel", key)
- protect[host] = true
- continue
- }
- if rec.Region != cfg.Region || !poolServed(cfg.Pools, rec.Pool) {
- continue // another agent's jurisdiction, not this pass's business
+ return SidecarManifest{}, false
}
- // Placement is the third scope axis (design §8), and it is applied
- // HERE, beside region and pool, precisely so it behaves like them: a
- // record this box may not run never enters recs, and the removal phase
- // below therefore evacuates any row it left behind. "none" is a
- // property of the BOX's network; "no-inbound" is a requirement of the
- // WORKLOAD — the point of the two halves being independent is that a
- // member gets a mechanical guarantee rather than an operator's promise,
- // which a row left running on an inbound box would not be.
- if m, _ := manifestFor(acct, app); !placeable(rec, m, cfg) {
- log.Printf("provision: sidecar %s is not placeable here: it asks for %q placement and this box accepts inbound work (CARLOS_INBOUND=%q)",
- rec.Host, sidecarPlacement(rec, m), cfg.Inbound)
- continue
+ manCache[k], manKnown[k] = *m, true
+ return manCache[k], manKnown[k]
+ }
+
+ // --- collect in-scope records --------------------------------------------
+ keys, partial, err := listAppSubtree(ctx, st, known, "sidecars/")
+ if err != nil {
+ return nil, fmt.Errorf("provision: list apps: %w", err)
+ }
+ if partial {
+ sc.readFailed = true // unseen records must not read as retired
+ }
+ recs := map[string]SidecarRecord{} // host -> record, in-scope only
+ // protect holds hosts whose record KEY parsed but whose body could not be
+ // trusted — unparseable JSON, a body disagreeing with its own path, or a
+ // shape this binary refuses. Such a host must NEVER read as "the bucket
+ // retired it": a non-additive record encoding change reaching an older
+ // binary would make EVERY record fail exactly this way, and one tick would
+ // then delete every sidecar in scope. Narrower than readFailed (which
+ // vetoes removal for the whole pass): only the unusable host is held back.
+ protect := map[string]bool{}
+ var recordKeys []string
+ for _, key := range keys {
+ if _, _, _, ok := ParseSidecarKey(key, known); ok {
+ recordKeys = append(recordKeys, key)
}
- // Two records claiming one host is a collision this pass cannot
- // arbitrate silently: whichever this listing reaches FIRST wins, and
- // the loser is skipped loudly rather than overwriting the winner in
- // the map with no trace of the conflict.
- if prev, dup := recs[rec.Host]; dup {
- log.Printf("provision: duplicate sidecar host %s: keeping %s, skipping %s", rec.Host,
- SidecarRecordKey(prev.Account, prev.App, prev.Name), key)
- continue
+ }
+ for _, part := range chunks(recordKeys) {
+ bodies := getEach(ctx, st, part)
+ for _, key := range part {
+ acct, app, name, _ := ParseSidecarKey(key, known)
+ // Derived from the KEY, never from the body: the body is what is
+ // under suspicion in every branch below.
+ host := SidecarHost(name, app, acct)
+ raw, err := bodies[key].body, bodies[key].err
+ if err != nil {
+ log.Printf("provision: skipping sidecar record %s: read failed: %v", key, err)
+ // Its absence from recs below must not read as "the bucket retired
+ // it" — a transient Get failure disables removal for the whole
+ // pass, same as an unreadable account manifest.
+ sc.readFailed = true
+ continue
+ }
+ var rec SidecarRecord
+ if err := json.Unmarshal(raw, &rec); err != nil {
+ log.Printf("provision: skipping sidecar record %s: malformed: %v", key, err)
+ protect[host] = true
+ continue
+ }
+ if rec.Name != name || rec.Account != acct || rec.App != app {
+ log.Printf("provision: skipping sidecar record %s: disagrees with its own path (name=%q account=%q app=%q)",
+ key, rec.Name, rec.Account, rec.App)
+ protect[host] = true
+ continue
+ }
+ // ValidateSidecarShape is the console create door's policy check — but
+ // a door is not a guarantee about what is already in the bucket:
+ // anything with bucket write access, and any record written by a
+ // different (older, or future) writer, arrives here unexamined. Both
+ // doors hold the invariant, neither trusts the other. Protected like a
+ // corrupted body, and for the same reason: a record that cannot be
+ // used is not a record that was retired.
+ if err := ValidateSidecarShape(rec); err != nil {
+ log.Printf("provision: skipping sidecar record %s: invalid shape: %v", key, err)
+ protect[host] = true
+ continue
+ }
+ // The host is DERIVED from the identity, never taken on trust: it
+ // becomes a database path and a registry primary key, and a record
+ // free to state its own host could name any row on the box.
+ if rec.Host != host {
+ log.Printf("provision: skipping sidecar record %s: host %q is not %q", key, rec.Host, host)
+ protect[host] = true
+ continue
+ }
+ // ValidateSidecarShape deliberately does not inspect Channel (it
+ // validates shape fields, and Channel is not one), but a channel-less
+ // record must not become — or converge — a route pinned to no channel:
+ // such a row resolves no release, so it has no build to exec, and the
+ // worker boot pass would try to run it against a symlink that does not
+ // exist. The console stamps a channel at create, so a record without
+ // one is malformed. Protected like a corrupted body: the record is
+ // there, it just cannot be used.
+ if rec.Channel == "" {
+ log.Printf("provision: skipping sidecar record %s: empty channel", key)
+ protect[host] = true
+ continue
+ }
+ if rec.Region != cfg.Region || !poolServed(cfg.Pools, rec.Pool) {
+ continue // another agent's jurisdiction, not this pass's business
+ }
+ // Placement is the third scope axis (design §8), and it is applied
+ // HERE, beside region and pool, precisely so it behaves like them: a
+ // record this box may not run never enters recs, and the removal phase
+ // below therefore evacuates any row it left behind. "none" is a
+ // property of the BOX's network; "no-inbound" is a requirement of the
+ // WORKLOAD — the point of the two halves being independent is that a
+ // member gets a mechanical guarantee rather than an operator's promise,
+ // which a row left running on an inbound box would not be.
+ if m, _ := manifestFor(acct, app); !placeable(rec, m, cfg) {
+ log.Printf("provision: sidecar %s is not placeable here: it asks for %q placement and this box accepts inbound work (CARLOS_INBOUND=%q)",
+ rec.Host, sidecarPlacement(rec, m), cfg.Inbound)
+ continue
+ }
+ // Two records claiming one host is a collision this pass cannot
+ // arbitrate silently: whichever this listing reaches FIRST wins, and
+ // the loser is skipped loudly rather than overwriting the winner in
+ // the map with no trace of the conflict.
+ if prev, dup := recs[rec.Host]; dup {
+ log.Printf("provision: duplicate sidecar host %s: keeping %s, skipping %s", rec.Host,
+ SidecarRecordKey(prev.Account, prev.App, prev.Name), key)
+ continue
+ }
+ recs[rec.Host] = rec
}
- recs[rec.Host] = rec
}
+ sc.recs, sc.protect, sc.manifestFor = recs, protect, manifestFor
+ return sc, nil
+ }
+ sc, err := scan(s)
+ if err != nil {
+ return err
}
-
- sc.recs, sc.protect, sc.manifestFor = recs, protect, manifestFor
- return sc, nil
-}
-
-// reconcileSidecarsScanned is the rest of a ReconcileSidecars pass over s,
-// from its record walk.
-func reconcileSidecarsScanned(ctx context.Context, s release.Store, reg *registry.Registry, cfg ReconcileConfig, sc *sidecarScan) error {
recs, protect, manifestFor := sc.recs, sc.protect, sc.manifestFor
+
trashed := trashGate(ctx, s, "sidecar")
// --- mint / converge -------------------------------------------------------
@@ -545,7 +535,7 @@ func reconcileSidecarsScanned(ctx context.Context, s release.Store, reg *registr
// every key, placement from the bucket's record and sidecars manifest
// against this box's inbound). Anything it cannot read keeps every row
// this pass, as in the walk.
- lsc, err := scanSidecars(ctx, freshStore(s), cfg)
+ lsc, err := scan(freshStore(s))
if err != nil || lsc.readFailed {
log.Printf("provision: not removing any sidecar route this pass: the record view lacks a sidecar this box would run, and the bucket's own walk could not be read cleanly%s", walkErrSuffix(err))
return nil
diff --git a/internal/provision/testdata/plan14-root-reads-s3-change-index.tsv b/internal/provision/testdata/plan14-root-reads-s3-change-index.tsv
index a2b4054d0..e76530d47 100644
--- a/internal/provision/testdata/plan14-root-reads-s3-change-index.tsv
+++ b/internal/provision/testdata/plan14-root-reads-s3-change-index.tsv
@@ -1,5 +1,5 @@
# Census overlay s3-change-index (amadan #336: the S3 change index; docs/superpowers/specs/2026-10-21-s3-change-index-design.md), loaded LAST, after console-brand-name. Proposed: new and re-pinned rows carry rev3=PROPOSED-s3-change-index and the H3 removals census-ruling-s3-change-index; the ruling is asked of the census owner on #280.
-# What changed. The deployment stores bump control/changes.json after each successful mutation (Put, PutFrom, Delete, DeleteIfMatch split into a raw body plus the bump). Readers armed by CARLOS_CHANGE_INDEX=read (unset is exactly today's behaviour) read records through a record view snapshot, skip unchanged generation, canary pointer and telemetry reads behind a gate whose maximum age is the 30 minute backstop, and run a scoped pass over the apps whose scope moved. A removal over a snapshot is confirmed in the live bucket first and a failed confirmation keeps the row.
+# What changed. The deployment stores bump control/changes.json after each successful mutation (Put, PutFrom, Delete, DeleteIfMatch split into a raw body plus the bump). Readers armed by CARLOS_CHANGE_INDEX=read (unset is exactly today's behaviour) read records through a record view snapshot, skip unchanged generation, canary pointer and telemetry reads behind a gate whose maximum age is the 30 minute backstop, and run a scoped pass over the apps whose scope moved. A pass over a snapshot that would remove a row on absence runs its own record walk again over the live bucket and decides every removal that pass from it (a walk that cannot read cleanly keeps every row); the moves pass uses the snapshot only to decide whether it has move work, and acts on its own walk of the bucket; with no change index armed, the telemetry pass is main's (final review R1 fixes).
# Who runs it. The new and changed units run in the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), the console (cmd/console serve, user carlos-console), or are store methods every deployment-store opener shares, as their siblings. Root's carlos adopt reaches only PassFilter, type passConfig and passConfig.gatePointers, with the gate nil (unchanged pass). runSystemClaims (operator CLI, uid 0) now opens the deployment store with the change index, so its writes bump control/changes.json; the bump reads and rewrites that one object and decides nothing else.
# Re-pins keep each unit's class and append this branch's basis. New units take their siblings' class. Frozen declarations are added, so the seal moves; console-brand-name's is checked first.
@legacy 8aed1441fabaa3bb95898b31bfd1d0e00dfc93ef0e608612c83c80e5b166d32c cmd/console/main.go serve legacy accepted-legacy accepted-legacy;rev3=PROPOSED-scan-demand-revival;basis=Console service wires the optional callback signer and starts the claim-guarded queue worker. The same three data path literals move; it does not add a privileged reader.;rev3=PROPOSED-email-signin;identity=the console (cmd/console serve under console.service, user carlos-console);basis=passes CARLOS_CONSOLE_NAME to NewServer as Config.ConsoleName, the name the console's emails use; the same three /data literals at the same offsets; no read added;rev3=PROPOSED-s3-change-index;identity=the console (cmd/console serve under console.service, user carlos-console);basis=arms the record view when CARLOS_CHANGE_INDEX=read (armChangeIndex) for the run and seed sweeps and starts its backstop loop; the same three /data literals at the same offsets; no read added data-literal@4077,data-literal@5178,data-literal@5415 32740c27448264baa40a1c8062fa847b992d02ca21b6117fa2e55dfaf10febdc
@@ -10,18 +10,18 @@ internal/appconfig/syncexec.go SyncExecWithCallbacks legacy accepted-legacy acce
internal/console/runsweep.go Server.runSweepPass legacy accepted-legacy accepted-legacy;rev3=census-ruling-carlos-run;basis=the console (cmd/console serve under console.service, user carlos-console): the console's run sweep: expires queued runs and ends lost ones by CAS on the record;rev3=PROPOSED-s3-change-index;identity=the console (cmd/console serve under console.service, user carlos-console);basis=armed, reads the records through the record view (recordWalkStore) and lists runs/ for orphans only for apps with a run-start audit row in the last 48 hours (orphanCandidates, Store.AppsWithActionSince), with a full orphan sweep at start and every 24 hours; every write and the runs/ listing stay on the bucket; read site unchanged, offset moved file:Open@1438 466d9bb74c5f5fa33d968c3862dfd5c9662b63b7659844ff43d55bb8d937ecc1
@legacy d63b9da377834935321f22b7af726257ebbc1b6e6204afc6e85205850ffcc257 internal/host/agent.go configGenLoop legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-fixes;basis=root-route (J1, main's disposition); the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's loop, its tick's body moved into configGenTick; the registry listing stays here;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=builds the generation cache's change gate (newChangeGate) after the agent armed the index; read site unchanged, offset moved whole:Route@1362 c5d039380bf66781652a6e75df4d4614d192e68c939ceef7c8875b383b0dcaeb
internal/host/agent.go configGenLoop legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-fixes;basis=root-route (J1, main's disposition); the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's loop, its tick's body moved into configGenTick; the registry listing stays here;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=builds the generation cache's change gate (newChangeGate) after the agent armed the index; read site unchanged, offset moved whole:Route@1362 c5d039380bf66781652a6e75df4d4614d192e68c939ceef7c8875b383b0dcaeb
-@legacy 25d21235ae57b8378e8cc2ec24abf8fc04adfb91be3e61cfd846679fddb7a28e internal/host/agent.go fastTick legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=observes the change index before any pass (observeIndex), runs the backstop's requested full pass and a scoped pass for moved app scopes (indexTick), and arms the canary pointer gate on the sweep (canaryPointerGate); read site unchanged, offset moved registry:Host@4381 83841634974cc5058a882a0fb642c84983c54e4c46a9e31bd619307549797864
-internal/host/agent.go fastTick legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=observes the change index before any pass (observeIndex), runs the backstop's requested full pass and a scoped pass for moved app scopes (indexTick), and arms the canary pointer gate on the sweep (canaryPointerGate); read site unchanged, offset moved registry:Host@4381 83841634974cc5058a882a0fb642c84983c54e4c46a9e31bd619307549797864
+@legacy 619ddec1235e248f234943915a064de44f6c6c8e5c2c37ae432bd629e0e5d359 internal/host/agent.go fastTick legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=observes the change index before any pass (observeIndex), runs the backstop's requested full pass and a scoped pass for moved app scopes (indexTick), and arms the canary pointer gate on the sweep (canaryPointerGate) only on a tick whose own index observation succeeded; read site unchanged, offset moved registry:Host@4720 936882c271ea015144472e2726b9c51f926b9ed2ac7314702449359441b1f33f
+internal/host/agent.go fastTick legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=observes the change index before any pass (observeIndex), runs the backstop's requested full pass and a scoped pass for moved app scopes (indexTick), and arms the canary pointer gate on the sweep (canaryPointerGate) only on a tick whose own index observation succeeded; read site unchanged, offset moved registry:Host@4720 936882c271ea015144472e2726b9c51f926b9ed2ac7314702449359441b1f33f
@legacy ce2cf944137713e8cb39ddade175b99907b510b0c0d6033f0a9d2c408f4e4e79 internal/host/agent.go genPollPass legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=armed, an app already in the cache skips its generation read unless its scope moved, its last read failed, or that read is the backstop's age (release.ReadGate); read sites unchanged at the same offsets whole:Route@399,whole:Route@639,whole:Route@685 cc5bfbdba246803782a029bc3868d1f250b92e1868a785a70783368b0f72091e
internal/host/agent.go genPollPass legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=armed, an app already in the cache skips its generation read unless its scope moved, its last read failed, or that read is the backstop's age (release.ReadGate); read sites unchanged at the same offsets whole:Route@399,whole:Route@639,whole:Route@685 cc5bfbdba246803782a029bc3868d1f250b92e1868a785a70783368b0f72091e
@legacy 3539c4d974f5965c27b0f61531f483b5ce395f24005e190de130bbece08a8f05 internal/host/steering_loop.go steeringPass legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=reads the steered records through the record view when it can vouch (viewStore), the bucket otherwise; read site unchanged, offset moved whole:Route@475 5db289406e7e014db706e6e37146396ae88865ffb8a8c43aed90c2433da1ed6d
internal/host/steering_loop.go steeringPass legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=reads the steered records through the record view when it can vouch (viewStore), the bucket otherwise; read site unchanged, offset moved whole:Route@475 5db289406e7e014db706e6e37146396ae88865ffb8a8c43aed90c2433da1ed6d
-@legacy 921dfa45400dc39e0652907d9c16bb21cffc823f63b852a310586dbccb789f46 internal/provision/reconcile.go Reconcile legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import journal read before the records are acted on (journalPass), seeded records dispatched first (seedAction), journaled hosts kept out of the removal phase and a row's seed column converged from its record; the agent's own pass;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=over a record view snapshot, a record-gone or app-in-the-trash removal is confirmed in the bucket first (confirmRecordGone, confirmTrashed) and a confirmation that cannot read cleanly keeps the row; disarmed, the store is never a snapshot and both answer true without reading; one whole-Route, one Account and one App site added, each passing rt to a confirmation; a removal can only be withheld, never added registry:Account@19247,registry:Account@20339,registry:Account@33924,registry:Account@33970,registry:Account@35180,registry:App@19220,registry:App@20312,registry:App@33944,registry:App@33982,registry:App@35192,registry:ClaimOwnership@19834,registry:DBPath@26035,registry:DBPath@26050,registry:DBPath@26296,registry:DBPath@26827,registry:DBPath@26840,registry:Gate@22975,registry:Gate@23115,registry:Gate@23380,registry:Hibernate@21953,registry:Hibernate@22271,registry:Hibernate@22622,registry:Hibernate@22910,registry:Host@13124,registry:Host@33902,registry:Host@34072,registry:Host@34169,registry:Host@34284,registry:Host@34629,registry:Host@34726,registry:Host@35324,registry:Host@35482,registry:Host@35584,registry:Kind@19976,registry:Kind@20239,registry:Kind@25953,registry:Kind@25966,registry:Kind@26076,registry:Kind@26089,registry:Kind@26738,registry:Kind@26749,registry:Kind@33138,registry:Kind@35315,registry:Kind@35473,registry:Kind@35575,registry:Pool@33230,registry:Provisioned@19196,registry:Provisioned@20288,registry:Provisioned@33188,registry:Region@33219,registry:Replication@22356,registry:Replication@22483,registry:Seed@24455,registry:SeedSource@23960,registry:Socket@26001,registry:Socket@26016,registry:Socket@26313,registry:Socket@26797,registry:Socket@26810,registry:Unit@25919,registry:Unit@25932,registry:Unit@26764,registry:Unit@26775,whole:ClaimOwnership@19837,whole:ClaimOwnership@19854,whole:Route@13106,whole:Route@13117,whole:Route@13135,whole:Route@14235,whole:Route@14535,whole:Route@14542,whole:Route@14582,whole:Route@14943,whole:Route@15261,whole:Route@16122,whole:Route@16478,whole:Route@16487,whole:Route@16533,whole:Route@18841,whole:Route@19312,whole:Route@19322,whole:Route@19679,whole:Route@19686,whole:Route@19754,whole:Route@20077,whole:Route@20720,whole:Route@22043,whole:Route@26145,whole:Route@27624,whole:Route@27669,whole:Route@27679,whole:Route@28542,whole:Route@29294,whole:Route@32586,whole:Route@33255,whole:Route@35008,whole:Route@35395 a7d6072c888cfcf87a8eb3b4c076495ca22201e2eb2ed49e9fbc92dd20868852
-internal/provision/reconcile.go Reconcile legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import journal read before the records are acted on (journalPass), seeded records dispatched first (seedAction), journaled hosts kept out of the removal phase and a row's seed column converged from its record; the agent's own pass;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=over a record view snapshot, a record-gone or app-in-the-trash removal is confirmed in the bucket first (confirmRecordGone, confirmTrashed) and a confirmation that cannot read cleanly keeps the row; disarmed, the store is never a snapshot and both answer true without reading; one whole-Route, one Account and one App site added, each passing rt to a confirmation; a removal can only be withheld, never added registry:Account@19247,registry:Account@20339,registry:Account@33924,registry:Account@33970,registry:Account@35180,registry:App@19220,registry:App@20312,registry:App@33944,registry:App@33982,registry:App@35192,registry:ClaimOwnership@19834,registry:DBPath@26035,registry:DBPath@26050,registry:DBPath@26296,registry:DBPath@26827,registry:DBPath@26840,registry:Gate@22975,registry:Gate@23115,registry:Gate@23380,registry:Hibernate@21953,registry:Hibernate@22271,registry:Hibernate@22622,registry:Hibernate@22910,registry:Host@13124,registry:Host@33902,registry:Host@34072,registry:Host@34169,registry:Host@34284,registry:Host@34629,registry:Host@34726,registry:Host@35324,registry:Host@35482,registry:Host@35584,registry:Kind@19976,registry:Kind@20239,registry:Kind@25953,registry:Kind@25966,registry:Kind@26076,registry:Kind@26089,registry:Kind@26738,registry:Kind@26749,registry:Kind@33138,registry:Kind@35315,registry:Kind@35473,registry:Kind@35575,registry:Pool@33230,registry:Provisioned@19196,registry:Provisioned@20288,registry:Provisioned@33188,registry:Region@33219,registry:Replication@22356,registry:Replication@22483,registry:Seed@24455,registry:SeedSource@23960,registry:Socket@26001,registry:Socket@26016,registry:Socket@26313,registry:Socket@26797,registry:Socket@26810,registry:Unit@25919,registry:Unit@25932,registry:Unit@26764,registry:Unit@26775,whole:ClaimOwnership@19837,whole:ClaimOwnership@19854,whole:Route@13106,whole:Route@13117,whole:Route@13135,whole:Route@14235,whole:Route@14535,whole:Route@14542,whole:Route@14582,whole:Route@14943,whole:Route@15261,whole:Route@16122,whole:Route@16478,whole:Route@16487,whole:Route@16533,whole:Route@18841,whole:Route@19312,whole:Route@19322,whole:Route@19679,whole:Route@19686,whole:Route@19754,whole:Route@20077,whole:Route@20720,whole:Route@22043,whole:Route@26145,whole:Route@27624,whole:Route@27669,whole:Route@27679,whole:Route@28542,whole:Route@29294,whole:Route@32586,whole:Route@33255,whole:Route@35008,whole:Route@35395 a7d6072c888cfcf87a8eb3b4c076495ca22201e2eb2ed49e9fbc92dd20868852
+@legacy 5f09d85d9586e22f1d8447c122cde4c75a2ecacb28c85ab28e3f5e7090760460 internal/provision/reconcile.go Reconcile legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import journal read before the records are acted on (journalPass), seeded records dispatched first (seedAction), journaled hosts kept out of the removal phase and a row's seed column converged from its record; the agent's own pass;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=the record walk moves unchanged into the pass's scan closure (over a store argument) and the removal phase into its retire closure; over a record view snapshot, a pass that reaches a removal candidate proved by absence (record gone, app in the trash) removes nothing on the snapshot's word: it runs scan again over the bucket (freshStore) and decides every removal that pass from that walk, by the walk's own rules (unusable records protected before scope, hosts matched across every key, the bucket's trash marker); a walk that cannot read cleanly keeps every row; with no candidate, or disarmed (never a snapshot), nothing is read again; the registry sites are main's, moved; relative to main's single walk a removal can only be withheld, never added registry:Account@20586,registry:Account@21678,registry:Account@35895,registry:Account@35941,registry:App@20559,registry:App@21651,registry:App@35915,registry:App@35953,registry:ClaimOwnership@21173,registry:DBPath@27374,registry:DBPath@27389,registry:DBPath@27635,registry:DBPath@28166,registry:DBPath@28179,registry:Gate@24314,registry:Gate@24454,registry:Gate@24719,registry:Hibernate@23292,registry:Hibernate@23610,registry:Hibernate@23961,registry:Hibernate@24249,registry:Host@14463,registry:Host@35873,registry:Host@36043,registry:Host@36140,registry:Host@36255,registry:Host@36600,registry:Host@36697,registry:Host@36874,registry:Host@37032,registry:Host@37134,registry:Kind@21315,registry:Kind@21578,registry:Kind@27292,registry:Kind@27305,registry:Kind@27415,registry:Kind@27428,registry:Kind@28077,registry:Kind@28088,registry:Kind@35109,registry:Kind@36865,registry:Kind@37023,registry:Kind@37125,registry:Pool@35201,registry:Provisioned@20535,registry:Provisioned@21627,registry:Provisioned@35159,registry:Region@35190,registry:Replication@23695,registry:Replication@23822,registry:Seed@25794,registry:SeedSource@25299,registry:Socket@27340,registry:Socket@27355,registry:Socket@27652,registry:Socket@28136,registry:Socket@28149,registry:Unit@27258,registry:Unit@27271,registry:Unit@28103,registry:Unit@28114,whole:ClaimOwnership@21176,whole:ClaimOwnership@21193,whole:Route@14445,whole:Route@14456,whole:Route@14474,whole:Route@15574,whole:Route@15874,whole:Route@15881,whole:Route@15921,whole:Route@16282,whole:Route@16600,whole:Route@17461,whole:Route@17817,whole:Route@17826,whole:Route@17872,whole:Route@20180,whole:Route@20651,whole:Route@20661,whole:Route@21018,whole:Route@21025,whole:Route@21093,whole:Route@21416,whole:Route@22059,whole:Route@23382,whole:Route@27484,whole:Route@28963,whole:Route@29008,whole:Route@29018,whole:Route@29881,whole:Route@30633,whole:Route@34557,whole:Route@35226,whole:Route@36945 b93306e178252e56c67dd2ed58b87250e1b3756bddaa2589c3f7392d03300832
+internal/provision/reconcile.go Reconcile legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import journal read before the records are acted on (journalPass), seeded records dispatched first (seedAction), journaled hosts kept out of the removal phase and a row's seed column converged from its record; the agent's own pass;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=the record walk moves unchanged into the pass's scan closure (over a store argument) and the removal phase into its retire closure; over a record view snapshot, a pass that reaches a removal candidate proved by absence (record gone, app in the trash) removes nothing on the snapshot's word: it runs scan again over the bucket (freshStore) and decides every removal that pass from that walk, by the walk's own rules (unusable records protected before scope, hosts matched across every key, the bucket's trash marker); a walk that cannot read cleanly keeps every row; with no candidate, or disarmed (never a snapshot), nothing is read again; the registry sites are main's, moved; relative to main's single walk a removal can only be withheld, never added registry:Account@20586,registry:Account@21678,registry:Account@35895,registry:Account@35941,registry:App@20559,registry:App@21651,registry:App@35915,registry:App@35953,registry:ClaimOwnership@21173,registry:DBPath@27374,registry:DBPath@27389,registry:DBPath@27635,registry:DBPath@28166,registry:DBPath@28179,registry:Gate@24314,registry:Gate@24454,registry:Gate@24719,registry:Hibernate@23292,registry:Hibernate@23610,registry:Hibernate@23961,registry:Hibernate@24249,registry:Host@14463,registry:Host@35873,registry:Host@36043,registry:Host@36140,registry:Host@36255,registry:Host@36600,registry:Host@36697,registry:Host@36874,registry:Host@37032,registry:Host@37134,registry:Kind@21315,registry:Kind@21578,registry:Kind@27292,registry:Kind@27305,registry:Kind@27415,registry:Kind@27428,registry:Kind@28077,registry:Kind@28088,registry:Kind@35109,registry:Kind@36865,registry:Kind@37023,registry:Kind@37125,registry:Pool@35201,registry:Provisioned@20535,registry:Provisioned@21627,registry:Provisioned@35159,registry:Region@35190,registry:Replication@23695,registry:Replication@23822,registry:Seed@25794,registry:SeedSource@25299,registry:Socket@27340,registry:Socket@27355,registry:Socket@27652,registry:Socket@28136,registry:Socket@28149,registry:Unit@27258,registry:Unit@27271,registry:Unit@28103,registry:Unit@28114,whole:ClaimOwnership@21176,whole:ClaimOwnership@21193,whole:Route@14445,whole:Route@14456,whole:Route@14474,whole:Route@15574,whole:Route@15874,whole:Route@15881,whole:Route@15921,whole:Route@16282,whole:Route@16600,whole:Route@17461,whole:Route@17817,whole:Route@17826,whole:Route@17872,whole:Route@20180,whole:Route@20651,whole:Route@20661,whole:Route@21018,whole:Route@21025,whole:Route@21093,whole:Route@21416,whole:Route@22059,whole:Route@23382,whole:Route@27484,whole:Route@28963,whole:Route@29008,whole:Route@29018,whole:Route@29881,whole:Route@30633,whole:Route@34557,whole:Route@35226,whole:Route@36945 b93306e178252e56c67dd2ed58b87250e1b3756bddaa2589c3f7392d03300832
@legacy 96ccad12ba9ca42b8baf649552e8a9d63ad61439e00f1818c490df1e2d725804 internal/provision/reconcile.go holdExisting legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=the hold's record re-read reads the bucket (freshStore), never a record view snapshot; read sites unchanged, offsets moved registry:Account@640,registry:Account@795,registry:App@613,registry:App@781,registry:HoldOp@333,registry:HoldOp@371,registry:HoldOp@489,registry:Provisioned@589,registry:Status@1885,registry:Status@472 752df1628829a1effd249e58a5c52535e047c691affabc902c68f18f8fc8c28a
internal/provision/reconcile.go holdExisting legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=the hold's record re-read reads the bucket (freshStore), never a record view snapshot; read sites unchanged, offsets moved registry:Account@640,registry:Account@795,registry:App@613,registry:App@781,registry:HoldOp@333,registry:HoldOp@371,registry:HoldOp@489,registry:Provisioned@589,registry:Status@1885,registry:Status@472 752df1628829a1effd249e58a5c52535e047c691affabc902c68f18f8fc8c28a
-@legacy 3c23bfc0c57c80d04a2d114323c5f4b0a8459f5ae049c74de654160fe5c2ab51 internal/provision/sidecar_reconcile.go ReconcileSidecars legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=over a record view snapshot, a record-gone removal is confirmed in the bucket first (confirmSidecarGone) and a confirmation that cannot read cleanly keeps the row; one whole-Route site added, passing rt to it; a removal can only be withheld, never added registry:Account@10349,registry:Account@10588,registry:Account@11541,registry:Account@12291,registry:App@10322,registry:App@10574,registry:App@11514,registry:App@12277,registry:Args@11166,registry:Args@11437,registry:Channel@11154,registry:ClaimOwnership@10967,registry:Host@13167,registry:Host@13214,registry:Host@13337,registry:Host@13749,registry:Host@13898,registry:Host@14005,registry:Host@7943,registry:Kind@10263,registry:Kind@10537,registry:Kind@11454,registry:Kind@12240,registry:Kind@13000,registry:Pool@13118,registry:Provisioned@10295,registry:Provisioned@10552,registry:Provisioned@11486,registry:Provisioned@12255,registry:Provisioned@13027,registry:Region@13068,whole:ClaimOwnership@10970,whole:ClaimOwnership@10987,whole:Route@10812,whole:Route@10819,whole:Route@10887,whole:Route@11222,whole:Route@11599,whole:Route@12985,whole:Route@13514,whole:Route@13815,whole:Route@7925,whole:Route@7936,whole:Route@7954,whole:Route@8140,whole:Route@8509,whole:Route@8518,whole:Route@9951 da6e3c45950cb9ebb61d49a080fcb700a3a0bf373354269f503e52abe71cb72d
-internal/provision/sidecar_reconcile.go ReconcileSidecars legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=over a record view snapshot, a record-gone removal is confirmed in the bucket first (confirmSidecarGone) and a confirmation that cannot read cleanly keeps the row; one whole-Route site added, passing rt to it; a removal can only be withheld, never added registry:Account@10349,registry:Account@10588,registry:Account@11541,registry:Account@12291,registry:App@10322,registry:App@10574,registry:App@11514,registry:App@12277,registry:Args@11166,registry:Args@11437,registry:Channel@11154,registry:ClaimOwnership@10967,registry:Host@13167,registry:Host@13214,registry:Host@13337,registry:Host@13749,registry:Host@13898,registry:Host@14005,registry:Host@7943,registry:Kind@10263,registry:Kind@10537,registry:Kind@11454,registry:Kind@12240,registry:Kind@13000,registry:Pool@13118,registry:Provisioned@10295,registry:Provisioned@10552,registry:Provisioned@11486,registry:Provisioned@12255,registry:Provisioned@13027,registry:Region@13068,whole:ClaimOwnership@10970,whole:ClaimOwnership@10987,whole:Route@10812,whole:Route@10819,whole:Route@10887,whole:Route@11222,whole:Route@11599,whole:Route@12985,whole:Route@13514,whole:Route@13815,whole:Route@7925,whole:Route@7936,whole:Route@7954,whole:Route@8140,whole:Route@8509,whole:Route@8518,whole:Route@9951 da6e3c45950cb9ebb61d49a080fcb700a3a0bf373354269f503e52abe71cb72d
+@legacy 96cdfa7e1f0264c82646ee7f44d1a8147818a4a455e895fd00e6b6bd69ae51fa internal/provision/sidecar_reconcile.go ReconcileSidecars legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=the record walk and its sidecars manifest lookup move unchanged into the pass's scan closure (over a store argument) and the removal phase into its retire closure; over a record view snapshot, a pass that reaches a removal candidate (a sidecar gone or no longer placeable here) removes nothing on the snapshot's word: it runs scan again over the bucket (freshStore) and decides every removal that pass from that walk, by the walk's own rules (unusable records protected before scope, hosts matched across every key, placement from the bucket's record and sidecars manifest against this box's inbound); a walk that cannot read cleanly keeps every row; with no candidate, or disarmed, nothing is read again; the registry sites are main's, moved; relative to main's single walk a removal can only be withheld, never added registry:Account@11687,registry:Account@11926,registry:Account@12879,registry:Account@13629,registry:App@11660,registry:App@11912,registry:App@12852,registry:App@13615,registry:Args@12504,registry:Args@12775,registry:Channel@12492,registry:ClaimOwnership@12305,registry:Host@14965,registry:Host@15012,registry:Host@15135,registry:Host@15312,registry:Host@15461,registry:Host@15568,registry:Host@9281,registry:Kind@11601,registry:Kind@11875,registry:Kind@12792,registry:Kind@13578,registry:Kind@14798,registry:Pool@14916,registry:Provisioned@11633,registry:Provisioned@11890,registry:Provisioned@12824,registry:Provisioned@13593,registry:Provisioned@14825,registry:Region@14866,whole:ClaimOwnership@12308,whole:ClaimOwnership@12325,whole:Route@11289,whole:Route@12150,whole:Route@12157,whole:Route@12225,whole:Route@12560,whole:Route@12937,whole:Route@14783,whole:Route@15378,whole:Route@9263,whole:Route@9274,whole:Route@9292,whole:Route@9478,whole:Route@9847,whole:Route@9856 cc2aa4dbcb68f06f1190ad58a37c58e2608517e7388318b5b9e0b4bad0e8b5db
+internal/provision/sidecar_reconcile.go ReconcileSidecars legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=the record walk and its sidecars manifest lookup move unchanged into the pass's scan closure (over a store argument) and the removal phase into its retire closure; over a record view snapshot, a pass that reaches a removal candidate (a sidecar gone or no longer placeable here) removes nothing on the snapshot's word: it runs scan again over the bucket (freshStore) and decides every removal that pass from that walk, by the walk's own rules (unusable records protected before scope, hosts matched across every key, placement from the bucket's record and sidecars manifest against this box's inbound); a walk that cannot read cleanly keeps every row; with no candidate, or disarmed, nothing is read again; the registry sites are main's, moved; relative to main's single walk a removal can only be withheld, never added registry:Account@11687,registry:Account@11926,registry:Account@12879,registry:Account@13629,registry:App@11660,registry:App@11912,registry:App@12852,registry:App@13615,registry:Args@12504,registry:Args@12775,registry:Channel@12492,registry:ClaimOwnership@12305,registry:Host@14965,registry:Host@15012,registry:Host@15135,registry:Host@15312,registry:Host@15461,registry:Host@15568,registry:Host@9281,registry:Kind@11601,registry:Kind@11875,registry:Kind@12792,registry:Kind@13578,registry:Kind@14798,registry:Pool@14916,registry:Provisioned@11633,registry:Provisioned@11890,registry:Provisioned@12824,registry:Provisioned@13593,registry:Provisioned@14825,registry:Region@14866,whole:ClaimOwnership@12308,whole:ClaimOwnership@12325,whole:Route@11289,whole:Route@12150,whole:Route@12157,whole:Route@12225,whole:Route@12560,whole:Route@12937,whole:Route@14783,whole:Route@15378,whole:Route@9263,whole:Route@9274,whole:Route@9292,whole:Route@9478,whole:Route@9847,whole:Route@9856 cc2aa4dbcb68f06f1190ad58a37c58e2608517e7388318b5b9e0b4bad0e8b5db
@legacy 047df94a818a724f8f2a922d08335c594677e9604cdd637c396f7d3465b893a6 internal/telemetry/telemetry.go Resolve legacy accepted-legacy accepted-legacy;rev3=J4;basis=root-input;rev3=PROPOSED-s3-change-index;identity=unchanged (the console and the agent);basis=the fold over the defaults moved into Fold, which the agent's switch pass calls over cached settings; the same two telemetry.Read calls, offsets moved file:Read@167,file:Read@279 a8ebfdad89a2b5ca7d41883bfe62c5c7a4a0989cf44909a131026b95178890f2
internal/telemetry/telemetry.go Resolve legacy accepted-legacy accepted-legacy;rev3=J4;basis=root-input;rev3=PROPOSED-s3-change-index;identity=unchanged (the console and the agent);basis=the fold over the defaults moved into Fold, which the agent's switch pass calls over cached settings; the same two telemetry.Read calls, offsets moved file:Read@167,file:Read@279 a8ebfdad89a2b5ca7d41883bfe62c5c7a4a0989cf44909a131026b95178890f2
internal/host/activation_command_linux.go runSystemClaims authority G,J4 rev3=census-ruling-install-console-upgrade;identity=explicit operator CLI uid 0;basis=as census-ruling-claim-step6-artifacts-fix1; install-console also takes --upgrade --from <sha256>, which upgradeFlagsRefused (no read site) admits only together and only for install-console, refusing them elsewhere as unknown flags were; without --upgrade the install path and its output are unchanged;rev3=PROPOSED-s3-change-index;identity=explicit operator CLI uid 0;basis=opens the deployment store with NewDeploymentS3StoreIn in place of NewS3StoreIn, so its deployment-bucket writes bump control/changes.json after they succeed (the bump reads and rewrites only that object and decides nothing else); read site unchanged, offset moved file:Read@1771 7541f194a34f6e85b8176e5ebb7302d9f99582caa3e40bef034af0e1ba6180c8
@@ -34,21 +34,17 @@ internal/host/buildstate.go buildStates.refreshAll authority E3,J1,J4 root-route
internal/appconfig/syncexec.go syncOptions.kept legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as SyncExecWithCallbacks; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the scoped pass's route filter; a nil filter keeps every route, so it only ever narrows a pass whole:Route@84 c1fdeba96e3f8de8dd74bd1082bc704908de0352b9974229c235f662e8112bca
@legacy b55d739eb0dea7335f1ac74733f2e960f1b3d3bb210f318ed6cf9835e076a9bc internal/console/store.go Store.AppsWithActionSince legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; console SQL on its own audit table, a plain SELECT like Store.Events, as its store siblings (J4); the console (cmd/console serve under console.service, user carlos-console): the run sweep's orphan candidates file:Query@102 687ad5b1aa378b7bec6eae7eb6799dc02bd29431a3bb4dab00d5b8ee93a8382b
internal/console/store.go Store.AppsWithActionSince legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; console SQL on its own audit table, a plain SELECT like Store.Events, as its store siblings (J4); the console (cmd/console serve under console.service, user carlos-console): the run sweep's orphan candidates file:Query@102 687ad5b1aa378b7bec6eae7eb6799dc02bd29431a3bb4dab00d5b8ee93a8382b
-@legacy f28343c6b0a5ca31cc0d46e1bdd739cd85f0e1c15d45ec4152b17157ced81b0d internal/host/agent.go fastDeps.canaryPointerGate legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as fastTick; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the fast sweep's pointer gate skips a canary group's pointer read only while its app scope has not moved, its last good read is younger than the backstop, and every route of the group is live on that read's head (canarySettled); otherwise the pointer is read as before. Non-canary groups are never gated whole:Route@486 292b54654ad519079463fa62fd0b77fed4082ed451143a5315f804a6b4b0df92
-internal/host/agent.go fastDeps.canaryPointerGate legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as fastTick; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the fast sweep's pointer gate skips a canary group's pointer read only while its app scope has not moved, its last good read is younger than the backstop, and every route of the group is live on that read's head (canarySettled); otherwise the pointer is read as before. Non-canary groups are never gated whole:Route@486 292b54654ad519079463fa62fd0b77fed4082ed451143a5315f804a6b4b0df92
-@legacy 645f221929437d885441b81d21e99723934e93784dd32b99b95b86ed60aa3431 internal/host/agent.go fastDeps.canarySettled legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as fastTick; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): compares each route's live version (release.LiveVersion under the agent's opt dir) with the group's last good head; any doubt answers false and the pointer is read registry:Host@244,whole:Route@137,whole:Route@190 0755dca3a80d24fda9fbff0cc9dd46f981d82aa9a897e0e2da0a2bd606a83928
-internal/host/agent.go fastDeps.canarySettled legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as fastTick; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): compares each route's live version (release.LiveVersion under the agent's opt dir) with the group's last good head; any doubt answers false and the pointer is read registry:Host@244,whole:Route@137,whole:Route@190 0755dca3a80d24fda9fbff0cc9dd46f981d82aa9a897e0e2da0a2bd606a83928
+@legacy 922094bdd23498a803000cd5f18ad4da362bf0b2b2db6e041a48f42c68780c02 internal/host/agent.go fastDeps.canaryPointerGate legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as fastTick; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the fast sweep's pointer gate skips a canary group's pointer read only while its app scope has not moved since the group's own last good read (its head, the generation captured before it and its time, kept per account, app and channel), that read is younger than the gate's maximum age, and every route of the group is live on that read's head (canarySettled); otherwise the pointer is read as before. Non-canary groups are never gated whole:Route@486 341b7dbfc3846fbc00b65a78a457ba08d29d27bd4da363d712c4f504a686bd08
+internal/host/agent.go fastDeps.canaryPointerGate legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as fastTick; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the fast sweep's pointer gate skips a canary group's pointer read only while its app scope has not moved since the group's own last good read (its head, the generation captured before it and its time, kept per account, app and channel), that read is younger than the gate's maximum age, and every route of the group is live on that read's head (canarySettled); otherwise the pointer is read as before. Non-canary groups are never gated whole:Route@486 341b7dbfc3846fbc00b65a78a457ba08d29d27bd4da363d712c4f504a686bd08
+@legacy be4f50bf8ed1f25ea01a813ad7fd229cc19e9d4528fd9e0d0ae3c86aa4db1112 internal/host/agent.go fastDeps.canarySettled legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as fastTick; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): checks the group's own last good read against the generation the gate returned and the gate's maximum age (ReadGate.MaxAge), then compares each route's live version (release.LiveVersion under the agent's opt dir) with that read's head; any doubt answers false and the pointer is read registry:Host@328,whole:Route@163,whole:Route@274 feafad16a8ffce66c7d8db1014f7a60bf23a65c78d5f8786af6d878640c4d30c
+internal/host/agent.go fastDeps.canarySettled legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as fastTick; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): checks the group's own last good read against the generation the gate returned and the gate's maximum age (ReadGate.MaxAge), then compares each route's live version (release.LiveVersion under the agent's opt dir) with that read's head; any doubt answers false and the pointer is read registry:Host@328,whole:Route@163,whole:Route@274 feafad16a8ffce66c7d8db1014f7a60bf23a65c78d5f8786af6d878640c4d30c
internal/host/buildstate.go buildStates.refreshKept authority E3,J1,J4 root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=refreshAll's body, moved, with an optional route filter for the scoped pass; a filtered call reads only the hosts it keeps and never moves the rotation point; refreshAll's E3,J1,J4 authority carried over registry:Host@549,whole:Route@442,whole:Route@472,whole:Route@517 ae4f5c22ca45a5234ccf839949f57704a12e7998b40463a845c96b8ddc3e7665
@legacy 2b132b661a502799e3d1cc6441f558042e84152cdde7a7b3f56985e550e7ff07 internal/host/changeindex.go movedRoutes legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the scoped pass's route filter, keeping the routes whose app scope the change index says moved registry:App@297,whole:Route@292 3d4f7ef1ca7ebe9573f8f9b02d9bebcc4f8a8dac6762c4314e5f655575598624
internal/host/changeindex.go movedRoutes legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the scoped pass's route filter, keeping the routes whose app scope the change index says moved registry:App@297,whole:Route@292 3d4f7ef1ca7ebe9573f8f9b02d9bebcc4f8a8dac6762c4314e5f655575598624
@legacy cbe3829c5481a82e62de8f1a6c02f1491428c194ba7474465818232caf23aa15 internal/host/telemetry_pass.go telemetryReads.read legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; J4, as telemetry.Resolve; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the switch pass's read of one telemetry settings object (telemetry.Read), skipped while its scope has not moved and a last good value is held; a failed read keeps the last good value and marks the scope for a re-read file:Read@396 3fe9990dab690ff466226f7f65939ab82ba09ef31ddd5ab60f6ad3d8b64354f0
internal/host/telemetry_pass.go telemetryReads.read legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; J4, as telemetry.Resolve; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the switch pass's read of one telemetry settings object (telemetry.Read), skipped while its scope has not moved and a last good value is held; a failed read keeps the last good value and marks the scope for a re-read file:Read@396 3fe9990dab690ff466226f7f65939ab82ba09ef31ddd5ab60f6ad3d8b64354f0
-@legacy 99dc23ec49d8ed4f18d24e660b93e53a72dda9743fbcfc089eff922298880188 internal/host/telemetry_pass.go telemetrySwitchesWith legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as telemetrySwitches; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): telemetrySwitches' body, moved, reading through telemetryReads under its own mutex; a pair with no good value at either level is left off, the safe side of the switch registry:App@459,registry:App@547,registry:App@842,registry:Kind@436,whole:Route@422,whole:Route@521 447b8b5b67dee2c43268dc4176c9b3c5be9383f2c4cf5f19a739b0536553ff01
-internal/host/telemetry_pass.go telemetrySwitchesWith legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as telemetrySwitches; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): telemetrySwitches' body, moved, reading through telemetryReads under its own mutex; a pair with no good value at either level is left off, the safe side of the switch registry:App@459,registry:App@547,registry:App@842,registry:Kind@436,whole:Route@422,whole:Route@521 447b8b5b67dee2c43268dc4176c9b3c5be9383f2c4cf5f19a739b0536553ff01
-@legacy 694edc3d0bd428dd36e2f12b6d0044e94dc7ec1b293fd616893d908fd82d397f internal/provision/recordview_store.go confirmRecordGone legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as Reconcile; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): re-reads the instance record behind rt from the bucket (freshStore) only when Reconcile runs over a record view snapshot; it can only keep a row (absent or out of scope confirms the removal; present and in scope, or unreadable, keeps the row); over any other store it answers true without reading registry:Account@195,registry:App@207,registry:Host@215,registry:Host@428,registry:Host@646 3ba665dac788963a8387bede69c1e714b58c9fd80c96860460e21745d33a579a
-internal/provision/recordview_store.go confirmRecordGone legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as Reconcile; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): re-reads the instance record behind rt from the bucket (freshStore) only when Reconcile runs over a record view snapshot; it can only keep a row (absent or out of scope confirms the removal; present and in scope, or unreadable, keeps the row); over any other store it answers true without reading registry:Account@195,registry:App@207,registry:Host@215,registry:Host@428,registry:Host@646 3ba665dac788963a8387bede69c1e714b58c9fd80c96860460e21745d33a579a
-@legacy ea53a4122d022bb65b87451838a997e51a9f2f444ad3c06d7da5e2d3a1d5058e internal/provision/recordview_store.go confirmSidecarGone legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as ReconcileSidecars; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): confirmRecordGone for a sidecar row's record; it can only keep a row; over any other store it answers true without reading registry:Account@210,registry:App@222,registry:Host@451,registry:Host@498,registry:Host@700,registry:Slug@230 c86f50acb20c1f2b8058b708c035640fbd8ed511f05b6b2e0d00317baa2e907a
-internal/provision/recordview_store.go confirmSidecarGone legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as ReconcileSidecars; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): confirmRecordGone for a sidecar row's record; it can only keep a row; over any other store it answers true without reading registry:Account@210,registry:App@222,registry:Host@451,registry:Host@498,registry:Host@700,registry:Slug@230 c86f50acb20c1f2b8058b708c035640fbd8ed511f05b6b2e0d00317baa2e907a
+@legacy 99ce28f0e8f9754f4e33ed4b67c0edd4aaec3c7fe2c7be3cbf08f558c796da26 internal/host/telemetry_pass.go telemetrySwitchesWith legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as telemetrySwitches; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): with a change index armed, telemetrySwitches' body, moved, reading through telemetryReads under its own mutex; a pair with no good value at either level is left off, the safe side of the switch. With none armed (a nil watch) it hands the pass to telemetrySwitchesResolve, main's body, before reading anything registry:App@538,registry:App@626,registry:App@921,registry:Kind@515,whole:Route@501,whole:Route@600 8976b8a38f4c02a002b22336543be59169ac99fc0bf941bae5202517c7bc621a
+internal/host/telemetry_pass.go telemetrySwitchesWith legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-route; J1, as telemetrySwitches; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): with a change index armed, telemetrySwitches' body, moved, reading through telemetryReads under its own mutex; a pair with no good value at either level is left off, the safe side of the switch. With none armed (a nil watch) it hands the pass to telemetrySwitchesResolve, main's body, before reading anything registry:App@538,registry:App@626,registry:App@921,registry:Kind@515,whole:Route@501,whole:Route@600 8976b8a38f4c02a002b22336543be59169ac99fc0bf941bae5202517c7bc621a
@legacy a5465363888fad7a0da13831699aad0c7ed0df31228b7afcf3da62a3f9086f93 internal/provision/recordview_store.go snapStore.Open legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; J4, as the other store wrappers' Open; the agent and the console through the record view: forwards to the live store (release.OpenObject); the snapshot caches no bodies for Open file:Open@20 41ea2555c81b1091989cf1acd25b6ccf8c7081a6135f0a86e128b3c9fd775e1c
internal/provision/recordview_store.go snapStore.Open legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; J4, as the other store wrappers' Open; the agent and the console through the record view: forwards to the live store (release.OpenObject); the snapshot caches no bodies for Open file:Open@20 41ea2555c81b1091989cf1acd25b6ccf8c7081a6135f0a86e128b3c9fd775e1c
internal/release/adopt.go passConfig.gatePointers authority B3,E3,J1 root-route;kept=B3,E3;scope=protected-decision-only;rev3=PROPOSED-s3-change-index;identity=carlos adopt uid 0 (gate nil: returns adopts unchanged, reads nothing); the agent's fast sweep uid carlos (gate armed);basis=groups the routes adopts admits by (account, app, channel) and asks the gate once per group; it can only narrow adopts, never widen it; PassFilter's B3,E3,J1 authority registry:App@305,whole:Route@300,whole:Route@326,whole:Route@420,whole:Route@442,whole:Route@479,whole:Route@497,whole:Route@548,whole:Route@567,whole:Route@578,whole:Route@750,whole:Route@955,whole:Route@979 e9f5ff820fdf8522b3613b9c102c32d474391cf83761c6f5795629fadea02c31
@@ -63,6 +59,10 @@ internal/release/store.go DirStore.ListETags legacy accepted-legacy accepted-leg
@legacy c93045dc7bc00cc27518f23dba471a499989b910d0197bf2b3d99d94d12f916c internal/release/store.go S3Store.GetIfChanged legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; J4, as S3Store.Get; every process that opens a deployment store, as its siblings: S3Store.Get's read sent with If-None-Match, a 304 answering unchanged without the body file:ReadAll@511 959fea16d1332f47c2444ced07034544d733b4d831b7b0382517e100aa431dcc
internal/release/store.go S3Store.GetIfChanged legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; J4, as S3Store.Get; every process that opens a deployment store, as its siblings: S3Store.Get's read sent with If-None-Match, a 304 answering unchanged without the body file:ReadAll@511 959fea16d1332f47c2444ced07034544d733b4d831b7b0382517e100aa431dcc
# Four frozen units still declared now read nothing; each is retired by an H3 census-ruling removal, in the form email-signin used. A removal is not in the seal.
+@legacy 42299887c5c59955ac44f8d7af640818cc8e07963f084da46c734ff77b1ced66 internal/host/movespass.go movesDirHolds legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; J4, as movesWorker.sweepFinalJournals; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): lists <DataDir>/.moves and each directory directly beneath it, only to learn whether an op journal or a page outbox entry exists, in which case the moves pass walks the bucket as before the index; it opens, reads and changes nothing inside them, and an unreadable directory counts as holding something (the walk runs) file:ReadDir@136,file:ReadDir@322 31c55e433debcbc511f97b0eb723a87304f5839ffd9c73f68bcd6d58855bc817
+internal/host/movespass.go movesDirHolds legacy accepted-legacy accepted-legacy;rev3=PROPOSED-s3-change-index;basis=root-input; J4, as movesWorker.sweepFinalJournals; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): lists <DataDir>/.moves and each directory directly beneath it, only to learn whether an op journal or a page outbox entry exists, in which case the moves pass walks the bucket as before the index; it opens, reads and changes nothing inside them, and an unreadable directory counts as holding something (the walk runs) file:ReadDir@136,file:ReadDir@322 31c55e433debcbc511f97b0eb723a87304f5839ffd9c73f68bcd6d58855bc817
+@legacy 5516c964c4348ca37231ab08f3a87f36ef8e35d6bab6d9bf21f00d46bbe13949 internal/host/telemetry_pass.go telemetrySwitchesResolve legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=main's telemetrySwitches body, unchanged but for its name, with the same six sites at the same relative offsets (shifted by the longer name); runs only when no change index is armed, through telemetrySwitchesWith over a nil watch, so a disarmed box resolves each app on its own exactly as main registry:App@293,registry:App@381,registry:App@486,registry:Kind@270,whole:Route@256,whole:Route@355 cb6e294852b19939d12818472f125f639e6c7dab77a0aaac271735de6259476e
+internal/host/telemetry_pass.go telemetrySwitchesResolve legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=main's telemetrySwitches body, unchanged but for its name, with the same six sites at the same relative offsets (shifted by the longer name); runs only when no change index is armed, through telemetrySwitchesWith over a nil watch, so a disarmed box resolves each app on its own exactly as main registry:App@293,registry:App@381,registry:App@486,registry:Kind@270,whole:Route@256,whole:Route@355 cb6e294852b19939d12818472f125f639e6c7dab77a0aaac271735de6259476e
@remove internal/release/store.go DirStore.Put
@removed internal/release/store.go DirStore.Put H3 census-ruling-s3-change-index (PROPOSED, awaiting the census owner on #280): still declared, and reads nothing now: its body and its one site (file:Stat) moved unchanged into DirStore.putRaw, an accepted-legacy row in this overlay; Put calls it and, after a successful write, bumps the change index.
@remove internal/release/store.go DirStore.PutFrom
@@ -70,17 +70,17 @@ internal/release/store.go S3Store.GetIfChanged legacy accepted-legacy accepted-l
@remove internal/release/conditional_delete.go DirStore.DeleteIfMatch
@removed internal/release/conditional_delete.go DirStore.DeleteIfMatch H3 census-ruling-s3-change-index (PROPOSED, awaiting the census owner on #280): still declared, and reads nothing now: its body and its one site (file:ReadFile) moved unchanged into DirStore.deleteIfMatchRaw, an accepted-legacy row in this overlay; DeleteIfMatch calls it and, after a successful delete, bumps the change index.
@remove internal/host/telemetry_pass.go telemetrySwitches
-@removed internal/host/telemetry_pass.go telemetrySwitches H3 census-ruling-s3-change-index (PROPOSED, awaiting the census owner on #280): still declared, and reads nothing now: its body and its six sites moved into telemetrySwitchesWith, an accepted-legacy row in this overlay, which it calls with the process's telemetryReads and the time. It runs in the agent as carlos.
+@removed internal/host/telemetry_pass.go telemetrySwitches H3 census-ruling-s3-change-index (PROPOSED, awaiting the census owner on #280): still declared, and reads nothing: it calls telemetrySwitchesWith with the process's telemetryReads and the time, which runs main's body (telemetrySwitchesResolve, an accepted-legacy row in this overlay) when no change index is armed and the gated pass otherwise, both accepted-legacy rows in this overlay. It runs in the agent as carlos.
# Envelopes re-pinned: ., cmd/console, internal/appconfig, internal/console, internal/edge, internal/host, internal/hostops, internal/ops, internal/provision, internal/release, internal/telemetry, internal/vet. The scan's only read-site changes are the rows above.
@coverage . f181735991e3c549167c6845c3b280ca5554c5f598c66b02c08447b566e2135f
@coverage cmd/console 3f8cf7ac42db92a130af5bba06bdd34f5f53bd8728ee7ff7bf0a51d20a11a6ee
@coverage internal/appconfig ec91c8e0e6bc3599f021ff360e1549559bf61d80d60d8dd9ae9ef0c38bd5503c
@coverage internal/console b427d685dcf5ebcba922529f27ec85e358f73f9d539f53da1e9d627d187d1373
-@coverage internal/edge f9552de00786e2d31023a7bd4835a0eb86c754b295a2659c5c70c4ded00ba431
-@coverage internal/host 02bf9d577ced0f1f630cbd4618631e3c2811f996224287ecb944fb94ffb9e2c7
+@coverage internal/edge 1cc0801c03b5f087cdbcbab3c816afc95ec656846be58563294f8164b2e269d1
+@coverage internal/host 0c37473bcefc911f3c03f9e05fc8f7d1edd3748b9c2347a443018303654d93e9
@coverage internal/hostops fe58f0e6036bfccdf39ab6d9575addf11f94f87b17fd139964b4f5f22cb93be4
@coverage internal/ops afe4c144d6cd68e3fc46b2967767b605747300dead1259e81a484276b1b1088b
-@coverage internal/provision 1e213d9d9e698cecf266dfd855129dbadc1c1707fa47bf4b33fdc77919d72397
-@coverage internal/release 55ea0a4bb25f00c3b4494ae4cd6129d072c9311e81ddc908260192540008739a
+@coverage internal/provision 8d82529f3fb0628598e600c05581a90efef570924bf87044e988e60370dd49fa
+@coverage internal/release 17d277cdc333b1c67a2b6c5953f613001346505543f962069433e056b71e7800
@coverage internal/telemetry 4f3f802bac2db2136eeaaee607678f34a629e19d305f327f42f34594a6ff65f8
@coverage internal/vet 933738430ab95c59f0570e0d892f91c99c3de8cfcc6b2f7d8b1caaad21c1847d