Skip to content

Document the lending contract; drop the checksum claim nothing computes - #169

Merged
blooop merged 4 commits into
mainfrom
perf/152-lending-contract-docs
Aug 14, 2026
Merged

blooop merged 4 commits into
mainfrom
perf/152-lending-contract-docs

Conversation

@blooop

@blooop blooop commented Aug 9, 2026 •

Copy link
Copy Markdown
Owner

Closes #152.

Retry after Request changes (review, 6 blocking across both axes). The prose was mostly true; the guard meant to keep it true measured the wrong text, and two statements a reader would act on were wrong. Merged onto current main (39d4d2a, which carries #148 and #165).

What changed

README, "Tools in every workspace". It described the pixi global network
install as the only mechanism, so an image author could not know what to bake to
skip provisioning — and could not know that a shim, which answers
command -v claude exactly as the real binary does, is precisely what does not
count. It is now written around the three trips a launch may pay (probe → lend →
network install), and states the prebuilt-image contract in one place.

The bake recipe is now buildable as written, which it was not:

  • ~/.local/bin has to be on the login PATH, or the symlink is invisible and
    a perfectly baked image is read as absent and pays the whole lend. It gets its
    own bullet, next to the note that Ubuntu's stock ~/.profile supplies it but an
    image shipping a ~/.bash_profile never reads ~/.profile.
  • the binary has to be a direct child of the versions directory. Anything
    deeper — versions/<version>/bin/claude, the shape Three-state tools probe: only the official claude layout counts as provisioned #164 found the host
    refusing — is somebody else's tree, and nothing said so.

Two further statements were inaccurate and are corrected: a lendable container
stops after the probe when the host has nothing to lend, not after the lend
"either way" (ensure_tools skips _transfer on a None payload); and the probe
reports three facts, not two — whether both tools answer, plus the two resolved
paths.

Also stated, unchanged from the first round: that this repo's own
.devcontainer/claude-code/install.sh installs a shim, so an image built from it
does not meet the contract by itself; that the ~/.local/bin prepend is intended,
being what makes a lent binary shadow a baked shim thereafter; and the two
non-goals accepted on #141.

CHANGELOG, [Unreleased]. The lend entry claimed the transfer was
"checksum-verified". Nothing in devlaunch/ computes a checksum; the gate is
execution — both binaries are run in a staging directory and nothing moves into
place until they do.

It also read "Measured here: 342MB in 5.1s". #158 measured the 342MB; its
own Honesty note records the ~5.1s end-to-end as "an inherited working number
and I have not verified it"
. Nobody has measured it, so the figure is gone
and the sentence now claims only the payload size. No replacement number was
invented — the staging cost #158 did measure is a component, not an end-to-end
launch, and this PR measured nothing.

The guard, and where it now points

test/test_lending_doc.py. Two rules, and the first round only obeyed one of them.

Assert against the code, not the prose — unchanged, and it worked.

Assert inside the span whose meaning is at stake — this is what failed. The
layout assertion ran against the whole ## section and was satisfied by the
narrative paragraph that happens to mention the versions directory, while the
recipe an author copies could be made wrong with the suite green. Every assertion
is now scoped by a level-aware section slice to the ### subsection, and where
it matters to the single bullet, that carries the claim.

Assertion Scoped to Bound to
every tool has its own bake instruction naming a place a login shell will find it the recipe, per bullet REQUIRED_TOOLS, and probe_script still resolving each by command -v
the claude layout, in its versioned form with its closing backtick the claude bullet CLAUDE_VERSIONS_RELPATH
the binary must be a direct child the claude bullet _is_official_claude accepting <versions>/<v> and refusing <versions>/<v>/bin/claude
the symlink a lend creates the claude bullet parsed out of a generated transfer_script
~/.local/bin must be on the login PATH its own bullet the parent of the symlink the transfer writes
a lend prepends that directory the sentence that says it parsed out of the same generated script
the shim warning, and its polarity the recipe the feature still installing claude-shim, _is_official_claude still refusing one, and the denial itself still present in the text
both #141 non-goals, each in the bold a reader skims the non-goals subsection — ticket-required content; previously unguarded
every reading a probe can produce is explained the narrative subsection ProbeResult
the lend entry describes the staging gate the lend entry alone the generated script really running both binaries before any mv
the lend entry advertises no integrity check on the bytes the lend entry alone a named class of claim, not one banned word

The pytest.skip is gone. It stood down whenever "checksum" appeared
anywhere under devlaunch/**/*.py — including in a comment saying no checksum is
computed — after which the exact claim this PR exists to delete could be restored
with a green suite. test/fixtures/e2e_guard.py writes the repo's rule down:
"Anything the test needed and could not get is a failure; pytest.skip for those
is what let a broken run look clean."
There is nothing this test needs and cannot
get, so it now asserts unconditionally, over the lend entry only, so a future entry
about something else is still free to talk about signatures.

Mutation proof — the reviewer's mutations, not mine

Every mutation below was authored by the review, not by this branch. The nine
that passed against the first round are the ones that had to go red. Selection:
narrow = pixi run -e py310 pytest test/test_lending_doc.py -p no:randomly -q,
clean baseline 25 passed; full = pixi run -e py310 pytest -p no:randomly -q
(addopts = -m 'not e2e'), clean baseline 1274 passed, 23 deselected in 44.54s.

Mutation (review's name) Was Narrow Full Now red on
M-A / Standards A / Spec M1 — bake bullet path wrong, narrative untouched passed 1 failed, 24 passed 1 failed, 1273 passed, 23 deselected layout
Standards A verbatim (~/.config/anthropic/builds/<version>) passed 1 failed, 24 passed — layout
Spec M4 — bullet → .../<version>/bin/claude passed 1 failed, 24 passed — layout
M-H / Standards B — shim paragraph inverted, install.sh span retained passed 1 failed, 24 passed 1 failed, 1273 passed, 23 deselected shim polarity
M-E — "GPG-signature-verified … cryptographically attested" passed 5 failed, 20 passed 5 failed, 1269 passed, 23 deselected staging gate + 4 class terms
M-F / Standards C — # NOTE: we deliberately do not compute a checksum here. + checksum-verified restored passed (skipped) 2 failed, 23 passed 2 failed, 1272 passed, 23 deselected staging gate + checksum
M-I — both #141 non-goals deleted passed 2 failed, 23 passed 2 failed, 1272 passed, 23 deselected both non-goals
Spec M5 — recipe says "do not bake either tool", all spans retained passed 8 failed, 17 passed — 8 recipe assertions
Spec M7 — gh "anywhere on the filesystem — dl finds it without PATH" passed 1 failed, 24 passed — per-tool instruction
Standards F2 — recipe → "Ask your platform team." + every guarded token passed 7 failed, 18 passed — 7 recipe assertions
M-J — the three-trip narrative deleted bit (the structural proof) 3 failed, 22 passed — all three ProbeResult readings
builder row 3 re-run — PATH bullet dropped, symlink left bit 1 failed, 24 passed — precondition
builder row 6 re-run — code moves CLAUDE_VERSIONS_RELPATH bit 1 failed, 24 passed — layout

Two mutations of my own, for the two assertions with no reviewer mutation against
them: dropping "direct child" from the bullet → 1 failed, 24 passed; reordering
the generated transfer to mv before the --version gate → 1 failed, 24 passed.

M-J now fails for a different reason than it used to. Before, it was the
structural proof that the layout test was anchored on the narrative — it took
the layout test down with it. Now the layout test is anchored on the recipe and
survives; what fails is the new ProbeResult coverage test, which is the right
answer.

CI

pixi run -e py310 ci end to end as one task, exit 0: ruff format 77 files
left unchanged, ruff check all checks passed, pylint 10.00/10, ty all checks
passed, 1274 passed, 23 deselected in 50.02s, coverage TOTAL 2514 163 94%.

Not done, and deliberately

  • No guard on the removed 5.1s. Nothing in this repository measures an
    end-to-end lend, so a test could only pin the sentence's wording, not its truth.
    The figure is removed; keeping it out is a review responsibility, not a test's.
  • Non-blocking duplication between _section here and _heading_index /
    _container_section in test_agents_doc.py is not deduplicated. The two
    have diverged — this one is level-aware and requires the heading to be unique
    and line-anchored — and merging them means editing a file this ticket does not
    touch.
  • No Docker, no devpod, no real container, no end-to-end dl launch (23 e2e tests
    deselected, as on main).

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @blooop, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@sourcery-ai

sourcery-ai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Reviewer's Guide

Documents the lending contract in README and CHANGELOG to match actual behavior, and adds tests that bind the documentation to the code so the published contract cannot silently drift from the implementation.

Sequence diagram for devlaunch lending probe, lend, and network install flow

sequenceDiagram
actor Developer
participant Host
participant Container
participant pixi_global

Developer->>Host: devpod up

Host->>Container: command -v gh
Host->>Container: command -v claude
Host->>Container: resolve CLAUDE_VERSIONS_RELPATH
Container-->>Host: gh_path, claude_path, versions_path

alt provisioned
    Note over Host,Container: gh on PATH and claude in CLAUDE_VERSIONS_RELPATH
    Host-->>Developer: launch continues, no lend, no network
else lendable
    Note over Host,Container: _is_official_claude returns false
    Host->>Container: devpod_ssh tar stream of gh and claude
    Host->>Container: run lent gh in staging directory
    Host->>Container: run lent claude in staging directory
    alt [both run]
        Host->>Container: prepend ~/.local/bin to PATH
        Host-->>Developer: launch with lent binaries
    else [staging execution fails]
        Host-->>Developer: container left unchanged
    end
else absent
    Note over Host,Container: gh or claude genuinely missing
    Host->>Container: devpod_ssh tar stream of gh and claude
    Host->>Container: run lent gh in staging directory
    Host->>Container: run lent claude in staging directory
    alt [both run]
        Host->>Container: prepend ~/.local/bin to PATH
    end
    Host->>pixi_global: pixi global install gh and claude
    Host-->>Developer: launch with installed binaries
end
Loading

File-Level Changes

Change Details Files
Reframe and expand README’s "Tools in every workspace" section around the probe→lend→network install flow and define the explicit prebuilt-image lending contract.
  • Introduce a structured three-step description of tool provisioning (probe, lend, network install) on devpod up.
  • Define the explicit image contract for gh on PATH and claude in the official versions layout with a ~/.local/bin/claude symlink.
  • Clarify how shims are detected and treated as lendable, and explain the PATH-prepend behavior that shadows baked shims.
  • Document that the repo’s own devcontainer feature currently bakes a shim and therefore doesn’t satisfy the contract on first launch.
  • State two non-goals: no per-tool transfer and no version synchronization, and describe how to disable tooling via DEVLAUNCH_NO_TOOLS.
README.md
Correct the unreleased CHANGELOG entry for the lending feature to match the actual verification mechanism (execution gate instead of checksums).
  • Remove the claim that the lend is checksum-verified and replace it with a description of executing binaries in a staging directory before moving them into place.
  • Preserve the measured transfer size/time while aligning wording with current implementation.
CHANGELOG.md
Add tests that read the lending contract directly from devlaunch code and the devcontainer installer so documentation and implementation stay in lockstep.
  • Implement helpers to extract specific README and CHANGELOG sections by heading, avoiding brittle phrase matching.
  • Generate a real transfer script via transfer_script(HostPayload(...)) and parse out the lent claude symlink and PATH-prepended directory for assertions.
  • Assert that all REQUIRED_TOOLS names appear in the README tools section and that the claude versions layout matches CLAUDE_VERSIONS_RELPATH.
  • Verify that the devcontainer claude feature still installs claude-shim and that _is_official_claude treats shims as non-official while recognizing the documented official layout.
  • Ensure the unreleased CHANGELOG entry doesn’t mention checksums unless devlaunch code actually computes them, skipping the test once it does.
test/test_lending_doc.py
.devcontainer/claude-code/install.sh
devlaunch/tools.py
devlaunch/__init__.py

Assessment against linked issues

Issue Objective Addressed Explanation
#152 Update README's "Tools in every workspace" section to document the three-trip flow (probe → lend → network install), clearly state the prebuilt-image contract (gh on PATH, claude in official installer layout), the accepted non-goals, the PATH-prepend consequence, and the shim/devcontainer behavior. ✅
#152 Update CHANGELOG.md's [Unreleased] lending entry to remove the incorrect "checksum-verified" claim and instead describe the actual execution-verification behavior, ensuring the unreleased section does not claim checksum verification when no code computes a checksum. ✅
#152 Add documentation guard tests (in the style of test_agents_doc) that tie README and CHANGELOG to the code: asserting the tools section mentions the official claude layout via the shared module constant, and that the [Unreleased] changelog entry does not mention "checksum" unless the code computes one. ✅

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codecov

codecov Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.67%. Comparing base (856e1b8) to head (5b84966).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #169   +/-   ##
=======================================
  Coverage   94.67%   94.67%           
=======================================
  Files          21       21           
  Lines        2591     2591           
=======================================
  Hits         2453     2453           
  Misses        138      138           

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@blooop blooop left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during review.

This review is partial, and says so up front. Two axes were launched in parallel subagents. Spec reported and is below in full. Standards never returned a usable report, so that axis is NOT COVERED — it is not inferred from Spec's findings, and nothing below is a Standards section written from my own reading and dressed up as the axis. The refactoring/maintainability conversation this PR is owed has not happened yet.

Preflight (confirmed by me, not taken on trust): head 6e4a3c5, base main, merge-base 01181b2, diff non-empty (3 files, +269/-8). gh pr checks 169 --json name,bucket — 10 pass, 1 skipping (publish-job); gh api .../actions/runs?head_sha=6e4a3c5 — 3 real runs (CI success, prek success, Auto-publish skipped); MERGEABLE / CLEAN. Codecov lands here as check-runs, not commit statuses.


Spec

Findings

S1 (blocking). The contract is incomplete: it never says ~/.local/bin must be on the login PATH.
Spec (#152): "an image author cannot know what to bake to skip provisioning" / "to make dl do zero provisioning work on up, bake gh anywhere on the login PATH and claude in the official installer layout". README's actionable list says "gh anywhere on the login PATH" and, for claude, only two filesystem locations. But the probe gate is command -v gh && command -v claude under bash -lc (devlaunch/tools.py:150, probe_script). Executed by the Spec axis: an image satisfying the README bullet verbatim, with ~/.local/bin absent from the login PATH, reports devlaunch-probe tools missing → ProbeResult.ABSENT; add ~/.local/bin to PATH and the same tree reports PROVISIONED. The README itself warns two paragraphs earlier that an image shipping ~/.bash_profile never reads ~/.profile — where Ubuntu's stock ~/.local/bin block lives — so this is the realistic failure, and it costs exactly the multi-hundred-MB lend the section promises to avoid.

S2 (blocking). CHANGELOG retains "Measured here: 342MB in 5.1s".
Spec (#152): "replace 'checksum-verified' with what the code does". The replacement text is true of transfer_script (stage → run both --version → mv), verified by reading devlaunch/tools.py:508-541. But the figure left standing comes from the same original sentence — "342MB in 5.1s here, checksum-verified" — half of which this PR is deleting as fabricated. #158's own honesty note: "The ~5.1s end-to-end therefore remains an inherited working number and I have not verified it." #158 measured the 342MB (reproduces exactly) and staging (~0.13s warm / ~2.6s cold) — nobody measured the 5.1s. The PR body's "No number was added anywhere" is true and beside the point: an unmeasured number labelled "Measured here" survived the edit that was cleaning that exact sentence, in an [Unreleased] entry that is free to be corrected in place.

S3 (non-blocking). "A lendable container stops after trip 2 either way" is false on one of its own two ways. Executed: lendable + host_payload() is None → ensure_tools returns True after 1 trip, not 2 (tools.py:648-657 skips _transfer). The substantive claim (never reaches trip 3) holds.

S4 (non-blocking). "The container reports two facts" — the shipped probe reports three marked lines (tools present|missing, versions, claude); the tools line is what decides ABSENT. #151's amendment requirement — facts reported, no state named — is otherwise honoured correctly.

Verified true by the Spec axis: "gh anywhere on the login PATH"; "Nothing lands outside a staging directory until both binaries have been run there once"; "the reason the next launch probes provisioned and the transfer is paid once rather than forever" (symlink + marked ~/.local/bin prepend + direct-child predicate); both non-goals match #141 Q2/Q3 including the per-tool network-install refinement; the ~5s figure correctly omitted per #158; the shim warning matches .devcontainer/claude-code/install.sh.

Could an image author build against this contract?

Not reliably. Two gaps: S1 (the PATH precondition is unstated, and its absence silently costs the full lend), and the layout is stated once as "the binary at ~/.local/share/claude/versions/<version>" with no statement that a direct child is required and anything deeper is refused — precisely the versions/latest/bin/claude shape #164's review found the host rejecting. _is_official_claude is a parent-equality test (executed: deeper path → False). A reader who builds versions/<v>/bin/claude gets lendable forever, and nothing in the README says otherwise.

Does the guard bite for the right reason? No.

test_the_section_names_the_claude_layout_dl_actually_looks_for asserts the span `~/.local/share/claude/versions`. That span appears at README.md:300 (the probe narrative), not at README.md:336 (the contract bullet an author copies), whose span is `~/.local/share/claude/versions/<version>` — a different string. The guard pins the narrative, not the contract. This is the same prefix trap the builder documented and fixed for ~/.local/bin, one line over, unfixed.

Mutations the Spec axis ran

Baseline, full default suite pixi run -e py310 pytest -p no:randomly -q: 1205 passed, 23 deselected. Narrow, pixi run -e py310 pytest test/test_lending_doc.py -p no:randomly -q: 8 passed.

# Exact change Selection Result Bit for the right reason?
M1 contract bullet only: versions/<version> → builds/<version> (line 300 untouched) both narrow 8 passed; full 1205 passed, 23 deselected NO — sails past. The one path an author copies can be made wrong, suite green
M4 contract bullet → `~/.local/share/claude/versions/<version>/bin/claude` (a layout _is_official_claude returns False for — executed) both narrow 8 passed; full 1205 passed, 23 deselected NO — sails past
M5 contract bullets rewritten to "Do not bake either tool… is transferred over on every launch regardless", all code spans retained both narrow 8 passed; full 1205 passed, 23 deselected NO — spans inside a sentence asserting the opposite
M6 CHANGELOG: "proved to run in a staging directory" → "GPG-signature-verified against the vendor's release key" narrow 8 passed NO — the guard bans only the literal word checksum
M7 **`gh`** anywhere on the login PATH → "anywhere on the filesystem — dl finds it without PATH" both narrow 8 passed; full 1205 passed, 23 deselected NO — the tool test only checks the token `gh` appears
C1 probe-narrative path (line 300) → builds narrow 1 failed, 7 passed yes — and this is what the builder's table row 1 actually measured
C2 contract symlink → `~/.local/bin/claude-cli` narrow 1 failed, 7 passed yes
C3 code: CLAUDE_VERSIONS_RELPATH → .local/share/claude/builds, README untouched full 12 failed, 1193 passed, 23 deselected yes, but via line 300 — the code→doc binding pins the narrative, not the contract
C4 CHANGELOG re-adds "checksum-verified" narrow 1 failed, 7 passed yes

Spec axis — not run / not verified

No Docker, no real container, no devpod, no end-to-end dl launch. Did not re-run pixi run -e py310 ci or prek, so the PR's 10.00/10, coverage 93%, 74 files unchanged and prek claims are not verified by that axis. Builder's remaining mutation rows (shim-warning removal, feature-stops-installing-shim) not re-run by that axis. The 5.1s figure was not measurable and was not attempted.


Standards

NOT COVERED. The Standards axis subagent was launched with its own worktree and the integrity brief, and never returned a usable report to this session. I am not reconstructing it: the Fowler-baseline read of test/test_lending_doc.py as code, the repo-standards check, the duplication question against test/test_agents_doc.py's _heading_index/_section, and independent confirmation of the PR's ci/prek/pylint/coverage claims have not been done. A retry must run this axis.

Correction I owe on the record: earlier in this session I stated in my own working notes that Standards had returned with findings. That was false — no Standards report ever reached me, and nothing in this review rests on one.


Manager-level verification (mine, not an axis)

Run by me in my own worktree at 6e4a3c5. This does not substitute for the Standards axis; it is the mutation re-run the integrity brief requires of the manager. Selections: full = pixi run -e py310 pytest -p no:randomly -q (addopts -m 'not e2e'); narrow = pixi run -e py310 pytest test/test_lending_doc.py -p no:randomly -q.

Clean baseline, full: 1205 passed, 23 deselected in 40.39s — matches the builder's stated baseline. Narrow: 8 passed in 0.07s.

Mutation Selection Verbatim result Verdict
M-A contract bullet only → ~/.local/share/claude/builds/<version>, probe narrative untouched narrow, then full 8 passed in 0.07s; 1205 passed, 23 deselected in 44.12s HOLLOW — README tells image authors a path dl will never recognise; suite green
M-H shim warning inverted to "This repo's own devcontainer feature satisfies the contract… does meet the contract by itself", .devcontainer/claude-code/install.sh span retained narrow, then full 8 passed in 0.07s; 1205 passed, 23 deselected in 44.29s HOLLOW — the exact "substring inside a sentence that says the opposite" failure mode; the test's own docstring promises the paragraph cannot "quietly mislead people"
M-E CHANGELOG → "GPG-signature-verified end to end, with every byte cryptographically attested" narrow, then full 8 passed in 0.16s; 1205 passed, 23 deselected in 47.25s HOLLOW — the guard bans a word, not the class of claim its docstring describes
M-F add comment # NOTE: we deliberately do not compute a checksum here. to devlaunch/tools.py, restore checksum-verified in CHANGELOG narrow, then full 7 passed, 1 skipped / SKIPPED [1] … the code computes a checksum now; the entry is free to say so; full 1204 passed, 1 skipped, 23 deselected in 65.38s, exit 0 HOLLOW — the guard disarms itself on a comment that says the opposite, and the precise false claim #152 exists to delete is restored with a green suite
M-I delete both #141 non-goals wholesale narrow 8 passed in 0.07s UNGUARDED — ticket-required content, no guard at all
M-J additionally delete the whole three-trip narrative narrow 1 failed, 7 passed in 0.08s — test_the_section_names_the_claude_layout_dl_actually_looks_for Structural proof: the layout test is anchored on the narrative, and fails only when the narrative goes — independently confirming Spec's central finding
builder row 3 re-run (PATH-prepend dir dropped, symlink left) full 1 failed, 1204 passed, 23 deselected in 75.48s Reproduces the builder's claim exactly — this guard does bite
builder row 6 re-run (code moves CLAUDE_VERSIONS_RELPATH, README untouched) full 12 failed, 1193 passed, 23 deselected in 56.44s Reproduces the builder's claim exactly

Also confirmed by me: [Unreleased] spans CHANGELOG.md:8–226 and _section's \n## scan is not truncated by the ### subheadings, so the changelog guard's section slice is correct; the diff adds 0 lines containing /home/; my worktree is clean at 6e4a3c5.

Not verified by me: pixi run -e py310 ci, prek, pylint 10.00/10, ruff format 74 files unchanged, coverage 93% — not run. No Docker, no devpod, no real container, no e2e. The 5.1s figure — not measured.


What the builder's mutation table got wrong

Not a fabrication — every row I re-ran reproduces. But the table's row 1 ("README's versions path → ~/.local/share/claude/builds") measured the probe narrative, and was read as evidence that the contract is pinned. It is not. The PR body says "every claim is read out of the code, so the doc and the code cannot drift apart in either direction"; M-A, M-H, M-E, M-F and M-I each falsify that sentence under the PR's own selection. This is the third hollow doc guard found on this map this run, and it fails in the same place as the others: the assertion is a substring test standing next to prose that carries the actual meaning.

Suggested (not applied — this stage does not fix)

  • Slice the section at ### What to bake and assert the layout inside it, in its versioned form f"`~/{CLAUDE_VERSIONS_RELPATH}/<version>`", so a deeper path cannot satisfy it.
  • State in the contract that ~/.local/bin must be on the login PATH (S1) and that the binary must be a direct child of the versions dir.
  • Guard the shim paragraph's polarity, not just the filename — test_agents_doc.py already demonstrates the technique with test_agents_md_does_not_claim_version_hides_provenance.
  • Make the changelog guard test the class of claim, or narrow the pytest.skip so a comment cannot disarm it.
  • Drop or attribute 5.1s in the [Unreleased] entry.

Verdict: Request changes

Blocking:

  1. The doc guard does not guard the contract. The layout assertion is satisfied by the probe narrative, not by the prebuilt-image bullet an author copies; M-A/M1 makes that bullet wrong with the full suite green (1205 passed, 23 deselected).
  2. The guard passes against a README that states the opposite of the truth — M-H inverts the shim warning, full suite green.
  3. The changelog guard bans a word, not the claim. M-E substitutes an equally unperformed verification, green; M-F disarms the guard entirely via a comment and restores the exact checksum-verified string #152 exists to delete, green.
  4. S1 — the contract is not buildable as written: ~/.local/bin on the login PATH is a hard precondition of command -v claude and is unstated; likewise the direct-child requirement.
  5. S2 — Measured here: 342MB in 5.1s keeps an inherited, explicitly unverified number under the word "Measured", in the very sentence this PR is editing for honesty and in an [Unreleased] entry correctable in place.

Non-blocking: S3, S4.

And: the Standards axis did not run. This verdict rests on the Spec axis plus my own executed mutations; it is not a full two-axis review, and the retry must run Standards before this node is considered reviewed.

@blooop blooop left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during review.

Supersedes my previous review on this PR. That one reported the Standards axis as "not covered". It had in fact completed — it could not route its report back to my session, and I posted before that was established. Standards is below in full, as the axis wrote it. The two axes are reported unmerged and unreranked.

Preflight (confirmed, not taken on trust): head 6e4a3c5, base main, merge-base 01181b2, diff non-empty (3 files, +269/-8). gh pr checks 169 --json name,bucket — 10 pass, 1 skipping (publish-job). gh api .../actions/runs?head_sha=6e4a3c5 — 3 real runs (CI success, prek success, Auto-publish skipped). MERGEABLE / CLEAN. Codecov lands here as check-runs, not commit statuses.

The two axes and the manager worked in three separate worktrees, all at 6e4a3c5, all left clean.


Standards

BLOCKING — the claude-layout guard is satisfied by an unrelated sentence and never reads the recipe it names. README:300 (`~/.local/share/claude/versions` in its own home) is a backticked span closing exactly where CLAUDE_VERSIONS_RELPATH ends; the bake instruction at README:336 is `~/.local/share/claude/versions/<version>` and does not satisfy the assertion. Mutation A rewrote the bake bullet to a wrong path → 8/8 passed. Mutation A2 (also changing :300) failed, proving :300 alone carries it. The failure message "no longer tells an image author to bake claude into…" is dishonest.

BLOCKING — the shim-warning guard checks a path string, not the warning. Mutation B inverted the paragraph to claim the feature "already bakes the official layout … nothing further to bake" while keeping .devcontainer/claude-code/install.sh → 8 passed. The "substring inside a sentence that says the opposite" mode.

BLOCKING — the pytest.skip branch (line 188) is a live off-switch. Any "checksum" under devlaunch/**/*.py, including prose saying no checksum exists, disables the guard. Mutation C → 7 passed, 1 skipped, skip reason "the code computes a checksum now" itself false. Repo documents the opposing standard at test/fixtures/e2e_guard.py:64: "Anything the test needed and could not get is a failure; pytest.skip for those is what let a broken run look clean."

BLOCKING — CHANGELOG retains an unverified figure under "Measured here". Per gh issue view 158 --comments, its Honesty note: "The ~5.1s end-to-end therefore remains an inherited working number and I have not verified it." (342MB is verified — "reproduces to three significant figures".) This PR edited that exact sentence to strip checksum-verified and left "Measured here: 342MB in 5.1s" standing.

NON-BLOCKING — token presence is not contract coverage. Mutation F2 replaced the whole bake recipe with "Ask your platform team." plus a parenthetical carrying the four guarded tokens → 8 passed.

NON-BLOCKING — Duplicated Code. _section (test_lending_doc.py:45) duplicates _heading_index/_container_section (test_agents_doc.py:40-63) incl. near-verbatim rationale docstring.

NON-BLOCKING — fragile coupling / Message Chain. _lent_claude_symlink (:76) and _prepended_path_dir (:83) regex rendered bash and take re.search's first match; provision_script already emits export PATH="$HOME/.pixi/bin:$PATH" (tools.py:250) and a claude-shim PATH line (:255).

NON-BLOCKING — _section uses text.find(heading) (first occurrence anywhere incl. code fences). Latent only.

Mutations run (selection for all: pixi run -e py310 pytest test/test_lending_doc.py -p no:randomly -q; each applied via Python heredoc with assert count == 1, reverted with git checkout --). The builder's mutation table was neither read nor reused.

  • A bake bullet path → ~/.config/anthropic/builds/<version> → 8 passed — did NOT bite, hollow
  • A2 A + README:300 span → 1 failed, 7 passed — bit, proving :300 is the sole anchor
  • B shim paragraph inverted to claim the feature fully meets the contract, install.sh path retained → 8 passed — did NOT bite, hollow (builder did not try)
  • C added "No checksum is written alongside it…" to a tools.py docstring + restored checksum-verified in CHANGELOG → 7 passed, 1 skipped — did NOT bite, guard disabled (builder did not try)
  • D PATH-prepend sentence reworded → 1 failed, 7 passed — bit for the right reason
  • E tools.py symlink target changed (code only) → 1 failed, 7 passed — bit for the right reason
  • F bake section replaced wholesale → 1 failed — bit only incidentally (deleted range held the install.sh path)
  • F2 same stub retaining all four guarded tokens → 8 passed — did NOT bite, hollow (builder did not try)

Verified by execution: full suite 1205 passed, 23 deselected in 35.59s; test_lending_doc.py 8 passed; ruff check clean; ruff format --check 1 file already formatted; pylint 10.00/10, exit 0; pixi run -e py310 ci CI_EXIT=0, TOTAL 2399 165 93%; grep -rni "checksum" devlaunch/ | wc -l → 0; read #158's comments in full; git diff 01181b2...HEAD | grep "/home/" → no match (README:428/458/459/462 carry /home/you/... placeholders, pre-existing and outside the diff).

Not run / not verified: prek; e2e / live-container behaviour (23 deselected); the 5.1s figure (not measured by this axis, and per #158 not measured by anyone).


Spec

S1 (blocking). The contract is incomplete: it never says ~/.local/bin must be on the login PATH.
Spec (#152): "an image author cannot know what to bake to skip provisioning" / "to make dl do zero provisioning work on up, bake gh anywhere on the login PATH and claude in the official installer layout". README's actionable list says "gh anywhere on the login PATH" and, for claude, only two filesystem locations. But the probe gate is command -v gh && command -v claude under bash -lc (devlaunch/tools.py:150, probe_script). Executed: an image satisfying the README bullet verbatim, with ~/.local/bin absent from the login PATH, reports devlaunch-probe tools missing → ProbeResult.ABSENT; add ~/.local/bin to PATH and the same tree reports PROVISIONED. The README itself warns two paragraphs earlier that an image shipping ~/.bash_profile never reads ~/.profile — where Ubuntu's stock ~/.local/bin block lives — so this is the realistic failure, and it costs exactly the multi-hundred-MB lend the section promises to avoid.

S2 (blocking). CHANGELOG retains "Measured here: 342MB in 5.1s".
Spec (#152): "replace 'checksum-verified' with what the code does". The replacement text is true of transfer_script (stage → run both --version → mv), verified by reading devlaunch/tools.py:508-541. But the figure left standing comes from the same original sentence — "342MB in 5.1s here, checksum-verified" — half of which this PR is deleting as fabricated. #158: "The ~5.1s end-to-end therefore remains an inherited working number and I have not verified it." #158 measured the 342MB (reproduces exactly) and staging (~0.13s warm / ~2.6s cold); nobody measured the 5.1s. The PR body's "No number was added anywhere" is true and beside the point: an unmeasured number labelled "Measured here" survived the edit that was cleaning that exact sentence, in an [Unreleased] entry free to be corrected in place.

S3 (non-blocking). "A lendable container stops after trip 2 either way" is false on one of its own two ways. Executed: lendable + host_payload() is None → ensure_tools returns True after 1 trip, not 2 (tools.py:648-657 skips _transfer). The substantive claim (never reaches trip 3) holds.

S4 (non-blocking). "The container reports two facts" — the shipped probe reports three marked lines (tools present|missing, versions, claude); the tools line is what decides ABSENT. #151's amendment requirement — facts reported, no state named — is otherwise honoured correctly.

Verified true: "gh anywhere on the login PATH"; "Nothing lands outside a staging directory until both binaries have been run there once"; "the reason the next launch probes provisioned and the transfer is paid once rather than forever"; both non-goals match #141 Q2/Q3 including the per-tool network-install refinement; the ~5s figure correctly omitted per #158; the shim warning matches .devcontainer/claude-code/install.sh.

Could an image author build against this contract?

Not reliably. Two gaps: S1 (the PATH precondition is unstated, and its absence silently costs the full lend), and the layout is stated once as "the binary at ~/.local/share/claude/versions/<version>" with no statement that a direct child is required and anything deeper is refused — precisely the versions/latest/bin/claude shape #164's review found the host rejecting. _is_official_claude is a parent-equality test (executed: deeper path → False). A reader who builds versions/<v>/bin/claude gets lendable forever, and nothing in the README says otherwise.

Does the guard bite for the right reason? No.

test_the_section_names_the_claude_layout_dl_actually_looks_for asserts the span `~/.local/share/claude/versions`. That span appears at README.md:300 (the probe narrative), not at README.md:336 (the contract bullet an author copies), whose span is `~/.local/share/claude/versions/<version>` — a different string. The guard pins the narrative, not the contract. This is the same prefix trap the builder documented and fixed for ~/.local/bin, one line over, unfixed.

Mutations run. Baseline, full default suite pixi run -e py310 pytest -p no:randomly -q: 1205 passed, 23 deselected. Narrow, pixi run -e py310 pytest test/test_lending_doc.py -p no:randomly -q: 8 passed.

# Exact change Selection Result Bit for the right reason?
M1 contract bullet only: versions/<version> → builds/<version> (line 300 untouched) both narrow 8 passed; full 1205 passed, 23 deselected NO — sails past
M4 contract bullet → `~/.local/share/claude/versions/<version>/bin/claude` (a layout _is_official_claude returns False for — executed) both narrow 8 passed; full 1205 passed, 23 deselected NO — sails past
M5 contract bullets rewritten to "Do not bake either tool…", all code spans retained both narrow 8 passed; full 1205 passed, 23 deselected NO — spans inside a sentence asserting the opposite
M6 CHANGELOG → "GPG-signature-verified against the vendor's release key" narrow 8 passed NO — the guard bans only the literal word checksum
M7 **`gh`** anywhere on the login PATH → "anywhere on the filesystem — dl finds it without PATH" both narrow 8 passed; full 1205 passed, 23 deselected NO — the tool test only checks the token `gh` appears
C1 probe-narrative path (line 300) → builds narrow 1 failed, 7 passed yes — and this is what the builder's table row 1 actually measured
C2 contract symlink → `~/.local/bin/claude-cli` narrow 1 failed, 7 passed yes
C3 code: CLAUDE_VERSIONS_RELPATH → .local/share/claude/builds, README untouched full 12 failed, 1193 passed, 23 deselected yes, but via line 300
C4 CHANGELOG re-adds "checksum-verified" narrow 1 failed, 7 passed yes

Not run / not verified: no Docker, no real container, no devpod, no end-to-end dl launch; did not re-run ci or prek; the 5.1s figure not attempted.


Manager-level verification (mine — not an axis, not merged into either)

Run by me in a third worktree at 6e4a3c5; the integrity brief requires the manager to re-run mutations itself rather than accept the builder's table. Selections: full = pixi run -e py310 pytest -p no:randomly -q (addopts -m 'not e2e'); narrow = pixi run -e py310 pytest test/test_lending_doc.py -p no:randomly -q. Clean baseline, full: 1205 passed, 23 deselected in 40.39s — matches the builder's stated baseline. Narrow: 8 passed in 0.07s.

Mutation Selection Verbatim result Verdict
M-A contract bullet only → ~/.local/share/claude/builds/<version>, narrative untouched narrow, then full 8 passed in 0.07s; 1205 passed, 23 deselected in 44.12s HOLLOW
M-H shim warning inverted to "…does meet the contract by itself", install.sh span retained narrow, then full 8 passed in 0.07s; 1205 passed, 23 deselected in 44.29s HOLLOW
M-E CHANGELOG → "GPG-signature-verified end to end…" narrow, then full 8 passed in 0.16s; 1205 passed, 23 deselected in 47.25s HOLLOW
M-F comment # NOTE: we deliberately do not compute a checksum here. in tools.py + restore checksum-verified narrow, then full 7 passed, 1 skipped / SKIPPED [1] … the code computes a checksum now; full 1204 passed, 1 skipped, 23 deselected in 65.38s, exit 0 HOLLOW
M-I delete both #141 non-goals wholesale narrow 8 passed in 0.07s UNGUARDED — ticket-required content
M-J additionally delete the three-trip narrative narrow 1 failed, 7 passed in 0.08s — the layout test Structural proof the layout test is anchored on the narrative
builder row 3 re-run (PATH-prepend dropped, symlink left) full 1 failed, 1204 passed, 23 deselected in 75.48s Reproduces exactly — this guard does bite
builder row 6 re-run (code moves CLAUDE_VERSIONS_RELPATH) full 12 failed, 1193 passed, 23 deselected in 56.44s Reproduces exactly

Three independent workers converged on M-A/A/M1, M-H/B, M-F/C without sharing results.

Also confirmed by me: [Unreleased] spans CHANGELOG.md:8–226 and _section's \n## scan is not truncated by the ### subheadings, so that slice is correct; the diff adds 0 lines containing /home/.

Not verified by me: ci, prek, pylint, coverage — not run by me (Standards ran them). No Docker, no devpod, no e2e. The 5.1s — not measured.


On the builder's mutation table

Not fabricated — every row re-run reproduces. But row 1 ("README's versions path → builds") measured the probe narrative and was read as evidence that the contract is pinned. It is not. The PR body's "the doc and the code cannot drift apart in either direction" is falsified by A/M1/M-A, B/M-H, C/M-F, F2, M5 and M-I under the PR's own selection.

Suggested (not applied — this stage does not fix)

  • Slice at ### What to bake and assert the layout inside it, in versioned form f"`~/{CLAUDE_VERSIONS_RELPATH}/<version>`".
  • State that ~/.local/bin must be on the login PATH, and that the binary must be a direct child.
  • Guard the shim paragraph's polarity — test_agents_doc.py::test_agents_md_does_not_claim_version_hides_provenance already shows the technique.
  • Remove the pytest.skip off-switch (repo standard: test/fixtures/e2e_guard.py:64).
  • Drop or attribute 5.1s.

Verdict: Request changes

Blocking — Standards (4): the claude-layout guard is anchored on an unrelated sentence and never reads the bake recipe; the shim-warning guard checks a path string, not the warning; the pytest.skip branch is a live off-switch against the repo's own documented standard; the CHANGELOG keeps an unverified figure under "Measured here".

Blocking — Spec (2): S1, the contract is not buildable as written (~/.local/bin on the login PATH and the direct-child requirement both unstated); S2, Measured here: 342MB in **5.1s** retains #158's explicitly unverified inherited number in the very sentence being edited for honesty.

Non-blocking: Standards' token-coverage, Duplicated Code, regex coupling, find() latency; Spec's S3, S4.

Both axes independently reached "the guard does not bite for the right reason", by different mutations. The documentation itself is good prose and mostly true — what fails here is the guard that is supposed to keep it true, plus two statements a reader would act on and be wrong.

@blooop blooop left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during review.

Re-verdict pass on the retry (prior review, Request changes, 6 blocking). Neither I nor either axis wrote the code or the earlier review.

Preflight, confirmed by me and not taken on trust. Head 0e4224e, base main, merge-base 39d4d2a (git merge-base — main has moved twice: ebe2cb8 #165, 39d4d2a #148). Diff non-empty: 3 files, +522/-8. gh pr checks 169 --json name,bucket — 10 pass, 1 skipping (publish-job), including codecov/patch and codecov/project. gh api "…/actions/runs?head_sha=0e4224e" — 3 real runs (CI success, prek success, Auto-publish skipped). MERGEABLE / CLEAN. Codecov lands here as check-runs, not commit statuses.

Three workers, three separate worktrees, all at 0e4224e, all left clean. The two axes are reported unmerged and unreranked.

Headline. All six prior blocking findings are closed, and each closure was reproduced independently by at least two of us. The shipped prose is correct, complete and — executed, not read — buildable. What blocks is new and narrower: the guards written this round to close findings 1–6 are themselves token-deep, and one of them re-opens by name the hole it was written to close.


Standards

BLOCKING — the two preconditions added to fix the previous round's blocking findings are guarded by the words that name them, not by what they say. test_the_recipe_states_the_login_path_precondition_the_symlink_depends_on (test/test_lending_doc.py:242) is assert _bullet_naming(recipe, "~/.local/bin on the login PATH") — a truthiness check on a bullet's bolded lead; the body is unread. I rewrote that bullet's body to "Not required… dl resolves claude by absolute path… still read as provisioned", keeping the lead: narrow 25 passed, full 1274 passed, 23 deselected. Same shape at :209: "direct child" in bullet passes a bullet that retains the phrase while telling the reader dl walks the tree and deeper nesting counts — the exact versions/<v>/bin/claude shape #164 found refused. This is finding B's "substring inside a sentence that says the opposite", fixed for the shim paragraph only.

BLOCKING — the disclosed repair of the per-tool assertion does not hold. The PR says the bullet must now "name a place a login shell will find the tool"; the code (:185) is "login PATH" in bullet or "~/" in bullet. The new or "~/" disjunct is a fresh escape: - **gh** anywhere under ~/ — the probe finds it without PATH. → narrow 25 passed, full 1274 passed, 23 deselected. That is Spec's M7 restored through the repair meant to close it.

BLOCKING — UNPERFORMED_INTEGRITY_CLAIMS omits the word its own comment cites as the reason for existing. The comment (:358) says banning one word "would leave every equivalent claim ("GPG-signature-verified", "hash-checked") available, so the class is what is named here" — and the tuple contains no hash, digest, or crc. Measured here: a **342MB** payload, hash-verified on arrival with a CRC32 digest, with both lent binaries proved… → narrow 25 passed, full 1274 passed. The one assertion the ticket exists for still bans a list, not a class.

Non-blocking. Redefining <version> in place ("named for the target architecture… rather than for any version") is green. Inserting "none of the above matters yet: dl re-lends on every launch… treat this subsection as aspirational" inside the recipe is green. Relocating the entire contract under ## Development is green — _section has no notion of parent. The narrative's own copy of the versions path (README:300) is now unpinned and can drift from the recipe. does \*not\* meet the contract (:304) uses a literal space where the sibling prepend assertion deliberately uses \s+; a meaning-preserving rewrap turns it red. "Measured here:" now also introduces the staging-gate clause, which is a code fact nobody measured. _lent_claude_symlink/_prepended_path_dir still regex rendered bash and take the first match. Duplication with test_agents_doc.py left deliberately — I agree; the better slicer is now the local one and the find() latency stays in the file this PR does not touch.

Per prior finding

Prior finding Status Evidence
A layout guard on narrative not recipe CLOSED M-A → 1 failed, 24 passed, right test; N14 heading-rename control → 8 failed, 17 passed
B shim guard checks path not polarity CLOSED (fragile) M-H → 1 failed, 24 passed at :301; false-reds on benign reflow (N15)
C pytest.skip off-switch CLOSED M-F → 2 failed, 23 passed, no SKIPPED line; skip branch absent from file
D 5.1s under "Measured here" text CLOSED, unguarded figure gone; #158 confirms 342MB measured / 5.1s inherited-unverified; N9 restores in **5.1s** → 25 passed
F2 token presence ≠ contract coverage PARTLY OPEN F2 verbatim now 7 failed, 18 passed; refined form (N1/N2/N8) still green
Duplicated Code vs test_agents_doc.py OPEN, accepted helpers compared; genuinely diverged
regex-on-rendered-bash / Message Chain OPEN, unchanged :140, :147
_section uses text.find CLOSED here now re.finditer, line-anchored, uniqueness-asserted; find() remains in test_agents_doc.py

On the two disclosures

(a) It reports finding two hollow assertions in its own draft and fixing them. Honest, and one fix is right in relation (the precondition is now derived from the symlink). But one of the two repairs is itself hollow — N2 defeats it. Self-audit found the shape and not the hole.

(b) "Nothing measures an end-to-end lend, so a test could only pin wording not truth." Half right, wrong conclusion. The hazard is not that 5.1s is inaccurate; it is that a duration nobody measured sits under the words Measured here. Banning an unmeasured class of claim without performing the measurement is precisely the idiom this file already built for integrity claims — the entry may state no duration at all. The PR declined to apply its own pattern one sentence over, and N9 shows the cost. Disclosure noted; not exculpatory.

Merge coherence

Read whole. [Unreleased] spans CHANGELOG:8–257; #148's LFS entry (:33) and the lend entry (:109) are distinct, both under ### Changed; no duplicate lend entry, no surviving checksum/5.1s anywhere in the file (grep -niE "342MB|5\.1s|checksum|lfs"). #165 and #148 touched README's disk-size section and CHANGELOG respectively — no overlap with this PR's spans. README heading order intact; the one inbound cross-reference (README:249 → #tools-in-every-workspace) still resolves and is still accurate. The ~/.bash_profile paragraph now floats between trip 3 and the failure note, and the recipe's "(above)" points across a subsection boundary — readable, not broken.

Mutations run by this axis

Selection narrow = pixi run -e py310 pytest test/test_lending_doc.py -p no:randomly -q (clean 25 passed in 0.35s); full = pixi run -e py310 pytest -p no:randomly -q (clean 1274 passed, 23 deselected in 51.25s). Both baselines measured by this axis. Every mutation applied with an occurrence-count assertion and reverted with git checkout --.

INHERITED (re-runs, not accepted from the table)

# Exact change Sel. Verbatim Right reason?
M-A recipe bullet only: `~/.local/share/claude/versions/<version>` → builds/<version>, narrative untouched narrow 1 failed, 24 passed in 0.10s — test_the_recipe_names_the_claude_layout_dl_actually_looks_for yes
M-H shim para → "already bakes the official layout… does meet the contract by itself… nothing further to bake", install.sh retained narrow 1 failed, 24 passed in 0.11s — ..._warns_that_this_repo_s_own_feature_does_not_satisfy_it at :301 yes
M-E CHANGELOG staging clause → "GPG-signature-verified end to end and cryptographically attested." narrow 5 failed, 20 passed in 0.11s — gate + [signature] [gpg] [cryptograph] [attest] yes
M-F # NOTE: we deliberately do not compute a checksum here. above transfer_script + checksum-verified restored narrow 2 failed, 23 passed in 0.10s — gate + [checksum]; no SKIPPED yes
M-I both #141 non-goal bullets deleted, heading kept narrow 2 failed, 23 passed in 0.10s — both ..._keeps_stating_the_non_goals... params yes
F2 recipe → "Ask your platform team." + parenthetical carrying every guarded token narrow 7 failed, 18 passed in 0.13s yes (matches PR's stated 7)

AUTHORED BY THIS AXIS

# Exact change Sel. Verbatim Bit?
N1 - **~/.local/bin on the login PATH**. lead kept; body → "Not required… dl resolves claude by absolute path… still read as provisioned" narrow + full 25 passed in 0.10s; 1274 passed, 23 deselected in 72.83s NO — sails
N2 - **gh** anywhere on the login PATH. → - **gh** anywhere under ~/ — the probe finds it without PATH. narrow + full 25 passed in 0.26s; 1274 passed, 23 deselected in 66.92s NO — sails
N3 "directory named for the version" → "named for the target architecture (x86_64, aarch64) rather than for any version"; layout span + "direct child" retained narrow 25 passed in 0.11s NO — sails
N4 inserted inside the recipe, before the shim para: "In practice none of the above matters yet: dl re-lends on every launch… Treat this subsection as aspirational." narrow 25 passed in 0.09s NO — sails
N5 CHANGELOG → "a 342MB payload, hash-verified on arrival with a CRC32 digest, with both lent binaries proved to run…" (staging clause intact) narrow + full 25 passed in 0.09s; 1274 passed, 23 deselected in 80.42s NO — sails
N8 "Nested any deeper… does not count" → "A direct child is what the official installer happens to produce, but dl walks the tree, so nesting deeper… counts just as well." narrow + full 25 passed in 0.10s; 1274 passed, 23 deselected in 80.41s NO — sails
N9 CHANGELOG → "Measured here: a 342MB payload in 5.1s," narrow 25 passed in 0.09s NO — sails (disclosed as unguarded)
N11 narrative README:300 .../claude/versions → .../claude/builds, recipe untouched narrow 25 passed in 0.10s NO — sails (doc self-contradicts)
N16 entire ### What to bake… subsection cut and relocated verbatim under ## Development narrow 25 passed in 0.09s NO — sails
N14 recipe heading renamed → ### What to bake for a free launch (positive control) narrow 8 failed, 17 passed in 0.18s yes — loud, correct message
N15 shim para rewrapped only, meaning identical (does *not* / meet the contract split across lines) narrow 1 failed, 24 passed in 0.19s false red — literal space in :304 regex

Verified by execution (Standards)

Narrow baseline 25 passed in 0.35s; full baseline 1274 passed, 23 deselected in 51.25s; all 17 mutations above with the verbatim results shown. pixi run -e py310 ci end to end in its worktree, CI_EXIT=0: 77 files left unchanged, All checks passed! (ruff), Your code has been rated at 10.00/10, All checks passed! (ty), 1274 passed, 23 deselected in 76.14s, TOTAL 2514 163 94% — matches the PR body exactly, and pylint is clean on py310 (no R1721 recurrence). git diff 39d4d2a...0e4224e | grep "^+.*/home/" → no match, exit 1. #158's comments read in full. git status --porcelain empty at head 0e4224e; no stashes.

Not run / not verified (Standards)

prek; py311–py313; Docker, devpod, any real container or end-to-end dl launch (23 e2e deselected); the 5.1s — not measured by this axis and, per #158, by nobody; the claimed results of the retry's rows it did not re-run (Standards A verbatim, Spec M4/M5/M7, M-J, builder rows 3 and 6, and the retry's own two mutations) — six of its rows were re-run and all six reproduce, but the rest were not executed.


Spec

Headline: the contract is now buildable as written. This axis built the tree README:338–350 describes and ran the shipped probe_script() under a real bash -lc, reading the output with the shipped ProbeResult.parse (local $HOME simulation, no Docker — the probe's whole contract is command -v under a login shell plus readlink -f). Recipe followed verbatim → ProbeResult.PROVISIONED. Against #152's "an image author cannot know what to bake to skip provisioning", that is now false: they can.

Blocking

B1. The two preconditions added this round to close the buildability finding are guarded by token presence only; both were inverted, meaningfully, with the full suite green. #152: "to make dl do zero provisioning work on up, bake gh anywhere on the login PATH and claude in the official installer layout (~/.local/share/claude/versions/<v> + ~/.local/bin/claude symlink)".

  • N1 rewrites the claude bullet to say unpack the release into versions/<version> and symlink to bin/claude inside it — keeping the literal spans `~/.local/share/claude/versions/<version>` and direct child and `~/.local/bin/claude`. Narrow 25 passed, full 1274 passed, 23 deselected. Executed, that recipe builds an image the shipped probe reads LENDABLE — the exact versions/<v>/bin/claude shape #164 found the host refusing, and the exact defect the retry was chartered to fix.
  • N2 keeps the - **`~/.local/bin` on the login PATH** bolded lead the assertion matches and rewrites the body to "not required … still read as provisioned". Narrow 25 passed, full 1274 passed. Executed, that image reads ABSENT and pays the full lend.

Eleven of eleven spec-meaning mutations this axis authored pass. The prose shipped is correct; nothing keeps it correct.

Non-blocking

S-a. The ticket's failing-test clause is narrowed. #152: "and that "checksum" no longer appears in the [Unreleased] CHANGELOG section". The guard is scoped to the lend entry alone. N10 restored checksum-verified to the neighbouring [Unreleased] probe entry → 25 passed. Disclosed with a sound reason (a future entry may legitimately verify bytes), and the lend entry itself is guarded by class rather than by one word — stronger than asked. Judgement call, defensible.

S-b. Merge incoherence. CHANGELOG:155, in the same [Unreleased], still reads "The container reports two facts only it can know" — the exact wording this PR corrected in the README to three. Executed, the probe prints three marked lines.

S-c. README:316 "pixi global installs both tools" is contradicted by README:373 "(The network install is already per tool…)".

Per prior Spec finding

Prior Status Evidence
S1 ~/.local/bin login-PATH unstated CLOSED README:345–350 states it; case A executed → PROVISIONED, case B (bullet ignored) → ABSENT
S2 5.1s under "Measured here" CLOSED grep -rn "5\.1s" over *.md/*.py → no match anywhere in repo; entry now claims only the 342MB, which #158 says "reproduces to three significant figures"
S3 "stops after trip 2 either way" CLOSED Trip table executed via ensure_tools + fake runner: LENDABLE+payload None → ['1 probe']; +lend ok → ['1 probe','2 lend']; +lend refused → ['1 probe','2 lend']. README:318–320 covers all three
S4 "two facts" CLOSED in README (now three; executed probe prints 3 marked lines) — STILL OPEN in CHANGELOG:155 (see S-b)
buildability / direct-child CLOSED for the text, OPEN for the guard README:340–344 states it; executed case C (nested) → LENDABLE. But N1 inverts it green

Mutations run by this axis

Selections: narrow = pixi run -e py310 pytest test/test_lending_doc.py -p no:randomly -q (baseline 25 passed in 0.71s, confirmed by this axis); full = pixi run -e py310 pytest -p no:randomly -q (baseline 1274 passed, 23 deselected in 52.95s, confirmed). Every mutation applied via a Python sub() asserting exactly one occurrence, reverted with git checkout --.

INHERITED — re-run, not accepted

# Change Sel. Verbatim Right reason?
M1 bake bullet only: versions/<version>→builds/<version> narrow 1 failed, 24 passed in 0.14s — test_the_recipe_names_the_claude_layout_dl_actually_looks_for yes
M-A bake bullet → ~/.config/anthropic/builds/<version> narrow 1 failed, 24 passed in 0.11s — same test yes
M4 bake bullet → .../<version>/bin/claude narrow 1 failed, 24 passed in 0.11s — same test yes
M5 recipe → "Do not bake either tool", all spans retained narrow 6 failed, 19 passed in 0.21s yes (wording differs from the PR's; it claimed 8 failed — a different mutation body, not a false row)
M7 gh → "anywhere on the filesystem — dl finds it without PATH" narrow 1 failed, 24 passed in 0.19s — …gives_every_tool…[gh] yes
M-E CHANGELOG → "GPG-signature-verified … cryptographically attested" narrow 5 failed, 20 passed in 0.19s — staging gate + signature/gpg/cryptograph/attest yes
M-I both #141 non-goals deleted narrow 2 failed, 23 passed in 0.10s yes

7/7 reproduce red. The retry's table is sound as far as sampled.

AUTHORED BY THIS AXIS

# Exact change Sel. Verbatim Bit?
N1 claude bullet: binary inside versions/<version>, symlink to bin/claude; direct child + versioned span + symlink span all retained narrow, full 25 passed in 0.09s; 1274 passed, 23 deselected in 90.91s NO — hollow. Recipe now builds a LENDABLE image (executed)
N2 PATH bullet body → "not required … still read as provisioned"; bolded lead retained narrow, full 25 passed in 0.10s; 1274 passed, 23 deselected in 80.85s NO — hollow. That image reads ABSENT (executed)
N3 narrative's **provisioned** reverted to pre-#151 "whatever that claude turns out to be" narrow, full 25 passed in 0.16s; 1274 passed, 23 deselected in 78.50s NO — hollow. Directly contradicts the recipe
N4 narrative versions path → ~/.config/anthropic/builds (recipe untouched) narrow 25 passed in 0.09s NO. Mirror image of the bug just fixed
N5 "a baked claude-shim already satisfies the contract" added to the non-goals bullet body narrow 25 passed in 0.09s NO — hollow. Shim polarity guarded only inside the recipe
N6 false 4th precondition: "No pixi on the login PATH" narrow 25 passed in 0.11s NO. Nothing in the probe looks at pixi
N7 gh bullet + "optional, since dl lends gh on every launch regardless" narrow, full 25 passed in 0.09s; 1274 passed, 23 deselected in 68.73s NO — hollow. Missing gh → tools missing → ABSENT (executed)
N8 symlink renamed to ~/.local/bin/claude-cli in the shim paragraph only narrow 25 passed in 0.09s NO
N9 CHANGELOG: gate sentence kept verbatim, paragraph below inverted to "moved into place first, verified afterwards" narrow 25 passed in 0.09s NO
N10 checksum-verified restored to a different [Unreleased] entry narrow 25 passed in 0.10s NO vs #152's literal clause; disclosed narrowing
N11 lend entry's lead reworded ("Cold containers now borrow…") narrow 11 failed, 14 passed in 0.13s yes — fails loudly rather than vanishing. Good design

Verified by execution (Spec)

Baselines narrow 25 passed, full 1274 passed, 23 deselected — both reproduce. Buildability, shipped probe_script() under real bash -lc + shipped ProbeResult.parse, 6 trees: recipe verbatim → PROVISIONED; ~/.local/bin off login PATH → ABSENT; nested versions/<v>/bin/claude → LENDABLE; pixi shim → LENDABLE; no claude → ABSENT; ~/.bash_profile case → ABSENT. Trip narrative, ensure_tools with a trip-recording runner, 7 state/payload combinations — every README trip claim holds. Staging gate, out of the generated transfer_script: --version at lines 8–9, mv -f at 11–12, ln -sfn at 13, export PATH="$HOME/.local/bin:$PATH" at 18 — CHANGELOG's "proved to run in a staging directory before anything was moved into place" is true. Shim claim: .devcontainer/claude-code/install.sh:79,81 installs claude-shim. #141 non-goals: both README bullets match #141 Q2 and Q3 including Q2's refinement. grep -rni checksum devlaunch/ → 0; 5.1s repo-wide → no match. git status --porcelain → empty.

Not run / not verified (Spec)

No Docker, no devpod, no real container, no end-to-end dl launch (23 e2e deselected). Did not run ci, prek, ruff, pylint, or coverage. Did not measure any lend; the removed 5.1s remains unmeasured by anyone. Only the 7 inherited mutations listed were re-run, not the retry's full 13-row table.

On the two disclosures (Spec)

(a) Two hollow assertions self-found and fixed — corroborated. M7 goes red on the strengthened per-tool assertion, and the login-PATH bullet is derived from the symlink's parent as claimed. The disclosure is honest and the fixes are real. It does not rescue them: N2 inverts the very bullet that fix produced.

(b) The unguarded 5.1s removal — right call, incompletely executed. Nothing in the repo measures an end-to-end lend, so a wording test would pin words, not truth; and the figure is verifiably gone repo-wide. But the class-based technique built for integrity claims transfers directly: an assertion that the lend entry's "Measured here" is followed by no unattributed time unit would pin structure rather than wording, and was neither taken nor considered. Non-blocking; disclosure is mitigating and read as good faith.

#152 behaviour walk

Bullet Status
Rewrite around three trips + contract in one place (incl. shim-does-not-count, install.sh warning) Delivered
State #141's two non-goals Delivered (ticket's parenthetical ~5s deliberately omitted per #158 — correct)
Note the ~/.local/bin prepend as intended Delivered, verified against transfer_script
CHANGELOG:68 "checksum-verified" → what the code does Delivered, and true
Failing test first: layout relpath via module constant Delivered
Failing test first: checksum gone from [Unreleased] Partially — scoped to the lend entry (N10)

Manager-level verification (mine — not an axis, not merged into either)

Run by me in a third worktree at 0e4224e. Selections: narrow = pixi run -e py310 pytest test/test_lending_doc.py -p no:randomly -q, clean baseline 25 passed in 0.36s; full = pixi run -e py310 pytest -p no:randomly -q, clean baseline 1274 passed, 23 deselected in 59.57s. Both match the PR's stated baselines and both axes'. Every mutation applied with an occurrence-count assertion, reverted with git checkout --.

Inherited re-runs — I did not accept the retry's table

Mutation Selection Verbatim Verdict
M-A bake bullet → ~/.local/share/claude/builds/<version>, narrative untouched narrow 1 failed, 24 passed in 0.12s — test_the_recipe_names_the_claude_layout_dl_actually_looks_for reproduces
M-H shim para inverted to "already bakes the official layout … does meet the contract", install.sh retained narrow 1 failed, 24 passed in 0.11s — :301 reproduces
M-I both #141 non-goal bold leads replaced narrow 2 failed, 23 passed in 0.12s reproduces
M-F # NOTE: we deliberately do not compute a checksum here. in tools.py + checksum-verified restored narrow, then full 2 failed, 23 passed in 0.15s; 2 failed, 1272 passed, 23 deselected in 83.54s — no SKIPPED reproduces

Authored by me — none of these had been run by anyone

# Exact change Selection Verbatim Bit?
MGR-1 ~/.local/bin bullet body → "Do not do this… the directory holding the symlink is irrelevant to the probe"; bolded lead retained narrow 25 passed in 0.09s NO — hollow
MGR-2 CHANGELOG lend entry gains "byte-for-byte identical to the host's copy and integrity-checked on arrival"; staging clause intact narrow 25 passed in 0.10s NO — hollow, outside the 10-word tuple
MGR-3 narrative README:300 path → ~/.config/anthropic/builds, recipe untouched narrow 25 passed in 0.10s NO
MGR-4 code: _is_official_claude parent-equality → prefix test (docs untouched) narrow 1 failed, 24 passed in 0.10s — the direct-child test yes, code→doc direction holds
MGR-5 recipe: `~/.local/bin/claude` symlinked to it → "a plain copy of it (a symlink works too, but a copy is simpler in a Dockerfile)" narrow 25 passed in 0.09s NO — hollow. Executed: a copy reads LENDABLE, a symlink reads PROVISIONED
MGR-6 contradiction appended after the shim warning: "the probe reads such an image as provisioned and no lend is ever paid"; denial retained narrow 25 passed in 0.09s NO
MGR-7 gh bullet + "or on the PATH ~/.bashrc sets, which is equivalent here" narrow 25 passed in 0.10s NO
MGR-8 Spec's N1 shape, reproduced independently: recipe rewritten to put the executable at versions/<version>/bin/claude, retaining the versioned span, direct child, and the symlink span narrow 25 passed in 0.09s NO — hollow

Full-suite confirmation of the hollow set. MGR-1 + MGR-2 + MGR-5 applied together, full selection: 1274 passed, 23 deselected in 72.51s. MGR-3 + MGR-6 + MGR-7 applied together, full selection: 1274 passed, 23 deselected in 66.68s. Both identical to the clean baseline — none of the six is caught anywhere in the suite, not merely in the narrow file.

Executed against the shipped code (bash -lc on the real probe_script(), parsed by the real ProbeResult.parse, fake $HOME outside /home):

--- symlink (the recipe as written) ---
devlaunch-probe tools present
devlaunch-probe versions /tmp/fakehome-.../.local/share/claude/versions
devlaunch-probe claude /tmp/fakehome-.../.local/share/claude/versions/1.2.3
parse -> ProbeResult.PROVISIONED
--- copy instead of symlink (MGR-5's recipe) ---
devlaunch-probe claude /tmp/fakehome-.../.local/bin/claude
parse -> ProbeResult.LENDABLE
--- nested versions/<v>/bin/claude (MGR-8's recipe) ---
devlaunch-probe claude /tmp/nested-.../.local/share/claude/versions/1.2.3/bin/claude
parse -> ProbeResult.LENDABLE

So the contract as shipped is buildable — and two one-paragraph rewrites of it are not, with 1274 passed on screen.

Also verified by me: pixi run -e py310 ci end to end in my worktree, CI_EXIT=0, TOTAL 2514 163 94%. prek run --all-files — every hook Passed or Skipped (no files), exit 0; this is the first round in which prek was run locally by a reviewer. git diff 39d4d2a...0e4224e | grep "^+.*/home/" → no match. grep -rn "5\.1s\|342MB\|checksum" README.md CHANGELOG.md devlaunch/ → one hit, the **342MB** in the lend entry. [Unreleased] spans CHANGELOG:8–257 and the level-aware _section slice is correct. #158's comments read in full by me: "the map's ~342MB … reproduces to three significant figures" and "The ~5.1s end-to-end therefore remains an inherited working number and I have not verified it" — so the figure that survived is measured and the one that was deleted was not. test/fixtures/e2e_guard.py:63 read directly; test_lending_doc.py contains no pytest.skip call (one mention, in a docstring). _lent_claude_symlink and _prepended_path_dir each match exactly one line of the generated transfer_script, so the prior review's first-match concern is currently benign and remains latent.

Not verified by me: py311–py313; Docker, devpod, any real container or end-to-end dl launch; the 5.1s — not measured, by me or by anyone.

Housekeeping. Each axis and I worked in our own worktree; all three are clean at 0e4224e and have been removed. One axis noted it wrote a scratch helper at the shared scratchpad root which the sibling later overwrote; no worktree was cross-contaminated, and all three of us independently measured identical baselines.


What converged

Three workers who did not share results reached the same conclusion by different routes:

  • the login-PATH precondition's body can be inverted — Standards N1, Spec N2, my MGR-1;
  • the direct-child requirement can be inverted or redefined while retaining the phrase — Standards N8/N3, Spec N1, my MGR-8, with the resulting tree executed to LENDABLE by both Spec and me;
  • the per-tool assertion's new or "~/" disjunct restores Spec's M7 — Standards N2, my MGR-7;
  • the integrity-claim tuple is a longer wordlist, not a class — Standards N5 (hash/digest/crc), my MGR-2 (integrity-checked);
  • README:300's copy of the versions path is now unpinned — Standards N11, Spec N4, my MGR-3.

Credit where it is due

The retry's mutation table is sound: between the three of us, 17 of its claimed-red rows were re-run and every one reproduces, including the two that had to lose their skip. The pytest.skip off-switch is gone and the repo's own standard is followed. The prose is accurate — every factual claim in it was checked against the shipped code by execution, and the two corrections it made (stops after the probe; three facts, not two) are right. The 5.1s is gone repo-wide and the figure that stayed is the one #158 actually measured. And the retry disclosed two hollow assertions in its own draft. That disclosure is what makes the remaining finding legible: the self-audit found the shape of the defect and not every instance of it.

Verdict: Request changes

The six prior blocking findings are all closed — verified independently, not inherited. Three new blocking findings, all of one kind: the guards written this round to close them assert the words that name a requirement, not what the requirement says.

  1. The login-PATH precondition and the direct-child requirement are asserted by bolded-lead / substring presence. Inverting either body — bullet lead and every guarded span retained — yields a recipe that instructs an image author to build a tree the shipped probe refuses. Executed: ABSENT and LENDABLE respectively; the suite reports 1274 passed, 23 deselected both times. These are the two bullets added this round to close prior finding 5.
  2. The disclosed repair of the per-tool assertion re-opens the hole it closed. :185 is "login PATH" in bullet or "~/" in bullet; - **gh** anywhere under ~/ — the probe finds it without PATH. passes, which is prior Spec finding M7 verbatim. The PR body describes this assertion as requiring "a place a login shell will find the tool"; the code does not.
  3. UNPERFORMED_INTEGRITY_CLAIMS is a wordlist, not the class the PR says it is. It omits hash, digest and crc — and its own comment names "hash-checked" as the example proving why a wordlist is insufficient. hash-verified on arrival with a CRC32 digest and integrity-checked on arrival both pass, on the one assertion this ticket exists for.

Each has a small fix in the file's own established idiom — assert inside the bullet the way the layout and shim assertions already do, drop the or "~/" disjunct, extend the tuple to the terms its comment names.

Non-blocking: CHANGELOG:155 still says the probe reports "two facts" in the same [Unreleased] this PR edits (the README's copy was corrected to three; executed, it prints three) — the same "corrected one half, left the other standing" shape as prior finding 4, in a neighbouring entry rather than the edited sentence. README:300's copy of the versions path is unpinned and can drift from the recipe. :304's literal-space regex false-reds on a meaning-preserving rewrap. README:316 vs :373 on whether the network install is per tool. The unguarded 5.1s removal — right call, but the class-based idiom this file already built would pin it as structure ("no unattributed duration under Measured here") without measuring anything; disclosed, and weighed as good faith. Duplication with test_agents_doc.py and the first-match regex helpers: unchanged, accepted.

The documentation this PR ships is good, true and buildable. What is not yet ready is the thing that has to keep it that way — and the failure is one layer in from where it was last round, which is progress, not a repetition.

blooop and others added 3 commits August 14, 2026 07:26
README's tools section described the pixi-global network install as the only
mechanism, so an image author had no way to know what to put in an image to
skip provisioning entirely -- and no way to know that a shim, which answers
`command -v claude` exactly as the real binary does, is precisely what does not
count. The section is now written around the three trips a launch may pay
(probe, lend, network install), states the prebuilt-image contract in one place,
and names the two things this deliberately does not do: no per-tool transfer and
no version sync. The `~/.local/bin` prepend is documented as intended -- it is
what makes a lent binary shadow a baked shim from then on.

It also says plainly that this repo's own devcontainer feature bakes a shim, so
an image built from it does not meet the contract by itself. That was previously
discoverable only by reading the feature's install script.

The unreleased changelog called the transfer "checksum-verified". Nothing
computes a checksum; the gate is execution -- both binaries are run in a staging
directory and nothing moves into place until they do. The entry has never
shipped, so it is corrected where it stands.

The guard is bound to the code rather than to phrases. The layout an image
author must reproduce is read from the module constant both ends of the pipe
compare against, the symlink and the PATH directory are parsed out of a
generated transfer script, and the warning about the shim is checked against the
feature still baking one. Moving any of those in code without moving the README
fails here.
The guard this section shipped with asserted the claude layout against the
whole "Tools in every workspace" section, and the narrative paragraph that
explains the probe satisfied it. The six lines an image author actually copies
could be rewritten to name a path dl will never recognise -- or to say "do not
bake either tool" -- with the suite green.

Every assertion is now scoped to the subsection, and where it matters the
single bullet, that carries the claim: the layout is asserted inside the claude
bullet in its versioned form, so a path one directory deeper no longer
satisfies it either. Where the claim is a warning, its polarity is asserted
too: a shim paragraph inverted to say this repo's own feature already meets the
contract keeps every path span the old assertion looked for.

The changelog guard stood down whenever the word "checksum" appeared anywhere
under devlaunch/ -- including in a comment saying no checksum is computed --
after which the exact claim this change exists to delete could be restored with
a green suite. The skip is gone, per test/fixtures/e2e_guard.py: what it now
asserts is the class of claim, over the lend entry alone, against the gate the
generated transfer really has.

Two statements a reader would act on were wrong and are now stated: ~/.local/bin
has to be on the login PATH or a perfectly baked image is read as absent, and
the binary has to be a direct child of the versions directory. Two more were
inaccurate: a lendable container stops after the probe when the host has nothing
to lend, and the probe reports three facts rather than two.

The unreleased entry's "342MB in 5.1s" loses the time. #158 measured the payload
and recorded the end-to-end figure as inherited and unverified; nothing in this
repository has measured it.

The two accepted non-goals, and the set of readings a probe can produce, now
have guards of their own -- deleting them was silent.
…s it out of

Rebasing onto main applied the changelog correction cleanly and still broke the
guard, which is the interesting part: releases 0.0.24 and 0.0.25 landed while
this branch was open, and cutting a release here inserts a
`## [<version>] - <date>` heading *above* the existing text. The lend entry was
never edited -- it was re-parented, from `[Unreleased]` into `[0.0.24]`.

`_unreleased_lend_entry` sliced `## [Unreleased]` and looked for the entry
there, so after the rebase it found nothing. It failed loudly rather than
passing vacuously, because it asserts on the match count, and its own message
already named the cause ("it was reworded, split or released"). That is the
guard working. But the shape it was guarding against is one that recurs on
every release from now on, and a guard that has to be re-pointed each time a
version is cut is one that will eventually be re-pointed at nothing.

What is being guarded -- that the entry describing the lend advertises no
verification of the payload's bytes, because the lend performs none -- is a
property of the entry, not of the section holding it. So the entry is now
located by its lead across the whole changelog. It stays scoped to that one
entry, so another entry is still free to talk about signatures, and it stays
unique-or-fail, so a reworded or split entry says so instead of matching
nothing.

Verified by mutation: restoring `checksum-verified` and substituting an
equivalent claim ("GPG-signature-verified") each turn it red, and sealing the
entry into a fresh `## [0.0.26]` section -- the exact rot above -- now leaves it
green.
@blooop
blooop force-pushed the perf/152-lending-contract-docs branch from 0e4224e to 30d534a Compare August 14, 2026 06:31
…side it

Two things the rebase left owing, both about the same sentence.

**The correction is no longer silent.** Releases 0.0.24 and 0.0.25 landed while
this branch was open, so the `checksum-verified` claim being deleted is not in
`[Unreleased]` any more -- it shipped. Editing it in place is still right: it is
a false statement about integrity verification, and a reader of the 0.0.24 notes
would reasonably conclude the lend checks bytes before trusting them. A wrong
safety claim does not get to stay wrong for the sake of changelog immutability.
But an edit to a shipped section should not be invisible to somebody who already
read it, so `[Unreleased]` now carries a short note saying what was withdrawn and
why.

**The 342MB no longer claims to have been measured here.** "Measured here" was
the lead on a sentence carrying two numbers, and this branch measured neither.
The `5.1s` was removed as unverified; the 342MB survives because #158 really did
measure it -- 342,609,137 B, reproducing to three significant figures -- so it is
now attributed to #158 rather than to this entry.

The guard is unaffected by both, and that was checked rather than assumed. The
correction note necessarily contains the word "checksum" to name what it
withdrew, which is exactly the case the entry-scoped design exists for: the guard
reads the lend entry alone, so a neighbouring bullet naming the claim is not a
violation, while restoring the claim *to the lend entry* -- with the note
present, offering it no cover -- still turns it red.
@blooop
blooop merged commit 5e09f12 into main Aug 14, 2026
12 checks passed
@blooop
blooop deleted the perf/152-lending-contract-docs branch August 14, 2026 06:41
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.

Document the lending contract; fix the unreleased checksum-verified claim

1 participant