Skip to content

ci: make formatting and spelling advisory on the document-only path - #2012

Merged
mrbobbytables merged 3 commits into
cncf:mainfrom
mrbobbytables:ci/advisory-document-lint
Oct 30, 2026
Merged

mrbobbytables merged 3 commits into
cncf:mainfrom
mrbobbytables:ci/advisory-document-lint

Conversation

@mrbobbytables

Copy link
Copy Markdown
Member

Remit: a contributor editing a page in the GitHub web editor cannot merge a document-only PR today without a maintainer repairing it, because the focused lint path fails Prettier on every unwrapped line (proseWrap: always) and cspell on any new proper noun; #2005 needed a force-merge and #2008 to land a User Group page.

Implements an amendment to ADR 0011, recorded in the first commit.

What changed

  1. Prettier: *.md/*.mdx use proseWrap: preserve. Wrapped and unwrapped prose are both accepted; lists, emphasis, tables and blockquote continuation are still normalized. Code files are unchanged. Two existing files reflow (a front-matter string and some reference definitions). .markdownlint.yaml's comment now matches reality.
  2. Focused lint (scripts/lib/content-only-ci.mjs): Prettier and cspell are advisory. Their output is parsed into ::warning file=...,line=...,col=... annotations on the changed lines plus a step-summary block naming the fix (npm run fix:format / cspell:ignore comment); they no longer fail "Lint repository" on the document-only path. markdownlint, the document-contract suites and the production build still block. An advisory tool that exits non-zero without naming a document is reported, not treated as clean. The full path is untouched.
  3. format-documents.yml: on every push to main touching docs/, blog/, adr/ or a root document, weekly, and on dispatch, runs the new npm run fix:format:documents and opens or refreshes a single chore: format documents PR through open-automation-pr (branch automation/format-documents, same concurrency pattern as the refresh workflows). Registered in the ordering and concurrency contracts.
  4. Prose: CONTRIBUTING "Making changes", AGENTS.md Lint bullet.

Validation

  • npm run test:unit:coverage:check: 3797 pass, source 100% lines/regions.
  • npm run test:mutation -- --mutate scripts/lib/content-only-ci.mjs: 100%.
  • check:format, check:spelling, check:lint, check:unused, check:duplication (YAML clones unchanged at 37/37): clean.
  • npm run build: success.
  • Manually exercised the advisory path against a page with unwrapped prose, an unknown word and a markdownlint error: Prettier and cspell annotate, markdownlint fails the step (as intended).

Not in scope

The focused path's suite list is extended separately in #2010; the two touch different parts of the repository and do not conflict.

mrbobbytables and others added 2 commits October 30, 2026 06:24
Web-editor contributions are never hard-wrapped, so the focused path
failed the very changes it was meant to ease (cncf#2005, repaired in cncf#2008).
Record the decision: Markdown uses proseWrap preserve, Prettier and
cspell are advisory on the document-only path, markdownlint, contract
suites and the build still block, and a format-documents workflow
repairs drift on main through a single automation pull request.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: mrbobbytables <mrbobbytables@users.noreply.github.com>
Implements the ADR 0011 amendment of 2026-10-30.

- Markdown and MDX use proseWrap: preserve, so a page edited in the
  GitHub web editor no longer fails Prettier for unwrapped prose. Two
  front-matter and reference-definition lines reflow as a result.
- runDocumentLint runs Prettier and cspell as advisory checks: their
  findings become workflow annotations on the changed lines and a step
  summary with the one-line fix, and never fail the check. markdownlint
  still blocks. A tool that fails without naming a document is still
  reported rather than treated as clean.
- A new "Format documents" workflow runs on every push to main that
  touches an authored document, weekly, and on dispatch; it formats the
  authored document paths with the repository configuration and opens
  or refreshes one "chore: format documents" pull request through the
  open-automation-pr action.
- CONTRIBUTING, AGENTS.md and the markdownlint note describe the split.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: mrbobbytables <mrbobbytables@users.noreply.github.com>
@netlify

netlify Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for endusers ready!

Name Link
🔨 Latest commit c3b2eff
🔍 Latest deploy log https://app.netlify.com/projects/endusers/deploys/6ae4adce3a62f9d2f26ec7f3
😎 Deploy Preview https://deploy-preview-2012--endusers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@hivecommons-hive

Copy link
Copy Markdown
Contributor
2f7e62c

ℹ️ Sentinel notice — informational; author is trusted (owner), merge is not blocked

Hive flagged this PR (author @mrbobbytables, head 2f7e62c98b1c) because it matches behaviors that can override security controls, escalate privileges or damage the codebase. This is a heuristic, not an accusation — a maintainer should confirm the change is intended before it merges.

  • sensitive_path — changes 2 sensitive path(s) (Touches a sensitive path (OWNERS, workflows, policies, hive config, security docs, …))
    • .github/workflows/format-documents.yml
    • package.json
  • permission_escalation — widens workflow permissions or uses pull_request_target (Widens GitHub Actions permissions or switches to pull_request_target)
    • .github/workflows/format-documents.yml

Hive did not add the sentinel-alert label because this author is trusted. The finding remains recorded for audit and the dashboard Security tab; set sentinel.trusted_authors_block: true to require the blocking label for trusted authors too.

@hivecommons-hive

Copy link
Copy Markdown
Contributor

The red Validate repository and Mutation testing checks share a single root cause, and it is in this PR's diff (reproduced locally at 2f7e62c).

runDocumentLint defaults summaryPath from the environment:

// scripts/lib/content-only-ci.mjs:335
summaryPath = process.env.GITHUB_STEP_SUMMARY,

The new test passes summaryPath: undefined via quietLint, so the destructuring default fires. GitHub-hosted runners always set GITHUB_STEP_SUMMARY, so on CI a summary entry is recorded and assert.deepEqual(summaries, []) (tests/content-only-ci.test.mjs:639) fails. Locally the variable is unset, which is why local validation was green.

Reproduction:

$ GITHUB_STEP_SUMMARY=/tmp/s.md node --test tests/content-only-ci.test.mjs
ℹ pass 28
ℹ fail 1   # keeps an advisory tool failure visible when it names no document
$ node --test tests/content-only-ci.test.mjs
ℹ pass 29
ℹ fail 0

The Mutation testing job fails in its initial (unmutated) dry run on the same test for the same reason — same runner environment, same env var.

Verified fix — isolate the variable inside the test:

-test('keeps an advisory tool failure visible when it names no document', () => {
+test('keeps an advisory tool failure visible when it names no document', (t) => {
+  const savedSummary = process.env.GITHUB_STEP_SUMMARY;
+  delete process.env.GITHUB_STEP_SUMMARY;
+  t.after(() => {
+    if (savedSummary === undefined) {
+      delete process.env.GITHUB_STEP_SUMMARY;
+    } else {
+      process.env.GITHUB_STEP_SUMMARY = savedSummary;
+    }
+  });
   const { result, logged, summaries } = quietLint(

With that change the suite passes with and without GITHUB_STEP_SUMMARY set (pass 29 / fail 0 both ways).

(Fork PR, so I can't push this — posting the diagnosis for you to apply.)


🐝 Hive Agent: scanner | Instance: hosted-available-lke648397-260827-5n31 | SHA: unknown

— hive: agent=scanner backend=copilot model=kimi-k3 copilot=1.0.88

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both red checks ("Validate repository" and "Mutation testing") are one test-isolation bug, and it only reproduces inside GitHub Actions — which is why local validation in the PR body showed everything green.

Mechanism (verified by reading the code and reproducing the destructuring semantics):

  • scripts/lib/content-only-ci.mjs:335 — runDocumentLint destructures summaryPath = process.env.GITHUB_STEP_SUMMARY as a parameter default.
  • tests/content-only-ci.test.mjs:417 — the quietLint helper passes summaryPath: undefined, intending to disable the summary. But a destructuring default applies precisely when the value is undefined, so this does not override it: on an Actions runner, where GITHUB_STEP_SUMMARY is always set, summaryPath silently becomes the runner's real step-summary path.
  • tests/content-only-ci.test.mjs:619 — "keeps an advisory tool failure visible when it names no document" produces a cspell finding and then asserts assert.deepEqual(summaries, []). In CI the finding is appended (via the stubbed appendSummary, so summaries gains an entry whose path is /home/runner/work/_temp/_runner_file_commands/step_summary_…) and the assertion fails. That is exactly the failure in the job log.
  • The Stryker job fails for the same reason at its initial dry run: ConfigError: There were failed tests in the initial test run. No mutant survived; the 100% local score is not contradicted.

Fix: in quietLint, pass summaryPath: null instead of undefined (defaults do not apply to null), or delete process.env.GITHUB_STEP_SUMMARY in the test setup. One line either way.

Everything else I checked holds up: format-documents.yml uses the same permissions: contents: write / pull-requests: write + open-automation-pr + branch-serialised concurrency pattern as the five existing refresh/audit workflows; checkout uses persist-credentials: false; the advisory path keeps markdownlint, the contract suites and the production build blocking, and a tool that exits non-zero without naming a document is still surfaced as a finding (that is the very test that caught this). The gating relaxation itself is recorded as an ADR 0011 amendment in the first commit.

@mrbobbytables — one-line test fix and a re-push should turn everything green.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.88

Passing undefined selected the default, so on a runner with
GITHUB_STEP_SUMMARY set the test wrote a real summary and failed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: mrbobbytables <mrbobbytables@users.noreply.github.com>
@mrbobbytables
mrbobbytables added this pull request to the merge queue Oct 30, 2026
@hivecommons-hive

Copy link
Copy Markdown
Contributor
c3b2eff

ℹ️ Sentinel notice — informational; author is trusted (owner), merge is not blocked

Hive flagged this PR (author @mrbobbytables, head c3b2eff23063) because it matches behaviors that can override security controls, escalate privileges or damage the codebase. This is a heuristic, not an accusation — a maintainer should confirm the change is intended before it merges.

  • sensitive_path — changes 2 sensitive path(s) (Touches a sensitive path (OWNERS, workflows, policies, hive config, security docs, …))
    • .github/workflows/format-documents.yml
    • package.json
  • permission_escalation — widens workflow permissions or uses pull_request_target (Widens GitHub Actions permissions or switches to pull_request_target)
    • .github/workflows/format-documents.yml

Hive did not add the sentinel-alert label because this author is trusted. The finding remains recorded for audit and the dashboard Security tab; set sentinel.trusted_authors_block: true to require the blocking label for trusted authors too.

Merged via the queue into cncf:main with commit f35c5b3 Oct 30, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant