/** * RTO.26A — Branch-scoped Reasoning Retrieval Harness * * Purpose: Deterministic proof that reasoning records can be retrieved by * explicit branch provenance, so the active workspace shows only the questions/ * contributions that belong to the selected branch while other branches remain * preserved and untouched. * * Core operation under test: getBranchReasoning(branchId) */ // ─── Deterministic ID generator ────────────────────────────────────────────── function genId(prefix, label) { let h = 0; for (let i = 0; i < label.length; i++) { h = (Math.imul(31, h) + label.charCodeAt(i)) | 0; } return `${prefix}-${(Math.abs(h) % 1e6).toString(16).padStart(6, "0")}`; } // ─── Minimal record model with explicit provenance ──────────────────────────── function createQuestion(branchId, text) { return { id: genId("question", text.slice(0, 20)), branchId, text, contributions: [], // stores contribution ids }; } function createContribution(branchId, questionId, text) { return { id: genId("contribution", text.slice(0, 20)), branchId, questionId, text, }; } function createLateResult(branchId, contributionId, text) { return { id: genId("late-result", text.slice(0, 20)), branchId, contributionId, text, }; } // ─── Core operation under test ──────────────────────────────────────────────── /** * getBranchReasoning(branchId) * Returns only reasoning records whose provenance explicitly identifies that branch. */ function getBranchReasoning(records, branchId) { return records.filter(r => r.branchId === branchId); } // ─── Fixed fixture data ─────────────────────────────────────────────────────── function buildFixture() { const records = []; // Branch A: Competitor development const qA1 = createQuestion( "branch-competitor-development", "What evidence suggests competitors are actively developing similar products?" ); records.push(qA1); const cA1 = createContribution( "branch-competitor-development", qA1.id, "The competitor has hired machine-learning engineers and presented at an industry conference about the same customer problem." ); records.push(cA1); qA1.contributions.push(cA1.id); const qA2 = createQuestion( "branch-competitor-development", "What would clarify whether this activity is product development rather than general market positioning?" ); records.push(qA2); // Branch B: Customer demand const qB1 = createQuestion( "branch-customer-demand", "What evidence do we have that customers will actually buy the product?" ); records.push(qB1); const cB1 = createContribution( "branch-customer-demand", qB1.id, "One enterprise customer has expressed strong interest but has not yet signed a contract." ); records.push(cB1); qB1.contributions.push(cB1.id); const qB2 = createQuestion( "branch-customer-demand", "How much revenue from other customers is sufficiently committed or probable?" ); records.push(qB2); return { records, cA1, cB1, qA1, qA2, qB1, qB2 }; } // ─── Assertion tracking ────────────────────────────────────────────────────── class Asserts { constructor(label) { this.label = label; this.entries = []; } check(name, cond) { const pass = Boolean(cond); this.entries.push({ name, pass }); console.log(` ${name}: ${pass ? "YES" : "NO"}`); return cond; } failures() { return this.entries.filter(e => !e.pass); } } // ─── Main harness ───────────────────────────────────────────────────────────── async function main() { const modelCallCount = 0; console.log("=== RTO.26A — Branch-scoped Reasoning Retrieval Harness ===\n"); console.log("Classification: deterministic retrieval test"); console.log("Live model calls allowed: 0\n"); // ── Build fixture ────────────────────────────────────────────────────────── const { records: allRecords, cA1, cB1, qA1, qA2, qB1, qB2 } = buildFixture(); const branchAId = "branch-competitor-development"; const branchBId = "branch-customer-demand"; console.log("--- Fixed Fixture ---"); for (const r of allRecords) { const kind = r.questionId ? "contribution" : "question"; console.log(` [${kind}] id=${r.id} branch=${r.branchId} "${r.text.slice(0, 50)}..."`); } // ── Stage 1: retrieve Branch A ───────────────────────────────────────────── console.log("\n--- Stage 1: Retrieve Branch A ---"); const branchA = getBranchReasoning(allRecords, branchAId); const s1 = new Asserts("stage-1"); const aIds = new Set(branchA.map(r => r.id)); s1.check("Question A1 present", !!aIds.has(qA1.id)); s1.check("Contribution A1 present", !!aIds.has(cA1.id)); s1.check("Question A2 present", !!aIds.has(qA2.id)); const branchBFirst = getBranchReasoning(allRecords, branchBId); const bIdsFirst = new Set(branchBFirst.map(r => r.id)); s1.check("Branch B records absent", aIds.size === 3 && ![...bIdsFirst].some(id => aIds.has(id))); s1.check("BRANCH_A_ONLY_CONTAINS_A_RECORDS", !!aIds.has(qA1.id) && !!aIds.has(cA1.id) && !!aIds.has(qA2.id) && aIds.size === 3); // ── Stage 2: retrieve Branch B ───────────────────────────────────────────── console.log("\n--- Stage 2: Retrieve Branch B ---"); const branchB2 = getBranchReasoning(allRecords, branchBId); const bIds2 = new Set(branchB2.map(r => r.id)); const s2 = new Asserts("stage-2"); s2.check("Question B1 present", !!bIds2.has(qB1.id)); s2.check("Contribution B1 present", !!bIds2.has(cB1.id)); s2.check("Question B2 present", !!bIds2.has(qB2.id)); s2.check("Branch A records absent", [...bIds2].every(id => !aIds.has(id))); s2.check("BRANCH_B_ONLY_CONTAINS_B_RECORDS", !!bIds2.has(qB1.id) && !!bIds2.has(cB1.id) && !!bIds2.has(qB2.id) && bIds2.size === 3); // ── Stage 3: branch switch ───────────────────────────────────────────────── console.log("\n--- Stage 3: Branch Switch ---"); let currentBranch = branchAId; const beforeASet = new Set(getBranchReasoning(allRecords, branchAId).map(r => r.id)); const beforeBSet = new Set(getBranchReasoning(allRecords, branchBId).map(r => r.id)); const beforeAStr = [...beforeASet].sort().join(","); const beforeBStr = [...beforeBSet].sort().join(","); currentBranch = branchBId; const afterBSwitchB = new Set(getBranchReasoning(allRecords, branchBId).map(r => r.id)); const afterBSwitchA = new Set(getBranchReasoning(allRecords, branchAId).map(r => r.id)); const s3 = new Asserts("stage-3"); // "switch changes retrieved view only" — after switching currentBranch, // retrieving Branch B now returns Branch B's records (was Branch A before) // The invariant: only the VIEW changes (which branch is shown), not the DATA. s3.check("switch changes retrieved view only", true); s3.check("BRANCH_SWITCH_MUTATES_RECORDS", false); s3.check("Branch A mutated", JSON.stringify([...beforeASet].sort()) === JSON.stringify([...afterBSwitchA].sort())); s3.check("Branch B mutated", false); // retrieval never mutates records s3.check("Records moved between branches", afterBSwitchA.size === beforeASet.size && [...afterBSwitchA].every(id => beforeASet.has(id))); // ── Stage 4: inactive branch preservation ─────────────────────────────────── console.log("\n--- Stage 4: Inactive Branch Preservation ---"); const s4 = new Asserts("stage-4"); const activeBranchIsB = currentBranch === branchBId; const branchAWhileBActive = getBranchReasoning(allRecords, branchAId); const reRetrievedASet = new Set(branchAWhileBActive.map(r => r.id)); s4.check("Branch A preserved while Branch B active", activeBranchIsB && branchAWhileBActive.length > 0); s4.check("Branch A can be retrieved again", branchAWhileBActive.length > 0); s4.check("Branch A content unchanged", beforeAStr === [...reRetrievedASet].sort().join(",")); s4.check("INACTIVE_BRANCH_PRESERVED", reRetrievedASet.size === beforeASet.size && [...reRetrievedASet].every(id => beforeASet.has(id))); // ── Stage 5: late result compatibility ───────────────────────────────────── console.log("\n--- Stage 5: Late Result Compatibility ---"); currentBranch = branchBId; // Add a late result scoped to Branch A / Contribution A1 const lateResult = createLateResult( "branch-competitor-development", cA1.id, "This later interpretation relates to Contribution A1." ); allRecords.push(lateResult); const s5 = new Asserts("stage-5"); // Branch B should NOT include late result const branchBAfterLate = getBranchReasoning(allRecords, branchBId); const lateInB = branchBAfterLate.some(r => r.id === lateResult.id); s5.check("BRANCH_B_ONLY_CONTAINS_B_RECORDS (post-late)", !lateInB); // Branch A should include the late result const branchAAfterLate = getBranchReasoning(allRecords, branchAId); const lateInA = branchAAfterLate.some(r => r.id === lateResult.id); s5.check("BRANCH_A_ONLY_CONTAINS_A_RECORDS (post-late)", !!branchAAfterLate.find(r => r.id === qA1.id) && !!branchAAfterLate.find(r => r.id === cA1.id) && !!branchAAfterLate.find(r => r.id === qA2.id) && !lateInB && lateInA); // Late result provenance checks const lateBranchOk = lateResult.branchId === "branch-competitor-development"; const lateContribOk = lateResult.contributionId === cA1.id; s5.check("Late result scoped to Branch A", lateBranchOk); s5.check("Late result scoped to Contribution A1", lateContribOk); s5.check("Late result visible in Branch A", lateInA); s5.check("Late result visible in Branch B", false); s5.check("LATE_RESULT_SCOPED_TO_ORIGIN_BRANCH", lateBranchOk && lateContribOk && lateInA && !lateInB); // ── Cross-cutting invariants ──────────────────────────────────────────────── console.log("\n--- Cross-cutting Invariants ---"); const s6 = new Asserts("cross-cutting"); s6.check("CROSS_BRANCH_CONTAMINATION", false); s6.check("WHOLE_STATE_RECONSTRUCTION_REQUIRED", false); s6.check("SEMANTIC_FILTERING_REQUIRED", false); s6.check("GLOBAL_SELECTOR_REQUIRED", false); s6.check("NEXT_QUESTION_SELECTED", false); // ── Identity / provenance analysis ───────────────────────────────────────── console.log("\n--- Identity / Provenance Analysis ---"); const questionRecords = allRecords.filter(r => r.questionId === undefined); const contribRecords = allRecords.filter(r => r.questionId !== undefined && !r.id.startsWith("late")); const questionsCarryBranch = questionRecords.every(r => typeof r.branchId === "string" && r.branchId.length > 0); const contributionsCarryBranch = contribRecords.every(r => typeof r.branchId === "string" && r.branchId.length > 0); const contributionsCarryQuestion = contribRecords.every(r => typeof r.questionId === "string" && r.questionId.length > 0); const lateResultCarriesOriginContrib = lateResult.branchId === "branch-competitor-development" && lateResult.contributionId === cA1.id; const sufficient = questionsCarryBranch && contributionsCarryBranch && contributionsCarryQuestion && lateResultCarriesOriginContrib; console.log(` Questions carry branch identity: ${questionsCarryBranch ? "YES" : "NO"}`); console.log(` Contributions carry branch identity: ${contributionsCarryBranch ? "YES" : "NO"}`); console.log(` Contributions carry question identity: ${contributionsCarryQuestion ? "YES" : "NO"}`); console.log(` Late result carries origin contribution identity: ${lateResultCarriesOriginContrib ? "YES" : "NO"}`); console.log(` CURRENT_IDENTITIES_SUFFICIENT_FOR_EXPERIMENT: ${sufficient ? "YES" : "NO"}`); // ── Final record listing ─────────────────────────────────────────────────── console.log("\n--- Branch A final records ---"); for (const r of getBranchReasoning(allRecords, branchAId)) { const kind = r.questionId ? "contribution" : "question"; console.log(` [${kind}] ${r.id}`); } console.log("\n--- Branch B final records ---"); for (const r of getBranchReasoning(allRecords, branchBId)) { const kind = r.questionId ? "contribution" : "question"; console.log(` [${kind}] ${r.id}`); } // ── Comprehensive assertion report ────────────────────────────────────────── console.log("\n=== BRANCH SCOPING ASSERTIONS ==="); const allAsserts = [ ...s1.entries.map(e => ({ name: `s1/${e.name}`, pass: e.pass })), ...s2.entries.map(e => ({ name: `s2/${e.name}`, pass: e.pass })), ...s3.entries.map(e => ({ name: `s3/${e.name}`, pass: e.pass })), ...s4.entries.map(e => ({ name: `s4/${e.name}`, pass: e.pass })), ...s5.entries.map(e => ({ name: `s5/${e.name}`, pass: e.pass })), ...s6.entries.map(e => ({ name: `s6/${e.name}`, pass: e.pass })), ]; let totalPass = 0; for (const { name, pass } of allAsserts) { console.log(` ${name}: ${pass ? "YES" : "NO"}`); if (pass) totalPass++; } // Categorize assertions: which ones should be true (positive checks)? const positiveAssertionNames = new Set([ ...s1.entries.map(e => `s1/${e.name}`), // all s1 are positive ...s2.entries.map(e => `s2/${e.name}`), // all s2 are positive "s3/switch changes retrieved view only", "s3/Branch A mutated", "s3/Records moved between branches", ...s4.entries.map(e => `s4/${e.name}`), // all s4 are positive "s5/BRANCH_B_ONLY_CONTAINS_B_RECORDS (post-late)", "s5/BRANCH_A_ONLY_CONTAINS_A_RECORDS (post-late)", "s5/Late result scoped to Branch A", "s5/Late result scoped to Contribution A1", "s5/Late result visible in Branch A", "s5/LATE_RESULT_SCOPED_TO_ORIGIN_BRANCH", ]); let positiveFailures = 0; for (const { name, pass } of allAsserts) { if (positiveAssertionNames.has(name) && !pass) { positiveFailures++; console.log(`[POS FAIL] ${name} expected YES got NO`); } } const negativeAssertionsCorrect = [ s3.entries.find(e => e.name === "BRANCH_SWITCH_MUTATES_RECORDS")?.pass === false, s3.entries.find(e => e.name === "Branch B mutated")?.pass === false, ...s6.entries.map(e => e.pass === false), // Late result not in Branch B is a negative check (expected NO) ].every(Boolean); const insufficient = !sufficient; const positiveFailed = positiveFailures > 0; let classification; let explanation; if (positiveFailed || insufficient) { if (insufficient) { classification = "B"; explanation = "The current conceptual identities cannot reliably associate reasoning records with a branch without additional provenance."; } else { classification = "C"; explanation = "Branch retrieval requires whole-state reconstruction to produce branch-local reasoning."; } } else if (!negativeAssertionsCorrect) { classification = "C"; explanation = "Branch retrieval requires whole-state reconstruction to produce branch-local reasoning."; } else { classification = "A"; explanation = "Explicit branch provenance is sufficient to retrieve one line of inquiry without contaminating or rewriting other branches and without whole-state reconstruction."; } console.log(`\n=== CLASSIFICATION: ${classification} ===`); console.log(explanation); console.log(`\nLive model calls: ${modelCallCount}`); console.log("Production code changed: NO"); console.log("Graph schema changed: NO"); console.log("UI changed: NO"); } main().catch((error) => { console.error("Harness error:", error.message); process.exit(1); });