chore: docs/CI governance — fix drift, trim duplication, add guardrails#51
Conversation
- process.md: drop 6 references to removed `unit-tests.slnf`; use full
`dotnet test` on `Axis.sln` consistent with CLAUDE.md Gate 1.
- PR template: rebuild around Summary + Linked spec + Requirements; ticks
now mirror Gates 0-3 ordering with explicit no-new-TODO checkbox.
- agent-checklist: dedupe PR-body guidance; clarify that paste blocks are
for agent walk-through, not the PR description; drop manual TODO grep
from Gate 1 (now enforced by drift script).
- CONTRIBUTING: align gate language with template ("walk locally, tick in
PR"); note bash requirement for drift script on Windows.
- CLAUDE.md: same bash note; remove duplicate TODO grep now that the
drift script enforces it.
- check-doc-drift.sh: scan *added* diff lines for new raw-SQL calls in
module code (cross-module P0 guard) and for new TODO/FIXME/stub
markers; handle renamed handlers, not just added.
- build-and-test.yml: add `concurrency` group to cancel superseded PR
runs; tighten `permissions: contents: read`; add `docker info`
pre-check on the .NET job so Testcontainers failures surface early.
- .gitignore: ignore nCrunch temp project files.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- ARCHITECTURE.md: rewrite as a thin architectural overview that points at owners instead of duplicating them. Drop the SignalR "Real-Time Updates" section (admitted as not implemented; speculation pretending to be reference), the source-tree dup (now owned by CLAUDE.md), and the version column on the Containers table (now owned by TECH_STACK.md). Net: 150 → 88 lines. - docs/README.md: drop the Roadmap section (Phase 1/2/3 dup of PRODUCT_VISION § MVP Scope). Replace with a "single source of truth per topic" ownership table so every contributor can answer "which doc do I edit?" in one glance. - CONTRIBUTING.md: rebuild as a short first-contributor pointer (branch/commit conventions + Gates link). Removes ~50 lines of duplication with CLAUDE.md and agent-checklist.md. - PRODUCT_VISION.md: drop "Success Metrics" — aspirational numbers nobody is measuring or testing against. - TECH_STACK.md: mark SignalR row as ⏳ not yet wired so the table no longer implies the hub is live. - agent-checklist.md: update Gate 2 "Project structure" pointer from ARCHITECTURE.md to CLAUDE.md § Solution tree (the new owner). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Doctrine without automation rots — every rule here is paired with a CI
or script check.
- CI: add Markdown link check job (lychee, offline mode via lychee.toml).
Catches broken internal links and #anchor drift on every PR. External
http(s) intentionally not blocking — third-party 503s don't belong in
PR CI.
- CI: add Dependabot config for github-actions. Auto-pins `@v2` to SHA
on first run and keeps actions fresh weekly. Canonical alternative to
hand-rolled SHA hunting.
- drift script: speculation guard. Fails if docs/ARCHITECTURE.md
contains phrases that indicate forward-looking content ("Not yet
implemented", "planned design", "Will be wired"). Reference docs
describe what EXISTS; forward-looking belongs in PROGRESS.md or epic
feature files. Smoke-tested with a fixture.
- New playbook: docs/playbooks/docs-style.md. Short anti-pattern
checklist + size budgets + when-to-create-vs-absorb. The doctrine
exists so the CI rules feel justified, not arbitrary.
- CLAUDE.md: remove the mini Tech stack and Modules tables — both were
duplicates of TECH_STACK.md / epics README and a known drift source.
CLAUDE.md now owns *rules*, not catalogs. Add docs-style.md to the
Docs index.
- agent-checklist: note the two CI-only gates (Doc drift, Link check)
so agents don't try to run them locally.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
📝 WalkthroughWalkthroughRepository governance updates: CI concurrency and Markdown link checking (lychee), Dependabot for GitHub Actions, enhanced scripts/check-doc-drift.sh guards (raw-SQL, handler-test, TODO/FIXME/speculation), updated contributor docs and PR template, a docs playbook, architecture clarifications, and small config fixes. ChangesDocumentation Governance and CI Standards
Sequence DiagramsequenceDiagram
participant Developer
participant GitHub as GitHub Actions
participant Lychee as lycheeverse/lychee-action
participant Drift as scripts/check-doc-drift.sh
Developer->>GitHub: open/push PR (triggers workflow)
GitHub->>Lychee: run Markdown link/anchor checks (uses ./lychee.toml)
GitHub->>Drift: run doc-drift script
Lychee-->>GitHub: link/anchor results
Drift-->>GitHub: drift/hygiene results
GitHub->>Developer: CI status (pass/fail)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
docs/TECH_STACK.md (1)
19-19: ⚡ Quick winPrefer current-state wording over future-state promise in the stack table.
This line mixes intended behavior and current implementation status. Consider phrasing it as present-state only (e.g., capability available, no hub registered yet) and keep roadmap intent in epics/PROGRESS.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/TECH_STACK.md` at line 19, Update the SignalR row in the TECH_STACK table to describe only the current state: keep the capability ("Real-time updates") and state that no hub is registered yet (e.g., "capability available; no `*Hub.cs` in `src/`"), removing future-facing promises like "Not yet wired" or roadmap language so the table reflects present implementation status only.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/build-and-test.yml:
- Line 93: Replace the mutable tag for the GitHub Action usage (currently
referenced as lycheeverse/lychee-action@v2) with a pinned full commit SHA;
locate the step that uses "lycheeverse/lychee-action@v2" and change the
reference to "lycheeverse/lychee-action@<full-commit-sha>" (use the action
repository’s latest commit SHA for the v2 release) so the workflow is pinned to
an immutable commit.
In `@docs/ARCHITECTURE.md`:
- Line 26: The Architecture doc's API Server row contains speculative language
("SignalR hub planned for execution push updates"); update the "**API Server**"
table cell to reflect only current state by removing "planned" wording—either
delete the SignalR mention or move it to a parenthetical pointing to the
epic/progress doc (e.g., "SignalR hub for execution push updates — see
epic/progress doc") so the table remains strictly current-state; edit the table
row containing "**API Server**" accordingly.
- Around line 58-62: The fenced code block showing the PostgreSQL schema diagram
lacks a language tag, causing markdownlint MD040 failures; edit the block
containing the lines "PostgreSQL", "├── public schema # organizations,
subscription_plans, users, roles", and "└── tenant_{orgId} schemas #
per-tenant: models, workflows, executions, …" and add an explicit language tag
(e.g., ```text) after the opening backticks so the block becomes ```text ... ```
to satisfy the linter.
---
Nitpick comments:
In `@docs/TECH_STACK.md`:
- Line 19: Update the SignalR row in the TECH_STACK table to describe only the
current state: keep the capability ("Real-time updates") and state that no hub
is registered yet (e.g., "capability available; no `*Hub.cs` in `src/`"),
removing future-facing promises like "Not yet wired" or roadmap language so the
table reflects present implementation status only.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f30a7318-1e77-4aad-837c-6050990a92a7
📒 Files selected for processing (15)
.github/PULL_REQUEST_TEMPLATE.md.github/dependabot.yml.github/workflows/build-and-test.yml.gitignoreCLAUDE.mdCONTRIBUTING.mddocs/ARCHITECTURE.mddocs/PRODUCT_VISION.mddocs/README.mddocs/TECH_STACK.mddocs/playbooks/agent-checklist.mddocs/playbooks/docs-style.mddocs/playbooks/process.mdlychee.tomlscripts/check-doc-drift.sh
💤 Files with no reviewable changes (1)
- docs/PRODUCT_VISION.md
Two pre-existing bugs that the new Markdown link check job exposed on PR #51 — fix in the same PR so the gate lands green. - patterns.md / patterns-index.md: anchor link to `#result-pattern-vs-exceptions----when-to-use-what` (4 dashes) was wrong. GitHub's slugger collapses " — " (space-emdash-space) to two dashes, not four. Correct anchor: `#result-pattern-vs-exceptions--when-to-use-what`. Fixed in 4 spots. - docs/epics/E07-page-builder/README.md: feature rows linked to features/F0N-*.md files that don't exist (E07 is Phase 2, not started). Per docs-style.md "empty TODO sections" anti-pattern, converted to plain text with a callout explaining files will be authored when the epic begins. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Four review comments — all valid; fixed plus one durable improvement.
- workflows/build-and-test.yml: pin lycheeverse/lychee-action to full
SHA (v2.8.0 = 8646ba30...). Dependabot will keep it fresh; pinning
now closes the gap between merge and first Dependabot run.
- ARCHITECTURE.md API Server row: drop "planned for execution push
updates" speculation; point to E06 epic where the real spec lives.
Reference docs describe what exists.
- ARCHITECTURE.md PostgreSQL diagram: add `text` language tag to
fenced block (MD040).
- TECH_STACK.md SignalR row: rephrase as pure current state
("capability available; no `*Hub.cs` currently registered in
`src/`") instead of "Not yet wired" which implied a forward
promise. Link to PROGRESS and E06 for status / epic acceptance.
- check-doc-drift.sh speculation guard: broaden pattern to catch the
class of "planned X" / "Will be X" the bot just exposed — the
earlier `planned design` literal was too narrow. Smoke-tested with
a fixture containing "planned for push".
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
scripts/check-doc-drift.sh (1)
150-156: ⚡ Quick winMake speculation matching case-insensitive to avoid guardrail blind spots.
Line 156 uses case-sensitive
grep -nE, so lowercase variants likewill beandcoming soonare missed by the current pattern. The verification confirms thatgrep -nEwith the current mixed-case pattern fails to match "This will be added later." whilegrep -nEicatches it.Suggested patch
-SPEC_PATTERN='Not yet|\bplanned\b|Will be|To be implemented|Coming soon|in the future' +SPEC_PATTERN='not yet|\bplanned\b|will be|to be implemented|coming soon|in the future' @@ - if matches="$(grep -nE "${SPEC_PATTERN}" "${target}" 2>/dev/null)"; then + if matches="$(grep -nEi "${SPEC_PATTERN}" "${target}" 2>/dev/null)"; then🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/check-doc-drift.sh` around lines 150 - 156, The grep call in the loop that checks SPEC_PATTERN against files is case-sensitive (grep -nE "${SPEC_PATTERN}" ...) so lowercase variants are missed; update the check to perform case-insensitive matching by either enabling grep's -i flag (change grep -nE to grep -nEi) or make the regex itself case-insensitive (prefix pattern with (?i)); ensure SPEC_PATTERN remains the same and only the grep invocation or pattern modifier is adjusted so matches like "will be" and "coming soon" are detected.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@scripts/check-doc-drift.sh`:
- Around line 150-156: The grep call in the loop that checks SPEC_PATTERN
against files is case-sensitive (grep -nE "${SPEC_PATTERN}" ...) so lowercase
variants are missed; update the check to perform case-insensitive matching by
either enabling grep's -i flag (change grep -nE to grep -nEi) or make the regex
itself case-insensitive (prefix pattern with (?i)); ensure SPEC_PATTERN remains
the same and only the grep invocation or pattern modifier is adjusted so matches
like "will be" and "coming soon" are detected.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6ccde0c6-c2e5-4580-b975-c7e5ecbc00e2
📒 Files selected for processing (4)
.github/workflows/build-and-test.ymldocs/ARCHITECTURE.mddocs/TECH_STACK.mdscripts/check-doc-drift.sh
✅ Files skipped from review due to trivial changes (1)
- docs/TECH_STACK.md
Summary
Three-commit cleanup of the docs and CI governance layer. Commit 1 fixes concrete drift (removed
unit-tests.slnfstill referenced 6×, conflicting Gate-paste guidance across PR template / CONTRIBUTING / agent-checklist, missingnCrunchTempignore, no concurrency on CI, no cross-module SQL gate). Commit 2 removes duplication and one speculative section (ARCHITECTURE.md "Real-Time Updates / SignalR" admitted as not implemented; README "Roadmap" dup of PRODUCT_VISION; CONTRIBUTING ~50% dup of CLAUDE.md). Commit 3 locks in guardrails so this class of rot can't return without CI catching it (Lychee link check, Dependabot for action pinning, speculation guard in drift script,docs-style.mdanti-pattern playbook, removed catalog tables from CLAUDE.md).Net: +287 / −227 lines. The doctrine surface area shrank; the automation surface area grew. Every new rule in
docs-style.mdis paired with a CI/script check — no "process about process".Linked spec
Docs-governance change. Touches: CLAUDE.md, CONTRIBUTING.md, docs/ARCHITECTURE.md, docs/README.md, docs/PRODUCT_VISION.md, docs/TECH_STACK.md, docs/playbooks/agent-checklist.md, docs/playbooks/process.md, new docs/playbooks/docs-style.md, .github/PULL_REQUEST_TEMPLATE.md, .github/workflows/build-and-test.yml, new .github/dependabot.yml, new lychee.toml, scripts/check-doc-drift.sh, .gitignore.
Requirements & rules followed
src/changes, no AC to map).dotnet *andnpm *not triggered (nosrc/,tests/, orfrontend/changes).dotnet format --verify-no-changesnot triggered../scripts/check-doc-drift.shran green locally on the branch.docs/README.mdplaybooks table, and agent-checklist all updated to reference the newdocs-style.md. No epic feature touched (no module code changed).docs/playbooks/docs-style.mdand in the newcheck-doc-drift.shguards (speculation + new-raw-SQL review + no-new-TODO + renamed-handler tests). One direction change mid-task — initial cross-module SQL guard scanned the whole tree (too noisy); narrowed to diff-added lines only, documented in commit message.TODO/FIXME/NotImplementedException/ placeholder / stub undersrc/,tests/,frontend/src/— verified by the new drift-script guard (which scans added lines in the diff).New guardrails introduced
lychee, offline mode) — internal links and#anchorsmust resolve.github-actions— auto-pins@v2→@<sha> # v2.4.1on first run, weekly bumps thereafter.concurrencygroup on CI workflow — cancels superseded PR runs.docker infopre-check on .NET job — Testcontainers failures surface early.ARCHITECTURE.mdmust not contain "Not yet implemented" / "planned design" / "Will be wired" / "To be implemented" / "Coming soon"). Smoke-tested with a fixture.src/,tests/,frontend/src/).Rgit status), not just added.Summary by CodeRabbit
Documentation
Chores