Host Repository Configuration Only in the Hub - #861
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request moves all repository-configuration artifacts under repo-config/ to be hub-only, and updates the fleet procedures/spec/docs to always apply, check, and audit configuration by reaching the hub at main (instead of relying on downstream-carried payloads or payload-based inference).
Changes:
- Make downstream configuration checks route through the hub’s
repo-config/payloads and scripts (and update standup/resync/audit guidance accordingly). - Remove downstream payload-based workflow-model inference from
repo-config/configure.sh. - Update prose gate behavior and documentation to scope the
home-pathexemption toOPERATIONS.md(and align retire-ledger handling for hub-hosted paths).
Reviewed changes
Copilot reviewed 40 out of 40 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| WORKFLOW.md | Removes repo-config/README.md as a downstream reference target in workflow-model documentation. |
| STANDUP.md | Updates standup steps and references to treat repo-config/ as hub-only and route via hub main. |
| spec/readme-structure.md | Updates README “Contributing” guidance to reference governance sections instead of repo-config/README.md. |
| spec/project-types.json | Updates assertions to reference hub main payloads and removes repo-config/ from carried-file coordination rules. |
| spec/host-tools.json | Updates jq justification to reflect hub-only configuration docs and tooling. |
| spec/files.json | Removes repo-config/ payloads from the downstream baseline and repoints intent refs to docs/repo-config.md. |
| spec/divergences.json | Retires all repo-config/ payload paths as hub-hosted (and updates the ledger accordingly). |
| scripts/tests/test_prose_lint.py | Updates tests to align home-path exemption with OPERATIONS.md and with the retire-ledger mapping. |
| scripts/README.md | Updates prose-lint documentation to describe the new OPERATIONS.md exemption model. |
| RESYNC.md | Updates resync procedure to run hub repo-config/configure.sh from main and delete downstream repo-config/. |
| repo-config/README.md | Reframes repo-config/ as hub-only and updates usage guidance for apply/check via hub main. |
| repo-config/configure.sh | Removes carried-payload inference and requires registry presence (or an explicit model) for model selection. |
| README.md | Updates hub README references from docs/repo-config-carry.md to docs/repo-config.md and clarifies hub-only repo-config/. |
| OPERATIONS.md | Updates operational guidance to reflect hub-only configuration and correct risks around default targeting. |
| GOVERNANCE.md | Updates layout and rules text to reflect hub-only repo-config/ payload ownership. |
| docs/repo-config.md | Renames/reframes hub-only configuration procedure and aligns it with hub main-sourced payloads. |
| AUDIT.md | Replaces manual diff commands with hub repo-config/configure.sh check as the configuration verification method. |
| .github/skills/workflow-ci-contract/SKILL.md | Updates wording to reference hub repo-config/ payloads for required-check coordination. |
| .github/skills/standup-a-repo/SKILL.md | Updates standup skill to explicitly run repo-config steps from hub main. |
| .github/skills/resync-a-repo/SKILL.md | Updates resync skill to explicitly run repo-config steps from hub main. |
| .github/skills/operational-vs-release-workflow/references/branch-protection-and-promotion.md | Updates branch protection guidance to be hub-payload-driven and hub-main executed. |
| .github/skills/comment-and-doc-style/SKILL.md | Removes repo-config/ from the set of “carried files” that must avoid coordination references. |
| .github/skills/comment-and-doc-style/references/carried-doc-references.md | Same as above, for the references doc. |
| .github/skills/audit-a-repo/SKILL.md | Updates audit skill to use hub main config checking via configure.sh check. |
| .github/actions/prose-gate/prose_lint.py | Updates retire-ledger exemptions and changes home-path exemption to OPERATIONS.md only. |
| .claude-plugin/fleet-skills/skills/workflow-ci-contract/SKILL.md | Mirrors the workflow skill wording update for the plugin-distributed skills. |
| .claude-plugin/fleet-skills/skills/standup-a-repo/SKILL.md | Mirrors the standup skill update for the plugin-distributed skills. |
| .claude-plugin/fleet-skills/skills/resync-a-repo/SKILL.md | Mirrors the resync skill update for the plugin-distributed skills. |
| .claude-plugin/fleet-skills/skills/operational-vs-release-workflow/references/branch-protection-and-promotion.md | Mirrors the branch-protection reference update for the plugin-distributed skills. |
| .claude-plugin/fleet-skills/skills/comment-and-doc-style/SKILL.md | Mirrors the carried-doc coordination-reference update for the plugin-distributed skills. |
| .claude-plugin/fleet-skills/skills/comment-and-doc-style/references/carried-doc-references.md | Mirrors the carried-doc coordination-reference update for the plugin-distributed skills. |
| .claude-plugin/fleet-skills/skills/audit-a-repo/SKILL.md | Mirrors the audit skill update for the plugin-distributed skills. |
| .claude-plugin/fleet-skills/.source-digest | Updates the plugin skill digest to match the new skill content. |
| .agents/skills/workflow-ci-contract/SKILL.md | Mirrors the workflow skill wording update for agent-distributed skills. |
| .agents/skills/standup-a-repo/SKILL.md | Mirrors the standup skill update for agent-distributed skills. |
| .agents/skills/resync-a-repo/SKILL.md | Mirrors the resync skill update for agent-distributed skills. |
| .agents/skills/operational-vs-release-workflow/references/branch-protection-and-promotion.md | Mirrors the branch-protection reference update for agent-distributed skills. |
| .agents/skills/comment-and-doc-style/SKILL.md | Mirrors the carried-doc coordination-reference update for agent-distributed skills. |
| .agents/skills/comment-and-doc-style/references/carried-doc-references.md | Mirrors the carried-doc coordination-reference update for agent-distributed skills. |
| .agents/skills/audit-a-repo/SKILL.md | Mirrors the audit skill update for agent-distributed skills. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 40 changed files in this pull request and generated no new comments.
Suppressed comments (2)
docs/repo-config.md:48
- The regeneration snippet selects the operational develop payload output path by checking whether
repo-config/develop.jsonexists. In a hub checkout bothrepo-config/develop.jsonandrepo-config/operational/develop.jsonexist, so this condition never switches and an operational ruleset regeneration would be written torepo-config/develop.json(the release payload), corrupting the canonical files.
OPERATIONS.md:81 - This runbook is part of the downstream baseline (spec/files.json), but the example commands and the following paragraph assume the reader is already in a hub checkout ("registry beside the script"). Since downstream repositories no longer carry
repo-config/, this section should explicitly say the commands must be run from a hub checkout atmain, and avoid implying the registry is present in every repo checkout.
**Always pass the command, the repository, and the model.** A bare `repo-config/configure.sh` with no arguments defaults to `apply` against the current repo, so an invocation meant to test whether the script runs performs a live write instead. Never run it without a command. An omitted target resolves to the hub repository, and applying fleet configuration there while meaning to configure a downstream repo is a well-formed write to the wrong place. This checkout has the registry beside the script, so a repo the registry does not name resolves through `defaults.workflowModel` to `release`. An operational repo outside the registry therefore requires the explicit model argument.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 40 changed files in this pull request and generated no new comments.
Suppressed comments (3)
scripts/tests/test_prose_lint.py:2274
- Same issue as above: patching
is_operations_runbookhere is ineffective (it is called with the file path, not.) and obscures what the test is validating. Removing it makes the test easier to understand and maintain.
RESYNC.md:77 - Step 5 unconditionally instructs deleting the target repo's
repo-config/directory, but section 4 states deletions are authorized only forretiredispositions and untriaged path collisions must be read before touching. This is internally inconsistent and could lead to deleting repo-owned content at a colliding path.
Reword step 5 to follow the section 4 deletion flow (delete only retire-classified repo-config/ paths, and read untriaged collisions first).
5. **Settings, rulesets, and secrets.** From a hub checkout at `main`, run `repo-config/configure.sh check <owner>/<repo> release|operational`, then `apply` for what it reports. Pass the model explicitly. Delete the target repository's `repo-config/` directory because every file under that path is hub-only.
scripts/tests/test_prose_lint.py:2257
- This test patches
is_operations_runbookwith alambda root: Path(root) == Path('.'), butis_operations_runbookis called with the scanned file path (e.g..../notes.md), so this patch never returns true and adds confusing, dead setup.
Since the exemption is now per-file (OPERATIONS.md only), this patch can be removed to keep the test focused on what it actually exercises.
This issue also appears on line 2268 of the same file.
ptr727
commented
Aug 20, 2026
Fixed in a6038e7. Addressed all 5 suppressed findings. From review round 2:
From review round 3:
Verification: 733 script tests; audit, workflow-reuse, and agent-safety self-tests; spec validation; generated-skill consistency; changed-line prose; repository policy; and diff hygiene all pass. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 40 changed files in this pull request and generated no new comments.
Suppressed comments (1)
GOVERNANCE.md:203
- The term "hub-hosted" here is ambiguous and conflicts with how this repo uses "hub-hosted" elsewhere (meaning reached rather than carried).
.github/workflows/publish-release.ymlis a workflow file in this repo and is also listed inspec/files.jsonas a required (interface) file, so calling it hub-hosted can mislead downstream readers.
Reword to refer to the workflow by path without labeling it hub-hosted.
- **Concurrency**: top-level workflows declare `concurrency: { group: '${{ github.workflow }}-${{ github.ref }}', cancel-in-progress: true }` so a fresh push supersedes an in-flight run on the same ref. **Documented exceptions** (both record the rationale inline in their header comment): (1) [`merge-bot-pull-request.yml`](./.github/workflows/merge-bot-pull-request.yml) uses `cancel-in-progress: false` because the merge-bot's job model (enable-auto-merge on opened, disable-auto-merge on maintainer-pushed synchronize, with method dispatched by base) requires each event to run to completion in arrival order, because cancellation would leave auto-merge in an inconsistent state. (2) The hub-hosted `.github/workflows/publish-release.yml` uses both a **global, ref-independent group** (`group: ${{ github.workflow }}`, dropping the usual `-${{ github.ref }}`) and `cancel-in-progress: false`. It publishes shared ref-independent artifacts (both branches' Docker tags/caches and GitHub releases) on schedule/dispatch regardless of the triggering ref, so a ref-scoped group would let a scheduled run (ref `main`) and a manual dispatch (ref `develop`) run concurrently and double-push, and cancelling a publish mid-flight can leave a partially pushed tag set or a half-created release. The global group + queueing serializes every publish run to completion.
ptr727
commented
Aug 20, 2026
Fixed in e51820d82cfa0c970910351c24b5f9b1069ca37f.
Verification: spec validation, changed-line prose checks, generated-skill consistency, and diff hygiene pass. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 40 changed files in this pull request and generated no new comments.
Suppressed comments (2)
.github/actions/prose-gate/prose_lint.py:462
is_operations_runbook()only checkspath.name, so any nested file namedOPERATIONS.md(for exampledocs/OPERATIONS.md) would be exempted from thehome-pathrule. This can mask a real home-directory disclosure outside the intended root runbook.
Make the exemption specific to the repository-root OPERATIONS.md by comparing against root / 'OPERATIONS.md' when root is provided.
def is_operations_runbook(path: Path) -> bool:
"""Whether this path is the repository operations runbook."""
return path.name == "OPERATIONS.md"
.github/actions/prose-gate/prose_lint.py:1520
check_file()now exemptshome-pathfor operations runbooks, but it does not pass the scan root intois_operations_runbook(). Ifis_operations_runbook()is tightened to only match the repository-root runbook, this call site needs to passrootso the exemption is correctly scoped.
if "home-path" in rules and not is_operations_runbook(path):
out.extend(home_path_findings(i, line))
ptr727
commented
Aug 20, 2026
Fixed in 4405bff46e27500dc2c5f442b3e2ee3a824244cd. Addressed both linked suppressed findings.
A regression test proves docs/OPERATIONS.md still reports a home-path finding. Verification: 250 prose-lint tests, ruff, formatting, mypy, spec validation, changed-line prose, generated-skill consistency, and diff hygiene pass. |
Uh oh!
There was an error while loading. Please reload this page.
## Summary - D1.6 pointed at `spec/secrets.json` `typeMechanisms` as a bare "see" instruction. A source-only or other-type repo's own adapted copy carries `baseline` alone (per `docs/repo-config.md`, unchanged in shape by #861's hub-only `repo-config/` move), so the pointer reads as actionable in a repo where the key never exists. - Anchored the pointer to "that repo" (the C# or Python repo with tests D1.6 already scopes to), so the same sentence reads correctly whether or not the reader's own copy carries the key. ## Verification - `scripts/prose_lint.py --diff origin/develop`: 0 issues - `scripts/repo_gate.py`: 0 issues (eol, eol-coverage, sha-pin) - `markdownlint-cli2 WORKFLOW.md`: 0 issues - Re-checked the issue's claim against current `main` (a week old): the underlying carry pattern it describes is unchanged by #861 (repo-config-carry.md renamed to repo-config.md, repo-config/ made hub-only, but `spec/secrets.json`'s per-repo adapted-copy shape, including the source-only baseline-only case, is unchanged in substance). Fixes#728. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Documentation** - Updated workflow guidance for C# and Python repositories that include tests. - Coverage requirements must now be declared in each repository’s coverage configuration under the appropriate mechanism entry. - Replaced the previous generic configuration reference with a repository-specific requirement, helping ensure coverage settings are clearly defined and consistently applied. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…#995) Fixes#987 ## What Adds an explicit RESYNC.md section 4 step: before retiring a locally-carried hub-hosted path that has a matching `HUB_HOSTED` prose-gate exemption, verify that the repository's pinned `validate-task.yml` SHA is at or after the hub commit that added that exemption. If the pin predates it, bump the pin first, in the same resync, before deleting the local copy. ## Why `spec/divergences.json`'s `retire` disposition entries get paired with a matching `HUB_HOSTED` exemption entry in `dead_path_findings()` (`.github/actions/prose-gate/prose_lint.py`), usually landed in the same commit (`#861` / `e31d3fc` is the example this issue is built from). Nothing previously kept a downstream repository's own pinned `validate-task.yml` SHA in sync with a `HUB_HOSTED` addition landed after that repository's pin was last bumped. A repository that retires its local copy of an exempted path while its pin still predates the exemption hits a `dead-path` finding in its own CI at the promotion-PR gate, for a path that is already exempted on current hub `main`, just not at the repository's pinned SHA. ## Scope decision: RESYNC.md only, no `spec/audit.py` check The issue asks me to judge whether this also warrants a mechanical `spec/audit.py` advisory. I looked closely and decided against it, for reasons specific to this check rather than general reluctance to add checks: - A genuine mechanical version needs to (1) locate whichever workflow file in the target repository pins `validate-task.yml` (`spec/audit.py`'s `check_interface` only verifies the literal string `"validate-task.yml"` appears in a job's code, it never extracts or compares the `@<sha>` pin value itself, see `spec/audit.py:1504-1550` and its `requireTokensInJob` contract), (2) extract that 40-hex SHA, (3) derive the hub commit that added the matching `HUB_HOSTED` entry (via `git log -S` on `.github/actions/prose-gate/prose_lint.py`, a literal-string match with no structural guarantee it names only the intended entry), and (4) run `git merge-base --is-ancestor` between the two SHAs against this checkout's own history. Nothing like step (4) exists anywhere in `spec/audit.py` today. The closest existing "pin-based" check, `classify_branch_drift`, compares this same repository's own `main` and `develop` trees, it never parses or reasons about a downstream repository's action pin. - Step (4) also needs the pinned commit to actually be a reachable object in the hub checkout running the audit. That holds for an ordinary full clone (the normal case for an interactive `spec/audit.py <Repo>` run), but the `validate` job that runs `spec/audit.py --selftest` in CI checks out with no `fetch-depth: 0` override (only the `lint` job does, for the prose gate's own dead-path history requirement), so the same mechanism would behave differently depending on where it runs. - The failure this guards against is narrow: it only bites a repository whose resync happens to land inside the window between a hub `HUB_HOSTED` addition and that repository's own next pin bump. A one-command manual check (`git log -1 --format=%H -S'<path>' -- .github/actions/prose-gate/prose_lint.py`, compared against the pin already visible in the target repository's own workflow file) closes the same gap at a fraction of the risk of a new, first-of-its-kind ancestry-check mechanism added to an already-large audit script. RESYNC.md section 5 already documents several categories the audit deliberately leaves to a manual read rather than mechanizing, so a documented procedure step is consistent with the file's own established pattern, not a gap unique to this fix. ## Verification Ran the full documented local gate set from `OPERATIONS.md` "Run the gates the way CI runs them" (ruff, mypy, `unittest discover -s scripts/tests`, `spec/audit.py --selftest`, `gh-write-guard.py --selftest`, `test_install.py`, `build_dist.py --check`, `repo_gate.py`, `prose_lint.py` default and `charset-unknown` passes, JSON validation, `spec/validate.py`) plus `scripts/docker_lint.py` (markdownlint, cspell, actionlint, editorconfig-checker, shellcheck, shfmt, PSScriptAnalyzer). All green, no findings against the changed file. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Added guidance for resyncing repositories with outdated validation workflow references when retiring hosted paths. * Clarified that relevant version pins should be updated before removing local configuration files. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary - Retire the downstream repo's adapted `spec/secrets.json` carry, the same shape #861 already fixed for `repo-config/`. `baseline` never varied per repo, and `mechanisms`/`targetMechanisms`/`typeMechanisms` are already computed centrally by `spec/audit.py` from the hub's own `spec/secrets.json` plus `registry/repos.json`, so a downstream copy could only restate that computation or drift from it between resyncs. - `spec/files.json` no longer declares the file, and `spec/divergences.json` gains a `retire` gap for it (mirrors the `repo-config/*` entries #861 added). - `AUDIT.md` section 6, and the `audit-a-repo`/`resync-a-repo` skills, route the Secrets check through `spec/audit.py <repo>` from a hub checkout instead of implying a local file to read. - `docs/repo-config.md`'s "Per-Repository Secrets" section is rewritten for the hub-only model, and `repo-config/configure.sh`'s secrets note points at `spec/audit.py` instead of a bare "verify manually." - `prose_lint.py`'s `HUB_HOSTED` literal (a test-enforced mirror of the `divergences.json` ledger) gains the retired path. - Two prose spots that assumed a downstream copy exists are fixed: `WORKFLOW.md` D1.6's `typeMechanisms` note, and `STANDUP.md`'s `$schema`-drop worked example (now `host-tools.json`, which carries the identical convention and needed no other file to reference). - `recurring.norepoxref`'s enumerated carried-file list drops `spec/secrets.json`, since it is no longer one. - `TODO.md`'s "Reducing the Carried Surface Further" cluster is resolved for its `spec/secrets.json` half; the `AUDIT.md` half stays open. ## Verification - `python3 -m unittest discover -s scripts/tests`: 852 tests, OK (caught the `HUB_HOSTED` ledger mismatch before the fix) - `python3 spec/validate.py`: OK - `python3 spec/audit.py --selftest`: OK - `python3 scripts/prose_lint.py --diff origin/develop`: 0 issues - `python3 scripts/repo_gate.py`: 0 issues (eol, eol-coverage, sha-pin) - `python3 scripts/build_dist.py --check`: current - `markdownlint-cli2` and `cspell` on every changed file: 0 new issues (cspell's remaining hits are all pre-existing, unmodified lines) Fixes#993. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Documentation** - Updated audit and resynchronization guidance to validate settings, rulesets, and secrets from the central checkout. - Clarified that secret requirements are resolved centrally and downstream repositories no longer carry a local secrets file. - Corrected the schema reference in standup documentation. - Clarified applicability for tested C# and Python repositories. - **Chores** - Retired the downstream secrets specification from repository baselines and tracking. - Updated repository configuration guidance and validation metadata. - Refreshed the skills source digest. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
repo-config/directory hub-onlymainVerification
Ref #827