Skip to content

docs(sdk): the buildkit file header names the knob that exists - #476

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

github-actions[bot] merged 1 commit into
mainfrom
feat/build-helpers-stage-parallelism

Conversation

@aitrawog

Copy link
Copy Markdown
Contributor

Summary

Head 40e889cf3d875b004e85d3226fda09442eef29ca — the commit this PR pushes: 1 file changed, 1 insertion(+), 1 deletion(-).

The defect. The header of buildkit/build_helpers.go maps what the file holds:

// build_helpers.go — pure build-engine helpers relocated out of charly core (the BUILD-cone
// "every capability is a plugin" cutover): box-arg normalization, podman-jobs resolution, host
// platform detection, the charly-binary freshness check, and the pacstrap bootstrap-conf
// renderers.

podman-jobs is the retired name of the inner-concurrency knob. The contract renamed it —
podman_jobs → stage_parallelism (opencharly/spec spec/schema/box.cue:120-121, spec commit
4e61d3d) — and this repo's own rename leg moved the helper (ResolvePodmanJobs →
ResolveStageParallelism), its fallback constant, and their doc (CHANGELOG/0.2026287.2213.md).
The header was left behind: it still told a reader that this file resolves a knob that no longer
exists.

The RCA.

  • Mechanism — the rename leg's sweep was keyed to the retired SYMBOL names (PodmanJobs,
    podman_jobs) and to the retired driver's flag spelling (podman build --jobs). The header's
    spelling is the CLI's HYPHENATED form, one derivation away from every pattern in that list.
  • Missed control — the pattern list was name-keyed rather than knob-keyed: it enumerated the
    identifiers of the deleted symbols instead of every name derived from the knob. The same
    changelog had already generalised the lesson — "knob-keyed, not name-keyed: search for the knob
    itself and every name derived from it"
    — and the pattern that carried it was still name-keyed.
  • Blast radius — one line, in the file that implements the knob's successor: the map of what
    the file holds. No behaviour, no exported surface, no call site, no schema, no build output.
  • Root fix — the header now names the knob the file resolves, and this leg's sweep is
    knob-keyed and case-insensitive, so it reaches the hyphenated spelling the old list missed. The
    calibration is pasted below.

What this change does NOT do. The rename-history notes stay exactly where they are: the
constant's own doc ("the knob the contract renamed from podman_jobs to stage_parallelism"), the
note on what the value used to drive ("it was podman build --jobs N"), the daemon-side note in
buildkitdrive/paths.go ("the semantic successor of podman build --jobs N"), and the historical
entry in CHANGELOG/0.2026239.1643.md (--podman-jobs 1). Their subject IS the rename — they
name the predecessor in order to explain the successor — and this repo's own prior sweep
classified exactly those lines as negative references and quoted them in its changelog. The finding
here is a header that presents a retired name as CURRENT; deleting the notes would erase the only
record of what the knob used to be.

This is leg 6 of opencharly/opencharly#785, the fan-out of the stage_parallelism rename. It
depends only on the contract, which is landed, so it is independent of the producer leg and of the
other consumer legs.

How tested

Everything below ran on the committed tree this PR pushes.

# head 40e889cf3d875b004e85d3226fda09442eef29ca (git rev-parse HEAD)
# base d71b9abb4b0566865bc30ee15dd720f2af5f9ebe (git rev-parse origin/main)
$ git diff --stat origin/main...HEAD
 buildkit/build_helpers.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

1. The repo's CI gate, reproduced locally under CI's own toolchain. .github/workflows/ci.yml
installs Go from go-version-file: go.mod (→ go 1.26.8) and runs gofmt, go vet,
golangci-lint v2.13.2, go test and the cross-compile matrix. That is the gate below, on the
tree above.

CI: actions/setup-go@v5 with go-version-file: go.mod  →  go 1.26.8
linter: golangci-lint v2.13.2 (the pin in .github/workflows/ci.yml)
tree: HEAD=40e889cf3d875b004e85d3226fda09442eef29ca tree=8102759ed6c7fd080cf3b026004e624ec32cc517 origin/main=d71b9abb4b0566865bc30ee15dd720f2af5f9ebe
toolchain: go version go1.26.8 linux/amd64

$ gofmt -l .

GOFMT_RC=0
(empty: every file is gofmt-clean)

$ go build ./...
BUILD_RC=0

$ go vet ./...
VET_RC=0

