Make cultnet-ts a self-contained package again; revert fa00f3f's rootDir widen

REC-032 Soul finding: dist/contracts.js required "../../../contracts/cultnet/...",
escaping the cultnet-ts package tree entirely. That breaks every installed
consumer: the two-runtime sample script (packs and installs cultnet-ts into a
clean consumer), test-typescript-package-closure.mjs, and Heimdall's pnpm copy
of cultnet-ts (honours `files`, would 404 on its next vendor/CultLib bump).
Only Stonks (file: symlink into the live checkout) happened to still work.

Fix: keep CultLib/contracts/cultnet as the only tracked source, but have
tools/generate-swarm-contracts.mjs wipe and re-copy it into a package-local,
gitignored packages/cultnet-ts/contracts/cultnet/ every time it runs (build,
typecheck, test, test:interop, prepack, the two-runtime script, and Heimdral's
`npm run build` all already invoke it). src/contracts.ts and the swarm-contracts
manifest now import that package-local copy ("../contracts/cultnet/...") instead
of reaching three directories up. package.json gets back `files: ["dist",
"contracts"]` and `prepack` so a packed tarball carries its own schema copy.

Also revert fa00f3f's tsconfig.test.json rootDir widen ("." -> "../..") and the
matching test-script/dist-test path changes and __dirname-relative recomputation
in cultnet-interop.test.ts and runtime-presence-health.test.ts: that widening
was working around dist-test not receiving a copy of the (now out-of-package)
contracts, but nothing in this repo actually needs the wider rootDir once the
schemas are package-local again, and the widened paths never matched what CI's
interop lanes and package.json's own dist-test paths expect --
packages/cultnet-ts/dist-test/test/interop/cultnet-interop.test.js, not
.../dist-test/packages/cultnet-ts/test/interop/.... PR #3 CI run 34766892424 on
7d3a3dc failed the first interop lane on exactly this missing-file defect.
cultnet-interop.test.ts's interopSchemaPath already resolved correctly once
cultNetTsRoot was reverted (it was never touched by fa00f3f) and continues to
point at the canonical CultLib/contracts/cultnet/interop copy, which is fine
since it is only read by the spawned non-TS peer processes, not required() by
this package. The cultmesh-ts shard-catalog $id lookup fix from fa00f3f
(cultnet.shard_catalog_request.v0 -> the CultLib contracts URL id) is unrelated
to the rootDir defect and is left as is.

REC-032, Soul redirect on branch claude/rec-032-cultnet-contracts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-13 18:03:29 +02:00
commit 61549aa90b
9 changed files with 64 additions and 45 deletions

View file

@ -2,3 +2,6 @@ node_modules/
dist/
dist-test/
*.tgz
# Mirrored from CultLib/contracts/cultnet by tools/generate-swarm-contracts.mjs
# (REC-032). Not tracked: CultLib/contracts/cultnet is the only source.
contracts/

View file

