168 lines
6.1 KiB
JavaScript
168 lines
6.1 KiB
JavaScript
import { describe, it, expect } from "vitest";
|
|
import { createHash } from "node:crypto";
|
|
|
|
/**
|
|
* TEST-ONLY helpers for Experiment 54I.
|
|
* NOT exported into production.
|
|
* These reproduce the smallest possible identity
|
|
* mechanism needed to test interpretation lineage.
|
|
*/
|
|
|
|
/**
|
|
* Deterministic source record (identical to Exp 54H's helper).
|
|
*/
|
|
function createSourceRecord(rawInput) {
|
|
const verbatimText = String(rawInput);
|
|
return {
|
|
sourceId: createHash("sha256")
|
|
.update(verbatimText, "utf8")
|
|
.digest("hex"),
|
|
sourceType: "user_input",
|
|
verbatimText,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Deterministic interpretation record.
|
|
* The interpretationId is derived from sourceId + exact interpretation text.
|
|
*/
|
|
function createInterpretationRecord(sourceId, interpretationText) {
|
|
const combined = sourceId + "|" + interpretationText;
|
|
return {
|
|
interpretationId: createHash("sha256")
|
|
.update(combined, "utf8")
|
|
.digest("hex"),
|
|
sourceId,
|
|
interpretationText,
|
|
};
|
|
}
|
|
|
|
// Fixed inputs for Experiment 54I
|
|
|
|
const RAW_USER_INPUT =
|
|
"Revenue is down. I think pricing may be part of the problem, but I am not sure.";
|
|
|
|
const INTERPRETATION_A_TEXT =
|
|
"Pricing may be contributing materially to the revenue decline.";
|
|
|
|
const INTERPRETATION_B_TEXT =
|
|
"The revenue decline may have causes other than pricing, and pricing has not yet been established as the main problem.";
|
|
|
|
describe("Source -> interpretation lineage (Exp 54I - test-only)", () => {
|
|
let source;
|
|
let interpretationA;
|
|
let interpretationB;
|
|
|
|
beforeEach(() => {
|
|
source = createSourceRecord(RAW_USER_INPUT);
|
|
interpretationA = createInterpretationRecord(source.sourceId, INTERPRETATION_A_TEXT);
|
|
interpretationB = createInterpretationRecord(source.sourceId, INTERPRETATION_B_TEXT);
|
|
});
|
|
|
|
it("Test 1: the source retains the exact verbatim user input", () => {
|
|
expect(source.verbatimText).toBe(RAW_USER_INPUT);
|
|
});
|
|
|
|
it("Test 2: Interpretation A references the source's exact sourceId", () => {
|
|
expect(interpretationA.sourceId).toBe(source.sourceId);
|
|
});
|
|
|
|
it("Test 3: Interpretation B references the same exact sourceId", () => {
|
|
expect(interpretationB.sourceId).toBe(source.sourceId);
|
|
});
|
|
|
|
it("Test 4: A and B have different interpretationId values", () => {
|
|
expect(interpretationA.interpretationId).not.toBe(interpretationB.interpretationId);
|
|
});
|
|
|
|
it("Test 5: recreating A produces exactly the same interpretationId", () => {
|
|
const a2 = createInterpretationRecord(source.sourceId, INTERPRETATION_A_TEXT);
|
|
expect(a2.interpretationId).toBe(interpretationA.interpretationId);
|
|
});
|
|
|
|
it("Test 6: recreating B produces exactly the same interpretationId", () => {
|
|
const b2 = createInterpretationRecord(source.sourceId, INTERPRETATION_B_TEXT);
|
|
expect(b2.interpretationId).toBe(interpretationB.interpretationId);
|
|
});
|
|
|
|
it("Test 7: changing interpretation text changes the interpretation ID", () => {
|
|
const aVariant = createInterpretationRecord(source.sourceId, INTERPRETATION_A_TEXT + " (nuanced)");
|
|
expect(aVariant.interpretationId).not.toBe(interpretationA.interpretationId);
|
|
});
|
|
|
|
it("Test 8: neither interpretation mutates the source record", () => {
|
|
const originalVerbatim = source.verbatimText;
|
|
const originalSourceId = source.sourceId;
|
|
const originalKeys = [...Object.keys(source)];
|
|
expect(source.verbatimText).toBe(originalVerbatim);
|
|
expect(source.sourceId).toBe(originalSourceId);
|
|
expect(Object.keys(source)).toEqual(originalKeys);
|
|
});
|
|
|
|
it("Test 9: creating one interpretation does not mutate the other", () => {
|
|
const aSnapshot = { interpretationId: interpretationA.interpretationId };
|
|
const freshSource = createSourceRecord(RAW_USER_INPUT);
|
|
const freshB = createInterpretationRecord(freshSource.sourceId, INTERPRETATION_B_TEXT);
|
|
expect(interpretationA.interpretationId).toBe(aSnapshot.interpretationId);
|
|
});
|
|
|
|
it("Test 10: a deterministic consumer can identify one shared source and two distinct interpretations", () => {
|
|
const sharedSourceIds = new Set([
|
|
interpretationA.sourceId,
|
|
interpretationB.sourceId,
|
|
]);
|
|
expect(sharedSourceIds.size).toBe(1);
|
|
|
|
const interpretationIds = new Set([
|
|
interpretationA.interpretationId,
|
|
interpretationB.interpretationId,
|
|
]);
|
|
expect(interpretationIds.size).toBe(2);
|
|
|
|
expect(source.sourceId).toBe(interpretationA.sourceId);
|
|
expect(source.sourceId).toBe(interpretationB.sourceId);
|
|
});
|
|
|
|
it("Test 11: no semantic judgement chooses A over B", () => {
|
|
const aKeys = Object.keys(interpretationA);
|
|
const bKeys = Object.keys(interpretationB);
|
|
expect(aKeys).toEqual(["interpretationId", "sourceId", "interpretationText"]);
|
|
expect(bKeys).toEqual(["interpretationId", "sourceId", "interpretationText"]);
|
|
expect(aKeys).toEqual(bKeys);
|
|
});
|
|
|
|
it("Test 12: no LLM or network call occurs", () => {
|
|
expect(true).toBe(true);
|
|
});
|
|
|
|
it("Cross-check: different source produces different interpretationId for the same text", () => {
|
|
const otherSource = createSourceRecord("Another input entirely.");
|
|
const aFromOther = createInterpretationRecord(otherSource.sourceId, INTERPRETATION_A_TEXT);
|
|
expect(aFromOther.interpretationId).not.toBe(interpretationA.interpretationId);
|
|
});
|
|
|
|
it("Source record is unchanged after multiple interpretation creations", () => {
|
|
const sourceBefore = JSON.parse(JSON.stringify(source));
|
|
for (let i = 0; i < 10; i++) {
|
|
createInterpretationRecord(source.sourceId, "Variant " + i);
|
|
}
|
|
expect(JSON.stringify(source)).toBe(JSON.stringify(sourceBefore));
|
|
});
|
|
|
|
it("Test 10b: a deterministic consumer traces both interpretations to the exact same verbatim source", () => {
|
|
const lineage = {
|
|
sourceId: source.sourceId,
|
|
verbatimText: source.verbatimText,
|
|
interpretations: [interpretationA, interpretationB].map((i) => ({
|
|
interpretationId: i.interpretationId,
|
|
interpretationText: i.interpretationText,
|
|
sharedSourceId: i.sourceId,
|
|
})),
|
|
};
|
|
expect(lineage.verbatimText).toBe(RAW_USER_INPUT);
|
|
expect(
|
|
lineage.interpretations.every((i) => i.sharedSourceId === lineage.sourceId)
|
|
).toBe(true);
|
|
});
|
|
});
|