$ go test -count=1 ./...
ok  	github.com/opencharly/sdk	0.367s
ok  	github.com/opencharly/sdk/agentkit	0.554s
ok  	github.com/opencharly/sdk/artifactkit	0.031s
ok  	github.com/opencharly/sdk/buildcache	1.640s
ok  	github.com/opencharly/sdk/buildkit	0.112s
ok  	github.com/opencharly/sdk/buildkitdrive	0.034s
ok  	github.com/opencharly/sdk/candywalk	0.065s
ok  	github.com/opencharly/sdk/charlylib	0.018s
ok  	github.com/opencharly/sdk/checkkit	0.026s
ok  	github.com/opencharly/sdk/cmd/charly-lib-gen	0.030s
ok  	github.com/opencharly/sdk/deploykit	6.512s
ok  	github.com/opencharly/sdk/enginekit	0.014s
ok  	github.com/opencharly/sdk/kit	12.203s
ok  	github.com/opencharly/sdk/llmkit	2.163s
ok  	github.com/opencharly/sdk/loaderkit	0.999s
ok  	github.com/opencharly/sdk/packagekit	0.044s
ok  	github.com/opencharly/sdk/storekit	0.312s
ok  	github.com/opencharly/sdk/vmshared	0.125s
ok  	github.com/opencharly/sdk/workflowkit	0.019s
TEST_RC=0

