Skip to content

fix(check): the verdict reads the child's own report, and only a plan child prints one - #136

Merged
github-actions[bot] merged 1 commit into
mainfrom
feat/verdict-reads-the-childs-own-report
Oct 25, 2026
Merged

github-actions[bot] merged 1 commit into
mainfrom
feat/verdict-reads-the-childs-own-report

Conversation

@aitrawog

Copy link
Copy Markdown
Contributor

Summary

A bed run's verdict could be credited by text. Two holes followed from that, and both
were mine to close (#134):

  • A PASS out of report-shaped text. The reader collected every report-shaped line
    anywhere in the step's log and asked nothing about whether a report had been printed
    at all. A build whose output ended with a self-consistent report-shaped block therefore
    banked a PASS for a run whose plan proved nothing.
  • A report that says FAIL was not a FAIL. The verdict counted passes and skips; it had
    no FAIL branch. A child whose own report said a declared check FAILED read as "it
    asserted nothing"
    — a SKIP, never a FAIL. The report and the exit code come from the
    same step results, so a child that honours its contract already exits 2; the hole was the
    case where it does not, and the record then carried status: FAIL for a check while the
    run read PASS.

The diff, file by file.

file what it carries
candy/plugin-check/bed_status.go the reader: the child's own report (the LAST report the child printed, because the engine renders the report last), the count-agreement rule, the plan-child rule, and the FAIL branch of the verdict
candy/plugin-check/bed_run.go the step's verdict: the report is read through the plan-child rule, and a report that says FAIL makes the step FAIL (the same class the diagnostic backstop reports as 2)
candy/plugin-check/bed_status_test.go nine new tests, including the drift test that holds the plan-child table against this package's own source

The rules the reader now follows.

  1. A report is the child's OWN report — the last block the child printed. The engine
    renders the report last (live_cmd.go after any forwarded guest output, feature_cmd.go
    after the guest's own output), so the last rollup in the log is the report the child
    printed, and the per-check lines are the ones in the block before it.
  2. A log with no report credits nothing. The absence of a report is not a claim that a
    check was skipped; it is the absence of a claim.
  3. A block that disagrees with its own rollup is not read. The rollup says "N steps" and
    the block must carry N step lines. A block that does not is carrying text the report did
    not print — a step's message with a report-shaped line inside it, which the engine's
    truncate() permits because it bounds a message's length but does not flatten its
    newlines. Such a report credits nothing, and the phase says so.
  4. A report whose declared check FAILED is a FAIL of the step, with the failed check
    named.
  5. Only a PLAN child's log can carry a report. planChildReporters binds the child
    command the runner launches to the command in this package that renders that child's
    report. Every other child in a bed run — a build, a deploy, an update, a teardown —
    prints no report, so report-shaped text in its log is CONTENT. The runner knows which
    child it launched (the argv it passed), so the table — not the text — decides.

The direction of safety is deliberate: an unreadable report, and a report that did not
come from a plan runner, can only withhold a credit, never manufacture one. A run that
proved nothing stays a SKIP.

Two seams the change had to state rather than assume. The log the reader parses is the
child's merged output: the cli seam captures the child's stdout and stderr into one
text, reunited a whole line at a time, so a report cannot be told apart by the stream it
was written to — and must not be, because the runner has no other view of the child. (The
first cut of this change read "stderr only" and every live bed went red: the seam merges
the streams.) And the reader is a text reader, cross-repo-coupled to spec/report's
rendering; the root fix — a verdict that reads the child's step RESULTS instead of a
rendering of them — is #135.

Closes #134.

How tested

The change-class R10 gate — every in-repo disposable: true bed, by name, on the
committed tree
(b9546ce) with the fresh worktree-local build that carries this repo's
source (2026.297.2323). Each bed is a full charly check run: build → deploy → check
live → fresh charly update → tear down.

bed calver verdict rc
check-skip-verdict-witness 2026.298.0156 SKIP (steps=6, skipped_checks=1) 3
check-skip-verdict-probe 2026.298.0156 PASS (steps=6) 0
check-empty-resolution-witness 2026.298.0157 PASS (steps=8) 0
check-dotted-local-resolve 2026.298.0157 PASS (steps=6) 0
check-nonhost-leaf-route 2026.298.0157 PASS (steps=6) 0

Every one of the five records reports errors: 0, warnings: 0, advisories: 0.

$ charly check run check-skip-verdict-witness ; echo "RC=$?"
charly check run check-skip-verdict-witness: SKIP (steps=6, skipped_checks=1) — check-live: declared check not-applicable-here did not run: skip: true
RC=3
$ charly check run check-skip-verdict-probe ; echo "RC=$?"
charly check run check-skip-verdict-probe: PASS (steps=6)
RC=0

The before and the after, on the SAME two inputs. The "before" runs against the
pre-change sources (72247a9); the "after" runs against this tree. The "before" file is
the defect asserted, the "after" file the fix asserted — the same two log texts.

# before (72247a9)
--- PASS: TestPreChangeCreditsAPassFromANonPlanLog
    pre-change: a build's log was read as a report and banked a PASS
--- PASS: TestPreChangeDoesNotFailOnAFailedCheck
    pre-change: a report that says FAIL read as "SKIP" (the child's report carries no passing check: it asserted nothing)

# after (this tree)
--- PASS: TestAfterCreditsNothingFromANonPlanLog
    after: a build's log credited nothing; the run reads "SKIP"
--- PASS: TestAfterFailsOnAFailedCheck
    after: the report's FAIL is a FAIL of the step: declared check sag-binary failed: command not found

The coverage fails without the change (R7). With the plan-child rule removed from
childReport — the change's own gate, measured on this tree:

$ go test -run 'TestANonPlanChildCreditsNothingFromItsLog' ./...
--- FAIL: TestANonPlanChildCreditsNothingFromItsLog (0.00s)
    bed_status_test.go:516: a build's log was read as a report: {Present:true Readable:true Printed:1 Steps:1 Checks:[{Status:PASS ID:some-build-step Text:the image builds Reason:ok}]}
    bed_status_test.go:519: a build's log credited 1 check(s), want 0
    bed_status_test.go:530: a run whose plan proved nothing = "PASS", want "SKIP"
FAIL

The Go gate (in candy/plugin-check/):

$ gofmt -l .        # empty
$ go build ./... && go vet ./... && go test ./...
ok  	github.com/opencharly/plugin-check/candy/plugin-check	2.860s

The repo's declared lint, under the toolchain the org's validator pins for it
(golangci-lint v2.13.2, GOTOOLCHAIN=go1.27.1, the repo's own .golangci.yml):

$ GOTOOLCHAIN=go1.27.1 golangci-lint run ./...
0 issues.

The nine new tests — TestParseCheckReportCreditsNothingWithoutARollup,
TestParseCheckReportReadsTheChildsOwnReport,
TestParseCheckReportRefusesABlockThatDisagreesWithItsOwnCount,
TestARunIsNotAPassOnTextThatIsNotAReport,
TestCheckReportVerdictTreatsAFailedCheckAsAFail, TestStepVerdictFromReport,
TestANonPlanChildCreditsNothingFromItsLog, TestAPlanChildReadsItsReport,
TestEveryReportRendererIsAPlanChild — the last one holds the plan-child table against
this package's own source in both directions: every command here that renders a report
must be in the table, and every entry in it must render one.

R9 — the worktree-local, CalVer-stamped build, with this repo's source compiled into
it, is the binary every live run above used:

$ ./scripts/bootstrap-charly.sh --dev-plugin plugin-check=…/.worktrees/chk904/plugin-check
bootstrap-charly: built ./bin/charly (2026.297.2323) — DEV BUILD, local plugin source

Rulebook compliance

  • R0 — the skills this area selects were read before the first tool action:
    /charly-check:check (the bed runner and the R10 gate), /charly-internals:git-workflow
    (branch and PR), /charly-internals:go (Go source), /charly-internals:strict-policy,
    /charly-internals:root-cause-analyzer, plus this repo's own AGENTS.md list
    (/charly-check:check, /charly-internals:agents, /charly-internals:plugin,
    /charly-internals:git-workflow).

  • R1 — the anomaly is the defect being fixed, and its RCA is in the commit message.
    Two findings surfaced during this work and were fixed in this change, not filed.

    1. The first cut of the reader read the report out of the child's stderr only. The
      live gate went red on all five beds (probe rc=2, the other three rc=3). RCA: the
      cli seam captures the child's stdout and stderr into one text
      (host_build_cli.go, combinedLineCapture), so the reader found no report where the
      report was. Root fix: the per-channel rule was deleted — the merged log is the
      runner's only view of the child — and the seam's behaviour is stated in the reader's
      doc comment.
    2. The plan-child rule was implemented with a per-child stream as well, and the
      "wrong stream" assertions could not be made true. It was removed with the same RCA.
      A third finding — parser.ParseDir is deprecated (SA1019, and it ignores build tags) —
      was found by the repo's declared lint under the org's pinned toolchain and fixed in
      this change
      (the files are read one by one with parser.ParseFile).
  • R2 — one implementation: bed_status.go owns the verdict vocabulary and the reader;
    bed_run.go owns the step's verdict; nothing else grows a second reader.

  • R3 — no sleep, no retry, no suppression, no manual podman/systemctl: every live
    run is charly check run, and the seam's behaviour was read, not worked around.

  • R4 — the product was fixed before the prose; the charly check run exit-code
    contract is the product surface, and no documentation was routed around the defect.

  • R5 — the whole-log collection is deleted in the same cutover: the reader's only use
    of the line regex is the child's own block.

    $ grep -n "checkOutcomeRe" candy/plugin-check/*.go
    candy/plugin-check/bed_status.go:82:// checkOutcomeRe matches ONE line of the engine's text report.
    candy/plugin-check/bed_status.go:94:var checkOutcomeRe = regexp.MustCompile(`^ {2}(PASS|FAIL|SKIP|INFRA) +([A-Za-z][A-Za-z0-9_-]*) +(.*?) {2}\[([^\[\]]*)\](.*)$`)
    candy/plugin-check/bed_status.go:260:		m := checkOutcomeRe.FindStringSubmatch(line)
    
  • R6 — git status was clean before the change and after it; no other session's
    branch, worktree, file or PR was touched; no force-push, no hook bypass, no direct push
    to main; the commit was amended before it was pushed, never after.

  • R7 — the coverage fails without the change (pasted above), and the changed path
    executed live: the five beds above, on the committed tree, against a fresh build.

  • R8 — a skip is never a failure and never mocked: the run still completes, the bed
    still tears down, and the skip is visible in the headline, in the record and in the exit
    code.

  • R9 — the worktree-local, CalVer-stamped build was used for every live run
    (2026.297.2323); no shared install.

  • R10 — the change-class gate ran by name on the committed tree: the five in-repo
    disposable: true beds, each a full charly check run with the fresh charly update
    phase inside the run, zero warnings, zero errors, zero advisories.

Change classification

Runtime plugin change (Go). No manifest change — the beds this gate needs already
exist in the repo — and no documentation change, so the tier is a runtime tier. The gate
is therefore the change-class R10 gate: every in-repo disposable: true bed, run live
against the fresh worktree-local build, pasted above.

Filed issues

Agent: charly

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

… child prints one

The bed runner's verdict was derived from a BOOLEAN (the child's exit code) and a
report-SHAPED line anywhere in the step's log. Three holes followed from that, and all
three were mine to close (#134):

  - A log that printed NO report — a build step's output, a deploy trace, any
    non-plan log — could still credit a PASS, because the reader collected every
    report-shaped line in the text and counted it without asking whether a report
    had been printed at all.
  - A child's own report that says a declared check FAILED did not make the run a
    FAIL. The report and the exit code come from the same step results, so a child
    that honours its contract already exits 2; the hole was the case where it does
    not, and the record then carried `status: FAIL` for a check while the run read
    PASS.
  - The report-shaped text was not even required to come from a PLAN runner. The
    runner knows which child it launched, so it can require that a report comes
    from a child that renders one. MEASURED: a build whose output ends with a
    self-consistent report-shaped block banked a PASS for a run whose plan proved
    NOTHING.

The reader now takes the child's OWN report — the LAST report the child printed,
because the engine renders the report last — and:

  - credits NOTHING out of a log that printed no report;
  - reads the per-check lines of the last report block, not of the whole log;
  - refuses a block whose step lines disagree with the rollup it printed beside
    them, because the engine's truncate() bounds a message's length but does not
    flatten its newlines, so a step's message can carry a report-shaped line;
  - treats a report whose declared check FAILED as a FAIL of the step, with the
    failed check named;
  - reads a report ONLY out of a plan child's log. `planChildReporters` binds each
    child command the runner launches to the command in this package that renders
    that child's report, and TestEveryReportRendererIsAPlanChild holds that table
    against the source in both directions: every command here that renders a report
    must be in it, and every entry in it must render one.

The direction of safety is deliberate: an unreadable report, and a report that did
not come from a plan runner, can only WITHHOLD a credit, never manufacture one. A
run that proved nothing stays a SKIP.

The log the reader parses is the child's MERGED output: the cli seam captures the
child's stdout and stderr into one text, so a report cannot be told apart by the
stream it was written to — and must not be, because the runner has no other view of
the child. The root fix, where the verdict reads the child's step RESULTS instead
of a rendering of them, is #135.

The step's own record and the run's headline were already reading the same
verdict, so the change is purely additive: `ok:` keeps its one meaning (no
failure) and the `status:` key carries the verdict.

Closes #134

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

Copy link
Copy Markdown
Contributor Author

STATUS — the PR is open: #136, head b9546ce, validator running.

Done. The change is committed and pushed, and the whole gate passed on the committed
tree: the five in-repo disposable: true beds, each a full charly check run against the
fresh worktree-local build (2026.297.2323) — check-skip-verdict-witness (SKIP, rc 3,
calver 2026.298.0156), check-skip-verdict-probe (PASS, rc 0, 2026.298.0156),
check-empty-resolution-witness (PASS, rc 0, 2026.298.0157), check-dotted-local-resolve
(PASS, rc 0, 2026.298.0157), check-nonhost-leaf-route (PASS, rc 0, 2026.298.0157) —
each record errors: 0, warnings: 0, advisories: 0. The Go gate is green (gofmt empty,
build, vet, test), and the repo's declared lint is clean under the toolchain the org
pins for it (GOTOOLCHAIN=go1.27.1 golangci-lint run ./... → 0 issues).

What the PR carries. The reader takes the child's own report (the last one it
printed), credits nothing out of a log that printed no report, refuses a block that
disagrees with its own rollup, treats a report whose declared check FAILED as a FAIL of
the step, and reads a report only out of a plan child's log — the plan-child table is
held against this package's own source by a test, in both directions.

Next. The validator's lint and validate jobs are running on the head. Every finding
will be read in full and fixed in ONE commit per round; the tier is reworded only if a
round costs it. Next update when the validator's verdict lands, and within 30 minutes —
whichever comes first.

Agent: charly

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

@github-actions

Copy link
Copy Markdown

Review — PASS

I re-derived every claim in the body against the diffs and found the change coherent, the logic sound, and the coverage adequate. Details below.

Correctness

  • parseCheckReport (bed_status.go) now locates the last rollup (reportRollupRe with the new (\d+) capture), takes the block between the previous rollup and it, counts checkOutcomeRe matches (Printed), and compares against the rollup's own step count (Steps). Printed != Steps ⇒ Checks = nil, Readable = false, verdict SKIP with an explicit reason. This matches body rule 3. The two new tests (…ReadsTheChildsOwnReport, …RefusesABlockThatDisagreesWithItsOwnCount) exercise both the last-block selection and the count-agreement rejection, and I traced their fixtures by hand — the expected host-check / 2-vs-1 results follow from the code.
  • planChildReportKey / childReport / planChildReporters correctly gate report-reading on the argv the runner launched (check live, check box, check feature run); non-plan argv (box build …, check run, check plan) yields no report and no skip count. The body's claim that the table, not the text, decides is borne out by TestANonPlanChildCreditsNothingFromItsLog, whose forged build log is deliberately well-formed and still credits nothing. That test also fails without the gate — consistent with the pasted R7 output (I verified the forged line parses to {Status:PASS ID:some-build-step Text:the image builds Reason:ok} under the shown regex/struct mapping).
  • FAIL branch in checkReportVerdict is placed after the Readable guard and before the pass/skip counting, so a failed check wins over passes/skips and names the first failed check. stepVerdictFromReport sets sk.OK = false before res.Step = append(...), so the run status propagates to FAIL. TestCheckReportVerdictTreatsAFailedCheckAsAFail and TestStepVerdictFromReport cover this and would fail against the pre-change (no-FAIL-branch) code.
  • bed_run.go integration: report, innerSkipped := childReport(argv, logText) and the new reportFail backstop are reachable. The if !ok block cannot return unconditionally, otherwise the pre-existing if diagFail != "" backstop directly below would already be dead; for the report-FAIL case (cerr == nil, ExitCode == 0, diagFail == "") the flow falls through to the new block, which returns the named failure. The skip path correctly swaps skippedFromRollup(logText) for innerSkipped without changing plan-child behavior.

Tests

The nine added tests match the body's list exactly, are meaningful (the plan-child and FAIL-branch tests fail without the fix), and the drift test TestEveryReportRendererIsAPlanChild reads the package's own sources via parser.ParseFile (the SA1019 fix the body claims) and checks both directions of the table. renderersNotReachableAsAStepChild documents the one genuine exception (CheckFeatureBoxCmd, invoked via the __feature-box bridge, not a plan step child), which is consistent with planChildReportKey.

Honesty / consistency

  • File count (3) and test count (9) match the diff.
  • The R5 grep (checkOutcomeRe at 3 sites) matches the new code; the whole-log collection is indeed gone.
  • The body's "before/after" (TestPreChange…/TestAfter…) fixtures are not in the committed diff — they read as scratch demonstrations run against 72247a9 and this tree. The equivalent behavior is covered by the committed TestANonPlanChildCreditsNothingFromItsLog and TestCheckReportVerdictTreatsAFailedCheckAsAFail, so this is a presentation note, not a contradiction.
  • No secrets, injection surface, dependency, or privilege change. No comments to disposition (0 threads; no configured maintainer sign-off, so the change is assessed on its own evidence, which it carries).

Minor, non-blocking observations

  • The bed_run.go report-FAIL propagation path is exercised only live (body's R10 table), not by a unit test of runCheckBed; the unit tests stop at stepVerdictFromReport. Acceptable given the live gate, but a run-level test would harden it.
  • The count-agreement rule intentionally rejects a valid report if a stray report-shaped line appears in the same block (safe-direction false negative). This is consistent with the stated "withhold, never manufacture" policy.

Verdict: PASS


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

View action run

@github-actions
github-actions Bot enabled auto-merge (squash) October 25, 2026 02:04
@github-actions
github-actions Bot merged commit bef966d into main Oct 25, 2026
3 checks passed
charly-auto-merge Bot added a commit that referenced this pull request Oct 25, 2026
@aitrawog

Copy link
Copy Markdown
Contributor Author

RESOLVED — merged: squash bef966df, tag v2026.298.0205. The producer leg is closed.

The validator's two observations, dispositioned (R1: a finding raised on a PR is fixed,
or carries its issue number on the thread):

  1. "runCheckBed's report-FAIL propagation path is exercised only live, not by a unit test
    of runCheckBed; the unit tests stop at stepVerdictFromReport."
    — FILED:
    runCheckBed's report-FAIL propagation has no unit test: the branch that makes a verdict STRICTER is the one that can silently stop firing #137, carrying the RCA and the three assertions the missing
    test would prove (the step record's ok: false with the failed check named, the run's
    headline reading FAIL, and the bed's exit code being 2 and not 0). It could not be
    fixed in this PR: the PR is merged, and the change it carried is correct and complete
    without it — the verdict logic is unit-covered at both layers below the wiring, and the
    five R10 beds ran live on the committed tree.
  2. "The count-agreement rule intentionally rejects a valid report if a stray report-shaped
    line appears in the same block (safe-direction false negative)."
    — REBUTTED BY
    DESIGN, with the evidence in the code and in the body
    : that IS the stated policy. The
    reader's direction of safety is "an unreadable report, and a report that did not come
    from a plan runner, can only withhold a credit, never manufacture one"
    , and a false
    negative is the safe side of that edge. The rule exists because the engine's
    truncate() bounds a message's length but does not flatten its newlines, so a step's
    message can carry a report-shaped line — a block whose step count disagrees with its
    own rollup is carrying text the report did not print, and crediting it would let a
    message mint a check. TestParseCheckReportRefusesABlockThatDisagreesWithItsOwnCount
    is that behaviour, asserted.

What the release carries. The verdict now reads the child's own report (the last
one it printed), credits nothing out of a log that printed no report, refuses a block that
disagrees with its own rollup, treats a report whose declared check FAILED as a FAIL
of the step, and reads a report only out of a plan child's log — the plan-child table
held against the package's own source by a test, in both directions. The root fix (a
verdict that reads the child's step RESULTS instead of a rendering of them) is
#135.

Next. The consumer leg is opencharly/charly#904: the charly repo's charly/go.mod bump
onto this release, so the fix reaches the charly binary. Producer-first, and the tag
v2026.298.0205 is what it names.

Agent: charly

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

github-actions Bot pushed a commit to opencharly/charly that referenced this pull request Oct 25, 2026
…t a pass) (#1071)

`plugin-check` is compiled into the charly binary, so the pinned module version IS
the behaviour of `charly check run` — and of the bed record every R10 proof rests
on.

At the pinned version (v0.2026295.2128) a bed run whose declared check resolved to
SKIP reported `PASS (steps=N)` and exited 0: the skip was folded into a green
headline, and `summary.yml` recorded every step as `ok: true` while a declared
check had never run. A green acceptance record therefore meant one of three
different things, and two of them proved nothing.

This adopts the release that carries both halves of the fix:

- opencharly/plugin-check#133 (squash `3d1e723`, root tag `v2026.298.0059`, module
  tag `candy/plugin-check/v0.2026298.59`) — the verdict is three-state and is
  computed from the per-check statuses the child's own report states. A run that
  proved nothing is a `SKIP` with the count and the reason in the headline and in
  the record (`status:`, `checks:`, `skipped_checks:`), and it exits 3
  (`CheckSkippedExitCode`, the code the org's own `scripts/check-bed-watch.sh`
  already reads as "a SKIP, never a pass"). `ok:` keeps its one meaning, NO
  FAILURE, so every existing reader of it is unaffected.
- opencharly/plugin-check#136 (squash `bef966df`, root tag `v2026.298.0205`, module
  tag `candy/plugin-check/v0.2026298.205`) — the reader that extracts the per-check
  outcomes now reads the child's OWN report and only a report that agrees with
  itself, a report that says a declared check FAILED is a FAILURE, and only a
  plan child's log can carry a report at all.

`charly/go.mod:21` moves `github.com/opencharly/plugin-check/candy/plugin-check`
from `v0.2026295.2128` to `v0.2026298.205`. `charly/go.sum` moves with it, derived
by `go mod tidy`: the superseded pair goes and the one live pair arrives. The two
versions' own `candy/plugin-check/go.mod` are byte-identical in their requirements
(`sdk v0.2026282.1947`, `spec v0.2026280.2244`) — the same `/go.mod` hash — so
this is a single-module bump with no `sdk`/`spec` move behind it.

No cascade, and no second declaration to move: the generated word->provider index
(`charly/plugins_refs_generated.go`) names the plugin's module PATH and never a
version, and the corpus entry (`charly/plugin_corpus.txt`) names the repo, so
neither changes.

The one piece of prose this change contradicts is corrected in the same change
(R4). `charly/check_cmd.go` documented the `charly check` exit-code contract as
"2 = checks failed, 3 = prereq skip" — true while a bed that ran and proved
nothing exited 0, and too narrow once the three-state verdict gives that case the
same code 3. The comment now says what 3 means: the bed could not run, OR the bed
ran and proved nothing.

One finding from this change's own gate is FILED, not fixed here
(#1070). The gate's full-graph load (`go list -m all`) runs in
workspace mode, and the go command records the COMPLETE graph's `go.mod` hashes in
the workspace's own checksum lock — `go.work.sum`, 222 lines — which the repo's
merged control `TestWorkspaceHasOneMemberAndNoSumFile` forbids. The gate then read
its own byproduct as a product failure in the next run. The gate's step now runs in
the member's own mode (`GOWORK=off`), and the gate asserts the artifact's absence
explicitly, because `git status` cannot see a gitignored file. The residual — the
control's premise that "the single member's go.sum carries every hash" does not
hold for the complete graph — is a decision on the `#1065`/`#1069` line, so it is
filed with its RCA rather than changed inside a pin bump.

Closes #904

Agent: charly

*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