Skip to content

feat(invariants): consume relationship hints, reporting expected-but-absent - #78

Merged
copyleftdev merged 1 commit into
mainfrom
feat/wire-relationship-hints
Jul 30, 2026
Merged

feat(invariants): consume relationship hints, reporting expected-but-absent#78
copyleftdev merged 1 commit into
mainfrom
feat/wire-relationship-hints

Conversation

@copyleftdev

Copy link
Copy Markdown
Owner

Closes #74.

The problem

VajraPlugin::relationship_hints was declared by every domain plugin and consumed by nothing:

$ rg -n "relationship_hints" vajra-cli/src vajra-essence/src vajra-core/src
$ # (no matches)

~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 → reviewer as a functional dependency, weighted 0.85 — so deleting it would throw away content that took effort to author.

invariants now 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: false means the domain expects those fields to relate, the fields are present, and the data does not show it. Above, pr_review_assignment expects pr_author to determine reviewer; the measured strength is exactly 0.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

  • Hints never weight the information theory. Entropy and MI are measured from the data alone; a hint is context laid alongside them. Weighting would make the numbers unfalsifiable, which is the opposite of the point.
  • A hint needs two present fields to be evaluated. One is untestable, and reporting it as a failure would be noise.
  • Confirmation requires spanning two distinct patterns. Two paths matching the same pattern prove nothing — tested with $.a.state$.b.state.
  • max_strength is always reported, so a near-miss below the threshold stays visible instead of collapsing to a bare false.
  • No wrapper when no hint applies — the common case keeps the documented flat-array contract.

A bug caught in testing

The first implementation silently never fired. Two path vocabularies are in play: invariants names 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 had reviewer and review_state perfectly correlated, so a 0.0 was impossible.

Matching is now on the trailing key throughout, with a regression test pinning the exact mismatch ($.reviewer relationship against $[*].reviewer document 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 --check clean. 0 clippy errors.

…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.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@copyleftdev, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3846fd7d-62f7-4bc5-98dd-11ae590355d9

📥 Commits

Reviewing files that changed from the base of the PR and between 302276a and f0248ca.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • docs/src/cmd-invariants.md
  • vajra-cli/src/hints.rs
  • vajra-cli/src/main.rs

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

❤️ Share

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

@copyleftdev
copyleftdev merged commit c66b648 into main Jul 30, 2026
5 checks passed
@copyleftdev
copyleftdev deleted the feat/wire-relationship-hints branch July 30, 2026 05:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VajraPlugin::relationship_hints is declared by every plugin and consumed by nothing

1 participant