$ golangci-lint run ./...   (v2.13.2, built with go1.27.3; GOTOOLCHAIN=go1.26.8 so the export data is the CI toolchain's)
0 issues.
LINT_RC=0

$ for a in amd64 arm64 arm 386; do GOOS=linux GOARCH=$a CGO_ENABLED=0 go build ./...; done
linux/amd64 RC=0
linux/arm64 RC=0
linux/arm RC=0
linux/386 RC=0

The lint arm needed the pair, and #466 carries the RCA: the linter must be BUILT with
a Go new enough for the tree's dependency build constraints (golang.org/x/net v0.58.0 ships
//go:build go1.27 files, so a go1.26-built linter panics on them) and RUN under the toolchain
go.mod pins, so the export data it reads is the one CI reads. The gate above is green under that
pair, and the same pair reproduces CI's own configuration.

2. R5's claim-keyed sweep — the retired knob's spellings, before and after. The claim: every
occurrence of the retired knob's name in this module is either the defect this PR fixes or a
reference whose subject is the rename itself. The predicate is knob-keyed — every spelling derived
from the knob, case-insensitive — and it is CALIBRATED against a known positive, the defect
itself, before it is used to decide anything (parts A and B below).

# A. the BASE tree (d71b9ab) with the pattern the prior sdk sweep used
$ git grep -nE "PodmanJobs|podman_jobs|podman build --jobs" d71b9ab -- "*.go"
d71b9ab:buildkit/build_helpers.go:38:// knob the contract renamed from `podman_jobs` to `stage_parallelism`), used ONLY when
d71b9ab:buildkit/build_helpers.go:43:// ⚑ What the value now DRIVES changed with the builder: it was `podman build --jobs N` (the
d71b9ab:buildkit/build_helpers.go:61:// where BuildKit's equivalent of `podman build --jobs` lives (see the constant above).
d71b9ab:buildkitdrive/paths.go:102:	// the same time"), and therefore the semantic successor of `podman build --jobs N`,
# B. the BASE tree (d71b9ab) with the KNOB-KEYED pattern set
$ git grep -niE "podman[-_ ]?jobs|podman build --jobs" d71b9ab -- "*.go"
d71b9ab:buildkit/build_helpers.go:18:// "every capability is a plugin" cutover): box-arg normalization, podman-jobs resolution, host
d71b9ab:buildkit/build_helpers.go:38:// knob the contract renamed from `podman_jobs` to `stage_parallelism`), used ONLY when
d71b9ab:buildkit/build_helpers.go:43:// ⚑ What the value now DRIVES changed with the builder: it was `podman build --jobs N` (the
d71b9ab:buildkit/build_helpers.go:61:// where BuildKit's equivalent of `podman build --jobs` lives (see the constant above).
d71b9ab:buildkitdrive/paths.go:102:	// the same time"), and therefore the semantic successor of `podman build --jobs N`,
# C. the COMMITTED tree (HEAD) with the knob-keyed pattern set
$ git grep -niE "podman[-_ ]?jobs|podman build --jobs" HEAD -- "*.go"
HEAD:buildkit/build_helpers.go:38:// knob the contract renamed from `podman_jobs` to `stage_parallelism`), used ONLY when
HEAD:buildkit/build_helpers.go:43:// ⚑ What the value now DRIVES changed with the builder: it was `podman build --jobs N` (the
HEAD:buildkit/build_helpers.go:61:// where BuildKit's equivalent of `podman build --jobs` lives (see the constant above).
HEAD:buildkitdrive/paths.go:102:	// the same time"), and therefore the semantic successor of `podman build --jobs N`,
# D. the COMMITTED tree, the defect's own spelling, in the SOURCE files only
$ git grep -niE "podman-jobs" HEAD -- "*.go"
exit=1
# E. the COMMITTED tree, the defect's own spelling, repo-wide (the CHANGELOG is history)
$ git grep -niE "podman-jobs" HEAD -- .
HEAD:CHANGELOG/0.2026239.1643.md:9:This was surfaced by distro-arch#25's box rebuilds (the merged distro sweeps were static ref sweeps — R8 N/A, no image builds — so the seam was never exercised). The buildah `--jobs` stage-parallelism panic on the 62-stage Containerfile was a separate, masking symptom; `--podman-jobs 1` surfaced the real header error.

What the calibration shows. Part A is the pattern the prior sdk sweep used; on the base tree it
returns the four surviving references and does NOT return the defect. Part B is this leg's
knob-keyed pattern; on the same base tree it returns those four AND the defect. That is the
instrument's proof — it reaches the thing the claim is about. Part C is the same pattern on the
committed tree, where the defect is gone and the four negative references remain.

The claim, in the committed tree. The retired knob's spelling has no matches in any Go
source: the grep that decides it and its exit=1 are pasted in part D above. Every surviving hit
of the knob-keyed pattern (part C) is classified:

hit what it is why it stays
buildkit/build_helpers.go:38 the constant's own doc: "the knob the contract renamed from podman_jobs to stage_parallelism" its subject IS the rename — it names the predecessor to name the successor
buildkit/build_helpers.go:43 the note on what the value USED to drive: "it was podman build --jobs N" same shape — the retired spelling is the past, not the present
buildkit/build_helpers.go:61 "where BuildKit's equivalent of podman build --jobs lives" same shape
buildkitdrive/paths.go:102 "the semantic successor of podman build --jobs N" same shape
CHANGELOG/0.2026239.1643.md:9 --podman-jobs 1, a historical entry about a box rebuild a changelog is where a name's history belongs; this repo's own prior leg quoted its surviving hits in its changelog for the same reason

This repo's own prior leg (CHANGELOG/0.2026287.2213.md) drew exactly this line between a
comment that presents a retired name as what the code resolves NOW (the defect this PR fixes) and
a comment that presents it as the predecessor (the four hits above).

Rulebook compliance

  • R0 — skills first. /charly-internals:strict-policy, /charly-internals:cutover-policy,
    /charly-internals:git-workflow and /charly-internals:go were loaded before the first source
    read and before the first git action.
  • R1 — RCA every anomaly. The anomaly is the stale phrase, and its RCA (mechanism, missed
    control, blast radius, root fix) is in the Summary above and in the commit message. The
    local lint arm failed twice before it was run under the CI's toolchain; that anomaly was RCA'd
    separately and its record is golangci-lint v2.13.2 cannot decode the Go 1.27.3 stdlib export data — the local lint gate is red on main too #466, which this session added the working pair to
    (see Filed issues). Zero warnings in every gate above: no gofmt output, no go vet
    output, go test rc=0 across 19 packages, golangci-lint "0 issues", four cross-compiles
    rc=0.
  • R2 — no duplication. One header, one line, one sweep. The sweep pattern is not copied
    beside the existing one; the prior leg's pattern list is superseded by the knob-keyed one.
  • R3 — no workaround. No alias, no shim, no suppressed check, no retry, no magic string. The
    retired name is deleted from the header rather than tolerated.
  • R4 — the product first, then the prose. The product here is the CONTRACT's name; the
    contract already carries it, and this change brings the prose onto it. No documented command
    changes.
  • R5 — legacy deleted completely. The claim-keyed sweep is pasted in How tested with its
    calibration, and every surviving hit is classified there.
  • R6 — Git safety. git status was clean before every action; this PR is one commit on
    feat/build-helpers-stage-parallelism off origin/main (d71b9ab); no force-push, no amend
    after the push, no direct push to main, no hook bypass.
  • R7 — prove behaviour. The change class is documentation-only, so the instrument is the
    claim-keyed sweep, and it is shown failing on the pre-change tree and passing on the committed
    tree (parts A/B against the base, part C against the head, and the defect's own spelling at
    exit=1 in part D). A prose change has no runtime path to execute live.
  • R8 — live or skip. N/A — no service is crossed: the change is a comment in a Go source
    file, and every gate above runs on the host against the committed tree.
  • R9 — binary equals source. N/A — the sdk publishes a library, not a binary; the gate ran
    against the committed tree of this checkout.
  • R10 — fresh disposable proof. The change class is documentation-only (a comment-only edit,
    zero behaviour change), so the gate is the non-runtime standards — this repo's own CI gate,
    reproduced locally under CI's toolchain and pasted in How tested. This repo carries no
    per-repo candy bed (its AGENTS.md says so), so there is no disposable target to run.

Cutover. One cutover, one PR: the stale phrase in the one file that carries it. The
rename-history notes are not in scope, and the reason is stated in the Summary — they are the
rename's own record, and this repo's prior leg drew the same line.

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 (documentation reviewed)

The contract renamed the inner-concurrency knob from `podman_jobs` to
`stage_parallelism` (spec `4e61d3d`), and this repo's own rename leg moved the
helper, its fallback constant and their doc (CHANGELOG/0.2026287.2213.md). The
file header was left behind: it still described the file as doing "podman-jobs
resolution", naming the retired knob as what the code resolves today.

RCA — mechanism: that leg's sweep was keyed to the retired SYMBOL names
(`PodmanJobs`, `podman_jobs`) plus the retired driver's flag spelling
(`podman build --jobs`); the header's spelling is the CLI's hyphenated form
(`podman-jobs`), which no pattern in that list matched. Missed control: the
pattern list was name-keyed rather than knob-keyed — it enumerated the
identifiers of the deleted symbols instead of every name derived from the knob,
and the CLI's own spelling of that knob was one derivation away. Blast radius:
one line — the map of what build_helpers.go contains, in the file that
implements the knob's successor. Root fix: the header names the knob the file
resolves, and the sweep for this leg is knob-keyed and case-insensitive, so it
matches the hyphenated spelling the old list missed.

Documentation-only: no behaviour change, no exported-surface change.

Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (documentation reviewed)
@github-actions

Copy link
Copy Markdown

Review — PASS

Change under review. A single-line comment edit in buildkit/build_helpers.go: the file-header map changes "podman-jobs resolution" → "stage-parallelism resolution". Nothing else in the diff moves.

Body honesty / internal consistency. The body's central numeric claim — "1 file changed, 1 insertion(+), 1 deletion(-)" — is exactly reproduced by the diff (one - line, one + line, same file). The head SHA 40e889c… and the single-commit history match what was supplied. The stated defect (a header naming the retired podman-jobs knob) is precisely the line the diff removes, and the replacement names the successor knob the body says the contract adopted (stage_parallelism, hyphenated in prose). The body's explicit scoping — that the rename-history notes at build_helpers.go:38/43/61, buildkitdrive/paths.go:102, and CHANGELOG/0.2026239.1643.md:9 are deliberately left alone because their subject is the rename itself — is consistent with the diff, which touches none of those lines. No claim in the body contradicts the change.

Correctness. The edit makes the header describe what the file now resolves. It introduces no symbol, no behaviour, no exported surface change; the diff is confined to a // comment block. There is no risk of a stale or dangling reference being created.

Tests. Not applicable and correctly not claimed: a comment-only change has no runtime path. The body classifies it as documentation-only and substitutes a claim-keyed grep sweep (with a calibrated positive/negative, parts A–E) for a runtime test, which is the appropriate instrument for this class. No test is owed.

Security. No secrets, no injection surface, no dependency, pin, or privilege change — a prose line in a comment.

Scope & cleanliness. Minimal and coherent: one stale phrase, one file, one line. No leftover legacy path introduced, no duplication, no dead code. The change does not attempt to sweep the negative references, which would have been scope creep and would have erased rename history; the body justifies that boundary.

Comments. The comment thread is empty (0 comments), so there is no sign-off to weigh and no third-party claim to re-derive. With no designated maintainer comment present, the change stands on its own evidence — and its own evidence (the diff vs. the body) is consistent.

Residual note (non-blocking). The "How tested" gate output and the grep transcripts are not independently reproducible from this read-only context (no shell). They are, however, internally coherent: part B shows the defect present on the base tree at line 18, part C shows it gone on HEAD, and part D's exit=1 for the hyphenated spelling is consistent with the surviving hits being the podman build --jobs / podman_jobs forms rather than podman-jobs. Nothing in them is contradicted by the diff. This does not rise to a block for a one-line comment fix.

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 15:56
@github-actions
github-actions Bot merged commit 352755d into main Oct 28, 2026
8 checks passed
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)
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.

1 participant