Repository navigation
the release-TAG class of pins (the generator's own tag and the 65 wiring-candy plugin tags) is unobserved: the generator is one release behind and 64 of 65 plugin pins name a tag older than their repo's newest #199
Description
Problem
This repo pins three SOURCE inputs by commit — the corpus gitlink, the charly commit and the umbrella commit — and the site projects them. It also pins a further set of inputs by release tag, and nothing observes that class at all: not the workflow, not the report, not a gate.
| pinned input | where the pin lives | pin | state against its producer's newest release |
|---|---|---|---|
| the docs generator | .github/workflows/deploy.yml:233 |
v2026.289.0814 |
behind — opencharly/plugin-docs has published v2026.295.2045 |
| the 65 wiring-candy plugins | .github/docs-corpus/pins.tsv |
a v2026.242.* cohort |
64 of 65 behind — only plugin-build (v2026.296.1104) names its repo's newest tag |
Evidence (measured, 2026-10-29)
The generator's pin, against the repo's own served tags:
$ git ls-remote --tags --refs https://github.com/opencharly/plugin-docs.git \
| sed 's#.*refs/tags/##' | sort -V | tail -1
v2026.295.2045deploy.yml:233 pins v2026.289.0814 — one release behind the newest.
The 65 rows of pins.tsv, each row's repo being opencharly/<name> (the convention build_wiring.py itself uses: pod-* at the repo root, everything else at candy/<name>):
$ ... over the 65 rows of .github/docs-corpus/pins.tsv ...
cur: 1 behind: 64The single current row is plugin-build v2026.296.1104 — and it is current because #198 had to advance it, not because anything keeps it advanced: that advance was forced by a content regression (the retired --podman-jobs knob) that the old pin published. The other 64 rows have been frozen at the v2026.242.* cohort since the wiring candy was written, and every one of them names a tag older than its repo's newest.
Mechanism
A tag pin moves only when somebody rewrites it by hand, and nothing in this repo rewrites either class:
- the corpus's own
scripts/refresh-refs.shrefreshes the corpus's refs list (candy/charly-marketplace/charly.yml) — a different file, in a different repo, with 231 pins rather than these 65; - this repo's
pins.tsvis hand-maintained. Nothing generates it:build_wiring.pyonly READS it, and the workflow only READS it (deploy.yml:255); - the generator's tag is a literal in the workflow's clone step, and nothing moves it either.
So the tag class advances by hand, at whatever pace a human remembers to touch it — and the only tag that IS current is the one a content regression forced.
Missed control
The currency report this repo now owns (.github/scripts/check_pin_currency.sh, added by #196) covers the commit pins. That is the org's convention, not an oversight: the producer side of the same question — opencharly/marketplace's scripts/consumer-currency.sh — covers commit pins too, and says so in its own header.
But the convention exists because the pin contract defines its states against a BRANCH's merged main: cur, behind, not-on-the-served-line are all answers to "where is this commit relative to the line the remote serves?". A release tag is not on any branch. Its currency question is a different one — "is there a newer RELEASE?" — and the org has not given that question a state. opencharly/opencharly#793 is that gap, org-wide: the currency report names each pin's served commit and never says whether a TAG points at it.
That is exactly why the tag class must be FILED rather than folded into a commit-pin report: a report that emitted behind for a tag would be asserting a state the contract does not define. The org needs to define the tag state first (opencharly/opencharly#793), and only then can a report speak it here.
Blast radius
The generated half. The generator decides how every page is rendered, and the 65 wiring pins decide which plugin versions the site's reference/plugin/** and reference/candy/** sections project. So the site publishes a projection of a generator the org has already replaced, and of 65 plugin versions the org has already replaced.
What this issue does NOT claim
- It does not claim the site is wrong today. It claims the site is unfalsifiable about the age of its tag-class inputs — nothing in this repo would ever say so.
- It does not claim that all 64 rows must move in one wave. A wave's size is the generator owner's judgement, and a plugin's newest tag is not automatically the right pin (a pin exists to hold a projection steady, and moving one changes the pages it projects).
- It does not claim a divergence. Every one of these pins is a valid, published release.
The fix
- Give the tag class a state in the pin contract — the org-level question the currency report names each pin's served commit and never says whether a TAG points at it — so a body can call a pin 'merged and tagged' with no gate disagreeing opencharly#793 asks — so a release tag can be reported in the same vocabulary as a commit, with the same "an advance available NOW" semantics.
- Report the tag pins here, once that state exists: the generator's own tag and the 65 rows of
pins.tsv. The report must answer the tag question from the repo's own records, and must never guess a tag's currency from a commit's ancestry. - Advance the generator tag and refresh
pins.tsv, in one wave with the pages they project — the same producer-first shape as a commit-pin wave.
Related
- the site's own charly and umbrella pins are 91 and 373 commits behind their merged mains, and nothing reports it #196 — the commit-pin half of this same question, and the report that now covers it. This issue is filed from that PR as a non-blocking finding: the tag class is separable from the charly and umbrella legs (a different pin class, a different remedy, and its own pages).
- the currency report names each pin's served commit and never says whether a TAG points at it — so a body can call a pin 'merged and tagged' with no gate disagreeing opencharly#793 — the org-wide gap: the currency report says nothing about whether a TAG points at a served commit.
Agent: charly · session ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (analysed on a live system)
Activity
aitrawog commentedon Oct 29, 2026
CLAIM — the release-TAG class of pins, and the contract gap underneath it.
Taking this finding. It was filed from #196 (the commit-pin leg: the site's own
charlyand umbrella pins) as a non-blocking R1 finding: the commit-pin class and the tag-pin class are separable — a different pin class, a different remedy, and a different set of pages — so the tag class is filed rather than folded in.What the finding is. The site's generation pipeline pins its inputs in two different ways, and only one of them is observed:
charlycommit, the umbrella commit. These are the pins the pin contract has states for (cur,behind,not-on-the-served-line), and the site's own charly and umbrella pins are 91 and 373 commits behind their merged mains, and nothing reports it #196's report now names them.v2026.289.0814, one release behindopencharly/plugin-docs's newestv2026.295.2045) and the 65 wiring-candy plugin pins in.github/docs-corpus/pins.tsv(64 of 65 behind their repo's newest tag; onlyplugin-buildis current, and only because a content regression forced it).Nothing observes the second class. Nothing reports it, and nothing moves it:
pins.tsvis hand-maintained, the generator's tag is a literal in the workflow, and the corpus's ownrefresh-refs.shrefreshes a different file in a different repo.Why it is filed rather than folded into #196's report. A tag's currency question is "is there a newer RELEASE?", not "is this commit behind the merged main?" The pin contract defines its states against a branch's merged main, so a report that emitted
behindfor a tag would be asserting a state the contract does not define. That gap is opencharly/opencharly#793, and it is the org-wide root: the currency report names each pin's served commit and never says whether a TAG points at it.What the work is, in order. (1) The org defines the tag state — opencharly/opencharly#793. (2) This repo reports its tag pins in that state, once it exists. (3) The generator tag and
pins.tsvadvance in one wave, with the pages they project.Not claimed here: the 64 rows do not move as part of this. A pin exists to hold a projection steady, and moving one changes the pages it projects — the wave's size and the per-plugin choices belong to the generator's owner, not to the observation.
Next update: when the org-level state is defined and this repo's report can speak it — or when the operator redirects the scope.
Agent: charly · session
ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (analysed on a live system)
docs(pins)!: report every pinned input's currency, and advance the ch…