This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow-steward.git


The following commit(s) were added to refs/heads/main by this push:
     new 5eee612  docs: enable markdownlint MD040 and tag all fenced code 
blocks (supersedes #30) (#44)
5eee612 is described below

commit 5eee612551d0c15946af43262b692760c0f4e36c
Author: Jarek Potiuk <[email protected]>
AuthorDate: Mon May 4 12:11:58 2026 +0200

    docs: enable markdownlint MD040 and tag all fenced code blocks (supersedes 
#30) (#44)
    
    * docs: enable markdownlint MD040 and tag all fenced code blocks
    
    Follow-up to #18. Flips MD040 from `false` to `true` and tags the 64
    previously untagged fences across the tree.
    
    Most fences ended up `text` (MCP call sketches, URL examples, dir
    trees, plain output, commit trailers). 3 got `html` for HTML-comment
    idempotency markers and the <details> envelope, 3 `markdown` for the
    AI-disclosure block and rollup body samples, 1 `yaml` for the
    subagent return block in sync-security-issue.
    
    One nested-fence case in allocate-cve/SKILL.md needed the outer
    fence promoted from 3 to 4 backticks so the inner 3-backtick block
    renders as an actual nested code block instead of breaking the outer
    one.
    
    Signed-off-by: André Ahlert <[email protected]>
    
    * docs: extend MD040 tagging to skills added since #30
    
    #30 was opened against an earlier tree state; the pr-management
    skill family (lifted in #33, renamed to type-what-action in
    #35) added 9 new skill supporting files with 20 untagged
    fences that fail markdownlint MD040 once it's enabled.
    
    This commit applies the same tagging convention #30 established
    for the security family + tools to the new pr-management files:
    
      pr-management-triage/fetch-and-batch.md     1 fence
      pr-management-triage/comment-templates.md   2 fences  → markdown
      pr-management-triage/interaction-loop.md    4 fences  → text (UI mockups)
      pr-management-triage/workflow-approval.md   2 fences  → text (UI mockups)
      pr-management-stats/fetch.md                3 fences  → text (search 
queries)
      pr-management-stats/render.md               3 fences  → text (output 
samples)
      pr-management-stats/classify.md             3 fences  → text (pseudocode)
      pr-management-code-review/review-flow.md    1 fence   → text (CLI mockup)
      pr-management-code-review/prerequisites.md  1 fence   → text (HTTP error)
    
    Most fences ended up `text` (the same catch-all #30's commit
    message used for "MCP call sketches, URL examples, dir trees,
    plain output"). Two `markdown` fences in
    `pr-management-triage/comment-templates.md` because the
    content is a markdown link / list item example that GitHub
    should render as markdown.
    
    prek run --all-files clean. MD040 reports zero violations
    across the tree.
    
    Generated-by: Claude Code (Claude Opus 4.7)
    
    ---------
    
    Signed-off-by: André Ahlert <[email protected]>
    Co-authored-by: André Ahlert <[email protected]>
---
 .../pr-management-code-review/prerequisites.md     |  2 +-
 .../pr-management-code-review/review-flow.md       |  2 +-
 .claude/skills/pr-management-stats/classify.md     |  6 +++---
 .claude/skills/pr-management-stats/fetch.md        |  6 +++---
 .claude/skills/pr-management-stats/render.md       |  6 +++---
 .../pr-management-triage/comment-templates.md      |  4 ++--
 .../skills/pr-management-triage/fetch-and-batch.md |  2 +-
 .../pr-management-triage/interaction-loop.md       |  8 ++++----
 .../pr-management-triage/workflow-approval.md      |  4 ++--
 .claude/skills/security-cve-allocate/SKILL.md      |  6 +++---
 .claude/skills/security-issue-fix/SKILL.md         |  2 +-
 .../skills/security-issue-import-from-md/SKILL.md  | 12 +++++------
 .../skills/security-issue-import-from-pr/SKILL.md  |  6 +++---
 .claude/skills/security-issue-import/SKILL.md      |  6 +++---
 .claude/skills/security-issue-invalidate/SKILL.md  |  6 +++---
 .claude/skills/security-issue-sync/SKILL.md        | 14 ++++++-------
 .markdownlint.json                                 |  8 ++++----
 AGENTS.md                                          | 12 +++++------
 CONTRIBUTING.md                                    |  2 +-
 docs/setup/secure-agent-setup.md                   |  4 ++--
 projects/_template/fix-workflow.md                 |  2 +-
 tools/github/status-rollup.md                      |  6 +++---
 tools/gmail/draft-backends.md                      |  2 +-
 tools/gmail/operations.md                          | 10 ++++-----
 tools/gmail/ponymail-archive.md                    | 10 ++++-----
 tools/ponymail/operations.md                       | 24 +++++++++++-----------
 tools/ponymail/tool.md                             |  6 +++---
 tools/vulnogram/allocation.md                      |  2 +-
 28 files changed, 90 insertions(+), 90 deletions(-)

diff --git a/.claude/skills/pr-management-code-review/prerequisites.md 
b/.claude/skills/pr-management-code-review/prerequisites.md
index 54784ba..097146e 100644
--- a/.claude/skills/pr-management-code-review/prerequisites.md
+++ b/.claude/skills/pr-management-code-review/prerequisites.md
@@ -25,7 +25,7 @@ the target repo (`<upstream>` by default). Without
 collaborator access, the eventual `gh pr review` mutation in
 [`posting.md`](posting.md) returns:
 
-```
+```text
 HTTP 403: Resource not accessible by integration
 ```
 
diff --git a/.claude/skills/pr-management-code-review/review-flow.md 
b/.claude/skills/pr-management-code-review/review-flow.md
index 3d95e15..b0d72a8 100644
--- a/.claude/skills/pr-management-code-review/review-flow.md
+++ b/.claude/skills/pr-management-code-review/review-flow.md
@@ -28,7 +28,7 @@ multi-line headline. Per Golden rule 10 in `SKILL.md`, the PR
 number is always printed alongside its full URL so the
 maintainer can click straight through:
 
-```
+```text
 PR #65934 — Fix scheduler N+1 on serialized Dag load
   https://github.com/<upstream>/pull/65934
   Author: alice (CONTRIBUTOR, [external])
diff --git a/.claude/skills/pr-management-stats/classify.md 
b/.claude/skills/pr-management-stats/classify.md
index 71c01ef..a3a0785 100644
--- a/.claude/skills/pr-management-stats/classify.md
+++ b/.claude/skills/pr-management-stats/classify.md
@@ -91,7 +91,7 @@ Mark which path the skill used in the legend output (`drafted 
by triager (heuris
 
 The age of a PR for bucketing is the time since the author's *last 
interaction*:
 
-```
+```text
 last_author_interaction = max(
     most_recent_comment.createdAt where comment.author.login == 
pr.author.login,
     last_commit.committedDate,
@@ -120,7 +120,7 @@ Four buckets is the deliberate minimum — each one maps to a 
distinct maintaine
 
 A PR is by a *contributor* (for the `Contrib.` column) when:
 
-```
+```text
 authorAssociation NOT IN (OWNER, MEMBER, COLLABORATOR)
 ```
 
@@ -138,7 +138,7 @@ The `Ready` column counts PRs carrying the `ready for 
maintainer review` label.
 
 Table 1's `Responded` column measures, per area, how many triaged PRs got an 
author reply *before* they were closed or merged. For a PR in the closed-since 
set:
 
-```
+```text
 responded_before_close =
     is_triaged AND
     exists(comment by pr.author where comment.createdAt > 
triage_comment.createdAt AND comment.createdAt <= pr.closedAt)
diff --git a/.claude/skills/pr-management-stats/fetch.md 
b/.claude/skills/pr-management-stats/fetch.md
index b552cb5..78eff1d 100644
--- a/.claude/skills/pr-management-stats/fetch.md
+++ b/.claude/skills/pr-management-stats/fetch.md
@@ -55,7 +55,7 @@ query(
 
 ### `searchQuery`
 
-```
+```text
 is:pr is:open repo:<repo> sort:created-asc
 ```
 
@@ -199,7 +199,7 @@ Empirical delta on `<upstream>`, cutoff 2026-03-11:
 
 When the maintainer explicitly asks for a quick approximation (`fast-closed` 
flag, or in a low-budget context), fall back to the search-based path:
 
-```
+```text
 is:pr -is:open repo:<repo> closed:>=<cutoff> sort:updated-desc
 ```
 
@@ -207,7 +207,7 @@ The fast path must print a clear caveat above Table 1: 
*"fast-closed mode: Table
 
 ### `searchQuery`
 
-```
+```text
 is:pr -is:open repo:<repo> closed:>=<cutoff> sort:updated-desc
 ```
 
diff --git a/.claude/skills/pr-management-stats/render.md 
b/.claude/skills/pr-management-stats/render.md
index 5c1b996..9f57ae7 100644
--- a/.claude/skills/pr-management-stats/render.md
+++ b/.claude/skills/pr-management-stats/render.md
@@ -121,7 +121,7 @@ Counts must sum to the open-PR total (non-bot). If they 
don't, print a warning a
 
 Before the first table, print one line summarising the scope. This line is 
plain text (no Rich markup needed — it's header-style, not a table) so it 
renders identically in the terminal and in the Markdown fallback.
 
-```
+```text
 <upstream> — 413 open PRs (non-bot) · closed/merged since 2026-03-11 · viewer 
@potiuk · 2026-04-22 22:33 UTC
 ```
 
@@ -131,7 +131,7 @@ The `<now>` is the fetch-start timestamp, not the 
render-end timestamp — a slo
 
 If the closed-since counts came from the lagging search index (see 
[`fetch.md#known-limitation`](fetch.md)), print a one-line caveat between the 
context line and Table 1:
 
-```
+```text
 ⚠ Table 1 built from GitHub's free-text search of the quality-criteria marker. 
The index lags — older triaged+merged PRs are likely undercounted. Pass 
accurate-closed for the hybrid REST + GraphQL path.
 ```
 
@@ -229,7 +229,7 @@ console.print(Panel("\n".join(legend_lines), 
border_style="dim", expand=False))
 
 Close with a single-line summary the maintainer can use for at-a-glance 
reporting:
 
-```
+```text
 Summary: 413 open · 66 triaged (16%) · 3 responded (5% of triaged) · 126 ready 
for review · 43 drafted by triager in last 7d.
 ```
 
diff --git a/.claude/skills/pr-management-triage/comment-templates.md 
b/.claude/skills/pr-management-triage/comment-templates.md
index b471bac..b289da5 100644
--- a/.claude/skills/pr-management-triage/comment-templates.md
+++ b/.claude/skills/pr-management-triage/comment-templates.md
@@ -26,7 +26,7 @@ Placeholders:
 All templates use the canonical link to the quality-criteria
 document:
 
-```
+```markdown
 [Pull Request quality 
criteria](https://github.com/<upstream>/blob/main/contributing-docs/05_pull_requests.rst#pull-request-quality-criteria)
 ```
 
@@ -421,7 +421,7 @@ bad-faith actor a footnote to argue with.
 one bullet per violation returned by the classifier. Each
 bullet has the form:
 
-```
+```markdown
 - :x: **<category>** — <explanation>. See [docs](<doc_link>).
 ```
 
diff --git a/.claude/skills/pr-management-triage/fetch-and-batch.md 
b/.claude/skills/pr-management-triage/fetch-and-batch.md
index 13a74e4..c4d7f91 100644
--- a/.claude/skills/pr-management-triage/fetch-and-batch.md
+++ b/.claude/skills/pr-management-triage/fetch-and-batch.md
@@ -119,7 +119,7 @@ query(
 below. The typical production shape for the default sweep on
 `<upstream>` is:
 
-```
+```text
 is:pr is:open repo:<upstream>
 -label:"ready for maintainer review"
 sort:updated-asc
diff --git a/.claude/skills/pr-management-triage/interaction-loop.md 
b/.claude/skills/pr-management-triage/interaction-loop.md
index ecb897c..b4cbe79 100644
--- a/.claude/skills/pr-management-triage/interaction-loop.md
+++ b/.claude/skills/pr-management-triage/interaction-loop.md
@@ -74,7 +74,7 @@ For each group, present one screen of information. The goal is
 a decision in under 15 seconds when the suggestion looks right,
 or a natural path to per-PR inspection when it doesn't.
 
-```
+```text
 ─────────────────────────────────────────────────────
 Group 3 of 8  —  deterministic_flag → draft  —  5 PRs
 
@@ -155,7 +155,7 @@ step in place of `[A]`/`[E]`.
 When a PR is pulled out of a group (via `[P]`, `[E]`, or
 because its group mandates per-PR), present the full detail:
 
-```
+```text
 ─────────────────────────────────────────────────────
 PR #65471   "Add support for new db dialect"
 Author: @eve  (tier: new, 2 merged / 5 total on this repo)
@@ -307,7 +307,7 @@ the drill-in, it's instant.
 When `[A]` triggers batched mutations, show live progress as a
 short table that updates in-place:
 
-```
+```text
 Applying action: draft  (5 PRs, parallelism: 5)
 
   #65401 @alice — posting comment… done
@@ -330,7 +330,7 @@ before moving on.
 On exit (either `[Q]` or after the last group), print a
 session summary:
 
-```
+```text
 Session summary — 2026-04-22 09:42 UTC → 10:07 UTC (25m)
 
 PRs presented:  47
diff --git a/.claude/skills/pr-management-triage/workflow-approval.md 
b/.claude/skills/pr-management-triage/workflow-approval.md
index 601a808..e230b87 100644
--- a/.claude/skills/pr-management-triage/workflow-approval.md
+++ b/.claude/skills/pr-management-triage/workflow-approval.md
@@ -160,7 +160,7 @@ For each PR in the group, in the order returned by the
 classifier (which is age-ascending so the freshest PRs land
 first), print:
 
-```
+```text
 ─────────────────────────────────────────────────────
 [N] PR #NNNNN  "<title>"
 Author: @<login>  (account: D days old, R repos, M merged PRs)
@@ -192,7 +192,7 @@ patterns matched"*. That's the green-light 
pre-classification.
 After all blocks are printed, render the summary table and
 prompt for selection:
 
-```
+```text
 ─────────────────────────────────────────────────────
 pending_workflow_approval — N PRs · choose what to approve
 ─────────────────────────────────────────────────────
diff --git a/.claude/skills/security-cve-allocate/SKILL.md 
b/.claude/skills/security-cve-allocate/SKILL.md
index 78ca386..39652c4 100644
--- a/.claude/skills/security-cve-allocate/SKILL.md
+++ b/.claude/skills/security-cve-allocate/SKILL.md
@@ -305,14 +305,14 @@ over-stripping is worse than leaving one redundant word 
in.
 Compose a proposal block that carries everything the user needs in
 one copy-paste pass:
 
-```markdown
+````markdown
 **Allocate a CVE for 
[<tracker>#<N>](https://github.com/<tracker>/issues/<N>).**
 
 1. Open the ASF Vulnogram allocation form:
    <https://cveprocess.apache.org/allocatecve>
 2. In the *Title* field, paste this:
 
-   ```
+   ```text
    <stripped title>
    ```
 
@@ -326,7 +326,7 @@ one copy-paste pass:
 4. Click *Allocate*. Vulnogram returns a `CVE-YYYY-NNNNN` ID.
 5. Paste the allocated CVE ID back into this conversation — the
    skill will pick it up and update the tracker automatically.
-```
+````
 
 Scope → Vulnogram product table: the adopting project's scope labels
 and their CVE product / package-name mappings are defined in
diff --git a/.claude/skills/security-issue-fix/SKILL.md 
b/.claude/skills/security-issue-fix/SKILL.md
index 3d8ca2b..b25ead4 100644
--- a/.claude/skills/security-issue-fix/SKILL.md
+++ b/.claude/skills/security-issue-fix/SKILL.md
@@ -462,7 +462,7 @@ Write out the exact `--body` the skill will pass to
 - the standard Gen-AI disclosure block per
   
[`<upstream>/contributing-docs/05_pull_requests.rst`](https://github.com/<upstream>/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions):
 
-  ```
+  ```markdown
   ##### Was generative AI tooling used to co-author this PR?
 
   - [X] Yes — Claude Opus 4.6 (1M context)
diff --git a/.claude/skills/security-issue-import-from-md/SKILL.md 
b/.claude/skills/security-issue-import-from-md/SKILL.md
index f2c2847..a3ed0db 100644
--- a/.claude/skills/security-issue-import-from-md/SKILL.md
+++ b/.claude/skills/security-issue-import-from-md/SKILL.md
@@ -286,7 +286,7 @@ The tracker title is the finding's `# Title` with the 
standard
 convention; see
 [`tools/github/issue-template.md`](../../../tools/github/issue-template.md)):
 
-```
+```text
 [ Security Report ] <finding title>
 ```
 
@@ -377,7 +377,7 @@ exactly one blank line before `</details>`.
 
 Render a single proposal covering every parsed finding:
 
-```
+```text
 <file-basename> — N findings parsed.
 
 | # | Severity | Category                       | Title                        
                      | Possible duplicate |
@@ -581,7 +581,7 @@ purpose for this finding and would otherwise accumulate.
 After every finding lands, print a short one-liner so the user can
 see progress on long batches:
 
-```
+```text
 [K/N] <tracker>#NNN — <finding title>
 ```
 
@@ -661,7 +661,7 @@ the validity discussion produces signal.
 
 ### Example 1 — A six-finding AI-scan output
 
-```
+```text
 import findings from /tmp/scan-michaelwinser-airflow-2026-04-28.md
 ```
 
@@ -675,7 +675,7 @@ reference.
 
 ### Example 2 — A single-finding scanner export
 
-```
+```text
 import findings from ~/Downloads/sast-export.md
 ```
 
@@ -686,7 +686,7 @@ as a Gmail import; the only difference is the source format.
 
 ### Example 3 — Malformed input
 
-```
+```text
 import findings from /tmp/notes.md
 ```
 
diff --git a/.claude/skills/security-issue-import-from-pr/SKILL.md 
b/.claude/skills/security-issue-import-from-pr/SKILL.md
index db0071b..8fb4c10 100644
--- a/.claude/skills/security-issue-import-from-pr/SKILL.md
+++ b/.claude/skills/security-issue-import-from-pr/SKILL.md
@@ -710,7 +710,7 @@ with other trackers.
 
 ### Example 1 — `providers` scope, already merged
 
-```
+```text
 import from pr 65703
 ```
 
@@ -729,7 +729,7 @@ disclosure; see *[Reporter credit 
policy](#reporter-credit-policy-for-public-pr-
 
 ### Example 2 — `airflow` scope, in-flight
 
-```
+```text
 import from pr https://github.com/<upstream>/pull/65999
 ```
 
@@ -742,7 +742,7 @@ proposes everything; on user confirmation, the tracker lands
 
 ### Example 3 — Mixed-scope PR (blocker)
 
-```
+```text
 import from pr 66042
 ```
 
diff --git a/.claude/skills/security-issue-import/SKILL.md 
b/.claude/skills/security-issue-import/SKILL.md
index 696d57e..1ff9f17 100644
--- a/.claude/skills/security-issue-import/SKILL.md
+++ b/.claude/skills/security-issue-import/SKILL.md
@@ -250,7 +250,7 @@ When PonyMail MCP is enabled and authenticated (Step 0) 
**and**
 `tools.ponymail.private_lists`, run the archive as a **paired
 authoritative check** against the Gmail result set:
 
-```
+```text
 mcp__ponymail__search_list(
   list: "security",
   domain: "<project>.apache.org",
@@ -481,7 +481,7 @@ fuzzy-match search against existing issues on three 
orthogonal keys:
 For every candidate, surface the match results under a *Potential
 duplicates* sub-item in the Step 5 proposal — format:
 
-```
+```markdown
 - thread <threadId> — "<candidate title>"
   - GHSA match: [#NNN](...) "GHSA-xxxx-yyyy-zzzz"  (STRONG)
   - Code-pointer match: [#MMM](...) "BaseSerialization.deserialize"  (MEDIUM)
@@ -553,7 +553,7 @@ authenticated (Step 0) **and** 
`security@<project>.apache.org`
 is in `config/user.md` → `tools.ponymail.private_lists`,
 **PonyMail MCP is the primary backend for this step**:
 
-```
+```text
 mcp__ponymail__search_list(
   list: "security",
   domain: "<project>.apache.org",
diff --git a/.claude/skills/security-issue-invalidate/SKILL.md 
b/.claude/skills/security-issue-invalidate/SKILL.md
index 9e5f897..a98f96e 100644
--- a/.claude/skills/security-issue-invalidate/SKILL.md
+++ b/.claude/skills/security-issue-invalidate/SKILL.md
@@ -658,7 +658,7 @@ Hand-off line:
 
 ### Example 1 — `security@`-imported, dag-author-input class
 
-```
+```text
 invalidate 244
 ```
 
@@ -676,7 +676,7 @@ verbatim quotes and the draft ID. Hand-off: terminal.
 
 ### Example 2 — PR-imported, no email
 
-```
+```text
 invalidate 355
 ```
 
@@ -694,7 +694,7 @@ import-from-pr skill's golden rules.
 
 ### Example 3 — Hard stop: CVE already allocated
 
-```
+```text
 invalidate 257
 ```
 
diff --git a/.claude/skills/security-issue-sync/SKILL.md 
b/.claude/skills/security-issue-sync/SKILL.md
index 2bd573f..e700eaf 100644
--- a/.claude/skills/security-issue-sync/SKILL.md
+++ b/.claude/skills/security-issue-sync/SKILL.md
@@ -237,7 +237,7 @@ concurrently, which is exactly what the sync needs.
 Each subagent must return a single code block (or JSON) with exactly
 these fields so the orchestrator can merge deterministically:
 
-```
+```yaml
 issue: <N>
 title: <one line>
 scope_label: airflow | providers | chart | <missing>
@@ -481,7 +481,7 @@ backend for this step** — the archive is authoritative and
 reaches back further than any single user's Gmail window. Run the
 distinctive-phrase search against:
 
-```
+```text
 mcp__ponymail__search_list(
   list: "security",
   domain: "<project>.apache.org",
@@ -723,7 +723,7 @@ authenticated (Step 0) **and** 
`security@<project>.apache.org` is
 in `config/user.md` → `tools.ponymail.private_lists`, **PonyMail
 MCP is the primary path** for reviewer-comment archive queries:
 
-```
+```text
 mcp__ponymail__search_list(
   list: "security",
   domain: "<project>.apache.org",
@@ -1115,7 +1115,7 @@ will change and *why*. Group them by category:
      - **PonyMail MCP (preferred when enabled).** If Step 0
        recorded `ponymail_authenticated: true`, call:
 
-       ```
+       ```text
        mcp__ponymail__search_list(
          list: "users",
          domain: "<project>.apache.org",
@@ -1497,7 +1497,7 @@ will change and *why*. Group them by category:
 
   **Idempotency.** Before proposing, scan the issue's existing
   comments for the marker
-  ```
+  ```html
   <!-- apache-steward: release-manager-handoff v1 -->
   ```
   exactly. If a comment carrying this marker already exists, **do
@@ -1579,7 +1579,7 @@ will change and *why*. Group them by category:
 
   **Idempotency.** Before proposing, scan the issue's existing
   comments for the marker
-  ```
+  ```html
   <!-- apache-steward: release-manager-publication-ready v1 -->
   ```
   exactly. If a comment carrying this marker already exists, do not
@@ -1666,7 +1666,7 @@ the actual person, in this order:
    - **PonyMail MCP (preferred when enabled).** `dev@` is a public
      list; no LDAP allowlist check is needed. Call:
 
-     ```
+     ```text
      mcp__ponymail__search_list(
        list: "dev",
        domain: "<project-domain>",
diff --git a/.markdownlint.json b/.markdownlint.json
index a336c7d..5bc76c3 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -1,5 +1,5 @@
 {
-  "$comment": "Markdownlint config for apache/airflow-steward. The rule set is 
deliberately minimal — only enables checks that catch real bugs (broken 
anchors, malformed code spans, malformed link references). Style choices that 
the existing docs already settled (compact tables, hyphen list markers, 
ordered-list numbering, fenced-language tagging) are left alone so the 
consolidation does not balloon the diff.",
+  "$comment": "Markdownlint config for apache/airflow-steward. The rule set is 
deliberately minimal — only enables checks that catch real bugs (broken 
anchors, malformed link references, untagged fenced code). Style choices that 
the existing docs already settled (compact tables, hyphen list markers, 
ordered-list numbering) are left alone.",
 
   "default": true,
 
@@ -16,7 +16,7 @@
   "MD033": false,
   "MD034": false,
   "MD036": false,
-  "MD040": false,
+  "MD038": false,
   "MD041": false,
   "MD046": false,
   "MD050": false,
@@ -24,11 +24,11 @@
   "MD059": false,
   "MD060": false,
 
-  "MD038": false,
+  "MD040": true,
   "MD051": true,
   "MD053": true,
 
   "$comment-MD038": "MD038 (no space inside code spans) is disabled because 
the steward docs intentionally use literal markdown-syntax samples like `# ` 
(H1), `### ` (H3), `- ` (list marker) inside backticks to illustrate markdown 
rendering. The rule has no per-context allowlist and would force 
escape-everywhere across many files. Re-enable in a follow-up that escapes 
those samples consistently.",
 
-  "$comment-rationale": "MD051 (link-fragments) catches broken 
cross-references — exactly the bug class that surfaced 5 real broken anchors on 
the existing tree. MD053 catches dangling link-reference definitions. 
Everything else is style and is intentionally off so this PR stays 
diff-minimal."
+  "$comment-rationale": "MD040 catches untagged fenced code blocks — surfaces 
64 of them in the initial sweep, all tagged in this PR. MD051 (link-fragments) 
catches broken cross-references — exactly the bug class that surfaced 5 real 
broken anchors on the previous sweep. MD053 catches dangling link-reference 
definitions."
 }
diff --git a/AGENTS.md b/AGENTS.md
index 76b0926..8caf4de 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -235,7 +235,7 @@ at the root of its tracker repository. The framework refers 
to this
 directory via the placeholder `<project-config>`. Concretely, an
 adopting project lays out:
 
-```
+```text
 <adopter-tracker-repo>/
 └── .apache-steward/
     ├── apache-steward/         # (submodule) clone of this framework
@@ -374,13 +374,13 @@ if a hook is failing, fix the underlying issue or update 
the hook configuration
   itself. **Re-read this rule before preparing every `git commit`.**
   Use a `Generated-by:` trailer instead. The form is:
 
-  ```
+  ```text
   Generated-by: <agent name and version>
   ```
 
   Concrete example for Claude Code:
 
-  ```
+  ```text
   Generated-by: Claude Code (Opus 4.7)
   ```
 
@@ -862,7 +862,7 @@ not as bare text. The canonical link is the adopting 
project's CVE-tool
 record URL, which any security team member can click through to the
 live CVE record we control:
 
-```
+```text
 https://cveprocess.apache.org/cve5/<CVE-ID>
 ```
 
@@ -876,7 +876,7 @@ CVE record is visible on public databases), additionally 
link to the public
 `cve.org` / MITRE record so non-security-team readers can see the public
 description without needing access to the ASF tool:
 
-```
+```text
 https://www.cve.org/CVERecord?id=<CVE-ID>
 ```
 
@@ -967,7 +967,7 @@ messages, internal notes, `SKILL.md` files — render it as a
 **clickable markdown link**, not as a bare `#NNN` or
 `<tracker>#NNN`. The URL format is:
 
-```
+```text
 https://github.com/<tracker>/issues/<N>
 https://github.com/<tracker>/pull/<N>
 https://github.com/<tracker>/issues/<N>#issuecomment-<C>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3117a71..d403615 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -79,7 +79,7 @@ four — no hard-coded project assumptions anywhere.
 
 ### Directory tree
 
-```
+```text
 .
 ├── README.md                      # Canonical 16-step handling process + 
conventions
 ├── AGENTS.md                      # Editorial rules: tone, brevity, 
confidentiality,
diff --git a/docs/setup/secure-agent-setup.md b/docs/setup/secure-agent-setup.md
index 532556f..cc79cbd 100644
--- a/docs/setup/secure-agent-setup.md
+++ b/docs/setup/secure-agent-setup.md
@@ -311,7 +311,7 @@ the manifest, never installs anything, never opens a PR.
 The framework's `/schedule` slash-command lets you wire the check
 script into a recurring agent without leaving Claude Code:
 
-```
+```text
 /schedule weekly run tools/agent-isolation/check-tool-updates.sh
                   and surface upgrade candidates
 ```
@@ -742,7 +742,7 @@ already follow this pattern.
 
 A minimal repo layout:
 
-```
+```text
 ~/.claude-config/                       # the synced repo's checkout
 ├── CLAUDE.md                           # symlinked → ~/.claude/CLAUDE.md
 ├── scripts/
diff --git a/projects/_template/fix-workflow.md 
b/projects/_template/fix-workflow.md
index ec1f447..0a87bb7 100644
--- a/projects/_template/fix-workflow.md
+++ b/projects/_template/fix-workflow.md
@@ -68,7 +68,7 @@ TODO: the project's convention for AI-assisted commits. 
Example:
 
 And the concrete trailer text for this project:
 
-```
+```text
 Generated-by: TODO: model + URL to the project's Gen-AI disclosure anchor
 ```
 
diff --git a/tools/github/status-rollup.md b/tools/github/status-rollup.md
index 0d28b8f..1ea00d2 100644
--- a/tools/github/status-rollup.md
+++ b/tools/github/status-rollup.md
@@ -193,7 +193,7 @@ let them pick which one to keep.
 Construct the new body by concatenating the old body + a ruler + the
 new entry, with exactly one blank line on each side of the ruler:
 
-```
+```text
 <old body>
 
 ---
@@ -229,7 +229,7 @@ arbitrary comment, and the `--input` flag is needed because
 Only if Step 1 returned no existing rollup. Prepend the marker line
 and emit the new entry as the rollup's first entry:
 
-```
+```markdown
 <!-- airflow-s status rollup v1 — all bot-authored status updates fold into 
this single comment. -->
 <new entry>
 ```
@@ -292,7 +292,7 @@ For each foldable legacy comment, in chronological order:
 1. **Reconstruct the entry shape.** Take the legacy body and wrap it
    in the rollup's `<details>` envelope:
 
-   ```
+   ```html
    <details><summary><createdAt date> · @<author.login> · <Action></summary>
 
    <legacy body — verbatim, left-trimmed>
diff --git a/tools/gmail/draft-backends.md b/tools/gmail/draft-backends.md
index ff64002..92fffe3 100644
--- a/tools/gmail/draft-backends.md
+++ b/tools/gmail/draft-backends.md
@@ -142,7 +142,7 @@ The detection rule depends on which backend created the 
prior draft:
   (see the *Known issue* section below). Detect them by reading the
   thread directly:
 
-  ```
+  ```text
   mcp__claude_ai_Gmail__get_thread(threadId: "<inbound-thread-id>", 
messageFormat: MINIMAL)
   ```
 
diff --git a/tools/gmail/operations.md b/tools/gmail/operations.md
index c45a735..0d75e26 100644
--- a/tools/gmail/operations.md
+++ b/tools/gmail/operations.md
@@ -44,7 +44,7 @@ Every skill that talks to Gmail does a one-call pre-flight in 
Step 0
 to confirm the MCP is reachable and the user's account subscribes to
 the project's security list:
 
-```
+```text
 mcp__claude_ai_Gmail__search_threads(
   query='list:<security-list-domain>',
   pageSize=1,
@@ -65,7 +65,7 @@ fix the setup rather than guessing.
 
 ### Search threads
 
-```
+```text
 mcp__claude_ai_Gmail__search_threads(
   query='<gmail search expression>',
   pageSize=<N>,
@@ -82,7 +82,7 @@ the skills use, see [`search-queries.md`](search-queries.md).
 
 ### Get thread
 
-```
+```text
 mcp__claude_ai_Gmail__get_thread(
   threadId='<threadId>',
   messageFormat='FULL_CONTENT',   # or 'METADATA' when bodies are not needed
@@ -119,7 +119,7 @@ created via this backend always start a new conversation on 
the
 subject + `In-Reply-To` / `References` matching, which usually works
 but is not guaranteed.
 
-```
+```text
 mcp__claude_ai_Gmail__create_draft(
   subject='Re: <root subject of the inbound message>',
   to=['<primary>'],
@@ -184,7 +184,7 @@ For the ASF-security-relay special case (different `to` /
 
 ### List drafts
 
-```
+```text
 mcp__claude_ai_Gmail__list_drafts(
   query='<optional filter>',    # e.g. 'list:<security-list-domain>'
 )
diff --git a/tools/gmail/ponymail-archive.md b/tools/gmail/ponymail-archive.md
index 0fbd9b2..b9edbd5 100644
--- a/tools/gmail/ponymail-archive.md
+++ b/tools/gmail/ponymail-archive.md
@@ -51,7 +51,7 @@ Placeholder convention:
 
 ### Archive search (query returns a list-page with matching threads)
 
-```
+```text
 https://lists.apache.org/list?<list>:YYYY-M:<url-encoded search>
 ```
 
@@ -64,13 +64,13 @@ https://lists.apache.org/list?<list>:YYYY-M:<url-encoded 
search>
 Alternative bare URL form used by the sync skill when scanning the
 public archive for a CVE ID:
 
-```
+```text
 https://lists.apache.org/list.html?<list>:YYYY:<CVE-ID>
 ```
 
 ### Archive API (JSON response, the sync skill uses this first)
 
-```
+```text
 
https://lists.apache.org/api/thread.lua?list=<list-local>&domain=<list-domain>&q=<search>
 ```
 
@@ -83,7 +83,7 @@ public lists.
 
 ### Resolved thread URL (what the skill records in the tracker)
 
-```
+```text
 https://lists.apache.org/thread/<hash>?<list>
 ```
 
@@ -105,7 +105,7 @@ the archive URL programmatically. Instead, the skill 
**constructs**
 the search URL for the month the message was received and proposes
 it to the user at Step 5 as a one-click lookup:
 
-```
+```text
 https://lists.apache.org/list?<security-list>:YYYY-M:<url-encoded subject>
 ```
 
diff --git a/tools/ponymail/operations.md b/tools/ponymail/operations.md
index 62176d9..9afac56 100644
--- a/tools/ponymail/operations.md
+++ b/tools/ponymail/operations.md
@@ -60,7 +60,7 @@ Every skill that talks to PonyMail MCP does a one-call 
pre-flight
 in Step 0 to verify the session is authenticated before relying on
 private-list queries:
 
-```
+```text
 mcp__ponymail__auth_status()
 ```
 
@@ -79,7 +79,7 @@ auth tools:
 
 ### Login
 
-```
+```text
 mcp__ponymail__login()
 ```
 
@@ -90,7 +90,7 @@ Code session pick up the cached cookie automatically.
 
 ### Auth status
 
-```
+```text
 mcp__ponymail__auth_status()
 ```
 
@@ -101,7 +101,7 @@ handled by the [Error handling](#error-handling) section 
below.
 
 ### Logout
 
-```
+```text
 mcp__ponymail__logout()
 ```
 
@@ -113,7 +113,7 @@ logout on their own — it is a user-driven lifecycle step.
 
 ### List lists
 
-```
+```text
 mcp__ponymail__list_lists()
 ```
 
@@ -133,7 +133,7 @@ the MCP itself, so repeat invocations are fast.
 
 ### Search a list
 
-```
+```text
 mcp__ponymail__search_list(
   list: "<list>",
   domain: "<domain>",
@@ -180,7 +180,7 @@ tid) — not full bodies. Fetch the body via
 
 ### Get a thread
 
-```
+```text
 mcp__ponymail__get_thread(
   list: "<list>",
   domain: "<domain>",
@@ -200,7 +200,7 @@ conversation.
 
 ### Get an email
 
-```
+```text
 mcp__ponymail__get_email(
   id: "<mid or Message-ID header value>"
 )
@@ -216,7 +216,7 @@ reference) and want its full body.
 
 ### Get an mbox dump
 
-```
+```text
 mcp__ponymail__get_mbox(
   list: "<list>",
   domain: "<domain>",
@@ -245,7 +245,7 @@ Until then, common recipes:
 
 ### Find the advisory archive thread on `users@<project>.apache.org`
 
-```
+```text
 mcp__ponymail__search_list(
   list: "users",
   domain: "<project>.apache.org",
@@ -262,7 +262,7 @@ for the tracker's *Public advisory URL* body field.
 
 ### Pull the original report thread on `security@<project>.apache.org`
 
-```
+```text
 mcp__ponymail__search_list(
   list: "security",
   domain: "<project>.apache.org",
@@ -277,7 +277,7 @@ string — same heuristic as the Gmail equivalent in
 
 ### Find the `[RESULT][VOTE]` thread for a release
 
-```
+```text
 mcp__ponymail__search_list(
   list: "dev",
   domain: "<project>.apache.org",
diff --git a/tools/ponymail/tool.md b/tools/ponymail/tool.md
index 42893ab..d28ec4d 100644
--- a/tools/ponymail/tool.md
+++ b/tools/ponymail/tool.md
@@ -152,7 +152,7 @@ is picked up and its tools appear in the deferred-tool list.
 
 In a Claude Code session, run:
 
-```
+```text
 mcp__ponymail__login()
 ```
 
@@ -164,7 +164,7 @@ Code sessions until the cookie expires.
 
 Verify:
 
-```
+```text
 mcp__ponymail__auth_status()
 ```
 
@@ -177,7 +177,7 @@ lists but returns empty results for private-list queries.
 Pull the list overview to confirm the session sees the expected
 lists:
 
-```
+```text
 mcp__ponymail__list_lists()
 ```
 
diff --git a/tools/vulnogram/allocation.md b/tools/vulnogram/allocation.md
index 4004a64..846a3a7 100644
--- a/tools/vulnogram/allocation.md
+++ b/tools/vulnogram/allocation.md
@@ -29,7 +29,7 @@ ID) lives in
 
 ## Allocation URL
 
-```
+```text
 https://cveprocess.apache.org/allocatecve
 ```
 


Reply via email to