Skip to content

Add a scope model and selector mechanism for carried rules (#368, PR-1) - #369

Merged
ptr727 merged 9 commits into
developfrom
rule-scope-mechanism-368
Jul 20, 2026
Merged

Add a scope model and selector mechanism for carried rules (#368, PR-1)#369
ptr727 merged 9 commits into
developfrom
rule-scope-mechanism-368

Conversation

@ptr727

Copy link
Copy Markdown
Owner

What and why

First of four staged PRs for #368: give every governance rule a single explicit scope, so carried docs become granular single-scope pieces composed per repo rather than large pieces with internal carve-outs a reader must piece out. This PR is the inert foundation — it adds the mechanism and documents the model, with zero fleet-finding delta. Policy changes (turning on section-presence checking, the doc surgery, carrying Verification Discipline) follow in later PRs, each held before main.

Changes

  • spec/scope-model.md (new, hub-only, not in the carried baseline): the two axes — home (host vs repo) and reach (hub-only / all-downstream / type-specific) — and the appliesToselector vocabulary: four disjoint namespaces (project types, workflowModel, releaseTrigger, consumerModel). States the load-bearing semantics: appliesTo is any-of (cross-axis AND is deliberately not expressible — that's the signal to split a piece), and entry-level AND section-level appliesTo compose. Records CODESTYLE.md's section→scope mapping (whole-carried, so documented not mechanized).
  • spec/files.schema.json: a sections element may be a bare string or a {name, appliesTo} object (oneOf). Backward-compatible — every existing entry stays valid.
  • spec/audit.py: match appliesTo against a repo's full selector set (repo_selectors), and replace the hardcoded operational develop.json path-swap with two data entries in files.json (appliesTo: ["release"] vs ["operational"]). This is the proof that the selector model subsumes an existing ad-hoc carve-out.
  • spec/validate.py: first pass over files.json — every appliesTo token must resolve to a known selector, no project type may collide with a reserved token (keeps the namespaces disjoint), and every cataloged repo must declare consumerModel so a push/pull-scoped section can't fail open.
  • AUDIT.md §3 + files.json note: one-line pointers to the scope model.

Inertness — verified

The four selector namespaces are disjoint and no current appliesTo token is non-*, so broadening the matcher changes no match. Proven by computing the required-file set for all 21 cataloged repos under old-code+old-data vs new-code+new-data: 0 differences. spec/validate.py stays green (and now also validates files.json). markdownlint, editorconfig-checker clean.

Held on develop — no develop → main promotion — per the standing instruction to observe what returns to develop first.

Foundational, deterministically inert step toward giving every governance rule
a single explicit scope so carried docs are granular single-scope pieces
composed per repo, not large pieces with internal carve-outs.
- spec/scope-model.md (new, hub-only, not carried): defines the two axes
(host vs repo home; hub-only / all-downstream / type-specific reach) and the
appliesTo selector vocabulary - four disjoint namespaces (project types,
workflowModel, releaseTrigger, consumerModel) - with the any-of and
entry-AND-section semantics. Records CODESTYLE's section->scope mapping.
- spec/files.schema.json: a sections element may now be a bare string or a
{name, appliesTo} object (oneOf), so a section can be scoped, not just a file.
Backward-compatible - every existing entry stays valid.
- spec/audit.py: match appliesTo against a repo's full selector set
(repo_selectors: types + workflowModel + releaseTrigger + consumerModel), and
replace the hardcoded operational develop.json path swap with two data
entries in files.json (appliesTo release vs operational). The namespaces are
disjoint and no current appliesTo token is non-star, so the required-file set
is unchanged for all 21 cataloged repos (verified by diffing old vs new).
- spec/validate.py: first pass over files.json - every appliesTo token must
resolve to a known selector, no project type may collide with a reserved
token, and every cataloged repo must declare consumerModel (push/pull) so a
push/pull-scoped section cannot fail open.
- AUDIT.md section 3 + files.json note: one-line pointers to the scope model.
No fleet-finding delta: this PR adds capability and codifies the current state.
The section-presence check, the doc surgery, and carrying Verification
Discipline follow in later PRs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings July 20, 2026 19:37

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Introduces a scope model and selector mechanism (appliesTo) for carried governance files/sections, enabling per-repo composition without changing current fleet findings.

Changes:

  • Add scope-selector vocabularies and files.json selector validation to spec/validate.py.
  • Add selector-aware matching to spec/audit.py, including moving the operational develop.json swap from code into spec/files.json data.
  • Add the appliesTo model documentation (spec/scope-model.md) and extend spec/files.schema.json to allow per-section selector objects.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
spec/validate.pyAdds selector vocab + validates consumerModel presence and files.jsonappliesTo tokens.
spec/scope-model.mdDocuments the scope model, selector namespaces, and appliesTo semantics.
spec/files.schema.jsonExtends schema to allow sections entries as strings or { name, appliesTo } objects.
spec/files.jsonAdds selector-scoped baseline entries (notably release vs operational develop rulesets) and documents appliesTo.
spec/audit.pyComputes repo selector sets and applies appliesTo matching when auditing baseline file presence.
AUDIT.mdPoints readers to the scope model when explaining applicability for carried files/sections.

Comment threadspec/scope-model.md Outdated
Comment threadAUDIT.md Outdated
…#369)
The repo doc convention (AGENTS.md) requires reference-style links in every
markdown file except the agent-instruction files. Convert spec/scope-model.md's
inline links to reference-style with a definitions block, and change the new
AUDIT.md pointer to the reference-style [scope-model] with its definition added
alphabetically to the Repo group. Both Copilot round-1 findings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings July 20, 2026 19:48

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

spec/files.schema.json:40

  • The top-level entry "appliesTo" schema is also unconstrained for array element types. Restrict it to "string" or "array of strings" for consistency with the section-level form and to prevent non-string tokens from reaching runtime matchers.
 "intentRef": { "type": "string" },
"appliesTo": { "type": ["string", "array"] }
}

Comment threadspec/scope-model.md Outdated
Comment threadspec/scope-model.md Outdated
Comment threadspec/files.schema.json
Comment threadspec/validate.py
Comment threadspec/audit.py
…ons (#369)
Copilot round-2 findings:
- files.schema.json: appliesTo array items are now constrained to strings at
both the entry level and the new section-object level, so a non-string token
cannot reach the runtime matchers.
- validate.py: check_selector guards a non-string token explicitly (CI runs no
JSON-schema validation) instead of crashing on set membership of an
unhashable value.
- scope-model.md, audit.py, AUDIT.md: replace clause-joining semicolons in the
new prose and docstring with the house comma/two-sentence form.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings July 20, 2026 19:54

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment threadspec/scope-model.md Outdated
Comment threadspec/audit.py Outdated
Copilot round-3 findings: scope-model.md and the repo_selectors docstring
claimed every selector resolves repo -> defaults -> fleet default, but
consumerModel has no fleet default - validate.py requires it on every cataloged
repo instead. State each selector's resolution accurately: workflowModel and
releaseTrigger fall back to a fleet default (release, two-phase); consumerModel
is required per cataloged repo, so a cataloged repo always contributes one.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings July 20, 2026 20:00

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment threadspec/validate.py
Copilot round-4 finding: check_selector accepted an empty appliesTo list, which
scopes an entry or section to no repo at all (it fails open - silently applies
nowhere). Reject [] in validate.py with a clear message, and add minItems:1 to
both appliesTo definitions in files.schema.json so an empty list is also a
schema violation. Use "*" for all repos, or list selectors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings July 20, 2026 20:04

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment threadspec/validate.py
Comment threadspec/validate.py
Copilot round-5 findings: releaseTrigger is now a scope selector, but validate
checked only workflowModel, so an invalid releaseTrigger would silently fail to
match any releaseTrigger-scoped section instead of erroring. Add per-repo and
defaults.releaseTrigger validation against RELEASE_TRIGGERS, mirroring the
workflowModel checks, and drive all three model/trigger/consumer checks off the
vocabulary constants so the messages and membership tests share one source.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings July 20, 2026 20:10

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Comment threadspec/scope-model.md Outdated
Comment threadspec/scope-model.md Outdated
Comment threadspec/scope-model.md Outdated
Comment threadspec/scope-model.md Outdated
…#369)
Copilot round-6 findings: three scope-model.md headings were sentence-case
(AGENTS.md title-case rule) and the CODESTYLE section-scope list used semicolons
between comma-free items, reading as clause-joining. Title-case the headings and
switch the list to commas.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings July 20, 2026 20:15

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

spec/audit.py:100

  • repo_selectors() falls back to defaults.get('consumerModel'), but registry/repos.schema.json does not allow defaults.consumerModel (defaults has additionalProperties:false and only defines groundTruthBranch/releaseTrigger/workflowModel). Keeping a defaults fallback here is dead code and can mislead future editors about supported registry shape; prefer to read only the per-repo consumerModel (which validate.py already requires for cataloged repos).
 sel.add(entry.get("workflowModel") or defaults.get("workflowModel") or "release")
sel.add(entry.get("releaseTrigger") or defaults.get("releaseTrigger") or "two-phase")
cm = entry.get("consumerModel") or defaults.get("consumerModel")
if cm:
sel.add(cm)

Copilot round-7 low-confidence finding (correct): repo_selectors fell back to
defaults.get("consumerModel"), but registry/repos.schema.json's defaults object
is additionalProperties:false with only groundTruthBranch/releaseTrigger/
workflowModel, so defaults.consumerModel can never exist - the fallback was dead
code that misrepresents the supported registry shape. Read only the per-repo
consumerModel (validate.py requires it on every cataloged repo); the guard stays
to shield a malformed non-cataloged entry. Still inert: required-file set
unchanged for all 21 repos.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings July 20, 2026 20:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment threadspec/validate.py
Copilot round-8 finding: the files.json validation loop exists because CI runs
no JSON-schema validation, but it assumed well-formed input - a non-array
baseline, a non-object entry, a non-array sections, or a non-string/non-object
section element would raise AttributeError or iterate a string instead of
reporting a clear validation error. Guard each shape and continue, mirroring the
existing secrets.json shape checks. Verified all four malformed shapes now exit
1 with a clear message and no traceback.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings July 20, 2026 20:23

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@ptr727
ptr727 merged commit 426591f into developJul 20, 2026
7 checks passed
@ptr727
ptr727 deleted the rule-scope-mechanism-368 branch July 20, 2026 21:32
Sign up for freeto 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.

2 participants

@ptr727