Skip to content

feat: v0.3.0 — per-lens threshold + weighted signals#2

Merged
broomva merged 1 commit into
mainfrom
feat/v0.3.0-per-lens-thresholds
May 14, 2026
Merged

feat: v0.3.0 — per-lens threshold + weighted signals#2
broomva merged 1 commit into
mainfrom
feat/v0.3.0-per-lens-thresholds

Conversation

@broomva
Copy link
Copy Markdown
Owner

@broomva broomva commented May 14, 2026

Summary

Trigger-strategy upgrade. Lenses can now declare:

  • threshold: int (top-level) — per-lens score threshold override; defaults to 2
  • signals.weights.<type>: int (nested) — per-signal-type multiplier; defaults to 1; `0` disables

Closes the "global scoring rules apply to every lens" limitation from v0.1.0/v0.2.0. Specialist lenses can raise threshold to 3 to avoid false positives; broad lenses can lower to 1; branch-pattern-dominant lenses can weight branch matches 3× and keyword matches 1× to reflect signal specificity.

Example — strict security-review lens

```yaml

name: security-review
threshold: 3
signals:
paths: ["/auth/", "**/credentials*"]
prompt_keywords: ["auth", "secret", "credential", "JWT", "OAuth"]
branch_patterns: ["feat/auth-", "feat/security-"]
linear_labels: ["topic:security"]
weights:
branch_patterns: 3 # branch is a strong signal
prompt_keywords: 1
paths: 1

```

Prompt = "rotate the JWT signing key" on branch `feat/auth-rotate` →

  • prompt_keywords=1 (×1=1), branch_patterns=1 (×3=3), paths=0 → total 4 ≥ threshold 3 → fires

Without weights, this would be 1+1+0=2 — below threshold; lens wouldn't fire.

Test plan

  • 20/20 pytest pass (7 new v0.3.0 tests: threshold-3-blocks-2-sig, threshold-1-fires-on-1, weighted-amplify, zero-weight-disables, validate-rejects-negative-threshold, validate-rejects-unknown-weight-key, validate-accepts-v030)
  • Workspace lenses (`_meta`, `rust-systems`) still validate clean — backward compat
  • Workspace rust-keyword prompt still fires `rust-systems` lens identically to v0.2.0
  • events.jsonl schema unchanged — raw counts preserved for M5 dream-cycle consumers
  • CHANGELOG + README + references/lens-schema.md + references/selection-algorithm.md updated
  • CI matrix (Python 3.11 + 3.12) will run on push

Backward compatibility

Lenses without `threshold` or `signals.weights` keep identical v0.2.0 scoring. No migration needed.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Per-lens threshold configuration: Set activation requirements independently for each lens
    • Per-signal-type weights: Control scoring contribution by signal type to fine-tune lens behavior
    • Enhanced validation for threshold and signal weight constraints
  • Documentation

    • Updated lens schema documentation with new v0.3.0 optional configuration fields
    • Refined selection algorithm documentation explaining weighted scoring model with practical examples

Review Change Stack

Closes the "global scoring rules apply to every lens" limitation. Lenses
can now declare their own `threshold` (top-level) and `signals.weights`
(nested per-signal-type) to tune routing for their specificity.

Added (v0.3.0 optional fields):
- `threshold: int` — per-lens score threshold override; defaults to 2
- `signals.weights: {paths, prompt_keywords, branch_patterns, linear_labels}`
  — per-signal-type integer multipliers; defaults to 1 each; 0 disables

Implementation:
- `_resolve_threshold(lens)` / `_resolve_weights(lens)` helpers
- `_score_lens` now computes Σ(raw_count × weight) per signal type
- `_select_lenses` selects on `score(L) >= effective_threshold(L)`
- `validate_lens` rejects non-positive threshold, non-int / negative weight,
  unrecognised weight keys

