WIP checkpoint (not for merge): files seed checkpoint 7
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5 files changed,
+557
−17
internal/host/claimfilesseed_restore_linux_test.go+522 −0internal/host/claimservinglegacyroot_linux_test.go+28 −11internal/host/claimservingpark_linux_test.go+1 −1internal/host/claimwakestop.go+3 −3internal/provision/testdata/plan14-root-reads-seed.tsv+3 −2
CI passed — run details
CI log
=== gate ===
cd launchctx && go vet ./... && go test ./... -count=1
ok amadan.net/carlos/platform.git/launchctx 0.011s
? amadan.net/carlos/platform.git/launchctx/controlname [no test files]
? amadan.net/carlos/platform.git/launchctx/wireid [no test files]
go vet ./...
gofmt -l .: clean
go test ./... -count=1 -timeout 30m
ok github.com/carlosframework/platform 356.734s
? github.com/carlosframework/platform/cmd/changelog [no test files]
ok github.com/carlosframework/platform/cmd/console 3.057s
ok github.com/carlosframework/platform/cmd/moveprobe 92.230s
ok github.com/carlosframework/platform/cmd/zddprobe 0.705s
ok github.com/carlosframework/platform/internal/activator 234.953s
ok github.com/carlosframework/platform/internal/agentsock 0.018s
ok github.com/carlosframework/platform/internal/alerting 0.006s
ok github.com/carlosframework/platform/internal/analytics 0.020s
ok github.com/carlosframework/platform/internal/appconfig 2.333s
ok github.com/carlosframework/platform/internal/apperr 0.078s
ok github.com/carlosframework/platform/internal/applog 0.130s
ok github.com/carlosframework/platform/internal/awsinv 0.004s
ok github.com/carlosframework/platform/internal/boxchoice 0.004s
ok github.com/carlosframework/platform/internal/boxid 0.848s
? github.com/carlosframework/platform/internal/boxid/boxidtest [no test files]
? github.com/carlosframework/platform/internal/boxid/internal/signtest [no test files]
ok github.com/carlosframework/platform/internal/boxvolumes 0.009s
ok github.com/carlosframework/platform/internal/caps 0.012s
ok github.com/carlosframework/platform/internal/certwarm 0.003s
ok github.com/carlosframework/platform/internal/cgroup 0.704s
ok github.com/carlosframework/platform/internal/changelog 0.306s
ok github.com/carlosframework/platform/internal/clamd 0.054s
? github.com/carlosframework/platform/internal/cliflag [no test files]
ok github.com/carlosframework/platform/internal/console 366.593s
? github.com/carlosframework/platform/internal/controlname [no test files]
? github.com/carlosframework/platform/internal/controlsock [no test files]
ok github.com/carlosframework/platform/internal/dbdoor 6.030s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.015s
ok github.com/carlosframework/platform/internal/dbverify 0.006s
ok github.com/carlosframework/platform/internal/dnsrec 0.003s
ok github.com/carlosframework/platform/internal/docsite 0.006s
ok github.com/carlosframework/platform/internal/domains 2.142s
ok github.com/carlosframework/platform/internal/doorkey 0.007s
ok github.com/carlosframework/platform/internal/economics 0.009s
ok github.com/carlosframework/platform/internal/edge 26.302s
? github.com/carlosframework/platform/internal/edgeproof [no test files]
ok github.com/carlosframework/platform/internal/edgesfile 0.010s
ok github.com/carlosframework/platform/internal/fleetapi 0.127s
ok github.com/carlosframework/platform/internal/gate 1.671s
ok github.com/carlosframework/platform/internal/genselect 0.020s
ok github.com/carlosframework/platform/internal/geo 0.016s
ok github.com/carlosframework/platform/internal/geoip 0.037s
ok github.com/carlosframework/platform/internal/host 137.863s
ok github.com/carlosframework/platform/internal/hostactors 0.391s
ok github.com/carlosframework/platform/internal/hostbox 2.193s
ok github.com/carlosframework/platform/internal/hostclaim 0.527s
ok github.com/carlosframework/platform/internal/hostevidence 0.015s
ok github.com/carlosframework/platform/internal/hostexec 4.862s
ok github.com/carlosframework/platform/internal/hostfence 0.033s
ok github.com/carlosframework/platform/internal/hostfiles 10.497s
ok github.com/carlosframework/platform/internal/hostfloor 0.015s
ok github.com/carlosframework/platform/internal/hostguard 0.978s
ok github.com/carlosframework/platform/internal/hostops 1.460s
? github.com/carlosframework/platform/internal/hostops/fencerelease [no test files]
ok github.com/carlosframework/platform/internal/hostops/internal/fencerelease 0.015s
ok github.com/carlosframework/platform/internal/hostquarantine 0.015s
ok github.com/carlosframework/platform/internal/hostrelocate 0.450s
ok github.com/carlosframework/platform/internal/hostresolve 0.139s
ok github.com/carlosframework/platform/internal/hostwrite 0.015s
ok github.com/carlosframework/platform/internal/infraview 0.015s
ok github.com/carlosframework/platform/internal/instancectl 1.817s
ok github.com/carlosframework/platform/internal/instanceexec 2.710s
ok github.com/carlosframework/platform/internal/instancefs 0.019s
ok github.com/carlosframework/platform/internal/instancekey 0.016s
ok github.com/carlosframework/platform/internal/instanceupdates 0.021s
ok github.com/carlosframework/platform/internal/layout 1.445s
ok github.com/carlosframework/platform/internal/lease 9.439s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.006s
ok github.com/carlosframework/platform/internal/ledger 0.015s
ok github.com/carlosframework/platform/internal/mail 0.181s
ok github.com/carlosframework/platform/internal/maintenance 0.080s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.540s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.085s
ok github.com/carlosframework/platform/internal/metrics 0.006s
ok github.com/carlosframework/platform/internal/moves 21.029s
ok github.com/carlosframework/platform/internal/moves/archive 0.783s
ok github.com/carlosframework/platform/internal/objstore 0.171s
ok github.com/carlosframework/platform/internal/ops 0.175s
ok github.com/carlosframework/platform/internal/park 0.209s
ok github.com/carlosframework/platform/internal/privatefile 0.004s
ok github.com/carlosframework/platform/internal/provision 11.786s
ok github.com/carlosframework/platform/internal/publicrelease 0.006s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 4.031s
ok github.com/carlosframework/platform/internal/relay 7.231s
ok github.com/carlosframework/platform/internal/release 20.116s
ok github.com/carlosframework/platform/internal/rollout 3.652s
ok github.com/carlosframework/platform/internal/rolloutwords 0.004s
ok github.com/carlosframework/platform/internal/rootaws 0.007s
ok github.com/carlosframework/platform/internal/rootparticipation 0.007s
ok github.com/carlosframework/platform/internal/rootstate 0.025s
ok github.com/carlosframework/platform/internal/s3compat 0.005s
ok github.com/carlosframework/platform/internal/safefile 0.004s
ok github.com/carlosframework/platform/internal/schedule 2.289s
ok github.com/carlosframework/platform/internal/sim/hostlife 9.262s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 4.154s
ok github.com/carlosframework/platform/internal/status 0.041s
ok github.com/carlosframework/platform/internal/steering 0.006s
ok github.com/carlosframework/platform/internal/stopevidence 0.349s
ok github.com/carlosframework/platform/internal/svcrole 0.002s
ok github.com/carlosframework/platform/internal/telemetry 0.004s
ok github.com/carlosframework/platform/internal/termfence 0.004s
ok github.com/carlosframework/platform/internal/tunnelclient 0.004s
ok github.com/carlosframework/platform/internal/unixdial 0.003s
ok github.com/carlosframework/platform/internal/updatewords 0.004s
ok github.com/carlosframework/platform/internal/usage 0.004s
ok github.com/carlosframework/platform/internal/version 0.002s
ok github.com/carlosframework/platform/internal/vet 1.588s
=== cross ===
--- shard 0 of 5 ---
cross-compiling darwin/arm64
--- shard 1 of 5 ---
cross-compiling darwin/amd64
--- shard 2 of 5 ---
cross-compiling linux/arm64
--- shard 3 of 5 ---
cross-compiling windows/amd64
--- shard 4 of 5 ---
cross-compiling windows/arm64
=== minio-contract ===
minio contract: arm64, minio RELEASE.2025-09-07T16-13-09Z, mc RELEASE.2025-08-13T08-35-41Z
minio: cached, digest verified
mc: cached, digest verified
minio healthy on 127.0.0.1:20999
Added `local` successfully.
Bucket created successfully `local/contract-bucket`.
Bucket created successfully `local/denied-bucket`.
Created policy `contract-only` successfully.
Added user `scopeduser` successfully.
Attached Policies: [contract-only]
To User: scopeduser
buckets and scoped user ready
=== RUN TestDeliveredContractMinio
=== RUN TestDeliveredContractMinio/put
=== RUN TestDeliveredContractMinio/get_round-trips_the_body
=== RUN TestDeliveredContractMinio/list_shows_the_key
=== RUN TestDeliveredContractMinio/head_and_list_agree_on_the_version
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_its_own_object
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed
=== RUN TestDeliveredContractMinio/delete_removes_it
=== RUN TestDeliveredContractMinio/cross-bucket_denial
--- PASS: TestDeliveredContractMinio (0.02s)
--- PASS: TestDeliveredContractMinio/put (0.00s)
--- PASS: TestDeliveredContractMinio/get_round-trips_the_body (0.00s)
--- PASS: TestDeliveredContractMinio/list_shows_the_key (0.00s)
--- PASS: TestDeliveredContractMinio/head_and_list_agree_on_the_version (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route (0.01s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/delete_removes_it (0.00s)
--- PASS: TestDeliveredContractMinio/cross-bucket_denial (0.00s)
PASS
ok github.com/carlosframework/platform/internal/objstore 0.024s
=== RUN TestT4StorageProbeMinio
2026/10/14 13:23:35 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18DE68263A9D5D4F, HostID: 7c420053e0fbcd7f41653fdd92ffa2802c903d05303b1aa15adc2e8bb65d183f, api error SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
--- PASS: TestT4StorageProbeMinio (0.01s)
PASS
ok github.com/carlosframework/platform/internal/host 0.024s
minio contract: PASS
diff --git a/internal/host/claimfilesseed_restore_linux_test.go b/internal/host/claimfilesseed_restore_linux_test.go| new file mode 100644 |
| index 000000000..b28b7d688 |
| --- /dev/null |
| +++ b/internal/host/claimfilesseed_restore_linux_test.go |
| @@ -0,0 +1,522 @@ |
| +//go:build linux |
| + |
| +package host |
| + |
| +import ( |
| + "bytes" |
| + "context" |
| + "errors" |
| + "net/http/httptest" |
| + "os" |
| + "path/filepath" |
| + "reflect" |
| + "strings" |
| + "syscall" |
| + "testing" |
| + "time" |
| + |
| + "github.com/carlosframework/platform/internal/activator" |
| + "github.com/carlosframework/platform/internal/cgroup" |
| + "github.com/carlosframework/platform/internal/genselect" |
| + "github.com/carlosframework/platform/internal/hostbox" |
| + "github.com/carlosframework/platform/internal/hostclaim" |
| + "github.com/carlosframework/platform/internal/hostwrite" |
| + "github.com/carlosframework/platform/internal/lease" |
| + "github.com/carlosframework/platform/internal/lease/leasetest" |
| + "github.com/carlosframework/platform/internal/provision" |
| + "github.com/carlosframework/platform/internal/registry" |
| + "github.com/superfly/ltx" |
| + "golang.org/x/sys/unix" |
| +) |
| + |
| +// This fixture ends at Restore: a legacy holder has no C8 evidence yet. |
| +// It uses the real selector, lease against local S3, retry wrapper, admission, |
| +// activation, prelaunch journal, selected Work, stop coordinator and retirement |
| +// transport. Kernel checks, installation enrollment and launch preflight are |
| +// explicit seams; it does not claim an installed-unit or privileged witness. |
| +type servingPreparation struct { |
| + f *servingRootFixture |
| + owners *claimServingOwners |
| + wake *ClaimWakeAssembly |
| + runtime *activator.ClaimRuntime |
| + local claimStopLocal |
| + events []string |
| + baseline *genselect.Plan |
| + enrollFailure error |
| + afterEnroll func() |
| +} |
| + |
| +func newServingPreparation(t *testing.T, f *servingRootFixture, boot, controller string) *servingPreparation { |
| + t.Helper() |
| + p := &servingPreparation{f: f, local: claimStopLocal{Actor: f.actor, BootID: boot, ControllerID: controller, PID: 77, ProcessStart: controller + "-start"}} |
| + f.f.peer = StopPeer{UID: 1001, PID: p.local.PID, ProcessStart: p.local.ProcessStart, BootID: boot, ControllerID: controller} |
| + launchFixture := plan9D5Fixture(t) |
| + launchFixture.launch.Args = []string{"--socket", provision.NestedSocket(recoveryHost), "--db", f.db} |
| + launchFixture.launch.Limit = cgroup.TierDefault |
| + launchFixture.launch.Env = []string{"CARLOS_ADMIN_TOKEN=test"} |
| + sources := launchFixture.owners.Sources |
| + p.owners = &claimServingOwners{Data: f.f.data, Bucket: f.f.bucket, Region: f.actor.Region, Box: f.actor.Box, Sources: sources, Now: func() time.Time { return f.f.now }, NewID: f.f.newID} |
| + producers := &ClaimProducerSet{} |
| + w := &ClaimWakeAssembly{LeaseRegion: "eu-west-1", Manager: new(cgroup.Manager), Inputs: p.owners, RequireServingEnrollment: true} |
| + p.wake = w |
| + w.AfterAdmission = func(ctx context.Context, _, admitted hostclaim.Observed) error { |
| + p.events = append(p.events, "admit") |
| + // The production root installation door requires privileged host inventory. |
| + // Retain that explicit seam, but do not advance it before admission. |
| + f.install(admitted) |
| + return nil |
| + } |
| + w.Prelaunch = func(ctx context.Context, o hostclaim.Observed, work hostwrite.Work, in ClaimLaunchInputs) (*activator.RoleLaunch, error) { |
| + p.events = append(p.events, "prelaunch") |
| + target := recoveryTuple(o, p.local) |
| + err := work.With(ctx, in.Identity, func() error { |
| + return f.f.journal.Prelaunch(ctx, hostbox.LaunchInventory{Target: target, ControllerPID: p.local.PID, ProcessStart: p.local.ProcessStart, NoState: true, Groups: []hostbox.LaunchGroup{{RelativePath: "carlos/" + claimContainmentName(target), Device: 1, Inode: target.Session}}}) |
| + }) |
| + return &activator.RoleLaunch{Target: target, Journal: f.f.journal}, err |
| + } |
| + roles := &ClaimRoleAssembly{Inventory: f.p.root.Journals.Inventory, ManagedRoots: map[string]string{"data": f.f.guard.DataDir}, Identity: handoverRecoveryIdentity(t, f.actor)} |
| + w.Roles = roles |
| + roles.Root = fakeLaunchRoot{protocol: hostbox.RoleLaunchProtocol} |
| + w.PrepareState = func(ctx context.Context, o hostclaim.Observed, work hostwrite.Work, in ClaimLaunchInputs) error { |
| + p.events = append(p.events, "state") |
| + return roles.PrepareState(ctx, o, work, in) |
| + } |
| + w.Launch = func(context.Context, hostclaim.Observed, hostwrite.Work, ClaimLaunchInputs, *activator.RoleLaunch) (*activator.RoleLaunch, error) { |
| + t.Fatal("tenant launch in restore witness") |
| + return nil, hostbox.ErrUnsupported |
| + } |
| + w.Producers = func(_ context.Context, o hostclaim.Observed) (*ClaimProducers, error) { |
| + return producers.Ensure(recoveryTuple(o, p.local), p.local.ProcessStart, f.f.journal.RecordProducer) |
| + } |
| + w.Retain = func(hostclaim.Observed, activator.Proc, activator.Rep, error) {} |
| + w.ObserveLoss = func(hostclaim.Observed, error) {} |
| + w.Retries = activator.ServingRetries{Claims: f.f.claims, Box: f.actor.Box, Enrollment: f.actor.Enrollment, BootID: boot, ControllerID: controller, Now: func() time.Time { return f.f.now }, NewID: f.f.newID, Inputs: p.owners.launchDigest} |
| + a := ClaimAssembly{Claims: f.f.claims, Launches: f.f.journal, Wake: w, Producers: producers, stopLocal: func(context.Context) (claimStopLocal, error) { return p.local, nil }} |
| + a.collectStop = func(ctx context.Context, req StopRequest, drain StopDrainer) (StopResult, error) { |
| + f.f.requests = append(f.f.requests, req) |
| + coordinator := f.p.root.Stop.Coordinator |
| + coordinator.Drainer = drain |
| + coordinator.RetainNoProcess = f.p.retainLegacyNoProcess |
| + if req.WriterSession != 0 { |
| + coordinator.Kernel = f.f.kernel |
| + } |
| + result, err := coordinator.FenceAndStop(ctx, req) |
| + if err != nil { |
| + return result, err |
| + } |
| + return validateTransportStop(req, result) |
| + } |
| + a.bindClaimWakeStop() |
| + retirement := &claimServingArtifactRetirement{Claims: f.f.claims, Guard: f.f.guard, DataDir: f.f.guard.DataDir, Box: f.actor.Box, Region: f.actor.Region, Root: hostbox.ServingParkClient{Call: servingParkSocket(t, servingTransportRoot(t, f))}} |
| + w.RetireArtifacts = retirement.Retire |
| + w.RecoverArtifacts = func(ctx context.Context, o hostclaim.Observed, in ClaimLaunchInputs) error { |
| + p.events = append(p.events, "recover") |
| + return retirement.Recover(ctx, o, in) |
| + } |
| + w.BeforeLegacyInstall = retirement.BeforeLegacyInstall |
| + w.BeforeInstallLocked = func(ctx context.Context, o hostclaim.Observed, in ClaimLaunchInputs) error { |
| + if err := retirement.EnrollLocked(ctx, o, in); err != nil { |
| + return err |
| + } |
| + p.events = append(p.events, "enrolled") |
| + if p.afterEnroll != nil { |
| + p.afterEnroll() |
| + } |
| + return p.enrollFailure |
| + } |
| + source := hostbox.WorkSource{Guard: f.f.guard, Box: f.actor.Box, Region: f.actor.Region, Now: func() time.Time { return f.f.now }, Policy: func(context.Context, *hostclaim.Claim, hostbox.Selection, hostwrite.Identity) error { return nil }, Local: func(context.Context, *hostclaim.Claim, hostbox.Selection) error { return nil }} |
| + writer := hostbox.Writer{Data: f.f.data, Bucket: f.f.bucket, Claims: f.f.claims, Box: f.actor.Box, Region: f.actor.Region, AdmissionEvidence: p.owners.admissionEvidence} |
| + var err error |
| + p.runtime, err = w.Build(t.Context(), source, writer) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + t.Cleanup(func() { |
| + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) |
| + defer cancel() |
| + if err := w.Close(ctx); err != nil { |
| + t.Error(err) |
| + } |
| + }) |
| + return p |
| +} |
| + |
| +func (p *servingPreparation) prepare(t *testing.T) (hostclaim.Observed, activator.ClaimStart) { |
| + t.Helper() |
| + f := p.f |
| + rt := registry.Route{Host: recoveryHost, DBPath: f.db} |
| + o := f.f.read() |
| + // Prerequisites' isolated launch preflight requires an installed /data |
| + // namespace. Drive its selection, stop and real lease in the same order; |
| + // Admit and Prepare below are the unmodified production runtime closures. |
| + var err error |
| + if f.f.guard.DataDir == "/data" { |
| + if err = p.runtime.Prerequisites(t.Context(), rt, o, recoveryPolicy); err != nil { |
| + t.Fatal("prerequisites", err) |
| + } |
| + p.events = append(p.events, "prerequisites") |
| + pending := p.wake.get(rt.Host) |
| + if pending == nil || pending.held == nil { |
| + t.Fatal("prerequisites returned without a lease") |
| + } |
| + _, selected := pending.snapshot() |
| + p.baseline = selected.Baseline |
| + } else { |
| + selected, err := p.owners.Select(t.Context(), rt, o, recoveryPolicy) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + p.events = append(p.events, "select") |
| + if selected.Empty || selected.Baseline == nil { |
| + t.Fatal("baseline restore replaced by empty install") |
| + } |
| + p.baseline = selected.Baseline |
| + if err = p.wake.stopPredecessor(t.Context(), o); err != nil { |
| + t.Fatal("stop predecessor", err) |
| + } |
| + p.events = append(p.events, "stop") |
| + held, err := lease.Acquire(t.Context(), f.f.bucket, o.Claim.Holder.Location, p.wake.LeaseRegion) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + p.events = append(p.events, "lease") |
| + live, cancel := context.WithCancel(t.Context()) |
| + done := make(chan struct{}) |
| + go func() { <-live.Done(); close(done) }() |
| + p.wake.pending[rt.Host] = &claimWakeAttempt{owner: p.wake, observed: o, inputs: selected, held: held, ctx: live, cancel: cancel, done: done} |
| + } |
| + admitted, err := p.runtime.Admit(t.Context(), rt, f.f.read(), recoveryPolicy) |
| + if err != nil { |
| + t.Fatal("admit", err) |
| + } |
| + r := admitted.Claim.Holder.WakeRetry |
| + if r == nil || r.Attempt == nil || r.Attempt.Session != admitted.Claim.Holder.Session || r.Attempt.ControllerID != p.local.ControllerID { |
| + t.Fatalf("retry not bound: %+v", r) |
| + } |
| + start, err := p.runtime.Prepare(t.Context(), rt, admitted, recoveryPolicy) |
| + if err != nil { |
| + t.Fatal("prepare", err) |
| + } |
| + return admitted, start |
| +} |
| + |
| +func TestFilesSeedOrdinaryPreparationRestore(t *testing.T) { |
| + for _, failure := range []string{"", "enrolled-refusal", "missing-marker", "cancel-after-enrollment", "disk-after-enrollment", "invalid-sqlite"} { |
| + for _, restart := range []string{"same-controller", "controller", "reboot"} { |
| + t.Run(failure+"/"+restart, func(t *testing.T) { runFilesSeedOrdinaryPreparation(t, failure, restart) }) |
| + } |
| + } |
| +} |
| + |
| +func runFilesSeedOrdinaryPreparation(t *testing.T, failure, restart string, mounted ...bool) { |
| + t.Setenv("CARLOS_HOST_CLAIM", "1") |
| + t.Setenv("CARLOS_HOST_CLAIM_ORIGINS", "1") |
| + t.Setenv("CARLOS_MOVES_PHASE1", "") |
| + var f *servingRootFixture |
| + if len(mounted) > 0 && mounted[0] { |
| + |
| + t.Cleanup(func() { |
| + if err := os.RemoveAll("/data"); err != nil { |
| + t.Error(err) |
| + } |
| + }) |
| + t.Cleanup(func() { |
| + if err := os.RemoveAll("/var/lib/carlos-claims"); err != nil { |
| + t.Error(err) |
| + } |
| + }) |
| + if failure == "restore-enospc" { |
| + if err := os.Mkdir("/data", 0700); err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := unix.Mount("tmpfs", "/data", "tmpfs", unix.MS_NOSUID|unix.MS_NODEV, "size=1m"); err != nil { |
| + t.Fatal(err) |
| + } |
| + t.Cleanup(func() { |
| + if err := unix.Unmount("/data", 0); err != nil { |
| + t.Error(err) |
| + } |
| + }) |
| + } |
| + state, err := openClaimServingParkAuthority() |
| + if err != nil { |
| + t.Fatal("production private store", err) |
| + } |
| + t.Cleanup(func() { |
| + if err := state.Close(); err != nil { |
| + t.Error(err) |
| + } |
| + }) |
| + f, _, _ = newServingLegacyRootSetup(t, false, "/data") |
| + instances := filepath.Join(f.f.guard.DataDir, "instances") |
| + if err := unix.Mount(instances, instances, "", unix.MS_BIND, ""); err != nil { |
| + t.Fatal(err) |
| + } |
| + t.Cleanup(func() { |
| + if err := unix.Unmount(instances, 0); err != nil { |
| + t.Error(err) |
| + } |
| + }) |
| + if err := unix.Mount("", instances, "", unix.MS_BIND|unix.MS_REMOUNT|unix.MS_NOSYMFOLLOW|unix.MS_NOSUID|unix.MS_NODEV|unix.MS_NOEXEC, ""); err != nil { |
| + t.Fatal(err) |
| + } |
| + // Use the production UID and mount checks in this isolated namespace. |
| + f.p.ledger.state = state |
| + f.p.ledger.fs = newServingParkFS(f.f.guard.DataDir, state) |
| + source, err := os.Open(filepath.Dir(f.db)) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + sourceID, err := servingParkDirID(source) |
| + source.Close() |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + outside, err := os.Open(f.f.guard.DataDir) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + outsideID, err := servingParkDirID(outside) |
| + outside.Close() |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if sourceID.Device != outsideID.Device || sourceID.Mount == outsideID.Mount { |
| + t.Fatal("fixture did not create same-device cross-mount boundary") |
| + } |
| + if err := os.Rename(f.db, filepath.Join(f.f.guard.DataDir, "old-flat-park")); !errors.Is(err, syscall.EXDEV) { |
| + t.Fatalf("old destination must fail with EXDEV: %v", err) |
| + } |
| + } else { |
| + f, _, _ = newServingLegacyRootSetup(t, false) |
| + } |
| + selected := plan12RestoreBaseline(t, f.f) |
| + raw, err := f.f.data.GetVersion(t.Context(), f.f.bucket, selected.Files[0].Key, selected.Files[0].VersionID) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + bucket := f.f.data.(*leasetest.VersionedBucket) |
| + key := strings.Replace(selected.Files[0].Key, "/g-src/", "/", 1) |
| + bucket.Put(f.f.bucket, key, []byte("older invalid snapshot")) |
| + version := bucket.Put(f.f.bucket, key, raw) |
| + // Keep a valid LTX envelope so failures occur inside the production restore, |
| + // after legacy retirement, rather than at selected-object decoding. |
| + if failure == "invalid-sqlite" { |
| + var spec ltx.FileSpec |
| + if _, err := spec.ReadFrom(bytes.NewReader(raw)); err != nil { |
| + t.Fatal(err) |
| + } |
| + copy(spec.Pages[0].Data, []byte("not a sqlite db!")) |
| + var encoded bytes.Buffer |
| + if _, err := spec.WriteTo(&encoded); err != nil { |
| + t.Fatal(err) |
| + } |
| + version = bucket.Put(f.f.bucket, key, encoded.Bytes()) |
| + } |
| + handler, _ := leasetest.NewS3Server(bucket) |
| + server := httptest.NewServer(handler) |
| + t.Cleanup(server.Close) |
| + for key, value := range map[string]string{"AWS_ACCESS_KEY_ID": "test-key", "AWS_SECRET_ACCESS_KEY": "test-secret", "AWS_SESSION_TOKEN": "", "AWS_EC2_METADATA_DISABLED": "true", "AWS_CONFIG_FILE": filepath.Join(t.TempDir(), "absent"), "AWS_SHARED_CREDENTIALS_FILE": filepath.Join(t.TempDir(), "absent"), "CARLOS_S3_ENDPOINT": server.URL} { |
| + t.Setenv(key, value) |
| + } |
| + sentinels := map[string]string{filepath.Join(filepath.Dir(f.db), "files", "payload"): "live files", filepath.Join(filepath.Dir(f.db), ".env"): "environment"} |
| + for path, body := range sentinels { |
| + if err = os.MkdirAll(filepath.Dir(path), 0700); err != nil { |
| + t.Fatal(err) |
| + } |
| + if err = os.WriteFile(path, []byte(body), 0600); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + p := newServingPreparation(t, f, "boot", "controller") |
| + var legacy servingParkRecord |
| + var baseline *genselect.Plan |
| + for i := 0; i < 2; i++ { |
| + if i == 1 { |
| + if failure == "invalid-sqlite" { |
| + version = bucket.Put(f.f.bucket, key, raw) |
| + } |
| + f.f.now = f.f.now.Add(time.Minute) |
| + } |
| + p.events = nil |
| + admitted, start := p.prepare(t) |
| + if len(p.baseline.Files) != 1 || p.baseline.Files[0].Key != key || p.baseline.Files[0].VersionID != version { |
| + t.Fatalf("wrong exact baseline: %+v", p.baseline) |
| + } |
| + if baseline != nil && failure != "invalid-sqlite" && !reflect.DeepEqual(baseline, p.baseline) { |
| + t.Fatal("baseline changed") |
| + } |
| + baseline = p.baseline |
| + p.enrollFailure = nil |
| + restoreCtx, cancel := context.WithCancel(t.Context()) |
| + p.afterEnroll = nil |
| + if i == 0 { |
| + switch failure { |
| + case "enrolled-refusal": |
| + p.enrollFailure = os.ErrPermission |
| + case "disk-after-enrollment": |
| + p.enrollFailure = syscall.ENOSPC |
| + case "cancel-after-enrollment": |
| + p.afterEnroll = cancel |
| + case "restore-enospc": |
| + p.afterEnroll = func() { |
| + err := os.WriteFile(filepath.Join(filepath.Dir(f.db), ".disk-full-witness"), make([]byte, 1<<20), 0600) |
| + if !errors.Is(err, syscall.ENOSPC) { |
| + t.Fatalf("small private tmpfs did not fill: %v", err) |
| + } |
| + } |
| + } |
| + } |
| + restoreErr := start.Restore(restoreCtx) |
| + if i == 0 && failure == "restore-enospc" { |
| + if !errors.Is(restoreErr, syscall.ENOSPC) || !strings.Contains(restoreErr.Error(), "restore selected generation") { |
| + t.Fatalf("not a production restore ENOSPC: %v", restoreErr) |
| + } |
| + if err := os.Remove(filepath.Join(filepath.Dir(f.db), ".disk-full-witness")); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + cancel() |
| + failed := i == 0 && failure != "" && failure != "missing-marker" |
| + if failed { |
| + if restoreErr == nil { |
| + t.Fatal("missed restore failure") |
| + } |
| + if p.enrollFailure != nil && !errors.Is(restoreErr, p.enrollFailure) { |
| + t.Fatalf("wrong failure: %v", restoreErr) |
| + } |
| + if failure == "cancel-after-enrollment" && !errors.Is(restoreErr, context.Canceled) { |
| + t.Fatalf("wrong cancellation: %v", restoreErr) |
| + } |
| + if failure == "invalid-sqlite" && !strings.Contains(restoreErr.Error(), "check restored database") { |
| + t.Fatalf("failure before database check: %v", restoreErr) |
| + } |
| + if _, err = os.Stat(f.db); !os.IsNotExist(err) { |
| + t.Fatalf("failed restore left database: %v", err) |
| + } |
| + temps, err := filepath.Glob(filepath.Join(filepath.Dir(f.db), ".restore-*")) |
| + if err != nil || len(temps) != 0 { |
| + t.Fatalf("restore scratch survived: %v %v", temps, err) |
| + } |
| + } else { |
| + if restoreErr != nil { |
| + t.Fatal("restore", restoreErr) |
| + } |
| + if got := mwReadDB(t, f.db); got != "selected recovery baseline" { |
| + t.Fatal(got) |
| + } |
| + marker, err := hostbox.ReadGenerationMarker(f.db + ".gen") |
| + if err != nil || marker != admitted.Claim.Holder.Generation { |
| + t.Fatalf("marker %q %v", marker, err) |
| + } |
| + if i == 0 && failure == "missing-marker" { |
| + if err = os.Remove(f.db + ".gen"); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + } |
| + want := []string{"select", "stop", "lease", "admit", "prelaunch", "recover", "state", "enrolled"} |
| + if f.f.guard.DataDir == "/data" { |
| + want = append([]string{"prerequisites"}, want[3:]...) |
| + } |
| + if !reflect.DeepEqual(p.events, want) { |
| + t.Fatalf("preparation order: %v", p.events) |
| + } |
| + current, err := servingWriterIdentity(f.f.read(), f.actor.Box, f.actor.Region) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + slot, err := f.p.ledger.slot(servingParkAuthorization{Successor: current}) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + record, err := f.p.ledger.read(slot.ID) |
| + if err != nil || !record.Complete || !record.Authorization.Legacy { |
| + t.Fatalf("legacy slot: %+v %v", record, err) |
| + } |
| + if i == 0 { |
| + legacy = record |
| + } else if !reflect.DeepEqual(legacy, record) { |
| + t.Fatal("never-launched restore displaced legacy park or changed deadline") |
| + } |
| + if i == 0 && restart != "same-controller" { |
| + // Lose only the controller's lease and memory. Leave its retry and |
| + // prelaunch evidence unsettled for the next controller's stop path. |
| + attempt := p.wake.get(recoveryHost) |
| + if err = p.wake.release(t.Context(), recoveryHost, attempt); err != nil { |
| + t.Fatal(err) |
| + } |
| + // This is ordinary retry recovery, not Task 1R's future seed rerun. |
| + nextBoot := "boot" |
| + if restart == "reboot" { |
| + nextBoot = "boot-2" |
| + } |
| + next := newServingPreparation(t, f, nextBoot, "controller-2") |
| + err = next.runtime.Prerequisites(t.Context(), registry.Route{Host: recoveryHost, DBPath: f.db}, f.f.read(), recoveryPolicy) |
| + if !errors.Is(err, hostbox.ErrChanged) { |
| + t.Fatalf("retry settlement: %v", err) |
| + } |
| + if r := f.f.retry(); r.State != "open" || r.Attempt != nil || r.AttemptsReserved != 1 { |
| + t.Fatalf("settlement refunded/stranded: %+v", r) |
| + } |
| + p = next |
| + } else { |
| + if err = p.runtime.FailedAdmission(t.Context(), admitted, errors.New("restore-only witness")); err != nil { |
| + t.Fatal("settlement", err) |
| + } |
| + } |
| + } |
| + for suffix, want := range map[string]string{"": "legacy bytes", "-wal": "legacy WAL", "-shm": "legacy SHM"} { |
| + body, err := os.ReadFile(filepath.Join(f.f.guard.DataDir, "instances", ".serving-parked", legacy.Authorization.ID, filepath.Base(f.db)+suffix)) |
| + if err != nil || string(body) != want { |
| + t.Fatalf("park bytes %q %v", body, err) |
| + } |
| + } |
| + for path, want := range sentinels { |
| + body, err := os.ReadFile(path) |
| + if err != nil || string(body) != want { |
| + t.Fatalf("unrelated bytes: %s %v", path, err) |
| + } |
| + } |
| + after, err := f.f.data.GetVersion(t.Context(), f.f.bucket, key, version) |
| + if err != nil || string(after) != string(raw) { |
| + t.Fatal("remote baseline changed", err) |
| + } |
| + if r := f.f.retry(); r.State != "open" || r.Attempt != nil || r.AttemptsReserved != 2 { |
| + t.Fatalf("final retry: %+v", r) |
| + } |
| + if restart != "same-controller" && len(f.f.kernel.recovered) == 0 { |
| + t.Fatal("restart did not recover original launch tuple") |
| + } |
| +} |
| + |
| +func TestFilesSeedLegacyStopRefusesForeignWriterBeforeRoot(t *testing.T) { |
| + f, _, _ := newServingLegacyRootSetup(t, false) |
| + o, err := hostclaim.Update(t.Context(), f.f.claims, f.f.read(), func(c *hostclaim.Claim) error { c.Holder.WriterBox = "foreign-box"; return nil }) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + calls := 0 |
| + a := ClaimAssembly{Claims: f.f.claims, collectStop: func(context.Context, StopRequest, StopDrainer) (StopResult, error) { calls++; return StopResult{}, nil }} |
| + local := claimStopLocal{Actor: f.actor, BootID: "boot", ControllerID: "controller", PID: 77, ProcessStart: "start"} |
| + before, _ := f.disk.Names() |
| + _, err = a.collectCapturedStop(t.Context(), o, local, claimLaunchOwner{BootID: local.BootID, ControllerID: local.ControllerID}, false) |
| + if !errors.Is(err, hostbox.ErrChanged) || calls != 0 { |
| + t.Fatalf("foreign legacy writer: calls %d error %v", calls, err) |
| + } |
| + after, _ := f.disk.Names() |
| + if !reflect.DeepEqual(before, after) { |
| + t.Fatal("foreign legacy stop wrote private evidence") |
| + } |
| +} |
| + |
| +func TestServingParkNestedBindMount(t *testing.T) { |
| + if !plan14RootFixture(t) { |
| + return |
| + } |
| + for _, failure := range []string{"", "enrolled-refusal", "missing-marker", "cancel-after-enrollment", "disk-after-enrollment", "invalid-sqlite", "restore-enospc"} { |
| + for _, restart := range []string{"same-controller", "controller", "reboot"} { |
| + t.Run(failure+"/"+restart, func(t *testing.T) { runFilesSeedOrdinaryPreparation(t, failure, restart, true) }) |
| + } |
| + } |
| +} |
diff --git a/internal/host/claimservinglegacyroot_linux_test.go b/internal/host/claimservinglegacyroot_linux_test.go| index 12953f965..ccecb2bd8 100644 |
| --- a/internal/host/claimservinglegacyroot_linux_test.go |
| +++ b/internal/host/claimservinglegacyroot_linux_test.go |
| @@ -20,11 +20,21 @@ import ( |
| "github.com/carlosframework/platform/internal/hostguard" |
| "github.com/carlosframework/platform/internal/lease" |
| "github.com/carlosframework/platform/internal/lease/leasetest" |
| + "github.com/carlosframework/platform/internal/provision" |
| ) |
| -func newServingLegacyRootFixture(t *testing.T, empty bool, beforeAdmission ...func(*servingRootFixture, *ClaimStopCoordinator, StopRequest)) (*servingRootFixture, ClaimLaunchInputs) { |
| +func newServingLegacyRootSetup(t *testing.T, empty bool, dataRoot ...string) (*servingRootFixture, ClaimLaunchInputs, ClaimStopCoordinator) { |
| t.Helper() |
| f, _, _, in := servingRetirementFixture(t) |
| + if len(dataRoot) != 0 { |
| + f.guard.DataDir = dataRoot[0] |
| + in.DBPath = provision.NestedDBPath(f.guard.DataDir, recoveryHost) |
| + for _, dir := range []string{filepath.Join(f.guard.DataDir, "hostguard"), filepath.Dir(in.DBPath)} { |
| + if err := os.MkdirAll(dir, 0700); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + } |
| if !empty { |
| _, err := hostclaim.Update(t.Context(), f.claims, f.read(), func(c *hostclaim.Claim) error { |
| c.Holder.WriterBox = "box-1" |
| @@ -59,6 +69,23 @@ func newServingLegacyRootFixture(t *testing.T, empty bool, beforeAdmission ...fu |
| fx.p.root = ClaimRootHTTP{Roots: map[string]string{"data": f.guard.DataDir}, Journals: journals, Stop: ClaimStopHTTP{Coordinator: coordinator, Authenticate: func(context.Context, net.Conn) (StopPeer, error) { return f.peer, nil }}, InventoryActor: func(context.Context) (hostbox.Actor, error) { return fx.actor, nil }, RequireNewWork: func(context.Context) error { return nil }} |
| fx.install(f.read()) |
| coordinator.RetainNoProcess = fx.p.retainLegacyNoProcess |
| + if !empty { |
| + for suffix, body := range map[string]string{"": "legacy bytes", "-wal": "legacy WAL", "-shm": "legacy SHM"} { |
| + if err := os.WriteFile(fx.db+suffix, []byte(body), 0600); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + } |
| + left, right := net.Pipe() |
| + fx.conn = left |
| + t.Cleanup(func() { left.Close(); right.Close() }) |
| + return fx, in, coordinator |
| +} |
| + |
| +func newServingLegacyRootFixture(t *testing.T, empty bool, beforeAdmission ...func(*servingRootFixture, *ClaimStopCoordinator, StopRequest)) (*servingRootFixture, ClaimLaunchInputs) { |
| + t.Helper() |
| + fx, in, coordinator := newServingLegacyRootSetup(t, empty) |
| + f := fx.f |
| o := f.read() |
| h := o.Claim.Holder |
| req := StopRequest{Region: "ie", Host: o.Host, Incarnation: h.Incarnation, InstallationStamp: h.Stamp, Box: "box-1", Enrollment: "enrollment", BootID: "boot", ControllerID: "controller", ExpectedClaimETag: o.ETag, ExpectedDirectoryRevision: "7"} |
| @@ -83,16 +110,6 @@ func newServingLegacyRootFixture(t *testing.T, empty bool, beforeAdmission ...fu |
| } |
| fx.install(admitted) |
| in.Admission, in.Empty = admission, empty |
| - if !empty { |
| - for suffix, body := range map[string]string{"": "legacy bytes", "-wal": "legacy WAL", "-shm": "legacy SHM"} { |
| - if err := os.WriteFile(fx.db+suffix, []byte(body), 0600); err != nil { |
| - t.Fatal(err) |
| - } |
| - } |
| - } |
| - left, right := net.Pipe() |
| - fx.conn = left |
| - t.Cleanup(func() { left.Close(); right.Close() }) |
| return fx, in |
| } |
diff --git a/internal/host/claimservingpark_linux_test.go b/internal/host/claimservingpark_linux_test.go| index 3af4ca23d..976cb82e9 100644 |
| --- a/internal/host/claimservingpark_linux_test.go |
| +++ b/internal/host/claimservingpark_linux_test.go |
| @@ -249,7 +249,7 @@ func TestServingParkLedgerExpiryAndIdentity(t *testing.T) { |
| if err := os.Rename(path, path+".saved"); err != nil { |
| t.Fatal(err) |
| } |
| - if err := os.WriteFile(path, []byte("replacement"), 0600); err != nil { |
| + if err := os.WriteFile(path, []byte("victim"), 0600); err != nil { |
| t.Fatal(err) |
| } |
| if err := os.Rename(path+".saved", filepath.Join(t.TempDir(), "original")); err != nil { |
diff --git a/internal/host/claimwakestop.go b/internal/host/claimwakestop.go| index a66b71cd0..529a149db 100644 |
| --- a/internal/host/claimwakestop.go |
| +++ b/internal/host/claimwakestop.go |
| @@ -313,9 +313,9 @@ func (a ClaimAssembly) collectCapturedStop(ctx context.Context, captured hostcla |
| req := StopRequest{Region: actor.Region, Recover: recovering, Host: observed.Host, Incarnation: holder.Incarnation, InstallationStamp: holder.Stamp, WriterSession: holder.Session, OperationID: claim.Op.ID, Phase: claim.Op.Phase, ObligationID: obligation, Box: actor.Box, Enrollment: actor.Enrollment, BootID: owner.BootID, ControllerID: owner.ControllerID, ExpectedClaimETag: observed.ETag, ExpectedDirectoryRevision: directoryRevision} |
| target := hostguard.FenceTarget{Region: req.Region, Host: req.Host, Incarnation: req.Incarnation, Stamp: req.InstallationStamp, Session: req.WriterSession, Op: req.OperationID, Phase: req.Phase, ObligationID: req.ObligationID, Box: req.Box} |
| if zero && claim.Op.Kind == hostclaim.KindServing { |
| - // A created incarnation names no writer box or admission; its |
| - // authority is the executor, and root checks the never-admitted holder. |
| - if claim.Op.Exec != actor.Box || holder.WriterBox != "" || len(holder.Admissions) != 0 { |
| + // A never-admitted holder may be a new creator or an adopted legacy |
| + // writer on this box. Root independently proves that no process remains. |
| + if claim.Op.Exec != actor.Box || (holder.WriterBox != "" && holder.WriterBox != actor.Box) || len(holder.Admissions) != 0 { |
| return StopResult{}, hostbox.ErrChanged |
| } |
| } else if !hostguard.StopAuthorityMatches(claim, target) { |
diff --git a/internal/provision/testdata/plan14-root-reads-seed.tsv b/internal/provision/testdata/plan14-root-reads-seed.tsv| index 235f17ca5..28581a042 100644 |
| --- a/internal/provision/testdata/plan14-root-reads-seed.tsv |
| +++ b/internal/provision/testdata/plan14-root-reads-seed.tsv |
| @@ -1,4 +1,4 @@ |
| -# Files seed checkpoint 6 overlay; pending Paul’s census ruling. |
| +# Files seed checkpoint 7 overlay; pending Paul’s census ruling. |
| # Generation, legacy and empty-bootstrap root authority have test callers only; production binding remains refused. |
| # Load after zddr4 and its explicit seal check. No legacy fingerprints are added or removed. |
| # Every classification below is rev3=PROPOSED-seed, not an approved disposition. |
| @@ -75,7 +75,7 @@ internal/host/claimservingparkroot_linux.go validateServingRootHistory authority |
| internal/host/claimservingpark_records.go servingParkRecord.activeAuthorization authority C,J4 rev3=PROPOSED-seed; last persisted continuation authorization or immutable original authorization; no source or deadline changes fe168fe52317e45ce70c3e97a9bc2c52d2409328ab4844a8d2a34fc4babba36d |
| internal/host/claimservingpark_records.go servingParkLedger.continueLocked authority C,J4 rev3=PROPOSED-seed; namespace/host-protected slot and record locks; pending original retirement, absent source and retained parked identities before durable bounded continuation 87f297a924f7f153624304233218d8b5548a016fc7dbf0f7cb8dedb789324009 |
| internal/host/claimservingpark_records.go servingParkLedger.replaceLocked authority C,J4 rev3=PROPOSED-seed; completed incumbent record under its record lock; resumes its recorded deletion cause before slot replacement 3e67316e959c9a901c32a2a61fda4e6ea5e92fe51bdb7fdb5f5c53d9d5960aad |
| -@coverage internal/host d9e2304b55fd9f7653139cc17d2254ef7ec730b2e8c812a9c8f343603f2f6aa6 |
| +@coverage internal/host 2d65820f0366a1ee92490ef9af8888cfda33292f5a5367d35d353e320f031a85 |
| @coverage internal/hostbox d48f1a63963edb2551230477c8162f7ac182761c80571c3d753fe19dd7acacba |
| @coverage internal/hostguard 94912485e1e5fad4bad56985dd48ede776cfcb5fe18e0f4a59953584ddab06c0 |
| internal/host/claimservinglegacy.go servingLegacyKey authority C,J4 rev3=PROPOSED-seed; box, host and incarnation derive private stop and consumption keys; never a caller path 93c10e40202ab23986b54a366edd7abfab9f8d942736305b5732e8741e96f3ab |
| @@ -120,3 +120,4 @@ internal/hostbox/servingpark_transport.go journalServingParkV4 authority C,J4 re |
| internal/hostbox/servingpark_transport.go servingParkResponse authority C,J4 rev3=PROPOSED-seed; typed retirement reply and exact requested successor; missing or mismatched result stays uncertain fc8602dfe28b78ee04809509b1357778777b26c191b089a47d70defbca8ffd88 |
| internal/hostbox/servingpark_transport.go validateServingParkRequest authority C,J4 rev3=PROPOSED-seed; v4 envelope, nonce, digest and identities; rejects mixed operation fields and unsupported pressure before any effect 2c87ae130afc670925c87f52b9688fdc24d940d0a5fcdbf09667df2b662f7f59 |
| internal/host/claimservingpark_transport.go var openClaimServingParkAuthority authority C,J4 rev3=PROPOSED-seed; descriptor-relative private rootstate at /var/lib/carlos-claims/authority/serving-parks with creation enabled and public reads disabled file:Open@78 7a1db088a7240e6a65ba0bed96fc5f973a69f70c2273c4475c486a6e0359fb23 |
| +internal/host/claimwakestop.go ClaimAssembly.collectCapturedStop authority C,G,J4 rev3=PROPOSED-seed; fresh claim and verified local stop identity; session-zero legacy holder may name only the local writer box, with no admissions; root independently proves and retains no-process evidence file:Exec@2994,file:Read@605 d4cd80663dfae5f9737a74e319d3423f4ef853e1843666b02b4cd2341e869d72 |