docs: scaffold the Integration Kit — front page, outline, and the checks #1

Merged
whitlocktech merged 1 commits from docs/scaffold into main 2026-08-12 14:48:19 +00:00
Member

Phase 5 slice 0. This repo's first pull request. Plan: docs#145 (MODULE_SYSTEM.md §2.11.1).

The initial commit went straight to main because an empty repo cannot take a PR — but unlike Module-uo's bootstrap, it carries only LICENSE.md and CODE_OF_CONDUCT.md, both verbatim copies of files already approved elsewhere. Everything authored is here instead, because in this repo the prose is the product and landing it unreviewed on main would skip the review that matters most.

The front page

README.md opens with what the reader is building — module, sidecar, game plugin, with a diagram of the data path — and carries the draft banner decision 5 asks for: the kit is finished when someone outside this project builds a working module by following it alone, that has not happened, and the places they get stuck are the most valuable thing the repo can receive.

It states the sidecar rule on the front page rather than saving it for chapter 3. A reader who skims a README and starts coding should still get that one right.

The outline, landed before the prose

book/README.md is four chapters with what each will cover, so the shape can be argued with before there is prose to defend. Chapters are named but not linked — a link to a file that does not exist is exactly what the link check is for, and an outline should not be the first thing to fail it.

The two checks

scripts/checkLinks.js — relative links resolve, anchors match a real heading, and no link pins a reader to a /src/commit/<sha>/ snapshot of a document we want them reading the current version of. Nothing is fetched, on purpose: this project's Gitea is self-hosted, so an HTTP check would fail on a credential-less runner, flake when the host is busy, and teach everyone to ignore red. Fenced blocks and code spans are stripped by a line walk, not a regexp — a fence's content can contain anything, including a line that looks like the end of one, and a code fence in this repo legitimately contains paths that do not exist yet.

Its first run found a real one, which is now encoded with its reason: a PR template's relative links resolve from the repo root, because that is where their text ends up when Gitea inlines the template into a pull-request body. [CONTRIBUTING.md](CONTRIBUTING.md) is correct in .gitea/PULL_REQUEST_TEMPLATE.md and wrong anywhere else.

scripts/checkCoreApi.js — the anti-rot mechanism (decision 2). It asserts template/module.json's coreApi equals the pinned core's MODULE_API_VERSION.

Equality and not "satisfies", and that is the whole point: a range check is what core does at load time and it is right there, but it is the wrong question here. If core moves to 1.5.0, ^1.4.0 still satisfies, the build stays green, and nobody ever re-reads the chapters. Green would mean "the template still loads" when we need it to mean "someone has looked at this since the contract changed". So this failing on a core bump is the system working, and the failure message says so and lists the three steps — with a note that bumping the two files without doing step 2 is the one way to make the check worthless.

How it was tested

  • node scripts/checkLinks.js31 link(s) across 9 markdown file(s) — OK.
  • checkCoreApi.js exercised on all three branches against a real core checkout: matching (^1.4.0 vs 1.4.0) exits 0; stale (^1.3.0 vs 1.4.0) exits 1 with the explanation; a --core with no server/src/modules/ exits 1 naming the pin and the main-vs-edge reason.
  • The workflow's run: blocks contain zero ${{ }} tokens (checked, not eyeballed) — a literal empty expression in a run: script silently skips the step and has cost this org months before.

Two things carried over from other repos' scars

  • The pin points at core's edge, not main (ci/core-ref.json) — the module system has not cut over and main has no server/src/modules/ at all. The file says so, and says the cutover has to revisit it.
  • The template job is guarded on template/module.json existing. The template lands in slice 1; until then the job reports green with a notice saying why, and arms itself the moment the file appears with no edit to the workflow. Same guard Module-uo#1 used through its planning phase — it beats leaving the repo ungated, and beats red-Xing every docs PR until there is code to check.

Owed, one-time and manual

Branch protection on main (PR Checks / *) still has to be set in the Gitea UI, and Gitea only lists a status context after it has reported once — so this PR is the run that makes it selectable. The workflow header records it.


  • AI-assisted: written with Claude Code (Claude Opus), reviewed by the author.

🤖 Generated with Claude Code

https://claude.ai/code/session_018ocYxQWk3EhZe5gWRJXFU8

