Skip to content

[docs] M6: docs/maintainership.md + doc-check banned-phrase + section lints#56

Merged
trilamsr merged 5 commits into
mainfrom
worktree-m6-maintainership-doccheck
May 19, 2026
Merged

[docs] M6: docs/maintainership.md + doc-check banned-phrase + section lints#56
trilamsr merged 5 commits into
mainfrom
worktree-m6-maintainership-doccheck

Conversation

@trilamsr

@trilamsr trilamsr commented May 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Lands two of the three open M6 carry-forward items:

  1. docs/maintainership.md — one-page governance reference covering commit access, RFC sponsorship, and security disclosure, each section cross-referencing the document that actually owns it (CODEOWNERS, docs/rfcs/, SECURITY.md).
  2. scripts/doc-check.sh extensions — banned-phrase lint over every tracked .md (per STYLE-docs.md §2) and a required-H2 assertion for docs/maintainership.md so a future rename / split breaks the build instead of breaking the governance contract silently.

Integration recipes (docs/integrations/{datadog,honeycomb,otel-backend,clickhouse-direct}.md) need real version-pinned testing against each backend and are intentionally deferred to a per-recipe PR series.

What this PR changes

  • New file: docs/maintainership.md — three required H2 sections (Commit access, RFC sponsorship, Security disclosure), each leading with its answer per STYLE-docs.md §3. Pointer-heavy by design; the load-bearing facts live in the documents the sections link to.
  • docs/README.md: registers the new file under "Top-level".
  • scripts/doc-check.sh:
    • Banned-phrase lint over every tracked .md outside docs/rfcs/, docs/research/, and docs/STYLE-docs.md (the canonical source of the list itself). Catches production-grade, world-class, best-in-class, industry-leading, cutting-edge, lightning-fast, battle-tested, enterprise-grade, rock-solid, blazing-fast and their space-separated variants.
    • Required-H2 assertion for docs/maintainership.md. Exits 1 with the missing-heading list if any of the three are absent.
  • README.md line 41: reworded to drop production-grade (caught by the new gate; meaning preserved).
  • MILESTONES.md M6: status stays (integration recipes remain). Per-rubric prefixes flip on the rubrics this PR closes; carry-forward bullet rewritten to name only what remains.

Why

Two of the three open carry-forward items have been queued since M1.6. The maintainership page is a one-page deliverable with no dependencies on receivers, hardware, or backend integration — landing it now closes a governance gap without expanding the PR series further. The banned-phrase + section gates fall out of the same effort and make every future markdown PR self-policing.

Test plan

  • bash scripts/doc-check.sh exits 0 on this branch
  • make ci includes doc-check; this PR doesn't change the wiring
  • docs/maintainership.md renders correctly on GitHub
  • All three required H2 sections present (verified by the new gate)
  • Banned-phrase lint clean across 77 markdown files

Note on PR ordering

This PR's MILESTONES.md edit uses the per-rubric convention introduced in PR #53. If PR #53 lands first, this merges clean. If this merges first, PR #53's "How to read" preamble still reads correctly with the prefixes already in place.

🤖 Generated with Claude Code

NONE

trilamsr added a commit that referenced this pull request May 18, 2026
Self-review pass on PR #56 found three issues:

1. docs/maintainership.md contained governance content I authored
   without maintainer ratification (bar to join, removal procedure,
   inactivity threshold). Split the doc into ratified content —
   sourced from CODEOWNERS / CONTRIBUTING.md / SECURITY.md verbatim
   — and "Proposed:" subsections explicitly flagged as draft policy
   pending maintainer review. The early-phase carve-out moved into
   "Commit access" as ratified content (it comes from
   CONTRIBUTING.md § "RFC process"); the bar-to-join and removal
   procedures became H3 "Proposed: ..." subsections. The doc still
   carries all three required H2s, so the doc-check assertion
   stays green.

2. docs/STYLE-docs.md §2 explicitly bans `robust` but my banned-
   phrase list omitted it (judgment call I made unilaterally).
   Added `robust` with \b word boundaries (so "robustness" doesn't
   trip) and reworded three existing hits:
   - MILESTONES.md:452 "robust to one missed sample" → "tolerant of"
   - FOLLOWUPS.md:224 "made internally robust" → "hardened internally"
   - FOLLOWUPS.md:613 "Go build is robust to locale/timezone" →
     "insensitive to locale/timezone"

