<a id="writeback"></a>
# Finding과 증거 흐름

Worker는 관찰을 `asset`, `fact`, `finding`으로 구분해 writeback한다. Finding은 탐색 graph의 node와 조회·편집용 `findings` row를 함께 만들며, 선택한 proxy exchange는 별도 snapshot/binding으로 고정된다. 이 구조는 provenance를 강화하지만 취약점 결론의 진실성을 자동 판정하지 않는다.

<a id="result-types"></a>
## 결과 타입

| 결과 | 최소 의미 | 저장·검사 | 후속 |
|---|---|---|---|
| asset | 새 공격 표면 또는 기존 자산의 새 속성 | 유형별 정규화/upsert, caller별 asset gate | coverage·anchor·후속 intent 후보 |
| fact | 관찰, 부정 결과, 제약 또는 추론 | exploration node/payload와 lineage | planner graph/digest/goal proof 입력 |
| finding | 취약점으로 보고할 후보 | graph node + finding row + optional traffic bindings transaction | planner 즉시 wake, reporter/notify/retest |
| hint/digest | 사람 전략 또는 cold graph 요약 | exploration node와 source/round | 다음 planner context |

Worker prompt는 직접 재현 근거가 있을 때 finding으로 올리고 의심은 fact로 남기라고 지시한다. Tool handler는 모델이 내린 security 의미를 독립적으로 재실행하지 않는다. [Worker](evidence:worker) [Finding workflow](evidence:finding-workflow)

<a id="finding-transaction"></a>
## Finding writeback transaction

```mermaid
sequenceDiagram
  participant W as Worker
  participant T as ToolSet / Recorder
  participant E as Evidence Store
  participant P as PostgreSQL
  participant N as Engine / Notifier
  W->>T: report_finding(fields, asset_ids, traffic_refs?)
  T->>E: RecordFindingInput + refs
  E->>P: begin + advisory lock
  E->>E: lock 보유 중 traffic ref normalize·body hash 확인·blob write
  P->>P: finding node + yields edge + anchors
  P->>P: findings row + snapshots + ordered bindings
  opt notification event best-effort
    P->>P: SAVEPOINT + notification_events INSERT
    alt insert 성공
      P->>P: RELEASE SAVEPOINT
    else insert 실패
      P->>P: ROLLBACK TO SAVEPOINT 시도
    end
  end
  P-->>E: commit
  E-->>T: finding id + node id + evidence version
  T-->>W: structured result
  T->>N: NotifyFinding after commit
```

transaction은 task/exploration/source intent 일치, graph node·edge·anchor, finding row와 snapshot metadata/bindings를 한 PostgreSQL commit 경계에 묶는다. Notification event는 같은 transaction 안에서 best-effort로 시도할 뿐 core finding의 원자성 조건이 아니다. Snapshot marshal 실패는 DB를 건드리지 않고 false를 반환하며, INSERT 실패는 savepoint rollback으로 격리되면 caller가 반환값을 무시하고 finding+evidence를 event 없이 commit할 수 있다. SAVEPOINT 또는 rollback 복구 자체가 실패해 transaction이 unusable해지면 뒤 SQL/commit도 실패할 수 있다. Evidence body filesystem write는 `WithEvidenceTx`와 advisory lock을 보유한 callback 안에서 일어나지만 PostgreSQL rollback 대상은 아니다. 따라서 뒤의 SQL/commit이 실패하면 staged blob이 orphan으로 남을 수 있고 process crash recovery는 evidence store 절차에 의존한다. [Finding transaction](evidence:finding-tx) [Evidence store](evidence:evidence-store)

`confirmed`는 graph finding node의 writeback 상태 이름이다. 독립 exploit 재현, CVSS 산정, bug-bounty 중복 심사, scope 승인 상태가 아니다.

<a id="traffic-evidence"></a>
## 트래픽에서 증거 snapshot까지

