Read a Tool Row Without a Trailing Pipe, and Report the License Column - #636
Conversation
The 3rd Party Tools check required a closing pipe on every table row, which GitHub's Markdown makes optional, so a row written without one was skipped outright and its link, description and ordering all went unread. A table written that way scored clean rather than unread. spec/project-types.json asserted "The section carries no license column" at verdict letter, and nothing read it. The header is now read for that column, once per table rather than once per row, and it is the only extra column named, since spec/readme-structure.md forbids that one and no other. Measured against all 22 cataloged READMEs, in both directions: 56 findings become 57, the one addition being Blog's License column, and no verdict is lost. No repo writes a trailing-pipe-less row today, so that half closes a blind spot rather than a live miss. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR tightens the README audit’s parsing of the 3rd Party Tools section so valid Markdown table rows aren’t skipped, and adds a new rule to report a forbidden License column based on the table header. It also updates TODO.md to reflect the newly measured finding counts and corrected breakdown.
Changes:
- Update
_TOOL_ROWparsing to accept tool-table rows that omit the trailing|. - Add header-based detection of a
Licensecolumn in the 3rd Party Tools table, plus selftests for the new behaviors. - Refresh
TODO.mdmeasurement dates/counts and correct prior miscounts.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| TODO.md | Updates the recorded fleet measurement totals/dates and corrects the described breakdown for 3rd Party Tools findings. |
| spec/audit.py | Improves Markdown table parsing for 3rd Party Tools rows and adds a header-based License-column finding with expanded selftests. |
Suppressed comments (1)
spec/audit.py:710
- table_cells() only recognizes rows that start with
|. GitHub-flavored Markdown also allows header/separator/data rows without the leading pipe (e.g.Tool | Role). With the new License-column check keyed off the header, a table using that valid form won’t be recognized and can again score as clean despite being present. Expanding table_cells() to accept rows with or without the leading pipe avoids that blind spot.
s = line.strip()
if not s.startswith("|"):
return None
s = s[1:-1] if s.endswith("|") else s[1:]
return [c.strip() for c in s.split("|")]
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Uh oh!
There was an error while loading. Please reload this page.
Copilot raised the symmetric case on #636: GitHub's Markdown makes the leading pipe optional as well, so a table written without it was skipped by _TOOL_ROW and unread by table_cells, which is the exact shape the first commit fixed on the other side. table_cells now requires a separating pipe rather than a leading one. That is what keeps a thematic break out: `---` alone carries no pipe, where treating it as a one-cell delimiter row would have read the paragraph above it as a table header. Re-measured against all 22 cataloged READMEs: the total stays 57 and no verdict moves in either direction, so the widening introduces no false positive and catches nothing the fleet writes today. Five new selftest cases cover the leading-pipe row, a table with neither outer pipe, a License column without them, the thematic break, and prose naming a cataloged tool. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ptr727
commented
Aug 9, 2026
Answering the suppressed comment on
Accepted, and fixed in
Re-measured across all 22 cataloged READMEs, in both directions: the total stays 57 and no verdict moves, so no false positive. Worth being plain about the other half of that result, though: neither outer-pipe form appears anywhere in the fleet today, so both fixes close a silent blind spot rather than catch a live miss. The 17 repos that still owe this section have not written their tables yet, which is the reason to take it now rather than after. |
Uh oh!
There was an error while loading. Please reload this page.
…ate (#635) Promotion of develop at 2082547, six squashes since the last one. Closes#633. #631 routes the README by reader and documents the GH_WRITE_GUARD_ALLOW grant where a denied cross-owner write puts the reader. #632 moves readme.sections from intent to letter with four checks beside it, backed by spec/readme-sections.json and spec/third-party-tools.json, and settles the tagline rule. #634 adds repo_gate.py --check eol-coverage, reading the line-ending pins against the tree rather than only against .editorconfig. #636 and #637 repair two readers Copilot found on this pull request, both defects develop already carried: a tool row required both outer table pipes that GitHub's Markdown makes optional, and a retired badge written as an inline image was invisible to a scan that read reference definitions alone. #638 turns the host contract's presence check into a version gate, and retires two gh workarounds that were artifacts of a stale distribution package, re-tested on an upgraded host rather than inferred. Four carried files owe a downstream re-vendor and none is recorded in the TODO.md entry yet. GOVERNANCE.md Repository Details is verbatim, so the audit reports it, and it propagates a rule: the About description is the tagline alone, and Docker Hub receives it from the About panel rather than from the README. CODESTYLE.md item 4 and .gitattributes are intent, so nothing reports them, and the second couples to the new gate through the forward-declared mark. .github/copilot-instructions.md is intent and propagates a correction rather than a refresh, so a repo left on the old copy is wrong rather than merely stale.
Raised by Copilot on the promotion pull request #635, against
developcode rather than against anything that promotion introduces. Both halves of the finding are real, and both are measured below rather than argued.The trailing pipe
_TOOL_ROWrequired a closing|after the description. GitHub's Markdown makes that pipe optional, so a valid row written without one matched nothing and was skipped bycontinuebefore any check ran on it:A skipped row loses its link check, its description check, and its place in the ordering list, so a whole table written that way reports zero findings. That is the failure shape this dimension exists to avoid: it scores as clean rather than as unread.
Nothing else catches it either.
MD060is disabled outright in.markdownlint-cli2.jsonc, andMD055defaults toconsistent, which passes a table whose rows all omit the closing pipe. So the form is permitted everywhere and was read nowhere.The License column
spec/project-types.jsonalready asserted "The section carries no license column" at verdictletter, and nothing read it.spec/readme-structure.mdstates the rule and the reason: a license belongs to the dependency and is authoritative at its source. This makes the existing assert honest rather than adding a new rule.Two decisions bound it:
A row carrying the extra column still parses correctly, because the description capture is non-greedy, so the per-tool checks keep working alongside the new finding.
Measured against the corpus
All 22 cataloged READMEs, at their ground-truth branches, old check against new, read in both directions:
One finding added, Blog's License column, and no verdict lost in the other direction. The categories break down as 48 absent descriptions, 4 links, 3 descriptions, 1 ordering, 1 License column.
The honest half of that result: no repo in the fleet writes a trailing-pipe-less row today, so that fix closes a blind spot rather than a live miss. It is worth taking anyway, because the blind spot is silent and the 17 repos that still owe this section have not written their tables yet.
TODO.mdtakes the new count, and two pre-existing miscounts in the same bullet are corrected while I am in it: PlexCleaner's 27 is its total rather than its absent-description count, which is 25, and all three of Blog's roles differ from the catalog rather than two, since Hugo's matches in substance but differs by its opening capital and its full stop.Verification
spec/audit.py --selftestpasses with 7 new cases, covering both halves in both directions: a row read without a trailing pipe, one judged without one, a whole table ordered without them, the License column reported once, the rows still read alongside it, a table without the column not reported, and a row cell reading "License" not mistaken for the header.spec/validate.py,prose_lint.py --diff develop,repo_gate.py --check eol-coverage, editorconfig-checker, markdownlint-cli2 and cspell all clean.spec/audit.pystays LF,TODO.mdstays CRLF.🤖 Generated with Claude Code