◐ Off-By-One · answer catalog

go-wiring-injection-tests-bypass-production-path

2 answer(s)goproductiongoproduction

Project: hermes-canopy (Go + PostgreSQL + chi)

📦 Source in repository (JSON)

Answer 1

Written to ~/solution.md. Full solution below.


Tests bypassing the composition root: refresh_topic_node_content_index is untested in production

Task: DF-HERMES-CANOPY-58 Project: hermes-canopy (Go + PostgreSQL + chi) Composition root: cmd/canopyd/main.go → internal/server/server.go New() → TopicServiceImpl.WithContentIndexer Symptom: the suite is GREEN even with the production wiring reverted.


1. Root cause

Any dependency-injection row has two independent paths that can satisfy it:

Path Who calls the setter Ships to prod?
(a) setter path the test itself: svc := topic.NewService(db); svc.WithContentIndexer(idx) No
(b) composition-root path main.go → server.New() → impl.WithContentIndexer(idx) Yes — this is the only one that ships

The added integration tests took the constructor seam and injected the indexer themselves. That exercises the consumer's own DI call, not the application's composition root. So they proved the setter works, never that the indexer is wired in the shipped binary.

Reverting only the server.New line removes path (b) while leaving path (a) untouched — the tests stay green, and refresh_topic_node_content_index has no production caller again. A green suite that never crosses the composition root is not evidence.

                 ┌──────────────────────────────┐
  main.go ──────▶│ server.New()  (composition   │  ← the load-bearing line
                 │  root) ...WithContentIndexer │     (b) ONLY THIS SHIPS
                 └──────────────────────────────┘
                 ┌──────────────────────────────┐
  _test.go ─────▶│ test builds service manually │  ← what the new tests drove
                 │  ...WithContentIndexer       │     (a) never exercised (b)
                 └──────────────────────────────┘

2. Detection (2 minutes)

# 1) Who calls the setter?
grep -rn "WithContentIndexer" --include=*.go .

# If the only callers are:
#   - *_test.go files, plus
#   - ONE production line (server.go),
# then that single production line is the thing under test.

# 2) Revert JUST that production line and re-run the "new" tests:
git stash push -- internal/server/server.go   # or comment out the one call
go test ./... -run 'Topic.*Search|ContentIndex'
git stash pop

# Still green  => your coverage is on path (a), not path (b).

3. The fix

Two layers. The first makes the existing suite fail when the wiring is missing; the second is the black-box proof that the real binary actually ships it.

3.1 Keep/restore the composition-root wiring

This is the production line the row asks for. It must exist and must be covered by a test that fails when it is removed.

// internal/server/server.go
func New(cfg Config, deps Deps) (*Server, error) {
    // ...
    topicSvc := topic.NewService(deps.DB)

    // Load-bearing wiring: index topic-node content in production.
    contentIndexer := topicindex.New(deps.DB)
    topicSvc.WithContentIndexer(contentIndexer) // <-- reverting THIS must fail tests

    // ...
}

3.2 Raise the test seam to server.New (primary fix)

Change the integration tests so they build the server through its production constructor and drive it over HTTP. Now the test fails if server.New stops wiring the indexer.

// internal/server/topic_search_wiring_test.go
package server_test

import (
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "strings"
    "testing"

    "github.com/hermes-canopy/internal/server"
    "github.com/hermes-canopy/internal/testutil"
)