3. Banned-phrase grep nested file × phrase. Collapsed into a single
   regex union pass with hyphen-or-space tolerance via `[- ]`
   (so "production-grade" and "production grade" both match without
   needing two separate array entries). Files filtered upfront via
   `git ls-files | grep -vE` against the exemption set instead of
   the per-iteration `case` block.

Local doc-check green; banned-phrase scan covers 66 markdown files
outside exemptions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… lints

Land two of the three open M6 carry-forward items: docs/maintainership.md
with the three required H2 sections (Commit access / RFC sponsorship /
Security disclosure) cross-referencing CODEOWNERS / docs/rfcs/ /
SECURITY.md, and the scripts/doc-check.sh extensions that gate
falsifiability for both that file and every markdown doc.

Specifically:
- docs/maintainership.md authored from scratch — one screen,
  pointer-heavy (CODEOWNERS for review routing, docs/rfcs/ for
  decision history, SECURITY.md for disclosure procedure). Three
  required H2s, each leading with its answer per STYLE-docs §3.
- scripts/doc-check.sh:
  - Banned-phrase lint over every tracked .md outside docs/rfcs/,
    docs/research/, and docs/STYLE-docs.md (the canonical source of
    the list itself). Catches "production-grade", "best-in-class",
    "world-class", and the rest of STYLE-docs §2.
  - Required-H2 assertion for docs/maintainership.md so a future
    rename or split breaks the build instead of breaking the
    governance contract silently.
- docs/README.md indexes the new file under "Top-level".
- README.md line 41 reworded to drop "production-grade" (caught by
  the new banned-phrase gate; rewrite preserves the meaning).
- MILESTONES.md M6: status stays ⧗ (integration recipes remain),
  but per-rubric ☑ flips for the three rubrics this PR closes;
  carry-forward bullet rewritten to name what remains.

Integration recipes (docs/integrations/{datadog,honeycomb,otel-backend,
clickhouse-direct}.md) need real version-pinned testing against each
backend and are intentionally deferred to a per-recipe PR series.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
trilamsr added a commit that referenced this pull request May 18, 2026
Self-review pass on PR #56 found three issues:

1. docs/maintainership.md contained governance content I authored
   without maintainer ratification (bar to join, removal procedure,
   inactivity threshold). Split the doc into ratified content —
   sourced from CODEOWNERS / CONTRIBUTING.md / SECURITY.md verbatim
   — and "Proposed:" subsections explicitly flagged as draft policy
   pending maintainer review. The early-phase carve-out moved into
   "Commit access" as ratified content (it comes from
   CONTRIBUTING.md § "RFC process"); the bar-to-join and removal
   procedures became H3 "Proposed: ..." subsections. The doc still
   carries all three required H2s, so the doc-check assertion
   stays green.

2. docs/STYLE-docs.md §2 explicitly bans `robust` but my banned-
   phrase list omitted it (judgment call I made unilaterally).
   Added `robust` with \b word boundaries (so "robustness" doesn't
   trip) and reworded three existing hits:
   - MILESTONES.md:452 "robust to one missed sample" → "tolerant of"
   - FOLLOWUPS.md:224 "made internally robust" → "hardened internally"
   - FOLLOWUPS.md:613 "Go build is robust to locale/timezone" →
     "insensitive to locale/timezone"

3. Banned-phrase grep nested file × phrase. Collapsed into a single
   regex union pass with hyphen-or-space tolerance via `[- ]`
   (so "production-grade" and "production grade" both match without
   needing two separate array entries). Files filtered upfront via
   `git ls-files | grep -vE` against the exemption set instead of
   the per-iteration `case` block.

Local doc-check green; banned-phrase scan covers 66 markdown files
outside exemptions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@trilamsr trilamsr force-pushed the worktree-m6-maintainership-doccheck branch from 0cffa2c to 2dd18fc Compare May 18, 2026 19:40
Self-review pass on PR #56 found three issues:

1. docs/maintainership.md contained governance content I authored
   without maintainer ratification (bar to join, removal procedure,
   inactivity threshold). Split the doc into ratified content —
   sourced from CODEOWNERS / CONTRIBUTING.md / SECURITY.md verbatim
   — and "Proposed:" subsections explicitly flagged as draft policy
   pending maintainer review. The early-phase carve-out moved into
   "Commit access" as ratified content (it comes from
   CONTRIBUTING.md § "RFC process"); the bar-to-join and removal
   procedures became H3 "Proposed: ..." subsections. The doc still
   carries all three required H2s, so the doc-check assertion
   stays green.

