carlos / platform Public
REJECT
Reviewed acc6de7a..7b239870 only.
- F1 — NOT ADDRESSED (R12). Clearing
workerServingat activator.go:1972 ends the retry loop but does not protect captured builds. Worker A can still lose its staged copy after promotions to B and C remove its live-link and registry pins. An absent generations file still supplies no pins at pins.go:194. Sweep/restage can therefore destroy A’s recovery artifact. R12 does not satisfy §4.2’s requirement that referenced copies remain unchanged; it also introduces defect N1 below.
- F2 — ADDRESSED, with a new pacing defect (R13). Same-build respawns preserve
staleSinceat activator.go:1993, and crash/max-run recycling evaluates drift at workerbuild.go:64. Those changes remove the reported starvation. R13’s unconditional convergence is nevertheless incompatible with §7.9’s admission requirement; see N2.
- F3 — ADDRESSED for the reported chained-link case (R14). pins.go:60 pins every returned hop, and staged.go:101 captures the terminal path. The added restage-refusal test covers the original
live → operator-current → staged executablecase. However, R14’s exclusion of parent-directory resolution introduces N3.
- R11 note — ADDRESSED (R15). adopt.go:1739 no longer promises that the next full pass will restage a held version. Recovery is conditional on a pass actually restaging that version, or shipping a new name. The conservative refusal remains consistent with §4.2.
New defects introduced by the fix diff:
- N1 — P1: A digest refusal becomes acceptance on the next retry. activator.go:1972. Suppose live still names A, but A’s executable has changed from its retained digest. The first recycle correctly refuses it, then discards the retained identity. The next retry passes
onto=nil;StartWorkerStagedcallsResolveLive, hashes the damaged bytes as a fresh identity, and executes them. No promotion is required. §4.2’s refusal therefore lasts only one retry. Smallest fix: retain the captured identity after refusal; permit a different build only through explicit convergence/adoption admission. Address F1 through complete pins or conservative suppression of destructive staging and eviction.
- N2 — P2: Recycles bypass convergence pacing and a negative coalescing decision. workerbuild.go:64. Multiple workers with overdue drift and synchronized
max_rundeadlines all execute the installed build in one sweep. None consumescycled, so the existing one-per-sweep limit is ineffective for this path. Moreover, whenCoalesceRecyclereturns false because another canary is running, this branch still changes builds after the grace period—contrary to §7.9. Replacing one spawn with one spawn does not preserve rollout pacing. Smallest fix: share the sweep’s convergence budget with these paths; when scheduler admission is present, require it before changing builds. Otherwise recycle the captured build while preserving drift age.
- N3 — P2: Relative chained links can resolve to the wrong executable. staged.go:64. Consider
live/h → /opt/carlos/alias/current, wherealias → /opt/carlos/versions/v1/linksandcurrent → ../app. Filesystem resolution reaches/opt/carlos/versions/v1/app. The new lexical join/clean instead produces/opt/carlos/app. Previously, hashing and executing the intermediate path followed the filesystem correctly; now startup fails or executes the wrong file, and the real staged copy remains unpinned. Smallest fix: resolve each symlink’s containing directory before interpreting relative targets, retain intermediate pins, and fail closed when resolution is uncertain.
Out of scope: unchanged deferred findings and later-plan scheduler/generation integration were not re-reviewed.
Static review only; no files modified or tests run. git diff --check acc6de7a..HEAD passed.