carlos / platform Public
- P1 — Task 5, Step 3:
StripAllleaves forged headers in the reserved namespace. Plan:1458 deletes only the five known app headers and the hop header. A client-suppliedX-Carlos-Geo-City, for example, survives both ingress andsetGeo. Spec §8.1 requires stripping everyX-Carlos-Geo-*header. Iterate over header keys using a case-insensitive prefix match, remove the hop header, and test unknown suffixes through the proxies.
- P1 — Task 12, Step 3: the prescribed status loader can falsely report “ready.” Plan:3982 explicitly calls
systemBoxes, contradicting the task’s prohibition at line 3879.internal/console/apisystemupdate.go:233and:258useLoadBoxes, which omits unreadable records; the proposed verdict function also receives no expected-box inventory. Replace this recipe withLoadBoxesCompletefor every prefix, reconciled against platform edges records and active fleet boxes. Test missing and unreadable heartbeats. UseBox.GeneratedAt, not the nonexistentUpdatednamed at line 3880.
- P1 — Task 7, Step 3: expiry cleanup deletes an in-progress replacement download. Plan:2510 makes
cleanLockedremove every.incoming-*, whiledownloadwrites those files outsidegenMuat line 2609. If A expires while B downloads,ExpireTick → clearLocked → cleanLockedunlinks B. Its later rename fails, leaving GeoIP unavailable until another poll. Restrict stale-download cleanup to boot, or track active downloads and exclude them. Add a deterministic test that pauses B’s download while A expires.
- P1 — Task 7, Step 3: a directory-sync failure leaves
currentnaming a deleted generation. Plan:2495 renamescurrentbefore returning the directory-sync result. On any returned error,installdeletes the newly named generation at line 2667. Restart then encounters a danglingcurrentand cleans away the previous generation too. Distinguish failures before and after the rename; never delete a generation thatcurrentmay already name. Inject a post-rename sync failure and verify restart recovery.
- P1 — Task 7, Step 3: initialization occurs after the edge has been published and after the dev-mode return. Plan:2792 inserts initialization around
edge.go:3088, butready(e)runs atinternal/edge/edge.go:3015, and dev mode returns at:3038. Dev edges therefore never initialize or run the mirror. In production, Task 8’s heartbeat callback can readgeoModeandgeoMirrorconcurrently with their later assignments. Initialize and boot GeoIP beforeready, and start its loop for both serving modes.
- P1 — Task 6, Step 3: blob CAS conflicts are accepted without the required size check. Plan:1962 treats every
ErrCASConflictas proof that the exact blob exists. Spec §3 requires checking that the existing object’s size matches. A truncated object under that key would be published as current, followed by deletion of the previous good blob. Verify existence and length after a conflict; refuse mismatches without moving the pointer or sweeping. Cover both an existing wrong-size object and a conflict without a readable object.
- P1 — Task 7, Step 3: unknown pointer versions retain the active database. Plan:2555 handles every parse error by retaining the current reader. Spec §3, lines 190–191, explicitly treats an unknown
vas no pointer: GeoIP must turn off. Distinguish unsupported versions from ordinary read/parse failures, clear the generation, and log once. Test a loaded database followed by a version-2 pointer.
- P1 — Task 7, Step 3: rejected-digest suppression survives pointer changes. Plan:2570 returns for the loaded SHA before clearing
skipSHA; the missing-pointer branch also leaves it intact. After rejecting B, observing A again—or observing off—and then republishing repaired B, the mirror still refuses to download B. Spec §5.3 permits retry once the pointer changes. Track the observed pointer separately and reset suppression whenever that identity changes, including removal.
- P1 — Task 4, Step 3: the streaming DirStore implementation reads the existing blob into memory. Plan:1005 calls
os.ReadFile(p)before checking create-only existence. Republishing an existing database therefore allocates its entire contents—potentially 1 GiB—despite introducing this interface to bound memory. UseStatfor create-only checks and streamed hashing when an existing ETag must be compared.
- P1 — Task 6, Step 3:
ctxReadercollides with an existing test type. Plan:2009 declaresctxReaderand itsReadmethod in packageconsole.internal/console/apidb_test.go:642already declares both, with a different shape and behavior. The console test package will not compile. Give the publisher helper a distinct name and updatecopyCapped.
- P1 — Task 7, Steps 1 and 3: the supplied oversize test fails against the supplied implementation. Plan:2317 sets
maxBytes = p.Size - 1. The implementation readslimit + 1bytes, obtaining exactlyp.Size, then checks onlyn != p.Sizeat line 2630. The blob passes both size and digest checks. Rejectn > limitas well, or reject a declared size above the configured cap before downloading.
- P1 — Task 11, Step 3: the CLI insertion references an undefined variable. Plan:3827 prescribes
printAnalyticsTable(w, "Countries", resp.Countries). The renderer usesres, including the adjacent call atanalytics_cmd.go:149. Change the insertion tores.Countries; the literal instruction otherwise breaks the root package build.
- P1 — Tasks 9 and 12, Step 5: commit commands omit required implementation changes. Plan:3401 omits
backhaul_e2e_test.go, although Task 9’s new test depends on fields added there. The Task 12 command at line 4068 omitsgeoippublish.go, although its handler depends on the newStage/Commitsplit. Following these commands produces commits missing dependencies that local working-tree tests can conceal. Include both files and verify the committed result from a clean checkout.
- P2 — Task 12, Step 1: the HTTP expectations contradict the asynchronous contract and existing authorization behavior. Plan:3899 requires successful PUTs to return 200 and invalid databases to return 422, while the same task requires staging followed by a 202 job. Its service-token expectation is also 404, whereas
internal/console/authcli.go:438returns 403 for an empty role set. Update the tests to expect 202 and poll for validation results, and preserve the existing 403 service-credential gate.
- P2 — Task 12, Step 3: the reused job API cannot return the promised pointer. Plan:3935 requires the existing job type, and lines 3939 and 4036 require polling to return the publication pointer.
systemJobatinternal/console/apisystemupdate.go:48stores only steps, completion, and error; its handler at:587exposes only those fields. Explicitly add an optional result to the job, locked snapshot, response schema, and CLI polling path. Preserve the result belonging to that job rather than rereading the potentially changed current pointer.
- P2 — Task 10, Step 3:
Loopdrops the TLS configuration required by its new integration test. Plan:3536 introducesDialConfigand updates the handler used byLoop, but does not replaceLoop’s existingDial(ctx, cfg.URL, cfg.Name, cfg.Token)call atinternal/tunnelclient/tunnelclient.go:105. That call cannot carrycfg.TLSConfig, so the test server’s certificate pool is lost. Explicitly changeLoopto callDialConfig(ctx, cfg)and verify the TLS integration test with certificate verification enabled.
- P2 — Tasks 10 and 11, Step 1: tunnel analytics assertions contradict each other and the ingress counting rule. Plan:3475 asks the remote meter to record GB; line 3682 requires zero remote observations, and line 3684 asks to complete the earlier assertion. Line 3682 also expects zero hub countries over plaintext, although the hub still computes its own ingress result. Replace these with one consistent table: zero remote observations for either transport, and hub country counts from the hub’s result. With the stated GB setup, both transports produce two GB pageviews at the hub.
- P2 — Tasks 9 and 10, Step 1: required trust-boundary tests are unassigned. Plan:3094 tests forgery through the TCP helper, while Task 10’s scene covers a successful tunnel and plaintext fallback. Neither task assigns the full spec §8.4 matrix: every proxy type with connection nomination and cache replay, the tunnel box’s public listener, a backhauled door, rotation-window backhaul, and transported miss/off states. Assign these cases explicitly to the relevant task, with assertions on backend headers and lookup/counting behavior.
- P2 — Task 7, Step 1: the recovery tests do not exercise the promised failure paths. Plan:2227 uses
deadbeefas a SHA, so the “missing file” test succeeds through invalid-SHA handling before opening a generation. The expiry test at line 2291 is sequential, and line 2272 tests pointer metadata rather than expired downloaded metadata. Add a valid missing-generation SHA, injected disk/crash failures, pointer-read and deleted-blob failures, and controlled concurrent expiry/install tests, as required by spec §§5.3 and 14.
- P2 — Task 6, Step 1: the different-type shrink assertion passes without enforcing its intended property. Plan:1715 force-publishes the Country fixture, resetting the inflated node count from 99,999 to 1,704. The subsequent City fixture has 1,547 nodes, so it passes even if the implementation incorrectly applies the shrink check across types. Reinstate the inflated count before the different-type assertion, or isolate that case. Also assign the spec-required publish/off race and foreign-pointer CAS tests; the sequential sweep/off test at line 1765 covers neither.
- P2 — Task 9, Step 1: the WebSocket helper does not expose request headers. Plan:3284 claims
upgradeEchoBackendechoes received headers. Atinternal/edge/edge_test.go:2012, it actually reads a client-supplied line after upgrading and echoes that line with a tag. The named bypass-recording test also does not supply the claimed real-client handshake. Add a backend that records the actual upgrade request headers, and use the real connection pattern fromTestMultiUpstreamServesWebSocketUpgradeat:2030.
- P2 — Task 1 and the final gate: the required real GeoLite2 measurement has no assigned step. Plan:116 makes Task 1 solely the bucket lifecycle change; the final gate does not restore the measurement requirement. Spec §17 explicitly assigns real DB-IP and GeoLite2 City probe and
Verifymemory measurements to Plan 1.2026-10-06-platform-geoip-FACTS.md:30confirms GeoLite2 was not measured. Add an explicit measurement step and record its results, or mark that requirement outstanding pending access to a real GeoLite2 City file.
Verdict: revise.