Skip to content

Add page/button wiring guardrails and fix audited defects#1030

Merged
BigSimmo merged 15 commits into
mainfrom
claude/wiring-audit-issues-emke3m
Jul 21, 2026
Merged

Add page/button wiring guardrails and fix audited defects#1030
BigSimmo merged 15 commits into
mainfrom
claude/wiring-audit-issues-emke3m

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

A repo-wide page/button wiring audit (85 pages, 40 API routes, 146 components). The app is actually well-wired — the audit surfaced only a few real gaps. This PR fixes the clear-cut defects and installs a prevention layer so the class of bug (dead buttons, orphan routes) is caught by a gate instead of by a user noticing a control that does nothing.

Fixes

  • Dead button — the "Language and region" globe in the workflow header (master-search-header.tsx) was styled + aria-labelled but had no onClick and was not disabled. Converted to the codebase's disabled "coming soon" placeholder convention (aria-disabled + sr-only note), matching favourites-hub.tsx.
  • Three stale doc claims/documents/source redirect target in the site-map generator (the canonical /documents/[id], not the invalid-id /documents/search fallback the first-redirect() regex captured); and in codebase-index.md, /applications (a redirect, not a composer mode home) plus the missing dsm/specifiers mode-param redirects.

Prevention (documentation + memory + rules)

  • Rule (prose) — new AGENTS.md page-and-button-wiring durable block.
  • Rule (lint) — new local ESLint rule require-button-wiring flags a <button type="button"> with no handler / formAction / disabled state (the globe-button class). Scoped to src/**; mockups exempt.
  • Rule (test) — new offline tests/route-reachability.test.ts asserts every static production page route has an inbound nav link (catches orphans like /tools), with a documented REACHABILITY_ALLOWLIST. Closes the gap site-map.test.ts left (it checks routes are documented, not reachable).
  • Documentation — new docs/wiring-conventions.md, registered in docs/README.md and cross-linked from codebase-index.md.
  • Memory — judgment-call findings recorded as #006#010 in the /issues ledger (docs/outstanding-issues.md): the /tools vs /?mode=tools duplicate entry point, the unused document-flow-routes.ts href builders, the server-only /api/jobs, and the un-built "coming soon" placeholders.

Both new gates are offline and join verify:cheap + CI automatically (lint and the unit suite).

Verification

  • npm run verify:pr-local

During development, use npm run verify:cheap as the faster iteration gate before the final PR-local preflight.

  • npm run verify:ui when UI, routing, styling, browser behavior, reduced-motion, or forced-colors behavior changed
  • npm run verify:release before release or handoff confidence claims

Ran (all offline, all green): npm run verify:cheap — every check:*, sitemap:check, docs:check-index, check:knip, check:gate-manifest, lint, typecheck, and the full unit suite (3030 passed, incl. the two new gates). Confirmed the new require-button-wiring rule has zero src/** violations after the globe fix, and the reachability test flags exactly /tools when its allowlist entry is removed (guard has teeth, zero false positives).

Verification not run: verify:pr-local/verify:release — not needed for this docs + lint/test-tooling + disabled-placeholder change; the offline verify:cheap superset was run instead.

UI verification not run: browser e2e (verify:ui) was not run in this remote environment. The only UI change is the globe button → disabled placeholder; its Playwright assertion in tests/ui-tools.spec.ts was updated to the new accessible name and aria-disabled state, and lint/typecheck pass.

One unrelated, pre-existing test fails: tests/pdf-extraction-budget.test.ts (a Python child-process SIGKILL-timing test) — verified to fail identically on clean origin/main; it is environment/timing-related and tracked as ledger #002. Not touched by this PR.

Risk and rollout

  • Risk: Low. Doc/tooling changes plus one button converted to an explicit disabled placeholder. The two new gates are additive and passed against the current tree.
  • Rollback: Revert the commit; no data, schema, migration, or provider change.
  • Provider or production effects: None.

Clinical Governance Preflight

N/A — this change is UI wiring conventions, documentation, lint/test tooling, and a disabled-placeholder button. It does not touch ingestion, answer generation, search/ranking/retrieval, source rendering, document access, privacy, production env, or clinical output.

Notes

  • No src/lib/rag/** or other RAG-ranking surface was modified, so no RAG impact: line is required.
  • The pre-existing broken doc reference src/lib/rag/clinical-search.ts in ledger row #005 (advisory docs:check-links only; present on origin/main) was intentionally left untouched — it is another row on a protected RAG surface and out of scope here.

Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added an accessibility-friendly “Language and region settings (coming soon)” disabled state to the workflow header.
    • Added automated enforcement to prevent unwired buttons and orphan/unreachable production routes.
  • Documentation
    • Expanded repo-wide wiring conventions for button behavior and internal navigation.
    • Updated architecture, codebase index, outstanding issues, and related sitemap guidance.
  • Bug Fixes
    • Fixed the /documents/source sitemap redirect to point to the canonical document viewer.

A repo-wide wiring audit found the app well-wired, with a few real gaps.
This fixes the clear-cut defects and installs a prevention layer so the
class of bug (dead buttons, orphan routes) is caught by a gate instead of
by a user noticing a control that does nothing.

Fixes:
- Wire the dead "Language and region" globe button in the workflow header
  to the codebase's disabled "coming soon" placeholder convention
  (aria-disabled + sr-only note); it was styled and labelled but had no
  handler and was not disabled.
- Correct three stale doc claims: the /documents/source redirect target in
  the site-map generator (canonical /documents/[id], not the invalid-id
  /documents/search fallback the first-redirect regex captured), and, in
  codebase-index, /applications (a redirect, not a composer mode home) plus
  the missing dsm/specifiers mode-param redirects.

Prevention:
- New AGENTS.md `page-and-button-wiring` durable rule block.
- New local ESLint rule `require-button-wiring` flagging a
  `<button type="button">` with no handler / formAction / disabled state
  (the globe-button class); scoped to src/**, mockups exempt.
- New offline tests/route-reachability.test.ts asserting every static
  production page route has an inbound nav link (catches orphan routes such
  as /tools), with a documented allowlist.
- New docs/wiring-conventions.md reference, registered in docs/README and
  cross-linked from codebase-index.
- Record the judgment-call findings (#6-#10) in the /issues ledger.

Verified offline: lint, typecheck, sitemap:check, docs:check-index, knip,
and the full unit suite (both new gates included) pass. The unrelated,
pre-existing pdf-extraction-budget process-timing test fails on origin/main
too (tracked as ledger #2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFM6m7WAnLuo9kqh2ExPNh
@supabase

supabase Bot commented Jul 21, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e642fb72-9084-4330-9393-0b0b4f257a8c

📥 Commits

Reviewing files that changed from the base of the PR and between 370fa5d and 890f9d1.

📒 Files selected for processing (1)
  • eslint-rules/require-button-wiring.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • eslint-rules/require-button-wiring.mjs

📝 Walkthrough

Walkthrough

Adds documented button and navigation conventions, production ESLint enforcement for unwired buttons, route-reachability tests, a canonical sitemap redirect, and a disabled “coming soon” language-region control with updated UI coverage.

Changes

Wiring and reachability

Layer / File(s) Summary
Document wiring conventions
AGENTS.md, docs/README.md, docs/codebase-index.md, docs/wiring-conventions.md, docs/outstanding-issues.md
Documents button behavior, internal navigation, route checklists, mockup exemptions, automated gates, and tracked wiring issues.
Enforce button wiring and placeholders
eslint-rules/require-button-wiring.mjs, eslint.config.mjs, src/components/clinical-dashboard/master-search-header.tsx, tests/ui-tools.spec.ts
Adds production lint enforcement for unwired explicit buttons and changes the language-region control to an accessible disabled placeholder with updated assertions.
Validate route reachability and sitemap targets
docs/site-map.md, scripts/generate-site-map.ts, tests/route-reachability.test.ts
Aligns the /documents/source redirect with /documents/[id] and verifies static routes have navigation references or documented allowlist entries.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • BigSimmo/Database#441: Updates overlapping UI test expectations for the language and region settings control.
  • BigSimmo/Database#591: Updates sitemap documentation and canonical /tools routing relevant to the new reachability checks.

Suggested labels: codex

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: wiring guardrails plus fixes for audited defects.
Description check ✅ Passed The description matches the template sections and includes summary, verification notes, risk, governance, and notes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/wiring-audit-issues-emke3m

Comment @coderabbitai help to get the list of available commands.

@BigSimmo
BigSimmo marked this pull request as ready for review July 21, 2026 01:26
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@BigSimmo
BigSimmo enabled auto-merge (squash) July 21, 2026 01:27

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

🧹 Nitpick comments (1)
tests/route-reachability.test.ts (1)

29-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Require a non-empty reason for every allowlisted route.

The stale-entry check validates only the key; an entry such as ["/route", ""] would still silence an orphan. Assert reason.trim().length > 0 while iterating the allowlist so exemptions cannot bypass the documented rationale requirement.

As per coding guidelines, route-reachability tests must maintain coverage for production page routes unless exemptions are consciously documented.

Also applies to: 131-135

🤖 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 `@tests/route-reachability.test.ts` around lines 29 - 43, Update the
REACHABILITY_ALLOWLIST validation in the route-reachability tests to assert that
each exemption reason has non-whitespace content by checking
reason.trim().length > 0 during iteration, while preserving the existing
route-key validation and production-route coverage behavior.

Source: Coding guidelines

🤖 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 `@docs/wiring-conventions.md`:
- Around line 47-49: Update the globe defect fix date in the “Language and
region” guidance to 2026-07-21, matching the maintained date in AGENTS.md while
leaving the surrounding wiring convention unchanged.

In `@eslint-rules/require-button-wiring.mjs`:
- Around line 26-48: Update isWiringAttr to recognize only the onClick handler
and the existing EXPLICIT_WIRING_ATTRS entries, removing the broad on* event
check; also remove formAction from EXPLICIT_WIRING_ATTRS because it does not
provide behavior for type="button". Preserve isTypeButton and the
disabled/aria-disabled placeholder handling.

In `@eslint.config.mjs`:
- Around line 18-21: Update MOCKUP_IGNORES to remove the broad "**/*mockup*"
pattern and retain only the documented /mockups routes, *-mockups/ directories,
and *-mockups.tsx singleton patterns. In the associated button-rule file scope,
include all declared JavaScript and TypeScript source extensions, including .js,
while preserving the existing mockup exclusions.

