Skip to content

docs(corpus): advance the corpus submodule to the corpus's served head - #208

Merged
github-actions[bot] merged 1 commit into
mainfrom
feat/corpus-pin-206
Oct 29, 2026
Merged

github-actions[bot] merged 1 commit into
mainfrom
feat/corpus-pin-206

Conversation

@aitrawog

Copy link
Copy Markdown
Contributor

Closes #206

Summary

Head ee9b3098c71565ce0cf40e8631cddbce2787f0a9 — the commit this PR pushes. 1 file changed, 1 insertion(+), 1 deletion(-): the marketplace submodule gitlink.

The site stops projecting a corpus that is behind the published one. This repo's marketplace submodule advances 3cf744b9ef3dcaf5e3dadff01648db087385ef19 → 75e1d4a1379daf164a1ed2bc9c0678ad1ed20312 — the head opencharly/marketplace's merged main serves. It is one commit above that repo's tag v2026.302.1126 (ec7ee57c) because tag-on-merge writes CHANGELOG/ after the tag, so the pin names what main serves, not the tag and not the merge commit.

The scope was derived from the producer's own report, not written by hand. Run live at the advanced pin, the corpus's own consumer-currency report names exactly one consumer behind — this repo — and this diff moves exactly that one:

$ bash scripts/consumer-currency.sh
consumer-currency: 2 consumer(s) read, 1 behind, 0 not-on-the-served-line, 0 undecidable, 0 unreadable (merged main: 75e1d4a)
  opencharly/docs  marketplace  3cf744b  behind — 2 commit(s) behind the corpus's merged main; an advance available NOW (a pin-bump PR in that consumer's repo)
  opencharly/opencharly  marketplace  75e1d4a  cur — at the corpus's merged main
CURRENCY_RC=0

(The report reads each consumer's RECORDED pin, so it keeps naming this repo as behind until this PR lands; the umbrella's consumer leg of the same wave landed first and already reads cur.) The other consumer of this corpus is not a consumer of THIS repo's pages, so there is no second leg here.

No generated page changes — and that is measured, not assumed. The corpus's own diff between the two pins touches two paths, and neither is an authored body:

$ git -C marketplace diff --stat 3cf744b9 75e1d4a
 CHANGELOG/2026.302.1126.md          | 256 ++++++++++++++++++++++++++++++++++++
 candy/charly-marketplace/charly.yml |   4 +-
 2 files changed, 258 insertions(+), 2 deletions(-)

$ git -C marketplace diff --name-only 3cf744b9 75e1d4a -- '*/SKILL.md' '*/references/*'
(no hits — no authored skill body changed)

The second path is the corpus's refs list, and it advanced two owners:

-            - '@github.com/opencharly/plugin-marketplace:v2026.302.0533'
+            - '@github.com/opencharly/plugin-marketplace:v2026.302.0634'
-            - '@github.com/opencharly/opencharly:v2026.302.0124'
+            - '@github.com/opencharly/opencharly:v2026.302.1105'

