Skip to content

ci: generate registry.yaml and the README table from front matter - #32

Merged
phipsae merged 2 commits into
mainfrom
ci/registry-generator
Sep 17, 2026
Merged

phipsae merged 2 commits into
mainfrom
ci/registry-generator

Conversation

@phipsae

@phipsae phipsae commented Sep 14, 2026 •

Copy link
Copy Markdown
Collaborator

Third of three pull requests implementing #29. Based on #31, which is based on #30. Review those first. The diff shown here is only this change.

Makes front matter the only place spec metadata is written down. The index table in the README and registry.yaml are derived from it, so they cannot drift from the specs they describe.

What runs

scripts/build_registry.py writes registry.yaml and splices the README table between two markers. With --check it writes nothing and fails if the committed output is stale. CI runs that on every pull request touching specs/, the script or either generated file, and on every push to main.

Run against the specs as #31 leaves them, it reproduces the hand-written README table byte for byte.

What it rejects

The same pass validates front matter against process/front-matter.md and fails the build on any of these.

Check Example failure
Folder naming a folder that is not the number plus the shortname in lowercase
Parseable front matter missing, invalid YAML, or not a mapping
Required fields no shortname, no editor
Identity id not a whole number or disagreeing with the folder number, a duplicate id, a shortname that is not upper-case letters, digits and hyphens
Allowed values a status outside the lifecycle, an unknown type, role or domain
Provenance mirrored or indexed with no upstream
References depends_on, replaces or a numeric replaced_by naming a spec that does not exist
Indexing rule an indexed entry without index_reason, a dependency no hosted spec lists in depends_on, or a moved with no upstream

The last row is the rule from #30 that stops the repository slowly becoming a catalogue of every interesting spec in the world. index_reason takes exactly two values and each has one condition CI can check. A sentence of your own is not a reason.

Two things are validated but not listed. The legacy bare-number folders specs/1/ to specs/5/ are pointers kept so old links resolve, not specs. And a spec still at 0000-shortname while in review goes through every check, references and indexing rule included, but stays out of the table and registry.yaml until a maintainer assigns its number on merge and regenerates, see process/intake.md. While such a draft is in the tree, 0 is a valid reference target meaning the draft in the same pull request, so a new spec and the external standard it depends on can be proposed together. Once no 0000 folder is left, a leftover 0 fails.

I tested each failure mode by breaking the repository on purpose. Sample output:

Front matter problems:

  4-excubiae: folder must end in the shortname in lowercase, something-else
  2-anon-aadhaar-v2: status 'idea' is not one of ['deprecated', 'draft', 'living', 'review',
    'stable', 'stagnant', 'withdrawn']
  5-zk-proof-of-personhood: an indexed entry needs index_reason set to one of
    ['dependency', 'moved'], see process/front-matter.md

Also here

Two sentences in process/ change because the generator now exists. front-matter.md loses "until the generator lands, the README table is edited by hand", and intake steps 4 and 5 say how a dependency is proposed alongside a new spec as 0, that the merging maintainer replaces the 0 and runs the script, and that a 0000 draft is validated but not listed.

Note on cost

This is the one pull request of the three that the repository does not strictly need. It is worth having before the sixth spec arrives rather than after, because a hand-kept index is the thing that quietly goes wrong. If you would rather not carry a Python dependency yet, close this and #30 and #31 still stand on their own. The index table in the README stays hand-kept, as it is today.

🤖 Generated with Claude Code

@phipsae
phipsae force-pushed the ci/registry-generator branch from 43af693 to 7e3d247 Compare September 14, 2026 22:22
@phipsae
phipsae force-pushed the specs/normalize-front-matter branch from afc78b0 to 3269bdd Compare September 14, 2026 22:22
@phipsae
phipsae force-pushed the specs/normalize-front-matter branch from 3269bdd to 1c2d51f Compare September 14, 2026 22:43
@phipsae
phipsae force-pushed the ci/registry-generator branch from 7e3d247 to c232a3a Compare September 14, 2026 22:46
@phipsae
phipsae force-pushed the specs/normalize-front-matter branch from 1c2d51f to 18aa59c Compare September 14, 2026 23:01
@phipsae
phipsae force-pushed the ci/registry-generator branch from c232a3a to 8484514 Compare September 14, 2026 23:02
phipsae added a commit that referenced this pull request Sep 16, 2026
…ance