Traffic recorder는 MITM HTTP proxy와 로컬 store를 결합한다. metadata/search index는 SQLite, 작은 body는 inline, 큰 body는 content-addressed blob, host별 사람이 읽는 파일은 `data/traffic` 아래에 둔다. 저장 위치와 정리 규칙은 [Traffic DB](../contracts/db/traffic-sqlite.md#db-sqlite)에서 찾을 수 있다. [Traffic 구현](evidence:traffic)

```mermaid
flowchart LR
  Request[WebFetch/Bash HTTP 또는 enrich] --> Proxy[Recording proxy]
  Proxy --> Exchange[(SQLite exchange)]
  Proxy --> Blob[(traffic body/blob)]
  Exchange --> Ref[traffic_ref]
  Blob --> Ref
  Ref --> Verify[length + SHA-256]
  Verify --> Snapshot[(traffic_evidence_snapshots)]
  Snapshot --> Binding[(finding_traffic_bindings)]
  Binding --> Finding[(findings)]

  click Exchange "../contracts/db/traffic-sqlite.md#table-exchanges" "exchange table"
  click Snapshot "../contracts/db/findings-operations.md#table-traffic-evidence-snapshots" "snapshot table"
  click Binding "../contracts/db/findings-operations.md#table-finding-traffic-bindings" "binding table"
```

Evidence store는 참조 exchange를 읽고 request/response body 길이와 SHA-256을 검증해 별도 evidence CAS에 기록한다. Binding은 순서, request/response role과 설명을 갖는다. 원 traffic을 지워도 snapshot이 남도록 설계됐지만 실제 filesystem/DB backup 일관성은 별도 운영 문제다.

Proxy가 TLS interception에 실패한 host를 pass/tunnel 대상으로 처리하거나 tool이 proxy 밖으로 요청하면 원격 요청은 성공해도 exchange가 없을 수 있다. “tool success”와 “traffic evidence complete”를 같은 상태로 취급하지 않는다.

<a id="evidence-semantics"></a>
## 증거가 보장하는 것

| 주장 | deterministic 확인 | 남는 조건 |
|---|---|---|
| 참조한 exchange가 저장소에 있었다 | id/host/body 조회 | proxy 밖 요청은 분모에 없음 |
| snapshot body가 읽은 bytes와 같다 | length·SHA-256 | 대상 서버의 전체 상태나 앞선 요청은 증명하지 않음 |
| finding과 binding 순서가 일관된다 | PostgreSQL transaction/constraint | 설명의 의미 정확성은 작성자 판단 |
| report가 최신 evidence를 반영한다 | `evidence_version`과 `report_evidence_version` 비교 | reporter 문장과 bytes의 의미 일치는 별도 검토 |
| 취약점이 재현된다 | 자동 보장 없음 | retest/사람 검토 필요 |
| severity/vulnclass가 맞다 | enum/형식 일부만 검사 | 영향·blast radius 판단 필요 |
| 기존 finding과 중복이 아니다 | semantic unique 없음 | root cause/asset/role 비교 필요 |

<a id="finding-edit"></a>
## 편집·evidence version·stale report

Finding name, severity, vulnclass, status와 report는 API에서 변경할 수 있다. Traffic binding add/edit/delete/reorder는 evidence version을 올리고, reporter가 사용한 version은 `report_evidence_version`으로 따로 남는다. 두 값이 다르면 report가 현재 evidence 묶음보다 오래된 상태다. [Finding HTTP](evidence:finding-http) [Finding DB](evidence:finding-tx)

Binding body detail API는 context task의 provenance를 확인하고 inherited finding에는 쓰기 제한을 적용한다. 단순 finding id 보유만으로 모든 task context에서 수정할 수 있다고 가정하지 않는다.

<a id="downstream"></a>
## Reporter, retest, export

| 후속 | trigger/input | 완료 신호 | 한계 |
|---|---|---|---|
| Reporter | `report_finding` tool call trigger, finding/traffic/worker trace | `update_finding_report`와 report evidence version | 원 exploit을 기본적으로 재실행하지 않음 |
| Retest | 사람이 finding에서 시작 | 별도 conversation과 terminal verdict/history | finding당 active retest 하나; 결과도 agent 판단 포함 |
| Export | filter/ids로 finding rows와 report를 읽음 | HTTP download/response | 외부 제출 성공은 아님 |
| Notification | transaction에 기록한 event를 background notifier가 fan-out | delivery `sent` 또는 terminal failure | channel filter/rate/retry/digest에 따라 지연·억제 |
| Deepen | finding 기반 follow-up intent 생성 | new intent id/graph edge | 재현 확인과 같은 동작은 아님 |

Reporter trigger는 agent configuration에 의해 직렬/병렬·merge mode가 달라질 수 있다. Notification은 lease/retry와 digest batch를 사용하며 HTTP response와 실제 외부 채널 전달을 분리한다. [Reporter](evidence:reporter) [Retest](evidence:retest) [Notifier](evidence:notifier)

<a id="review-checklist"></a>
## finding을 실제 결과로 승인하기 전 확인점

이 목록은 현재 코드가 자동 수행한다고 주장하는 기능이 아니라 `confirmed`와 실제 bug-bounty finding 사이의 검토 경계다.

- source intent, task, target asset과 scope/program rule이 같은 실행 문맥인가?
- request/response binding이 상태 변화 전후와 인증 주체·tenant·object identity를 구별하는가?
- 대조군이나 differential response가 우연한 응답·cache·rate limit을 배제하는가?
- destructive effect 없이 허용된 방식으로 재현되는가?
- report의 각 영향 주장이 evidence bytes, worker trace와 재현 결과보다 강하지 않은가?
- severity가 필요한 권한, 데이터 민감도, 사용자 수와 복구 가능성을 반영하는가?
- 같은 root cause/endpoint/asset/role의 기존 finding과 중복되지 않는가?
- evidence version이 바뀐 뒤 report/retest가 stale하지 않은가?
