Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
"test:smoke:observability": "node scripts/smoke-observability-traces.mjs",
"test:smoke:browser:install": "playwright install chromium",
"test:smoke:browser": "node scripts/smoke-ui-browser.mjs",
"test:ci": "git diff --check && npm run actionlint && npm run db:migrations:check && npm run db:schema-drift:check && npm run selfhost:env-reference:check && npm run selfhost:validate-observability && npm run cf-typegen:check && npm run typecheck && npm run test:coverage && npm run test:engine-parity && npm run test:workers && npm run build:mcp && npm run test:mcp-pack && npm run build:miner && npm run test:miner-pack && npm run rees:test && npm run ui:openapi:check && npm run ui:openapi:settings-parity && npm run ui:version-audit && npm run docs:drift-check && npm run manifest:drift-check && npm run command-reference:check && npm run ui:lint && npm run ui:typecheck && npm run ui:test && npm run ui:build",
"test:ci": "git diff --check && npm run actionlint && npm run db:migrations:check && npm run db:schema-drift:check && npm run selfhost:env-reference:check && npm run selfhost:validate-observability && npm run cf-typegen:check && npm run typecheck && npm run test:coverage && npm run test:engine-parity && npm run test --workspace @jsonbored/gittensory-engine && npm run test:workers && npm run build:mcp && npm run test:mcp-pack && npm run build:miner && npm run test:miner-pack && npm run rees:test && npm run ui:openapi:check && npm run ui:openapi:settings-parity && npm run ui:version-audit && npm run docs:drift-check && npm run manifest:drift-check && npm run command-reference:check && npm run ui:lint && npm run ui:typecheck && npm run ui:test && npm run ui:build",
"test:release": "npm run test:ci && npm run changelog:check",
"test:release:mcp": "npm run test:ci && npm run changelog:check:mcp",
"test:watch": "vitest",
Expand Down
1 change: 1 addition & 0 deletions packages/gittensory-engine/test/ai-policy-map.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ test("renderAiPolicyFatigueMarkdown escapes summaries and policy source fields",

test("resolveAiPolicyFatigueVerdict is byte-stable for the same metadata", () => {
const input = {
repoFullName: "JSONbored/gittensory",
now: NOW,
docs: { aiUsage: null, contributing: "Normal guide." },
pullRequests: [aiPr({ id: "a" }), aiPr({ id: "b" })],
Expand Down
29 changes: 14 additions & 15 deletions packages/gittensory-engine/test/duplicate-winner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,13 @@ test("isDuplicateClusterWinnerByClaim: fails closed on an invalid claim timestam
);
});

test("isDuplicateClusterWinnerByClaim createdAt precedence: elects the PR GitHub says opened first, even when observed later", () => {
// #3956 (anti-backdating): createdAt is deliberately NOT part of the election (see
// prPrecedesSibling's doc comment in src/duplicate-winner.ts) -- an older PR could otherwise steal
// winner credit by editing its body to claim the linked issue later. This block replaces three
// stale "createdAt precedence" tests that asserted the OLD, since-removed createdAt-based ordering
// (root test/unit/duplicate-winner.test.ts was updated for the same fix in #3956; this package's
// own parallel test file wasn't, because it isn't part of test:ci and nobody noticed).
test("isDuplicateClusterWinnerByClaim: ignores createdAt even when present on both sides, decides purely by claim time", () => {
const openedFirstButClaimedLater = {
number: 9,
createdAt: "2026-01-01T00:00:00Z",
Expand All @@ -65,22 +71,15 @@ test("isDuplicateClusterWinnerByClaim createdAt precedence: elects the PR GitHub
createdAt: "2026-01-02T00:00:00Z",
linkedIssueClaimedAt: "2026-01-01T00:00:00Z",
};
assert.equal(isDuplicateClusterWinnerByClaim(openedFirstButClaimedLater, [openedSecondButClaimedFirst]), true);
assert.equal(isDuplicateClusterWinnerByClaim(openedSecondButClaimedFirst, [openedFirstButClaimedLater]), false);
// openedSecondButClaimedFirst claimed earlier, so it wins despite its later createdAt.
assert.equal(isDuplicateClusterWinnerByClaim(openedFirstButClaimedLater, [openedSecondButClaimedFirst]), false);
assert.equal(isDuplicateClusterWinnerByClaim(openedSecondButClaimedFirst, [openedFirstButClaimedLater]), true);
});

test("isDuplicateClusterWinnerByClaim createdAt precedence: falls back to claim-time when only one side has a valid createdAt", () => {
const modern = { number: 9, createdAt: "2026-01-01T00:00:00Z", linkedIssueClaimedAt: "2026-01-05T00:00:00Z" };
const legacy = { number: 3, linkedIssueClaimedAt: "2026-01-02T00:00:00Z" };
// Neither side has BOTH createdAt values, so this falls back to claim-time comparison: modern claimed later, so legacy wins.
assert.equal(isDuplicateClusterWinnerByClaim(legacy, [modern]), true);
assert.equal(isDuplicateClusterWinnerByClaim(modern, [legacy]), false);
});

test("isDuplicateClusterWinnerByClaim createdAt precedence: ties break by PR number", () => {
const a = { number: 3, createdAt: "2026-01-01T00:00:00Z" };
const b = { number: 9, createdAt: "2026-01-01T00:00:00Z" };
assert.equal(isDuplicateClusterWinnerByClaim(a, [b]), true);
test("isDuplicateClusterWinnerByClaim: still fails closed when createdAt is present but claim timing is missing", () => {
const a = { number: 12, createdAt: "2026-06-29T10:00:00.000Z" };
const b = { number: 13, createdAt: "2026-06-29T10:05:00.000Z" };
assert.equal(isDuplicateClusterWinnerByClaim(a, [b]), false);
assert.equal(isDuplicateClusterWinnerByClaim(b, [a]), false);
});

Expand Down
118 changes: 64 additions & 54 deletions packages/gittensory-engine/test/gate-verdict-calibration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
resolveGateVerdictCalibrationConfig,
scoreObjectiveAnchor,
} from "../dist/index.js";
import type { GateVerdictCalibrationIngestion } from "../dist/index.js";

test("barrel: exports structured gate-verdict calibration APIs (#3015)", () => {
assert.equal(typeof resolveGateVerdictCalibrationConfig, "function");
Expand Down Expand Up @@ -475,35 +476,41 @@ test("renderGateVerdictCalibrationAuditMarkdown escapes markdown controls and co
});

test("computeGateVerdictCompositeCalibrationScore sanitizes pre-ingested audit rows", () => {
// Deliberately malformed/untrusted input (extra rawReviewText/privateMetadata/trustScore fields
// an external, unsanitized source could send) -- the cast simulates data that arrived outside
// TypeScript's type system (e.g. JSON.parse of a webhook payload), which is exactly what
// isGateVerdictCalibrationIngestion + sanitizeGateVerdictCalibrationIngestion exist to validate
// and strip at runtime.
const gateVerdicts = {
accepted: [
{
repoFullName: "JSONbored/Gittensory",
replayRunId: " replay-13 ",
gateRunId: "gate-13",
observedAt: "not an ISO timestamp",
score: 1,
dimensions: [
{ dimension: "correctness", outcome: "pass", confidence: 1, rawReviewText: "private" },
{ dimension: "trustScore", outcome: "pass", confidence: 1, privateMetadata: "private" },
],
rawReviewText: "private",
trustScore: 99,
},
],
rejected: [
{
repoFullName: "JSONbored/Gittensory",
replayRunId: "replay-13",
gateRunId: "gate-13",
reason: "not_opted_in",
privateMetadata: "private",
},
],
} as unknown as GateVerdictCalibrationIngestion;
const result = computeGateVerdictCompositeCalibrationScore({
objectiveAnchor: 0.5,
pairwise: 0.5,
gateVerdicts: {
accepted: [
{
repoFullName: "JSONbored/Gittensory",
replayRunId: " replay-13 ",
gateRunId: "gate-13",
observedAt: "not an ISO timestamp",
score: 1,
dimensions: [
{ dimension: "correctness", outcome: "pass", confidence: 1, rawReviewText: "private" },
{ dimension: "trustScore", outcome: "pass", confidence: 1, privateMetadata: "private" },
],
rawReviewText: "private",
trustScore: 99,
},
],
rejected: [
{
repoFullName: "JSONbored/Gittensory",
replayRunId: "replay-13",
gateRunId: "gate-13",
reason: "not_opted_in",
privateMetadata: "private",
},
],
},
gateVerdicts,
});
const serialized = JSON.stringify(result);

Expand Down Expand Up @@ -533,37 +540,40 @@ test("computeGateVerdictCompositeCalibrationScore sanitizes pre-ingested audit r
});

test("computeGateVerdictCompositeCalibrationScore ignores malformed pre-ingested rows", () => {
// Same as above: deliberately invalid enum values ("trustScore" as a dimension, "private" as an
// outcome, "privateMetadata" as a rejection reason) simulating untrusted external input.
const gateVerdicts = {
accepted: [
{
repoFullName: "not a repo",
replayRunId: "replay-14",
gateRunId: "gate-14",
observedAt: "2026-07-04T17:00:00.000Z",
score: 1,
dimensions: [{ dimension: "correctness", outcome: "pass", confidence: 1 }],
},
{
repoFullName: "jsonbored/gittensory",
replayRunId: "replay-14",
gateRunId: "gate-14",
observedAt: "2026-07-04T17:00:00.000Z",
score: 1,
dimensions: [{ dimension: "rawReviewText", outcome: "private", confidence: 1 }],
},
],
rejected: [
{
repoFullName: "jsonbored/gittensory",
replayRunId: "replay-14",
gateRunId: "gate-14",
reason: "privateMetadata",
},
],
} as unknown as GateVerdictCalibrationIngestion;
const result = computeGateVerdictCompositeCalibrationScore({
objectiveAnchor: 0.5,
pairwise: 0.5,
gateVerdicts: {
accepted: [
{
repoFullName: "not a repo",
replayRunId: "replay-14",
gateRunId: "gate-14",
observedAt: "2026-07-04T17:00:00.000Z",
score: 1,
dimensions: [{ dimension: "correctness", outcome: "pass", confidence: 1 }],
},
{
repoFullName: "jsonbored/gittensory",
replayRunId: "replay-14",
gateRunId: "gate-14",
observedAt: "2026-07-04T17:00:00.000Z",
score: 1,
dimensions: [{ dimension: "rawReviewText", outcome: "private", confidence: 1 }],
},
],
rejected: [
{
repoFullName: "jsonbored/gittensory",
replayRunId: "replay-14",
gateRunId: "gate-14",
reason: "privateMetadata",
},
],
},
gateVerdicts,
});

assert.equal(result.structuredGateVerdictScore, null);
Expand Down
Loading