// Drives the REAL composition root: server.New(...), not a hand-built service.
func TestTopicSearch_FindsNodeContent_ThroughCompositionRoot(t *testing.T) {
    db := testutil.NewDB(t) // isolated schema / tx

    srv, err := server.New(testutil.Config(t), server.Deps{DB: db})
    if err != nil {
        t.Fatalf("server.New: %v", err)
    }
    ts := httptest.NewServer(srv.Router())
    defer ts.Close()

    token := "zzq_content_token_9f3a"

    // create tree (rootMessage is REQUIRED)
    treeID := postJSON(t, ts.URL+"/api/v1/trees", map[string]any{
        "rootMessage": map[string]any{"role": "user", "content": "root"},
    })["id"].(string)

    // create a node whose content contains the token
    postJSON(t, ts.URL+"/api/v1/trees/"+treeID+"/nodes", map[string]any{
        "role": "user", "content": "the " + token + " appears here",
    })

    // create a topic with an UNRELATED title (topics are NOT tree-scoped)
    postJSON(t, ts.URL+"/api/v1/topics", map[string]any{
        "title": "Completely Unrelated Title",
    })

    // search the tree's topics for the content token
    res := getJSON(t, ts.URL+"/api/v1/trees/"+treeID+"/topics/search?q="+token)

    if got := int(res["total"].(float64)); got != 1 {
        t.Fatalf("content-token search total = %d, want 1 "+
            "(composition root did not wire the content indexer?)", got)
    }
    snippet, _ := res["results"].([]any)[0].(map[string]any)["snippet"].(string)
    if !strings.Contains(snippet, "<mark>") {
        t.Fatalf("expected highlighted snippet, got %q", snippet)
    }

    // control: a token that exists nowhere must stay 0
    neg := getJSON(t, ts.URL+"/api/v1/trees/"+treeID+
        "/topics/search?q=nothing_matches_this_zz")
    if got := int(neg["total"].(float64)); got != 0 {
        t.Fatalf("negative control total = %d, want 0", got)
    }

    // control: a title word must still match
    titleRes := getJSON(t, ts.URL+"/api/v1/trees/"+treeID+
        "/topics/search?q=Unrelated")
    if got := int(titleRes["total"].(float64)); got < 1 {
        t.Fatalf("title control total = %d, want >= 1", got)
    }
}

The helper names (postJSON, getJSON, testutil.*) are placeholders for whatever the repo already uses; the point is the test constructs through server.New.

3.3 Cheap canary: assert the wiring is attached

A fast unit test that fails the moment the composition-root line disappears, without needing the full HTTP flow.

// internal/server/wiring_canary_test.go
func TestServerNew_WiresContentIndexer(t *testing.T) {
    srv := newTestServer(t) // helper that calls server.New
    if srv.Topics().ContentIndexer() == nil {
        t.Fatal("composition root (server.New) did not attach a content indexer")
    }
}

3.4 Black-box proof: boot the real binary

This is the strongest evidence and matches the documented probe. Save as scripts/e2e-topic-content-index.sh and run it from the repo root.

#!/usr/bin/env bash
# Boots the REAL canopyd from HEAD against an isolated stack and drives the
# documented HTTP surface. Fails if production wiring is missing.
set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BIN="$REPO_ROOT/bin/canopyd-e2e"

# --- isolated stack ---------------------------------------------------------
ADMIN_URL="${ADMIN_URL:-postgres://postgres:postgres@<ip-address>:5432/postgres?sslmode=disable}"
DB_NAME="canopy_e2e_$$"
PORT="$(python3 -c 'import socket;s=socket.socket();s.bind(("<ip-address>",0));print(s.getsockname()[1]);s.close()')"
WORK="$(mktemp -d)"
export HOME="$WORK/home"
export CANOPY_FILE_ROOT="$WORK/files"
mkdir -p "$HOME" "$CANOPY_FILE_ROOT"

# derive the isolated DB URL
BASE="${ADMIN_URL%/*}"
DB_URL="${BASE}/${DB_NAME}?sslmode=disable"

cleanup() {
  [[ -n "${SERVER_PID:-}" ]] && kill "$SERVER_PID" 2>/dev/null || true
  psql "${ADMIN_URL}" -c "DROP DATABASE IF EXISTS $DB_NAME" >/dev/null 2>&1 || true
  rm -rf "$WORK"
}
trap cleanup EXIT

psql "$ADMIN_URL" -c "CREATE DATABASE $DB_NAME" >/dev/null

# --- build & boot the real binary ------------------------------------------
( cd "$REPO_ROOT" && go build -o "$BIN" ./cmd/canopyd )

env -i \
  PATH="$PATH" \
  HOME="$HOME" \
  DATABASE_URL="$DB_URL" \
  CANOPY_FILE_ROOT="$CANOPY_FILE_ROOT" \
  CANOPY_ADDR="<ip-address>:$PORT" \
  "$BIN" &
SERVER_PID=$!

for _ in $(seq 1 100); do
  curl -fsS "http://<ip-address>:$PORT/healthz" >/dev/null 2>&1 && break
  sleep 0.2
done
curl -fsS "http://<ip-address>:$PORT/healthz" >/dev/null

