CASS - Coding Agent Session Search Unified, high-performance CLI/TUI to index and search your local coding agent history. Aggregates sessions from 23 agents , including Codex, Claude Code, Gemini CLI, Cline, OpenCode, Amp, Cursor, ChatGPT, Aider, Pi-Agent, Factory (Droid), OpenHands, Antigravity, and Grok Build. CRITICAL: Robot Mode Required for AI Agents NEVER run bare - it launches an interactive TUI that blocks your session! Always use or flags for machine-readable output. --- Quick Reference for AI Agents Bounded History Retrieval For a quick project-history question, start with one scope…

\\t'}\n case \"$tracked_mode\" in\n 100644|100755) ;;\n *)\n echo \"Error: source-tree receipt forbids non-regular Git mode $tracked_mode at $tracked_path\"\n exit 1\n ;;\n esac\n if printf '%s' \"$tracked_path\" | LC_ALL=C grep -q '[[:cntrl:]]'; then\n echo \"Error: source-tree receipt forbids control bytes in tracked path: $tracked_path\"\n exit 1\n fi\n done \u003c \u003c(git ls-files --stage -z -- \"${SOURCE_TREE_PATHS[@]}\")\n SOURCE_TREE_SHA256=$(\n git ls-files --cached -z -- \"${SOURCE_TREE_PATHS[@]}\" \\\n | LC_ALL=C sort -z \\\n | xargs -0 -r sha256sum --zero -- \\\n | sha256sum \\\n | awk '{print $1}'\n )\n if [[ ! \"$SOURCE_TREE_SHA256\" =~ ^[0-9a-f]{64}$ ]]; then\n echo \"Error: could not compute a canonical source-tree SHA-256\"\n exit 1\n fi\nfi\n\nFINAL_RUN_ROOT=\"$E2E_RESULTS_ROOT/runs/$RUN_ID\"\nmkdir -p \"$E2E_RESULTS_ROOT/runs\" \"$E2E_RESULTS_ROOT/reports\"\n\nif [[ \"$QUICK_MODE\" == false ]]; then\n echo \"Step 1: Running E2E tests into an immutable strict-RCH bundle...\"\n if [[ -z \"$WORKER_ID\" ]]; then\n echo \"Error: RCH_WORKER or --worker is required; full acceptance never auto-selects\"\n exit 2\n fi\n validate_worker_id \"$WORKER_ID\"\n if [[ -e \"$FINAL_RUN_ROOT\" ]]; then\n echo \"Error: refusing to reuse existing run destination: $FINAL_RUN_ROOT\"\n exit 1\n fi\n ensure_rch\n resolve_worker_ssh_target\n\n E2E_TEST_ARGS=()\n if [[ \"$CONTRACT_ONLY\" == true ]]; then\n E2E_TEST_ARGS=(--test \"$CONTRACT_TARGET\" \"$CONTRACT_FILTER\")\n else\n while IFS= read -r test_file; do\n test_target=$(basename \"$test_file\" .rs)\n E2E_TEST_ARGS+=(--test \"$test_target\")\n done \u003c \u003c(find tests -maxdepth 1 -type f -name 'e2e_*.rs' | sort)\n fi\n if [[ ${#E2E_TEST_ARGS[@]} -eq 0 ]]; then\n echo \"FAIL: No tests/e2e_*.rs targets were discovered\"\n exit 1\n fi\n echo \" Run ID: $RUN_ID\"\n echo \" Worker: $WORKER_ID\"\n echo \" Source: $SOURCE_SHA\"\n echo \" Source diff SHA-256: $SOURCE_DIFF_SHA256\"\n echo \" Source tree SHA-256: $SOURCE_TREE_SHA256\"\n echo \" Evidence scope: $EVIDENCE_SCOPE\"\n if [[ \"$CONTRACT_ONLY\" == true ]]; then\n echo \" Contract target/filter: $CONTRACT_TARGET :: $CONTRACT_FILTER\"\n else\n echo \" Explicit E2E targets: $((${#E2E_TEST_ARGS[@]} / 2))\"\n fi\n\n mkdir -p \"$E2E_RESULTS_ROOT/rch-streams\"\n TEST_OUTPUT_FILE=\"$E2E_RESULTS_ROOT/rch-streams/$RUN_ID.log\"\n set +e\n run_cargo run --locked --bin e2e-run-bundle -- \\\n run \\\n --run-id \"$RUN_ID\" \\\n --worker-id \"$WORKER_ID\" \\\n --source-sha \"$SOURCE_SHA\" \\\n --source-diff-sha256 \"$SOURCE_DIFF_SHA256\" \\\n --source-tree-sha256 \"$SOURCE_TREE_SHA256\" \\\n --timeout-seconds \"${RCH_TEST_TIMEOUT_SEC:-7200}\" \\\n -- \\\n --locked \\\n \"${E2E_TEST_ARGS[@]}\" \\\n -- \\\n --test-threads=1 2>&1 | tee \"$TEST_OUTPUT_FILE\"\n RCH_EXIT=$?\n set -e\n RCH_RESULT_ACCEPTABLE=false\n if RCH_ARTIFACT_SYNC_DISPOSITION=$(\n classify_rch_runner_result \"$RCH_EXIT\" \"$TEST_OUTPUT_FILE\" \"$WORKER_ID\"\n ); then\n RCH_RESULT_ACCEPTABLE=true\n fi\n\n mapfile -t RUN_STARTS \u003c \u003c(\n jq -Rrc \\\n --arg run_id \"$RUN_ID\" \\\n --arg worker_id \"$WORKER_ID\" \\\n --arg source_sha \"$SOURCE_SHA\" \\\n --arg source_diff_sha256 \"$SOURCE_DIFF_SHA256\" \\\n --arg source_tree_sha256 \"$SOURCE_TREE_SHA256\" \\\n 'fromjson? | select(\n .schema_version == 2\n and .kind == \"e2e-run-started\"\n and .run_id == $run_id\n and .worker_id == $worker_id\n and .source_sha == $source_sha\n and .source_diff_sha256 == $source_diff_sha256\n and .source_tree_sha256 == $source_tree_sha256\n and (.run_root | type == \"string\")\n )' \\\n \"$TEST_OUTPUT_FILE\"\n )\n mapfile -t RUN_SUMMARIES \u003c \u003c(\n jq -Rrc \\\n --arg run_id \"$RUN_ID\" \\\n --arg worker_id \"$WORKER_ID\" \\\n --arg source_sha \"$SOURCE_SHA\" \\\n --arg source_diff_sha256 \"$SOURCE_DIFF_SHA256\" \\\n --arg source_tree_sha256 \"$SOURCE_TREE_SHA256\" \\\n 'fromjson? | select(\n .schema_version == 2\n and .kind == \"e2e-run-finalized\"\n and .run_id == $run_id\n and .worker_id == $worker_id\n and .source_sha == $source_sha\n and .source_diff_sha256 == $source_diff_sha256\n and .source_tree_sha256 == $source_tree_sha256\n and (.manifest | type == \"string\")\n )' \\\n \"$TEST_OUTPUT_FILE\"\n )\n if [[ ${#RUN_SUMMARIES[@]} -ne 1 ]]; then\n echo \"Error: expected one versioned runner receipt for $RUN_ID; found ${#RUN_SUMMARIES[@]}\"\n if [[ ${#RUN_STARTS[@]} -eq 1 ]]; then\n INCOMPLETE_REMOTE_ROOT=$(jq -er '.run_root' \u003c\u003c\u003c\"${RUN_STARTS[0]}\")\n if [[ \"$INCOMPLETE_REMOTE_ROOT\" =~ ^/[A-Za-z0-9_./-]+$ ]] \\\n && [[ \"$INCOMPLETE_REMOTE_ROOT\" != *\"..\"* ]] \\\n && [[ \"$INCOMPLETE_REMOTE_ROOT\" == */test-results/e2e/runs/\"$RUN_ID\" ]] \\\n && worker_ssh \"test -d '$INCOMPLETE_REMOTE_ROOT'\"; then\n INCOMPLETE_STAGING_PARENT=\"$E2E_RESULTS_ROOT/incoming/$(date -u +%Y%m%dT%H%M%SZ)-$\"\n INCOMPLETE_STAGING_DIR=\"$INCOMPLETE_STAGING_PARENT/$RUN_ID\"\n mkdir -p \"$INCOMPLETE_STAGING_DIR\"\n worker_rsync \\\n \"$SSH_TARGET:$INCOMPLETE_REMOTE_ROOT/\" \\\n \"$INCOMPLETE_STAGING_DIR/\"\n echo \" Incomplete remote run retained for diagnosis: $INCOMPLETE_STAGING_DIR\"\n else\n echo \" Started receipt did not name one retrievable, validated remote run root\"\n fi\n else\n echo \" Expected one versioned started receipt; found ${#RUN_STARTS[@]}\"\n fi\n exit 1\n fi\n REMOTE_MANIFEST=$(jq -er '.manifest' \u003c\u003c\u003c\"${RUN_SUMMARIES[0]}\")\n REMOTE_RUN_ROOT=${REMOTE_MANIFEST%/manifest.json}\n if [[ \"$REMOTE_RUN_ROOT\" == \"$REMOTE_MANIFEST\" ]] \\\n || [[ ! \"$REMOTE_RUN_ROOT\" =~ ^/[A-Za-z0-9_./-]+$ ]] \\\n || [[ \"$REMOTE_RUN_ROOT\" == *\"..\"* ]] \\\n || [[ \"$REMOTE_RUN_ROOT\" != */test-results/e2e/runs/\"$RUN_ID\" ]]; then\n echo \"Error: runner receipt contains an unsafe or mismatched manifest path\"\n exit 1\n fi\n if ! worker_ssh \\\n \"test -d '$REMOTE_RUN_ROOT' && test -f '$REMOTE_MANIFEST'\"; then\n echo \"Error: exact RCH worker does not contain the receipted bundle\"\n exit 1\n fi\n REMOTE_HOSTNAME=$(worker_ssh hostname | tr -d '\\r\\n')\n if [[ -z \"$REMOTE_HOSTNAME\" ]]; then\n echo \"Error: exact worker returned an empty hostname\"\n exit 1\n fi\n\n STAGING_PARENT=\"$E2E_RESULTS_ROOT/incoming/$(date -u +%Y%m%dT%H%M%SZ)-$\"\n STAGING_DIR=\"$STAGING_PARENT/$RUN_ID\"\n mkdir -p \"$STAGING_DIR\"\n worker_rsync \\\n \"$SSH_TARGET:$REMOTE_RUN_ROOT/\" \\\n \"$STAGING_DIR/\"\n\n if ! verify_bundle_locally \\\n \"$STAGING_DIR\" \\\n \"$RUN_ID\" \\\n \"$WORKER_ID\" \\\n \"$REMOTE_HOSTNAME\" \\\n \"$SOURCE_SHA\" \\\n \"$SOURCE_DIFF_SHA256\" \\\n \"$SOURCE_TREE_SHA256\"; then\n echo \"Error: retrieved run failed byte/provenance verification\"\n echo \" Recoverable staging evidence retained at: $STAGING_DIR\"\n exit 1\n fi\n CARGO_EXIT=$(jq -er '.cargo_exit_code' \"$STAGING_DIR/manifest.json\")\n ACCEPTANCE_PASS=$(jq -er '.complete and (.cargo_exit_code == 0) and ([.gates[].passed] | all)' \\\n \"$STAGING_DIR/manifest.json\")\n if [[ \"$RCH_RESULT_ACCEPTABLE\" != true || \"$ACCEPTANCE_PASS\" != true ]]; then\n echo \"Error: run failed closed (rch=$RCH_EXIT disposition=$RCH_ARTIFACT_SYNC_DISPOSITION cargo=$CARGO_EXIT acceptance=$ACCEPTANCE_PASS)\"\n echo \" Recoverable staging evidence retained at: $STAGING_DIR\"\n if [[ \"$CARGO_EXIT\" -ne 0 ]]; then\n exit \"$CARGO_EXIT\"\n fi\n exit 1\n fi\n if [[ \"$RCH_EXIT\" -eq 102 ]]; then\n echo \" RCH disposition: $RCH_ARTIFACT_SYNC_DISPOSITION\"\n echo \" The remote runner and verified bundle are complete; no local runner binary is consumed.\"\n fi\n TEST_RESULTS_DIR=\"$STAGING_DIR\"\n PUBLISH_PENDING=true\n echo \" Verified staged run bundle: $TEST_RESULTS_DIR\"\n TEST_EXIT=0\nelse\n echo \"Step 1: Quick mode - verifying only explicit run $RUN_ID...\"\n EVIDENCE_SCOPE=\"sealed-run-reverification\"\n if [[ ! -d \"$FINAL_RUN_ROOT\" ]]; then\n echo \"Error: completed run directory does not exist: $FINAL_RUN_ROOT\"\n exit 1\n fi\n SOURCE_SHA=$(jq -er '.source_sha' \"$FINAL_RUN_ROOT/manifest.json\")\n SOURCE_DIFF_SHA256=$(jq -er '.source_diff_sha256' \"$FINAL_RUN_ROOT/manifest.json\")\n SOURCE_TREE_SHA256=$(jq -er '.source_tree_sha256' \"$FINAL_RUN_ROOT/manifest.json\")\n if [[ -z \"$WORKER_ID\" ]]; then\n WORKER_ID=$(jq -er '.worker_id' \"$FINAL_RUN_ROOT/manifest.json\")\n fi\n validate_worker_id \"$WORKER_ID\"\n REMOTE_HOSTNAME=$(jq -er '.worker_hostname' \"$FINAL_RUN_ROOT/manifest.json\")\n verify_bundle_locally \\\n \"$FINAL_RUN_ROOT\" \\\n \"$RUN_ID\" \\\n \"$WORKER_ID\" \\\n \"$REMOTE_HOSTNAME\" \\\n \"$SOURCE_SHA\" \\\n \"$SOURCE_DIFF_SHA256\" \\\n \"$SOURCE_TREE_SHA256\"\n ACCEPTANCE_PASS=$(jq -er '.complete and (.cargo_exit_code == 0) and ([.gates[].passed] | all)' \\\n \"$FINAL_RUN_ROOT/manifest.json\")\n if [[ \"$ACCEPTANCE_PASS\" != true ]]; then\n echo \"Error: completed bundle is integrity-valid but not an acceptance pass\"\n exit 1\n fi\n TEST_RESULTS_DIR=\"$FINAL_RUN_ROOT\"\n TEST_EXIT=0\nfi\n\nREPORT_FILE=\"$E2E_RESULTS_ROOT/reports/$RUN_ID.txt\"\n\n# Step 2: Verify JSONL files were created\necho \"\"\necho \"Step 2: Verifying JSONL files created...\"\nJSONL_FILES=()\nTRACE_FILES=()\nwhile IFS= read -r -d '' file; do\n JSONL_FILES+=(\"$file\")\ndone \u003c \u003c(\n find \"$TEST_RESULTS_DIR\" \\\n -type f \\( -name \"*.jsonl\" -o -name \"cass.log\" \\) \\\n ! -name \"trace.jsonl\" \\\n ! -name \"combined.jsonl\" \\\n ! -path \"$TEST_RESULTS_DIR/.previous/*\" \\\n -print0 2>/dev/null | sort -z\n)\nwhile IFS= read -r -d '' file; do\n TRACE_FILES+=(\"$file\")\ndone \u003c \u003c(\n find \"$TEST_RESULTS_DIR\" \\\n -type f -name \"trace.jsonl\" \\\n ! -path \"$TEST_RESULTS_DIR/.previous/*\" \\\n -print0 2>/dev/null | sort -z\n)\n\nJSONL_COUNT=${#JSONL_FILES[@]}\nif [[ \"$JSONL_COUNT\" -eq 0 ]]; then\n echo \"FAIL: No JSONL files created in $TEST_RESULTS_DIR\"\n echo \" Make sure E2E_LOG=1 is set when running tests\"\n exit 1\nfi\necho \" Found $JSONL_COUNT JSONL/log files\"\necho \" Found ${#TRACE_FILES[@]} versioned per-test trace files\"\n\nNONEMPTY_TRACE_COUNT=0\nTRACE_BYTES=0\nTRACE_EVENTS=0\nfor trace_file in \"${TRACE_FILES[@]}\"; do\n if [[ -s \"$trace_file\" ]]; then\n NONEMPTY_TRACE_COUNT=$((NONEMPTY_TRACE_COUNT + 1))\n TRACE_BYTES=$((TRACE_BYTES + $(wc -c \u003c \"$trace_file\")))\n TRACE_EVENTS=$((TRACE_EVENTS + $(wc -l \u003c \"$trace_file\")))\n fi\ndone\necho \" Non-empty trace files: $NONEMPTY_TRACE_COUNT\"\necho \" Persisted trace bytes: $TRACE_BYTES\"\necho \" Persisted trace events: $TRACE_EVENTS\"\nif [[ \"$QUICK_MODE\" == false && \"$NONEMPTY_TRACE_COUNT\" -eq 0 ]]; then\n echo \"FAIL: Full acceptance run produced no diagnostic trace events\"\n exit 1\nfi\n\n# Step 3: Validate all JSONL files with schema validator\necho \"\"\necho \"Step 3: Validating JSONL schema...\"\nif [[ -x \"$SCRIPT_DIR/validate-e2e-jsonl.sh\" ]]; then\n if ! \"$SCRIPT_DIR/validate-e2e-jsonl.sh\" \"${JSONL_FILES[@]}\" \"${TRACE_FILES[@]}\"; then\n echo \"FAIL: JSONL schema validation failed\"\n exit 1\n fi\n echo \" Schema validation passed\"\nelse\n echo \" Warning: validate-e2e-jsonl.sh not found, skipping schema validation\"\nfi\n\nif [[ \"$NONEMPTY_TRACE_COUNT\" -gt 0 ]]; then\n echo \" Trace target histogram (top 20):\"\n jq -r '.target // \"unknown\"' \"${TRACE_FILES[@]}\" 2>/dev/null \\\n | sort \\\n | uniq -c \\\n | sort -nr \\\n | head -20 \\\n | sed 's/^/ /'\n echo \" Trace receipts:\"\n jq -r '.fields.event // empty' \"${TRACE_FILES[@]}\" 2>/dev/null \\\n | awk '\n $0 == \"trace_truncated\" { truncated += 1 }\n $0 == \"trace_filter_summary\" { filtered += 1 }\n $0 == \"command_summary\" { commands += 1 }\n END {\n printf \" command_summary=%d trace_filter_summary=%d trace_truncated=%d\\n\",\n commands, filtered, truncated\n }\n '\nfi\n\n# Step 4: Check event type coverage\necho \"\"\necho \"Step 4: Checking event coverage...\"\nEVENTS=$(cat \"${JSONL_FILES[@]}\" 2>/dev/null | jq -r '.event' 2>/dev/null | sort -u | grep -v '^

CASS - Coding Agent Session Search Unified, high-performance CLI/TUI to index and search your local coding agent history. Aggregates sessions from 23 agents , including Codex, Claude Code, Gemini CLI, Cline, OpenCode, Amp, Cursor, ChatGPT, Aider, Pi-Agent, Factory (Droid), OpenHands, Antigravity, and Grok Build. CRITICAL: Robot Mode Required for AI Agents NEVER run bare - it launches an interactive TUI that blocks your session! Always use or flags for machine-readable output. --- Quick Reference for AI Agents Bounded History Retrieval For a quick project-history question, start with one scope…

|| true)\n\n# In quick mode, only require test_start/test_end (per-test logs don't have run events)\n# In full mode, require all event types including run_start/run_end\nif [[ \"$QUICK_MODE\" == true ]]; then\n REQUIRED_EVENTS=\"test_start test_end\"\n echo \" (Quick mode: only checking for test events)\"\nelse\n REQUIRED_EVENTS=\"run_start test_start test_end run_end\"\nfi\nMISSING_EVENTS=()\n\nfor event in $REQUIRED_EVENTS; do\n if ! echo \"$EVENTS\" | grep -q \"^${event}$\"; then\n MISSING_EVENTS+=(\"$event\")\n fi\ndone\n\nif [[ ${#MISSING_EVENTS[@]} -gt 0 ]]; then\n echo \"FAIL: Missing required event types: ${MISSING_EVENTS[*]}\"\n exit 1\nfi\necho \" All required event types present: $REQUIRED_EVENTS\"\n\n# List all event types found\nUNIQUE_EVENT_COUNT=$(echo \"$EVENTS\" | wc -l | tr -d ' ')\necho \" Found $UNIQUE_EVENT_COUNT unique event types: $(echo \"$EVENTS\" | tr '\\n' ' ')\"\n\n# Step 5: Check phase event coverage\necho \"\"\necho \"Step 5: Checking phase event coverage...\"\nPHASE_START_COUNT=$(cat \"${JSONL_FILES[@]}\" 2>/dev/null | jq 'select(.event == \"phase_start\")' 2>/dev/null | wc -l | tr -d ' ')\nPHASE_END_COUNT=$(cat \"${JSONL_FILES[@]}\" 2>/dev/null | jq 'select(.event == \"phase_end\")' 2>/dev/null | wc -l | tr -d ' ')\n\necho \" phase_start events: $PHASE_START_COUNT\"\necho \" phase_end events: $PHASE_END_COUNT\"\n\nPHASE_WARNING=\"\"\nif [[ \"$PHASE_END_COUNT\" -lt 10 ]]; then\n PHASE_WARNING=\"WARNING: Only $PHASE_END_COUNT phase_end events (target: > 10)\"\n echo \" $PHASE_WARNING\"\nelse\n echo \" Phase coverage: OK (> 10 phase events)\"\nfi\n\n# Step 6: Check metrics event coverage\necho \"\"\necho \"Step 6: Checking metrics coverage...\"\nMETRICS_COUNT=$(cat \"${JSONL_FILES[@]}\" 2>/dev/null | jq 'select(.event == \"metrics\")' 2>/dev/null | wc -l | tr -d ' ')\necho \" metrics events: $METRICS_COUNT\"\n\nMETRICS_WARNING=\"\"\nif [[ \"$METRICS_COUNT\" -lt 5 ]]; then\n METRICS_WARNING=\"WARNING: Only $METRICS_COUNT metrics events (target: > 5)\"\n echo \" $METRICS_WARNING\"\nelse\n echo \" Metrics coverage: OK (> 5 metrics events)\"\nfi\n\n# Step 7: Generate summary report\necho \"\"\necho \"Step 7: Generating summary report...\"\nTOTAL_EVENTS=$(cat \"${JSONL_FILES[@]}\" 2>/dev/null | wc -l | tr -d ' ')\nif [[ \"$PUBLISH_PENDING\" == true ]]; then\n OLD_RESULTS_DIR=\"$TEST_RESULTS_DIR\"\n mv \"$TEST_RESULTS_DIR\" \"$FINAL_RUN_ROOT\"\n TEST_RESULTS_DIR=\"$FINAL_RUN_ROOT\"\n for index in \"${!JSONL_FILES[@]}\"; do\n JSONL_FILES[$index]=\"$FINAL_RUN_ROOT/${JSONL_FILES[$index]#\"$OLD_RESULTS_DIR\"/}\"\n done\n for index in \"${!TRACE_FILES[@]}\"; do\n TRACE_FILES[$index]=\"$FINAL_RUN_ROOT/${TRACE_FILES[$index]#\"$OLD_RESULTS_DIR\"/}\"\n done\n echo \" Published verified run bundle after all blocking gates: $FINAL_RUN_ROOT\"\nfi\nMANIFEST_FILE=\"$TEST_RESULTS_DIR/manifest.json\"\nCOMPLETION_FILE=\"$TEST_RESULTS_DIR/complete.json\"\nMANIFEST_SHA256=$(sha256sum \"$MANIFEST_FILE\" | awk '{print $1}')\nCOMPLETION_SHA256=$(sha256sum \"$COMPLETION_FILE\" | awk '{print $1}')\nWORKER_HOSTNAME=$(jq -er '.worker_hostname' \"$MANIFEST_FILE\")\nCOMMAND_SHA256=$(jq -er '.command_sha256' \"$MANIFEST_FILE\")\nCOMMAND_JSON=$(jq -c '.command' \"$MANIFEST_FILE\")\nSTARTED_AT_UNIX_MS=$(jq -er '.started_at_unix_ms' \"$MANIFEST_FILE\")\nENDED_AT_UNIX_MS=$(jq -er '.ended_at_unix_ms' \"$MANIFEST_FILE\")\nGATE_REPORT=$(jq -r '.gates[] | \" \\(.name): \\(.passed) - \\(.detail)\"' \"$MANIFEST_FILE\")\n\nmkdir -p \"$TEST_RESULTS_DIR\"\ncat > \"$REPORT_FILE\" \u003c\u003cEOF\n=== E2E Logging Acceptance Report ===\nGenerated: $(date -Iseconds)\n\nRun Identity\n------------\nRun ID: $RUN_ID\nEvidence scope: $EVIDENCE_SCOPE\nSource SHA: $SOURCE_SHA\nSource diff SHA-256: $SOURCE_DIFF_SHA256\nSource tree SHA-256: $SOURCE_TREE_SHA256\nWorker ID: $WORKER_ID\nWorker hostname: $WORKER_HOSTNAME\nCommand: $COMMAND_JSON\nCommand SHA-256: $COMMAND_SHA256\nStarted Unix ms: $STARTED_AT_UNIX_MS\nEnded Unix ms: $ENDED_AT_UNIX_MS\nManifest SHA-256: $MANIFEST_SHA256\nCompletion receipt SHA-256: $COMPLETION_SHA256\n\nTest Execution\n--------------\nExit code: $TEST_EXIT\nQuick mode: $QUICK_MODE\nRCH wrapper exit: $RCH_EXIT\nRCH artifact sync disposition: $RCH_ARTIFACT_SYNC_DISPOSITION\nTest output: ${TEST_OUTPUT_FILE:-n/a}\n\nFile Coverage\n-------------\nJSONL/log files: $JSONL_COUNT\nTotal events: $TOTAL_EVENTS\nTrace files: ${#TRACE_FILES[@]}\nNon-empty trace files: $NONEMPTY_TRACE_COUNT\nTrace bytes: $TRACE_BYTES\nTrace events: $TRACE_EVENTS\n\nEvent Type Coverage\n-------------------\nRequired events: $REQUIRED_EVENTS\nAll required present: YES\nUnique event types: $UNIQUE_EVENT_COUNT\n\nPhase Coverage\n--------------\nphase_start: $PHASE_START_COUNT\nphase_end: $PHASE_END_COUNT\nStatus: $([ \"$PHASE_END_COUNT\" -ge 10 ] && echo \"PASS (>= 10)\" || echo \"WARN (\u003c 10)\")\n\nMetrics Coverage\n----------------\nmetrics events: $METRICS_COUNT\nStatus: $([ \"$METRICS_COUNT\" -ge 5 ] && echo \"PASS (>= 5)\" || echo \"WARN (\u003c 5)\")\n\nManifest Gates\n--------------\n$GATE_REPORT\n\nFiles Validated\n---------------\n$(printf '%s\\n' \"${JSONL_FILES[@]}\")\n$(printf '%s\\n' \"${TRACE_FILES[@]}\")\n\n=== End Report ===\nEOF\n\necho \" Report saved to: $REPORT_FILE\"\necho \"\"\ncat \"$REPORT_FILE\"\n\n# Final result\necho \"\"\necho \"=============================================\"\nif [[ $TEST_EXIT -ne 0 ]]; then\n echo \"=== ACCEPTANCE TEST FAILED ===\"\n echo \"E2E test exit code: $TEST_EXIT\"\n exit 1\nelif [[ -z \"$PHASE_WARNING\" ]] && [[ -z \"$METRICS_WARNING\" ]]; then\n echo \"=== ACCEPTANCE TEST PASSED ===\"\n exit 0\nelse\n echo \"=== ACCEPTANCE TEST PASSED (with warnings) ===\"\n [[ -n \"$PHASE_WARNING\" ]] && echo \" - $PHASE_WARNING\"\n [[ -n \"$METRICS_WARNING\" ]] && echo \" - $METRICS_WARNING\"\n echo \"\"\n echo \"Note: Logging infrastructure is working. Warnings indicate\"\n echo \"some tests may need additional instrumentation.\"\n exit 0\nfi\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":55279,"content_sha256":"7df93875c079a8e98b780ac728731baa71df464717d9af43de1f589e08f14b75"},{"filename":"scripts/gate.sh","content":"#!/usr/bin/env bash\n# gate.sh — the blocking quality gate, batched into ONE rch fleet admission.\n#\n# Why this exists (reality check 2026-09-01, WS-A.2): every GitHub workflow is\n# disabled, so the only gate is agent-run. Fleet admissions are scarce, and an\n# agent that spends one on `cargo check`, then another on clippy, then another\n# on tests loses most of an hour to refusals — and the temptation to push\n# unverified follows. This script runs exactly what CI will run, inside a\n# single remote job, and prints one receipt line per stage:\n#\n# STAGE=\u003cname> EXIT=\u003ccode>\n#\n# The receipt is what a bead closure or a push cites. Nothing here weakens a\n# gate: stages run with the same flags CI uses, and a stage failure never stops\n# the later stages (you want the whole picture from one admission).\n#\n# Usage:\n# scripts/gate.sh # fmt, clippy, lib tests, targeted integration, goldens\n# scripts/gate.sh --lib-filter 'quill_bridge::tests health_watermark' # narrow the lib run\n# scripts/gate.sh --no-lib # skip the lib suite (e.g. while bet45 wedge is open)\n# scripts/gate.sh --no-bin # skip the cass bin's own unit tests (stage bin-cass)\n# scripts/gate.sh --local # run stages locally (only where rch is not required)\n# scripts/gate.sh --print-remote-script # inspect the batch without admitting or executing it\n# GATE_RETRIES=40 GATE_RETRY_SLEEP=90 scripts/gate.sh # keep retrying fleet refusals\n#\n# Exit code: 0 when every stage exited 0, 1 otherwise, 103 if the fleet refused\n# every attempt (RCH_REQUIRE_REMOTE=1 forbids local fallback).\n\nset -uo pipefail\n\ntest_log_counts() {\n local log=\"$1\"\n shift\n local filters_nl=\"\"\n if [ \"$#\" -gt 0 ]; then\n printf -v filters_nl '%s\\n' \"$@\"\n fi\n GATE_TEST_FILTERS=\"$filters_nl\" awk '\n BEGIN {\n n = split(ENVIRON[\"GATE_TEST_FILTERS\"], raw_filters, \"\\n\")\n for (i = 1; i \u003c= n; i++) {\n if (length(raw_filters[i]) > 0) {\n filters[++filter_count] = raw_filters[i]\n }\n }\n }\n /^running [0-9]+ tests?$/ {\n announced[++depth] = $2\n next\n }\n depth == 1 && /^test [^ ].* \\.\\.\\. ok$/ {\n line = $0\n sub(/^test /, \"\", line)\n sub(/ \\.\\.\\. ok$/, \"\", line)\n sub(/ - should panic$/, \"\", line)\n for (f = 1; f \u003c= filter_count; f++) {\n if (index(line, filters[f]) > 0) {\n matched[f]++\n }\n }\n next\n }\n /^test result: ok\\. [0-9]+ passed; [0-9]+ failed; [0-9]+ ignored; [0-9]+ measured; [0-9]+ filtered out/ {\n if (depth == 0) { incomplete++; next }\n if ($6 != 0 || $4 + $6 + $8 + $10 != announced[depth]) incomplete++\n if ($4 == 0) empty++\n delete announced[depth--]\n # Inherited subprocess output nests inside its parent test run.\n # Count each top-level binary once; every child must still finish.\n if (depth == 0) { binaries++; passed += $4 }\n next\n }\n /^test result:/ { incomplete++ }\n END {\n for (f = 1; f \u003c= filter_count; f++) {\n if (!matched[f]) {\n printf \"gate: test filter matched 0 passing tests: %s\\n\", filters[f] > \"/dev/stderr\"\n unmatched++\n }\n }\n if (binaries == 0 || empty > 0 || incomplete > 0 || depth != 0 || unmatched > 0) exit 1\n printf \"PASSED=%d BINARIES=%d\\n\", passed, binaries\n }\n ' \"$log\"\n}\n\nverify_receipt() {\n local receipt=\"$1\" remote_rc=\"$2\"\n shift 2\n local failed=0 line name stage last_stage=\"\"\n local -A seen=() counts=()\n if [ \"$remote_rc\" -ne 0 ]; then\n echo \"STAGE=rch EXIT=${remote_rc} (remote job did not complete normally)\"\n failed=1\n fi\n while IFS= read -r line; do\n if [[ \"$line\" =~ ^TEST_COUNT=([a-z0-9_-]+)\\ PASSED=([1-9][0-9]*)\\ BINARIES=([1-9][0-9]*)$ ]]; then\n counts[\"${BASH_REMATCH[1]}\"]=1\n elif [[ \"$line\" =~ ^STAGE=([a-z0-9_-]+)\\ EXIT=([0-9]+)$ ]]; then\n name=\"${BASH_REMATCH[1]}\"\n [ -n \"${seen[$name]:-}\" ] && failed=1\n seen[\"$name\"]=1\n last_stage=\"$name\"\n [ \"${BASH_REMATCH[2]}\" -eq 0 ] || failed=1\n echo \"$line\"\n fi\n done \u003c \"$receipt\"\n for stage in \"$@\"; do\n if [ -z \"${seen[$stage]:-}\" ]; then\n echo \"STAGE=${stage} EXIT=missing (no terminal receipt)\"\n failed=1\n fi\n case \"$stage\" in\n lib-tests|test-*|goldens|goldens-regen)\n if [ -z \"${counts[$stage]:-}\" ]; then\n echo \"gate: ${stage} has no positive terminal test count\" >&2\n failed=1\n fi ;;\n esac\n done\n if [ \"$last_stage\" != job-complete ]; then\n echo \"gate: missing final job-complete receipt\" >&2\n failed=1\n fi\n return \"$failed\"\n}\n\nrun_fmt() {\n local formatter wrapper rc\n formatter=\"${RUSTFMT:-$(command -v rustfmt)}\" || return 1\n wrapper=\"$(mktemp -t cass-gate-rustfmt.XXXXXX)\" || return 1\n # cargo-fmt maps a signal-killed rustfmt's missing exit code to success.\n # A waiting shell converts that signal into a normal nonzero exit status.\n # Keep the wrapper for diagnostics and never exec away its waiting shell.\n cat > \"$wrapper\" \u003c\u003c'SH'\n#!/usr/bin/env bash\n\"${CASS_GATE_RUSTFMT:?}\" \"$@\"\nexit \"$?\"\nSH\n chmod +x \"$wrapper\" || return 1\n CASS_GATE_RUSTFMT=\"$formatter\" RUSTFMT=\"$wrapper\" cargo fmt --check\n rc=$?\n return \"$rc\"\n}\n\nprepare_compile_inputs() (\n set -o pipefail\n local paths=\"$1\" expected=\"$2\" actual identity_rc=0 freshness_rc=0\n actual=\"$(printf '%s' \"$paths\" | base64 -d | gzip -d | \\\n xargs -0 -r sha256sum | sha256sum | cut -d' ' -f1)\" || identity_rc=$?\n [ \"$actual\" = \"$expected\" ] || identity_rc=1\n echo \"SOURCE_CONTENT_SHA256=${actual} EXPECTED=${expected}\"\n echo \"STAGE=source-identity EXIT=${identity_rc}\"\n [ \"$identity_rc\" -eq 0 ] || return 1\n\n # Transfers preserve mtimes, which can predate a warm Cargo fingerprint\n # even when the input bytes changed. Refresh verified inputs before any\n # compiler runs. Keep cache artifacts and source bytes intact; -c never\n # recreates an input removed since verification. The second digest catches\n # missing or changed inputs, including a concurrent edit during refresh.\n printf '%s' \"$paths\" | base64 -d | gzip -d | \\\n xargs -0 -r touch -c -- || freshness_rc=$?\n actual=\"$(printf '%s' \"$paths\" | base64 -d | gzip -d | \\\n xargs -0 -r sha256sum | sha256sum | cut -d' ' -f1)\" || freshness_rc=$?\n [ \"$actual\" = \"$expected\" ] || freshness_rc=1\n echo \"STAGE=source-freshness EXIT=${freshness_rc}\"\n [ \"$freshness_rc\" -eq 0 ]\n)\n\n# Exercise the exact receipt parser without admitting a build or substituting\n# tools. The shell regression suite feeds it recorded terminal-output shapes.\nif [ \"${1:-}\" = --verify-receipt ]; then\n shift\n verify_receipt \"$@\"\n exit $?\nfi\nif [ \"${1:-}\" = --verify-test-log ]; then\n shift\n test_log_counts \"$@\"\n exit $?\nfi\nif [ \"${1:-}\" = --verify-fmt ]; then\n run_fmt\n exit $?\nfi\nif [ \"${1:-}\" = --verify-compile-inputs ]; then\n prepare_compile_inputs \"$2\" \"$3\"\n exit $?\nfi\n\nPROJECT_ROOT=\"$(cd \"$(dirname \"$0\")/..\" && pwd)\" || exit 1\ncd \"$PROJECT_ROOT\" || exit 1\n\n# GitHub Actions is permanently off (owner, 2026-10-09: \"NO GH ACTIONS,\n# PERIOD!!! EVER!!! we ONLY ever use /dsr\"). A workflow file is never a\n# verification or publication lane: fixes parked in them for a job that never\n# runs sat unapplied on main (bead nqbwq). Refuse to gate a tree carrying one.\nif [ -d .github/workflows ] && [ -n \"$(ls -A .github/workflows)\" ]; then\n echo \"gate: .github/workflows must stay empty (GitHub Actions is off; verify with scripts/gate.sh, release with dsr):\" >&2\n ls -A .github/workflows >&2\n exit 2\nfi\n\nLIB_FILTER=\"\"\nRUN_LIB=1\nRUN_INTEGRATION=1\nRUN_BIN=1\nRUN_GOLDENS=1\nLOCAL=0\nREGEN_GOLDENS=0\nRUN_DOCS_TRUTH=0\nPRINT_REMOTE_SCRIPT=0\nUBS_FILES=()\n# Each entry is `\u003ctest-binary>` or `\u003ctest-binary>:\u003cfilter words>`; the filter\n# is passed after `--` so one admission can run only the tests a change touches.\n# search_metamorphic is the set-algebra oracle for search semantics (terms,\n# Boolean grammar, time windows; bead 2l1b0.68): a wrong-answer regression\n# there is invisible to every golden. pages_bundle holds the Pages viewer's\n# safety checks (CSP, sanitizer, crypto worker, auth expiry, service worker);\n# 20 of them sat red for days because no gate ran the target (2l1b0.77).\n# search_service compiles the `cass serve` sources and their unit tests (the\n# cass bin itself is `test = false`); 8 of them sat red for 9 days (5188e).\nINTEGRATION_TESTS=(cli_robot bookmarks_cli search_metamorphic pages_bundle search_service)\nwhile [ $# -gt 0 ]; do\n case \"$1\" in\n --lib-filter) LIB_FILTER=\"$2\"; shift 2 ;;\n --no-lib) RUN_LIB=0; shift ;;\n --local) LOCAL=1; shift ;;\n --ubs-files) IFS=',' read -r -a UBS_FILES \u003c\u003c\u003c\"$2\"; shift 2 ;;\n --integration) IFS=',' read -r -a INTEGRATION_TESTS \u003c\u003c\u003c\"$2\"; shift 2 ;;\n # Regenerate goldens (UPDATE_GOLDENS=1) before verifying them. The\n # verify stage still runs, and every resulting diff under tests/golden\n # must be read before it is committed — regeneration is never a way to\n # make a red golden green.\n --regen-goldens) REGEN_GOLDENS=1; shift ;;\n # The fleet closes an SSH session after 30 minutes (rch E104). A full\n # lib suite plus integration plus goldens does not fit in one job on a\n # busy worker, so split: `--lib-only` (fmt, clippy, lib suite) and a\n # second run with `--no-lib` for integration + goldens.\n --lib-only) RUN_INTEGRATION=0; RUN_GOLDENS=0; shift ;;\n --no-goldens) RUN_GOLDENS=0; shift ;;\n --no-bin) RUN_BIN=0; shift ;;\n # README ↔ code truth (WS-A.9): key bindings, `cass … --flag` usages\n # and env vars, checked with the debug binary the integration stage\n # just built. Opt-in until the README is clean against main.\n --docs-truth) RUN_DOCS_TRUTH=1; shift ;;\n --print-remote-script) PRINT_REMOTE_SCRIPT=1; shift ;;\n -h|--help) sed -n '2,25p' \"$0\"; exit 0 ;;\n *) echo \"unknown argument: $1\" >&2; exit 2 ;;\n esac\ndone\n\n# The fleet's warm target dir. Deliberately NOT the ambient CARGO_TARGET_DIR:\n# that variable points at a local build dir in many agent shells, and passing\n# it through made a gate run compile clippy from scratch on the worker\n# (13 minutes instead of 5). Override with GATE_TARGET_DIR when needed.\nTARGET_DIR=\"${GATE_TARGET_DIR:-/data/tmp/cass-check-target}\"\nRETRIES=\"${GATE_RETRIES:-1}\"\nRETRY_SLEEP=\"${GATE_RETRY_SLEEP:-90}\"\nBUILD_JOBS=\"${GATE_BUILD_JOBS:-2}\"\nUBS_TIMEOUT=\"${GATE_UBS_TIMEOUT_SECS:-300}\"\nif [[ ! \"$BUILD_JOBS\" =~ ^[1-9][0-9]*$ ]] || [[ ! \"$RETRIES\" =~ ^[1-9][0-9]*$ ]]; then\n echo \"gate: GATE_BUILD_JOBS and GATE_RETRIES must be positive integers\" >&2\n exit 2\nfi\nif [[ ! \"$UBS_TIMEOUT\" =~ ^[1-9][0-9]*$ ]]; then\n echo \"gate: GATE_UBS_TIMEOUT_SECS must be a positive integer\" >&2\n exit 2\nfi\nSOURCE_HEAD=\"$(git rev-parse HEAD)\" || exit 1\nif [ \"${#UBS_FILES[@]}\" -eq 0 ]; then\n UBS_BASE=\"${GATE_BASE:-$(git merge-base origin/main \"$SOURCE_HEAD\")}\" || exit 1\n while IFS= read -r -d '' path; do\n [ -f \"$path\" ] && UBS_FILES+=(\"$path\")\n done \u003c \u003c({\n git diff --name-only -z \"$UBS_BASE\" -- '*.rs' '*.py' '*.sh' '*.js' '*.ts' '*.tsx' '*.jsx'\n git ls-files --others --exclude-standard -z -- '*.rs' '*.py' '*.sh' '*.js' '*.ts' '*.tsx' '*.jsx'\n } | sort -zu)\nfi\n# Honour .ubsignore. The pinned runner scans every file it is named, even one\n# its own .ubsignore, --ignore-file or --exclude covers, so the config-level\n# suppression AGENTS.md prescribes only takes effect if the gate drops those\n# paths before naming them. Each skipped path is printed in the receipt.\nif [ -f .ubsignore ] && [ \"${#UBS_FILES[@]}\" -gt 0 ]; then\n declare -A ubs_ignored=()\n while IFS= read -r -d '' path; do\n ubs_ignored[\"$path\"]=1\n done \u003c \u003c(git ls-files -z -c -o -i --exclude-from=.ubsignore -- \"${UBS_FILES[@]}\")\n ubs_kept=()\n for path in \"${UBS_FILES[@]}\"; do\n if [ -n \"${ubs_ignored[${path#./}]:-}\" ]; then\n echo \"gate: UBS skips .ubsignore path ${path}\" >&2\n else\n ubs_kept+=(\"$path\")\n fi\n done\n UBS_FILES=(\"${ubs_kept[@]}\")\nfi\nUBS_FILES_ARG=\"\"\nif [ \"${#UBS_FILES[@]}\" -gt 0 ]; then\n for path in \"${UBS_FILES[@]}\"; do\n if [[ \"$path\" = /* || \"$path\" = .. || \"$path\" = ../* || \"$path\" = */../* ]] || [ ! -f \"$path\" ]; then\n echo \"gate: UBS source must be an existing repository-relative file: ${path}\" >&2\n exit 2\n fi\n printf -v quoted_path ' %q' \"./${path}\"\n UBS_FILES_ARG+=\"$quoted_path\"\n done\nfi\nsource_digest() {\n {\n git diff --binary HEAD\n git ls-files --others --exclude-standard -z | xargs -0 -r sha256sum\n } | sha256sum | cut -d' ' -f1\n}\nSOURCE_DIFF=\"$(source_digest)\" || exit 1\n# RCH 1.0.63 does not combine --job with clean-overlay/content-receipt.\n# Verify the transferred inputs ourselves before running any stage.\n# rch's global transfer excludes drop every `.beads/` directory, so tracked\n# files such as tests/.beads/* never reach the worker. Hashing them made the\n# identity verdict depend on stale leftovers of whichever worker was chosen\n# (green on one worker, red on another for the same tree). No build or test\n# reads them, so they are not inputs this gate can or needs to verify.\nSOURCE_PATHS=\"$(git ls-files --cached --others --exclude-standard -z -- \\\n Cargo.toml Cargo.lock rust-toolchain.toml build.rs build_support src tests benches scripts \\\n .cargo .github README.md ':(exclude,glob)**/.beads/**' | \\\n sort -zu | gzip -c | base64 -w0)\" || exit 1\nSOURCE_CONTENT=\"$(printf '%s' \"$SOURCE_PATHS\" | base64 -d | gzip -d | \\\n xargs -0 -r sha256sum | sha256sum | cut -d' ' -f1)\" || exit 1\n\n# Keep complete terminal output and require a positive test count. Cargo exits\n# zero when a misspelled filter selects no tests; that is not validation.\nrun_tests() {\n local stage=\"$1\"\n shift\n local -a filters=()\n while [ \"${1:-}\" = --filter ]; do\n filters+=(\"$2\")\n shift 2\n done\n local log rc counts\n local -a statuses\n log=\"$(mktemp -t cass-gate-tests.XXXXXX)\"\n \"$@\" 2>&1 | tee \"$log\"\n statuses=(\"${PIPESTATUS[@]}\")\n rc=${statuses[0]}\n [ \"${statuses[1]}\" -eq 0 ] || rc=1\n if [ \"$rc\" -eq 0 ]; then\n if counts=\"$(test_log_counts \"$log\" \"${filters[@]}\")\"; then\n echo \"TEST_COUNT=${stage} ${counts}\"\n else\n echo \"gate: ${stage} has missing or empty test binaries (log=${log})\" >&2\n rc=1\n fi\n fi\n echo \"STAGE=${stage} EXIT=${rc}\"\n}\n\nrun_ubs() {\n local expected actual scanner installed expected_sha expected_contract_sha tool_dir\n expected=\"$(tr -d '[:space:]' \u003c scripts/ubs-version.txt)\"\n # The runner verifies its language modules against embedded release hashes.\n # Updating the pin also requires reviewing the new runner digest here.\n if [ \"$expected\" != v5.4.4 ]; then\n echo \"gate: no reviewed UBS runner digest for ${expected}\" >&2\n return 1\n fi\n expected_sha=bdeccbb35f2056e6177c73b3f0f9966d20d1cbeff22b7f084133c4a6ac625ee2\n expected_contract_sha=7319b2e5e085d0dd2434e5114291b2dee9fbbb96e2cfe02027eb263abcb06ac3\n # Keep both runner and modules private: a different pinned UBS invocation\n # would otherwise replace the shared module cache while this one scans.\n tool_dir=\"$(mktemp -d -t cass-gate-ubs.XXXXXX)\" || return 1\n scanner=\"$tool_dir/ubs\"\n installed=\"$(command -v ubs || true)\"\n if [ -n \"$installed\" ] && [ \"$(sha256sum \"$installed\" | cut -d' ' -f1)\" = \"$expected_sha\" ]; then\n cp \"$installed\" \"$scanner\" || return 1\n else\n echo \"gate: acquiring pinned UBS ${expected} in ${tool_dir}\"\n curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 \\\n --max-time 60 --user-agent 'cass-gate (+https://github.com/Dicklesworthstone/coding_agent_session_search)' \\\n \"https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/${expected}/ubs\" \\\n --output \"$scanner\" || return 1\n fi\n if [ \"$(sha256sum \"$scanner\" | cut -d' ' -f1)\" != \"$expected_sha\" ]; then\n echo \"gate: UBS runner bytes differ from the pinned release\" >&2\n return 1\n fi\n # Multi-file language routing runs before module acquisition. A private\n # runner without its contract would classify every explicit target as\n # unsupported and exit without scanning anything.\n mkdir -p \"$tool_dir/modules\" || return 1\n curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 \\\n --max-time 60 --user-agent 'cass-gate (+https://github.com/Dicklesworthstone/coding_agent_session_search)' \\\n \"https://raw.githubusercontent.com/Dicklesworthstone/ultimate_bug_scanner/${expected}/modules/contract.json\" \\\n --output \"$tool_dir/modules/contract.json\" || return 1\n if [ \"$(sha256sum \"$tool_dir/modules/contract.json\" | cut -d' ' -f1)\" != \"$expected_contract_sha\" ]; then\n echo \"gate: UBS routing contract bytes differ from the pinned release\" >&2\n return 1\n fi\n actual=\"$(bash \"$scanner\" --version)\" || return 1\n echo \"UBS_VERSION=${actual} UBS_PIN=${expected} UBS_SHA256=${expected_sha}\"\n echo \"UBS_MODULE_DIR=${tool_dir}/modules\"\n echo \"UBS_CONTRACT_SHA256=${expected_contract_sha}\"\n if [ \"$#\" -eq 0 ]; then\n echo \"UBS_FILES=0 (no changed scanner-supported source files)\"\n return 0\n fi\n printf 'UBS_FILE=%s\\n' \"$@\"\n # Text retains categories and source samples needed to diagnose a red gate.\n bash \"$scanner\" --module-dir=\"$tool_dir/modules\" --no-auto-update --format=text --ci --fail-on-warning \"$@\"\n}\n\n# Every stage records its own exit code and preserves complete test output.\nlib_stage=\"\"\nif [ \"$RUN_LIB\" = 1 ]; then\n # A wedged test (the bet45 class: a producer parked forever at ~0 CPU)\n # would otherwise hold the fleet admission until the job's own ceiling.\n # `timeout` turns that into a loud EXIT=124 on this stage instead. It\n # bounds the test run only: lib-build compiles first, because a loaded\n # worker can spend the whole budget compiling (gate b82: lib-tests EXIT=124\n # before any test ran, after a 72-minute clippy compile).\n LIB_TIMEOUT=\"${GATE_LIB_TIMEOUT_SECS:-2400}\"\n if [[ ! \"$LIB_TIMEOUT\" =~ ^[1-9][0-9]*$ ]]; then\n echo \"gate: GATE_LIB_TIMEOUT_SECS must be a positive integer\" >&2\n exit 2\n fi\n read -r -a filter_words \u003c\u003c\u003c \"$LIB_FILTER\"\n filter_args=\"\"\n filter_check_args=\"\"\n if [ \"${#filter_words[@]}\" -gt 0 ]; then\n printf -v filter_args ' %q' \"${filter_words[@]}\"\n for fw in \"${filter_words[@]}\"; do\n printf -v fw_q ' --filter %q' \"$fw\"\n filter_check_args+=\"$fw_q\"\n done\n fi\n lib_stage=\"cargo test --locked -j ${BUILD_JOBS} --lib --no-run; echo STAGE=lib-build EXIT=\\$?; \\\nrun_tests lib-tests${filter_check_args} timeout ${LIB_TIMEOUT} cargo test --locked -j ${BUILD_JOBS} --lib -- --test-threads=${BUILD_JOBS} ${filter_args};\"\nfi\n# Every stage the remote script will run, in order. The receipt check below\n# requires each one to report: a job cut short by the fleet's SSH ceiling\n# leaves later stages missing, and a missing stage is RED, never green.\nEXPECTED_STAGES=(source-identity source-freshness fmt clippy)\n[ \"$RUN_LIB\" = 1 ] && EXPECTED_STAGES+=(lib-build lib-tests)\nintegration_stage=\"\"\nif [ \"$RUN_INTEGRATION\" = 1 ]; then\n declare -A integration_targets=()\n for entry in \"${INTEGRATION_TESTS[@]}\"; do\n [ -n \"$entry\" ] || continue\n t=\"${entry%%:*}\"\n if [[ ! \"$t\" =~ ^[a-zA-Z0-9_-]+$ ]]; then\n echo \"gate: invalid integration target ${t}\" >&2\n exit 2\n fi\n if [ -n \"${integration_targets[$t]:-}\" ]; then\n echo \"gate: repeated target ${t}; combine its filters in one target:filter1 filter2 entry\" >&2\n exit 2\n fi\n integration_targets[\"$t\"]=1\n filter=\"\"\n if [ \"$entry\" != \"$t\" ]; then\n filter=\"${entry#*:}\"\n fi\n read -r -a filter_words \u003c\u003c\u003c \"$filter\"\n filter_args=\"\"\n filter_check_args=\"\"\n if [ \"${#filter_words[@]}\" -gt 0 ]; then\n printf -v filter_args ' %q' \"${filter_words[@]}\"\n for fw in \"${filter_words[@]}\"; do\n printf -v fw_q ' --filter %q' \"$fw\"\n filter_check_args+=\"$fw_q\"\n done\n fi\n integration_stage+=\"run_tests test-${t}${filter_check_args} cargo test --locked -j ${BUILD_JOBS} --test ${t} -- --test-threads=${BUILD_JOBS} ${filter_args};\"\n EXPECTED_STAGES+=(\"test-${t}\")\n done\nfi\nif [ \"$RUN_INTEGRATION\" = 1 ] && [ \"$RUN_BIN\" = 1 ]; then\n # The cass bin is `test = false`, so the unit tests of its own modules\n # (logical_archive's backup/restore codec, the CLI modules) ran in no gate;\n # one hung for hours unseen (m5cob). search_service's share runs as\n # --test search_service. Every other skip names the bead whose fix\n # removes it.\n BIN_TIMEOUT=\"${GATE_BIN_TIMEOUT_SECS:-900}\"\n if [[ ! \"$BIN_TIMEOUT\" =~ ^[1-9][0-9]*$ ]]; then\n echo \"gate: GATE_BIN_TIMEOUT_SECS must be a positive integer\" >&2\n exit 2\n fi\n BIN_SKIPS=(\n search_service::\n logical_archive::import::publication_tests::publication_materializes_wal_rows_without_borrowing_replay_sidecars # svhcf\n logical_archive::export::ordering_tests::explicit_or_unattested_collations_keep_binary_order_and_verify # p94yt\n )\n printf -v bin_skip_args ' --skip %q' \"${BIN_SKIPS[@]}\"\n # As for lib-tests, the timeout bounds the test run, not the compile.\n integration_stage+=\"cargo test --locked -j ${BUILD_JOBS} --bin cass --no-run; echo STAGE=bin-build EXIT=\\$?; \\\nrun_tests bin-cass timeout ${BIN_TIMEOUT} cargo test --locked -j ${BUILD_JOBS} --bin cass -- --test-threads=${BUILD_JOBS}${bin_skip_args};\"\n EXPECTED_STAGES+=(bin-build bin-cass)\nfi\ngolden_regen_stage=\"\"\ngolden_stage=\"\"\nif [ \"$RUN_GOLDENS\" = 1 ]; then\n if [ \"$REGEN_GOLDENS\" = 1 ]; then\n golden_regen_stage=\"UPDATE_GOLDENS=1 run_tests goldens-regen cargo test --locked -j ${BUILD_JOBS} --test golden_robot_json --test golden_robot_docs -- --test-threads=${BUILD_JOBS};\"\n EXPECTED_STAGES+=(goldens-regen)\n fi\n golden_stage=\"run_tests goldens cargo test --locked -j ${BUILD_JOBS} --test golden_robot_json --test golden_robot_docs -- --test-threads=${BUILD_JOBS};\"\n EXPECTED_STAGES+=(goldens)\nfi\n\ndocs_truth_stage=\"\"\nif [ \"$RUN_DOCS_TRUTH\" = 1 ]; then\n # Never inspect a pre-existing target binary when the selected tests did\n # not build it. This invocation must establish its source and ELF first.\n printf -v docs_binary '%q' \"${TARGET_DIR}/debug/cass\"\n docs_truth_stage=\"cargo build --locked -j ${BUILD_JOBS} --bin cass; build_rc=\\$?; echo STAGE=docs-build EXIT=\\$build_rc;\nif [ \\\"\\$build_rc\\\" -eq 0 ]; then\n sha256sum ${docs_binary}; echo STAGE=docs-binary-identity EXIT=\\$?;\n CASS_BIN=${docs_binary} scripts/validate_docs.sh --truth; echo STAGE=docs-truth EXIT=\\$?;\nfi;\"\n EXPECTED_STAGES+=(docs-build docs-binary-identity docs-truth)\nfi\n\nREMOTE_SCRIPT=\"$(declare -f test_log_counts run_tests run_fmt run_ubs prepare_compile_inputs)\nset -o pipefail\necho SOURCE_HEAD=${SOURCE_HEAD}\nprepare_compile_inputs '${SOURCE_PATHS}' '${SOURCE_CONTENT}' || exit 1\nrun_fmt; echo STAGE=fmt EXIT=\\$?; \\\ncargo clippy --locked -j ${BUILD_JOBS} --all-targets -- -D warnings; echo STAGE=clippy EXIT=\\$?; \\\n${lib_stage} ${integration_stage} ${golden_regen_stage} ${golden_stage} ${docs_truth_stage} \\\nrun_ubs ${UBS_FILES_ARG}; echo STAGE=ubs EXIT=\\$?; echo STAGE=job-complete EXIT=0\"\n# Scan after behavioral validation: a slow scanner must not consume the whole\n# admission before any product test runs. UBS remains mandatory and blocking.\nEXPECTED_STAGES+=(ubs job-complete)\n\nif [ \"$PRINT_REMOTE_SCRIPT\" = 1 ]; then\n printf '%s\\n' \"$REMOTE_SCRIPT\"\n exit 0\nfi\n\nrun_once() {\n # Match .cargo/config.toml: storage futures have exceeded a 16 MiB stack.\n # This is virtual address reservation; pages are committed as needed.\n if [ \"$LOCAL\" = 1 ]; then\n env CARGO_TARGET_DIR=\"$TARGET_DIR\" RUST_MIN_STACK=134217728 UBS_MODULE_TIMEOUT=\"$UBS_TIMEOUT\" bash -c \"$REMOTE_SCRIPT\"\n return $?\n fi\n RCH_REQUIRE_REMOTE=1 rch exec --job --result-dir tests/golden -- env CARGO_TARGET_DIR=\"$TARGET_DIR\" RUST_MIN_STACK=134217728 UBS_MODULE_TIMEOUT=\"$UBS_TIMEOUT\" bash -c \"$REMOTE_SCRIPT\"\n}\n\n# The receipt survives a RED run for post-mortem (GATE_RECEIPT_FILE overrides).\nreceipt_file=\"${GATE_RECEIPT_FILE:-$(mktemp -t cass-gate.XXXXXX)}\"\nif [ -s \"$receipt_file\" ]; then\n echo \"gate: refusing to overwrite existing receipt ${receipt_file}\" >&2\n exit 2\nfi\nprintf 'SOURCE_HEAD=%s SOURCE_DIFF_SHA256=%s SOURCE_CONTENT_SHA256=%s\\n' \\\n \"$SOURCE_HEAD\" \"$SOURCE_DIFF\" \"$SOURCE_CONTENT\" >> \"$receipt_file\"\nattempt=1\nrc=103\nwhile [ \"$attempt\" -le \"$RETRIES\" ]; do\n echo \"gate attempt ${attempt}/${RETRIES} $(date +%T)\" >&2\n # Both streams: rch relays remote output on whichever stream it chooses,\n # and a receipt that misses the STAGE lines reads as a truncated job.\n attempt_file=\"$(mktemp \"${receipt_file}.attempt-${attempt}.XXXXXX\")\"\n run_once 2>&1 | tee \"$attempt_file\"\n pipeline_status=(\"${PIPESTATUS[@]}\")\n rc=${pipeline_status[0]}\n [ \"${pipeline_status[1]}\" -eq 0 ] || rc=1\n cat \"$attempt_file\" >> \"$receipt_file\"\n if [ \"$rc\" -ne 103 ]; then\n break\n fi\n attempt=$((attempt + 1))\n [ \"$attempt\" -le \"$RETRIES\" ] && sleep \"$RETRY_SLEEP\"\ndone\n\nif [ \"$rc\" -eq 103 ]; then\n echo \"gate: fleet refused every attempt (exit 103); nothing was verified\" >&2\n echo \"gate: receipt kept at ${receipt_file}\" >&2\n exit 103\nfi\n\necho \"---- gate receipt $(date -u +%Y-%m-%dT%H:%M:%SZ) HEAD=${SOURCE_HEAD} DIFF_SHA256=${SOURCE_DIFF} rch_exit=${rc} receipt=${receipt_file} lines=$(wc -l \u003c \"$receipt_file\") ----\"\nfailed=0\nif [ \"$(git rev-parse HEAD)\" != \"$SOURCE_HEAD\" ] || \\\n [ \"$(source_digest)\" != \"$SOURCE_DIFF\" ]; then\n echo \"STAGE=source-stability EXIT=1 (checkout changed during validation)\"\n failed=1\nfi\nverify_receipt \"$attempt_file\" \"$rc\" \"${EXPECTED_STAGES[@]}\" || failed=1\nif [ \"$failed\" -ne 0 ]; then\n echo \"gate: RED (receipt kept at ${receipt_file})\" >&2\n exit 1\nfi\necho \"gate: GREEN (receipt kept at ${receipt_file})\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":26877,"content_sha256":"e072487b5b1e2863230c6fa4e36815cbe15cafe13edadfc62cac440c2264dea5"},{"filename":"scripts/generate-gap-report.sh","content":"#!/usr/bin/env bash\n# generate-gap-report.sh - Generate coverage gap report from coverage.json\n#\n# shellcheck disable=SC2129\n#\n# Reads coverage.json (cargo-llvm-cov JSON format) and produces a markdown\n# report highlighting coverage gaps, uncovered modules, and recommendations.\n#\n# Usage:\n# ./scripts/generate-gap-report.sh [coverage.json] [output.md]\n#\n# Environment:\n# COVERAGE_THRESHOLD - Target coverage % (default: 60)\n\nset -euo pipefail\n\n# Defaults\nCOVERAGE_JSON=\"${1:-coverage.json}\"\nOUTPUT_FILE=\"${2:-gap-report.md}\"\nTHRESHOLD=\"${COVERAGE_THRESHOLD:-60}\"\n\n# Check dependencies\nif ! command -v jq &> /dev/null; then\n echo \"Error: jq is required but not installed\"\n echo \"Install with: apt install jq (Linux) or brew install jq (macOS)\"\n exit 1\nfi\n\n# Check input file\nif [ ! -f \"$COVERAGE_JSON\" ]; then\n echo \"Error: Coverage file not found: $COVERAGE_JSON\"\n echo \"\"\n echo \"Generate it first with:\"\n echo \" rch exec -- env CARGO_TARGET_DIR=\\${TMPDIR:-/tmp}/rch_target_cass_gap_report cargo llvm-cov --lib --json --output-path $COVERAGE_JSON\"\n exit 1\nfi\n\n# Extract totals\nTOTAL_LINES=$(jq -r '.data[0].totals.lines.count // 0' \"$COVERAGE_JSON\")\nCOVERED_LINES=$(jq -r '.data[0].totals.lines.covered // 0' \"$COVERAGE_JSON\")\nTOTAL_FUNCTIONS=$(jq -r '.data[0].totals.functions.count // 0' \"$COVERAGE_JSON\")\nCOVERED_FUNCTIONS=$(jq -r '.data[0].totals.functions.covered // 0' \"$COVERAGE_JSON\")\n\n# Calculate percentages\nif [ \"$TOTAL_LINES\" -gt 0 ]; then\n LINE_COVERAGE=$(awk \"BEGIN {printf \\\"%.2f\\\", $COVERED_LINES * 100 / $TOTAL_LINES}\")\nelse\n LINE_COVERAGE=\"0.00\"\nfi\n\nif [ \"$TOTAL_FUNCTIONS\" -gt 0 ]; then\n FUNCTION_COVERAGE=$(awk \"BEGIN {printf \\\"%.2f\\\", $COVERED_FUNCTIONS * 100 / $TOTAL_FUNCTIONS}\")\nelse\n FUNCTION_COVERAGE=\"0.00\"\nfi\n\nUNCOVERED_LINES=$((TOTAL_LINES - COVERED_LINES))\n\nfloat_ge() {\n awk -v left=\"$1\" -v right=\"$2\" 'BEGIN { exit !(left >= right) }'\n}\n\n# Generate report\ncat > \"$OUTPUT_FILE\" \u003c\u003c EOF\n# Coverage Gap Report\n\nGenerated: $(date -I)\n\n## Summary\n\n| Metric | Value |\n|--------|-------|\n| Total Lines | ${TOTAL_LINES} |\n| Covered Lines | ${COVERED_LINES} |\n| Uncovered Lines | ${UNCOVERED_LINES} |\n| Line Coverage | **${LINE_COVERAGE}%** |\n| Function Coverage | ${FUNCTION_COVERAGE}% |\n| Threshold | ${THRESHOLD}% |\n\nEOF\n\n# Status indicator\nif float_ge \"$LINE_COVERAGE\" 90; then\n echo \":trophy: **Excellent** - Phase 4 target achieved (90%+)\" >> \"$OUTPUT_FILE\"\nelif float_ge \"$LINE_COVERAGE\" 80; then\n echo \":star: **Good** - Phase 3 target achieved (80%+)\" >> \"$OUTPUT_FILE\"\nelif float_ge \"$LINE_COVERAGE\" 70; then\n echo \":white_check_mark: **Adequate** - Phase 2 target achieved (70%+)\" >> \"$OUTPUT_FILE\"\nelif float_ge \"$LINE_COVERAGE\" \"$THRESHOLD\"; then\n echo \":heavy_check_mark: **Foundation** - Phase 1 target met (${THRESHOLD}%+)\" >> \"$OUTPUT_FILE\"\nelse\n echo \":x: **Below Threshold** - Coverage ${LINE_COVERAGE}% \u003c ${THRESHOLD}%\" >> \"$OUTPUT_FILE\"\nfi\n\necho \"\" >> \"$OUTPUT_FILE\"\n\n# Top uncovered modules (by uncovered lines)\ncat >> \"$OUTPUT_FILE\" \u003c\u003c 'EOF'\n## Top 20 Uncovered Modules (by uncovered lines)\n\n| Coverage | Uncovered | Module | Category |\n|----------|-----------|--------|----------|\nEOF\n\n# Extract per-file data and compute uncovered lines\n# Note: filenames may be full paths, so we check for \"src/\" anywhere in the path\njq -r '.data[0].files[] |\n select(.filename | contains(\"/src/\")) |\n {\n filename: (.filename | split(\"/src/\") | last | \"src/\" + .),\n total: .summary.lines.count,\n covered: .summary.lines.covered,\n uncovered: (.summary.lines.count - .summary.lines.covered),\n percent: (if .summary.lines.count > 0 then (.summary.lines.covered * 100 / .summary.lines.count) else 0 end)\n } |\n select(.uncovered > 50) |\n \"\\(.percent | floor)%|\\(.uncovered)|\\(.filename)\"' \"$COVERAGE_JSON\" | \\\n sort -t'|' -k2 -nr | head -20 | \\\n while IFS='|' read -r percent uncovered filename; do\n # Categorize the file\n case \"$filename\" in\n src/lib.rs) category=\"CLI entry point\" ;;\n src/ui/*) category=\"UI\" ;;\n src/pages/wizard*) category=\"Export wizard\" ;;\n src/pages/secret*) category=\"Security\" ;;\n src/pages/deploy*) category=\"Deploy\" ;;\n src/pages/*) category=\"Pages\" ;;\n src/sources/*) category=\"Sources\" ;;\n src/search/*) category=\"Search\" ;;\n src/connectors/*) category=\"Connectors\" ;;\n src/storage/*) category=\"Storage\" ;;\n src/indexer/*) category=\"Indexer\" ;;\n src/model/*) category=\"Model\" ;;\n *) category=\"Other\" ;;\n esac\n echo \"| ${percent} | ${uncovered} | ${filename} | ${category} |\" >> \"$OUTPUT_FILE\"\n done\n\necho \"\" >> \"$OUTPUT_FILE\"\n\n# Analysis by category\ncat >> \"$OUTPUT_FILE\" \u003c\u003c 'EOF'\n## Analysis by Category\n\n### Critical Gaps (Security/Reliability)\nEOF\n\n# Find modules with 0% or very low coverage that are critical\njq -r '.data[0].files[] |\n select(.filename | contains(\"/src/\")) |\n select(.summary.lines.count > 100) |\n {\n filename: (.filename | split(\"/src/\") | last | \"src/\" + .),\n total: .summary.lines.count,\n covered: .summary.lines.covered,\n percent: (if .summary.lines.count > 0 then (.summary.lines.covered * 100 / .summary.lines.count) else 0 end)\n } |\n select(.percent \u003c 30) |\n \"- **\\(.filename)**: \\(.percent | floor)% coverage (\\(.total - .covered) uncovered lines)\"' \"$COVERAGE_JSON\" >> \"$OUTPUT_FILE\"\n\necho \"\" >> \"$OUTPUT_FILE\"\n\n# Well-covered modules\ncat >> \"$OUTPUT_FILE\" \u003c\u003c 'EOF'\n## Well-Covered Modules (>80%)\n\n| Coverage | Module |\n|----------|--------|\nEOF\n\njq -r '.data[0].files[] |\n select(.filename | contains(\"/src/\")) |\n select(.summary.lines.count > 50) |\n {\n filename: (.filename | split(\"/src/\") | last | \"src/\" + .),\n percent: (if .summary.lines.count > 0 then (.summary.lines.covered * 100 / .summary.lines.count) else 0 end)\n } |\n select(.percent > 80) |\n \"| \\(.percent | . * 100 | floor / 100)% | \\(.filename) |\"' \"$COVERAGE_JSON\" | \\\n sort -t'|' -k2 -nr | head -15 >> \"$OUTPUT_FILE\"\n\necho \"\" >> \"$OUTPUT_FILE\"\n\n# Recommendations\ncat >> \"$OUTPUT_FILE\" \u003c\u003c 'EOF'\n## Recommendations\n\n### High Priority\n1. Add tests for security-critical modules (secret scanning, encryption)\n2. Increase coverage for modules with 0% coverage and >100 lines\n3. Focus on error handling paths\n\n### Medium Priority\n4. Add integration tests for source management\n5. Improve UI component coverage with snapshot tests\n6. Add tests for deploy functionality\n\n### Testing Notes\n- Use real fixtures where possible (avoid mocks)\n- Prefer integration tests over unit tests for I/O-heavy code\n- E2E tests can cover CLI dispatch and wizard flows\n\n---\n\n*Report generated by scripts/generate-gap-report.sh*\n*See docs/COVERAGE_POLICY.md for coverage targets and exclusions*\nEOF\n\necho \"Gap report generated: $OUTPUT_FILE\"\necho \"Line coverage: ${LINE_COVERAGE}% (threshold: ${THRESHOLD}%)\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":7008,"content_sha256":"2fd7db5cf03ad79da56c5958d7ece7f10002bdcb12dfa8108b639c0ef8b54ed7"},{"filename":"scripts/migration_e2e_validate.sh","content":"#!/usr/bin/env bash\n# scripts/migration_e2e_validate.sh\n# Cross-repo e2e validation for the frankensearch + FAD migration.\n# Validates the assembled three-repo ecosystem after both migrations.\n#\n# Usage:\n# ./scripts/migration_e2e_validate.sh # Run all checks\n# ./scripts/migration_e2e_validate.sh --quick # Skip benchmarks and slow checks\n#\n# Environment:\n# RCH_BIN rch executable (default: rch)\n# RCH_TARGET_DIR cargo target dir for offloaded validation commands\n# CASS_ROUTINE_FEATURES\n# cass feature set for routine gates, excluding\n# strict-path-dep-validation unless explicitly overridden\n#\n# Exit code: 0 if all pass, 1 if any fail.\n\nset -uo pipefail\n\n# =============================================================================\n# Configuration\n# =============================================================================\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nCASS_ROOT=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\nFS_ROOT=\"/data/projects/frankensearch\"\nFAD_ROOT=\"/data/projects/franken_agent_detection\"\nBASELINE_DIR=\"${CASS_ROOT}/docs/artifacts/migration-baseline\"\nRCH_BIN=\"${RCH_BIN:-rch}\"\nRCH_TARGET_DIR=\"${RCH_TARGET_DIR:-${TMPDIR:-/tmp}/rch_target_cass_migration_e2e_validate}\"\nCASS_ROUTINE_FEATURES=\"${CASS_ROUTINE_FEATURES:-qr encryption backtrace}\"\n\n# Colors (only when stdout is a terminal)\nif [[ -t 1 ]]; then\n RED='\\033[0;31m'\n GREEN='\\033[0;32m'\n YELLOW='\\033[1;33m'\n BLUE='\\033[0;34m'\n BOLD='\\033[1m'\n NC='\\033[0m'\nelse\n RED='' GREEN='' YELLOW='' BLUE='' BOLD='' NC=''\nfi\n\n# Options\nQUICK_MODE=0\nfor arg in \"$@\"; do\n case \"$arg\" in\n --quick) QUICK_MODE=1 ;;\n --help)\n echo \"Usage: $0 [--quick]\"\n echo \" --local Unsupported; agent builds must use rch\"\n echo \" --quick Skip benchmarks and slow checks\"\n exit 0\n ;;\n --local)\n echo \"Error: --local is unsupported; migration validation cargo commands must be offloaded through rch\" >&2\n exit 2\n ;;\n esac\ndone\n\n# Tracking\nTOTAL_CHECKS=0\nPASSED_CHECKS=0\nFAILED_CHECKS=0\nWARNED_CHECKS=0\nFAILURES=()\nWARNINGS=()\n\n# Logging\nLOG_FILE=\"${CASS_ROOT}/test-logs/migration_e2e_$(date +%Y%m%d_%H%M%S).log\"\nmkdir -p \"$(dirname \"$LOG_FILE\")\"\n\n# =============================================================================\n# Helpers\n# =============================================================================\n\nlog() {\n local ts\n ts=\"$(date +%H:%M:%S)\"\n echo -e \"[${ts}] $*\" | tee -a \"$LOG_FILE\"\n}\n\nsection() {\n echo \"\" | tee -a \"$LOG_FILE\"\n log \"${BOLD}${BLUE}═══ $1 ═══${NC}\"\n}\n\npass() {\n TOTAL_CHECKS=$((TOTAL_CHECKS + 1))\n PASSED_CHECKS=$((PASSED_CHECKS + 1))\n log \" ${GREEN}✓${NC} $1\"\n}\n\nfail() {\n TOTAL_CHECKS=$((TOTAL_CHECKS + 1))\n FAILED_CHECKS=$((FAILED_CHECKS + 1))\n FAILURES+=(\"$1\")\n log \" ${RED}✗${NC} $1\"\n}\n\nwarn() {\n TOTAL_CHECKS=$((TOTAL_CHECKS + 1))\n WARNED_CHECKS=$((WARNED_CHECKS + 1))\n WARNINGS+=(\"$1\")\n log \" ${YELLOW}⚠${NC} $1\"\n}\n\ncargo_cmd() {\n if ! command -v \"$RCH_BIN\" >/dev/null 2>&1; then\n echo \"Error: rch is required for offloaded Cargo execution\" >&2\n return 127\n fi\n \"$RCH_BIN\" exec -- env CARGO_TARGET_DIR=\"$RCH_TARGET_DIR\" cargo \"$@\"\n}\n\nelapsed_since() {\n local start=$1\n local now\n now=$(date +%s)\n echo $((now - start))\n}\n\n# =============================================================================\n# 1. BUILD ALL THREE REPOS\n# =============================================================================\n\nsection \"1. Build Verification\"\nSTEP_START=$(date +%s)\n\nlog \"Building frankensearch...\"\nif (cd \"$FS_ROOT\" && cargo_cmd check --all-features) >> \"$LOG_FILE\" 2>&1; then\n pass \"frankensearch: cargo check --all-features\"\nelse\n fail \"frankensearch: cargo check --all-features\"\nfi\n\nlog \"Building FAD...\"\nif (cd \"$FAD_ROOT\" && cargo_cmd check --all-features) >> \"$LOG_FILE\" 2>&1; then\n pass \"FAD: cargo check --all-features\"\nelse\n fail \"FAD: cargo check --all-features\"\nfi\n\nlog \"Building cass...\"\nif (cd \"$CASS_ROOT\" && cargo_cmd check --features \"$CASS_ROUTINE_FEATURES\") >> \"$LOG_FILE\" 2>&1; then\n pass \"cass: cargo check --features '$CASS_ROUTINE_FEATURES'\"\nelse\n fail \"cass: cargo check --features '$CASS_ROUTINE_FEATURES'\"\nfi\n\nlog \" Build step: $(elapsed_since \"$STEP_START\")s\"\n\n# =============================================================================\n# 2. TEST SUITES\n# =============================================================================\n\nsection \"2. Test Suites\"\nSTEP_START=$(date +%s)\n\n# Helper: sum all \"N passed\" / \"N failed\" lines from cargo test output\nsum_test_metric() {\n local output=\"$1\" metric=\"$2\"\n echo \"$output\" | grep -oP \"\\d+ $metric\" | grep -oP '\\d+' | paste -sd+ | bc 2>/dev/null || echo \"0\"\n}\n\n# Frankensearch tests\nlog \"Running frankensearch tests...\"\nFS_TEST_OUT=$(cd \"$FS_ROOT\" && cargo_cmd test --all-features 2>&1) || true\necho \"$FS_TEST_OUT\" >> \"$LOG_FILE\"\nFS_PASSED=$(sum_test_metric \"$FS_TEST_OUT\" \"passed\")\nFS_FAILED=$(sum_test_metric \"$FS_TEST_OUT\" \"failed\")\nif [[ \"$FS_FAILED\" -eq 0 && \"$FS_PASSED\" -gt 0 ]]; then\n pass \"frankensearch tests: $FS_PASSED passed, $FS_FAILED failed\"\nelif [[ \"$FS_FAILED\" -le 3 ]]; then\n warn \"frankensearch tests: $FS_PASSED passed, $FS_FAILED failed (known env failures)\"\nelse\n fail \"frankensearch tests: $FS_PASSED passed, $FS_FAILED failed\"\nfi\n\n# FAD tests\nlog \"Running FAD tests...\"\nFAD_TEST_OUT=$(cd \"$FAD_ROOT\" && cargo_cmd test --all-features 2>&1) || true\necho \"$FAD_TEST_OUT\" >> \"$LOG_FILE\"\nFAD_PASSED=$(sum_test_metric \"$FAD_TEST_OUT\" \"passed\")\nFAD_FAILED=$(sum_test_metric \"$FAD_TEST_OUT\" \"failed\")\nif [[ \"$FAD_FAILED\" -eq 0 && \"$FAD_PASSED\" -gt 0 ]]; then\n pass \"FAD tests: $FAD_PASSED passed, $FAD_FAILED failed\"\nelif [[ \"$FAD_FAILED\" -le 2 ]]; then\n warn \"FAD tests: $FAD_PASSED passed, $FAD_FAILED failed (known env failures)\"\nelse\n fail \"FAD tests: $FAD_PASSED passed, $FAD_FAILED failed\"\nfi\n\n# Cass tests\nlog \"Running cass tests...\"\nCASS_TEST_OUT=$(cd \"$CASS_ROOT\" && cargo_cmd test --features \"$CASS_ROUTINE_FEATURES\" --lib 2>&1) || true\necho \"$CASS_TEST_OUT\" >> \"$LOG_FILE\"\nCASS_PASSED=$(sum_test_metric \"$CASS_TEST_OUT\" \"passed\")\nCASS_FAILED=$(sum_test_metric \"$CASS_TEST_OUT\" \"failed\")\nif [[ \"$CASS_FAILED\" -eq 0 && \"$CASS_PASSED\" -gt 0 ]]; then\n pass \"cass lib tests: $CASS_PASSED passed, $CASS_FAILED failed\"\nelse\n fail \"cass lib tests: $CASS_PASSED passed, $CASS_FAILED failed\"\nfi\n\n# Combined test count vs baseline (3635)\nTOTAL_TESTS=$((FS_PASSED + FAD_PASSED + CASS_PASSED))\nif [[ \"$TOTAL_TESTS\" -ge 3635 ]]; then\n pass \"Combined test count: $TOTAL_TESTS >= 3635 baseline\"\nelse\n fail \"Combined test count: $TOTAL_TESTS \u003c 3635 baseline (regression!)\"\nfi\n\nlog \" Test step: $(elapsed_since \"$STEP_START\")s\"\n\n# =============================================================================\n# 3. CLIPPY ALL THREE\n# =============================================================================\n\nsection \"3. Clippy\"\nSTEP_START=$(date +%s)\n\nlog \"Clippy: frankensearch...\"\nif (cd \"$FS_ROOT\" && cargo_cmd clippy --all-targets -- -D warnings) >> \"$LOG_FILE\" 2>&1; then\n pass \"frankensearch clippy: clean (no errors)\"\nelse\n fail \"frankensearch clippy: failed with errors or denied warnings\"\nfi\n\nlog \"Clippy: FAD...\"\nif (cd \"$FAD_ROOT\" && cargo_cmd clippy --all-targets -- -D warnings) >> \"$LOG_FILE\" 2>&1; then\n pass \"FAD clippy: clean (no errors)\"\nelse\n fail \"FAD clippy: failed with errors or denied warnings\"\nfi\n\nlog \"Clippy: cass...\"\nif (cd \"$CASS_ROOT\" && cargo_cmd clippy --all-targets --features \"$CASS_ROUTINE_FEATURES\" -- -D warnings) >> \"$LOG_FILE\" 2>&1; then\n pass \"cass clippy: clean (no errors)\"\nelse\n fail \"cass clippy: failed with errors or denied warnings\"\nfi\n\nlog \" Clippy step: $(elapsed_since \"$STEP_START\")s\"\n\nif [[ \"$QUICK_MODE\" -eq 1 ]]; then\n section \"4. Quick Mode\"\n log \"Skipping binary size, search quality, serialization compatibility, and FAD feature gate checks (--quick).\"\nelse\n\n# =============================================================================\n# 4. BINARY SIZE COMPARISON\n# =============================================================================\n\nsection \"4. Binary Size\"\n\n# Find release binary: check CARGO_TARGET_DIR, then standard, then rch\nCASS_BINARY=\"\"\nfor candidate in \\\n \"${CARGO_TARGET_DIR:-}/release/cass\" \\\n \"${CASS_ROOT}/target/release/cass\" \\\n \"${CASS_ROOT}/target_amber_rch/release/cass\"; do\n if [[ -f \"$candidate\" ]]; then\n CASS_BINARY=\"$candidate\"\n break\n fi\ndone\nif [[ -z \"$CASS_BINARY\" ]]; then\n CASS_BINARY=\"${CASS_ROOT}/target/release/cass\" # default for error messages\nfi\nBASELINE_SIZE=35584616 # from BASELINE_SUMMARY.md\n\nif [[ -f \"$CASS_BINARY\" ]]; then\n CURRENT_SIZE=$(stat --format='%s' \"$CASS_BINARY\" 2>/dev/null || stat -f '%z' \"$CASS_BINARY\" 2>/dev/null)\n DELTA_PCT=$(python3 -c \"print(f'{($CURRENT_SIZE - $BASELINE_SIZE) / $BASELINE_SIZE * 100:.1f}')\")\n DELTA_ABS=$(python3 -c \"print(f'{($CURRENT_SIZE - $BASELINE_SIZE) / 1024 / 1024:.2f}')\")\n log \" Baseline: ${BASELINE_SIZE} bytes (33.94 MB)\"\n log \" Current: ${CURRENT_SIZE} bytes ($(python3 -c \"print(f'{$CURRENT_SIZE/1024/1024:.2f}')\")MB)\"\n log \" Delta: ${DELTA_PCT}% (${DELTA_ABS} MB)\"\n\n # Hard fail at 15%, warn at 5%\n if python3 -c \"exit(0 if abs($CURRENT_SIZE - $BASELINE_SIZE) / $BASELINE_SIZE \u003c= 0.05 else 1)\"; then\n pass \"Binary size: within 5% of baseline (${DELTA_PCT}%)\"\n elif python3 -c \"exit(0 if abs($CURRENT_SIZE - $BASELINE_SIZE) / $BASELINE_SIZE \u003c= 0.15 else 1)\"; then\n warn \"Binary size: ${DELTA_PCT}% from baseline (exceeds 5% threshold, within 15%)\"\n else\n fail \"Binary size: ${DELTA_PCT}% from baseline (exceeds 15% threshold!)\"\n fi\nelse\n warn \"Binary not found at $CASS_BINARY (run cargo build --release first)\"\nfi\n\n# =============================================================================\n# 5. SEARCH QUALITY VALIDATION\n# =============================================================================\n\nsection \"5. Search Quality\"\n\nif [[ -f \"$CASS_BINARY\" ]] && [[ -f \"${BASELINE_DIR}/baseline_search_quality.json\" ]]; then\n QUALITY_RESULT=$(CASS_BIN=\"$CASS_BINARY\" BASELINE_FILE=\"${BASELINE_DIR}/baseline_search_quality.json\" python3 \u003c\u003c 'PYEOF'\nimport json, subprocess, sys, os\n\ncass = os.environ[\"CASS_BIN\"]\nbaseline_file = os.environ[\"BASELINE_FILE\"]\n\nbaseline = json.load(open(baseline_file))\nall_ok = True\nmax_delta = 0.0\nresults = []\n\nfor i, b in enumerate(baseline):\n q = b[\"query\"]\n proc = subprocess.run([cass, \"search\", q, \"--limit\", \"10\", \"--json\"], capture_output=True, text=True)\n if proc.returncode != 0:\n print(f\"FAIL query_{i+1}: search returned error\")\n all_ok = False\n continue\n\n data = json.loads(proc.stdout)\n hits = data.get(\"hits\", [])\n current_count = len(hits)\n baseline_count = b[\"result_count\"]\n\n # Check result count\n if current_count != baseline_count:\n print(f\"FAIL query_{i+1} '{q}': count {current_count} != baseline {baseline_count}\")\n all_ok = False\n continue\n\n # Check scores within tolerance\n current_scores = [h[\"score\"] for h in hits[:3]]\n baseline_scores = b[\"top_3_scores\"]\n\n for j, (cs, bs) in enumerate(zip(current_scores, baseline_scores)):\n delta_pct = abs(cs - bs) / bs * 100 if bs else 0\n max_delta = max(max_delta, delta_pct)\n if delta_pct > 5.0: # 5% tolerance for individual scores\n print(f\"WARN query_{i+1} '{q}' score[{j}]: {cs:.2f} vs baseline {bs:.2f} ({delta_pct:+.1f}%)\")\n\n results.append({\"query\": q, \"ok\": True, \"count\": current_count, \"max_score_delta_pct\": max_delta})\n\nprint(f\"OK max_delta={max_delta:.2f}%\" if all_ok else f\"FAIL max_delta={max_delta:.2f}%\")\nPYEOF\n )\n echo \"$QUALITY_RESULT\" >> \"$LOG_FILE\"\n if echo \"$QUALITY_RESULT\" | grep -q \"^OK\"; then\n MAX_D=$(echo \"$QUALITY_RESULT\" | grep -oP 'max_delta=[\\d.]+' | grep -oP '[\\d.]+')\n pass \"Search quality: all 10 queries match baseline (max delta: ${MAX_D}%)\"\n else\n fail \"Search quality: regression detected — $QUALITY_RESULT\"\n fi\nelse\n warn \"Search quality: skipped (binary or baseline not available)\"\nfi\n\n# =============================================================================\n# 6. SERIALIZATION COMPATIBILITY\n# =============================================================================\n\nsection \"6. Serialization Compatibility\"\n\nif [[ -f \"$CASS_BINARY\" ]]; then\n # Check that the tantivy index schema hash matches between cass and frankensearch\n SCHEMA_CHECK=$(\"$CASS_BINARY\" diag 2>&1 || true)\n if echo \"$SCHEMA_CHECK\" | grep -q \"Index Status\" && echo \"$SCHEMA_CHECK\" | grep -A1 \"Index Status\" | grep -q \"OK\"; then\n pass \"Index schema: post-migration binary can read existing index\"\n else\n fail \"Index schema: post-migration binary cannot read existing index\"\n fi\n\n # Verify NormalizedConversation type compatibility by checking the cass search output\n # parses correctly (JSON serialization hasn't changed)\n COMPAT_OUT=$(\"$CASS_BINARY\" search \"test\" --limit 1 --json 2>/dev/null || true)\n if echo \"$COMPAT_OUT\" | python3 -c \"import json,sys; d=json.load(sys.stdin); assert 'hits' in d or 'count' in d\" 2>/dev/null; then\n pass \"JSON serialization: search output schema intact\"\n else\n fail \"JSON serialization: search output schema changed\"\n fi\nelse\n warn \"Serialization checks: skipped (release binary not found)\"\nfi\n\n# =============================================================================\n# 7. FEATURE GATE VALIDATION (FAD)\n# =============================================================================\n\nsection \"7. FAD Feature Gate Validation\"\n\n# Build with default features (no optional deps)\nlog \"Building FAD with default features...\"\nif (cd \"$FAD_ROOT\" && cargo_cmd check 2>&1) >> \"$LOG_FILE\"; then\n pass \"FAD default features: builds\"\nelse\n fail \"FAD default features: build failed\"\nfi\n\n# Check: default build should NOT have rusqlite or aes-gcm\nFAD_DEFAULT_DEPS=$(cd \"$FAD_ROOT\" && cargo_cmd tree --no-dedupe --depth 1 2>/dev/null || echo \"\")\nif echo \"$FAD_DEFAULT_DEPS\" | grep -qi \"rusqlite\"; then\n fail \"FAD default: rusqlite present in dep tree (should be optional)\"\nelse\n pass \"FAD default: no rusqlite in dep tree\"\nfi\nif echo \"$FAD_DEFAULT_DEPS\" | grep -qi \"aes-gcm\"; then\n fail \"FAD default: aes-gcm present in dep tree (should be optional)\"\nelse\n pass \"FAD default: no aes-gcm in dep tree\"\nfi\n\n# Build with all-connectors\nlog \"Building FAD with all-connectors...\"\nif (cd \"$FAD_ROOT\" && cargo_cmd check --features all-connectors 2>&1) >> \"$LOG_FILE\"; then\n pass \"FAD all-connectors: builds\"\nelse\n fail \"FAD all-connectors: builds failed\"\nfi\n\nfi\n\n# =============================================================================\n# 8. SUMMARY\n# =============================================================================\n\nsection \"8. Summary\"\n\nTOTAL_TIME_S=$SECONDS\nlog \"\"\nlog \"${BOLD}Migration E2E Validation Results${NC}\"\nlog \"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\"\nlog \" ${GREEN}Passed:${NC} $PASSED_CHECKS\"\nlog \" ${YELLOW}Warned:${NC} $WARNED_CHECKS\"\nlog \" ${RED}Failed:${NC} $FAILED_CHECKS\"\nlog \" Total: $TOTAL_CHECKS\"\nlog \" Time: ${TOTAL_TIME_S}s\"\nlog \"\"\n\nif [[ ${#WARNINGS[@]} -gt 0 ]]; then\n log \"${YELLOW}Warnings:${NC}\"\n for w in \"${WARNINGS[@]}\"; do\n log \" ${YELLOW}⚠${NC} $w\"\n done\n log \"\"\nfi\n\nif [[ ${#FAILURES[@]} -gt 0 ]]; then\n log \"${RED}Failures:${NC}\"\n for f in \"${FAILURES[@]}\"; do\n log \" ${RED}✗${NC} $f\"\n done\n log \"\"\nfi\n\nlog \"Full log: $LOG_FILE\"\n\nif [[ \"$FAILED_CHECKS\" -gt 0 ]]; then\n log \"${RED}${BOLD}RESULT: FAIL${NC} ($FAILED_CHECKS failures)\"\n exit 1\nelse\n log \"${GREEN}${BOLD}RESULT: PASS${NC} ($PASSED_CHECKS passed, $WARNED_CHECKS warnings)\"\n exit 0\nfi\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":16070,"content_sha256":"c6455f6257670d8c8580a27ccd802694c66df81f28a379f09af6ca02ce238c83"},{"filename":"scripts/test_benchmark_lexical_admission.py","content":"\"\"\"Protocol-harness tests; fake services are NOT CASS performance evidence.\"\"\"\nfrom __future__ import annotations\n\nimport argparse\nimport importlib.util\nimport json\nfrom pathlib import Path\nimport sys\nimport tempfile\nimport unittest\nfrom unittest.mock import patch\n\nspec = importlib.util.spec_from_file_location(\n 'admission_benchmark', Path(__file__).with_name('benchmark_lexical_admission.py'))\nassert spec is not None and spec.loader is not None\nbench = importlib.util.module_from_spec(spec)\nspec.loader.exec_module(bench)\n\nFAKE = '''#!{python}\nimport json, sys, time\nfrom pathlib import Path\nmode = {mode!r}\nloaded = False\nfor line in sys.stdin:\n req = json.loads(line)\n op = req['op']\n if mode == 'timeout' and op == 'status':\n time.sleep(10)\n if mode == 'eof' and op == 'status':\n sys.exit(3)\n result = {{}}\n if op == 'search':\n result = {{'hits': [{{'score': 2.0 if mode == 'mismatch' else 1.0,\n 'source_id': 'local', 'message_index': 1}}],\n 'reader_reused': loaded, 'setup_ms': 0, 'search_ms': 0}}\n loaded = True\n if mode == 'empty':\n result['hits'] = []\n if mode == 'false_reuse':\n result['reader_reused'] = True\n elif op == 'unload':\n loaded = False\n elif op == 'reload':\n loaded = True\n ident = req['id'] + 1 if mode == 'wrong_id' else req['id']\n response = {{'schema_version': 1, 'id': ident, 'ok': True, 'result': result}}\n if mode == 'request_error' and op == 'search':\n response = {{'id': ident, 'ok': False, 'error': {{'message': 'refused'}}}}\n if mode == 'oversized' and op == 'status':\n print('x' * 1048577, flush=True)\n elif mode == 'malformed' and op == 'status':\n print('not json', flush=True)\n else:\n print(json.dumps(response), flush=True)\nif mode == 'bad_exit':\n sys.exit(7)\n'''\n\n\[email protected](sys.platform.startswith('linux'), 'requires Linux /proc counters')\nclass HarnessTests(unittest.TestCase):\n def setUp(self) -> None:\n self.temp = tempfile.TemporaryDirectory()\n self.addCleanup(self.temp.cleanup)\n self.root = Path(self.temp.name)\n self.index = self.root / 'index'\n self.index.mkdir()\n (self.index / 'MANIFEST').write_text('fixture marker, not a real index')\n self.binary = self.service('baseline', 'ok')\n\n def service(self, name: str, mode: str) -> Path:\n path = self.root / name\n path.write_text(FAKE.format(python=sys.executable, mode=mode))\n path.chmod(0o755)\n return path\n\n def args(self, **changes: object) -> argparse.Namespace:\n values = dict(cass=self.binary, candidate_cass=None, index=self.index,\n query=['performance'], rounds=2, limit=10, timeout=2)\n values.update(changes)\n return argparse.Namespace(**values)\n\n def test_baseline_never_claims_a_candidate(self) -> None:\n report = bench.run(self.args())\n self.assertEqual(report['mode'], 'baseline_only')\n self.assertEqual(set(report['fresh_medians']), {'baseline'})\n self.assertEqual(len(report['fresh']), 2)\n self.assertTrue(report['hits_equal'])\n self.assertTrue(all(row['process_cpu_s'] >= 0 for row in report['fresh']))\n self.assertEqual([r['phase'] for r in report['retained']], [\n 'first_admission', 'retained_query', 'retained_query', 'unload',\n 'admission_after_unload', 'reload', 'query_after_reload'])\n\n def test_comparison_alternates_and_measures_retention_for_both(self) -> None:\n candidate = self.service('candidate', 'also_ok')\n report = bench.run(self.args(candidate_cass=candidate))\n self.assertEqual(report['mode'], 'comparison')\n self.assertEqual([r['arm'] for r in report['fresh']],\n ['baseline', 'candidate', 'candidate', 'baseline'])\n self.assertEqual({r['arm'] for r in report['retained']}, {'baseline', 'candidate'})\n self.assertNotEqual(report['binaries']['baseline']['sha256'],\n report['binaries']['candidate']['sha256'])\n\n def test_identical_binaries_cannot_masquerade_as_comparison(self) -> None:\n with self.assertRaisesRegex(ValueError, 'identical'):\n bench.run(self.args(candidate_cass=self.binary))\n\n def test_candidate_score_mismatch_refused(self) -> None:\n with self.assertRaisesRegex(AssertionError, 'hits differ'):\n bench.run(self.args(candidate_cass=self.service('candidate', 'mismatch')))\n\n def test_all_empty_workload_refused(self) -> None:\n with self.assertRaisesRegex(ValueError, 'zero hits'):\n bench.run(self.args(cass=self.service('empty', 'empty')))\n\n def test_reused_fresh_reader_refused(self) -> None:\n with self.assertRaisesRegex(AssertionError, 'fresh process'):\n bench.run(self.args(cass=self.service('reused', 'false_reuse')))\n\n def test_bad_exit_does_not_produce_evidence(self) -> None:\n with self.assertRaisesRegex(RuntimeError, 'unclean service shutdown'):\n bench.run(self.args(cass=self.service('bad', 'bad_exit')))\n\n def test_startup_transport_errors(self) -> None:\n for mode, error in [('wrong_id', RuntimeError), ('eof', RuntimeError),\n ('malformed', json.JSONDecodeError), ('oversized', RuntimeError)]:\n with self.subTest(mode=mode), self.assertRaises(error):\n bench.Service(self.service(mode, mode), self.index, 2)\n\n def test_timeout_kills_and_reaps_child(self) -> None:\n children = []\n original = bench.subprocess.Popen\n\n def spawn(*args: object, **kwargs: object):\n child = original(*args, **kwargs)\n children.append(child)\n return child\n\n with patch.object(bench.subprocess, 'Popen', side_effect=spawn):\n with self.assertRaises(TimeoutError):\n bench.Service(self.service('slow', 'timeout'), self.index, 0.1)\n self.assertEqual(len(children), 1)\n self.assertIsNotNone(children[0].returncode)\n self.assertFalse(Path(f'/proc/{children[0].pid}').exists())\n\n def test_request_error_refused(self) -> None:\n with self.assertRaisesRegex(RuntimeError, 'failed'):\n bench.run(self.args(cass=self.service('error', 'request_error')))\n\n\nif __name__ == '__main__':\n unittest.main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":6430,"content_sha256":"18fbed40e766871e4bb8b0837a365983ddae414f6f7931e0a75132e338d9f07c"},{"filename":"scripts/test_benchmark_lexical_ipc.py","content":"#!/usr/bin/env python3\n\"\"\"Failure-aware workload harness tests, not real CASS performance results.\"\"\"\nimport hashlib\nimport json\nfrom pathlib import Path\nimport subprocess\nimport sys\nimport tempfile\nimport unittest\n\nimport test_cass_lexical_ipc as guards\n\nMODULE_PATH = guards.MODULE_PATH\n\n\[email protected](sys.platform.startswith(\"linux\"), \"Linux IPC required\")\nclass BenchmarkTests(unittest.TestCase):\n def setUp(self):\n self.temp = tempfile.TemporaryDirectory()\n self.home = Path(self.temp.name)\n # The positive comparison must really exercise supported local reuse.\n # Leave the fake executable on an executable mount, not /dev/shm.\n self.index_temp = tempfile.TemporaryDirectory(dir=\"/dev/shm\")\n self.addCleanup(self.index_temp.cleanup)\n self.index = Path(self.index_temp.name) / \"index\"\n self.index.mkdir()\n payload = b\"alpha beta \" * 1024\n (self.index / \"segment.qseg\").write_bytes(payload)\n (self.index / \"MANIFEST\").write_text(json.dumps({\n \"hash\": hashlib.sha256(payload).hexdigest()}))\n fake = guards.FAKE.replace(\"quill.manifest.json\", \"MANIFEST\")\n fake = fake.replace(\"#!/usr/bin/env python3\", \"#!\" + sys.executable + \" -S\")\n fake = fake.replace(\n \" print(json.dumps(dict(schema_version=1, id=request['id'], ok=True, result=result)), flush=True)\",\n \" if mode == 'different_reuse' and loaded:\\n\"\n \" result['hits'][0]['score'] = 9.0\\n\"\n \" print(json.dumps(dict(schema_version=1, id=request['id'], ok=True, result=result)), flush=True)\")\n self.cass = self.home / \"fake-cass\"\n self.cass.write_text(fake)\n self.cass.chmod(0o700)\n\n def tearDown(self):\n self.temp.cleanup()\n\n def mode(self, value):\n (self.home / \"mode\").write_text(value)\n\n\n def benchmark(self, *extra):\n evidence = self.home / \"measurement.json\"\n result = subprocess.run(\n [sys.executable, \"-S\", str(MODULE_PATH.with_name(\"benchmark_lexical_ipc.py\")),\n \"--cass\", str(self.cass), \"--index\", str(self.index),\n \"--query\", \"alpha\", \"--rounds\", \"2\", \"--timeout\", \"2\",\n \"--output\", str(evidence), *extra],\n capture_output=True, timeout=10)\n return result, evidence\n\n def test_benchmark_separates_fresh_retained_and_client_cpu(self):\n result, evidence = self.benchmark()\n self.assertEqual(result.returncode, 0, result.stderr.decode())\n report = json.loads(evidence.read_text())\n workloads = report[\"workloads\"]\n self.assertEqual(len(workloads[\"strict_fresh_process\"][\"samples\"]), 2)\n self.assertEqual(len(workloads[\"retained_native\"][\"retained_queries\"]), 2)\n clients = workloads[\"fresh_ipc_clients\"]\n self.assertEqual([sample[\"phase\"] for sample in clients[\"samples\"]],\n [\"initial_admission\", \"fresh_client_reuse\", \"fresh_client_reuse\",\n \"full_verify_control\", \"post_verify_reuse\"])\n self.assertIn(\"complete_group_cpu_ms\", clients)\n self.assertIn(\"client_cpu_ms\", clients[\"samples\"][0])\n self.assertEqual(clients[\"client_kind\"], \"python_frontend\")\n self.assertTrue(report[\"identical_hits_scores_and_order\"])\n\n def test_benchmark_refuses_missing_explicit_native_client(self):\n result, evidence = self.benchmark(\"--client\", str(self.home / \"missing\"))\n self.assertNotEqual(result.returncode, 0)\n self.assertFalse(evidence.exists())\n\n def test_benchmark_refuses_reuse_score_mismatch(self):\n self.mode(\"different_reuse\")\n result, evidence = self.benchmark()\n self.assertNotEqual(result.returncode, 0)\n self.assertFalse(evidence.exists())\n\n def test_benchmark_refuses_changed_index(self):\n self.mode(\"mutate\")\n result, evidence = self.benchmark()\n self.assertNotEqual(result.returncode, 0)\n self.assertFalse(evidence.exists())\n\n def test_benchmark_refuses_corrupted_worker_output(self):\n self.mode(\"bad_json\")\n result, evidence = self.benchmark()\n self.assertNotEqual(result.returncode, 0)\n self.assertFalse(evidence.exists())\n\n def test_benchmark_refuses_forged_reuse_on_fresh_admission(self):\n self.mode(\"forged_reuse\")\n result, evidence = self.benchmark()\n self.assertNotEqual(result.returncode, 0)\n self.assertFalse(evidence.exists())\n\n def test_benchmark_refuses_unmeasured_reader_reclamation(self):\n self.mode(\"drop_reader\")\n result, evidence = self.benchmark()\n self.assertNotEqual(result.returncode, 0)\n self.assertFalse(evidence.exists())\n\n def test_benchmark_does_not_overwrite_existing_evidence(self):\n evidence = self.home / \"measurement.json\"\n evidence.write_text(\"previous evidence\")\n result, _ = self.benchmark()\n self.assertNotEqual(result.returncode, 0)\n self.assertEqual(evidence.read_text(), \"previous evidence\")\n\n\nif __name__ == \"__main__\":\n unittest.main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":5097,"content_sha256":"7e8805952f22feb07643e6125cbaf0e3f12cb5571dab6f916022d52c2332e8b7"},{"filename":"scripts/test_cass_lexical_ipc.py","content":"#!/usr/bin/env python3\n\"\"\"Exercise the real IPC/guard implementation with a fake strict CASS process.\n\nThis validates transport, lifecycle and filesystem guard behavior; it does not\nqualify Quill or claim CASS timings. Run: python3 -m unittest discover -s scripts\n-p 'test_cass_lexical_ipc.py' -v\n\"\"\"\nimport hashlib\nimport importlib.util\nimport json\nimport os\nfrom pathlib import Path\nimport signal\nimport socket\nimport subprocess\nimport sys\nimport tempfile\nimport time\nimport unittest\nfrom unittest import mock\n\nMODULE_PATH = Path(__file__).with_name(\"cass_lexical_ipc.py\")\nspec = importlib.util.spec_from_file_location(\"cass_lexical_ipc\", MODULE_PATH)\nipc = importlib.util.module_from_spec(spec)\nspec.loader.exec_module(ipc)\n\nFAKE = r\"\"\"#!/usr/bin/env python3\nimport hashlib, json, os, pathlib, sys, time\nindex = pathlib.Path(sys.argv[sys.argv.index('--index') + 1])\nhome = pathlib.Path(__file__).parent\nmode = (home / 'mode').read_text() if (home / 'mode').exists() else 'normal'\nif mode == 'root_probe':\n # Capture at process startup, while the test has redirected an ancestor.\n retained_bytes = (index / 'segment.qseg').read_bytes()\n retained_manifest = (index / 'quill.manifest.json').read_text()\n root_info = index.stat()\n inherited = []\n for name in os.listdir('/proc/self/fd'):\n try:\n os.fstat(int(name))\n except OSError:\n continue\n if int(name) > 2:\n inherited.append(int(name))\n root_probe = {'identity': [root_info.st_dev, root_info.st_ino],\n 'sha256': hashlib.sha256(retained_bytes).hexdigest(),\n 'inherited': sorted(inherited)}\n (home / 'root_ready').write_text(json.dumps(root_probe))\nloaded = False\nfor line in sys.stdin:\n request = json.loads(line)\n if mode == 'hang':\n time.sleep(60)\n if mode == 'exit':\n sys.exit(7)\n if mode == 'bad_json':\n print('not json', flush=True)\n continue\n if mode == 'duplicate':\n print('{\"schema_version\":1,\"id\":1,\"ok\":true,\"ok\":false}', flush=True)\n continue\n if mode == 'oversized':\n print('x' * (1024*1024+1), flush=True)\n continue\n if mode == 'wrong_id':\n print(json.dumps(dict(schema_version=1, id=request['id'] + 1, ok=True, result={})), flush=True)\n continue\n if mode == 'bad_schema':\n print(json.dumps(dict(schema_version=True, id=request['id'], ok=True, result={})), flush=True)\n continue\n if mode == 'drop_reader':\n loaded = False\n if not loaded:\n with (home / 'opens').open('a') as log:\n log.write(str(os.getpid()) + '\\n')\n expected = json.loads(retained_manifest if mode == 'root_probe' else\n (index / 'quill.manifest.json').read_text())\n actual = hashlib.sha256(retained_bytes if mode == 'root_probe' else\n (index / 'segment.qseg').read_bytes()).hexdigest()\n if actual != expected['hash']:\n print(json.dumps(dict(schema_version=1, id=request['id'], ok=False,\n error={'kind':'corrupt', 'message':'full hash failed'})), flush=True)\n continue\n if mode == 'mutate':\n with (index / 'segment.qseg').open('r+b') as changed:\n changed.write(b'Z')\n result = {'hits':[{'content': 'alpha', 'score':1.0}], 'reader_reused':loaded}\n if mode == 'forged_reuse':\n result['reader_reused'] = True\n if mode == 'non_boolean_reuse':\n result['reader_reused'] = 1\n if mode == 'missing_reuse':\n del result['reader_reused']\n if mode == 'mixed_outcome':\n print(json.dumps(dict(schema_version=1, id=request['id'], ok=True,\n result=result, error={'kind':'corrupt'})), flush=True)\n continue\n if mode == 'forged_admission':\n print(json.dumps(dict(schema_version=1, id=request['id'], ok=True,\n result=result, admission={'mode':'strict_full'})), flush=True)\n continue\n if mode == 'root_probe':\n result['root_probe'] = root_probe\n result['current_root'] = [index.stat().st_dev, index.stat().st_ino]\n print(json.dumps(dict(schema_version=1, id=request['id'], ok=True, result=result)), flush=True)\n loaded = True\n\"\"\"\n\n\[email protected](sys.platform.startswith(\"linux\"), \"Linux peer credentials required\")\nclass AdmissionTests(unittest.TestCase):\n def setUp(self):\n # Positive reuse must exercise real supported storage, not silently skip\n # when CI's normal temporary directory lives on overlayfs. Keep the fake\n # executable outside tmpfs because /dev/shm is commonly mounted noexec.\n self.temp = tempfile.TemporaryDirectory(dir=\"/dev/shm\")\n self.executable_temp = tempfile.TemporaryDirectory()\n self.addCleanup(self.executable_temp.cleanup)\n self.home = Path(self.temp.name)\n self.index = self.home / \"index\"\n self.index.mkdir()\n self.segment = self.index / \"segment.qseg\"\n self.segment.write_bytes(b\"alpha beta \" * 1024)\n self.publish_manifest()\n self.cass = Path(self.executable_temp.name) / \"fake-cass\"\n fake = FAKE.replace(\"#!/usr/bin/env python3\", \"#!\" + sys.executable + \" -S\")\n self.cass.write_text(fake.replace(\"home = pathlib.Path(__file__).parent\",\n f\"home = pathlib.Path({str(self.home)!r})\"))\n self.cass.chmod(0o700)\n self.owner = ipc.Owner(str(self.cass), self.index, 2)\n self.server = None\n\n def tearDown(self):\n self.owner.close()\n if self.server is not None:\n self.server.terminate()\n try:\n self.server.communicate(timeout=5)\n except subprocess.TimeoutExpired:\n self.server.kill()\n self.server.communicate(timeout=5)\n self.temp.cleanup()\n\n def publish_manifest(self):\n (self.index / \"quill.manifest.json\").write_text(json.dumps({\n \"hash\": hashlib.sha256(self.segment.read_bytes()).hexdigest()}))\n\n def request(self, **extra):\n return {\"op\": \"search\", \"id\": 1, \"query\": \"alpha\", **extra}\n\n def search(self, **extra):\n return self.owner.search(self.request(**extra))\n\n def opens(self):\n log = self.home / \"opens\"\n return log.read_text().splitlines() if log.exists() else []\n\n def mode(self, value):\n (self.home / \"mode\").write_text(value)\n\n def start_server(self):\n private = self.home / \"private\"\n private.mkdir(mode=0o700)\n endpoint = private / \"lexical.sock\"\n self.server = subprocess.Popen(\n [sys.executable, \"-S\", str(MODULE_PATH), \"serve\", \"--socket\", str(endpoint),\n \"--index\", str(self.index), \"--cass\", str(self.cass), \"--timeout\", \"2\"],\n stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n deadline = time.monotonic() + 5\n while time.monotonic() \u003c deadline:\n if self.server.poll() is not None:\n self.fail(self.server.communicate()[1].decode())\n if endpoint.exists() and endpoint.stat().st_mode & 0o777 == 0o600:\n return endpoint\n time.sleep(0.01)\n self.fail(\"IPC owner did not start\")\n\n def test_first_open_and_reuse(self):\n first, second = self.search(), self.search()\n self.assertEqual(first[\"admission\"][\"mode\"], \"strict_full\")\n self.assertEqual(second[\"admission\"][\"mode\"], \"retained_guarded\")\n self.assertEqual(first[\"result\"][\"hits\"], second[\"result\"][\"hits\"])\n self.assertEqual(len(self.opens()), 1)\n self.assertTrue(second[\"result\"][\"reader_reused\"])\n\n def test_full_verify_releases_and_reopens(self):\n self.search()\n first_pid = self.owner.process.pid\n response = self.search(full_verify=True)\n self.assertNotEqual(self.owner.process.pid, first_pid)\n self.assertEqual(response[\"admission\"][\"mode\"], \"strict_full\")\n self.assertEqual(response[\"admission\"][\"owner_epoch\"], 2)\n self.assertEqual(len(self.opens()), 2)\n\n def test_full_verify_rejects_a_fresh_worker_claiming_reuse(self):\n self.search()\n self.mode(\"forged_reuse\")\n with self.assertRaises(ipc.Failure) as raised:\n self.search(full_verify=True)\n self.assertEqual(raised.exception.kind, \"worker_protocol\")\n self.assertEqual(len(self.opens()), 2)\n self.assertIsNone(self.owner.process)\n self.assertIsNone(self.owner.guard)\n\n def test_native_reader_reclamation_is_reported_as_strict_admission(self):\n self.mode(\"drop_reader\")\n first = self.search()\n pid = self.owner.process.pid\n second = self.search()\n self.assertEqual(self.owner.process.pid, pid)\n self.assertFalse(second[\"result\"][\"reader_reused\"])\n self.assertEqual(first[\"admission\"][\"mode\"], \"strict_full\")\n self.assertEqual(second[\"admission\"][\"mode\"], \"strict_full\")\n self.assertEqual(second[\"admission\"][\"owner_epoch\"], 2)\n self.assertEqual(len(self.opens()), 2)\n\n def test_unsupported_filesystems_force_strict_readers(self):\n table = ipc.kernel_bytes(\"/proc/self/mountinfo\", ipc.MOUNTINFO_LIMIT)\n for filesystem in (b\"nfs\", b\"nfs4\", b\"cifs\", b\"fuse.sshfs\", b\"overlay\", b\"unknown\"):\n with self.subTest(filesystem=filesystem):\n self.owner.close()\n previous = len(self.opens())\n records = ipc.mount_records(table)\n for key, record in tuple(records.items()):\n records[key] = (*record[:2], filesystem, record[3])\n with mock.patch.object(ipc, \"mount_records\", return_value=records):\n first, second = self.search(), self.search()\n self.assertEqual(first[\"admission\"][\"mode\"], \"strict_full\")\n self.assertEqual(second[\"admission\"][\"mode\"], \"strict_full\")\n self.assertFalse(second[\"result\"][\"reader_reused\"])\n self.assertEqual(len(self.opens()), previous + 2)\n self.assertIsNone(self.owner.guard.local_mounts)\n\n def test_unknown_kernel_metadata_disables_reuse_without_breaking_search(self):\n for error in (PermissionError(\"proc denied\"), FileNotFoundError(\"proc absent\"),\n ValueError(\"corrupt proof metadata\")):\n with self.subTest(error=error):\n self.owner.close()\n before = len(self.opens())\n with mock.patch.object(ipc, \"kernel_bytes\", side_effect=error):\n first, second = self.search(), self.search()\n self.assertTrue(first[\"ok\"] and second[\"ok\"])\n self.assertEqual(second[\"admission\"][\"mode\"], \"strict_full\")\n self.assertEqual(len(self.opens()), before + 2)\n\n def test_unsupported_nested_mount_and_device_mismatch_cannot_reuse(self):\n self.search()\n guard = self.owner.guard\n self.assertTrue(guard.reusable())\n real_mount = ipc.descriptor_mount\n segment_inode = self.segment.stat().st_ino\n table = ipc.mount_records(ipc.kernel_bytes(\"/proc/self/mountinfo\", ipc.MOUNTINFO_LIMIT))\n new_id = max(table) + 1\n segment_device = self.segment.stat().st_dev\n record = (os.major(segment_device), os.minor(segment_device), b\"nfs\", b\"nested\")\n table[new_id] = record\n\n def mount_for(fd):\n return new_id if os.fstat(fd).st_ino == segment_inode else real_mount(fd)\n\n with mock.patch.object(ipc, \"mount_records\", return_value=table), \\\n mock.patch.object(ipc, \"descriptor_mount\", side_effect=mount_for):\n self.assertIsNone(ipc.LocalMounts.capture(guard.nodes))\n table[new_id] = (record[0] + 1, record[1], b\"tmpfs\", b\"wrong-device\")\n self.assertIsNone(ipc.LocalMounts.capture(guard.nodes))\n del table[new_id]\n self.assertIsNone(ipc.LocalMounts.capture(guard.nodes))\n self.assertTrue(guard.reusable())\n\n def test_namespace_and_mount_changes_invalidate_warm_admission(self):\n self.search()\n namespace = self.owner.guard.local_mounts.namespace\n with mock.patch.object(ipc, \"namespace_identity\", return_value=(namespace[0], namespace[1] + 1)):\n changed = self.search()\n self.assertEqual(changed[\"admission\"][\"mode\"], \"strict_full\")\n self.assertIsNone(self.owner.guard.local_mounts)\n self.search()\n self.assertTrue(self.owner.guard.reusable())\n table = ipc.mount_records(ipc.kernel_bytes(\"/proc/self/mountinfo\", ipc.MOUNTINFO_LIMIT))\n watched = next(iter(self.owner.guard.local_mounts.records))\n record = table[watched]\n table[watched] = (*record[:3], record[3] + b\" changed-options\")\n with mock.patch.object(ipc, \"mount_records\", return_value=table):\n changed = self.search()\n self.assertEqual(changed[\"admission\"][\"mode\"], \"strict_full\")\n self.assertEqual(len(self.opens()), 4)\n\n def test_unrelated_mount_record_changes_do_not_evict_reader(self):\n self.search()\n table = ipc.mount_records(ipc.kernel_bytes(\"/proc/self/mountinfo\", ipc.MOUNTINFO_LIMIT))\n unrelated = max(table) + 1\n table[unrelated] = (0, 99, b\"tmpfs\", b\"unrelated mount\")\n with mock.patch.object(ipc, \"mount_records\", return_value=table):\n response = self.search()\n self.assertEqual(response[\"admission\"][\"mode\"], \"retained_guarded\")\n self.assertEqual(len(self.opens()), 1)\n\n def test_reuse_eligibility_loss_during_query_discards_result(self):\n self.search()\n with mock.patch.object(ipc.LocalMounts, \"unchanged\", side_effect=[True, False]):\n with self.assertRaises(ipc.Failure) as raised:\n self.search()\n self.assertEqual(raised.exception.kind, \"index_changed\")\n self.assertIsNone(self.owner.process)\n self.assertIsNone(self.owner.guard)\n\n def test_ancestor_aba_cannot_redirect_native_admission(self):\n # Moving the ancestor away and back does not change the guarded root's\n # metadata. Pathname checks alone therefore cannot catch this ABA.\n live = self.home / \"live\"\n alternate = self.home / \"alternate\"\n saved = self.home / \"saved\"\n live.mkdir()\n alternate.mkdir()\n self.index.rename(live / \"index\")\n self.index = live / \"index\"\n self.segment = self.index / \"segment.qseg\"\n other = alternate / \"index\"\n other.mkdir()\n other_bytes = b\"different but valid published index\"\n (other / \"segment.qseg\").write_bytes(other_bytes)\n (other / \"quill.manifest.json\").write_text(json.dumps({\n \"hash\": hashlib.sha256(other_bytes).hexdigest()}))\n expected = ipc.stamp(self.index.stat())\n expected_hash = hashlib.sha256(self.segment.read_bytes()).hexdigest()\n self.owner = ipc.Owner(str(self.cass), self.index, 2)\n self.mode(\"root_probe\")\n real_popen = subprocess.Popen\n\n def redirected_spawn(*args, **kwargs):\n live.rename(saved)\n alternate.rename(live)\n process = None\n try:\n process = real_popen(*args, **kwargs)\n deadline = time.monotonic() + 2\n while not (self.home / \"root_ready\").exists():\n if process.poll() is not None or time.monotonic() >= deadline:\n self.fail(\"worker did not sample the redirected root\")\n time.sleep(0.005)\n return process\n except BaseException:\n if process is not None:\n process.kill()\n process.communicate(timeout=2)\n raise\n finally:\n live.rename(alternate)\n saved.rename(live)\n\n with mock.patch.object(ipc.subprocess, \"Popen\", side_effect=redirected_spawn):\n first = self.search()\n self.assertEqual(ipc.stamp(self.index.stat()), expected)\n self.assertTrue(self.owner.guard.unchanged())\n self.assertEqual(first[\"result\"][\"root_probe\"][\"identity\"], list(expected[:2]))\n self.assertEqual(first[\"result\"][\"root_probe\"][\"sha256\"], expected_hash)\n second = self.search()\n self.assertEqual(second[\"admission\"][\"mode\"], \"retained_guarded\")\n self.assertEqual(second[\"result\"][\"root_probe\"], first[\"result\"][\"root_probe\"])\n self.assertEqual(len(self.opens()), 1)\n\n def test_worker_retains_only_the_guarded_root_descriptor(self):\n self.mode(\"root_probe\")\n unrelated = os.open(self.cass, os.O_RDONLY)\n os.set_inheritable(unrelated, True)\n try:\n first, second = self.search(), self.search()\n finally:\n os.close(unrelated)\n root_fd = self.owner.guard.nodes[0][0]\n identity = list(ipc.stamp(self.index.stat())[:2])\n self.assertEqual(first[\"result\"][\"root_probe\"][\"inherited\"], [root_fd])\n self.assertEqual(second[\"result\"][\"current_root\"], identity)\n self.assertEqual(len(self.opens()), 1)\n\n def test_adversarial_segment_changes_force_strict_failure(self):\n cases = (\"replacement\", \"truncation\", \"same_length\", \"restored_mtime\")\n original = self.segment.read_bytes()\n for kind in cases:\n with self.subTest(kind=kind):\n self.owner.close()\n self.segment.write_bytes(original)\n self.publish_manifest()\n self.assertTrue(self.search()[\"ok\"])\n info = self.segment.stat()\n if kind == \"replacement\":\n new = self.index / \"replacement\"\n new.write_bytes(b\"x\" * len(original))\n os.utime(new, ns=(info.st_atime_ns, info.st_mtime_ns))\n new.replace(self.segment)\n elif kind == \"truncation\":\n self.segment.write_bytes(original[:128])\n else:\n with self.segment.open(\"r+b\") as changed:\n changed.write(b\"x\")\n if kind == \"restored_mtime\":\n os.utime(self.segment, ns=(info.st_atime_ns, info.st_mtime_ns))\n response = self.search()\n self.assertFalse(response[\"ok\"])\n self.assertEqual(response[\"error\"][\"kind\"], \"corrupt\")\n self.assertIsNone(self.owner.process)\n self.assertIsNone(self.owner.guard)\n\n def test_valid_publication_reopens(self):\n self.search()\n self.segment.write_bytes(b\"new contents\")\n self.publish_manifest()\n response = self.search()\n self.assertTrue(response[\"ok\"])\n self.assertEqual(response[\"admission\"][\"mode\"], \"strict_full\")\n self.assertEqual(len(self.opens()), 2)\n\n def test_directory_replacement_reopens(self):\n self.search()\n self.index.rename(self.home / \"old\")\n self.index.mkdir()\n self.segment.write_bytes(b\"corruption\")\n (self.index / \"quill.manifest.json\").write_text(\n (self.home / \"old\" / \"quill.manifest.json\").read_text())\n self.assertFalse(self.search()[\"ok\"])\n self.assertEqual(len(self.opens()), 2)\n\n def test_mutation_during_query_discards_result(self):\n self.mode(\"mutate\")\n with self.assertRaises(ipc.Failure) as raised:\n self.search()\n self.assertEqual(raised.exception.kind, \"index_changed\")\n self.assertIsNone(self.owner.process)\n\n def test_corrupted_worker_protocol_never_admits(self):\n for mode in (\"bad_json\", \"duplicate\", \"oversized\", \"wrong_id\", \"bad_schema\", \"exit\",\n \"forged_reuse\", \"non_boolean_reuse\", \"missing_reuse\", \"mixed_outcome\",\n \"forged_admission\"):\n with self.subTest(mode=mode):\n self.mode(mode)\n with self.assertRaises(ipc.Failure):\n self.search()\n self.assertIsNone(self.owner.process)\n self.assertIsNone(self.owner.guard)\n\n def test_timeout_reaps_worker(self):\n self.mode(\"hang\")\n self.owner.timeout = 0.15\n start = time.monotonic()\n with self.assertRaises(ipc.Failure) as raised:\n self.search()\n self.assertEqual(raised.exception.kind, \"timeout\")\n self.assertLess(time.monotonic() - start, 3)\n self.assertIsNone(self.owner.process)\n\n def test_invalid_requests_do_not_start_worker(self):\n for extra in ({\"query\": \"\"}, {\"id\": True}, {\"full_verify\": 1},\n {\"limit\": 101}, {\"offset\": -1}, {\"receipt\": {}},\n {\"op\": \"reload\"}, {\"query\": \"\\ud800\"}):\n with self.subTest(extra=extra):\n with self.assertRaises(ipc.Failure):\n self.search(**extra)\n self.assertIsNone(self.owner.process)\n self.assertEqual(self.opens(), [])\n\n def test_index_symlink_refused(self):\n target = self.home / \"outside\"\n target.write_text(\"data\")\n (self.index / \"linked\").symlink_to(target)\n with self.assertRaises(OSError):\n self.search()\n self.assertIsNone(self.owner.process)\n\n def test_fifo_refused_without_blocking(self):\n os.mkfifo(self.index / \"fifo\")\n start = time.monotonic()\n with self.assertRaises(ipc.Failure):\n self.search()\n self.assertLess(time.monotonic() - start, 1)\n\n def test_guard_detects_new_files(self):\n self.search()\n (self.index / \"added\").write_text(\"new sidecar\")\n response = self.search()\n self.assertEqual(response[\"admission\"][\"mode\"], \"strict_full\")\n\n def test_file_descriptor_cleanup(self):\n before = len(os.listdir(\"/proc/self/fd\"))\n for _ in range(12):\n self.search(full_verify=True)\n self.owner.close()\n self.assertLessEqual(len(os.listdir(\"/proc/self/fd\")), before)\n\n def test_fresh_clients_share_one_admission(self):\n endpoint = self.start_server()\n command = [sys.executable, \"-S\", str(MODULE_PATH), \"search\", \"alpha\",\n \"--socket\", str(endpoint)]\n responses = []\n for extra in ([], [], [\"--full-verify\"]):\n result = subprocess.run(command + extra, capture_output=True, timeout=5)\n self.assertEqual(result.returncode, 0, result.stderr.decode())\n responses.append(json.loads(result.stdout))\n self.assertEqual([r[\"admission\"][\"mode\"] for r in responses],\n [\"strict_full\", \"retained_guarded\", \"strict_full\"])\n self.assertEqual(len(self.opens()), 2)\n self.assertEqual(responses[0][\"result\"][\"hits\"], responses[1][\"result\"][\"hits\"])\n\n def test_direct_full_verify_does_not_need_socket(self):\n result = subprocess.run(\n [sys.executable, \"-S\", str(MODULE_PATH), \"search\", \"alpha\",\n \"--index\", str(self.index), \"--cass\", str(self.cass)],\n capture_output=True, timeout=5)\n self.assertEqual(result.returncode, 0, result.stderr.decode())\n self.assertTrue(json.loads(result.stdout)[\"admission\"][\"full_verify_requested\"])\n\n def test_insecure_and_symlink_socket_parent_refused(self):\n insecure = self.home / \"insecure\"\n insecure.mkdir(mode=0o755)\n with self.assertRaises(ipc.Failure):\n ipc.query(insecure / \"s\", self.request(), 1)\n private = self.home / \"private\"\n private.mkdir(mode=0o700)\n linked = self.home / \"linked\"\n linked.symlink_to(private, target_is_directory=True)\n with self.assertRaises(OSError):\n ipc.query(linked / \"s\", self.request(), 1)\n\n def test_existing_endpoint_is_not_deleted(self):\n endpoint = self.start_server()\n original = endpoint.stat().st_ino\n result = subprocess.run(\n [sys.executable, \"-S\", str(MODULE_PATH), \"serve\", \"--socket\", str(endpoint),\n \"--index\", str(self.index), \"--cass\", str(self.cass)],\n capture_output=True, timeout=5)\n self.assertEqual(result.returncode, 1)\n self.assertEqual(endpoint.stat().st_ino, original)\n self.assertTrue(ipc.query(endpoint, self.request(), 2)[\"ok\"])\n\n def test_bad_frames_do_not_poison_next_connection(self):\n endpoint = self.start_server()\n for raw in (b\"not json\\n\", b'{\"id\":1,\"id\":2}\\n',\n b\"x\" * (ipc.REQUEST_LIMIT + 1) + b\"\\n\"):\n with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:\n client.settimeout(2)\n client.connect(str(endpoint))\n client.sendall(raw)\n with __import__(\"contextlib\").suppress(ConnectionResetError):\n response = client.recv(ipc.RESPONSE_LIMIT)\n if response:\n self.assertFalse(json.loads(response)[\"ok\"])\n self.assertTrue(ipc.query(endpoint, self.request(), 2)[\"ok\"])\n\n def test_corrupted_lock_contents_are_not_an_admission_proof(self):\n endpoint = self.start_server()\n endpoint.with_name(endpoint.name + \".lock\").write_text('{\"verified\":true}')\n self.assertTrue(ipc.query(endpoint, self.request(), 2)[\"ok\"])\n self.assertEqual(len(self.opens()), 1)\n self.segment.write_bytes(b\"bad\")\n response = ipc.query(endpoint, self.request(), 2)\n self.assertFalse(response[\"ok\"])\n self.assertEqual(len(self.opens()), 2)\n\n def test_sigterm_cleans_socket_and_child(self):\n endpoint = self.start_server()\n ipc.query(endpoint, self.request(), 2)\n child = int(self.opens()[0])\n self.server.terminate()\n self.server.communicate(timeout=5)\n self.assertFalse(endpoint.exists())\n with self.assertRaises(ProcessLookupError):\n os.kill(child, 0)\n\n\nclass MetadataAndProtocolTests(unittest.TestCase):\n RECORD = b\"17 1 0:42 / /index rw,nosuid shared:2 future-tag:x - tmpfs none rw\\n\"\n\n def test_mount_records_validate_binding_and_ignore_optional_fields(self):\n records = ipc.mount_records(self.RECORD)\n self.assertEqual(records[17], (0, 42, b\"tmpfs\", self.RECORD.rstrip(b\"\\n\")))\n # Escaped whitespace in a mount path does not affect descriptor matching.\n self.assertEqual(ipc.mount_records(self.RECORD.replace(b\"/index\", b\"/a\\\\040b\"))[17][:3],\n (0, 42, b\"tmpfs\"))\n\n def test_corrupt_truncated_oversized_and_duplicate_mount_state_is_refused(self):\n for bad in (b\"\", self.RECORD[:-1], self.RECORD + self.RECORD,\n self.RECORD.replace(b\"17 1\", b\"-1 1\"),\n self.RECORD.replace(b\"17 1\", b\"9\" * 21 + b\" 1\"),\n self.RECORD.replace(b\"0:42\", b\"0:bad\"),\n self.RECORD.replace(b\" - \", b\" \"),\n self.RECORD.replace(b\" - \", b\" - - \"),\n self.RECORD.replace(b\"/index\", b\"relative\"),\n b\"x\" * (ipc.MOUNTINFO_LIMIT + 1)):\n with self.subTest(bad=bad[:80]), self.assertRaises(ValueError):\n ipc.mount_records(bad)\n with mock.patch.object(ipc, \"MAX_MOUNTS\", 1), self.assertRaises(ValueError):\n ipc.mount_records(self.RECORD + self.RECORD.replace(b\"17 1\", b\"18 1\"))\n\n def test_descriptor_mount_requires_one_bounded_kernel_id(self):\n for bad in (b\"pos:\\t0\\n\", b\"mnt_id: 1\\nmnt_id: 1\\n\", b\"mnt_id: -1\\n\",\n b\"mnt_id: nonsense\\n\", b\"mnt_id: \" + b\"9\" * 21 + b\"\\n\"):\n with mock.patch.object(ipc, \"kernel_bytes\", return_value=bad), self.assertRaises(ValueError):\n ipc.descriptor_mount(7)\n with mock.patch.object(ipc, \"kernel_bytes\", return_value=b\"pos: 0\\nmnt_id:\\t17\\n\") as read:\n self.assertEqual(ipc.descriptor_mount(7), 17)\n read.assert_called_once_with(\"/proc/self/fdinfo/7\", ipc.FDINFO_LIMIT)\n\n def test_kernel_reads_are_bounded_and_require_complete_frames(self):\n with tempfile.TemporaryDirectory() as directory:\n path = Path(directory) / \"kernel-fixture\"\n for bad in (b\"\", b\"abc\", b\"abcde\\n\"):\n path.write_bytes(bad)\n with self.assertRaises(ValueError):\n ipc.kernel_bytes(path, 4)\n path.write_bytes(b\"abc\\n\")\n self.assertEqual(ipc.kernel_bytes(path, 4), b\"abc\\n\")\n\n @staticmethod\n def response(reused=False, full=False):\n return {\"schema_version\": 1, \"id\": 1, \"ok\": True,\n \"result\": {\"hits\": [], \"reader_reused\": reused},\n \"admission\": {\"mode\": \"retained_guarded\" if reused else \"strict_full\",\n \"owner_epoch\": 1, \"full_verify_requested\": full,\n \"persistent_proof\": False, \"file_identity_checked\": True,\n \"immutable_generation_certified\": False}}\n\n def test_client_accepts_only_the_requested_admission_contract(self):\n for reused, full in ((False, False), (False, True), (True, False)):\n ipc.validate_response(self.response(reused, full), 1, full)\n for key, value in ((\"mode\", \"unchecked\"), (\"owner_epoch\", True), (\"owner_epoch\", 0),\n (\"owner_epoch\", 2**64), (\"full_verify_requested\", 0),\n (\"persistent_proof\", 0), (\"persistent_proof\", True),\n (\"file_identity_checked\", False), (\"immutable_generation_certified\", True)):\n bad = self.response()\n bad[\"admission\"][key] = value\n with self.subTest(key=key, value=value), self.assertRaises(ipc.Failure):\n ipc.validate_response(bad, 1, False)\n with self.assertRaises(ipc.Failure):\n ipc.validate_response(self.response(True, True), 1, True)\n bad = self.response()\n bad[\"admission\"][\"unrecognized_proof\"] = True\n with self.assertRaises(ipc.Failure):\n ipc.validate_response(bad, 1, False)\n\n def test_mixed_error_and_success_proof_envelopes_are_rejected(self):\n error = {\"schema_version\": 1, \"id\": 1, \"ok\": False, \"error\": {\"kind\": \"corrupt\"}}\n ipc.validate_response(error, 1, True)\n for extra in ({\"admission\": self.response()[\"admission\"]}, {\"result\": {}}, {\"unknown\": 1}):\n with self.assertRaises(ipc.Failure):\n ipc.validate_response({**error, **extra}, 1, False)\n good = self.response()\n with self.assertRaises(ipc.Failure):\n ipc.validate_response({**good, \"error\": {\"kind\": \"corrupt\"}}, 1, False)\n with self.assertRaises(ipc.Failure):\n ipc.validate_response(good, 1) # The native worker cannot mint the owner's proof.\n\n def test_python_client_validates_proof_on_the_actual_socket_path(self):\n # Socket transport is isolated here; the real client function, envelope\n # validation and full-verify request all execute without a helper bypass.\n request = {\"op\": \"search\", \"id\": 1, \"query\": \"alpha\", \"full_verify\": True}\n with tempfile.TemporaryDirectory() as directory:\n endpoint = Path(directory) / \"owner.sock\"\n with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as listener:\n listener.bind(str(endpoint))\n endpoint.chmod(0o600)\n with mock.patch.object(ipc.socket, \"socket\"), mock.patch.object(ipc, \"check_peer\"), \\\n mock.patch.object(ipc, \"receive\", return_value=self.response(True, True)):\n with self.assertRaises(ipc.Failure):\n ipc.query(endpoint, request, 1)\n\n\nif __name__ == \"__main__\":\n unittest.main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":31758,"content_sha256":"1bb8b1a8e81fe9dd32faffa52bd090e3ecf133745898d5627df8da53f0318538"},{"filename":"scripts/test_codex_contract.py","content":"#!/usr/bin/env python3\n\"\"\"Run the real CASS Codex module and its tests without the storage/TUI build.\n\n python3 scripts/test_codex_contract.py\n python3 scripts/test_codex_contract.py --fad-checkout ../franken_agent_detection\n\nThe temporary crate stages byte-identical production Rust files with their\nnormal module layout; there is no maintained fork or mock connector.\nBy default dependency sources, versions and the initial lockfile come from CASS.\nThe resolved FAD source must match CASS's lockfile before tests may start.\n--fad-checkout tests an upstream change before publication, verifies Cargo\nselected that checkout, and changes only the temporary crate's dependency.\nOnly FAD's unrelated SQLite/crypto features are omitted. The integration\ntests also remain normal CASS cargo test targets.\nRequires Python 3.11+ and the repository's Rust toolchain.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport os\nfrom pathlib import Path\nimport shutil\nimport subprocess\nimport tempfile\nimport tomllib\n\n\n# APIs that exist only in the full CASS crate. A staged test that uses one can\n# never build here; 11fcce89 added such a module and left this lane red for\n# days behind a bare compile error (bead coding_agent_session_search-2l1b0.62).\nFULL_CRATE_ONLY = (\"assert_cmd::\", \"cargo_bin!(\", \"get_connector_factories(\")\n\n\ndef toml_value(value: object) -> str:\n \"\"\"Encode the string/bool/list values used by Cargo dependency tables.\"\"\"\n if isinstance(value, str):\n # JSON's ASCII surrogate pairs are not legal TOML Unicode escapes.\n return json.dumps(value, ensure_ascii=False)\n if isinstance(value, bool):\n return \"true\" if value else \"false\"\n if isinstance(value, list):\n return \"[\" + \", \".join(toml_value(item) for item in value) + \"]\"\n raise ValueError(f\"unsupported Cargo dependency value type: {type(value).__name__}\")\n\n\ndef dependency_for_harness(\n name: str, specification: str | dict, root: Path,\n fad_checkout: Path | None, fad_version: str,\n) -> str:\n spec = {\"version\": specification} if isinstance(specification, str) else dict(specification)\n if \"workspace\" in spec:\n raise ValueError(f\"{name}: resolve workspace inheritance before staging this dependency\")\n if name == \"franken-agent-detection\":\n if fad_checkout is not None:\n for key in (\"git\", \"rev\", \"tag\", \"branch\", \"path\", \"registry\", \"registry-index\"):\n spec.pop(key, None)\n spec.update(version=\"=\" + fad_version, path=str(fad_checkout))\n # The only deliberate feature reduction: unrelated FAD SQLite/crypto.\n # Keep its git/rev (or registry/path) source, not just its version.\n spec.update({\"default-features\": False, \"features\": [\"connectors\", \"codex-zstd\"]})\n elif name == \"serde\":\n spec[\"features\"] = list(dict.fromkeys([*spec.get(\"features\", []), \"derive\"]))\n if \"path\" in spec:\n spec[\"path\"] = str((root / spec[\"path\"]).resolve(strict=True))\n return name + \" = { \" + \", \".join(\n f\"{key} = {toml_value(value)}\" for key, value in spec.items()\n ) + \" }\"\n\n\ndef verify_fad_selection(metadata: dict, lockfile: dict, fad_checkout: Path | None) -> None:\n selected = [package for package in metadata[\"packages\"] if package[\"name\"] == \"franken-agent-detection\"]\n if len(selected) != 1:\n raise RuntimeError(\"Cargo must select exactly one franken-agent-detection package\")\n package = selected[0]\n if fad_checkout is not None:\n if package.get(\"source\") is not None or Path(package[\"manifest_path\"]).resolve() != fad_checkout / \"Cargo.toml\":\n raise RuntimeError(\"Cargo did not select the requested local FAD checkout\")\n else:\n locked = [entry for entry in lockfile[\"package\"] if entry[\"name\"] == \"franken-agent-detection\"]\n if len(locked) != 1 or (\n package[\"version\"], package.get(\"source\")\n ) != (locked[0][\"version\"], locked[0].get(\"source\")):\n raise RuntimeError(\"Cargo's FAD version/source differs from CASS's committed lockfile\")\n print(f\"Verified FAD {package['version']}: {package.get('source') or package['manifest_path']}\", flush=True)\n\n\ndef refuse_full_crate_tests(root: Path, tests: tuple[str, ...]) -> None:\n for test in tests:\n path = root / f\"tests/{test}.rs\"\n found = [token for token in FULL_CRATE_ONLY if token in path.read_text(encoding=\"utf-8\")]\n if found:\n raise SystemExit(\n f\"tests/{test}.rs uses full-crate APIs ({', '.join(found)}), which this slim \"\n \"consumer crate cannot build; put those tests in their own integration target \"\n \"(as tests/codex_source_budget_override.rs does)\"\n )\n\n\ndef main() -> None:\n parser = argparse.ArgumentParser(description=__doc__)\n parser.add_argument(\"--fad-checkout\", type=Path, help=\"Test this local FAD checkout without changing CASS's published dependency pin\")\n args = parser.parse_args()\n fad_checkout = None\n fad_version = \"\"\n if args.fad_checkout is not None:\n try:\n fad_checkout = args.fad_checkout.resolve(strict=True)\n package = tomllib.loads((fad_checkout / \"Cargo.toml\").read_text(encoding=\"utf-8\"))[\"package\"]\n if package.get(\"name\") != \"franken-agent-detection\" or not isinstance(package.get(\"version\"), str):\n raise ValueError(\"expected the franken-agent-detection package with an explicit version\")\n fad_version = package[\"version\"]\n except (OSError, KeyError, ValueError) as error:\n parser.error(f\"invalid --fad-checkout: {error}\")\n\n root = Path(__file__).resolve().parents[1]\n manifest = tomllib.loads((root / \"Cargo.toml\").read_text(encoding=\"utf-8\"))\n lockfile = tomllib.loads((root / \"Cargo.lock\").read_text(encoding=\"utf-8\"))\n dependencies = manifest[\"dependencies\"]\n names = (\n \"anyhow\", \"blake3\", \"chrono\", \"dirs\", \"dotenvy\", \"franken-agent-detection\", \"walkdir\",\n \"serde\", \"serde_json\", \"tempfile\", \"thiserror\", \"tracing\", \"zstd\",\n )\n tests = (\"connector_codex_exclusions\", \"codex_source_containment\")\n refuse_full_crate_tests(root, tests)\n lines = [\n \"[package]\", 'name = \"cass-codex-contract\"', 'version = \"0.0.0\"',\n 'edition = \"2024\"', \"publish = false\", \"\", \"[lib]\",\n 'name = \"coding_agent_search\"', 'path = \"lib.rs\"',\n ]\n for test in tests:\n lines.extend([\n \"\", \"[[test]]\", f'name = \"{test}\"',\n \"path = \" + json.dumps((root / f\"tests/{test}.rs\").as_posix(), ensure_ascii=False),\n ])\n lines.extend([\"\", \"[dependencies]\"])\n for name in names:\n spec = dependencies[name] if name in dependencies else manifest[\"dev-dependencies\"][name]\n lines.append(dependency_for_harness(name, spec, root, fad_checkout, fad_version))\n lines.extend([\"\", \"[lints.rust]\", 'unsafe_code = \"forbid\"', \"\"])\n\n library = '''// Re-exports only; the Codex implementation is unmodified production code.\n// Crate-internal entry points used only by unstaged CASS modules (such as\n// ingest diagnostics) are unused here; the full crate's clippy checks them.\n#![allow(dead_code)]\npub use franken_agent_detection::{\n Connector, DetectionResult, DiscoveredSourceFile, DiscoveredSourceRole, NormalizedConversation,\n NormalizedMessage, Origin, ScanContext, ScanRoot, SourceKind, parse_timestamp, reindex_messages,\n};\npub mod codex;\npub mod connectors {\n pub use super::{\n Connector, DetectionResult, DiscoveredSourceFile, DiscoveredSourceRole, NormalizedConversation,\n NormalizedMessage, Origin, ScanContext, ScanRoot, SourceKind, codex,\n };\n}\n'''\n cargo = shutil.which(\"cargo\")\n if cargo is None:\n raise SystemExit(\"cargo is required; install the repository's Rust toolchain\")\n source_dir = root / \"src/connectors\"\n source_files = [source_dir / \"codex.rs\", *sorted((source_dir / \"codex\").rglob(\"*.rs\"))]\n with tempfile.TemporaryDirectory(prefix=\"cass-codex-contract-\") as directory:\n work = Path(directory)\n project = work / \"Cargo.toml\"\n project.write_text(\"\\n\".join(lines), encoding=\"utf-8\")\n (work / \"lib.rs\").write_text(library, encoding=\"utf-8\")\n # Normal `mod codex` preserves the nested lookup rules that #[path]\n # overrides. Check equality rather than rewriting source to fit a stub.\n for original in source_files:\n staged = work / original.relative_to(source_dir)\n staged.parent.mkdir(parents=True, exist_ok=True)\n source = original.read_bytes()\n staged.write_bytes(source)\n if staged.read_bytes() != source:\n raise RuntimeError(f\"staged source differs from {original}\")\n for name in (\"Cargo.lock\", \"rust-toolchain.toml\", \"rustfmt.toml\", \".rustfmt.toml\"):\n original = root / name\n if original.is_file():\n shutil.copyfile(original, work / name)\n env = os.environ.copy()\n # The ordinary unit tests must not inherit operator scan exclusions.\n # Integration tests supply each child's own real exclusion value.\n env[\"CASS_EXCLUDE_PATHS\"] = \"\"\n # The reduced crate needs its own root entry in the copied lockfile.\n # Normalize once, verify the actual source (including the resolved Git\n # commit), then disallow resolution changes during tests and Clippy.\n metadata = json.loads(subprocess.check_output(\n [cargo, \"metadata\", \"--manifest-path\", str(project), \"--format-version\", \"1\"],\n cwd=root, env=env, text=True,\n ))\n verify_fad_selection(metadata, lockfile, fad_checkout)\n commands = [\n [cargo, \"test\", \"--locked\", \"--manifest-path\", str(project), \"--all-targets\"],\n [cargo, \"clippy\", \"--locked\", \"--manifest-path\", str(project), \"--all-targets\", \"--\", \"-D\", \"warnings\"],\n ]\n for command in commands:\n print(\"+ \" + \" \".join(command), flush=True)\n subprocess.run(command, cwd=root, env=env, check=True)\n # Each file is checked individually, so do not resolve its children as\n # if that file were a crate root. Never reformat the actual working tree.\n rustfmt = shutil.which(\"rustfmt\")\n if rustfmt is None:\n raise SystemExit(\"rustfmt is required\")\n command = [\n rustfmt, \"--edition\", \"2024\", \"--check\", \"--config\", \"skip_children=true\",\n *map(str, source_files),\n *(str(root / f\"tests/{test}.rs\") for test in tests),\n ]\n print(\"+ \" + \" \".join(command), flush=True)\n subprocess.run(command, cwd=root, env=env, check=True)\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":10745,"content_sha256":"6de1ddb346f6967bd3efe2f7b57ae47b347f0e1cbc120898cdde865fc658104d"},{"filename":"scripts/test_openclaw_contract.py","content":"#!/usr/bin/env python3\n\"\"\"Exercise CASS's actual OpenClaw surface and SQLite bridge without the TUI.\n\nNormal mode uses the production dependency declarations unchanged. Qualification\nmode enables only openclaw-sqlite in a candidate manifest, never the checkout.\nIt is for validating the feature change before landing it, not for release use.\n\"\"\"\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport os\nfrom pathlib import Path\nimport re\nimport shutil\nimport subprocess\nimport tempfile\nimport tomllib\n\n\ndef declaration(source: str, name: str) -> str:\n section = re.search(r\"(?ms)^\\[dependencies\\]\\n(.*?)(?=^\\[)\", source)\n if section is None:\n raise ValueError(\"missing normal dependency section\")\n matches = re.findall(r\"(?m)^\" + re.escape(name) + r\"\\s*=.*$\", section[1])\n if len(matches) != 1:\n raise ValueError(f\"missing or ambiguous declaration: {name}\")\n if tomllib.loads(matches[0])[name] != tomllib.loads(source)[\"dependencies\"][name]:\n raise ValueError(f\"incomplete declaration: {name}\")\n return matches[0]\n\n\n# APIs that exist only in the full CASS crate. A staged test that uses one can\n# never build here; the registry/CLI module once did and left this lane red\n# behind a bare compile error (bead coding_agent_session_search-2l1b0.62).\n# get_connector_factories is not listed: the staged lib provides the same\n# OpenClaw registry adapter for connectors::openclaw's own unit tests.\nFULL_CRATE_ONLY = (\"assert_cmd::\", \"cargo_bin!(\")\n\n\ndef refuse_full_crate_tests(tests: list[Path]) -> None:\n for path in tests:\n found = [token for token in FULL_CRATE_ONLY if token in path.read_text(encoding=\"utf-8\")]\n if found:\n raise SystemExit(\n f\"{path.name} uses full-crate APIs ({', '.join(found)}), which this slim \"\n \"consumer crate cannot build; put those tests in their own integration target \"\n \"(as tests/connector_openclaw_registry_cli.rs does)\"\n )\n\n\ndef main() -> None:\n parser = argparse.ArgumentParser(description=__doc__)\n parser.add_argument(\"--qualify-feature\", action=\"store_true\")\n parser.add_argument(\"--candidate-output\", type=Path)\n args = parser.parse_args()\n root = Path(__file__).resolve().parents[1]\n manifest = (root / \"Cargo.toml\").read_text(encoding=\"utf-8\")\n fad = declaration(manifest, \"franken-agent-detection\")\n features = tomllib.loads(fad)[\"franken-agent-detection\"].get(\"features\", [])\n if \"openclaw-sqlite\" not in features:\n if not args.qualify_feature:\n raise SystemExit(\"standard CASS dependency is missing openclaw-sqlite\")\n candidate = fad.replace(\"features = [\", 'features = [\"openclaw-sqlite\", ', 1)\n if candidate == fad:\n raise SystemExit(\"unrecognized dependency declaration; not modifying it\")\n manifest = manifest.replace(fad, candidate, 1)\n names = [\"anyhow\", \"chrono\", \"dirs\", \"dotenvy\", \"asupersync\", \"frankensqlite\", \"fsqlite-types\", \"franken-agent-detection\", \"serde_json\", \"tempfile\"]\n dependencies = [declaration(manifest, name) for name in names]\n cargo = shutil.which(\"cargo\")\n if cargo is None:\n raise SystemExit(\"cargo is required\")\n test = root / \"tests/connector_openclaw_sqlite.rs\"\n refuse_full_crate_tests([test, root / \"tests/connector_openclaw.rs\"])\n registry = (root / \"src/connectors/mod.rs\").read_text(encoding=\"utf-8\")\n seam = \"(name, openclaw::with_wal_freshness(name, factory))\"\n if registry.count(seam) != 1:\n old = \" (name, factory)\\n\"\n if not args.qualify_feature or registry.count(old) != 1:\n raise RuntimeError(\"application registry no longer uses the tested OpenClaw adapter\")\n registry = registry.replace(old, \" \" + seam + \"\\n\", 1)\n with tempfile.TemporaryDirectory(prefix=\"cass-openclaw-contract-\") as directory:\n work = Path(directory)\n (work / \"connectors\").mkdir()\n for relative, destination in [\n (\"src/connectors/openclaw.rs\", \"connectors/openclaw.rs\"),\n (\"src/franken_sync.rs\", \"franken_sync.rs\"),\n ]:\n shutil.copyfile(root / relative, work / destination)\n (work / \"lib.rs\").write_text('''pub mod franken_sync;\npub mod connectors {\n pub use franken_agent_detection::{Connector, ScanContext, ScanRoot};\n pub mod openclaw;\n // Same final registry adapter as CASS; unrelated CASS wrappers are not\n // needed here, and this probe makes no claims about those providers.\n pub type ConnectorFactory = fn() -> Box\u003cdyn Connector + Send>;\n pub fn get_connector_factories() -> Vec\u003c(&'static str, ConnectorFactory)> {\n franken_agent_detection::get_connector_factories().into_iter()\n .map(|(name, factory)| (name, openclaw::with_wal_freshness(name, factory)))\n .collect()\n }\n}\n// The full application calls this private production teardown. Keep it used\n// in this small crate too, without changing or suppressing its diagnostics.\npub fn shutdown_contract_driver() -> bool { franken_sync::shutdown_driver() }\n''', encoding=\"utf-8\")\n project = work / \"Cargo.toml\"\n project.write_text('\\n'.join([\n '[package]', 'name = \"cass-openclaw-contract\"', 'version = \"0.0.0\"',\n 'edition = \"2024\"', 'publish = false', '[lib]',\n 'name = \"coding_agent_search\"', 'path = \"lib.rs\"',\n '[[test]]', 'name = \"connector_openclaw_sqlite\"',\n 'path = ' + json.dumps(test.as_posix(), ensure_ascii=False),\n '[[test]]', 'name = \"connector_openclaw\"',\n 'path = ' + json.dumps((root / \"tests/connector_openclaw.rs\").as_posix(), ensure_ascii=False),\n '[dependencies]', *dependencies, '[profile.dev]', 'debug = 0',\n '[profile.dev.package.\"*\"]', 'opt-level = 1',\n '[lints.rust]', 'unsafe_code = \"forbid\"', '',\n ]), encoding=\"utf-8\")\n for name in [\"Cargo.lock\", \"rust-toolchain.toml\"]:\n if (root / name).is_file():\n shutil.copyfile(root / name, work / name)\n env = os.environ.copy()\n env[\"CARGO_TARGET_DIR\"] = str(root / \"target/openclaw-contract\")\n env.setdefault(\"RUST_MIN_STACK\", \"134217728\")\n env[\"CASS_EXCLUDE_PATHS\"] = \"\"\n env[\"OPENCLAW_STATE_DIR\"] = \"\"\n metadata = json.loads(subprocess.check_output([\n cargo, \"metadata\", \"--manifest-path\", str(project), \"--format-version\", \"1\",\n ], cwd=root, env=env))\n expected = tomllib.loads((root / \"Cargo.lock\").read_text(encoding=\"utf-8\"))[\"package\"]\n expected = {(p[\"name\"], p[\"version\"], p.get(\"source\")) for p in expected}\n for package in metadata[\"packages\"]:\n name = package[\"name\"]\n if name in {\"franken-agent-detection\", \"asupersync\"} or name.startswith(\"fsqlite\"):\n key = (name, package[\"version\"], package.get(\"source\"))\n if key not in expected:\n raise RuntimeError(f\"dependency is not from the CASS lockfile: {key}\")\n print(\"LOCKED_CONSUMER\", key, flush=True)\n for command in [\n [cargo, \"test\", \"--locked\", \"--manifest-path\", str(project), \"--lib\", \"connectors::openclaw::tests\"],\n [cargo, \"test\", \"--locked\", \"--manifest-path\", str(project), \"--test\", \"connector_openclaw_sqlite\", \"--test\", \"connector_openclaw\"],\n [cargo, \"clippy\", \"--locked\", \"--manifest-path\", str(project), \"--all-targets\", \"--\", \"-D\", \"warnings\"],\n ]:\n print(\"+\", \" \".join(command), flush=True)\n subprocess.run(command, cwd=root, env=env, check=True)\n if args.candidate_output is not None:\n args.candidate_output.parent.mkdir(parents=True, exist_ok=True)\n args.candidate_output.write_text(manifest, encoding=\"utf-8\")\n args.candidate_output.with_name(\"connectors_mod.rs\").write_text(registry, encoding=\"utf-8\")\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":7962,"content_sha256":"e9b0a6e663cf5126cab4f5167bcf53379a9cd38f4599fe52d8869d25f93a1727"},{"filename":"scripts/test_raw_mirror_exclusions.py","content":"#!/usr/bin/env python3\n\"\"\"Test the real raw-mirror storage and Codex exclusion boundary.\n\nDefault: stage byte-identical capture, Codex and franken_sync implementations.\nThe small keep-tag database opener uses the real read-only FrankenSQLite API,\nnot the full CASS storage open/recovery policy. No capture or parser is mocked.\nUse --full to run the actual CASS library and CLI acceptance test instead.\nRequires Python 3.11+ and the repository's Rust toolchain. Dependency versions,\nfeatures and the initial lockfile are taken from CASS.\n\"\"\"\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport os\nfrom pathlib import Path\nimport shutil\nimport subprocess\nimport tempfile\nimport tomllib\n\n\ndef execute(command: list[str], root: Path, env: dict[str, str]) -> None:\n print(\"+ \" + \" \".join(command), flush=True)\n subprocess.run(command, cwd=root, env=env, check=True)\n\n\ndef main() -> None:\n parser = argparse.ArgumentParser(description=__doc__)\n parser.add_argument(\"--full\", action=\"store_true\", help=\"run full CASS targets, without a harness\")\n args = parser.parse_args()\n root = Path(__file__).resolve().parents[1]\n cargo = shutil.which(\"cargo\")\n if cargo is None:\n raise SystemExit(\"cargo is required\")\n env = os.environ.copy()\n env[\"CASS_EXCLUDE_PATHS\"] = \"\"\n if args.full:\n execute([cargo, \"test\", \"--locked\", \"--lib\", \"raw_mirror::\"], root, env)\n execute([cargo, \"test\", \"--locked\", \"--test\", \"e2e_codex_exclusion_capture\"], root, env)\n return\n\n manifest = tomllib.loads((root / \"Cargo.toml\").read_text(encoding=\"utf-8\"))\n names = (\n \"anyhow\", \"asupersync\", \"blake3\", \"chrono\", \"dirs\", \"dotenvy\",\n \"franken-agent-detection\", \"frankensqlite\", \"fs2\", \"glob\", \"libc\",\n \"serde\", \"serde_json\", \"tempfile\", \"thiserror\", \"tracing\",\n )\n lines = [\n \"[package]\", 'name = \"cass-raw-mirror-contract\"', 'version = \"0.0.0\"',\n 'edition = \"2024\"', 'publish = false', \"\", \"[lib]\", 'path = \"lib.rs\"',\n \"\", \"[dependencies]\",\n ]\n for name in names:\n spec = manifest[\"dependencies\"].get(name, manifest.get(\"dev-dependencies\", {}).get(name))\n if spec is None:\n raise SystemExit(f\"missing CASS dependency: {name}\")\n if isinstance(spec, str):\n spec = {\"version\": spec}\n else:\n spec = dict(spec)\n if name == \"franken-agent-detection\":\n # codex-zstd: the staged Codex consumer reads .jsonl.zst rollouts\n # through FAD (GH #513), exactly as the full application builds it.\n spec = {\n \"version\": spec[\"version\"],\n \"default-features\": False,\n \"features\": [\"connectors\", \"codex-zstd\"],\n }\n fields = []\n for key in (\"version\", \"package\", \"default-features\", \"features\"):\n if key in spec:\n fields.append(f\"{key} = {json.dumps(spec[key], ensure_ascii=False)}\")\n lines.append(name + \" = { \" + \", \".join(fields) + \" }\")\n library = '''// Capture, parser, and sync-bridge files are unmodified production code.\n// Full-application-only entry points are unused in this focused consumer.\n#![allow(dead_code)]\npub use franken_agent_detection::{\n Connector, DetectionResult, DiscoveredSourceFile, NormalizedConversation,\n NormalizedMessage, ScanContext, ScanRoot, parse_timestamp, reindex_messages,\n};\npub mod codex;\npub mod connectors {\n pub use super::{Connector, DiscoveredSourceFile, ScanContext, ScanRoot, codex};\n}\npub mod franken_sync;\npub mod raw_mirror;\npub mod storage {\n pub mod sqlite {\n // Only keep-tag prune fixtures use this helper. It is a real read-only\n // engine connection, but deliberately not the full application's\n // recovery, busy-retry, schema-admission, or canonical storage layer.\n pub fn open_franken_raw_readonly_connection_with_timeout(\n path: &std::path::Path,\n timeout: std::time::Duration,\n ) -> anyhow::Result\u003ccrate::franken_sync::Connection> {\n use crate::franken_sync::compat::{OpenFlags, open_with_flags};\n let path = path.to_str().ok_or_else(|| anyhow::anyhow!(\"non-UTF-8 fixture database path\"))?;\n let conn = open_with_flags(path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;\n conn.execute(&format!(\"PRAGMA busy_timeout = {};\", timeout.as_millis()))?;\n Ok(conn)\n }\n }\n}\n'''\n with tempfile.TemporaryDirectory(prefix=\"cass-raw-mirror-\") as directory:\n work = Path(directory)\n project = work / \"Cargo.toml\"\n project.write_text(\"\\n\".join(lines) + \"\\n\", encoding=\"utf-8\")\n (work / \"lib.rs\").write_text(library, encoding=\"utf-8\")\n for source_base, module in [\n (root / \"src/connectors\", \"codex\"),\n (root / \"src\", \"raw_mirror\"),\n (root / \"src\", \"franken_sync\"),\n ]:\n sources = [source_base / f\"{module}.rs\", *sorted((source_base / module).rglob(\"*.rs\"))]\n for source in sources:\n target = work / source.relative_to(source_base)\n target.parent.mkdir(parents=True, exist_ok=True)\n target.write_bytes(source.read_bytes())\n if target.read_bytes() != source.read_bytes():\n raise RuntimeError(f\"staged source differs: {source}\")\n for name in [\"Cargo.lock\", \"rust-toolchain.toml\", \"rustfmt.toml\", \".rustfmt.toml\"]:\n source = root / name\n if source.is_file():\n shutil.copyfile(source, work / name)\n for command in [\n [cargo, \"test\", \"--manifest-path\", str(project), \"--lib\", \"raw_mirror::\", \"--\", \"--nocapture\"],\n [cargo, \"clippy\", \"--manifest-path\", str(project), \"--all-targets\", \"--\", \"-D\", \"warnings\"],\n ]:\n execute(command, root, env)\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":5908,"content_sha256":"68e94cc11c3b7013fcd1b1ba9110c49f865a409c1687bd5ecbd805f31fa1cdd7"},{"filename":"scripts/test_source_ledger_matcher.py","content":"#!/usr/bin/env python3\n\"\"\"Compile the exact production filesystem matcher against CASS's dependency pins.\n\nThis is a native matcher test/benchmark, NOT connector, storage or CLI coverage.\n--watch-components also exercises the exact watch source-stability helper and\nreceipt serialization buffer with the pinned FAD metadata methods. Its declared\nprovenance/policy adapters do not implement connector parsing or persistence.\nCargo may prune unused features/edges in this disposable graph, but every retained\npackage identity, checksum and edge must come from the repository lockfile before\nany compilation. Native tests then run with --locked. The repository is read-only.\n\"\"\"\nfrom __future__ import annotations\n\nimport argparse\nimport datetime\nimport hashlib\nimport json\nimport os\nfrom pathlib import Path\nimport platform\nimport re\nimport shutil\nimport signal\nimport subprocess\nimport tempfile\nimport time\nimport tomllib\nfrom typing import Any\n\nPACKAGE = \"cass-source-ledger-matcher\"\nVERSION = \"0.0.0\"\nDIRECT = (\"serde_json\", \"tempfile\")\n\n\ndef identity(package: dict[str, Any]) -> tuple[str, str, str]:\n return package[\"name\"], package[\"version\"], package.get(\"source\", \"\")\n\n\ndef resolve(spec: str, packages: list[dict[str, Any]]) -> dict[str, Any]:\n parts = spec.split()\n matches = [\n package for package in packages\n if package[\"name\"] == parts[0]\n and (len(parts) \u003c 2 or package[\"version\"] == parts[1])\n and (len(parts) \u003c 3 or package.get(\"source\") == parts[2].strip(\"()\"))\n ]\n if len(matches) != 1 or len(parts) > 3:\n raise RuntimeError(f\"ambiguous or missing locked dependency: {spec}\")\n return matches[0]\n\n\ndef dependency_closure(\n lock: dict[str, Any], names: tuple[str, ...] = DIRECT,\n) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:\n packages = lock[\"package\"]\n root = resolve(\"coding-agent-search\", packages)\n direct = [resolve(next(spec for spec in root[\"dependencies\"] if spec.split()[0] == name),\n packages) for name in names]\n selected = {}\n pending = list(direct)\n while pending:\n package = pending.pop()\n key = identity(package)\n if key in selected:\n continue\n if not key[2].startswith(\"registry+\") or not package.get(\"checksum\"):\n raise RuntimeError(f\"matcher dependency is not checksum-pinned: {key}\")\n selected[key] = package\n pending.extend(resolve(spec, packages) for spec in package.get(\"dependencies\", []))\n return direct, list(selected.values())\n\n\ndef validate_normalized_lock(\n lock: dict[str, Any], allowed: list[dict[str, Any]], direct: list[dict[str, Any]],\n) -> list[dict[str, Any]]:\n \"\"\"Permit feature pruning, never a new version, source, checksum or edge.\"\"\"\n packages = lock[\"package\"]\n observed = {identity(package): package for package in packages}\n if len(observed) != len(packages):\n raise RuntimeError(\"duplicate package identity in matcher lockfile\")\n root = resolve(f\"{PACKAGE} {VERSION}\", packages)\n if root.get(\"source\") or root.get(\"checksum\"):\n raise RuntimeError(\"matcher root is not the local harness\")\n expected = {identity(package): package for package in allowed}\n root_edges = {identity(resolve(spec, packages)) for spec in root.get(\"dependencies\", [])}\n if root_edges != {identity(package) for package in direct}:\n raise RuntimeError(\"matcher direct dependencies changed\")\n retained = []\n for package in packages:\n if package is root:\n continue\n key = identity(package)\n original = expected.get(key)\n if original is None or package.get(\"checksum\") != original.get(\"checksum\"):\n raise RuntimeError(f\"dependency pin drift: {key}\")\n old_edges = {identity(resolve(spec, allowed)) for spec in original.get(\"dependencies\", [])}\n new_edges = {identity(resolve(spec, packages)) for spec in package.get(\"dependencies\", [])}\n if not new_edges \u003c= old_edges:\n raise RuntimeError(f\"dependency edge drift: {key}\")\n retained.append(package)\n return retained\n\n\ndef watch_component_sources(\n root: Path, lock: dict[str, Any], checkout: Path, include_scan: bool = False,\n) -> dict[str, Any]:\n \"\"\"Copy tested logic verbatim; identify every type/policy boundary adapter.\"\"\"\n inputs = {}\n ranges = []\n outputs = {}\n\n def read(path: Path, label: str) -> str:\n data = path.read_bytes()\n inputs[label] = {\"path\": str(path), \"sha256\": hashlib.sha256(data).hexdigest()}\n return data.decode()\n\n def piece(text: str, label: str, start: str, end: str | None = None) -> str:\n if text.count(start) != 1:\n raise RuntimeError(f\"ambiguous extraction boundary: {label}: {start}\")\n first = text.index(start)\n last = text.index(end, first) if end else len(text)\n selected = text[first:last]\n ranges.append({\n \"input\": label, \"start_line\": text.count(\"\\n\", 0, first) + 1,\n \"end_line\": text.count(\"\\n\", 0, last),\n \"start_byte\": len(text[:first].encode()), \"end_byte\": len(text[:last].encode()),\n \"sha256\": hashlib.sha256(selected.encode()).hexdigest(),\n })\n return selected\n\n fad = resolve(\"franken-agent-detection\", lock[\"package\"])\n revision = fad[\"source\"].rsplit(\"#\", 1)[-1]\n actual = subprocess.check_output(\n [\"git\", \"rev-parse\", \"HEAD\"], cwd=checkout, timeout=30,\n ).decode().strip()\n if actual != revision:\n raise RuntimeError(f\"FAD checkout differs from Cargo.lock: {actual} != {revision}\")\n scan_path = checkout / \"src/connectors/scan.rs\"\n scan = read(scan_path, \"pinned-fad:src/connectors/scan.rs\")\n if subprocess.check_output([\"git\", \"show\", f\"{revision}:src/connectors/scan.rs\"],\n cwd=checkout, timeout=30) != scan.encode():\n raise RuntimeError(\"pinned FAD source has local modifications\")\n outputs[\"src/fad.rs\"] = (\n \"use crate::connectors::{Origin, Platform, ScanRoot};\\n\"\n \"use std::path::PathBuf;\\nuse std::time::UNIX_EPOCH;\\n\"\n + piece(scan, \"pinned-fad:src/connectors/scan.rs\",\n \"/// Connector-declared role for a file\", \"/// Completion record for one\")\n )\n\n observation_path = root / \"src/connectors/source_dependencies/observation.rs\"\n observation = read(observation_path, \"cass:src/connectors/source_dependencies/observation.rs\")\n outputs[\"src/connectors/source_dependencies/observation.rs\"] = observation\n windows = root / \"src/connectors/source_dependencies/observation/windows.rs\"\n outputs[\"src/connectors/source_dependencies/observation/windows.rs\"] = read(\n windows, \"cass:src/connectors/source_dependencies/observation/windows.rs\")\n stability_path = root / \"src/indexer/watch_source_stability.rs\"\n stability = read(stability_path, \"cass:src/indexer/watch_source_stability.rs\")\n outputs[\"src/indexer/watch_source_stability.rs\"] = stability\n ledger = read(root / \"src/indexer/watch_source_ledger.rs\", \"cass:src/indexer/watch_source_ledger.rs\")\n entry_limit = re.search(r\"(?m)^const MAX_RECEIPT_ENTRY_BYTES: usize = .+;\\n\", ledger)\n if entry_limit is None:\n raise RuntimeError(\"missing production receipt entry byte limit\")\n boundary_marker = '\\n#[cfg(test)]\\n#[path = \"watch_source_ledger_tests.rs\"]'\n receipt_start = ledger.index(\"#[derive(Default)]\\nstruct ReceiptBuffer\")\n receipt_end = boundary_marker if ledger.find(boundary_marker, receipt_start) >= 0 else None\n outputs[\"src/receipt_buffer.rs\"] = (\n piece(ledger, \"cass:src/indexer/watch_source_ledger.rs\",\n entry_limit.group(), \"const MAX_REUSED_PATH_BYTES:\")\n + piece(ledger, \"cass:src/indexer/watch_source_ledger.rs\",\n \"#[derive(Default)]\\nstruct ReceiptBuffer\", receipt_end)\n )\n policy = read(root / \"src/connectors/source_dependencies.rs\",\n \"cass:src/connectors/source_dependencies.rs\")\n outputs[\"src/policy.rs\"] = piece(\n policy, \"cass:src/connectors/source_dependencies.rs\",\n \"/// Whether discovery of a new sibling\", \"pub(crate) struct ConnectorRegistration\",\n )\n indexer = read(root / \"src/indexer/mod.rs\", \"cass:src/indexer/mod.rs\")\n observation_helper = piece(\n indexer, \"cass:src/indexer/mod.rs\", \"fn source_file_observation(\",\n \"fn source_ledger_matches_with_contract(\",\n )\n folder_helper = piece(indexer, \"cass:src/indexer/mod.rs\", \"fn source_folder_is_dependency(\",\n \"fn source_parent_observation(\")\n # These carriers only satisfy the copied FAD constructor's provenance\n # fields. They perform no filesystem I/O and are not parser substitutes.\n outputs[\"src/lib.rs\"] = \"\"\"#![allow(dead_code)]\nmod fad;\npub mod connectors {\n pub use crate::fad::{DiscoveredSourceFile, DiscoveredSourceRole};\n #[derive(Debug, Clone, PartialEq, Eq)]\n pub struct Origin;\n #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n pub struct Platform;\n pub struct ScanRoot {\n pub path: std::path::PathBuf,\n pub origin: Origin,\n pub platform: Option\u003cPlatform>,\n }\n impl ScanRoot {\n pub fn local(path: std::path::PathBuf) -> Self {\n Self { path, origin: Origin, platform: None }\n }\n }\n pub mod claude_code { pub struct ClaudeCodeConnector; }\n pub mod codex { pub struct CodexConnector; }\n pub mod codebuff { pub struct CodebuffConnector; }\n pub(crate) mod source_dependencies {\n include!(\"policy.rs\");\n pub(crate) mod observation;\n // Adapter dispatches only fixture names to the exact capability\n // declarations above; the application's full factory is not built.\n pub(crate) fn source_dependency_policy(slug: &str) -> SourceDependencyPolicy {\n match slug {\n \"claude\" | \"claude_code\" =>\n \u003csuper::claude_code::ClaudeCodeConnector as SourceDependencyCapability>::SOURCE_DEPENDENCIES,\n \"codex\" =>\n \u003csuper::codex::CodexConnector as SourceDependencyCapability>::SOURCE_DEPENDENCIES,\n \"codebuff\" =>\n \u003csuper::codebuff::CodebuffConnector as SourceDependencyCapability>::SOURCE_DEPENDENCIES,\n _ => SourceDependencyPolicy::default(),\n }\n }\n }\n}\nmod indexer {\n use crate::connectors::DiscoveredSourceFile;\n use std::path::Path;\n\"\"\" + observation_helper + folder_helper + \"\"\"\n mod watch_source_stability;\n mod watch_source_ledger { include!(\"receipt_buffer.rs\"); }\n}\n\"\"\"\n selected = re.findall(r\"(?m)^ fn (gh538_\\w+)\\(\", stability)\n selected.extend(re.findall(r\"(?m)^ fn (receipt_\\w+)\\(\", outputs[\"src/receipt_buffer.rs\"]))\n projections = {\n \"provenance_carriers\": \"Minimal Origin, Platform, ScanRoot/local fields for the verbatim FAD constructor\",\n \"policy_dispatch\": \"Fixture names map to verbatim CASS capability declarations; full connector registry excluded\",\n \"receipt_scope\": \"Verbatim MAX_RECEIPT_ENTRY_BYTES, ReceiptBuffer Write implementation, and both unit tests only\",\n }\n exclusions = [\n \"Full CASS compilation and application tests\",\n \"Connector parsing, discovery, notifications and source-hook integration\",\n \"WatchSourceLedger completion map, admission, memory accounting and receipt/debt transactions\",\n \"Canonical database, lexical publication, searchability, restart and exactly-once integration\",\n \"Full connector registry and native macOS qualification\",\n ]\n if include_scan:\n def fad_read(relative: str) -> str:\n data = read(checkout / relative, \"pinned-fad:\" + relative)\n if subprocess.check_output([\"git\", \"show\", f\"{revision}:{relative}\"],\n cwd=checkout, timeout=30) != data.encode():\n raise RuntimeError(f\"pinned FAD source has local modifications: {relative}\")\n return data\n\n types = fad_read(\"src/types.rs\")\n outputs[\"src/fad_types.rs\"] = piece(\n types, \"pinned-fad:src/types.rs\", \"//! Normalized types\",\n '#[cfg(all(test, feature = \"connectors\"))]',\n )\n fad_connector = fad_read(\"src/connectors/mod.rs\")\n outputs[\"src/fad.rs\"] = (\n \"use crate::connectors::{Origin, Platform, ScanRoot};\\n\"\n \"use crate::fad_types::{DetectionResult, NormalizedConversation};\\n\"\n \"use std::path::PathBuf;\\nuse std::time::UNIX_EPOCH;\\nuse std::sync::Arc;\\n\"\n + piece(scan, \"pinned-fad:src/connectors/scan.rs\",\n '/// A cheap \"still alive\" tick', \"#[cfg(test)]\\nmod tests {\")\n + piece(fad_connector, \"pinned-fad:src/connectors/mod.rs\",\n \"pub trait Connector {\", \"#[cfg(test)]\\npub(crate) fn assert_discovery_covers_scan_sources\")\n )\n storage = read(root / \"src/storage/sqlite.rs\", \"cass:src/storage/sqlite.rs\")\n entry = piece(storage, \"cass:src/storage/sqlite.rs\", \"pub struct SourceIngestLedgerEntry {\",\n \"/// Whether a replayed conversation's workspace\")\n source_helpers = piece(\n indexer, \"cass:src/indexer/mod.rs\", \"fn source_ledger_key(\",\n \"/// Keep only the final bounded batch\",\n )\n workspace_policy = piece(\n indexer, \"cass:src/indexer/mod.rs\", \"#[derive(Debug, Clone, Default)]\\nstruct WorkspaceExclusions\",\n \"const WORKSPACE_EXCLUSION_SCAN_PREFIX:\",\n )\n exclusion_check = piece(\n indexer, \"cass:src/indexer/mod.rs\", \"fn scan_path_exclusions_value_active(\",\n \"fn active_session_source_skip_observed(\",\n )\n # The two SQL methods are absent, not replaced with fake transactions.\n scan_core = piece(\n ledger, \"cass:src/indexer/watch_source_ledger.rs\", \"const MAX_RECEIPT_ENTRIES:\",\n \" /// An earlier publication receipt\",\n ) + \"}\\n\"\n tail = piece(ledger, \"cass:src/indexer/watch_source_ledger.rs\",\n \"fn observation_has_watch_publication(\", receipt_end)\n outputs[\"src/indexer/watch_source_ledger.rs\"] = (\n \"use super::*;\\nuse std::cell::{Cell, RefCell};\\n\"\n \"use crate::storage::sqlite::SourceIngestLedgerEntry;\\n\" + scan_core + tail\n + '\\n#[cfg(test)]\\n#[path = \"watch_source_ledger_tests.rs\"]\\nmod boundary_tests;\\n'\n )\n boundary = read(root / \"src/indexer/watch_source_ledger_tests.rs\",\n \"cass:src/indexer/watch_source_ledger_tests.rs\")\n if boundary.count(\"use serial_test::serial;\\n\") != 1 or boundary.count(\"#[serial]\\n\") != 2:\n raise RuntimeError(\"boundary serial-test projection changed; review before qualification\")\n outputs[\"src/indexer/watch_source_ledger_tests.rs\"] = boundary.replace(\n \"use serial_test::serial;\\n\", \"\").replace(\"#[serial]\\n\", \"\")\n selected.extend(re.findall(r\"(?m)^fn (gh538_\\w+)\\(\", boundary))\n # Reuse the identical fixture capability declarations/dispatch from\n # the smaller component, but replace provenance carriers with the\n # actual FAD types and expose its exact trait and source hooks.\n base = outputs[\"src/lib.rs\"]\n policies = base[base.index(\" pub mod claude_code\"):base.index(\"\\nmod indexer {\")]\n policies = policies.replace(\n \" pub(crate) mod observation;\",\n \" pub(crate) mod observation;\\n\"\n \" pub(crate) fn can_reuse_with_path_exclusions(_: &str, _: &str) -> bool {\\n\"\n ' panic!(\"excluded-source policy is outside this fixture\");\\n'\n \" }\",\n )\n outputs[\"src/lib.rs\"] = \"\"\"#![allow(dead_code)]\nextern crate self as franken_agent_detection;\nmod fad;\nmod fad_types;\npub use fad::{SourceCompletion, SourceScanHooks};\npub mod connectors {\n pub use crate::fad::*;\n pub use crate::fad_types::*;\n #[derive(Debug, Clone)]\n pub struct ScanRoot {\n pub path: std::path::PathBuf,\n pub origin: Origin,\n pub platform: Option\u003cPlatform>,\n pub workspace_rewrites: Vec\u003cPathMapping>,\n }\n impl ScanRoot {\n pub fn local(path: std::path::PathBuf) -> Self {\n Self { path, origin: Origin::local(), platform: None, workspace_rewrites: Vec::new() }\n }\n }\n\"\"\" + policies + \"\\npub mod storage { pub mod sqlite {\\n\" + entry + \"\\n} }\\n\" + \"\"\"\nmod indexer {\n use anyhow::{Context, Result};\n use crate::connectors::*;\n use std::collections::{HashMap, BTreeSet};\n use std::fs::{self, OpenOptions};\n use std::path::{Path, PathBuf};\n use std::time::Duration;\n\"\"\" + source_helpers + workspace_policy + exclusion_check + \"\"\"\n // These fixtures deliberately pass None progress and no active writers.\n // Calling a progress method is an error, not a simulated successful stop.\n struct IndexingProgress;\n impl IndexingProgress {\n fn stop_requested(&self) -> bool { panic!(\"progress not included in boundary fixture\") }\n fn tick_activity(&self) { panic!(\"progress not included in boundary fixture\") }\n fn check_stop(&self) -> Result\u003c()> { panic!(\"progress not included in boundary fixture\") }\n }\n struct ActiveSessionSourceFilter;\n impl ActiveSessionSourceFilter {\n fn with_recent_write_window_for_test(window: Option\u003cDuration>) -> Self {\n assert!(window.is_none(), \"recent-writer policy is outside this fixture\");\n Self\n }\n fn take_deferred_sources(&self) -> BTreeSet\u003cPathBuf> { BTreeSet::new() }\n }\n fn should_skip_active_session_source(_: &ActiveSessionSourceFilter, _: SourceKind, _: &Path) -> bool {\n false // Explicit no-active-writer fixture adapter; not an activity probe.\n }\n mod watch_source_stability;\n mod watch_source_ledger;\n}\n\"\"\"\n projections.update({\n \"provenance_carriers\": \"Exact pinned FAD normalized types, Origin, Platform, context, Connector trait and hooks; ScanRoot retains constructor fields needed by fixture/key only\",\n \"active_filter\": \"No-active-writer fixture adapter; recent-write option must be None; not a writer-probe test\",\n \"progress\": \"Absent-progress fixture adapter; all methods panic if invoked\",\n \"producer_contract\": \"Explicit supplemental fixture contract with source reuse enabled; CASS build-contract generation is not exercised\",\n \"serial_test\": \"Removed only serial_test import and two serial attributes; executable runs with --test-threads=1\",\n \"scan_scope\": \"Verbatim fields and scan method; begin_publication and publish_batch excluded completely; exact SourceIngestLedgerEntry carrier without storage implementation\",\n })\n exclusions = [\n \"Full CASS compilation and application tests\",\n \"Native connector parsing, discovery, filesystem notifications; boundary tests use their explicit synthetic connector\",\n \"Active-writer, exclusion-policy dispatch, cancellation/progress and full registry integration\",\n \"begin_publication/publish_batch, source receipt and debt persistence, canonical SQL and lexical/search recovery\",\n \"Aggregate receipt memory limits, replay/restart integration, native macOS qualification\",\n ]\n if len(selected) != (12 if include_scan else 10):\n raise RuntimeError(f\"watch selection changed; explicitly review its inventory: {selected}\")\n return {\n \"inputs\": inputs, \"source_ranges\": ranges, \"outputs\": outputs,\n \"required_watch_tests\": selected, \"fad_revision\": revision,\n \"projections\": projections, \"exclusions\": exclusions,\n }\n\n\ndef run_watch_components(args: argparse.Namespace, root: Path) -> None:\n if os.name != \"posix\":\n raise RuntimeError(\"the selected watch tests include Unix metadata and native-path controls\")\n env = os.environ.copy()\n if args.toolchain_bin:\n env[\"PATH\"] = str(args.toolchain_bin.resolve()) + os.pathsep + env.get(\"PATH\", \"\")\n cargo, rustc = (shutil.which(name, path=env.get(\"PATH\")) for name in (\"cargo\", \"rustc\"))\n if not cargo or not rustc:\n raise RuntimeError(\"cargo and rustc required; use --toolchain-bin for the repository pin\")\n env[\"RUSTUP_TOOLCHAIN\"] = tomllib.loads((root / \"rust-toolchain.toml\").read_text())[\"toolchain\"][\"channel\"]\n env[\"RUSTC\"] = rustc\n env[\"CARGO_BUILD_RUSTC\"] = rustc\n env[\"CARGO_BUILD_JOBS\"] = \"1\"\n for variable in (\"RUSTFLAGS\", \"CARGO_ENCODED_RUSTFLAGS\", \"RUSTC_WRAPPER\", \"RUSTC_WORKSPACE_WRAPPER\"):\n env.pop(variable, None)\n lock_bytes = (root / \"Cargo.lock\").read_bytes()\n lock = tomllib.loads(lock_bytes.decode())\n fad_revision = resolve(\"franken-agent-detection\", lock[\"package\"])[\"source\"].rsplit(\"#\", 1)[-1]\n checkout = args.fad_checkout\n if checkout is None:\n cargo_home = Path(env.get(\"CARGO_HOME\", str(Path.home() / \".cargo\"))).resolve()\n matches = list((cargo_home / \"git/checkouts\").glob(f\"franken_agent_detection-*/{fad_revision[:7]}\"))\n if len(matches) != 1:\n raise RuntimeError(\"cannot identify pinned FAD checkout; pass --fad-checkout\")\n checkout = matches[0]\n checkout = checkout.resolve()\n now = datetime.datetime.now(datetime.timezone.utc)\n output_root = (args.output_dir or Path(tempfile.mkdtemp(prefix=\"cass-watch-components-\"))).resolve()\n work = output_root / \"runs\" / (now.strftime(\"%Y%m%dT%H%M%S.%fZ\") + f\"-{os.getpid()}\")\n work.mkdir(parents=True, exist_ok=False)\n logs = work / \"logs\"\n logs.mkdir()\n env[\"CARGO_TARGET_DIR\"] = str((args.target_dir or output_root / \"target\").resolve())\n report = {\n \"format\": 1, \"qualification\": \"supplemental exact-source components, not full CASS/live watcher/macOS\",\n \"status\": \"failed\", \"started_utc\": now.isoformat(), \"evidence_directory\": str(work),\n \"platform\": platform.platform(), \"repository_lock_sha256\": hashlib.sha256(lock_bytes).hexdigest(),\n \"runner_sha256\": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),\n \"commands\": [], \"environment\": {name: env.get(name) for name in (\n \"CARGO_HOME\", \"CARGO_TARGET_DIR\", \"CARGO_BUILD_JOBS\", \"RUSTUP_TOOLCHAIN\", \"RUSTC\", \"CARGO_BUILD_RUSTC\")},\n }\n\n def run(command: list[str], label: str) -> subprocess.CompletedProcess:\n print(f\"watch components: {label}\", flush=True)\n started = time.monotonic()\n process = subprocess.Popen(command, cwd=work, env=env, stdout=subprocess.PIPE,\n stderr=subprocess.PIPE, start_new_session=True)\n timed_out = False\n drain_timed_out = False\n termination_error = None\n try:\n stdout, stderr = process.communicate(timeout=args.build_timeout)\n except subprocess.TimeoutExpired as initial_timeout:\n timed_out = True\n # This process group was created exclusively for this command;\n # drain a timed-out compiler as well as its Cargo parent.\n try:\n os.killpg(process.pid, signal.SIGKILL)\n except ProcessLookupError:\n pass # The owned process group exited before the signal.\n except OSError as error:\n termination_error = str(error)\n try:\n stdout, stderr = process.communicate(timeout=30)\n except subprocess.TimeoutExpired as drain_timeout:\n drain_timed_out = True\n # Retrying communicate retains its cumulative captured bytes.\n # Preserve those logs even when kernel/pipe state prevents a\n # verified process exit and complete drain after SIGKILL.\n stdout = drain_timeout.output or initial_timeout.output or b\"\"\n stderr = drain_timeout.stderr or initial_timeout.stderr or b\"\"\n for stream in (process.stdout, process.stderr):\n if stream is not None:\n stream.close()\n process.poll()\n result = subprocess.CompletedProcess(command, process.returncode, stdout, stderr)\n out_path, err_path = logs / f\"{label}.stdout.log\", logs / f\"{label}.stderr.log\"\n out_path.write_bytes(result.stdout)\n err_path.write_bytes(result.stderr)\n report[\"commands\"].append({\n \"command\": command, \"returncode\": result.returncode, \"timed_out\": timed_out,\n \"drain_timed_out\": drain_timed_out, \"termination_error\": termination_error,\n \"process_exit_and_pipe_drain_verified\": not drain_timed_out,\n \"wall_seconds\": round(time.monotonic() - started, 3),\n \"stdout\": str(out_path.relative_to(work)), \"stderr\": str(err_path.relative_to(work)),\n \"stdout_sha256\": hashlib.sha256(result.stdout).hexdigest(),\n \"stderr_sha256\": hashlib.sha256(result.stderr).hexdigest(),\n })\n if drain_timed_out:\n raise RuntimeError(\n f\"{label} exceeded its deadline and the 30-second termination/drain deadline; \"\n f\"child cleanup is unverified and partial logs are retained in {logs}\"\n )\n if timed_out or result.returncode:\n print(result.stderr.decode(errors=\"replace\"), flush=True)\n raise RuntimeError(\n f\"{label} failed with exit {result.returncode}, timed_out={timed_out}; see {work}\"\n )\n return result\n\n try:\n sources = watch_component_sources(root, lock, checkout, args.watch_scan)\n for name, text in sources.pop(\"outputs\").items():\n destination = work / name\n destination.parent.mkdir(parents=True, exist_ok=True)\n destination.write_bytes(text.encode())\n report.update(sources)\n report[\"source_verified_before\"] = True\n direct_names = DIRECT + ((\"anyhow\", \"serde\", \"glob\", \"dotenvy\", \"blake3\", \"dunce\")\n if args.watch_scan else ())\n direct, allowed = dependency_closure(lock, direct_names)\n selected = {identity(package) for package in allowed}\n tables = [\"[[package]]\" + block for block in lock_bytes.decode().split(\"[[package]]\")[1:]\n if identity(tomllib.loads(\"[[package]]\" + block)[\"package\"][0]) in selected]\n dependencies = [f'{p[\"name\"]} = \"={p[\"version\"]}\"' for p in direct if p[\"name\"] != \"serde\"]\n if args.watch_scan:\n serde = next(package for package in direct if package[\"name\"] == \"serde\")\n dependencies.append(f'serde = {{ version = \"={serde[\"version\"]}\", features = [\"derive\"] }}')\n env[\"CASS_SOURCE_INGEST_CONTRACT\"] = \"supplemental-gh538-source-boundary-fixture\"\n env[\"CASS_SOURCE_INGEST_REUSE\"] = \"true\"\n for name in (\"CASS_EXCLUDE_PATHS\", \"CASS_EXCLUDE_WORKSPACES\", \"CASS_TEST_ACTIVE_SESSION_SOURCE_PATHS\"):\n env.pop(name, None)\n report[\"environment\"].update({name: env.get(name) for name in (\n \"CASS_SOURCE_INGEST_CONTRACT\", \"CASS_SOURCE_INGEST_REUSE\", \"CASS_EXCLUDE_PATHS\",\n \"CASS_EXCLUDE_WORKSPACES\", \"CASS_TEST_ACTIVE_SESSION_SOURCE_PATHS\")})\n manifest = \"\\n\".join([\n \"[package]\", f'name = \"{PACKAGE}\"', f'version = \"{VERSION}\"', 'edition = \"2024\"',\n \"[features]\", 'default = [\"connectors\"]', 'connectors = []',\n \"[dependencies]\", *dependencies,\n \"[profile.dev]\", \"debug = 0\", \"incremental = false\", \"[profile.test]\",\n \"debug = 0\", \"incremental = false\", \"\",\n ])\n harness_lock = \"\\n\".join([\n f'version = {lock[\"version\"]}', \"\", \"[[package]]\", f'name = \"{PACKAGE}\"',\n f'version = \"{VERSION}\"', \"dependencies = \" + json.dumps(list(direct_names)), \"\", *tables,\n ])\n (work / \"Cargo.toml\").write_bytes(manifest.encode())\n (work / \"Cargo.lock\").write_bytes(harness_lock.encode())\n report[\"cargo\"] = run([cargo, \"--version\", \"--verbose\"], \"cargo-version\").stdout.decode().strip()\n report[\"rustc\"] = run([rustc, \"--version\", \"--verbose\"], \"rustc-version\").stdout.decode().strip()\n offline = [\"--offline\"] if args.offline else []\n run([cargo, \"metadata\", \"--format-version\", \"1\", *offline], \"metadata\")\n normalized = (work / \"Cargo.lock\").read_bytes()\n retained = validate_normalized_lock(tomllib.loads(normalized.decode()), allowed, direct)\n report[\"dependencies\"] = [\n {key: package[key] for key in (\"name\", \"version\", \"source\", \"checksum\")}\n for package in sorted(retained, key=identity)\n ]\n report[\"harness_lock_sha256\"] = hashlib.sha256(normalized).hexdigest()\n report[\"output_sha256\"] = {\n str(path.relative_to(work)): hashlib.sha256(path.read_bytes()).hexdigest()\n for path in sorted(work.rglob(\"*.rs\"))\n }\n report[\"manifest_sha256\"] = hashlib.sha256((work / \"Cargo.toml\").read_bytes()).hexdigest()\n build = run([cargo, \"test\", \"--locked\", \"--lib\", \"--no-run\", \"--message-format=json\", \"-j1\", *offline],\n \"build\")\n artifacts = []\n for line in build.stdout.decode().splitlines():\n message = json.loads(line)\n if (message.get(\"reason\") == \"compiler-artifact\" and message.get(\"profile\", {}).get(\"test\")\n and message.get(\"executable\")):\n artifacts.append(message)\n if len(artifacts) != 1:\n raise RuntimeError(f\"expected one test executable, found {len(artifacts)}\")\n binary = Path(artifacts[0][\"executable\"])\n report[\"executable\"] = str(binary)\n report[\"executable_sha256\"] = hashlib.sha256(binary.read_bytes()).hexdigest()\n listing = run([str(binary), \"--list\"], \"inventory\").stdout.decode()\n names = [line.removesuffix(\": test\") for line in listing.splitlines() if line.endswith(\": test\")]\n required = set(report[\"required_watch_tests\"])\n matched = [name for name in names if name.rsplit(\"::\", 1)[-1] in required]\n if len(matched) != len(required) or {name.rsplit(\"::\", 1)[-1] for name in matched} != required:\n raise RuntimeError(\"compiled inventory omitted or duplicated a required watch test\")\n report[\"compiled_tests\"] = names\n tests = run([str(binary), \"--nocapture\", \"--test-threads=1\"], \"tests\")\n text = tests.stdout.decode(errors=\"replace\") + tests.stderr.decode(errors=\"replace\")\n for name in matched:\n if f\"test {name} ... ok\" not in text:\n raise RuntimeError(f\"required watch test did not execute successfully: {name}\")\n summary = re.search(r\"test result: ok\\. (\\d+) passed; (\\d+) failed; (\\d+) ignored; (\\d+) measured; (\\d+) filtered out\", text)\n if summary is None:\n raise RuntimeError(\"missing complete libtest result\")\n report[\"counts\"] = dict(zip((\"passed\", \"failed\", \"ignored\", \"measured\", \"filtered_out\"),\n map(int, summary.groups())))\n if (report[\"counts\"][\"passed\"] + report[\"counts\"][\"ignored\"] != len(names)\n or report[\"counts\"][\"failed\"] != 0\n or report[\"counts\"][\"measured\"] != 0\n or report[\"counts\"][\"filtered_out\"] != 0):\n raise RuntimeError(\"libtest counts do not match the compiled inventory\")\n if args.bench:\n run([str(binary), \"gh512_benchmark_4159\", \"--ignored\", \"--nocapture\"], \"benchmark\")\n if (work / \"Cargo.lock\").read_bytes() != normalized:\n raise RuntimeError(\"component dependency pins changed during qualification\")\n for name, digest in report[\"output_sha256\"].items():\n if hashlib.sha256((work / name).read_bytes()).hexdigest() != digest:\n raise RuntimeError(f\"generated source changed during qualification: {name}\")\n for entry in report[\"inputs\"].values():\n if hashlib.sha256(Path(entry[\"path\"]).read_bytes()).hexdigest() != entry[\"sha256\"]:\n raise RuntimeError(f\"input changed during qualification: {entry['path']}\")\n if (root / \"Cargo.lock\").read_bytes() != lock_bytes:\n raise RuntimeError(\"repository dependency pins changed during qualification\")\n if hashlib.sha256(binary.read_bytes()).hexdigest() != report[\"executable_sha256\"]:\n raise RuntimeError(\"executed test binary changed during qualification\")\n report[\"source_verified_after\"] = True\n report[\"status\"] = \"supplemental-passed\"\n except Exception as error:\n report[\"error\"] = f\"{type(error).__name__}: {error}\"\n raise\n finally:\n report[\"finished_utc\"] = datetime.datetime.now(datetime.timezone.utc).isoformat()\n (work / \"report.json\").write_text(json.dumps(report, indent=2) + \"\\n\")\n (output_root / \"report.json\").write_text(json.dumps(report, indent=2) + \"\\n\")\n print(f\"{report['status']}: {work / 'report.json'}\", flush=True)\n\n\ndef main() -> None:\n parser = argparse.ArgumentParser(description=__doc__)\n parser.add_argument(\"--bench\", action=\"store_true\", help=\"also run the 4159-source benchmark\")\n parser.add_argument(\"--watch-components\", action=\"store_true\",\n help=\"also qualify exact watch stability and receipt serialization sources\")\n parser.add_argument(\"--watch-scan\", action=\"store_true\",\n help=\"include exact scan method and synthetic source-boundary tests (implies --watch-components)\")\n parser.add_argument(\"--fad-checkout\", type=Path, help=\"checkout of the FAD revision pinned by Cargo.lock\")\n parser.add_argument(\"--output-dir\", type=Path, help=\"retain watch component sources, logs, and reports here\")\n parser.add_argument(\"--target-dir\", type=Path, help=\"separate cached watch component build directory\")\n parser.add_argument(\"--toolchain-bin\", type=Path, help=\"directory containing pinned cargo and rustc\")\n parser.add_argument(\"--offline\", action=\"store_true\", help=\"use cached watch component dependencies only\")\n parser.add_argument(\"--build-timeout\", type=int, default=300)\n args = parser.parse_args()\n root = Path(__file__).resolve().parents[1]\n if args.watch_components or args.watch_scan:\n run_watch_components(args, root)\n return\n source = root / \"src/connectors/source_dependencies/observation.rs\"\n source_bytes = source.read_bytes()\n lock_path = root / \"Cargo.lock\"\n lock_bytes = lock_path.read_bytes()\n lock_text = lock_bytes.decode()\n lock = tomllib.loads(lock_text)\n direct, allowed = dependency_closure(lock)\n selected = {identity(package) for package in allowed}\n tables = []\n for block in lock_text.split(\"[[package]]\")[1:]:\n package = tomllib.loads(\"[[package]]\" + block)[\"package\"][0]\n if identity(package) in selected:\n tables.append(\"[[package]]\" + block)\n manifest = \"\\n\".join([\n \"[package]\", f'name = \"{PACKAGE}\"', f'version = \"{VERSION}\"',\n 'edition = \"2024\"', \"[lib]\", 'path = \"observation.rs\"', \"[dependencies]\",\n *(f'{package[\"name\"]} = \"={package[\"version\"]}\"' for package in direct), \"\",\n ])\n harness_lock = \"\\n\".join([\n f'version = {lock[\"version\"]}', \"\", \"[[package]]\",\n f'name = \"{PACKAGE}\"', f'version = \"{VERSION}\"',\n 'dependencies = [\"serde_json\", \"tempfile\"]', \"\", *tables,\n ])\n receipt = {\n \"source_sha256\": hashlib.sha256(source_bytes).hexdigest(),\n \"repository_lock_sha256\": hashlib.sha256(lock_bytes).hexdigest(),\n \"scope\": \"exact production filesystem matcher only; full integration is separate\",\n }\n with tempfile.TemporaryDirectory(prefix=\"cass-source-ledger-\") as directory:\n work = Path(directory)\n (work / \"observation.rs\").write_bytes(source_bytes)\n # Preserve TOML bytes without Windows text-mode newline translation:\n # checked-out dependency blocks can already contain valid CRLF endings.\n (work / \"Cargo.toml\").write_bytes(manifest.encode(\"utf-8\"))\n (work / \"Cargo.lock\").write_bytes(harness_lock.encode(\"utf-8\"))\n env = os.environ.copy()\n toolchain = tomllib.loads((root / \"rust-toolchain.toml\").read_text())[\"toolchain\"][\"channel\"]\n env[\"RUSTUP_TOOLCHAIN\"] = toolchain\n for variable in (\"RUSTFLAGS\", \"CARGO_ENCODED_RUSTFLAGS\"):\n env.pop(variable, None)\n try:\n # Metadata resolves the smaller feature graph without compiling code.\n # The copied CASS graph can contain optional edges not used here; let\n # Cargo normalize only this temporary lock, then audit it before test.\n subprocess.run(\n [\"cargo\", \"metadata\", \"--format-version\", \"1\", \"--manifest-path\", str(work / \"Cargo.toml\")],\n cwd=work, env=env, stdout=subprocess.DEVNULL, check=True,\n )\n normalized = (work / \"Cargo.lock\").read_bytes()\n retained = validate_normalized_lock(tomllib.loads(normalized.decode()), allowed, direct)\n receipt[\"harness_lock_sha256\"] = hashlib.sha256(normalized).hexdigest()\n receipt[\"dependencies\"] = [\n {key: package[key] for key in (\"name\", \"version\", \"source\", \"checksum\")}\n for package in sorted(retained, key=identity)\n ]\n receipt[\"pruned_packages\"] = len(allowed) - len(retained)\n print(\"GH512_MATCHER_SOURCE=\" + json.dumps(receipt, sort_keys=True), flush=True)\n command = [\"cargo\", \"test\", \"--release\", \"--locked\", \"--manifest-path\", str(work / \"Cargo.toml\")]\n subprocess.run(command + [\"--\", \"--nocapture\"], cwd=work, env=env, check=True)\n if args.bench:\n subprocess.run(command + [\"gh512_benchmark_4159\", \"--\", \"--ignored\", \"--nocapture\"],\n cwd=work, env=env, check=True)\n if (work / \"Cargo.lock\").read_bytes() != normalized:\n raise RuntimeError(\"matcher dependency pins changed during qualification\")\n if (work / \"observation.rs\").read_bytes() != source_bytes:\n raise RuntimeError(\"tested matcher changed during qualification\")\n finally:\n if source.read_bytes() != source_bytes or lock_path.read_bytes() != lock_bytes:\n raise RuntimeError(\"repository source or dependency lock changed during qualification\")\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":38519,"content_sha256":"533b3de32e518fd842f8bdaefbdc0c6ece218db4b269ee5d3972227203b7f268"},{"filename":"scripts/test-all.sh","content":"#!/usr/bin/env bash\n# scripts/test-all.sh\n# Comprehensive test runner with detailed logging for cass\n#\n# Usage:\n# ./scripts/test-all.sh # Run all standard tests\n# ./scripts/test-all.sh --all # Include SSH and slow tests\n# ./scripts/test-all.sh --help # Show all options\n\nset -euo pipefail\n\n# =============================================================================\n# Configuration\n# =============================================================================\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\nLOG_DIR=\"${PROJECT_ROOT}/test-logs\"\nTIMESTAMP=$(date +\"%Y%m%d_%H%M%S\")\nLOG_FILE=\"${LOG_DIR}/test_${TIMESTAMP}.log\"\nJSON_LOG_FILE=\"${LOG_DIR}/test_${TIMESTAMP}.jsonl\"\n\n# Colors (only when stdout is a terminal)\nif [[ -t 1 ]]; then\n RED='\\033[0;31m'\n GREEN='\\033[0;32m'\n YELLOW='\\033[1;33m'\n BLUE='\\033[0;34m'\n CYAN='\\033[0;36m'\n BOLD='\\033[1m'\n NC='\\033[0m'\nelse\n RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' NC=''\nfi\n\n# Options with defaults\nVERBOSE=${VERBOSE:-0}\nPARALLEL=${PARALLEL:-1}\nINCLUDE_SSH=${INCLUDE_SSH:-0}\nINCLUDE_SLOW=${INCLUDE_SLOW:-0}\nUSE_NEXTEST=${USE_NEXTEST:-1}\nFAIL_FAST=${FAIL_FAST:-0}\nQUICK_MODE=${QUICK_MODE:-0}\nRCH_BIN=${RCH_BIN:-rch}\nRCH_TARGET_DIR=${RCH_TARGET_DIR:-${TMPDIR:-/tmp}/rch_target_cass_test_all}\n\n# Results tracking\ndeclare -A TIMINGS\ndeclare -A RESULTS\n\n# =============================================================================\n# Logging Functions\n# =============================================================================\n\nlog() {\n local level=$1\n shift\n local msg=\"$*\"\n local timestamp\n timestamp=$(date +\"%Y-%m-%d %H:%M:%S.%3N\")\n\n local color\n case $level in\n INFO) color=$GREEN ;;\n WARN) color=$YELLOW ;;\n ERROR) color=$RED ;;\n DEBUG) color=$CYAN ;;\n PHASE) color=$BOLD$BLUE ;;\n *) color=$NC ;;\n esac\n\n # Console output (colored)\n echo -e \"${color}[${timestamp}] [${level}]${NC} ${msg}\"\n\n # Plain text log file\n echo \"[${timestamp}] [${level}] ${msg}\" >> \"$LOG_FILE\"\n\n # JSON log file for CI parsing\n local json_msg\n json_msg=$(echo \"$msg\" | sed 's/\"/\\\\\"/g' | tr '\\n' ' ')\n echo \"{\\\"ts\\\":\\\"${timestamp}\\\",\\\"level\\\":\\\"${level}\\\",\\\"msg\\\":\\\"${json_msg}\\\"}\" >> \"$JSON_LOG_FILE\"\n}\n\nlog_section() {\n local title=$1\n echo \"\"\n echo -e \"${BOLD}${BLUE}==================================================================${NC}\"\n echo -e \"${BOLD}${BLUE} $title${NC}\"\n echo -e \"${BOLD}${BLUE}==================================================================${NC}\"\n log PHASE \"$title\"\n}\n\nlog_subsection() {\n local title=$1\n echo \"\"\n echo -e \"${CYAN}--- $title ---${NC}\"\n log INFO \"--- $title ---\"\n}\n\n# =============================================================================\n# Timing Functions\n# =============================================================================\n\ntime_start() {\n local name=$1\n TIMINGS[\"${name}_start\"]=$(date +%s.%N)\n}\n\ntime_end() {\n local name=$1\n local start=${TIMINGS[\"${name}_start\"]}\n local end\n end=$(date +%s.%N)\n local duration\n duration=$(echo \"$end - $start\" | bc 2>/dev/null || echo \"0\")\n TIMINGS[\"${name}_duration\"]=$duration\n log INFO \"Completed in ${duration}s\"\n}\n\n# =============================================================================\n# Test Runner Functions\n# =============================================================================\n\nensure_rch() {\n if ! command -v \"$RCH_BIN\" &> /dev/null; then\n log ERROR \"rch binary not found; test-all cargo tests must be offloaded\"\n return 1\n fi\n}\n\nrun_cargo() {\n \"$RCH_BIN\" exec -- env CARGO_TARGET_DIR=\"$RCH_TARGET_DIR\" cargo \"$@\"\n}\n\ncheck_nextest() {\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest --version > /dev/null 2>&1; then\n return 0\n else\n log WARN \"cargo-nextest unavailable through rch, falling back to run_cargo test\"\n USE_NEXTEST=0\n fi\n fi\n return 0\n}\n\n# =============================================================================\n# Test Phases\n# =============================================================================\n\nrun_unit_tests() {\n log_section \"PHASE 1: Unit Tests\"\n time_start \"unit_tests\"\n\n local exit_code=0\n\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest run --profile ci --workspace -E 'kind(lib)' --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"Unit tests passed\"\n else\n log ERROR \"Unit tests failed\"\n exit_code=1\n fi\n else\n if run_cargo test --lib --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"Unit tests passed\"\n else\n log ERROR \"Unit tests failed\"\n exit_code=1\n fi\n fi\n\n time_end \"unit_tests\"\n RESULTS[\"unit_tests\"]=$exit_code\n return $exit_code\n}\n\nrun_connector_tests() {\n if [[ $QUICK_MODE -eq 1 ]]; then\n log_section \"PHASE 2: Connector Tests (SKIPPED - quick mode)\"\n RESULTS[\"connector_tests\"]=\"skipped\"\n return 0\n fi\n\n log_section \"PHASE 2: Connector Tests\"\n time_start \"connector_tests\"\n\n local connectors=(\"claude\" \"codex\" \"gemini\" \"cline\" \"aider\" \"amp\" \"opencode\")\n local failed=0\n\n for conn in \"${connectors[@]}\"; do\n log_subsection \"Testing connector: $conn\"\n local filter=\"binary(connector_${conn})\"\n\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest run --profile ci -E \"$filter\" --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \" $conn connector passed\"\n else\n log ERROR \" $conn connector failed\"\n ((failed += 1))\n fi\n else\n if run_cargo test --test \"connector_${conn}\" --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \" $conn connector passed\"\n else\n log ERROR \" $conn connector failed\"\n ((failed += 1))\n fi\n fi\n\n if [[ $FAIL_FAST -eq 1 ]] && [[ $failed -gt 0 ]]; then\n break\n fi\n done\n\n time_end \"connector_tests\"\n\n if [[ $failed -gt 0 ]]; then\n log ERROR \"$failed connector test(s) failed\"\n RESULTS[\"connector_tests\"]=1\n return 1\n fi\n\n log INFO \"All connector tests passed\"\n RESULTS[\"connector_tests\"]=0\n return 0\n}\n\nrun_cli_tests() {\n log_section \"PHASE 3: CLI E2E Tests\"\n time_start \"cli_tests\"\n\n local test_files=(\"e2e_cli_flows\" \"e2e_sources\" \"e2e_filters\" \"cli_robot\")\n local failed=0\n\n for test in \"${test_files[@]}\"; do\n log_subsection \"Running $test\"\n\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest run --profile e2e -E \"binary($test)\" --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \" $test passed\"\n else\n log ERROR \" $test failed\"\n ((failed += 1))\n fi\n else\n if run_cargo test --test \"$test\" --color=always -- --test-threads=1 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \" $test passed\"\n else\n log ERROR \" $test failed\"\n ((failed += 1))\n fi\n fi\n\n if [[ $FAIL_FAST -eq 1 ]] && [[ $failed -gt 0 ]]; then\n break\n fi\n done\n\n time_end \"cli_tests\"\n\n if [[ $failed -gt 0 ]]; then\n log ERROR \"$failed CLI test(s) failed\"\n RESULTS[\"cli_tests\"]=1\n return 1\n fi\n\n log INFO \"All CLI tests passed\"\n RESULTS[\"cli_tests\"]=0\n return 0\n}\n\nrun_ui_tests() {\n log_section \"PHASE 4: UI Component Tests\"\n time_start \"ui_tests\"\n\n local exit_code=0\n\n if [[ $USE_NEXTEST -eq 1 ]]; then\n # UI tests are run with the ci profile which has proper thread overrides\n if run_cargo nextest run --profile ci -E 'test(ui_)' --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"UI tests passed\"\n else\n log ERROR \"UI tests failed\"\n exit_code=1\n fi\n else\n if run_cargo test --tests -- ui_ --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"UI tests passed\"\n else\n log ERROR \"UI tests failed\"\n exit_code=1\n fi\n fi\n\n time_end \"ui_tests\"\n RESULTS[\"ui_tests\"]=$exit_code\n return $exit_code\n}\n\nrun_ssh_tests() {\n if [[ $INCLUDE_SSH -eq 0 ]]; then\n log_section \"PHASE 5: SSH Tests (SKIPPED - use --include-ssh to run)\"\n RESULTS[\"ssh_tests\"]=\"skipped\"\n return 0\n fi\n\n log_section \"PHASE 5: SSH Integration Tests\"\n time_start \"ssh_tests\"\n\n # Check Docker is available\n if ! command -v docker &> /dev/null; then\n log WARN \"Docker not available, skipping SSH tests\"\n RESULTS[\"ssh_tests\"]=\"skipped\"\n return 0\n fi\n\n local exit_code=0\n\n # Run SSH tests (marked with #[ignore] so need --ignored flag)\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest run --profile e2e -E 'test(ssh)' --run-ignored=all --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"SSH tests passed\"\n else\n log ERROR \"SSH tests failed\"\n exit_code=1\n fi\n else\n if run_cargo test ssh -- --ignored --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"SSH tests passed\"\n else\n log ERROR \"SSH tests failed\"\n exit_code=1\n fi\n fi\n\n time_end \"ssh_tests\"\n RESULTS[\"ssh_tests\"]=$exit_code\n return $exit_code\n}\n\nrun_slow_tests() {\n if [[ $INCLUDE_SLOW -eq 0 ]]; then\n log_section \"PHASE 6: Slow Tests (SKIPPED - use --include-slow to run)\"\n RESULTS[\"slow_tests\"]=\"skipped\"\n return 0\n fi\n\n log_section \"PHASE 6: Slow/Performance Tests\"\n time_start \"slow_tests\"\n\n local test_files=(\"watch_e2e\" \"regression_behavioral\")\n local failed=0\n\n for test in \"${test_files[@]}\"; do\n log_subsection \"Running $test\"\n\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest run --profile e2e -E \"binary($test)\" --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \" $test passed\"\n else\n log ERROR \" $test failed\"\n ((failed += 1))\n fi\n else\n if run_cargo test --test \"$test\" --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \" $test passed\"\n else\n log ERROR \" $test failed\"\n ((failed += 1))\n fi\n fi\n done\n\n time_end \"slow_tests\"\n\n if [[ $failed -gt 0 ]]; then\n log ERROR \"$failed slow test(s) failed\"\n RESULTS[\"slow_tests\"]=1\n return 1\n fi\n\n log INFO \"All slow tests passed\"\n RESULTS[\"slow_tests\"]=0\n return 0\n}\n\n# =============================================================================\n# Summary Report\n# =============================================================================\n\nprint_summary() {\n log_section \"TEST SUMMARY\"\n\n echo \"\"\n printf \"${BOLD}%-25s %12s %10s${NC}\\n\" \"Phase\" \"Duration\" \"Status\"\n printf \"%-25s %12s %10s\\n\" \"-------------------------\" \"------------\" \"----------\"\n\n local phases=(\"unit_tests\" \"connector_tests\" \"cli_tests\" \"ui_tests\" \"ssh_tests\" \"slow_tests\")\n local total_failed=0\n\n for phase in \"${phases[@]}\"; do\n local duration=${TIMINGS[\"${phase}_duration\"]:-\"-\"}\n local status=${RESULTS[$phase]:-\"?\"}\n\n local status_text status_color\n if [[ $status == \"0\" ]]; then\n status_text=\"PASS\"\n status_color=$GREEN\n elif [[ $status == \"skipped\" ]]; then\n status_text=\"SKIP\"\n status_color=$YELLOW\n duration=\"-\"\n else\n status_text=\"FAIL\"\n status_color=$RED\n ((total_failed += 1))\n fi\n\n local duration_display=\"${duration}s\"\n [[ $duration == \"-\" ]] && duration_display=\"-\"\n printf \"%-25s %12s ${status_color}%10s${NC}\\n\" \"$phase\" \"$duration_display\" \"$status_text\"\n done\n\n echo \"\"\n echo -e \"${BOLD}Log files:${NC}\"\n echo \" Text: $LOG_FILE\"\n echo \" JSON: $JSON_LOG_FILE\"\n\n if [[ $USE_NEXTEST -eq 1 ]]; then\n local junit_path=\"${PROJECT_ROOT}/target/nextest/ci/junit.xml\"\n if [[ -f \"$junit_path\" ]]; then\n echo \" JUnit: $junit_path\"\n fi\n fi\n\n echo \"\"\n return $total_failed\n}\n\n# =============================================================================\n# Main\n# =============================================================================\n\nshow_help() {\n cat \u003c\u003c EOF\nUsage: $0 [options]\n\nComprehensive test runner for cass with detailed logging.\n\nOptions:\n -v, --verbose Verbose output\n -q, --quick Quick mode (skip connector and slow tests)\n --no-parallel Run tests sequentially\n --fail-fast Stop on first failure\n --include-ssh Include SSH integration tests (requires Docker)\n --include-slow Include slow/performance tests\n --all Include all optional tests\n --no-nextest Use run_cargo test instead of run_cargo nextest\n -h, --help Show this help\n\nEnvironment Variables:\n VERBOSE=1 Same as --verbose\n QUICK_MODE=1 Same as -q/--quick\n PARALLEL=0 Same as --no-parallel\n INCLUDE_SSH=1 Same as --include-ssh\n INCLUDE_SLOW=1 Same as --include-slow\n USE_NEXTEST=0 Same as --no-nextest\n RCH_BIN=rch Remote compilation helper binary\n RCH_TARGET_DIR=... Remote Cargo target dir (default: \\${TMPDIR:-/tmp}/rch_target_cass_test_all)\n\nExamples:\n $0 # Standard test run\n $0 --all # Full test suite including SSH and slow tests\n $0 --fail-fast # Stop on first failure\n $0 -q # Quick tests only\n\nEOF\n exit 0\n}\n\nmain() {\n mkdir -p \"$LOG_DIR\"\n\n # Initialize log files\n echo \"# cass test run - $TIMESTAMP\" > \"$LOG_FILE\"\n echo \"\" > \"$JSON_LOG_FILE\"\n\n log_section \"CASS TEST RUNNER\"\n log INFO \"Project root: $PROJECT_ROOT\"\n log INFO \"Log directory: $LOG_DIR\"\n log INFO \"Timestamp: $TIMESTAMP\"\n log INFO \"Options: QUICK_MODE=$QUICK_MODE PARALLEL=$PARALLEL INCLUDE_SSH=$INCLUDE_SSH INCLUDE_SLOW=$INCLUDE_SLOW\"\n\n cd \"$PROJECT_ROOT\"\n ensure_rch || exit 1\n log INFO \"RCH binary: $RCH_BIN\"\n log INFO \"RCH target dir: $RCH_TARGET_DIR\"\n\n # Check for nextest\n check_nextest\n log INFO \"Test runner: $([ \"$USE_NEXTEST\" -eq 1 ] && echo 'run_cargo nextest' || echo 'run_cargo test')\"\n\n # Run all phases, collecting results\n local failed=0\n\n run_unit_tests || ((failed += 1))\n [[ $FAIL_FAST -eq 1 ]] && [[ $failed -gt 0 ]] && { print_summary; exit 1; }\n\n run_connector_tests || ((failed += 1))\n [[ $FAIL_FAST -eq 1 ]] && [[ $failed -gt 0 ]] && { print_summary; exit 1; }\n\n run_cli_tests || ((failed += 1))\n [[ $FAIL_FAST -eq 1 ]] && [[ $failed -gt 0 ]] && { print_summary; exit 1; }\n\n run_ui_tests || ((failed += 1))\n [[ $FAIL_FAST -eq 1 ]] && [[ $failed -gt 0 ]] && { print_summary; exit 1; }\n\n run_ssh_tests || ((failed += 1))\n run_slow_tests || ((failed += 1))\n\n print_summary\n local summary_failed=$?\n\n if [[ $summary_failed -gt 0 ]]; then\n log ERROR \"TESTS FAILED ($summary_failed phase(s) failed)\"\n exit 1\n fi\n\n log INFO \"ALL TESTS PASSED\"\n exit 0\n}\n\n# Parse arguments\nwhile [[ $# -gt 0 ]]; do\n case $1 in\n -v|--verbose) VERBOSE=1; shift ;;\n -q|--quick) QUICK_MODE=1; shift ;;\n --no-parallel) PARALLEL=0; shift ;;\n --fail-fast) FAIL_FAST=1; shift ;;\n --include-ssh) INCLUDE_SSH=1; shift ;;\n --include-slow) INCLUDE_SLOW=1; shift ;;\n --all) INCLUDE_SSH=1; INCLUDE_SLOW=1; shift ;;\n --no-nextest) USE_NEXTEST=0; shift ;;\n -h|--help) show_help ;;\n *)\n echo \"Unknown option: $1\"\n echo \"Use --help for usage information\"\n exit 1\n ;;\n esac\ndone\n\nmain\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":16162,"content_sha256":"d72cce708c9414da4b31b0f5f2d39c4c8d463b405e7c86a7141802f7c0c36f09"},{"filename":"scripts/test-pages-e2e.sh","content":"#!/usr/bin/env bash\n# scripts/test-pages-e2e.sh\n# Pages E2E test runner with detailed JSONL logging\n#\n# Usage:\n# ./scripts/test-pages-e2e.sh # Run all pages E2E tests\n# ./scripts/test-pages-e2e.sh --verbose # With debug output\n# ./scripts/test-pages-e2e.sh --help # Show options\n\nset -euo pipefail\n\n# =============================================================================\n# Configuration\n# =============================================================================\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\nLOG_DIR=\"${PROJECT_ROOT}/test-logs\"\nTIMESTAMP=$(date +\"%Y%m%d_%H%M%S\")\nLOG_FILE=\"${LOG_DIR}/pages_e2e_${TIMESTAMP}.log\"\nJSON_LOG_FILE=\"${LOG_DIR}/pages_e2e_${TIMESTAMP}.jsonl\"\n\n# Colors (only when stdout is a terminal)\nif [[ -t 1 ]]; then\n RED='\\033[0;31m'\n GREEN='\\033[0;32m'\n YELLOW='\\033[1;33m'\n BLUE='\\033[0;34m'\n CYAN='\\033[0;36m'\n BOLD='\\033[1m'\n NC='\\033[0m'\nelse\n RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' NC=''\nfi\n\n# Options\nVERBOSE=${VERBOSE:-0}\nUSE_NEXTEST=${USE_NEXTEST:-1}\nFAIL_FAST=${FAIL_FAST:-0}\nINCLUDE_MASTER=${INCLUDE_MASTER:-0}\nRCH_BIN=${RCH_BIN:-rch}\nRCH_TARGET_DIR=${RCH_TARGET_DIR:-${TMPDIR:-/tmp}/rch_target_cass_pages_e2e}\n\n# =============================================================================\n# Logging Functions\n# =============================================================================\n\nlog() {\n local level=$1\n shift\n local msg=\"$*\"\n local timestamp\n timestamp=$(date +\"%Y-%m-%d %H:%M:%S.%3N\")\n\n local color\n case $level in\n INFO) color=$GREEN ;;\n WARN) color=$YELLOW ;;\n ERROR) color=$RED ;;\n DEBUG) color=$CYAN ;;\n PHASE) color=$BOLD$BLUE ;;\n *) color=$NC ;;\n esac\n\n # Console output (colored)\n echo -e \"${color}[${timestamp}] [${level}]${NC} ${msg}\"\n\n # Plain text log file\n echo \"[${timestamp}] [${level}] ${msg}\" >> \"$LOG_FILE\"\n\n # JSON log file for CI parsing\n local json_msg\n json_msg=$(echo \"$msg\" | sed 's/\"/\\\\\"/g' | tr '\\n' ' ')\n echo \"{\\\"ts\\\":\\\"${timestamp}\\\",\\\"level\\\":\\\"${level}\\\",\\\"msg\\\":\\\"${json_msg}\\\"}\" >> \"$JSON_LOG_FILE\"\n}\n\nlog_section() {\n local title=$1\n echo \"\"\n echo -e \"${BOLD}${BLUE}==================================================================${NC}\"\n echo -e \"${BOLD}${BLUE} $title${NC}\"\n echo -e \"${BOLD}${BLUE}==================================================================${NC}\"\n log PHASE \"$title\"\n}\n\n# =============================================================================\n# Test Runner Functions\n# =============================================================================\n\nensure_rch() {\n if ! command -v \"$RCH_BIN\" &> /dev/null; then\n log ERROR \"rch binary not found; pages E2E cargo tests must be offloaded\"\n return 1\n fi\n}\n\nrun_cargo() {\n \"$RCH_BIN\" exec -- env CARGO_TARGET_DIR=\"$RCH_TARGET_DIR\" cargo \"$@\"\n}\n\ncheck_nextest() {\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest --version > /dev/null 2>&1; then\n return 0\n else\n log WARN \"cargo-nextest unavailable through rch, falling back to run_cargo test\"\n USE_NEXTEST=0\n fi\n fi\n return 0\n}\n\nrun_pages_e2e_tests() {\n log_section \"Pages E2E Tests\"\n local start_time\n start_time=$(date +%s.%N)\n\n local exit_code=0\n local test_files=(\"e2e_pages\" \"pages_pipeline_e2e\" \"pages_bundle\")\n\n if [[ $INCLUDE_MASTER -eq 1 ]]; then\n test_files+=(\"pages_master_e2e\")\n fi\n\n for test_file in \"${test_files[@]}\"; do\n log INFO \"Running $test_file...\"\n\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest run --profile e2e -E \"binary($test_file)\" --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \" $test_file PASSED\"\n echo \"{\\\"test_file\\\":\\\"$test_file\\\",\\\"status\\\":\\\"PASS\\\"}\" >> \"$JSON_LOG_FILE\"\n else\n log ERROR \" $test_file FAILED\"\n echo \"{\\\"test_file\\\":\\\"$test_file\\\",\\\"status\\\":\\\"FAIL\\\"}\" >> \"$JSON_LOG_FILE\"\n exit_code=1\n [[ $FAIL_FAST -eq 1 ]] && break\n fi\n else\n if run_cargo test --test \"$test_file\" --color=always -- --nocapture 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \" $test_file PASSED\"\n echo \"{\\\"test_file\\\":\\\"$test_file\\\",\\\"status\\\":\\\"PASS\\\"}\" >> \"$JSON_LOG_FILE\"\n else\n log ERROR \" $test_file FAILED\"\n echo \"{\\\"test_file\\\":\\\"$test_file\\\",\\\"status\\\":\\\"FAIL\\\"}\" >> \"$JSON_LOG_FILE\"\n exit_code=1\n [[ $FAIL_FAST -eq 1 ]] && break\n fi\n fi\n done\n\n local end_time\n end_time=$(date +%s.%N)\n local duration\n duration=$(echo \"$end_time - $start_time\" | bc 2>/dev/null || echo \"0\")\n\n if [[ $exit_code -eq 0 ]]; then\n log INFO \"All pages E2E tests passed in ${duration}s\"\n else\n log ERROR \"Some pages E2E tests failed\"\n fi\n\n return $exit_code\n}\n\nrun_pages_accessibility_tests() {\n log_section \"Pages Accessibility Tests\"\n\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest run --profile ci -E \"binary(pages_accessibility_e2e)\" --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"Accessibility tests PASSED\"\n return 0\n else\n log ERROR \"Accessibility tests FAILED\"\n return 1\n fi\n else\n if run_cargo test --test pages_accessibility_e2e --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"Accessibility tests PASSED\"\n return 0\n else\n log ERROR \"Accessibility tests FAILED\"\n return 1\n fi\n fi\n}\n\nrun_pages_error_handling_tests() {\n log_section \"Pages Error Handling Tests\"\n\n if [[ $USE_NEXTEST -eq 1 ]]; then\n if run_cargo nextest run --profile ci -E \"binary(pages_error_handling_e2e)\" --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"Error handling tests PASSED\"\n return 0\n else\n log ERROR \"Error handling tests FAILED\"\n return 1\n fi\n else\n if run_cargo test --test pages_error_handling_e2e --color=always 2>&1 | tee -a \"$LOG_FILE\"; then\n log INFO \"Error handling tests PASSED\"\n return 0\n else\n log ERROR \"Error handling tests FAILED\"\n return 1\n fi\n fi\n}\n\n# =============================================================================\n# Main\n# =============================================================================\n\nshow_help() {\n cat \u003c\u003c EOF\nUsage: $0 [options]\n\nPages E2E test runner with detailed JSONL logging for CI.\n\nOptions:\n -v, --verbose Verbose output (set RUST_LOG=debug)\n --fail-fast Stop on first failure\n --include-master Include master E2E tests (slower)\n --no-nextest Use run_cargo test instead of run_cargo nextest\n -h, --help Show this help\n\nEnvironment Variables:\n VERBOSE=1 Same as --verbose\n FAIL_FAST=1 Same as --fail-fast\n INCLUDE_MASTER=1 Same as --include-master\n USE_NEXTEST=0 Same as --no-nextest\n RCH_BIN=rch Remote compilation helper binary\n RCH_TARGET_DIR=... Remote Cargo target dir (default: \\${TMPDIR:-/tmp}/rch_target_cass_pages_e2e)\n\nOutput:\n Text log: test-logs/pages_e2e_TIMESTAMP.log\n JSON log: test-logs/pages_e2e_TIMESTAMP.jsonl\n\nExamples:\n $0 # Run standard pages E2E tests\n $0 --include-master # Include comprehensive master tests\n $0 --verbose # With debug logging\n\nEOF\n exit 0\n}\n\nmain() {\n mkdir -p \"$LOG_DIR\"\n\n # Initialize log files\n echo \"# Pages E2E test run - $TIMESTAMP\" > \"$LOG_FILE\"\n echo \"\" > \"$JSON_LOG_FILE\"\n\n # Write test run metadata\n echo \"{\\\"event\\\":\\\"test_run_start\\\",\\\"timestamp\\\":\\\"$TIMESTAMP\\\",\\\"project\\\":\\\"cass\\\"}\" >> \"$JSON_LOG_FILE\"\n\n log_section \"PAGES E2E TEST RUNNER\"\n log INFO \"Project root: $PROJECT_ROOT\"\n log INFO \"Log directory: $LOG_DIR\"\n log INFO \"Timestamp: $TIMESTAMP\"\n\n cd \"$PROJECT_ROOT\"\n ensure_rch || exit 1\n log INFO \"RCH binary: $RCH_BIN\"\n log INFO \"RCH target dir: $RCH_TARGET_DIR\"\n\n # Check for nextest\n check_nextest\n log INFO \"Test runner: $([ \"$USE_NEXTEST\" -eq 1 ] && echo 'run_cargo nextest' || echo 'run_cargo test')\"\n\n # Set verbose logging if requested\n if [[ $VERBOSE -eq 1 ]]; then\n export RUST_LOG=debug\n log INFO \"Verbose logging enabled\"\n fi\n\n # Track total results\n local failed=0\n\n # Run test phases\n run_pages_e2e_tests || ((failed += 1))\n [[ $FAIL_FAST -eq 1 ]] && [[ $failed -gt 0 ]] && exit 1\n\n run_pages_accessibility_tests || ((failed += 1))\n [[ $FAIL_FAST -eq 1 ]] && [[ $failed -gt 0 ]] && exit 1\n\n run_pages_error_handling_tests || ((failed += 1))\n\n # Summary\n log_section \"SUMMARY\"\n\n echo \"\"\n echo -e \"${BOLD}Log files:${NC}\"\n echo \" Text: $LOG_FILE\"\n echo \" JSON: $JSON_LOG_FILE\"\n echo \"\"\n\n # Write final status\n local final_status=\"PASS\"\n [[ $failed -gt 0 ]] && final_status=\"FAIL\"\n echo \"{\\\"event\\\":\\\"test_run_end\\\",\\\"status\\\":\\\"$final_status\\\",\\\"failed_phases\\\":$failed}\" >> \"$JSON_LOG_FILE\"\n\n if [[ $failed -gt 0 ]]; then\n log ERROR \"TESTS FAILED ($failed phase(s) failed)\"\n exit 1\n fi\n\n log INFO \"ALL PAGES E2E TESTS PASSED\"\n exit 0\n}\n\n# Parse arguments\nwhile [[ $# -gt 0 ]]; do\n case $1 in\n -v|--verbose) VERBOSE=1; shift ;;\n --fail-fast) FAIL_FAST=1; shift ;;\n --include-master) INCLUDE_MASTER=1; shift ;;\n --no-nextest) USE_NEXTEST=0; shift ;;\n -h|--help) show_help ;;\n *)\n echo \"Unknown option: $1\"\n echo \"Use --help for usage information\"\n exit 1\n ;;\n esac\ndone\n\nmain\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":9930,"content_sha256":"111ca6a44abf70dae2d901b74b6f66ce41add91207d3fa51a7fa12cd871ac020"},{"filename":"scripts/test-quick.sh","content":"#!/usr/bin/env bash\n# scripts/test-quick.sh\n# Fast feedback loop for development - runs only essential tests\n#\n# Usage:\n# ./scripts/test-quick.sh # Run quick tests\n# ./scripts/test-quick.sh --lib # Only library unit tests\n# ./scripts/test-quick.sh --cli # Only CLI tests\n\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\nRCH_BIN=\"${RCH_BIN:-rch}\"\nRCH_TARGET_DIR=\"${RCH_TARGET_DIR:-/tmp/rch_target_cass_test_quick}\"\n\n# Colors\nif [[ -t 1 ]]; then\n GREEN='\\033[0;32m'\n RED='\\033[0;31m'\n CYAN='\\033[0;36m'\n BOLD='\\033[1m'\n NC='\\033[0m'\nelse\n GREEN='' RED='' CYAN='' BOLD='' NC=''\nfi\n\ncd \"$PROJECT_ROOT\"\n\nrun_cargo_test() {\n if ! command -v \"$RCH_BIN\" >/dev/null 2>&1; then\n echo \"ERROR: rch binary not found; quick tests must be offloaded\" >&2\n return 127\n fi\n\n \"$RCH_BIN\" exec -- env CARGO_TARGET_DIR=\"$RCH_TARGET_DIR\" cargo test \"$@\"\n}\n\nrun_lib_tests() {\n echo -e \"${CYAN}Running library unit tests...${NC}\"\n run_cargo_test --lib --color=always\n}\n\nrun_cli_tests() {\n echo -e \"${CYAN}Running CLI tests...${NC}\"\n run_cargo_test --test e2e_cli_flows --color=always\n}\n\nrun_connector_tests() {\n echo -e \"${CYAN}Running Claude connector tests...${NC}\"\n run_cargo_test --test connector_claude --color=always\n}\n\nshow_help() {\n cat \u003c\u003c EOF\nUsage: $0 [options]\n\nFast feedback loop for cass development.\n\nOptions:\n --lib Only run library unit tests\n --cli Only run CLI e2e tests\n --all Run lib, cli, and connector tests (default)\n -h, --help Show this help\n\nEOF\n exit 0\n}\n\n# Parse arguments\nRUN_LIB=0\nRUN_CLI=0\nRUN_CONNECTOR=0\nRUN_ALL=1\n\nwhile [[ $# -gt 0 ]]; do\n case $1 in\n --lib) RUN_LIB=1; RUN_ALL=0; shift ;;\n --cli) RUN_CLI=1; RUN_ALL=0; shift ;;\n --connector) RUN_CONNECTOR=1; RUN_ALL=0; shift ;;\n -h|--help) show_help ;;\n *)\n echo \"Unknown option: $1\"\n exit 1\n ;;\n esac\ndone\n\necho -e \"${BOLD}Quick Test Runner${NC}\"\necho \"Using: rch-backed cargo test\"\necho \"Target dir: $RCH_TARGET_DIR\"\necho \"\"\n\nSTART_TIME=$(date +%s)\nFAILED=0\n\nif [[ $RUN_ALL -eq 1 ]] || [[ $RUN_LIB -eq 1 ]]; then\n run_lib_tests || FAILED=1\nfi\n\nif [[ $FAILED -eq 0 ]]; then\n if [[ $RUN_ALL -eq 1 ]] || [[ $RUN_CLI -eq 1 ]]; then\n run_cli_tests || FAILED=1\n fi\nfi\n\nif [[ $FAILED -eq 0 ]]; then\n if [[ $RUN_ALL -eq 1 ]] || [[ $RUN_CONNECTOR -eq 1 ]]; then\n run_connector_tests || FAILED=1\n fi\nfi\n\nEND_TIME=$(date +%s)\nDURATION=$((END_TIME - START_TIME))\n\necho \"\"\nif [[ $FAILED -eq 0 ]]; then\n echo -e \"${GREEN}${BOLD}Quick tests passed${NC} (${DURATION}s)\"\n exit 0\nelse\n echo -e \"${RED}${BOLD}Quick tests failed${NC} (${DURATION}s)\"\n exit 1\nfi\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":2820,"content_sha256":"6b5804eff17daa3ac170afe47fb6c9d746274d9349667225c33373d6db4ebba3"},{"filename":"scripts/test-report.sh","content":"#!/usr/bin/env bash\n# test-report.sh - Run tests with JUnit XML and optional HTML report\n#\n# Usage:\n# ./scripts/test-report.sh # Run all tests with JUnit output\n# ./scripts/test-report.sh --quick # Run unit tests only (skip E2E)\n# ./scripts/test-report.sh --e2e # Run E2E tests only\n# ./scripts/test-report.sh --open # Open HTML report after generation\n#\n# Reports are generated in ${RCH_TARGET_DIR}/nextest/\u003cprofile>/\n\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\nRCH_BIN=\"${RCH_BIN:-rch}\"\nRCH_TARGET_DIR=\"${RCH_TARGET_DIR:-${TMPDIR:-/tmp}/rch_target_cass_test_report}\"\n\nQUICK_MODE=false\nE2E_ONLY=false\nOPEN_REPORT=false\nPROFILE=\"ci\"\n\n# Parse arguments\nfor arg in \"$@\"; do\n case $arg in\n --quick)\n QUICK_MODE=true\n ;;\n --e2e)\n E2E_ONLY=true\n PROFILE=\"e2e\"\n ;;\n --open)\n OPEN_REPORT=true\n ;;\n --help|-h)\n echo \"Usage: $0 [--quick] [--e2e] [--open]\"\n echo \"\"\n echo \"Options:\"\n echo \" --quick Run unit tests only (skip E2E tests)\"\n echo \" --e2e Run E2E tests only (uses e2e profile)\"\n echo \" --open Open HTML report in browser (requires junit2html)\"\n echo \"\"\n echo \"Profiles:\"\n echo \" ci - Full test suite with JUnit XML output\"\n echo \" e2e - E2E tests with sequential execution\"\n echo \"\"\n echo \"Environment:\"\n echo \" RCH_BIN rch executable (default: rch)\"\n echo \" RCH_TARGET_DIR cargo target dir for offloaded tests (default: \\${TMPDIR:-/tmp}/rch_target_cass_test_report)\"\n echo \"\"\n echo \"Reports generated in: \\$RCH_TARGET_DIR/nextest/\u003cprofile>/junit.xml\"\n echo \"\"\n exit 0\n ;;\n esac\ndone\n\ncd \"$PROJECT_ROOT\"\n\nensure_rch() {\n if ! command -v \"$RCH_BIN\" &> /dev/null; then\n echo \"Error: rch binary not found; test-report cargo work must be offloaded\"\n exit 1\n fi\n}\n\nrun_cargo() {\n \"$RCH_BIN\" exec -- env CARGO_TARGET_DIR=\"$RCH_TARGET_DIR\" cargo \"$@\"\n}\n\nensure_rch\n\n# Check if cargo-nextest is available through the offloaded cargo toolchain.\nif ! run_cargo nextest --version > /dev/null 2>&1; then\n echo \"Error: cargo-nextest is unavailable through rch\"\n echo \"\"\n echo \"Install it on the rch worker toolchain, or use a worker image that includes cargo-nextest.\"\n echo \"\"\n exit 1\nfi\n\necho \"===================================\"\necho \" cass Test Report Generator\"\necho \"===================================\"\necho \"\"\n\n# Build first\necho \"Building project...\"\nrun_cargo build --tests --quiet\n\n# Determine filter expression\nFILTER_ARGS=()\nif [ \"$E2E_ONLY\" = true ]; then\n FILTER_ARGS=(-E \"binary(install_scripts) | binary(e2e_index_tui) | binary(e2e_filters) | binary(e2e_multi_connector)\")\n echo \"Running: E2E tests only\"\nelif [ \"$QUICK_MODE\" = true ]; then\n FILTER_ARGS=(-E \"not (test(install_sh) | test(install_ps1) | binary(~e2e) | binary(install_scripts))\")\n echo \"Running: Unit tests (skipping E2E and install script tests)\"\nelse\n FILTER_ARGS=(-E \"not (test(install_sh) | test(install_ps1))\")\n echo \"Running: All tests (skipping install script tests)\"\nfi\n\necho \"Profile: $PROFILE\"\necho \"Target dir: $RCH_TARGET_DIR\"\necho \"\"\n\n# Run tests\necho \"Running tests...\"\necho \"-----------------------------------\"\n\nrun_cargo nextest run --profile \"$PROFILE\" \"${FILTER_ARGS[@]}\" --no-fail-fast 2>&1 || true\n\necho \"\"\necho \"-----------------------------------\"\necho \"Test Report\"\necho \"-----------------------------------\"\n\nJUNIT_PATH=\"$RCH_TARGET_DIR/nextest/$PROFILE/junit.xml\"\n\nif [ -f \"$JUNIT_PATH\" ]; then\n echo \"JUnit XML report: $JUNIT_PATH\"\n\n # Parse basic stats from JUnit XML\n if command -v xmllint &> /dev/null; then\n # Use /testsuites for aggregate stats (nextest puts totals on root element)\n TESTS=$(xmllint --xpath 'string(/testsuites/@tests)' \"$JUNIT_PATH\" 2>/dev/null || echo \"?\")\n FAILURES=$(xmllint --xpath 'string(/testsuites/@failures)' \"$JUNIT_PATH\" 2>/dev/null || echo \"?\")\n ERRORS=$(xmllint --xpath 'string(/testsuites/@errors)' \"$JUNIT_PATH\" 2>/dev/null || echo \"?\")\n TIME=$(xmllint --xpath 'string(/testsuites/@time)' \"$JUNIT_PATH\" 2>/dev/null || echo \"?\")\n\n echo \"\"\n echo \"Summary:\"\n echo \" Tests: $TESTS\"\n echo \" Failures: $FAILURES\"\n echo \" Errors: $ERRORS\"\n echo \" Time: ${TIME}s\"\n fi\n\n # Generate HTML report if junit2html is available\n if [ \"$OPEN_REPORT\" = true ]; then\n if command -v junit2html &> /dev/null; then\n HTML_PATH=\"$RCH_TARGET_DIR/nextest/$PROFILE/report.html\"\n echo \"\"\n echo \"Generating HTML report...\"\n junit2html \"$JUNIT_PATH\" \"$HTML_PATH\"\n echo \"HTML report: $HTML_PATH\"\n\n # Open in browser\n if command -v open &> /dev/null; then\n open \"$HTML_PATH\" # macOS\n elif command -v xdg-open &> /dev/null; then\n xdg-open \"$HTML_PATH\" # Linux\n else\n echo \"Could not detect browser opener. Open manually: $HTML_PATH\"\n fi\n else\n echo \"\"\n echo \"Note: Install junit2html for HTML reports: pip install junit2html\"\n echo \"Opening raw XML file...\"\n if command -v open &> /dev/null; then\n open \"$JUNIT_PATH\" # macOS\n elif command -v xdg-open &> /dev/null; then\n xdg-open \"$JUNIT_PATH\" # Linux\n fi\n fi\n fi\nelse\n echo \"Warning: JUnit XML report not found at $JUNIT_PATH\"\n echo \"Tests may have failed to run.\"\nfi\n\necho \"\"\necho \"Done!\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":5853,"content_sha256":"821810bff4bbb898553dbddfef3fe921cc9a5a895c5af90e6baa9285b84785c5"},{"filename":"scripts/ubs-version.txt","content":"v5.4.4\n","content_type":"text/plain; charset=utf-8","language":null,"size":7,"content_sha256":"1fd8e70fac9dbc8750a96297e253a9aa11d9813e24a8d670caae76611644e99e"},{"filename":"scripts/validate_ci.sh","content":"#!/bin/bash\n# scripts/validate_ci.sh\n\nset -e\n\n# Parse arguments\nNO_MOCK_ONLY=false\nARTIFACT_HYGIENE_ONLY=false\nNO_MOCK_FAILED=false\nE2E_COMPLIANCE_FAILED=false\nRCH_BIN=${RCH_BIN:-rch}\nRCH_TARGET_DIR=${RCH_TARGET_DIR:-${TMPDIR:-/tmp}/rch_target_cass_validate_ci}\nCASS_ROUTINE_FEATURES=\"${CASS_ROUTINE_FEATURES:-qr encryption backtrace}\"\n\nusage() {\n cat \u003c\u003c'USAGE'\nUsage: scripts/validate_ci.sh [--no-mock-only|--artifact-hygiene-only]\n\nEnvironment:\n RCH_BIN=rch Remote compilation helper binary for heavy Cargo gates\n RCH_TARGET_DIR=... Remote Cargo target dir for heavy gates\n CASS_ROUTINE_FEATURES=\"qr encryption backtrace\"\n Cass features for routine gates; excludes\n strict-path-dep-validation by default\nUSAGE\n}\n\nensure_rch() {\n if ! command -v \"$RCH_BIN\" &> /dev/null; then\n echo \"ERROR: rch binary not found; validate_ci Cargo gates must be offloaded\" >&2\n return 1\n fi\n}\n\nrun_cargo() {\n \"$RCH_BIN\" exec -- env CARGO_TARGET_DIR=\"$RCH_TARGET_DIR\" cargo \"$@\"\n}\n\nwhile [ \"$#\" -gt 0 ]; do\n case \"$1\" in\n --no-mock-only)\n NO_MOCK_ONLY=true\n shift\n ;;\n --artifact-hygiene-only)\n ARTIFACT_HYGIENE_ONLY=true\n shift\n ;;\n --help|-h)\n usage\n exit 0\n ;;\n *)\n echo \"unknown argument: $1\" >&2\n usage >&2\n exit 2\n ;;\n esac\ndone\n\nif [ \"$NO_MOCK_ONLY\" = true ] && [ \"$ARTIFACT_HYGIENE_ONLY\" = true ]; then\n echo \"--no-mock-only and --artifact-hygiene-only are mutually exclusive\" >&2\n usage >&2\n exit 2\nfi\n\necho \"=== Validating CI Pipeline ===\"\n\n# ============================================================\n# Repository Artifact Hygiene Check\n# ============================================================\nif [ \"$NO_MOCK_ONLY\" != true ] || [ \"$ARTIFACT_HYGIENE_ONLY\" = true ]; then\n echo \"0. Checking repository artifact hygiene...\"\n\n FORBIDDEN_TRACKED=$(\n git ls-files | while IFS= read -r path; do\n case \"$path\" in\n .ntm/*|.claude/*|.ruff_cache/*|artifacts/*|ci-artifacts/*|data/*|logs/*|proptest-regressions/*|refactor/*|test-results/*|tests/artifacts/*|tests/e2e/exports/*|tests/e2e/pages_preview/*|tests/test-results/*|tests/tests/*|tmp/*)\n echo \"$path\"\n continue\n ;;\n *.db-wal|*.db-shm|*.db-journal|*.sqlite-wal|*.sqlite-shm|*.sqlite-journal|*.sqlite3-wal|*.sqlite3-shm|*.sqlite3-journal|*.sqlite3.bak|*.sqlite3.bak-*|*.sqlite3-wal.bak|*.sqlite3.corrupt-*|*.sqlite3-wal.corrupt-*)\n echo \"$path\"\n continue\n ;;\n esac\n\n if [[ \"$path\" != */* ]]; then\n case \"$path\" in\n .aider.chat.history.md|a.out|claude-upgrade-progress.json|clippy*.txt|fix_*.py|*.log|*.mcp.json|parse_ubs.py|path_test|perf.data|perf.data.old|scan.txt|storage.sqlite3*|temp_*.rs|test_empty_db.rs|ubs.json|ubs_filtered.txt|ubs-report.*|*.sarif)\n echo \"$path\"\n ;;\n esac\n fi\n done\n )\n\n if [ -n \"$FORBIDDEN_TRACKED\" ]; then\n echo \" ERROR: generated or local-only artifacts are tracked:\"\n printf '%s\\n' \"$FORBIDDEN_TRACKED\" | sed 's/^/ - /'\n echo \"\"\n echo \" Move durable evidence to docs/artifacts/, docs/assets/, docs/planning/,\"\n echo \" or tests/policies/ as appropriate. Keep generated run output, local\"\n echo \" SQLite state, logs, scratch files, and agent harness state ignored.\"\n exit 1\n fi\n\n echo \" No forbidden tracked artifacts found - OK\"\n\n if [ \"$ARTIFACT_HYGIENE_ONLY\" = true ]; then\n exit 0\n fi\nfi\n\n# ============================================================\n# No-Mock Policy Check\n# ============================================================\necho \"1. Checking no-mock policy compliance...\"\n\nif [ \"$SKIP_NO_MOCK_CHECK\" = \"1\" ]; then\n echo \" (Skipping no-mock check: SKIP_NO_MOCK_CHECK=1)\"\nelif command -v rg &> /dev/null && command -v jq &> /dev/null; then\n ALLOWLIST_FILE=\"tests/policies/no_mock_allowlist.json\"\n VIOLATIONS_FILE=$(mktemp)\n\n # Search for mock/fake/stub patterns\n # Use explicit patterns to avoid false positives with -i flag\n # - CamelCase: MockFoo, FakeBar, StubBaz (without -i, exact case)\n # - snake_case: mock_, fake_, stub_ (case insensitive)\n # Exclude node_modules (anywhere), target, .git, and fixture files\n rg -n \"(Mock[A-Z][a-z]|Fake[A-Z][a-z]|Stub[A-Z][a-z]|mock_|fake_|stub_)\" \\\n --glob '!**/node_modules/**' \\\n --glob '!target/**' \\\n --glob '!.git/**' \\\n --glob '!tests/fixtures/**' \\\n --glob '!test-results/**' \\\n --glob '!*.md' \\\n --glob '!*.json' \\\n src/ tests/ 2>/dev/null > \"$VIOLATIONS_FILE\" || true\n\n # Count violations\n VIOLATION_COUNT=$(wc -l \u003c \"$VIOLATIONS_FILE\" | tr -d ' ')\n\n if [ \"$VIOLATION_COUNT\" -gt 0 ]; then\n echo \" Found $VIOLATION_COUNT mock/fake/stub pattern(s)\"\n\n # Check if allowlist exists\n if [ -f \"$ALLOWLIST_FILE\" ]; then\n ALLOWLIST_ENTRIES=$(jq -r '.entries[] | \"\\(.path):\\(.pattern)\"' \"$ALLOWLIST_FILE\" 2>/dev/null || echo \"\")\n UNALLOWED_COUNT=0\n\n while IFS= read -r line; do\n FILE=$(echo \"$line\" | cut -d: -f1)\n PATTERN=$(echo \"$line\" | grep -oiE \"(Mock[A-Z][a-zA-Z]*|Fake[A-Z][a-zA-Z]*|Stub[A-Z][a-zA-Z]*|mock_[a-z_]+|fake_[a-z_]+|stub_[a-z_]+)\" | head -1)\n\n # Check if this file:pattern combination is allowlisted\n ALLOWED=false\n for entry in $ALLOWLIST_ENTRIES; do\n ENTRY_PATH=$(echo \"$entry\" | cut -d: -f1)\n ENTRY_PATTERN=$(echo \"$entry\" | cut -d: -f2)\n\n if [[ \"$FILE\" == *\"$ENTRY_PATH\"* ]] && [[ \"$PATTERN\" == *\"$ENTRY_PATTERN\"* || \"$ENTRY_PATTERN\" == *\"$PATTERN\"* ]]; then\n ALLOWED=true\n break\n fi\n done\n\n if [ \"$ALLOWED\" = false ]; then\n echo \" VIOLATION: $line\"\n UNALLOWED_COUNT=$((UNALLOWED_COUNT + 1))\n fi\n done \u003c \"$VIOLATIONS_FILE\"\n\n if [ \"$UNALLOWED_COUNT\" -gt 0 ]; then\n echo \"\"\n echo \" ERROR: $UNALLOWED_COUNT unapproved mock/fake/stub pattern(s) found!\"\n echo \" See TESTING.md 'No-Mock Policy' for how to request an exception.\"\n echo \"\"\n rm -f \"$VIOLATIONS_FILE\"\n if [ \"$NO_MOCK_ONLY\" = true ]; then\n exit 1\n else\n # Continue with other checks but mark as failed\n NO_MOCK_FAILED=true\n fi\n else\n echo \" All patterns are allowlisted - OK\"\n fi\n else\n echo \" ERROR: Allowlist file not found at $ALLOWLIST_FILE\"\n echo \" Run 'br show bd-28iz' for setup instructions\"\n if [ \"$NO_MOCK_ONLY\" = true ]; then\n rm -f \"$VIOLATIONS_FILE\"\n exit 1\n fi\n NO_MOCK_FAILED=true\n fi\n else\n echo \" No mock/fake/stub patterns found - OK\"\n fi\n\n rm -f \"$VIOLATIONS_FILE\"\nelse\n MISSING_TOOLS=()\n command -v rg &> /dev/null || MISSING_TOOLS+=(\"rg\")\n command -v jq &> /dev/null || MISSING_TOOLS+=(\"jq\")\n echo \" ERROR: cannot run no-mock check; missing required tool(s): ${MISSING_TOOLS[*]}\"\n echo \" Install the missing tool(s), or set SKIP_NO_MOCK_CHECK=1 for an explicit local bypass.\"\n if [ \"$NO_MOCK_ONLY\" = true ]; then\n exit 1\n fi\n NO_MOCK_FAILED=true\nfi\n\n# Exit early if --no-mock-only flag was passed\nif [ \"$NO_MOCK_ONLY\" = true ]; then\n if [ \"$NO_MOCK_FAILED\" = true ]; then\n exit 1\n fi\n echo \" No-mock check passed\"\n exit 0\nfi\n\necho \"2. Running local CI simulation...\"\nensure_rch\necho \" - Using rch target dir: $RCH_TARGET_DIR\"\necho \" - Using cass features: $CASS_ROUTINE_FEATURES\"\necho \" - Checking formatting...\"\nrun_cargo fmt --all -- --check\n\necho \" - Running Clippy...\"\nrun_cargo clippy --all-targets --features \"$CASS_ROUTINE_FEATURES\" -- -D warnings\n\necho \" - Running Rust tests...\"\nrun_cargo test --features \"$CASS_ROUTINE_FEATURES\"\n\necho \" - Running Crypto Vector tests...\"\nrun_cargo test --test crypto_vectors\n\necho \" - Running cargo audit (if installed)...\"\nif run_cargo audit --version >/dev/null 2>&1; then\n run_cargo audit\nelse\n echo \" (Skipping cargo audit: cargo-audit not available through rch)\"\nfi\n\nif [ -f \"web/package.json\" ]; then\n echo \" - Running web tests (if npm is available)...\"\n if command -v npm >/dev/null 2>&1; then\n (cd web && npm ci && npm test)\n else\n echo \" (Skipping web tests: npm not found)\"\n fi\nfi\n\n# ============================================================\n# E2E Logging Compliance Check\n# ============================================================\necho \"3. Checking E2E logging compliance...\"\n\nE2E_ERRORS=0\nE2E_WARNINGS=0\n\n# Check that all e2e_*.rs files import e2e_log module\nfor f in tests/e2e_*.rs; do\n if [ ! -f \"$f\" ]; then\n continue\n fi\n name=$(basename \"$f\")\n\n # Check for e2e_log import or PhaseTracker usage\n if ! grep -q \"use.*e2e_log\\|mod.*e2e_log\\|PhaseTracker\\|E2eLogger\" \"$f\"; then\n echo \" WARNING: $name not using E2E logging infrastructure\"\n ((E2E_WARNINGS += 1))\n fi\ndone\n\n# Check shell scripts source e2e_log.sh\nfor f in scripts/e2e/*.sh; do\n if [ -f \"$f\" ] && [ -s \"$f\" ]; then\n name=$(basename \"$f\")\n if ! grep -q \"e2e_log.sh\" \"$f\"; then\n echo \" WARNING: $name not sourcing e2e_log.sh\"\n ((E2E_WARNINGS += 1))\n fi\n fi\ndone\n\nif [ $E2E_ERRORS -gt 0 ]; then\n echo \" FAILED: $E2E_ERRORS E2E logging compliance error(s)\"\n E2E_COMPLIANCE_FAILED=true\nelse\n if [ $E2E_WARNINGS -gt 0 ]; then\n echo \" OK with $E2E_WARNINGS warning(s) (non-blocking)\"\n else\n echo \" OK: E2E logging compliance checks passed\"\n fi\nfi\n\n# Final check for deferred no-mock failures\nif [ \"$NO_MOCK_FAILED\" = true ]; then\n echo \"\"\n echo \"=== CI Validation FAILED ===\"\n echo \"No-mock policy violations found. See output above.\"\n exit 1\nfi\n\nif [ \"$E2E_COMPLIANCE_FAILED\" = true ]; then\n echo \"\"\n echo \"=== CI Validation FAILED ===\"\n echo \"E2E logging compliance violations found. See output above.\"\n exit 1\nfi\n\necho \"=== CI Validation Complete ===\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":10690,"content_sha256":"849db3cbc18a9a38b399c7fdd1c7e7e6c1c7a7fc4f6e4624933f1e853fe9e188"},{"filename":"scripts/validate_docs.sh","content":"#!/usr/bin/env bash\n# Documentation validation script for cass.\n#\n# Validates:\n# - Link validity in markdown files\n# - Required sections in README\n# - CLI help text consistency\n# - Example code validity\n#\n# Usage:\n# ./scripts/validate_docs.sh # Run all validations\n# ./scripts/validate_docs.sh --links # Only check links\n# ./scripts/validate_docs.sh --readme # Only check README\n# ./scripts/validate_docs.sh --help # Only check CLI help\n\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\nRCH_BIN=\"${RCH_BIN:-rch}\"\nRCH_TARGET_DIR=\"${RCH_TARGET_DIR:-${TMPDIR:-/tmp}/rch_target_cass_validate_docs}\"\n\n# Colors\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nNC='\\033[0m' # No Color\n\n# Counters\nERRORS=0\nWARNINGS=0\nCHECKS=0\n\n# =============================================================================\n# Helper Functions\n# =============================================================================\n\nlog_pass() {\n ((CHECKS += 1))\n echo -e \"${GREEN}✓${NC} $1\"\n}\n\nlog_fail() {\n ((CHECKS += 1))\n ((ERRORS += 1))\n echo -e \"${RED}✗${NC} $1\"\n}\n\nlog_warn() {\n ((WARNINGS += 1))\n echo -e \"${YELLOW}!${NC} $1\"\n}\n\nlog_info() {\n echo -e \" $1\"\n}\n\nensure_rch() {\n if ! command -v \"$RCH_BIN\" &> /dev/null; then\n log_fail \"rch binary not found; validate_docs cargo work must be offloaded\"\n return 1\n fi\n}\n\nrun_cargo() {\n \"$RCH_BIN\" exec -- env CARGO_TARGET_DIR=\"$RCH_TARGET_DIR\" cargo \"$@\"\n}\n\nsection() {\n echo \"\"\n echo \"═══════════════════════════════════════════════════════════════\"\n echo \" $1\"\n echo \"═══════════════════════════════════════════════════════════════\"\n}\n\n# =============================================================================\n# Link Validation\n# =============================================================================\n\ncheck_links() {\n section \"Link Validation\"\n\n local md_files\n md_files=$(find . -name \"*.md\" -not -path \"./target/*\" -not -path \"./.git/*\" 2>/dev/null || true)\n\n if [[ -z \"$md_files\" ]]; then\n log_warn \"No markdown files found\"\n return\n fi\n\n local file\n for file in $md_files; do\n log_info \"Checking $file...\"\n\n # Check for broken internal links (relative paths)\n local links\n links=$(grep -oE '\\[([^]]+)\\]\\(([^)]+)\\)' \"$file\" 2>/dev/null | grep -v 'http' | grep -v 'mailto' || true)\n\n while IFS= read -r link; do\n [[ -z \"$link\" ]] && continue\n\n # Extract the path from the link\n local path\n path=$(echo \"$link\" | sed -E 's/.*\\]\\(([^)#]+).*/\\1/')\n\n # Skip anchors and empty paths\n [[ -z \"$path\" || \"$path\" == \"#\"* ]] && continue\n\n # Resolve relative to file directory\n local dir\n dir=$(dirname \"$file\")\n local full_path=\"$dir/$path\"\n\n if [[ ! -e \"$full_path\" && ! -e \"$path\" ]]; then\n log_fail \"Broken link in $file: $path\"\n fi\n done \u003c\u003c\u003c \"$links\"\n\n # Check for valid URL patterns in external links\n local urls\n urls=$(grep -oE 'https?://[^)\"\\s>]+' \"$file\" 2>/dev/null || true)\n\n while IFS= read -r url; do\n [[ -z \"$url\" ]] && continue\n\n # Basic URL format validation\n if ! echo \"$url\" | grep -qE '^https?://[a-zA-Z0-9]'; then\n log_fail \"Malformed URL in $file: $url\"\n fi\n done \u003c\u003c\u003c \"$urls\"\n done\n\n log_pass \"Link validation complete\"\n}\n\n# =============================================================================\n# README Validation\n# =============================================================================\n\ncheck_readme() {\n section \"README Validation\"\n\n local readme=\"README.md\"\n\n if [[ ! -f \"$readme\" ]]; then\n log_fail \"README.md not found\"\n return\n fi\n\n log_info \"Checking required sections...\"\n\n # Check for key sections\n local sections=(\"installation\" \"usage\" \"features\" \"license\")\n\n for sec in \"${sections[@]}\"; do\n if grep -qi \"## .*$sec\\|# .*$sec\" \"$readme\"; then\n log_pass \"README has $sec section\"\n else\n log_warn \"README may be missing $sec section\"\n fi\n done\n\n # Check for examples\n if grep -q '```' \"$readme\"; then\n log_pass \"README contains code examples\"\n else\n log_warn \"README has no code examples\"\n fi\n\n # Check for badges (optional)\n if grep -qE '!\\[.*\\]\\(https?://' \"$readme\"; then\n log_pass \"README has badges/images\"\n else\n log_info \"README has no badges (optional)\"\n fi\n\n # Check file isn't empty or too short\n local lines\n lines=$(wc -l \u003c \"$readme\")\n if [[ \"$lines\" -lt 20 ]]; then\n log_warn \"README seems short ($lines lines)\"\n else\n log_pass \"README has adequate content ($lines lines)\"\n fi\n}\n\n# =============================================================================\n# CLI Help Validation\n# =============================================================================\n\ncheck_help() {\n section \"CLI Help Validation\"\n\n # Check if binary exists\n local binary=\"$RCH_TARGET_DIR/release/cass\"\n if [[ ! -x \"$binary\" ]]; then\n binary=\"$RCH_TARGET_DIR/debug/cass\"\n fi\n if [[ ! -x \"$binary\" ]]; then\n binary=\"target/release/cass\"\n fi\n if [[ ! -x \"$binary\" ]]; then\n binary=\"target/debug/cass\"\n fi\n\n if [[ ! -x \"$binary\" ]]; then\n log_warn \"cass binary not found, building through rch...\"\n ensure_rch || return\n run_cargo build --quiet --bin cass 2>/dev/null || {\n log_fail \"Could not build cass binary\"\n return\n }\n binary=\"$RCH_TARGET_DIR/debug/cass\"\n if [[ ! -x \"$binary\" ]]; then\n log_fail \"Built cass binary not found at $binary\"\n return\n fi\n fi\n\n log_info \"Using binary: $binary\"\n\n # Test --help\n if \"$binary\" --help &>/dev/null; then\n log_pass \"--help flag works\"\n else\n log_fail \"--help flag failed\"\n fi\n\n # Test -h\n if \"$binary\" -h &>/dev/null; then\n log_pass \"-h flag works\"\n else\n log_fail \"-h flag failed\"\n fi\n\n # Test --version\n local version_output\n version_output=$(\"$binary\" --version 2>&1 || true)\n if echo \"$version_output\" | grep -qE '[0-9]+\\.[0-9]+\\.[0-9]+'; then\n log_pass \"--version shows version number\"\n else\n log_fail \"--version doesn't show version number\"\n fi\n\n # Test subcommand help\n local subcommands=(\"search\" \"index\" \"export\" \"tui\" \"health\")\n for cmd in \"${subcommands[@]}\"; do\n if \"$binary\" \"$cmd\" --help &>/dev/null; then\n log_pass \"Subcommand '$cmd' has help\"\n else\n log_warn \"Subcommand '$cmd' help unavailable\"\n fi\n done\n\n # Check help mentions key features\n local help_output\n help_output=$(\"$binary\" --help 2>&1 || true)\n\n if echo \"$help_output\" | grep -qi \"search\"; then\n log_pass \"Help mentions search\"\n else\n log_warn \"Help doesn't mention search\"\n fi\n\n if echo \"$help_output\" | grep -qi \"index\"; then\n log_pass \"Help mentions index\"\n else\n log_warn \"Help doesn't mention index\"\n fi\n}\n\n# =============================================================================\n# Security Doc Validation\n# =============================================================================\n\ncheck_security() {\n section \"Security Documentation\"\n\n local security=\"SECURITY.md\"\n\n if [[ ! -f \"$security\" ]]; then\n log_warn \"SECURITY.md not found (may be generated at publish time)\"\n return\n fi\n\n log_info \"Checking security documentation...\"\n\n # Check for key security concepts\n local concepts=(\"encrypt\" \"argon\" \"aes\" \"password\" \"key\")\n\n for concept in \"${concepts[@]}\"; do\n if grep -qi \"$concept\" \"$security\"; then\n log_pass \"Security doc mentions $concept\"\n else\n log_warn \"Security doc may not cover $concept\"\n fi\n done\n}\n\n# =============================================================================\n# Example Code Validation\n# =============================================================================\n\n# =============================================================================\n# README ↔ code truth checks (reality check 2026-09-01, WS-A.9)\n#\n# The README is the vision document; these checks make its concrete claims\n# executable: every key binding in a README key table must have a matching arm\n# in the TUI key map, every `cass` flag the README shows must exist in\n# `cass introspect --json`, and every env var in the README env table must be\n# one `cass robot-docs env` knows. `README_PATH` overrides the file under test\n# (used to plant a negative); `CASS_BIN` overrides the binary.\n# =============================================================================\n\nresolve_cass_binary() {\n local candidate\n for candidate in \"${CASS_BIN:-}\" \"$RCH_TARGET_DIR/release/cass\" \"$RCH_TARGET_DIR/debug/cass\" \\\n \"target/release/cass\" \"target/debug/cass\"; do\n if [[ -n \"$candidate\" && -x \"$candidate\" ]]; then\n echo \"$candidate\"\n return 0\n fi\n done\n if command -v cass &> /dev/null; then\n command -v cass\n return 0\n fi\n return 1\n}\n\n# Translate one README key token (`Alt+Shift+W`, `F4`, `Ctrl+Del`, `Esc`, `?`)\n# into an extended regex over the TUI key map source, or print nothing when the\n# token is not a key (prose in the key column).\nkey_token_pattern() {\n local token=\"$1\" mods=\"\" base\n local ctrl=0 alt=0 shift=0\n base=\"$token\"\n while [[ \"$base\" == *+* && ${#base} -gt 1 ]]; do\n case \"${base%%+*}\" in\n Ctrl|ctrl) ctrl=1 ;;\n Alt|alt|Meta|Opt|Option) alt=1 ;;\n Shift|shift) shift=1 ;;\n *) break ;;\n esac\n base=\"${base#*+}\"\n done\n local code=\"\"\n case \"$base\" in\n F[0-9]|F1[0-2]) code=\"KeyCode::F\\\\(${base#F}\\\\)\" ;;\n Esc|Escape) code=\"KeyCode::Esc\" ;;\n Enter|Return) code=\"KeyCode::Enter\" ;;\n Tab) if [[ $shift == 1 ]]; then code=\"KeyCode::BackTab\"; shift=0; else code=\"KeyCode::Tab\"; fi ;;\n BackTab) code=\"KeyCode::BackTab\" ;;\n Del|Delete) code=\"KeyCode::Delete\" ;;\n Backspace) code=\"KeyCode::Backspace\" ;;\n Up|Down|Left|Right|Home|End) code=\"KeyCode::${base}\" ;;\n PageUp|PgUp) code=\"KeyCode::PageUp\" ;;\n PageDown|PgDn) code=\"KeyCode::PageDown\" ;;\n Space) code=\"Char\\\\(' '\\\\)\" ;;\n [1-9]) # README writes digit ranges as `Alt+1`..`Alt+9`; the map has one\n # range arm: `KeyCode::Char(c @ '1'..='9') if \u003cmodifier>`.\n code=\"(Char\\\\('${base}'\\\\)|Char\\\\(c @ '1'\\\\.\\\\.='9'\\\\))\" ;;\n ?) # single printable character: either case is accepted, and either\n # of the two forms the TUI uses — a `KeyCode::Char('x')` arm, or a\n # typed-character re-dispatch `text == \"x\"` (the detail pane).\n local lower upper escaped\n lower=$(printf '%s' \"$base\" | tr '[:upper:]' '[:lower:]')\n upper=$(printf '%s' \"$base\" | tr '[:lower:]' '[:upper:]')\n case \"$base\" in\n [A-Za-z]) code=\"(Char\\\\('(${lower}|${upper})'\\\\)|text == \\\"(${lower}|${upper})\\\")\" ;;\n \"'\") code=\"Char\\\\('\\\\\\\\''\\\\)\" ;;\n *)\n escaped=$(printf '%s' \"$base\" | sed 's/[][\\\\.*^$/?+(){}|]/\\\\&/g')\n code=\"(Char\\\\('${escaped}'\\\\)|text == \\\"${escaped}\\\")\"\n ;;\n esac\n ;;\n *) return 0 ;;\n esac\n [[ $ctrl == 1 ]] && mods=\"${mods}(?=.*ctrl)\"\n [[ $alt == 1 ]] && mods=\"${mods}(?=.*alt)\"\n [[ $shift == 1 ]] && mods=\"${mods}(?=.*shift)\"\n # PCRE: the arm line must mention the code and every modifier guard.\n echo \"^(?=.*${code})${mods}\"\n}\n\ncheck_keys() {\n section \"README key bindings ↔ TUI key map\"\n local readme=\"${README_PATH:-README.md}\" keymap=\"src/ui/app.rs\"\n local missing=0 checked=0 token pattern cell\n while IFS= read -r cell; do\n # Split multi-key cells: `F3` / `Alt+G`\n while IFS= read -r token; do\n token=\"${token#\\`}\"; token=\"${token%\\`}\"\n [[ -z \"$token\" ]] && continue\n pattern=$(key_token_pattern \"$token\")\n [[ -z \"$pattern\" ]] && continue\n checked=$((checked + 1))\n if ! grep -P -q \"$pattern\" \"$keymap\"; then\n log_fail \"README key \\`$token\\` has no matching arm in $keymap\"\n missing=$((missing + 1))\n fi\n done \u003c \u003c(printf '%s\\n' \"$cell\" | grep -o -E '`[^`]+`')\n done \u003c \u003c(grep -E '^\\| `[^|]+` *\\|' \"$readme\" | sed -E 's/^\\| ([^|]*)\\|.*/\\1/' | grep -E '`(F[0-9]+|Esc|Enter|Tab|Del|Delete|Backspace|Up|Down|Left|Right|Home|End|Page(Up|Down)|Space|Ctrl|Alt|Shift|.)`|\\+' )\n if [[ $missing -eq 0 ]]; then\n log_pass \"all $checked README key bindings resolve to a TUI key-map arm\"\n fi\n}\n\ncheck_flags() {\n section \"README cass flags ↔ cass introspect\"\n local readme=\"${README_PATH:-README.md}\" binary known\n if ! binary=$(resolve_cass_binary); then\n log_warn \"cass binary not found (set CASS_BIN); skipping flag check\"\n return\n fi\n # `cass introspect --json` lists top-level commands only (nested\n # subcommands such as `sources sync` are not described there — a contract\n # gap noted in the reality check), so the truth source for a README\n # invocation is clap itself: `cass \u003ccommand path> --help`. Help output is\n # collected once per command path.\n local global_flags\n global_flags=$(\"$binary\" --help 2>/dev/null | grep -o -E -- '--[a-z][a-z0-9-]+' | sort -u)\n if [[ -z \"$global_flags\" ]]; then\n log_fail \"cass --help printed no flags from $binary\"\n return\n fi\n # Filled in this shell, never inside a pipeline: a function on the left of\n # `|` runs in a subshell, so the cache used to be rebuilt for every flag.\n # The exit status is kept so a crashing `--help` is reported as a crash,\n # not as a README flag that clap does not accept.\n declare -A help_cache=() help_status=()\n cache_help_for_path() {\n local path=\"$1\" out rc=0\n [[ -n \"${help_cache[$path]+x}\" ]] && return 0\n # shellcheck disable=SC2086\n out=$(\"$binary\" $path --help 2>/dev/null) || rc=$?\n help_status[$path]=$rc\n help_cache[$path]=$(printf '%s\\n' \"$out\" | grep -o -E -- '--[a-z][a-z0-9-]+' | sort -u || true)\n }\n local missing=0 checked=0 line path token flag\n # README lines that deliberately show WRONG spellings (the auto-correction\n # tables) are not claims about the contract. A line may hold several\n # invocations; each `cass …` segment is judged on its own.\n while IFS= read -r line; do\n path=\"\"\n local first=1\n for token in $(printf '%s' \"$line\"); do\n if [[ $first == 1 ]]; then first=0; continue; fi # the literal `cass`\n case \"$token\" in\n -*|\\\"*|\\'*|\\`*|\\||'#'*) break ;;\n *)\n if [[ \"$token\" =~ ^[a-z][a-z0-9-]*$ ]]; then\n path=\"${path:+$path }$token\"\n else\n break\n fi\n ;;\n esac\n done\n while IFS= read -r flag; do\n [[ -z \"$flag\" ]] && continue\n case \"$flag\" in --help|--version) continue ;; esac\n checked=$((checked + 1))\n if printf '%s\\n' \"$global_flags\" | grep -q -x -- \"$flag\"; then\n continue\n fi\n if [[ -z \"$path\" ]]; then\n # `cass --robot` in prose names a flag without its command;\n # not checkable against one --help, so it is a warning.\n log_warn \"README mentions \\`cass $flag\\` without a command; cannot check it against --help\"\n continue\n fi\n cache_help_for_path \"$path\"\n if grep -q -x -- \"$flag\" \u003c\u003c\u003c\"${help_cache[$path]}\"; then\n continue\n fi\n if [[ \"${help_status[$path]}\" != 0 ]]; then\n log_fail \"\\`cass $path --help\\` exited ${help_status[$path]}, so README's \\`cass $path $flag\\` could not be checked\"\n else\n log_fail \"README shows \\`cass $path $flag\\` but \\`cass $path --help\\` does not list $flag\"\n fi\n missing=$((missing + 1))\n done \u003c \u003c(printf '%s\\n' \"$line\" | grep -o -E -- '--[a-z][a-z0-9-]+' | sort -u)\n done \u003c \u003c(grep -E '(^|[^a-z])cass ' \"$readme\" \\\n | grep -v -i -E 'typo|alias|corrected|auto-correct|Levenshtein|wrong|converted|become|normalized|promoted|route' \\\n | sed -E 's/(^|[^a-z])cass /\\ncass /g' | grep -E '^cass ' \\\n | sed -E 's/`.*$//') # an inline code span ends at the next backtick\n if [[ $missing -eq 0 ]]; then\n log_pass \"all $checked README cass flag usages are accepted by the matching \\`cass … --help\\`\"\n fi\n}\n\ncheck_env() {\n section \"README env vars ↔ code\"\n local readme=\"${README_PATH:-README.md}\" binary robot_known=\"\"\n # Truth source: the variable must be read somewhere in src/ (dotenvy::var,\n # env::var, or a named constant). `cass robot-docs env` is a curated subset\n # for agents, so a README variable it omits is only a warning.\n if binary=$(resolve_cass_binary); then\n robot_known=$(\"$binary\" robot-docs env 2>/dev/null | grep -o -E '^\\s+[A-Z][A-Z0-9_]+' | tr -d ' ' | sort -u)\n fi\n # Connector root overrides (`CASS_\u003cAGENT>_DATA_ROOT`) are read by the\n # franken_agent_detection crate, not by src/; look in its checkout or the\n # cargo registry copy when present.\n local -a env_roots=(src)\n local fad fad_found=0\n for fad in /data/projects/franken_agent_detection/src \\\n \"${CARGO_HOME:-$HOME/.cargo}\"/registry/src/*/franken_agent_detection-*/src; do\n if [[ -d \"$fad\" ]]; then\n env_roots+=(\"$fad\")\n fad_found=1\n fi\n done\n local missing=0 checked=0 unlisted=0 var\n while IFS= read -r var; do\n checked=$((checked + 1))\n if ! grep -r -q -F -- \"\\\"$var\\\"\" \"${env_roots[@]}\" --include='*.rs'; then\n if [[ $fad_found == 0 && \"$var\" == CASS_*_DATA_ROOT ]]; then\n # Connector root overrides live in the detection crate; without\n # its source on this host the claim cannot be checked.\n log_warn \"README env var \\`$var\\` is a connector root override; the agent-detection crate source is not available here to confirm it\"\n continue\n fi\n log_fail \"README env table documents \\`$var\\` but nothing in src/ (or the agent-detection crate) reads \\\"$var\\\"\"\n missing=$((missing + 1))\n elif [[ -n \"$robot_known\" ]] && ! printf '%s\\n' \"$robot_known\" | grep -q -x -- \"$var\"; then\n unlisted=$((unlisted + 1))\n fi\n done \u003c \u003c(grep -E '^\\| `CASS_[A-Z0-9_]+`' \"$readme\" | grep -o -E 'CASS_[A-Z0-9_]+' | sort -u)\n if [[ $missing -eq 0 ]]; then\n log_pass \"all $checked README env vars are read by the code\"\n fi\n if [[ $unlisted -gt 0 ]]; then\n log_warn \"$unlisted README env vars are not in the curated \\`cass robot-docs env\\` list\"\n fi\n}\n\ncheck_examples() {\n section \"Example Code Validation\"\n\n # Extract code blocks from README\n local readme=\"README.md\"\n\n if [[ ! -f \"$readme\" ]]; then\n log_warn \"README.md not found\"\n return\n fi\n\n # Check for shell examples\n if grep -qE '```(bash|sh|shell)' \"$readme\"; then\n log_pass \"README has shell examples\"\n else\n log_info \"No shell examples in README\"\n fi\n\n # Check for Rust examples\n if grep -qE '```rust' \"$readme\"; then\n log_pass \"README has Rust examples\"\n else\n log_info \"No Rust examples in README\"\n fi\n\n # Validate cargo commands mentioned work\n local cargo_cmds\n cargo_cmds=$(grep -oE 'cargo (build|test|run|install|bench)[^`]*' \"$readme\" 2>/dev/null | head -5 || true)\n\n if [[ -n \"$cargo_cmds\" ]]; then\n log_info \"Found cargo commands in README\"\n while IFS= read -r cmd; do\n [[ -z \"$cmd\" ]] && continue\n log_info \" - $cmd\"\n done \u003c\u003c\u003c \"$cargo_cmds\"\n fi\n}\n\n# =============================================================================\n# Cargo Doc Validation\n# =============================================================================\n\ncheck_cargo_docs() {\n section \"Cargo Documentation\"\n\n log_info \"Building documentation...\"\n\n ensure_rch || return\n\n if run_cargo doc --no-deps --quiet 2>/dev/null; then\n log_pass \"cargo doc builds successfully\"\n else\n log_fail \"cargo doc has errors\"\n fi\n\n # Check for documentation warnings\n local doc_output\n doc_output=$(run_cargo doc --no-deps 2>&1 || true)\n\n local missing_docs\n missing_docs=$(echo \"$doc_output\" | grep -c \"missing documentation\" || true)\n\n if [[ \"$missing_docs\" -gt 0 ]]; then\n log_warn \"$missing_docs items missing documentation\"\n else\n log_pass \"No missing documentation warnings\"\n fi\n}\n\n# =============================================================================\n# Main\n# =============================================================================\n\nmain() {\n echo \"╔═══════════════════════════════════════════════════════════════╗\"\n echo \"║ CASS Documentation Validation ║\"\n echo \"╚═══════════════════════════════════════════════════════════════╝\"\n\n cd \"$PROJECT_ROOT\"\n\n case \"${1:-all}\" in\n --links)\n check_links\n ;;\n --readme)\n check_readme\n ;;\n --help)\n check_help\n ;;\n --security)\n check_security\n ;;\n --examples)\n check_examples\n ;;\n --cargo)\n check_cargo_docs\n ;;\n --keys)\n check_keys\n ;;\n --flags)\n check_flags\n ;;\n --env)\n check_env\n ;;\n --truth)\n check_keys\n check_flags\n check_env\n ;;\n all|*)\n check_readme\n check_links\n check_help\n check_security\n check_examples\n check_cargo_docs\n check_keys\n check_flags\n check_env\n ;;\n esac\n\n # Summary\n section \"Summary\"\n echo \"\"\n echo \" Checks: $CHECKS\"\n echo \" Passed: $((CHECKS - ERRORS))\"\n echo \" Errors: $ERRORS\"\n echo \" Warnings: $WARNINGS\"\n echo \"\"\n\n if [[ \"$ERRORS\" -gt 0 ]]; then\n echo -e \"${RED}Documentation validation failed with $ERRORS error(s)${NC}\"\n exit 1\n elif [[ \"$WARNINGS\" -gt 0 ]]; then\n echo -e \"${YELLOW}Documentation validation passed with $WARNINGS warning(s)${NC}\"\n exit 0\n else\n echo -e \"${GREEN}Documentation validation passed!${NC}\"\n exit 0\n fi\n}\n\nmain \"$@\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":23700,"content_sha256":"a30c9c18993d7331ecb932668595e6a0561163fcf29e9ec72541d2b94bf6f534"},{"filename":"scripts/validate_fixtures.sh","content":"#!/usr/bin/env bash\n# Validate all JSONL fixture files in tests/fixtures/message_grouping/\n# Each line must be valid JSON\n\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nFIXTURE_DIR=\"$SCRIPT_DIR/../tests/fixtures/message_grouping\"\n\necho \"=== Validating Message Grouping Fixtures ===\"\necho \"\"\n\nerrors=0\nfor f in \"$FIXTURE_DIR\"/*.jsonl; do\n filename=$(basename \"$f\")\n echo -n \"Checking $filename... \"\n\n line_num=0\n while IFS= read -r line || [[ -n \"$line\" ]]; do\n line_num=$((line_num + 1))\n # Skip empty lines\n if [[ -z \"${line// }\" ]]; then\n continue\n fi\n # Validate JSON\n if ! echo \"$line\" | jq -e . > /dev/null 2>&1; then\n echo \"INVALID\"\n echo \" Line $line_num: Invalid JSON\"\n echo \" Content: ${line:0:80}...\"\n errors=$((errors + 1))\n continue 2 # Continue to next file\n fi\n done \u003c \"$f\"\n\n echo \"OK ($line_num lines)\"\ndone\n\necho \"\"\nif [[ $errors -gt 0 ]]; then\n echo \"=== FAILED: $errors file(s) had errors ===\"\n exit 1\nelse\n echo \"=== All fixtures valid! ===\"\n exit 0\nfi\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":1152,"content_sha256":"f2088e15175deb97bbb8f07b7539006576cd6b628d75e7c26b5a76f9cd2822be"},{"filename":"scripts/validate-e2e-jsonl.sh","content":"#!/usr/bin/env bash\n# E2E JSONL Log Validator\n#\n# Validates that E2E test log files conform to the expected schema.\n# Exit code 0 = valid, non-zero = invalid\n#\n# Usage: ./scripts/validate-e2e-jsonl.sh [file.jsonl ...]\n# ./scripts/validate-e2e-jsonl.sh test-results/e2e/*.jsonl test-results/e2e/**/{cass.log,trace.jsonl}\n#\n# Part of T7.1: JSONL log validator + CI gate\n\nset -eo pipefail\n\n# Stats\ntotal_files=0\nvalid_files=0\ninvalid_files=0\ntotal_events=0\naggregate_failures=0\nsemantic_trace_bytes=0\nsemantic_trace_files=0\n\n# Error collection\ndeclare -a errors=()\n\nvalidate_line() {\n local file=\"$1\"\n local line_num=\"$2\"\n local line=\"$3\"\n\n # Skip empty lines\n [[ -z \"${line// }\" ]] && return 0\n\n # Parse event type\n local event\n event=$(echo \"$line\" | jq -r '.event // empty' 2>/dev/null) || {\n errors+=(\"$file:$line_num: Invalid JSON\")\n return 1\n }\n\n if [[ -z \"$event\" ]]; then\n errors+=(\"$file:$line_num: Missing 'event' field\")\n return 1\n fi\n\n # Validate common required fields\n for field in ts run_id runner; do\n if ! echo \"$line\" | jq -e \".$field\" >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: Event '$event' missing required field '$field'\")\n return 1\n fi\n done\n\n # Validate event-specific fields\n case \"$event\" in\n run_start)\n if ! echo \"$line\" | jq -e '.env' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: run_start missing 'env' field\")\n return 1\n fi\n ;;\n test_start)\n if ! echo \"$line\" | jq -e '.test.name' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: $event missing 'test.name' field\")\n return 1\n fi\n ;;\n test_end)\n if ! echo \"$line\" | jq -e '.test.name' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: $event missing 'test.name' field\")\n return 1\n fi\n if ! echo \"$line\" | jq -e '.result.status' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: test_end missing 'result.status' field\")\n return 1\n fi\n ;;\n run_end)\n if ! echo \"$line\" | jq -e '.summary' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: run_end missing 'summary' field\")\n return 1\n fi\n ;;\n phase_start|phase_end)\n if ! echo \"$line\" | jq -e '.phase.name' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: $event missing 'phase.name' field\")\n return 1\n fi\n ;;\n metrics)\n if ! echo \"$line\" | jq -e '.metrics' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: metrics missing 'metrics' field\")\n return 1\n fi\n ;;\n esac\n\n return 0\n}\n\nvalidate_trace_line() {\n local file=\"$1\"\n local line_num=\"$2\"\n local line=\"$3\"\n\n [[ -z \"${line// }\" ]] && return 0\n\n if ! echo \"$line\" | jq -e '\n type == \"object\"\n and .schema_version == \"cass-trace-v1\"\n and ((.timestamp | type) == \"string\" and (.timestamp | length) > 0)\n and ((.level | type) == \"string\" and (.level | length) > 0)\n and ((.target | type) == \"string\" and (.target | length) > 0)\n and has(\"trace_id\")\n and has(\"test_id\")\n and (.fields | type == \"object\")\n and (\n ((.fields.event | type) == \"string\" and (.fields.event | length) > 0)\n or ((.fields.message | type) == \"string\" and (.fields.message | length) > 0)\n )\n ' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: Invalid cass-trace-v1 JSONL envelope\")\n return 1\n fi\n\n if [[ \"$file\" == *\"test-results/e2e/\"* ]] && ! echo \"$line\" | jq -e '\n ((.trace_id | type) == \"string\" and (.trace_id | length) > 0)\n and ((.test_id | type) == \"string\" and (.test_id | length) > 0)\n ' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: E2E trace correlation IDs must be non-empty strings\")\n return 1\n fi\n\n local receipt\n receipt=$(echo \"$line\" | jq -r '.fields.event // empty')\n case \"$receipt\" in\n trace_truncated)\n if ! echo \"$line\" | jq -e '\n .fields.artifact_complete == false\n and ((.fields.suppressed_events | type) == \"number\"\n and .fields.suppressed_events > 0)\n and ((.fields.suppressed_bytes | type) == \"number\")\n and ((.fields.reason | type) == \"string\")\n and ((.fields.suppression_reasons | type) == \"object\")\n and ((.fields.failure_tail_events | type) == \"number\")\n and ((.fields.failure_tail_bytes | type) == \"number\")\n and ((.fields.failure_tail_dropped_events | type) == \"number\")\n and (\n .fields.suppression_reasons.byte_budget\n + .fields.suppression_reasons.event_budget\n + .fields.suppression_reasons.oversize_event\n == .fields.suppressed_events\n )\n ' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: Invalid trace_truncated receipt\")\n return 1\n fi\n ;;\n trace_filter_summary)\n if ! echo \"$line\" | jq -e '\n .fields.artifact_complete == true\n and ((.fields.filtered_events | type) == \"number\"\n and .fields.filtered_events > 0)\n ' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: Invalid trace_filter_summary receipt\")\n return 1\n fi\n ;;\n command_summary)\n if ! echo \"$line\" | jq -e '\n ((.fields.duration_ms | type) == \"number\")\n and ((.fields.exit_code | type) == \"number\")\n ' >/dev/null 2>&1; then\n errors+=(\"$file:$line_num: command_summary missing duration or outcome\")\n return 1\n fi\n ;;\n esac\n\n return 0\n}\n\nvalidate_file() {\n local file=\"$1\"\n local file_valid=true\n local line_num=0\n local has_run_start=false\n local has_test_start=false\n local has_command_summary=false\n local is_trace_file=false\n [[ \"$(basename \"$file\")\" == \"trace.jsonl\" ]] && is_trace_file=true\n\n echo \"Validating: $file\"\n\n # Check file exists and is readable\n if [[ ! -f \"$file\" ]]; then\n errors+=(\"$file: File not found\")\n return 1\n fi\n\n if [[ ! -s \"$file\" ]]; then\n echo \" Warning: Empty file\"\n return 0\n fi\n\n if [[ \"$is_trace_file\" == true ]] && [[ \"$file\" == *\"test-results/e2e/\"* ]]; then\n local trace_bytes\n trace_bytes=$(wc -c \u003c \"$file\")\n if (( trace_bytes > 524288 )); then\n errors+=(\"$file: $trace_bytes bytes exceeds the 524288-byte E2E trace budget\")\n file_valid=false\n fi\n if [[ \"$file\" == *\"/e2e_semantic_search/\"* ]]; then\n semantic_trace_bytes=$((semantic_trace_bytes + trace_bytes))\n semantic_trace_files=$((semantic_trace_files + 1))\n fi\n if grep -Eq '/home/|/data/projects/' \"$file\"; then\n errors+=(\"$file: trace contains an unredacted private path\")\n file_valid=false\n fi\n fi\n\n # Validate each line. The helper only uses the file path for diagnostics.\n # shellcheck disable=SC2094\n while IFS= read -r line || [[ -n \"$line\" ]]; do\n ((line_num += 1))\n ((total_events += 1))\n\n # Skip empty lines\n [[ -z \"${line// }\" ]] && continue\n\n # Track event types\n local event\n if [[ \"$is_trace_file\" == true ]]; then\n event=$(echo \"$line\" | jq -r '.fields.event // empty' 2>/dev/null) || true\n [[ \"$event\" == \"command_summary\" ]] && has_command_summary=true\n else\n event=$(echo \"$line\" | jq -r '.event // empty' 2>/dev/null) || true\n [[ \"$event\" == \"run_start\" ]] && has_run_start=true\n [[ \"$event\" == \"test_start\" ]] && has_test_start=true\n fi\n\n # Validate the line\n if [[ \"$is_trace_file\" == true ]]; then\n if ! validate_trace_line \"$file\" \"$line_num\" \"$line\"; then\n file_valid=false\n fi\n elif ! validate_line \"$file\" \"$line_num\" \"$line\"; then\n file_valid=false\n fi\n done \u003c \"$file\"\n\n if [[ \"$is_trace_file\" == true ]]; then\n if [[ \"$has_command_summary\" != true ]]; then\n errors+=(\"$file: trace has no command_summary outcome record\")\n file_valid=false\n fi\n if [[ \"$file_valid\" == true ]]; then\n echo \" Valid ($line_num trace events)\"\n return 0\n fi\n echo \" Invalid\"\n return 1\n fi\n\n # Structural validation\n # Per-test log files (in test subdirectories) don't have run_start - only test_start/test_end\n # Main run logs (at the root e2e level) should have run_start\n local is_per_test_log=false\n if [[ \"$file\" == *\"/cass.log\" ]]; then\n local parent_name\n parent_name=$(basename \"$(dirname \"$file\")\")\n # If parent directory is not \"e2e\", it's a per-test log in a subdirectory\n if [[ \"$parent_name\" != \"e2e\" ]]; then\n is_per_test_log=true\n fi\n fi\n\n if [[ \"$has_test_start\" == true ]] && [[ \"$has_run_start\" != true ]] && [[ \"$is_per_test_log\" == false ]]; then\n errors+=(\"$file: Has test events but no run_start\")\n file_valid=false\n fi\n\n # Count test starts and ends\n local test_starts test_ends\n test_starts=$(jq -s '[.[] | select(.event == \"test_start\")] | length' \"$file\" 2>/dev/null || echo 0)\n test_ends=$(jq -s '[.[] | select(.event == \"test_end\")] | length' \"$file\" 2>/dev/null || echo 0)\n\n if [[ \"$test_starts\" != \"$test_ends\" ]]; then\n errors+=(\"$file: Mismatched test_start ($test_starts) and test_end ($test_ends)\")\n file_valid=false\n fi\n\n if [[ \"$file_valid\" == true ]]; then\n echo \" Valid ($line_num events)\"\n return 0\n else\n echo \" Invalid\"\n return 1\n fi\n}\n\nmain() {\n echo \"E2E JSONL Log Validator\"\n echo \"=======================\"\n echo \"\"\n\n # Check for jq\n if ! command -v jq &> /dev/null; then\n echo \"Error: jq is required but not installed\"\n exit 1\n fi\n\n # Get files to validate\n local files=(\"$@\")\n if [[ ${#files[@]} -eq 0 ]]; then\n if [[ -z \"${CASS_E2E_RUN_ID:-}\" ]] \\\n || [[ ! \"$CASS_E2E_RUN_ID\" =~ ^[A-Za-z0-9][A-Za-z0-9_-]*[A-Za-z0-9]$ ]] \\\n || [[ ${#CASS_E2E_RUN_ID} -lt 8 || ${#CASS_E2E_RUN_ID} -gt 128 ]]; then\n echo \"Error: no-argument validation requires a valid CASS_E2E_RUN_ID\"\n echo \"Pass explicit files or select one immutable run.\"\n exit 2\n fi\n local run_root=\"test-results/e2e/runs/$CASS_E2E_RUN_ID\"\n # Default: validate only the selected run's event logs and traces.\n if [[ -d \"$run_root\" ]]; then\n while IFS= read -r -d '' file; do\n files+=(\"$file\")\n done \u003c \u003c(\n find \"$run_root\" \\\n -type f \\( -name \"*.jsonl\" -o -name \"cass.log\" \\) \\\n ! -name \"combined.jsonl\" \\\n -print0 | sort -z\n )\n fi\n fi\n\n if [[ ${#files[@]} -eq 0 ]]; then\n echo \"No JSONL files found in selected run.\"\n echo \"Usage: $0 [file.jsonl ...]\"\n exit 1\n fi\n\n # Validate each file\n for file in \"${files[@]}\"; do\n ((total_files += 1))\n if validate_file \"$file\"; then\n ((valid_files += 1))\n else\n ((invalid_files += 1))\n fi\n echo \"\"\n done\n\n if (( semantic_trace_bytes > 10485760 )); then\n errors+=(\"semantic trace aggregate is $semantic_trace_bytes bytes, exceeding the 10485760-byte campaign gate\")\n aggregate_failures=$((aggregate_failures + 1))\n fi\n\n # Summary\n echo \"=======================\"\n echo \"Summary\"\n echo \"=======================\"\n echo \"Files checked: $total_files\"\n echo \"Valid: $valid_files\"\n echo \"Invalid: $invalid_files\"\n echo \"Total events: $total_events\"\n echo \"Semantic trace files: $semantic_trace_files\"\n echo \"Semantic trace bytes: $semantic_trace_bytes\"\n echo \"Aggregate gate failures: $aggregate_failures\"\n\n # Print errors\n if [[ ${#errors[@]} -gt 0 ]]; then\n echo \"\"\n echo \"Errors:\"\n for err in \"${errors[@]}\"; do\n echo \" - $err\"\n done\n fi\n\n # Exit code\n if [[ $invalid_files -gt 0 || $aggregate_failures -gt 0 ]]; then\n exit 1\n fi\n exit 0\n}\n\nmain \"$@\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":12818,"content_sha256":"2b69c9c2bd4595690a7eb2154a0716b0fb9e733ef772f47eebdca23c37b1f94a"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"CASS - Coding Agent Session Search","type":"text"}]},{"type":"paragraph","content":[{"text":"Unified, high-performance CLI/TUI to index and search your local coding agent history. Aggregates sessions from ","type":"text"},{"text":"23 agents","type":"text","marks":[{"type":"strong"}]},{"text":", including Codex, Claude Code, Gemini CLI, Cline, OpenCode, Amp, Cursor, ChatGPT, Aider, Pi-Agent, Factory (Droid), OpenHands, Antigravity, and Grok Build.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"CRITICAL: Robot Mode Required for AI Agents","type":"text"}]},{"type":"paragraph","content":[{"text":"NEVER run bare ","type":"text","marks":[{"type":"strong"}]},{"text":"cass","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" - it launches an interactive TUI that blocks your session!","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# WRONG - blocks terminal\ncass\n\n# CORRECT - JSON output for agents\ncass search \"query\" --robot\ncass search \"query\" --json # alias","type":"text"}]},{"type":"paragraph","content":[{"text":"Always use ","type":"text","marks":[{"type":"strong"}]},{"text":"--robot","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" or ","type":"text","marks":[{"type":"strong"}]},{"text":"--json","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" flags for machine-readable output.","type":"text","marks":[{"type":"strong"}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Reference for AI Agents","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Bounded History Retrieval","type":"text"}]},{"type":"paragraph","content":[{"text":"For a quick project-history question, start with one scoped query. The flag set below is verified on cass 0.8.0; check ","type":"text"},{"text":"cass --version","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"cass search --help","type":"text","marks":[{"type":"code_inline"}]},{"text":" once per installed version. If ","type":"text"},{"text":"--no-maintenance","type":"text","marks":[{"type":"code_inline"}]},{"text":" is unsupported, stop and report the version mismatch; silently removing it permits maintenance.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Specific terms, one workspace, recent history, small cited result set\ncass search \"performance regression\" --workspace /path/to/project --days 7 \\\n --mode lexical --no-maintenance --robot --robot-meta --fields minimal \\\n --limit 5 --max-tokens 2000 --timeout 2000\n\n# Expand only a useful hit, using its exact source_path and line_number\ncass view /path/to/session.jsonl -n 42 -C 3 --json --timeout 2000","type":"text"}]},{"type":"paragraph","content":[{"text":"--timeout","type":"text","marks":[{"type":"code_inline"}]},{"text":" is in milliseconds; ","type":"text"},{"text":"--max-tokens","type":"text","marks":[{"type":"code_inline"}]},{"text":" is an approximate output budget, not a CPU or memory limit. Apply a caller-side wall-clock deadline as well (for example, GNU ","type":"text"},{"text":"timeout 10s","type":"text","marks":[{"type":"code_inline"}]},{"text":" before the command). Exit 124 from that wrapper is an incomplete attempt; its interrupted stdout may not be valid JSON. In JSON search output, inspect ","type":"text"},{"text":"budget.timed_out","type":"text","marks":[{"type":"code_inline"}]},{"text":" even after exit 0: empty timed-out hits do not prove that no history exists.","type":"text"}]},{"type":"paragraph","content":[{"text":"view -C 3","type":"text","marks":[{"type":"code_inline"}]},{"text":" limits surrounding lines, not bytes or tokens; a single JSONL record can be large. Check its output size before adding excerpts to a prompt.","type":"text"}]},{"type":"paragraph","content":[{"text":"Hybrid remains the product default. Explicit lexical mode keeps this workflow out of semantic inference; ","type":"text"},{"text":"--no-maintenance","type":"text","marks":[{"type":"code_inline"}]},{"text":" prevents index repair, catch-up, and daemon auto-spawn. If it returns ","type":"text"},{"text":"maintenance-required","type":"text","marks":[{"type":"code_inline"}]},{"text":", report that blocker and stop this retrieval attempt. Do not turn a summary request into an index, repair, model-install, wildcard-aggregate, or repeated health/status workflow. Use readiness commands when diagnosing readiness; review their proposed actions before starting a separate mutating task. Broaden dates or terms deliberately after a completed query; choose semantic/hybrid only when conceptual retrieval is needed and its cost is acceptable. Preserve source/line citations in summaries.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Essential Commands","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Find the current session for this workspace\ncass sessions --current --json\n\n# List recent sessions for a specific project\ncass sessions --workspace \"$(pwd)\" --json --limit 5\n\n# Common agent flow: find current session, then export it\ncass export-html \"$(cass sessions --current --json | jq -r '.sessions[0].path')\" --json\n\n# Search with JSON output\ncass search \"authentication error\" --robot --limit 5\n\n# Search with metadata (elapsed_ms, cache stats, freshness)\ncass search \"error\" --robot --robot-meta\n\n# Minimal payload (path, line, agent only)\ncass search \"bug\" --robot --fields minimal\n\n# View source at specific line\ncass view /path/to/session.jsonl -n 42 --json\n\n# Expand context around a line\ncass expand /path/to/session.jsonl -n 42 -C 5 --json\n\n# Capabilities discovery\ncass capabilities --json\n\n# Full API schema\ncass introspect --json\n\n# LLM-optimized documentation\ncass robot-docs guide\ncass robot-docs commands\ncass robot-docs schemas\ncass robot-docs examples\ncass robot-docs exit-codes","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Why Use CASS","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Cross-Agent Knowledge Transfer","type":"text"}]},{"type":"paragraph","content":[{"text":"Your coding agents create scattered knowledge:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Claude Code sessions in ","type":"text"},{"text":"~/.claude/projects","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Codex sessions in ","type":"text"},{"text":"~/.codex/sessions","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cursor state in SQLite databases","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Aider history in markdown files","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"CASS ","type":"text"},{"text":"unifies all of this","type":"text","marks":[{"type":"strong"}]},{"text":" into a single searchable index. When you're stuck on a problem, search across ALL your past agent sessions to find relevant solutions.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Use Cases","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# \"I solved this before...\"\ncass search \"TypeError: Cannot read property\" --robot --days 30\n\n# Cross-agent learning (what has ANY agent said about X?)\ncass search \"authentication\" --robot --workspace /path/to/project\n\n# Agent-to-agent handoff\ncass search \"database migration\" --robot --fields summary\n\n# Daily review\ncass timeline --today --json","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Command Reference","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Indexing","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Full rebuild of DB and search index\ncass index --full\n\n# Incremental update (since last scan)\ncass index\n\n# Watch mode: auto-reindex on file changes\ncass index --watch\n\n# Force rebuild even if schema unchanged\ncass index --full --force-rebuild\n\n# Safe retries with idempotency key (24h TTL)\ncass index --full --idempotency-key \"build-$(date +%Y%m%d)\"\n\n# JSON output with stats\ncass index --full --json","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Search","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Basic search (JSON output required for agents!)\ncass search \"query\" --robot\n\n# With filters\ncass search \"error\" --robot --agent claude --days 7\ncass search \"bug\" --robot --workspace /path/to/project\ncass search \"panic\" --robot --today\n\n# Time filters\ncass search \"auth\" --robot --since 2024-01-01 --until 2024-01-31\ncass search \"test\" --robot --yesterday\ncass search \"fix\" --robot --week\n\n# Wildcards\ncass search \"auth*\" --robot # prefix: authentication, authorize\ncass search \"*tion\" --robot # suffix: authentication, exception\ncass search \"*config*\" --robot # substring: misconfigured\n\n# Token budget management (critical for LLMs!)\ncass search \"error\" --robot --fields minimal # path, line, agent only\ncass search \"error\" --robot --fields summary # adds title, score\ncass search \"error\" --robot --max-content-length 500 # truncate fields\ncass search \"error\" --robot --max-tokens 2000 # soft budget (~4 chars/token)\ncass search \"error\" --robot --limit 5 # cap results\n\n# Pagination (cursor-based)\ncass search \"TODO\" --robot --robot-meta --limit 20\n# Use _meta.next_cursor from response:\ncass search \"TODO\" --robot --robot-meta --limit 20 --cursor \"eyJ...\"\n\n# Match highlighting\ncass search \"authentication error\" --robot --highlight\n\n# Query analysis/debugging\ncass search \"auth*\" --robot --explain # parsed query, cost estimates\ncass search \"auth error\" --robot --dry-run # validate without executing\n\n# Aggregations (server-side counts)\ncass search \"error\" --robot --aggregate agent,workspace,date\n\n# Request correlation\ncass search \"bug\" --robot --request-id \"req-12345\"\n\n# Source filtering (for multi-machine setups)\ncass search \"auth\" --robot --source laptop\ncass search \"error\" --robot --source remote\n\n# Traceability (for debugging agent pipelines)\ncass search \"error\" --robot --trace-file /tmp/cass-trace.json","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Session Analysis","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Export conversation to markdown/HTML/JSON\ncass export /path/to/session.jsonl --format markdown -o conversation.md\ncass export /path/to/session.jsonl --format html -o conversation.html\ncass export /path/to/session.jsonl --format json --include-tools\n\n# Expand context around a line (from search result)\ncass expand /path/to/session.jsonl -n 42 -C 5 --json\n# Shows 5 messages before and after line 42\n\n# View source at line\ncass view /path/to/session.jsonl -n 42 --json\n\n# Activity timeline\ncass timeline --today --json --group-by hour\ncass timeline --days 7 --json --agent claude\ncass timeline --since 7d --json\n\n# Find related sessions for a file\ncass context /path/to/source.ts --json","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Status & Diagnostics","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Readiness diagnosis, when needed; not a prerequisite for every query\ncass health --json\n\n# Full status snapshot\ncass status --json\ncass state --json # alias\n\n# Statistics\ncass stats --json\ncass stats --by-source # for multi-machine\n\n# Full diagnostics\ncass diag --verbose","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Aggregation & Analytics","type":"text"}]},{"type":"paragraph","content":[{"text":"Aggregate search results server-side to get counts and distributions without transferring full result data:","type":"text"}]},{"type":"paragraph","content":[{"text":"Aggregations reduce output volume, not necessarily scan work. They are not the first step for a quick history question; use the scoped retrieval recipe above.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Count results by agent\ncass search \"error\" --robot --aggregate agent\n# → { \"aggregations\": { \"agent\": { \"buckets\": [{\"key\": \"claude_code\", \"count\": 45}, ...] } } }\n\n# Multi-field aggregation\ncass search \"bug\" --robot --aggregate agent,workspace,date\n\n# Combine with filters\ncass search \"TODO\" --agent claude --robot --aggregate workspace","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Aggregation Field","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Description","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"agent","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Group by agent type (claude_code, codex, cursor, etc.)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"workspace","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Group by workspace/project path","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"date","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Group by date (YYYY-MM-DD)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"match_type","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Group by match quality (exact, prefix, fuzzy)","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Top 10 buckets returned per field, with ","type":"text"},{"text":"other_count","type":"text","marks":[{"type":"code_inline"}]},{"text":" for remaining items.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Remote Sources (Multi-Machine Search)","type":"text"}]},{"type":"paragraph","content":[{"text":"Search across sessions from multiple machines via SSH/rsync.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Setup Wizard (Recommended)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cass sources setup","type":"text"}]},{"type":"paragraph","content":[{"text":"The wizard:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Discovers SSH hosts from ","type":"text"},{"text":"~/.ssh/config","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Probes each for agent data and cass installation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Optionally installs cass on remotes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Indexes sessions on remotes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Configures ","type":"text"},{"text":"sources.toml","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Syncs data locally","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cass sources setup --hosts css,csd,yto # Specific hosts only\ncass sources setup --dry-run # Preview without changes\ncass sources setup --resume # Resume interrupted setup","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Manual Setup","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Add a remote machine\ncass sources add [email protected] --preset macos-defaults\ncass sources add dev@workstation --path ~/.claude/projects --path ~/.codex/sessions\n\n# List sources\ncass sources list --json\n\n# Sync sessions\ncass sources sync\ncass sources sync --source laptop --verbose\n\n# Check connectivity\ncass sources doctor\ncass sources doctor --source laptop --json\n\n# Path mappings (rewrite remote paths to local)\ncass sources mappings list laptop\ncass sources mappings add laptop --from /home/user/projects --to /Users/me/projects\ncass sources mappings test laptop /home/user/projects/myapp/src/main.rs\n\n# Remove source\ncass sources remove laptop --purge -y","type":"text"}]},{"type":"paragraph","content":[{"text":"Configuration stored in ","type":"text"},{"text":"~/.config/cass/sources.toml","type":"text","marks":[{"type":"code_inline"}]},{"text":" (Linux) or ","type":"text"},{"text":"~/Library/Application Support/cass/sources.toml","type":"text","marks":[{"type":"code_inline"}]},{"text":" (macOS).","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Robot Mode Deep Dive","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Self-Documenting API","type":"text"}]},{"type":"paragraph","content":[{"text":"CASS teaches agents how to use itself:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Quick capability check\ncass capabilities --json\n# Returns: features, connectors, limits\n\n# Full API schema\ncass introspect --json\n# Returns: all commands, arguments, response shapes\n\n# Topic-based docs (LLM-optimized)\ncass robot-docs commands # all commands and flags\ncass robot-docs schemas # response JSON schemas\ncass robot-docs examples # copy-paste invocations\ncass robot-docs exit-codes # error handling\ncass robot-docs guide # quick-start walkthrough\ncass robot-docs contracts # API versioning\ncass robot-docs sources # remote sources guide","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Forgiving Syntax (Agent-Friendly)","type":"text"}]},{"type":"paragraph","content":[{"text":"CASS auto-corrects common mistakes:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"What you type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"What CASS understands","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass serach \"error\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass search \"error\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" (typo corrected)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass -robot -limit=5","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass --robot --limit=5","type":"text","marks":[{"type":"code_inline"}]},{"text":" (single-dash fixed)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass --Robot --LIMIT 5","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass --robot --limit 5","type":"text","marks":[{"type":"code_inline"}]},{"text":" (case normalized)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass find \"auth\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass search \"auth\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" (alias resolved)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass --limt 5","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass --limit 5","type":"text","marks":[{"type":"code_inline"}]},{"text":" (Levenshtein \u003c=2)","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Command Aliases:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"find","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"query","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"q","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"lookup","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"grep","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"search","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ls","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"list","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"info","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"summary","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"stats","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"st","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"state","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"status","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"reindex","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"idx","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"rebuild","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"index","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"show","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"get","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"read","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"view","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"docs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"help-robot","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"robotdocs","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"robot-docs","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Output Formats","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Pretty-printed JSON (default)\ncass search \"error\" --robot\n\n# Streaming JSONL (header + one hit per line)\ncass search \"error\" --robot-format jsonl\n\n# Compact single-line JSON\ncass search \"error\" --robot-format compact\n\n# With performance metadata\ncass search \"error\" --robot --robot-meta","type":"text"}]},{"type":"paragraph","content":[{"text":"Design principle:","type":"text","marks":[{"type":"strong"}]},{"text":" stdout = JSON only; diagnostics go to stderr.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Token Budget Management","type":"text"}]},{"type":"paragraph","content":[{"text":"LLMs have context limits. Control output size:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Flag","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Effect","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--fields minimal","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Only ","type":"text"},{"text":"source_path","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"line_number","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"agent","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--fields summary","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Adds ","type":"text"},{"text":"title","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"score","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--fields score,title,snippet","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom field selection","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--max-content-length 500","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Truncate long fields (UTF-8 safe)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--max-tokens 2000","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Soft budget (~4 chars/token)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--limit 5","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cap number of results","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Truncated fields include ","type":"text"},{"text":"*_truncated: true","type":"text","marks":[{"type":"code_inline"}]},{"text":" indicator.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Structured Error Handling","type":"text"}]},{"type":"paragraph","content":[{"text":"Errors are JSON with actionable hints:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"error\": {\n \"code\": 3,\n \"kind\": \"index_missing\",\n \"message\": \"Search index not found\",\n \"hint\": \"Run 'cass index --full' to build the index\",\n \"retryable\": false\n }\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Exit Codes","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Code","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Meaning","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Action","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Success","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Parse stdout","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Health check failed","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Inspect the reported condition; no automatic rebuild","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Usage error","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fix syntax (hint provided)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Index/DB missing","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Report missing assets; indexing is a separate mutating task","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Network error","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Check connectivity","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Data/maintenance failure","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Read error kind; preserve the archive and report the blocker","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"6","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Incompatible version","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Update cass","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"7","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Lock/busy","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Retry later","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"8","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Partial result","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Report incomplete coverage; do not silently retry","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"9","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Unknown error","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Check ","type":"text"},{"text":"retryable","type":"text","marks":[{"type":"code_inline"}]},{"text":" flag","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Codes are command-specific: consult ","type":"text"},{"text":"cass robot-docs exit-codes","type":"text","marks":[{"type":"code_inline"}]},{"text":" and the JSON error kind. Search budget expiry can return exit 0 with ","type":"text"},{"text":"budget.timed_out=true","type":"text","marks":[{"type":"code_inline"}]},{"text":"; session-path output instead uses exit 10 for timeout.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Search Modes","type":"text"}]},{"type":"paragraph","content":[{"text":"Three search modes, selectable with ","type":"text"},{"text":"--mode","type":"text","marks":[{"type":"code_inline"}]},{"text":" flag:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mode","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Algorithm","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Best For","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"lexical","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"BM25 full-text","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Exact term matching, bounded history recipes","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"semantic","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Vector similarity","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Conceptual queries, \"find similar\"","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"hybrid","type":"text","marks":[{"type":"strong"}]},{"text":" (default)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reciprocal Rank Fusion","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Lexical retrieval with semantic refinement when ready","type":"text"}]}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cass search \"authentication\" --mode lexical --robot\ncass search \"how to handle user login\" --mode semantic --robot\ncass search \"auth error handling\" --mode hybrid --robot","type":"text"}]},{"type":"paragraph","content":[{"text":"Hybrid","type":"text","marks":[{"type":"strong"}]},{"text":" combines lexical and semantic using RRF:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"RRF_score = Σ 1 / (60 + rank_i)","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Pipeline Mode (Chained Search)","type":"text"}]},{"type":"paragraph","content":[{"text":"Chain searches by piping session paths:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Find sessions mentioning \"auth\", then search within those for \"token\"\ncass search \"authentication\" --robot-format sessions | \\\n cass search \"refresh token\" --sessions-from - --robot\n\n# Build a filtered corpus from today's work\ncass search --today --robot-format sessions > today_sessions.txt\ncass search \"bug fix\" --sessions-from today_sessions.txt --robot","type":"text"}]},{"type":"paragraph","content":[{"text":"Use cases:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Drill-down","type":"text","marks":[{"type":"strong"}]},{"text":": Broad search → narrow within results","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cross-reference","type":"text","marks":[{"type":"strong"}]},{"text":": Find sessions with term A, then find term B within them","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Corpus building","type":"text","marks":[{"type":"strong"}]},{"text":": Save session lists for repeated searches","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Query Language","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Basic Queries","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Query","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Matches","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"error","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Messages containing \"error\" (case-insensitive)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"python error","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Both \"python\" AND \"error\"","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"authentication failed\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Exact phrase","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Boolean Operators","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Operator","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Example","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Meaning","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"AND","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"python AND error","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Both terms required (default)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"OR","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"error OR warning","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Either term matches","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"NOT","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"error NOT test","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"First term, excluding second","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"error -test","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Shorthand for NOT","type":"text"}]}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Complex boolean query\ncass search \"authentication AND (error OR failure) NOT test\" --robot\n\n# Exclude test files\ncass search \"bug fix -test -spec\" --robot\n\n# Either error type\ncass search \"TypeError OR ValueError\" --robot","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Wildcard Patterns","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pattern","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Performance","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"auth*","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prefix","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fast (edge n-grams)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"*tion","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Suffix","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Slower (regex)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"*config*","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Substring","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Slowest (regex)","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Match Types","type":"text"}]},{"type":"paragraph","content":[{"text":"Results include ","type":"text"},{"text":"match_type","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Meaning","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Score Boost","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"exact","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Verbatim match","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Highest","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"prefix","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Via prefix expansion","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"High","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"suffix","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Via suffix pattern","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"substring","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Via substring pattern","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Lower","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fuzzy","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Auto-fallback (sparse results)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Lowest","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Auto-Fuzzy Fallback","type":"text"}]},{"type":"paragraph","content":[{"text":"When exact query returns \u003c3 results, CASS automatically retries with wildcards:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"auth","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"*auth*","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Results flagged with ","type":"text"},{"text":"wildcard_fallback: true","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Flexible Time Input","type":"text"}]},{"type":"paragraph","content":[{"text":"CASS accepts a wide variety of time/date formats:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Format","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Examples","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Relative","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"-7d","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"-24h","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"-30m","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"-1w","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Keywords","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"now","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"today","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"yesterday","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ISO 8601","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2024-11-25","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"2024-11-25T14:30:00Z","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"US Dates","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"11/25/2024","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"11-25-2024","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Unix Timestamp","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1732579200","type":"text","marks":[{"type":"code_inline"}]},{"text":" (seconds or milliseconds)","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Ranking Modes","type":"text"}]},{"type":"paragraph","content":[{"text":"Cycle with ","type":"text"},{"text":"F12","type":"text","marks":[{"type":"code_inline"}]},{"text":" in TUI or use ","type":"text"},{"text":"--ranking","type":"text","marks":[{"type":"code_inline"}]},{"text":" flag:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mode","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Formula","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Best For","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recent Heavy","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"relevance*0.3 + recency*0.7","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"What was I working on?\"","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Balanced","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"relevance*0.5 + recency*0.5","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"General search","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Relevance","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"relevance*0.8 + recency*0.2","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"Best explanation of X\"","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Match Quality","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Penalizes fuzzy matches","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Precise technical searches","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Date Newest","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pure chronological","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recent activity","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Date Oldest","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reverse chronological","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"When did I first...\"","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Score Components","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Text Relevance (BM25)","type":"text","marks":[{"type":"strong"}]},{"text":": Term frequency, inverse document frequency, length normalization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Recency","type":"text","marks":[{"type":"strong"}]},{"text":": Exponential decay (today ~1.0, last week ~0.7, last month ~0.3)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Match Exactness","type":"text","marks":[{"type":"strong"}]},{"text":": Exact phrase=1.0, Prefix=0.9, Suffix=0.8, Substring=0.6, Fuzzy=0.4","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Blended Scoring Formula","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"Final_Score = BM25_Score × Match_Quality + α × Recency_Factor","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mode","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"α Value","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Effect","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recent Heavy","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1.0","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recency dominates","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Balanced","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Moderate recency boost","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Relevance Heavy","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"BM25 dominates","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Match Quality","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.0","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pure text matching","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Supported Agents (23 Connectors)","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Agent","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Location","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Format","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Claude Code","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.claude/projects","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Codex","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.codex/sessions","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL (Rollout)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Gemini CLI","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.gemini/tmp","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSON","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cline","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"VS Code global storage","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Task directories","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"OpenCode","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":".opencode","type":"text","marks":[{"type":"code_inline"}]},{"text":" directories","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"SQLite","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Amp","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.local/share/amp","type":"text","marks":[{"type":"code_inline"}]},{"text":" + VS Code","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mixed","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cursor","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/Library/Application Support/Cursor","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"SQLite (state.vscdb)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ChatGPT","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/Library/Application Support/com.openai.chat","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSON (v1 unencrypted)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Aider","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.aider.chat.history.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" + per-project","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Markdown","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pi-Agent","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.pi/agent/sessions","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL with thinking","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Factory (Droid)","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.factory/sessions","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL by workspace","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"GitHub Copilot Chat","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"VS Code global storage","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSON / SQLite","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"GitHub Copilot CLI","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.copilot/session-state","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"OpenClaw","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.openclaw","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ClawdBot","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.clawdbot","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Vibe","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.vibe/logs/session","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Crush","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.crush/crush.db","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"SQLite","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hermes","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.hermes","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Kimi Code","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.kimi/sessions","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Qwen Code","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.qwen/tmp","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSON / JSONL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"OpenHands","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.openhands/conversations","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSON event stream","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Antigravity","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~/.gemini/antigravity-cli","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSONL / SQLite","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Grok Build","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"$GROK_HOME/sessions","type":"text","marks":[{"type":"code_inline"}]},{"text":" (default ","type":"text"},{"text":"~/.grok/sessions","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ACP updates JSONL","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Note:","type":"text","marks":[{"type":"strong"}]},{"text":" ChatGPT v2/v3 are AES-256-GCM encrypted (keychain access required). Legacy v1 unencrypted conversations are indexed automatically.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"TUI Features (for Humans)","type":"text"}]},{"type":"paragraph","content":[{"text":"Launch with ","type":"text"},{"text":"cass","type":"text","marks":[{"type":"code_inline"}]},{"text":" (no flags):","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Keyboard Shortcuts","type":"text"}]},{"type":"paragraph","content":[{"text":"Navigation:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Up/Down","type":"text","marks":[{"type":"code_inline"}]},{"text":": Move selection","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Left/Right","type":"text","marks":[{"type":"code_inline"}]},{"text":": Switch panes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tab/Shift+Tab","type":"text","marks":[{"type":"code_inline"}]},{"text":": Cycle focus","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enter","type":"text","marks":[{"type":"code_inline"}]},{"text":": Open in ","type":"text"},{"text":"$EDITOR","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Space","type":"text","marks":[{"type":"code_inline"}]},{"text":": Full-screen detail view","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Home/End","type":"text","marks":[{"type":"code_inline"}]},{"text":": Jump to first/last result","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PageUp/PageDown","type":"text","marks":[{"type":"code_inline"}]},{"text":": Scroll by page","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Filtering:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"F3","type":"text","marks":[{"type":"code_inline"}]},{"text":": Agent filter","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"F4","type":"text","marks":[{"type":"code_inline"}]},{"text":": Workspace filter","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"F5/F6","type":"text","marks":[{"type":"code_inline"}]},{"text":": Time filters (from/to)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shift+F3","type":"text","marks":[{"type":"code_inline"}]},{"text":": Scope to current result's agent","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shift+F4","type":"text","marks":[{"type":"code_inline"}]},{"text":": Clear workspace filter","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shift+F5","type":"text","marks":[{"type":"code_inline"}]},{"text":": Cycle presets (24h/7d/30d/all)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+Del","type":"text","marks":[{"type":"code_inline"}]},{"text":": Clear all filters","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Modes:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"F2","type":"text","marks":[{"type":"code_inline"}]},{"text":": Toggle theme (6 presets)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"F7","type":"text","marks":[{"type":"code_inline"}]},{"text":": Context window size (S/M/L/XL)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"F9","type":"text","marks":[{"type":"code_inline"}]},{"text":": Match mode (prefix/standard)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"F12","type":"text","marks":[{"type":"code_inline"}]},{"text":": Ranking mode","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+B","type":"text","marks":[{"type":"code_inline"}]},{"text":": Toggle border style","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Selection & Actions:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"m","type":"text","marks":[{"type":"code_inline"}]},{"text":": Toggle selection","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+A","type":"text","marks":[{"type":"code_inline"}]},{"text":": Select all","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"A","type":"text","marks":[{"type":"code_inline"}]},{"text":": Bulk actions menu","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+Enter","type":"text","marks":[{"type":"code_inline"}]},{"text":": Add to queue","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+O","type":"text","marks":[{"type":"code_inline"}]},{"text":": Open all queued","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"y","type":"text","marks":[{"type":"code_inline"}]},{"text":": Copy path/content","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+Y","type":"text","marks":[{"type":"code_inline"}]},{"text":": Copy all selected","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"/","type":"text","marks":[{"type":"code_inline"}]},{"text":": Find in detail pane","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"n/N","type":"text","marks":[{"type":"code_inline"}]},{"text":": Next/prev match","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Views & Palette:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+P","type":"text","marks":[{"type":"code_inline"}]},{"text":": Command palette","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"1-9","type":"text","marks":[{"type":"code_inline"}]},{"text":": Load saved view","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shift+1-9","type":"text","marks":[{"type":"code_inline"}]},{"text":": Save view to slot","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Source Filtering (multi-machine):","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"F11","type":"text","marks":[{"type":"code_inline"}]},{"text":": Cycle source filter (all/local/remote)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shift+F11","type":"text","marks":[{"type":"code_inline"}]},{"text":": Source selection menu","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Global:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+C","type":"text","marks":[{"type":"code_inline"}]},{"text":": Quit","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"F1","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"?","type":"text","marks":[{"type":"code_inline"}]},{"text":": Toggle help","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+Shift+R","type":"text","marks":[{"type":"code_inline"}]},{"text":": Force re-index","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ctrl+Shift+Del","type":"text","marks":[{"type":"code_inline"}]},{"text":": Reset all TUI state","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Detail Pane Tabs","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tab","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Content","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Switch With","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Messages","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Full conversation with markdown","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"]","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Snippets","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Keyword-extracted summaries","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"]","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Raw","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Unformatted JSON/text","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"]","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Context Window Sizing","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Size","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Characters","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use Case","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Small","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~200","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Quick scanning","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~400","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Default balanced view","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Large","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~800","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Longer passages","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"XLarge","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"~1600","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Full context, code review","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Peek Mode","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"Ctrl+Space","type":"text","marks":[{"type":"code_inline"}]},{"text":"): Temporarily expand to XL without changing default.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Theme Presets","type":"text"}]},{"type":"paragraph","content":[{"text":"Cycle through 6 built-in themes with ","type":"text"},{"text":"F2","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Theme","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Description","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Best For","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dark","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tokyo Night-inspired deep blues","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Low-light environments","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Light","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"High-contrast light background","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Bright environments","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Catppuccin","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Warm pastels, reduced eye strain","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"All-day coding","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dracula","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purple-accented dark theme","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Popular developer theme","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Nord","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Arctic-inspired cool tones","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Calm, focused work","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"High Contrast","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Maximum readability","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Accessibility needs","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"All themes validated against WCAG contrast requirements (4.5:1 minimum for text).","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Role-Aware Message Styling","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Role","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Visual Treatment","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"User","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Blue-tinted background, bold","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Assistant","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Green-tinted background","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"System","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Gray/muted background","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Orange-tinted background","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Saved Views","type":"text"}]},{"type":"paragraph","content":[{"text":"Save filter configurations to 9 slots for instant recall.","type":"text"}]},{"type":"paragraph","content":[{"text":"What Gets Saved:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Active filters (agent, workspace, time range)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Current ranking mode","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The search query","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Keyboard:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shift+1","type":"text","marks":[{"type":"code_inline"}]},{"text":" through ","type":"text"},{"text":"Shift+9","type":"text","marks":[{"type":"code_inline"}]},{"text":": Save current view","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"1","type":"text","marks":[{"type":"code_inline"}]},{"text":" through ","type":"text"},{"text":"9","type":"text","marks":[{"type":"code_inline"}]},{"text":": Load view from slot","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Via Command Palette:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"Ctrl+P","type":"text","marks":[{"type":"code_inline"}]},{"text":" → \"Save/Load view\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Views persist in ","type":"text"},{"text":"tui_state.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" across sessions.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Density Modes","type":"text"}]},{"type":"paragraph","content":[{"text":"Control lines per search result. Cycle with ","type":"text"},{"text":"Shift+D","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mode","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Lines","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Best For","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Compact","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Maximum results visible","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cozy","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Balanced view (default)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Spacious","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"8","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Detailed preview","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Bookmark System","type":"text"}]},{"type":"paragraph","content":[{"text":"Save important results with notes and tags:","type":"text"}]},{"type":"paragraph","content":[{"text":"In TUI: Press ","type":"text"},{"text":"b","type":"text","marks":[{"type":"code_inline"}]},{"text":" to bookmark, add notes and tags.","type":"text"}]},{"type":"paragraph","content":[{"text":"Bookmark Structure:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"title","type":"text","marks":[{"type":"code_inline"}]},{"text":": Short description","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"source_path","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"line_number","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"agent","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"workspace","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"note","type":"text","marks":[{"type":"code_inline"}]},{"text":": Your annotations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"tags","type":"text","marks":[{"type":"code_inline"}]},{"text":": Comma-separated labels","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"snippet","type":"text","marks":[{"type":"code_inline"}]},{"text":": Extracted content","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Storage: ","type":"text"},{"text":"~/.local/share/coding-agent-search/bookmarks.db","type":"text","marks":[{"type":"code_inline"}]},{"text":" (SQLite)","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Optional Semantic Search","type":"text"}]},{"type":"paragraph","content":[{"text":"Local-only semantic search using MiniLM (no cloud):","type":"text"}]},{"type":"paragraph","content":[{"text":"Required files","type":"text","marks":[{"type":"strong"}]},{"text":" (place in data directory):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"model.onnx","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"tokenizer.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"config.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"special_tokens_map.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"tokenizer_config.json","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"Vector index stored as ","type":"text"},{"text":"vector_index/index-minilm-384.cvvi","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"paragraph","content":[{"text":"CASS does NOT auto-download models; you must manually install them.","type":"text"}]},{"type":"paragraph","content":[{"text":"Hash Embedder Fallback:","type":"text","marks":[{"type":"strong"}]},{"text":" When MiniLM not installed, CASS uses a hash-based embedder for approximate semantic similarity.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Watch Mode","type":"text"}]},{"type":"paragraph","content":[{"text":"Real-time index updates:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cass index --watch","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Debounce:","type":"text","marks":[{"type":"strong"}]},{"text":" 2 seconds (wait for burst to settle)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Max wait:","type":"text","marks":[{"type":"strong"}]},{"text":" 5 seconds (force flush during continuous activity)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Incremental:","type":"text","marks":[{"type":"strong"}]},{"text":" Only re-scans modified files","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"TUI automatically starts watch mode in background.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Deduplication Strategy","type":"text"}]},{"type":"paragraph","content":[{"text":"CASS uses multi-layer deduplication:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Message Hash","type":"text","marks":[{"type":"strong"}]},{"text":": SHA-256 of ","type":"text"},{"text":"(role + content + timestamp)","type":"text","marks":[{"type":"code_inline"}]},{"text":" - identical messages stored once","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Conversation Fingerprint","type":"text","marks":[{"type":"strong"}]},{"text":": Hash of first N message hashes - detects duplicate files","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Search-Time Dedup","type":"text","marks":[{"type":"strong"}]},{"text":": Results deduplicated by content similarity","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Noise Filtering:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Empty messages and pure whitespace","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"System prompts (unless searching for them)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Repeated tool acknowledgments","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Performance Characteristics","type":"text"}]},{"type":"paragraph","content":[{"text":"Latency and memory depend on archive size, index readiness, model state, and whether the process is cold. Historical small-corpus timings are not deadlines for a large archive. Measure the complete command, bound each retrieval attempt, and distinguish successful results from timeout or maintenance refusal.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Response Shapes","type":"text"}]},{"type":"paragraph","content":[{"text":"Search Response:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"query\": \"error\",\n \"limit\": 10,\n \"count\": 5,\n \"total_matches\": 42,\n \"hits\": [\n {\n \"source_path\": \"/path/to/session.jsonl\",\n \"line_number\": 123,\n \"agent\": \"claude_code\",\n \"workspace\": \"/projects/myapp\",\n \"title\": \"Authentication debugging\",\n \"snippet\": \"The error occurs when...\",\n \"score\": 0.85,\n \"match_type\": \"exact\",\n \"created_at\": \"2024-01-15T10:30:00Z\"\n }\n ],\n \"_meta\": {\n \"elapsed_ms\": 12,\n \"cache_hit\": true,\n \"wildcard_fallback\": false,\n \"next_cursor\": \"eyJ...\",\n \"index_freshness\": { \"stale\": false, \"age_seconds\": 120 }\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"Aggregation Response:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"aggregations\": {\n \"agent\": {\n \"buckets\": [\n {\"key\": \"claude_code\", \"count\": 120},\n {\"key\": \"codex\", \"count\": 85}\n ],\n \"other_count\": 15\n }\n }\n}","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Environment Variables","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Variable","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CASS_DATA_DIR","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Override data directory","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CHATGPT_ENCRYPTION_KEY","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Base64 key for encrypted ChatGPT","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PI_CODING_AGENT_DIR","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Override Pi-Agent sessions path","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CASS_CACHE_SHARD_CAP","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Per-shard cache entries (default 256)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CASS_CACHE_TOTAL_CAP","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Total cached hits (default 2048)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CASS_DEBUG_CACHE_METRICS","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enable cache debug logging","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CODING_AGENT_SEARCH_NO_UPDATE_PROMPT","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Skip update checks","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Shell Completions","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cass completions bash > ~/.local/share/bash-completion/completions/cass\ncass completions zsh > \"${fpath[1]}/_cass\"\ncass completions fish > ~/.config/fish/completions/cass.fish\ncass completions powershell >> $PROFILE","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"API Contract & Versioning","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cass api-version --json\n# → { \"version\": \"0.4.0\", \"contract_version\": \"1\", \"breaking_changes\": [] }\n\ncass introspect --json\n# → Full schema: all commands, arguments, response types","type":"text"}]},{"type":"paragraph","content":[{"text":"Guaranteed Stable:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Exit codes and their meanings","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"JSON response structure for ","type":"text"},{"text":"--robot","type":"text","marks":[{"type":"code_inline"}]},{"text":" output","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Flag names and behaviors","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"_meta","type":"text","marks":[{"type":"code_inline"}]},{"text":" block format","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Integration with CASS Memory (cm)","type":"text"}]},{"type":"paragraph","content":[{"text":"CASS provides ","type":"text"},{"text":"episodic memory","type":"text","marks":[{"type":"strong"}]},{"text":" (raw sessions). CM extracts ","type":"text"},{"text":"procedural memory","type":"text","marks":[{"type":"strong"}]},{"text":" (rules and playbooks):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 1. CASS indexes raw sessions\ncass index --full\n\n# 2. Search for relevant past experience\ncass search \"authentication timeout\" --robot --limit 10\n\n# 3. CM reflects on sessions to extract rules\ncm reflect","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Troubleshooting","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Issue","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Solution","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"missing index\" / ","type":"text"},{"text":"maintenance-required","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Report the blocker; separate retrieval from authorized indexing/repair","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Stale warning","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Report the age/coverage; decide separately whether to refresh","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Empty results","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Check ","type":"text"},{"text":"budget.timed_out","type":"text","marks":[{"type":"code_inline"}]},{"text":"; then reconsider query scope if the attempt completed","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"JSON parsing errors","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"--robot-format compact","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Watch not triggering","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Check ","type":"text"},{"text":"watch_state.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", verify file event support","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reset TUI state","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cass tui --reset-state","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"Ctrl+Shift+Del","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Installation","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# One-liner install\ncurl -fsSL https://raw.githubusercontent.com/Dicklesworthstone/coding_agent_session_search/main/install.sh \\\n | bash -s -- --easy-mode --verify\n\n# Windows\nirm https://raw.githubusercontent.com/Dicklesworthstone/coding_agent_session_search/main/install.ps1 | iex","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Integration with Flywheel","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Integration","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CM","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CASS provides episodic memory, CM extracts procedural memory","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"NTM","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Robot mode flags for searching past sessions","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Agent Mail","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Search threads across agent history","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"BV","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cross-reference beads with past solutions","type":"text"}]}]}]}]}]},"metadata":{"date":"2026-11-02","name":"cass","author":"@skillopedia","source":{"stars":1199,"repo_name":"coding_agent_session_search","origin_url":"https://github.com/Dicklesworthstone/coding_agent_session_search/blob/HEAD/SKILL.md","repo_owner":"Dicklesworthstone","body_sha256":"2e5800dabf76e8cfa87a97bfc4c921606dde49cf1c8168767750f5d41a606930","cluster_key":"ef629c39955f605777abcfd812d3a894af7eb0826b27cf9248fcc2e1592f18e2","clean_bundle":{"format":"clean-skill-bundle-v1","source":"Dicklesworthstone/coding_agent_session_search/SKILL.md","text_bytes":1048461,"source_commit":"88d60aaf9c30f9022d3b63442b8acdac8de6392b","skills_sh_rank":5995,"attachment_count":98,"text_attachments":98,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"ai-agent-development","category_label":"AI"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"ai-agent-development","import_tag":"skills-sh-top20k-2026-11","description":"Coding Agent Session Search - unified CLI/TUI to index and search local coding agent history from Claude Code, Codex, Gemini, Cursor, Aider, ChatGPT, Pi-Agent, Factory, and more. Purpose-built for AI agent consumption with robot mode."}},"renderedAt":1793666615021}

CASS - Coding Agent Session Search Unified, high-performance CLI/TUI to index and search your local coding agent history. Aggregates sessions from 23 agents , including Codex, Claude Code, Gemini CLI, Cline, OpenCode, Amp, Cursor, ChatGPT, Aider, Pi-Agent, Factory (Droid), OpenHands, Antigravity, and Grok Build. CRITICAL: Robot Mode Required for AI Agents NEVER run bare - it launches an interactive TUI that blocks your session! Always use or flags for machine-readable output. --- Quick Reference for AI Agents Bounded History Retrieval For a quick project-history question, start with one scope…