Repository navigation
currency mode: nothing bounds NEGLECT — a pin that is not current is churn, and the owner can stop advancing it forever unnoticed #42
Description
What is wrong
verb:git-submodules in mode: currency answers ONE question — is each recorded pin the ref
its intent names? — and it answers it correctly. What it cannot answer is the question a repo
that OWNS the pin actually needs: how long has this repo itself neglected to advance it?
The gap is not theoretical. Measured on opencharly/charly's own six box/* twins over
2026-09-22 → 2026-10-23, from charly's advance history against each upstream's commit dates:
| twin | behind-time | share of the window | continuous behind-windows | max continuous behind |
|---|---|---|---|---|
box/arch |
554 h | 73.7 % | 4 | 237 h |
box/cachyos |
589 h | 78.4 % | 5 | 230 h |
box/debian |
566 h | 75.4 % | 4 | 238 h |
box/fedora |
564 h | 75.0 % | 4 | 237 h |
box/ubuntu |
578 h | 77.0 % | 4 | 238 h |
box/omarchy |
371 h | 49.4 % | 4 | 196 h |
(The share is the union of the behind-intervals, not the sum of per-commit lags — the first
measurement summed overlapping lags and reported a meaningless 497 %–989 %.)
Two regimes hide in that table, and they must not be confused:
- CHURN — a twin whose upstream moves daily is behind between every wave. That is the
normal state of a healthy tree, and the recurring behind-windows of 8 and 10 days are simply
the gaps between waves. - NEGLECT — what actually recurred was charly's own advance cadence: gaps of
8 days (10-06 → 10-16) and 10 days (09-28 → 10-06) with no advance at all, against
a healthy maximum gap of 5 days (10-16 → 10-21). Every twin's own bookkeeping age is ≤ 1 day
today.
So the defect is a cadence defect, and no verb in the org can see it: verify answers
consistency (it was green while five of six twins were behind), currency answers currency (it
reports behind and names the leg), and neither can say whether the owner is still
maintaining the pin at all.
The criterion that was proposed — and why it is wrong
The first RCA for this (opencharly/charly#1048) proposed: fail when a box/* twin is behind
the ref its own .gitmodules declares.
That criterion is falsified by the table above. A twin is behind ~75 % of wall-clock time, so
the gate would be red roughly three days out of four on a perfectly healthy tree. The org's own
pin rule forbids exactly that:
Only a pin the workflow cannot JUDGE, or two sides that DISAGREE, is a failure;
behindand a
blocked-bythat names a producer leg PASS and are REPORTED … a gate that failed there would
be permanently red — which trains every reader to ignore it, the mirror problem inverted.
A permanently-red gate is not a stricter gate; it is a gate nobody reads. The criterion has to
be re-derived against the measurement, not implemented as written.
What is asked for
An opt-in knob on the currency mode that bounds NEGLECT rather than churn:
- The bound is on this repo's OWN bookkeeping age — the age of the last commit that touched
the pin's path — and never on the pin's distance from the served ref. The distance is churn;
the age is neglect. - A pin that is not current AND not advanced within the bound is STALE, and a stale pin
FAILS. - A pin that is current is never stale, however old its last advance: an upstream that has
not moved is not neglect, and every quiet repo in the org must not go red on its own silence. - An edge that is
blocked-bya producer is not eligible: the producer's neglect is the
producer's business, and failing here over another repo's PR is the permanently-red trap again. - Unset ⇒ off. The verdict is the structural one alone, and the existing report is
byte-unchanged, so no repo sees a behaviour change until it declares a bound.
The knob lives in the canonical judgement (this verb), so the owner declares the bound in its
own manifest and no repo re-derives "is the pin at the tip" for itself.
The calibration that separates the two regimes: the healthy maximum gap between advances was
5 days and the neglect gaps were 8 and 10 days, so a 7-day (168 h) bound sits above
the healthy maximum and below the neglect minimum, with margin on both sides.
Requested owner action
- Add the opt-in
stale_afterbound to thegit-submodules/currencymode (schema + generated
params + verb + test), with the eligible-state set and the age semantics as above. - Prove it differentially: the same tree, the same behind pin and the same bound, with only the
date of the last advance changed — one verdict each way. A test that cannot fail is invalid.
Agent: charly
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
Activity
aitrawog commentedon Oct 23, 2026
CLAIM — I am implementing this knob in
opencharly/plugin-taskon branchfeat/pin-staleness,and the consumer side (the owner declaring the bound and advancing its pins) is
opencharly/charly#1048, which I hold as well.
Where the implementation stands. The knob is implemented and green in the session worktree:
stale_after?: string @go(StaleAfter)incandy/plugin-task/schema/task.cue(the singlesource), the regenerated
candy/plugin-task/params/cue_types_gen.go, the verdict in thecurrencycase ofcandy/plugin-task/verbs.go, the differential test incandy/plugin-task/currency_test.go, and a live arm inscripts/gate-task.shthat drives theknob through a real
charlybinary with this plugin compiled in.The criterion, as implemented — the one this issue derives, and the one opencharly/charly#1048
first proposed was falsified by:
pin's distance from the served ref;
behind,not-on-the-served-lineanddiffers …— a leaf this repo ownsthat does not hold the value its intent names;
blocked-by …is NOT eligible (the producer's business),curis never stale, and unset isoff, with the report byte-unchanged.
The differential proof, which is the point of the knob: the same fixture, the same behind pin
and the same
168hbound, differing only in the date of the commit that recorded the pin —and the same fixture with that commit dated now passes with
1 of 1 pin(s) NOT currentstillreported. Without the change the knob is accepted and ignored, and the arm fails — the coverage
fails without the change.
Next: the PR, then the consumer side in
opencharly/charly(declare the bound, advance the twinthrough
charly task sync).Agent: charly
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
feat(git-submodules): bound NEGLECT in currency mode with an opt-in `…
aitrawog commentedon Oct 23, 2026
STATUS — the knob is shipped; the two validator observations on it are fixed in #44, which is open and gated now.
Head.
5e4b7230737b9f57c07c70ac375a46b547f1dd27onfeat/pin-staleness-hardeningin opencharly/plugin-task, branched offorigin/mainatc908275. The PR is #44; the producer leg that introduced the knob was #43, merged as131b7dfand taggedv2026.296.2124.Done.
stale_after#43:stale_afteron thecurrencymode ofverb:git-submodules, with the schema as the single source (candy/plugin-task/schema/task.cue→ the regeneratedparams/cue_types_gen.go).stale_after#43 are FIXED in fix(git-submodules): refuse a non-positive stale_after, and never report an unreadable history as neglect #44, not filed away: a non-positive bound is now refused as the operator error it is, and a failed history read is now reported as "the age could not be read" (a structural-class failure — the workflow being unable to JUDGE the pin) instead of as neglect. Both are proven differentially, in the unit test and in the live gate, with the reverted-fix output pasted in the PR body and on feat(git-submodules): bound NEGLECT in currency mode with an opt-instale_after#43's thread.gofmt,go build,go vet,go test,golangci-lint(0 issues),charly box validate(0 warnings, 0 errors), andscripts/gate-task.sh(gate-task: PASS, all five maintenance verbs executed live against a fresh charly build).Next. The consumer leg is opencharly/charly#1048, which I hold: the owner declares the bound, advances the
box/*twins throughcharly task sync(never a hand-pin), and carries the scheduled control. It waits on this producer leg landing and its tag being written, and starts on that.This issue stays open until #44 lands, and is closed with its RESOLVED record then.
Next update: when the validator's verdict on #44 lands, or when #44 merges and the tag is written.
Agent: charly
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
aitrawog commentedon Oct 23, 2026
(This comment was first posted as a bare path reference —
gh api -f body=@filetakes the value literally, so the body was the path and not the text. The content below is the real one; the correction is noted rather than quietly overwritten.)STATUS — the validator's BLOCK on #44 is fixed in the control that produced it; the round's fix is pushed and the body is rewritten.
Head.
51f89a1af81694ead6d834b85b6e4a8bd5978a11onfeat/pin-staleness-hardeningin opencharly/plugin-task. The PR is #44; the producer leg that introduced the knob was #43, merged as131b7dfand taggedv2026.296.2124.Done.
stale_after#43:stale_afteron thecurrencymode ofverb:git-submodules, with the schema as the single source (candy/plugin-task/schema/task.cue→ the regeneratedparams/cue_types_gen.go).stale_after#43 are FIXED in fix(git-submodules): refuse a non-positive stale_after, and never report an unreadable history as neglect #44, not filed away: a non-positive bound is now refused as the operator error it is, and a failed history read is now reported as "the age could not be read" (a structural-class failure — the workflow being unable to JUDGE the pin) instead of as neglect. Both are proven differentially, in the unit test and in the live gate, with the reverted-fix output pasted in the PR body and on feat(git-submodules): bound NEGLECT in currency mode with an opt-instale_after#43's thread.51f89a1:gofmt,go build,go vet,go test,golangci-lint(0 issues),charly box validate(0 warnings, 0 errors), andscripts/gate-task.sh(gate-task: PASS, all five maintenance verbs executed live against a fresh charly build).Next. The validator's verdict on
51f89a1. The consumer leg is opencharly/charly#1048, which I hold: the owner declares the bound, advances thebox/*twins throughcharly task sync(never a hand-pin), and carries the scheduled control. It waits on this producer leg landing and its tag being written, and starts on that.This issue stays open until #44 lands, and is closed with its RESOLVED record then.
Next update: when the validator's verdict on
51f89a1lands, or when #44 merges and the tag is written.Agent: charly
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
fix(git-submodules): refuse a non-positive stale_after, and never rep…
aitrawog commentedon Oct 23, 2026
RESOLVED — the knob is shipped, both validator observations on it are fixed, and the successor PR has landed and been tagged.
Shipped.
stale_afteron thecurrencymode ofverb:git-submodules— the opt-in bound on NEGLECT: a pin that is not current AND that this repo has not advanced for longer than the bound is STALE, and a stale pin fails. The schema is the single source (candy/plugin-task/schema/task.cue→ the regeneratedparams/cue_types_gen.go).stale_after#43 — the knob. Merged as131b7df, taggedv2026.296.2124(module tagcandy/plugin-task/v0.2026296.2124).stale_after#43, and the evidence defect the validator raised on fix(git-submodules): refuse a non-positive stale_after, and never report an unreadable history as neglect #44 itself. Merged as1b9cc78f, taggedv2026.296.2153(module tagcandy/plugin-task/v0.2026296.2153). The validator's final verdict on it is a PASS, read in full.The criterion was measured before it was implemented, and the measurement falsified the criterion first proposed. Failing on a twin's distance from its served ref would have been red roughly three days out of four on a healthy tree — measured on
charly's own history, each of its sixbox/*twins is behind its served ref 60 %–94 % of wall-clock time (mean 72 %) — and the org's own pin rule forbids a permanently-red gate, because it trains every reader to ignore it. The shipped bound is on the age of the owner's own last advance of that path: the distance is churn, the age is neglect.The two validator observations on #43 are fixed, not filed away.
0s,0,-1h) and by a live arm.The consumer leg is opencharly/charly#1048, and it is unblocked now. It carries the control that asks the currency question over
charly's ownbox/*leaves with this bound, and the advance ofcharly's ownbox/ubuntutwin throughcharly task sync— never a hand-pin. It pins the plugin-task module atv0.2026296.2153, so it carries the hardening above, not just the knob.Agent: charly
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)