ci: add agent docs structure linter with Setup section - #476
Conversation
PR Summary by QodoCI: lint agent docs structure and require a Setup section
AI Description
Diagram
High-Level Assessment
Files changed (9)
|
|
🤖 Finished Review · ✅ Success · Started 7:04 PM UTC · Completed 7:21 PM UTC |
Code Review by Qodo
Context used✅ Compliance rules (platform):
55 rules 1.
|
ReviewFindingsHigh
Low
Next steps:
Previous runReviewFindingsHigh
Low
Next steps:
Previous run (2)ReviewFindingsHigh
Low
Next steps:
Previous run (3)ReviewFindingsHigh
Medium
Low
Next steps:
Previous run (4)ReviewFindingsHigh
Low
Next steps:
Previous run (5)ReviewFindingsHigh
Low
Next steps:
Previous run (6)ReviewFindingsHigh
Low
Next steps:
Previous run (7)ReviewFindingsHigh
Low
Next steps:
Previous run (8)ReviewFindingsHigh
Low
Next steps:
Previous run (9)ReviewFindingsHigh
Low
Next steps:
Previous run (10)ReviewFindingsHigh
Low
Previous run (11)ReviewFindingsHigh
Low
Labels: PR modifies agent documentation structure and adds a documentation linter Previous run (12)ReviewFindingsHigh
Low
Previous run (13)ReviewFindingsHigh
Low
Previous run (14)ReviewFindingsHigh
Low
|
|
🤖 Finished Fix · ✅ Success · Started 7:23 PM UTC · Completed 7:28 PM UTC |
Add `head -1` after `grep -E '^doc:'` in all three extraction sites in hack/lint-agent-docs so only the first match is used. Current harness files are unaffected (each has exactly one doc: line), but the defensive guard prevents silent breakage if a future YAML file happens to contain the pattern on more than one line. Addresses review feedback on #476
🔧 Fix agent — iteration 1 (bot-triggered)Fixed 1 of 5 review findings. Applied defensive Fixed (1):
Disagreed (4):
Tests: passed Updated by fullsend fix agent |
|
🤖 Finished Review · ✅ Success · Started 7:30 PM UTC · Completed 7:45 PM UTC |
|
🤖 Finished Fix · ✅ Success · Started 7:46 PM UTC · Completed 7:53 PM UTC |
🔧 Fix agent — iteration 2 (bot-triggered)Addressed 2 of 4 review findings (CI coverage gap, architectural coherence). Disagreed with 2 process-level findings (protected-path authorization and scope-authorization) that require human action outside the fix agent's scope. Fixed (2):
Disagreed (2):
Tests: passed Decision points
Updated by fullsend fix agent |
- Move Setup from REQUIRED_SECTIONS to OPTIONAL_SECTIONS in the linter, eliminating stub "No additional setup required" sections in 6 of 7 agent docs while keeping scribe.md's substantive Setup content - Expand pre-commit hook files pattern to include hack/lint-agent-docs so modifications to the linter itself trigger the hook locally Addresses review feedback on #476
|
🤖 Finished Review · ✅ Success · Started 7:55 PM UTC · Completed 8:15 PM UTC |
|
🤖 Finished Fix · ✅ Success · Started 8:16 PM UTC · Completed 8:21 PM UTC |
🔧 Fix agent — iteration 3 (bot-triggered)Fixed 1 of 4 review findings. Added duplicate heading detection to the agent docs linter. Disagreed with 3 findings: 1 requires human approval for a protected path, 1 is a stale PR description the fix agent cannot edit, and 1 would require modifying a protected file. Fixed (1):
Disagreed (3):
Tests: passed Updated by fullsend fix agent |
Add a uniqueness check after extracting actual_sections so that duplicate required section names are flagged as errors instead of silently passing the linter. Addresses review feedback on #476
|
🤖 Finished Review · ✅ Success · Started 8:23 PM UTC · Completed 8:36 PM UTC |
|
🤖 Finished Fix · ✅ Success · Started 8:37 PM UTC · Completed 8:45 PM UTC |
🔧 Fix agent — iteration 4 (bot-triggered)Addressed 1 of 3 review findings. Moved Setup from OPTIONAL_SECTIONS to REQUIRED_SECTIONS in the linter and added Setup stubs to all 6 agent docs that lacked one. Disagreed with 2 findings (both relate to .pre-commit-config.yaml, a protected infrastructure file requiring human approval). Fixed (1):
Disagreed (2):
Tests: passed
Updated by fullsend fix agent |
Move Setup from OPTIONAL_SECTIONS to REQUIRED_SECTIONS in the agent docs linter, aligning the implementation with the PR description which states Setup is required. Add Setup stubs to all agent docs that lack one (code, fix, prioritize, retro, review, triage). Addresses review feedback on #476
|
🤖 Finished Retro · ✅ Success · Started 7:26 PM UTC · Completed 7:40 PM UTC |
waynesun09
left a comment
There was a problem hiding this comment.
Review-only pass on the linter script — reproduced two remaining fence/whitespace edge cases live against PR head 455d9a1f (see inline comments). No approval/changes-requested state set; this is informational only.
|
|
||
| # True if a doc has an unmatched ``` fence. | ||
| has_unbalanced_fence() { | ||
| awk 'BEGIN{f=0} /^[[:space:]]*```/{f=1-f} END{exit !f}' "$1" |
There was a problem hiding this comment.
[MEDIUM] Fence-state detection never recognizes tilde (~~~) fences, causing both false passes and false duplicate-section failures
has_unbalanced_fence() and all four section/heading-extraction awk passes (lines 12, 94, 106, 158, 163) toggle their "inside a fenced code block" flag only on /^[[:space:]]*```/, never on GFM/CommonMark's alternate ~~~ fence marker. Reproduced twice live against PR head 455d9a1f, cloned and run directly (not simulated):
- A doc with a real
## Configurationbut no real### Variablessubsection, where the only occurrence of the literal text### Variablessits inside a~~~example block, is reportedwidget.md: OKby the Variables check instead of the intended "missing ### Variables subsection" error. - A doc with one real
## Setupplus an illustrative## Setupinside a~~~block is reportedduplicate section "## Setup"and exits 1, even though the doc has no real duplicate.
This is the same class of bug already fixed twice for backtick-fence edge cases in this PR (unterminated-fence cascade, column-0-only fence match), but the tilde variant was never addressed. No current docs/*.md use ~~~, so it doesn't fail today, but it's a live, reproducible gap in the exact invariant (required/no-duplicate sections) this linter exists to enforce.
Suggestion: Extend the fence-toggle regex in has_unbalanced_fence() and all four extraction awk one-liners to match both markers, e.g. /^[[:space:]]*(```|~~~)/, ideally factored into one shared helper given it's already duplicated five times.
| fi | ||
|
|
||
| # Extract ## headers outside fenced code blocks | ||
| actual_sections="$(awk 'BEGIN{f=0} /^[[:space:]]*```/{f=1-f; next} f==0 && /^## /{sub(/^## /,""); sub(/[ \t]*#*[ \t]*$/,""); print}' "$doc_path")" |
There was a problem hiding this comment.
[MEDIUM] Heading-extraction regex only strips a single space after #/##/###, so valid multi-space GFM headings produce a false "missing section" error
GFM/CommonMark permits any amount of whitespace between the ATX marker and heading text, but the extraction awk patterns match a literal single space (/^# [^#]/, /^## /, /^### /) and sub() only removes that one space (sub(/^## /,"")). A heading written with two spaces, e.g. ## Source (valid, renders as a normal H2 on GitHub), still matches the initial /^## / test but sub() leaves a stray leading space in the extracted text (" Source" instead of "Source"), which then fails the exact-match grep -Fqx "Source" comparison.
Reproduced live against PR head 455d9a1f: took docs/code.md (which has every required section present), changed only ## Source to ## Source, and got:
widget.md: FAIL
missing: "## Source"
even though the section exists — misleading, since a contributor debugging the failure would look for a missing section rather than an extra space. The same defect would equally cause a false "missing ### Variables" report.
This is a different whitespace bug than the already-fixed trailing-whitespace/ATX-closing-hash issue (fixed in 63afb90, which trims trailing content, not a doubled leading space).
Suggestion: Normalize whitespace when stripping the marker, e.g. sub(/^##[ \t]+/,"") instead of the literal sub(/^## /,""), and loosen the initial match regex to /^##[ \t]+/ (and analogously for # and ###).
|
Review skipped — this PR is already merged. The Posted by fullsend post-review check |
Retro: PR #476 — CI: lint agent docs structure and require a Setup sectionOverviewPR #476 by @ralphbean added a Key metrics
Review quality gapThe human reviewer (@waynesun09) was strictly superior to the review agent:
The human caught 12+ substantive bugs the agent never raised, including 3 HIGH-severity shell portability issues: macOS bash 3.2 unbound-variable crash, BSD sed backreference no-op, and a false Drive isolation claim in Evidence for existing open issues
What went well
Proposals filed
|
Add `head -1` after `grep -E '^doc:'` in all three extraction sites in hack/lint-agent-docs so only the first match is used. Current harness files are unaffected (each has exactly one doc: line), but the defensive guard prevents silent breakage if a future YAML file happens to contain the pattern on more than one line. Addresses review feedback on #476
- Move Setup from REQUIRED_SECTIONS to OPTIONAL_SECTIONS in the linter, eliminating stub "No additional setup required" sections in 6 of 7 agent docs while keeping scribe.md's substantive Setup content - Expand pre-commit hook files pattern to include hack/lint-agent-docs so modifications to the linter itself trigger the hook locally Addresses review feedback on #476
Add a uniqueness check after extracting actual_sections so that duplicate required section names are flagged as errors instead of silently passing the linter. Addresses review feedback on #476
Move Setup from OPTIONAL_SECTIONS to REQUIRED_SECTIONS in the agent docs linter, aligning the implementation with the PR description which states Setup is required. Add Setup stubs to all agent docs that lack one (code, fix, prioritize, retro, review, triage). Addresses review feedback on #476
- Remove dead OPTIONAL_SECTIONS/OPTIONAL_LIST mechanism from linter to eliminate unbound-variable crash on bash < 4.4 (macOS 3.2.57) - Add zero-harness-files guard so the linter fails loudly instead of silently passing when no YAML files are found - Rewrite scribe.md summary line to clarify the Gemini→Drive→agent pipeline instead of incorrectly saying "Google Meet" - Rewrite scribe.md Setup section to accurately describe Drive keyword+time-window search semantics, removing the incorrect "only that event" per-event isolation claim Addresses review feedback on #476
Harden the doc: field extraction to strip surrounding quotes and trailing # comments instead of adding a yq dependency for a single-purpose bash script. Also dedupe the extraction logic (previously copy-pasted three times) into an extract_doc_value helper. Addresses review feedback on #476. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
The quote-stripping regex relied on a backreference (\1) inside an extended regex, which GNU sed accepts as an extension but BSD/macOS sed does not honor the same way — it silently no-ops instead of erroring, producing false "doc does not exist" failures on macOS for quoted doc: values. Replace it with portable bash parameter expansion. Addresses review feedback from waynesun09 on PR #476. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
…H1/missing-file test coverage Fixes lint-agent-docs to only strip inline # comments when preceded by whitespace, so doc paths containing a literal # (e.g. c#-guide.md) aren't truncated. Adds three test cases to lint-agent-docs-test.sh: missing top-level heading, heading not ending in " Agent", and doc: field pointing at a nonexistent file — covering branches the existing fixtures never exercised. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Adds run_case coverage for double-quoted, single-quoted, and trailing-comment doc: field values, per review feedback on #476. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Add `head -1` after `grep -E '^doc:'` in all three extraction sites in hack/lint-agent-docs so only the first match is used. Current harness files are unaffected (each has exactly one doc: line), but the defensive guard prevents silent breakage if a future YAML file happens to contain the pattern on more than one line. Addresses review feedback on fullsend-ai#476
- Move Setup from REQUIRED_SECTIONS to OPTIONAL_SECTIONS in the linter, eliminating stub "No additional setup required" sections in 6 of 7 agent docs while keeping scribe.md's substantive Setup content - Expand pre-commit hook files pattern to include hack/lint-agent-docs so modifications to the linter itself trigger the hook locally Addresses review feedback on fullsend-ai#476
Add a uniqueness check after extracting actual_sections so that duplicate required section names are flagged as errors instead of silently passing the linter. Addresses review feedback on fullsend-ai#476
Move Setup from OPTIONAL_SECTIONS to REQUIRED_SECTIONS in the agent docs linter, aligning the implementation with the PR description which states Setup is required. Add Setup stubs to all agent docs that lack one (code, fix, prioritize, retro, review, triage). Addresses review feedback on fullsend-ai#476
- Remove dead OPTIONAL_SECTIONS/OPTIONAL_LIST mechanism from linter to eliminate unbound-variable crash on bash < 4.4 (macOS 3.2.57) - Add zero-harness-files guard so the linter fails loudly instead of silently passing when no YAML files are found - Rewrite scribe.md summary line to clarify the Gemini→Drive→agent pipeline instead of incorrectly saying "Google Meet" - Rewrite scribe.md Setup section to accurately describe Drive keyword+time-window search semantics, removing the incorrect "only that event" per-event isolation claim Addresses review feedback on fullsend-ai#476
Harden the doc: field extraction to strip surrounding quotes and trailing # comments instead of adding a yq dependency for a single-purpose bash script. Also dedupe the extraction logic (previously copy-pasted three times) into an extract_doc_value helper. Addresses review feedback on fullsend-ai#476. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
The quote-stripping regex relied on a backreference (\1) inside an extended regex, which GNU sed accepts as an extension but BSD/macOS sed does not honor the same way — it silently no-ops instead of erroring, producing false "doc does not exist" failures on macOS for quoted doc: values. Replace it with portable bash parameter expansion. Addresses review feedback from waynesun09 on PR fullsend-ai#476. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
…mment, add H1/missing-file test coverage Fixes lint-agent-docs to only strip inline # comments when preceded by whitespace, so doc paths containing a literal # (e.g. c#-guide.md) aren't truncated. Adds three test cases to lint-agent-docs-test.sh: missing top-level heading, heading not ending in " Agent", and doc: field pointing at a nonexistent file — covering branches the existing fixtures never exercised. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Adds run_case coverage for double-quoted, single-quoted, and trailing-comment doc: field values, per review feedback on fullsend-ai#476. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Summary
hack/lint-agent-docsfrom fullsend-ai/fullsend, adapted for this repo's layout##sections are present; does not flag extra/unexpected sections, since that was forcing legitimate topics (like fix.md's## Custom sandbox image) to be demoted into###subsections just to satisfy the linter## Setupas a required section across all agent docsdocs/fix.md's sections (Control labels,Configuration,How the agent works) to match the canonical order used by every other agent doc —fix.mdwas the outlier, with those sections trailing afterWhat the agent acts oninstead of leadingWhat the linter checks
harness/*.yamlhas adoc:field pointing to an existing file# H1ends with " Agent"##sections: How it helps, Setup, Triggers, Commands, Control labels, Configuration, How the agent works, Source### Variablessubsection under## ConfigurationSupersedes #475.
Test plan
./hack/lint-agent-docspasses (all 7 agents OK)pre-commit run --all-filespasses (full suite)hack/lint-agent-docs-test.shfixture tests pass🤖 Generated with Claude Code