- idea removed, draft is the first status, spec 5 is living
- description field moved here from #32, where the generator needed it
- governance no longer names a tie-breaker or an open item
- zkID links point at the ethereum org
- process/README.md opening line in plain words

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@phipsae
phipsae force-pushed the specs/normalize-front-matter branch from 18aa59c to 9725ae7 Compare September 16, 2026 20:40
@phipsae
phipsae force-pushed the ci/registry-generator branch from 8484514 to 74cb2bd Compare September 16, 2026 22:05
phipsae added a commit that referenced this pull request Sep 16, 2026
Same change as the previous commit, in the hand-kept index table that #32 later replaces with a generated one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@phipsae
phipsae force-pushed the ci/registry-generator branch from 74cb2bd to 8740432 Compare September 16, 2026 23:09
@phipsae
phipsae requested a review from Meyanis95 September 17, 2026 14:06

@Meyanis95 Meyanis95 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

phipsae added a commit that referenced this pull request Sep 17, 2026
* process: add repo process docs and rewrite README

Adds the process/ folder that #29 proposes, playing the role EIP-1 plays
for EIPs, and rewrites the README around Access Layer scope rather than
zkspecs scope.

- lifecycle: idea, draft, review, stable, deprecated, plus stagnant,
  withdrawn and living, with the evidence gate for stable
- front matter: the id, role, type, status, domains and relationship
  fields, and the versioning rule agreed on #29
- intake: issue first, then PR, and the numbering rule
- spec template: copyable skeleton with RFC 2119 wording
- governance: the four pieces that cannot be retrofitted, licence open

No spec text is touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* process: keep shortname and tags as optional front-matter fields

Specs here are already cited as 1/COSS and 3/SEMAPHORE-V4 in each other's
bodies, and three specs carry tags today. Dropping both would lose
information the repo already has, so document them as optional.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: repo renamed to access-layer-specs

The rename asked for in #29 happened, so the pending note goes and the
old pull request links point at the new name. Old links still redirect.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* process: reconcile the indexed definition and specify replaced_by

Review found two contradictions in these docs.

lifecycle.md said a graduated spec keeps its content, while
front-matter.md called every indexed entry a stub. Graduation is now
named as the exception, and it gains an index_reason recording the move.

The indexing guardrail only accepted an entry a hosted spec depends on,
which blocked graduation outright, since a spec nothing depends on could
never flip to indexed. An entry now earns its place either that way or
by carrying index_reason.

replaced_by was documented as 'a spec id or external standard' while
being used for a repo path. All three forms are now written down, with
which of them the validator checks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* process: close the free-text hole in the indexing rule

The previous round fixed graduation by letting any non-empty
index_reason satisfy the guardrail. That is worse than the bug it
replaced, because 'index_reason: interesting' admits any external
standard while looking like the rule is enforced.

There are now exactly three ways an indexed entry qualifies, each with
something the validator can check. A hosted spec depending on it,
index_basis: graduated with replaced_by set, or index_basis:
formerly-hosted with upstream set. index_reason stays as the human
sentence required alongside index_basis. No other value is accepted and
there is no free-text route in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* process: licence is CC0, same as EIPs, question closed

The repository file switches from MIT to CC0. Specs 2 to 5 already ended
with the CC0 waiver line, so this makes the repository match the specs.
governance.md drops the open-licence flag and the contributor-agreement
item, the waiver line in each spec is the agreement. Spec template now
carries the exact waiver line.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: fix facts and cross-doc contradictions found in review

