Ship branch rulesets as versioned JSON in the re-sync / drift loop - #212

Merged
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json
Jun 26, 2026
Merged

Ship branch rulesets as versioned JSON in the re-sync / drift loop#212
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json

Conversation

@ptr727

@ptr727ptr727 commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Problem

Closes#211. Branch rulesets are live GitHub config applied once at repo creation, so they sit outside the file-based re-sync loop (AGENTS.md "Staying in Sync"). Two consequences: a corrected template ruleset never propagates to existing derived repos, and downstream ruleset drift is invisible. This bit ptr727/PlexCleaner — its synced docs said strict=false while its live rulesets stayed strict=true on both develop and main (the exact #82 failure mode), fixed locally only after it broke auto-merge and blocked a promotion.

Change

  • Canonical rulesets as committed files, maintained in this template only..github/rulesets/develop.json and .github/rulesets/main.json hold the re-importable writable subset ({name, target, enforcement, bypass_actors, conditions, rules}), strict_required_status_checks_policy: false on both. They port verbatim with no placeholders — conditions key on refs/heads/{develop,main}, bypass_actors uses the global Admin role actor_id: 5, the required check binds by name.
  • README "Rules / Rulesets" repoints the source of truth to these committed files: setup imports from them; the live export becomes the regenerate recipe run in the template when the maintainer changes the live rulesets.
  • AGENTS.md documents that the rulesets are deliberately not in the verbatim-carry set and are not carried/re-synced downstream as a per-repo copy — they are live config, not a file a derived repo consumes. They ride the re-sync loop from the hub: diff each derived repo's live rulesets against the template's committed JSON and correct drift via a full-payload PUT. The drift command normalizes rules[]/bypass_actors[] order so a reordered-but-equivalent ruleset doesn't read as drift.
  • Also folds in pending spell-dict / workspace-extension additions (and mirrors the two new general extensions into both devcontainers).

Verification

  • jq -S round-trip stable for both files; order-normalized drift diff against the template's own live rulesets reports develop: in sync / main: in sync.
  • Ran the drift check across all 8 derived repos (read-only): 6 in sync, Utilities has real live drift, homeassistant-purpleair has no rulesets configured — both surfaced to the maintainer (issues filed), not auto-applied.
  • markdownlint-cli2 clean on README.md and AGENTS.md (0 errors).

🤖 Generated with Claude Code

Closes the gap from #211: branch rulesets were live GitHub config applied
once at repo creation, so they sat outside the file-based re-sync loop - a
corrected template ruleset never propagated to derived repos, and downstream
drift was invisible (PlexCleaner's docs said strict=false while live config
stayed strict=true on both branches).
- Commit the canonical writable subset as .github/rulesets/{develop,main}.json
(strict_required_status_checks_policy false on both - the #82 value this
exists to keep propagated). They port verbatim: conditions key on
refs/heads/{develop,main}, bypass_actors uses global Admin role actor_id 5,
the required check binds by name.
- README "Rules / Rulesets": repoint the source of truth to the committed
files - import from them at setup; the live export becomes the regenerate
recipe run when the maintainer changes the template's live rulesets.
- AGENTS.md: add the rulesets to the verbatim-carry set and document the
live-vs-committed drift check (full-payload PUT to correct) in Staying in
Sync. Note that carrying the file only syncs the source of truth; live
config changes only on import/PUT.
Also folds in pending spell-dictionary / workspace-extension additions and
three deferred-item bullets that were already staged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 16:52

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

This PR brings branch rulesets into the repo-based re-sync/drift workflow by committing canonical develop/main ruleset JSON and updating documentation to treat those files as the versioned source of truth, plus minor editor/workspace hygiene updates.

Changes:

  • Add committed GitHub ruleset definitions for develop and main under .github/rulesets/.
  • Update README.md and AGENTS.md to import/sync rulesets from committed JSON and document how to detect/correct drift against live GitHub config.
  • Reformat and extend ProjectTemplate.code-workspace (spellings + recommended extensions).

Reviewed changes

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

Show a summary per file
FileDescription
README.mdUpdates ruleset setup docs to import from committed JSON; adds deferred-pattern notes.
ProjectTemplate.code-workspaceNormalizes formatting; adds cSpell words and extension recommendations.
AGENTS.mdAdds ruleset JSON to verbatim-carry list and documents drift-check procedure.
.github/rulesets/main.jsonIntroduces canonical main branch ruleset JSON (importable subset).
.github/rulesets/develop.jsonIntroduces canonical develop branch ruleset JSON (importable subset).

