Skip to content

chore(pins): compile in the plugin-box that spells the knob --stage-parallelism - #1082

Merged
github-actions[bot] merged 1 commit into
mainfrom
feat/plugin-box-stage-parallelism-pin
Oct 28, 2026
Merged

github-actions[bot] merged 1 commit into
mainfrom
feat/plugin-box-stage-parallelism-pin

Conversation

@aitrawog

@aitrawog aitrawog commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1081

Summary

Head 368aac4d5a484abd8c1e4e269dc12e86d5f17aaa — the commit this PR pushes: 3 files changed, 4 insertions(+), 4 deletions(-).

The defect. The charly binary this repo builds and ships COMPILES candy/plugin-box in, and the
pin it compiles is github.com/opencharly/plugin-box/candy/plugin-box v0.2026294.21 — the release
whose charly box build grammar still spells the inner-concurrency flag --podman-jobs, with the
env binding CHARLY_PODMAN_JOBS. The contract renamed that knob podman_jobs →
stage_parallelism (opencharly/spec spec/schema/box.cue:120-121, spec commit 4e61d3d), and
opencharly/plugin-box#66 renamed the FLAG to match — --stage-parallelism /
CHARLY_STAGE_PARALLELISM, tag v2026.301.1542.

So the shipped binary REJECTS the spelling the contract publishes, at the flag:

$ charly box build --stage-parallelism 2
charly: error: command "build": unknown flag --stage-parallelism
(exit 80)