- versioning example is Semaphore v3 to v4, there is no v5
- shortname: specs 2 to 4 cite 1/COSS, nothing cites each other
- registry.yaml and the README table: say the table is hand-edited until the generator lands
- folder is number plus slug, matching intake and the template
- graduated entries require upstream, not replaced_by, matching lifecycle.md
- replaced_by path form: reviewer confirms it opens, CI does not
- editor is accountable for the entry, not for upstream text
- governance: CC0 waiver is on specs 2 to 4, spec 5 is a stub
- README: spec 5 is indexed with status idea, raw is not a lifecycle status
- example front matter no longer repeats a domain value as a tag

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: merge graduated and formerly-hosted into one index_basis value

Both required upstream and differed only in whether the old text stays,
which depends on dependants and status, not on where the text went. One
value, moved, with the text kept when any spec depends on it or it had
reached stable.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: every indexed entry names its reason in index_basis

dependency or moved, always set when role is indexed. The reason no longer
lives only in another spec's depends_on, and a moved spec keeps its history
even when something depends on it. The dependency check now reads in the
right direction, a hosted spec must list the entry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: index_reason replaces index_basis, fixed values only

The free-text line duplicated depends_on and upstream, so it goes. The
checked field keeps the name that says what it is.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: plainer wording for the index_reason gate and the mention rule

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: lowercase rationale

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: front-matter.md read through line by line

- interface and schema bullets say how each is proven
- shortname required, explained as citation handle and folder name
- replaced_by rewritten, plus a paragraph on replaced versus moved
- versioning section rewritten around the Semaphore v3 to v4 change

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: drop the tie-breaker section, owner decides disputes

Spec 1's licence origin corrected, it was copied from ZeroMQ's COSS text,
not derived from C4.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: intake and lifecycle read through

- merge happens at draft, said explicitly in lifecycle.md and intake step 5
- two roles, editor and maintainer, and three approval rules replace the
  undefined reviewer
- folder placeholder is 0000 plus the lowercase shortname
- Labels section cut, step 1 already covers it

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: drop the idea status, add the description field, tidy governance

- idea removed, draft is the first status, spec 5 is living
- description field moved here from #32, where the generator needed it
- governance no longer names a tie-breaker or an open item
- zkID links point at the ethereum org
- process/README.md opening line in plain words

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: README says the repo is the default home, not the last resort

- decision chart is two questions, Access Layer scope and whether it
  changes a standard someone else owns, everything else is written here
- indexing promises removed, the front-matter rule is the only one
- profiles bullet in plain words, EIP process is now ERC process

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* readme: drop the spec map, plain words for why specs live apart

The map listed other teams' specs, which the indexing rule says the repo
does not do. Spec 5's stub already says where its text lives.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* process: say shortname in lowercase, not slug

There is no slug field. The folder name is the number plus the shortname
in lowercase, which is what the shortname section already says, so the
opening line said it a second way with a word nothing else uses.

* process: a stub carries no contributors, and its editor owns the link

An indexed stub holds no text, so crediting contributors for it credits
them for a pointer. Their names stay on the spec upstream. The editor
row already says the editor owns the link and the context line, this
says it where the role is defined.

* process: tags are lower case with hyphens, not spaces

The five existing specs write multi-word tags both ways, and spec 3 does
both in one line. Either reading is fine for a human, but a search or a
grouping would count "proof of membership" and "proof-of-membership" as
two different tags.

* process: the repo is the home for Access Layer specs, name the guarantees

