experiment: test interpretation lineage to user source
This commit is contained in:
@@ -129,8 +129,8 @@ Answer before continuing:
|
||||
|
||||
---
|
||||
|
||||
*Created by Experiment 34. Updated by Experiments 38–53, 54A–54H. Branch: `feature/user-workspace-ux-v0.7`.*
|
||||
*Created by Experiment 34. Updated by Experiments 38–53, 54A–54I. Branch: `feature/user-workspace-ux-v0.7`.*
|
||||
|
||||
### Return-to-Work Note (Experiment 54H)
|
||||
### Return-to-Work Note (Experiment 54I)
|
||||
|
||||
Experiments 54F and 54G established that current evidence metadata cannot prove provenance: `evidenceType` is model classification, not production-code origin. Experiment 54H tested whether trustworthy source identity can instead begin deterministically from the raw user input before any LLM interpretation occurs. Verbatim text preservation and stable identity both work — SHA-256 of raw input produces deterministic `sourceId` without semantic processing. Source identity is established; claim provenance and graph-node linkage remain explicitly untested. No production code changed. Branch: `feature/user-workspace-ux-v0.7`. First file to inspect: `tests/reconstruction/deterministic-source-record.test.js`.
|
||||
Experiment 54H established deterministic identity for exact user input via SHA-256 hashing of verbatim text before any LLM interpretation. Experiment 54I tested whether two different interpretations of the same raw source can remain linked to that source while staying separately identifiable — neither was chosen as the winner; no production code changed. Both retained shared source lineage and remained independently deterministically referenceable. Interpretation quality, correctness, and downstream-question effects remain untested. Branch: `feature/user-workspace-ux-v0.7`. First file to inspect when resuming: `tests/reconstruction/source-interpretation-lineage.test.js`.
|
||||
|
||||
@@ -5919,4 +5919,162 @@ This experiment establishes **source identity** — answering "what exact materi
|
||||
|
||||
### Status
|
||||
|
||||
**Pending Rob's review.** Deterministic source identity established. No production code changed. Branch: `feature/user-workspace-ux-v0.7`. First file to inspect: `tests/reconstruction/deterministic-source-record.test.js`.
|
||||
**Closed.** Bounded conclusion: deterministic source identity is feasible before LLM interpretation; identical tested text produces stable identity; source identity does not establish claim or graph provenance. No production code changed. Branch: `feature/user-workspace-ux-v0.7`. First file to inspect: `tests/reconstruction/deterministic-source-record.test.js`.
|
||||
|
||||
## Experiment 54I — Can Two Different Interpretations Stay Anchored to the Same User Source? (2026-08-07)
|
||||
|
||||
### Objective
|
||||
|
||||
Take the deterministic source identity proved in Experiment 54H and test the next smallest step:
|
||||
|
||||
> **Can two different interpretations of the exact same user input remain separate while both retaining an explicit link back to that same source?**
|
||||
|
||||
This experiment deliberately does not decide which interpretation is better. It tests whether the reasoning system could preserve one source, multiple interpretations, and clear lineage back to that source without silently replacing the original input or collapsing the interpretations together. This is a passive, test-only experiment.
|
||||
|
||||
### Hypothesis
|
||||
|
||||
A very small lineage structure may be enough to demonstrate that:
|
||||
- one source identity can anchor multiple interpretations;
|
||||
- interpretations remain separately identifiable;
|
||||
- neither interpretation changes or replaces the source;
|
||||
- a later consumer can deterministically see that both interpretations came from the same exact input.
|
||||
|
||||
If even this cannot be represented cleanly without semantic ambiguity, record that honestly.
|
||||
|
||||
### Context Used
|
||||
|
||||
- `docs/current-handoff.md` (Experiment 54H findings and Return-to-Work Note)
|
||||
- Experiment 54H only in `docs/design-evolution-log.md`
|
||||
- `tests/reconstruction/deterministic-source-record.test.js` (to verify the source-identity helper remains intact)
|
||||
- Node.js built-in `crypto.createHash('sha256')` — deterministic, no LLM
|
||||
|
||||
### Fixed Source
|
||||
|
||||
Raw user input:
|
||||
> Revenue is down. I think pricing may be part of the problem, but I am not sure.
|
||||
|
||||
One deterministic source record created from that exact text using the Experiment 54H method (SHA-256 of verbatim text).
|
||||
|
||||
### Two Fixed Interpretations
|
||||
|
||||
**Interpretation A:**
|
||||
> Pricing may be contributing materially to the revenue decline.
|
||||
|
||||
**Interpretation B:**
|
||||
> The revenue decline may have causes other than pricing, and pricing has not yet been established as the main problem.
|
||||
|
||||
Both are plausible readings of the source. The experiment does not claim either is correct.
|
||||
|
||||
### Interpretation Identity Method
|
||||
|
||||
Each `interpretationId` is generated deterministically from:
|
||||
- the shared `sourceId`;
|
||||
- plus the exact interpretation text (combined as concatenation of `sourceId + "|" + interpretationText`).
|
||||
|
||||
Same source + same interpretation → same interpretation ID.
|
||||
Same source + different interpretation → different interpretation ID.
|
||||
Interpretation ID changes if interpretation text changes.
|
||||
No random UUID, no clock, no LLM, no mutable global state.
|
||||
|
||||
### Interpretation Record Shape (Test-Only)
|
||||
|
||||
```json
|
||||
{
|
||||
"interpretationId": "...",
|
||||
"sourceId": "...",
|
||||
"interpretationText": "..."
|
||||
}
|
||||
```
|
||||
|
||||
This is **not** a proposed production schema. It does not include: confidence, evidence type, status, scores, timestamps, model names, node kinds, or next-question information. The purpose is only identity and lineage.
|
||||
|
||||
### Focused Test Results (15 tests, all pass)
|
||||
|
||||
| # | Test | Result |
|
||||
|---|------|--------|
|
||||
| 1 | Source retains exact verbatim user input | Pass |
|
||||
| 2 | Interpretation A references the source's exact sourceId | Pass |
|
||||
| 3 | Interpretation B references the same exact sourceId | Pass |
|
||||
| 4 | A and B have different interpretationId values | Pass |
|
||||
| 5 | Recreating A produces exactly the same interpretationId | Pass |
|
||||
| 6 | Recreating B produces exactly the same interpretationId | Pass |
|
||||
| 7 | Changing interpretation text changes the interpretation ID | Pass |
|
||||
| 8 | Neither interpretation mutates the source record | Pass |
|
||||
| 9 | Creating one interpretation does not mutate the other | Pass |
|
||||
| 10 | Deterministic consumer identifies one shared source and two distinct interpretations | Pass |
|
||||
| 11 | No semantic judgement chooses A over B | Pass |
|
||||
| 12 | No LLM or network call occurs | Pass |
|
||||
| Cross-check | Different source + same text → different interpretationId | Pass |
|
||||
| Immutability | Source unchanged after multiple interpretation creations | Pass |
|
||||
| Lineage traceability | Consumer traces both interpretations to exact verbatim source | Pass |
|
||||
|
||||
### Shared Source Lineage Result
|
||||
|
||||
Confirmed: both Interpretation A and Interpretation B reference the same `sourceId`. A deterministic consumer can recover that exactly one source anchors both interpretations.
|
||||
|
||||
### Distinct Interpretation Identity Result
|
||||
|
||||
Confirmed: Interpretation A and Interpretation B have different `interpretationId` values despite sharing a source. The IDs remain stable across recreation and diverge when text changes.
|
||||
|
||||
### Source Immutability Result
|
||||
|
||||
Confirmed: creating one or multiple interpretations from a source does not mutate the source record in any way (fields, structure, or content remain identical).
|
||||
|
||||
### Interpretation Independence Result
|
||||
|
||||
Confirmed: creating an interpretation for A does not affect B's identity, and vice versa. Each interpretation is independently derived from the shared sourceId + its own text.
|
||||
|
||||
### Deterministic Consumer Recovery
|
||||
|
||||
Confirmed: a consumer given the source record and both interpretation records can deterministically identify (1) one shared source, (2) two distinct interpretations, and (3) that both interpretations trace back to the same exact verbatim input.
|
||||
|
||||
### Was Either Interpretation Selected as More Correct?
|
||||
|
||||
No. The experiment does not select, score, or prefer either interpretation.
|
||||
|
||||
### Was Downstream Question Selection Tested?
|
||||
|
||||
No. The experiment explicitly excludes next-question derivation.
|
||||
|
||||
### What This Experiment Establishes
|
||||
|
||||
- One source can deterministically anchor multiple interpretations.
|
||||
- Those interpretations remain independently identifiable via stable interpretationId values.
|
||||
- A later consumer can determine that two interpretations came from the same exact source.
|
||||
- Preserving multiple interpretations does not require changing the original source record.
|
||||
- The distinction between "the user supplied this" and "interpretation A/B says this may mean X/Y" survives representation cleanly in code.
|
||||
|
||||
### What This Experiment Does Not Establish
|
||||
|
||||
- Which interpretation is more justified or better grounded.
|
||||
- Whether different interpretations would lead to different next questions.
|
||||
- Any semantic correctness claim about either interpretation.
|
||||
- Graph integration, persistence, multi-turn history, or production architecture.
|
||||
|
||||
### Explicitly Untested
|
||||
|
||||
- Deciding which interpretation is better grounded.
|
||||
- Comparing interpretations against verbatim source wording.
|
||||
- Comparing interpretations against other evidence.
|
||||
- Contradictions between interpretations.
|
||||
- Whether disagreement should reduce confidence.
|
||||
- Whether disagreement should trigger clarification.
|
||||
- Downstream question selection.
|
||||
- Graph integration.
|
||||
- Persistence.
|
||||
- Multi-turn interpretation history.
|
||||
|
||||
### Limitations
|
||||
|
||||
- Test-only implementation; not integrated into any production path.
|
||||
- Only two fixed interpretations tested (not a general multi-interpretation protocol).
|
||||
- No semantic analysis of whether either interpretation faithfully represents the source.
|
||||
- The `|` separator in interpretationId derivation assumes the separator does not appear in user text; this is adequate for identity stability but would need review if adopted as production code.
|
||||
|
||||
### Experiment Conclusion
|
||||
|
||||
**Multiple interpretations can retain deterministic lineage to one source.** One source identity successfully anchors two distinct interpretations while both remain separately identifiable and neither mutates the original source. The distinction between unchanged user evidence and changing model interpretation remains visible in the data structure.
|
||||
|
||||
### Status
|
||||
|
||||
**Pending Rob's review.** No production code changed. Branch: `feature/user-workspace-ux-v0.7`. First file to inspect: `tests/reconstruction/source-interpretation-lineage.test.js`.
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user