Both of those owners advanced without touching a body, which is why the corpus's checked-in projections of them are byte-identical at the two corpus pins — and why the site's recipes/** pages, which ARE that projection, do not move:

$ gh api "repos/opencharly/plugin-marketplace/compare/v2026.302.0533...v2026.302.0634" \
    --jq '"ahead_by=\(.ahead_by) behind_by=\(.behind_by)", (.files[]|"  \(.status) +\(.additions) -\(.deletions)  \(.filename)")'
ahead_by=2 behind_by=0
  added +147 -0  CHANGELOG/2026.302.0533.md
  modified +2 -2  candy/plugin-marketplace/charly.yml

$ gh api "repos/opencharly/opencharly/compare/v2026.302.0124...v2026.302.1105" \
    --jq '"ahead_by=\(.ahead_by) behind_by=\(.behind_by) files=\(.files|length)", (.files[]|select(.filename|startswith(".agents/"))|"  \(.status) +\(.additions) -\(.deletions)  \(.filename)")'
ahead_by=4 behind_by=0 files=9
(no `.agents/` line — the umbrella's authored bodies are byte-identical across the two tags)

The published site already teaches the current stage selector and no longer teaches the retired one. The retired builder selector is gone from every page of this site:

$ grep -rn "podman-jobs\|CHARLY_PODMAN_JOBS\|podman_jobs" src/
(no hits)

$ grep -rln "stage-parallelism\|stage_parallelism" src/content/docs | head -5
src/content/docs/recipes/build/build.md
src/content/docs/recipes/check/check/beds-and-r10.md
src/content/docs/recipes/internals/agents/parallel-bed-testing.md
src/content/docs/reference/plugin/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build.md
src/content/docs/reference/plugin/github-com-opencharly-plugin-build-v2026-296-1104/plugin-build.md

Two CI-time pins remain behind, and they are filed, not folded in. The charly pin is #202's scope; the umbrella pin — measured, and correcting my own claim on this issue — turns out to be a pointer advance rather than a content one, because the site projects exactly four umbrella files (SOUL.md, VISION.md, GRIEVANCES.md, LIBERATION.md) and the umbrella's missed commits touch none of them. That is filed as #207, with the RCA.

How tested

1 — the baseline: a regeneration at the OLD pin is a byte-exact no-op against the committed tree. This is what makes the diff attributable to the corpus bump alone, and it was measured against the tree this PR pushes.

$ git clone -q --filter=blob:none --no-checkout https://github.com/opencharly/marketplace.git /tmp/lcn-docs-oldcorpus
$ git -C /tmp/lcn-docs-oldcorpus checkout -q 3cf744b9ef3dcaf5e3dadff01648db087385ef19
$ git -C /tmp/lcn-docs-oldcorpus rev-parse HEAD
3cf744b9ef3dcaf5e3dadff01648db087385ef19

$ /tmp/plugin-docs-bin generate \
    --root /tmp/lcn-docs-src/charly \
    --narrative /tmp/lcn-docs-src/umbrella \
    --plugins /tmp/lcn-docs-oldcorpus \
    --out /home/atrawog/Sync/Atrapub/a/claude/opencharly/.worktrees/lcn-pin6/docs/src/content/docs
charly docs: 395 recipe pages, 196 plugin pages (205 provider words), 79 cli pages, 834 candy pages, 216 box pages (1726 generated pages cleared before regeneration)
GENERATE_OLD_RC=0

$ git status --porcelain=v1 --untracked-files=all -- src/content/docs | wc -l
0

(--out is the content root itself — plugin-docs' own flag help says "Docs content root to write into (e.g. docs/src/content/docs)" — so the regenerated pages land in the committed tree and git status is the comparison.)

The regeneration runs IN PLACE, and that is the measured detail. The first attempt wrote into an empty scratch directory, and it failed:

$ /tmp/plugin-docs-bin generate ... --out /tmp/lcn-docs-out-baseline      # an empty scratch dir
7 internal link target(s) resolve to no page:
  /concepts/00-vocabulary/
    linked from: index.md
  /concepts/01-the-box-is-the-boundary/
    linked from: index.md
  /guides/authoring-a-candy/
    linked from: index.md
  /guides/the-cli/
    linked from: index.md
  /guides/troubleshooting/
    linked from: index.md
  /start/install/
    linked from: index.md
every internal link must resolve to a page the site emits
GENERATE_RC=1

RCA. The generator's link gate is a site gate, not a corpus gate: it collects the route set from the out root and checks every page's internal links against it, and it deliberately covers "the HAND-AUTHORED pages, which the generator does not own but does sit alongside." Those seven targets are exactly this repo's own authored pages. CI writes into the repo's src/content/docs, where they are present and the gate is satisfied; a corpus-only scratch directory is not a site root, so the gate can never be satisfied there. The tool is right and the measurement was wrong — the out root must be a site root, which is why the baseline is measured the way CI measures it, in place, with git status as the comparison. No product defect and no repo defect is involved; the failing run left the tree untouched.

The toolchain is CI's: plugin-docs v2026.289.0814 built from cmd/serve in this session, charly at this repo's CHARLY_PIN be7a505f476c1a5b0302d878e0b5686a2cde3e07, the umbrella at its UMBRELLA_PIN 1c88fcf15f8fb9dd8b2814210472a63d3a79d0e2, and the corpus at the OLD pin this repo recorded.

2 — the regeneration at the NEW pin, on the committed tree, and the drift gate.

$ git rev-parse HEAD:marketplace
75e1d4a1379daf164a1ed2bc9c0678ad1ed20312

$ git diff --stat $(git merge-base origin/main HEAD)..HEAD
 marketplace | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

$ /tmp/plugin-docs-bin generate \
    --root /tmp/lcn-docs-src/charly \
    --narrative /tmp/lcn-docs-src/umbrella \
    --plugins <this repo>/marketplace \
    --out <this repo>/src/content/docs
charly: resolving github.com/opencharly/pod-dbus:v2026.235.2057 (709 resolved, 149 queued)
charly: resolving github.com/opencharly/layer-ssh-client:v2026.237.458 (710 resolved, 124 queued)
charly docs: 395 recipe pages, 196 plugin pages (205 provider words), 79 cli pages, 834 candy pages, 216 box pages (1726 generated pages cleared before regeneration)
GENERATE_RC=0

$ bash .github/docs-corpus/check_drift.sh
content: committed tree matches the pinned inputs (regeneration is a no-op).
DRIFT_RC=0

$ git status --porcelain=v1 --untracked-files=all -- src/content/docs
(empty — the advanced-pin regeneration is a byte-exact no-op too)

Both regenerations report the same page counts, 1726 generated pages cleared and rewritten each time, and neither leaves a diff.

3 — the drift gate's own fixtures.

$ python3 .github/docs-corpus/test_check_drift.py
test_clean_content (__main__.DriftGateTest.test_clean_content) ... ok
test_deleted_content (__main__.DriftGateTest.test_deleted_content) ... ok
test_modified_content (__main__.DriftGateTest.test_modified_content) ... ok
test_staged_content (__main__.DriftGateTest.test_staged_content) ... ok
test_unrelated_change (__main__.DriftGateTest.test_unrelated_change) ... ok
test_untracked_route_without_tracked_diff (__main__.DriftGateTest.test_untracked_route_without_tracked_diff) ... ok

----------------------------------------------------------------------
Ran 6 tests in 0.044s

OK

4 — the pin-currency report, on the committed tree. This repo reports each pinned input's currency and never fails on it, because the remedy for a stale pin is a regeneration PR that bumps the pin, not a gate that fails.

$ bash .github/scripts/check_pin_currency.sh .
corpus pin: 75e1d4a1379daf164a1ed2bc9c0678ad1ed20312 is cur — at the corpus's merged main (merged main: 75e1d4a1379daf164a1ed2bc9c0678ad1ed20312)
charly pin: be7a505f476c1a5b0302d878e0b5686a2cde3e07 is behind — 2 commit(s) behind charly's merged main; an advance available NOW (a pin-bump PR in this repo) (merged main: 1637a5e43380550b68d53b2e1167e0628768cd52)
umbrella pin: 1c88fcf15f8fb9dd8b2814210472a63d3a79d0e2 is behind — 6 commit(s) behind the umbrella's merged main; an advance available NOW (a pin-bump PR in this repo) (merged main: b63ff6724105a5eb452e53f6a7f495ae229f8145)
CURRENCY_RC=0

The corpus pin is cur after this change — it was 2 commits behind before it. The two CI-time pins are a different pin class with their own producers; they are filed, below.

5 — the rest of this repo's own workflow gates, on the committed tree.

$ python3 .github/scripts/check_step_timeouts.py
check-step-timeouts: OK (1 workflow file(s) asserted; every job and every step carries a deadline)
note: .github/workflows/tag-on-merge.yml: not asserted here - a distributed copy of opencharly/.github's tag-on-merge-dispatcher.yml; its deadline belongs in that template (opencharly/.github#256), and the copy-to-template binding is opencharly/.github#192
RC=0

$ python3 .github/scripts/check_step_timeouts.py --self-test
check-step-timeouts self-test: OK (unbounded steps, jobs and traps are all caught, and the org-distributed copy is reported)
RC=0

$ python3 .github/scripts/test_check_step_timeouts.py
ok  mutA-nomark — the block-scalar marking removed, and the self-test turned red on it
ok  mutB-crossjob — the cross-job step bound removed, and the self-test turned red on it
ok  mutC-jobsend — the jobs-mapping end bound removed, and the self-test turned red on it
ok  mutE-deadbound — the dead-step-bound rule removed, and the self-test turned red on it
ok  mutF-orgdistributed — the org-distributed exclusion removed, and the self-test turned red on it
test_check_step_timeouts: OK (5 mutants; every one of them turns the self-test red)
RC=0

$ python3 .github/scripts/check_dependency_advisories.py
check-dependency-advisories: OK (no known advisory in the production tree or the dev tree)
RC=0

$ python3 .github/scripts/check_dependency_advisories.py --self-test
check-dependency-advisories self-test: OK (a production finding, a dev finding and a clean tree are all told apart, and an unauditable tree is an error)
RC=0

$ python3 .github/scripts/test_check_dependency_advisories.py
ok  mutA-noproductionaudit — the production audit removed, and the self-test turned red on it
ok  mutB-nofindings — the findings loop removed, and the self-test turned red on it
ok  mutC-invertedlabel — the tree label removed, and the self-test turned red on it
ok  mutD-swallowederror — the report guard removed, and the self-test turned red on it
ok  mutE-noadvisories — the advisory extraction removed, and the self-test turned red on it
test_check_dependency_advisories: OK (5 mutants; every one of them turns the self-test red)
RC=0

$ bash .github/scripts/test_check_pin_currency.sh
PASS=40  FAIL=0
test_check_pin_currency: OK (every state is reported, and none of them fails)
RC=0

Every gate exits 0, with zero warnings.

6 — the site itself builds, under the node version this repo pins (.node-version 22.23.4):

$ node --version && npm --version
v22.23.4    10.9.9
$ npm ci --no-audit --no-fund
added 306 packages in 2s
NPM_CI_RC=0
$ npm run build
13:36:24 [starlight:pagefind] Building search index with Pagefind...
13:36:28 [starlight:pagefind] Found 1749 HTML files.
13:36:29 [starlight:pagefind] Finished building search index in 4.66s.
13:36:29 [@astrojs/sitemap] `sitemap-index.xml` created at `dist`
13:36:29 [build] 1749 page(s) built in 1m 8s
13:36:29 [build] Complete!
NPM_BUILD_RC=0
$ test -f dist/index.html && find dist -name '*.html' | wc -l
1749

7 — the R5 sweep, keyed on the retired text itself. The claim is that the published site teaches the current stage selector and no longer teaches the retired one.

$ grep -rn "podman-jobs\|CHARLY_PODMAN_JOBS\|podman_jobs" src/
(no hits)

$ grep -rn "3cf744b9ef3dcaf5e3dadff01648db087385ef19" --include='*.md' --include='*.yml' --include='*.tsv' . | grep -v '^./marketplace/'
CHANGELOG/2026.302.1030.md:22:| `marketplace` | the corpus gitlink: `197f42a57ab88fcaed6a044bf312d753a72062b2` → `3cf744b9ef3dcaf5e3dadff01648db087385ef19`, the corpus's default-branch tip after opencharly/marketplace#601 |

The only surviving hit for the retired pin is in CHANGELOG/ — history, which the rulebook exempts ("CHANGELOG/ — history only"). Every current surface is clean.

Rulebook compliance

Change classification

  • Change class: a pin change (the marketplace submodule gitlink this repo records) plus the generated recipe pages that pin projects. In this instance the pin projects no page change — the corpus's advance touches no authored body — so the published content is unchanged and the diff is exactly one gitlink.
  • Diffstat: 1 file changed, 1 insertion(+), 1 deletion(-) — the marketplace gitlink, 3cf744b9 → 75e1d4a1.
  • Gate run: this repo's own generation workflow — .github/workflows/deploy.yml, whose steps are the step-deadline gate (with its self-test and its mutation harness), the pin-currency report and its fixtures, the dependency-advisory gate (with its self-test and its mutation harness), the plugin-docs build, the drift gate and its fixtures, the regeneration, the drift check (content: committed tree matches the pinned inputs) and the Astro build — run on the committed tree, every step, zero failures, zero warnings. The org's required check on this repo is validate / validate, from opencharly/.github's org-wide-pr-validator-required.yml (the charly/pr-validator), plus this repo's own deploy workflow; both are named here from the repo's CURRENT workflow files, not from a remembered name.
  • Attribution tier: fully tested and validated — the change-class gate passed on the final tree, and the changed path (the generator, run against the real pinned inputs, at both the old and the new pin) was executed live, with the "before" retained as a byte-exact no-op.
  • Breaking change + rollback: none — the corpus's advance touches no authored body, so no published page changes and the site's content is byte-identical before and after; the only thing that moves is the marketplace gitlink this repo records, and the remedy for a pointer that must go back is the reverse bump of that one gitlink.
  • No rebuild leg applies: this change touches no disposable: true target; the site is built by the real Astro build, pasted above.

Filed issues

  • the pinned charly CI-time commit is behind charly's merged main — the drift gate cannot see it #202 — the charly CI-time pin is behind charly's merged main: be7a505f476c1a5b0302d878e0b5686a2cde3e07 is 2 commits behind 1637a5e43380550b68d53b2e1167e0628768cd52. It is a different pin class with its own producer and its own remedy, and this change's claim is about the corpus pin, which is cur after it. Separable by construction; it pre-dates this change; it is filed, not folded in.
  • the pinned umbrella CI-time commit is behind the umbrella's merged main — the report says how far, never what the missed commits touch #207 — the umbrella CI-time pin is behind the umbrella's merged main: 1c88fcf15f8fb9dd8b2814210472a63d3a79d0e2 is 6 commits behind b63ff6724105a5eb452e53f6a7f495ae229f8145. Measured: those commits touch only CHANGELOG/ records and gitlinks — the site projects exactly four umbrella files (SOUL.md, VISION.md, GRIEVANCES.md, LIBERATION.md) and none of them appears in the compare — so that advance is a pointer advance, not a content regeneration. The issue carries the RCA for the missing control: this repo's currency report names the DISTANCE of a pin's drift and never the CONSEQUENCE, so a reader cannot tell a pointer bump from a content regeneration without a second comparison by hand, and nobody does it, because the state is reported and green on every push. Filed, not claimed by this session; separable by construction; not folded in.

Agent: charly · session ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)

The `marketplace` submodule advances from 3cf744b9ef3dcaf5e3dadff01648db087385ef19
to 75e1d4a1379daf164a1ed2bc9c0678ad1ed20312 — the head opencharly/marketplace's
merged `main` serves, one commit above its tag v2026.302.1126 because tag-on-merge
writes CHANGELOG/ after the tag.

No generated page changes, and that is measured rather than assumed: the corpus's own
diff between the two pins touches two paths — CHANGELOG/2026.302.1126.md and the refs
list — and no authored skill body, so the site's recipes/** pages are the projection
of byte-identical bodies at both pins. A regeneration at the OLD pin and a regeneration
at the NEW pin are both byte-exact no-ops against the committed tree.

RCA. Mechanism: the corpus repo's daily refresh advances `main`, and this repo's
submodule gitlink did not move with it — the pinned corpus was 2 commits behind.
Missed control: the pin-currency comparison against the corpus's merged `main`. This
repo REPORTS each pinned input's currency and never fails on it, because the remedy
for a stale pin is a regeneration PR that bumps the pin — and the drift gate cannot
see a stale pin at all, by construction: the PINNED sources regenerate their own
(old) pages perfectly, so the gate stays green over a corpus that is no longer the
published one. Blast radius: the site's recipe pages project a corpus that is behind
the published corpus, and nothing in the tree says so. Root fix: bump the submodule
and carry the REGENERATED pages in the same change — the regeneration is what proves
the bump is coherent, and here it produces no page change, which is itself the proof
that this advance is a pointer advance.

Closes #206

Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
@github-actions

Copy link
Copy Markdown

Review — PASS

Correctness

The diff is exactly what the body claims: the marketplace submodule gitlink advances 3cf744b9ef3dcaf5e3dadff01648db087385ef19 → 75e1d4a1379daf164a1ed2bc9c0678ad1ed20312, 1 file, 1 insertion(+), 1 deletion(-). The head SHA (ee9b3098c715…) and the single commit ("docs(corpus): advance the corpus submodule…") both match the stated head. There is no mismatch between the body's diffstat and the actual diff.

The body's central claim — "no generated page changes" — is consistent with a diff that touches only the gitlink. It is also backed by a measured, internally coherent baseline (regeneration at the OLD pin is a byte-exact no-op; regeneration at the NEW pin is likewise a byte-exact no-op), which is the correct way to attribute a pin-only change.

Honesty of the body

Every checkable number re-derives against the current state:

  • File count (1), insertions/deletions (1/1), and the two commit SHAs all match the diff.
  • The submodule target in the body equals the target in the diff (75e1d4a1…).
  • The claim that the corpus advance touches only CHANGELOG/ and candy/charly-marketplace/charly.yml is consistent with the stated --stat, and the claim that no authored skill body changed (*/SKILL.md, */references/* → no hits) explains the absence of a page diff.

The one sentence that could read as self-contradictory — "one commit above the tag … not the tag and not the merge commit" — resolves correctly once read against the tag-on-merge mechanism (the tag is the merge commit ec7ee57c; the pin is the CHANGELOG follow-up commit above it). No contradiction remains.

Tests

For a pin change, the meaningful "coverage" is the drift gate proving the committed tree matches the pinned inputs, plus the live regeneration that would reveal a page diff if one existed. The body reports the drift gate green (content: committed tree matches the pinned inputs), the regeneration a byte-exact no-op at both pins, and the drift gate's own 6-test fixture suite passing. That is the right evidence class for a submodule bump; there is no behavior introduced that would warrant a new unit test.

Security

No code, no secrets, no input handling, no dependency change. The only effect is a pointer move. No security surface.

Scope & cleanliness

Scope is coherent and minimal: the gitlink advance plus its (empty) page projection, landed together. The two separable CI-time pin drifts (charly → #202, umbrella → #207) are explicitly filed rather than folded in, and the body gives the RCA distinguishing pointer advances from content regeneration — that is correct scoping, not a leftover legacy path. No dead code or duplication is introduced.

Comments

There are zero comments on the PR, so there is nothing to re-derive or disposition. No maintainer sign-off is present, but the change stands on its own measured evidence as required.

The change is correct, minimal, internally consistent, and adequately evidenced for its class.

Verdict: PASS


ollama-cloud/deepseek-v4.1-flash — action-review.

View action run

@github-actions
github-actions Bot enabled auto-merge (squash) October 29, 2026 13:18
@github-actions
github-actions Bot merged commit c7ae3f7 into main Oct 29, 2026
4 checks passed
charly-auto-merge Bot added a commit that referenced this pull request Oct 29, 2026
@aitrawog

Copy link
Copy Markdown
Contributor Author

RESOLVED — landed (squash c7ae3f70, tag v2026.302.1321), issue #206 closed, validator PASS.

Agent: charly · session ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

the corpus submodule is behind the corpus's served head again — the recipe pages project a corpus that moved

2 participants