carlos / platform Public

host: Establish proves and carries only the origins the live manifest references (Task 6b, Plan 15 review P2)

Establish proved every retained-chain candidate and every carried hint
and carried the whole set forward, so old hints stayed after their
objects were gone and the proof's cost grew with the history, squared
once claim Plan 15's per-origin walk is in.

movesFilesAllowed now proves the origins the live manifest's entries
actually reference, plus the one generation the admission opens (round
4's binding, one call); the retained chain's other generations are not
candidates and a carried hint no entry references is neither proven nor
carried. The next manifest's Origins is the proven set, which the
entries reference, plus its own prefix. Origins stays a hint and the
proof still goes only through movesOriginProof; every referenced origin
and the admitted generation are proven as before. One previously
refused shape now passes, as the ruling asks: a never-granted origin
carried as a hint that no entry references is dropped, not refused, and
does not survive into the next manifest (a never-granted origin an entry
references is refused as before).

Tests: an unreferenced, unprovable hint neither blocks the
establishment nor is carried forward; a referenced origin the proof
refuses still refuses the whole; a counting proof is asked exactly the
distinct referenced origins and the admitted generation, once each; the
pruned-ancestor and never-admitted tests follow the rule.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 7196746a6e6223fad952dd17bce12c41512404c8 parent d88b05f
2 files changed, +123 −50
  • internal/host/movesfiles.go +26 −24
  • internal/host/movesfiles_test.go +97 −26
diff --git a/internal/host/movesfiles.go b/internal/host/movesfiles.go
index d62d33396..a51557cce 100644
--- a/internal/host/movesfiles.go
+++ b/internal/host/movesfiles.go
@@ -398,7 +398,7 @@ func (f *movesFiles) newestManifest(ctx context.Context, o hostclaim.Observed, i
if !found {
return hostfiles.Manifest{}, nil, false, fmt.Errorf("host: the files manifest %s@%s is not readable", key, version)
}
- allowed, err := f.movesFilesAllowed(ctx, o, in, location, append(append([]string(nil), chain...), in.NewGeneration), m)
+ allowed, err := f.movesFilesAllowed(ctx, o, in, location, in.NewGeneration, m)
if err != nil {
return hostfiles.Manifest{}, nil, false, fmt.Errorf("host: the files manifest %s@%s: %w", key, version, err)
}
@@ -469,32 +469,34 @@ func (f *movesFiles) proveOrigin(ctx context.Context, o hostclaim.Observed, in h
}
// movesFilesAllowed is the origin set an admission allows for m, the
-// manifest it establishes from: the candidate generations (the admitted
-// chain, and the generation this admission opens or the prepared one),
-// every origin m's entries name, and every origin m carries
-// (Manifest.Origins, a hint and nothing more), each proven against the
-// claim's records through proveOrigin, the chain's generations included,
-// after the location rule (movesFilesOrigins). A generation or origin the
-// proof cannot prove is ErrOrigin, whatever its name and whether an entry
-// uses it: a manifest that adds a never-granted origin to its own set is
-// refused, and so is a chain the proof no longer vouches for. Then
-// ValidateManifest over the proven set, which is the new manifest's set
-// (SetOrigins).
-func (f *movesFiles) movesFilesAllowed(ctx context.Context, o hostclaim.Observed, in hostclaim.Admission, location string, candidates []string, m hostfiles.Manifest) ([]string, error) {
+// manifest it establishes from (Task 6b, the moves side of claim Plan 15's
+// review): the origins m's entries actually reference, each proven against
+// the claim's records through proveOrigin after the location rule
+// (movesFilesOrigins), plus the one generation this admission opens
+// (admitted: proven through the same route, round 4's binding, one call).
+// Nothing else is proven and nothing else is carried: the retained chain's
+// other generations are not candidates, and a carried hint
+// (Manifest.Origins) that no entry references is neither proven nor
+// carried forward, so the proof's cost follows the live references, not
+// the history. A referenced origin the proof cannot prove is ErrOrigin.
+// Then ValidateManifest over the proven set, which is the new manifest's
+// carried set (SetOrigins). Nothing refused before is accepted now: every
+// referenced origin and the admitted generation go through the proof as
+// before; only unreferenced hints and unreferenced chain generations, which
+// no entry depends on, are no longer asked about.
+func (f *movesFiles) movesFilesAllowed(ctx context.Context, o hostclaim.Observed, in hostclaim.Admission, location, admitted string, m hostfiles.Manifest) ([]string, error) {
set := map[string]bool{}
- for _, g := range candidates {
- origin, err := f.proveOrigin(ctx, o, in, location, g)
- if err != nil {
- return nil, err
- }
- set[origin] = true
+ own, err := f.proveOrigin(ctx, o, in, location, admitted)
+ if err != nil {
+ return nil, err
}
+ set[own] = true
named, err := movesFilesOrigins(location, "", m)
if err != nil {
return nil, err
}
base := strings.TrimSuffix(location, "/") + "/files/g-"
- for _, origin := range append(append([]string(nil), named...), m.Origins...) {
+ for _, origin := range named {
if set[origin] {
continue
}
@@ -601,13 +603,13 @@ func (f *movesFiles) openPrepared(ctx context.Context, files release.Store, o ho
if err != nil || !found {
return nil, fmt.Errorf("host: the prepared files manifest %s@%s: %v", key, pm.Version, err)
}
- // The prepared manifest's allowed set: what it carries (its own prefix,
- // seeded by the build; an old one carries none) plus the admitted
- // chain, plus P itself.
+ // The prepared manifest's allowed set: the origins its entries
+ // reference, proven, plus P itself (its carried set, seeded by the
+ // build with its own prefix, is a hint only; an old one carries none).
if len(prepared.Origins) == 0 {
prepared.Origins = []string{prefix}
}
- allowed, err := f.movesFilesAllowed(ctx, o, in, h.Location, append(movesFilesChain(h, f.HomeRegion, f.Region), gen), prepared)
+ allowed, err := f.movesFilesAllowed(ctx, o, in, h.Location, gen, prepared)
if err != nil {
return nil, fmt.Errorf("host: the prepared files manifest %s@%s: %w", key, pm.Version, err)
}
diff --git a/internal/host/movesfiles_test.go b/internal/host/movesfiles_test.go
index cf8e51ce6..f86dccdac 100644
--- a/internal/host/movesfiles_test.go
+++ b/internal/host/movesfiles_test.go
@@ -557,17 +557,14 @@ func TestEstablishKeepsOriginsPastAdmissionPruning(t *testing.T) {
if !found || m.Entries["a.txt"].Object != movesFilesPrefix(filesLoc, "g1")+"objects/0000000000000001-"+sha([]byte("A")) {
t.Fatalf("g11: %+v %v", m, found)
}
- // The carried set (fix round 2, finding 3): the previous manifest's
- // set, the then-admitted chain and the new generation, so the pruned
- // ancestor stays proven by it.
- want := []string{}
- for _, g := range append(gens, "g11") {
- want = append(want, movesFilesPrefix(filesLoc, g))
- }
- sort.Strings(want)
+ // The carried set (fix round 2, finding 3; Task 6b): only what the
+ // entries reference, g1, plus the new generation. The hints for the
+ // generations between, which nothing references, are dropped.
+ want := []string{movesFilesPrefix(filesLoc, "g1"), movesFilesPrefix(filesLoc, "g11")}
if !reflect.DeepEqual(m.Origins, want) {
t.Fatalf("g11 origins %v, want %v", m.Origins, want)
}
+ _ = gens
// Under the location but not a generation's files prefix: refused.
for name, object := range map[string]string{
"another location": "instances/other/files/g-g1/objects/0000000000000001-" + sha([]byte("A")),
@@ -853,26 +850,22 @@ func TestEstablishRefusesANeverAdmittedOrigin(t *testing.T) {
}
}
// Origins vouch for nothing by themselves (platform-1e's ruling): a
- // manifest that adds the never-granted origin to its own carried set,
- // with the object named or not, is refused, and so is a carried set
- // naming a never-granted origin with no entry under it.
- for name, entries := range map[string]map[string]hostfiles.Entry{
- "named and carried": {"a.txt": g1.Entries["a.txt"], "n.txt": {Object: never, SHA256: sha([]byte("N")), Size: 1, Seq: 1}},
- "carried only": {"a.txt": g1.Entries["a.txt"]},
- } {
- bad := g1
- bad.Entries = entries
- bad.Origins = []string{movesFilesPrefix(filesLoc, "g1"), movesFilesPrefix(filesLoc, "never")}
- x.bucket.Put("data", hostfiles.ManifestKey(movesFilesPrefix(filesLoc, "g1")), mustJSON(t, bad))
- if err := x.f.Establish(ctx, o, launchInputs("g2"), x); !errors.Is(err, hostfiles.ErrOrigin) {
- t.Fatalf("%s: %v", name, err)
- }
- if _, found := x.manifest("g2"); found {
- t.Fatalf("%s: a manifest was written over a self-vouched origin", name)
- }
+ // manifest that adds the never-granted origin to its own carried set
+ // and names an object under it is refused. A carried hint that no entry
+ // references is neither proven nor carried (Task 6b): the
+ // establishment goes through and the hint does not survive it.
+ bad := g1
+ bad.Entries = map[string]hostfiles.Entry{"a.txt": g1.Entries["a.txt"], "n.txt": {Object: never, SHA256: sha([]byte("N")), Size: 1, Seq: 1}}
+ bad.Origins = []string{movesFilesPrefix(filesLoc, "g1"), movesFilesPrefix(filesLoc, "never")}
+ x.bucket.Put("data", hostfiles.ManifestKey(movesFilesPrefix(filesLoc, "g1")), mustJSON(t, bad))
+ if err := x.f.Establish(ctx, o, launchInputs("g2"), x); !errors.Is(err, hostfiles.ErrOrigin) {
+ t.Fatalf("named and carried: %v", err)
+ }
+ if _, found := x.manifest("g2"); found {
+ t.Fatal("a manifest was written over a self-vouched origin")
}
// The genuine manifest establishes, and the new set is exactly the
- // chain and the new generation.
+ // referenced origin and the new generation.
x.bucket.Put("data", hostfiles.ManifestKey(movesFilesPrefix(filesLoc, "g1")), mustJSON(t, g1))
if err := x.f.Establish(ctx, o, launchInputs("g2"), x); err != nil {
t.Fatal(err)
@@ -881,6 +874,20 @@ func TestEstablishRefusesANeverAdmittedOrigin(t *testing.T) {
if want := []string{movesFilesPrefix(filesLoc, "g1"), movesFilesPrefix(filesLoc, "g2")}; !reflect.DeepEqual(m.Origins, want) {
t.Fatalf("g2 origins %v, want %v", m.Origins, want)
}
+ // A carried hint that no entry references (planted at g2, the newest
+ // the chain from g3 reads): the establishment goes through and the
+ // hint does not survive it.
+ hint := m
+ hint.Origins = []string{movesFilesPrefix(filesLoc, "g1"), movesFilesPrefix(filesLoc, "g2"), movesFilesPrefix(filesLoc, "never")}
+ x.bucket.Put("data", hostfiles.ManifestKey(movesFilesPrefix(filesLoc, "g2")), mustJSON(t, hint))
+ o3 := servingObserved("g3", "g1:uk:@root:uk", "g2:uk:g1:uk", "g3:uk:g2:uk")
+ if err := x.f.Establish(ctx, o3, launchInputs("g3"), x); err != nil {
+ t.Fatalf("carried only: %v", err)
+ }
+ m3, _ := x.manifest("g3")
+ if want := []string{movesFilesPrefix(filesLoc, "g1"), movesFilesPrefix(filesLoc, "g2"), movesFilesPrefix(filesLoc, "g3")}; !reflect.DeepEqual(m3.Origins, want) {
+ t.Fatalf("g3 origins %v, want %v (the env object under g2 is referenced; the hint is not)", m3.Origins, want)
+ }
}
// A legacy adopted location, with no incarnation component, gets the same
@@ -1060,6 +1067,70 @@ func TestChainProofRefusesAFreeStandingGeneration(t *testing.T) {
}
}
+// countingProof records every generation it is asked about, in order,
+// answering from proven.
+type countingProof struct {
+ proven map[string]bool
+ asked []string
+}
+
+func (c *countingProof) Proven(_ context.Context, _ hostclaim.Observed, _ hostclaim.Admission, generation string) (bool, error) {
+ c.asked = append(c.asked, generation)
+ return c.proven[generation], nil
+}
+
+// Only referenced origins are proven and carried (Task 6b, the moves side
+// of claim Plan 15's review): the origins the live manifest's entries
+// name, plus the one generation the admission opens (round 4's binding,
+// one call). A carried hint nothing references is neither proven nor
+// carried forward, so old hints do not accumulate and the proof's cost
+// does not grow with the history; a referenced origin is still proven and
+// refused when the proof says no; and the count of Proven calls is the
+// distinct referenced origins plus the admitted generation, each asked
+// once.
+func TestEstablishProvesAndCarriesOnlyReferencedOrigins(t *testing.T) {
+ x := newFilesFixture(t)
+ ctx := context.Background()
+ x.writeEnv("K=1\n")
+ // g5's object, referenced by the live manifest at g1 through a carried
+ // entry; g7 is a hint nothing references and nothing can prove.
+ g5obj := movesFilesPrefix(filesLoc, "g5") + "objects/0000000000000001-" + sha([]byte("F"))
+ x.bucket.Put("data", g5obj, []byte("F"))
+ live := x.publish("g1", func(p *hostfiles.Publisher) {
+ if err := p.Stage(ctx, "a.txt", []byte("A"), 0o600, false); err != nil {
+ t.Fatal(err)
+ }
+ })
+ live.Entries["f.txt"] = hostfiles.Entry{Object: g5obj, SHA256: sha([]byte("F")), Size: 1, Seq: 1}
+ live.Origins = []string{movesFilesPrefix(filesLoc, "g1"), movesFilesPrefix(filesLoc, "g5"), movesFilesPrefix(filesLoc, "g7")}
+ x.bucket.Put("data", hostfiles.ManifestKey(movesFilesPrefix(filesLoc, "g1")), mustJSON(t, live))
+ o := servingObserved("g2", "g1:uk:@root:uk", "g2:uk:g1:uk")
+ // The hint g7 is not proven: the establishment still goes through, and
+ // g7 is not carried; g1, g5 and the admitted g2 are, each asked once.
+ proof := &countingProof{proven: map[string]bool{"g1": true, "g2": true, "g5": true}}
+ x.f.Proof = proof
+ if err := x.f.Establish(ctx, o, launchInputs("g2"), x); err != nil {
+ t.Fatalf("an unreferenced hint blocked the establishment: %v", err)
+ }
+ m, found := x.manifest("g2")
+ want := []string{movesFilesPrefix(filesLoc, "g1"), movesFilesPrefix(filesLoc, "g2"), movesFilesPrefix(filesLoc, "g5")}
+ if !found || !reflect.DeepEqual(m.Origins, want) {
+ t.Fatalf("g2 origins %v, want %v", m.Origins, want)
+ }
+ sort.Strings(proof.asked)
+ if !reflect.DeepEqual(proof.asked, []string{"g1", "g2", "g5"}) {
+ t.Fatalf("Proven asked %v, want each referenced origin and the admitted generation once", proof.asked)
+ }
+ // A referenced origin the proof refuses still refuses the whole.
+ x.f.Proof = &countingProof{proven: map[string]bool{"g1": true, "g2": true, "g3": true}}
+ if err := x.f.Establish(ctx, servingObserved("g3", "g1:uk:@root:uk", "g2:uk:g1:uk", "g3:uk:g2:uk"), launchInputs("g3"), x); !errors.Is(err, hostfiles.ErrOrigin) {
+ t.Fatalf("a referenced origin the proof refuses: %v", err)
+ }
+ if _, found := x.manifest("g3"); found {
+ t.Fatal("a manifest was written over a refused referenced origin")
+ }
+}
+
// The instance key rule (O1'): the manifest Establish leaves carries the
// env file with exactly the bytes on disk when it runs, staged and
// committed before it returns, and no adoption item; the local adoption