feat(invariants): consume relationship hints, reporting expected-but-absent - #78
Conversation
…absent `VajraPlugin::relationship_hints` was declared by every domain plugin and consumed by nothing — vajra-cli, vajra-essence and vajra-core never read it. Roughly 68 curated hints across six plugins were inert. That is dead surface under CLAUDE.md rule 6, and worse, it misleads plugin authors into thinking declaring a hint does something. Wired up rather than deleted, because the hint data is real domain knowledge worth keeping. `invariants` now matches each applicable hint against what it discovered and reports the outcome. The valuable half is absence, not confirmation. `observed: false` means the domain expects those fields to relate, the fields are present, and the data does not show it. On GitHub-shaped input the `pr_review_assignment` hint expects pr_author to determine reviewer; measured strength is 0.0, so reviewers are being assigned independently of who wrote the PR. Unobserved hints sort first for that reason. Deliberate constraints: - Hints never weight the information theory. Conditional entropy and mutual information are measured from the data alone; a hint is context laid alongside them. Weighting would make the numbers unfalsifiable. - A hint is evaluated only when two or more of its fields are present. One present field is untestable, and reporting it as a failure would be noise. - Confirmation requires spanning two *distinct* patterns of the hint. Two paths matching the same pattern prove nothing about it. - `max_strength` is always reported, so a near-miss below the confirmation threshold stays visible rather than collapsing to a bare false. - When no hint applies — the common case — output stays the documented flat array rather than gaining a wrapper. Caught while testing: the first implementation silently never fired. Two path vocabularies are in play — `invariants` names fields relative to each record (`$.reviewer`) while the document trie names them relative to the whole document (`$[*].reviewer`) — and intersecting the two sets never matches. Matching is now on the trailing key throughout, with a regression test pinning the exact mismatch. Closes #74.
|
Warning Review limit reached
Next review available in: 53 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: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
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 |
Closes #74.
The problem
VajraPlugin::relationship_hintswas declared by every domain plugin and consumed by nothing:~68 curated hints across six plugins, all inert. Dead surface under CLAUDE.md rule 6, and worse than merely unused — it misleads plugin authors into believing that declaring a hint does something. I hit exactly that in #61 and declared none.
Wired up rather than deleted
The issue offered both. The hint data is real domain knowledge —
pr_author → revieweras a functional dependency, weighted 0.85 — so deleting it would throw away content that took effort to author.invariantsnow matches each applicable hint against what it discovered:{ "relationships": [ ... ], "domain_hints": [ { "name": "pr_review_assignment", "relationship": "FunctionalDependency", "weight": 0.85, "observed": false, "max_strength": 0.0, "matched_fields": ["$[*].pr_author", "$[*].reviewer"] }, { "name": "review_network", "relationship": "CoOccurrence", "weight": 0.9, "observed": true, "max_strength": 1.0, "matched_fields": ["$[*].review_state", "$[*].reviewer"] } ] }Absence is the useful half
observed: falsemeans the domain expects those fields to relate, the fields are present, and the data does not show it. Above,pr_review_assignmentexpectspr_authorto determinereviewer; the measured strength is exactly0.0, so reviewers are being assigned independently of who wrote the PR. That's a finding. Unobserved hints sort first for that reason.Confirmation is the weaker half — a correlation you already expected.
Constraints I built in deliberately
$.a.state↔$.b.state.max_strengthis always reported, so a near-miss below the threshold stays visible instead of collapsing to a barefalse.A bug caught in testing
The first implementation silently never fired. Two path vocabularies are in play:
invariantsnames fields relative to each record ($.reviewer), the document trie names them relative to the whole document ($[*].reviewer). I was intersecting the two sets, which can never match.Symptom was subtle — hints appeared in the output with
observed: false, max_strength: 0.0, which looks exactly like a legitimate "expected relationship absent" result. I only caught it because my fixture hadreviewerandreview_stateperfectly correlated, so a 0.0 was impossible.Matching is now on the trailing key throughout, with a regression test pinning the exact mismatch (
$.reviewerrelationship against$[*].reviewerdocument path).That's the fifth time this session a "comparable-looking number that wasn't" nearly shipped. Worth noting the pattern.
Tests
9 unit tests: trailing-key matching at any depth, observed when spanning two fields, unobserved when the relationship is missing, weak relationship doesn't count but is still reported, hint needs two present fields, relationship within one pattern doesn't confirm, unobserved-first ordering, determinism, and the vocabulary-bridging regression.
Full workspace suite: 77 test binaries, 0 failures.
cargo fmt --checkclean. 0 clippy errors.