In `@tests/route-reachability.test.ts`:
- Around line 82-87: Update the Therapy Compass route discovery logic around
tcBindingsSrc to import the exported BASE and RESERVED_SEGMENTS constants when
possible; otherwise require both source regex matches to succeed and fail the
test explicitly if parsing fails. Preserve adding every reserved route target
from the parsed values, without silently falling back to an empty set.
- Around line 89-106: Replace the raw full-file regex check in isReachable and
referenceRegExp with AST/token-aware extraction of actual Link hrefs and
router/redirect navigation calls, or reuse the existing shared route manifest if
available. Ensure comments, strings, ownership checks, and unrelated object
properties do not count as references, while object-form and computed navigation
expressions are recognized; preserve builderTargets handling and selfFile
exclusion.
- Around line 53-64: Update collectSourceFiles to scan JavaScript and JSX files
in addition to TypeScript and TSX files, while preserving the existing directory
recursion, mockup exclusion, relative-path normalization, and file-content
collection behavior.
- Around line 69-75: Update the builderTargets setup in the route reachability
test to invoke appModeHomeHref with representative query inputs, including
document and namespaced search cases, and add each resulting path to the set.
Preserve the existing default-target collection and ensure all valid
query-dependent static routes are covered.

---

Nitpick comments:
In `@tests/route-reachability.test.ts`:
- Around line 29-43: Update the REACHABILITY_ALLOWLIST validation in the
route-reachability tests to assert that each exemption reason has non-whitespace
content by checking reason.trim().length > 0 during iteration, while preserving
the existing route-key validation and production-route coverage behavior.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9c7f63b5-7a76-4c22-8868-189d396bfe99

