Dashboard › opencode-lore › Session 0kkAloNNpQiJ
0kkAloNNpQiJYGCvFPerform a substantive independent immutable security/privacy review of exact revision objects in /home/byk/Code/opencode-lore-provider-error. Review ONLY base literal 2cbf40060c67df229731cf1b9e34d5bf22ec2145 through candidate stable change lpmvqrurxwlmrmwnyllmxlvkmplvwnlz, exact commit 0dd569b520bad37adbaea230f32100c7f83f463c. Expected plain jj diff --from 2cbf40060c67df229731cf1b9e34d5bf22ec2145 --to lpmvqrur | sha256sum is 3458ce2dc248950b13dc69dda91a07f95a2dcd49f128f2f4ec8e218a6d68b46e. Expected exactly six paths: packages/gateway/src/pipeline.ts, packages/gateway/src/stream/openai-responses.ts, packages/gateway/test/openai-responses-recall-aware-stream.test.ts, packages/gateway/test/openai-responses-stream.test.ts, packages/gateway/test/pipeline-streaming.test.ts, packages/gateway/test/recall-codex-stream.test.ts. IMPORTANT: the workspace has later descendant commits and a clean empty working child. Do not require the working child to equal the candidate and do not inspect descendant content as candidate content. Use immutable jj file show -r lpmvqrur <path>, jj diff --from ... --to ..., and revision metadata. The candidate itself must match; descendants are irrelevant. Read AGENTS.md and quality/REVIEW.md from the candidate/base as appropriate. Do not edit/format/install/mutate VCS, access server/network/production DB, or run exhaustive validation. Inspect every changed line and relevant validation, accumulation, streaming, callback, logging, telemetry, persistence, cancellation/backpressure, source-sequence, failure alias, usage/accounting, and retry paths. ...
<skill_content name="jj-guide"> # Skill: jj-guide # jj Guide for AI Agents Jujutsu (jj) is a Git-compatible VCS with mutable commits, automatic snapshotting, no staging area, and first-class conflicts. This skill teaches you how to use it safely from a non-interactive agent environment. If `.jj/` exists in the repo root, this is a jj repo. **Use `jj` commands, not `git`.** In a colocated repo (`.jj/` *and* `.git/`), git tools can read the state, but mutations should go through `jj` so the operation log stays consistent. ## Critical Rules - **NEVER** use interactive flags (`-i`, `--interactive`). TUI prompts hang in agent environments. This applies to `jj split -i`, `jj squash -i`, `jj commit -i`, `jj resolve`, `jj diffedit`, etc. - **ALWAYS** pass `-m "msg"` when describing/committing. Without `-m`, an editor opens and hangs. - **VERIFY** mutations with `jj st` and `jj log` after `squash`, `abandon`, `rebase`, `restore`, `commit`. ...
The working copy has no changes. Working copy (@) : qnmstlol 248b42ff (empty) (no description set) Parent commit (@-): qzwttkwl 493b0655 fix/responses-provider-failures | fix(responses): isolate failure telemetry Warning: These bookmarks have conflicts: fix/responses-private-references Hint: Use `jj bookmark list` to see details. Use `jj bookmark set <name> -r <rev>` to resolve. Error: Failed to parse template: Method `hex` doesn't exist for type `ChangeId` Caused by: --> 1:11 | 1 | change_id.hex() ++ "\n" ++ commit_id.hex() ++ "\n" ++ description.first_line() ++ "\n" | ^-^ | = Method `hex` doesn't exist for type `ChangeId`
lpmvqrurxwlmrmwnyllmxlvkmplvwnlz 0dd569b520bad37adbaea230f32100c7f83f463c fix(responses): unify provider failure handling pxrvwsvvkmpoxnsqmrkwrnlqvvkoltwz 2cbf40060c67df229731cf1b9e34d5bf22ec2145 feat(cch): add seeds for Claude Code up to 2.1.272 (#1780)
3458ce2dc248950b13dc69dda91a07f95a2dcd49f128f2f4ec8e218a6d68b46e -
M packages/gateway/src/pipeline.ts M packages/gateway/src/stream/openai-responses.ts M packages/gateway/test/openai-responses-recall-aware-stream.test.ts M packages/gateway/test/openai-responses-stream.test.ts M packages/gateway/test/pipeline-streaming.test.ts M packages/gateway/test/recall-codex-stream.test.ts lpmvq 0dd569b520ba fix(responses): unify provider failure handling wswl 24880457763b fix(responses): reject non-monotonic provider failures plz a1020a45be13 fix(responses): preserve trusted failure metadata skw 01a6e06b08ba fix(responses): make provider failure settlement atomic xqm b1bc7cd46c4e fix(responses): complete provider failure sanitization qnl 29dee093d7ce fix(responses): bind sanitized failures to trusted state prp d385b39653b0 fix(responses): sanitize provider failures pxr 2cbf40060c67 feat(cch): add seeds for Claude Code up to 2.1.272 (#1780) wswlsmrnuzlqtxyskqotksrlqtzplrkl 24880457763b6f10831856d01c41bd72d62ddc28 fix(responses): reject non-monotonic provider ...
<!-- This section is maintained by the coding agent via lore (https://github.com/BYK/loreai) --> ## Long-term Knowledge For long-term knowledge entries managed by [lore](https://github.com/BYK/loreai) (gotchas, patterns, decisions, architecture), see [`.lore.md`](.lore.md) in the project root. <!-- End lore-managed section --> ## Review See [`quality/REVIEW.md`](quality/REVIEW.md) for the review heuristics and workflow — regression-test discipline, adversarial-order state setup, fan-out registry coverage, recurring bug-class batteries, and the two-reviewer rule. Every non-trivial PR requires an adversarial correctness review before merge. # Project Overview Lore is a **three-tier memory architecture** for AI coding agents. It intercepts LLM API calls (as a transparent proxy or native plugin), distills conversation history into compressed summaries, and extracts long-term knowledge entries that persist across sessions. **Runtime:** Node.js >= 22.5 (development/tests/production). ...
packages/gateway/src/pipeline.ts | 369 +++++- packages/gateway/src/stream/openai-responses.ts | 1090 ++++++++++++------- ...st/openai-responses-recall-aware-stream.test.ts | 1245 ++++++++++++++++++++- ...es/gateway/test/openai-responses-stream.test.ts | 1044 +++++++++++++++++- packages/gateway/test/pipeline-streaming.test.ts | 147 +- packages/gateway/test/recall-codex-stream.test.ts | 3 +- 6 files changed, 3398 insertions(+), 500 deletions(-)
Modified regular file packages/gateway/src/pipeline.ts:
...
203 203: streamResponsesPassthrough,
204 204: translateAnthropicStreamToResponses,
205 205: applyResponsesEvent,
206: cloneResponsesAccState,
206 207: finalizeResponsesAcc,
208: finalizeUnsuccessfulResponsesAcc,
207 209: formatResponsesEvent,
208 210: makeResponsesAccState,
209 211: mapStatusFromStopReason,
...
212 214: isValidResponsesReasoningEncryptedContent,
213 215: responsesDoneItemMatchesAdded,
214 216: responsesTerminalItemMatches,
217: restoreResponsesAccState,
215 218: normalizeCodexResponsesEvent,
219: projectResponsesInProgressEvent,
220: RESPONSES_PROVIDER_FAILURE_LOG,
221: sanitizeResponsesProviderFailureTerminal,
222: validateResponsesProviderFailureTerminal,
223: validateResponsesSourceSequence,
216 224: ResponsesTerminalError,
217 225: type ResponsesAccState,
218 226: } from ...
...output truncated...
Full output saved to: /home/byk/.local/share/opencode/tool-output/tool_0ace8637a00152z7bfkOXQLtlo
1065: ...(state.codexRateLimits
1066: ? { codexRateLimits: structuredClone(state.codexRateLimits) }
1067: : {}),
1068: };
1069: }
1070:
903 1071: // ---------------------------------------------------------------------------
904 1072: // Stream accumulator (buffered)
905 1073: // ---------------------------------------------------------------------------
...
942 1110: if (!response || typeof response !== "object" || Array.isArray(response)) {
943 1111: throw new Error("malformed Responses terminal event");
944 1112: }
1113: if (event === "response.created" && state.created) {
1114: malformed();
1115: } else if (event === "response.in_progress" && !state.created) {
1116: malformed();
1117: }
945 1118: if (state.id && response.id !== ...
<path>/home/byk/.local/share/opencode/tool-output/tool_0ace8637a00152z7bfkOXQLtlo</path>
<type>file</type>
<content>
1: Modified regular file packages/gateway/src/stream/openai-responses.ts:
2: ...
3: 48 48: export interface ResponsesAccState {
4: 49 49: id: string;
5: 50 50: model: string;
6: 51: created: boolean;
7: 52: createdAt?: number;
8: 53: lastAcceptedSequenceNumber?: number;
9: 51 54: stopReason: string;
10: 52 55: usage: GatewayUsage;
11: 53 56: terminalEvent?:
12: ...
13: 557 560: return {
14: 558 561: id: "",
15: 559 562: model: "",
16: 563: created: false,
17: 560 564: stopReason: "end_turn",
18: 561 565: usage: { inputTokens: 0, outputTokens: 0 },
19: 562 566: items: new Map(),
20: ... ...
<path>/home/byk/.local/share/opencode/tool-output/tool_0ace8637a00152z7bfkOXQLtlo</path>
<type>file</type>
<content>
1081: 2526: !responsesDoneItemMatchesAdded(completedSnapshot, accumulated)
1082: 2527: ) {
1083: 2528: throw new Error("malformed Responses terminal event");
1084: 2529: }
1085: 2530: assertResponsesDoneMatchesAccumulatedState(
1086: 2531: state,
1087: 2532: outputIndex,
1088: 2533: completedSnapshot,
1089: 2534: terminalContentParts,
1090: 2535: );
1091: 2536: applyResponsesEvent(state, "response.output_item.done", {
1092: 2537: output_index: outputIndex,
1093: 2538: item: completedSnapshot,
1094: 2539: });
1095: 2540: ...
1 /**
2 * OpenAI Responses API SSE stream accumulator.
3 *
4 * Parses upstream Responses API streaming events and accumulates the full
5 * response into a `GatewayResponse`. The Responses API uses a different
6 * SSE event lifecycle than Anthropic:
7 *
8 * response.created → response.in_progress →
9 * response.output_item.added → response.output_text.delta (repeated) →
10 * response.output_item.done → response.function_call_arguments.delta →
11 * response.function_call_arguments.done →
12 * response.completed
13 *
14 * Reuses `parseSSEStream` from the Anthropic stream module since the
15 * underlying SSE wire format is the same.
16 */
17 import { asString, log } from "@loreai/core";
18 import { isDeepStrictEqual } from "node:util";
19 import {
20 ZERO_USAGE,
21 type GatewayContentBlock,
22 type GatewayResponse,
23 type GatewayUsage,
24 } from ...
1101 if (
1102 event === "response.created" ||
1103 event === "response.in_progress" ||
1104 event === "response.failed" ||
1105 event === "response.completed" ||
1106 event === "response.incomplete" ||
1107 event === "response.done"
1108 ) {
1109 const response = parsed.response as Record<string, unknown> | undefined;
1110 if (!response || typeof response !== "object" || Array.isArray(response)) {
1111 throw new Error("malformed Responses terminal event");
1112 }
1113 if (event === "response.created" && state.created) {
1114 malformed();
1115 } else if (event === "response.in_progress" && !state.created) {
1116 malformed();
1117 }
1118 if (state.id && response.id !== undefined && response.id !== state.id) {
1119 throw new Error("malformed Responses terminal event");
1120 }
1121 if (
1122 state.model &&
1123 response.model !== undefined &&
...
2090 * Consumes the upstream Response body and returns the accumulated result.
2091 */
2092 export async function accumulateResponsesSSEStream(
2093 response: Response,
2094 opts: {
2095 /** Omit to preserve the legacy tolerant accumulator behavior. */
2096 validation?: ResponsesValidationMode;
2097 stopAtTerminal?: boolean;
2098 signal?: AbortSignal;
2099 inactivityMs?: number;
2100 maxFrames?: number;
2101 onSemanticContent?: () => void;
2102 /** Called only after the event has passed strict validation and mutation. */
2103 onValidatedEvent?: (event: string, data: string) => void | Promise<void>;
2104 /** Passthrough clients must receive a provider's valid failure terminal. */
2105 allowFailureTerminal?: boolean;
2106 /** Buffered callers that run successful-turn side effects must reject
2107 * incomplete terminals rather than treating a parsed body as completion. ...
2660 if (
2661 opts.validation &&
2662 opts.requireCompletedTerminal &&
2663 terminalStatus !== "completed"
2664 ) {
2665 throw new ResponsesTerminalError(
2666 finalizeResponsesAcc(state),
2667 terminalStatus ?? "unknown",
2668 );
2669 }
2670
2671 return finalizeResponsesAcc(state);
2672 }
2673
2674 // ---------------------------------------------------------------------------
2675 // True pass-through streamer (Responses upstream → Responses client)
2676 // ---------------------------------------------------------------------------
2677
2678 /**
2679 * Serialize a parsed SSE event back to wire form, preserving the original data
2680 * payload (multi-line `data:` payloads are re-prefixed per line so nothing is
2681 * dropped or re-serialized — `reasoning_summary`, content_part annotations,
2682 * etc. survive intact because we forward the original `data` string). ...
9900 id: item.id,
9901 role: "assistant",
9902 status: "completed",
9903 content: [{ type: "refusal", refusal: item.refusal }],
9904 });
9905 continue;
9906 }
9907 finalOutput.push({
9908 type: "message",
9909 id: item.id,
9910 role: "assistant",
9911 status: "completed",
9912 content: [{ type: "output_text", text: item.text, annotations: [] }],
9913 });
9914 } else {
9915 const raw = state.rawItems.get(index);
9916 finalOutput.push({
9917 ...raw,
9918 type: "function_call",
9919 id: item.id,
9920 call_id: item.callId,
9921 name: item.name,
9922 arguments: item.args,
9923 status: typeof raw?.status === "string" ? raw.status : "completed",
9924 });
9925 }
9926 }
9927 return ...
10700 if (contentPosition < 0) {
10701 throw new RecallContinuationFailure("missing_recall_block");
10702 }
10703 let executed: Awaited<ReturnType<typeof settleRecall>>;
10704 try {
10705 executed = await settleRecall({
10706 query: recall.query,
10707 scope: recall.scope,
10708 id: recall.id,
10709 ids: recall.ids,
10710 detailOffset: recall.detailOffset,
10711 detailLimit: recall.detailLimit,
10712 outputIndex: recall.outputIndex,
10713 toolUseId: recall.toolUseId,
10714 contentPosition,
10715 acc: recallAcc,
10716 signal,
10717 });
10718 } catch (error) {
10719 if (signal.aborted) throw error;
...
11440 );
11441 }
11442 if (contPending.length > 1) {
11443 throw new RecallContinuationFailure("parallel_recall");
11444 }
11445 if (
11446 contState.terminalEvent === "response.incomplete" &&
11447 contPending.length > 0
11448 ) {
11449 throw new RecallContinuationFailure(
11450 "nested_recall_incomplete",
11451 );
11452 }
11453 assertUsageMergeable(state.usage, contState.usage);
11454 let nextRecall: (typeof contPending)[number] | undefined;
11455 let nextExecuted:
11456 | {
11457 anchorText: string;
11458 resultText: ...
...output truncated...
Full output saved to: /home/byk/.local/share/opencode/tool-output/tool_0aceb4ec20010tSdH1pCHhA5kq
1889: log.registerSink({
1895: const privateCause = "private post-text socket failure";
1896: const privateSession = "private-session\nforged-log-entry";
1917: onComplete: () => {},
1937: expect(out).not.toContain("event: response.failed");
1940: "openai-responses recall-aware stream failed category=principal_transport",
1943: expect(errors.join("\n")).not.toContain("forged-log-entry");
1958: controller.error(new Error("private post-tool socket failure"));
1973: onComplete: () => {},
1992: expect(out).not.toContain("event: response.failed");
1993: expect(out).not.toContain("private post-tool socket failure");
1999: test("does not retry a pre-output principal inactivity failure", async () => {
2010: onComplete: () => {},
2023: expect(out.match(/^event: response\.failed$/gm)).toHaveLength(1);
2026: { kind: ...
...output truncated...
Full output saved to: /home/byk/.local/share/opencode/tool-output/tool_0acebd392001BA5ROmYeUNNYRj
415: const capturedLogs: string[] = [];
416: log.registerSink({
417: info: (message) => capturedLogs.push(message),
418: warn: (message) => capturedLogs.push(message),
419: error: (message) => capturedLogs.push(message),
420: captureException: (error) => capturedLogs.push(String(error)),
421: });
422: const completions: Array<{
423: response: GatewayResponse;
424: successful: boolean;
425: }> = [];
426: const client = streamResponsesRecallAware(
427: streamFrom([
428: sseEvent("response.created", {
429: sequence_number: 7,
430: response: {
431: id: "resp_principal_diagnostic",
432: created_at: 456,
...
<path>/home/byk/.local/share/opencode/tool-output/tool_0acebd392001BA5ROmYeUNNYRj</path> <type>file</type> <content> 1: Modified regular file packages/gateway/test/openai-responses-recall-aware-stream.test.ts: 2: ... 3: 173 173: const PUBLIC_RECALL_ERROR = "Lore could not continue the response after recall"; 4: 174 174: const PUBLIC_GATEWAY_ERROR = "Gateway request failed"; 5: 175 175: 6: 176: const nonMonotonicProviderFailures = ( 7: 177: [ 8: 178: ["response.failed", "response.failed", "failed"], 9: 179: ["failed response.done", "response.done", "failed"], 10: 180: ["cancelled response.done", "response.done", "cancelled"], 11: 181: ["error", "error", undefined], 12: 182: ["response.error", "response.error", undefined], 13: 183: ] as const 14: 184: ).flatMap(([alias, event, status]) => 15: 185: ([10, 9] as const).map( 16: 186: (sequence) => [alias, sequence, event, status] as ...
<path>/home/byk/.local/share/opencode/tool-output/tool_0acebd392001BA5ROmYeUNNYRj</path>
<type>file</type>
<content>
1001: 1242: }),
1002: 1243: },
1003: 1244: ]);
1004: 1245: });
1005: 1246:
1006: 1247: test("finalizes validated failure usage when cancellation wins terminal backpressure", async () => {
1007: 1248: const completions: Array<{
1008: 1249: response: GatewayResponse;
1009: 1250: successful: boolean;
1010: 1251: }> = [];
1011: 1252: const client = streamResponsesRecallAware(
1012: 1253: streamFrom([
1013: 1254: created("resp_failure_backpressure", "gpt-5.6-terra"),
1014: 1255: sseEvent("response.failed", {
1015: 1256: response: {
1016: 1257: id: "resp_failure_backpressure",
1017: 1258: model: "gpt-5.6-terra",
1018: 1259: status: "failed",
1019: 1260: ...
1 /**
2 * Lightweight logger that suppresses informational messages by default.
3 *
4 * In TUI mode, all stderr output renders as red "error" text — confusing
5 * for routine status messages like "incremental distillation" or "pruned
6 * temporal messages". Only actual errors should be visible by default.
7 *
8 * Set LORE_DEBUG=1 to see informational messages (useful when debugging
9 * the plugin itself).
10 *
11 * ## Sink registration
12 *
13 * An optional {@link LogSink} can be registered via {@link registerSink}.
14 * When registered, every log call (regardless of `isDebug`) also forwards
15 * to the sink. This is used by the gateway to bridge logs → Sentry without
16 * adding a Sentry dependency to `@loreai/core`.
17 *
18 * ## File logging
19 *
20 * All log calls (info, warn, error) are written to a persistent log file
21 * at `~/.local/share/lore/lore.log` regardless ...
320
321 function tightenExistingLogFile(path: string): void {
322 const existing = lstatSync(path);
323 if (!existing.isFile() || existing.isSymbolicLink()) {
324 throw new Error(`Refusing non-regular log file: ${path}`);
325 }
326 assertCurrentOwner(existing, path);
327 const fd = openSync(
328 path,
329 constants.O_WRONLY | constants.O_APPEND | constants.O_NONBLOCK | NO_FOLLOW,
330 );
331 try {
332 const info = fstatSync(fd);
333 if (!info.isFile())
334 throw new Error(`Refusing non-regular log file: ${path}`);
335 assertCurrentOwner(info, path);
336 assertSameFile(existing, info, path);
337 if (process.platform !== "win32") fchmodSync(fd, LOG_FILE_MODE);
338 } finally {
339 closeSync(fd);
340 }
341 }
342
343 function removeExistingRotationBackup(path: string): void {
344 let existing: Stats;
345 try {
346 existing = lstatSync(path);
...
9360 return;
9361 }
9362 if (!Array.isArray(response.output)) {
9363 throw new Error("Responses terminal output must be an array");
9364 }
9365 // ChatGPT/Codex can omit some or all streamed items from the terminal
9366 // snapshot. Treat the output_item lifecycle as authoritative while still
9367 // requiring every repeated terminal item to match in stream order.
9368 const actualOutput = response.output.map((item) => {
9369 if (!item || typeof item !== "object" || Array.isArray(item)) {
9370 throw new Error("Responses terminal output contains malformed item");
9371 }
9372 return item as Record<string, unknown>;
9373 });
9374 const expected = [...acc.rawItems.entries()].sort(([a], [b]) => a - b);
9375 if (
9376 opts.validation === "public" &&
9377 actualOutput.length !== expected.length
9378 ) {
9379 throw new Error("Responses terminal output ...
370: reportRecallContinuationFailure,
6849: onTransactionReady?: (transaction: {
6901: if (recallPersistence) recallContext?.onTransactionReady?.(recallPersistence);
6907: const recallDiagnostics = createRecallDiagnostics(
7224: recallDiagnostics.record(input, result, coverage);
7414: recallDiagnostics.finish("completed");
7488: recallDiagnostics.finish("failed");
7527: recallDiagnostics.finish("failed");
7665: recallDiagnostics.finish("completed");
7679: recallDiagnostics.finish(streamSignal.aborted ? "aborted" : "failed");
7681: reportRecallContinuationFailure(err.category);
7726: if (!recallContext?.onTransactionReady) recallPersistence?.rollback();
7727: recallDiagnostics.finish("aborted");
7751: if (!recallPersistence || recallContext?.onTransactionReady) return response;
7806: onTransactionReady?: (transaction: {
7884: const recallDiagnostics = ...
7860 anchorText: string;
7861 resultText: string;
7862 /** Private source coverage; never emitted to the client. */
7863 coverage?: readonly import("@loreai/core").RecallCoverage[];
7864 commit?: () => void;
7865 rollback?: () => void;
7866 }>;
7867 /** Streaming follow-up stage: build + forward + assert-SSE + reader. */
7868 runFollowUp: (ctx: {
7869 /** This is the one final continuation after the last allowed recall. */
7870 finalRecallRound: boolean;
7871 anchorText: string;
7872 resultText: string;
7873 acc: GatewayResponse;
7874 toolUseId: string;
7875 contentPosition: number;
7876 signal: AbortSignal;
7877 }) => Promise<{
7878 reader: ReadableStreamDefaultReader<Uint8Array>;
7879 /** Advance request state only after this continuation starts another recall. */
7880 commit?: () => void;
7881 }>;
7882 },
7883 ): ...
Error: No such path: packages/gateway/src/observability.ts
packages/core/src/read-telemetry.ts packages/core/test/curator-reobservation.test.ts packages/core/test/read-telemetry.test.ts packages/gateway/src/recall-continuation-failure.ts packages/gateway/src/telemetry-privacy.ts packages/gateway/test/delta-upgrade-telemetry.test.ts packages/gateway/test/empty-completion-telemetry.e2e.test.ts packages/gateway/test/sentry-recall-continuation-failure.test.ts packages/gateway/test/telemetry-privacy.test.ts
1 export const RECALL_CONTINUATION_FAILURE_CATEGORIES = [
2 "recall_execution",
3 "follow_up_setup",
4 "follow_up_transport",
5 "follow_up_protocol",
6 "follow_up_failed",
7 "follow_up_missing_output",
8 "follow_up_incomplete_arguments",
9 "parallel_recall",
10 "nested_recall_incomplete",
11 "nested_recall_execution",
12 "depth_exhausted",
13 "missing_recall_block",
14 "resource_limit",
15 "delivery",
16 "unexpected",
17 ] as const;
18
19 export type RecallContinuationFailureCategory =
20 (typeof RECALL_CONTINUATION_FAILURE_CATEGORIES)[number];
21
22 type RecallContinuationFailureHook = (
23 category: RecallContinuationFailureCategory,
24 ) => void;
25
26 let failureHook: RecallContinuationFailureHook | undefined;
27
28 export class RecallContinuationFailure extends Error {
29 constructor(readonly category: ...
Modified regular file packages/gateway/test/openai-responses-stream.test.ts:
...
8 8: * - Stop reason mapping from status
9 9: * - Mixed text + function_call output
10 10: */
11 : import { describe, test, expect, vi } from "vitest";
11: import { log } from "@loreai/core";
12: import { afterEach, describe, test, expect, vi } from "vitest";
12 13: import {
13 14: accumulateResponsesSSEStream,
14 15: isSupportedResponsesOutputItemType,
15 16: isValidResponsesOutputItemStatus,
17: makeResponsesAccState,
16 18: responsesDoneItemMatchesAdded,
17 19: responsesTerminalItemMatches,
18 20: SUPPORTED_RESPONSES_OUTPUT_ITEM_TYPES,
...
23 25: import type { GatewayResponse } from "../src/translate/types";
24 26: import { validateResponsesUsage } from "../src/usage-validation";
25 27:
28: const silentLogSink = {
29: info: () => {},
30: warn: () => {},
31: ...
Modified regular file packages/gateway/test/pipeline-streaming.test.ts:
...
85 85: import { translateAnthropicStreamToOpenAI } from "../src/stream/openai";
86 86: import { translateAnthropicStreamToResponses } from "../src/stream/openai-responses";
87 87: import { translateAnthropicStreamToGemini } from "../src/stream/gemini";
88: import { setRecallContinuationFailureHook } from "../src/recall-continuation-failure";
88 89: import {
89 90: makeConversationFixtures,
90 91: STANDARD_TOOLS,
...
726 727: afterEach(() => harness?.teardown());
727 728: afterEach(() => vi.mocked(getDegradationWarning).mockReset());
728 729: afterEach(() => vi.mocked(Sentry.startInactiveSpan).mockReset());
730: afterEach(() => setRecallContinuationFailureHook(undefined));
729 731:
730 732: it("does not deadlock when an OpenAI translator drops Anthropic lifecycle frames", async () => {
731 733: const anthropic = buildStreamingResponse(
...
--- lpmvqrurxwlmrmwnyllmxlvkmplvwnlz 0dd569b520bad37adbaea230f32100c7f83f463c --- fix(responses): unify provider failure handling --- wswlsmrnuzlqtxyskqotksrlqtzplrkl 24880457763b6f10831856d01c41bd72d62ddc28 --- fix(responses): reject non-monotonic provider failures --- plzxzousrzuvukvvtzlvvynqpokuptqu a1020a45be1382893a183e2ff39506e78a08fb76 --- fix(responses): preserve trusted failure metadata --- skwrwnvkvulpwztqsvprtnrozswvtptx 01a6e06b08ba1b54f42c5b4c757ec449eb8e8490 --- fix(responses): make provider failure settlement atomic --- xqmskzvmnqkrnvmyrznrxkxsxtwyurvu b1bc7cd46c4eb09f23a7a5c6db257c380401ca02 --- fix(responses): complete provider failure sanitization --- qnlnmzlxyynvkvssnkusztrzyxzylkzo 29dee093d7ceed38b0ed823c9d5b26f8c1ba3d7c --- fix(responses): bind sanitized failures to trusted state --- prpmozzzqvktqmyxkmyprklpmqxwktkv d385b39653b0085833e281b6347b15071cee6801 --- fix(responses): sanitize provider failures
The working copy has no changes. Working copy (@) : qnmstlol 248b42ff (empty) (no description set) Parent commit (@-): qzwttkwl 493b0655 fix/responses-provider-failures | fix(responses): isolate failure telemetry Warning: These bookmarks have conflicts: fix/responses-private-references Hint: Use `jj bookmark list` to see details. Use `jj bookmark set <name> -r <rev>` to resolve. lpmvqrurxwlmrmwnyllmxlvkmplvwnlz 0dd569b520bad37adbaea230f32100c7f83f463c M packages/gateway/src/pipeline.ts M packages/gateway/src/stream/openai-responses.ts M packages/gateway/test/openai-responses-recall-aware-stream.test.ts M packages/gateway/test/openai-responses-stream.test.ts M packages/gateway/test/pipeline-streaming.test.ts M packages/gateway/test/recall-codex-stream.test.ts 3458ce2dc248950b13dc69dda91a07f95a2dcd49f128f2f4ec8e218a6d68b46e -
8860 expect(out).not.toContain("private query");
8861 expect(failures).toEqual(["recall_execution"]);
8862 });
8863
8864 test("recall-only: never converts a failed continuation into completed", async () => {
8865 const failures: RecallContinuationFailureCategory[] = [];
8866 setRecallContinuationFailureHook((category) => failures.push(category));
8867 const failedFollowUp = streamFrom([
8868 created("resp_followup_failure", "gpt-5.6-terra"),
8869 textItem(0, "partial answer"),
8870 sseEvent("response.failed", {
8871 response: {
8872 id: "resp_followup_failure",
8873 status: "failed",
8874 usage: { input_tokens: 1_000, output_tokens: 100 },
8875 error: { message: "provider failed" },
8876 },
8877 }),
8878 ]);
8879 const capturedLogs: string[] = [];
8880 log.registerSink({
8881 info: (message) => ...
4145 },
4146 cancel() {
4147 sourceCancelled = true;
4148 return new Promise<void>(() => {});
4149 },
4150 }),
4151 );
4152 const downstreamBody = streamResponsesPassthrough(upstream, () => {}).body;
4153 if (!downstreamBody) throw new Error("test stream has no body");
4154 const reader = downstreamBody.getReader();
4155 await reader.read();
4156 const outcome = await Promise.race([
4157 reader.cancel().then(() => "cancelled"),
4158 new Promise<string>((resolve) => setImmediate(() => resolve("hung"))),
4159 ]);
4160 expect(outcome).toBe("cancelled");
4161 expect(sourceCancelled).toBe(true);
4162 expect(upstream.body?.locked).toBe(false);
4163 });
4164
4165 test("does not emit a second terminal when onComplete throws", async () => {
4166 const output = await streamResponsesPassthrough(
4167 buildSSEResponse([
4168 ...
PASS
2cbf40060c67df229731cf1b9e34d5bf22ec2145lpmvqrurxwlmrmwnyllmxlvkmplvwnlz0dd569b520bad37adbaea230f32100c7f83f463c3458ce2dc248950b13dc69dda91a07f95a2dcd49f128f2f4ec8e218a6d68b46eqnmstlol/248b42ff; I did not treat it or later descendants as candidate content.AGENTS.md and quality/REVIEW.md. The required repo-setup skill was unavailable; I loaded the required Jujutsu guidance instead.Accepted provider failures call log.error() before the state flags, accounting callback, and terminal delivery complete:
packages/gateway/src/stream/openai-responses.ts:2195-2229packages/gateway/src/pipeline.ts:10292-10319packages/gateway/src/pipeline.ts:10965-10998The logger invokes registered sinks without containment:
packages/core/src/log.ts:463-504Attack/failure sequence:
response.created and provider failure pass sequence, alias, status, and usage validation.applyResponsesEvent() records the failed usage.error().openai-responses.ts:2909-2914; that can throw before the fixed terminal and onComplete.providerFailureSeen and finish() at pipeline.ts:10315-10319. The outer error logger at pipeline.ts:11831-11840 can throw again, reaching controller.error() at pipeline.ts:11973-11981. ...Date: Sep 17, 2026 * 🔴 (01:08) User requires failed usage/accounting to be processed independently of client demand; candidate `packages/gateway/src/stream/openai-responses.ts:2864` states: `// Failed usage/accounting never depends on client demand.` * 🟡 (01:08) Candidate diff inspection of `packages/gateway/src/stream/openai-responses.ts:1113-1117` showed validation rejecting duplicate `respon…
Date: Sep 17, 2026 * 🟡 [requested-security-review] (01:03) User requested a substantive, independent, immutable security/privacy review in `/home/byk/Code/opencode-lore-provider-error`, limited strictly to base commit `2cbf40060c67df229731cf1b9e34d5bf22ec2145` through candidate stable change `lpmvqrurxwlmrmwnyllmxlvkmplvwnlz`, exact candidate commit `0dd569b520bad37adbaea230f32100c7f83f463c`. * …