carlos / platform Public

census: fix-empty-app-key ruled (census-ruling-fix-empty-app-key, platform-1e)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 251fb629c04c4b69acf5b3a093c9c540d1def64d parent 90ae63b
2 files changed, +4 −4
  • internal/provision/plan9_b8_census_test.go +3 −3
  • internal/provision/testdata/plan14-root-reads-fix-empty-app-key.tsv +1 −1

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	306.202s
?   	github.com/carlosframework/platform/cmd/changelog	[no test files]
ok  	github.com/carlosframework/platform/cmd/console	2.765s
ok  	github.com/carlosframework/platform/cmd/moveprobe	93.349s
ok  	github.com/carlosframework/platform/cmd/zddprobe	0.722s
ok  	github.com/carlosframework/platform/internal/activator	249.122s
ok  	github.com/carlosframework/platform/internal/agentsock	0.015s
ok  	github.com/carlosframework/platform/internal/alerting	0.005s
ok  	github.com/carlosframework/platform/internal/analytics	0.022s
ok  	github.com/carlosframework/platform/internal/appconfig	2.505s
ok  	github.com/carlosframework/platform/internal/apperr	0.070s
ok  	github.com/carlosframework/platform/internal/applog	0.124s
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.763s
?   	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.008s
ok  	github.com/carlosframework/platform/internal/caps	0.011s
ok  	github.com/carlosframework/platform/internal/certwarm	0.002s
ok  	github.com/carlosframework/platform/internal/cgroup	0.690s
ok  	github.com/carlosframework/platform/internal/changelog	0.326s
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	396.683s
?   	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	5.956s
ok  	github.com/carlosframework/platform/internal/dbdoor/dbdoortest	0.009s
ok  	github.com/carlosframework/platform/internal/dbverify	0.004s
ok  	github.com/carlosframework/platform/internal/dnsrec	0.002s
ok  	github.com/carlosframework/platform/internal/docsite	0.005s
ok  	github.com/carlosframework/platform/internal/domains	2.435s
ok  	github.com/carlosframework/platform/internal/doorkey	0.006s
ok  	github.com/carlosframework/platform/internal/economics	0.003s
ok  	github.com/carlosframework/platform/internal/edge	27.305s
?   	github.com/carlosframework/platform/internal/edgeproof	[no test files]
ok  	github.com/carlosframework/platform/internal/edgesfile	0.007s
ok  	github.com/carlosframework/platform/internal/fleetapi	0.130s
ok  	github.com/carlosframework/platform/internal/gate	1.656s
ok  	github.com/carlosframework/platform/internal/genselect	0.014s
ok  	github.com/carlosframework/platform/internal/geo	0.016s
ok  	github.com/carlosframework/platform/internal/geoip	0.030s
ok  	github.com/carlosframework/platform/internal/host	172.473s
ok  	github.com/carlosframework/platform/internal/hostactors	0.454s
ok  	github.com/carlosframework/platform/internal/hostbox	2.796s
ok  	github.com/carlosframework/platform/internal/hostclaim	0.527s
ok  	github.com/carlosframework/platform/internal/hostevidence	0.006s
ok  	github.com/carlosframework/platform/internal/hostexec	6.183s
ok  	github.com/carlosframework/platform/internal/hostfence	0.035s
ok  	github.com/carlosframework/platform/internal/hostfiles	11.354s
ok  	github.com/carlosframework/platform/internal/hostfloor	0.012s
ok  	github.com/carlosframework/platform/internal/hostguard	1.011s
ok  	github.com/carlosframework/platform/internal/hostops	1.628s
?   	github.com/carlosframework/platform/internal/hostops/fencerelease	[no test files]
ok  	github.com/carlosframework/platform/internal/hostops/internal/fencerelease	0.002s
ok  	github.com/carlosframework/platform/internal/hostquarantine	0.002s
ok  	github.com/carlosframework/platform/internal/hostrelocate	0.434s
ok  	github.com/carlosframework/platform/internal/hostresolve	0.141s
ok  	github.com/carlosframework/platform/internal/hostwrite	0.002s
ok  	github.com/carlosframework/platform/internal/infraview	0.002s
ok  	github.com/carlosframework/platform/internal/instancectl	4.189s
ok  	github.com/carlosframework/platform/internal/instanceexec	2.762s
ok  	github.com/carlosframework/platform/internal/instancefs	0.018s
ok  	github.com/carlosframework/platform/internal/instancekey	0.016s
ok  	github.com/carlosframework/platform/internal/instanceupdates	0.019s
ok  	github.com/carlosframework/platform/internal/layout	1.629s
ok  	github.com/carlosframework/platform/internal/lease	9.891s
ok  	github.com/carlosframework/platform/internal/lease/leasetest	0.005s
ok  	github.com/carlosframework/platform/internal/ledger	0.012s
ok  	github.com/carlosframework/platform/internal/mail	0.183s
ok  	github.com/carlosframework/platform/internal/maintenance	0.089s
ok  	github.com/carlosframework/platform/internal/maintenanceexec	5.687s
ok  	github.com/carlosframework/platform/internal/maintenanceguard	0.076s
ok  	github.com/carlosframework/platform/internal/metrics	0.004s
ok  	github.com/carlosframework/platform/internal/moves	21.841s
ok  	github.com/carlosframework/platform/internal/moves/archive	0.821s
ok  	github.com/carlosframework/platform/internal/objstore	0.174s
ok  	github.com/carlosframework/platform/internal/ops	0.171s
ok  	github.com/carlosframework/platform/internal/park	0.198s
ok  	github.com/carlosframework/platform/internal/privatefile	0.003s
ok  	github.com/carlosframework/platform/internal/provision	19.332s
ok  	github.com/carlosframework/platform/internal/publicrelease	0.016s
?   	github.com/carlosframework/platform/internal/regionname	[no test files]
ok  	github.com/carlosframework/platform/internal/registry	5.469s
ok  	github.com/carlosframework/platform/internal/relay	7.255s
ok  	github.com/carlosframework/platform/internal/release	21.264s
ok  	github.com/carlosframework/platform/internal/rollout	4.575s
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.008s
ok  	github.com/carlosframework/platform/internal/rootstate	0.025s
ok  	github.com/carlosframework/platform/internal/runs	0.579s
ok  	github.com/carlosframework/platform/internal/s3compat	0.005s
ok  	github.com/carlosframework/platform/internal/safefile	0.003s
ok  	github.com/carlosframework/platform/internal/schedule	2.833s
ok  	github.com/carlosframework/platform/internal/seeds	0.011s
ok  	github.com/carlosframework/platform/internal/sim/hostlife	13.692s
ok  	github.com/carlosframework/platform/internal/sim/litestreamfacts	4.362s
ok  	github.com/carlosframework/platform/internal/status	0.038s
ok  	github.com/carlosframework/platform/internal/steering	0.006s
ok  	github.com/carlosframework/platform/internal/stopevidence	0.190s
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.002s
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.635s
=== 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
linux/arm64 carlos binary: 47120546 bytes (ceiling 52000000)
--- 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: downloading https://github.com/minio/minio/releases/download/RELEASE.2025-09-07T16-13-09Z/minio.linux-arm64.RELEASE.2025-09-07T16-13-09Z
  minio: downloaded, digest verified
  mc: downloading https://github.com/minio/mc/releases/download/RELEASE.2025-08-13T08-35-41Z/mc.linux-arm64.RELEASE.2025-08-13T08-35-41Z
  mc: downloaded, 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.022s
