[verified] Gate adoption of delegated evidence

This commit is contained in:
2026-10-11 06:08:32 +00:00
parent da7598b1c3
commit 9367d5a3a1
9 changed files with 1095 additions and 4 deletions
+40
View File
@@ -371,6 +371,46 @@ python3 <harness-root>/harness/lib/workflow_guard.py check-tests --input GUARD_I
File/hash binding PASS는 named symbol·parameter 존재나 실제 collection 실행을 인증하지 않는다. `argv`/`evidence`의 형식과 source scope 결속을 확인해도 명령이 실행됐다는 증명은 아니다. Main이 실제 command/output/exit·환경·collection ID/status·범위의 적절성과 manifest 결속을 기존 provenance 규칙으로 별도 확인한다. 필요한 근거가 부족하면 해당 증빙을 채택하지 않으며 현재 collection을 baseline으로 재명명하지 않는다. 기존 revision evidence 재사용은 원래 source에 먼저 결속한 뒤 source-to-head 영향 평가를 유지한다. 별도 checkout이나 전체 테스트 재실행을 요구하지 않는다. Source-binding 실패를 제품 결함이나 자동 `REQUEST_CHANGES`로 전환하지 않는다.
### Delegation evidence acceptance preflight
위임 결과를 판정·delivery·publication 증빙으로 채택하기 **이전**에 main이 `harness/lib/delegation_evidence.py`를 실행한다. 기존 source-preservation snapshot/compare-source, test inventory source-binding, `check-tests`는 각각 유지한다. 이 gate는 보호 범위 변경 검출이나 collection completeness 검사를 대신하지 않는다.
```sh
python3 <harness-root>/harness/lib/delegation_evidence.py \
--bundle-root ABS_FROZEN_BUNDLE --context ABS_MAIN_CONTEXT_JSON \
--result ABS_WORKER_RESULT_JSON --git-dir ABS_ADMITTED_GIT_DIRECTORY
```
`--git-dir`는 `git_tree` source에서 필수이며 `captured_worktree`에서는 Git provenance를 주장하지 않으므로 생략할 수 있다. Linux의 신뢰된 `/usr/bin/git`, pinned directory FD와 `/proc/self/fd/`를 사용한다. Helper는 기존 자료만 읽으며 file/ref write, source import, eval, checkout/fetch, test 실행, credential 조회, 환경 repair를 하지 않는다. Context/result input, frozen bundle source와 evidence는 canonical absolute root 아래의 bounded regular files여야 한다. Alias·symlink ancestor·FIFO·duplicate/unknown JSON keys·잘못된 type을 거부한다.
**독립 trust 입력:** main이 source identity, 실제 bundle bytes, stage, 허용 작업, 승인된 검증 항목, 실제 command/output/exit와 실패 원인을 검토하여 context와 독립 실행 catalog를 고정한다. Worker의 주장·테스트 개수·자체 failure_kind를 그대로 복사하여 trust 입력을 만들지 않는다. 위임 시작 시점 bundle과 채택 대상 source가 다르면 새 source의 입력·기록을 main이 독립적으로 다시 결속한다. 이전 snapshot의 PASS를 다른 source에 재사용하지 않는다. 이 gate는 context의 신뢰성을 스스로 인증하지 않는다. Context/catalog의 인증·독립성, evidence의 실제 실행 provenance와 assertion 검출력은 main 책임이다. Secret-bearing source/output를 무작정 bundle로 복사하지 않으며 record와 digest가 필요해도 credential 값은 기록하지 않는다.
**Main context 계약:** exact top-level keys는 `schema`, `source`, `stage`, `bundle_sha256`, `files`, `allowed_actions`, `obligations`, `executions`이다.
- `schema`: exact `gitea-agent.delegation-evidence-context/v1`.
- `source`: exact variant `{kind: "git_tree", revision: lowercase40}` 또는 `{kind: "captured_worktree", base_revision: lowercase40}`. `git_tree`는 exact commit과 regular Git blob까지 확인한다. `captured_worktree`는 main이 별도로 고정한 pending-change snapshot의 bytes를 검사하며 base revision과 동일한 내용 또는 commit된 source라고 주장하지 않는다. 두 mode를 서로 재명명하지 않는다.
- `stage`: 독립적으로 고정한 nonempty 단계 문자열.
- `files`: 추출한 source의 안전한 repository-relative path → lowercase SHA-256 exact map. 실제 frozen file bytes와 대조한다. 추출 범위는 **listed files only**이고 bundle에 없다는 이유로 repository 부재로 판정하지 않는다. `git_tree`에서는 snapshot bytes와 같은 pinned commit blob 모두에 결속한다.
- `bundle_sha256`: `SHA256(json.dumps(files, sort_keys=True, separators=(',', ':'), ensure_ascii=True).encode('utf-8'))`. Mutable 실행 metadata는 source map에 억지로 포함하지 않으며 별도 catalog/evidence digest로 결속한다.
- `allowed_actions`: 중복 없는 `static`/`execute` subset. Context에서 지정한 worker의 허용 작업이며 자동 실행 권한을 부여하거나 숨겨진 실행을 탐지하는 sandbox가 아니다.
- `obligations`: unique `{id: nonempty, kind: "static" | "execution" | "red_green"}` array. Main이 승인된 범위에 필요한 항목만 지정한다. 모든 제품 입력의 Cartesian product나 새 제품 요구사항을 만들지 않는다.
- `executions`: main이 독립적으로 검토한 실행 catalog array. 각 record의 exact keys는 `id`, `origin`, `test_id`, `bundle_sha256`, `test_file_sha256`, `argv`, `exit_code`, `failure_kind`, `evidence_path`, `evidence_sha256`이다. `id`는 unique nonempty string, `test_id`는 named regression의 `path::symbol` ID이며 일반 실행-only record에서는 빈 문자열을 허용한다. 빈 ID/placeholder test digest는 named-test 검증 근거가 아니고 `red_green`에는 사용할 수 없다. Digest는 lowercase64, `argv`는 nonempty string array, exit는 bool이 아닌 integer다. `failure_kind`는 `none`/`assertion`/`approved_behavior`/`import`/`environment`/`timeout`이다. Relative `evidence_path`는 bundle root 아래 별도 immutable 실행 기록을 참조하며 실제 regular file bytes가 `evidence_sha256`와 같아야 한다. Source map에 실행 metadata를 넣어 source를 순환 결속하지 않는다.
- Catalog `origin`은 `direct`/`inherited`이며 main이 실제 actor·관찰 출처를 대조한다. `direct` 실행 인용은 `execute` 허용이 있어야 한다. `inherited`는 이미 검토된 다른 producer의 기록을 static-only worker가 인용하는 경우이며 직접 실행했다고 인정하지 않는다. Worker는 catalog origin을 재정의할 수 없다. Hash와 metadata 형식의 PASS 자체는 실행 인증이 아니다.
**Worker result 계약:** exact top-level keys는 `schema`, `source`, `stage`, `bundle_sha256`, `claims`이다. `schema`는 exact `gitea-agent.delegation-evidence-result/v1`이고 source/stage/bundle digest는 main context와 exact-match해야 한다. `claims`의 exact record는 `{id, status, anchors, execution_ids}`이다. Claim ID set은 main obligations와 exact-match해야 하고 누락·추가·중복은 거부한다. `status`는 `supported`/`indeterminate`; indeterminate는 PASS로 채택하지 않는다. `execution_ids`는 중복 없는 기존 독립 catalog ID 참조이며 worker가 새 실행 record를 스스로 만들어 넣는 형식이 아니다.
Anchor variant의 exact keys와 검증은 다음과 같다.
- `{kind: "lines", path, start_line, end_line, text_sha256}`: 파일 범위 내 positive integer line range와 raw `splitlines(keepends=True)` byte slice의 SHA-256을 대조한다. 인용 text의 존재를 검증할 뿐 주장한 동작과 text가 의미적으로 일치한다는 판정은 main이 한다.
- `{kind: "test", path, symbol}`: Python 파일을 실행/import하지 않고 AST에서 qualified named test function/method의 존재를 확인한다. Local nested function·dynamic 생성·파싱할 수 없는 source를 실제 수집된 test로 추정하지 않는다. named symbol 존재는 assertion 검출력을 인증하지 않는다. Pytest parameter instance/collection completeness도 인증하지 않는다.
- `{kind: "absence", path}`: `git_tree`의 authoritative exact Git tree에서만 부재를 확인한다. Git 조회 실패나 bundle 누락을 repository 부재로 판정하지 않는다. `captured_worktree`의 부재 주장은 authoritative current-tree 근거가 없어 indeterminate/BLOCK으로 남긴다.
Static obligation은 유효 anchor를 요구하고 execution obligation은 독립 catalog 참조를 요구한다. `red_green`은 실제 snapshot에 저장된 named test와 같은 ID/file SHA-256의 RED·GREEN을 연결한다. RED는 nonzero `assertion`/`approved_behavior`, GREEN은 exit 0이며 GREEN source bundle digest가 채택 대상과 일치해야 한다. TDD의 RED bundle digest는 수정 전 source일 수 있으므로 GREEN으로 재명명하지 않고 독립 기록의 원래 scope를 유지한다. import·환경 오류는 RED로 인정하지 않는다. Missing regression/record, 잘못된 test/hash/scope, unauthorized direct execution과 출처 불명 기록은 채택을 차단한다.
**판정:** CLI exit 0은 증빙 연결 PASS, 1은 불일치·indeterminate BLOCK, 2는 입력 거부다. 고정된 reason codes/counts의 bounded JSON만 출력하며 source·argv·입력값·Git stderr·credential을 echo하지 않는다. BLOCK/입력 거부를 자동 제품 결함이나 `REQUEST_CHANGES`로 바꾸지 않는다. 해당 주장을 판정 근거에서 제외하고 main이 원본을 직접 재검증하거나 미검증으로 보고한다. Gate의 PASS는 의미 검토, 실제 실행 관찰, 외부 게시 readback 또는 전체 작업 완료의 증명이 아니다.
이 JSON은 기존 자료를 잇는 harness adapter 입력이다. 정본 verification run 또는 허용된 reviewer workflow artifact에 보존하며 제품의 추가 evidence commit이나 전체 테스트 재실행 의무를 만들지 않는다. 별도 collector 실행, 제품별 테스트 정책, manifest v2 변경 또는 role의 제품 실행 제한 완화를 추가하지 않는다. Skill/document wiring 테스트는 소비 workflow가 실제 이 절차를 실행했다는 증명이 아니다.
#### Nested input contracts
All object keys below are required and exact; unknown/missing keys, duplicate JSON keys, duplicate list identities, incorrect scalar types and non-regular/unbounded JSON inputs block. Empty strings are allowed only where explicitly stated. References are nonempty strings identifying existing verification command/result or approval records, not their secret contents. Full source revision is lowercase 40-hex; byte/scope digests are lowercase 64-hex. Integer fields reject booleans. CLI exit codes are 0 for structural PASS, 1 for detected violations/drift, 2 for rejected input; APIs raise `GuardError` for rejected input or return a status/violations result.