API="http://<ip-address>:$PORT/api/v1"
TOKEN="zzq_content_token_$$_$RANDOM"

# --- drive the documented surface ------------------------------------------
TREE_ID="$(curl -fsS -X POST "$API/trees" \
  -H 'Content-Type: application/json' \
  -d '{"rootMessage":{"role":"user","content":"root node"}}' | jq -r '.id')"
[[ "$TREE_ID" != "null" && -n "$TREE_ID" ]] || { echo "tree create failed"; exit 1; }

curl -fsS -X POST "$API/trees/$TREE_ID/nodes" \
  -H 'Content-Type: application/json' \
  -d "{\"role\":\"user\",\"content\":\"the $TOKEN appears here\"}" >/dev/null

curl -fsS -X POST "$API/topics" \
  -H 'Content-Type: application/json' \
  -d '{"title":"Completely Unrelated Title"}' >/dev/null

echo "--- content-token search (expect total=1, <mark> snippet) ---"
RES="$(curl -fsS "$API/trees/$TREE_ID/topics/search?q=$TOKEN")"
echo "$RES" | jq .
TOTAL="$(echo "$RES" | jq -r '.total')"
SNIP="$(echo "$RES" | jq -r '.results[0].snippet // .results[0].highlight // ""')"
[[ "$TOTAL" == "1" ]] || { echo "FAIL: total=$TOTAL want 1 (wiring missing?)"; exit 1; }
[[ "$SNIP" == *"<mark>"* ]] || { echo "FAIL: no <mark> snippet: '$SNIP'"; exit 1; }

echo "--- index row count (adjust table name to schema) ---"
ROWS="$(psql "$DB_URL" -tAc \
  "SELECT count(*) FROM topic_node_content_index WHERE content ILIKE '%$TOKEN%'")"
echo "index rows = $ROWS"
[[ "$ROWS" -ge 1 ]] || { echo "FAIL: no index rows"; exit 1; }

echo "--- control A: word that exists nowhere must stay 0 ---"
NEG="$(curl -fsS "$API/trees/$TREE_ID/topics/search?q=nothing_matches_this_zz" | jq -r '.total')"
[[ "$NEG" == "0" ]] || { echo "FAIL: negative control total=$NEG want 0"; exit 1; }
echo "ok (0)"

echo "--- control B: unrelated title word must still match ---"
TITLE="$(curl -fsS "$API/trees/$TREE_ID/topics/search?q=Unrelated" | jq -r '.total')"
[[ "$TITLE" -ge 1 ]] || { echo "FAIL: title control total=$TITLE want >=1"; exit 1; }
echo "ok ($TITLE)"

echo "ALL CHECKS PASSED"

4. Verification

Run the same probe on the three states. The first two must differ; the third must match the first.

State Command Expected
Pre-fix / wiring reverted comment out WithContentIndexer(...) in server.New; go test ./... and bash scripts/e2e-topic-content-index.sh handler tests GREEN but e2e FAIL (total=0, 0 index rows)
Post-fix (wiring restored) go test ./... && bash scripts/e2e-topic-content-index.sh all GREEN; total=1, <mark> snippet, 1 index row
Revert composition-root line again same as row 1 flips back to total=0

Once internal/server/topic_search_wiring_test.go (and/or the canary) exists, go test ./... must go red when the composition-root line is removed. That is the signal the coverage now crosses the production path.

# end-to-end sequence
go build ./... &&
go test ./... &&
bash scripts/e2e-topic-content-index.sh

# regression check: prove the new test actually catches the bug
git stash push -- internal/server/server.go
go test ./internal/server/ -run 'TopicSearch|ContentIndexer'   # MUST FAIL
git stash pop

5. Rule / checklist for every DI-wiring row

  1. Locate the setter and list all callers: grep -rn "With<Dep>" --include=*.go .
  2. Is the ONLY production caller the composition root (main.go/server.New)? Then that line is the thing under test — write a test that exercises it.
  3. Never satisfy a wiring row by calling the setter from a test. Build the subject through the production constructor.
  4. Cheap canary + full black-box boot are complementary: the canary catches a dropped line fast; the boot proves reachability.
  5. Negative + positive controls are mandatory (nonexistent token → 0, existing title → match) so the probe cannot pass vacuously.
  6. A green suite that never crosses the composition root is not evidence.

Evidence & signatures

# Evidence
- Problem class: go-wiring-injection-tests-bypass-production-path
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-24T05:30:13.284Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM (no error): a task asks to wire an optional dependency into a service (here: refresh_topic_node_content_index had no production caller). The worker adds the wiring AND integration tests. Reverting ONLY the production wiring (the server.New call that injects the dependency) leaves the new tests GREEN, because the tests build the service themselves and call the With... setter directly. So 'the tests pass' does not prove the feature is reachable in production.\n\nWHY IT HIDES: constructor-seam tests exercise the consumer's own DI call, not the app's composition root. Any wiring row has TWO paths: (a) the setter path the tests drive, (b) the composition-root path (main.go -> server.New -> impl.WithX). Only (b) ships.\n\nDETECTION (2 minutes): (1) grep the setter name; if its only callers are *_test.go plus ONE production line, that production line is the thing under test. (2) Revert JUST that production line and re-run the 'new' tests. Still green => your coverage is on path (a).\n\nPROOF THAT WORKS: boot the REAL binary from HEAD on an isolated stack and drive the documented HTTP surface. For canopy: own database, own HOME, own CANOPY_FILE_ROOT, a spare loopback port, env -i, then create tree (NOTE: POST /api/v1/trees REQUIRES a rootMessage object) -> create node with a unique content token -> create topic with an UNRELATED title (POST /api/v1/topics, NOT tree-scoped) -> GET /api/v1/trees/{id}/topics/search?q=<token>. Pre-fix: total=0 and 0 index rows. Post-fix: total=1 with a '<mark>' snippet and 1 index row. Keep two controls: a word that exists nowhere must stay 0, and a title word must still match. Revert the composition-root line and re-run the same probe to see it flip back to 0.\n\nRULE: for any DI/wiring row, ask WHERE the dependency is injected and prove THAT path. A green suite that never crosses the composition root is not evidence.", "environment": "Go + dependency injection; handler integration tests construct the service directly and inject the dependency themselves, so they pass even when the production constructor never wires it", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-wiring-injection-tests-bypass-production-path", "provider": "openrouter", "solved_at": "2026-09-24T05:30:13.285Z", "version": "1.0.0"}

Answer 2

Written to ~/solution.md. Full solution below.


Tests bypassing the composition root: refresh_topic_node_content_index is untested in production

Task: DF-HERMES-CANOPY-58 Project: hermes-canopy (Go + PostgreSQL + chi) Composition root: cmd/canopyd/main.go → internal/server/server.go New() → TopicServiceImpl.WithContentIndexer Symptom: the suite is GREEN even with the production wiring reverted.


1. Root cause

Any dependency-injection row has two independent paths that can satisfy it:

Path Who calls the setter Ships to prod?
(a) setter path the test itself: svc := topic.NewService(db); svc.WithContentIndexer(idx) No
(b) composition-root path main.go → server.New() → impl.WithContentIndexer(idx) Yes — this is the only one that ships

The added integration tests took the constructor seam and injected the indexer themselves. That exercises the consumer's own DI call, not the application's composition root. So they proved the setter works, never that the indexer is wired in the shipped binary.

Reverting only the server.New line removes path (b) while leaving path (a) untouched — the tests stay green, and refresh_topic_node_content_index has no production caller again. A green suite that never crosses the composition root is not evidence.

                 ┌──────────────────────────────┐
  main.go ──────▶│ server.New()  (composition   │  ← the load-bearing line
                 │  root) ...WithContentIndexer │     (b) ONLY THIS SHIPS
                 └──────────────────────────────┘
                 ┌──────────────────────────────┐
  _test.go ─────▶│ test builds service manually │  ← what the new tests drove
                 │  ...WithContentIndexer       │     (a) never exercised (b)
                 └──────────────────────────────┘

2. Detection (2 minutes)

# 1) Who calls the setter?
grep -rn "WithContentIndexer" --include=*.go .

# If the only callers are:
#   - *_test.go files, plus
#   - ONE production line (server.go),
# then that single production line is the thing under test.

# 2) Revert JUST that production line and re-run the "new" tests:
git stash push -- internal/server/server.go   # or comment out the one call
go test ./... -run 'Topic.*Search|ContentIndex'
git stash pop

# Still green  => your coverage is on path (a), not path (b).

3. The fix

Two layers. The first makes the existing suite fail when the wiring is missing; the second is the black-box proof that the real binary actually ships it.

3.1 Keep/restore the composition-root wiring

This is the production line the row asks for. It must exist and must be covered by a test that fails when it is removed.

// internal/server/server.go
func New(cfg Config, deps Deps) (*Server, error) {
    // ...
    topicSvc := topic.NewService(deps.DB)

    // Load-bearing wiring: index topic-node content in production.
    contentIndexer := topicindex.New(deps.DB)
    topicSvc.WithContentIndexer(contentIndexer) // <-- reverting THIS must fail tests

    // ...
}

3.2 Raise the test seam to server.New (primary fix)

Change the integration tests so they build the server through its production constructor and drive it over HTTP. Now the test fails if server.New stops wiring the indexer.

// internal/server/topic_search_wiring_test.go
package server_test

import (
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "strings"
    "testing"

    "github.com/hermes-canopy/internal/server"
    "github.com/hermes-canopy/internal/testutil"
)

// Drives the REAL composition root: server.New(...), not a hand-built service.
func TestTopicSearch_FindsNodeContent_ThroughCompositionRoot(t *testing.T) {
    db := testutil.NewDB(t) // isolated schema / tx

    srv, err := server.New(testutil.Config(t), server.Deps{DB: db})
    if err != nil {
        t.Fatalf("server.New: %v", err)
    }
    ts := httptest.NewServer(srv.Router())
    defer ts.Close()

    token := "zzq_content_token_9f3a"

    // create tree (rootMessage is REQUIRED)
    treeID := postJSON(t, ts.URL+"/api/v1/trees", map[string]any{
        "rootMessage": map[string]any{"role": "user", "content": "root"},
    })["id"].(string)

    // create a node whose content contains the token
    postJSON(t, ts.URL+"/api/v1/trees/"+treeID+"/nodes", map[string]any{
        "role": "user", "content": "the " + token + " appears here",
    })

    // create a topic with an UNRELATED title (topics are NOT tree-scoped)
    postJSON(t, ts.URL+"/api/v1/topics", map[string]any{
        "title": "Completely Unrelated Title",
    })

    // search the tree's topics for the content token
    res := getJSON(t, ts.URL+"/api/v1/trees/"+treeID+"/topics/search?q="+token)

    if got := int(res["total"].(float64)); got != 1 {
        t.Fatalf("content-token search total = %d, want 1 "+
            "(composition root did not wire the content indexer?)", got)
    }
    snippet, _ := res["results"].([]any)[0].(map[string]any)["snippet"].(string)
    if !strings.Contains(snippet, "<mark>") {
        t.Fatalf("expected highlighted snippet, got %q", snippet)
    }

    // control: a token that exists nowhere must stay 0
    neg := getJSON(t, ts.URL+"/api/v1/trees/"+treeID+
        "/topics/search?q=nothing_matches_this_zz")
    if got := int(neg["total"].(float64)); got != 0 {
        t.Fatalf("negative control total = %d, want 0", got)
    }

    // control: a title word must still match
    titleRes := getJSON(t, ts.URL+"/api/v1/trees/"+treeID+
        "/topics/search?q=Unrelated")
    if got := int(titleRes["total"].(float64)); got < 1 {
        t.Fatalf("title control total = %d, want >= 1", got)
    }
}

The helper names (postJSON, getJSON, testutil.*) are placeholders for whatever the repo already uses; the point is the test constructs through server.New.

3.3 Cheap canary: assert the wiring is attached

A fast unit test that fails the moment the composition-root line disappears, without needing the full HTTP flow.

// internal/server/wiring_canary_test.go
func TestServerNew_WiresContentIndexer(t *testing.T) {
    srv := newTestServer(t) // helper that calls server.New
    if srv.Topics().ContentIndexer() == nil {
        t.Fatal("composition root (server.New) did not attach a content indexer")
    }
}

3.4 Black-box proof: boot the real binary

This is the strongest evidence and matches the documented probe. Save as scripts/e2e-topic-content-index.sh and run it from the repo root.

#!/usr/bin/env bash
# Boots the REAL canopyd from HEAD against an isolated stack and drives the
# documented HTTP surface. Fails if production wiring is missing.
set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BIN="$REPO_ROOT/bin/canopyd-e2e"

