# Code Diagnosis V2 — Validation Handoff

Last updated: 2026-08-31 (Asia/Shanghai)

## Latest live-progress update (2026-08-31)

### Source continuation implementation: locally verified, image validation pending

Code-investigator continuation now follows the evidence-agent-style artifact
model without trying to resume a completed child session:

- every successful submission is append-only at
  `evidences/agent-runs/code-investigator/<request_id>.json`;
- a backend-owned `code-investigator.manifest.json` records request lineage,
  SHA, focus terms, reason, timestamp, and artifact path; the existing
  `code-investigator.json` remains a derived latest-result view;
- a targeted follow-up must use the exact
  `INVESTIBOOK_CODE_CONTEXT_FOLLOW_UP_V1` header with the initial request ID,
  the same SHA, new focus terms, and a bounded user-request reason;
- the backend rejects a missing/non-initial parent, SHA mismatch, duplicate
  focus terms, duplicate request ID, and a second follow-up. The hard budget
  is one initial run plus one targeted follow-up per lineage.

The child cannot initiate another run. The parent may initiate the follow-up
only after an explicit user request to deepen an unresolved source question;
an invalid initial delivery remains a one-time retry, not a continuation.

Focused local verification after this change:

```text
46 passed
ruff: all checks passed
git diff --check: passed
```

Live validation needs one manual CI image build from the updated functional
branch, followed by a fresh initial-and-follow-up TCOC against the isolated
`backend-code-test` Pod. The previous two TCOCs validate the artifact-first
delivery path only; they predate the append-only continuation implementation.

### Source continuation image validation: passed