=== RUN   TestT4StorageProbeMinio
2026/10/16 13:43:39 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18DF0667B9FE4029, 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.020s
minio contract: PASS
diff --git a/internal/provision/plan9_b8_census_test.go b/internal/provision/plan9_b8_census_test.go
index 3641cd3f6..9df7fd0e1 100644
--- a/internal/provision/plan9_b8_census_test.go
+++ b/internal/provision/plan9_b8_census_test.go
@@ -650,7 +650,7 @@ var plan9B8CensusInventory = []censusEntry{
{"schedule.go", "renderScheduleList", "key-site", "lit:instances", "af6d666083fbbc753eecc98809d3d307344cc15110362a7e93afab573749ea6e"},
{"internal/activator/layout.go", "LayoutInputs.sockets", "key-site", "lit:instances", "1d11ac5ac5be6a42e676e064771141fe8f4367c78cbb7e5c5cca072f40c27c42"},
{"internal/activator/paths.go", "ExecBackend.pathsFor", "key-site", "lit:instances", "cbc01865e27934cb38baab9329a0867b899149531b4706a533a6956afc7c71b3"},
- // Re-digested for fix-empty-app-key (RULING OWED, platform-1e): DayKey now returns an error for an empty or invalid account, app, box or date, and UpsertDay returns it before any Get or Put. Same single Put of the app-day file; no record key.
+ // Re-digested for fix-empty-app-key (census-ruling-fix-empty-app-key, platform-1e 2026-10-16): DayKey now returns an error for an empty or invalid account, app, box or date, and UpsertDay returns it before any Get or Put. Same single Put of the app-day file; no record key.
{"internal/analytics/day.go", "UpsertDay", "nonrecord", "sel:Put", "ab892656cdbce1c80f0c33441341cf9c94dd22f06716ffffbd6c025100adb1b8"},
{"internal/appconfig/configack.go", "WriteConfigAck", "nonrecord", "sel:Put", "211c8417bdbd6c6721fc503db085e9df073adeba623d9daa1e226554760ef5d1"},
{"internal/appconfig/generation.go", "claimRawTouchGeneration", "nonrecord", "sel:Put", "313a5de17aee1b9ed6a344f6b785637c6978b60552a2243ef208c28eb8401a02"},
@@ -761,10 +761,10 @@ var plan9B8CensusInventory = []censusEntry{
{"internal/host/claimretire_transport.go", "retirementAcknowledgement", "nonrecord", "sel:Put", "5c09795fbe9b952436d16bcd58e846ac27e9dbcf959fcf1cd6c432af0f3ee416"},
// D1 compares the retained registration's record key to the fresh claim; no record write.
{"internal/host/rootexecution_authority.go", "ClaimRootHTTP.executionAuthority", "key-site", "key:RecordKey", "107989f561409fd8c11c2666d0672b8dbeb368842fe00ad6a7b84fece2150438"},
- // Re-digested for fix-empty-app-key (RULING OWED, platform-1e): a chunk key the errors builder refuses (empty or invalid account or app) drops that app's records and logs once; no Put happens for it. Same single Put of the errors chunk; no record key.
+ // Re-digested for fix-empty-app-key (census-ruling-fix-empty-app-key, platform-1e 2026-10-16): a chunk key the errors builder refuses (empty or invalid account or app) drops that app's records and logs once; no Put happens for it. Same single Put of the errors chunk; no record key.
{"internal/host/errship.go", "errshipFlush", "nonrecord", "sel:Put", "b340b3dede6d5cab08a13a2ee8dbef5bb6dfb4943264e9835489292c479a379d"},
{"internal/host/fleetbind.go", "WriteFleetBinding", "nonrecord", "sel:Put", "44ab984c2c9b30abcc938132118f61a6922ccc0cd40ed2b6cb61c7654aa0a1c3"},
- // Re-digested for fix-empty-app-key (RULING OWED, platform-1e): as errshipFlush, for the logs family. Same single Put of the log chunk; no record key.
+ // Re-digested for fix-empty-app-key (census-ruling-fix-empty-app-key, platform-1e 2026-10-16): as errshipFlush, for the logs family. Same single Put of the log chunk; no record key.
{"internal/host/logship.go", "logshipFlush", "nonrecord", "sel:Put", "214a52ecc3bef193b8edcd6998cdaa75da182d552f4e605f68a5dededa4ffb68"},
{"internal/host/metrics_loop.go", "putAlertState", "nonrecord", "sel:Put", "d5b6e8b34dc5a731d6bbafeac0b7d0c5c20706d6f413dff38088b3321b35a26c"},
// Clears an aborting record through SetRecordMove (MoveGuardedAbortComplete) once nothing is owed under the op, then ReleaseAbort: record first, ruling M4.
diff --git a/internal/provision/testdata/plan14-root-reads-fix-empty-app-key.tsv b/internal/provision/testdata/plan14-root-reads-fix-empty-app-key.tsv
index 7a286b5c4..566baca57 100644
--- a/internal/provision/testdata/plan14-root-reads-fix-empty-app-key.tsv
+++ b/internal/provision/testdata/plan14-root-reads-fix-empty-app-key.tsv
@@ -1,4 +1,4 @@
-# Plan 14 census overlay fix-empty-app-key (branch fix-empty-app-key, 2026-10-16; loaded last, after home-part2). RULING OWED: platform-1e has not ruled on this overlay. Envelope-only, at main's dispositions: no root-read unit is added, removed or changed, so no row and no frozen declaration moves, and the legacy seal stands.
+# Plan 14 census overlay fix-empty-app-key (branch fix-empty-app-key, 2026-10-16; loaded last, after home-part2). RULED by the Plan 14 controller 2026-10-16 as census-ruling-fix-empty-app-key. Envelope-only, at main's dispositions: no root-read unit is added, removed or changed, so no row and no frozen declaration moves, and the legacy seal stands.
# The fix: the apps/<sqid>/<app>/{logs,errors,analytics}/ key builders (internal/applog FamilyPrefix, FamilyBoxPrefix, FamilyHourPrefix, FamilyChunkKey and their logs, errors and analytics wrappers, and analytics DayKey) return an error, applog.ErrBadKeySegment, for an empty or invalid account or app, or an empty or slash-bearing box, hour or date. They never build a key with an empty segment. An app-less route on the dev box leo-climbing (proof.dev.carlosframework.com: kind instance, account bab, app "", an Addr upstream nobody listens on) had its refused 502s filed under (bab, "") and shipped to apps/bab//errors/, which hostops.Apps refuses to walk.
# Envelopes: internal/applog gains the checks (CheckApp, CheckSegment, ErrBadKeySegment) and ReadWindow returns the builder's error. internal/apperr and internal/analytics change their builder signatures, and their readers (apperr.ReadWindow, analytics.ReadRange) and analytics.UpsertDay return the error before any store call. internal/host's logshipFlush, errshipFlush, chunkPrune and usageFlush skip a refused app and log once (unshippable, unshippableSeen); usageFlush drops a refused analytics delta instead of re-queueing it. None of these reads anything new, from the box or the bucket; the only reads that change are ones a refused key no longer makes.
@coverage internal/analytics e7461d39edd1660289669fdb5185f5231ef52e380978ce1d5765e91878f2c907