Comment threadREADME.md Outdated
ptr727and others added 2 commits June 26, 2026 09:56
GitHub returns a ruleset's rules[] (and bypass_actors[]) in arbitrary order,
so the plain diff false-positived on a reordered-but-equivalent ruleset
(PlexCleaner's develop/main read as DRIFT when only the rule order differed).
Sort both arrays before diffing so only real differences surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The versioned rulesets are live GitHub config, not a file a derived repo
consumes, so copying them into every downstream repo only adds noise and
divergence. Drop them from the verbatim-carry set; document that they live
only in the template as the source of truth and ride the re-sync loop from
the hub - diffing each derived repo's live config against the template's
committed JSON and correcting drift via full-payload PUT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17: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 5 out of 5 changed files in this pull request and generated 4 comments.

Comment threadREADME.md Outdated
Comment threadREADME.md Outdated
Comment threadProjectTemplate.code-workspace
Comment threadAGENTS.md Outdated
ptr727and others added 3 commits June 26, 2026 10:52
Two of the pre-staged Deferred Patterns are no longer deferred:
- "Factor cleanup-artifacts into a reusable workflow" is moot - #214 removes
the blanket cleanup job entirely (surgical consume-then-delete instead), so
there is nothing left to factor.
- "Generalize the input-validation step into a reusable pattern" is realized -
#213 codifies the validate-input/state-at-entry pattern in AGENTS.md.
Keep the publish-docker-readme "Validate inputs step" downstream-resync entry;
that concrete downstream action is still pending.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reword "never copied into derived repos" (README + AGENTS.md): the JSON is
maintained in the template as the source of truth and reconciled against a
repo's live config; it is not carried/re-synced as a per-repo copy. Avoids
the inaccurate absolute (a template-instantiated repo does receive the files).
- Mirror the two new general extensions (actionlint, shellcheck) into both
devcontainers and fix the stale `*.code-workspace` reference (the per-language
workspaces were consolidated into ProjectTemplate.code-workspace in #210).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 18:17
@ptr727
ptr727 merged commit 59e0e91 into developJun 26, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/rulesets-as-versioned-json branch June 26, 2026 18: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 7 out of 7 changed files in this pull request and generated 4 comments.

"customizations": {
"vscode": {
// Mirror of `recommendations` in Python.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
"customizations": {
"vscode": {
// Mirror of `recommendations` in DotNet.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
Comment threadAGENTS.md
Comment on lines +285 to +286
The branch rulesets ([`.github/rulesets/{develop,main}.json`](./.github/rulesets/)) are deliberately **not** in this carry set: they are live GitHub config, not a file a derived repo consumes, so carrying and re-syncing them downstream only adds noise. They are maintained **in this template** as the source of truth and are reconciled against each repo's *live* config during porting/re-sync - see [Staying in Sync](#staying-in-sync-and-reporting-drift-upstream).

Comment threadREADME.md
Comment on lines 504 to +508
for name in develop main; do
id=$(gh api repos/ptr727/ProjectTemplate/rulesets --jq ".[] | select(.name==\"$name\") | .id")
gh api "repos/ptr727/ProjectTemplate/rulesets/$id" \
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' > "$name-ruleset.json"
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' \
| jq -S '.' > ".github/rulesets/$name.json"
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Ship branch rulesets as versioned JSON in the re-sync / drift loop - #212

Merged
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json
Jun 26, 2026
Merged

Ship branch rulesets as versioned JSON in the re-sync / drift loop#212
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json

Conversation

@ptr727

@ptr727ptr727 commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Problem

Closes#211. Branch rulesets are live GitHub config applied once at repo creation, so they sit outside the file-based re-sync loop (AGENTS.md "Staying in Sync"). Two consequences: a corrected template ruleset never propagates to existing derived repos, and downstream ruleset drift is invisible. This bit ptr727/PlexCleaner — its synced docs said strict=false while its live rulesets stayed strict=true on both develop and main (the exact #82 failure mode), fixed locally only after it broke auto-merge and blocked a promotion.

Change

  • Canonical rulesets as committed files, maintained in this template only..github/rulesets/develop.json and .github/rulesets/main.json hold the re-importable writable subset ({name, target, enforcement, bypass_actors, conditions, rules}), strict_required_status_checks_policy: false on both. They port verbatim with no placeholders — conditions key on refs/heads/{develop,main}, bypass_actors uses the global Admin role actor_id: 5, the required check binds by name.
  • README "Rules / Rulesets" repoints the source of truth to these committed files: setup imports from them; the live export becomes the regenerate recipe run in the template when the maintainer changes the live rulesets.
  • AGENTS.md documents that the rulesets are deliberately not in the verbatim-carry set and are not carried/re-synced downstream as a per-repo copy — they are live config, not a file a derived repo consumes. They ride the re-sync loop from the hub: diff each derived repo's live rulesets against the template's committed JSON and correct drift via a full-payload PUT. The drift command normalizes rules[]/bypass_actors[] order so a reordered-but-equivalent ruleset doesn't read as drift.
  • Also folds in pending spell-dict / workspace-extension additions (and mirrors the two new general extensions into both devcontainers).

Verification

  • jq -S round-trip stable for both files; order-normalized drift diff against the template's own live rulesets reports develop: in sync / main: in sync.
  • Ran the drift check across all 8 derived repos (read-only): 6 in sync, Utilities has real live drift, homeassistant-purpleair has no rulesets configured — both surfaced to the maintainer (issues filed), not auto-applied.
  • markdownlint-cli2 clean on README.md and AGENTS.md (0 errors).

🤖 Generated with Claude Code

Closes the gap from #211: branch rulesets were live GitHub config applied
once at repo creation, so they sat outside the file-based re-sync loop - a
corrected template ruleset never propagated to derived repos, and downstream
drift was invisible (PlexCleaner's docs said strict=false while live config
stayed strict=true on both branches).
- Commit the canonical writable subset as .github/rulesets/{develop,main}.json
(strict_required_status_checks_policy false on both - the #82 value this
exists to keep propagated). They port verbatim: conditions key on
refs/heads/{develop,main}, bypass_actors uses global Admin role actor_id 5,
the required check binds by name.
- README "Rules / Rulesets": repoint the source of truth to the committed
files - import from them at setup; the live export becomes the regenerate
recipe run when the maintainer changes the template's live rulesets.
- AGENTS.md: add the rulesets to the verbatim-carry set and document the
live-vs-committed drift check (full-payload PUT to correct) in Staying in
Sync. Note that carrying the file only syncs the source of truth; live
config changes only on import/PUT.
Also folds in pending spell-dictionary / workspace-extension additions and
three deferred-item bullets that were already staged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 16:52

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

This PR brings branch rulesets into the repo-based re-sync/drift workflow by committing canonical develop/main ruleset JSON and updating documentation to treat those files as the versioned source of truth, plus minor editor/workspace hygiene updates.

Changes:

  • Add committed GitHub ruleset definitions for develop and main under .github/rulesets/.
  • Update README.md and AGENTS.md to import/sync rulesets from committed JSON and document how to detect/correct drift against live GitHub config.
  • Reformat and extend ProjectTemplate.code-workspace (spellings + recommended extensions).

Reviewed changes

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

Show a summary per file
FileDescription
README.mdUpdates ruleset setup docs to import from committed JSON; adds deferred-pattern notes.
ProjectTemplate.code-workspaceNormalizes formatting; adds cSpell words and extension recommendations.
AGENTS.mdAdds ruleset JSON to verbatim-carry list and documents drift-check procedure.
.github/rulesets/main.jsonIntroduces canonical main branch ruleset JSON (importable subset).
.github/rulesets/develop.jsonIntroduces canonical develop branch ruleset JSON (importable subset).

Comment threadREADME.md Outdated
ptr727and others added 2 commits June 26, 2026 09:56
GitHub returns a ruleset's rules[] (and bypass_actors[]) in arbitrary order,
so the plain diff false-positived on a reordered-but-equivalent ruleset
(PlexCleaner's develop/main read as DRIFT when only the rule order differed).
Sort both arrays before diffing so only real differences surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The versioned rulesets are live GitHub config, not a file a derived repo
consumes, so copying them into every downstream repo only adds noise and
divergence. Drop them from the verbatim-carry set; document that they live
only in the template as the source of truth and ride the re-sync loop from
the hub - diffing each derived repo's live config against the template's
committed JSON and correcting drift via full-payload PUT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17: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 5 out of 5 changed files in this pull request and generated 4 comments.

Comment threadREADME.md Outdated
Comment threadREADME.md Outdated
Comment threadProjectTemplate.code-workspace
Comment threadAGENTS.md Outdated
ptr727and others added 3 commits June 26, 2026 10:52
Two of the pre-staged Deferred Patterns are no longer deferred:
- "Factor cleanup-artifacts into a reusable workflow" is moot - #214 removes
the blanket cleanup job entirely (surgical consume-then-delete instead), so
there is nothing left to factor.
- "Generalize the input-validation step into a reusable pattern" is realized -
#213 codifies the validate-input/state-at-entry pattern in AGENTS.md.
Keep the publish-docker-readme "Validate inputs step" downstream-resync entry;
that concrete downstream action is still pending.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reword "never copied into derived repos" (README + AGENTS.md): the JSON is
maintained in the template as the source of truth and reconciled against a
repo's live config; it is not carried/re-synced as a per-repo copy. Avoids
the inaccurate absolute (a template-instantiated repo does receive the files).
- Mirror the two new general extensions (actionlint, shellcheck) into both
devcontainers and fix the stale `*.code-workspace` reference (the per-language
workspaces were consolidated into ProjectTemplate.code-workspace in #210).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 18:17
@ptr727
ptr727 merged commit 59e0e91 into developJun 26, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/rulesets-as-versioned-json branch June 26, 2026 18: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 7 out of 7 changed files in this pull request and generated 4 comments.

"customizations": {
"vscode": {
// Mirror of `recommendations` in Python.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
"customizations": {
"vscode": {
// Mirror of `recommendations` in DotNet.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
Comment threadAGENTS.md
Comment on lines +285 to +286
The branch rulesets ([`.github/rulesets/{develop,main}.json`](./.github/rulesets/)) are deliberately **not** in this carry set: they are live GitHub config, not a file a derived repo consumes, so carrying and re-syncing them downstream only adds noise. They are maintained **in this template** as the source of truth and are reconciled against each repo's *live* config during porting/re-sync - see [Staying in Sync](#staying-in-sync-and-reporting-drift-upstream).

Comment threadREADME.md
Comment on lines 504 to +508
for name in develop main; do
id=$(gh api repos/ptr727/ProjectTemplate/rulesets --jq ".[] | select(.name==\"$name\") | .id")
gh api "repos/ptr727/ProjectTemplate/rulesets/$id" \
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' > "$name-ruleset.json"
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' \
| jq -S '.' > ".github/rulesets/$name.json"
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Ship branch rulesets as versioned JSON in the re-sync / drift loop - #212

Merged
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json
Jun 26, 2026
Merged

Ship branch rulesets as versioned JSON in the re-sync / drift loop#212
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json

Conversation

@ptr727

@ptr727ptr727 commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Problem

Closes#211. Branch rulesets are live GitHub config applied once at repo creation, so they sit outside the file-based re-sync loop (AGENTS.md "Staying in Sync"). Two consequences: a corrected template ruleset never propagates to existing derived repos, and downstream ruleset drift is invisible. This bit ptr727/PlexCleaner — its synced docs said strict=false while its live rulesets stayed strict=true on both develop and main (the exact #82 failure mode), fixed locally only after it broke auto-merge and blocked a promotion.

Change

  • Canonical rulesets as committed files, maintained in this template only..github/rulesets/develop.json and .github/rulesets/main.json hold the re-importable writable subset ({name, target, enforcement, bypass_actors, conditions, rules}), strict_required_status_checks_policy: false on both. They port verbatim with no placeholders — conditions key on refs/heads/{develop,main}, bypass_actors uses the global Admin role actor_id: 5, the required check binds by name.
  • README "Rules / Rulesets" repoints the source of truth to these committed files: setup imports from them; the live export becomes the regenerate recipe run in the template when the maintainer changes the live rulesets.
  • AGENTS.md documents that the rulesets are deliberately not in the verbatim-carry set and are not carried/re-synced downstream as a per-repo copy — they are live config, not a file a derived repo consumes. They ride the re-sync loop from the hub: diff each derived repo's live rulesets against the template's committed JSON and correct drift via a full-payload PUT. The drift command normalizes rules[]/bypass_actors[] order so a reordered-but-equivalent ruleset doesn't read as drift.
  • Also folds in pending spell-dict / workspace-extension additions (and mirrors the two new general extensions into both devcontainers).

Verification

  • jq -S round-trip stable for both files; order-normalized drift diff against the template's own live rulesets reports develop: in sync / main: in sync.
  • Ran the drift check across all 8 derived repos (read-only): 6 in sync, Utilities has real live drift, homeassistant-purpleair has no rulesets configured — both surfaced to the maintainer (issues filed), not auto-applied.
  • markdownlint-cli2 clean on README.md and AGENTS.md (0 errors).

🤖 Generated with Claude Code

Closes the gap from #211: branch rulesets were live GitHub config applied
once at repo creation, so they sat outside the file-based re-sync loop - a
corrected template ruleset never propagated to derived repos, and downstream
drift was invisible (PlexCleaner's docs said strict=false while live config
stayed strict=true on both branches).
- Commit the canonical writable subset as .github/rulesets/{develop,main}.json
(strict_required_status_checks_policy false on both - the #82 value this
exists to keep propagated). They port verbatim: conditions key on
refs/heads/{develop,main}, bypass_actors uses global Admin role actor_id 5,
the required check binds by name.
- README "Rules / Rulesets": repoint the source of truth to the committed
files - import from them at setup; the live export becomes the regenerate
recipe run when the maintainer changes the template's live rulesets.
- AGENTS.md: add the rulesets to the verbatim-carry set and document the
live-vs-committed drift check (full-payload PUT to correct) in Staying in
Sync. Note that carrying the file only syncs the source of truth; live
config changes only on import/PUT.
Also folds in pending spell-dictionary / workspace-extension additions and
three deferred-item bullets that were already staged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 16:52

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

This PR brings branch rulesets into the repo-based re-sync/drift workflow by committing canonical develop/main ruleset JSON and updating documentation to treat those files as the versioned source of truth, plus minor editor/workspace hygiene updates.

Changes:

  • Add committed GitHub ruleset definitions for develop and main under .github/rulesets/.
  • Update README.md and AGENTS.md to import/sync rulesets from committed JSON and document how to detect/correct drift against live GitHub config.
  • Reformat and extend ProjectTemplate.code-workspace (spellings + recommended extensions).

Reviewed changes

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

Show a summary per file
FileDescription
README.mdUpdates ruleset setup docs to import from committed JSON; adds deferred-pattern notes.
ProjectTemplate.code-workspaceNormalizes formatting; adds cSpell words and extension recommendations.
AGENTS.mdAdds ruleset JSON to verbatim-carry list and documents drift-check procedure.
.github/rulesets/main.jsonIntroduces canonical main branch ruleset JSON (importable subset).
.github/rulesets/develop.jsonIntroduces canonical develop branch ruleset JSON (importable subset).

Comment threadREADME.md Outdated
ptr727and others added 2 commits June 26, 2026 09:56
GitHub returns a ruleset's rules[] (and bypass_actors[]) in arbitrary order,
so the plain diff false-positived on a reordered-but-equivalent ruleset
(PlexCleaner's develop/main read as DRIFT when only the rule order differed).
Sort both arrays before diffing so only real differences surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The versioned rulesets are live GitHub config, not a file a derived repo
consumes, so copying them into every downstream repo only adds noise and
divergence. Drop them from the verbatim-carry set; document that they live
only in the template as the source of truth and ride the re-sync loop from
the hub - diffing each derived repo's live config against the template's
committed JSON and correcting drift via full-payload PUT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17: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 5 out of 5 changed files in this pull request and generated 4 comments.

Comment threadREADME.md Outdated
Comment threadREADME.md Outdated
Comment threadProjectTemplate.code-workspace
Comment threadAGENTS.md Outdated
ptr727and others added 3 commits June 26, 2026 10:52
Two of the pre-staged Deferred Patterns are no longer deferred:
- "Factor cleanup-artifacts into a reusable workflow" is moot - #214 removes
the blanket cleanup job entirely (surgical consume-then-delete instead), so
there is nothing left to factor.
- "Generalize the input-validation step into a reusable pattern" is realized -
#213 codifies the validate-input/state-at-entry pattern in AGENTS.md.
Keep the publish-docker-readme "Validate inputs step" downstream-resync entry;
that concrete downstream action is still pending.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reword "never copied into derived repos" (README + AGENTS.md): the JSON is
maintained in the template as the source of truth and reconciled against a
repo's live config; it is not carried/re-synced as a per-repo copy. Avoids
the inaccurate absolute (a template-instantiated repo does receive the files).
- Mirror the two new general extensions (actionlint, shellcheck) into both
devcontainers and fix the stale `*.code-workspace` reference (the per-language
workspaces were consolidated into ProjectTemplate.code-workspace in #210).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 18:17
@ptr727
ptr727 merged commit 59e0e91 into developJun 26, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/rulesets-as-versioned-json branch June 26, 2026 18: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 7 out of 7 changed files in this pull request and generated 4 comments.

"customizations": {
"vscode": {
// Mirror of `recommendations` in Python.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
"customizations": {
"vscode": {
// Mirror of `recommendations` in DotNet.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
Comment threadAGENTS.md
Comment on lines +285 to +286
The branch rulesets ([`.github/rulesets/{develop,main}.json`](./.github/rulesets/)) are deliberately **not** in this carry set: they are live GitHub config, not a file a derived repo consumes, so carrying and re-syncing them downstream only adds noise. They are maintained **in this template** as the source of truth and are reconciled against each repo's *live* config during porting/re-sync - see [Staying in Sync](#staying-in-sync-and-reporting-drift-upstream).

Comment threadREADME.md
Comment on lines 504 to +508
for name in develop main; do
id=$(gh api repos/ptr727/ProjectTemplate/rulesets --jq ".[] | select(.name==\"$name\") | .id")
gh api "repos/ptr727/ProjectTemplate/rulesets/$id" \
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' > "$name-ruleset.json"
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' \
| jq -S '.' > ".github/rulesets/$name.json"
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Ship branch rulesets as versioned JSON in the re-sync / drift loop - #212

Merged
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json
Jun 26, 2026
Merged

Ship branch rulesets as versioned JSON in the re-sync / drift loop#212
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json

Conversation

@ptr727

@ptr727ptr727 commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Problem

Closes#211. Branch rulesets are live GitHub config applied once at repo creation, so they sit outside the file-based re-sync loop (AGENTS.md "Staying in Sync"). Two consequences: a corrected template ruleset never propagates to existing derived repos, and downstream ruleset drift is invisible. This bit ptr727/PlexCleaner — its synced docs said strict=false while its live rulesets stayed strict=true on both develop and main (the exact #82 failure mode), fixed locally only after it broke auto-merge and blocked a promotion.

Change

  • Canonical rulesets as committed files, maintained in this template only..github/rulesets/develop.json and .github/rulesets/main.json hold the re-importable writable subset ({name, target, enforcement, bypass_actors, conditions, rules}), strict_required_status_checks_policy: false on both. They port verbatim with no placeholders — conditions key on refs/heads/{develop,main}, bypass_actors uses the global Admin role actor_id: 5, the required check binds by name.
  • README "Rules / Rulesets" repoints the source of truth to these committed files: setup imports from them; the live export becomes the regenerate recipe run in the template when the maintainer changes the live rulesets.
  • AGENTS.md documents that the rulesets are deliberately not in the verbatim-carry set and are not carried/re-synced downstream as a per-repo copy — they are live config, not a file a derived repo consumes. They ride the re-sync loop from the hub: diff each derived repo's live rulesets against the template's committed JSON and correct drift via a full-payload PUT. The drift command normalizes rules[]/bypass_actors[] order so a reordered-but-equivalent ruleset doesn't read as drift.
  • Also folds in pending spell-dict / workspace-extension additions (and mirrors the two new general extensions into both devcontainers).

Verification

  • jq -S round-trip stable for both files; order-normalized drift diff against the template's own live rulesets reports develop: in sync / main: in sync.
  • Ran the drift check across all 8 derived repos (read-only): 6 in sync, Utilities has real live drift, homeassistant-purpleair has no rulesets configured — both surfaced to the maintainer (issues filed), not auto-applied.
  • markdownlint-cli2 clean on README.md and AGENTS.md (0 errors).

🤖 Generated with Claude Code

Closes the gap from #211: branch rulesets were live GitHub config applied
once at repo creation, so they sat outside the file-based re-sync loop - a
corrected template ruleset never propagated to derived repos, and downstream
drift was invisible (PlexCleaner's docs said strict=false while live config
stayed strict=true on both branches).
- Commit the canonical writable subset as .github/rulesets/{develop,main}.json
(strict_required_status_checks_policy false on both - the #82 value this
exists to keep propagated). They port verbatim: conditions key on
refs/heads/{develop,main}, bypass_actors uses global Admin role actor_id 5,
the required check binds by name.
- README "Rules / Rulesets": repoint the source of truth to the committed
files - import from them at setup; the live export becomes the regenerate
recipe run when the maintainer changes the template's live rulesets.
- AGENTS.md: add the rulesets to the verbatim-carry set and document the
live-vs-committed drift check (full-payload PUT to correct) in Staying in
Sync. Note that carrying the file only syncs the source of truth; live
config changes only on import/PUT.
Also folds in pending spell-dictionary / workspace-extension additions and
three deferred-item bullets that were already staged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 16:52

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

This PR brings branch rulesets into the repo-based re-sync/drift workflow by committing canonical develop/main ruleset JSON and updating documentation to treat those files as the versioned source of truth, plus minor editor/workspace hygiene updates.

Changes:

  • Add committed GitHub ruleset definitions for develop and main under .github/rulesets/.
  • Update README.md and AGENTS.md to import/sync rulesets from committed JSON and document how to detect/correct drift against live GitHub config.
  • Reformat and extend ProjectTemplate.code-workspace (spellings + recommended extensions).

Reviewed changes

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

Show a summary per file
FileDescription
README.mdUpdates ruleset setup docs to import from committed JSON; adds deferred-pattern notes.
ProjectTemplate.code-workspaceNormalizes formatting; adds cSpell words and extension recommendations.
AGENTS.mdAdds ruleset JSON to verbatim-carry list and documents drift-check procedure.
.github/rulesets/main.jsonIntroduces canonical main branch ruleset JSON (importable subset).
.github/rulesets/develop.jsonIntroduces canonical develop branch ruleset JSON (importable subset).

Comment threadREADME.md Outdated
ptr727and others added 2 commits June 26, 2026 09:56
GitHub returns a ruleset's rules[] (and bypass_actors[]) in arbitrary order,
so the plain diff false-positived on a reordered-but-equivalent ruleset
(PlexCleaner's develop/main read as DRIFT when only the rule order differed).
Sort both arrays before diffing so only real differences surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The versioned rulesets are live GitHub config, not a file a derived repo
consumes, so copying them into every downstream repo only adds noise and
divergence. Drop them from the verbatim-carry set; document that they live
only in the template as the source of truth and ride the re-sync loop from
the hub - diffing each derived repo's live config against the template's
committed JSON and correcting drift via full-payload PUT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17: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 5 out of 5 changed files in this pull request and generated 4 comments.

Comment threadREADME.md Outdated
Comment threadREADME.md Outdated
Comment threadProjectTemplate.code-workspace
Comment threadAGENTS.md Outdated
ptr727and others added 3 commits June 26, 2026 10:52
Two of the pre-staged Deferred Patterns are no longer deferred:
- "Factor cleanup-artifacts into a reusable workflow" is moot - #214 removes
the blanket cleanup job entirely (surgical consume-then-delete instead), so
there is nothing left to factor.
- "Generalize the input-validation step into a reusable pattern" is realized -
#213 codifies the validate-input/state-at-entry pattern in AGENTS.md.
Keep the publish-docker-readme "Validate inputs step" downstream-resync entry;
that concrete downstream action is still pending.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reword "never copied into derived repos" (README + AGENTS.md): the JSON is
maintained in the template as the source of truth and reconciled against a
repo's live config; it is not carried/re-synced as a per-repo copy. Avoids
the inaccurate absolute (a template-instantiated repo does receive the files).
- Mirror the two new general extensions (actionlint, shellcheck) into both
devcontainers and fix the stale `*.code-workspace` reference (the per-language
workspaces were consolidated into ProjectTemplate.code-workspace in #210).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 18:17
@ptr727
ptr727 merged commit 59e0e91 into developJun 26, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/rulesets-as-versioned-json branch June 26, 2026 18: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 7 out of 7 changed files in this pull request and generated 4 comments.

"customizations": {
"vscode": {
// Mirror of `recommendations` in Python.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
"customizations": {
"vscode": {
// Mirror of `recommendations` in DotNet.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
Comment threadAGENTS.md
Comment on lines +285 to +286
The branch rulesets ([`.github/rulesets/{develop,main}.json`](./.github/rulesets/)) are deliberately **not** in this carry set: they are live GitHub config, not a file a derived repo consumes, so carrying and re-syncing them downstream only adds noise. They are maintained **in this template** as the source of truth and are reconciled against each repo's *live* config during porting/re-sync - see [Staying in Sync](#staying-in-sync-and-reporting-drift-upstream).

Comment threadREADME.md
Comment on lines 504 to +508
for name in develop main; do
id=$(gh api repos/ptr727/ProjectTemplate/rulesets --jq ".[] | select(.name==\"$name\") | .id")
gh api "repos/ptr727/ProjectTemplate/rulesets/$id" \
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' > "$name-ruleset.json"
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' \
| jq -S '.' > ".github/rulesets/$name.json"
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Ship branch rulesets as versioned JSON in the re-sync / drift loop - #212

Merged
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json
Jun 26, 2026
Merged

Ship branch rulesets as versioned JSON in the re-sync / drift loop#212
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json

Conversation

@ptr727

@ptr727ptr727 commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Problem

Closes#211. Branch rulesets are live GitHub config applied once at repo creation, so they sit outside the file-based re-sync loop (AGENTS.md "Staying in Sync"). Two consequences: a corrected template ruleset never propagates to existing derived repos, and downstream ruleset drift is invisible. This bit ptr727/PlexCleaner — its synced docs said strict=false while its live rulesets stayed strict=true on both develop and main (the exact #82 failure mode), fixed locally only after it broke auto-merge and blocked a promotion.

Change

  • Canonical rulesets as committed files, maintained in this template only..github/rulesets/develop.json and .github/rulesets/main.json hold the re-importable writable subset ({name, target, enforcement, bypass_actors, conditions, rules}), strict_required_status_checks_policy: false on both. They port verbatim with no placeholders — conditions key on refs/heads/{develop,main}, bypass_actors uses the global Admin role actor_id: 5, the required check binds by name.
  • README "Rules / Rulesets" repoints the source of truth to these committed files: setup imports from them; the live export becomes the regenerate recipe run in the template when the maintainer changes the live rulesets.
  • AGENTS.md documents that the rulesets are deliberately not in the verbatim-carry set and are not carried/re-synced downstream as a per-repo copy — they are live config, not a file a derived repo consumes. They ride the re-sync loop from the hub: diff each derived repo's live rulesets against the template's committed JSON and correct drift via a full-payload PUT. The drift command normalizes rules[]/bypass_actors[] order so a reordered-but-equivalent ruleset doesn't read as drift.
  • Also folds in pending spell-dict / workspace-extension additions (and mirrors the two new general extensions into both devcontainers).

Verification

  • jq -S round-trip stable for both files; order-normalized drift diff against the template's own live rulesets reports develop: in sync / main: in sync.
  • Ran the drift check across all 8 derived repos (read-only): 6 in sync, Utilities has real live drift, homeassistant-purpleair has no rulesets configured — both surfaced to the maintainer (issues filed), not auto-applied.
  • markdownlint-cli2 clean on README.md and AGENTS.md (0 errors).

🤖 Generated with Claude Code

Closes the gap from #211: branch rulesets were live GitHub config applied
once at repo creation, so they sat outside the file-based re-sync loop - a
corrected template ruleset never propagated to derived repos, and downstream
drift was invisible (PlexCleaner's docs said strict=false while live config
stayed strict=true on both branches).
- Commit the canonical writable subset as .github/rulesets/{develop,main}.json
(strict_required_status_checks_policy false on both - the #82 value this
exists to keep propagated). They port verbatim: conditions key on
refs/heads/{develop,main}, bypass_actors uses global Admin role actor_id 5,
the required check binds by name.
- README "Rules / Rulesets": repoint the source of truth to the committed
files - import from them at setup; the live export becomes the regenerate
recipe run when the maintainer changes the template's live rulesets.
- AGENTS.md: add the rulesets to the verbatim-carry set and document the
live-vs-committed drift check (full-payload PUT to correct) in Staying in
Sync. Note that carrying the file only syncs the source of truth; live
config changes only on import/PUT.
Also folds in pending spell-dictionary / workspace-extension additions and
three deferred-item bullets that were already staged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 16:52

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

This PR brings branch rulesets into the repo-based re-sync/drift workflow by committing canonical develop/main ruleset JSON and updating documentation to treat those files as the versioned source of truth, plus minor editor/workspace hygiene updates.

Changes:

  • Add committed GitHub ruleset definitions for develop and main under .github/rulesets/.
  • Update README.md and AGENTS.md to import/sync rulesets from committed JSON and document how to detect/correct drift against live GitHub config.
  • Reformat and extend ProjectTemplate.code-workspace (spellings + recommended extensions).

Reviewed changes

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

Show a summary per file
FileDescription
README.mdUpdates ruleset setup docs to import from committed JSON; adds deferred-pattern notes.
ProjectTemplate.code-workspaceNormalizes formatting; adds cSpell words and extension recommendations.
AGENTS.mdAdds ruleset JSON to verbatim-carry list and documents drift-check procedure.
.github/rulesets/main.jsonIntroduces canonical main branch ruleset JSON (importable subset).
.github/rulesets/develop.jsonIntroduces canonical develop branch ruleset JSON (importable subset).

Comment threadREADME.md Outdated
ptr727and others added 2 commits June 26, 2026 09:56
GitHub returns a ruleset's rules[] (and bypass_actors[]) in arbitrary order,
so the plain diff false-positived on a reordered-but-equivalent ruleset
(PlexCleaner's develop/main read as DRIFT when only the rule order differed).
Sort both arrays before diffing so only real differences surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The versioned rulesets are live GitHub config, not a file a derived repo
consumes, so copying them into every downstream repo only adds noise and
divergence. Drop them from the verbatim-carry set; document that they live
only in the template as the source of truth and ride the re-sync loop from
the hub - diffing each derived repo's live config against the template's
committed JSON and correcting drift via full-payload PUT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17: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 5 out of 5 changed files in this pull request and generated 4 comments.

Comment threadREADME.md Outdated
Comment threadREADME.md Outdated
Comment threadProjectTemplate.code-workspace
Comment threadAGENTS.md Outdated
ptr727and others added 3 commits June 26, 2026 10:52
Two of the pre-staged Deferred Patterns are no longer deferred:
- "Factor cleanup-artifacts into a reusable workflow" is moot - #214 removes
the blanket cleanup job entirely (surgical consume-then-delete instead), so
there is nothing left to factor.
- "Generalize the input-validation step into a reusable pattern" is realized -
#213 codifies the validate-input/state-at-entry pattern in AGENTS.md.
Keep the publish-docker-readme "Validate inputs step" downstream-resync entry;
that concrete downstream action is still pending.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reword "never copied into derived repos" (README + AGENTS.md): the JSON is
maintained in the template as the source of truth and reconciled against a
repo's live config; it is not carried/re-synced as a per-repo copy. Avoids
the inaccurate absolute (a template-instantiated repo does receive the files).
- Mirror the two new general extensions (actionlint, shellcheck) into both
devcontainers and fix the stale `*.code-workspace` reference (the per-language
workspaces were consolidated into ProjectTemplate.code-workspace in #210).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 18:17
@ptr727
ptr727 merged commit 59e0e91 into developJun 26, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/rulesets-as-versioned-json branch June 26, 2026 18: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 7 out of 7 changed files in this pull request and generated 4 comments.

"customizations": {
"vscode": {
// Mirror of `recommendations` in Python.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
"customizations": {
"vscode": {
// Mirror of `recommendations` in DotNet.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
Comment threadAGENTS.md
Comment on lines +285 to +286
The branch rulesets ([`.github/rulesets/{develop,main}.json`](./.github/rulesets/)) are deliberately **not** in this carry set: they are live GitHub config, not a file a derived repo consumes, so carrying and re-syncing them downstream only adds noise. They are maintained **in this template** as the source of truth and are reconciled against each repo's *live* config during porting/re-sync - see [Staying in Sync](#staying-in-sync-and-reporting-drift-upstream).

Comment threadREADME.md
Comment on lines 504 to +508
for name in develop main; do
id=$(gh api repos/ptr727/ProjectTemplate/rulesets --jq ".[] | select(.name==\"$name\") | .id")
gh api "repos/ptr727/ProjectTemplate/rulesets/$id" \
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' > "$name-ruleset.json"
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' \
| jq -S '.' > ".github/rulesets/$name.json"
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Ship branch rulesets as versioned JSON in the re-sync / drift loop - #212

Merged
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json
Jun 26, 2026
Merged

Ship branch rulesets as versioned JSON in the re-sync / drift loop#212
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json

Conversation

@ptr727

@ptr727ptr727 commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Problem

Closes#211. Branch rulesets are live GitHub config applied once at repo creation, so they sit outside the file-based re-sync loop (AGENTS.md "Staying in Sync"). Two consequences: a corrected template ruleset never propagates to existing derived repos, and downstream ruleset drift is invisible. This bit ptr727/PlexCleaner — its synced docs said strict=false while its live rulesets stayed strict=true on both develop and main (the exact #82 failure mode), fixed locally only after it broke auto-merge and blocked a promotion.

Change

  • Canonical rulesets as committed files, maintained in this template only..github/rulesets/develop.json and .github/rulesets/main.json hold the re-importable writable subset ({name, target, enforcement, bypass_actors, conditions, rules}), strict_required_status_checks_policy: false on both. They port verbatim with no placeholders — conditions key on refs/heads/{develop,main}, bypass_actors uses the global Admin role actor_id: 5, the required check binds by name.
  • README "Rules / Rulesets" repoints the source of truth to these committed files: setup imports from them; the live export becomes the regenerate recipe run in the template when the maintainer changes the live rulesets.
  • AGENTS.md documents that the rulesets are deliberately not in the verbatim-carry set and are not carried/re-synced downstream as a per-repo copy — they are live config, not a file a derived repo consumes. They ride the re-sync loop from the hub: diff each derived repo's live rulesets against the template's committed JSON and correct drift via a full-payload PUT. The drift command normalizes rules[]/bypass_actors[] order so a reordered-but-equivalent ruleset doesn't read as drift.
  • Also folds in pending spell-dict / workspace-extension additions (and mirrors the two new general extensions into both devcontainers).

Verification

  • jq -S round-trip stable for both files; order-normalized drift diff against the template's own live rulesets reports develop: in sync / main: in sync.
  • Ran the drift check across all 8 derived repos (read-only): 6 in sync, Utilities has real live drift, homeassistant-purpleair has no rulesets configured — both surfaced to the maintainer (issues filed), not auto-applied.
  • markdownlint-cli2 clean on README.md and AGENTS.md (0 errors).

🤖 Generated with Claude Code

Closes the gap from #211: branch rulesets were live GitHub config applied
once at repo creation, so they sat outside the file-based re-sync loop - a
corrected template ruleset never propagated to derived repos, and downstream
drift was invisible (PlexCleaner's docs said strict=false while live config
stayed strict=true on both branches).
- Commit the canonical writable subset as .github/rulesets/{develop,main}.json
(strict_required_status_checks_policy false on both - the #82 value this
exists to keep propagated). They port verbatim: conditions key on
refs/heads/{develop,main}, bypass_actors uses global Admin role actor_id 5,
the required check binds by name.
- README "Rules / Rulesets": repoint the source of truth to the committed
files - import from them at setup; the live export becomes the regenerate
recipe run when the maintainer changes the template's live rulesets.
- AGENTS.md: add the rulesets to the verbatim-carry set and document the
live-vs-committed drift check (full-payload PUT to correct) in Staying in
Sync. Note that carrying the file only syncs the source of truth; live
config changes only on import/PUT.
Also folds in pending spell-dictionary / workspace-extension additions and
three deferred-item bullets that were already staged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 16:52

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

This PR brings branch rulesets into the repo-based re-sync/drift workflow by committing canonical develop/main ruleset JSON and updating documentation to treat those files as the versioned source of truth, plus minor editor/workspace hygiene updates.

Changes:

  • Add committed GitHub ruleset definitions for develop and main under .github/rulesets/.
  • Update README.md and AGENTS.md to import/sync rulesets from committed JSON and document how to detect/correct drift against live GitHub config.
  • Reformat and extend ProjectTemplate.code-workspace (spellings + recommended extensions).

Reviewed changes

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

Show a summary per file
FileDescription
README.mdUpdates ruleset setup docs to import from committed JSON; adds deferred-pattern notes.
ProjectTemplate.code-workspaceNormalizes formatting; adds cSpell words and extension recommendations.
AGENTS.mdAdds ruleset JSON to verbatim-carry list and documents drift-check procedure.
.github/rulesets/main.jsonIntroduces canonical main branch ruleset JSON (importable subset).
.github/rulesets/develop.jsonIntroduces canonical develop branch ruleset JSON (importable subset).

Comment threadREADME.md Outdated
ptr727and others added 2 commits June 26, 2026 09:56
GitHub returns a ruleset's rules[] (and bypass_actors[]) in arbitrary order,
so the plain diff false-positived on a reordered-but-equivalent ruleset
(PlexCleaner's develop/main read as DRIFT when only the rule order differed).
Sort both arrays before diffing so only real differences surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The versioned rulesets are live GitHub config, not a file a derived repo
consumes, so copying them into every downstream repo only adds noise and
divergence. Drop them from the verbatim-carry set; document that they live
only in the template as the source of truth and ride the re-sync loop from
the hub - diffing each derived repo's live config against the template's
committed JSON and correcting drift via full-payload PUT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17: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 5 out of 5 changed files in this pull request and generated 4 comments.

Comment threadREADME.md Outdated
Comment threadREADME.md Outdated
Comment threadProjectTemplate.code-workspace
Comment threadAGENTS.md Outdated
ptr727and others added 3 commits June 26, 2026 10:52
Two of the pre-staged Deferred Patterns are no longer deferred:
- "Factor cleanup-artifacts into a reusable workflow" is moot - #214 removes
the blanket cleanup job entirely (surgical consume-then-delete instead), so
there is nothing left to factor.
- "Generalize the input-validation step into a reusable pattern" is realized -
#213 codifies the validate-input/state-at-entry pattern in AGENTS.md.
Keep the publish-docker-readme "Validate inputs step" downstream-resync entry;
that concrete downstream action is still pending.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reword "never copied into derived repos" (README + AGENTS.md): the JSON is
maintained in the template as the source of truth and reconciled against a
repo's live config; it is not carried/re-synced as a per-repo copy. Avoids
the inaccurate absolute (a template-instantiated repo does receive the files).
- Mirror the two new general extensions (actionlint, shellcheck) into both
devcontainers and fix the stale `*.code-workspace` reference (the per-language
workspaces were consolidated into ProjectTemplate.code-workspace in #210).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 18:17
@ptr727
ptr727 merged commit 59e0e91 into developJun 26, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/rulesets-as-versioned-json branch June 26, 2026 18: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 7 out of 7 changed files in this pull request and generated 4 comments.

"customizations": {
"vscode": {
// Mirror of `recommendations` in Python.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
"customizations": {
"vscode": {
// Mirror of `recommendations` in DotNet.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
Comment threadAGENTS.md
Comment on lines +285 to +286
The branch rulesets ([`.github/rulesets/{develop,main}.json`](./.github/rulesets/)) are deliberately **not** in this carry set: they are live GitHub config, not a file a derived repo consumes, so carrying and re-syncing them downstream only adds noise. They are maintained **in this template** as the source of truth and are reconciled against each repo's *live* config during porting/re-sync - see [Staying in Sync](#staying-in-sync-and-reporting-drift-upstream).

Comment threadREADME.md
Comment on lines 504 to +508
for name in develop main; do
id=$(gh api repos/ptr727/ProjectTemplate/rulesets --jq ".[] | select(.name==\"$name\") | .id")
gh api "repos/ptr727/ProjectTemplate/rulesets/$id" \
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' > "$name-ruleset.json"
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' \
| jq -S '.' > ".github/rulesets/$name.json"
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Ship branch rulesets as versioned JSON in the re-sync / drift loop - #212

Merged
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json
Jun 26, 2026
Merged

Ship branch rulesets as versioned JSON in the re-sync / drift loop#212
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json

Conversation

@ptr727

@ptr727ptr727 commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Problem

Closes#211. Branch rulesets are live GitHub config applied once at repo creation, so they sit outside the file-based re-sync loop (AGENTS.md "Staying in Sync"). Two consequences: a corrected template ruleset never propagates to existing derived repos, and downstream ruleset drift is invisible. This bit ptr727/PlexCleaner — its synced docs said strict=false while its live rulesets stayed strict=true on both develop and main (the exact #82 failure mode), fixed locally only after it broke auto-merge and blocked a promotion.

Change

  • Canonical rulesets as committed files, maintained in this template only..github/rulesets/develop.json and .github/rulesets/main.json hold the re-importable writable subset ({name, target, enforcement, bypass_actors, conditions, rules}), strict_required_status_checks_policy: false on both. They port verbatim with no placeholders — conditions key on refs/heads/{develop,main}, bypass_actors uses the global Admin role actor_id: 5, the required check binds by name.
  • README "Rules / Rulesets" repoints the source of truth to these committed files: setup imports from them; the live export becomes the regenerate recipe run in the template when the maintainer changes the live rulesets.
  • AGENTS.md documents that the rulesets are deliberately not in the verbatim-carry set and are not carried/re-synced downstream as a per-repo copy — they are live config, not a file a derived repo consumes. They ride the re-sync loop from the hub: diff each derived repo's live rulesets against the template's committed JSON and correct drift via a full-payload PUT. The drift command normalizes rules[]/bypass_actors[] order so a reordered-but-equivalent ruleset doesn't read as drift.
  • Also folds in pending spell-dict / workspace-extension additions (and mirrors the two new general extensions into both devcontainers).

Verification

  • jq -S round-trip stable for both files; order-normalized drift diff against the template's own live rulesets reports develop: in sync / main: in sync.
  • Ran the drift check across all 8 derived repos (read-only): 6 in sync, Utilities has real live drift, homeassistant-purpleair has no rulesets configured — both surfaced to the maintainer (issues filed), not auto-applied.
  • markdownlint-cli2 clean on README.md and AGENTS.md (0 errors).

🤖 Generated with Claude Code

Closes the gap from #211: branch rulesets were live GitHub config applied
once at repo creation, so they sat outside the file-based re-sync loop - a
corrected template ruleset never propagated to derived repos, and downstream
drift was invisible (PlexCleaner's docs said strict=false while live config
stayed strict=true on both branches).
- Commit the canonical writable subset as .github/rulesets/{develop,main}.json
(strict_required_status_checks_policy false on both - the #82 value this
exists to keep propagated). They port verbatim: conditions key on
refs/heads/{develop,main}, bypass_actors uses global Admin role actor_id 5,
the required check binds by name.
- README "Rules / Rulesets": repoint the source of truth to the committed
files - import from them at setup; the live export becomes the regenerate
recipe run when the maintainer changes the template's live rulesets.
- AGENTS.md: add the rulesets to the verbatim-carry set and document the
live-vs-committed drift check (full-payload PUT to correct) in Staying in
Sync. Note that carrying the file only syncs the source of truth; live
config changes only on import/PUT.
Also folds in pending spell-dictionary / workspace-extension additions and
three deferred-item bullets that were already staged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 16:52

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

This PR brings branch rulesets into the repo-based re-sync/drift workflow by committing canonical develop/main ruleset JSON and updating documentation to treat those files as the versioned source of truth, plus minor editor/workspace hygiene updates.

Changes:

  • Add committed GitHub ruleset definitions for develop and main under .github/rulesets/.
  • Update README.md and AGENTS.md to import/sync rulesets from committed JSON and document how to detect/correct drift against live GitHub config.
  • Reformat and extend ProjectTemplate.code-workspace (spellings + recommended extensions).

Reviewed changes

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

Show a summary per file
FileDescription
README.mdUpdates ruleset setup docs to import from committed JSON; adds deferred-pattern notes.
ProjectTemplate.code-workspaceNormalizes formatting; adds cSpell words and extension recommendations.
AGENTS.mdAdds ruleset JSON to verbatim-carry list and documents drift-check procedure.
.github/rulesets/main.jsonIntroduces canonical main branch ruleset JSON (importable subset).
.github/rulesets/develop.jsonIntroduces canonical develop branch ruleset JSON (importable subset).

Comment threadREADME.md Outdated
ptr727and others added 2 commits June 26, 2026 09:56
GitHub returns a ruleset's rules[] (and bypass_actors[]) in arbitrary order,
so the plain diff false-positived on a reordered-but-equivalent ruleset
(PlexCleaner's develop/main read as DRIFT when only the rule order differed).
Sort both arrays before diffing so only real differences surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The versioned rulesets are live GitHub config, not a file a derived repo
consumes, so copying them into every downstream repo only adds noise and
divergence. Drop them from the verbatim-carry set; document that they live
only in the template as the source of truth and ride the re-sync loop from
the hub - diffing each derived repo's live config against the template's
committed JSON and correcting drift via full-payload PUT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17: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 5 out of 5 changed files in this pull request and generated 4 comments.

Comment threadREADME.md Outdated
Comment threadREADME.md Outdated
Comment threadProjectTemplate.code-workspace
Comment threadAGENTS.md Outdated
ptr727and others added 3 commits June 26, 2026 10:52
Two of the pre-staged Deferred Patterns are no longer deferred:
- "Factor cleanup-artifacts into a reusable workflow" is moot - #214 removes
the blanket cleanup job entirely (surgical consume-then-delete instead), so
there is nothing left to factor.
- "Generalize the input-validation step into a reusable pattern" is realized -
#213 codifies the validate-input/state-at-entry pattern in AGENTS.md.
Keep the publish-docker-readme "Validate inputs step" downstream-resync entry;
that concrete downstream action is still pending.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reword "never copied into derived repos" (README + AGENTS.md): the JSON is
maintained in the template as the source of truth and reconciled against a
repo's live config; it is not carried/re-synced as a per-repo copy. Avoids
the inaccurate absolute (a template-instantiated repo does receive the files).
- Mirror the two new general extensions (actionlint, shellcheck) into both
devcontainers and fix the stale `*.code-workspace` reference (the per-language
workspaces were consolidated into ProjectTemplate.code-workspace in #210).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 18:17
@ptr727
ptr727 merged commit 59e0e91 into developJun 26, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/rulesets-as-versioned-json branch June 26, 2026 18: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 7 out of 7 changed files in this pull request and generated 4 comments.

"customizations": {
"vscode": {
// Mirror of `recommendations` in Python.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
"customizations": {
"vscode": {
// Mirror of `recommendations` in DotNet.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
Comment threadAGENTS.md
Comment on lines +285 to +286
The branch rulesets ([`.github/rulesets/{develop,main}.json`](./.github/rulesets/)) are deliberately **not** in this carry set: they are live GitHub config, not a file a derived repo consumes, so carrying and re-syncing them downstream only adds noise. They are maintained **in this template** as the source of truth and are reconciled against each repo's *live* config during porting/re-sync - see [Staying in Sync](#staying-in-sync-and-reporting-drift-upstream).

Comment threadREADME.md
Comment on lines 504 to +508
for name in develop main; do
id=$(gh api repos/ptr727/ProjectTemplate/rulesets --jq ".[] | select(.name==\"$name\") | .id")
gh api "repos/ptr727/ProjectTemplate/rulesets/$id" \
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' > "$name-ruleset.json"
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' \
| jq -S '.' > ".github/rulesets/$name.json"
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Ship branch rulesets as versioned JSON in the re-sync / drift loop - #212

Merged
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json
Jun 26, 2026
Merged

Ship branch rulesets as versioned JSON in the re-sync / drift loop#212
ptr727 merged 6 commits into
developfrom
feature/rulesets-as-versioned-json

Conversation

@ptr727

@ptr727ptr727 commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Problem

Closes#211. Branch rulesets are live GitHub config applied once at repo creation, so they sit outside the file-based re-sync loop (AGENTS.md "Staying in Sync"). Two consequences: a corrected template ruleset never propagates to existing derived repos, and downstream ruleset drift is invisible. This bit ptr727/PlexCleaner — its synced docs said strict=false while its live rulesets stayed strict=true on both develop and main (the exact #82 failure mode), fixed locally only after it broke auto-merge and blocked a promotion.

Change

  • Canonical rulesets as committed files, maintained in this template only..github/rulesets/develop.json and .github/rulesets/main.json hold the re-importable writable subset ({name, target, enforcement, bypass_actors, conditions, rules}), strict_required_status_checks_policy: false on both. They port verbatim with no placeholders — conditions key on refs/heads/{develop,main}, bypass_actors uses the global Admin role actor_id: 5, the required check binds by name.
  • README "Rules / Rulesets" repoints the source of truth to these committed files: setup imports from them; the live export becomes the regenerate recipe run in the template when the maintainer changes the live rulesets.
  • AGENTS.md documents that the rulesets are deliberately not in the verbatim-carry set and are not carried/re-synced downstream as a per-repo copy — they are live config, not a file a derived repo consumes. They ride the re-sync loop from the hub: diff each derived repo's live rulesets against the template's committed JSON and correct drift via a full-payload PUT. The drift command normalizes rules[]/bypass_actors[] order so a reordered-but-equivalent ruleset doesn't read as drift.
  • Also folds in pending spell-dict / workspace-extension additions (and mirrors the two new general extensions into both devcontainers).

Verification

  • jq -S round-trip stable for both files; order-normalized drift diff against the template's own live rulesets reports develop: in sync / main: in sync.
  • Ran the drift check across all 8 derived repos (read-only): 6 in sync, Utilities has real live drift, homeassistant-purpleair has no rulesets configured — both surfaced to the maintainer (issues filed), not auto-applied.
  • markdownlint-cli2 clean on README.md and AGENTS.md (0 errors).

🤖 Generated with Claude Code

Closes the gap from #211: branch rulesets were live GitHub config applied
once at repo creation, so they sat outside the file-based re-sync loop - a
corrected template ruleset never propagated to derived repos, and downstream
drift was invisible (PlexCleaner's docs said strict=false while live config
stayed strict=true on both branches).
- Commit the canonical writable subset as .github/rulesets/{develop,main}.json
(strict_required_status_checks_policy false on both - the #82 value this
exists to keep propagated). They port verbatim: conditions key on
refs/heads/{develop,main}, bypass_actors uses global Admin role actor_id 5,
the required check binds by name.
- README "Rules / Rulesets": repoint the source of truth to the committed
files - import from them at setup; the live export becomes the regenerate
recipe run when the maintainer changes the template's live rulesets.
- AGENTS.md: add the rulesets to the verbatim-carry set and document the
live-vs-committed drift check (full-payload PUT to correct) in Staying in
Sync. Note that carrying the file only syncs the source of truth; live
config changes only on import/PUT.
Also folds in pending spell-dictionary / workspace-extension additions and
three deferred-item bullets that were already staged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 16:52

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

This PR brings branch rulesets into the repo-based re-sync/drift workflow by committing canonical develop/main ruleset JSON and updating documentation to treat those files as the versioned source of truth, plus minor editor/workspace hygiene updates.

Changes:

  • Add committed GitHub ruleset definitions for develop and main under .github/rulesets/.
  • Update README.md and AGENTS.md to import/sync rulesets from committed JSON and document how to detect/correct drift against live GitHub config.
  • Reformat and extend ProjectTemplate.code-workspace (spellings + recommended extensions).

Reviewed changes

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

Show a summary per file
FileDescription
README.mdUpdates ruleset setup docs to import from committed JSON; adds deferred-pattern notes.
ProjectTemplate.code-workspaceNormalizes formatting; adds cSpell words and extension recommendations.
AGENTS.mdAdds ruleset JSON to verbatim-carry list and documents drift-check procedure.
.github/rulesets/main.jsonIntroduces canonical main branch ruleset JSON (importable subset).
.github/rulesets/develop.jsonIntroduces canonical develop branch ruleset JSON (importable subset).

Comment threadREADME.md Outdated
ptr727and others added 2 commits June 26, 2026 09:56
GitHub returns a ruleset's rules[] (and bypass_actors[]) in arbitrary order,
so the plain diff false-positived on a reordered-but-equivalent ruleset
(PlexCleaner's develop/main read as DRIFT when only the rule order differed).
Sort both arrays before diffing so only real differences surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The versioned rulesets are live GitHub config, not a file a derived repo
consumes, so copying them into every downstream repo only adds noise and
divergence. Drop them from the verbatim-carry set; document that they live
only in the template as the source of truth and ride the re-sync loop from
the hub - diffing each derived repo's live config against the template's
committed JSON and correcting drift via full-payload PUT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 17: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 5 out of 5 changed files in this pull request and generated 4 comments.

Comment threadREADME.md Outdated
Comment threadREADME.md Outdated
Comment threadProjectTemplate.code-workspace
Comment threadAGENTS.md Outdated
ptr727and others added 3 commits June 26, 2026 10:52
Two of the pre-staged Deferred Patterns are no longer deferred:
- "Factor cleanup-artifacts into a reusable workflow" is moot - #214 removes
the blanket cleanup job entirely (surgical consume-then-delete instead), so
there is nothing left to factor.
- "Generalize the input-validation step into a reusable pattern" is realized -
#213 codifies the validate-input/state-at-entry pattern in AGENTS.md.
Keep the publish-docker-readme "Validate inputs step" downstream-resync entry;
that concrete downstream action is still pending.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Reword "never copied into derived repos" (README + AGENTS.md): the JSON is
maintained in the template as the source of truth and reconciled against a
repo's live config; it is not carried/re-synced as a per-repo copy. Avoids
the inaccurate absolute (a template-instantiated repo does receive the files).
- Mirror the two new general extensions (actionlint, shellcheck) into both
devcontainers and fix the stale `*.code-workspace` reference (the per-language
workspaces were consolidated into ProjectTemplate.code-workspace in #210).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings June 26, 2026 18:17
@ptr727
ptr727 merged commit 59e0e91 into developJun 26, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/rulesets-as-versioned-json branch June 26, 2026 18: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 7 out of 7 changed files in this pull request and generated 4 comments.

"customizations": {
"vscode": {
// Mirror of `recommendations` in Python.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
"customizations": {
"vscode": {
// Mirror of `recommendations` in DotNet.code-workspace.
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
Comment threadAGENTS.md
Comment on lines +285 to +286
The branch rulesets ([`.github/rulesets/{develop,main}.json`](./.github/rulesets/)) are deliberately **not** in this carry set: they are live GitHub config, not a file a derived repo consumes, so carrying and re-syncing them downstream only adds noise. They are maintained **in this template** as the source of truth and are reconciled against each repo's *live* config during porting/re-sync - see [Staying in Sync](#staying-in-sync-and-reporting-drift-upstream).

Comment threadREADME.md
Comment on lines 504 to +508
for name in develop main; do
id=$(gh api repos/ptr727/ProjectTemplate/rulesets --jq ".[] | select(.name==\"$name\") | .id")
gh api "repos/ptr727/ProjectTemplate/rulesets/$id" \
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' > "$name-ruleset.json"
--jq '{name, target, enforcement, bypass_actors, conditions, rules}' \
| jq -S '.' > ".github/rulesets/$name.json"
@ptr727ptr727 mentioned this pull request Jul 4, 2026
ptr727 added a commit that referenced this pull request Jul 4, 2026
Promote the accumulated `develop` work to `main`. Twelve changes since
the last promotion:
- Add `WORKFLOW.md`: workflow style, architecture, behavioral contract,
test methodology (#223)
- Use NBGV `IGNORE_GITHUB_REF` instead of the ineffective `GITHUB_REF`
override (#222)
- Skip validate-release on smoke builds (#220)
- Gate asset delete on the release create/refresh condition (#218)
- Ship branch rulesets as versioned JSON in the re-sync / drift loop
(#212)
- Clean up transfer artifacts surgically at consumption, not
blanket-delete (#216)
- Version each publish leg against its own branch; validate at entry
(#215)
- Consolidate workspace configurations into a unified ProjectTemplate
workspace (#210)
- Template convergence barrier: absorb pins, generic release +
docker-readme, carry-whole-file (#207)
- Key merge-bot concurrency on PR number, not `github.ref` (#206)
- Codify orchestrated re-sync personas and full-replacement rule (#205)
- Lead action pins; affirm pattern-based artifact handoff (#204)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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