// src/layer/adapters/bash-passthrough-small.ts
//
// Named passthrough adapter for small Bash tool outputs.
//
// Purpose: produce per-adapter telemetry ("ft gain --by-adapter") that
// separates small-Bash skips from the generic `passthrough` fallback.
// No bytes are saved; model sees identical content either way.
//
// Load-bearing rules (see ./types.ts for full contract):
//   Rule A — frozen bytes: compress() is deterministic; same input bytes
//             always produce byte-identical output. (No Date.now(), no
//             Math.random(), no unordered Map/Set iteration.)
//   Rule B — latest-turn only: Wave 3 enforces this; adapter never
//             touches historical turns.
//   Conservative match: BOTH conditions must hold — tool name AND byte
//             budget. Matching on tool name alone would pass large outputs
//             to the wrong downstream path.
//   No side effects: no file writes, no logging, no KB mutations.

import type { ToolResult } from "../../provider/canonical.ts";
import type { ToolResultAdapter, CompressedResult } from "./types.ts";

/** Byte threshold below which Bash output is passed through without compression. */
const SMALL_BYTE_LIMIT = 2048;

/**
 * Derive the raw string representation of a ToolResult's content.
 * Mirrors the same logic used by passthroughAdapter for consistency.
 */
function rawContent(r: ToolResult): string {
  return typeof r.content === "string" ? r.content : JSON.stringify(r.content);
}

export const bashPassthroughSmall: ToolResultAdapter = {
  id: "bash-passthrough-small",

  /**
   * Matches iff:
   *   1. r.toolName === "Bash"        — only Bash tool results
   *   2. UTF-8 byte length < 2048     — only small outputs
   *
   * Conservative: both conditions required. A false positive here would
   * route a large Bash result through unchanged instead of compressing it.
   */
  match(r: ToolResult): boolean {
    if (r.toolName !== "Bash") return false;
    const raw = rawContent(r);
    // Use Buffer.byteLength for correct UTF-8 byte count (not codepoint/char count).
    return Buffer.byteLength(raw, "utf8") < SMALL_BYTE_LIMIT;
  },

  /**
   * Returns the raw content unchanged with zero bytes saved.
   * Semantically identical to passthroughAdapter, but tagged with this
   * adapter's id so telemetry can count small-Bash skips separately.
   */
  compress(r: ToolResult): CompressedResult {
    const raw = rawContent(r);
    return {
      preview: raw,
      kbEntries: [],
      bytesSaved: 0,
    };
  },
};