**Phase 5 slice 0.** This repo's first pull request. Plan: docs#145 (`MODULE_SYSTEM.md` §2.11.1). The initial commit went straight to `main` because an empty repo cannot take a PR — but unlike Module-uo's bootstrap, it carries **only `LICENSE.md` and `CODE_OF_CONDUCT.md`**, both verbatim copies of files already approved elsewhere. Everything authored is here instead, because in this repo the prose *is* the product and landing it unreviewed on `main` would skip the review that matters most. ## The front page `README.md` opens with what the reader is building — module, sidecar, game plugin, with a diagram of the data path — and carries **the draft banner** decision 5 asks for: the kit is finished when someone outside this project builds a working module by following it alone, that has not happened, and the places they get stuck are the most valuable thing the repo can receive. It states the sidecar rule on the front page rather than saving it for chapter 3. A reader who skims a README and starts coding should still get that one right. ## The outline, landed before the prose `book/README.md` is four chapters with what each will cover, so the shape can be argued with before there is prose to defend. Chapters are **named but not linked** — a link to a file that does not exist is exactly what the link check is for, and an outline should not be the first thing to fail it. ## The two checks **`scripts/checkLinks.js`** — relative links resolve, anchors match a real heading, and no link pins a reader to a `/src/commit/<sha>/` snapshot of a document we want them reading the current version of. Nothing is fetched, on purpose: this project's Gitea is self-hosted, so an HTTP check would fail on a credential-less runner, flake when the host is busy, and teach everyone to ignore red. Fenced blocks and code spans are stripped by a **line walk, not a regexp** — a fence's content can contain anything, including a line that looks like the end of one, and a code fence in this repo legitimately contains paths that do not exist yet. > Its first run found a real one, which is now encoded with its reason: **a PR template's relative links resolve from the repo root**, because that is where their text ends up when Gitea inlines the template into a pull-request body. `[CONTRIBUTING.md](CONTRIBUTING.md)` is correct in `.gitea/PULL_REQUEST_TEMPLATE.md` and wrong anywhere else. **`scripts/checkCoreApi.js`** — the anti-rot mechanism (decision 2). It asserts `template/module.json`'s `coreApi` **equals** the pinned core's `MODULE_API_VERSION`. Equality and not "satisfies", and that is the whole point: a range check is what *core* does at load time and it is right there, but it is the wrong question here. If core moves to 1.5.0, `^1.4.0` still satisfies, the build stays green, and nobody ever re-reads the chapters. Green would mean "the template still loads" when we need it to mean "someone has looked at this since the contract changed". **So this failing on a core bump is the system working**, and the failure message says so and lists the three steps — with a note that bumping the two files without doing step 2 is the one way to make the check worthless. ## How it was tested - `node scripts/checkLinks.js` → `31 link(s) across 9 markdown file(s) — OK`. - `checkCoreApi.js` exercised on all three branches against a real core checkout: matching (`^1.4.0` vs 1.4.0) exits 0; stale (`^1.3.0` vs 1.4.0) exits 1 with the explanation; a `--core` with no `server/src/modules/` exits 1 naming the pin and the `main`-vs-`edge` reason. - The workflow's `run:` blocks contain **zero `${{ }}` tokens** (checked, not eyeballed) — a literal empty expression in a `run:` script silently skips the step and has cost this org months before. ## Two things carried over from other repos' scars - **The pin points at core's `edge`, not `main`** (`ci/core-ref.json`) — the module system has not cut over and `main` has no `server/src/modules/` at all. The file says so, and says the cutover has to revisit it. - **The `template` job is guarded on `template/module.json` existing.** The template lands in slice 1; until then the job reports green with a notice saying why, and arms itself the moment the file appears with no edit to the workflow. Same guard Module-uo#1 used through its planning phase — it beats leaving the repo ungated, and beats red-Xing every docs PR until there is code to check. ## Owed, one-time and manual Branch protection on `main` (`PR Checks / *`) still has to be set in the Gitea UI, and Gitea only lists a status context after it has reported once — so this PR is the run that makes it selectable. The workflow header records it. --- - [x] AI-assisted: written with Claude Code (Claude Opus), reviewed by the author. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_018ocYxQWk3EhZe5gWRJXFU8
wtclaude added 1 commit 2026-08-12 14:47:56 +00:00
docs: scaffold the Integration Kit — front page, outline, and the checks
All checks were successful
PR Checks / template (pull_request) Successful in 6s
PR Checks / links (pull_request) Successful in 7s
cffd525bdf
Phase 5 slice 0 (MODULE_SYSTEM.md §2.11.1). The repo's governance, the front
page, the book's outline, and the CI that keeps the whole thing from rotting.

README.md
  What the reader is building, all three parts, and the draft banner: the kit is
  finished when someone outside this project builds a working module by
  following it alone, and that has not happened. Says the sidecar rule plainly
  (MODULE_API.md §2.7) rather than leaving it to chapter 3, because a reader who
  skims the front page and starts coding should still get that one right.

book/README.md
  The outline of four chapters, landed before the prose so the shape can be
  argued with. Chapters are named but NOT linked — a link to a file that does
  not exist is what the link check is for, and an outline should not be the
  first thing to fail it.

CONTRIBUTING.md
  The rule that governs every change here: the kit never re-specifies a
  contract. Also the prose conventions, and why the pinned ref points at core's
  `edge` rather than `main`.

SECURITY.md
  Scoped for a repo that runs nothing: the two things that ARE reportable are a
  template that teaches an insecure pattern (it is meant to be copied) and a
  chapter that teaches something dangerous.

scripts/checkLinks.js
  Relative links resolve; anchors match a real heading; no link pins a reader to
  a commit snapshot of a moving document. Nothing is fetched — a self-hosted
  Gitea would fail on a credential-less runner and teach us to ignore red.
  Fences and code spans are stripped by a line walk, not a regexp.

  Its first run found a real one: a PR template's relative links resolve from
  the REPO ROOT, because that is where their text ends up when Gitea inlines
  them into a pull request body. Encoded, with the reason.

scripts/checkCoreApi.js
  The anti-rot check. Asserts template/module.json's `coreApi` EQUALS the pinned
  core's MODULE_API_VERSION — equality, not "satisfies", because a range check
  stays green across a contract bump and green would then mean "the template
  still loads" instead of "someone has re-read the book". Both failure branches
  and the pass were exercised against a real core checkout.

ci/core-ref.json
  The pin, same convention as Module-uo's. Points at `edge`: core's `main` has
  no server/src/modules/ until the cutover, and that pin is one of the things
  the cutover has to revisit.

.gitea/workflows/pr-checks.yml
  Two jobs. `links` always runs; `template` is conditional on
  template/module.json existing, so the repo is gated now and the job arms
  itself when slice 1 lands, with no edit to the workflow. Same guard Module-uo
  used through its planning phase.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech merged commit 1156a89509 into main 2026-08-12 14:48:19 +00:00
whitlocktech deleted branch docs/scaffold 2026-08-12 14:48:20 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/Integration-kit#1
No description provided.