Skip to content

docs(readme): make Troubleshooting a lookup table again — 35,250 → 19,182 bytes - #625

Merged
ZacxDev merged 3 commits into
mainfrom
fix/readme-troubleshooting-compression
Sep 15, 2026
Merged

ZacxDev merged 3 commits into
mainfrom
fix/readme-troubleshooting-compression

Conversation

@ZacxDev

@ZacxDev ZacxDev commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Phase 3 of the README reduction arc (plan: claudedocs/readme-reduction-plan.md, #623). The Troubleshooting section becomes a lookup table again: column 1 is the string you got, column 2 is what the message did not tell you, column 3 is where the detail lives.

Correction (round-1). The first revision of this PR claimed "No facts deleted". That was overstated by two clauses — both are now itemised under Disclosed deletions below. The claim is now: no fact deleted except the two listed there.

before after Δ
## Troubleshooting 35,250 19,182 −16,068 (−45.6%)
whole README.md 314,712 305,021 −9,691
cross-section give-back 6,377 (was 6,382 before round-1)
symptom strings (col 1) 68 68 0 — byte-identical
in-document links 212 216 +4
## / ### headings 27 / 47 27 / 47 0

Mean cause cell 469 → 204 bytes. Largest non-frozen cell 2,832 → 611. Per bucket (table rows + header + divider): Credentials 5,965→3,912 · Scaffolding 1,120→636 · Validating and submitting 15,857→8,261 · Generating 3,339→2,351 · Everything else 8,011→3,381.

All 60 rows are still present and column 1 of every one is byte-identical to origin/main — verified with a positive control (mutating row 1's column 1 is detected).

Round-1: the cells that restated the binary

14 cause cells were near-verbatim paraphrases of the error string the CLI had just printed on the line above. Column 2 is pinned against nothing — unlike column 1, which TestREADMETroubleshootingSymptomsExistInTheSource holds to the source — so that mirror can drift silently while adding nothing a reader does not already have on screen. Each is trimmed to what the message does not say (the exit code, a cross-command caveat) plus the anchor.

Rows trimmed: cannot derive a slug from · is not valid UTF-8 · … and the limit is … · refusing to overwrite. Scaffold somewhere else · there is no open revision to submit · this listing is not live · pass a URL or --clear, not both · the source-repository URL is blank · no such directory … · is not a directory … · refusing to submit without --yes · is ambiguous — it matches · checksum mismatch for · git is required for `civitai app pull` . Column 2 loses 1,103 bytes across the 14.

No ROW was removed. TestREADMETroubleshootingCoversTheRefusalsAuthorsActuallyHit puts 7 rows on an incident floor, and 4 of these 14 are on it: cannot derive a slug from, refusing to overwrite. Scaffold somewhere else, no such directory — pass the path to an App project root, refusing to submit without --yes. That list was re-derived from the test, not carried over.

Every retained exit code was measured against the built binary, not derived from the classifier. Rows 15/16/17 exit 2; 18 exits 1; 27/29/31/32 exit 2; 36 exits 1; 56 exits 2 (local stub for the model-version read); 59 exits 1 (local stub for the clone-info query). Row 58's exit code is deliberately not claimedcivitai upgrade has no API-base override, so it could not be measured here, and a derived code is not a measured one.

Two cells gained a correction the measurement surfaced:

  • is not valid UTF-8 said "Pass --slug, and a --name that is valid UTF-8". Measured: the refusal is about the display name, which goes into block.manifest.json verbatim, and it fires with --slug supplied. --slug is not part of the remedy.
  • is ambiguous — it matches described a different message — the exact same-name collision, which prints matches N files that share this name. The fragment the row quotes is the substring match (download.go:647).

Source strings were read with find … -print0 | xargs -0 grep over 136 non-test .go files under internal/, cmd/ and pkg/ — the repo's grep is ugrep and is .gitignore-blind — with a positive control (a string that must exist: 1 hit) and a negative control (a string that must not: 0 hits).

Round-1: three other audit findings

The relocated detail was unreachable from the row that sent you there. The from a dirty git work tree row linked #exit-code-1 — whose bullet says the guard "degrades rather than enforcing", the opposite of what a git init-with-no-commits author just saw — and the top of a 533-line section, 275 lines above the two bullets that are the answer. The row now names the sub-head, the house pattern rows 11 and 40 already use.

####/##### anchors are deliberately not linked. readmeHeadingRe in readme_nav_test.go matches ##/### only, so a direct #what-the-… link fails TestREADMEAnchorLinksResolve. Measured, not assumed — the first attempt did exactly that and reddened.

The relocation target was itself a misfile. #### What the packager left out documents the Skipped N path(s) line. The paragraph about the dirty-work-tree guard sharing that exclusion list belongs there; the two bullets after it are properties of the guard, and now sit under their own ##### What the dirty-work-tree guard counts as a change. The heading is paid for out of the same block, so the cross-section give-back does not grow: 6,382 → 6,377.

The gate warning now ships somewhere durable. It lived only in this PR body and in claudedocs/readme-reduction-plan.md (#623, retired when the arc closes). It is now a comment on TestAttributionProseCheckAcceptsCorrectProseAndRejectsMisattribution, next to the frozen spans it protects, carrying the measured pair below.

Disclosed deletions

Deleted as maintainer history: a reporter credit, a dated measurement, "#422 retired the … refusal", and a preamble paragraph about which tests guard the table.

Two clauses were deleted without being disclosed, and are disclosed now — both from the the server rejected this store-listing change (400) cell (2,832 → 611):

  1. (a revision that exists but was never reordered proves nothing either) — the symmetric twin of the icon parenthetical. The icon half (a listing being re-branded already has an *old* icon, which proves nothing) was carried across into After you submit; this one was not, and is absent from the whole after-README under whitespace-normalised search.
  2. The #430 archaeology clause. The carried-over sentence ends at "…which is also when a live reorder started reaching the revision routes at all." The original continued: "before it, a reorder of a live listing could only ever produce this row, because it was addressed to the parent listing while the ids it carried belonged to the open revision."

Both are deliberate: restoring them adds bytes to After you submit, one of the five sections this PR already grew, and the audit's own constraint is that the give-back must not grow. Disclosing is the option the audit offered, and it is the one taken.

Two things the plan got wrong, corrected by measurement

1. "The middle column is pinned by nothing" is FALSE. Rows 19 and 20 are pinned. Row 20's cause cell carries exact strings.Replace spans that t.Fatal when absent — including "because validation reports the row above first. ", with a trailing space. Both cells are additionally prose-parsed for positive/negative command attribution. Both are byte-identical to origin/main; they are 969 of the remaining bytes.

2. The 13,000-byte target was below the floor. Re-measured on the final tree: 6,948 bytes of the section are not cause cells at all — the pinned symptom column, the link column, 60 row delimiters, five bucket headers, the preamble and footer — and the 60 cause cells are 12,234. With rows 19–20 frozen at 969 of those, a 13,000 target leaves ~104 bytes for each of the other 58 cells. Round-1's trim gets the section to 19,182, which is the floor for cells that still say something the binary did not. #623 should be updated to match.

Gates

go test ./internal/cmd/ -run 'Attribution|Troubleshooting|README|Readme|readme'
                                        rc=0  97 --- PASS lines (37 top-level), 0 FAIL
go test ./internal/cmd/ -run 'README|Readme|readme'      rc=0  60 PASS (35 top-level)
go test ./internal/cmd/ -run 'Attribution|Troubleshooting' rc=0 51 PASS (5 top-level)
make ci                                                  21 packages ok, 0 FAIL
gofmt -s -l .                                            clean (491 .go files present)
golangci-lint run (v2.13.2)                              0 issues.
./scripts/ci-shallow.sh (post-commit, SHA 59030488919b)  ok=21/21, 0 failures, 0 timeouts

Negative controls run, not assumed.

  • Lint: a deliberately broken file in internal/cmd/ produced 1 issues: unused: 1. Removed; tree clean, 0 issues. again.
  • The wide filter can go red, and the narrow one cannot see it. Mutant A — reword row 20's shipped cell (never print itdo not emit it): 7 --- FAIL lines under -run 'Attribution|Troubleshooting|README|Readme|readme', all in TestAttributionProseCheckAcceptsCorrectProseAndRejectsMisattribution, and a plain ok under -run 'README|Readme|readme'. Mutant B — mutate a trimmed row's column 1 (cannot derive a slug fromslugg): reddens TestREADMETroubleshootingSymptomsExistInTheSource and …CoversTheRefusalsAuthorsActuallyHit, proving the filter reaches the rows round-1 touched. README restored from a checkpoint after each; md5sum identical.
  • The byte-table instrument was validated against the previous revision first: run on origin/maina6ebe54 it reproduces the audit's own numbers exactly (give-back 6,382 across 5 sections, Troubleshooting 35,250 → 20,229).
  • Heading invariance was checked by diff over the extracted ##/### list (74 before, 74 after, identical) with a positive control appending a fake heading, which the diff detects.

Merged tree

Branched on exit code, never a marker grep. origin/main has moved to 7c5a39c (#619) since this branch was cut, so this was re-run, not carried over.

against merge-tree --write-tree
origin/main (7c5a39c) rc 0
#626 docs/rank-31-closed rc 0
#623 docs/readme-reduction-plan rc 0
#602 zach/585-follow-up rc 1 — conflicts

The #602 conflict pre-dates round-1: a6ebe54 × #602 was already rc 1, while origin/main × #602 is rc 0. #602 edits the the server can receive and What this CLI sent rows, which this PR rewrote; round-1 touched neither, so it neither introduces nor widens it. It still needs resolving before either merges, and #602 should be rebased.

A real merge was built and tested, not reasoned about. origin/main (7c5a39c) + this branch in a throwaway worktree: go test ./... 21/21 ok, gofmt -s -l . clean, golangci-lint run 0 issues, wide filter 97 PASS / 0 FAIL. Worktree removed and its branch deleted.

Reported, not done: bucket placement

Validating and submitting is still the largest bucket and about half of it is misfiled — 12 rows are live-listing management or the ready-ack advisory rather than validation or submission; the server can receive sits under Credentials but is a submit-size refusal; rate limited / Civitai returned HTTP are transport, not credentials. A defensible re-sort needs 5 ### headings moved, which the brief rules out of scope. Left for phase 4, where the reorder lives.

ZacxDev and others added 2 commits September 15, 2026 00:25
…0,229 bytes

Sixty rows whose cause cells had grown to essay length (individual cells at
2,952, 2,299 and 1,636 bytes; a 470-byte mean) against a section that opens with
"Look up the message you got". Every cell is now one or two sentences — what
happened, and the one thing to do next — plus the anchor the row already carried.

No fact is deleted. Detail that the owning section did not already state was
moved there, merged into the existing prose rather than appended:

- the version guard's four cases and the `liveUrl` definition of "live"
  -> "Is your repo behind what you shipped?"
- what the dirty-work-tree guard counts (the packager exemptions, a repo with
  no commits yet, `git mv` as two changes) -> "What the packager left out"
- the three conditions under which a below-floor refusal is reported as progress
  -> "After you submit", replacing its pointer back at this row
- the download-path sanitisation list and its two non-shared exceptions
  -> "Download model files"
- the fixed 79-column wrap, "no words are dropped", and why prompts are NOT
  wrapped -> "What a table cell can contain"
- the #513 numeric-username decode and what the error snippet is made of
  -> "Scripting with --json", beside the #525 repair it already documented

Everything else displaced was already stated at length under the anchor the row
points at (verified per row), or was maintainer-facing history and is deleted.

Column one is untouched: all 68 symptom strings are byte-identical, which is what
readme_troubleshooting_test.go pins. Rows 19 and 20 keep their cells verbatim --
TestAttributionProseCheckAcceptsCorrectProseAndRejectsMisattribution pins ~8
exact substrings of row 20 (one with a trailing space) and parses both cells for
the commands they attribute the message to.

Measured floors, before -> after: symptoms 68 -> 68 (>= 15), in-document links
212 -> 216 (>= 40), `##` 27 -> 27 (>= 15), `###` 47 -> 47, Troubleshooting's own
`###` 5 -> 5 (the TOC exemption requires >= 1). Whole file 314,712 -> 306,073.

The 13,000-byte target this was scoped to is below the section's structural
floor: 7,081 bytes are the symptom column, the link column, the table scaffolding
and the prose around it, so 13,000 leaves 99 bytes per cause cell -- one clause,
not two sentences -- and rows 19 and 20 alone are 969 of it.
Round-0 audit follow-up on #625. Four fixes and one deletion.

D1 — 14 cause cells were near-verbatim restatements of the error the
binary already printed, in a column that (unlike column 1) is pinned
against nothing and can drift silently. Each is trimmed to what the
message does NOT say — the exit code, a cross-command caveat — plus the
anchor. No ROW is removed: `TestREADMETroubleshootingCoversTheRefusalsAuthorsActuallyHit`
puts 7 rows on an incident floor and 4 of these 14 (`cannot derive a slug
from`, `refusing to overwrite. Scaffold somewhere else`, `no such
directory …`, `refusing to submit without --yes`) are among them.
Column 2 loses 1,103 bytes across the 14; column 1 of all 60 rows is
byte-identical to origin/main.

Every retained exit code was MEASURED against the built binary, not
derived: rows 15/16/17 exit 2, 18 exits 1, 27/29/31/32 exit 2, 36 exits
1, 56 exits 2 (via a local stub for the model-version read), 59 exits 1
(via a local stub for the clone-info query). Row 58's code is not
claimed — `upgrade` has no API-base override, so it could not be
measured here.

Two cells also gained a correction the measurement surfaced:
- `is not valid UTF-8` claimed `--slug` was part of the remedy; measured,
  the refusal is about the DISPLAY name and fires with `--slug` given.
- `is ambiguous — it matches` described a different message (the exact
  same-name collision, `matches N files that share this name`); the
  quoted fragment is the SUBSTRING match.

F1 — the `from a dirty git work tree` row sent readers to `#exit-code-1`
(whose bullet says the guard "degrades rather than enforcing" — the
opposite of the no-commits case) and to the top of a 533-line section.
It now names the sub-head holding the detail, the house pattern rows 11
and 40 already use. `####`/`#####` anchors are deliberately NOT linked:
`readmeHeadingRe` only sees `##`/`###`, so a direct `#what-…` link fails
`TestREADMEAnchorLinksResolve` — measured, not assumed.

F2 — the two bullets #625 moved under `#### What the packager left out`
are properties of the GUARD, not of the exclusion list, and now sit under
their own `##### What the dirty-work-tree guard counts as a change`. The
heading pays for itself out of the same block, so the cross-section
give-back does not grow (6,382 -> 6,377).

F5 — the gate warning lived only in the PR body and a doc retired when
the arc closes. It is now a comment on
`TestAttributionProseCheckAcceptsCorrectProseAndRejectsMisattribution`,
with the measured pair: rewording row 20's cell produces 7 `--- FAIL`
lines under `-run 'Attribution|Troubleshooting|README|Readme|readme'` and
a plain `ok` under `-run 'README|Readme|readme'`.

Rows 19 and 20 stay byte-identical; no `##`/`###` heading moved, was
renamed, added or removed (74 before, 74 after, diffed).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFpMJ3mBc2XygE2EdSigSA
@ZacxDev ZacxDev changed the title docs(readme): compress the Troubleshooting cause cells, -15,021 bytes, no facts deleted docs(readme): make Troubleshooting a lookup table again — 35,250 → 19,182 bytes Sep 15, 2026
…d stop the intro overclaiming

Round 1 on this PR returned no high-severity findings; these are its two 🟡.

F2 is a real regression this PR introduced. Compressing the `unexpected
response from` row dropped "please open an issue with the snippet" -- the only
next step a user has when they hit an undecodable 200 that is NOT one of the two
known causes. The replacement read as "this cannot happen to you", and the
section footer names only --help and exit codes. Restored, and the row now links
Scripting with --json, where the two known decodes are actually documented,
instead of Exit code 1, which says nothing about an undecodable body.

F1 is self-inflicted: the intro sentence this PR added claimed the third column
"links the section that explains it in full", which the compression made false
for five rows -- a checkable claim the table breaks. Rows 25 and 26 pointed at
Listing media requirements, which contains nothing about revisions (measured: 0
hits for revision|not live in 2319-2392); they now point at After you submit,
where the explanation actually lives. Rows 18 and 59 have no better target --
their remedy is in the emitted message -- so the sentence now says what is true
of them rather than promising what only most rows deliver.
@ZacxDev
ZacxDev merged commit e3c5bd0 into main Sep 15, 2026
13 checks passed
@ZacxDev
ZacxDev deleted the fix/readme-troubleshooting-compression branch September 15, 2026 06:37
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