From f24907e7dc5fad34cb83aed245ab6c7c643956db Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 18 Sep 2026 09:28:33 +0400 Subject: [PATCH 1/9] Fix Pi upstream evidence source --- internal/harness/builtin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/harness/builtin.go b/internal/harness/builtin.go index 4d3e803..eb0a5f9 100644 --- a/internal/harness/builtin.go +++ b/internal/harness/builtin.go @@ -34,7 +34,7 @@ type piHarness struct{} func (piHarness) ID() string { return "pi" } func (piHarness) Detect(ctx context.Context) (Capabilities, error) { p, err := exec.LookPath("pi") - return Capabilities{ID: "pi", Available: err == nil, Executable: p, Integration: "JSONL RPC: pi --mode rpc --no-session", StructuredOutput: true, SessionProtocol: true, EvidenceSources: []string{"earendil-works/pi packages/coding-agent/docs/rpc.md"}}, nil + return Capabilities{ID: "pi", Available: err == nil, Executable: p, Integration: "JSONL RPC: pi --mode rpc --no-session", StructuredOutput: true, SessionProtocol: true, EvidenceSources: []string{"mitsuhiko/pi-mono packages/coding-agent/docs/rpc.md"}}, nil } func (piHarness) Analyze(ctx context.Context, req AnalysisRequest) (AnalysisResult, error) { p, err := exec.LookPath("pi") From 7cda2e1b4f7aa1c45856b79d254d7cf2606bfa5c Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 18 Sep 2026 09:28:52 +0400 Subject: [PATCH 2/9] Refresh Pi harness provenance --- docs/harnesses.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/harnesses.md b/docs/harnesses.md index 871bab0..8182ac2 100644 --- a/docs/harnesses.md +++ b/docs/harnesses.md @@ -2,14 +2,14 @@ Harnesses interpret already-collected evidence. They are not evidence collectors and cannot promote their output to FACT. -The table below records the upstream repository/source inspected during the initial implementation. The point is to make integration claims auditable rather than guessed. +The table below records the upstream repository/source inspected during the initial implementation. The point is to make integration claims auditable rather than guessed. Pi repository provenance was refreshed on **2026-09-18** after its upstream ownership move. | ID | Official/current upstream inspected | Verified mechanism used | Notes | |---|---|---|---| | `codex` | `openai/codex` — `codex-rs/exec/src/cli.rs`, `exec_events.rs` | `codex exec --json --ephemeral --skip-git-repo-check -` | CLI source documents non-interactive exec, JSONL, ephemeral sessions and stdin prompt `-`. | | `claude-code` | `anthropics/claude-code` — release feed and `plugins/plugin-dev` hook docs | print mode with `--output-format stream-json` | Upstream also exposes hooks including PreToolUse/PostToolUse/Stop/Session lifecycle events. WhyThis uses one-shot synthesis, not hooks. | | `opencode` | `anomalyco/opencode` — `packages/web/src/content/docs/cli.mdx` | `opencode run --format json` | The former `opencode-ai/opencode` repository is archived; the active repository inspected is `anomalyco/opencode`. Docs also expose a headless `serve` backend. | -| `pi` | `earendil-works/pi` — `packages/coding-agent/docs/rpc.md` | `pi --mode rpc --no-session` | Strict JSONL RPC over stdin/stdout; WhyThis sends a `prompt` command and consumes events until `agent_end`. The repository is the current destination of the former `badlogic/pi-mono` project. | +| `pi` | `mitsuhiko/pi-mono` — `packages/coding-agent/docs/rpc.md` | `pi --mode rpc --no-session` | Strict JSONL RPC over stdin/stdout; WhyThis sends a `prompt` command and consumes events until `agent_end`. The current package is `@mariozechner/pi-coding-agent`; the upstream project has moved owners over time, so capability evidence points at the current canonical repository. | | `gemini` | `google-gemini/gemini-cli` — `docs/reference/configuration.md` | `gemini -p ... --output-format stream-json` | Upstream documents `json` and streaming `stream-json` non-interactive output. | | `aider` | `Aider-AI/aider` — `aider/args.py` and config docs | `aider --message-file --yes-always` | `--message-file` is documented as send/process/exit. WhyThis runs synthesis in a temporary directory to isolate it from the analyzed repo. | | `goose` | `aaif-goose/goose` — `crates/goose-cli/src/cli.rs` and headless docs | `goose run --text ... --output-format stream-json --no-session` | CLI source defines text input, JSON/stream-JSON output and no-session automation mode. | @@ -27,7 +27,6 @@ For subprocess-based synthesis WhyThis creates a temporary working directory and Availability means the integration surface was detected locally; it does not mean provider credentials are configured. - ## External adapters The built-ins are not a closed list. `pkg/harness` exposes the public `Adapter`, `Capabilities`, `AnalysisRequest` and `AnalysisResult` types so external Go modules can integrate additional harnesses without importing internal packages. See [`adapter-development.md`](adapter-development.md). From cd55096b50f06d3662d253706923a60c345f35b7 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 18 Sep 2026 09:29:14 +0400 Subject: [PATCH 3/9] Refresh GitHub Actions toolchain --- .github/workflows/ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83a8fe4..17e5842 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,7 @@ name: CI on: push: - branches: [main, "feat/**"] + branches: [main, "feat/**", "fix/**"] pull_request: permissions: contents: read @@ -9,10 +9,10 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v7 with: go-version: '1.27.1' cache: true @@ -37,8 +37,8 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 with: go-version: '1.27.1' cache: true @@ -53,8 +53,8 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 with: go-version: '1.27.1' cache: true From 7f3a53598089be9f4007a9bdba5092d922c378d7 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 18 Sep 2026 09:29:27 +0400 Subject: [PATCH 4/9] Align research notes with current symbol indexing --- docs/research.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/research.md b/docs/research.md index 3c49992..46668d8 100644 --- a/docs/research.md +++ b/docs/research.md @@ -16,4 +16,4 @@ The GitHub search did not reveal an established project with the exact WhyThis c 2. Historical metrics/risk remain deterministic. 3. GitHub discussion is evidence only when fetched and preserved with provenance. 4. AI is a semantic interpreter behind a `--no-ai`-complete deterministic path. -5. Symbol identity is not overclaimed: current support starts with pickaxe/text history, with language-aware identity tracking left for later work. +5. Symbol identity is not overclaimed. The initial design used pickaxe/text history as the portable fallback; the current implementation also uses Go AST declarations and `git log -L` for Go symbols, while non-Go and deleted-symbol paths retain the textual fallback. From 461f06116663574c3ec384fa02eb47b10db40475 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 18 Sep 2026 09:33:26 +0400 Subject: [PATCH 5/9] Refresh release workflow actions --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7fc64ec..8410ff9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,8 +17,8 @@ jobs: - { goos: windows, goarch: arm64 } runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 with: go-version: '1.27.1' - run: go mod download From 50dc4b9da58627fc407afb85edb724ea9507d07d Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 18 Sep 2026 09:33:44 +0400 Subject: [PATCH 6/9] Refresh PR archaeology workflow actions --- .github/workflows/whythis-pr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/whythis-pr.yml b/.github/workflows/whythis-pr.yml index e695357..253d1ad 100644 --- a/.github/workflows/whythis-pr.yml +++ b/.github/workflows/whythis-pr.yml @@ -30,10 +30,10 @@ jobs: COMMENT_ENABLED: ${{ (github.event_name == 'workflow_dispatch' && inputs.comment) || (github.event_name == 'pull_request' && vars.WHYTHIS_AUTO_COMMENT == 'true') }} RISK_THRESHOLD: ${{ inputs.risk_threshold || vars.WHYTHIS_RISK_THRESHOLD || '50' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v7 with: go-version: '1.27.1' cache: true From 14cfb5e833e052f646153b1371c8e204ea9b7d8b Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 18 Sep 2026 09:36:05 +0400 Subject: [PATCH 7/9] Fix Aider one-shot confirmation flag --- internal/harness/builtin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/harness/builtin.go b/internal/harness/builtin.go index eb0a5f9..bea82b6 100644 --- a/internal/harness/builtin.go +++ b/internal/harness/builtin.go @@ -19,7 +19,7 @@ func builtins() []Harness { commandHarness{id: "opencode", binary: "opencode", integration: "process: opencode run --format json", structured: true, sources: []string{"anomalyco/opencode packages/web/src/content/docs/cli.mdx"}, args: func(_ string, p string) []string { return []string{"run", "--format", "json", p} }}, piHarness{}, commandHarness{id: "gemini", binary: "gemini", integration: "process: gemini -p + stream-json", structured: true, sources: []string{"google-gemini/gemini-cli docs/reference/configuration.md"}, args: func(_ string, p string) []string { return []string{"-p", p, "--output-format", "stream-json"} }}, - commandHarness{id: "aider", binary: "aider", integration: "process: --message-file (one-shot)", structured: false, sources: []string{"Aider-AI/aider aider/args.py"}, args: func(f string, _ string) []string { return []string{"--message-file", f, "--yes-always"} }}, + commandHarness{id: "aider", binary: "aider", integration: "process: --message-file (one-shot)", structured: false, sources: []string{"Aider-AI/aider aider/website/docs/scripting.md"}, args: func(f string, _ string) []string { return []string{"--message-file", f, "--yes"} }}, commandHarness{id: "goose", binary: "goose", integration: "process: goose run --text + stream-json", structured: true, sources: []string{"aaif-goose/goose crates/goose-cli/src/cli.rs"}, args: func(_ string, p string) []string { return []string{"run", "--text", p, "--output-format", "stream-json", "--no-session"} }}, From f2a87ea0911684779bc213c34c9e017d9e7af394 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 18 Sep 2026 09:36:23 +0400 Subject: [PATCH 8/9] Correct Aider documented invocation --- docs/harnesses.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/harnesses.md b/docs/harnesses.md index 8182ac2..75164ab 100644 --- a/docs/harnesses.md +++ b/docs/harnesses.md @@ -11,7 +11,7 @@ The table below records the upstream repository/source inspected during the init | `opencode` | `anomalyco/opencode` — `packages/web/src/content/docs/cli.mdx` | `opencode run --format json` | The former `opencode-ai/opencode` repository is archived; the active repository inspected is `anomalyco/opencode`. Docs also expose a headless `serve` backend. | | `pi` | `mitsuhiko/pi-mono` — `packages/coding-agent/docs/rpc.md` | `pi --mode rpc --no-session` | Strict JSONL RPC over stdin/stdout; WhyThis sends a `prompt` command and consumes events until `agent_end`. The current package is `@mariozechner/pi-coding-agent`; the upstream project has moved owners over time, so capability evidence points at the current canonical repository. | | `gemini` | `google-gemini/gemini-cli` — `docs/reference/configuration.md` | `gemini -p ... --output-format stream-json` | Upstream documents `json` and streaming `stream-json` non-interactive output. | -| `aider` | `Aider-AI/aider` — `aider/args.py` and config docs | `aider --message-file --yes-always` | `--message-file` is documented as send/process/exit. WhyThis runs synthesis in a temporary directory to isolate it from the analyzed repo. | +| `aider` | `Aider-AI/aider` — `aider/website/docs/scripting.md` | `aider --message-file --yes` | `--message-file` is documented as send/process/exit and `--yes` is the documented non-interactive confirmation flag. WhyThis runs synthesis in a temporary directory to isolate it from the analyzed repo. | | `goose` | `aaif-goose/goose` — `crates/goose-cli/src/cli.rs` and headless docs | `goose run --text ... --output-format stream-json --no-session` | CLI source defines text input, JSON/stream-JSON output and no-session automation mode. | | `cline` | `cline/cline` — `apps/cli/README.md`, `apps/cli/src/main.ts` | `cline --json ` | Current Cline CLI explicitly documents one-shot/headless operation and NDJSON output. | | `roo-code` | `RooCodeInc/Roo-Code` — `README.md` | installed-extension detection and prompt handoff | Upstream README states the extension was shut down on May 15, 2026. WhyThis does **not** invent a maintained headless CLI. | From 3cf72e37309d1d56e5be4d6da1c7a938aa7a76cb Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 18 Sep 2026 09:36:48 +0400 Subject: [PATCH 9/9] Add Aider and Pi harness contract tests --- internal/harness/harness_test.go | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/internal/harness/harness_test.go b/internal/harness/harness_test.go index 1057689..7ff0292 100644 --- a/internal/harness/harness_test.go +++ b/internal/harness/harness_test.go @@ -2,6 +2,7 @@ package harness import ( "context" + "reflect" "testing" ) @@ -11,6 +12,41 @@ func TestRegistryHasTenHarnesses(t *testing.T) { t.Fatalf("expected 10 adapters, got %d", len(r.items)) } } + +func TestBuiltinHarnessContracts(t *testing.T) { + var aider commandHarness + var foundAider bool + for _, h := range builtins() { + if h.ID() != "aider" { + continue + } + var ok bool + aider, ok = h.(commandHarness) + if !ok { + t.Fatalf("aider adapter has unexpected type %T", h) + } + foundAider = true + break + } + if !foundAider { + t.Fatal("aider adapter not found") + } + + got := aider.args("/tmp/prompt.md", "ignored") + want := []string{"--message-file", "/tmp/prompt.md", "--yes"} + if !reflect.DeepEqual(got, want) { + t.Fatalf("aider args = %#v, want %#v", got, want) + } + + piCaps, err := (piHarness{}).Detect(context.Background()) + if err != nil { + t.Fatal(err) + } + if len(piCaps.EvidenceSources) != 1 || piCaps.EvidenceSources[0] != "mitsuhiko/pi-mono packages/coding-agent/docs/rpc.md" { + t.Fatalf("unexpected pi evidence sources: %#v", piCaps.EvidenceSources) + } +} + func TestExtractText(t *testing.T) { got := extractText("{\"type\":\"x\",\"text\":\"hello\"}\n") if got != "hello" {