Skip to content

Latest commit

 

History

History
154 lines (113 loc) · 8.51 KB

File metadata and controls

154 lines (113 loc) · 8.51 KB

Org metadata policy

Repository descriptions, repository topics, and the organisation description are copy. They are read before anything else in this organisation and they are governed by nothing, which is why this file exists.

Written 9 August 2026, after a sweep of all 25 public repositories found retired claims in metadata that had been corrected on the website months earlier.


1. Two surfaces, and only one of them is a file

This distinction was got wrong in the handover that commissioned the sweep, and getting it wrong means correcting the wrong thing.

surface where it lives reviewable?
profile/README.md this repository, profile/README.md yes: commit, diff, PR, history
the org description GitHub organisation settings no: no file, no commit, no history

The README renders above the repository list. The description renders in the org sidebar and in search results. They are different strings on the same page, and the second one, which reaches further, is the only string in this estate that nothing can gate.

A change to the org description leaves no record anywhere. One settings click reverts any correction made to it, silently, and no diff shows it.

Since 9 August 2026 it is watched: the expected value lives in org-description.expected.txt and .github/workflows/org-description-drift.yml compares it against the API daily.

What that check is, precisely. It is a drift detector, not a gate. The string changes outside git, so no pull_request check can prevent the change. A green run means "it matched when we last looked". It never means "it cannot be changed". Detection lag is the schedule interval.

Verified end to end on the day it was written, in all three directions:

case result
live value matches the file run succeeds
file deliberately wrong, dispatched on a branch run fails
the failure's ntfy notification delivered, confirmed by polling the topic from op-vps

The third row is the one worth re-running. A red cron job nobody reads is the classic inert control, and a notification path is only real once a message has actually arrived over it.

Two ways this check can quietly stop being one:

  1. GitHub disables scheduled workflows in a repository with no activity for 60 days, and this repository is deliberately low-activity. Nothing announces the stop, and a detector that has silently stopped is indistinguishable from one that keeps finding nothing. Treat the absence of recent runs as the signal it is, and re-run by hand from the Actions tab.
  2. The NTFY_TOPIC secret going missing. The job still fails, and the log says explicitly that nobody was told, so a missing notification cannot pass for a delivered one.

Still unwatched: the other 41 values. 25 repo descriptions and 16 topic values drift exactly the same way and are equally unversioned. The same workflow with a loop and a larger expected file would cover them; the 2026-08-09 sweep was the manual version of that job.

2. Archived repositories: public, and therefore corrected

profile/README.md rules that archived repositories stay public, because a published package's repository link must keep resolving.

That ruling has a consequence nobody had recorded: their metadata is a permanent public claim.

The policy: archived repositories remain public, and their metadata is corrected when found wrong. Unarchive, correct, re-archive. Both answers were available and this is the one taken.

The reasoning, so it can be argued with rather than obeyed:

  • A false claim on an archived repository is worse than a false claim on a live one, not better. A live repository has someone working in it who might notice. An archived one has nobody, forever.
  • "Archived" describes the code, not the sentence next to it. Freezing the description as an historical record would be defensible if anything marked it as historical. Nothing does: GitHub renders an archived repo's description in the same type as a live one.
  • The alternative policy, freeze metadata at archive date, is only honest if the org page says so. It does not, and adding that notice costs more than fixing the descriptions.

GitHub serves archived repositories read-only, so a correction requires the unarchive step. That is friction, not a reason. Batch the corrections so the unarchive window is short.

Use the script. This document deliberately does not tell you how to write.

tools/apply-repo-metadata.sh applies a correction by whichever path the target repository actually allows. Use it rather than a direct push.

The 2026-08-09 window is why. Seven archived repositories were corrected in one pass. Five took a direct push. Two, x402-op-authorize and ap2-op-authorize, refused it:

remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: - Changes must be made through a pull request.

Their descriptions had already applied, because a description is settings and branch protection does not reach it. So those two sat briefly in the precise state the pass existed to prevent: a corrected description in front of an uncorrected README. It was caught only because the runner printed the failed push instead of reporting the pass as done.

Two things follow, and both are in the script rather than in this paragraph:

  • Protection is detected from the refusal, not read from settings. Reading branch protection needs admin scope; a token that cannot read it would conclude "unprotected" and take the path that fails. On a protected repository the script opens a pull request and merges it.
  • The file change goes first and the description is held if it fails. Of the two possible half-states, only one actively misleads: an accurate summary in front of a stale body. The other half-state, both uncorrected, is merely unfinished.

This document does not name which repositories are protected, and should not. That set changes when somebody edits a settings page: no commit, no diff, nothing to review. A list here would be wrong the first time it changed and would look authoritative while it was wrong. The detection belongs where it runs.

3. What metadata is checked against

Repository descriptions and topics are subject to the same rulings as website copy, because they are read by the same person in the same sitting and they are read first.

The rulings live in observerprotocol-website/.github/CONVENTIONS.md, and the machine-readable part of them lives in observerprotocol-website/scripts/shared-copy.json:

  • the forbidden stems ($forbidden): scor, reputat, at-ars, at_ars, anchored at a word boundary. Reputation is ruled off this organisation, not merely off the website.
  • the four defect families (CONVENTIONS §2a): a mark never derived from anything; a mechanism named with no implementation; claims a reader combines across surfaces; a number correct under a wrong predicate.
  • the fourth escalation step (CONVENTIONS §12): phrase, subject, stem, mechanism. A stem check reads what a description says. It cannot read what a repository does. Ask of anything that ranks, tiers or gates by accumulated history: what would a user do to move up this? If the answer is "transact more", it is a reputation system whatever the labels say.

No check enforces any of this against org metadata today. check-shared-copy.mjs reads HTML files in the website repository and nothing else. The 2026-08-09 sweep was run by hand.

4. The failure this sweep actually found

Not the three descriptions naming reputation. Those were known.

A ruling applied to one tree does not reach the others. Reputation was ruled off the estate and removed from the website across ten enumerated instances. The cross-rail budget claim was corrected so thoroughly that a whole page was rewritten around "the budget is a design, the ceiling is a control". The ARP brand was retired on 18 March 2026 with a commit message that says "one protocol, one name".

All three survived in org metadata, because the sweep unit was the page and the metadata is not a page.

When a ruling is made, list the surfaces it binds before fixing any of them. For this organisation that list is: website HTML, repository descriptions, repository topics, the org description, profile/README.md, published package description fields on npm, and repository READMEs. Seven surfaces. A sweep that names fewer is reporting a result it did not get.