Commit graph CultLib/scripts
Author SHA1 Message Date
Meta Vens
3de72c6333 Content vectors: C#-written acceptance cases, trap inputs for keys, padded pack vector
CultMeshContentVectorTests writes content-acceptance-vectors.json (what the reference accepts, refuses, rewrites and
keys over nil, arity, trailing, integer/float, string-family and invalid-UTF-8 shapes), extends the record-key
vectors with the prefix-fold, fallback-hash traps, and the TS writer adds a whitespace-version, padded kind and
MIME pack vector. GameCult.Mesh exposes internals to its test project so the judge can call ValidateManifest.
The generated files follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:40:55 +02:00
Meta Vens
0ca81f52da cultnet-ts/content: the TypeScript CDN manifest, codec, hashing, record keys and packer
One browser-safe module owns the manifest and chunk-ref shapes, their MessagePack form (positional ten-array, metadata as
ordered entries, duplicate keys and unsafe integers refused, payload depth through cultcache-ts's own checkPayloadDepth),
normalizeHash/parseSha256Hex, both record-key grammars (StableToken per UTF-16 unit), WebCrypto sha256Hex and packContent.
cultcache-ts/document re-exports checkPayloadDepth. scripts/write-cultmesh-content-vectors.mjs writes the TypeScript
manifest vectors for the C# reference to judge.

Builds. Co-Authored-By below.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:35:15 +02:00
Meta Vens
986faf1f33 test:pack:ts probe shows each exported function a map and a slot record (readWire refuses a map, so a wrapper of it passed the map-only probe)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 01:22:47 +02:00
Meta Vens
d64f688459 test fixes: the grey-image schema is a custom check, and the pack probe treats a throwing result as not a reader
Fixes the previous commit (05f9937b, mislabelled wip): its test file did not compile (TS2322) and the pack probe threw on a lazy codec's getters. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 01:08:44 +02:00
Meta Vens
27b9e2b315 test:pack:ts denies payload readers by identity and behaviour, not by name
Finding pack-denial-by-name: the package-internal readers (readWire, resolveDocumentFormatter, @msgpack decode) are loaded from the packed dist by path and searched by identity through every packed entry, including default and namespace members; every other exported function is shown a MessagePack map and must not return it decoded.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 01:04:27 +02:00
Meta Vens
b69d3057a5 cultcache-ts: the payload nesting bound (256) in the one document-payload owner, so every TS payload door shares it
checkPayloadDepth is an iterative header walk run by decodeDocumentPayload before the formatter and by
encodeDocumentPayload on the formatter's bytes; the two plain-decode inspection doors call it first. The plain
formatter's encoder depth is set above the limit so the walk decides. Tests: the C# bounds vectors, the walk's
header and scalar rules, the owner, the inspector, the legacy version inference, and the mesh network doors;
test:pack:ts denies decoder-shaped exports by enumerating the packed entries.

Builds and passes untested at this commit (verification runs on Yggdrasil next).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 00:01:59 +02:00
Meta Vens
71d8ff3080 cultcache-ts: codecFormatter moves into the private document-formatter module; pack smoke refuses it from the root and ./document
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 22:03:20 +02:00
Meta Vens
12a0fd7744 cultcache-ts: resolveDocumentFormatter moves out of the ./document entry into a module no export names
The packed-consumer smoke now fails if the document entry exports it, at run time and at compile time.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 21:05:09 +02:00
Meta Vens
8cff9b7f30 verify-eve-browser-network: a waiter matches only lines whose newline has arrived
A stdout chunk can end inside the benchmark JSON line; the waiter matched the half line and JSON.parse threw (seen once
in two runs on the rust image). Waiters now read complete lines only.

All commits build.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 20:51:35 +02:00
Meta Vens
195c37b867 Eve browser sample reads its payloads through definitions, and the verifier type-checks the page
main.ts called decodeCultNetPayload with no definition, which the required-definition signature refuses; esbuild strips
types, so only the browser noticed. The sample now holds a counter definition and plain-map definitions for the Eve
documents, and verify-eve-browser-network.mjs runs tsc over main.ts against the module map the bundle uses (and builds
cultcache-ts, which cultmesh-browser now imports) before bundling. The receipt is read as the typed wire object instead
of a cast of the Eve receipt type.

All commits build.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 20:37:29 +02:00
Meta Vens
0c5207b55f One typed owner of document-payload reads and writes: DocumentPayload is opaque, the definition is required
DocumentPayload is an opaque object type over the same runtime Uint8Array, keyed by a string
property, and types CultCacheEnvelope.payload, CultNetRawDocumentRecord.payload and
CultMeshRealtimeFrame.payload. decodeDocumentPayload(definition, payload) and
encodeDocumentPayload(definition, value) are the only reader and writer; documentPayloadFromBytes
and documentPayloadBytes are the two named escapes at the edges where bytes enter and leave.
resolveDocumentFormatter leaves the package index. The cache, cultnet replication, the mesh read
paths, the provider command (now a CultCache document), and the browser's decodeCultNetPayload
(definition required, cultcache-ts/document entry) all go through the owner.

Compile-fail fixtures per payload-carrying package pin the type with expect-error lines.
check-typescript-tests-wired.mjs fails when a test file is run by no script; cultcache-ts now
runs dist-test/test/*.test.js, and the portability workflow runs the check and the cache suite.

Builds in every package (tsc, src and tests); the suites run once, at the end of the pass.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 19:33:42 +02:00
Meta Vens
a126914efc Release guard tidy: the Python build guard starts without NODE_OPTIONS too
The python-build step runs the same guard whose output is the dist PyPI
uploads, so a NODE_OPTIONS preload in the workflow or job env could stub
its checks exactly as it could on the npm Publish line. It now starts
under env -u NODE_OPTIONS; the pin's exact text and semver-policy.md say
so. The pin test's if: always() edit matched the npm line's old text and
had become a no-op; it now matches the pinned line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:16:57 +02:00
Meta Vens
49a5526ede Release guard tidy: threat model stated, preload route pinned shut, dated changelog headings read
- The npm Publish step starts the guard under `env -u NODE_OPTIONS`, and the
  pin's exact text carries it, so a workflow or job NODE_OPTIONS preload
  cannot run inside the guard (preload-fakes-guard).
- The pin's shell/defaults ban and its test are gone: it defended only a
  deliberate edit, which is review's job (suite-gate-structural-not-parsed),
  and refused a harmless defaults.run.working-directory. A step-level shell
  still fails the exact comparison (shell-ban-deliberate-only).
- docs/semver-policy.md states that the guard and pin stop accidental edits,
  that the cleaned environment removes known variables rather than proving no
  inherited one matters (env-denylist-overclaim), recommends a
  required-reviewer environment for the npm job, and gives the first-release
  note with the valid next versions.
- check-changelog-semver accepts `## [x.y.z] - YYYY-MM-DD` and
  `## x.y.z - YYYY-MM-DD` beside the plain forms (changelog-first-entry).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:02:55 +02:00
Meta Vens
19b52b16c3 Release pin: keep the shell and defaults ban, which still guards what the pinned release line runs
A job or workflow defaults.run.shell can run the exact Publish line through any
command, with the token in its env. Only continue-on-error leaves the pin: a
check that fails inside the guard refuses the release whatever the step allows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:37:38 +02:00
Meta Vens
7a36848b98 Release guard: the checks run in a clean env, and every per-tag check runs in the guard
release-after-suite.mjs now takes the run's git ref and, from one process, checks
the tag against the declared prefix and manifest version, runs the release-checks
suite, the semver policy check and the package's own tests, then releases. The
checks run without NODE_OPTIONS, NODE_TEST_*, or NODE_AUTH_TOKEN; only the release
action gets the token. The workflow's separate tag, semver and test steps are gone,
and so is the pin's continue-on-error/shell/defaults ban, which no release check
needs any more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:05:28 +02:00
Meta Vens
48784fa4d8 Unity build: the no-.git guard asks git for the checkout top, so an empty .git is refused and a worktree passes
Finding asura:finding:cut-3-gate.s3.git-guard-existence-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:44:19 +02:00
Meta Vens
bc4af4fa58 Release gate: publish-packages.yml releases through one entrypoint that runs the suite first; the if: pin is gone
scripts/release-after-suite.mjs runs the release-checks suite and then the
release action (npm publish, or the Python sdist and wheel build that the PyPI
step uploads) from one process, and releases only if the suite passed. No step
condition can release what the suite did not pass, so the pin that read if:
conditions (status functions, multi-line if:, the leading-conjunct rule) is
deleted with its tests and docs. What remains compares each job's release steps
with their expected text exactly, less their if: line, and refuses
continue-on-error, shell and defaults in the workflow.

Ruling asura:ruling:suite-gate-structural-not-parsed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:43:47 +02:00
Meta Vens
303476db6c cultlib byte gate: CultMath source checks out CRLF everywhere, and the build refuses a tree without .git
Soul s2 found the CultMath bytes follow the checkout's line endings (an LF clone
built 53084D94, not the tracked 6781BF20) and its path when no .git maps the root
to /_/. .gitattributes pins packages/cultmath/src/** to eol=crlf, which the
tracked DLL was built from, so no re-release. The build script refuses up front
without .git, and the refusal and docs name line endings beside source and
toolchain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:27:18 +02:00
Meta Vens
942e4033b2 Workflow pin: refuses success() and any if: continued past its line, the way block scalars are refused
Soul s2 found 'success() || c' and plain or quoted if: values continued on a
following line passing the pin. Any status function now refuses, and stepCondition
reports an if: whose value continues (block scalar or a deeper-indented next line)
as multi-line, which the pin refuses. Soul's four probe forms are asserted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:26:43 +02:00
Meta Vens
8ed6095a90 Workflow pin: refuses status functions and block-scalar if:, and says which sound conditions it refuses
A Publish if: calling always(), cancelled() or failure() runs after the suite failed, the
continue-on-error bypass by another name; a block-scalar if: was compared by its indicator, so
'>-' equalled '>-' whatever followed. Both are now refused. The third refusal no longer calls
sound conditions narrower: it names the three accepted shapes, and the code comment and
docs/semver-policy.md list the sound forms textual matching refuses and why.
(Soul findings cut-3-gate.s1.status-function-bypass, block-scalar-if-compared-as-text,
pin-refusal-cost-undocumented.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:02:58 +02:00
Meta Vens
1eece6beef cultlib byte gate: the refusal names toolchain drift beside a source change, and says what to check
Unchanged CultMath source built on another SDK or host gives other bytes (Linux sdk:10.0:
db2a11cc against tracked 6781bf20), so the refusal no longer sends the operator to release a
CultMath with no change (Soul finding cut-3-gate.s1.toolchain-drift-named-as-source-change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:00:54 +02:00
Meta Vens
a287b6f8a5 cultlib release gate: clear every project's intermediates, CultMath's included, before the byte gate
Directory.Build.props puts CultMath's obj at obj\packages\cultmath\src\CultMath, which the
obj\src-only clean left in place, so an old-mtime CultMath source change could reuse a stale
CultMath.dll and pass the byte gate (Soul finding cut-3-gate.s1.cultmath-obj-not-cleared).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 12:59:20 +02:00
Meta Vens
0884361731 Workflow pin: a suite condition that is a textual prefix but not a whole conjunct is refused
Kills the surviving mutant that drops the ' && ' separator from the
leading-conjunct rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 12:39:00 +02:00
Meta Vens
c64c2a0e06 Workflow pin: the suite step's condition must be implied by Publish's
The suite step's if: is absent, equal to Publish's, or a leading conjunct of
a Publish condition that has no ||. A disabled or narrowed suite step fails
the pin. Closes asura:follow_up:suite-step-condition-pin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 12:25:18 +02:00
Meta Vens
9c50297cab cultlib release gate binds CultMath by bytes: one list owns the publish roots
The declared org.gamecult.cultmath dependency must equal the CultMath package
version (-ne, not -gt), and every CultMath.dll a managed publish produced must
equal the DLL that package tracks. The type-name check and its helper,
scripts/check-cultmath-types.cs, are gone: the byte gate subsumes them.
$managedPublishes is the single owner of publish-root identity for the clean
step, the publish loop, $publishedByName, the byte gate and --api-refs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 12:25:18 +02:00
Meta Vens
7ec300a5aa Semver release: the suite runs first in CI and in the Unity scripts, and the Caching Unity prefix is its own tag family
publish-packages.yml runs the suite in both jobs, after .NET setup on a full-depth
checkout and before any check or publish step; the three Unity release scripts run
it before the checker. A test reads each file and fails when the step is removed,
moved, or made non-fatal. The Caching Unity pin now needs a prefix declared once
whose exact tags hold the package's own manifest at the tag's version. No NUL byte
in the checker is a test. The policy records that releases run from a full clone.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 11:43:43 +02:00
Meta Vens
c84a1fcc06 Semver check: the NUL and TAB in the ls-tree reader are escapes, so the file is text
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 11:43:42 +02:00
Meta Vens
8c9faf06c6 Semver check tests: the first-release probe's cwd and blob size are pinned, and assembly-less packages read no tags' trees
Also defines the PE fixture before the tests that use it, so a filtered run no
longer reaches it before initialization.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 09:53:17 +02:00
Meta Vens
8c3e834967 Semver check: a first release is proved only by a managed assembly in the declared folder
Monorepo snapshot tags track every package's directory, so tracking a file
proved nothing about a package's own releases. A package with an assemblies
directory is a first release only when no tag under any prefix tracks a managed
assembly there (decided by PE bytes, once per blob). Assembly-less packages are
a first release when no tag of their own prefix exists; their prefix is pinned
by the suite test tying each declared prefix to a workflow trigger or an
existing tag, which now fails on a typo for every assembly-less package.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 08:57:06 +02:00
Meta Vens
e940a37316 Semver check: the folder pathspec has no root special case and the tree listing is compared as git prints it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 08:50:30 +02:00
Meta Vens
2610434917 Semver check: a first release is one whose package folder no tag has tracked
The changelog-heading guard missed 12 of 17 heading shapes and a first changelog
entry. It and its parsing are deleted. A release with no same-prefix baseline is
a first release only when no tag in the repository, under any prefix, tracks a
file under the package's folder (declared assemblies dir, else the changelog's
directory); otherwise it refuses naming the tag. A tag whose tree cannot be read
refuses. Tests pin the mistyped prefix for CultMath 0.3.1, cultlib 1.0.61 and a
Python package, a genuine first release, the moved-folder choice, and an
unreadable ancestry and tree.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 08:01:30 +02:00
Meta Vens
3a25a9d3aa Semver check: baseline is the newest older tag that is an ancestor of the commit; first release refused when the changelog lists an earlier version; declaration checked whole
The previous release is chosen by version order among same-prefix tags strictly older than the version, and must be an ancestor of HEAD, so a later backport on another branch never moves a rebuild's predecessor. A release with no previous tag is refused when the changelog already lists an earlier version, so a mistyped prefix cannot make an unmeasured first release. The declaration is validated as a whole: two packages sharing a prefix, or an entry without a string tagPrefix and changelog, refuse.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 05:55:12 +02:00
Meta Vens
23d7beac20 Semver check derives what callers used to declare: first release, tag prefix, changelog and measured set
The checker reads each package's tag prefix, changelog and assemblies directory
from scripts/release-packages.mjs and derives the release record from git tags.
A first release is the absence of any older tag in a checkout that holds other
tags; a malformed same-prefix tag, a checkout without tags and an unreadable
repository refuse. The measured set is every managed assembly (CLI header in
the PE bytes) tracked at the previous tag at any depth; an unbuilt one is a
break, a built assembly with no namesake is an addition.

Deleted with their branches, refusals and tests: --first-release, --api-new,
--tag-prefix, --changelog, --api-baseline-path and the workflow first-release
decision line. Any unknown option is now a usage error.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 02:36:54 +02:00
Meta Vens
652b0837d2 Semver check: one rule for an unbuilt tracked assembly, comparisons must run, git failures are refusals, a first release is cross-checked
Every assembly the previous tag tracks that the build does not hand over is a break, whatever its name; a run that compared nothing is refused (the --api-new rename of a lone assembly). The cultlib build now hands over every shipped assembly. --first-release is believed only with no other same-prefix tag and the prefix its changelog directory names. git ls-tree/show failures and an unreadable changelog become refusals. Tests pin the CultMath-shaped rename, the left-reference scenario (a dependency's netstandard base chain changes), the first-release probes and the workflow's own first-release line.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 00:58:33 +02:00
Meta Vens
68c1296b7a Semver check: keep git's stderr out of the refusal (the fatal-message test fails without it)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:44:03 +02:00
Meta Vens
c358ef9739 Semver check: drop the unobservable stdio option; the empty-package test really creates the directory
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:38:55 +02:00
Meta Vens
df13b502b9 Semver check: built and reference paths are resolved against the process, not the tool's directory
The ApiCompat tool runs from scripts/api-gate, so a relative --api-built or --api-refs
failed as an unreadable assembly. The release scripts pass absolute paths; any other
caller does not have to.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 21:30:37 +02:00
Meta Vens
0ac870f132 Semver check tests: pin git's silence, the gate manifest file, netstandard.dll, the first-release hint
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:28:26 +02:00
Meta Vens
e7786ffac2 Semver check: a malformed version is refused by name, and refusals are pinned never to repeat input contents
A malformed --version fell into the tag-reading catch and was reported as unreadable
tags. It is now validated first and refused without repeating the value. A canary test
runs seven refusals (measured break, unreadable built DLL, unreadable baseline blob,
missing entry, skipped version, breaking under too small a bump) with a canary in the
changelog and the assemblies and asserts it never appears in the output.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 21:27:03 +02:00
Meta Vens
83e3f81263 Semver check: measuring nothing refuses; reference assemblies; tool restored alone
- A missing or moved baseline path, a previous tag that does not track the DLLs, and a built DLL
  with no namesake at the tag (unless declared with --api-new) refuse, naming what is missing.
- First release is declared with --first-release, never inferred: no previous tag, or tags that
  cannot be read, refuse without it.
- The "already published" skip is removed; a local tag of the released version exempts nothing.
- ApiCompat and the pinned NETStandard.Library.Ref 2.1.0 live in scripts/api-gate and are restored
  there, so the root manifest (dotnet-stryker) is no longer needed by a release. Both sides resolve
  netstandard through the reference assemblies.
- Tests: refusals, netstandard false breaks, cross-assembly references, restore diagnostics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 19:52:14 +02:00
Meta Vens
32f5700b2a Semver check tests: double trailing slash, and a process started outside the target repo
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 19:03:00 +02:00
Meta Vens
84a34b8735 Semver check tests: pin the broken-manifest failure text
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 18:35:27 +02:00
Meta Vens
f40069dd88 Semver check tests: scope the cleanup assertion to the checker's own temp dirs, cover a broken manifest
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 18:34:05 +02:00
Meta Vens
6a3dae8954 Semver check: run tests from outside the repo, pin cleanup, usage and restore failure
The checker now runs with the target repo as its working directory in tests,
so the tool manifest is found from the script's own location as it is in the
release scripts. Adds tests for usage errors, a missing changelog, backslash
and trailing-slash baseline paths, temp-file cleanup, a restore failure and a
missing dotnet failing closed, the five-line failure excerpt and the
five-diagnostic cap. Drops two unreachable defaults and an unreachable
spawn-error branch from the checker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 18:32:38 +02:00
Meta Vens
ed31a97689 Semver check tests: cache built fixture assemblies by content
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 18:01:37 +02:00
Meta Vens
b8e1f7e0f6 Unity release scripts: run the semver check after the build, with the built DLLs
The check moves from before the build to once the assemblies under judgement
exist, and receives every shipped GameCult.* DLL (cultlib) or the fresh
CultMath.dll with the baseline path of the previous tag's tracked plugins.
The early calls are deleted; each script keeps exactly one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 17:08:36 +02:00
Meta Vens
8f2eab7651 Semver check: behavioural tests for the measured public API
Real assemblies built in the test and compared through the CLI: removal
without ### Breaking, removal under too small a bump (post-1.0 and 0.y.z),
additions alone, a declared break with nothing measured, a removed GameCult.*
assembly, tool failure failing closed, inherited-member removals, an
already-published version, the baseline coming from the tag's blob, and a
first release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 17:08:36 +02:00
Meta Vens
716ef9341c Semver check: measure the public API against the previous tag's DLLs
check-changelog-semver.mjs takes --api-baseline-path, --api-built and
--api-refs, extracts the previous tag's tracked DLLs as git blobs, and runs
the pinned Microsoft.DotNet.ApiCompat.Tool on each built assembly. Measured
breaks make the release breaking for the lane check and must be declared
under ### Breaking; a tool failure without a diagnostic refuses the release;
a GameCult.* assembly the tag tracked and the build lacks is a break.
Behavioural tests follow in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 17:03:09 +02:00
Meta Vens
9b4167d9ab pack-nuget: pack the ProjectReference closure, not a hand list
Merge 69bd45ff made GameCult.Caching.MessagePack reference CultMath
(PackageId GameCult.Math), so its nuspec depends on GameCult.Math 0.2.4.
The packer's hand-written project list never packed it, and GameCult.Math
is not on nuget.org, so every clean consumer of the local feed failed
restore with NU1101. That is the Eve surface consumer smoke in the
"one-command multiplayer onboarding" jobs, red on both OSes since then.

The packer now walks ProjectReference from the public roots (GameCult.Mesh,
GameCult.Networking.WebSockets) and packs the whole closure. The expected
package names come from MSBuild's PackageId and Version for each project,
since GameCult.Math carries its own identity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 16:02:08 +02:00
Meta Vens
fee55e89c5 Check the CultMath release gate against the type-definition table
scripts/check-cultmath-types.cs reads the assembly with System.Reflection.Metadata
and reports which named types are not public top-level CultMath types. The old
NUL-delimited string search passed an appended string or a member named like the
type, and failed a real type whose name is tail-shared in the string heap.
Prerelease and range versions now get a clear message instead of a raw
System.Version error.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 18:31:16 +02:00