Files
Jyotisha/frontend/scripts/rectification-segment-bridge.ts
T
66f087b588 feat(rectification): submit varga-resolution implementation for review
Review-only snapshot for BUG-1115 through BUG-1117; not merge-ready. New opening and append-turn PostgreSQL permission failures remain blocked. Persisted joint replay has zero completed questions; segment ordering remains off by default. The existing offline replay JSON is retained stale and unchanged after a denied overwrite, including its CRLF line endings. Browser/provider validation and final serial gates remain pending. No deployment, role permission changes, or staging/main push.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 08:04:04 +08:00

97 lines
6.9 KiB
TypeScript

import readline from "node:readline";
import { rawMinuteWeights, summarizeSegmentWeights, type SegmentCandidate } from "../src/lib/rectification-agentic/core/segment-summary.ts";
import { segmentInformationGain } from "../src/lib/rectification-agentic/core/segment-probe-order.ts";
import type { ConflictProbe, AnswerClass } from "../src/lib/rectification-agentic/core/types.ts";
import { buildInferenceState, applyAnswerToState } from "../src/lib/rectification-agentic/core/build-state.ts";
import { runV9CandidateScore } from "../src/lib/rectification-agentic/v9/engine-client.ts";
import { buildCaseInferenceState } from "../src/lib/rectification-agentic/v9/inference-adapter.ts";
import { rectificationFollowupCatalog, decideFromDossier, holdoutStatusFromInference, type DecisionDossier } from "../src/lib/rectification-agentic/v9/decision-from-dossier.ts";
import { buildMethodFollowupPlan } from "../src/lib/rectification-agentic/v9/method-followup.ts";
import { evidenceLedgerFingerprint } from "../src/lib/rectification-agentic/v9/tool-service.ts";
import { refinementFromDecisionReceipt } from "../src/lib/rectification-agentic/v9/refinement-packet.ts";
import { segmentReplayOracleAnswer } from "./rectification-segment-oracle.ts";
for await (const line of readline.createInterface({ input: process.stdin })) {
try {
const input = JSON.parse(line);
const candidates: SegmentCandidate[] = (input.rows ?? []).map((row: Record<string, unknown>) => ({
time: row.time, score: row.score, cluster_times: row.cluster_times,
eliminated: input.eliminated?.includes(row.time) ?? false,
}));
const weights = input.weights ?? rawMinuteWeights(candidates);
if (input.operation === "method_replay") {
const previousFetch = globalThis.fetch;
try {
// Transport a real score API response unchanged through its production parser.
globalThis.fetch = (async () => new Response(JSON.stringify(input.response), { status: 200 })) as typeof fetch;
const score = await runV9CandidateScore({ baselineBirthSnapshot: input.snapshot,
candidateRange: input.range, events: input.request.events });
const probes = refinementFromDecisionReceipt(score.decisionReceipt).discriminating_event_probes;
let state = buildCaseInferenceState({ range: input.range, candidates: score.candidates,
evidence: input.evidence, probes, segmentMinutes: input.minutes, segmentTargets: input.targets,
segmentScanComplete: true, segmentOrderEnabled: input.enabled });
const asked: string[] = [];
const rounds: unknown[] = [];
let stop = "budget";
for (let round = 0; round < input.ask_count; round++) {
const latest = { ...score, resultId: score.engineResultId,
evidenceLedgerFingerprint: evidenceLedgerFingerprint(input.evidence),
decisionReceipt: { ...score.decisionReceipt, inference_state: state } };
const dossier: DecisionDossier = { latestResult: latest, evidence: input.evidence,
conversationSummary: { activeFocus: null, declinedSkippedTopics: [] },
case: { acceptedTime: null, status: "candidate_ready", stage: "minute",
candidateRange: input.range, reportedBirthTime: input.snapshot.reported_birth_time,
birthTimeSource: input.snapshot.birth_time_source } };
const decision = decideFromDossier(dossier, { birthDate: input.snapshot.birth_date });
const catalog = rectificationFollowupCatalog(latest, input.evidence);
const plan = buildMethodFollowupPlan({ ...catalog, evidence: input.evidence,
sessionOutcome: decision.sessionOutcome, birthDate: input.snapshot.birth_date,
candidatesSeparated: decision.separation.status === "separated" || decision.separation.status === "sole_candidate",
holdoutValidation: holdoutStatusFromInference(state, catalog.oosBlindPrompts),
caseStage: "minute", candidateRange: input.range, reportedTime: input.snapshot.reported_birth_time });
const followup = plan.next_followup;
const probe = state.probes.find(probe => probe.semantic_key === followup?.semantic_key);
rounds.push({ outcome: decision.sessionOutcome, key: followup?.semantic_key ?? null,
intent: followup?.intent ?? null, choice: Boolean(followup?.choice_frame), dropped: plan.dropped_probes });
if (!probe || followup?.intent !== "distinguish_candidates" || !followup.choice_frame) {
stop = decision.sessionOutcome;
break;
}
// Truth is used only by the offline answer oracle, never by question selection.
const answer = segmentReplayOracleAnswer(probe, input.true_time, state.transitions);
asked.push(probe.semantic_key);
state = applyAnswerToState(state, probe.id, answer);
}
process.stdout.write(JSON.stringify({ asked, rounds, stop, state }) + "\n");
} finally {
globalThis.fetch = previousFetch;
}
} else if (input.operation === "replay_raw") {
const probes: ConflictProbe[] = input.probes.map((probe: ConflictProbe & { user_meaning?: string }) => ({
...probe, id: probe.semantic_key, question: probe.user_meaning ?? probe.question,
}));
const times = input.rows.map((row: SegmentCandidate) => row.time).sort();
const state = buildInferenceState({ range_start: times[0], range_end: times.at(-1),
candidates: input.rows.map((row: SegmentCandidate) => ({ id: row.time, time: row.time, raw_score: row.score,
relative_support: row.score, cluster_times: row.cluster_times })), events: [], probes,
answered_probes: probes.flatMap((probe, index) => {
const answer = input.answers[index] as AnswerClass | null;
return answer ? [{ probe_id: probe.id, semantic_key: probe.semantic_key, candidate_split_hash: probe.candidate_split_hash,
answer_class: answer, classified_from: "choice" as const }] : [];
}),
});
process.stdout.write(JSON.stringify({ scores: Object.fromEntries(state.candidates.map((candidate) =>
[candidate.time, candidate.raw_posterior_score])), eliminated: state.candidates.filter((candidate) => candidate.raw_eliminated).map((candidate) => candidate.time) }) + "\n");
} else if (input.operation === "weights") {
process.stdout.write(JSON.stringify(weights) + "\n");
} else if (input.operation === "summary" || input.operation === "summary_weights") {
process.stdout.write(JSON.stringify(summarizeSegmentWeights(weights, input.segments, input.offsets, input.truth_offset)) + "\n");
} else {
const gains = input.probes.map((probe: ConflictProbe) => segmentInformationGain(probe, weights, input.segments, input.offsets));
process.stdout.write(JSON.stringify({ gains }) + "\n");
}
} catch (error) {
process.stdout.write(JSON.stringify({ error: error instanceof Error ? error.message : "bridge_error" }) + "\n");
}
}