Skip to content

governance: ship unified Cultures release manifest (Phase C step 2)#576

Merged
ChBrain merged 1 commit into
mainfrom
governance/unified-manifest
May 27, 2026
Merged

governance: ship unified Cultures release manifest (Phase C step 2)#576
ChBrain merged 1 commit into
mainfrom
governance/unified-manifest

Conversation

@ChBrain

@ChBrain ChBrain commented May 27, 2026

Copy link
Copy Markdown
Owner

Step 2 of the unified-contract rollout. KAIHACKS #274 (step 1) taught the consumer to read groupings from available.json, with a fallback fetch of the legacy groupings.json during the transition. This change teaches the producer to ship the unified shape.

What changed

What used to be two scripts and two delivered files is now one.

Before After
scripts/generate_available_json.py — produces available.json (cultures + release tag) Same script, now produces available.json with cultures[] AND groupings[] in one atomic shape
scripts/generate_groupings.py — produces groupings.json DELETED. Logic folded into the script above.
deliver-available-json.yml — two regen steps, two-file PR One regen step, one-file PR; PR title/body reference the unified manifest. Adds an explicit pip install pyyaml step (the frontmatter parser was previously imported transitively via the now-removed second script).

What this PR preserves exactly

  • Pickup mechanism — walk groups/<dir>/*_position.md, take every file whose YAML frontmatter has grouping: true. id, name, blurb, members project verbatim. id and name fall back to the directory name when unset. Bit-for-bit identical to the deleted generate_groupings.py.
  • Producer-side grouping invariantsid pattern ^[a-z0-9_-]+$, unique ids, non-empty members[], non-empty blurb. Same checks, now in check_manifest() alongside the culture invariants.
  • Culture id regex — unchanged (^[a-z0-9-]+$, no underscore). The two regexes are now named _CULTURE_ID_RE and _GROUPING_ID_RE to make the per-shape rule explicit at the call site.

Schema compatibility

The unified manifest still validates against available.schema.json on KAIHACKS, because step 1 (#274) added the optional groupings field at schemaVersion: 1. No bump needed — the addition is additive at v1.

Verification

  • python scripts/generate_available_json.py --release v0.99.0 --out /tmp/u.json
    wrote 16 cultures and 0 groupings (0 because the local tree has no groups/ dir; legacy generator also returned 0, behavior preserved) ✅
  • pytest tests/test_generate_available_json.py24 passed (+7 new TestGroupings tests covering clean shape, bad id, underscore allowed, duplicate id, empty members, empty blurb, empty list valid) ✅
  • pytest tests/test_branch_scope.py259 passed
  • .githooks/pre-commit → ✅

Rollout step left

Step 3 (after one release cycle proves the unified shape in production):

  1. KAIHACKS: drop the legacy fallback fetch from cultures-map.js
  2. KAIHACKS: delete groupings.json
  3. KAIHACKS: bump schemaVersion to 2 with groupings required

Refs: ChBrain/KAIHACKS#274


Generated by Claude Code

Step 2 of the unified-contract rollout. KAIHACKS #274 (step 1) taught
the consumer to read groupings from available.json, with a fallback
fetch of the legacy groupings.json during the transition. This change
teaches the producer to ship the unified shape.

What used to be two scripts and two delivered files is now one:

  scripts/generate_available_json.py   produces:
    {
      schemaVersion: 1,
      release:       <tag>,
      downloadBase:  <url>,
      cultures:      [...]      <-- from data/countries.json
      groupings:     [...]      <-- NEW: from groups/*/*_position.md
    }

  scripts/generate_groupings.py        DELETED

  .github/workflows/deliver-available-json.yml
    Drops the "Regenerate groupings.json" step.
    PR title + body now reference one file (available.json), the
    unified release manifest, rather than two.
    Adds an explicit `pip install pyyaml` step (the frontmatter
    parser was previously pulled in by the now-removed second
    script's import).

Why one file (recap from KAIHACKS #274):

  Release tag, cultures, and groupings are three concerns of the same
  release. Splitting them across two files leaves no atomicity
  guarantee -- a DACH grouping could name a culture id that the
  cultures[] array does not contain, or the badge could point to a
  release tag whose cultures the page is not showing. One file. One
  schema. Atomic versioning. One fetch on the consumer side.

What this commit preserves exactly:

  - Groupings pickup mechanism: walk groups/<dir>/*_position.md, take
    every file whose YAML frontmatter has `grouping: true`. The id,
    name, blurb, and members fields project verbatim. id and name
    fall back to the directory name when unset. Behavior is bit-for-
    bit identical to the deleted generate_groupings.py.
  - Producer-side grouping invariants: id pattern ^[a-z0-9_-]+$,
    unique ids, non-empty members[], non-empty blurb. Same checks,
    now in check_manifest() alongside the culture invariants.
  - Culture id regex unchanged (^[a-z0-9-]+$, no underscore). The
    two regexes are now named _CULTURE_ID_RE and _GROUPING_ID_RE
    to make the per-shape rule explicit at the call site.

Schema compatibility: the unified manifest still validates against
available.schema.json on KAIHACKS, because step 1 (#274) added the
optional `groupings` field at schemaVersion 1. No bump needed; the
addition is additive at v1.

Tests:
  +7 new tests in TestGroupings (clean shape, bad id, underscore id
  allowed, duplicate id, empty members, empty blurb, empty list is
  valid). _manifest() helper grew an optional groupings= kwarg
  (defaults to []), test_top_level_shape() now asserts the field is
  present.
  All 24 tests in test_generate_available_json.py pass.
  branch_scope.py and test_branch_scope.py drop the
  scripts/generate_groupings.py entry from the governance scope
  list (the file no longer exists). 259 branch-scope tests pass.

Smoke-test against the live tree:
  python scripts/generate_available_json.py --release v0.99.0 ...
  -> "wrote 16 cultures and 0 groupings"
  (0 groupings because the local tree has no groups/ directory yet;
   the legacy generator also returned 0 -- behavior preserved.)

Rollout step left (step 3, after one release cycle proves the
unified shape in production):

  KAIHACKS: drop the legacy fallback fetch from cultures-map.js,
  delete groupings.json, bump schemaVersion to 2 with `groupings`
  required.

Refs: ChBrain/KAIHACKS#274
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