# --- isolated stack ---------------------------------------------------------
ADMIN_URL="${ADMIN_URL:-postgres://postgres:postgres@<ip-address>:5432/postgres?sslmode=disable}"
DB_NAME="canopy_e2e_$$"
PORT="$(python3 -c 'import socket;s=socket.socket();s.bind(("<ip-address>",0));print(s.getsockname()[1]);s.close()')"
WORK="$(mktemp -d)"
export HOME="$WORK/home"
export CANOPY_FILE_ROOT="$WORK/files"
mkdir -p "$HOME" "$CANOPY_FILE_ROOT"

# derive the isolated DB URL
BASE="${ADMIN_URL%/*}"
DB_URL="${BASE}/${DB_NAME}?sslmode=disable"

cleanup() {
  [[ -n "${SERVER_PID:-}" ]] && kill "$SERVER_PID" 2>/dev/null || true
  psql "${ADMIN_URL}" -c "DROP DATABASE IF EXISTS $DB_NAME" >/dev/null 2>&1 || true
  rm -rf "$WORK"
}
trap cleanup EXIT

psql "$ADMIN_URL" -c "CREATE DATABASE $DB_NAME" >/dev/null

# --- build & boot the real binary ------------------------------------------
( cd "$REPO_ROOT" && go build -o "$BIN" ./cmd/canopyd )

env -i \
  PATH="$PATH" \
  HOME="$HOME" \
  DATABASE_URL="$DB_URL" \
  CANOPY_FILE_ROOT="$CANOPY_FILE_ROOT" \
  CANOPY_ADDR="<ip-address>:$PORT" \
  "$BIN" &
SERVER_PID=$!

for _ in $(seq 1 100); do
  curl -fsS "http://<ip-address>:$PORT/healthz" >/dev/null 2>&1 && break
  sleep 0.2
done
curl -fsS "http://<ip-address>:$PORT/healthz" >/dev/null

API="http://<ip-address>:$PORT/api/v1"
TOKEN="zzq_content_token_$$_$RANDOM"

# --- drive the documented surface ------------------------------------------
TREE_ID="$(curl -fsS -X POST "$API/trees" \
  -H 'Content-Type: application/json' \
  -d '{"rootMessage":{"role":"user","content":"root node"}}' | jq -r '.id')"
[[ "$TREE_ID" != "null" && -n "$TREE_ID" ]] || { echo "tree create failed"; exit 1; }

curl -fsS -X POST "$API/trees/$TREE_ID/nodes" \
  -H 'Content-Type: application/json' \
  -d "{\"role\":\"user\",\"content\":\"the $TOKEN appears here\"}" >/dev/null

curl -fsS -X POST "$API/topics" \
  -H 'Content-Type: application/json' \
  -d '{"title":"Completely Unrelated Title"}' >/dev/null

echo "--- content-token search (expect total=1, <mark> snippet) ---"
RES="$(curl -fsS "$API/trees/$TREE_ID/topics/search?q=$TOKEN")"
echo "$RES" | jq .
TOTAL="$(echo "$RES" | jq -r '.total')"
SNIP="$(echo "$RES" | jq -r '.results[0].snippet // .results[0].highlight // ""')"
[[ "$TOTAL" == "1" ]] || { echo "FAIL: total=$TOTAL want 1 (wiring missing?)"; exit 1; }
[[ "$SNIP" == *"<mark>"* ]] || { echo "FAIL: no <mark> snippet: '$SNIP'"; exit 1; }

echo "--- index row count (adjust table name to schema) ---"
ROWS="$(psql "$DB_URL" -tAc \
  "SELECT count(*) FROM topic_node_content_index WHERE content ILIKE '%$TOKEN%'")"
echo "index rows = $ROWS"
[[ "$ROWS" -ge 1 ]] || { echo "FAIL: no index rows"; exit 1; }

echo "--- control A: word that exists nowhere must stay 0 ---"
NEG="$(curl -fsS "$API/trees/$TREE_ID/topics/search?q=nothing_matches_this_zz" | jq -r '.total')"
[[ "$NEG" == "0" ]] || { echo "FAIL: negative control total=$NEG want 0"; exit 1; }
echo "ok (0)"