@ -17,14 +17,16 @@
}
},
"files": [
"dist"
"dist",
"contracts"
],
"scripts": {
"contracts:generate": "node tools/generate-swarm-contracts.mjs",
"build": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json",
"prepack": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json",
"typecheck": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json --pretty false",
"test": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test dist-test/packages/cultnet-ts/test/*.test.js",
"test:interop": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test --test-force-exit dist-test/packages/cultnet-ts/test/interop/*.test.js"
"test": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test dist-test/test/*.test.js",
"test:interop": "node tools/generate-swarm-contracts.mjs && node ../../node_modules/typescript/bin/tsc -p tsconfig.json && node ../../node_modules/typescript/bin/tsc -p tsconfig.test.json && node --test --test-force-exit dist-test/test/interop/*.test.js"
},
"keywords": [
"messagepack",

View file

@ -1,38 +1,38 @@
import Ajv2020, { type ValidateFunction } from "ajv/dist/2020";
import documentRecordSchema from "../../../contracts/cultnet/cultnet.document-record.schema.json";
import helloSchema from "../../../contracts/cultnet/cultnet.hello.schema.json";
import loginSchema from "../../../contracts/cultnet/cultnet.login.schema.json";
import registerSchema from "../../../contracts/cultnet/cultnet.register.schema.json";
import verifySchema from "../../../contracts/cultnet/cultnet.verify.schema.json";
import loginSuccessSchema from "../../../contracts/cultnet/cultnet.login-success.schema.json";
import errorSchema from "../../../contracts/cultnet/cultnet.error.schema.json";
import sampleChangeNameSchema from "../../../contracts/cultnet/cultnet.sample-change-name.schema.json";
import sampleChatSchema from "../../../contracts/cultnet/cultnet.sample-chat.schema.json";
import documentPutSchema from "../../../contracts/cultnet/cultnet.document-put.schema.json";
import documentDeleteSchema from "../../../contracts/cultnet/cultnet.document-delete.schema.json";
import rawDocumentRecordSchema from "../../../contracts/cultnet/cultnet.raw-document-record.schema.json";
import documentPutRawSchema from "../../../contracts/cultnet/cultnet.document-put-raw.schema.json";
import documentMutationContractSchema from "../../../contracts/cultnet/cultnet.document-mutation-contract.schema.json";
import transportProfileSchema from "../../../contracts/cultnet/cultnet.transport-profile.schema.json";
import snapshotRequestSchema from "../../../contracts/cultnet/cultnet.snapshot-request.schema.json";
import snapshotResponseSchema from "../../../contracts/cultnet/cultnet.snapshot-response.schema.json";
import snapshotResponseRawSchema from "../../../contracts/cultnet/cultnet.snapshot-response-raw.schema.json";
import databaseSubscribeSchema from "../../../contracts/cultnet/cultnet.database-subscribe.schema.json";
import databaseUnsubscribeSchema from "../../../contracts/cultnet/cultnet.database-unsubscribe.schema.json";
import databaseChangeRawSchema from "../../../contracts/cultnet/cultnet.database-change-raw.schema.json";
import schemaDescriptorSchema from "../../../contracts/cultnet/cultnet.schema-descriptor.schema.json";
import schemaCatalogRequestSchema from "../../../contracts/cultnet/cultnet.schema-catalog-request.schema.json";
import schemaCatalogResponseSchema from "../../../contracts/cultnet/cultnet.schema-catalog-response.schema.json";
import shardCatalogRequestSchema from "../../../contracts/cultnet/cultnet.shard-catalog-request.schema.json";
import shardCatalogResponseSchema from "../../../contracts/cultnet/cultnet.shard-catalog-response.schema.json";
import operationRequestSchema from "../../../contracts/cultnet/cultnet.operation-request.schema.json";
import operationResponseSchema from "../../../contracts/cultnet/cultnet.operation-response.schema.json";
import verseCatalogRequestSchema from "../../../contracts/cultnet/cultmesh.verse-catalog-request.schema.json";
import verseCatalogResponseSchema from "../../../contracts/cultnet/cultmesh.verse-catalog-response.schema.json";
import sessionOpenSchema from "../../../contracts/cultnet/cultmesh.session-open.schema.json";
import sessionAcceptedSchema from "../../../contracts/cultnet/cultmesh.session-accepted.schema.json";
import ghostlightAgentStateSchema from "../../../contracts/cultnet/ghostlight.agent-state.schema.json";
import documentRecordSchema from "../contracts/cultnet/cultnet.document-record.schema.json";
import helloSchema from "../contracts/cultnet/cultnet.hello.schema.json";
import loginSchema from "../contracts/cultnet/cultnet.login.schema.json";
import registerSchema from "../contracts/cultnet/cultnet.register.schema.json";
import verifySchema from "../contracts/cultnet/cultnet.verify.schema.json";
import loginSuccessSchema from "../contracts/cultnet/cultnet.login-success.schema.json";
import errorSchema from "../contracts/cultnet/cultnet.error.schema.json";
import sampleChangeNameSchema from "../contracts/cultnet/cultnet.sample-change-name.schema.json";
import sampleChatSchema from "../contracts/cultnet/cultnet.sample-chat.schema.json";
import documentPutSchema from "../contracts/cultnet/cultnet.document-put.schema.json";
import documentDeleteSchema from "../contracts/cultnet/cultnet.document-delete.schema.json";
import rawDocumentRecordSchema from "../contracts/cultnet/cultnet.raw-document-record.schema.json";
import documentPutRawSchema from "../contracts/cultnet/cultnet.document-put-raw.schema.json";
import documentMutationContractSchema from "../contracts/cultnet/cultnet.document-mutation-contract.schema.json";
import transportProfileSchema from "../contracts/cultnet/cultnet.transport-profile.schema.json";
import snapshotRequestSchema from "../contracts/cultnet/cultnet.snapshot-request.schema.json";
import snapshotResponseSchema from "../contracts/cultnet/cultnet.snapshot-response.schema.json";
import snapshotResponseRawSchema from "../contracts/cultnet/cultnet.snapshot-response-raw.schema.json";
import databaseSubscribeSchema from "../contracts/cultnet/cultnet.database-subscribe.schema.json";
import databaseUnsubscribeSchema from "../contracts/cultnet/cultnet.database-unsubscribe.schema.json";
import databaseChangeRawSchema from "../contracts/cultnet/cultnet.database-change-raw.schema.json";
import schemaDescriptorSchema from "../contracts/cultnet/cultnet.schema-descriptor.schema.json";
import schemaCatalogRequestSchema from "../contracts/cultnet/cultnet.schema-catalog-request.schema.json";
import schemaCatalogResponseSchema from "../contracts/cultnet/cultnet.schema-catalog-response.schema.json";
import shardCatalogRequestSchema from "../contracts/cultnet/cultnet.shard-catalog-request.schema.json";
import shardCatalogResponseSchema from "../contracts/cultnet/cultnet.shard-catalog-response.schema.json";
import operationRequestSchema from "../contracts/cultnet/cultnet.operation-request.schema.json";
import operationResponseSchema from "../contracts/cultnet/cultnet.operation-response.schema.json";
import verseCatalogRequestSchema from "../contracts/cultnet/cultmesh.verse-catalog-request.schema.json";
import verseCatalogResponseSchema from "../contracts/cultnet/cultmesh.verse-catalog-response.schema.json";
import sessionOpenSchema from "../contracts/cultnet/cultmesh.session-open.schema.json";
import sessionAcceptedSchema from "../contracts/cultnet/cultmesh.session-accepted.schema.json";
import ghostlightAgentStateSchema from "../contracts/cultnet/ghostlight.agent-state.schema.json";
export type CultNetWireContract = "cultnet.schema.v0" | "gamecult.networking.v0";

View file

@ -1,5 +1,5 @@
import { defineJsonSchemaContract } from "../json-schema-contract";
import ghostlightAgentStateGeneratedContractSchema from "../../../../contracts/cultnet/ghostlight.agent-state.schema.json";
import ghostlightAgentStateGeneratedContractSchema from "../../contracts/cultnet/ghostlight.agent-state.schema.json";
// Generated by tools/generate-swarm-contracts.mjs. Do not hand-edit this file unless you enjoy losing arguments with a machine.

View file

@ -21,7 +21,7 @@ const execFileAsync = promisify(execFile);
const cargoCommand = process.env.CARGO ?? (process.platform === "win32" ? join(homedir(), ".cargo", "bin", "cargo.exe") : "cargo");
const dotnetCommand = process.env.DOTNET ?? (process.platform === "win32" ? join("C:", "Program Files", "dotnet", "dotnet.exe") : "dotnet");
const pythonCommand = process.env.PYTHON ?? resolvePythonCommand();
const cultNetTsRoot = resolve(__dirname, "../../../../..");
const cultNetTsRoot = resolve(__dirname, "../../..");
const cultLibRoot = findAncestor(cultNetTsRoot, "CultLib.sln") ?? resolve(cultNetTsRoot, "..", "CultLib");
const cultcachePyRoot = resolve(cultLibRoot, "packages", "cultcache-py");
const cultcachePySrc = ["cultcache-py", "cultnet-py", "cultmesh-py"]

View file

@ -26,7 +26,7 @@ import {
// are generated output and must have exactly one home.
const VECTORS = JSON.parse(
readFileSync(
join(__dirname, "..", "..", "..", "..", "test", "fixtures", "runtime-presence-vectors.json"),
join(__dirname, "..", "..", "test", "fixtures", "runtime-presence-vectors.json"),
"utf8",
),
) as { proof: string; signed: string };

View file

@ -1,4 +1,4 @@
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
@ -6,9 +6,23 @@ import { compile } from "json-schema-to-typescript";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const repoRoot = path.resolve(__dirname, "..");
const manifestPath = path.join(repoRoot, "tools", "swarm-contracts.manifest.json");
const outputPath = path.join(repoRoot, "src", "generated", "swarm-contracts.generated.ts");
const packageRoot = path.resolve(__dirname, "..");
const cultLibRoot = path.resolve(packageRoot, "..", "..");
const manifestPath = path.join(packageRoot, "tools", "swarm-contracts.manifest.json");
const outputPath = path.join(packageRoot, "src", "generated", "swarm-contracts.generated.ts");
// CultLib/contracts/cultnet is the single source of CultNet schema contracts
// (REC-032). cultnet-ts is a standalone npm package (published or vendored by
// Heimdall independent of the CultLib checkout), so it cannot import schemas
// that live outside its own package tree. Mirror the canonical contracts into
// a package-local, gitignored copy every time this generator runs, so `dist`
// and `contracts` both ship self-contained. Wipe first: a stale local file
// left behind after a schema is deleted upstream must not survive as drift.
const sourceContractsDir = path.join(cultLibRoot, "contracts", "cultnet");
const localContractsDir = path.join(packageRoot, "contracts", "cultnet");
await rm(localContractsDir, { recursive: true, force: true });
await mkdir(path.dirname(localContractsDir), { recursive: true });
await cp(sourceContractsDir, localContractsDir, { recursive: true });
/**
* @typedef {{

View file

@ -1,7 +1,7 @@
{
"contracts": [
{
"schemaPath": "../../../contracts/cultnet/ghostlight.agent-state.schema.json",
"schemaPath": "../contracts/cultnet/ghostlight.agent-state.schema.json",
"typeName": "GhostlightAgentStateShape",
"contractExportName": "ghostlightAgentStateGeneratedContract",
"validateExportName": "validateGhostlightAgentStateGenerated",

View file

@ -1,7 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "../..",
"rootDir": ".",
"outDir": "dist-test",
"declaration": false,
"declarationMap": false