feat(patches): declare the patch tier in tier.json and the manifest #10

Merged
whitlocktech merged 1 commits from feat/patch-tier-metadata into main 2026-08-05 01:08:34 +00:00
Member

What & why

The Runic Gateway installer's patch tier (docs/installer/PLAN.md §2.2, Phase 3) needs facts about these patches that a .patch file cannot carry:

  • which patches form one all-or-nothing unit — the two vendor-sale patches are useless apart, since one adds the event, one raises it, and the companion subscribes to both;
  • which companion .cs may only be copied once that unit has landed;
  • whether the change needs a core solution rebuild (dotnet build ServUO.sln) or just ServUO's dynamic script build;
  • what capability an operator loses by declining.

None of that is derivable from the diffs. This PR declares it in patches/tier.json, and release.yml folds it into the tarball's manifest.json as patch_tier.

Why in the release rather than in the installer: the same rule PLAN.md §7.1 already applies to the bundle — a new or changed patch should regenerate release metadata, not require an installer release. The staged copy is removed from patches/ so the tarball carries exactly one statement of the table.

The gate is the point

The release job now checks the table in both directions, and each check has a failure mode that is otherwise invisible until someone runs the tier on a live shard:

Check What it stops
every .patch described by exactly one feature, and vice versa a patch that ships but is silently never offered
every named patch and companion exists a feature the installer reports but cannot apply
each declared target equals the file its diff actually edits the installer refusing at install time over a mismatch caught here for free
rebuild is core or scripts a typo that loses the core-rebuild warning

Backwards compatible: installers older than this key ignore it, and an installer newer than the overlay it is deploying falls back to a built-in copy of this table.

How it was tested

The gate and the jq fold were both run against this repo's real patches/ in a Linux container (alpine + jq 1.7.1), matching the CI environment rather than the Windows dev shell — all four checks pass and the fold produces the expected patch_tier block.

The emitted block is also checked in as a fixture on the installer side (tests/fixtures/patch_tier.json), where a test asserts it deserializes into the installer's Manifest and is identical to the installer's built-in fallback. So the two repos cannot drift apart quietly.

Paired with:

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • AI tools were used. Tool(s): Claude Code (Opus). I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a Co-Authored-By trailer.

License

  • I agree that my contribution is licensed under this project's license (GNU GPL v3.0 or later), and I have the right to contribute it.
## What & why The Runic Gateway installer's patch tier (docs/installer/PLAN.md §2.2, Phase 3) needs facts about these patches that **a `.patch` file cannot carry**: - which patches form **one all-or-nothing unit** — the two vendor-sale patches are useless apart, since one adds the event, one raises it, and the companion subscribes to both; - which **companion `.cs`** may only be copied once that unit has landed; - whether the change needs a **core solution rebuild** (`dotnet build ServUO.sln`) or just ServUO's dynamic script build; - what capability an operator **loses** by declining. None of that is derivable from the diffs. This PR declares it in `patches/tier.json`, and `release.yml` folds it into the tarball's `manifest.json` as `patch_tier`. **Why in the release rather than in the installer:** the same rule PLAN.md §7.1 already applies to the bundle — a new or changed patch should regenerate release metadata, not require an installer release. The staged copy is removed from `patches/` so the tarball carries exactly one statement of the table. ### The gate is the point The release job now checks the table **in both directions**, and each check has a failure mode that is otherwise invisible until someone runs the tier on a live shard: | Check | What it stops | |---|---| | every `.patch` described by exactly one feature, and vice versa | a patch that ships but is silently never offered | | every named patch and companion exists | a feature the installer reports but cannot apply | | each declared `target` equals the file its diff actually edits | the installer refusing at install time over a mismatch caught here for free | | `rebuild` is `core` or `scripts` | a typo that loses the core-rebuild warning | Backwards compatible: installers older than this key ignore it, and an installer newer than the overlay it is deploying falls back to a built-in copy of this table. ## How it was tested The gate and the `jq` fold were both run against this repo's real `patches/` in a Linux container (`alpine` + `jq 1.7.1`), matching the CI environment rather than the Windows dev shell — all four checks pass and the fold produces the expected `patch_tier` block. The emitted block is also checked in as a fixture on the installer side (`tests/fixtures/patch_tier.json`), where a test asserts it deserializes into the installer's `Manifest` and is **identical** to the installer's built-in fallback. So the two repos cannot drift apart quietly. Paired with: - RunicGateway/installer#6 — the tier that consumes this - RunicGateway/docs#92 — §7.0 and §2.2 ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [x] AI tools were used. Tool(s): `Claude Code (Opus)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it.
wtclaude added 1 commit 2026-08-05 00:58:34 +00:00
A .patch file does not carry enough for an installer to run the tier safely.
The installer additionally needs to know which patches form one all-or-nothing
unit (the two vendor-sale patches are useless apart), which companion .cs may
only be copied once that unit has landed, whether the change needs a core
solution rebuild or just ServUO's dynamic script build, and what capability an
operator loses by declining. None of that is derivable from the diffs.

patches/tier.json declares it, and release.yml folds it into manifest.json as
`patch_tier` — so a new or changed patch regenerates release metadata rather
than requiring an installer release, which is the same rule §7.1 already
applies to the bundle. The staged copy is removed from patches/ so the tarball
carries exactly one statement of the table.

The release gate now checks the table in both directions: every .patch
described by exactly one feature, every named patch and companion present,
every declared target equal to the file the diff actually edits, and every
rebuild kind one the installer understands. All four were previously invisible
until someone ran the tier on a live shard.

Refs: docs/installer/PLAN.md §2.2, §7.0

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech approved these changes 2026-08-05 01:08:27 +00:00
whitlocktech merged commit c045bdd566 into main 2026-08-05 01:08:34 +00:00
whitlocktech deleted branch feat/patch-tier-metadata 2026-08-05 01:08:35 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/servuo-plugins#10
No description provided.