Tests (13 → 20):
- per_lens_threshold_3_blocks_2_signal_fire
- per_lens_threshold_1_fires_on_single_signal
- weighted_keyword_amplifies_single_hit_to_fire
- zero_weight_disables_signal_type
- validate_rejects_negative_threshold
- validate_rejects_unknown_weight_key
- validate_accepts_v030_optional_fields

Backward compatibility:
- All v0.1.0/v0.2.0 lenses (no threshold, no weights) keep identical
  scoring (weights default 1 → Σ × 1 = current sum)
- events.jsonl schema unchanged — recorded counts remain raw (unweighted)
- CLI signatures unchanged
- Workspace lenses (_meta + rust-systems) verified: validate clean,
  intake fires rust-systems on 3-keyword Rust prompt as before

Docs updated:
- CHANGELOG.md v0.3.0 entry with example
- README.md roadmap (v0.3.0 = trigger strategies; M3-M5 renumbered to v0.4-0.6)
- references/lens-schema.md — Optional fields section with security-review example
- references/selection-algorithm.md — weighted score formula + per-lens threshold notes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5169b3ea-7f8d-4154-b42f-d2bb014c274a

📥 Commits

Reviewing files that changed from the base of the PR and between 4c6473d and 6ff7be2.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • README.md
  • references/lens-schema.md
  • references/selection-algorithm.md
  • scripts/role-x.py
  • tests/test_role_x.py

📝 Walkthrough

Walkthrough

This PR upgrades the role-x lens trigger strategy to v0.3.0 by introducing optional per-lens threshold and per-signal-type signals.weights configuration. Changes include weighted scoring computation, per-lens threshold resolution during selection, comprehensive documentation, schema validation, and seven new test cases covering threshold semantics, weight amplification, and signal disabling.

Changes

v0.3.0 Trigger-Strategy Feature

Layer / File(s) Summary
Feature specification and algorithm documentation
CHANGELOG.md, README.md, references/lens-schema.md, references/selection-algorithm.md
Changelog entries document the v0.3.0 upgrade with per-lens threshold, per-signal signals.weights, weighted scoring, and backward-compatibility guarantees. README roadmap is updated with v0.3.0–v0.6.0 milestones. Lens schema reference adds optional field table and weight/threshold guidance. Selection algorithm doc replaces simple scoring with weighted, per-signal-type model using L.signals.weights.<type> with defaults, and Step 4 uses per-lens L.threshold (defaulting to 2) for selection with _meta fallback.
Schema validation and scoring constants
scripts/role-x.py
Constants define v0.3.0 optional fields, default per-signal weight of 1, and allowed signal-type keys. Lens validation extended to check signals.weights (only recognized keys, non-negative integers) and threshold (positive integer when present).
Weighted scoring and per-lens threshold resolution
scripts/role-x.py
New helper functions _resolve_weights and _resolve_threshold return effective per-lens configuration. _score_lens computes weighted totals by applying resolved weights to raw signal counts and includes weights_applied in returned breakdown. _select_lenses defaults threshold to DEFAULT_THRESHOLD, resolves per-lens threshold for each candidate, selects lenses where score >= per_lens_threshold, and outputs per_lens_thresholds map alongside existing score breakdown.
Test fixtures and comprehensive v0.3.0 validation
tests/test_role_x.py
Four new v0.3.0 lens fixtures demonstrate threshold blocking (threshold=3 requires 3 signals), loose firing (threshold=1 fires on 1), weight amplification (keyword weight=2 triggers on single hit), and signal disabling (paths weight=0). Helper _seed_with builds temporary workspaces with custom lens configurations. Seven tests assert per-lens threshold semantics, keyword weight amplification, path signal disabling, and schema rejection of invalid threshold/weight values while accepting v0.3.0 optional fields.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A lens sees clearer when thresholds align,
With weights that amplify signal so fine,
Per-lens configuration, a strategy wise,
Backward compatible under the skies!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/v0.3.0-per-lens-thresholds

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 and usage tips.

@broomva broomva merged commit 9d2b223 into main May 14, 2026
2 of 3 checks passed
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.

1 participant