From bf5a09bd0452da40409e59c578862c8e43e97549 Mon Sep 17 00:00:00 2001 From: Libby Date: Sat, 7 Nov 2026 16:53:03 +0000 Subject: [PATCH] publish-packages: say that cultcache-ts publishing is off; keep the tag pin readable The header comment, semver-policy and F16 of the content map still listed cultcache-ts-v* as a trigger. They now say publishing is deliberately off and that a tag run uses the workflow at the tagged commit (cultcache-ts-v0.15.0 sits on 7d292085, before the guard). semver-policy gains a "Before pushing a tag" note. The guard's comment moves above `tags:`: inside the list it broke the three `workflow:` tests of check-changelog-semver.test.mjs, which read `tags:` followed directly by its items. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/publish-packages.yml | 23 ++++++++++++++++------- docs/cultmesh-ts-content-map.md | 2 +- docs/semver-policy.md | 15 +++++++++++++-- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml index f78c0bb2..caa24336 100644 --- a/.github/workflows/publish-packages.yml +++ b/.github/workflows/publish-packages.yml @@ -8,17 +8,26 @@ name: Publish packages # directly, which is already how Ghostlight, Epiphany, CodexConnector and Odin # consume the core stack. # -# Tag a release to publish, for example `cultcache-ts-v0.13.6` or -# `cultnet-py-v0.1.0`. The tag's version must match the version in the package -# manifest; scripts/release-after-suite.mjs refuses the release otherwise rather -# than shipping a mislabelled artifact. +# Tag a Python release to publish, for example `cultnet-py-v0.1.0`. The tag's +# version must match the version in the package manifest; +# scripts/release-after-suite.mjs refuses the release otherwise rather than +# shipping a mislabelled artifact. +# +# npm publishing of @gamecult/cultcache-ts is deliberately off: `cultcache-ts-v*` +# is not a tag trigger until it is ruled on (the cultcache-ts job below runs from +# workflow_dispatch only, which publishes nothing). A tag run uses the workflow +# file at the tagged commit, not the one on main, so a tag on an older commit +# (`cultcache-ts-v0.15.0` sits on 7d292085, before the guard) still runs that +# commit's triggers and jobs. Read this file at the tagged sha before pushing a tag. on: push: + # cultcache-ts-v* is deliberately not a trigger: publishing @gamecult/cultcache-ts is disabled + # until it is ruled on, and whether NPM_TOKEN is set is unknown, so a pushed tag must not reach + # `npm publish`. The cultcache-ts jobs below still run from workflow_dispatch, which publishes nothing. + # (The comment sits above `tags:` because the tag-prefix pin in scripts/check-changelog-semver.test.mjs + # reads the list as `tags:` followed directly by its items.) tags: - # cultcache-ts-v* is deliberately not a trigger: publishing @gamecult/cultcache-ts is disabled - # until it is ruled on, and whether NPM_TOKEN is set is unknown, so a pushed tag must not reach - # `npm publish`. The cultcache-ts jobs below still run from workflow_dispatch, which publishes nothing. - "cultcache-py-v*" - "cultnet-py-v*" - "cultmesh-py-v*" diff --git a/docs/cultmesh-ts-content-map.md b/docs/cultmesh-ts-content-map.md index 9aae6eba..de6b6d2f 100644 --- a/docs/cultmesh-ts-content-map.md +++ b/docs/cultmesh-ts-content-map.md @@ -34,7 +34,7 @@ ran under the session scratchpad (`imagination/`), not in the repo. | F13 | Cross-process precedent for C# against a Node provider exists. `packages/cultnet-ts/test/interop/cultnet-interop.test.ts:536-560` spawns the TS QUIC provider, then runs `dotnet test --filter NativeConnectorReceivesFromExternalProvider` with the endpoint in `CULTMESH_NATIVE_EXTERNAL_ENDPOINT`. The C# test skips without the variable (`tests/GameCult.Mesh.Quic.Native.Tests`, line 21). | source | | F14 | `cultnet-ts` is CommonJS. Its `./wire`, `./contracts` and `./authority` subpaths import only `@msgpack/msgpack`, `ajv` and `cultcache-ts/document`, so they are browser-safe. Its root `index` pulls `node:` modules (`peer`, `rudp`, `transport`, `security` and others). `cultmesh-browser` (ESM) already imports `cultnet-ts/wire`, `/contracts` and `/authority`. `cultmesh-ts` loads `koffi` lazily, inside a function (`realtime-quic-native.ts:139`), so a new subpath of it pays no native load. The root has `esbuild` ^0.28.1 as a devDependency. | source, grep | | F15 | TS packages build with `tsc` and test with `node --test dist-test/test/*.test.js` per workspace. `scripts/run-typescript-workspaces.mjs` runs them in order `cultcache-ts, cultnet-ts, cultmesh-ts, cultmesh-browser`, after `check-typescript-tests-wired.mjs`. No StrykerJS config exists in CultLib (`docs/mutation-testing.md:156-159`). | source | -| F16 | **No CultLib TS package except `cultcache-ts` has a publish job.** `publish-packages.yml` triggers on `cultcache-ts-v*`, `cultcache-py-v*`, `cultnet-py-v*` and `cultmesh-py-v*` only. Tags `cultnet-ts-v0.1.1` and `cultmesh-ts-v0.1.1` exist, but no workflow consumes them. `npm view` returns 404 anonymously for `cultnet-ts`, `cultmesh-ts`, `cultmesh-browser` and even `@gamecult/cultcache-ts` (`@gamecult/cultcache-ts` may be private; unverified). The doctrine's rule of at most three tags per push stands (SKILL.md:674). | source; `npm view` | +| F16 | **No CultLib TS package except `cultcache-ts` has a publish job.** `publish-packages.yml` triggered on `cultcache-ts-v*`, `cultcache-py-v*`, `cultnet-py-v*` and `cultmesh-py-v*` when this was written; it now triggers on the three `-py-v*` patterns only, because npm publishing is deliberately off until ruled on (a tag run uses the workflow at the tagged commit, so `cultcache-ts-v0.15.0` on `7d292085`, before that change, still ran the old one). Tags `cultnet-ts-v0.1.1` and `cultmesh-ts-v0.1.1` exist, but no workflow consumes them. `npm view` returns 404 anonymously for `cultnet-ts`, `cultmesh-ts`, `cultmesh-browser` and even `@gamecult/cultcache-ts` (`@gamecult/cultcache-ts` may be private; unverified). The doctrine's rule of at most three tags per push stands (SKILL.md:674). | source; `npm view` | | F17 | StreamPixels consumes CultLib as the git submodule `vendor/CultLib` (gitlink `30ee8b97`) with `file:` deps and `pnpm.overrides`. Its CI and Idunn recipes build the vendored workspaces (`npm ci --ignore-scripts`, then build `cultcache-ts`, `cultnet-ts` and `cultmesh-ts`). `apps/web` depends only on `cultnet-ts` today, not on `cultmesh-browser`. | StreamPixels `.gitmodules`, `apps/*/package.json`, CI workflow lines 62-95 | | F18 | The Rust reader sets two guards that the TS reader should match. A caller cap `max_bytes` is checked before any request. And a zero-size chunk is refused unless it is the only one, because a manifest of zero-size chunks would be a request flood. | source `cultnet-rs/src/content.rs:364-385` | | F19 | `BuildChunkUri` on more endpoint shapes, as `AbsoluteUri` (what `HttpClient` sends). `https://h` and `https://h/` both give `https://h/?chunkHash=…&recordKey=k`. `https://h:443/x` drops the default port. `https://H.Example/X/` lowercases the host and keeps the path's case. `https://h/x#frag` keeps the fragment after the query. `https://h/x?a=%20b+c` keeps the existing query verbatim and joins with `&`. **`https://h/x?` (an empty query) gives `https://h/x?&chunkHash=…`**, because `UriBuilder.Query` is `?`, which is not blank. `https://[::1]:8443/c` keeps the bracketed host. `Uri.EscapeDataString("!'()*~-._ +é𐐀")` is `%21%27%28%29%2A~-._%20%2B%C3%A9%F0%90%90%80`: unlike JS `encodeURIComponent`, it escapes `!'()*`. | probe: `dotnet fsi` on .NET 10, the three lines of `BuildChunkUri` (`CultMeshHttpsContentTransport.cs:114-122`) copied verbatim | diff --git a/docs/semver-policy.md b/docs/semver-policy.md index 324b1154..f1c2c170 100644 --- a/docs/semver-policy.md +++ b/docs/semver-policy.md @@ -352,10 +352,21 @@ own path into the DLL. No `global.json` pins the .NET SDK, so the same refusal at unchanged source and CRLF checkout means this SDK or host differs from the one that built the tracked DLL. +### Before pushing a tag + +A tag run uses the workflow files at the tagged commit, not the ones on main, and +the forge's GitHub mirror forwards the tag. Read `.github/workflows/publish-packages.yml` +(and any workflow that triggers on tags) at the tagged sha before pushing any tag: +a guard merged after that commit does not protect a tag that points before it. +`cultcache-ts-v0.15.0` sits on `7d292085`, which predates the guard, and its push +started a publish run (it failed; nothing reached npm). + ### Coverage gaps -`publish-packages.yml` only triggers on `cultcache-ts-v*`, `cultcache-py-v*`, -`cultnet-py-v*`, and `cultmesh-py-v*` tag pushes — it does not build or gate +`publish-packages.yml` only triggers on `cultcache-py-v*`, `cultnet-py-v*`, and +`cultmesh-py-v*` tag pushes (`cultcache-ts-v*` is deliberately not a trigger: npm +publishing is off until ruled on, and the cultcache-ts job runs from +`workflow_dispatch` only, publishing nothing) — it does not build or gate the Unity UPM packages at all; those are consumed directly by git tag (`unity/org.gamecult.cultlib`, `packages/cultmath/unity/org.gamecult.cultmath`, `src/GameCult.Unity/Assets/Caching`), so a workflow trigger on their tags