2. docs/STYLE-docs.md §2 explicitly bans `robust` but my banned-
   phrase list omitted it (judgment call I made unilaterally).
   Added `robust` with \b word boundaries (so "robustness" doesn't
   trip) and reworded three existing hits:
   - MILESTONES.md:452 "robust to one missed sample" → "tolerant of"
   - FOLLOWUPS.md:224 "made internally robust" → "hardened internally"
   - FOLLOWUPS.md:613 "Go build is robust to locale/timezone" →
     "insensitive to locale/timezone"

3. Banned-phrase grep nested file × phrase. Collapsed into a single
   regex union pass with hyphen-or-space tolerance via `[- ]`
   (so "production-grade" and "production grade" both match without
   needing two separate array entries). Files filtered upfront via
   `git ls-files | grep -vE` against the exemption set instead of
   the per-iteration `case` block.

Local doc-check green; banned-phrase scan covers 66 markdown files
outside exemptions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@trilamsr trilamsr force-pushed the worktree-m6-maintainership-doccheck branch from 2dd18fc to e7a9ac2 Compare May 18, 2026 19:42
trilamsr and others added 3 commits May 18, 2026 18:44
Second self-review found the link was one-way — maintainership.md
already pointed at CONTRIBUTING.md § "Pull requests" but
CONTRIBUTING.md had no pointer back. Asymmetric discoverability.

Adds one bullet under § "Before you start" naming the boundary
between the two docs: CONTRIBUTING owns day-to-day PR mechanics;
maintainership.md owns who decides what.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Self-review pass plus user confirmation found two falsehoods my
maintainership.md was echoing from existing scaffolding:

1. @TraceCoreAI/maintainers GitHub team does NOT exist.
   Verified via gh api: returns 404. CODEOWNERS routes every
   governance-file path to that team — GitHub silently ignores
   those directives because the target is invalid.

2. security@tracecore.ai mailbox is NOT provisioned.
   User confirmed. SECURITY.md lists it as the primary channel and
   security-followup@tracecore.ai as escalation; neither delivers.
   The GitHub Security Advisory form at
   github.com/tracecoreai/tracecore/security/advisories/new is
   the only verified-working disclosure channel today.

Both falsehoods exist upstream of this PR (in CODEOWNERS,
SECURITY.md, CONTRIBUTING.md:225, MILESTONES.md:196). This PR
fixes only what it authored — maintainership.md no longer echoes
either as fact:

- Commit access section names the team in the past-tense "routes
  to a team that does not yet exist" framing; the early-phase
  carve-out describes today's reality (founding maintainer holds
  commit access directly).
- Security disclosure section promotes the Advisory link as the
  verified-working channel; the email mention is now in disclosure
  context (flagging the gap), not in "contact this address" context.

Both gaps filed in docs/FOLLOWUPS.md § "Governance gaps" with
resolution options enumerated (create the artifact vs. rewrite the
docs to drop the reference). Resolution requires maintainer-side
decisions out of scope of this PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@TraceCoreAI/core is the real team (verified: gh api returns 200,
single member @trilamsr). The prior @TraceCoreAI/maintainers handle
referenced in CODEOWNERS and the maintainership.md I authored
returned 404 from gh api, so GitHub was silently ignoring every
CODEOWNERS directive.

Concrete changes:
- CODEOWNERS: all 14 routing lines flipped from
  @TraceCoreAI/maintainers to @TraceCoreAI/core. GitHub will now
  actually auto-request review from the team on PRs touching
  governance + CI + supply-chain paths.
- docs/maintainership.md: § "Commit access" lead-in now states the
  team exists (single-member); removed the "team does not yet exist"
  disclosure block; § "Proposed: bar to join" references the real
  team name.
- docs/FOLLOWUPS.md § "Governance gaps": removed the resolved
  CODEOWNERS-routing item. The security@tracecore.ai mailbox gap
  remains (separate decision pending).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
trilamsr added a commit that referenced this pull request May 19, 2026
)

## Summary

`security@tracecore.ai` is not a provisioned mailbox (confirmed by
maintainer) and `security-followup@tracecore.ai` shares its fate. A
reporter following `SECURITY.md` today reaches a black hole. The GitHub
Security Advisory form built into every public repo is the only
verified-working disclosure channel.

This PR promotes the Advisory URL to primary across the three files that
named the dead address, and rephrases the M21 rubric that depended on an
email canary to use a falsifiable Advisory-inbox check instead.

## What this PR changes