Manual CI run
[`33354120002`](https://github.com/tidbcloud/investibook/actions/runs/33354120002)
built the image from temporary validation ref `ac03f6f59bc069541953f49927a3de0f39dcf032`.
Only the isolated `backend-code-test` Pod was updated, to immutable digest
`sha256:1f3df61152261471686bc4d628560b48e407680c4fd6d11217beec154b922dfa`, and
the test ran through its localhost-only port 8001 service.

Fresh TCOC-5826 continuation workspace: `ws-1788147953526-ba30248b3`.

| Run | Request ID | Parent Task status | Artifact |
| --- | --- | --- | --- |
| Initial five-focus investigation | `code-d9ded4bd3d894949be0dffae383f0152` | `artifact_ready` | `evidences/agent-runs/code-investigator/code-d9ded4bd3d894949be0dffae383f0152.json` |
| Explicit partition state-machine follow-up | `code-3423f2c54e824addb41c65e9cd26c8ed` | `artifact_ready` | `evidences/agent-runs/code-investigator/code-3423f2c54e824addb41c65e9cd26c8ed.json` |

The server-owned manifest has exactly those two runs. The follow-up preserved
the initial SHA, carried only new focus terms, and its `parent_request_id` and
`root_request_id` both equal the initial request ID. Both artifact deliveries
have schema version 2 and non-empty server-issued request IDs. This validates
the initial + one bounded follow-up path over real OpenCode ACP transport.

### Long-term artifact-delivery implementation: ready for image validation

The fragile "put raw JSON in the child Task final text" protocol has been
replaced locally with an artifact-first custom-tool protocol:

- new OpenCode plugin `ya-opencode-code-artifact` exposes the typed
  `submit_code_artifact(artifact_json)` tool only to `code-investigator`;
- the bridge accepts a submission only when the ACP tool is named exactly
  `submit_code_artifact` and trusted OpenCode subagent metadata binds it to a
  registered `code-investigator` parent Task;
- the backend, not the model, validates the V2 envelope against the immutable
  SHA/focus contract and persists it; a duplicate submission is rejected;
- a parent Task now reports `artifact_ready` only after the controlled
  submission succeeds. Its natural-language final message is a human handoff
  and is never parsed as artifact data.

This removes the known ACP `<task_result>` wrapper/preamble failure mode
without loosening the artifact schema. Focused verification passed:

```text
44 passed
ruff: all checks passed
git diff --check: passed
```

The new plugin is compiled in `backend/Dockerfile` with Bun and copied into
the image. The local host has no Bun and its Docker daemon was unavailable on
2026-08-31, so an image-level plugin build and live TCOC rerun remain pending.
Do not copy this source-only change to `backend-code-test`; first build an
image (or otherwise provide the generated plugin bundle), then use the
temporary 8001 validation service.

### CI image validation: passed

The manual validation-image CI run
[`33350860011`](https://github.com/tidbcloud/investibook/actions/runs/33350860011)
built and pushed the immutable image tag
`552185537300.dkr.ecr.us-west-2.amazonaws.com/investibook/dev/backend:8f23abdf6106c4a58f953d0b9214ee45edaf5385`.
`backend-code-test` was the only Pod updated to that image; its temporary
localhost:8001 service ran both real validations:

| Case | Workspace | SHA | Parent Task | Artifact delivery |
| --- | --- | --- | --- | --- |
| TCOC-5826 | `ws-1788143835015-0bd09a9b9` | `d7709be036986aaf3885a03b0bb62638f84d5fdc` | `artifact_ready` | V2 artifact has five direct answers and non-empty `code-8f5ad34c45a84053875bca8f211ddd18` request ID. |
| TCOC-5820 | `ws-1788144306039-5949bdca0` | `202b7f47286a1109b5c957401d34c9358d130ae0` | `artifact_ready` | V2 artifact has exactly the `others` focus term and non-empty `code-f7a7415d0ed246e2992d511654247a69` request ID. |

For both runs, `submit_code_artifact` completed successfully, the backend logged
`code_investigator_artifact_submitted`, and the parent Task was completed only
after it emitted `artifact_ready`. This validates the artifact-first delivery
path against the real OpenCode ACP transport.

The request-correlation repair is committed and pushed on
`codex/tcoc-5820-code-investigator`:

- `3a33b51e` — decodes JSON-string ACP Task inputs and replaces a null or
  missing request ID when a sparse Task registration is upgraded;
- `b5440f9a` — removes the stale marker instruction from `tidb-code-context`;
- `7f78b7a1` — strictly unwraps OpenCode's outer ACP
  `<task><task_result>…</task_result></task>` transport envelope before V2
  artifact validation.

Focused verification after the final runtime change passed: `32 passed`, Ruff,
and `git diff --check`.

### TCOC-5826 prior result: not passed (superseded protocol)

Three fresh runs on `backend-code-test` / localhost:8001 registered the
authorized SHA but failed before artifact persistence with:

```json
{"status":"artifact_delivery_failed","reason":"invalid_envelope","detail":"code-investigator artifact is not valid JSON"}
```

- `ws-code-e2e-1788138101634-c991dd31`: first run after request-ID repair;
  the ACP Task result had an outer XML wrapper and pre-JSON prose.
- `ws-code-e2e-1788138773950-dc9f52f1`: same failure after the skill-contract
  update.
- `ws-code-e2e-1788139339951-8b4576c3`: same failure after the runtime strips
  the known outer ACP wrapper, proving that non-JSON text remains inside the
  task result and is correctly rejected by the artifact validator.

The null request-ID regression is covered by the bridge test, but it is not yet
validated in a persisted production-like artifact. Do not start TCOC-5820
until the new controlled-submission flow makes TCOC-5826 reach
`artifact_ready` with a non-empty request ID.

## Latest live-progress update (2026-08-30)

AWS SSO was refreshed with `/Users/huyibin/Downloads/setup-kubeconfig.sh` and
the dev kubeconfig is `/Users/huyibin/Downloads/kubeconfig-dev` (context
`devops-staging`). `backend-code-test` is present and healthy.

### TCOC-5826 most recent real run

- Workspace: `ws-code-e2e-1788098754773-3659a092`.
- The code-investigator source task completed and the artifact was written to:
  `/data/workspaces/ws-code-e2e-1788098754773-3659a092/evidences/agent-runs/code-investigator.json`.
- Verified artifact fields:
  - `contract_version = 2`;
  - focus terms are present for InfoSchema v2 GC, transaction-pinned
    InfoSchema, REORGANIZE PARTITION, compilation-time 1146, and #66527;
  - artifact keeps incident causality out of its source-only conclusion scope.
- **Current acceptance failure:** `delivery.request_id` is `null`. Do not mark
  TCOC-5826 passed yet. The Pod contains the expected request-ID code
  (`agent_runtime.py` calls `persist_code_investigator_envelope` with
  `expected_request_id`; `code_context.py` writes it), so trace the
  `_code_investigator_tasks[tool_id]` registration/upgrade record to find why
  its value reaches persistence as `None`.

### Prior regression and current fix state

- Earlier real run `ws-code-e2e-1788095499488-b5a91b56` failed with
  `missing_authorized_task_sha`; its persisted Task input was valid but runtime
  did not log registration.
- Current uncommitted fix in
  `backend/investibook/core/agent_runtime.py` adds `_decode_task_input()` so
  JSON-string ACP Task input is decoded before subagent/header parsing.
- Regression test added in `backend/tests/test_acp_workspace_evidence.py`:
  `_code_investigator_task_request(json.dumps(request))` must preserve the
  authorized SHA.
- Local verification of that change: 31 focused tests passed; Ruff and
  `git diff --check` passed.
- This fix has been copied to the Pod and temporary 8001 service restarted,
  but is not yet committed/pushed from the recreated worktree.

### Next actions, in order

1. Add a focused bridge regression for the real sequence that yields a null
   request ID: verify the registration record gets a non-empty `code-...` ID
   when it starts sparse and later gains parsed Task input.
2. Fix the registration path; rerun local focused tests/lint/diff checks.
3. Commit and push the regression fix and this handoff update.
4. Copy the updated runtime to the temporary Pod 8001 service and rerun
   TCOC-5826. Require non-empty `delivery.request_id` before passing it.
5. Only then create and run TCOC-5820, with exact focus term `others`.

## Scope and safety boundary

- This is a new code-diagnosis feature; no legacy workspace or artifact compatibility is required.
- Do **not** use Run9 for validation.
- Use the isolated `backend-code-test` Pod in the dev `investibook` namespace.
- Do not restart the shared backend on port 8000. The disposable validation server is Uvicorn on `127.0.0.1:8001` in the Pod.
- The main worktree contains user-owned changes to `deployment/kustomize/envs/dev/manual/backend-code-test.yaml`; do not touch them.

## Branch and local worktree

- PR branch: `codex/tcoc-5820-code-investigator`.
- Latest pushed implementation commit before the current uncommitted regression fix: `b4386072` (`refactor: make code diagnosis artifact contract v2`).
- Recreated isolated worktree: `/private/tmp/investibook-code-focus`.
- The current worktree has an uncommitted regression fix that accepts a Task input serialized by an ACP provider as a JSON string. Run tests and commit/push it before the next validation.

## V2 contract implemented so far

- Artifact output is a single raw JSON object; marker and XML Task wrappers are rejected.
- Artifact requires `contract_version: 2`.
- Runtime validates fixed SHA, exact focus-term coverage, and source references against the immutable source snapshot.
- Runtime creates a server-trusted `request_id` and injects it into artifact `delivery` metadata.
- Agent guidance requires `focus_terms` in the machine-readable Task header.

## Regression discovered during TCOC-5826

The Task artifact did not persist because runtime returned:

```json
{"status":"artifact_delivery_failed","reason":"missing_authorized_task_sha"}
```

The persisted Task input was valid and started with:

```text
INVESTIBOOK_CODE_CONTEXT_TASK_V1 {"repo":"pingcap/tidb","commit_sha":"d7709be036986aaf3885a03b0bb62638f84d5fdc","focus_terms":[...]}
```

However, the runtime did not log `code_investigator_task_registered`. The likely provider-shape mismatch is that ACP delivered the Task input as JSON text rather than a Python dict. The current uncommitted fix adds `_decode_task_input()` before `_task_subagent_name()` and `_code_investigator_task_request()`, plus a regression assertion for `json.dumps(task_input)`.

## Validation status

### Local verification

After the JSON-string normalization change:

```bash
uv run --directory backend pytest tests/test_acp_workspace_evidence.py tests/test_code_context.py -q
uv run --directory backend ruff check investibook/core/agent_runtime.py tests/test_acp_workspace_evidence.py
git diff --check
```

Result: `31 passed`; Ruff and diff checks passed.

### Dev Pod access

Authenticate and set kubeconfig:

```bash
bash /Users/huyibin/Downloads/setup-kubeconfig.sh
export KUBECONFIG=/Users/huyibin/Downloads/kubeconfig-dev
kubectl get pods -n investibook | rg backend-code-test
```

As of this handoff, `backend-code-test` is `Running`.

### Current temporary deployment

The tested `agent_runtime.py` was copied to `/app/investibook/core/agent_runtime.py` and only the temporary localhost server was restarted:

```bash
kubectl cp backend/investibook/core/agent_runtime.py \
  investibook/backend-code-test:/app/investibook/core/agent_runtime.py
kubectl exec -n investibook backend-code-test -- sh -c '
  pid=$(pgrep -f "uvicorn.*127.0.0.1.*8001" | head -1)
  kill "$pid"
  cd /app && nohup /app/.venv/bin/uvicorn investibook.main:app \
    --host 127.0.0.1 --port 8001 >/tmp/code-focus-uvicorn-v2c.log 2>&1 &
'
```

Do not restart Pod or port 8000, because that would discard the temporary test setup.

## Required real validations

Run both existing cases after committing/pushing the current regression fix:

1. **TCOC-5826** — fixed SHA `d7709be036986aaf3885a03b0bb62638f84d5fdc`; verify V2 artifact persistence, `delivery.request_id`, exact focus coverage, and non-leading source-only boundaries.
2. **TCOC-5820** — verify the narrow `others` focus-term answer remains direct and source-cited under V2.

### Common execution and acceptance procedure

For either case, use a fresh disposable workspace and the temporary service at
`http://127.0.0.1:8001`. Do not target port 8000 and do not use Run9.

The run passes only if all of the following are true:

1. The code-investigator Task completes with `status=artifact_ready`, not merely
   a successful-looking child chat response.
2. `/data/workspaces/<workspace-id>/evidences/agent-runs/code-investigator.json`
   exists and is valid JSON.
3. Artifact has `contract_version: 2` and a non-empty
   `delivery.request_id` generated by the server.
4. Artifact `commit_sha` is exactly the authorized 40-character SHA and every
   focus term is answered exactly once with a fixed-snapshot source reference.
5. The response is source-only: it distinguishes mechanism evidence from
   incident causality and names outstanding runtime evidence.

Record workspace ID, Task ID, elapsed time, artifact path, Task status, and any
failure code in the results table below.

### TCOC-5826 — DDL / old InfoSchema hypothesis

**Purpose:** Ensure V2 returns a bounded, non-leading source analysis for the
reported `REORGANIZE PARTITION` / `schema:1146` behavior at
`d7709be036986aaf3885a03b0bb62638f84d5fdc`.

**Required focus terms:**

- transaction-pinned InfoSchema lookup;
- v2 schema GC / `GC compact old schema version`;
- `REORGANIZE PARTITION` schema-version path;
- `schema:1146` during compilation;
- #66527 as a hypothesis, not a conclusion.

**Additional acceptance:** The artifact must not state that the source mechanism
caused the customer incident. It must identify runtime checks required to link
transaction start timestamp, DDL/schema versions, and GC log fields.

**Harness:** `/tmp/investibook_tcoc_5826_e2e.py` in the Pod (command below).

### TCOC-5820 — narrow `others` source question

**Purpose:** Ensure V2 does not widen a narrow user question into a broad
component diagnosis.

**Required focus term:** `others` (use the exact wording in the Task header).

**Additional acceptance:**

- `direct_answers` contains exactly one entry for `others`;
- the opening answer defines the source-level meaning of `others` directly,
  with a valid source reference;
- broader context is secondary and does not substitute for the direct answer;
- no incident/root-cause language is emitted without runtime evidence.

**Harness status:** create a disposable equivalent of the TCOC-5826 harness
with the same auth/workspace setup, a fixed full SHA appropriate to the prior
TCOC-5820 case, and a prompt whose only focus term is `others`. Keep that
harness in `/tmp` in the Pod and record its exact prompt and SHA here once run.

### Results record

| Case | Workspace | Task status | Artifact / request ID | Elapsed | Result / notes |
| --- | --- | --- | --- | --- | --- |
| TCOC-5826 | `ws-code-e2e-1788139339951-8b4576c3` | `artifact_delivery_failed` | no artifact | not recorded | Prior protocol blocker: the child Task result has non-JSON text inside the ACP `task_result` envelope. The new custom-tool delivery flow is pending image validation. |
| TCOC-5820 | not started | pending | pending | pending | Harness must be created after TCOC-5826 passes. |

Reusable TCOC-5826 harness currently exists in the Pod:

```bash
kubectl exec -n investibook backend-code-test -- sh -c '
  cd /app && PYTHONPATH=/app \
  INVESTIBOOK_TEST_BASE_URL=http://127.0.0.1:8001 \
  /app/.venv/bin/python /tmp/investibook_tcoc_5826_e2e.py
'
```

After each run, query the disposable workspace from `/data/db/investibook.db` and verify that the code-investigator Task reports `artifact_ready`; then read:

```text
/data/workspaces/<workspace-id>/evidences/agent-runs/code-investigator.json
```

## Immediate next actions

1. Make the code-investigator final-response path emit a JSON object without
   in-result prose; preserve the validator's rejection of any model-written
   prose, marker, or XML.
2. Rerun TCOC-5826 and require `artifact_ready` plus non-empty
   `delivery.request_id`.
3. Only after that pass, create/run the equivalent TCOC-5820 no-Run9 harness.
4. Update this document with final elapsed times and pass/fail results.
