Record settings_version on each repo, so "which repos are behind" is a query - #55
Merged
Conversation
The job summary says what one run did; nothing on a repo said what state
it was in, so "which repos are behind" meant reading run logs and trusting
that no repo had been created since. That gap is how officials-admin sat
unreconciled from creation until someone noticed by hand.
With --version, apply-settings.py now PATCHes the tag onto each repo as the
settings_version repository custom property, so the org-wide values endpoint
answers the question in one call.
Per repo rather than the org-level batch endpoint: PATCH /repos/{repo}/
properties/values is the entirety of what the repository-level Custom
properties permission grants, while PATCH /orgs/{org}/properties/values
rides on the organization permission, which also carries create, update and
delete of every property definition in the org. Same test that put the
releaser in its own app instead of widening the reconciler.
Only a repo that came through clean is stamped: the value means the repo
was taken through the whole of settings.yml at that tag, so one with drift
left on it must not claim it — that is what keeps it in the drift query's
output. Runs without --version stamp nothing, since create-repo.sh applies
whatever is on main and there is no release to name.
Closes #53
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgLE8cg9huy2EZnRoXhmwp
…missions Adds the one-time org-owner command that defines settings_version, the copy-paste "which repos are behind" query, and troubleshooting rows for the two setup gaps that make the write fail (property undefined, permission not granted or not yet accepted on the installation). The permission table was also wrong before this. It listed Metadata read and Administration write; the installation has held Issues write since label reconciliation landed in #48, undocumented. The table is now a permission -> endpoint -> reason mapping so a future addition has somewhere to go. Two things worth having written down that cost time to establish: editing a GitHub App's permissions does not change what its tokens can do until an org owner accepts the installation request, and gh's --jq is gojq, so the query uses env.WANT rather than needing a separate jq binary. 0003 records the property as part of version traceability rather than an open item, including why the definition stays an org-owner action and why it carries no default value. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CgLE8cg9huy2EZnRoXhmwp
…lout works
The property defaults to values_editable_by=org_actors, which is org owners and
property managers only. The reconciler holds the repository Custom properties
permission and writes through PATCH /repos/{repo}/properties/values, so it acts
as a repo actor and that default shuts it out with a 403 that looks identical
to a missing permission.
The define command now sets org_and_repo_actors, the troubleshooting row for a
403 lists all three causes, and the description matches the live property.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgLE8cg9huy2EZnRoXhmwp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #53
What & why
The job summary from #51 says what one rollout did. Nothing on a repo said what state it was in, so "which repos are behind" meant reading run logs and trusting no repo had been created since. That gap is how
officials-adminsat unreconciled from creation until someone noticed by hand — the failure that opened #34.With
--version,apply-settings.pynow PATCHes the tag onto each repo as thesettings_versionrepository custom property. The org-wide values endpoint then answers the question in one call:Per repo, not the org batch endpoint.
PATCH /repos/{owner}/{repo}/properties/valuesis the entirety of what the repository-level Custom properties permission grants — one endpoint, nothing else.PATCH /orgs/{org}/properties/valueswould do all seven repos in a single call but rides on the organization Custom properties permission, which also carries create, update and delete of every property definition in the org. That is the same test #51 applied when it put the releaser in its own app rather than widening the reconciler, so seven calls it is.Only a repo that came through clean is stamped. The value means "this repo was taken through the whole of
settings.ymlat this tag", so a repo with drift left on it must not claim it — leaving it unstamped is what keeps it in the query's output. Runs without--versionstamp nothing:create-repo.shapplies whatever is onmain, and there is no release to name.A failed write fails the run rather than skipping the way branch protection does. Every cause — property not defined, permission not granted,
values_editable_bylocking out the repository endpoint — is a setup gap nobody should sit in, so red is the right signal. It does mean the setup below has to be in place before merge, not after; it is.Also fixed: the permission table was wrong
It listed Metadata read and Administration write. The live installation has held
issues: writesince label reconciliation landed in #48, undocumented:Rather than add a row beside a wrong one, the table is now permission → endpoint → reason, so the next addition has somewhere to go.
Setup this depends on
rollout.ymlfails on every repo without it. Both are done onswimblocksand the runbook indocs/reconciler.mdcarries them for the next org:settings_versionat org level — string,required=false, no default (a default is reported for repos that were never reconciled and reads as an all-clear), andvalues_editable_by=org_and_repo_actors. That last one is not optional: it defaults toorg_actors, which is org owners and property managers only, and the reconciler writes through the repository endpoint as a repo actor. The 403 it would produce is indistinguishable from a missing permission.swimblocks-reconcilerCustom properties: Read & write, and accept the installation request. Editing an app's permissions changes nothing about its tokens until an org owner accepts; that is the usual reason a freshly granted permission still 403s.Live state, for the record:
Testing
ruff check .clean;pytest -q39 passed (5 new: payload shape, the property name the query depends on, the PATCH endpoint and body, failure reporting, stderr capture).orgs/swimblocks/installations, which is where theissues: writediscrepancy came from.ghproves nothing about the app: an org-owner token satisfiesvalues_editable_bywhatever it is set to, so it cannot distinguish the repo-actor path the installation token takes. The first real proof is the rollout after merge — expectOK settings_version: <tag>per repo, and the drift query returning nothing.Checklist
ruff check .clean (Python repos)🤖 Generated with Claude Code