📥 Commits

Reviewing files that changed from the base of the PR and between fd997d9 and 6a3af7e.

📒 Files selected for processing (12)
  • AGENTS.md
  • docs/README.md
  • docs/codebase-index.md
  • docs/outstanding-issues.md
  • docs/site-map.md
  • docs/wiring-conventions.md
  • eslint-rules/require-button-wiring.mjs
  • eslint.config.mjs
  • scripts/generate-site-map.ts
  • src/components/clinical-dashboard/master-search-header.tsx
  • tests/route-reachability.test.ts
  • tests/ui-tools.spec.ts

Comment thread docs/wiring-conventions.md
Comment thread eslint-rules/require-button-wiring.mjs Outdated
Comment thread eslint.config.mjs Outdated
Comment thread tests/route-reachability.test.ts
Comment thread tests/route-reachability.test.ts
Comment thread tests/route-reachability.test.ts
Comment thread tests/route-reachability.test.ts
BigSimmo and others added 7 commits July 21, 2026 10:08
… review

Addresses the CodeRabbit review threads on the new wiring tooling:

- require-button-wiring: only onClick (not any on*) and disabled/aria-disabled
  count as wired; drop formAction (no submit effect on type=button). onFocus/
  onMouseEnter no longer mask a click that does nothing.
