Resolve property-table columns by header name (#132) + record B-0024 command↔prose join - #133
Conversation
Triage of #131/#132 measured `lookupProperty` directly for the first time and found that #58, #61, and #131 are three symptoms of one structural defect: `commands.page_id` is the only join between rosetta's structure stores (`schema_nodes`/`commands`, `cliref_*`) and its prose store, and it is a nullable scalar, page-grained, and fuzzy. Key findings recorded in the new briefing: - The bridge prose is NOT unreachable. The global fallback returns the correct page-10 `pvid` rows with correct section anchors, labeled `low` and ranked under a corrupted Apps row. The defect is the confidence label and ordering. - Confidence is miscalibrated in both directions — `high` on column-shifted Apps/VETH rows, `low` on correct bridge rows. - `scoreCandidate` simulation: page 10 scores 0 in every case and no segment-matching tweak reaches it, so "link bridge to page 10" is new machinery, not a scorer change. There is no override mechanism today. - Census of all 589 property/parameter tables by header shape: 52 rows column-shifted (Apps, VETH) and 14 fabricated rows from a device-mode feature matrix. #100's audit enumerated zero-yield tables only, so a wrong-yield table was structurally invisible to it. - #132 must land before #100, or 70 more rows ingest with the same column bug. Cross-links added: - B-0023 gains the join as a second, correctness-driven consumer of total section coverage (Option A / `_lead` decision unchanged). - B-0016 Q5 gains its first concrete consumer — the overlay as a correctness input rather than advisory metadata. - B-0001 and B-0011 gain a revisit trigger: the `lookup_property` retirement is conditioned, not overturned. Both fold targets sit on the wrong side of the broken join. Order: fix the join, recalibrate confidence, then decide the surface. - BACKLOG briefings index gains B-0024, and B-0023 which was missing entirely. No user-visible behavior change, so no CHANGELOG bullet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`parseProperties` hardcoded `description: row.cells[1]`, so any property table wider than two columns stored the wrong cell as the description. Measured against the vendored corpus (589 property/parameter tables, 10 distinct header shapes — census in B-0024): - 5 tables are `| Property | Type | Default | Description |` (Apps, VETH). 52 rows stored their **Type** cell as the description with type/default_val left NULL. `|` was only the most *visible* symptom: VETH has no entity in its Type cells, so `address` silently returned "IPv4/IPv6 address" instead of its prose — at `high` confidence, since /interface/veth/add is linked to that page. - 1 table is a five-column `device-mode` feature matrix whose first header cell reads `**Feature / Property**`. It passed the old header regex and minted 14 rows that are not properties at all (`Containers` / type `/container` / description `"No"` — the Home column). Columns are now resolved by normalized header name: `Property`/`Parameter`, optional `Type`, optional `Default`, and a required `Description`. Requiring an explicit Description column is what excludes the feature matrix and `| Parameter | Value |`; both already yielded garbage or nothing. A dedicated Type/Default column wins over the parenthetical annotation in the name cell, falling back when the cell is empty. `|` is decoded once the cell is split — it is table *syntax*, not content. Deliberately narrow: general entity decoding would rewrite `"`/`<` corpus-wide, which is out of scope, and `page_tables.raw_markdown` stays byte-exact either way. The bold-kebab **name** gate is unchanged — broadening what qualifies as a property name is #100's classification work. That ordering matters: the two `| Property | Type | Description |` tables in route-selection-and-filtering.md hold 70 rows that yield nothing today because of that gate. Loosening it before this fix would have ingested them with Type-as-description. Corpus-wide diff of old vs new parser: 4575 -> 4561 rows, changes confined to exactly 3 files (device-mode 18->4, apps 45 corrected in place, veth 7 corrected in place). No collateral change anywhere else. Apps' two `auto-update` records are retained and now differ — they only looked duplicated because the shift replaced both descriptions with the same Type cell. Adds apps.md and veth.md as real fixtures; 22 new tests cover header-shape resolution, both header spellings, the 3- and 4-column shapes, entity decoding, empty-Type fallback, short rows, and the feature-matrix rejection. Closes #132 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR updates ChangesProperty parsing and command-prose join
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@briefings/B-0016-cli-reference-overlay-design.md`:
- Around line 330-338: The CLI-Reference crosswalk must use the complete join:
exact/alias resolution from cliref_entry_schema_links, source_path from
cliref_entries, and the computed field view cliref_field_inspect_links. Update
briefings/B-0016-cli-reference-overlay-design.md lines 330-338 to describe this
stored-entry-link-to-computed-field-view join, and update
briefings/B-0024-command-prose-join.md lines 112-124 to apply the same full join
in corroboration and rejection rules.
In `@briefings/B-0024-command-prose-join.md`:
- Around line 34-59: Update the `#132` measurement sections in this briefing,
including the repeated content around the later referenced range, so they are
explicitly marked as the pre-fix 2026-07-31 baseline or regenerated using the
header-based parseProperties() fix. Remove stale claims that parseProperties()
still hardcodes row.cells[1] and update the “Land `#132` first” future step to
reflect that the parser fix is already applied and documented in CHANGELOG.md.
🪄 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: ASSERTIVE
Plan: Pro Plus
Run ID: 41ed2d67-4666-4f28-9ab5-feeabb572ee2
⛔ Files ignored due to path filters (2)
fixtures/docusaurus/apps.mdis excluded by!fixtures/**fixtures/docusaurus/veth.mdis excluded by!fixtures/**
📒 Files selected for processing (10)
BACKLOG.mdCHANGELOG.mdbriefings/B-0001-lookup-property-broad-fts.mdbriefings/B-0011-tool-surface-review.mdbriefings/B-0016-cli-reference-overlay-design.mdbriefings/B-0023-page-section-normalization.mdbriefings/B-0024-command-prose-join.mdproject-words.txtsrc/extract-docusaurus.test.tssrc/extract-docusaurus.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
*
📄 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:
CHANGELOG.mdBACKLOG.mdproject-words.txt
**/*.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:
CHANGELOG.mdbriefings/B-0024-command-prose-join.mdbriefings/B-0011-tool-surface-review.mdBACKLOG.mdbriefings/B-0023-page-section-normalization.mdbriefings/B-0001-lookup-property-broad-fts.mdbriefings/B-0016-cli-reference-overlay-design.md
CHANGELOG.md
📄 CodeRabbit inference engine (CLAUDE.md)
Record user-visible shipped changes in
CHANGELOG.mdunder[Unreleased]or release sections.
Files:
CHANGELOG.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:
CHANGELOG.mdbriefings/B-0024-command-prose-join.mdbriefings/B-0011-tool-surface-review.mdBACKLOG.mdbriefings/B-0023-page-section-normalization.mdbriefings/B-0001-lookup-property-broad-fts.mdsrc/extract-docusaurus.test.tssrc/extract-docusaurus.tsbriefings/B-0016-cli-reference-overlay-design.md
briefings/B-*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Store grounded research and decision support in
briefings/B-*.md.
Files:
briefings/B-0024-command-prose-join.mdbriefings/B-0011-tool-surface-review.mdbriefings/B-0023-page-section-normalization.mdbriefings/B-0001-lookup-property-broad-fts.mdbriefings/B-0016-cli-reference-overlay-design.md
BACKLOG.md
📄 CodeRabbit inference engine (CLAUDE.md)
Put loose, unshaped thoughts in the
BACKLOG.mdInbox and items waiting on a named external event inBACKLOG.mdTriggers.
Files:
BACKLOG.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, andbunx.Rosetta uses Bun and TypeScript; prefer
bun,bun test, andmake verifywhere applicable, rather than Node/npm-oriented substitutes.
Files:
src/extract-docusaurus.test.tssrc/extract-docusaurus.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-docusaurus.test.tssrc/extract-docusaurus.ts
🪛 LanguageTool
briefings/B-0024-command-prose-join.md
[grammar] ~23-~23: Ensure spelling is correct
Context: ...-07-31 triage of #131/#132 measured the join directly for the first time; that measu...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[style] ~156-~156: Consider using “who” when you are referring to a person instead of an object.
Context: ...ce. The corroborated join is a consumer that is not advisory metadata: it uses t...
(THAT_WHO)
[grammar] ~192-~192: Use a hyphen to join words.
Context: ...ay's behavior). - Cons: unproven end to end (cliref empty locally); cliref cover...
(QB_NEW_EN_HYPHEN)
[style] ~218-~218: Consider using a different verb for a more formal wording.
Context: ... narrowed to), but must not be sold as fixing the reported problem. ### D. Do nothin...
(FIX_RESOLVE)
[style] ~289-~289: ‘out of reach’ might be wordy. Consider a shorter alternative.
Context: ...#61's prose-only properties are still out of reach. Corroboration tells you `/ip/firewal...
(EN_WORDINESS_PREMIUM_OUT_OF_REACH)
briefings/B-0001-lookup-property-broad-fts.md
[style] ~86-~86: Try using more formal phrasing here.
Context: ...ted, exactly as the 2026-07-14 decision already said. Grounding and the proposed join fix: ...
(MENTIONED_PREVIOUSLY)
briefings/B-0016-cli-reference-overlay-design.md
[style] ~335-~335: Consider an alternative for the overused word “exactly”.
Context: ...command→field-name index**, which is exactly what that join lacks: `lookupProperty(n...
(EXACTLY_PRECISELY)
🔇 Additional comments (15)
src/extract-docusaurus.ts (2)
357-415: LGTM!
433-451: LGTM!src/extract-docusaurus.test.ts (6)
37-37: LGTM!
53-54: LGTM!
233-289: LGTM!
291-328: LGTM!
330-351: LGTM!
353-388: LGTM!briefings/B-0016-cli-reference-overlay-design.md (1)
10-13: LGTM!briefings/B-0023-page-section-normalization.md (1)
5-7: LGTM!Also applies to: 189-198
briefings/B-0001-lookup-property-broad-fts.md (1)
5-17: LGTM!Also applies to: 60-89
briefings/B-0011-tool-surface-review.md (1)
5-7: LGTM!Also applies to: 32-40
BACKLOG.md (1)
70-70: LGTM!Also applies to: 80-93
CHANGELOG.md (1)
33-33: LGTM!project-words.txt (1)
229-229: LGTM!Also applies to: 231-231, 233-233, 237-237
Parser (per Codex review on #132): - `resolvePropertyColumns` now requires the name header to be *exactly* `property` or `parameter` after normalization, not merely to contain the word. The device-mode matrix was rejected only because it lacks a Description column; a two-column `| Feature / Property | Description |` would still have fabricated rows. The contract is now enforced by the code rather than by the corpus's present shape. - `normalizeAnnotationCell` strips only *paired* emphasis delimiters, so an unpaired asterisk survives — a default of `*` (wildcard) or a type containing `a*b` was previously deleted. The corpus writes value syntax as several spans in one cell (`*yes* | *no*`), so an outer-wrapper-only rule would not work. Both are behavior-neutral on the current corpus (old vs new parser over manual/pages: 4561 -> 4561 rows, 0 files changed), which is the point — they close holes the corpus does not happen to exercise. Three regression tests added. B-0024 re-grounded (per Codex review on #131 + two CodeRabbit threads): - **Blocker, confirmed empirically on v0.11.2-alpha.109:** CLI-Reference corroboration validates the *query*, not a *candidate row*. All four `properties` rows named `pvid` get the identical "field exists" answer, and no relational edge exists — `properties` has no entry_id/field_id/schema_node_id, and `cliref_entries.page_id` references `cliref_pages`, a different page store from `properties.page_id -> pages`. The claim that it could promote the bridge rows and reject the Apps row was wrong and is removed. - **New Option A, grounded on the artifact:** section-grained menu-path extraction as the discriminating key. Sections `Port Settings` (147) and `Bridge Port Settings` (168) name `/interface/bridge/port` in their own text; Apps' `Properties` (666) names no bridge path. That is the row-level discrimination corroboration cannot provide. Explicitly marked a hypothesis pending a corpus-wide precision/recall pass, not a lean. - CLI-Reference demoted to `(path, name)` validation only, with the complete two-hop crosswalk documented (stored entry link + computed field view) in both B-0024 and B-0016. - Grounding switched to the CI artifact via `make db-sync`. Corrects two errors: the provenance table is `db_meta`, not `meta` (the repo-root DB was never unprovenanced), and `cliref_*` ships populated (228/1,051/10,118/931/13,036), so this was never future homework. - #132 measurements relabeled as the pre-fix v0.11.1 baseline; "land #132 first" marked done in this PR. - #131's reachability claim narrowed: the rows are unreachable through command-grounded lookup (accurate as filed) while remaining globally discoverable at `low`. The earlier "the framing is wrong" over-corrected. - B-0023 corrected throughout: its lead-fragment work landed in PR #105, so B-0024 consumes total section coverage rather than raising its priority. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Codex Review
Independent review at 6ddca0c. The #132 extractor change itself looks solid: an isolated rebuild from the vendored /docs cache produced 4,561 properties, no | descriptions, 18→4 device-mode rows, correct Apps/VETH Type/Default/Description values, distinct properties/properties-1 anchors, source-row provenance, and clean SQLite integrity/FKs. Local validation is also green: 1,069 tests, focused extractor tests, typecheck, Biome, markdownlint, and cspell.
The remaining blockers are documentation/design-state corrections in the inline comments. One additional linked-issue loose end: #132's acceptance bullet currently says device-mode.md contributes zero property rows, but the correct rebuild retains four legitimate rows and removes only the 14 fabricated feature-matrix rows (the PR body correctly says 18→4). Please amend that acceptance bullet to say the feature matrix contributes zero rows so Closes #132 does not leave an apparently unmet criterion.
… text Codex review at 6ddca0c. All four findings valid. **Option A was overstated, and the omission was mine.** The section-grained key was presented as "current lean" with a table listing only the convenient paths. The same artifact I cited already shows it is coarser than that: - `/ip/settings` appears in section 140's text and *passes* `isRouterOsPath()` (`ip` is a top-level menu, src/link-commands.ts:82). I dropped it from the table. The doc-slug filter catches relative links; it does not catch a genuine but unrelated menu mention. - Section 140 is shared by **49** property rows, all inheriting that path set. A fragment-level signal was being presented as a row-level key. The option table now lists every path with its isRouterOsPath verdict struck through or not, records rows-sharing-fragment counts, and is relabeled **hypothesis, not yet a lean**. Step 3 now explicitly measures granularity (properties-per-fragment, paths-per-fragment, unrelated-path rate) alongside accuracy, and names the nearer candidate key Codex points at: `properties.source_table_row_id` -> `page_tables`, which is strictly finer than the section. If coarseness dominates, Option A is a ranking signal, not a key. "current lean" wording corrected in B-0023 and BACKLOG so downstream implementation does not treat the direction as settled. **B-0016 lifecycle text was stale.** It still said #124 was "cleared to implement" and named "#124 landing" as the next trigger. #124 is closed and the overlay shipped via #126/#128. Now records the landed/validated ETL with the shipped counts and leaves the briefing open only for Q3/Q5/Q7/Q8. **B-0023 carried a completed prerequisite as open.** Its decision was implemented in #105 and it ends with "Open questions: None blocking implementation", so per the briefings lifecycle it is now `status: resolved` with a dated resolution note, and the BACKLOG index matches. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codex review at
|
| Section | Page | Rows sharing it | Paths in its own text |
|---|---|---|---|
Port Settings (147) |
10 | 26 | /interface/bridge/port/set, /interface/bridge/port, /virtual-private-networks/eoip |
Bridge Port Settings (168) |
10 | 4 | /interface/bridge/port |
Bridge Interface Setup (140) |
10 | 49 | /interface/bridge, /interface/bridge/host, /ip/settings, /firewall-and-quality-of-service/packet-flow-in-routeros |
Properties (666) |
38 Apps | — | /authentication-authorization-accounting/certificates |
Heading is now "hypothesis, not yet a lean", and step 3 measures granularity (properties-per-fragment, paths-per-fragment, unrelated-path rate) alongside accuracy — with the explicit out that if coarseness dominates, Option A is a ranking signal rather than a key.
I also took your "nearer row/table-to-sub-menu key" hint concretely: properties.source_table_row_id → page_table_rows → page_tables gives each property its own table with its own source_heading, strictly finer than the section (140's 49 rows span more than one table). Named as a co-equal candidate to measure, not an assumption.
"current lean" wording corrected in B-0023 and BACKLOG too.
2. B-0016 lifecycle text updated
Replaced the stale "cleared to implement" / "stays open until #124's extractor lands" / "next trigger: #124 landing" text with the landed-and-validated state (#124 closed, shipped via #126/#128, with the v0.11.2-alpha.109 counts and the two CI gates). Q1/Q2/Q4/Q6/Q9/Q10 marked settled and implemented; the briefing stays open only for Q3, Q5, Q7, Q8, with the next trigger now an answer to Q3 on #25.
3. B-0023 closed out
Right — it ends with "None blocking implementation" and its work landed in #105, so carrying it as open contradicted the briefings lifecycle. Now status: resolved with a dated note pointing the follow-on join work at B-0024, and the BACKLOG index matches.
4. #132 acceptance bullet corrected
Posted as a correction on the issue: my bullet said "device-mode.md contributes zero property rows", which is wrong — only the feature matrix contributes zero. The page's real List of available properties table keeps its four legitimate rows (activation-timeout, flagging-enabled, flagged, advanced), so 18 → 4 as the PR body says. Closes #132 no longer has an unmet criterion.
Suite 1069 pass / 0 fail; make lint green.
mobileskyfi
left a comment
There was a problem hiding this comment.
Follow-up review at 885f34c: two original threads are fully addressed and resolved. The B-0024 design thread remains open because the proposed table-grained correction does not match the cited artifact. One additional stale cross-reference is inline below.
Codex re-review at 885f34c. Both findings valid and verified on v0.11.2-alpha.109. **The table-grained "nearer key" was wrong.** I claimed section 140's 49 rows span more than one table. They do not: all 49 point into a single page_tables row (id 70, 49 data rows, zero properties lacking source_table_row_id). Its source_heading is the bare text "Bridge Interface Setup" with no path, and the paths inside its own raw_markdown are the *same set* the section yields — /interface/bridge x2, /interface/bridge/host, and /ip/settings. So table granularity collapses onto section granularity here and cannot improve the example at all; the finding is slightly stronger than the review stated. Reframed as what would actually help: a nearest-preceding-menu-path (proximity) join. The /interface/bridge submenu context precedes the table in source order, so the discriminating signal is proximity to the property's own row — which needs source-position provenance the schema does not carry today. Recorded as a candidate requiring new provenance, not an existing key to switch to. Step 3 now measures tables-per-section distribution (before assuming a finer structural fragment exists) and proximity-join feasibility. Also corrected: Apps section 666 has 14 properties, not "—". **The demotion had not propagated.** B-0016 still called fragment alignment "B-0024's discriminating key"; B-0023 (note + cross-reference) and the BACKLOG B-0023 row still said "section→command join", which reads as settled. All now describe the open work as the command↔prose join evaluating fragment/proximity signals, with section granularity explicitly not established as its key. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two commits: the #132 extraction fix, and the briefing that came out of triaging #131/#132 together.
Resolve property-table columns by header name— closes #132parsePropertieshardcodeddescription: row.cells[1], so any property table wider than two columns stored the wrong cell as the description.Census of all 589 property/parameter tables in the vendored corpus (10 distinct header shapes):
Property|Description,Parameter|DescriptionProperty | Description |(ragged)Property|Type|Default|DescriptionProperty|Type|DescriptionParameter|Description|ExampleFeature / Property|Home|Basic|Advanced|ROSEParameter|Value· 1Menu|Parameter names|Page link|was only the most visible symptom. VETH has no entity in its Type cells, soaddresssilently returned"IPv4/IPv6 address"instead of its prose — athighconfidence, since/interface/veth/addis linked to that page.The
device-modecase was not in the issue as filed: a five-column feature matrix whose first header cell reads `Feature / Property` passed the old header regex and minted 14 rows that are not properties at all (`Containers` / type `/container` / description `"No"` — the Home column). #100's audit could not have caught it: that audit enumerated tables yielding zero properties, and this one yields garbage.What changed: columns resolve by normalized header name — `Property`/`Parameter`, optional `Type`, optional `Default`, and a required `Description`. Requiring Description is what excludes the feature matrix and `| Parameter | Value |`; both already yielded garbage or nothing, so nothing real is lost. A dedicated Type/Default column wins over the parenthetical annotation in the name cell, falling back when empty. `|` is decoded once the cell is split — it's table syntax, not content; deliberately narrow, since general entity decoding would rewrite `"`/`<` corpus-wide.
The name gate is unchanged — that's #100's classification work. The ordering is load-bearing: the two `Property|Type|Description` tables hold 70 rows that yield nothing today because of that gate, so loosening it first would have ingested them with Type-as-description.
Blast radius — old vs new parser over the whole corpus: 4575 → 4561 rows, changes confined to exactly 3 files (device-mode 18→4, apps 45 corrected in place, veth 7 corrected in place). No collateral change anywhere else.
Apps' two `auto-update` records are retained and now differ — they only looked duplicated because the shift replaced both descriptions with the same Type cell. Not deduped.
Adds `apps.md`/`veth.md` as real fixtures; 22 new tests. Full suite 1066 pass / 0 fail; `make lint` green.
Record B-0024: the command↔prose joinBriefing only, no behavior change. Triage found #58, #61, and #131 are three symptoms of one defect: `commands.page_id` is the only join between the structure stores and the prose store, and it's a fuzzy, page-grained scalar.
The measurement that reframed it — `lookupProperty` confidence is miscalibrated in both directions:
So #131's "prose is unreachable" framing is wrong (it's returned, just mislabeled and ranked under the corrupted Apps row — which this PR's first commit fixes), and linking bridge → page 27 would fix nothing (page 27 has zero properties; page 10 scores 0 unreachably).
Cross-links: B-0023 gains a second, correctness-driven consumer; B-0016 Q5 gains its first concrete consumer; B-0001/B-0011's `lookup_property` retirement is conditioned, not overturned — both fold targets sit on the wrong side of the broken join. Order: fix the join, recalibrate confidence, then decide the surface. BACKLOG index also gains B-0023, which was missing entirely.
🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Documentation