Dashboard › opencode-lore › Session 12LaOwvPsw1p
12LaOwvPsw1pWqEvfPerform an independent read-only security/privacy/pentest review of immutable projection candidate in /home/byk/Code/opencode-lore-responses-projection-fix. Base commit 2cbf40060c67df229731cf1b9e34d5bf22ec2145; candidate change ozrmvotwxzuykyvutstpwpzukpptktxv; head commit 583020fad43e1481470aac2588251b8636d16251. Expected plain jj diff --from main@origin --to ozrmvotw SHA-256 83d7c15b3b0c7dd4b58df93af5f20b0e18de6ad99e939d02aa75c0d5e7dea30d. Exactly two changed files. Do not edit files, format, or mutate VCS. Read AGENTS.md, quality/REVIEW.md, current scripts, every changed line, relevant parser/state/output/logging/callback/persistence/cancellation paths and tests. Verify identity/status/conflicts/scope/hash at start/end. Attack the stable source-index -> public-slot map with sparse/adversarial provider indices, late lower/higher visible items, hidden recall items, unresolved/ordinary tools, malformed events, identity collisions, retry state, continuation shifts, terminal rebuild, backpressure/cancel, and limits. Prove hidden recall data/IDs/arguments never escape; public output indices always identify terminal output slots; mapping changes fail before exposing the triggering frame; internal accumulation still reaches postResponse; public failures are fixed and output:[]; telemetry/logging cannot leak or alter behavior; complexity is bounded. Assess tests and mutation evidence. Use focused tests only if useful; exhaustive validation runs separately. Report PASS/CONCERN/MUST-FIX with exact current file:line evidence and residual risks, then end exactly MERGE or DO-NOT-MERGE. If model recall warns, preserve the session and use local lore recall '<specific query>' rather than returning a warning or empty result.
<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`. ...
=== root === /home/byk/Code/opencode-lore-responses-projection-fix === status === The working copy has no changes. Working copy (@) : qwnymkxp 9285e418 (empty) (no description set) Parent commit (@-): ozrmvotw 583020fa fix/responses-hidden-output* | fix(responses): stabilize sparse principal projection 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. === identities === qwnymkxpumsyyskn 9285e4185a10a4e4734964fed7e342ada4fda044 parents=583020fad43e1481470aac2588251b8636d16251 conflicts=false empty=true description= ozrmvotwxzuykyvu 583020fad43e1481470aac2588251b8636d16251 parents=ab979df5cddfec3952680e423e39564664e881fe conflicts=false empty=false description=fix(responses): stabilize sparse principal projection unznwpylspzqykmn ab979df5cddfec3952680e423e39564664e881fe parents=2cbf40060c67df229731cf1b9e34d5bf22ec2145 conflicts=false empty=false ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/AGENTS.md</path> <type>file</type> <content> 1: <!-- This section is maintained by the coding agent via lore (https://github.com/BYK/loreai) --> 2: ## Long-term Knowledge 3: 4: 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. 5: <!-- End lore-managed section --> 6: 7: ## Review 8: 9: 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. 10: 11: # Project Overview 12: 13: Lore is a **three-tier memory architecture** for AI coding agents. ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/quality/REVIEW.md</path> <type>file</type> <content> 1: # Review Heuristics — Lore 2: 3: This document codifies the review bar for pull requests. It exists because 4: adversarial review has repeatedly caught correctness bugs that a green test 5: suite missed — skip/early-return branches, lifecycle sequences, and fan-out 6: registry gaps. Institutionalizing these patterns so they compound. 7: 8: The review workflow (§6) is referenced from AGENTS.md. 9: 10: --- 11: 12: ## 1. Regression-test discipline 13: 14: Every adversarial-review finding that surfaces a defect **must** land a 15: deterministic regression test in the same PR. The test: 16: - fails on the base branch (proving it reproduces the bug), 17: - passes on the fix (proving the fix works), 18: - drives the *real* precondition, not an artificially-constructed state (e.g. ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "@loreai/gateway",
3: "version": "0.40.0",
4: "type": "module",
5: "license": "FSL-1.1-Apache-2.0",
6: "description": "Lore as a transparent LLM proxy — context management for any AI coding client",
7: "main": "./dist/index.cjs",
8: "types": "./dist/index.d.cts",
9: "exports": {
10: ".": {
11: "types": "./dist/index.d.cts",
12: "bun": "./dist/index.bun.js",
13: "require": "./dist/index.cjs",
14: "default": "./dist/index.cjs"
15: }
16: },
17: "bin": {
18: "lore": "./dist/bin.cjs",
19: "lore-gateway": "./dist/bin.cjs"
20: },
21: "scripts": {
22: "typecheck": "tsc --noEmit",
23: "build": "tsx script/build.ts",
24: "bundle": "tsx script/bundle.ts",
25: "build:binary": "tsx script/build.ts --binary",
26: "build:binary:sea": "tsx script/build-binary-sea.ts",
27: ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "lore-monorepo",
3: "private": true,
4: "type": "module",
5: "license": "FSL-1.1-Apache-2.0",
6: "description": "Monorepo root for Lore — three-tier memory architecture",
7: "main": "./packages/opencode/src/index.ts",
8: "exports": {
9: ".": "./packages/opencode/src/index.ts"
10: },
11: "packageManager": "pnpm@10.28.0",
12: "volta": {
13: "node": "24.16.0",
14: "pnpm": "10.28.0"
15: },
16: "pnpm": {
17: "onlyBuiltDependencies": [
18: "esbuild",
19: "onnxruntime-node",
20: "sharp"
21: ],
22: "overrides": {
23: "basic-ftp": "5.3.1",
24: "ip-address": "10.2.0",
25: "fast-xml-parser": "5.7.3",
26: "@huggingface/hub": "2.11.0",
27: "onnxruntime-node": "1.27.0",
28: "yaml": ">=2.8.3",
29: "esbuild": ">=0.28.1",
30: "@opentelemetry/core": ">=2.8.0",
31: ...
diff --git a/packages/gateway/src/pipeline.ts b/packages/gateway/src/pipeline.ts
index 004e03b3e2..df963c9d36 100644
--- a/packages/gateway/src/pipeline.ts
+++ b/packages/gateway/src/pipeline.ts
@@ -9836,12 +9836,19 @@
}
const terminalEvent = state.terminalEvent ?? "response.completed";
const terminalResponse = state.terminalResponse;
+ const incompleteDetails = terminalResponse?.incomplete_details;
+ const incompleteReason =
+ incompleteDetails &&
+ typeof incompleteDetails === "object" &&
+ !Array.isArray(incompleteDetails) &&
+ typeof (incompleteDetails as Record<string, unknown>).reason === "string"
+ ? (incompleteDetails as Record<string, unknown>).reason
+ : undefined;
return formatResponsesEvent(
terminalEvent,
JSON.stringify({
type: terminalEvent,
response: {
- ...terminalResponse,
id: state.id,
object: "response",
created_at:
@@ -9850,6 +9857,9 ...
Found 100 matches (more matches available)
/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts:
Line 395: type RecallFollowUpCtx,
Line 687: let postResponseStartObserver: (() => void) | undefined;
Line 845: postResponseStartObserver = observer;
Line 932: log.error(
Line 1011: postResponseStartObserver = undefined;
Line 1114: log.error("streaming post-response drop cleanup failed:", error);
Line 1124: log.info("streaming post-response skipped during pipeline reset");
Line 1139: log.warn("streaming post-response queue full; dropping finalizer");
Line 1164: log.error("streaming post-response processing failed:", error);
Line 2722: log.warn(
Line 3345: log.info(
Line 3362: log.info(
Line 3634: log.warn("entity injection failed (non-fatal):", err);
Line 3649: log.warn("knowledge catalog injection failed (non-fatal):", err);
Line 3714: log.info(
...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts</path> <type>file</type> <content> 7770: * 7771: * Unlike the buffered `accumulateResponsesSSEStream` path (which withholds ALL 7772: * client bytes until the entire slow reasoning-heavy upstream completes — the 7773: * cause of opencode's 10s `ProviderHeaderTimeoutError`), this function forwards 7774: * every upstream SSE event to the client AS IT ARRIVES, while transparently 7775: * intercepting a `recall` `function_call` output item: 7776: * 7777: * - **No recall**: forwards everything unchanged (identical to 7778: * `streamResponsesPassthrough`). 7779: * - **Recall + other tools (mixed)**: suppresses the recall item and its 7780: * flow events, emits a synthetic marker text item, then rebuilds the 7781: * terminal `response.completed` reflecting only client-visible output. ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
9139: applyResponsesEvent(acc, "response.output_item.added", {
9140: output_index: index,
9141: item: seedItem,
9142: });
9143: };
9144: const validateResponseLifecycle = (
9145: acc: ResponsesAccState,
9146: event: string,
9147: parsed: Record<string, unknown>,
9148: ): void => {
9149: const lifecycle = responseLifecycleFor(acc);
9150: if (lifecycle.terminal) {
9151: throw new Error(`Responses event after terminal: ${event}`);
9152: }
9153: if (event === "response.created") {
9154: if (lifecycle.created) throw new Error("duplicate response.created");
9155: const response = parsed.response as Record<string, unknown> | undefined;
9156: if (!response || typeof response.id !== "string" || !response.id) {
9157: throw new Error("response.created missing response identity");
9158: ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
10339: // Detect recall and unresolved sparse function-call identities.
10340: if (
10341: (event === "response.output_item.added" ||
10342: event === "response.output_item.done") &&
10343: outputIndex !== undefined
10344: ) {
10345: const item = parsed.item as Record<string, unknown> | undefined;
10346: const isRecallCall =
10347: item?.type === "function_call" && item?.name === "recall";
10348: if (isRecallCall) {
10349: recallDetected = true;
10350: if (!recallIndices.has(outputIndex)) {
10351: recallIndices.add(outputIndex);
10352: newlyPrivateRecallIndex = true;
10353: }
10354: resolvingRecallTool = true;
10355: ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
11445: emitTextItem(
11446: shiftedRecallIndex,
11447: nextExecuted.anchorText,
11448: ),
11449: ),
11450: );
11451: }
11452: }
11453: flushHeldContinuation();
11454: for (const index of contRecallIndices) {
11455: recallIndices.add(shiftedOutputIndex(index, contIndex));
11456: }
11457: mergeContinuation();
11458: if (continuationFollowUpInput.finalRecallRound)
11459: log.info("recall final continuation: completed");
11460: if (!nextRecall || !nextExecuted || ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
320: } from "./cch";
321: import { isClaudeCodeClient, isRotationEligible } from "./session";
322: import { isClaudeCodeSideChannel } from "./side-channel";
323: import {
324: analyzeCacheTurn,
325: categorizeBust,
326: type CacheBustCause,
327: } from "./cache-analytics";
328: import {
329: recordGap,
330: getSessionHistogram,
331: recordGlobalGap,
332: resolveProfile as resolveWarmingProfile,
333: clearWarmupAuthDisabled,
334: creditWarmupHit,
335: resetCircuitBreaker,
336: setWarmingEnabled,
337: } from "./cache-warmer";
338: import {
339: setSentryRequestContext,
340: setSentryCacheContext,
341: setSentryLightContext,
342: setGenAiUsageAttributes,
343: setCacheAnalyticsAttributes,
344: emitCostMetric,
345: emitCacheBustMetric,
346: emitWarmupHitMetric,
347: emitCurationMetrics,
348: spanStartupBackfill,
349: ...
Found 47 matches
/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts:
Line 205: applyResponsesEvent,
Line 206: finalizeResponsesAcc,
Line 208: makeResponsesAccState,
Line 241: parseSSEStream,
Line 248: cancelAndReleaseReader,
Line 6932: if (activeReader) cancelAndReleaseReader(activeReader, streamSignal.reason);
Line 7038: const eventStream = parseSSEStream(reader, {
Line 7127: cancelAndReleaseReader(reader);
Line 7420: // from how the continuation is consumed (parseSSEStream below).
Line 7564: } of parseSSEStream(contReader, {
Line 7591: cancelAndReleaseReader(contReader, streamSignal.reason);
Line 7685: cancelAndReleaseReader(activeReader, err);
Line 7729: cancelAndReleaseReader(activeReader);
Line 7877: let state = makeResponsesAccState();
Line 7940: normalizationState = makeResponsesAccState();
...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
180: buildAnthropicRequest,
181: buildAnthropicNonStreamResponse,
182: parseAnthropicResponseJSON,
183: type AnthropicCacheOptions,
184: } from "./translate/anthropic";
185: import {
186: bedrockMantleUrl,
187: isBedrockMantleDispatch,
188: toMantleModelId,
189: } from "./translate/bedrock";
190: import { buildVertexUpstream, vertexHost } from "./translate/vertex";
191: import { getVertexAccessToken, resolveVertexProject } from "./vertex-auth";
192: import {
193: buildOpenAIUpstreamRequest,
194: buildOpenAIResponse,
195: } from "./translate/openai";
196: import {
197: buildOpenAIResponsesUpstreamRequest,
198: buildOpenAIResponsesResponse,
199: parseOpenAIResponsesRequest,
200: } from "./translate/openai-responses";
201: import {
202: accumulateResponsesSSEStream,
203: streamResponsesPassthrough,
204: ...
Found 6 matches
/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/stream/openai-responses.ts:
Line 48: export interface ResponsesAccState {
Line 556: export function makeResponsesAccState(): ResponsesAccState {
Line 582: export function applyResponsesEvent(
Line 815: export function finalizeResponsesAcc(
Line 2383: export function formatResponsesEvent(event: string, data: string): string {
Line 3325: export function mapStatusFromStopReason(reason: string): string {
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/stream/openai-responses.ts</path> <type>file</type> <content> 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. ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/stream/openai-responses.ts</path>
<type>file</type>
<content>
530: return snapshot;
531: }
532: const finalizedContent = finalizedResponsesMessageContent(
533: outputIndex,
534: terminalContentParts,
535: ).map((part) =>
536: part.kind === "text"
537: ? { type: "output_text", text: part.value }
538: : { type: "refusal", refusal: part.value },
539: );
540: return finalizedContent.length > 0
541: ? { ...snapshot, content: finalizedContent }
542: : snapshot;
543: }
544:
545: /** Validated unsuccessful terminal, carrying usage for accounting-only paths. */
546: export class ResponsesTerminalError extends Error {
547: constructor(
548: readonly response: GatewayResponse,
549: readonly status: string,
550: ) {
551: super(`upstream Responses request ended with status ${status}`);
552: this.name = "ResponsesTerminalError";
553: }
554: }
555: ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/stream/openai-responses.ts</path>
<type>file</type>
<content>
887: return {
888: id: state.id,
889: model: state.model,
890: content,
891: rawOutputItems: Array.from(state.rawItems.entries())
892: .sort(([a], [b]) => a - b)
893: .map(([, item]) => item)
894: .filter((item) => item.type !== "item_reference"),
895: stopReason,
896: usage: state.usage,
897: ...(state.codexRateLimits
898: ? { codexRateLimits: state.codexRateLimits }
899: : {}),
900: };
901: }
902:
903: // ---------------------------------------------------------------------------
904: // Stream accumulator (buffered)
905: // ---------------------------------------------------------------------------
906:
907: function validatePublicResponsesEvent(
908: state: ResponsesAccState,
909: event: string,
910: parsed: Record<string, unknown>,
911: maxSparseIndex: number,
912: ): ...
Found 33 matches /home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/stream/openai-responses.ts: Line 26: DEFAULT_MAX_SSE_FRAMES, Line 907: function validatePublicResponsesEvent( Line 911: maxSparseIndex: number, Line 917: (outputIndex as number) < maxSparseIndex; Line 988: (parsed.content_index as number) >= maxSparseIndex) Line 1094: (parsed.content_index as number) >= maxSparseIndex || Line 1226: maxSparseIndex: number, Line 1229: while (index < maxSparseIndex && state.rawItems.has(index)) index += 1; Line 1230: if (index >= maxSparseIndex) malformedResponsesEvent(); Line 1483: maxSparseIndex: number, Line 1507: outputIndex = nextResponsesOutputIndex(state, maxSparseIndex); Line 1533: maxSparseIndex: number, Line 1579: outputIndex ??= nextResponsesOutputIndex(state, maxSparseIndex); Line 1629: maxSparseIndex: number, Line 1638: (parsed.output_index as number) >= ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/recall-diagnostics.ts</path>
<type>file</type>
<content>
1: import { createHash } from "node:crypto";
2: import { log, type RecallCoverage } from "@loreai/core";
3:
4: /** Keep request-local diagnostic state bounded while observing chains beyond ten rounds. */
5: export const MAX_RECALL_DIAGNOSTIC_ROUNDS = 64;
6:
7: /** Request-local comparisons only. Fingerprints and recall content never leave this closure. */
8: export function createRecallDiagnostics(enabled = true) {
9: const inputs = new Set<string>();
10: const results = new Set<string>();
11: const pairs = new Set<string>();
12: const coverage = new Set<string>();
13: const started = performance.now();
14: let finished = false;
15: let rounds = 0;
16: let detailCalls = 0;
17: let emptyBodies = 0;
18: let resultBytes = 0;
19: const fingerprint = (value: string) =>
20: createHash("sha256").update(value).digest("hex");
21: ...
Found 3 matches
/home/byk/Code/opencode-lore-responses-projection-fix/packages/core/src/log.ts:
Line 13: * An optional {@link LogSink} can be registered via {@link registerSink}.
Line 66: export function registerSink(s: LogSink): void {
Line 464: export function info(...args: unknown[]): void {
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/core/src/log.ts</path>
<type>file</type>
<content>
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`. ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/core/src/log.ts</path>
<type>file</type>
<content>
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);
347: } catch (error) {
348: if ((error as NodeJS.ErrnoException).code === "ENOENT") return;
349: throw error;
350: }
351: if (!existing.isFile() || existing.isSymbolicLink()) {
352: throw new Error(`Refusing non-regular rotated log file: ${path}`);
353: }
354: assertCurrentOwner(existing, path);
355: const fd = ...
Found 100 matches (more matches available)
/home/byk/Code/opencode-lore-responses-projection-fix/packages/pi/test/internal.test.ts:
Line 24: log.registerSink(silentSink);
Line 275: log.registerSink({
Line 300: log.registerSink({
Line 317: log.registerSink({
Line 392: log.registerSink({
/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/test/cache-stability.e2e.test.ts:
Line 1990: log.registerSink(captureSink);
Line 2053: log.registerSink(silentSink);
/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/test/cch.test.ts:
Line 951: log.registerSink({
Line 960: log.registerSink(silentSink);
/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/test/sync.test.ts:
Line 906: log.registerSink({
Line 917: log.registerSink(passthrough); // restore pass-through (no ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/instrument.ts</path>
<type>file</type>
<content>
170:
171: beforeSendTransaction(event) {
172: return scrubTelemetryEvent(event);
173: },
174:
175: // Drop transient network errors that are not actionable bugs.
176: // Each exception in the chain is tested independently so a real bug
177: // wrapping a transient cause isn't accidentally silenced.
178: beforeSend(event) {
179: if (event.message === "Recall continuation failed") {
180: return isolateRecallContinuationEvent(event);
181: }
182: return eventHasTransientError(event) ? null : scrubTelemetryEvent(event);
183: },
184:
185: // Final boundary: sanitize every envelope item, including payload types
186: // added by future SDK integrations that do not pass through hooks above. ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/recall-continuation-failure.ts</path> <type>file</type> <content> 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 ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/principal-transport-failure.ts</path>
<type>file</type>
<content>
1: export const PRINCIPAL_TRANSPORT_FAILURE_KINDS = [
2: "read",
3: "inactivity",
4: ] as const;
5:
6: export type PrincipalTransportFailureKind =
7: (typeof PRINCIPAL_TRANSPORT_FAILURE_KINDS)[number];
8:
9: export const PRINCIPAL_TRANSPORT_FAILURE_STAGES = [
10: "pre_output",
11: "post_output",
12: "post_tool",
13: ] as const;
14:
15: export type PrincipalTransportFailureStage =
16: (typeof PRINCIPAL_TRANSPORT_FAILURE_STAGES)[number];
17:
18: export const PRINCIPAL_TRANSPORT_FAILURE_OUTCOMES = [
19: "retry",
20: "retry_succeeded",
21: "retry_exhausted",
22: "continue",
23: "failed",
24: ] as const;
25:
26: export type PrincipalTransportFailureOutcome =
27: (typeof PRINCIPAL_TRANSPORT_FAILURE_OUTCOMES)[number];
28:
29: export type PrincipalTransportFailureSample = {
30: kind: ...
Found 2 matches
/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts:
Line 7794: export function streamResponsesRecallAware(
Line 18804: streamResponsesRecallAware(upstreamResponse, {
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
18690: }
18691: try {
18692: const postResponseFailed = new Error(
18693: "Responses recall post-response persistence failed",
18694: );
18695: try {
18696: withTenant(sessionState.storageTenantId ?? "", () =>
18697: withSavepoint("responses_recall_post_response", () => {
18698: const persisted = postResponseForTenant(
18699: req,
18700: resp,
18701: sessionState,
18702: config,
18703: temporalInput,
18704: requestBody,
18705: genAiSpan,
18706: suppressTemporalStorage,
18707: endGenAiSpan,
18708: );
18709: if (!persisted) throw postResponseFailed;
18710: ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
18985: const followUpBaseRequest = responsesRecallRequest;
18986: const follow = await runRecallFollowUpStreaming(
18987: followUpCtx,
18988: followUpBaseRequest,
18989: acc,
18990: resultText,
18991: recallBlock,
18992: signal,
18993: finalRecallRound,
18994: );
18995: if (!follow.ok) {
18996: throw new Error(
18997: `recall follow-up upstream error: ${follow.status ?? "?"}`,
18998: );
18999: }
19000: return {
19001: reader: follow.reader,
19002: commit: () => {
19003: responsesRecallRequest = follow.followUp;
19004: ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/test/openai-responses-recall-aware-stream.test.ts</path>
<type>file</type>
<content>
8180: const followUpBody = followUp.body;
8181: let completedResponse: GatewayResponse | undefined;
8182: const client = streamResponsesRecallAware(
8183: streamFrom([
8184: created("resp_allowlisted_principal", "gpt-5.6-terra"),
8185: recallCall(0, { query: "allowlisted continuation" }),
8186: completed("resp_allowlisted_principal"),
8187: ]),
8188: {
8189: validation: "codex",
8190: onComplete: (response) => {
8191: completedResponse = response;
8192: },
8193: onRecall: async ({ query }) => ({
8194: anchorText: buildAnchor(query),
8195: resultText: "private recall result",
8196: }),
8197: runFollowUp: async () => ({ reader: followUpBody.getReader() }),
8198: },
8199: );
8200:
8201: ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/test/openai-responses-recall-aware-stream.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Unit tests for `streamResponsesRecallAware` — the true-streaming,
3: * recall-aware OpenAI Responses (codex/ChatGPT) streamer.
4: *
5: * Regression for the "Provider response headers timed out after 10000ms" issue:
6: * the buffered `accumulateResponsesSSEStream` path withholds ALL client bytes
7: * until the entire (slow, reasoning-heavy) upstream completes, so opencode's
8: * 10s `ProviderHeaderTimeoutError` fired on ChatGPT sessions. This streamer
9: * forwards events live while transparently intercepting a `recall`
10: * function_call (emit marker, run follow-up, rebuild the terminal
11: * `response.completed`).
12: */
13: import { log } from "@loreai/core";
14: import { afterEach, describe, test, expect } from "vitest";
15: import { streamResponsesRecallAware } from "../src/pipeline";
16: import ...
=== first-change ===
Commit ID: ab979df5cddfec3952680e423e39564664e881fe
Change ID: unznwpylspzqykmnpxwnnswmnzpspxzq
Author : Burak Yigit Kaya <ben@byk.im> (2026-09-12 22:22:40)
Committer: Burak Yigit Kaya <ben@byk.im> (2026-09-15 22:20:26)
fix(responses): project hidden output consistently
M packages/gateway/src/pipeline.ts
M packages/gateway/test/openai-responses-recall-aware-stream.test.ts
=== second-change ===
Commit ID: 583020fad43e1481470aac2588251b8636d16251
Change ID: ozrmvotwxzuykyvutstpwpzukpptktxv
Bookmarks: fix/responses-hidden-output* fix/responses-hidden-output@git
Author : Burak Yigit Kaya <ben@byk.im> (2026-09-16 13:14:24)
Committer: Burak Yigit Kaya <ben@byk.im> (2026-09-16 13:43:03)
fix(responses): stabilize sparse principal projection
M packages/gateway/src/pipeline.ts
M packages/gateway/test/openai-responses-recall-aware-stream.test.ts
=== second-change-diff ===
diff --git a/packages/gateway/src/pipeline.ts b/packages/gateway/src/pipeline.ts
index ...
Found 1 matches /home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts: Line 13391: function accountUnsuccessfulResponse(
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/pipeline.ts</path>
<type>file</type>
<content>
13370: });
13371: if (!sessionState.headerSessionId) {
13372: const result = learnHeaders(
13373: sessionState.candidateHeaders,
13374: req.rawHeaders,
13375: );
13376: sessionState.candidateHeaders = result.updatedCandidates;
13377: }
13378: if (!noStore) {
13379: scheduleBackgroundWork(sessionState, config);
13380: }
13381: return true;
13382: } catch (e) {
13383: log.error("post-response processing failed:", e);
13384: return false;
13385: } finally {
13386: endSpan?.();
13387: }
13388: }
13389:
13390: /** Record validated provider usage without publishing successful-turn state. */
13391: function accountUnsuccessfulResponse(
13392: resp: GatewayResponse,
13393: sessionID: string,
13394: resolvedConversationTTL: "5m" | "1h" | undefined,
13395: genAiSpan: Sentry.Span ...
RUN v4.1.8 /home/byk/Code/opencode-lore-responses-projection-fix
Test Files 1 passed (1)
Tests 213 passed (213)
Start at 14:00:09
Duration 11.49s (transform 6.37s, setup 1.73s, import 8.49s, tests 1.02s, environment 0ms)
/home/byk/Code/opencode-lore-responses-projection-fix/stryker.config.mjs
<path>/home/byk/Code/opencode-lore-responses-projection-fix/stryker.config.mjs</path> <type>file</type> <content> 1: // Mutation testing — issue #832. 2: // 3: // Measures whether our tests CONSTRAIN behavior (not merely pass) on the 4: // high-risk STATEFUL modules where review — not tests — caught the recent bugs 5: // (sync prune-floor wedge #828, tier residue #828, decay/evict edge cases #816). 6: // A surviving mutant = a line the suite does not pin (sometimes an equivalent 7: // mutant). ALWAYS hand-verify a survivor by applying the EXACT replacement from 8: // the report — Stryker splits compound `A && B` conditions, so a `:col → "true"` 9: // mutant may be a sub-operand, not the whole condition. See 10: // quality/MUTATION_TESTING.md. 11: // 12: // Run nightly / on-demand; NOT per-PR (slow). No hard gate while we establish a 13: // baseline: `thresholds.break` is null, so the run never fails CI — we record 14: // the score and ratchet over time. ...
No files found
Found 1 matches /home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/stream/anthropic.ts: Line 150: export async function* parseSSEStream(
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/stream/anthropic.ts</path>
<type>file</type>
<content>
95: let onAbort: (() => void) | undefined;
96:
97: if (opts.signal) {
98: const signal = opts.signal;
99: reads.push(
100: new Promise<never>((_resolve, reject) => {
101: onAbort = () => {
102: void reader.cancel(signal.reason).catch(() => {});
103: try {
104: signal.throwIfAborted();
105: } catch (error) {
106: reject(error);
107: }
108: };
109: signal.addEventListener("abort", onAbort, { once: true });
110: if (signal.aborted) onAbort();
111: }),
112: );
113: }
114:
115: if (opts.inactivityMs) {
116: reads.push(
117: new Promise<never>((_resolve, reject) => {
118: inactivityTimer = setTimeout(() => {
119: inactivityError = new SSEStreamTransportError(
120: "inactivity",
121: ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/stream/anthropic.ts</path>
<type>file</type>
<content>
274: }
275: if (shouldProcess) {
276: // Join only when a complete event exists. An attacker fragmenting one
277: // unterminated event into tiny chunks therefore cannot force repeated
278: // copies and full-prefix delimiter scans.
279: const buffer = bufferParts.join("");
280: const delimiter = new RegExp(delimiterPattern, "g");
281: let consumedChars = 0;
282: let consumedBytes = 0;
283: for (;;) {
284: delimiter.lastIndex = consumedChars;
285: const boundary = delimiter.exec(buffer);
286: if (!boundary) break;
287: const block = buffer.slice(consumedChars, boundary.index);
288: // Every delimiter consumes parser work, even when its block is blank or
289: // comment-only and therefore yields no event to the caller. ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/test/openai-responses-recall-aware-stream.test.ts</path>
<type>file</type>
<content>
8125: resultText: "results",
8126: }),
8127: runFollowUp: async () => ({ reader: malformed.body!.getReader() }),
8128: },
8129: );
8130:
8131: const out = await drain(client);
8132: expect(out).not.toContain("must-not-leak");
8133: expect(out).toContain(PUBLIC_RECALL_ERROR);
8134: });
8135:
8136: test.each([
8137: {
8138: name: "custom continuation events",
8139: eventSecret: "private-custom-continuation-event",
8140: terminalSecret: undefined,
8141: },
8142: {
8143: name: "terminal extension fields",
8144: eventSecret: undefined,
8145: terminalSecret: "private-terminal-extension",
8146: },
8147: ])("allows only semantic $name after recall", async (testCase) => {
8148: const followUp = streamFrom([
8149: ...
<path>/home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/test/openai-responses-recall-aware-stream.test.ts</path>
<type>file</type>
<content>
5730: },
5731: },
5732: );
5733: const out = await drain(client);
5734:
5735: expect(out).toContain(buildAnchor("architecture"));
5736: expect(out).not.toContain("Searching");
5737: // Continuation text streamed inline.
5738: expect(out).toContain("Here is the answer from the continuation.");
5739: // Rebuilt terminal event.
5740: expect(out).toContain("response.completed");
5741: // No raw recall function_call leaked.
5742: expect(out).not.toMatch(/name":\s*"recall/);
5743: // The follow-up's OWN lifecycle/terminal events are suppressed — the
5744: // client sees exactly ONE response.created and ONE response.completed
5745: // (as `event:` boundaries; the rebuilt completed also carries
5746: // "type":"response.completed" in its payload, which is ...
No files found
Found 5 matches
/home/byk/Code/opencode-lore-responses-projection-fix/packages/pi/test/internal.test.ts:
Line 24: log.registerSink(silentSink);
Line 275: log.registerSink({
Line 300: log.registerSink({
Line 317: log.registerSink({
Line 392: log.registerSink({
=== status === The working copy has no changes. Working copy (@) : qwnymkxp 9285e418 (empty) (no description set) Parent commit (@-): ozrmvotw 583020fa fix/responses-hidden-output* | fix(responses): stabilize sparse principal projection 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. === identities === qwnymkxpumsyyskn 9285e4185a10a4e4734964fed7e342ada4fda044 parents=583020fad43e1481470aac2588251b8636d16251 conflicts=false empty=true ozrmvotwxzuykyvu 583020fad43e1481470aac2588251b8636d16251 parents=ab979df5cddfec3952680e423e39564664e881fe conflicts=false empty=false unznwpylspzqykmn ab979df5cddfec3952680e423e39564664e881fe parents=2cbf40060c67df229731cf1b9e34d5bf22ec2145 conflicts=false empty=false pxrvwsvvkmpoxnsq 2cbf40060c67df229731cf1b9e34d5bf22ec2145 parents=e977b4b1da8f8197c3238466d41de0bccd8eb054 conflicts=false empty=false === candidate-range-conflicts ...
Found 5 matches /home/byk/Code/opencode-lore-responses-projection-fix/packages/gateway/src/stream/openai-responses.ts: Line 2628: created_at: Math.floor(Date.now() / 1000), Line 2858: created_at: created, Line 2876: created_at: created, Line 3201: created_at: created, Line 3248: created_at: created,
Private recall data can escape through non-semantic SSE frames.
response. at packages/gateway/src/pipeline.ts:10900-10920.remapVisibleOutputIndices() forwards unparsable frames unchanged at packages/gateway/src/pipeline.ts:9983-9988, and transactional delivery emits them at packages/gateway/src/pipeline.ts:11536-11545.event: diagnosticdata: <private recall result, ID, or arguments>
and expose it to the client.packages/gateway/src/pipeline.ts:11604-11618, retained at packages/gateway/src/pipeline.ts:10716-10723, then delivered transactionally.packages/gateway/test/openai-responses-recall-aware-stream.test.ts:8136-8209 covers only JSON response.custom continuation events. It misses non-JSON continuation events and principal custom events.Terminal sanitization permits private-data smuggling through created_at.
buildTerminal() copies terminalResponse.created_at without validating its type at packages/gateway/src/pipeline.ts:9851-9856.created_at, at packages/gateway/src/pipeline.ts:9201-9247.packages/gateway/src/pipeline.ts:11460-11463.{"created_at":{"private_extension":"private recall result"}}
and the rebuilt client terminal will serialize ...