Moving to the ERC process is no longer described as the path a spec
takes, only as something that can happen. What belongs here now names
the Access Layer guarantees, censorship resistance, open source,
privacy, security and self-sovereignty, in the prose and in the chart.
Intake step 1 asks for the spec and its verbs, not for a case against
other bodies.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Philip Krause <philip.krause@ethereum.org>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
phipsae added a commit that referenced this pull request Sep 17, 2026
Same change as the previous commit, in the hand-kept index table that #32 later replaces with a generated one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@phipsae
phipsae force-pushed the specs/normalize-front-matter branch from 3953b5e to c93ee42 Compare September 17, 2026 18:50
phipsae added a commit that referenced this pull request Sep 17, 2026
…ame (#31)

* specs: normalise front matter and rename folders to number and shortname

The five existing specs go onto the schema #30 defines, and their folders
are renamed from a bare number to the number plus the spec's shortname in
lowercase. No spec text is rewritten, apart from spec 5's one-sentence
pointer.

Spec 5 is indexed rather than mirrored, because the file holds no copy of
the spec, only a pointer. It carries index_reason: moved with upstream
pointing at zkID, and status: draft, which is what the upstream calls
itself in its own front matter (COSS status: raw, and #30 has no raw).
Being a stub it has no contributors, and its editor is whoever keeps the
link correct here rather than the people who wrote the text upstream.

Specs 2, 3 and 4 do not list 1/COSS in depends_on. They declare
themselves governed by it, which is a governance link, not something
they cannot be used without. The governed-by line in each spec's prose
already says it, and #33 repoints those lines to process/.

The bare-number folders stay as one-line pointers so links made before
the rename keep resolving.

Pre-existing bugs fixed on the way, all in lines being touched anyway.
Spec 2's front matter sat below a heading so it never parsed. Specs 2 and
4 declared slug CS-02 and CS-04 against folders and titles saying 2 and 4.
Specs 2, 3 and 4 nested tags inside contributors, and specs 3 and 4
wrote multi-word tags with spaces where the others used hyphens. Spec 4 listed a literal
... as a contributor. Spec 3 linked to 1/COSS at the old zkspecs org and
spec 1 linked to itself at spec/1, a path that never existed.

* specs: retire 1/COSS in favour of process/

#30 adds process/, which defines how this repository works. 1/COSS already defines that, differently, so two process documents govern one repository. This settles which one wins.

1/COSS goes to status: deprecated with replaced_by: process/ and gets a note at the top pointing at the current rules. Every word of the text stays in place, so links keep resolving and the specs written under it can still be read against it. Specs 2, 3 and 4 declared themselves governed by 1/COSS, so they now point at process/ while still naming COSS as what came before.

The two differ on the lifecycle stages, on the evidence required to reach stable, and on editorial control. They agree on incremental numbering and on a functional change getting a new number rather than an edit, both of which process/ inherited from COSS rather than replacing.

Folded in here rather than kept as its own pull request, because this branch already migrates every spec's front matter and rewrites the same three governed-by lines.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* README: COSS row shows deprecated

Same change as the previous commit, in the hand-kept index table that #32 later replaces with a generated one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
phipsae and others added 2 commits September 17, 2026 13:51
Front matter becomes the only place spec metadata is written down.
scripts/build_registry.py writes registry.yaml and splices the README
table between markers, and --check fails if the committed output is
stale. CI runs the check on every pull request touching specs/, the
script or either generated file.

The same pass validates front matter. It rejects a folder that is not
number-slug, missing or unparseable front matter, a missing required
field, an id disagreeing with the folder or duplicated, a value outside
the allowed roles, types, statuses or domains, a mirrored or indexed
entry with no upstream, a depends_on or replaces naming a spec that does
not exist, a numeric replaced_by naming a spec that does not exist, and
an indexed entry whose index_reason is absent, not one of the two
allowed values, or not backed by the condition that value promises.

Run against the specs as #31 leaves them it reproduces the README table
byte for byte.
Picks up the retirement folded into #31. The generated file now matches the specs again, so --check passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@phipsae
phipsae force-pushed the ci/registry-generator branch from 8740432 to bf66203 Compare September 17, 2026 18:52
@phipsae
phipsae changed the base branch from specs/normalize-front-matter to main September 17, 2026 18:52
@phipsae
phipsae merged commit a4dfa06 into main Sep 17, 2026
2 checks passed
Sign up for free to 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