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.
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.
|
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.
|
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))
|
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. |
## 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