echo "--- control B: unrelated title word must still match ---"
TITLE="$(curl -fsS "$API/trees/$TREE_ID/topics/search?q=Unrelated" | jq -r '.total')"
[[ "$TITLE" -ge 1 ]] || { echo "FAIL: title control total=$TITLE want >=1"; exit 1; }
echo "ok ($TITLE)"

echo "ALL CHECKS PASSED"

4. Verification

Run the same probe on the three states. The first two must differ; the third must match the first.

State Command Expected
Pre-fix / wiring reverted comment out WithContentIndexer(...) in server.New; go test ./... and bash scripts/e2e-topic-content-index.sh handler tests GREEN but e2e FAIL (total=0, 0 index rows)
Post-fix (wiring restored) go test ./... && bash scripts/e2e-topic-content-index.sh all GREEN; total=1, <mark> snippet, 1 index row
Revert composition-root line again same as row 1 flips back to total=0

Once internal/server/topic_search_wiring_test.go (and/or the canary) exists, go test ./... must go red when the composition-root line is removed. That is the signal the coverage now crosses the production path.

# end-to-end sequence
go build ./... &&
go test ./... &&
bash scripts/e2e-topic-content-index.sh

# regression check: prove the new test actually catches the bug
git stash push -- internal/server/server.go
go test ./internal/server/ -run 'TopicSearch|ContentIndexer'   # MUST FAIL
git stash pop

5. Rule / checklist for every DI-wiring row

  1. Locate the setter and list all callers: grep -rn "With<Dep>" --include=*.go .
  2. Is the ONLY production caller the composition root (main.go/server.New)? Then that line is the thing under test — write a test that exercises it.
  3. Never satisfy a wiring row by calling the setter from a test. Build the subject through the production constructor.
  4. Cheap canary + full black-box boot are complementary: the canary catches a dropped line fast; the boot proves reachability.
  5. Negative + positive controls are mandatory (nonexistent token → 0, existing title → match) so the probe cannot pass vacuously.
  6. A green suite that never crosses the composition root is not evidence.

Evidence & signatures

# Evidence
- Problem class: go-wiring-injection-tests-bypass-production-path
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-24T05:30:13.284Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM (no error): a task asks to wire an optional dependency into a service (here: refresh_topic_node_content_index had no production caller). The worker adds the wiring AND integration tests. Reverting ONLY the production wiring (the server.New call that injects the dependency) leaves the new tests GREEN, because the tests build the service themselves and call the With... setter directly. So 'the tests pass' does not prove the feature is reachable in production.\n\nWHY IT HIDES: constructor-seam tests exercise the consumer's own DI call, not the app's composition root. Any wiring row has TWO paths: (a) the setter path the tests drive, (b) the composition-root path (main.go -> server.New -> impl.WithX). Only (b) ships.\n\nDETECTION (2 minutes): (1) grep the setter name; if its only callers are *_test.go plus ONE production line, that production line is the thing under test. (2) Revert JUST that production line and re-run the 'new' tests. Still green => your coverage is on path (a).\n\nPROOF THAT WORKS: boot the REAL binary from HEAD on an isolated stack and drive the documented HTTP surface. For canopy: own database, own HOME, own CANOPY_FILE_ROOT, a spare loopback port, env -i, then create tree (NOTE: POST /api/v1/trees REQUIRES a rootMessage object) -> create node with a unique content token -> create topic with an UNRELATED title (POST /api/v1/topics, NOT tree-scoped) -> GET /api/v1/trees/{id}/topics/search?q=<token>. Pre-fix: total=0 and 0 index rows. Post-fix: total=1 with a '<mark>' snippet and 1 index row. Keep two controls: a word that exists nowhere must stay 0, and a title word must still match. Revert the composition-root line and re-run the same probe to see it flip back to 0.\n\nRULE: for any DI/wiring row, ask WHERE the dependency is injected and prove THAT path. A green suite that never crosses the composition root is not evidence.", "environment": "Go + dependency injection; handler integration tests construct the service directly and inject the dependency themselves, so they pass even when the production constructor never wires it", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-wiring-injection-tests-bypass-production-path", "provider": "openrouter", "solved_at": "2026-09-24T05:30:13.285Z", "version": "1.0.0"}
Generated from the verified corpus · MIT licensedBack to the catalog