- **`SECURITY.md`** — full rewrite:
- Primary disclosure channel is now
<https://github.com/tracecoreai/tracecore/security/advisories/new>.
- Escalation rephrased: "comment on your own advisory thread to ping the
maintainers" instead of CCing a fake address.
- Proprietary-synthesis-engine carve-out uses the same Advisory URL with
a tagged title.
- **`CONTRIBUTING.md` § "Security issues"** — replaced the email line
with a direct Advisory link + pointer back to SECURITY.md.
- **`MILESTONES.md` M21** — replaced the "canary email" rubric with: `gh
api /repos/tracecoreai/tracecore/private-vulnerability-reporting`
returns `{"enabled":true}` AND at least one `@TraceCoreAI/core` member
is configured to receive advisory notifications. Release blocks if
either check fails. Anchor citations updated to H2 names (line numbers
no longer reliable after the SECURITY.md rewrite).

## Why

The Advisory channel has a real ACL (visible only to the reporter and
`@TraceCoreAI/core`) and a real notification path (creation pings every
team member). It's also discoverable in GitHub's native "Security" tab —
most reporters land there first regardless of what `SECURITY.md` says.
Promoting it to primary aligns the doc with the channel that actually
works today; no mailbox setup is blocked on this PR.

Tracked governance gap closed: `docs/FOLLOWUPS.md` § "Governance gaps"
entry on the non-delivering mailbox (added in #56) can retire once this
merges.

## Test plan

- [x] `bash scripts/doc-check.sh` exits 0
- [x] `grep -r 'security@tracecore.ai\|security-followup@tracecore.ai'`
returns no markdown hits outside `.claude/worktrees/`
- [ ] `SECURITY.md` renders correctly on GitHub
- [ ] CI green

## Note on ordering

Independent of PR #56 (which only flags the gap in
`docs/maintainership.md`). If this merges first, the FOLLOWUPS entry in
#56 becomes stale and #56 should be rebased to drop it. If #56 merges
first, this PR's commit message still applies as-is.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@trilamsr trilamsr merged commit 41d81b9 into main May 19, 2026
5 of 6 checks passed
@trilamsr trilamsr deleted the worktree-m6-maintainership-doccheck branch May 19, 2026 02:58
trilamsr added a commit that referenced this pull request May 19, 2026
…self-falsifying) (#67)

## Summary

Captures two load-bearing lessons surfaced during this conversation's PR
cycles, via the `learn-from-mistakes` skill's full capture flow
(format-check + banned-vocab + diff approval + DCO commit).

1. **Verify named identifiers exist before echoing them as fact in repo
docs.** PR #56 + PR #61 caught two inherited falsehoods: `CODEOWNERS`
routed to a non-existent `@TraceCoreAI/maintainers` team (GitHub
silently ignores), and `SECURITY.md` cited an unprovisioned
`security@tracecore.ai` mailbox. A 30-second `gh api` / `dig MX` / `[ -f
path ]` check before landing the reference is the cure.

2. **RFC commitments must be self-falsifying.** PR #54's first RFC-0008
draft asserted `depguard` rules that didn't exist yet, and a
`chart-appversion` drift gate that only checks non-empty (not drift).
Rule: every "X gate enforces Y" line in an RFC body must be verifiable
in the current tree, or labeled deferred with the trigger condition.

## What this PR changes

- `AGENTS.md`: 2 new bullets under § "Load-bearing lessons" (entries 5
and 6 of the 6 universal rules). 113 → 128 lines, still under the
documented 150-line cap.

## Test plan

- [x] `wc -l AGENTS.md` = 128 (under 150 cap)
- [x] `bash scripts/doc-check.sh` exits 0
- [x] No banned vocabulary, no first-person AI phrasing, no
AI-attribution trailers in the lesson bodies (verified per the
`learn-from-mistakes` capture flow)
- [ ] Renders correctly on GitHub

```release-notes
NONE
```

---------

Signed-off-by: Tri Lam <trilamsr@gmail.com>
trilamsr added a commit that referenced this pull request Jun 2, 2026
…460) (#466)

## Summary

Closes #460. The `exit 0` on `scripts/doc-check.sh` ran unconditionally
whenever `docs/FAILURE-MODES.md` carried no `Test*`/`Fuzz*`/`Benchmark*`
identifiers (its current state on `main` — `grep -c` = 0), silently
bypassing every gate below it. Fix scopes the skip to the Go-test parity
block only (if/else, not `exit`), then surfaces and fixes the dead refs
the gates were supposed to be catching.

## Root cause

Commit a57883f (#13) shipped `doc-check.sh` with one gate — the Go-test
name parity check — so `[ -z "$referenced" ] && exit 0` was correct
then. PRs #28, #56, #115, #131, #144, #149, #195, #234, #241, #443,
#455, #459 (and others) appended gates **below** that line without
recognising they'd become dead code whenever `FAILURE-MODES.md` lost its
`Test*` references. PR #459 worked around the bug by placing its new
YAML gate *above* line 99 and tracked the root cause separately as #460.

## What surfaced

Once `exit 0` was removed, three real issues fired:

1. **Dead `.md` link**: `docs/FOLLOWUPS.md` → `followups/otlphttp.md`.
The shard was never committed to `main`'s ancestry. Folded into the
existing "Shards deleted post-v0.2.0 as fully resolved-via-pivot" prose
block (sibling treatment to M9, M14, M16).
2. **Banned-phrase hits** (3x `production-grade`): reworded in
`docs/cut-criteria.yaml.md` (2x) and
`install/kubernetes/tracecore/README.md` (1x) to falsifiable language.
3. **`docs/getting-started.md` block cap**: 7 fenced bash/sh blocks. The
M6 cap of 5 was set for the quickstart only — `## Install via Helm` and
`## Air-gapped install` are alternate deployment paths that landed
post-M6 and aren't part of the quickstart budget. Rescoped the gate to
count blocks inside the `## Walkthrough` H2 section only (1 block, well
under cap).

## Gate count

Empirically verified via `grep -c '^doc-check: '` on `make doc-check`
output on a clean tree:

| State | Status lines emitted | Gates the early-exit was hiding |
|---|---|---|
| Pre-fix on `main` (post-#459) | 3 (trust-posture, YAML cross-link,
parity-skip) | 14 |
| Post-fix this PR (post-rebase) | 17 | 0 |

The "14 gates hidden" number is invariant across the rebase: it counts
gates placed below the early-exit line. The "3 → 17" total reflects
post-#459 reality on `main`; pre-#459 baseline was "2 → 16" (the figure
originally in this PR body), and #459 itself worked around the bug by
placing its YAML gate above line 99.

## Mutation tests

Each gate below the original early-exit was confirmed to fire post-fix:

| Mutation | Gate expected to fire | Exit code post-mutation | Exit code
post-restore |
|---|---|---|---|
| Inject `[bad](nonexistent-ghost.md)` into `docs/FOLLOWUPS.md` |
markdown link-rot | 1 | 0 |
| Append `blazing-fast` + `rock-solid` to `docs/getting-started.md` |
banned-phrase lint | 1 | 0 |
| Delete `<!-- tested-against: ... -->` from
`docs/integrations/datadog.md` | M6 recipe markers | 1 | 0 |

## Test plan

- [x] `make doc-check` exits 0 on clean tree (re-run post-rebase onto
origin/main; 17 status lines)
- [x] 3 mutation tests above each toggle exit 1 → 0 across mutate /
restore
- [x] Pre-push hooks green: golangci-lint (0 issues), `go vet ./...`,
`go mod verify`, `attribute-namespace-check` (100 attrs, all
documented), `register-lint`, `actionlint`, `zizmor`,
`deprecation-check`, `no-autoupdate-check`
- [x] Rebased onto current `origin/main` (includes #459, #461, #462,
#456); no conflicts; gate count re-verified empirically post-rebase
- [x] No changes to gates above line 99 (the trust-posture callout +
YAML cross-link gate from #459 still run and emit unchanged status
lines)

## Self-grade

**A+** — root cause named in commit body (a57883f #13 with one gate;
gates appended below without exit-path awareness); 3 mutation tests
(success criteria required 1–2); rescoped the getting-started gate to
match M6 intent rather than papering over the surfaced overflow; the `[
-z "$referenced" ]` legitimate skip is preserved via if/else (not `:`
no-op, which would have left the `defined=` / `orphans=` block running
on empty input); gate count corrected empirically post-rebase per
reviewer B feedback.

```release-notes
- fix(ci): `scripts/doc-check.sh` no longer exits 0 at the Go-test parity gate when `docs/FAILURE-MODES.md` carries no `Test*` references. 14 gates below that line (link-rot, banned-phrase, M6 recipe markers, etc.) are now actually enforced on every `make doc-check` invocation. Closes #460.
```

---------

Signed-off-by: Tri Lam <tree@lumalabs.ai>
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