[verified] Bound evidence commands and reap process groups

This commit is contained in:
2026-10-11 07:56:25 +00:00
parent 6cb2317667
commit 18222f2ca8
9 changed files with 630 additions and 50 deletions
@@ -311,10 +311,17 @@ Review write 응답, process exit, PR body의 test 주장, delegate 보고 또
## External Issue verification evidence boundary
제품 검증 실행 evidence의 정본은 공통 [Repository cache 운영 지침](../../../../operations/repository-cache.md)의 `<harness-root>/repositories/<owner>/<repo>/worktrees/issue-<number>/verification/<run-id>`다. 구현·재작업의 `evidence-manifest/v2`와 plan/output을 read-only로 소비하며 제품 저장소에 회차별 증빙 파일을 새로 요구하지 않는다. 기존 genuine 정본 문서와 fixture의 존재 자체를 결함으로 판정하거나 삭제를 요구하지 않는다.
제품 검증 실행 evidence의 정본은 공통 [Repository cache 운영 지침](../../../../operations/repository-cache.md)의 `<harness-root>/repositories/<owner>/<repo>/worktrees/issue-<number>/verification/<run-id>`다. 구현·재작업의 `evidence-manifest/v3`와 plan/output을 read-only로 소비하며 제품 저장소에 회차별 증빙 파일을 새로 요구하지 않는다. 기존 genuine 정본 문서와 fixture의 존재 자체를 결함으로 판정하거나 삭제를 요구하지 않는다.
- Authenticated repository/Issue identity, source full SHA, plan·manifest·source/output digest와 실제 command/result binding을 독립 검증한다. Manifest의 경로나 SHA 주장을 신뢰하는 것만으로 검증하지 않고 pinned provider/Git blob과 fresh PR head에 결합한다.
- Same-UID의 승인된 읽기 경로 또는 distinct-UID/host의 승인된 credential-free read-only export와 digest/readback receipt를 확인한다. 접근/무결성/source binding을 확인할 수 없으면 `evidence_gap`으로 남기고 증거를 만들어내지 않는다. `0700`/`0600`을 완화하거나 임의 외부 경로·다른 role credential로 우회하지 않는다.
- Producer evidence와 reviewer 실행을 구분한다. Spec reviewer는 제품 테스트를 실행하지 않으며 moving implementation checkout을 authority로 읽거나 재사용·수정하지 않는다. Impl helper의 `validate`는 clean current checkout을 요구하므로 spec review의 pinned source 검증을 대신하지 않는다. Immutable source bundle과 authoritative blob evidence를 사용한다.
- Native-review snapshot, matrix/result와 publication/readback 자료는 trusted `harness/.runtime`에 보존할 수 있다. 그것을 제품 실행 evidence로 오인하지 않는다. 구현자의 verification 기록을 수정하거나 reviewer 자료로 덮어쓰지 않는다.
- 기존 v1의 archived read-only 호환 분석은 허용하되 fresh 제품 실행·새 remote head 검증·native review publication 완료의 근거로 과장하지 않는다. 인증정보 값은 보존하지 않고 `[REDACTED]`로 기록한다.
Command deadline 계약: 새 plan의 각 command는 `timeout_seconds`를 명시한다. Boolean·문자열·누락·비유한 값·0 이하·3600 초 초과를 실행 전에 거절하며 암묵적인 무제한 실행을 허용하지 않는다. Monotonic wall-clock deadline은 무출력 대기, stdout EOF 이후 실행, leader 종료 뒤 descendant가 유지한 pipe까지 적용한다. 각 command는 별도 session/process group에서 실행하고 timeout·출력 초과·예외 시 해당 process group을 TERM → 제한된 grace → KILL로 정리하고 direct child를 bounded wait로 회수한다. Leader가 종료됐어도 같은 group의 살아 있는 descendant를 남기지 않는다. 이것은 sandbox가 아니며 별도 session으로 이탈한 descendant의 containment나 grandchild 직접 회수를 보장하지 않는다.
`evidence-manifest/v3`는 실제 timeout, `execution_status`, `termination`의 `term_sent`·`kill_sent`·`direct_child_reaped`·`group_cleanup_completed` boolean 기록과 안전한 bounded 부분 출력을 결합한다. 새 claim pointer는 기존 6개에 timeout·실행 상태·종료 기록을 추가한 9개다. Linux `/proc`로 같은 group의 non-zombie 프로세스를 확인하며 확인·정리에 실패하면 `cleanup_failed`로 차단한다. TERM grace는 0.25 초, KILL 후 group 종료·direct-child 회수 예산은 0.5 초이며 오류 fallback wait도 0.1 초로 제한한다. 새 command의 `max_output_bytes`는 0–1048576 범위의 non-boolean 정수만 허용한다. `execution_status`는 `completed|timeout|output_limit|cleanup_failed|descendant_cleanup`이다. 정상 종료 leader 뒤의 살아 있는 descendant를 신호로 정리한 경우도 `descendant_cleanup` 실패이며, `completed`에는 TERM/KILL 신호가 있을 수 없다. Timeout·출력 한도 초과·정리 실패는 expected exit code와 같아도 성공이 아니며 **TDD RED** 또는 제품 assertion 실패로 분류하지 않는다. 해당 실행은 실패로 보존하고 뒤의 command를 실행하지 않으며, 실행된 prefix의 claim만 기록한다. Partial output에도 기존 secret 탐지를 적용하고 인증정보 유출은 fail-closed한다. 자동 재실행은 하지 않으며 새로 승인된 실행에는 새 run-id를 사용한다.
기존 `evidence-manifest/v2`는 명시적 `validate-archived-v2 --contract-path <canonical-contract> --repo-root <checkout> --artifact-root <canonical-run> --manifest <run-relative-manifest>`로 read-only 호환 검증한다. Canonical identity, exact current HEAD, source/plan/output binding을 유지하지만 과거 기록에 없던 timeout이나 종료 보장을 추론하지 않는다. 새 `run`/`validate`에는 v2 fallback이 없다. v1은 기존 `validate-legacy`만 사용한다. 두 archive 경로의 성공은 새 실행·TDD RED·fresh publication proof가 아니며 기존 artifact를 수정하거나 새 schema로 자동 변환하지 않는다.