The fleet-wide conventions - Conventional Commit titles, squash merges, the all-green gate, and the code of conduct - are in Vivswan/.github's CONTRIBUTING.md. This page holds what is specific to this repository.
src/is TypeScript built with bun. The scripts inpackage.jsonare the commands;bun run checkis the whole local gate.- Run
bun installonce after cloning, and again afterlefthook.ymlchanges: it installs the dependencies and the git hooks. The hooks themselves never install or fetch anything, and a missing tool fails the commit naming that command. - GitHub's OpenAPI descriptor and GraphQL schema come from the
@octokit/openapiand@octokit/graphql-schemadevDependencies, so no test or generator touches the network. Dependabot moves the pins; a bump that stops documenting a path the action calls, starts documenting an upstream gap, or retires a field a query selects fails the schema tests on that PR by name. bun run build:openapi(.github/scripts/gen-openapi.ts) renders the files the descriptor dictates, the invitation role enums insrc/generated/spec-roles.ts, the ruleset rule rows insrc/generated/spec-rules.ts, and the passthrough vocabularies and bodies insrc/generated/spec-enums.ts; a descriptor bump regenerates them andtest/scripts/gen-openapi.test.tsfails on a committed copy that drifted.bun run testandbun run fuzzrunbun run build:schemafirst: the tests and the fuzzer load the built, gitignoredlib/settings.schema.json.- Committed generated output is the table in
.github/scripts/generated.ts: the whole files undersrc/generated/and the generated regions ofaction.ymland the docs pages. bun run build:checkregenerates every table entry and fails on drift.lib/index.js(the action bundle),lib/settings.schema.json(the published schema), andlib/pkg/(the npm library) are built where they are needed and never committed onmain. Every runtime dependency is compiled into the bundle and the library.- docs/reference/coverage.md is the inventory of the supported API surface, one link per call. A change that adds or extends a section keeps its
<key>.docs.ymlrows and.github/scripts/endpoint-docs.ymlin step.
- A compat path that stays (an alias, a retired input still accepted, an arm for an older artifact) carries a comment
COMPAT(vN): <what stays working and what to delete>, N the major that deletes it. Compat kept today for a pre-3 shape is marked v3; compat introduced during 3.x for a 3.0 shape is marked v4. - JSON takes no comments, so compat in a JSON file is marked in the code that reads it.
- A path that must work forever is not compat and gets no marker.
bun run check:compat(inbun run checkand in CI) rejects a malformed marker and any marker whose major is at or belowpackage.json's, and prints the remaining markers grouped by major.- A release PR's tree already carries the version it cuts, so the same check makes a major release PR unmergeable until every marker for that major is deleted on
mainfirst: with 3.0.0 in preparation, every v3-marked path goes before v3 cuts.
- Line caps: code wraps at biome's
lineWidthof 100. The fleet's check-file-size caps source, test, workflow, and shell lines at 256 characters; markdown prose has no width cap. A comment block is at most 10 lines. - Markdown keeps one source line per paragraph or list item, so a long item is split into items, never wrapped.
- A source file under
src/or.github/scripts/opens with a one-paragraph header comment saying what the file owns; test files need none. - Tests live under
test/, mirroringsrc/: a section's unit tests,mock.ts,generators.ts, andscenarios/sit intest/sections/<key>/, except that a mock fragment or snapshot row that is one family-factory call lives in the family table instead;src/holds code only.
- Every temp directory a test creates is removed on every exit path, failure included:
withTempDir()fromtest/temp-dir.ts, or a try/finally of its own. A fixture that outlives one test removes its dir when it ends (the release-pipeline fixture in afterAll, the e2e bundle on process exit). - An Io a test records through is
captureIo()fromtest/io/capture.ts: every channel in its own list and in one ordered event log. - A repository-relative path in a test resolves from
ROOTintest/root.ts; a file beside the test resolves fromimport.meta.dir. - A test in
test/docs,test/workflows, ortest/configguards an invariant between artifacts (a doc's claim against the code, a workflow against the constant a script prints); a pin of one file's own text is not kept.
The end-to-end tests build the bundle to a temp path and run it as a subprocess against a mock GitHub API, so they exercise the same single-file bundle a release ships.
bun run test:e2eruns the curated scenario corpus.- Every section ships the standard scenario set under
test/sections/<key>/scenarios/, named after the section's dashed key:<slug>-apply-converges,<slug>-check-drift(a section with a planning read),<slug>-snapshot-roundtrip(a section with snapshot()), and for a section under the undeclared policy<slug>-undeclared-deleteand<slug>-undeclared-keep-note;test/sections/scenario-set.test.tsderives the set from the registry. bun run fuzzruns seeded property fuzzing: random scenarios, each checked against an oracle that predicts the outcome class from the token mask, policy, and mode.- The mock serves the section endpoints plus the core routes the action calls outside the sections. A request that matches no registered route fails loudly; the mock never invents a response.
- PR CI runs the full scenario corpus, the endpoint-coverage tripwire, and 25 fuzz iterations on every pull request, and uploads the e2e failure artifacts.
- The release gate (
.github/workflows/release-gate.yml) runs the deep fuzz and the OpenAPI drift probe on the release PR, on a manual dispatch, and every night. It is required underall-greenon the release PR and on a manual dispatch. - The nightly workflow covers the Octokit freshness probes (the packages that describe GitHub's API, at their latest releases) and runs the full gate against them, covers the float canary, and opens the
@octokit/openapibump PR once the committed bump passes the full gate. A red night, the release gate included, files under thenightly-failureissue. - The fuzz workflow runs by dispatch alone, for a seeded replay or an ad-hoc soak, and files under
fuzz-nightlywith a replay command.
The fuzzer is deterministic. It prints a master seed and a per-iteration seed:
FUZZ_SEED=<masterSeed> bun run fuzz # replay a whole run
bun run fuzz --seed <iterationSeed> --iterations 1 # replay one failing iteration- Releases run downstream of the
all-greengate: ci.yml calls the fleet's release workflow, so a release or a release-PR refresh only happens from a greenmain. - release-please does the version math, the changelog, the version pins, and the release PR; merging that PR cuts the release.
- Every ref a
uses:pin can name (vX.Y.Z, the moving major,latest) points at a packaged commit: the child of onemaincommit, carrying its tree plus the built bundle, schema, and library; every green push mints one under abuild/<position>.<sha7>tag, the ten newest kept. The tags up to v2.0.0 point atmaincommits from whenmaincommitted the bundle. - Three repo-owned hooks share the ref work:
post-green.ymlpackages every green push under itsbuild/tag, prunes the window, and moveslatest;update-release.ymlmintsvX.Y.Zand moves the major, packages the merge commit when no build tag does, and reconcileslatestand the build-tag window as post-green does;update-release-pr.ymlanchors release-please's boundary (last-release-sha) and publishes thenextpre-release to npm. The git topology lives in.github/scripts/release-pipeline/tags.tsand its test.