mirror of
https://github.com/msitarzewski/agency-agents.git
synced 2026-10-13 01:30:05 +00:00
Markdown has no nesting at equal fence length. Inside a ```markdown
template, a ```bash line is text, and the example's bare ``` closes the
template. Seven agents nest example blocks inside a template that way, so on
GitHub the rest of each template renders as headings and prose, and in three
of them the last block then runs open to the end of the file:
design-ux-architect code from line 414 to EOF
ats-validator-architect code from line 307 to EOF
master-plan-architect code from line 102 to EOF
technical-writer, incident-response-commander, developer-advocate,
workflow-architect templates end early, rest renders as markdown
The fix for each is the one CommonMark intends: fence the outer template
with four backticks so the three-backtick examples stay inside it. Nine outer
blocks change; no content does.
Nothing caught this because lib.sh's fence_closes_p accepted "```python" as
a closing fence. CommonMark allows only whitespace after a closing run, and
GitHub renders by that rule. With the old rule the linter and the OpenClaw
split read those seven files one way and GitHub another, so each agreed with
itself and all three disagreed with what users see. fence_closes_p now
requires a bare run, and the OpenClaw split invariant in
test-convert-outputs.sh uses the same rule.
lint-agents.sh gets two errors, each with the file line number:
- a fence line inside an open block that is long enough to close it but
carries an info string -- the only way that happens is an attempted
nest, and the message says how to fix it
- a block that is still open at the end of the file
The body loop now reads the file from the line after the frontmatter
instead of from $body, which drops every "---" line and so cannot give a
line number. It also keeps a last line with no trailing newline; two agents
end on a closing fence with none, and without that they read as unclosed.
The whole roster lints with 0 errors after the fix; on main the same check
reports 18 errors across the seven files.
scripts/test-lint-fences.sh covers both errors, the suggested fix, tilde
fences, and fence_closes_p directly, and runs in check-tools.yml.
88 lines
3.2 KiB
Bash
Executable File
88 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Code fences that GitHub renders differently from what the author meant must
|
|
# fail lint, and the fix the error message suggests must pass it.
|
|
#
|
|
# Markdown has no nesting at equal fence length. Inside a ```markdown template,
|
|
# a ```bash line is text, and the example's closing ``` ends the template, so
|
|
# the rest of it renders as headings and prose. Seven roster agents shipped
|
|
# that way, three of them with the last block left open to the end of the file.
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
FIXTURE="$(mktemp -d "${TMPDIR:-/tmp}/agency-lint-fences.XXXXXX")"
|
|
trap 'rm -rf "$FIXTURE"' EXIT
|
|
|
|
fail() { echo "FAIL: $*" >&2; exit 1; }
|
|
|
|
frontmatter() {
|
|
cat <<'EOF'
|
|
---
|
|
name: Fence Fixture
|
|
description: Fixture agent for the code-fence lint rules
|
|
color: blue
|
|
---
|
|
## Identity
|
|
Enough words to clear the short-body warning, repeated so the linter has a
|
|
body to read: this fixture exists to check how fenced code blocks are parsed.
|
|
## Core Mission
|
|
Show a template that contains a code example.
|
|
## Critical Rules
|
|
Keep fences balanced.
|
|
EOF
|
|
}
|
|
|
|
# 1. ```bash inside ```markdown: the inner fence does not nest.
|
|
{ frontmatter; cat <<'EOF'
|
|
### Template
|
|
```markdown
|
|
# Report
|
|
```bash
|
|
npm test
|
|
```
|
|
## Findings
|
|
```
|
|
EOF
|
|
} > "$FIXTURE/nested.md"
|
|
if bash "$SCRIPT_DIR/lint-agents.sh" "$FIXTURE/nested.md" > "$FIXTURE/nested.log" 2>&1; then
|
|
fail "linter accepted a \`\`\`bash fence nested in a \`\`\`markdown block of the same length"
|
|
fi
|
|
grep -Fq "nested.md:16: '\`\`\`bash' inside the block opened at line 14 does not nest" "$FIXTURE/nested.log" \
|
|
|| { cat "$FIXTURE/nested.log" >&2; fail "nested-fence error is missing or names the wrong lines"; }
|
|
|
|
# 2. A block left open to the end of the file.
|
|
{ frontmatter; printf '%s\n' '### Layout' '```' 'css/' 'js/'; } > "$FIXTURE/unclosed.md"
|
|
if bash "$SCRIPT_DIR/lint-agents.sh" "$FIXTURE/unclosed.md" > "$FIXTURE/unclosed.log" 2>&1; then
|
|
fail "linter accepted a code block that is never closed"
|
|
fi
|
|
grep -Fq "unclosed.md:14: code block is never closed" "$FIXTURE/unclosed.log" \
|
|
|| { cat "$FIXTURE/unclosed.log" >&2; fail "unclosed-fence error is missing or names the wrong line"; }
|
|
|
|
# 3. The fix the message suggests — a longer outer fence — passes, and so do
|
|
# tilde fences and a shorter run inside a longer block.
|
|
{ frontmatter; cat <<'EOF'
|
|
### Template
|
|
````markdown
|
|
# Report
|
|
```bash
|
|
npm test
|
|
```
|
|
## Findings
|
|
````
|
|
~~~text
|
|
```python is just text in here
|
|
~~~
|
|
EOF
|
|
} > "$FIXTURE/valid.md"
|
|
bash "$SCRIPT_DIR/lint-agents.sh" "$FIXTURE/valid.md" > "$FIXTURE/valid.log" 2>&1 \
|
|
|| { cat "$FIXTURE/valid.log" >&2; fail "linter rejected correctly nested fences"; }
|
|
|
|
# 4. The helper itself, which the OpenClaw split in convert.sh shares: only a
|
|
# bare run of the same character, at least as long, closes a block.
|
|
. "$SCRIPT_DIR/lib.sh"
|
|
fence_closes_p '```python' '`' 3 0 && fail "fence_closes_p treated '\`\`\`python' as a closing fence"
|
|
fence_closes_p '```' '`' 3 0 || fail "fence_closes_p rejected a bare closing fence"
|
|
fence_closes_p '```` ' '`' 3 0 || fail "fence_closes_p rejected a longer closing fence with trailing spaces"
|
|
fence_closes_p '```' '`' 4 0 && fail "fence_closes_p let a shorter run close a longer fence"
|
|
|
|
echo "PASS: nested and unclosed fences are rejected; correctly nested fences pass"
|