From 857dcd8025271b1caaef089ee74950e65c7f099f Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Fri, 3 Jul 2026 16:27:38 -0700 Subject: [PATCH] fix(engine): restore missing export brace and drop unresolvable node:util import Two independently-merged PRs (#2787, #2795) landed a build-breaking state on main: a spliced-in export block ate the opening brace of the adjacent contributor-fit re-export (TS1005/TS1109), and governor-ledger.ts imports node:util under this package's types:[] tsconfig, which never resolves the module's type declarations. Both broke `tsc --noEmit` and `build:miner` for every contributor. Replaced isDeepStrictEqual with a small local structural-equality check scoped to the JSON-safe values this one call site actually compares. --- .../gittensory-engine/src/governor-ledger.ts | 25 ++++++++++++++++--- packages/gittensory-engine/src/index.ts | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/gittensory-engine/src/governor-ledger.ts b/packages/gittensory-engine/src/governor-ledger.ts index aa7f449090..374542a26b 100644 --- a/packages/gittensory-engine/src/governor-ledger.ts +++ b/packages/gittensory-engine/src/governor-ledger.ts @@ -1,5 +1,3 @@ -import { isDeepStrictEqual } from "node:util"; - /** Immutable governor decision vocabulary — unknown values fail closed before insert. */ export const GOVERNOR_LEDGER_EVENT_TYPES = Object.freeze([ "allowed", @@ -46,6 +44,27 @@ function normalizeOptionalRepoFullName(repoFullName: unknown): string | null { return `${owner}/${repo}`; } +// Structural equality between a JSON.parse() result and the plain object it was stringified from. One side is +// always JSON-safe (parsed from JSON text); this only needs to compare plain objects/arrays/primitives, not the +// full generality of node:util's isDeepStrictEqual (no Dates/RegExp/Maps/getters/symbols to worry about) — this +// package's tsconfig deliberately sets `types: []` (no Node ambient types leak into its public .d.ts surface), +// so importing "node:util" here isn't viable; a small local check avoids that entirely. +function jsonRoundTripEqual(a: unknown, b: unknown): boolean { + if (a === b) return true; + if (typeof a !== typeof b || a === null || b === null) return false; + if (typeof a !== "object") return false; + const aIsArray = Array.isArray(a); + if (aIsArray !== Array.isArray(b)) return false; + if (aIsArray) { + const bArr = b as unknown[]; + const aArr = a as unknown[]; + return aArr.length === bArr.length && aArr.every((value, index) => jsonRoundTripEqual(value, bArr[index])); + } + const aKeys = Object.keys(a as object); + const bRecord = b as Record; + return aKeys.length === Object.keys(bRecord).length && aKeys.every((key) => Object.hasOwn(bRecord, key) && jsonRoundTripEqual((a as Record)[key], bRecord[key])); +} + function serializePayload(payload: unknown): string { if (payload === undefined) return "{}"; if (payload === null || typeof payload !== "object" || Array.isArray(payload)) { @@ -57,7 +76,7 @@ function serializePayload(payload: unknown): string { } catch { throw new Error("invalid_payload"); } - if (!isDeepStrictEqual(JSON.parse(json), payload)) { + if (!jsonRoundTripEqual(JSON.parse(json), payload)) { throw new Error("invalid_payload"); } return json; diff --git a/packages/gittensory-engine/src/index.ts b/packages/gittensory-engine/src/index.ts index 4adbe14d99..43b5f0cf32 100644 --- a/packages/gittensory-engine/src/index.ts +++ b/packages/gittensory-engine/src/index.ts @@ -49,6 +49,7 @@ export { computeLaneFit, type GoalModelInput, } from "./goal-model.js"; +export { classifyContributorFit, type ContributorFit, type ContributorFitCheck,