fix(skill-quality): stop check 21 passing silently under mawk (0.17.1) - #3058
Conversation
Check 21's fresh-eyes scanner used ERE interval expressions, two of them immediately followed by a group. mawk 1.3.4 panics on that construct with "REcompile() - panic: values still on machine stack" and dies before emitting a single record, so on a stock Debian/Ubuntu box every malformed fresh-eyes-exempt directive PASSed and the check reported a clean run over a file it never scanned. mawk 1.3.3, which implements no intervals at all, degrades the same way by matching the braces as literal text. Isolating the construct shows the trigger is narrow: interval-then-literal, interval-then-class, interval-then-interval and star/optional-then-group all compile fine under mawk; only interval-then-group panics. Sweeping every .sh file in the repo for that shape finds exactly the two sites in this scanner, which is why check 23 (written interval-free in #2963) was unaffected. The scanner is now interval-free throughout, preserving the exact CommonMark bounds it already enforced: the three-space indent cap as three optional spaces, the ordered-marker digit cap as one digit plus eight optional ones. gawk behavior is unchanged; on mawk the suite gains 21 passing assertions with no regressions (96 -> 117 ok). A source-level guard assertion fails the suite if any interval returns. It is deliberately implementation-aware rather than black-box, because a gawk CI runner compiles intervals happily and so cannot observe this class of break in any behavioral form. Closes #3005 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4
|
Claude finished @kyle-sexton's task in 50s —— View job Security review — no issues found
Skip gate: This PR has no security-relevant surface. All four changed files ( Verified there's no injection surface introduced:
No CRITICAL, IMPORTANT, or SUGGESTION findings. |
|
Last security-reviewed head: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c84cb36917
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Claude finished @kyle-sexton's task in 2m 46s —— View job Code review
This repo carries a Regex-conversion correctness (verified by hand-tracing, not by running the suite — I don't have test-execution access in this lane):
One finding posted inline on Everything else checked out:
No other correctness issues found. Test-run counts and CI results in the PR description are author-reported and were not independently re-executed here. |
…ount form Review on #3058 found two gaps in the portability guard, both verified against the tree before fixing. The pattern required a comma inside the braces, so an exact-count interval slipped through. That is the same silent-failure class the guard exists to prevent: mawk 1.3.4 panics on a{3}(b) exactly as it does on a{0,3}(b), confirmed by direct reproduction. All three forms are now rejected. Broadening alone would have introduced a false positive. check-skill.sh:703 dates a frontmatter value with a Bash [[ =~ ]] regex using ^[0-9]{4}-[0-9]{2}, which is legal there because Bash is not mawk. The guard is therefore scoped to what awk actually compiles rather than to the whole file: slash-delimited regex literals inside the embedded programs, plus the judge regex handed across with -v, which is a POSIX ERE awk compiles even though it is written as a shell string and never appears between slashes. Verified by reintroducing each of the three interval forms in turn and confirming the guard names the file and line for every one, while the clean tree still passes with the Bash date regex in place. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4
|
Claude finished @kyle-sexton's task in 52s —— View job Security review — no issues found
Skip gate: No security-relevant surface in the commits since the last-reviewed head ( Verified no new risk was introduced:
No CRITICAL, IMPORTANT, or SUGGESTION findings. |
|
Claude has reviewed this PR 3 times. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
|
Claude finished @kyle-sexton's task in 4m 40s —— View job Code review —
|
The scoping rationale said "the frontmatter date check below", but that check lives in check-skill.sh, not below this comment in the test file. Name the file and what the check does instead, and describe it rather than citing a line number that would rot on the next edit to that file. Comment only; the guard's behavior is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4
|
Claude finished @kyle-sexton's task in 37s —— View job Security review — no issues found
Skip gate: No security-relevant surface in the commits since the last-reviewed head ( Verified no functional change accompanies it:
No CRITICAL, IMPORTANT, or SUGGESTION findings. |
|
Claude finished @kyle-sexton's task in 57s —— View job Code review —
|
…on collisions Main landed six commits while this branch was open, three of which bumped plugins this branch also bumped, to the same numbers. Resolved by stacking this branch's entry above main's released one: claude-ops 0.34.0 (both) -> mine becomes 0.35.0, main's 0.34.0 kept session-flow 0.29.0 (both) -> mine becomes 0.30.0, main's 0.29.0 kept skill-quality 0.17.1 (both) -> mine becomes 0.17.2, main's 0.17.1 kept The two manifest conflicts were NOT the version field. Bumping with `jq` had rewritten each whole file, re-encoding main's — escapes as literal UTF-8 em-dashes in the description string. Resolved by taking main's exact bytes and editing only the version line, so no manifest carries an incidental encoding change. Also: main's audit-skill-visibility SKILL.md sat at exactly the 200-line soft target, so this branch's inline pair-cooccurrence section pushed it to 234 and tripped a warning. The detail moves to reference/pair-cooccurrence.md — the progressive-disclosure spoke the check recommends — and the pointer folds into the existing scope-boundary row rather than adding one, landing back at 200 with 0 errors and 0 warnings. Verified on the merged tree: 33/33 co-occurrence cases, changelog parity, shell portability (56 files), cross-plugin drift, fleet doc-grammar, fleet finding coverage, silent skips, markdownlint on every conflicted file, and check-skill on audit-skill-visibility. Main's mawk fix (#3058) also cleared the 21 assertion failures check-skill.test.sh was reporting in this tree; it now passes fully. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CnzwTKoTa6xNY7iyEzMYpm
…-interval sites (#3062) Closes #3000 ## Summary Materializes the project glossary that lane 6's term adoption deferred, and — at the maintainer's direction rather than as a filed follow-up — closes the two remaining ERE-interval sites in awk regexes that PR #3058 scoped out. Two commits, kept separate so neither is buried. Documentation and test-probe hardening only; no runtime behavior change. `markdown-format` 0.11.21 → 0.11.22. ## Fix **1. The glossary (#3000).** `curate-language`'s convention ladder found no existing glossary and more than one plausible home, so it deferred rather than inventing one — that was the entire blocker. The maintainer confirmed the flat `docs/GLOSSARY.md` placement, beside `CATALOG.md` and `SKILL-CHEAT-SHEET.md`, satisfying the ladder's step 4 ("ask when two or more plausible choices remain"). - **Seven ADOPTED terms**, each a 1–2 sentence what-it-IS definition: AFK criterion, asset rush, context load, cognitive load, navigation pointer, phase boundary, primary source, secondary source, smart zone. - **The REJECT rows recorded as rejected synonyms**, each mapped to the term or doctrine that owns the concept — `design concept` → shared understanding, `highway / stale highway` → navigation pointer, `cache` (doc-restating sense) → audit-derivability's doctrine, `sediment`, `push vs point` → point-don't-copy, `grill-execute-clear`, and `sycophancy` (owned by nothing — recorded so it is not reintroduced as project vocabulary, with free-prose use explicitly unaffected). - **Vocabulary only**, per the glossary contract: no decisions, specs, or open questions. The reasoning stays in the lane 6 table, which the glossary cites and which now links back — the issue's third acceptance criterion. - **Single language context**, so no context map. Stated in the file so the absence reads as a decision rather than an omission. **2. The two latent mawk-interval sites.** Both **compile** under mawk 1.3.4 — each interval precedes a literal or a bracket class, not a group, so neither hits the panic that broke check 21 — but mawk **1.3.3** implements no intervals at all and matches the braces as literal text. Each then degrades *silently*: | Site | Unfixed behavior on mawk 1.3.3 | |---|---| | `scripts/check-changelog-parity.sh` — fence probe `^ {0,3}` | stops recognizing code fences, so the scanner segments every changelog it reads wrongly | | `markdown-format.test.sh` — heading probe `#{1,6}` | stops recognizing headings, so the MD024 assertion passes vacuously — a test that cannot fail | Both rewritten interval-free with identical bounds: three optional spaces, and one hash plus five optional ones. Swept the repo for the same shape rather than trusting the two names. `ai-slop`'s `PATTERN_RULES` carry `[^.]{0,80}(...)` — the interval-then-group form that actually panics — but they reach `grep -E`, not awk, and that script's awk programs already avoid intervals deliberately. No change needed there; confirmed by reading its consumption sites. ## Verification - **Bounds verified in both directions** under this container's mawk 1.3.4: 0/1/2/3 leading spaces match and 4 does not; 1–6 hashes match and 7 does not. A rewrite that stopped panicking while quietly widening the bound would be the same class of silent defect these fix. - `plugins/markdown-format/hooks/markdown-format.test.sh` — **PASS=149 FAIL=0** - `scripts/check-changelog-parity.test.sh` — **PASS=82 FAIL=0** - `check-changelog-parity.sh` all four modes, re-run **after committing** so `--check-preserved` had something to compare: 83 changelogs newest-first, and **50 headings compared, all preserved** - `scripts/validate-plugins.sh`; `generate-catalog.mjs --check` / `generate-cheatsheet.mjs --check` — in sync - `check-changed-skills.sh origin/main` — no changed skills under `plugins/*/skills/` - `markdownlint-cli2` (3 files) — 0 issues; `typos` clean; `shellcheck` and `shfmt -d` clean on both touched scripts - `scripts/check-changelog-parity.sh` is a repo-level script with no plugin manifest, so it takes no version bump. One self-inflicted defect caught and fixed before pushing: the new changelog entry initially replaced the `## [0.11.21]` heading instead of sitting above it, absorbing that release's notes. `grep '^## \['` now reads 0.11.22 → 0.11.21 → 0.11.20 → 0.11.19, and `--check-preserved` confirms it. ## Related - Refs #2904 (lane 6, the term-adoption decisions), `docs/upstream/aihero-course.md` "Term adoption" - Refs #3005 / PR #3058 — established the interval-free shape and named these two sites as out of its scope - Refs #2994 — the AI Hero course roadmap this queue item belongs to 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4 --- _Generated by [Claude Code](https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
…l CSV-injection fix Lanes 5 and 10 of the cursor/plugins pstack port. LANE 5 (`show-me-your-work`) — absorbed into one consumer, no skill, no convention. Upstream keeps a reviewable decision trail for long or unattended work: `ts | phase | decision | why | evidence | result`, append-only, plus a log helper, a self-audit against the transcript, a mandatory cross-model review, and a standing per-reply section. The lane opened proposing to absorb this into session-flow:running-retro. An adversarial audit destroyed that premise correctly: running-retro's ledger is defect-shaped over five session-process categories, written by a transcript-parsing subagent after the fact, in a file whose cumulative-chain identity lives in YAML frontmatter a TSV cannot carry, and the skill "does not run builds, tests, or a code review" so it cannot produce a `result` cell at all. Two artifacts, not one. session-flow is also barred from the contract tier by its own binding, and topic-docs already records `history.md` (append-only decision log) as deliberately absent. The audit then argued the opposite verdict: ship a shared capture format that the fleet's "eight" existing audit-trail surfaces route into. That count was checked surface by surface and does not hold. One is a decision trail — implement-dispatch's DEVIATIONS.md. One is related but differently shaped (handoff's settled-decisions and abandoned-approaches sections, synthesized at pause time rather than appended at decision time). The other six are not decision trails: a change inventory, loop counters, a hook-wired notification record on a governed schema, a status comment edited in place, OTel spans whose contract explicitly forbids a parallel schema, and a return record whose first line reads "capturing RETURN — not activity". One consumer is below Rule of Three, so a marketplace convention would be the same speculative generality that killed `arena`. The full classification table is in the provenance file. So DEVIATIONS.md gains what it was missing: append-and-supersede rather than edit, evidence as a pointer with a preference for what a committed script produced, an explicit outcome that says `unverified` rather than reading as settled, and one-entry-is-one-decision. The unverified-vs-omitted rule cites the grounding discipline work-loop and babysit-loop already carry verbatim instead of restating it a third time. The formula-injection guard was the highest-value single item in the upstream file, and looking for somewhere to apply it found a live exposure rather than a hypothetical one. claude-ops:audit-install-state wrote scanned `relpath` and five other tree-derived fields raw through `csv.writer` into an artifact the skill tells the reader to open row by row — and a plugin, project, or worktree directory under `~/.claude` may be named anything, including a formula. Fixed with `csv_safe`, covering the leading tab, CR and LF a spreadsheet strips before deciding. `TestCsvFormulaInjection` was confirmed discriminating: 8 subtest failures with the guard disabled in memory, 0 with it restored. Rejected: the mandatory different-model-family review (the same unconditional cross-vendor demand already rejected for `arena`, against 15+ presence-gated sites); the standing per-reply "Attention" section (a session-wide output posture is a declared species here with one member, and the instruction-economy rule wants observed repeated stumbles); and the log-vs-transcript self-audit, which already ships verbatim in two lanes. LANE 10 (`bro`) — omitted, nothing absorbed. Seven lines upstream, two of them body, no mechanism. The capability ships twice already: education:explain's empty argument resolves to the previous assistant response by anaphora with 'rephrase that' among its triggers, and discipline:wait-what is the interjection-fired re-pitch. The brevity pressure that is `bro`'s only distinguishing note ships a third time as discipline:tighten-your-output, and adhd:clarify already states the routing between them by name. Shipping it would also need a second entry on the naming grammar's closed exception list, carrying the argument already spent on wait-what. Recorded at length only so a later reader sees the file was read rather than skipped for being short. Also merges origin/main, which independently landed the same check-21 mawk fix this branch carried (#3058). Main's is the faithful translation — it preserves the original 1-9 digit bound where this branch had widened it to unbounded — and its test suite already asserts the positive liveness case, so this branch's version was dropped entirely in favour of main's. `review` renumbered 0.24.0 to 0.25.0 after a collision with main. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EtvBfWQRz7w6kgRnJm4qgj
…ued absorb/omit verdicts (#3065) No linked issue ## Summary Ports the ten skills of cursor/plugins' `pstack` collection (MIT, pinned at `main@60c641e4`) into this marketplace — one lane at a time, each through interview → adversarial audit → plan → implement. Every lane is a **reauthor**, not a fork: substance kept where it earns its place, wrapper adapted to this marketplace's conventions, prose rewritten. Provenance lives in `docs/upstream/cursor-pstack.md` and the plugin CHANGELOGs, never in skill bodies. **Two skills ship. Eight lanes absorb or omit, each with a written argument.** That ratio is the point: an adversarial fresh-context validator ran over every lane's decision set with the rationale withheld, and overturned the majority of the recommendations on most lanes. Where it was right, the plan changed; where it was wrong on the facts, the record says so and why. | Lane | Upstream | Verdict | |---|---|---| | 1 | `why` | **Ships** `discovery:trace-intent` — intent archaeology from records, five evidence tiers | | 2 | `blast-radius` | **Ships** `review:quality-gate downstream` — the outward-looking review lens | | 3 | `arena` | Omitted; 4 ideas into `architecture:improve`, `prototype`, `naming` | | 4 | `technical-writing` | **Ships** `docs-hygiene:write-for-humans` — lane-2 shaped | | 5 | `show-me-your-work` | Absorbed into `implement-dispatch`; found a live CSV-injection bug | | 6 | `recall` | Omitted, absorbed nothing — every candidate already had an owner | | 7 | `teach` | 2 rules into `education:teach`'s lesson contract | | 8 | `tdd` | 2 rules into `testing:write` and `debugging:debug` | | 9 | `reflect` | Omitted; one routing gap closed in both retro skills | | 10 | `bro` | Omitted, nothing absorbed — capability already ships twice | ## Fix **Lane 1 — `discovery:trace-intent`.** Recovers *why* a change was made from review threads, tickets and design docs. Five intent-evidence tiers, renamed from upstream's "confidence" because the axis measures inferential distance, not certainty — ICD 203 forbids conflating them. Adds a per-citation source-reliability note that annotates without routing, because every comparable scheme (ICD 203, GRADE, Admiralty) separates directness from source quality. **One deliberate departure:** upstream admits labelled code-shape inference; this forbids it outright, on operational grounds — code is the one source always present and free to consult, so a weak-but-admissible rung for it gets filled exactly when the real record is thin. **Lane 2 — `review:quality-gate downstream`.** The whole review lane was diff-scoped and nothing looked outward; verified by reading each incumbent rather than assumed. Rejected upstream's five-rung proof ladder, which would have been this fleet's *ninth* evidence ladder. **Lane 4 — `docs-hygiene:write-for-humans`.** The sibling `write-for-agents` excludes human-facing prose in both its description and its own "does NOT do", and nothing else claimed it. Ships the Diátaxis mode picker, a rhythm section against machine-cadence prose, one sentence-rules spoke, and drift-stamped sources. **The re-posture is the port:** upstream ships Google style / ASD-STE100 / Global English as house rules; here they are a *named, replaceable default set*, applied only after a search for the consuming project's own style guide comes back empty. The plan's own draft contained the disproof — a decision existed solely to delete two rules because they conflicted with this repo's em-dash ruling, and a standard that must be pre-edited to stop fighting its home repo is not a value that "cannot conflict in any repo". **Lanes 3, 5, 6, 7, 8, 9, 10 — absorbed or omitted.** Highlights: `arena` omitted on Rule of Three (two consumers, not three, and they disagree about everything a shared runner would fix), with its rejected-shapes field, graft ledger and read-the-spread discipline absorbed. `recall` produced nothing and says so. `bro` contributes two sentences and no mechanism against three incumbents. **One real bug, found rather than ported.** Hunting for somewhere to apply upstream's formula-injection guard turned up a live exposure: `claude-ops:audit-install-state` wrote scanned `relpath` and five other tree-derived fields raw through `csv.writer` into an artifact the skill tells the reader to open row by row — and a plugin, project, or worktree directory under `~/.claude` may be named `=HYPERLINK(...)`. Fixed with `csv_safe`, covering the leading tab/CR/LF a spreadsheet strips before deciding. ## Verification All gates run locally against `origin/main` at the branch tip, all green: - `check-changed-skills` — 15 skills checked, 0 failed. Both new skills PASS with **0 errors, 0 warnings**. - `validate-plugins`, `validate-plugin-contracts` (48 setup skills, 2816 files) - `check-changelog-parity` — all four modes (`--check`, `--check-bump`, `--check-order`, `--check-preserved`; 13 changed changelogs, 329 headings compared) - `check-contract-slice-prune` — both modes; the change set leaves no path under `docs/topics/` - `check-skill-portability`, `check-skill-count-claims`, `check-skill-leaf-names`, `check-cross-plugin-source-drift`, `check-plugin-manifest-presence`, `check-orphaned-fixtures`, `check-silent-skips`, `check-fleet-audit-doc-grammar`, `check-lane-coverage`, `check-contract-clause-coverage`, `check-stale-base-overlap` - `check-evals-quality` on both new eval suites — PASS, 0 warnings - `markdownlint-cli2` on every touched markdown file — 0 issues - `install_state` Python suite — 50 tests OK, including the new `TestCsvFormulaInjection` **The CSV-injection test was confirmed discriminating**, not just passing: with `csv_safe` disabled in memory its cases fail 8 subtests, and pass with it restored. ## Related - `docs/upstream/cursor-pstack.md` — the single source of truth for everything derived from this upstream: eight attribution-table rows plus prose sections for the two lanes that shipped nothing, each with its argument and a recheck trigger. - ADR 0016 — the always-listed description budget the two new skills are measured against. - ADR 0004 — the incumbent-first gate every lane ran before recommending. - `docs/PLUGIN-PHILOSOPHY.md` — the two-lane convention posture that reshaped lane 4, and the instruction-economy rule that declined several otherwise-novel absorbs. - `docs/MIGRATION-PLAYBOOK.md` — the skill-split and Rule-of-Three rules behind the omissions. - #3058 — main's independent fix for the same check-21 mawk defect this branch had carried; main's version was taken wholesale (see below). ## Notes for the reviewer - **Where the audit changed the plan.** Lane 4 was re-postured from house rules to resolvable defaults. Lane 5's absorb target moved twice — the plan's `running-retro` was the wrong artifact, and the audit's counter-proposal of a marketplace convention was checked surface by surface and found to have **one** genuine adopter, not the eight claimed. Lane 7's two rules were re-homed off `visualization:visualize` (a form router that "is not a craft teacher"). Lane 8's cost branch moved to `testing:write`'s existing decline list. Lane 9's fix widened to cover `retro` as well as `running-retro`. Two of my own factual claims were caught and corrected in the record, including a grep that used `\|` without `-E` and so found nothing. - **One dissent is recorded, not smoothed over.** The audit argued for absorbing `reflect`'s three orthogonal review lenses, and correctly caught that the plan had miscited `arena`'s reasoning. They stay declined on the instruction-economy rule, and `cursor-pstack.md` says so plainly so a later reader who disagrees knows where to start. - **check-21 collision with main.** Main landed the same mawk fix independently while this branch was in flight. Main's is the faithful translation — it preserves the original 1–9 digit bound where this branch had widened it to unbounded — and its suite already asserts the positive liveness case, so this branch's version was dropped entirely. `review` renumbered 0.24.0 → 0.25.0 after a version collision. - **Pre-existing local test failures are not from this branch.** `scripts/run-plugin-tests.sh` fails 31 checks across four suites (`claude-config` ×3, `claude-ops:morning-brief`, `discovery:check-coverage-complete`). Every one reproduces identically on a clean `origin/main` worktree; the cause is the container running as uid 0, so `chmod 000` fixtures stay readable. Most suites SKIP for exactly this; these four hard-FAIL instead. CI runs non-root. --- _Generated by [Claude Code](https://claude.ai/code/session_01EtvBfWQRz7w6kgRnJm4qgj)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Closes #3005
Summary
Check 21 (fresh-eyes declaration conformance) silently passed every file it was given on any machine
whose
awkis mawk — the Ubuntu/Debian default. Its embedded awk program used ERE intervalexpressions, and mawk aborts the program before it emits a single record, so malformed
fresh-eyes-exemptdirectives that should FAIL were reported as a clean run. Silent-pass is the worstshape a gate can fail in, and the plugin advertises running "against any repo", so this made that
claim false for a large share of consumers.
Fix
The issue attributed the break to mawk not implementing ERE intervals. That turned out to be the wrong
diagnosis for the container in question, and the correction narrowed the fix.
awkthere is mawk1.3.4 20240123, which does implement intervals. Isolating each construct:
^ {0,3}> ?— interval + literal^ {0,3}[abc]— interval + bracket class^ {0,3}[0-9]{1,9}— interval + interval^ *([-*+])— star + group^ ? ? ?([-*+])— optionals + group^ {0,3}([-*+])[ \t]+— interval + groupThe trigger is specific: an ERE interval immediately followed by a parenthesized group panics mawk
1.3.4's regex compiler with
REcompile() - panic: values still on machine stack. The panic is fatal,which is the silent-pass mechanism. Sweeping every
.shfile in the repo for that shape finds exactlytwo sites, both in this scanner — the list-marker strip and fence detection — which is why check 23,
written interval-free in #2963, was unaffected.
The scanner is now interval-free throughout, not just at the two panicking sites. The two
surviving
{0,3}sites compiled fine under 1.3.4, but mawk 1.3.3 implements no intervals at alland matches the braces as literal text, degrading exactly the same way — a second silent failure mode
for the same regexes on an older but still widely deployed mawk. The rewrite preserves the exact
CommonMark bounds already enforced: the three-space indent cap becomes three optional spaces, the
ordered-marker digit cap one digit plus eight optional ones. Both bounds were verified to still reject
out-of-range input (4 spaces does not match; a 10-digit marker is not stripped).
The two alternatives the issue floated at triage were declined deliberately. A loud
gawk requiredexit would make the "runs against any repo" claim false on stock Debian/Ubuntu rather than fixing it,
and
command -v gawk || awkleaves the silent-pass path live wherever gawk is absent.The portability guard
A source-level guard assertion fails the suite if an interval returns to any awk-consumed regex. It is
deliberately implementation-aware rather than black-box: gawk compiles intervals happily, so a
reintroduced interval would pass the entire suite on the CI runner and break only for consumers. No
behavioral assertion can observe this class of break on gawk.
Two properties of the guard came out of the review cycle (see the resolved threads):
{n}included, not just the comma forms. mawk panics ona{3}(b)exactly as it does ona{0,3}(b)— verified directly — so a comma-only pattern would haveleft the same silent-failure class open.
check-skill.shlegitimately uses an interval in a[[ =~ ]]regex to date a frontmattersynced:value; an unscoped broadening would have failed the suite on correct code. The two surfaces that do
reach awk are covered: slash-delimited regex literals inside the embedded programs, and
FRESH_EYES_JUDGE_RE, which is a POSIX ERE awk compiles via-vbut which never appears betweenslashes and would be missed by a literal-only or line-range scan.
Verification
Run in the affected environment (
awk→/usr/bin/mawk, mawk 1.3.4 20240123):origin/main@d9f15d4ffirst —check-skill.test.shfailed 21assertions, all Check 21, emitting the
REcompile()panic.check-skill.test.sh: 96 → 118 passing, 0 failures, 0 panics. Diffing the baseline andpost-fix
oksets shows exactly +21 newly passing from the scanner fix, zero assertions thatregressed from passing to failing, plus the new guard assertion.
failures — the 21 restored panics plus the guard naming the file and line. After the review
hardening, each of
{n},{n,}and{n,m}was reintroduced in turn and the guard caught everyone, while the clean tree still passes with the Bash date regex untouched. Tree restored after each
probe.
scripts/check-changed-skills.test.sh: PASS=13 FAIL=0 — the other suite that exercisescheck-skill.sh, whose fixtures have broken on a checker change before.under mawk (previously none at all), and
skill-quality/skills/check,work-items/skills/workand
source-control/skills/pull-requestall still PASS with 0 errors.validate-plugins.sh;generate-catalog.mjs --checkandgenerate-cheatsheet.mjs --check;check-changelog-parity.shin all four modes, including--check-preserved origin/main(36 headings compared, all preserved) and--check-bump origin/main;check-changed-skills.sh origin/main; both portability lints;markdownlint-cli2onthe touched CHANGELOG (0 issues);
typoson the touched plugin (clean);shellcheckon bothtouched scripts (clean).
origin/mainimmediately before each push — main is onskill-quality 0.17.0, so 0.17.1 is uncontested.
These counts are reproducible from a clean checkout on any mawk box with
bash plugins/skill-quality/scripts/check-skill.test.sh.Related
check 21.
scripts/check-changelog-parity.sh:195and
plugins/markdown-format/hooks/markdown-format.test.sh:72also use ERE intervals in awk. Bothwere verified to compile cleanly under mawk 1.3.4 (they precede literals and classes, not groups),
so neither is broken today, but both would degrade on mawk 1.3.3. They sit in a different plugin
and a repo-level script, each needing its own version bump, so folding them in would widen this
diff past the issue's scope.
🤖 Generated with Claude Code
https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4