Repository navigation
docs(pins)!: report every pinned input's currency, and advance the charly and umbrella pins - #200
Conversation
…arly and umbrella pins Refs #196 The site is generated from THREE pinned inputs — the guidance corpus (this repo's `marketplace` gitlink), the `charly` commit the deploy clones, and the umbrella commit the deploy clones — and every one of them is advanced by a MANUAL act after its producer lands. The drift gate CANNOT see that: the PINNED sources regenerate their own (old) pages perfectly, so a stale pin is invisible to it. The gate answers "does the committed content match what the pinned inputs generate?" (yes, always); it never answers "is each pinned input itself current?". Measured before this change: charly pin: bafd8dbc3110904872831998fb4caa701cc2990c is behind — 97 commit(s) umbrella pin: e631aacf32df4e26a66f2cb6a75fc9e85e212399 is behind — 413 commit(s) Both were valid `behind` states — both ancestors of their producer's merged main, neither a divergence — and nothing in this repo said so. The report that watched the corpus alone watched one of the three. The corpus-only report is REPLACED, not extended beside itself: `.github/docs-corpus/ check_corpus_currency.sh` and its fixtures are deleted, and `.github/scripts/ check_pin_currency.sh` takes their place with the scope widened to every pinned input the site consumes. The corpus's own line is worded byte for byte as it was, so a reader who knows the old line reads the same words. The report speaks the pin contract's own states — `cur`, `behind`, `not-on-the-served-line` — plus two of its own for the cases it refuses to guess: `undecidable` (the history could not be deepened, so ancestry cannot be judged) and `unreadable` (the pin, or the producer's merged main, could not be read). It is REPORTED and never failed: a pin that is behind is an advance available NOW, and the remedy is a regeneration PR that bumps the pin, not a gate. The judgment must be DECIDABLE before it is reported. `merge-base --is-ancestor` answers "not an ancestor" for a commit the clone does not have — indistinguishable from a real squash-advance — and the corpus checkout in CI IS a depth-1 clone (actions/checkout runs `git submodule update --init --force --depth=<fetch-depth>` with its default `fetch-depth: 1`). A depth-1 history therefore cannot judge ancestry at all, and reporting from it would state a FALSE state: a divergence for a pin that is merely behind, with a wrong commit count. So a shallow history is DEEPENED first, and when the deepening cannot be done the report says `undecidable` and never guesses. A false state is worse than no report. The fixtures carry that case — a depth-1 checkout at a pin that IS behind — and the mutation that removes the deepening turns the suite red with the false state in it. THE TWO ADVANCES. `charly` moves bafd8dbc -> be7a505f (97 commits behind, now `cur`) and the umbrella moves e631aacf -> 1c88fcf1 (413 commits behind, now `cur`). Both are MERGED refs — the tips their producers' merged `main` serves — reached through the workflow's own recorded pin, never by a hand-pin. The pages each advance projects are regenerated here, and the umbrella's four root narratives are byte-identical across those 413 commits, so the umbrella's advance changes no narrative page. THE PINS ARE RECORDED ONCE. The two CI-time commits live in the workflow's own `env:` block, which the deploy's clone step consumes and the report reads — so a SHA can no longer be written in one place and forgotten in the other. The corpus pin is the committed gitlink, and the report reads it from the commit's TREE, not from the checkout's HEAD: the checkout is a convenience, the tree entry is the pin. No page is hand-edited. The pages are the generator's output for the advanced pins, and the drift gate proves the committed tree matches this repo's own pinned inputs exactly — RED on the working tree before this commit, a no-op after it. Two findings are separable from this change and are FILED, not fixed here: #199 (the release-TAG class of pins, whose currency question the org has not given a state) and opencharly/plugin-docs#24 (the generator's multi-owner command-word sentence, which counts pinned versions of one plugin as "plugin candies" and hardcodes "Both" — it predates this change and is wrong on 37 of the 79 command-word pages). Refs #196 Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
|
STATUS Agent: charly · session PR open: #200 — What is done. The report is in and green: Both CI-time pins are advanced to their producers' merged tips ( The proof, on the committed tree. 14 fixtures / 40 assertions, 0 FAIL, and three proven mutations (the deepening removed → 34 failing assertions; Two findings filed, not folded in. #199 (the release-TAG pin class, whose currency question the org has not given a state — claimed there) and opencharly/plugin-docs#24 (the generator's multi-owner command-word sentence counts pinned VERSIONS of one plugin as "plugin candies" and hardcodes "Both" — it pre-dates this change and is wrong on 37 of the 79 command-word pages). What is next. Read the validator's full report, fix every finding in ONE commit per round, and land on its PASS. The next update lands when the validator's verdict arrives, or at the end of the round it names. Agent: charly · session |
Review — PASSI re-derived every claim in the body against the current diff, commit list, and (empty) comment thread. No designated maintainers are configured for this run, so no comment is treated as a sign-off; the change stands on its own evidence. What I verifiedDiffstat and file accounting — internally consistent.
Test coverage — the count in the body is correct. Report correctness. Workflow. Generated pages. R5 sweep. Non-blocking observations
No correctness, security, scope, or honesty defect was found that would justify blocking. The body’s evidence is internally consistent and reproduced by the diff. Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
Closes #196
Summary
Head
4f824fca41725e9d133944ad9c4e67af61adf4dd— the commit this PR pushes: 133 files changed, 2782 insertions(+), 493 deletions(-) — 127 generated pages (50 added, 67 modified, 10 replaced by their newer version-stamped counterpart) and 6 control files (two new scripts, the two retired scripts deleted with them, the deploy workflow, and this repo'sAGENTS.md).The site stops trailing its producers, and nothing trails it silently any more. Two things land here, and they are the two halves of one question: is each pinned input the site is generated from current?
1 — the report. The site is generated from THREE pinned inputs: the guidance corpus (this repo's
marketplacegitlink), thecharlycommit the deploy clones, and the umbrella commit the deploy clones. Every one of them is advanced by a MANUAL act after its producer lands, so the site trails its producers by however long nobody ran the regeneration PR — and the drift gate CANNOT see it, because the PINNED sources regenerate their own (old) pages perfectly. The drift gate answers "does the committed content match what the pinned inputs generate?" (yes, always); it never answers "is each pinned input itself current?"..github/scripts/check_pin_currency.shanswers that second question for all three pins, and.github/scripts/check_corpus_currency.sh— which watched the corpus alone — is deleted in the same cutover (R5). The report speaks the pin contract's own vocabulary and its own states:cur— at the producer's merged main. Obligates nothing.behind— N commits behind the producer's merged main. An advance available NOW.not-on-the-served-line— the pin is off the producer's main line. A squash-advance, whose one remedy is the same asbehind's. NOT a divergence, and the report never calls it one.undecidable— the producer's history is shallow and could not be deepened, so ancestry cannot be judged.unreadable— the pin, or the producer's merged main, could not be read.The answer is REPORTED, never failed. A pin that is behind is an advance available now — the same shape the pin contract calls
behind: a reportable state, not a broken edge. A gate that FAILED on it would be red on every push until somebody ran the regeneration PR, and the remedy is that PR, not a gate. The report exits 0 in every state, and its fixtures assert that.The judgment must be DECIDABLE before it is reported.
merge-base --is-ancestoranswers "not an ancestor" for a commit the clone does not have — indistinguishable from a real squash-advance. The corpus checkout in CI IS a depth-1 clone (actions/checkout runsgit submodule update --init --force --depth=<fetch-depth>with its defaultfetch-depth: 1). A depth-1 history therefore cannot judge ancestry at all, and reporting from it would state a FALSE state — a divergence for a pin that is merely behind, with a wrong commit count. So a shallow history is DEEPENED first, and when the deepening cannot be done the report saysundecidableand never guesses: a false state is worse than no report.The pins are recorded ONCE. The two CI-time pins live in the workflow's own
env:block, which the deploy's clone step consumes and this report reads — one record, one occurrence of each SHA in the whole repository, so a SHA can no longer be written in one place and forgotten in the other. The corpus pin is the committed gitlink, and it is read from the commit's TREE rather than from the checkout's HEAD: the checkout is a convenience, the tree entry is the pin.2 — the two advances.
charlymovesbafd8dbc3110904872831998fb4caa701cc2990c→be7a505f476c1a5b0302d878e0b5686a2cde3e07(97 commits behind, nowcur), and the umbrella movese631aacf32df4e26a66f2cb6a75fc9e85e212399→1c88fcf15f8fb9dd8b2814210472a63d3a79d0e2(413 commits behind, nowcur). Both werebehind— valid states, both ancestors of their producer's merged main, neither a divergence. The pages each advance projects are regenerated in the same PR.What the advance changes, measured. The umbrella's four root narratives —
SOUL.md,VISION.md,GRIEVANCES.md,LIBERATION.md— are byte-identical across those 413 commits, so the umbrella's advance moves no narrative page; the charly advance moves thereference/**pages, which are the generator's output for the new tree.What it found, and where it went. Two findings are separable from this change and are FILED, not folded in:
How tested
1 — the report's own fixtures, and the mutations that prove they can fail.
Fourteen fixtures, forty assertions. Every state the report can name is built as a
fixture and asserted EXACTLY —
cur,behind,not-on-the-served-line,unreadable(in four distinct shapes),
undecidable, the CI-time pins, and the all-three-pinscount. The last one is what keeps the report honest about its SCOPE: a change that
quietly stopped reporting one of the three would leave the site exactly as unobserved
as it was before the report existed, with every other fixture still green.
The first mutant is the one that matters. With the deepening removed, the depth-1
fixture at a behind pin reports a FALSE state:
cur, with the pin's OWN sha as the "merged main" — a pin that is actually behind,reported as current, with a wrong tip. That is the false state the deepening exists
to prevent, and the fixture catches it.
2 — the report, against this repo's own records, before the advance.
3 — the report, against the same records, after the advance — on the committed tree.
All three are
cur, and the report still exits 0.4 — the R5 sweep: the retired corpus-only report is gone, and nothing live names it.
rc=1— no hits. The only surviving mentions of the retired name are inCHANGELOG/, which records history and is where history belongs:5 — the workflow's own gates, on the committed tree.
6 — the regeneration, and the drift gate.
The regeneration is the workflow's own command, run against the workflow's own pinned
inputs: the
charlyclone atbe7a505fwith itsbox/*submodules, the umbrella at1c88fcf1, the corpus at this repo's gitlink, and theplugin-docsCLI built from thetag this repo pins (
v2026.289.0814).Before the commit, the drift gate was RED — the committed tree did not yet carry the
regenerated pages:
After the commit, the regeneration was run again — over the committed tree, byte for
byte — and it changed NOTHING:
A fresh generation over the committed tree leaves ZERO changes — not one page, not one
byte — and the drift gate is green.
For contrast, the SAME generator over the OLD pins produced 194 plugin pages, 801 candy
pages and 201 box pages; the advance is what brings the site to 196/834/216:
7 — the site's own build, and the built site's content.
The build carries no warning and no error, and the search index is built over the same
1749 pages.
Rulebook compliance
/charly-build:docs(thecharly docs generateverb, the site repo's generation workflow and the drift-gate recipe),/charly-tools:docs-site(the Astro/Starlight candy and the site's build),/charly-internals:git-workflow(the pin contract, the PR body's form and the landing rules),/charly-internals:strict-policy(the discipline rules this change is judged by) and/charly-internals:root-cause-analyzer(the RCA the filed findings carry). This repo's ownAGENTS.mdwas read for it (Part II fix(deps): clear three high-severity advisories via wrangler 4.118.0 #4).reference/**andrecipes/**pages project a charly 97 commits and an umbrella 413 commits behind their producers' merged mains) and the root fix (this PR: the report that names every pinned input, plus the two advances, so the site is current again and the next drift is visible). Two further findings are separable by construction and are FILED, each with its own RCA: the release-TAG class of pins, in 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, and the generator's multi-owner command-word sentence, in every multi-owner command-word page counts pinned VERSIONS of one plugin as "plugin candies", and hardcodes "Both" plugin-docs#24. Both pre-date this change; neither is introduced by it.env:block — and the deploy's clone step and the report read that one record. The old corpus-only report is DELETED in the same cutover rather than left beside the new one.undecidable, not guessed. No sleep, no blind retry, no suppression.be7a505fand the umbrella at1c88fcf1are their mergedmaintips. This PR points the projection at the current sources and regenerates from them; it does not restate their rules in prose of its own. This repo's ownAGENTS.mdis updated to name the report and the pin record it reads.CHANGELOG/, where history belongs..worktrees/docs-196/docs— a clone of this repo alone — onfeat/pin-currency-report-196, branched from this repo's freshorigin/main(a166ee1). The tree's status was empty before the change. No other session's branch, worktree, issue or file was touched; no history was rewritten, no force-push, no hook bypass, and no push tomain.npm auditagainst the real advisory database.plugin-docsCLI built from the tag this repo's own workflow pins (v2026.289.0814), from its own source, in this session — not a shared install.disposable: truetarget.cur— no gitlink moves in this PR.mainserves — through the workflow's own recorded pin, never by a hand-pin or a branch checkout; the currency question was asked with this repo's own report, and the answer for all three iscur.AGENTS.mdwas read before any change here.STATUSis posted on it at each milestone. The two separable control gaps were filed as 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 (claimed there) and every multi-owner command-word page counts pinned VERSIONS of one plugin as "plugin candies", and hardcodes "Both" plugin-docs#24 (filed for its owning repo).Agent:line before the italic trailer, and every coordination comment on this scope is in the nine-label grammar, with the attribution block LAST in each.STATUScomment lands on the site's own charly and umbrella pins are 91 and 373 commits behind their merged mains, and nothing reports it #196 at each milestone.Change classification
reference/**projects — so this is not the documentation-only class, and the tier is a runtime tier.AGENTS.md; +689 −392).content: committed tree matches the pinned inputs), the pin-currency report, the dependency-advisory gate, the step-deadline gate and the Astro build — every step, zero failures, zero warnings.fully tested and validated— the change-class gate passed on the final tree, and the changed path (the sources the site is generated from) was executed live, with the "before" retained.disposable: truetarget; the site is built by the real Astro build, pasted above.Filed issues
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 — the site's release-TAG class of pins is unobserved: the generator itself is pinned at
v2026.289.0814whileopencharly/plugin-docshas publishedv2026.295.2045, and 64 of the 65 wiring-candy plugin pins in.github/docs-corpus/pins.tsvname a tag older than their repo's newest (the one current row,plugin-build v2026.296.1104, is current only because docs(corpus)!: advance the corpus and the plugin-build pin, and regenerate the site on --stage-parallelism #198 had to advance it for a content reason). The mechanism (a tag pin moves only when somebody rewrites it by hand, and nothing in this repo rewrites either class —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), the missed control (the pin contract defines its states against a BRANCH's merged main, so a tag's currency question — "is there a newer RELEASE?" — has no state to answer in; 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 is that gap, org-wide), the blast radius (the generated half: the generator decides how every page is rendered, and the 65 wiring pins decide which plugin versions the site'sreference/plugin/**andreference/candy/**sections project) and the root fix (the org defines the tag state, then this repo reports its tag pins in it, then a wave advances them with the pages they project) are on that issue, with the measured evidence. Not blocking here: this change's claim is that the site's COMMIT pins are current and reported, and the tag class is a different pin class with a different remedy and a different set of pages — separable by construction. The report's own header states the scope explicitly, so the omission is a stated scope, not a silent gap.every multi-owner command-word page counts pinned VERSIONS of one plugin as "plugin candies", and hardcodes "Both" plugin-docs#24 — the generator's multi-owner command-word sentence counts pinned VERSIONS of one plugin as "plugin candies" and hardcodes the quantifier "Both". Measured on the pages this PR regenerates: all 37 of the site's 79 multi-owner command-word pages carry a count that is not the number of distinct candies — 36 of them name ONE plugin repeated once per pinned version (
alias.mdreads "served by 2 plugin candies —plugin-aliasandplugin-alias"), and onlyfeature.mdnames two distinct candies while claiming three; five pages (the ones claiming three or four) additionally carry the wrong "Both are real invocations". The mechanism (the generator groupscommand:providers by word into an owner list of pinned version instances —byWord[word] = append(byWord[word], p)— then printslen(c.owners)as the number of "plugin candies" and joins the per-version names, with aBothliteral written for the two-owner case;cliPageDescriptionrepeats the same count in the frontmatter, so the wrong count is also the site's search-result text), the missed control (the only test of that sentence,TestGenerateCLIMultiOwnerPageNamesEveryOwner, uses two owners with two DIFFERENT names — the one shape in which the count, the name list and the literal all agree — so neither the count nor the quantifier is asserted anywhere), the blast radius (37 of the 79 command-word pages this repo publishes, plus their search-result text, and the defect grows with every corpus pin wave that adds a version) and the root fix (count the DISTINCT candy names, join the distinct names, derive the quantifier from that count, and add fixtures for a repeated owner name and for a count of three) are on that issue. Not blocking here: the defect pre-dates this change — the committed tree already carries all 37 pages in this shape — and the fix belongs to the generator, in another repo, with its own producer-first release. This PR changes exactly one of those pages, from "3" to "4", both of which are wrong in the same way; the finding is filed, not folded in.Agent: charly · session
ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)