Rule handbook metadata
- Rule
DET.NAV.IN_PAGE_TOC· lanedeterministic- Page status
- current
- page_version
73ca82c130c0f8d8ea17f8412cab30621bfb8fabd1924a6a943a3653e9680f47- generated_at
- 2026-05-25T20:30:00.000Z
- registry_fingerprint
2ce40848effce579d3e4879f6ca85535183a14db201870a6c007da424624550c
How this rule is fixed
Pilot deterministic fixer: handbook_after · harness mode standalone · verify expect_rule_clean.
- Harness:
apply-harness-fixture-remediation.pycopies the After example HTML from this handbook page onto the defect fixture, theninvoke-det-ruleset-remediation-verify.shre-audits and expects zero findings for this rule. - Production sites:
run-website-ux-remediation-loop.shrunshandbook_html_patch(HTML patches inlib/ux-deterministic-fixers/fixers/patches/) before invoking the Cursor agent when the quality gate still fails.
Detection module: docs/design/ux-audit/deterministic-design-rules.md#det-nav-in_page_toc. Scroll down for Before / After examples and Evidence and remediation steps.
Purpose
Long handbook, chapter, product, and showcase pages need a scannable on-this-page trail separate from the doc IA rail (Ksr, aside.forge-sidebar) and global primary nav (Kpn). Kitchen Sink contracts Ktx — the doc ToC sidebar — as nav.forge-toc inside .ks-doc-toc-rail or .col-lg-4.col-xl-3.order-1.order-lg-2, listing h2/h3 anchors that skip correctly into main#main.
This deterministic rule runs during the metrics phase. Playwright collects navInPageTocReport from det-nav-in-page-toc.check.js. A page requires an in-page TOC when it is not home and any doc-hub signal is present:
| Doc-hub signal | Detection |
|---|---|
| Layout slug | layout-handbook, layout-chapter, layout-product, layout-showcase, layout-listing, layout-gallery, or layout-split on [data-ks-type="layout"] |
| Doc sidebar | Visible .forge-sidebar, #ks-sidebar-aside, .fs-sidebar, or aside[data-ks-hash="Ksr"] |
| Showcase masthead | Visible .site-header .site-header-content |
Exempt: layout-landing, layout-marketing, and home (/, /index.html).
Length threshold (either condition):
- ≥ 4
h2/h3headings insidemain, or - ≥ 900 words in
mainbody text.
A page passes when a visible TOC root matches .col-lg-4.col-xl-3.order-1.order-lg-2, [data-ks-hash="Ktx"], nav.forge-toc, nav[aria-label="On this page"], or .ks-doc-toc with ≥ 2 hash links; every href="#…" resolves to an element inside main; and at viewports ≥ 992 px the rail is at least 140 px wide with link labels at least 100 px wide.
Plan: Emit Ktx when chapter/handbook layouts exceed length thresholds. Do: Use render_toc_sidebar() in components/components.py or the showcase ToC column in showcase_page(). Check: navInPageTocReport.requiresToc && tocPresent && brokenAnchors[] empty and rail width checks pass. Adjust: Add Ktx, fix stale heading ids, and use .ks-doc-toc-flow grid so the rail is not crushed by Bootstrap column math.
Passing signals
aside.ks-doc-toc-railwithhash="Ktx",data-ks-hash="Ktx",data-ks-type="chrome-region",data-ks-name="doc-toc-sidebar"wrapsnav.forge-tocwitharia-label="On this page"and ≥ 2a.nav-link[href^="#"]entries — matchesrender_toc_sidebar()output.- Showcase layouts use the
.col-lg-4.col-xl-3.order-1.order-lg-2ToC column with the samenav.forge-tocpattern fromshowcase_page()incomponents/layouts.py. - Each TOC link targets a real
idon anh2orh3insidemain#main; heading text changes regenerate matching slugs perdocs/design/catalog/chrome/Ktx-doc-toc-sidebar.md. - Long pages inside
.ks-doc-toc-flowplace prose in.ks-doc-toc-proseand the rail in.ks-doc-toc-railso link labels wrap instead of clipping (forge-theme.cssminmax(12rem, 16rem)rail column). - Home, landing, and marketing layouts correctly skip the requirement (
requiresToc=false). - Short doc pages (< 4 outline headings and < 900 words) pass without Ktx even on handbook layouts.
- Evidence shape:
navInPageTocReport.tocPresent=true,brokenAnchors=[],tocRailWidthPx ≥ 140,minTocLinkWidthPx ≥ 100at desktop viewport.
Failing signals
missing_in_page_toc: Doc-hub signals fire (layout:layout-handbook,doc-sidebar, orshowcase-header) and length threshold is met, but no visiblenav.forge-toc,[data-ks-hash="Ktx"], or equivalent ToC root with ≥ 2 hash links — readers scroll a long chapter with no section jump list.broken_toc_anchor: Ktx link useshref="#old-slug"but the matchingidis missing or lives outsidemainafter a title edit or generator refactor (severity: major).toc_rail_cramped: ToC column renders but rail width < 140 px or minimum link width < 100 px at ≥ 992 px viewport — often from nesting.ks-doc-toc-railinside Bootstrapcol-lg-*instead of.ks-doc-toc-flowgrid.- Hidden or inert ToC: node exists but is
display:none, has zero-size bounding box, or fewer than two hash links (placeholder shell). - Co-failures: headings skip levels or lack stable ids (
DET.SECTION.HEADING); crushed prose+rail layout (DET.LAYOUT.GRID_CONSISTENCY); complementary nav removed from tab order without top-nav coverage (DET.NAV.FOCUS_ORDER). - Evidence shapes:
missing_in_page_toc signals=layout:layout-chapter outline_h=6 main_words=1100;broken_toc_anchor href="#setup-guide" target_id="setup-guide";toc_rail_cramped rail_width_px=64 min_link_width_px=64.
Before example
Before (failing example)
Governance chapter
Governance chapter
Design principles
Long-form handbook prose that exceeds the configured word threshold without an on-this-page navigation column.
Design contracts
Each visual hash maps to an element-specific contract in the design catalog.
Deterministic checks
Repeatable UX issues become automated rules in the website auditor.
Remediation loop
Findings feed handbook rule pages and generator fixes.
Evidence trail
Screenshots, DOM snapshots, and anchor maps prove pass or fail.
Next steps
Ship Ktx beside this column so readers can jump sections without scrolling.
Failing KS markup: handbook shell with visible Ksr doc sidebar and six h2 sections in main, but no Ktx / nav.forge-toc rail — triggers missing_in_page_toc.
After example
After (passing example)
Governance chapter
Governance chapter
Design principles
Long-form handbook prose with a companion on-this-page navigation rail.
Design contracts
Each visual hash maps to an element-specific contract in the design catalog.
Deterministic checks
Repeatable UX issues become automated rules in the website auditor.
Remediation loop
Findings feed handbook rule pages and generator fixes.
Evidence trail
Screenshots, DOM snapshots, and anchor maps prove pass or fail.
Next steps
Readers jump directly to the section they need.
Passing KS markup: same long chapter wrapped in .ks-doc-toc-flow with Ktx rail listing every h2 anchor; links resolve to ids inside main.
Evidence and remediation
- Confirm requirement — inspect
navInPageTocReport.docHubSignals,outlineHeadingCount, andmainWordCount; verify the page is not home or a landing layout exempt from Ktx. - Emit Ktx — call
render_toc_sidebar(toc_entries)fromcomponents/components.pyor wire the showcase ToC column inshowcase_page()/handbook_page()when outline or word thresholds are met. - Repair broken anchors — regenerate heading
idvalues when titles change; ensure eachnav.forge-toc .nav-linkhrefmatches anh2/h3insidemain#main(seedocs/design/catalog/chrome/Ktx-doc-toc-sidebar.md). - Fix cramped rails — wrap prose + rail in
.ks-doc-toc-flow, keep measure on.ks-doc-toc-prose, and avoid stacking Bootstrapcol-lg-*on.ks-doc-toc-railso the grid assignsminmax(12rem, 16rem)width. - Verify — re-run
node tools/website-ux-auditor/analyze-website-ux.mjsorauditor-tests/invoke-det-ruleset-harness.sh --only-rule DET.NAV.IN_PAGE_TOC; expecttocPresent=true, emptybrokenAnchors, and notoc_rail_crampedfinding.
Typical evidence strings: missing_in_page_toc signals=doc-sidebar outline_h=6 main_words=1100 expected="nav.forge-toc"; broken_toc_anchor href="#old-title" target_id="old-title"; toc_rail_cramped rail_width_px=64 min_link_width_px=64.