feat(hygiene): bundled pre-push self-check helper for tick shards#3716
Conversation
Bundles the three self-checks I've been running per-tick this session into one command: MD032 paragraph-before-bullet awk-style scan + markdownlint-cli2 (the broad markdown surface including MD038) + audit-tick-shard-relative-paths (the dedicated relative-path audit). Motivation: today's self-bite tick 13 saw an MD038 violation ship to PR #3707 because I didn't run markdownlint before push; the required CI check failed and blocked merge for 70+ min. A bundled helper shortens the local-feedback loop from "push + wait for CI" to "single command + immediate output." DX helper, not a CI gate. CI gates remain authoritative. Usage: bun tools/hygiene/check-shard-before-push.ts <shard-path>... Exit codes: 0 all checks passed 1 one or more checks failed 64 argument error (missing files, non-files, no args) Local verify: - Clean shard (0334Z.md): exit 0; all 3 checks ok - Bad shard (synthetic MD032 + MD038): exit 1; specific findings printed - Missing file: exit 64 with structured "input not found" - No args: exit 64 with usage - bun --bun tsc --noEmit: exit 0 - markdownlint-cli2 on this file: exit 0 Composes with: audit-tick-shard-relative-paths.ts (the audit it wraps), AUDIT-LIFECYCLE.md (the lifecycle template that motivates pre-push catches), the §33 audit's same pattern. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a bundled pre-push self-check helper that runs MD032 scanning, markdownlint-cli2, and the relative-path audit on tick shard files to shorten the local feedback loop.
Changes:
- New TS tool
check-shard-before-push.tsrunning three per-tick checks - Validates input files exist and are regular files; exits 64 on arg errors
- Returns aggregated pass/fail status across all files
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9151d6cef1
ℹ️ 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".
…ed (PR #3716) (#3717) Tick 17: bundled the 3 per-tick self-checks (MD032 awk + markdownlint-cli2 + relative-path audit --files) into one command at tools/hygiene/check-shard-before-push.ts. 187-line TS script. Motivation: tick 13 self-bite — MD038 violation slipped past the awk-only manual self-check. Bundle closes the local-feedback gap. 3 prior PRs merged (#3711, #3709, #3710). Full tick-shard hygiene ecosystem on main: audit + baseline + CI enforce gate + AUDIT-LIFECYCLE.md + this DX helper. Wrong-depth-.. bug class is mechanized end to end. Co-authored-by: Claude <noreply@anthropic.com>
…D032, parseArgs exit Three real findings on PR #3716, fixed: L114 (substring fragility): runRelativePathAudit relied on out.includes( "0 broken relative-path links") as the success signal. Fragile to future wording tweaks AND ignored r.status entirely. Replace with: 1. r.status !== 0 → unambiguous failure (echo stdout+stderr+status) 2. Parse the "N broken relative-path links" count via regex; "0" = ok 3. Unrecognized output format → fail loud, echo, don't silent-pass L69 + L74/L75 + (3 duplicate threads on fenced-code MD032): the checkMd032 scan didn't track fence state, so a `- ` line inside ```...``` was flagged as a false-positive MD032 violation. Add buildCodeFenceFlags (same pattern as audit-tick-shard-relative-paths.ts) and skip lines inside fences. Verified with a synthetic shard containing a bullet inside a code block — was reported FAIL pre-fix, now reports OK. L124 (parseArgs process.exit): parseArgs called process.exit(64) directly on no-args, blocking unit-test of the no-args branch even though main is exported for testability. Replace with a typed ParseResult discriminated union ({ok:true,args} | {ok:false,exitCode:64,message}); main inspects the result and exits itself. Skipped (P2 optional, scope creep): multi-file batching of spawn calls. Markdownlint-cli2 + audit script accept multiple files natively; could reduce wall-clock for N>1 invocations. Filing for future iteration if multi-shard usage materializes. Local verify (5 tests): - Clean shard (0334Z.md): exit 0 - Bad shard (MD032 + MD038): exit 1, both findings printed - Fence-shard (- bullet inside ```text```): exit 0 ← fix verified - No args: exit 64 via main (was via process.exit inside parseArgs) - tsc --noEmit: exit 0 Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 38c4b58f8c
ℹ️ 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".
| if (!cur.startsWith("- ")) continue; | ||
| if (prev.trim() === "") continue; | ||
| if (/^[#>*\-|`]/.test(prev)) continue; |
There was a problem hiding this comment.
Skip intra-list continuations in MD032 scan
The custom checkMd032 heuristic flags any - line whose previous line is non-blank/non-structural, but that also matches valid multi-line list items (e.g., - first + indented continuation + - second). In that case markdownlint-cli2 passes, yet this helper sets anyFailed = true and exits 1, creating false blocking results for normal shard formatting. Because this script is intended as a reliable pre-push signal, it should track whether the current bullet is a continuation of an existing list context before reporting MD032.
Useful? React with 👍 / 👎.
…up/optional) (#3720) * shard(tick): 2026-05-16T03:50Z — PR #3716 round-2 (3 real fixes + 3 dup/optional) PR #3715 merged. 6 Copilot threads on PR #3716 (helper): - L114 substring fragility — REAL. Use r.status === 0 as primary signal + regex parse of count + fail-loud on unrecognized format. - L69/74/75 fenced-code MD032 — REAL (3 duplicate threads, same finding). Add buildCodeFenceFlags (same pattern as the audit script). - L124 parseArgs process.exit — REAL. Replace with typed ParseResult discriminated union; main exits, parseArgs returns. - L86 multi-file spawn batching — OPTIONAL, deferred. Fixup 38c4b58 pushed; 6 threads resolved via tmpfile pattern (the for-loop word-split approach hit IFS-quirks today; tmpfile is more robust). Co-Authored-By: Claude <noreply@anthropic.com> * fix(pr-3720): mark B-0545 next-tick candidate done (peer-Otto landed it) Copilot P1: my 'B-0545 renumber-sweep (claim still active until 2026-05-17T01:44Z)' next-tick candidate was stale — B-0545 is now status: done on main (completed: 2026-05-16; completed_by: otto-cli). A peer-Otto-CLI session landed the sweep in parallel with this session's work. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
… scan (#3724) PR #3716's helper had a false-positive class on bullet-continuation lines. Discovered during tick 19 self-test: running the helper on .claude/rules/blocked-green-ci-investigate-threads.md flagged 3 lines as MD032 violations where the prev line was a 2-space-indented continuation of a list-item bullet. Markdownlint correctly ignores these (exit 0). The structural-marker regex `/^[#>*\-|`]/` only matches LITERAL markers; their wrap-continuations (which start with whitespace) were treated as paragraph content. Fix: add `isContinuationLine(line)` predicate that detects leading whitespace. Skip when prev is a continuation line. Tested 3 cases: 1. bullet-continuation (the FP): now ok 2. real paragraph-before-bullet (no continuation): still caught 3. existing-clean-shard regression: still ok `tsc --noEmit`: exit 0. Co-authored-by: Claude <noreply@anthropic.com>
…ion (PR #3721) (#3722) * shard(tick): 2026-05-16T03:54Z — verify-reviewer-findings rule extension (PR #3721) PR #3716 (helper) + PR #3717 (0344Z) merged. Extended blocked-green-ci-investigate-threads.md with 3 composes-with sections: verification anchors + suspect-by-default Copilot finding list (table-pipe || hallucination, 4-FP entry) + stale-but-fresh-looking finding class. Self-discovery: running the just-merged check-shard-before-push.ts on the rule file surfaced a helper bug — checkMd032 flags bullet-continuation lines as false-positive paragraphs. Filing as next-tick fix. Also self-bite caught during shard authoring: 2 MD038 violations in the prose describing the helper bug (literal trailing-space-in-backticks examples). Rewrote the prose without the literal-trigger pattern. The self-check IS doing its job. GraphQL exhausted mid-tick after PR-3721 REST creation. PR #3721 NOT armed this tick; will arm post-reset at 03:55:31Z next tick. Co-Authored-By: Claude <noreply@anthropic.com> * fix(pr-3722): Copilot P1 — double-backtick code span for regex with literal backtick The inline code span containing the structural-marker regex contained a literal backtick inside the character class. Single-backtick delimiters ended early at the inner backtick, leaving the closing delimiter unmatched and tripping MD038 / breaking parse. Switch to a double-backtick code span (``/^[#>*\-|`]/``) which can carry single inner backticks since the closing run is two consecutive backticks. Verified: bun tools/hygiene/check-shard-before-push.ts ok; markdownlint-cli2 ok (exit 0). Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
What
tools/hygiene/check-shard-before-push.tsbundles three per-tick self-checks into one command:markdownlint-cli2for the broad markdown lint surface (MD038 no-space-in-code + others)audit-tick-shard-relative-pathsdetect-only mode on the input fileWhy
Today's tick 13 self-bite: an MD038 violation shipped to PR #3707 because I didn't run markdownlint before push. The required CI check failed and blocked merge for 70+ min (the markdownlint failure on the prior 0240Z fix, surfaced via tick 13). A bundled helper shortens the local-feedback loop from "push + wait for CI" to "single command + immediate output."
Usage
Exit codes
Local verify
input not foundtsc --noEmitScope
DX helper, not a CI gate. CI gates remain authoritative. This script just shortens the local-feedback loop.
Co-Authored-By: Claude noreply@anthropic.com