The RCA.

  • Mechanism — the flag lives in the PLUGIN's own kong grammar
    (candy/plugin-box/box.go, buildGrammar.StageParallelism), and this repo ships that plugin
    COMPILED IN at a pinned module version. The spelling a given binary accepts is therefore decided
    by the PIN, not by this repo's source; nothing in this repo's tree states the spelling at all.
  • Missed control — the rename's controls sat on the CONTRACT (the spec's schema and its
    migration ops) and in the PLUGIN's own repo. Nothing connected the contract's rename to the
    CONSUMER's compiled-in pin, so the consumer was never asked to move. This repo's own
    charly box validate cannot see it either: the flag is in the plugin's grammar, and the knob
    this project's charly.yml carries is a CONFIG KEY, whose own retirement is a separate and
    still-open defect (charly's own charly.yml still ships the retired podman_jobs / podman_jobs_cap keys, and validate accepts them silently #938) that validates green.
  • Blast radius — every user of the shipped binary who passes the published flag: the whole
    charly box build surface, plus every script, skill or CI step that spells it the way the
    contract does. One pin, two manifest lines, no behaviour of its own.
  • Root fix — move the compiled-in pin to the release that carries the renamed flag, in BOTH
    places that carry it (the Go module pin and the candy: pin the bed composes), and prove the
    SHIPPED binary's own grammar with a two-binary probe: the pre-change build and the post-change
    build, same command, opposite outcomes. The probe is pasted in How tested.

What lands. Two pins, and nothing else:

where was is
charly/go.mod (and charly/go.sum) github.com/opencharly/plugin-box/candy/plugin-box v0.2026294.21 v0.2026301.1542
charly.yml:2530 — the check-commands-app template's candy: list, the one check-commands-local composes @github.com/opencharly/plugin-box/candy/plugin-box:v2026.276.1843 v2026.301.1542

What this change does NOT do. It does not touch the knob's CONFIG-KEY surface: this repo's own
charly.yml:55-56 still carries podman_jobs / podman_jobs_cap, the retired key names, which
the schema drops silently rather than rejecting — that is #938, it is pre-existing,
and the pin bump does not change it (measured below: charly box validate on this tree is still
0 warnings, 0 errors). It does not advance any other pin: MVS leaves the sdk and spec pins
untouched, so the lockstep modules (tools/generate-packages, tools/golden-cloudinit,
tools/golden-compile) stay in step. It does not touch the plugin's own source, its tests or its
schema — the producer leg (opencharly/plugin-box#66) is landed and tagged v2026.301.1542.

This is consumer leg 2 of the stage_parallelism fan-out tracked in opencharly/opencharly#785.
The producer leg is landed; this is the leg that makes the SHIPPED binary accept the flag the
contract publishes.

How tested

Everything below ran on the committed tree this PR pushes.

$ git rev-parse HEAD
368aac4d5a484abd8c1e4e269dc12e86d5f17aaa
$ git rev-parse HEAD^{tree}
5b9b27474600b46bc5a616bd0754e3f43599cbf6
$ git diff --stat origin/main...HEAD
 charly.yml    | 2 +-
 charly/go.mod | 2 +-
 charly/go.sum | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

1. This repo's own core gate — go test ./... and go vet ./... from charly/, then the R9
build, exactly as AGENTS.md states.

$ cd charly && go vet ./...
VET_RC=0
$ cd charly && go test -count=1 ./...
ok  	github.com/opencharly/charly/charly	206.003s
ok  	github.com/opencharly/charly/charly/internal/pluginsgen	143.460s
TEST_RC=0

2. R9 — the binary is this worktree's own CalVer-stamped build, and it links the bumped plugin.

$ ./scripts/bootstrap-charly.sh
bootstrap-charly: regenerating compiled-in plugin wiring
bootstrap-charly: building bin/charly
bootstrap-charly: built ./bin/charly (2026.301.1605)
BOOTSTRAP_RC=0
$ ./bin/charly version
2026.301.1605
VERSION_RC=0
$ go version -m ./bin/charly | grep plugin-box
	dep	github.com/opencharly/plugin-box/candy/plugin-box	v0.2026301.1542	h1:OrUGBJJsZXAkG15k4ec4WUl8TmcbM50E2fG7KJgHnvE=

The bootstrap's own generated-file guard passed, and git status --porcelain is empty after the
build — so the regeneration of charly/plugins_generated.go and go.work was a byte-identical
no-op: this pin bump moves no generated file.

3. R7/R10 — the live discriminating probe. The pre-change binary (built from origin/main,
plugin-box v0.2026294.21) and this PR's binary, same command, opposite outcomes. The scratch
project directory is EMPTY, so no box can be built: the arms probe the GRAMMAR, not a build.

$ /tmp/charly-1079/bin/charly-base -C <scratch> box build --stage-parallelism 2
rc=80
charly: error: command "build": unknown flag --stage-parallelism
$ /tmp/charly-1079/bin/charly-base -C <scratch> box build --podman-jobs 2
rc=0
$ ./bin/charly -C <scratch> box build --stage-parallelism 2
rc=0
$ ./bin/charly -C <scratch> box build --podman-jobs 2
rc=80
charly: error: command "build": unknown flag --podman-jobs
$ ls -A <scratch> | wc -l
0

The probe fails without the change: on the pre-change binary the new spelling is rejected and the
retired one is accepted; on this PR's binary the two outcomes are swapped. That is the whole
defect and the whole fix, in one table.

4. The lockstep modules stay in step — charly task mods-tidy is the owning task, and it is a
no-op here, because MVS left the sdk and spec pins untouched.

$ ./bin/charly task mods-tidy
task mods-tidy: 2 step(s), 0 failed
MODS_TIDY_RC=0
$ git status --porcelain
(empty)

5. The project's own manifest still validates, on the tree that carries the bump.

$ ./bin/charly -C . box validate
charly box validate: OK — checked 603 candies, 122 boxes, 49 deploys, 7 distros, 7 builders; 0 warnings, 0 errors
VALIDATE_RC=0

6. R5 — the retired pin is gone from every live file. The predicate is calibrated against a
known positive first (part A returns the changelog history), and the claim is the same pattern
over the live files (part B, exit=1).

# A. the CALIBRATION — the same pattern over the WHOLE tree (the known positive: the changelog history)
$ git grep -nE "v0\.2026294\.21|v2026\.276\.1843" HEAD -- .
HEAD:CHANGELOG/2026.277.0342.md:9:  charly.yml: @github.com/opencharly/plugin-box/candy/plugin-box:v2026.275.1127 -> @github.com/opencharly/plugin-box/candy/plugin-box:v2026.276.1843
HEAD:CHANGELOG/2026.277.0342.md:15:- `plugin-box` → `v2026.276.1843` (released `18:43:20Z`), pinned at `v2026.275.1127`.
HEAD:CHANGELOG/2026.277.0342.md:28:| `charly.yml:2303` | the **`check-commands-app` template's** `candy:` list (`kind: local`): `plugin-box` `v2026.275.1127` → `v2026.276.1843`. The runnable bed **`check-commands-local`** composes this template via `from: check-commands-app`, so the bed's plugins get the bump — and it is `check-commands-local` that carries the `box-reconcile-remote-cached` step (line 2362) which detects the stale pin. |
HEAD:CHANGELOG/2026.277.0342.md:38:  charly.yml: @github.com/opencharly/plugin-box/candy/plugin-box:v2026.275.1127 -> @github.com/opencharly/plugin-box/candy/plugin-box:v2026.276.1843
HEAD:CHANGELOG/2026.278.0912.md:92:v2026.276.1453` and `plugin-box v2026.275.1127 → v2026.276.1843`, i.e. exactly the "would rewrite 2
HEAD:CHANGELOG/2026.295.0418.md:17:| `plugin-box/candy/plugin-box` | `v0.2026288.503` | `v0.2026294.21` | the only call site of `deploykit.CollectSkillBodies`; without it the sdk bump changes nothing observable in `box validate` |
HEAD:CHANGELOG/2026.295.0418.md:96:	dep	github.com/opencharly/plugin-box/candy/plugin-box	v0.2026294.21	h1:mAn3DQ3s3RjK1N3TX41OTRegE95qboZIF3ZJUFtt1ic=
HEAD:CHANGELOG/2026.295.0418.md:123:15:	github.com/opencharly/plugin-box/candy/plugin-box v0.2026294.21
HEAD:CHANGELOG/2026.295.0418.md:383:- **R9:** the binary is the worktree-local, CalVer-stamped build from this branch (`scripts/bootstrap-charly.sh` → `./bin/charly`), `charly version` = `2026.295.0327` = HEAD's CalVer, and `go version -m` records `sdk v0.2026294.1520` and `plugin-box v0.2026294.21` — both pasted above. No new runtime OS dependency, so `packaging/` is untouched: the toolchain bump is a source-build requirement (CI reads `go-version-file: charly/go.mod`), not a shipped package dependency.
HEAD:CHANGELOG/2026.295.0418.md:409:  site exists in `plugin-box` from `#57`/`#58` (`v0.2026294.21`); the blindness the issue measured was
HEAD:CHANGELOG/2026.295.0754.md:54:	dep	github.com/opencharly/plugin-box/candy/plugin-box	v0.2026294.21	h1:mAn3DQ3s3RjK1N3TX41OTRegE95qboZIF3ZJUFtt1ic=
HEAD:CHANGELOG/2026.295.0754.md:59:`2026.295.0704` is HEAD's own CalVer: `09:04:37+02:00` is 07:04 UTC on day 295, and the stamp is derived from the commit, never from the wall clock. `plugin-box v0.2026294.21` beside it is the sighted validator the brief named — this build CAN see a `box validate` failure, and it reports one below. `git status --short` is empty AFTER the build, so the bootstrap's regeneration of `charly/plugins_generated.go` and `go.work` is a byte-identical no-op.
HEAD:CHANGELOG/2026.295.0754.md:296:- **R9:** the binary is the worktree-local, CalVer-stamped build from this branch (`scripts/bootstrap-charly.sh` to `./bin/charly`), `charly version` is `2026.295.0704` = HEAD's CalVer, and `go version -m` records `plugin-migrate v0.2026294.1337`, `plugin-box v0.2026294.21` and `sdk v0.2026294.1520` — all pasted. No new runtime OS dependency, so `packaging/` is untouched: this pin is a source-build dependency, not a shipped package dependency.
HEAD:CHANGELOG/2026.295.1246.md:66:	dep	github.com/opencharly/plugin-box/candy/plugin-box	v0.2026294.21	h1:mAn3DQ3s3RjK1N3TX41OTRegE95qboZIF3ZJUFtt1ic=
rc=0
# B. the CLAIM — the same pattern over the LIVE files (the changelog is history)
$ git grep -nE "v0\.2026294\.21|v2026\.276\.1843" HEAD -- . ':!CHANGELOG'
exit=1
# C. the new pins, live
$ git grep -nE "v0\.2026301\.1542|v2026\.301\.1542" HEAD -- . ':!CHANGELOG'
HEAD:charly.yml:2530:            - '@github.com/opencharly/plugin-box/candy/plugin-box:v2026.301.1542'
HEAD:charly/go.mod:15:	github.com/opencharly/plugin-box/candy/plugin-box v0.2026301.1542
HEAD:charly/go.sum:160:github.com/opencharly/plugin-box/candy/plugin-box v0.2026301.1542 h1:OrUGBJJsZXAkG15k4ec4WUl8TmcbM50E2fG7KJgHnvE=
HEAD:charly/go.sum:161:github.com/opencharly/plugin-box/candy/plugin-box v0.2026301.1542/go.mod h1:+TD+jCQZuhlHmqES5rO7S8clL716jWKBOMoVehKUhTo=
exit=0

Part A shows the pattern reaches the retired strings (14 hits, every one of them a changelog entry
about a past pin — that is where a pin's history belongs). Part B is the claim: over the live
files the pattern finds nothing, exit=1. Part C shows the two pins in their three homes.

7. R10 — the disposable bed that composes the bumped pin. check-commands-local is the bed
whose check-commands-app template carries the candy: pin this PR moves (charly.yml:2530), so
it resolves, realizes and runs the plugin's charly box verbs end to end against the new pin.

$ ./bin/charly check run check-commands-local
charly check run check-commands-local: [deploy-add] PASS after 2m31.55s
charly check run check-commands-local: [bring-up-members] PASS after 0s
charly check run check-commands-local: [check-live] PASS after 2m29.811s
charly check run check-commands-local: [update] PASS after 1m23.215s
charly check run check-commands-local: [cleanup] PASS after 1m3.575s
charly check run check-commands-local: [cleanup-members] PASS after 0s
charly check run check-commands-local: PASS (steps=6)
BED_RC=0

The bed's own artifact — .check/check-commands-local/2026.301.1611/summary.yml:

bed: check-commands-local
calver: 2026.301.1611
driver: .../.worktrees/charly-1079/charly/bin/charly
driver_version: 2026.301.1605
steps:
  - name: deploy-add          ok: true   status: PASS   duration_seconds: 152
  - name: bring-up-members    ok: true   status: PASS   duration_seconds: 0
  - name: check-live          ok: true   status: PASS   duration_seconds: 150
  - name: update              ok: true   status: PASS   duration_seconds: 83
  - name: cleanup             ok: true   status: PASS   duration_seconds: 64
  - name: cleanup-members     ok: true   status: PASS   duration_seconds: 0
total_seconds: 448
diagnostics:
  errors: 0
  warnings: 0
  advisories: 0
  allowlisted: 0
skipped_checks: 0
ok: true
status: PASS

The bed's check-live step ran ten named checks, every one PASS. Two of them are the ones this
change is about: box-new-validate-generate proves the box command plugin — the plugin this
PR re-pins — dispatches its nested verbs end to end host-side (new through the scaffold engine,
validate through the plugin's own validate engine, generate to render the Containerfile), and
box-reconcile-remote-cached is the step that reports this repo's pin drift — the report whose
plugin-box line this PR moves. The bed's driver is this worktree's own binary, 2026.301.1605,
the same build the probe above used. Zero errors, zero warnings, zero advisories, zero skipped
checks, and git status --porcelain is empty afterwards (.check/ is gitignored).

Rulebook compliance

  • R0 — skills first. /charly-internals:git-workflow, /charly-internals:strict-policy,
    /charly-internals:go, /charly-internals:cutover-policy, /charly-internals:plugin,
    /charly-build:reconcile and /charly-check:check were loaded before the first source read and
    before the first git action, and this repo's own AGENTS.md was read before acting in it.
  • R1 — RCA every anomaly. The anomaly is the shipped binary's grammar, and its RCA (mechanism,
    missed control, blast radius, root fix) is in the Summary above and in the commit message.
    Two other anomalies were met on the way and each got its own RCA: the charly box reconcile --remote --dry-run plan for this repo rewrites 48 pins across ~30 repos, which this change does
    NOT do (the tool's granularity is per repo, so the single-repo advance was applied by hand, and
    the tool's own plan line for plugin-box is byte-identical to the line this PR carries); and this
    repo's charly.yml names plugin-kube at two versions, which is filed under Filed issues.
    Zero warnings in every gate above: go vet rc=0, go test rc=0 across both packages,
    box validate 0 warnings 0 errors, the bootstrap's generated-file guard rc=0, and the R10 bed
    (evidence block 7) with 0 errors, 0 warnings, 0 advisories, 0 skipped checks.
  • R2 — no duplication. One pin, in its two homes — the same RELEASE in both, in each home's
    own scheme (v0.<calver> in the Go module pin, v<calver> in the manifest pin), which is the
    dual scheme this repo already uses for every other pinned plugin (plugin-authoring
    v0.2026271.2244 ↔ v2026.271.2244). No shim, no alias, no second copy of the flag anywhere
    in this repo.
  • R3 — no workaround. The retired spelling is not aliased, not accepted alongside the new one
    and not tolerated: the new binary REJECTS it (rc=80), which is the probe in How tested.
  • R4 — the product first, then the prose. The product here is the shipped binary's grammar;
    the product is fixed by the pin, and the prose in other repos (the corpus, the skills) is a
    separate leg of the same cutover, named in Filed issues and in the umbrella's fan-out issue.
  • R5 — legacy deleted completely. The retired pin is gone from every live file of this repo,
    proven by the claim-keyed sweep in How tested with its calibration, and the new pin is in
    both of its homes (part C).
  • R6 — Git safety. git status was stated before every action; this PR is one commit on
    feat/plugin-box-stage-parallelism-pin off origin/main (874a8b11); no force-push, no amend
    after the push, no direct push to main, no hook bypass, and no file outside this repo touched.
  • R7 — prove behaviour, not compilation. The coverage is the two-binary probe in How
    tested
    , and it is shown FAILING without the change: on the pre-change build the new spelling
    is rejected and the retired one is accepted; on this PR's build the two outcomes are swapped.
    The changed path executes live — it is the shipped binary's own command line.
  • R8 — live or skip. No service is mocked: the probe runs the real binary against the real
    plugin, and the R10 bed above builds, realizes and runs the disposable deployment for real.
  • R9 — binary equals source. The binary is this worktree's own CalVer-stamped build
    (scripts/bootstrap-charly.sh → ./bin/charly), never a shared install; charly version is
    2026.301.1605, the stamp of THIS commit, and go version -m records the bumped plugin
    v0.2026301.1542. No new runtime OS dependency is introduced — a Go module pin is a
    source-build dependency, not a shipped package dependency — so packaging/ is untouched.
  • R10 — fresh disposable proof. The change class is a runtime pin bump, so the gate is the
    change-class bed: the disposable check-commands-local deployment, which composes the very pin
    this PR moves (charly.yml:2530) and exercises the plugin's charly box verbs end to end. Its
    result is pasted above (evidence block 7): PASS (steps=6), 448 s, 0 errors, 0 warnings,
    0 advisories, 0 skipped checks.

Cutover. One cutover, one PR: the compiled-in pin that decides which spelling of the knob the
shipped binary accepts. The config-key surface (this repo's own charly.yml:55-56) is a different
surface with a different owner and its own issue, and it is named rather than folded in; the reason
is measured, not asserted: box validate on this tree is green with the retired keys still in it.

Landing. PR-only; the org's charly/pr-validator is the merge gate and arms native
auto-merge on PASS. No agent merges this PR.

Change classification

Filed issues

Agent: charly · session ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0

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

…parallelism`

The shipped `charly` binary COMPILES candy/plugin-box in, and the pin it
compiles is `v0.2026294.21` — the release whose `charly box build` grammar
still spells the inner-concurrency flag `--podman-jobs` (and whose env var is
`CHARLY_PODMAN_JOBS`). The contract renamed that knob `podman_jobs` →
`stage_parallelism` (spec `spec/schema/box.cue:120-121`, spec commit
`4e61d3d`), and plugin-box#66 renamed the FLAG to match
(`--stage-parallelism` / `CHARLY_STAGE_PARALLELISM`, tag `v2026.301.1542`).

So the binary this repo builds and ships REJECTS the flag the contract
publishes: `charly box build --stage-parallelism 2` fails with
`unknown flag --stage-parallelism` (exit 80) on the pinned build. This bump
moves both pins that carry the plugin:

  - `charly/go.mod` + `charly/go.sum`: `github.com/opencharly/plugin-box/candy/plugin-box`
    `v0.2026294.21` → `v0.2026301.1542`;
  - `charly.yml:2530` (the `check-commands-app` template's `candy:` list, the
    one `check-commands-local` composes): `@github.com/opencharly/plugin-box/candy/plugin-box`
    `v2026.276.1843` → `v2026.301.1542`.

No other pin moves: MVS leaves the sdk and spec pins untouched, so the
lockstep modules (`tools/generate-packages`, `tools/golden-cloudinit`,
`tools/golden-compile`) stay in step and `charly task mods-tidy` is a no-op.
`charly box validate` on this tree is unchanged: 0 warnings, 0 errors.

This is consumer leg 2 of the `stage_parallelism` fan-out tracked in
opencharly/opencharly#785 (leg 1 — the producer, plugin-box#66 — is landed
and tagged `v2026.301.1542`).

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

Copy link
Copy Markdown
Contributor

Review — PASS

I re-derived every claim in the body against the current diff, and the change is internally consistent and correctly scoped.

Diff vs. body

  • The body claims "3 files changed, 4 insertions(+), 4 deletions(-)": charly.yml (+1/−1), charly/go.mod (+1/−1), charly/go.sum (+2/−2) = exactly 4/4. Confirmed.
  • charly/go.mod: plugin-box v0.2026294.21 → v0.2026301.1542. Confirmed.
  • charly.yml:2530: plugin-box:v2026.276.1843 → v2026.301.1542. Confirmed (line falls inside the check-commands-app template candy list shown in context).
  • charly/go.sum: both plugin-box lines updated to v0.2026301.1542, matching the go.mod and the go version -m hash (h1:OrUGBJ…) quoted in the body. Confirmed.

CalVer dual-scheme consistency. The two spellings (v0.2026301.1542 in go.mod, v2026.301.1542 in charly.yml) follow the same mapping the repo already uses for every other pinned plugin (e.g. plugin-authoring v0.2026271.2244 ↔ v2026.271.2244), so the bump is coherent across both homes.

go.sum sanity. The /go.mod hash is unchanged between the two releases while the module-zip h1 changes. That is exactly what a source-only change (the flag rename in box.go) produces — no new transitive dependency, so no extra go.sum lines are expected. This is consistent with the body's claim that mods-tidy was a no-op.

Behaviour proof. The body's two-binary probe (pre-change binary accepts --podman-jobs / rejects --stage-parallelism; post-change binary swaps both, rc=80 on the retired spelling) is the right kind of evidence for a compiled-in pin bump and demonstrates the change failing without the fix. No committed test ships, but for a dependency-pin change a live probe + the R10 bed is the appropriate gate class; nothing in the diff contradicts the reported results.

Pre-existing issue handling. The charly.yml:55-56 podman_jobs config-key retirement (#938) is correctly identified as a different surface (config key, not CLI flag) and is not folded into this PR. The schema is in the untouched spec module, so box validate staying green is consistent — not a contradiction.

Minor, non-blocking notes

  • R2 says "the same version string in both," but the two pins are spelled differently (v0.2026301.1542 vs v2026.301.1542). The body's own table lists both accurately, so this is loose prose, not a misleading claim.
  • No CHANGELOG/ entry is added; the body explicitly frames this as "two pins and nothing else." If the repo's convention mandates a changelog note per change, that would be worth confirming, but nothing in the provided context establishes such a requirement.

Comments. The thread is empty (0 comments); there is no maintainer sign-off to weigh, and the change stands on its own pasted evidence.

Scope & cleanliness. The change is minimal, single-purpose, and leaves no legacy path: the retired pin is gone from the live files (body's part-B sweep with calibration), the new pin appears in both of its homes (part-C), and no shim/alias for the old flag is introduced.

No blocking findings.

Verdict: PASS


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

View action run

@github-actions
github-actions Bot enabled auto-merge (squash) October 28, 2026 16:31
@aitrawog

Copy link
Copy Markdown
Contributor Author

STATUS

Agent: charly · session ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0

Answering the review's two minor notes. No blocking finding, and both notes are closed here —
one by a fix, one by evidence.

1 — the R2 sentence ("the same version string in both"). Fixed in the body. The two pins ARE
one release in two schemes, not one string; the body now says so and names the scheme the repo
already uses everywhere else:

R2 — no duplication. One pin, in its two homes — the same RELEASE in both, in each home's
own scheme (v0.<calver> in the Go module pin, v<calver> in the manifest pin), which is the
dual scheme this repo already uses for every other pinned plugin (plugin-authoring
v0.2026271.2244 ↔ v2026.271.2244).

That example is this repo's own tree, not an illustration: charly/go.mod:14 carries
github.com/opencharly/plugin-authoring/candy/plugin-authoring v0.2026271.2244 and charly.yml:2531
carries @github.com/opencharly/plugin-authoring/candy/plugin-authoring:v2026.271.2244 — the same
dual scheme, the same two homes, one line apart from the pins this PR moves. The body edit does
not touch the tree: head is still 368aac4d5a484abd8c1e4e269dc12e86d5f17aaa, so no gate re-runs
and no commit follows.

2 — the CHANGELOG entry. Rebutted with the repo's own mechanism, because adding one here
would be a DUPLICATE write, not a missing one. In this org the PR body IS the changelog source:
the org's shared tag-on-merge workflow (opencharly/.github/.github/workflows/tag-on-merge.yml@main,
dispatched by this repo's .github/workflows/tag-on-merge.yml) writes CHANGELOG/<CalVer>.md from
the merged PR's body, and the resulting file lands as a separate POST-MERGE commit authored by the
automation — not by the PR. This repo's own origin/main shows that pattern for every recent
merge, all of them after the squash:

874a8b11 docs: add CHANGELOG 2026.301.1258 for PR #1080   charly-auto-merge[bot]
ab917059 docs: add CHANGELOG 2026.300.1028 for PR #1076   charly-auto-merge[bot]
eab7d212 docs: add CHANGELOG 2026.300.1842 for PR #1078   charly-auto-merge[bot]
5a83e038 docs: add CHANGELOG 2026.300.0235 for PR #1074   charly-auto-merge[bot]
f1f85d19 docs: add CHANGELOG 2026.298.0310 for PR #1071   charly-auto-merge[bot]

So the entry for this PR is produced by that same write when this PR lands, from the body above.
Committing a CHANGELOG/ file here would put a second, hand-written copy of the same content in
the tree, racing the automation's write for the same path (R2, and the R5 sweep's own lesson:
one canonical copy per fact).

Next update: the landing, and the RESOLVED record on #1081 and on the
fan-out's thread in opencharly/opencharly#785.

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

@github-actions
github-actions Bot merged commit 2434fc8 into main Oct 28, 2026
6 checks passed
charly-auto-merge Bot added a commit that referenced this pull request Oct 28, 2026
github-actions Bot pushed a commit to opencharly/opencharly that referenced this pull request Oct 28, 2026
…s producers (#791)

The umbrella's currency report on this wave's base named SIX pins that were not
current, and every one of them had a producer that had already landed. This is
the consumer leg of that wave: the umbrella's tree changes only in its
gitlinks, and what those gitlinks now carry is the `stage_parallelism` rename
and the guidance it republished.

    currency: 6 of 409 pin(s) NOT current [2 behind, 403 cur, 4 differs (no checkout to judge ancestry)];
    intents: 403 upstream leaf/leaves (403 implicit), 6 derived-from edge(s);
    NOT CURRENT: charly: behind; intent upstream:main (implicit: .gitmodules branch=);
      recorded 874a8b113e; served be7a505f47 (branch);
    layer-charly-check: differs (no checkout to judge ancestry); intent upstream:main (implicit: .gitmodules branch=);
      recorded cbd44f223d; served c77ecbb77a (branch);
    marketplace: behind; intent upstream:main (implicit: .gitmodules branch=);
      recorded 99a1bb4a6f; served 5feb9c8b83 (branch);
    plugin-box: differs (no checkout to judge ancestry); intent upstream:main (implicit: .gitmodules branch=);
      recorded b9ed1216c8; served 803541c15d (branch);
    plugin-marketplace: differs (no checkout to judge ancestry); intent upstream:main (implicit: .gitmodules branch=);
      recorded ba254d57ee; served 12242956b6 (branch);
    sdk: differs (no checkout to judge ancestry); intent upstream:main (implicit: .gitmodules branch=);
      recorded d71b9abb4b; served 352755df2e (branch);
    producer-first legs: charly (874a8b113e -> be7a505f47) -> marketplace (99a1bb4a6f -> 5feb9c8b83)

WHAT EACH ADVANCE CARRIES.

  charly           874a8b113e -> be7a505f47  (4 commits, 6 files)
    opencharly/charly#1082 compiles in the plugin-box that spells the knob
    `--stage-parallelism`, and #1084 adopts the landed `stage_parallelism`
    vocabulary in the project manifest. The umbrella's effective binary now
    ACCEPTS `--stage-parallelism` and REJECTS `--podman-jobs` (rc=80).

  layer-charly-check  cbd44f223d -> c77ecbb77a  (2 commits, 2 files)
    opencharly/layer-charly-check#55 republishes the authoring-gotchas
    reference so it names the knob that exists: `--stage-parallelism`, and the
    outer `--jobs` beside it.

  marketplace      99a1bb4a6f -> 5feb9c8b83  (6 commits, 26 files)
    opencharly/marketplace#591 republishes the umbrella's own guidance from
    its post-fix tag, so the corpus teaches `--stage-parallelism` and the
    pin-advance verb's true scope. #586 and #590 ride along.

  plugin-box       b9ed1216c8 -> 803541c15d  (8 commits, 9 files)
    opencharly/plugin-box#66 is the rename's producer; #68, #70 and #72 are the
    follow-up that makes the skill-body control read the TREE (so a newly added
    body is covered without a hand-maintained slice) and gives the vacuity guard
    its own red arm.

  plugin-marketplace  ba254d57ee -> 12242956b6  (2 commits, 5 files)
    opencharly/plugin-marketplace#55 replaces the false family->owner table with
    the mechanism that cannot go stale.

  sdk              d71b9abb4b -> 352755df2e  (1 commit)
    opencharly/sdk#476 names the knob that exists in the buildkit file header.

THE SCOPE IS DERIVED, not hand-listed: the product's own currency report on
this wave's base names the pins that are not current, and its own
producer-first line is the wave's work list.

The wave ran in the sanctioned order on a light tree: `charly task sync` (the pin
moves in the index; the checkouts that exist are rolled), then `charly task init`
to materialize the advanced paths AT the pins the index records, then the gate.
The verb's own report is the scope control: 6 pin(s) moved — 6 pin_map entries
moved 0, 396 index-only advances moved 4, and 2 of the 7 rolled leaves moved.
The six `derived-from:charly` EDGES stay `cur`: the two `charly` trees record
identical `box/*` twins, so advancing the leaf changes what the edges are
judged against, not what they are worth.

Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
github-actions Bot pushed a commit to opencharly/docs that referenced this pull request Oct 29, 2026
…erate the site on --stage-parallelism (#198)

This repo's `marketplace` pin moves from 99a1bb4a6f10112f67e3ddd73d3e86b3f6bc3417 to
5feb9c8b8350849fd2d46d252b486844c18bd0a4 — the corpus's merged `main` tip, advanced
through the submodule's own remote-tracking path, never a hand-set gitlink. The
corpus is what decides which projection of the guidance corpus the site serves, and
at this tip it names the `build`-family owners DIRECTLY — plugin-box at
v2026.301.1542 among them — so the recipe pages it projects teach the renamed knob.

The wiring candy's own `plugin-build` pin moves from v2026.242.0525 to
v2026.296.1104 — the newest plugin-build tag, and the first one whose
`candy/plugin-build/schema/build.cue` carries `stage_parallelism?: int`. That is what
the site's `reference/plugin/**` and `reference/candy/**` sections project, so the
site's last `podman_jobs?: int` goes with the old pin.

THE REGRESSION THIS REPAIRS, AND ITS ROOT CAUSE. The published site taught the
retired flag before, then stopped, then taught it again — measured on this repo's own
history:

    $ for c in 81da73e c0e7db9 98a5f6c; do
        git show $c:src/content/docs/recipes/build/build.md \
          | grep -cE 'stage-parallelism|podman-jobs'; done
    7 0    # 81da73e — PR #167, the corpus pin at layer-charly-build:v2026.292.2017
    0 7    # c0e7db9 — PR #176, the corpus pin at layer-charly-build:v2026.296.0919
    0 7    # 98a5f6c — PR #197, the corpus pin at the corpus's merged main of Oct 28

The pin moved FORWARD in time every time, and the CONTENT moved BACKWARD. The
mechanism, measured on the corpus's own refs list and on the owner's tree at the tag
the corpus named:

    $ for c in 602324e 1c15651 99a1bb4a 5feb9c8; do
        git -C marketplace show $c:candy/charly-marketplace/charly.yml \
          | grep -oE '@github.com/opencharly/layer-charly-build:v[0-9.]+'; done
    602324e  layer-charly-build:v2026.292.2017   # the body teaches --stage-parallelism
    1c15651  layer-charly-build:v2026.296.0919   # the body teaches --podman-jobs
    99a1bb4a layer-charly-build:v2026.296.0919   # the body teaches --podman-jobs
    5feb9c8  (no ref — the build family is named from plugin-box:v2026.301.1542)

`layer-charly-build` was DRAINED by the build-family split, and at its tag
v2026.296.0919 it has no `.agents/` tree at all — its manifest says it "owns NO
`skill:` entity any more". So the corpus's `build/skills/build/SKILL.md` at 1c15651
and 99a1bb4a COULD NOT HAVE BEEN SOURCED from the tag the corpus's own refs list
names: it was an ORPHAN body, carried in the corpus's tree from before the drain.
The corpus published a body that no tag it named could supply, and the site
published that body faithfully.

The MISSED CONTROL is exactly there. A provenance check that compares a projected
body against the owner's file AT THE NAMED TAG has nothing to compare an orphan
against, so it is silent precisely where the defect lived. The site's drift gate is
downstream of the same blindness: it compares the committed tree to the pinned
inputs, and a faithful projection of a regressed input IS "no drift". The corpus
currency report asks a third question — is the PIN behind the corpus's merged main —
and answered `cur` throughout.

The BLAST RADIUS: the published `build` family and every page naming the flag. The
site told its readers to pass `--podman-jobs`, a flag the shipped binary REJECTS with
rc=80 since opencharly/charly#1082 landed (opencharly/plugin-box#66 renamed it).

THE NEW PIN HAS NO ORPHAN. The corpus's body at 5feb9c8 is plugin-box's file at
v2026.301.1542 plus the generator's own header, and nothing else:

    $ git -C marketplace show 5feb9c8:build/skills/build/SKILL.md > corpus.md
    $ git --git-dir=$GD/plugin-box show v2026.301.1542:.agents/skills/build/SKILL.md > owner.md
    $ diff owner.md corpus.md
    6a7,8
    > <!-- GENERATED by `charly marketplace generate` — DO NOT EDIT. … -->

THE CLAIM, MEASURED. The retired name is gone from the published tree, and the new one
is carried:

    $ grep -rnE "podman-jobs|podman_jobs|PODMAN_JOBS" src/content/docs
    (no output; exit 1)

    $ git grep --cached -nE "podman-jobs|podman_jobs|PODMAN_JOBS" -- src/content/docs
    (no output; exit 1)

Four carriers carried it at HEAD: the `build` recipe (the flag line, the
`Parallelism: --jobs vs --podman-jobs` section, the `defaults.podman_jobs` /
`podman_jobs_cap` example), the `beds-and-r10` recipe, the `parallel-bed-testing`
recipe, and the plugin-build reference page's schema block. The last is the pin
advance; the first three are the corpus advance.

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.

Refs #196
Refs opencharly/opencharly#785

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

1 participant