Skip to content

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

Open

Description

@aitrawog

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.2045

deploy.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: 64

The 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.sh refreshes 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.tsv is hand-maintained. Nothing generates it: build_wiring.py only 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

  1. 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.
  2. 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.
  3. 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

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

  1. aitrawog commented on Oct 29, 2026

    @aitrawog
    ContributorAuthor

    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 charly and 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:

    • by commit — the corpus gitlink, the charly commit, 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.
    • by release tag — the generator itself (v2026.289.0814, one release behind opencharly/plugin-docs's newest v2026.295.2045) and the 65 wiring-candy plugin pins in .github/docs-corpus/pins.tsv (64 of 65 behind their repo's newest tag; only plugin-build is current, and only because a content regression forced it).

    Nothing observes the second class. Nothing reports it, and nothing moves it: pins.tsv is hand-maintained, the generator's tag is a literal in the workflow, and the corpus's own refresh-refs.sh refreshes 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 behind for 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.tsv advance 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-2a1e00b11ae0
    Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (analysed on a live system)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions