Rosetta convergence arc + rung-stratified standing wave + anti-eigenvalue guards (36 commits)#852
Conversation
…ce-outranks-translation + independence weighting + doctrinal-vocab flag
… shape, stemma measured not asserted
…lta as anomaly magnitude; metric-x-taxonomy verdict table
…s in flight); gitignore keeps all rosetta generators
… wrong-sense; versification is per-edition)
…r 44%->4% unresolved
…class_guess flagged near-vacuous
…, fetch script ends WNDB ephemerality
…ured ladder-usefulness; coca rank column tech debt
… unwired; name the pass-rung-recipe edge
… ride the tail via trajectory meta-basins; suggestion-only outliers
…ntissa + read-as-of bound
…+ loud schema mismatch; redact private-store paths from source
… (budget-exhaustion != out-of-horizon)
…0), redirect to alignment transfer
…ass transfer successor
…tests is not a test
…ouse style promoted to a rule
…ategorical, None a real group
…n PMI, coverage cliff stated
… — conflation now unrepresentable
…capable; predicted-better refused as unmeasurable here
…s assertions replaced, closed-class transfer = 2nd negative
…rache/sprachen into two fold keys
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c11b71ad-f177-46aa-969c-56bbfc1f2da3) |
|
Warning Review limit reached
Next review available in: 41 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR adds Rosetta convergence plans and analysis records, separates witness-resolution outcomes, introduces temporal and spatial trajectory APIs, integrates rung-aware planner reliability and advisory outlier detection, instruments CAM-PQ rejection behavior, tightens tests, and updates governance and data-loading documentation. ChangesConvergence and governance
Witness and planner behavior
Scan and validation behavior
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Planner
participant PlanContext
participant WitnessWindow
participant StyleStrategy
participant RecipeCatalog
Planner->>PlanContext: attach optional witness window
PlanContext->>WitnessWindow: derive causal rung
WitnessWindow->>StyleStrategy: provide rung-aware context
StyleStrategy->>RecipeCatalog: select admissible recipes
RecipeCatalog-->>StyleStrategy: return recipes and peripheral set
StyleStrategy-->>Planner: return stratified reliability and plan
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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 |
…aration step (reader-state profile) before the register
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0dc581816b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for m in &self.members { | ||
| let t = trajectory_of(m.idx, window, locus, perturbed_hops); |
There was a problem hiding this comment.
Recompute complete basin membership after perturbation
When a row outside this basin changes to the same hop/escalation shape at the perturbed budget, this loop examines only the existing members and returns true, even though the basin has merged and no longer has the same member set promised by the API. coarse_flags consequently suppresses UnstableBasin suggestions for a grouping that changed; re-cluster the complete window at the perturbed budget and compare member indices.
Useful? React with 👍 / 👎.
| for watcher in rung.peripheral_sample(k) { | ||
| // Only watchers this style would ever fire are informative — a | ||
| // mechanism the style never selects is off-character, not dissent. | ||
| if watcher.mechanism != Self::cluster_mechanism(style.cluster()) { | ||
| continue; |
There was a problem hiding this comment.
Filter watchers before consuming the sample budget
Because the global periphery is sampled before filtering by the style's mechanism, ineligible recipes consume the entire k budget and can make this return None without observing any relevant tactic. For example, at Shallow with k = 8, the fixed catalogue's strided sample contains no TruthAwareInference recipe, so the default Analytical style reports agreement despite having several excluded truth-aware watchers; filter to the style's mechanism before spread-sampling, or continue until k eligible watchers have run.
Useful? React with 👍 / 👎.
…ase shipped (3 regime bundles)
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_11fd0097-bb05-4146-91dc-277d7b4751b5) |
There was a problem hiding this comment.
Actionable comments posted: 18
🧹 Nitpick comments (16)
crates/lance-graph-planner/src/physical/cam_pq_scan.rs (4)
464-473: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Self::adcnow duplicates the inline 6-term sum infull_adc/cascade.The uninstrumented paths still spell out the same expression twice. Reusing this helper there keeps the distance definition single-sourced without changing behavior (
#[inline]keeps the cost identical).🤖 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 `@crates/lance-graph-planner/src/physical/cam_pq_scan.rs` around lines 464 - 473, Update the uninstrumented distance calculations in full_adc and cascade to call the existing adc helper instead of duplicating the six-term lookup sum. Preserve the current inputs and behavior while keeping adc as the single source for the full 6-subspace ADC distance.
176-178: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueField name reads opposite to its value.
worst_miss_rankstores the lowest rank (computed viarank < worst_miss_rank), i.e. the best placement a probed reject would have taken. The doc comment has to correct the name. Since this is a fresh public field, considerbest_miss_rankordeepest_miss_rankwhile renaming is still free.🤖 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 `@crates/lance-graph-planner/src/physical/cam_pq_scan.rs` around lines 176 - 178, Rename the public field worst_miss_rank to best_miss_rank in its definition and all references, preserving its usize type and existing lowest-rank calculation. Update the associated documentation to describe the best (lowest, 0-based) rank a probed reject would have occupied.
978-980: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTest name claims more than the body checks.
disabled_policy_is_bit_identical_and_allocation_freeverifies bit-identity but nothing about allocations. Either drop_and_allocation_freeor assert it (e.g. a counting allocator behind a test-only global).🤖 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 `@crates/lance-graph-planner/src/physical/cam_pq_scan.rs` around lines 978 - 980, Rename disabled_policy_is_bit_identical_and_allocation_free to remove the unverified allocation-free claim, unless the test is extended with a test-only counting allocator that asserts no allocations occur. Preserve its existing bit-identity assertions.
533-539: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExpose or consume the scan strategy at the public API.
ScanOutcome::strategydocuments exact-over-ADC vs threshold-pruned semantics, butCamSearch::top_kcurrently runsexecute_observedand still returns onlyVec<(usize, f32)>, so clients cannot carry that indicator forward. Add atop_k_observed/outcome return, or expose a focused field if callers only needstrategy.is_exact_over_adc.🤖 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 `@crates/lance-graph-planner/src/physical/cam_pq_scan.rs` around lines 533 - 539, The public CamSearch API must expose the strategy selected by the scan instead of discarding it in CamSearch::top_k. Add a top_k_observed-style method returning the scan outcome, or otherwise expose the focused strategy indicator, while preserving existing top_k behavior for callers that only need Vec<(usize, f32)>; ensure callers can inspect strategy.is_exact_over_adc.crates/bgz-tensor/src/cascade.rs (1)
350-364: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe rate band cannot fail once the exact counts are asserted.
elimination_rate()is(eliminated_at[0] + eliminated_at[1]) / total, and both terms are pinned above, so(0.05..0.08).contains(&rate)is implied by the preceding assertions — no input reaching this line can fail it. Fine if kept purely as documentation, but the comment presents it as an independent bound. Consider stating it as a derived restatement (or drop it) so the anti-vacuity rule isn't undercut in the very test enforcing it.As per coding guidelines: "Tests must be falsifiable: identify an input that can make each assertion fail".
🤖 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 `@crates/bgz-tensor/src/cascade.rs` around lines 350 - 364, Update the rate assertion around stats.elimination_rate() so it is clearly documented as a derived restatement of the already-pinned elimination counts, not an independent falsifiable check; alternatively remove the redundant assertion. Preserve the exact count assertions and avoid presenting the rate band as an additional anti-vacuity condition.Source: Coding guidelines
crates/lance-graph-contract/src/witness_fabric.rs (1)
310-334: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDeduplicate the two budget loops —
standing_wave_groundedcan delegate tostanding_wave_stratified.The two loops are line-for-line identical apart from the return payload, and the doc itself says they "MUST stay in verdict parity" enforced only by a test. Delegation makes the parity structural rather than pinned.
Also, the fallthrough comment at Lines 445-448 ("causal at the FIRST pass") is only reachable when
passes <= 1; for a real single-hop terminal chain the loop returns at budget 2, as the doc at Lines 390-398 andcheap_settle_normalizes_to_a_shallow_rungstate. Worth rewording so the two comments don't contradict.♻️ Proposed delegation
pub fn standing_wave_grounded( focal_idx: usize, window: &[(usize, CausalWitnessFacet)], locus: Locus, passes: u8, ) -> WaveGrounding { - // ... duplicated budget loop ... + standing_wave_stratified(focal_idx, window, locus, passes).0 }Also applies to: 418-454
🤖 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 `@crates/lance-graph-contract/src/witness_fabric.rs` around lines 310 - 334, Update standing_wave_grounded to delegate its resolution loop to standing_wave_stratified, converting the stratified result into the grounded return payload so both paths share identical budget and horizon behavior. Remove the duplicated loop and revise the fallthrough comment near the grounded path to describe only the passes <= 1 case, avoiding conflict with the normal single-hop terminal-chain behavior.crates/lance-graph-planner/src/strategy/style_strategy.rs (1)
128-149: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueHoist the admitted-set replay out of the watcher loop.
ThoughtCtxisClone, so the baseline admitted-setThoughtCtxcan be built once outside the watcher loop and cloned per watcher, avoidingk × |admissible|replay executions.🤖 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 `@crates/lance-graph-planner/src/strategy/style_strategy.rs` around lines 128 - 149, Move the admitted-set recipe replay out of the watcher loop in the surrounding strategy method. Build one baseline ThoughtCtx after computing admitted by running recipes_for_at(style, rung), then clone that context for each eligible watcher before running its kernel; preserve the existing mechanism, missing-kernel, confidence, and min_rung behavior.crates/lance-graph-planner/examples/data/rosetta/closed_class_transfer.py (1)
122-133: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTSV loaders silently drop malformed rows with no counter or warning.
load_coca_reliable_closed,load_de_lexicon, andload_codebook_verse_dfallcontinueon a row that doesn't match the expected column count, with no counter or log line. If a schema drifts (same failure class as thecoca/lexicon.tsvissues just documented inTECH_DEBT.md), these functions will quietly under-populate their dictionaries with zero visibility — the exact silent-drop anti-pattern this PR's own audit trail elsewhere identifies as the highest-severity failure mode in the codebase.♻️ Example: make the skip visible in one loader
def load_codebook_verse_df(path: Path) -> dict[str, int]: out = {} + skipped = 0 with path.open(encoding="utf-8") as f: header_seen = False for line in f: if line.startswith("#"): continue if not header_seen: header_seen = True continue parts = line.rstrip("\n").split("\t") if len(parts) != 7: + skipped += 1 continue token, _freq, verse_df, *_rest = parts out[token] = int(verse_df) + if skipped: + print(f"warning: skipped {skipped} malformed rows in {path}", file=sys.stderr) return outAlso applies to: 188-199, 271-288
🤖 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 `@crates/lance-graph-planner/examples/data/rosetta/closed_class_transfer.py` around lines 122 - 133, Make malformed TSV-row handling observable in load_coca_reliable_closed, load_de_lexicon, and load_codebook_verse_df: when a row has fewer columns than its expected schema, increment a skipped-row counter and emit a warning or summary log identifying the loader and count. Preserve skipping invalid rows, but ensure each loader reports malformed-row occurrences instead of silently under-populating its results.crates/lance-graph-planner/examples/data/rosetta/build_rosetta_probe.py (2)
126-139: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winIntersection computed three times per candidate/associate pair.
wks & gksis materialised at Line 136, again insidepmi(Line 127), and a third time at Line 139. This is the hot loop (~|cand| × |de_items| pairs, two passes); computing it once is a straightforward win.♻️ Proposed refactor
- def pmi(a: set, b: set) -> float: - co = len(a & b) - if co < 5: - return -9.0 - return math.log2(co * n_v / (len(a) * len(b))) + def pmi(a: set, b: set, co: int) -> float: + if co < 5: + return -9.0 + return math.log2(co * n_v / (len(a) * len(b))) split_rows, split_hist = [], Counter() for w, wks in cand: assoc = [] for g, gks in de_items: - if len(wks & gks) >= 5: - s = pmi(wks, gks) - if s >= 3.0: - assoc.append((s, g, wks & gks)) + cov = wks & gks + if len(cov) >= 5: + s = pmi(wks, gks, len(cov)) + if s >= 3.0: + assoc.append((s, g, cov))🤖 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 `@crates/lance-graph-planner/examples/data/rosetta/build_rosetta_probe.py` around lines 126 - 139, Update the nested candidate/associate loop around pmi to compute wks & gks once per pair, reuse that intersection for the minimum-size check and assoc tuple, and adjust pmi to accept the precomputed intersection while preserving the existing PMI threshold behavior.
281-299: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUnused
split_rows_raw; andnormalize_deis run twice over the full vocabulary.Ruff flags
split_rows_raw(Line 281) as never used — only the histogram feeds the report. Separately, Lines 293-299 normalise every surface term twice;stem_groupsalone yields both stats.♻️ Proposed refactor
- split_rows_raw, split_hist_raw = compute_split_census(cand, de_items_raw, n_v) + _split_rows_raw, split_hist_raw = compute_split_census(cand, de_items_raw, n_v) @@ - norm_stems = {normalize_de(t) for t in de_surface_terms} - n_merged = len(de_surface_terms) - len(norm_stems) - # how many stems actually absorbed >=2 distinct surface forms stem_groups = defaultdict(set) for t in de_surface_terms: stem_groups[normalize_de(t)].add(t) + norm_stems = set(stem_groups) + n_merged = len(de_surface_terms) - len(norm_stems) + # how many stems actually absorbed >=2 distinct surface forms n_folding_stems = sum(1 for ws in stem_groups.values() if len(ws) > 1)🤖 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 `@crates/lance-graph-planner/examples/data/rosetta/build_rosetta_probe.py` around lines 281 - 299, Remove the unused split_rows_raw binding while preserving the split_hist_raw result used for reporting. Refactor the normaliser merge-statistics block around stem_groups to call normalize_de once per de_surface_terms entry, then derive both n_merged and n_folding_stems from those grouped results.Source: Linters/SAST tools
crates/lance-graph-planner/examples/data/rosetta/build_versification_map.py (3)
96-98: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueOnly the verse-initial word is skipped, not each sentence-initial word.
The comment claims sentence-initial capitals are excluded, but a multi-sentence verse still contributes the capital after every
./;as an "anchor". This adds symmetric noise to both scoring passes so the payoff delta stands, but the docstring on Line 92-93 overstates the filter.🤖 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 `@crates/lance-graph-planner/examples/data/rosetta/build_versification_map.py` around lines 96 - 98, The word-filtering loop should skip only the verse-initial word, not words following sentence boundaries such as “.” or “;”. Update the comment/docstring near the loop to describe verse-initial exclusion accurately, while preserving the existing anchor scoring behavior for later sentence-initial words.
258-261: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueRe-parses
bible_kjv.jsona second time just for book names.
load_lanealready parsed this file at Line 211; returning anr -> namemap from it avoids a full duplicate JSON parse of a multi-MB corpus.🤖 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 `@crates/lance-graph-planner/examples/data/rosetta/build_versification_map.py` around lines 258 - 261, Update load_lane to return the parsed Bible data or an accompanying nr-to-name map when it reads bible_kjv.json, then reuse that result for book_names instead of reading and parsing the file again in the displayed build flow. Remove the duplicate json.loads call while preserving the existing book name mapping behavior.
296-302: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
testable_beforeandtestable_afterare equal by construction.
testableis incremented purely from KJV tokens (Lines 298-302), independent ofuse_offsets, so the report's "should match" line can never fail. Given this PR's own push against vacuous assertions, either drop the comparison or turn it into a real invariant check (e.g. assert equality and fail loudly).Also applies to: 376-379
🤖 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 `@crates/lance-graph-planner/examples/data/rosetta/build_versification_map.py` around lines 296 - 302, Remove the vacuous testable_before/testable_after comparison from the report. In the versification-map counting flow around testable and the use_offsets branches, also remove any now-unused counters or output that claims the counts should match, since testable is derived identically in both cases.crates/lance-graph-planner/examples/data/wordnet/build_wordnet_rail.py (3)
379-386: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winSecond full parse of the v1 TSV just to print its row count.
load_v1_tsv(V1_TSV_PATH)is re-run inside the f-string afterv1_rowswas already truncated; capture the length before slicing.♻️ Proposed refactor
v1_rows = load_v1_tsv(V1_TSV_PATH) + total_v1 = len(v1_rows) if sample and sample > 0: v1_rows = v1_rows[:sample] sample_note = ( - f"**SAMPLE run**: first {sample} of {sum(1 for _ in load_v1_tsv(V1_TSV_PATH))} " + f"**SAMPLE run**: first {sample} of {total_v1} " "v1 rows only (deterministic prefix of the file, not random). " "Use `--sample 0` (or omit `--sample`) for the full audit." )🤖 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 `@crates/lance-graph-planner/examples/data/wordnet/build_wordnet_rail.py` around lines 379 - 386, Update the sample-count logic around load_v1_tsv and v1_rows to capture the original row count before truncating v1_rows, then use that stored count in sample_note instead of parsing V1_TSV_PATH again. Preserve the existing deterministic-prefix wording and full-audit behavior.
512-518: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueHand-rolled argv parsing; prefer
argparsefor consistency.
--samplewith a non-integer raises an uncaughtValueError, and a bare trailing--sampleis silently ignored. The siblingbuild_rosetta_probe.pyalready usesargparse.🤖 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 `@crates/lance-graph-planner/examples/data/wordnet/build_wordnet_rail.py` around lines 512 - 518, Update main to use argparse for --verify and --sample instead of manually inspecting sys.argv, with --sample typed as an integer and its value required. Match the established argparse pattern in build_rosetta_probe.py, preserving the existing defaults and verify behavior while allowing argparse to report invalid or missing sample values.
119-204: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftThird copy of the WNDB loader — reuse
tier_delta.WordNetDbinstead.
Synset,WordNetDb._load_data,_load_index, andfind_wndb_dirhere are near-verbatim reimplementations ofcrates/lance-graph-planner/examples/data/wordnet/tier_delta.py(Lines 132-229).coca_wordnet_convergence.pyalready establishes the pattern of importingtier_delta's loader via importlib rather than re-parsing WNDB. The only genuine delta is that this copy keeps the pointer symbol (kind_sym) alongside the target — a small addition to the canonicalSynsetcovers it, and then all three consumers share one parser (and one place to fix any wndb-format edge case).🤖 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 `@crates/lance-graph-planner/examples/data/wordnet/build_wordnet_rail.py` around lines 119 - 204, The wordnet rail duplicates the WNDB parser instead of using the canonical tier_delta.WordNetDb. Remove the local Synset and WordNetDb loading implementations, import and reuse tier_delta’s loader following coca_wordnet_convergence.py’s importlib pattern, and extend the canonical Synset pointer representation only as needed to preserve kind_sym for hypernym_word consumers. Update this module’s callers to use the shared loader while retaining existing sense ordering and hypernym behavior.
🤖 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 @.claude/board/EPIPHANIES.md:
- Around line 4497-4498: Preserve the board audit trail by restoring the
original prose at .claude/board/EPIPHANIES.md lines 4497-4498 and 3970-3974, and
append dated correction entries stating the numbers are not recorded in this
repo and scoping the brick-3 claim to the probe run. Restore the original
“Locked”/“Privacy split” line at .claude/board/PR_ARC_INVENTORY.md line 408 and
“Cross-ref” line at line 418, then append corrections removing private
restore-log references going forward; limit edits to prior entries’
Status/Confidence lines otherwise.
In @.claude/board/exec-runs/rcc-splitcensus.txt:
- Around line 78-81: Correct the verification statement in the split-census
report so the before/after metrics remain paired: report 1501 with 48.9% for the
before run and 1319 with 43.0% for the after run. Update only the inconsistent
numeric summary; preserve the claim that the flag adds a report section without
changing existing census numbers.
In @.claude/board/TECH_DEBT.md:
- Around line 3192-3238: Move the TD-COCA-LEXICON-RANK-UNRELIABLE-AT-HEAD and
TD-COCA-LEXICON-POS-UNUSABLE-FOR-FUNCTION-WORDS sections to the top of
.claude/board/TECH_DEBT.md, before TD-FLEET-CADENCE, while preserving the
existing order and content of all prior entries.
In `@crates/lance-graph-contract/src/witness_fabric.rs`:
- Around line 1448-1451: Replace the structural equality check in the
disjointness assertion near the superseded/runs validation with a comparison of
the relevant run identity fields, such as span and first_revision, so the
assertion can detect an actual overlap with runs.last(). Preserve the existing
assertion message and neighbouring length check.
In `@crates/lance-graph-planner/examples/data/rosetta/build_alignment.py`:
- Around line 148-180: Update the "-es" handling in normalize_en so a trailing
"s" in stem_no_es is treated as a genuine sibilant plural only when the stem has
a doubled sibilant consonant, while preserving the existing handling for x, z,
ch, and sh endings. Otherwise strip only the final plural "s" so silent-e forms
such as house/houses normalize to the same key, without changing the surrounding
suffix rules.
In `@crates/lance-graph-planner/examples/data/rosetta/build_rosetta_probe.py`:
- Around line 234-235: Update the row-cap condition in the loop around the name
check to use the number of accumulated output rows in lines rather than
receipts. Preserve the special-case inclusion for name == "swallow", while
ensuring other anchors stop appending rows once the intended 400-row cap is
reached.
- Around line 349-351: Correct the generated report text in the descriptive
string near the probe output so the example reads “gut/gute/guten” instead of
repeating “guten”; preserve the surrounding explanation and stated two-stem
behavior.
In `@crates/lance-graph-planner/examples/data/rosetta/closed_class_transfer.py`:
- Around line 412-416: Replace the session-specific absolute fallback in main’s
scratch_dir initialization with a portable default, such as a
repository-relative or system temporary directory, while preserving the explicit
sys.argv[1] override.
In `@crates/lance-graph-planner/examples/data/rosetta/fetch_greek_lane.py`:
- Line 220: Update the data acquisition flow in the argument handling around
args.no_fetch, translations.json loading, and the Tischendorf branch so
--no-fetch never performs network requests. Require cached files when the flag
is set, and fail clearly if any required cache is absent; retain the existing
fetch behavior when --no-fetch is not provided.
- Around line 100-116: Update scratchpad_dir() to remove the session-specific
hardcoded fallback path. Preserve support for the ROSETTA_SCRATCH_DIR
environment override, and replace the fallback with a reproducible,
environment-independent location derived from the repository or script context
that matches the sibling lane data layout.
In `@crates/lance-graph-planner/examples/data/wordnet/build_wordnet_rail.py`:
- Around line 403-413: Update the per-POS accounting in the v1_rows loop to
track a comparable-row count separately from by_pos_total, incrementing it only
after ABSENT rows are skipped. Use that per-POS comparable count as the
denominator for the By-POS error-rate calculation near the existing reporting
logic, while preserving total-row counts and wrong-row tracking.
In `@crates/lance-graph-planner/examples/data/wordnet/tier_delta.py`:
- Around line 132-142: Remove the unconditional /tmp/wn/dict candidate from
tier_delta.py’s find_wndb_dir, or gate it behind an explicit --allow-tmp-wndb
flag or environment opt-in, and report the selected candidate. In
build_wordnet_rail.py, remove the duplicate find_wndb_dir and reuse the gated
implementation from tier_delta.py; apply these changes at
crates/lance-graph-planner/examples/data/wordnet/tier_delta.py:132-142 and
crates/lance-graph-planner/examples/data/wordnet/build_wordnet_rail.py:106-116.
- Around line 423-427: Update tier_delta to validate both word_a and word_b
against the WordNet vocabulary before computing ancestors, returning ABSENT for
either missing word. Hoist a precomputed known_words set into __init__ and reuse
it for O(1) membership checks instead of scanning hypernym_of; preserve the
existing result behavior when both words are known.
In `@crates/lance-graph-planner/examples/insight_reason_wired.rs`:
- Around line 98-127: Add a falsifiable test for the schema-mismatch guard in
Basins::load, using a synthetic non-empty 7-column TSV fixture and asserting
that loading returns Err. Exercise the existing rails.is_empty() && wrong_arity
> 0 path directly, preserving normal parsing behavior for valid 4-column rows.
- Around line 97-117: Update the parsing flow around wrong_arity and rails so
any nonzero wrong_arity is surfaced, not only when rails is empty. Preserve
valid 4-column rail entries, but emit the existing error or skip signal when
mixed-schema input contains malformed rows, including when valid rails were also
collected.
In `@crates/lance-graph-planner/src/nars/meta_basin.rs`:
- Around line 703-720: Extend
perturbation_marks_budget_artifacts_and_spares_singletons with a fixture that
produces a basin containing multiple members and assert
stable_under_perturbation returns false for a budget perturbation that dissolves
it. Keep the existing singleton and no-panic coverage, and ensure the new
assertion exercises the unstable branch rather than accepting any result.
- Around line 486-501: Update stability_around to keep the sweep window centered
on max_hops when the upper bound is capped, while preserving bounded probing and
including max_hops itself. Adjust the budgets construction and any associated
range documentation so the resulting stability query reflects budgets plausible
for the caller.
In `@crates/lance-graph-planner/src/physical/cam_pq_scan.rs`:
- Around line 695-703: Replace the anti-vacuity assertion in the instrumented
cascade test with a check based on the survivor count, computed as cams.len()
minus rejects.heuristic_len(), rather than results.len(). Keep the existing
results length assertion and rejects.heuristic_len() assertion unchanged.
---
Nitpick comments:
In `@crates/bgz-tensor/src/cascade.rs`:
- Around line 350-364: Update the rate assertion around stats.elimination_rate()
so it is clearly documented as a derived restatement of the already-pinned
elimination counts, not an independent falsifiable check; alternatively remove
the redundant assertion. Preserve the exact count assertions and avoid
presenting the rate band as an additional anti-vacuity condition.
In `@crates/lance-graph-contract/src/witness_fabric.rs`:
- Around line 310-334: Update standing_wave_grounded to delegate its resolution
loop to standing_wave_stratified, converting the stratified result into the
grounded return payload so both paths share identical budget and horizon
behavior. Remove the duplicated loop and revise the fallthrough comment near the
grounded path to describe only the passes <= 1 case, avoiding conflict with the
normal single-hop terminal-chain behavior.
In `@crates/lance-graph-planner/examples/data/rosetta/build_rosetta_probe.py`:
- Around line 126-139: Update the nested candidate/associate loop around pmi to
compute wks & gks once per pair, reuse that intersection for the minimum-size
check and assoc tuple, and adjust pmi to accept the precomputed intersection
while preserving the existing PMI threshold behavior.
- Around line 281-299: Remove the unused split_rows_raw binding while preserving
the split_hist_raw result used for reporting. Refactor the normaliser
merge-statistics block around stem_groups to call normalize_de once per
de_surface_terms entry, then derive both n_merged and n_folding_stems from those
grouped results.
In `@crates/lance-graph-planner/examples/data/rosetta/build_versification_map.py`:
- Around line 96-98: The word-filtering loop should skip only the verse-initial
word, not words following sentence boundaries such as “.” or “;”. Update the
comment/docstring near the loop to describe verse-initial exclusion accurately,
while preserving the existing anchor scoring behavior for later sentence-initial
words.
- Around line 258-261: Update load_lane to return the parsed Bible data or an
accompanying nr-to-name map when it reads bible_kjv.json, then reuse that result
for book_names instead of reading and parsing the file again in the displayed
build flow. Remove the duplicate json.loads call while preserving the existing
book name mapping behavior.
- Around line 296-302: Remove the vacuous testable_before/testable_after
comparison from the report. In the versification-map counting flow around
testable and the use_offsets branches, also remove any now-unused counters or
output that claims the counts should match, since testable is derived
identically in both cases.
In `@crates/lance-graph-planner/examples/data/rosetta/closed_class_transfer.py`:
- Around line 122-133: Make malformed TSV-row handling observable in
load_coca_reliable_closed, load_de_lexicon, and load_codebook_verse_df: when a
row has fewer columns than its expected schema, increment a skipped-row counter
and emit a warning or summary log identifying the loader and count. Preserve
skipping invalid rows, but ensure each loader reports malformed-row occurrences
instead of silently under-populating its results.
In `@crates/lance-graph-planner/examples/data/wordnet/build_wordnet_rail.py`:
- Around line 379-386: Update the sample-count logic around load_v1_tsv and
v1_rows to capture the original row count before truncating v1_rows, then use
that stored count in sample_note instead of parsing V1_TSV_PATH again. Preserve
the existing deterministic-prefix wording and full-audit behavior.
- Around line 512-518: Update main to use argparse for --verify and --sample
instead of manually inspecting sys.argv, with --sample typed as an integer and
its value required. Match the established argparse pattern in
build_rosetta_probe.py, preserving the existing defaults and verify behavior
while allowing argparse to report invalid or missing sample values.
- Around line 119-204: The wordnet rail duplicates the WNDB parser instead of
using the canonical tier_delta.WordNetDb. Remove the local Synset and WordNetDb
loading implementations, import and reuse tier_delta’s loader following
coca_wordnet_convergence.py’s importlib pattern, and extend the canonical Synset
pointer representation only as needed to preserve kind_sym for hypernym_word
consumers. Update this module’s callers to use the shared loader while retaining
existing sense ordering and hypernym behavior.
In `@crates/lance-graph-planner/src/physical/cam_pq_scan.rs`:
- Around line 464-473: Update the uninstrumented distance calculations in
full_adc and cascade to call the existing adc helper instead of duplicating the
six-term lookup sum. Preserve the current inputs and behavior while keeping adc
as the single source for the full 6-subspace ADC distance.
- Around line 176-178: Rename the public field worst_miss_rank to best_miss_rank
in its definition and all references, preserving its usize type and existing
lowest-rank calculation. Update the associated documentation to describe the
best (lowest, 0-based) rank a probed reject would have occupied.
- Around line 978-980: Rename
disabled_policy_is_bit_identical_and_allocation_free to remove the unverified
allocation-free claim, unless the test is extended with a test-only counting
allocator that asserts no allocations occur. Preserve its existing bit-identity
assertions.
- Around line 533-539: The public CamSearch API must expose the strategy
selected by the scan instead of discarding it in CamSearch::top_k. Add a
top_k_observed-style method returning the scan outcome, or otherwise expose the
focused strategy indicator, while preserving existing top_k behavior for callers
that only need Vec<(usize, f32)>; ensure callers can inspect
strategy.is_exact_over_adc.
In `@crates/lance-graph-planner/src/strategy/style_strategy.rs`:
- Around line 128-149: Move the admitted-set recipe replay out of the watcher
loop in the surrounding strategy method. Build one baseline ThoughtCtx after
computing admitted by running recipes_for_at(style, rung), then clone that
context for each eligible watcher before running its kernel; preserve the
existing mechanism, missing-kernel, confidence, and min_rung 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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 7a3d3ab1-2360-401a-bde3-7f5127e873e9
📒 Files selected for processing (55)
.claude/board/EPIPHANIES.md.claude/board/INTEGRATION_PLANS.md.claude/board/PR_ARC_INVENTORY.md.claude/board/STATUS_BOARD.md.claude/board/TECH_DEBT.md.claude/board/exec-runs/aligner-lemma-key.txt.claude/board/exec-runs/chaoda-trajectory.txt.claude/board/exec-runs/closed-class-detector.txt.claude/board/exec-runs/closed-class-transfer.txt.claude/board/exec-runs/eigenvalue-sweep.txt.claude/board/exec-runs/greek-lane.txt.claude/board/exec-runs/m1-cascade-rejects.txt.claude/board/exec-runs/rcc-coca-wordnet.txt.claude/board/exec-runs/rcc-lane-codebooks.txt.claude/board/exec-runs/rcc-splitcensus.txt.claude/board/exec-runs/rcc-tierdelta.txt.claude/board/exec-runs/rcc-versification.txt.claude/board/exec-runs/rcc-wordnet-rebuild.txt.claude/board/exec-runs/rcc3-alignment.txt.claude/board/exec-runs/temporal-periphery.txt.claude/board/exec-runs/vacuous-assertions.txt.claude/board/exec-runs/wave-planner-context.txt.claude/board/exec-runs/wordnet-consumer-sweep.txt.claude/plans/rosetta-codebook-convergence-v1.md.gitignoreCLAUDE.mdcrates/bgz-tensor/src/cascade.rscrates/bgz-tensor/src/stacked.rscrates/deepnsm-v2/src/wave.rscrates/lance-graph-contract/src/recipes.rscrates/lance-graph-contract/src/witness_fabric.rscrates/lance-graph-planner/examples/data/coca/coca_wordnet_convergence.pycrates/lance-graph-planner/examples/data/rosetta/build_alignment.pycrates/lance-graph-planner/examples/data/rosetta/build_lane_codebooks.pycrates/lance-graph-planner/examples/data/rosetta/build_rosetta_probe.pycrates/lance-graph-planner/examples/data/rosetta/build_versification_map.pycrates/lance-graph-planner/examples/data/rosetta/closed_class.pycrates/lance-graph-planner/examples/data/rosetta/closed_class_transfer.pycrates/lance-graph-planner/examples/data/rosetta/fetch_greek_lane.pycrates/lance-graph-planner/examples/data/wordnet/build_wordnet_rail.pycrates/lance-graph-planner/examples/data/wordnet/tier_delta.pycrates/lance-graph-planner/examples/insight_coca_read.rscrates/lance-graph-planner/examples/insight_reason_wired.rscrates/lance-graph-planner/examples/insight_right_corner_read.rscrates/lance-graph-planner/src/api.rscrates/lance-graph-planner/src/lib.rscrates/lance-graph-planner/src/nars/meta_basin.rscrates/lance-graph-planner/src/nars/mod.rscrates/lance-graph-planner/src/physical/cam_pq_scan.rscrates/lance-graph-planner/src/strategy/chat_bundle.rscrates/lance-graph-planner/src/strategy/gql_parse.rscrates/lance-graph-planner/src/strategy/gremlin_parse.rscrates/lance-graph-planner/src/strategy/sparql_parse.rscrates/lance-graph-planner/src/strategy/style_strategy.rscrates/lance-graph-planner/src/traits.rs
| measured numbers are proprietary and are recorded nowhere in this repo — this | ||
| board records the design consequence, never the numbers. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Historical board entries edited in place instead of appending a correction. All four sites redact a private-archive location reference by rewriting prose inside already-merged, historical entries (2026-07-01/07-02), rather than appending a new dated correction entry. Per the retrieved board-hygiene learning, edits to prior entries in .claude/board/*.md must be limited to their Status/Confidence lines only — everything else is append-only, precisely so the audit trail is never rewritten. The repo's own convention already shows the correct mechanism a few lines away: E-BRICK3-CORRECTION-MINT-FACTORED-IS-SPLIT-BRAIN corrects E-BRICK3-RAN-TRUNCATION-DISALLOWED via a new dated entry, not an in-place edit. The redaction intent itself (never naming a private repo's location, per E-PRIVATE-STORE-DISCLOSURE-IN-SOURCE-1) is sound — only the mechanism needs to change.
.claude/board/EPIPHANIES.md#L4497-L4498: revert the private-archive wording change here and instead append a new dated entry (or a**Correction:**sub-entry) stating the numbers are recorded nowhere in this repo, leaving the original text intact..claude/board/EPIPHANIES.md#L3970-L3974: same treatment — restore the original prose and append a new dated note scoping the "brick-3 corrected form is shipped" claim to the probe run..claude/board/PR_ARC_INVENTORY.md#L408-L408: restore the original "Locked"/"Privacy split" line and append a correction note instead of rewriting it..claude/board/PR_ARC_INVENTORY.md#L418-L418: restore the original "Cross-ref" line and append a correction note dropping the private restore-log reference going forward.
📍 Affects 2 files
.claude/board/EPIPHANIES.md#L4497-L4498(this comment).claude/board/EPIPHANIES.md#L3970-L3974.claude/board/PR_ARC_INVENTORY.md#L408-L408.claude/board/PR_ARC_INVENTORY.md#L418-L418
🤖 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 @.claude/board/EPIPHANIES.md around lines 4497 - 4498, Preserve the board
audit trail by restoring the original prose at .claude/board/EPIPHANIES.md lines
4497-4498 and 3970-3974, and append dated correction entries stating the numbers
are not recorded in this repo and scoping the brick-3 claim to the probe run.
Restore the original “Locked”/“Privacy split” line at
.claude/board/PR_ARC_INVENTORY.md line 408 and “Cross-ref” line at line 418,
then append corrections removing private restore-log references going forward;
limit edits to prior entries’ Status/Confidence lines otherwise.
Source: Learnings
| from real text. Verified additive: running with --anchor lamb produced | ||
| identical split-census numbers (1319/48.9%/43.0%) to the run without | ||
| the flag; only appends a new report section. Verified via py_compile | ||
| and a plain import that the module still loads cleanly. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Verification triple mixes before/after numbers.
1319/48.9%/43.0% pairs the AFTER count with the BEFORE percentage. Per lines 47-53 the pair is 1501 (48.9%) before and 1319 (43.0%) after.
📝 Proposed fix
- from real text. Verified additive: running with --anchor lamb produced
- identical split-census numbers (1319/48.9%/43.0%) to the run without
+ from real text. Verified additive: running with --anchor lamb produced
+ identical split-census numbers (before 1501/48.9%, after 1319/43.0%) to the run without📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| from real text. Verified additive: running with --anchor lamb produced | |
| identical split-census numbers (1319/48.9%/43.0%) to the run without | |
| the flag; only appends a new report section. Verified via py_compile | |
| and a plain import that the module still loads cleanly. | |
| from real text. Verified additive: running with --anchor lamb produced | |
| identical split-census numbers (before 1501/48.9%, after 1319/43.0%) to the run without | |
| the flag; only appends a new report section. Verified via py_compile | |
| and a plain import that the module still loads cleanly. |
🤖 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 @.claude/board/exec-runs/rcc-splitcensus.txt around lines 78 - 81, Correct
the verification statement in the split-census report so the before/after
metrics remain paired: report 1501 with 48.9% for the before run and 1319 with
43.0% for the after run. Update only the inconsistent numeric summary; preserve
the claim that the flag adds a report section without changing existing census
numbers.
|
|
||
| ## TD-COCA-LEXICON-RANK-UNRELIABLE-AT-HEAD (2026-07-26) | ||
|
|
||
| `crates/lance-graph-planner/examples/data/coca/lexicon.tsv` (20,004 rows) is a | ||
| PRE-FILTERED list, not raw COCA rank 1..N, and its `rank` column is wrong in the | ||
| high-frequency band: `the` = 5645 (pos `i`), `and` = 3584 (pos `r`/adverb — also | ||
| a wrong tag), while `of` = 5. Pure function words `a, I, you, he, she, they, not, | ||
| what, which` are absent entirely. | ||
|
|
||
| Impact: any consumer treating `rank` as a frequency proxy gets a scrambled head of | ||
| the distribution; any coverage/decile analysis silently excludes function words. | ||
| Surfaced by `E-COVERAGE-INVERSION-CLAIM-REFUTED-1` (the decile analysis is sound | ||
| for content vocabulary only, for this reason). | ||
|
|
||
| Fix options: (a) re-derive rank from a real COCA frequency list; (b) rename the | ||
| column `list_order` and add a MANIFEST note that it is not a frequency rank; | ||
| (c) supersede with the verse-attested lane codebooks (`rosetta/build_lane_codebooks.py`), | ||
| whose `freq`/`rank`/`dispersion` ARE corpus-measured — at the cost of Bible-domain bias. | ||
|
|
||
| ## TD-COCA-LEXICON-POS-UNUSABLE-FOR-FUNCTION-WORDS (2026-07-26) | ||
|
|
||
| Extends `TD-COCA-LEXICON-RANK-UNRELIABLE-AT-HEAD`: the same file's **`pos` | ||
| column is wrong for exactly the words a POS column is most needed for.** | ||
| Spot-checked on the main thread: | ||
|
|
||
| | word | recorded pos | correct | | ||
| |---|---|---| | ||
| | `the` | `i` (preposition) | determiner | | ||
| | `and` | `r` (adverb) | coordinating conjunction | | ||
| | `it` | `n` (**noun**) | pronoun | | ||
| | `that` | `r` (adverb) | determiner/conjunction/pronoun | | ||
| | `of` | `i` (preposition) | ✓ correct | | ||
| | `a` | ABSENT | determiner | | ||
|
|
||
| 3 of 5 function words checked are mis-tagged and 1 is missing; the one | ||
| correct tag is the one that is unambiguously a preposition. | ||
|
|
||
| Impact: any consumer treating this column as POS ground truth for | ||
| closed-class vocabulary is reading noise. Surfaced by the closed-class | ||
| transfer work (`E-BOTH-CLOSED-CLASS-METHODS-LOSE-TO-RANK-150-1`), which had | ||
| to substitute a curated word list. **Do not use `coca/lexicon.tsv` `pos` for | ||
| function words.** For open-class content words it was not audited — unknown, | ||
| not vindicated. | ||
|
|
||
| Fix options: (a) re-derive POS from a real tagged corpus (the German lane | ||
| already uses UD-derived tags and they are sound); (b) rename the column to | ||
| mark it unreliable; (c) supersede with UD-derived English tags. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Board-hygiene violation: new entries appended at the end instead of prepended.
These two 2026-07-26 entries land after the existing 2026-07-02 TD-FLEET-CADENCE entry, breaking newest-first ordering.
Based on learnings, "For governance files in .claude/board/*.md, follow the Mandatory Board-Hygiene Rule defined in CLAUDE.md: treat these files as append-only ledgers that are ordered newest-first... prepend new entries rather than appending at the end."
📋 Fix: move the new entries to the top of the file
Relocate the TD-COCA-LEXICON-RANK-UNRELIABLE-AT-HEAD and TD-COCA-LEXICON-POS-UNUSABLE-FOR-FUNCTION-WORDS sections above the earlier TD-FLEET-CADENCE entry (or to the very top of the document, per convention), leaving all prior entries in their original order.
🤖 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 @.claude/board/TECH_DEBT.md around lines 3192 - 3238, Move the
TD-COCA-LEXICON-RANK-UNRELIABLE-AT-HEAD and
TD-COCA-LEXICON-POS-UNUSABLE-FOR-FUNCTION-WORDS sections to the top of
.claude/board/TECH_DEBT.md, before TD-FLEET-CADENCE, while preserving the
existing order and content of all prior entries.
Source: Learnings
| assert!( | ||
| !superseded.iter().any(|r| r == runs.last().unwrap()), | ||
| "the current run leaked into the periphery" | ||
| ); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
This disjointness assertion cannot fail.
superseded_at is Some(..) for every element of superseded and None for runs.last(), so derived PartialEq makes the any structurally false regardless of the tiling logic. The neighbouring superseded.len() + 1 == runs.len() check already carries the real claim; comparing on span()/first_revision instead would make this one falsifiable.
Based on the guideline that tests must be falsifiable — "identify an input that can make each assertion fail".
🤖 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 `@crates/lance-graph-contract/src/witness_fabric.rs` around lines 1448 - 1451,
Replace the structural equality check in the disjointness assertion near the
superseded/runs validation with a comparison of the relevant run identity
fields, such as span and first_revision, so the assertion can detect an actual
overlap with runs.last(). Preserve the existing assertion message and
neighbouring length check.
Source: Coding guidelines
| def normalize_en(tok: str) -> str: | ||
| """Crude English surface-form fold: plurals, -ed/-ing, archaic KJV verb | ||
| endings (-eth, -est). NOT a lemmatiser -- no irregular-verb table, so | ||
| `hath`/`saith`/`doth` (irregular, not simple suffixation) pass through | ||
| UNCHANGED rather than folding to `have`/`say`/`do`. This is a stated | ||
| gap, not a bug: a true lemmatiser is out of scope for this script's | ||
| "no external lexicon" discipline (see module docstring). | ||
| """ | ||
| t = tok | ||
| if t.endswith("ies") and len(t) - 3 + 1 >= EN_MIN_STEM_LEN: | ||
| return t[:-3] + "y" | ||
| for suf in ("eth", "est", "ing"): | ||
| if t.endswith(suf) and len(t) - len(suf) >= EN_MIN_STEM_LEN: | ||
| return t[: -len(suf)] | ||
| if t.endswith("ed") and len(t) - 2 >= EN_MIN_STEM_LEN: | ||
| return t[:-2] | ||
| if t.endswith("es") and len(t) - 2 >= EN_MIN_STEM_LEN: | ||
| # "-es" is added after a sibilant-ending stem (box->boxes, | ||
| # dish->dishes, church->churches); anything else spelled "-es" is | ||
| # really a silent-e stem + plain "-s" (grape->grapes), so strip | ||
| # only the final "s" and keep the "e" -- this is the difference | ||
| # between "grap" (wrong, the bug this comment replaces) and | ||
| # "grape" (right, what makes grape/grapes actually share a key). | ||
| # Crude and orthography-shaped, not a real morphological analyser. | ||
| stem_no_es = t[:-2] | ||
| if stem_no_es and (stem_no_es[-1] in "sxz" or stem_no_es.endswith(("ch", "sh"))): | ||
| return stem_no_es | ||
| if len(t) - 1 >= EN_MIN_STEM_LEN: | ||
| return t[:-1] | ||
| return stem_no_es | ||
| if t.endswith("s") and not t.endswith("ss") and len(t) - 1 >= EN_MIN_STEM_LEN: | ||
| return t[:-1] | ||
| return t |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
normalize_en's "-es" branch mis-stems silent-e words like house/houses, defeating the merge it's meant to perform.
houses → stem_no_es="hous", last char s is treated as a sibilant plural marker (like box→boxes) and the function returns "hous". But house itself (no trailing "es") returns "house" unchanged — so house and houses land on different, and one of them wrong, normalized keys. This is the exact fragmentation-vs-merge failure this task was built to fix (per the module docstring's grape/grapes rationale), just recurring for any word ending in silent‑e preceded by s (house, purse, curse, promise, praise, chase, horse, paradise) — all plausible KJV vocabulary. The root cause is that a bare trailing "s" on stem_no_es is ambiguous between a genuine doubled-sibilant plural (kiss→kisses) and a silent‑e‑plus‑s plural (house→houses); only the doubled-consonant case is a true -es sibilant plural.
🐛 Proposed fix: only treat a doubled sibilant consonant as a genuine "-es" plural
stem_no_es = t[:-2]
- if stem_no_es and (stem_no_es[-1] in "sxz" or stem_no_es.endswith(("ch", "sh"))):
+ if stem_no_es and (
+ stem_no_es[-1] in "xz"
+ or stem_no_es.endswith(("ch", "sh", "ss"))
+ ):
return stem_no_es
if len(t) - 1 >= EN_MIN_STEM_LEN:
return t[:-1]
return stem_no_esThis fixes house/houses, kiss/kisses, box/boxes, dish/dishes, church/churches all correctly. A residual ambiguity remains for silent-e words ending in x/z (gaze/gazes, size/sizes) — a suffix-only heuristic without a dictionary can't fully resolve that, but it's a much smaller vocabulary slice than the s case this fixes.
🤖 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 `@crates/lance-graph-planner/examples/data/rosetta/build_alignment.py` around
lines 148 - 180, Update the "-es" handling in normalize_en so a trailing "s" in
stem_no_es is treated as a genuine sibilant plural only when the stem has a
doubled sibilant consonant, while preserving the existing handling for x, z, ch,
and sh endings. Otherwise strip only the final plural "s" so silent-e forms such
as house/houses normalize to the same key, without changing the surrounding
suffix rules.
| let mut rails = HashMap::new(); | ||
| let mut wrong_arity = 0usize; | ||
| for l in wn_txt | ||
| .lines() | ||
| .filter(|l| !l.starts_with('#') && !l.is_empty()) | ||
| { | ||
| let c: Vec<&str> = l.split('\t').collect(); | ||
| // word<TAB>pos<TAB>kind<TAB>type ; keep the first (noun preferred) reading | ||
| if c.len() >= 4 && !rails.contains_key(c[0]) { | ||
| // v1 schema is EXACTLY `word<TAB>pos<TAB>kind<TAB>type`. The guard is | ||
| // `== 4`, not `>= 4`, deliberately: the v2 rail | ||
| // (`wordnet31_isa_v2.tsv`) has 7 columns and would satisfy a | ||
| // permissive guard while `c[2]`/`c[3]` silently became | ||
| // `sense_num`/`synset_offset` — garbage EntityType tenants and | ||
| // WordNet rails with no error anywhere. Same filename, different | ||
| // meaning, is the `I-LEGACY-API-FEATURE-GATED` failure shape; a | ||
| // strict arity check turns it into a loud skip. | ||
| if c.len() == 4 && !rails.contains_key(c[0]) { | ||
| rails.insert(c[0].to_string(), (c[2].to_string(), c[3].to_string())); | ||
| } else if c.len() != 4 { | ||
| wrong_arity += 1; | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Partial schema corruption is invisible.
wrong_arity is only surfaced when rails ends up completely empty. If a file is a mix of well-formed and v2-shaped (7-column) rows, the bad rows are silently dropped with no signal at all, even though a meaningful chunk of the rail set may be missing.
🐛 Proposed fix
if rails.is_empty() && wrong_arity > 0 {
return Err(format!(
"wordnet rail schema mismatch: {wrong_arity} rows, none with the \
expected 4 columns (`word<TAB>pos<TAB>kind<TAB>type`). The v2 rail \
has 7 columns and is NOT a drop-in replacement — point \
$WORDNET_DIR at a v1 rail, or migrate this reader."
));
+ } else if wrong_arity > 0 {
+ eprintln!(
+ "warning: {wrong_arity} wordnet rail rows had unexpected column count \
+ (kept {} well-formed rails)",
+ rails.len()
+ );
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let mut rails = HashMap::new(); | |
| let mut wrong_arity = 0usize; | |
| for l in wn_txt | |
| .lines() | |
| .filter(|l| !l.starts_with('#') && !l.is_empty()) | |
| { | |
| let c: Vec<&str> = l.split('\t').collect(); | |
| // word<TAB>pos<TAB>kind<TAB>type ; keep the first (noun preferred) reading | |
| if c.len() >= 4 && !rails.contains_key(c[0]) { | |
| // v1 schema is EXACTLY `word<TAB>pos<TAB>kind<TAB>type`. The guard is | |
| // `== 4`, not `>= 4`, deliberately: the v2 rail | |
| // (`wordnet31_isa_v2.tsv`) has 7 columns and would satisfy a | |
| // permissive guard while `c[2]`/`c[3]` silently became | |
| // `sense_num`/`synset_offset` — garbage EntityType tenants and | |
| // WordNet rails with no error anywhere. Same filename, different | |
| // meaning, is the `I-LEGACY-API-FEATURE-GATED` failure shape; a | |
| // strict arity check turns it into a loud skip. | |
| if c.len() == 4 && !rails.contains_key(c[0]) { | |
| rails.insert(c[0].to_string(), (c[2].to_string(), c[3].to_string())); | |
| } else if c.len() != 4 { | |
| wrong_arity += 1; | |
| } | |
| } | |
| let mut rails = HashMap::new(); | |
| let mut wrong_arity = 0usize; | |
| for l in wn_txt | |
| .lines() | |
| .filter(|l| !l.starts_with('#') && !l.is_empty()) | |
| { | |
| let c: Vec<&str> = l.split('\t').collect(); | |
| // v1 schema is EXACTLY `word<TAB>pos<TAB>kind<TAB>type`. The guard is | |
| // `== 4`, not `>= 4`, deliberately: the v2 rail | |
| // (`wordnet31_isa_v2.tsv`) has 7 columns and would satisfy a | |
| // permissive guard while `c[2]`/`c[3]` silently became | |
| // `sense_num`/`synset_offset` — garbage EntityType tenants and | |
| // WordNet rails with no error anywhere. Same filename, different | |
| // meaning, is the `I-LEGACY-API-FEATURE-GATED` failure shape; a | |
| // strict arity check turns it into a loud skip. | |
| if c.len() == 4 && !rails.contains_key(c[0]) { | |
| rails.insert(c[0].to_string(), (c[2].to_string(), c[3].to_string())); | |
| } else if c.len() != 4 { | |
| wrong_arity += 1; | |
| } | |
| } | |
| if rails.is_empty() && wrong_arity > 0 { | |
| return Err(format!( | |
| "wordnet rail schema mismatch: {wrong_arity} rows, none with the \ | |
| expected 4 columns (`word<TAB>pos<TAB>kind<TAB>type`). The v2 rail \ | |
| has 7 columns and is NOT a drop-in replacement — point \ | |
| $WORDNET_DIR at a v1 rail, or migrate this reader." | |
| )); | |
| } else if wrong_arity > 0 { | |
| eprintln!( | |
| "warning: {wrong_arity} wordnet rail rows had unexpected column count \ | |
| (kept {} well-formed rails)", | |
| rails.len() | |
| ); | |
| } |
🤖 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 `@crates/lance-graph-planner/examples/insight_reason_wired.rs` around lines 97
- 117, Update the parsing flow around wrong_arity and rails so any nonzero
wrong_arity is surfaced, not only when rails is empty. Preserve valid 4-column
rail entries, but emit the existing error or skip signal when mixed-schema input
contains malformed rows, including when valid rails were also collected.
| let mut wrong_arity = 0usize; | ||
| for l in wn_txt | ||
| .lines() | ||
| .filter(|l| !l.starts_with('#') && !l.is_empty()) | ||
| { | ||
| let c: Vec<&str> = l.split('\t').collect(); | ||
| // word<TAB>pos<TAB>kind<TAB>type ; keep the first (noun preferred) reading | ||
| if c.len() >= 4 && !rails.contains_key(c[0]) { | ||
| // v1 schema is EXACTLY `word<TAB>pos<TAB>kind<TAB>type`. The guard is | ||
| // `== 4`, not `>= 4`, deliberately: the v2 rail | ||
| // (`wordnet31_isa_v2.tsv`) has 7 columns and would satisfy a | ||
| // permissive guard while `c[2]`/`c[3]` silently became | ||
| // `sense_num`/`synset_offset` — garbage EntityType tenants and | ||
| // WordNet rails with no error anywhere. Same filename, different | ||
| // meaning, is the `I-LEGACY-API-FEATURE-GATED` failure shape; a | ||
| // strict arity check turns it into a loud skip. | ||
| if c.len() == 4 && !rails.contains_key(c[0]) { | ||
| rails.insert(c[0].to_string(), (c[2].to_string(), c[3].to_string())); | ||
| } else if c.len() != 4 { | ||
| wrong_arity += 1; | ||
| } | ||
| } | ||
| // A wholly wrong-arity file is a SCHEMA MISMATCH, not sparse data — | ||
| // fail loudly rather than silently reasoning over an empty rail set. | ||
| if rails.is_empty() && wrong_arity > 0 { | ||
| return Err(format!( | ||
| "wordnet rail schema mismatch: {wrong_arity} rows, none with the \ | ||
| expected 4 columns (`word<TAB>pos<TAB>kind<TAB>type`). The v2 rail \ | ||
| has 7 columns and is NOT a drop-in replacement — point \ | ||
| $WORDNET_DIR at a v1 rail, or migrate this reader." | ||
| )); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
New schema-mismatch guard has no can-it-fire test.
The new arity check and Err path (triggered when rails.is_empty() && wrong_arity > 0) is a guard, and per the coding guidelines tests must be falsifiable — "guards need can-it-fire tests." Nothing here exercises Basins::load() against a 7-column (v2-shaped) fixture to confirm the guard actually returns Err rather than, e.g., silently treating those rows as c.len() != 4 no-ops without ever reaching the failure branch.
As per coding guidelines, **/*.{rs,md}: "guards need can-it-fire tests." Consider extracting the parsing loop into a small helper (or adding a #[cfg(test)] unit test) that feeds a synthetic 7-column TSV and asserts load() returns Err.
🤖 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 `@crates/lance-graph-planner/examples/insight_reason_wired.rs` around lines 98
- 127, Add a falsifiable test for the schema-mismatch guard in Basins::load,
using a synthetic non-empty 7-column TSV fixture and asserting that loading
returns Err. Exercise the existing rails.is_empty() && wrong_arity > 0 path
directly, preserving normal parsing behavior for valid 4-column rows.
Source: Coding guidelines
| /// The sweep's default range: budgets `0..=max_hops`, capped so the probe | ||
| /// stays bounded on a `255` budget. Centring on the caller's own budget is | ||
| /// the point — the question is "would a different budget have grouped these | ||
| /// rows differently", and only budgets the caller might plausibly have | ||
| /// chosen answer it. | ||
| #[must_use] | ||
| pub fn stability_around( | ||
| &self, | ||
| window: &[(usize, CausalWitnessFacet)], | ||
| locus: Locus, | ||
| max_hops: u8, | ||
| ) -> Stability { | ||
| let hi = max_hops.saturating_add(2).min(16); | ||
| let budgets: Vec<u8> = (0..=hi).collect(); | ||
| self.stability_sweep(window, locus, &budgets) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
stability_around stops centring on the caller's budget once max_hops > 14.
The doc says the range is 0..=max_hops "centring on the caller's own budget", but the code probes 0..=min(max_hops+2, 16). For max_hops = 255 the sweep covers 0..=16 only — the caller's own budget is never probed, so the fraction answers a different question than the doc claims. Either window the cap around max_hops or state the absolute ceiling in the doc.
♻️ Window the sweep around the caller's budget
- let hi = max_hops.saturating_add(2).min(16);
- let budgets: Vec<u8> = (0..=hi).collect();
+ // Probe a bounded window CENTRED on the caller's budget, so the sweep
+ // still asks "would a nearby budget have grouped these differently?"
+ let lo = max_hops.saturating_sub(8);
+ let hi = max_hops.saturating_add(2);
+ let budgets: Vec<u8> = (lo..=hi).collect();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /// The sweep's default range: budgets `0..=max_hops`, capped so the probe | |
| /// stays bounded on a `255` budget. Centring on the caller's own budget is | |
| /// the point — the question is "would a different budget have grouped these | |
| /// rows differently", and only budgets the caller might plausibly have | |
| /// chosen answer it. | |
| #[must_use] | |
| pub fn stability_around( | |
| &self, | |
| window: &[(usize, CausalWitnessFacet)], | |
| locus: Locus, | |
| max_hops: u8, | |
| ) -> Stability { | |
| let hi = max_hops.saturating_add(2).min(16); | |
| let budgets: Vec<u8> = (0..=hi).collect(); | |
| self.stability_sweep(window, locus, &budgets) | |
| } | |
| /// The sweep's default range: budgets `0..=max_hops`, capped so the probe | |
| /// stays bounded on a `255` budget. Centring on the caller's own budget is | |
| /// the point — the question is "would a different budget have grouped these | |
| /// rows differently", and only budgets the caller might plausibly have | |
| /// chosen answer it. | |
| #[must_use] | |
| pub fn stability_around( | |
| &self, | |
| window: &[(usize, CausalWitnessFacet)], | |
| locus: Locus, | |
| max_hops: u8, | |
| ) -> Stability { | |
| // Probe a bounded window CENTRED on the caller's budget, so the sweep | |
| // still asks "would a nearby budget have grouped these differently?" | |
| let lo = max_hops.saturating_sub(8); | |
| let hi = max_hops.saturating_add(2); | |
| let budgets: Vec<u8> = (lo..=hi).collect(); | |
| self.stability_sweep(window, locus, &budgets) | |
| } |
🤖 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 `@crates/lance-graph-planner/src/nars/meta_basin.rs` around lines 486 - 501,
Update stability_around to keep the sweep window centered on max_hops when the
upper bound is capped, while preserving bounded probing and including max_hops
itself. Adjust the budgets construction and any associated range documentation
so the resulting stability query reflects budgets plausible for the caller.
| #[test] | ||
| fn perturbation_marks_budget_artifacts_and_spares_singletons() { | ||
| let win = vec![ | ||
| (0, w(&[(Locus::Antecedent, 1)])), | ||
| (1, CausalWitnessFacet::ZERO), | ||
| ]; | ||
| let graded = grade_rows(&win, Locus::Antecedent, 8); | ||
| for b in meta_cluster(&graded) { | ||
| // Singletons have nothing to dissolve — never reported unstable. | ||
| if b.members.len() < 2 { | ||
| assert!(b.stable_under_perturbation(&win, Locus::Antecedent, 1)); | ||
| } | ||
| // The call is total: any budget, no panic. | ||
| for p in [0u8, 1, 2, 8, 255] { | ||
| let _ = b.stable_under_perturbation(&win, Locus::Antecedent, p); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
The test never exercises the "marks budget artifacts" half of its name.
It only asserts singletons are spared and that the call does not panic; no input here produces an unstable basin, so a stable_under_perturbation that always returned true would still pass. Add a fixture where a multi-member basin dissolves at a perturbed budget.
Based on the guideline that guards need can-it-fire tests.
🤖 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 `@crates/lance-graph-planner/src/nars/meta_basin.rs` around lines 703 - 720,
Extend perturbation_marks_budget_artifacts_and_spares_singletons with a fixture
that produces a basin containing multiple members and assert
stable_under_perturbation returns false for a budget perturbation that dissolves
it. Keep the existing singleton and no-panic coverage, and ensure the new
assertion exercises the unstable branch rather than accepting any result.
Source: Coding guidelines
| // Anti-vacuity: the filter must actually filter (kept ≪ total). | ||
| let (_, rejects) = op.cascade_instrumented(&dt, &cams); | ||
| assert!( | ||
| results.len() * 3 < cams.len(), | ||
| "cascade kept {} of {} — the prune is inert", | ||
| results.len(), | ||
| cams.len() | ||
| ); | ||
| assert!(rejects.heuristic_len() > cams.len() / 2); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
This anti-vacuity assertion is itself vacuous.
Line 681 already pins results.len() == 10, so results.len() * 3 < cams.len() reduces to 30 < 10000 — no input can fail it, which is exactly the E-VACUOUS-ASSERTION-IS-THE-HOUSE-STYLE-1 pattern the surrounding comment is fixing. "Kept ≪ total" is a claim about the survivor count, which is cams.len() - rejects.heuristic_len(), not the truncated result list. The heuristic_len() assertion below is the one doing the work.
As per coding guidelines: "Tests must be falsifiable: identify an input that can make each assertion fail; filters need non-trivial anti-vacuity tests".
🧪 Assert on survivors, not on the truncated result list
// Anti-vacuity: the filter must actually filter (kept ≪ total).
let (_, rejects) = op.cascade_instrumented(&dt, &cams);
+ let kept = cams.len() - rejects.heuristic_len();
assert!(
- results.len() * 3 < cams.len(),
+ kept * 3 < cams.len(),
"cascade kept {} of {} — the prune is inert",
- results.len(),
+ kept,
cams.len()
);
- assert!(rejects.heuristic_len() > cams.len() / 2);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Anti-vacuity: the filter must actually filter (kept ≪ total). | |
| let (_, rejects) = op.cascade_instrumented(&dt, &cams); | |
| assert!( | |
| results.len() * 3 < cams.len(), | |
| "cascade kept {} of {} — the prune is inert", | |
| results.len(), | |
| cams.len() | |
| ); | |
| assert!(rejects.heuristic_len() > cams.len() / 2); | |
| // Anti-vacuity: the filter must actually filter (kept ≪ total). | |
| let (_, rejects) = op.cascade_instrumented(&dt, &cams); | |
| let kept = cams.len() - rejects.heuristic_len(); | |
| assert!( | |
| kept * 3 < cams.len(), | |
| "cascade kept {} of {} — the prune is inert", | |
| kept, | |
| cams.len() | |
| ); |
🤖 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 `@crates/lance-graph-planner/src/physical/cam_pq_scan.rs` around lines 695 -
703, Replace the anti-vacuity assertion in the instrumented cascade test with a
check based on the survivor count, computed as cams.len() minus
rejects.heuristic_len(), rather than results.len(). Keep the existing results
length assertion and rejects.heuristic_len() assertion unchanged.
Source: Coding guidelines
…source texts; record the unverified-verification miss
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_e9f8354b-5422-4086-8586-20fa022307e1) |
…es-z30uij
This PR is a PLATEAU of the thinking-substrate work: the standing wave, rung
stratification, peripheral-dissent guards, trajectory metric + CHAODA density,
the temporal (version) axis, the CascadeRejects channel, and the board record.
The 11 codebook/bake generators (5,790 LOC of Python under
examples/data/{coca,de,rosetta,wordnet}/) move to
`claude/rosetta-codebook-bakes-z30uij`, which is this branch's exact HEAD —
nothing is lost, only sequenced. They are a separate concern with a separate
review surface: corpus acquisition and codebook baking, not substrate.
The baked artifacts themselves already ship as Release assets
(`v0.1.0-codebooks-2026-07-26`, five regime-separated bundles), so the
data-in-Releases half is done independently of either branch.
NOTE for the Release MANIFESTs: they cite generator paths under
`crates/lance-graph-planner/examples/data/`. Those paths land on main when the
bake branch merges, not when this one does. Stated here rather than left as a
dangling reference.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.claude/board/EPIPHANIES.md (1)
637-647: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winPreserve the append-only audit trail.
These governance details appear to revise an existing historical entry in place. Revert the prose change and append a new dated correction entry instead. Based on learnings, prior
.claude/board/*.mdentries may only have their Status/Confidence changed.🤖 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 @.claude/board/EPIPHANIES.md around lines 637 - 647, Revert the edits to the existing historical entry in the board document and preserve its original prose. Append a new dated correction entry documenting the updated licensing conclusions and actions, changing only permitted Status/Confidence fields in prior entries.Source: Learnings
🤖 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.
Outside diff comments:
In @.claude/board/EPIPHANIES.md:
- Around line 637-647: Revert the edits to the existing historical entry in the
board document and preserve its original prose. Append a new dated correction
entry documenting the updated licensing conclusions and actions, changing only
permitted Status/Confidence fields in prior entries.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 654950ce-c562-4dbc-ac90-2fe133e34d20
📒 Files selected for processing (3)
.claude/board/EPIPHANIES.md.gitignorecrates/lance-graph-planner/examples/data/de/build_de_codebook.py
💤 Files with no reviewable changes (1)
- crates/lance-graph-planner/examples/data/de/build_de_codebook.py
…e-cursor rotating sample (probe_epoch not version); external claims quarantined
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c992bb93-cab0-43bc-9c0b-1103b3e7767e) |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
crates/lance-graph-contract/src/witness_fabric.rs (1)
1543-1546: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDisjointness assertion still cannot fail (unresolved from prior review).
supersededelements all havesuperseded_at = Some(..)whileruns.last()hassuperseded_at = None, so derivedPartialEqmakesr == runs.last().unwrap()structurally false for every input — this assertion is vacuous regardless of tiling correctness. This is the same code flagged in a previous review round (then at lines 1448-1451); it remains unchanged and unfixed. Comparing onspan()/first_revisioninstead would make the check falsifiable.Based on the guideline that tests must be falsifiable — "Tests must be falsifiable: identify an input that can fail; filters need non-trivial anti-vacuity tests, guards need tests proving they can fire".
🐛 Proposed fix
assert!( - !superseded.iter().any(|r| r == runs.last().unwrap()), + !superseded + .iter() + .any(|r| r.span() == runs.last().unwrap().span()), "the current run leaked into the periphery" );🤖 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 `@crates/lance-graph-contract/src/witness_fabric.rs` around lines 1543 - 1546, Replace the structural comparison in the disjointness assertion within the surrounding witness-fabric test with a comparison of the run identity fields, such as span() and first_revision, so superseded entries can be detected as matching runs despite differing superseded_at values. Preserve the assertion’s intent of rejecting the current run in superseded.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.
Duplicate comments:
In `@crates/lance-graph-contract/src/witness_fabric.rs`:
- Around line 1543-1546: Replace the structural comparison in the disjointness
assertion within the surrounding witness-fabric test with a comparison of the
run identity fields, such as span() and first_revision, so superseded entries
can be detected as matching runs despite differing superseded_at values.
Preserve the assertion’s intent of rejecting the current run in superseded.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a1de1ee0-6f8a-4cb4-94ff-6a9f6aa2bb1f
📒 Files selected for processing (3)
.claude/board/EPIPHANIES.mdcrates/lance-graph-contract/src/recipes.rscrates/lance-graph-contract/src/witness_fabric.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- .claude/board/EPIPHANIES.md
- crates/lance-graph-contract/src/recipes.rs
… findings - witness_fabric: ForesightSample/foresight_sample/foresight_calibration — the Epistemic Foresight Test in minimal honest form. Risk is churn computed through upto=v (hindsight-blind by parameter); the post segment overlaps the split by one revision so cross-boundary flips count; None on empty sides (absent != zero); calibration returns raw counts per risk band so empty bands stay visible. Five tests, each with a named falsifier (incl. calm-then-wild must read risk 0, and the miscalibrated wild-then-calm case must be recorded honestly). - board: adjudication of the external meta-awareness proposal — its centrepiece already ships as contract::mul (independent re-derivation = convergence evidence); RecipeCompetence three-gate and the MetaEpistemicFacet lane filed as tasks #41/#42, both producer-gated. - board: mutation wave-1 measured findings — false-witness clone detected at similarity 1.000000 with naive agreement +94% inflation and independence-weighting immune to direct inflation; the versification anchor detector is SCRIPT-BLIND on Latin-vs-Greek (0/258 recovery, offset=0 at confidence 0.0 on clean and corrupted alike) -> ISS-VERSIFICATION-SCRIPT-BLIND + task #43 (CannotMeasure state; Greek-lane versification is unverified until regenerated). - exec-runs: the two Sonnet executor tag-files consolidated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LFRfkNAyJCkLbtChuSHNay
The ChainResolution escalated-split touched deepnsm-v2, which is workspace-EXCLUDED — so neither `cargo fmt -p <workspace crate>` nor a workspace-level `--all` ever reaches it. CI checks it by explicit manifest path (style.yml), which is where the failure surfaced. Verified: all three manifests CI gates on (lance-graph, deepnsm, deepnsm-v2) are now rustfmt-clean. The 68 other files a bare `cargo fmt --all` reports are pre-existing and outside this branch's diff entirely — several are in the OGAR sibling reached through path deps, which is exactly the `--all` trap. Also consolidates the two mutation-operator tag-files into AGENT_LOG. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LFRfkNAyJCkLbtChuSHNay
…els, de-vacuify Reproducibility (the sharpest finding): - Restore all 11 data generators (5,790 lines) to main and revert the plateau's branch-local `**/*.py` ignore. That block re-ignored, by last-match-wins, the very files three `!`-negations in the same .gitignore deliberately track — under a rule that file states three times: data-in-Releases, CODE-IN-REPO. Main was left holding the measurement receipts while the instruments that produced them lived on another branch. Reproducibility is not a per-PR size concern. Correctness: - meta_basin: `stable_under_perturbation` re-clusters the whole window and compares member sets (catches basin MERGES, not just internal disagreement); `stability_around` windows on the caller's own budget instead of a fixed `.min(16)` cap that a 255-budget caller fell outside of; both now have can-it-fire fixtures. - style_strategy: `peripheral_sample_where` applies eligibility BEFORE the stride. Sampling globally and filtering after let ineligible watchers spend the whole budget, so the watchdog could report agreement without running a single relevant tactic — silence produced by the sampler rather than by the evidence. - style_strategy: add `cross_family_dissent`. The existing channel only consults watchers sharing the style's own Mechanism, so the only permitted dissenter was always a sibling — a monoculture by construction. The new channel samples a DIFFERENT mechanism and names which family objected. The two are never summed: one measures calibration, the other independence, and a merged number hides the second inside the first. Test-pinned that they can disagree. Falsifiability (three assertions that could not fail): - cam_pq_scan: the anti-vacuity assertion was itself vacuous (`results.len()` was already pinned above it). Now measures survivors. - witness_fabric: the disjointness check compared whole structs whose derived PartialEq made it structurally always-true. Now compares run identity. - insight_reason_wired: the schema guard had no can-it-fire test, and partial corruption was invisible. Now three fixtures and a warning that names the counts. Board: TECH_DEBT reordered newest-first; a mis-transcribed before/after pair corrected by appending to the exec record rather than rewriting it; a trace entry for the in-place redaction of four historical entries (the redaction stands — the silence did not); adjudication of the external confidence-vs-awareness review with its one rejected remedy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LFRfkNAyJCkLbtChuSHNay
One session's autonomous arc: the Bible-Rosetta convergence plan executed through D-RCC-1/3/5/7/9, the standing wave wired to the rung ladder and the 34 recipes, and the anti-eigenvalue discipline applied — then applied to itself. 55 files, +12,207/−73; 1,061 contract + 312 planner + 207 bgz-tensor + 96 deepnsm-v2 tests green.
Shipped
Rosetta substrate (plan
rosetta-codebook-convergence-v1.md)build_rosetta_probe.pyv2 (split census survives normalisation 48.9%→43.0%; swallow anchor 44%→4% unresolved),build_alignment.py(PMI/Dice,tongue→Zunge/Sprachereproduced; Dice NOT better),build_lane_codebooks.py,fetch_greek_lane.py,closed_class*.py, WordNet v2 rail + fetch script (v1 rail measured 12.76% wrong-sense, 33.84% on verbs).Thinking substrate (contract + planner)
RungLevel↔ recipe admissibility (4→11→24→34), derived from the recipes' own Bucket/Tier semantics; unstratified entry bit-identical.standing_wave_stratified+ multipass bug fixed: the wave escalated at budget 1 for every ≥2-hop chain (budget-exhaustion conflated with out-of-horizon);ChainResolutioncarrier split so the conflation is unrepresentable.quorum_mantissa(hindsight-blind by signature),TrajectorySignature+ CHAODA relative-density over a proven integer metric,RevisionTrajectory(version axis, read-as-of byuptobound), temporal periphery (BeliefRun, spread sample, reopening suggestions).peripheral_dissent(rung gate) andCascadeRejects+ThresholdDissent(CAM-PQ cascade). WitnessWindow threads the wave intoPlanContext(absent ≠ rung 0).Measured, including against ourselves
heel_threshold: 50.0is inert (max sub-distance 25.5) — stroke 1 is dead code on this fixture.rank<=150(F1 0.277 / 0.280 vs 0.386–0.388). Answered in the negative; stop searching.tongueanchor — the-chenrule splitssprache/spracheninto two fold keys; opt-in flag, default OFF, follow-up filed.Board
20+ EPIPHANIES entries (each finding named, incl. the self-refutations), STATUS_BOARD D-RCC rows, TECH_DEBT (coca lexicon rank AND pos columns unreliable for function words), plan updated in place. Licence table per lane; data-in-Releases (nothing restricted committed; NC treebank stays local oracle only).
🤖 Generated with Claude Code
https://claude.ai/code/session_01LFRfkNAyJCkLbtChuSHNay
Generated by Claude Code
Summary by CodeRabbit