The concrete papercut, already loaded
flyingrobots/edict branch docs/action-rename-upkeep renames Intent → Action workspace-wide. It is unmerged. The pinned Edict (df80f92a) still parses intent, and all three .edict sources here still say intent:
src/hello_echo.edict
effect/src/observe-workspace.edict
patch/src/apply-validated-patch.edict
When that branch lands, advancing producers.lock.json and renaming those sources must happen in one commit, or the build fails closed. That is the pin working correctly. It is also a manual step nobody is currently scheduled to notice.
The wrong fix
Failing CI when a pinned producer trails its main. That makes reproducibility subordinate to novelty. An exact lock exists to preserve a known basis; the producer advancing does not invalidate that basis. A stale pin is maintenance information, not a broken proof.
The right shape
Two mechanisms, deliberately separated:
Required CI — unchanged:
- pinned commits exist
- producer checkouts are clean
- lock matches checkout
- the full witness suite passes
Scheduled advisory — new, never blocking:
- detect newer producer heads
- update
producers.lock.json on a branch
- apply required source migrations (
intent → action is the live example)
- run every witness against the proposed pins
- open a PR carrying old coordinates, new coordinates, and any failures
Freshness becomes a proposed event with evidence attached, rather than either ambient drift or a red build.
Why now
The rename is the first migration that will actually require step 3. Building the mechanism after it bites is strictly worse than building it while there is exactly one known migration to encode.
Acceptance
- A scheduled workflow that can open a pin-advance PR with witness results included.
- It cannot fail the required gate.
- The
intent → action migration is encoded as its first case.
Provenance
Surfaced by an external review; the failing-CI-on-staleness version was my own suggestion and was wrong for the reason above.
The concrete papercut, already loaded
flyingrobots/edictbranchdocs/action-rename-upkeeprenames Intent → Action workspace-wide. It is unmerged. The pinned Edict (df80f92a) still parsesintent, and all three.edictsources here still sayintent:src/hello_echo.edicteffect/src/observe-workspace.edictpatch/src/apply-validated-patch.edictWhen that branch lands, advancing
producers.lock.jsonand renaming those sources must happen in one commit, or the build fails closed. That is the pin working correctly. It is also a manual step nobody is currently scheduled to notice.The wrong fix
Failing CI when a pinned producer trails its
main. That makes reproducibility subordinate to novelty. An exact lock exists to preserve a known basis; the producer advancing does not invalidate that basis. A stale pin is maintenance information, not a broken proof.The right shape
Two mechanisms, deliberately separated:
Required CI — unchanged:
Scheduled advisory — new, never blocking:
producers.lock.jsonon a branchintent→actionis the live example)Freshness becomes a proposed event with evidence attached, rather than either ambient drift or a red build.
Why now
The rename is the first migration that will actually require step 3. Building the mechanism after it bites is strictly worse than building it while there is exactly one known migration to encode.
Acceptance
intent→actionmigration is encoded as its first case.Provenance
Surfaced by an external review; the failing-CI-on-staleness version was my own suggestion and was wrong for the reason above.