- eslint.config MOCKUP_IGNORES: replace the broad **/*mockup* substring (which
  would exempt arbitrary production files) with the precise documented surface
  (src/app/mockups/**, *-mockups/, *-mockup(s).tsx); widen the rule's file scope
  to src/**/*.{js,jsx,ts,tsx}.
- route-reachability test: scan .js/.jsx source too; also seed builderTargets
  with the query-bearing appModeHomeHref variant (document/namespaced-search
  routes); fail loudly if therapy-compass BASE/RESERVED_SEGMENTS can't be parsed
  instead of silently checking nothing.
- Align the globe-defect fix date to 2026-07-21 across the doc + rule + config.

Verified: npm run lint (0 problems — no button newly flagged), typecheck,
route-reachability (2/2), format:check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013f523gDfoBXPYT4H9vXRkE

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 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 `@eslint-rules/require-button-wiring.mjs`:
- Around line 26-27: Update the button-wiring checks using EXPLICIT_WIRING_ATTRS
and the onClick handling to validate statically known literal values rather than
attribute presence alone: treat disabled={false}, aria-disabled="false", and
onClick={null} as unwired, while preserving dynamic expressions and
aria-disabled="true" as valid wiring. Apply the same value-aware logic in the
related validation path around the button analysis.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3fa4a994-406b-4935-a7e7-17d1897c2b39

📥 Commits

Reviewing files that changed from the base of the PR and between c53ebaa and 370fa5d.

📒 Files selected for processing (4)
  • docs/wiring-conventions.md
  • eslint-rules/require-button-wiring.mjs
  • eslint.config.mjs
  • tests/route-reachability.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/route-reachability.test.ts
  • docs/wiring-conventions.md
  • eslint.config.mjs

Comment thread eslint-rules/require-button-wiring.mjs
claude and others added 3 commits July 21, 2026 03:08
CodeRabbit re-review: disabled={false}, aria-disabled="false", and onClick={null}
satisfied the rule despite doing nothing. Add isStaticallyOff() so a statically-
known off value (literal false/null, string "false", identifier undefined — bare
or in an expression container) no longer counts as wiring/disabled, while dynamic
expressions and aria-disabled="true" stay valid. lint stays green (0 problems; no
existing button relies on those patterns).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013f523gDfoBXPYT4H9vXRkE
@BigSimmo
BigSimmo merged commit 0b5ba0d into main Jul 21, 2026
17 checks passed
@BigSimmo
BigSimmo deleted the claude/wiring-audit-issues-emke3m branch July 21, 2026 06:33
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.

2 participants