Skip to content

Fix CLI-Reference discovery gap and unscoped alias segments (#137, #136) - #138

Merged
mobileskyfi merged 2 commits into
mainfrom
fix/137-cliref-discovery-union
Aug 12, 2026
Merged

Fix CLI-Reference discovery gap and unscoped alias segments (#137, #136)#138
mobileskyfi merged 2 commits into
mainfrom
fix/137-cliref-discovery-union

Conversation

@mobileskyfi

@mobileskyfi mobileskyfi commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

MikroTik reshaped the CLI Reference from module pages into per-command leaf pages whose slug is the CLI path. Two defects surfaced. They turn out to need each other.

Discovery (#137)

The sitemap serves a branching menu as a trailing-slash category URL with no .md of its own. The menu's own Directory entry is published — at <dir>/<basename(dir)>.md (app/app/app.md) — and listed only in llms.txt.

Sitemap-only discovery therefore dropped 256 of 1,070 pages, and the field-heavy quarter of them: cliref_fields came out at 5,944 instead of 10,938. Those menus, their package/conditions/syscap gates, and their argument tables were absent from the DB, from the cli-reference/* export datasets, and from anything reading the overlay.

Discovery is now the union of both inventories. Reconciles exactly:

sitemap filtered 814 ∪ derived <dir>/<basename> 256 = 1,070
1,070 + index (glossary prose, no **Type:** entry) = 1,071 = llms.txt filtered

The old -- generated category pages ... every variant 404s (verified 2026-07-20) note was verified with the wrong candidate URLs — *.md, /index.md and /.md all 404, but <dir>/<basename>.md returns 200 with a valid **Type:** Directory and full ArgTable. A 404 on a probe is evidence about the probe, not about the page.

New blocking V-cliref-discovery: every sitemap category dir must contribute its <dir>/<basename> leaf, or the build fails. That is the gate that would have caught this originally, and it fails loud in both directions rather than absorbing an inventory change.

Alias scoping (#136)

KNOWN_ALIAS_SEGMENTS encoded "this word is a doc-internal module name" as a global property. It is positional: poe and qos are real menu segments published elsewhere in the same source. Three entries linked to different commands with disjoint field sets (PoE-out vs SFP/link; ~140 QoS per-queue fields vs 15 switch-port ones). Silent, because the alias branch only fires when the exact path is missing from schema_nodes — precisely the hardware-gated commands nobody can check from a CHR.

A segment is now never dropped when the prefix ending at it is itself a published entry. Isolated on the corrected corpus:

without prefix-scoping: exact 967  alias 3  manual-only 107
with    prefix-scoping: exact 967  alias 0  manual-only 110

  interface/ethernet/poe/monitor                      was alias:/interface/ethernet/monitor                    -> manual-only
  interface/ethernet/switch/qos/port                  was alias:/interface/ethernet/switch/port                -> manual-only
  interface/ethernet/switch/qos/port/reset-counters   was alias:/interface/ethernet/switch/port/reset-counters -> manual-only

The two fixes need each other. Recovering the 256 Directory leaves is what publishes interface/ethernet/switch/qos, which is what lets the guard see the third bad link. On the sitemap-only corpus the guard reaches only two of the three.

Before / after

Live rebuild, re-verified offline via --from-cache:

shipped (v0.11.2-alpha.109) this PR
cliref_pages 228 1,070
cliref_entries 1,051 1,077
cliref_fields 10,118 10,938
cliref_flags 948 976
cliref_entry_schema_links 931 (907 exact / 24 alias) 967 (967 exact / 0 alias)
manual-only 120 110
cliref_field_inspect_links (view) 13,036 13,417
entries per page {1:95, 2:29, 3:33, …, 62:2} {1:1,063, 2:7}

Export datasets move with it (pages.tsv 228→1,070, fields.tsv 10,118→10,938, source/*.md 228→1,070 files).

Notes on the numbers

  • There is no field-count drop. Sitemap-only discovery on the new source yields 5,944 fields, which reads as a 4,174-row loss and invites a "the source got thinner" story. The missing rows were the dropped Directory menus.
  • A page can still carry two entries. Seven derived leaves publish one path twice under different syscap gates (interface/ethernet/switch/port as musicswitch with 175 fields and rbswitch with 139; system/health as Settings Directory and Directory). Occurrence identity stays the right model — "one entry per page" would be the wrong invariant to add.
  • source_parent_id is now uniformly NULL — it is intra-page heading ancestry and a one-heading page has none. Docs-only: no consumer branches on it. fixtures/cli-reference/sample.md deliberately keeps the historical multi-entry shape, since it is what proves nesting still parses and no live page exercises it.
  • interface/ethernet went 35 → 160 fields on an unchanged path. Verified against live source (163 <ArgTableRow>) — genuine upstream expansion, not an extraction artifact.

Verification

  • bun test — 1,117 pass / 0 fail (new coverage for the discovery gate, the index exclusion, and prefix-scoping in both directions)
  • make lint, make typecheck — clean
  • V-cliref-link-drift, V-cliref-db-integrity — green on the rebuilt DB
  • extract-cliref --from-cache --check-counts — reproduces the corpus offline, parsed==source markers

Closes #137
Closes #136

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved CLI Reference discovery by combining sitemap and llms.txt sources.
    • Added coverage for Directory pages linked through branching menus.
    • Discovery now detects missing category pages and prevents incomplete reference updates.
    • Corrected several CLI command links by preserving valid nested menu paths.
  • Documentation

    • Updated CLI Reference counts, validation guidance, design notes, and extraction documentation to reflect the expanded corpus and corrected linking behavior.

MikroTik reshaped the CLI Reference from module pages into per-command leaf
pages. Two defects surfaced, and they turn out to need each other.

**Discovery (#137).** The sitemap serves a branching menu as a trailing-slash
category URL with no .md of its own, while the menu's own Directory entry is
published at `<dir>/<basename>.md` and listed only in llms.txt. Sitemap-only
discovery dropped 256 of 1,070 pages — and the field-heavy quarter: fields came
out at 5,944 instead of 10,938. Discovery is now the union of both inventories.

The earlier "generated category stubs — every .md variant 404s" note was
verified with the wrong candidate URLs; `<dir>/<basename>.md` returns 200 with a
valid `**Type:** Directory` and full ArgTable. New blocking V-cliref-discovery
gate asserts every category dir still contributes its leaf, so the next
inventory change fails the build instead of quietly shrinking the corpus.

**Alias scoping (#136).** KNOWN_ALIAS_SEGMENTS encoded "doc-internal module
name" as a global property, but it is positional: `poe` and `qos` are real menu
segments published elsewhere in the same source. Three entries linked to
different commands with disjoint field sets (PoE-out vs SFP/link). A segment is
now never dropped when the prefix ending at it is itself a published entry.

Recovering the 256 Directory leaves is what publishes
`interface/ethernet/switch/qos`, which lets the guard catch the third bad link —
on the sitemap-only corpus it only reaches two.

Rebuilt corpus (live, re-verified offline via --from-cache):

  pages    228 -> 1,070      fields  10,118 -> 10,938
  entries  1,051 -> 1,077    flags      948 ->    976
  links    931 (907 exact / 24 alias / 120 manual-only)
        -> 967 (967 exact /  0 alias / 110 manual-only)

V-cliref-link-drift, V-cliref-db-integrity, full `bun test`, `make lint` and
`make typecheck` all green.

Closes #137
Closes #136

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 12, 2026 13:43
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 53dce226-8d6e-4216-bc36-2629fd9aec5d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1ef1ae6a-918b-4b50-a9f1-701836c6f5a0

📥 Commits

Reviewing files that changed from the base of the PR and between a59ea71 and cd466f9.

⛔ Files ignored due to path filters (1)
  • cli-reference-links.tsv is excluded by !**/*.tsv, !*.tsv
📒 Files selected for processing (11)
  • .github/workflows/qa.yml
  • CHANGELOG.md
  • DESIGN.md
  • MANUAL.md
  • VALIDATION.md
  • briefings/B-0016-cli-reference-overlay-design.md
  • project-words.txt
  • src/extract-cliref.test.ts
  • src/extract-cliref.ts
  • src/link-cliref.test.ts
  • src/link-cliref.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: copilot-pull-request-reviewer
🧰 Additional context used
📓 Path-based instructions (11)
*

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Keep this Copilot instructions file short; put substantive rules in narrow instruction files under .github/instructions/*.instructions.md.

Files:

  • project-words.txt
  • MANUAL.md
  • VALIDATION.md
  • DESIGN.md
  • CHANGELOG.md
**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.md: Keep each project documentation file limited to its canonical role; prefer the documented canonical home instead of creating a new top-level Markdown file.
Do not duplicate content from this routing index; move operational detail, schema blocks, or long rule lists to their canonical documentation or instruction files.
Apply the repository's Markdown linting and fenced-code conventions, while excluding LLM instruction files where the repository explicitly requires that exclusion.

Files:

  • MANUAL.md
  • VALIDATION.md
  • DESIGN.md
  • CHANGELOG.md
  • briefings/B-0016-cli-reference-overlay-design.md
MANUAL.md

📄 CodeRabbit inference engine (CLAUDE.md)

Store installation, operations, release or re-extraction procedures, and schema reference material in MANUAL.md.

Files:

  • MANUAL.md
**/*.{ts,tsx,md}

📄 CodeRabbit inference engine (AGENTS.md)

Keep the attribution boundary visible when community RouterOS skills surface, because they are supplemental rather than official MikroTik documentation.

Files:

  • MANUAL.md
  • VALIDATION.md
  • src/extract-cliref.test.ts
  • DESIGN.md
  • src/link-cliref.ts
  • CHANGELOG.md
  • briefings/B-0016-cli-reference-overlay-design.md
  • src/extract-cliref.ts
  • src/link-cliref.test.ts
{README.md,MANUAL.md,src/setup.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Keep public client setup snippets aligned across README.md, src/setup.ts, and MANUAL.md, including codex mcp add rosetta -- bunx @tikoci/rosetta``.

Files:

  • MANUAL.md
VALIDATION.md

📄 CodeRabbit inference engine (CLAUDE.md)

Document load-bearing invariants and how CI proves them in VALIDATION.md.

Files:

  • VALIDATION.md
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Bun and TypeScript, including Bun-native runtime APIs such as bun:sqlite, Bun.serve, and bunx.

Rosetta uses Bun and TypeScript; prefer bun, bun test, and make verify where applicable, rather than Node/npm-oriented substitutes.

Files:

  • src/extract-cliref.test.ts
  • src/link-cliref.ts
  • src/extract-cliref.ts
  • src/link-cliref.test.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Rosetta is read-only documentation/schema context and must not connect to or modify a user's router.

Files:

  • src/extract-cliref.test.ts
  • src/link-cliref.ts
  • src/extract-cliref.ts
  • src/link-cliref.test.ts
DESIGN.md

📄 CodeRabbit inference engine (CLAUDE.md)

Store durable project rationale, data-source provenance, and architecture tradeoffs in DESIGN.md.

Read DESIGN.md when changing retrieval, MCP/TUI behavior, data sources, extraction, skills, command validation, or Docusaurus migration work.

Files:

  • DESIGN.md
CHANGELOG.md

📄 CodeRabbit inference engine (CLAUDE.md)

Record user-visible shipped changes in CHANGELOG.md under [Unreleased] or release sections.

Files:

  • CHANGELOG.md
briefings/B-*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Store grounded research and decision support in briefings/B-*.md.

Files:

  • briefings/B-0016-cli-reference-overlay-design.md
🧠 Learnings (6)
📚 Learning: 2026-07-12T20:33:29.883Z
Learnt from: mobileskyfi
Repo: tikoci/rosetta PR: 52
File: .github/workflows/qa.yml:101-101
Timestamp: 2026-07-12T20:33:29.883Z
Learning: In tikoci/rosetta, GitHub Actions workflow steps that reference official actions (e.g., `actions/checkout`, `actions/download-artifact`) may intentionally use version tags (e.g., `v4`, `v3`) instead of full commit SHAs. During code review, do not flag these unpinned `actions/*` tag references as a GitHub Actions security issue for this repository, because Dependabot’s `github_actions` updates tagged refs and GitHub surfaces action security advisories against tagged refs.

Applied to files:

  • .github/workflows/qa.yml
📚 Learning: 2026-07-12T20:33:35.489Z
Learnt from: mobileskyfi
Repo: tikoci/rosetta PR: 52
File: .github/workflows/codeql.yml:29-29
Timestamp: 2026-07-12T20:33:35.489Z
Learning: In this repo’s GitHub Actions workflows, preserve the maintainer’s security/maintenance intent: action references under `actions/*` may use version tags (e.g., `actions/checkoutv7`) instead of full commit SHAs, and `actions/checkout` may intentionally keep `persist-credentials: true`. During review, do not raise issues suggesting SHA pinning for `actions/*` or proposing `persist-credentials: false` unless the project adopts an org-wide policy that enforces SHA pinning.

Applied to files:

  • .github/workflows/qa.yml
📚 Learning: 2026-07-12T20:33:29.883Z
Learnt from: mobileskyfi
Repo: tikoci/rosetta PR: 52
File: .github/workflows/qa.yml:101-101
Timestamp: 2026-07-12T20:33:29.883Z
Learning: In this repository’s GitHub Actions workflows (under .github/workflows), do NOT flag actions/checkout steps for missing `persist-credentials: false` when the workflow is intentionally relying on the persisted GitHub token for later authenticated steps in the same job (e.g., release or subsequent steps that require auth). This exception applies to workflows where the checked-out workspace is not being uploaded as an artifact and the token persistence is an intentional part of the job’s authentication flow.

Applied to files:

  • .github/workflows/qa.yml
📚 Learning: 2026-07-12T20:33:31.549Z
Learnt from: mobileskyfi
Repo: tikoci/rosetta PR: 52
File: .github/workflows/release.yml:433-433
Timestamp: 2026-07-12T20:33:31.549Z
Learning: In this repo, GitHub Actions used in workflow files should be pinned to version tags (e.g., actions/checkoutvX, not full commit SHAs). During code review, do not flag or fail checks that look like “unpinned-uses”/“SHA pinning required” (e.g., zizmor unpinned-uses) for actions/checkout, actions/download-artifact, or other third-party actions referenced from `.github/workflows`—keep the existing tag-pinning policy so Dependabot’s `github_actions` tracking and GitHub’s action security advisory visibility against tagged refs are preserved.

Applied to files:

  • .github/workflows/qa.yml
📚 Learning: 2026-07-12T20:33:42.621Z
Learnt from: mobileskyfi
Repo: tikoci/rosetta PR: 52
File: .github/workflows/test.yml:19-19
Timestamp: 2026-07-12T20:33:42.621Z
Learning: In tikoci/rosetta workflows, follow the maintainer policy: do not require GitHub Actions step refs under `actions/*` (e.g., `actions/checkout`) to be pinned to full commit SHAs, and do not require `persist-credentials: false` to be set on `actions/checkout` (or other `actions/*`) by default. Only flag missing SHA pinning or missing `persist-credentials: false` if the maintainer explicitly indicates the policy has changed (for example, adopting an org-wide SHA-pinning enforcement).

Applied to files:

  • .github/workflows/qa.yml
📚 Learning: 2026-07-12T20:33:36.397Z
Learnt from: mobileskyfi
Repo: tikoci/rosetta PR: 52
File: .github/workflows/release.yml:74-74
Timestamp: 2026-07-12T20:33:36.397Z
Learning: For this repo (tikoci/rosetta), workflow files in .github/workflows should keep GitHub Actions `actions/*` pinned to version tags (e.g., `v3`, `v4`) rather than full commit SHAs. Do not raise/retain findings that would otherwise complain about unpinned uses (e.g., zizmor `unpinned-uses`) or SHA pinning, unless the maintainer later enables an org-wide enforcement policy requiring SHA pinning.

Applied to files:

  • .github/workflows/qa.yml
🔇 Additional comments (11)
src/extract-cliref.ts (1)

38-38: LGTM!

Also applies to: 55-72, 102-179, 590-594

src/extract-cliref.test.ts (1)

10-10: LGTM!

Also applies to: 27-69

.github/workflows/qa.yml (1)

291-294: LGTM!

Also applies to: 304-304

DESIGN.md (1)

205-213: LGTM!

MANUAL.md (1)

102-102: LGTM!

VALIDATION.md (1)

57-61: LGTM!

briefings/B-0016-cli-reference-overlay-design.md (1)

81-88: LGTM!

Also applies to: 415-456

project-words.txt (1)

261-261: LGTM!

Also applies to: 347-347

src/link-cliref.ts (1)

16-17: LGTM!

Also applies to: 112-112, 132-137, 167-179

src/link-cliref.test.ts (1)

78-109: LGTM!

CHANGELOG.md (1)

34-35: LGTM!


📝 Walkthrough

Walkthrough

The CLI-Reference extractor now discovers pages from sitemap and llms.txt, retains branching-menu directory leaves, and enforces discovery completeness. Crosswalk alias resolution now preserves published menu segments. Documentation, validation baselines, tests, and observed counts were updated.

Changes

CLI-Reference discovery and validation

Layer / File(s) Summary
Combined inventory and discovery gate
src/extract-cliref.ts, src/extract-cliref.test.ts, .github/workflows/qa.yml, VALIDATION.md
Discovery unions sitemap and llms.txt inventories, excludes the section landing page, retains directory leaves, and fails when a trailing category leaf is absent.
Corpus and source-model documentation
DESIGN.md, MANUAL.md, briefings/B-0016-cli-reference-overlay-design.md
Documentation records the 1,070-page corpus, recovered directory leaves, combined inventory sources, and updated overlay counts.
Supporting repository updates
project-words.txt
The project dictionary includes musicswitch and rbswitch.

Crosswalk alias resolution

Layer / File(s) Summary
Published-path alias scoping
src/link-cliref.ts, src/link-cliref.test.ts, CHANGELOG.md
resolveEntry accepts published paths and skips alias segment removal when the segment prefix is a published entry. Tests cover positional scoping and the resulting manual-only links. The changelog records the corrected links.

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

Sequence Diagram(s)

sequenceDiagram
  participant Sitemap
  participant LlmsTxt
  participant Extractor
  participant DiscoveryGate
  Sitemap->>Extractor: provide sitemap URLs
  LlmsTxt->>Extractor: provide Markdown inventory
  Extractor->>DiscoveryGate: submit combined page inventory
  DiscoveryGate-->>Extractor: accept complete directory coverage
Loading
sequenceDiagram
  participant linkEntries
  participant PublishedPaths
  participant resolveEntry
  linkEntries->>PublishedPaths: collect CLI-Reference source paths
  linkEntries->>resolveEntry: resolve path with published paths
  resolveEntry-->>linkEntries: exact, scoped alias, or manual-only link
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive Discovery and positional alias fixes match [#137, #136], but the cli-reference-links.tsv baseline refresh is excluded and cannot be verified. Review cli-reference-links.tsv and confirm the refreshed alias/manual-only rows and pinned counts before merge.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes both primary changes: CLI-Reference discovery and alias-segment scoping.
Out of Scope Changes check ✅ Passed The documented, tested, and source changes support the linked discovery and alias-scoping objectives without unrelated code changes.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/137-cliref-discovery-union

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copilot AI 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.

Pull request overview

Updates the CLI-Reference ingestion and crosswalk logic to match MikroTik’s reshaped Docusaurus CLI Reference, ensuring the extracted corpus is complete and schema links are no longer silently mis-normalized.

Changes:

  • Fix CLI-Reference discovery by taking the union of sitemap.xml and llms.txt, plus add a blocking validation gate to fail on trailing-slash category dirs that would otherwise drop Directory leaves (#137).
  • Scope alias-segment dropping in link-cliref so an alias segment is never dropped when its prefix is itself a published entry, eliminating three incorrect schema links (#136).
  • Refresh documentation, validation rows, QA commentary, and the committed crosswalk baseline to reflect the new corpus shape and counts.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
VALIDATION.md Adds V-cliref-discovery and updates V-cliref-link-drift wording to match the new discovery + baseline model.
src/extract-cliref.ts Implements union-based discovery (sitemap.xmlllms.txt), excludes section index, and adds reconcileTrailingDirs() discovery-shape gate.
src/extract-cliref.test.ts Adds tests for index exclusion, Directory-leaf preservation, and reconcileTrailingDirs() failure/pass behavior.
src/link-cliref.ts Adds prefix-scoping to alias dropping by passing a publishedPaths set into resolveEntry().
src/link-cliref.test.ts Adds unit coverage for prefix-scoping behavior and default/unscoped behavior.
cli-reference-links.tsv Updates the committed crosswalk baseline to the new corpus (967 exact / 0 alias / 110 manual-only / 1,077 entries).
CHANGELOG.md Documents the user-visible fixes for discovery completeness (#137) and crosswalk correctness (#136).
MANUAL.md Updates CLI-Reference overlay documentation (notably page count and discovery method) and references V-cliref-discovery.
DESIGN.md Updates design rationale and adds a “source reshaped” section documenting the new discovery contract and consequences.
briefings/B-0016-cli-reference-overlay-design.md Corrects the earlier category-page conclusion and records the reshaped-corpus findings.
.github/workflows/qa.yml Updates overlay floor commentary to reflect the new observed corpus sizes.
project-words.txt Adds new domain words (musicswitch, rbswitch) to keep spellchecking clean.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/extract-cliref.ts

@mobileskyfi mobileskyfi left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

gh pr review 138 --comment --body "Independent review (Hermes, 2026-08-12) — live census re-derived before reading this PR, so numbers below are re-measured not quoted.

Verified

  • Live sitemap raw CLI locs 1,071 = 814 filtered + 257 trailing. Trailing includes section root -> 256 derived unique. Matches PR counts.
  • llms.txt filtered 1,070 (index excluded) vs 1,071 raw. Union 814 + 256 = 1,070 = llms 1,070 exactly.
  • Derived leaves are real pages: app/app (35 args), caps-man/interface/interface (79 args) each 200 with valid heading and Type Directory. Dropping 256 leaves silently lost the Directory menus.
  • Field-count story: 5,944 on new source was not thinner source, it was the 256 missing Directory menus. After fix ~10,9xx correct.
  • Alias scoping: 3 wrong links poE/qos -> disjoint field sets, prefix-scoping (never drop when prefix is published entry) derives from publication alone. Without guard 3 alias, with guard 0. Overlap filtered∩derived 0 so guard only fires on real published menu.
  • bun test 1,117 pass on this branch, cli-reference-links header 967/0/110 matches fresh live sim.

Nits non-blocking

  1. reconcileTrailingDirs message names llms.txt as missing set but checks union (sitemap u llms). If sitemap later lists leaves, message will mislead while guard stays correct.
  2. --from-cache now needs both _sitemap.txt and _llms.txt cached, CLI help still says single flag. Worth a sentence in --help / MANUAL.
  3. index exclusion scoped to section root only, system/index preserved correctly - no issue, just noting edge handled.

No correctness concerns. The two fixes need each other as PR notes - recovering 256 Directory leaves publishes qos menu which lets guard reach third bad link."

- reconcileTrailingDirs named llms.txt as the missing set, but checks the
  union (sitemap ∪ llms.txt) — misleading if the sitemap later lists the
  leaves while the guard stays correct. Message now names the union.
- Document that --from-cache needs both _sitemap.txt and _llms.txt: since
  #137 llms.txt is a discovery input, not just the sidebar labels. Noted in
  the module usage block and MANUAL.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mobileskyfi

mobileskyfi commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Both actionable nits from the independent review are addressed in 612592a:

Nit 1 — reconcileTrailingDirs message named llms.txt but checks the union. Fixed; message now reads … in the discovered inventory (sitemap ∪ llms.txt) …. Same finding as Copilot's inline thread, resolved there too.

Nit 2 — --from-cache needs both _sitemap.txt and _llms.txt. Documented in the module usage block and in MANUAL.md's overlay bullet. Worth noting the requirement itself is pre-existing (loadTocNames has always thrown without _llms.txt), but it is more load-bearing now: llms.txt went from supplying sidebar labels to being half the page inventory, so a stale or absent cache is no longer a cosmetic failure. That's why it's called out explicitly rather than left implicit.

Nit 3 — index exclusion scoped to the section root. Agreed, no change; system/index is preserved and there's a test pinning both directions.

Thanks for re-deriving the census independently rather than quoting the PR — that's what makes the +820 field delta trustworthy.

@mobileskyfi
mobileskyfi merged commit c606333 into main Aug 12, 2026
9 of 10 checks passed
@mobileskyfi
mobileskyfi deleted the fix/137-cliref-discovery-union branch August 12, 2026 14:20
mobileskyfi added a commit to tikoci/centrs that referenced this pull request Aug 12, 2026
* fix(catalog): discover CLI Reference from both inventories (#285)

MikroTik reshaped the CLI Reference from module pages into per-command leaf
pages whose slug is the CLI path. Fixed upstream in tikoci/rosetta#138; this is
the centrs half.

Discovery was the sitemap alone, which serves a branching menu as a
trailing-slash category URL with no .md of its own. That menu's own entry IS
published, at <dir>/<basename>.md, and listed only in llms.txt. Grounded live
before touching code:

  sitemap 814 U derived <dir>/<basename> 256 = 1,070 = llms.txt (1,071 - index)

Discovery is now the union, with a BLOCKING gate that every sitemap category dir
contributes its leaf — the same assertion rosetta ships as V-cliref-discovery,
so the next reshape fails loudly instead of quietly shrinking the table. A page
only one inventory lists is reported rather than refused: the union already
carries it, and --check fails on the new row anyway. Corpus now reconciles with
rosetta exactly at 1,070 pages / 1,077 entries.

The alias allowlist is empty, and that is the correct state. All 20 source
spellings are gone from the publication and all 20 targets are published
directly. R0/R1/R2 stay asserted so the next entry is refused rather than
absorbed; the R1 test moved to a synthetic allowlist since no live entry exists.

Two paths publish twice as containers under different hardware gates
(/system/health as !i386 and health, /interface/ethernet/switch as musicswitch
and rbswitch). Both halves say the path is navigation, so the row records what
they agree on, exactly as a disagreed gate is dropped rather than picked. Only a
navigation-vs-command split still aborts. Anchored on a new frozen fixture of
the real page; "one entry per page" is explicitly not an invariant.

Catalog: 1,119 -> 1,124 paths, 439 -> 450 commands, and the ancestry-aware
unexplained residue 7 -> 1 (/interface/xfrm).

Corpus differential over the 948-script corpus, old table vs new, harness
verified by reproducing the #249 figures exactly on the old table:

  stmts          18,648 -> 18,648
  argCandidates  14,329 -> 14,336
  argReadable     7,385 ->  7,392
  abstentions     6,944 ->  6,944  (48.4612% -> 48.4375%)
  context-lost       69 ->     83

Six scripts move and every statement in them is a correction. Seven newly
resolve and read; five read the same with the right verb (/ip hotspot user
reset-counters took `hotspot` as the verb, now takes `reset-counters`, which
also reclassifies it as a write). No document changes containsWrite verdict.
context-lost rising is the resolver withdrawing a certainty claim it should
never have had: an unreadable statement might have been an absolute navigation
and so restored context; a known command never navigated.

Live --check is 1m34s cold, inside the QA job's 10-minute budget.

Closes #285

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* review: resolve inventory-drift and test-anchor findings (#286)

Three review findings, all fixed.

Copilot — `discoverSlugs` reported the sitemap-only direction but never the
inverse, while the docstring claimed both. The two directions are NOT symmetric,
and that asymmetry is the shape: every sitemap page is also in llms.txt, but
llms.txt legitimately carries 256 pages the sitemap lacks — those ARE the
category leaves, so reporting them would bury the signal. The residue is what
matters, and is now reported: an llms.txt page that is neither in the sitemap nor
a category leaf has appeared from nowhere.

CodeRabbit — `cliRefPath` used `new URL(link)`, which throws on a root-relative
or document-relative link and so returned null, indistinguishable from "not a
CLI page". Both inventories publish absolute URLs today (verified live), so this
was latent rather than live, but a silent inventory shrink is exactly the #285
defect class. Links now resolve against the document they were read from.

CodeRabbit — split the combined bare-word-head test. The abstention anchor
(`/interface reset`) and the catalog-resolution anchor (`/interface
reset-counters`) are separate mechanisms and now separate tests, so a catalog
change is legible as one.

Both new guards mutation-tested: reverting either fix turns its test red.
`explain:catalog:check` still matches live — the catalog itself is unmoved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants