Skip to content

feat(ir): per-rule target scope via params.target_scope (closes #279) - #289

Merged
uda-lab-agent merged 3 commits into
mainfrom
issue-279-target-scope
Jul 4, 2026
Merged

feat(ir): per-rule target scope via params.target_scope (closes #279)#289
uda-lab-agent merged 3 commits into
mainfrom
issue-279-target-scope

Conversation

@uda-lab-agent

Copy link
Copy Markdown
Collaborator

Summary

Implements S3 of umbrella #277 (incremental audit trunk): rules declare their own target domain via a new params.target_scope key, and the engine computes a per-rule effective set so validate rules.md --target-changed becomes a full incremental audit without the caller enumerating which rules care about which files.

Binding contract: docs/design/multi-target.md §9 (ratified in #287).

effective_set = scope_expansion(params.target_scope) ∩ run-level candidate set

Engine-side only (CLI / validator.py); backends are untouched and a rule without a scope dispatches byte-for-byte as before.

What changed

  • targets.resolve_rule_scope — grammar validation (§9.1), memoized repo-wide glob expansion keyed by (pattern, repo_root) (§9.6), scope ∩ candidate on normalized repo-relative POSIX paths (§9.2), returning a discriminated ScopeResolution.
  • validator — per-rule scope planning wired into both the sequential and bounded-concurrent dispatch loops. A non-empty effective set dispatches a per-rule TargetSpec and appends scope_effective_set evidence to the verdict; empty/invalid/over-cap short-circuit without a backend call.
  • Evidence vocabulary (§9.8): scope_effective_set (rides on the verdict), scope_emptyPASS, scope_invalidUNAVAILABLE, scope_file_limit_exceeded → per-rule UNAVAILABLE (one over-broad rule never sinks the run, §9.5).
  • Untouched by design: Deterministically short-circuit target_kind mismatch before invoking llm-rubric #178 target_kind precheck stays run-level (§9.7); an llm-rubric multi-file effective set stays multi_target_unsupported until S5 (§9.10).
  • No IR schema change: target_scope rides inside params (opaque passthrough dict), so --rules-format ir round-trips it and validate()'s public contract is backward compatible (§9.9, AC5). A new optional repo_root keyword on validate() is additive; it is resolved lazily from cwd when omitted.
  • Docs: docs/rule-ir.md (params.target_scope section), docs/cli-reference.md (per-rule target scope + refreshed S3 forward-references), docs/design/multi-target.md §9 status flipped to implemented.

Acceptance criteria (#279)

  • AC1 — two scopes (docs/**/*.md, src/**/*.py) against --target . evaluate disjoint subsets; per-rule effective set in evidence. (tests/test_cli_scope.py::test_ac1_two_scopes_disjoint_subsets)
  • AC2 — scope ∩ --target-changed end-to-end. (tests/test_cli_scope.py::test_ac2_scope_intersects_changed_set)
  • AC3 — empty effective set → scope_empty PASS, not a run abort. (tests/test_validator_scope.py::TestScopeEmpty)
  • AC4 — per-rule DEFAULT_FILE_LIMIT breach → per-rule diagnostic; other rules unaffected. (tests/test_validator_scope.py::TestPerRuleFileLimit)
  • AC5 — existing literal-path rules and validate() unchanged; IR round-trips target_scope. (tests/test_validator_scope.py::TestUnscopedByteIdentical, TestIrRoundTrip)

Validation

  • uv run pytest1652 passed (37 new across test_scope_resolution.py, test_validator_scope.py, test_cli_scope.py)
  • uvx ruff check . — clean
  • uv run pyright — 0 errors, 0 warnings

Closes #279

🤖 Generated with Claude Code

https://claude.ai/code/session_01Wx8qUs1ipy6Nf82hu2eDhg

@t-uda

t-uda commented Jul 4, 2026

Copy link
Copy Markdown
Owner

@codex please review this PR

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

gate-keeper dogfooding

rule status judgment primary_reason
rule-dogfooding-rules-L23 PASS pass The PR description body clearly describes the user-visible change by explaining that rules now declare params.target_scope and validate rules.md --target-changed becomes a full incremental audit...
rule-dogfooding-rules-L24 PASS pass The artifact is a PR description and it explicitly documents verification in a dedicated Validation section with concrete commands and results.
rule-dogfooding-rules-L25 PASS pass The PR description contains no hardcoded absolute filesystem locations tied to a specific user, host username, devcontainer user, or workspace root layout.

Tokens: in=7425 out=614, latency: 8335 ms, model: gpt-5.4, prompt_version: v7

See docs/dogfooding.md for the per-rule promotion path.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5024d4c9c

ℹ️ 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".

Comment thread src/gate_keeper/validator.py Outdated
uda-lab-agent and others added 3 commits July 4, 2026 23:37
S3 of umbrella #277 (incremental audit trunk). Rules may declare
params.target_scope (a list of repo-relative globs); the engine computes a
per-rule effective set (scope ∩ run-level candidate set) and dispatches each
rule against its own TargetSpec. Engine-side only per docs/design/multi-target.md
§9 — backends are untouched and a rule without a scope dispatches byte-for-byte
as before.

- targets.resolve_rule_scope: grammar validation, memoized repo-wide expansion
  (§9.6), scope ∩ candidate on repo-relative POSIX paths, discriminated outcome.
- validator: per-rule scope planning in both sequential and concurrent loops;
  scope_effective_set evidence rides on dispatched verdicts; scope_empty (PASS),
  scope_invalid (UNAVAILABLE), scope_file_limit_exceeded (per-rule UNAVAILABLE).
- #178 target_kind precheck stays run-level and untouched (§9.7); llm-rubric
  multi-file effective sets stay multi_target_unsupported until S5 (§9.10).
- target_scope rides inside params (opaque passthrough dict) so the IR schema is
  unchanged and --rules-format ir round-trips it (§9.9).
- Docs: rule-ir.md params.target_scope, cli-reference.md per-rule scope section,
  multi-target.md §9 status flipped to implemented.

Quality gates: uv run pytest (1652 passed), uvx ruff check (clean),
uv run pyright (0 errors).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wx8qUs1ipy6Nf82hu2eDhg
…format

Addresses codex P2 review on #289:
- Concurrent dispatch now appends scope_effective_set evidence to the ERROR
  diagnostic when a scoped rule's backend raises, matching the sequential
  path's auditability contract. Regression test covers both paths.
- Apply `ruff format` to the new files (the CI `lint` job runs
  `ruff format --check`, which was the failing check).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wx8qUs1ipy6Nf82hu2eDhg
The #288 eval-cache and #279 per-rule scope both dispatch through the validator
loop. After rebasing on #288, the cache is keyed on the rule's dispatched target
(the per-rule effective set) and a cache hit still carries scope_effective_set
evidence. Regression test covers both sequential and concurrent paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wx8qUs1ipy6Nf82hu2eDhg
@uda-lab-agent
uda-lab-agent force-pushed the issue-279-target-scope branch from f5024d4 to e8f0c4e Compare July 4, 2026 14:41
@uda-lab-agent
uda-lab-agent merged commit 9cd3b07 into main Jul 4, 2026
6 checks passed
@uda-lab-agent
uda-lab-agent deleted the issue-279-target-scope branch July 4, 2026 14:43
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.

IR: per-rule target scope with engine-computed effective target sets

2 participants