fix(stage1): execute asset-triage v.2 confirmed items — P2 dead constants/comment, manifest +6, matrix removal
- stage_1_part_2_v.8.yml (195,963 B, sha16 ec407309a5ab43f4): drop two dead R0 path constants (S0's own copies untouched); narrow the legacy_paths_forbidden header comment to old slice/seed paths and state that stage_a_context/source_universe/postb_* keep stage1_tmp/task_c_bo as canonical. R0 fragment synced; prior versions preserved under outdated/ (pre_asset_triage_fix) - Default_Agent/runtime_manifest.json 426->432: register six unanchored Part 1 assets (component union, client_goal schema, two reference catalogs, determinism contract, activation cue digest) with runtime_artifact_count updated and round-trip serialization kept - remove case_kind_domain_matrix.v2.json from deployment origin (byte-identical master kept in assembly tree; empty folders pruned); tree 210->209, listed∩tree 155 with zero hash mismatches - stage_1_2_3_assets_distribution_location.md rewritten as the Default_Agent change record only; full survey kept as *_old.md - Part 1|2 analysis doc: 10 targeted updates (sizes/sha, shifted line ranges A0 62-719 / B 720-849 / R0 850-1793, constant wording removed, §8 history row annotated with a dated note instead of rewriting) - verified: 3-pass dry run PASS with BO.json and legal_effect_structures.json byte-identical to the previous round; adversarial sub-agent check 29 items, findings 1 -> 0 - v.7/MEMORY.md entry 26 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1547,3 +1547,21 @@ task 2(L0 50–605 · L2 607–1,015 — 내용 종행 기준, 임베디드 code
|
||||
1. **"권장 조치"는 기존 설계 명문과 대조한 뒤에 낸다.** v.1 의 277 복사 권장은 사실 관찰은 정확했으나 4곳의 설계 명문을 확인하지 않아 정반대 처방이 됐다 — 관찰의 정확성과 처방의 타당성은 별개 검증이다.
|
||||
2. **"훼손 의심"은 git 이력이 즉답한다.** 생성 커밋 바이트 대조 한 번이면 저작/훼손이 갈린다 — 추론(라벨 병렬성)으로 판정하지 말 것.
|
||||
3. **보안 처방은 실행 가능성(백엔드 지원)과 노출 범위(저장소 전파)를 함께 재야 한다** — YAML 3본 치환은 402파일 노출 앞에서 본질이 아니다.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-20 ㉖ — 자산 정리 회차: v.2 확정 4건 실행 (P2 사문 상수·주석 / manifest +6 / matrix 제거 · sub-agent 2라운드 1→0)
|
||||
|
||||
v.2 §2 의 지정 4건만 수행. 산출:
|
||||
- **P2 통합본 개정** `stage_1_part_2_v.8.yml` → **195,963 B / 3,315행 / sha 앞 `ec407309a5ab43f4`** (구본 `outdated/stage_1_part_2_v.8.pre_asset_triage_fix.yml`). R0 사문 상수 2줄 삭제(ACTIVATION_MANIFEST_PATH 는 S0 2회만 잔존·REGISTRY_INDEX_PATH 전 파일 0회), L28 주석을 "구 slice/seed 경로 한정 + stage_a/universe/postb_* 5파일 정본 유지" 3줄로 교체. R0 조각 동기화(구본 `outdated/_pre_asset_triage_fix/`). 행 이동: A0 62–719 · B 720–849 · R0 850–1,793(주석 +2 · 상수 −2 상쇄로 R1 이후 무변).
|
||||
- **runtime_manifest 426→432**: P1 무앵커 자산 6종 직접 행 추가(count 동반 갱신·왕복 보존) — 복원 기준 확보(게이트 강제는 P1 개정 회차 몫).
|
||||
- **matrix 제거**: `case_kind_domain_matrix.v2.json` 을 배포 트리에서 제거(조립본 원본과 바이트 동일 확인 후 · 빈 폴더 정리) — 트리 209 파일 · 교집합 155/불일치 0 · 실물-미등재 54 · 277 무변.
|
||||
- **총람 회전**: `stage_1_2_3_assets_distribution_location.md` 를 Default_Agent 변화 기록만으로 재작성(전판 `_old.md` 존치).
|
||||
- **분석서 파급 10곳** 갱신(수치·행 범위·상수 서술 §3.3/§3.5 + §8 이력 행 시효 주석 — 원문 보존).
|
||||
|
||||
검증: 예행 3패스 PASS + **BO.json·legal_effect_structures.json·리포트 3본 전부 이전 회차와 바이트 동일**(수정이 값에 무영향 실증). sub-agent 검증 29항 — 지적 1건(§8 갱신 누락 — v.2 파급 문면 vs "§8 은 손대지 않는다" 관례 충돌 자리) 반영 후 0건.
|
||||
|
||||
### 교훈
|
||||
1. **이력 절은 개서하지 않고 시효 주석으로 닫는다** — §8 라운드 기록의 현재형 서술이 낡았을 때 원문 교체는 이력 위조, 방치는 오독 — "(…는 2026-08-20 회차에서 삭제됐다)" 부가가 정답.
|
||||
2. **주석 확장(+2)과 코드 삭제(−2)가 상쇄돼도 중간 블록 행 범위는 이동한다** — A0/B 는 +2, R0 는 시작 +2·끝 0, R1 이후 무변. 파일 총행 무변을 "행 범위 무변"으로 착각하지 말 것.
|
||||
|
||||
+25
-1
@@ -1280,6 +1280,18 @@
|
||||
"path": "law_versions/source_status/source_repin_status.json",
|
||||
"sha256": "f44e21988306748bfdde5d629d1e955f592d669c2af280eefb88f01c9ae74228"
|
||||
},
|
||||
{
|
||||
"path": "platform/contracts/determinism_scope_contract.json",
|
||||
"sha256": "8734102d9e2e9b695a3b12e91e7ab1b7208e1c1403729c082d708ee2c4a70532"
|
||||
},
|
||||
{
|
||||
"path": "platform/reference_catalogs/calculation_ids.json",
|
||||
"sha256": "fb14965b8315e01d47d694a10a674eda5db606ab9c7bbb6345de98495ba233b8"
|
||||
},
|
||||
{
|
||||
"path": "platform/reference_catalogs/domain_ids.json",
|
||||
"sha256": "4740d98e6a31bd0e7d9f792189712a8af1d0a87ec0bbd181deba1e34edb08355"
|
||||
},
|
||||
{
|
||||
"path": "platform/router/s3_sg01_router_config.json",
|
||||
"sha256": "4913b119f5ee08f96b52e10bd1f8376326564f1ab4742909fd2d0f07ded4efc6"
|
||||
@@ -1292,6 +1304,10 @@
|
||||
"path": "platform/router/s3_sg01_router_output.schema.json",
|
||||
"sha256": "4af85d52a60254149a3506cd5aa36cce1360e275b3c195d08307876379114b51"
|
||||
},
|
||||
{
|
||||
"path": "platform/schemas/client_goal_domain_profiles.schema.json",
|
||||
"sha256": "ae2bfe0d754a09cbae16b2c15bf1518fc23f9e1bda8fa1f5f949606c8e42c010"
|
||||
},
|
||||
{
|
||||
"path": "platform/schemas/domain_fanout_plan.schema.json",
|
||||
"sha256": "3b0948613a5996028b9c030a99f0b51d682f6035e019557756b1a15d43971113"
|
||||
@@ -1312,6 +1328,14 @@
|
||||
"path": "platform/schemas/structure_seed_bundle.schema.json",
|
||||
"sha256": "b7af9e422b6ac3876cffea39ec4f617eea76a631a57dfdfcd57d3785a83c667a"
|
||||
},
|
||||
{
|
||||
"path": "routing/activation_cue_digest.md",
|
||||
"sha256": "7e98885a50e1880b5ee7e2f459ab47010f90387e5c463a484a152054c2321e97"
|
||||
},
|
||||
{
|
||||
"path": "routing/evidence_component_union.md",
|
||||
"sha256": "ecd6e1877f476139012b79fdc04380c067b8e81af86707bcc5c2b311b3fabf79"
|
||||
},
|
||||
{
|
||||
"path": "routing/extension_payload_key_declarations.v1.json",
|
||||
"sha256": "1684e13896bc9dfd0e7aa1a3b01354f58b2fa6ed00908bec6f861bce4b47235c"
|
||||
@@ -1706,6 +1730,6 @@
|
||||
}
|
||||
],
|
||||
"program_release_status": "STAGE1_NOT_RELEASE_READY",
|
||||
"runtime_artifact_count": 426,
|
||||
"runtime_artifact_count": 432,
|
||||
"schema_version": "stage1_runtime_manifest.v1"
|
||||
}
|
||||
|
||||
-1
File diff suppressed because one or more lines are too long
+25
-157
@@ -1,169 +1,37 @@
|
||||
# Stage 1 Part 1·2·3 자산 배포 위치 총람
|
||||
# Stage 1 Part 1·2·3 자산 배포 — Default_Agent 변화 기록 (2026-08-20 자산 정리 회차)
|
||||
|
||||
- 근거: `stage_1_part_1_v.8.yml`(6,668행) · `stage_1_part_2_v.8.yml`(3,315행) · `stage_1_part_3_v.8.yml`(1,038행) 전량 판독 + 배포 트리 실측 (2026-08-20)
|
||||
- 크기: 배포 원본 트리(`v.7/extension_research/Default_Agent/`)에서 실측한 바이트 수. 실행 중 생성 산출물은 사건마다 달라져 "실행 생성"으로 표기.
|
||||
- 표기: P1 = Part 1(사건개요파악·기초작업), P2 = Part 2(BO·시그널 생성), P3 = Part 3(법률효과구조 생성)
|
||||
- 이 문서는 `problems_identified_in_detecting_assets_location_v.2.md` §2-B 작업의 실행 결과로 **배포 원본 `extension_research/Default_Agent/` 에 발생한 변화만**을 기록한다.
|
||||
- 변화 이전의 전체 배포 위치 총람은 `stage_1_2_3_assets_distribution_location_old.md`(2026-08-20 조사판)에 보존돼 있다 — 아래 두 변화를 제외한 모든 내용은 그 문서가 그대로 유효하다.
|
||||
|
||||
---
|
||||
|
||||
## 0. 배포 루트 3계층 (세 YAML 공통 규약)
|
||||
## 1. `runtime_manifest.json` — P1 자산 6종 등재 (426 → 432항)
|
||||
|
||||
| 계층 | 위치 | 성격 |
|
||||
v.2 §2-B "P1 자산 6종 manifest 등재" 의 실행이다. 해시 앵커가 없던 Part 1 소비 자산 6종의 sha256 행을 배포 원본 매니페스트에 **직접 추가**했다(이 회차 관례 — 빌더 등록은 조립본 동기화 회차의 이월 묶음). `runtime_artifact_count` 를 426 → **432** 로 동반 갱신했고(P2·P3 게이트의 count 등식·중복 경성 검사 대응), indent=2 왕복 직렬화를 보존했다.
|
||||
|
||||
| 등재 경로 (`Default_Agent/` 기준) | 크기 | sha256 (앞 16) |
|
||||
|---|---|---|
|
||||
| ① 정적 자산 루트 (`ASSET_ROOT`) | localdocs 논리 접두 **`Default_Agent/`** ← 배포 원본 **`v.7/extension_research/Default_Agent/`** 트리(210파일, .DS_Store 제외)를 통째로 배포 | P2·P3 remedy 명문: "배포 원본 extension_research/Default_Agent 트리를 서버 Default_Agent/에 통째로 배포하고 runtime_manifest.json의 등재·sha256과 대조. **부분 복사 불허**" |
|
||||
| ② 사건 워크스페이스 루트 | localdocs 문서 루트 (clientInfo에 `{{__user_hash__}}`/`{{__workspace_hash__}}` 필수 — 빠지면 루트 경로를 봄) | 접두 없는 상대경로 전부: `client_meeting.md`, `BO.json`, `routing/`, `quality_gates/`, `signals/`, `runtime/`, `fanout/`, `stage1_tmp/`, `validation_assets/`, `evidence_*` … |
|
||||
| ③ 실행 샌드박스 | code-executor 컨테이너 `EXECUTION_ROOT=/tmp/s1` (R0만 `/tmp/s1_r0`) — 모듈 반입처 `_rt/`, S0 signal 패키지 `_sig/`·`_signal_out/` | 임시 스테이징. 배포 대상 아님. 실행 인자 계약 `--asset-root/--execution-root/--logical-root` (D-5 §2.4 0-c-2) |
|
||||
| `platform/contracts/determinism_scope_contract.json` | 1,473 B | `8734102d9e2e9b69…` |
|
||||
| `platform/reference_catalogs/calculation_ids.json` | 1,139 B | `fb14965b8315e01d…` |
|
||||
| `platform/reference_catalogs/domain_ids.json` | 270 B | `4740d98e6a31bd0e…` |
|
||||
| `platform/schemas/client_goal_domain_profiles.schema.json` | 13,082 B | `ae2bfe0d754a09cb…` |
|
||||
| `routing/activation_cue_digest.md` | 35,110 B | `7e98885a50e1880b…` |
|
||||
| `routing/evidence_component_union.md` | 17,593 B | `ecd6e1877f476139…` |
|
||||
|
||||
**모듈 미러 규약**: localdocs가 `.py`를 서빙하지 않으므로 모든 런타임 `.py`는 **같은 디렉터리에 바이트 동일 `.txt` 미러**로 배포된다(유일 예외 = 빌더 `build_default_agent_stage1.py`). 반입 시 `Default_Agent/runtime_manifest.json`의 sha256과 대조하고 불일치면 실행 금지. 아래 표의 `.txt` 미러는 전부 `.py` 정본이 같은 디렉터리에 병존한다(크기 동일).
|
||||
갱신 후 매니페스트: **67,474 B · 432항 · sha256 `cebed7ff4bbbe9b4…`**. 등재는 **복원 기준** 확보다 — 무결성 강제(게이트)까지는 P1 YAML 수정이 필요하며 그것은 별도 설계 판단으로 남는다(v.2 §2-B 명문).
|
||||
|
||||
**runtime_manifest.json**: `stage1_runtime_manifest.v1`, 426건 등재. computations/ 등 Stage 1 Part 1~3 밖 자산도 등재되어 있으며 그 물리 실체는 `extension_research/선행구축/Default_Agent_Stage_1/`(1,322파일) 및 `ver_8_yaml_candidates/Default_Agent_Stage_1/`(560파일, 빌드·검증 산출 트리)에 있다. P1~P3 게이트는 각 Part가 선언한 필수 자산 목록에 대해서만 등재·sha256·가독을 검사한다.
|
||||
## 2. `validation_assets/routing/case_kind_domain_matrix.v2.json` — 배포 원본에서 제거
|
||||
|
||||
---
|
||||
v.2 §2-B 선택 항목의 실행이다. 런타임 읽기 금지가 명문(P1 프롬프트 2곳)인 오프라인 회귀 전용 자산(72,969 B)이 배포 트리에 있던 것을 제거해 트리 정의("실행이 읽는 자산 전부이자 그것만")에 정합시켰다. 제거 전 **조립본 원본(`선행구축/Default_Agent_Stage_1/validation_assets/routing/`)과 바이트 동일임을 확인**했다 — 정본은 조립본에 그대로 있다. 빈 폴더(`validation_assets/routing` · `validation_assets`)도 정리했다.
|
||||
|
||||
## 1. 공통자산 — 2개 Part 이상이 사용하는 사전배포 정적 자산 (`Default_Agent/`)
|
||||
## 3. 변화 후 배포 원본 요약
|
||||
|
||||
| 배포 위치 (`Default_Agent/` 이하) | 형태 | 크기(B) | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `runtime_manifest.json` | json | 66,526 | P1 D0 · P2 A0/R0/F0/S0 · P3 L0/L2 | 해시 장부(`stage1_runtime_manifest.v1`, entries[].path+sha256). 모든 모듈 반입·배포 게이트의 단일 근거. entries[].path는 `Default_Agent/` 접두를 뗀 상대경로 |
|
||||
| `domains/_registry_index.json` | json | 18,921 | P1 T0-02/T0-03/D0/T9 · P2 A0 · P3 L0/L2 | 도메인 registry 색인 정본(registry_version, entries[].domain_id/config_path/config_sha256). 원문 read_raw sha256이 스크리닝·활성 매니페스트·핸드오프에 봉인됨. **매니페스트 미등재 — SG-01 봉인(activation manifest의 registry_index_sha256)이 교체를 잡음**. P2 R0에는 상수로만 선언(미사용) |
|
||||
| `domains/{domain_id}/domain_config.json` | json ×26 | 2,468~17,324 (총 274,372) | P1 T0-03(후보만)/D0(전 26) · P2 A0 · P3 L0/L2(expected_runnable만) | 도메인별 config: 요건 슬롯·상대사실·증거 구성요소·항변·계산 바인딩·검토코드·structure_types 선언. registry index의 config_path만 따라 열람, config_sha256 사슬 대조. **LLM task(P1 T0-01·T1)는 직접 읽기 금지** |
|
||||
| `stage1_runtime/runtime_common.txt` | txt(py 미러) | 4,496 | P1 D0 · P2 A0/R0 · P3 L0/L2 | 런타임 공용 모듈. `/tmp/s1/_rt/*.py`로 실체화 후 sys.path 삽입 |
|
||||
| `stage1_runtime/schema_subset_validator.txt` | txt(py 미러) | 7,442 | P1 D0 · P2 A0/R0 · P3 L0/L2 | 닫힌 스키마 부분집합 검증기 — 산출물 스키마 검증의 공용 엔진 |
|
||||
| `stage1_runtime/registry_loader.txt` | txt(py 미러) | 6,404 | P1 D0 · P2 A0/R0 · P3 L0 | registry 적재기(load_registry). P3 L0은 compiler 의존 모듈로만 스테이징 |
|
||||
| `routing/evidence_component_union.md` | md | 17,593 | P1 T3(preflight) · P2 worker(어휘 참조) | 증거 구성요소 어휘 합집합(component_id + accepted_source_kinds + owner). `registry_component_ids`의 유일 허용 어휘 — 목록 밖 이름 생성 금지 |
|
||||
| `routing/extension_payload_key_declarations.v1.json` | json | 23,071 | P2 A0(게이트)/F0 · P3 L0 | BOType 합집합·확장 payload declared_key_union·legacy_alias_targets 선언표(`stage1_extension_payload_key_declarations.v1`). 생성기 `routing/_build_extension_payload_declarations.py`(배포 시점 접이, 런타임 미실행) |
|
||||
| `signals/signal_registry.v2.json` | json | 10,907 | P2 A0(게이트)/S0 · P3 L0(게이트만) | signal registry v2 — S0 스키마 $ref 폐포 walk의 출발점. P3에서는 배포 완전성 검사만 받고 파싱되지 않음 |
|
||||
| `contracts/signals/s5_execution_contract.v2.json` | json | 1,451 | P2 A0(게이트)/S0 · P3 L0(게이트만) | S5 실행 계약 — S0가 `/tmp/s1/_sig/contracts/`에 배치(모듈의 parents[1]/contracts 산술 재현). P3에서는 게이트 전용 |
|
||||
| `signals/adapters/sg01_activation_adapter.txt` | txt(py 미러) | 3,738 | P1 D0 · P2 S0 | SG-01 활성 어댑터 — D0 산출 매니페스트 자기검증(adapt_and_validate). 미러 위치는 `stage1_runtime/`이 아니라 `signals/adapters/`(YAML 헤더 명시) |
|
||||
| `signals/schemas/domain_activation_manifest.schema.json` | json | 3,535 | P1 D0(stage, 실패 시 경고) · P2 S0(registry가 결정하는 $ref 폐포에 포함 — 배포된 signal_registry.v2.json 등재 기준) | 활성 매니페스트 스키마 — D0 모듈은 직접 읽지 않음(어댑터가 검증 담당). §3의 폐포 17종 집계(28,476B)에 이 파일이 포함되므로 바이트 합산 시 중복 주의 |
|
||||
| 축 | 변화 전 | 변화 후 |
|
||||
|---|---|---|
|
||||
| 트리 파일 수(.DS_Store 제외) | 210 | **209** (−1: matrix 제거. 등재는 행 추가라 파일 수 무변) |
|
||||
| `runtime_manifest.json` | 426항 | **432항** (+6) |
|
||||
| 매니페스트 등재-실물 교집합 | 149 · 불일치 0 | **155 · 불일치 0** (신규 6종 포함 전수 재검) |
|
||||
| 실물-미등재 | 61 | **54** (P1 자산 6종 등재 + matrix 제거로 −7) |
|
||||
| 등재-실물없음(상위 장부 몫 — 설계) | 277 | 277 (무변 — v.2 §2-C: 복사 금지 확정) |
|
||||
|
||||
## 2. Part 1 전용 정적 자산
|
||||
|
||||
| 배포 위치 (`Default_Agent/` 이하) | 형태 | 크기(B) | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `routing/activation_cue_digest.md` | md | 35,110 | T0-01(preflight)/T0-02 | 라우팅 단어 사전 — 26개 도메인 활성 단서(P/N/C/OVR)+GLOBAL_DEFAULTS. "사실 원천이 아니다". 머리말에 registry_version·registry_index sha256 → 스냅숏 낡음 감지 |
|
||||
| `platform/schemas/client_goal_domain_profiles.schema.json` | json | 13,082 | T1(preflight) | client_goal의 domain_profiles 칸 형태를 정하는 닫힌 스키마 — "형식만 정하고 내용은 만들지 않음" |
|
||||
| `platform/reference_catalogs/domain_ids.json` | json | 270 | T0-03 | 도메인 ID 카탈로그 — 후보 멤버십 검사 |
|
||||
| `platform/reference_catalogs/calculation_ids.json` | json | 1,139 | T0-03 | 계산 ID 카탈로그(entries[].calculation_id/status) — calc 바인딩 존재·ready 검사 |
|
||||
| `stage1_runtime/activation_gate.txt` | txt(py 미러) | 66,715 | D0 | **도메인 활성 판정 모듈 본체** — "판정은 이 안에서만 일어난다. 결정 필드는 execution_eligible 하나뿐". main(--asset-root/--execution-root/--logical-root) 호출 |
|
||||
| `platform/contracts/determinism_scope_contract.json` | json | 1,473 | (헤더 선행조건만) | 결정론 범위 계약 — P1 정적 자산 선행 조건 5종의 하나. task 본문 직접 등장 없음(모듈 내부 소비 추정) |
|
||||
| `validation_assets/routing/case_kind_domain_matrix.v2.json` | json | 72,969 | **읽기 금지** (T0-01·T1에 금지 명문) | 사건유형 이름을 담은 **오프라인 회귀 전용** 자산 — 런타임 입력 금지 |
|
||||
|
||||
## 3. Part 2 전용 정적 자산
|
||||
|
||||
| 배포 위치 (`Default_Agent/` 이하) | 형태 | 크기(B) | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `stage1_runtime/registry_validator.txt` | txt(py 미러) | 11,080 | A0 | registry 검증기(validate_registry) — overlay 4개 오류코드만 경성 |
|
||||
| `stage1_runtime/prompt_compiler.txt` | txt(py 미러) | 15,164 | A0 | 프롬프트 조립기 — FragmentSpec/collect_domain_fragments/compile_fragments, rank 10→50 합성, 상한 96,000B/24,000자 |
|
||||
| `stage1_runtime/domain_slice_compiler.txt` | txt(py 미러) | 32,300 | A0 | slice 컴파일러(compile_domain_slices) — 낡으면 PART2_COMPILER_STALE |
|
||||
| `stage1_runtime/domain_fanout_planner.txt` | txt(py 미러) | 12,282 | A0 | fan-out 계획기(build_fanout_plan) |
|
||||
| `stage1_runtime/stage_a_context_builder.txt` | txt(py 미러) | 25,885 | A0 | stage_a_context/source_universe_manifest 빌더(v3 세 builder 이식) |
|
||||
| `stage1_runtime/worker_output_validator.txt` | txt(py 미러) | 21,302 | A0(게이트)/R0 | worker seed 산출 검증기(validate_worker_output; schema·slice 주입). 반입 실패는 경고 강등 |
|
||||
| `stage1_runtime/prompt_composition_policy.json` | json | 1,715 | A0 | 프롬프트 조립 정책(rank 순서·상한) |
|
||||
| `stage1_runtime/bo_surface_projection_policy.v1.json` | json | 6,355 | A0(게이트)/R0/F0 | BO 투영 정책(`stage1_bo_surface_projection_policy.v1`) — f0_normalization·review_item_projection 규칙 정본 |
|
||||
| `platform/schemas/domain_slice.schema.v2.json` | json | 17,725 | A0 | slice 스키마 — F-3 능력검사(stage_b_domain_slice.domain_declarations·compiled_prompt.hash_kind 필수) |
|
||||
| `platform/schemas/domain_fanout_plan.schema.json` | json | 11,148 | A0 | fan-out 계획 스키마(build_fanout_plan에 주입) |
|
||||
| `platform/schemas/domain_seed_output.schema.v3.json` | json | 21,965 | A0(게이트)/worker(참조)/R0 | worker seed 산출 스키마 v3(additionalProperties:false 봉인) |
|
||||
| `domains/_common/common_worker_contract.md` | md | 3,766 | A0 | rank 10 공통 worker 계약 조각 |
|
||||
| `domains/{domain_id}/seed_prompt_overlay.md` | md ×25 | 1,026~5,095 (총 83,177) | A0 | 도메인별 프롬프트 overlay 조각 — config의 `prompt_overlay_ref`가 선언한 경로 추적(실패 시 경고). EC-00은 대신 `common_fragment.md`(1,850B) 보유 |
|
||||
| `signals/compiler/{common, projections, schema_validator, signal_compiler, signal_gate, transaction_writer, writer_boundary}.txt` | txt(py 미러) ×7 | 1,089~11,095 (총 37,276) | S0 | signal 컴파일러 모듈 — `/tmp/s1/_sig/pkg/signals/compiler/`로 실체화. **파일 기록 권한은 transaction_writer 하나**(canonical_writer_uniqueness) |
|
||||
| `signals/adapters/{s3_domain_seed_adapter, s3_envelope_migration_adapter, s4_calculation_adapter}.txt` | txt(py 미러) ×3 | 1,071~7,223 (총 9,578) | S0 | 어댑터 모듈(sg01은 공통표 참조 — S0 어댑터 4종 반입에 포함) |
|
||||
| `signals/emitters/{emitter_runtime, emit_sg02..emit_sg13}.txt` | txt(py 미러) ×13 | 287~7,687 (총 11,131) | S0 | 생성기(emitter) — SG-02~SG-13 12종 + 공용 런타임 |
|
||||
| `signals/schemas/*.json` (signal_manifest·domain_signal_envelope.v2·SG별 12종 등 15종) + `signals/_common/{signal_item, evidence_slot_status}.schema.json` 2종 | json ×17 | 1,133~3,535 (총 28,476) | S0 | registry 선언에서 출발한 **상대 $ref 폐포 17종** — 목록 상수화 금지(F-4c), registry가 동적으로 결정 |
|
||||
|
||||
## 4. Part 3 전용 정적 자산
|
||||
|
||||
| 배포 위치 (`Default_Agent/` 이하) | 형태 | 크기(B) | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `stage1_runtime/structure_index_compiler.txt` | txt(py 미러) | 27,309 | L0 | **구조 seed 컴파일 모듈**(compile_structure_seeds) — Θ 조립·구조 seed·signal 조인. "판정 규칙을 YAML에 쓰지 않는다" |
|
||||
| `stage1_runtime/structure_index_policy.v1.json` | json | 7,032 | L0/L2 | 구조 색인 정책(`stage1_structure_index_policy.v1`) — 불일치 시 PART3_POLICY_INVALID |
|
||||
| `platform/schemas/structure_seed_bundle.schema.json` | json | 9,128 | L0 | seed bundle 닫힌 스키마 — theta·admission_policy 인지 능력검사(PART3_STRUCTURE_SCHEMA_STALE) |
|
||||
| `platform/schemas/legal_effect_structures.schema.json` | json | 6,809 | L0(게이트만)/L2 | 최종 색인 닫힌 스키마 — by_module·by_bo_id 인지 능력검사(PART3_INDEX_SCHEMA_STALE) |
|
||||
| `domains/{domain_id}/structure_types.json` | json ×25 | 390~1,360 (총 21,006) | L0 | 도메인 사이드카 1 — 구조 유형 정의. structure_types 선언 있는 도메인만 반입, 부재·미등재는 경성 실패 |
|
||||
| `domains/{domain_id}/module_role_projection.json` | json ×25 | 382~1,196 (총 18,248) | L0 | 도메인 사이드카 2 — 모듈 역할 사영. 위와 동일 규율 |
|
||||
|
||||
## 5. 사건 입력 자산 (실행 전 사건 워크스페이스에 존재해야 함)
|
||||
|
||||
| 배포 위치 (워크스페이스 루트 이하) | 형태 | 크기 | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `client_meeting.md` | md | 사건별 | P1 T0-01/T0-02/T1/T3/T4 · P2 A0 | 상담록 — "유일한 사실 원천". source unit(MTG.*) 채번·재산출 대조, meeting_clause_ids의 원천 |
|
||||
| `evidence_all.json` | json | 사건별 | P1 T2 | 증거 문서 전체 배열 — 배열 순서 = ordinal 부여 기준(array_order, 법적 재정렬 금지) |
|
||||
|
||||
## 6. 실행 중 생성 산출물 (전부 사건 워크스페이스 루트 이하; 크기 = 실행 생성)
|
||||
|
||||
### 6.1 Part 1 산출 (생산 → 소비)
|
||||
|
||||
| 위치 | 형태 | 생산 → 소비 | 비고 (스키마/역할) |
|
||||
|---|---|---|---|
|
||||
| `routing/domain_screening_draft.json` | json | T0-01 → T0-02 | 스크리닝 개방형 초안(판단 4종). `stage1_domain_screening_draft.v1` |
|
||||
| `routing/domain_screening.json` | json | T0-02 → T0-03/T1/D0/T9 · **P2 A0** | 봉인된 닫힌 스키마 스크리닝(`stage1_domain_screening.v1`, 비판단 6종 부착). T9·P2가 원문 sha256 봉인 대조 |
|
||||
| `routing/candidate_profile_vocabulary.md` | md | T0-03 → T1 · **P2 A0**(부재 허용) | 후보 도메인 낱말 목록(E\|O\|V\|D\|R 줄, 예산 28,000B) — "registry 원문이 정본, 이 파일은 파생본" |
|
||||
| `client_goal.json` | json | T1 → (Part 1 내 소비 없음, 후속 스테이지용) | 고객 소송목적·당사자·사건군 구조화 + domain_profiles. D0 입력 6종에 불포함 |
|
||||
| `evidence_shard_plan.json` | json | T2 → T5/T6 | fan-out/배리어/stale 정책 플랜(`evidence_shard_plan.v1`). stdout의 dynamic_fanout을 오케스트레이터가 소비 |
|
||||
| `evidence_shards/E-{nnn}.json` | json ×N | T2 → T3/T4 (T5 발췌) | 문서별 단일 evidence shard — mapper가 풀 대신 자기 shard만 읽도록 분리 |
|
||||
| `evidence_indexed_parts/E-{nnn}.json` | json ×N | T3 → T4/T5 | B1 mapper part(`evidence_indexed_part.v4`) |
|
||||
| `evidence_event_candidate_parts/E-{nnn}.json` | json ×N | T4 → T6 | B2 mapper part(`evidence_event_candidate_part.v4`) |
|
||||
| `evidence_indexed.json` | json | T5 → D0/T9 · **P2 A0** | 최종 증거 authority catalog(`evidence_indexed.v3`) — 작성은 quality gate 단독 권한 |
|
||||
| `evidence_event_candidates.json` | json | T6 → D0/T9 · **P2 A0** | 최종 event/state candidate(`evidence_event_candidates.v1`) |
|
||||
| `stage1_tmp/quality_gate/finalized_evidence_id_manifest.json` | json | T5 → T6 | 확정 evidence id 집합 + dropped_aliases(`finalized_evidence_id_manifest.v1`) |
|
||||
| `stage1_tmp/quality_gate/B1_precheck.json` | json | T5 → T6/T8 | B1 결정적 검사·suspects(`B1_precheck.v1`) |
|
||||
| `stage1_tmp/quality_gate/B2_precheck.json` | json | T6 → T8 | B2 결정적 검사·suspects(`B2_precheck.v1`) |
|
||||
| `stage1_tmp/quality_gate/B12_exception_pack.json` | json | T6 → T7(preflight)/T8 | GB 판정용 compact exception pack(`B12_exception_pack.v1`) — T7의 유일 입력 |
|
||||
| `stage1_tmp/quality_gate/B12_adjudication_decisions.json` | json | T7 → T8 | exception별 LLM 판정(`B12_adjudication_decisions.v1`) |
|
||||
| `quality_gates/B1_evidence_indexed_gate.json` | json | T8 → D0/T9 | B1 최종 audit(`B1_quality_gate.v3`) |
|
||||
| `quality_gates/B2_event_candidates_gate.json` | json | T8 → D0/T9 | B2 최종 audit(`B2_quality_gate.v3`) |
|
||||
| `routing/domain_activation_manifest.json` | json | D0 → T9 · **P2 A0/S0 · P3 L0/L2** | 도메인 활성 확정 매니페스트 — 모듈 산출 바이트 그대로 업로드(재직렬화 금지). execution_eligible·expected_runnable_domain_ids·registry_index_sha256(SG-01 봉인) |
|
||||
| `quality_gates/stage1_part1_soft_gate_handoff.json` | json | T9 → OUT · **P2 A0** | soft gate handoff sidecar(`stage1_part1_soft_gate_handoff.v1`) — digest_guard 7종·활성봉인 교차검증·review 큐 |
|
||||
|
||||
### 6.2 Part 2 산출
|
||||
|
||||
| 위치 | 형태 | 생산 → 소비 | 비고 (스키마/역할) |
|
||||
|---|---|---|---|
|
||||
| `runtime/compiled_prompts/{domain_id}.md` | md ×도메인 | A0 → worker(preflight) | 도메인별 조립 프롬프트(rank 10→50 합성) — 재조립 금지. 워크스페이스+로컬 이중 기록 |
|
||||
| `runtime/domain_slices/{domain_id}.json` | json ×도메인 | A0 → worker/R0/S0 · **P3 L0(옵션)** | 도메인 slice(`task_c_bo_stage_b_domain_slice.v2`) — source_universe·allowed_legal_effect_bo_types의 원천 |
|
||||
| `runtime/domain_seed_outputs/{domain_id}.json` | json ×도메인 | worker → R0/S0 | worker seed(`task_c_bo_stage_b_domain_bo_seed.v3`) — **기록자는 워커 유일**(R0 되쓰기 금지) |
|
||||
| `fanout/domain_fanout_plan.json` | json | A0 → R0/S0 (+오케스트레이터 {{item}} 주입원) | fan-out 계획(`domain_fanout_plan.v1`) — task_instances[]가 worker 인스턴스 생성, barrier 기대집합=expected_runnable |
|
||||
| `stage1_tmp/task_c_bo/stage_a_context.json` | json | A0 → R0/F0 | stage_a_context(`task_c_bo_stage_a_context.v1`) — P-1 개정으로 구 경로 유지 |
|
||||
| `stage1_tmp/task_c_bo/source_universe_manifest.json` | json | A0 → R0/S0 | 원천 우주 매니페스트(evidence_index_set·event_candidate_ids·meeting_clause_ids) |
|
||||
| `validation_assets/routing/stage_receipt.json` | json | A0 | 스테이지 영수증(`stage1_stage_receipt.v2`) — schema_injection·deployment_gate 실측 기록 |
|
||||
| `stage1_tmp/task_c_bo/postb_seed_ledger.json` | json | R0 → F0 | 원장(`task_c_bo_postb_seed_ledger.v1`): 투영 ledger_candidates + deterministic_decisions |
|
||||
| `quality_gates/stage1_part2_exception_pack.json` | json | R0 → R1(preflight, 유일 입력)/F0 | 예외 pack(`stage1_part2_exception_pack.v1`) — budget 8후보/2,000자 |
|
||||
| `quality_gates/stage1_part2_review_handoff.json` | json | R0 → F0(읽고 되씀) | 검토 핸드오프(`stage1_part2_review_handoff.v1`): PENDING_FINALIZE → FINALIZED |
|
||||
| `stage1_tmp/task_c_bo/postb_adjudication_decisions.json` | json | R1 → F0 | R1 판정(`task_c_bo_postb_exception_adjudication.v1`) — 예외 없어도 no-exception 객체 필수 |
|
||||
| `BO.json` | json | F0(기록+재읽기) → S0 · **P3 L0/L2** | **최종 BO 배열**(bh1..bhN) — 워크스페이스 루트. P3 보존 등식의 BO 계수 원본. 무봉인 입력(P3 receipt에 관찰 기록) |
|
||||
| `stage1_tmp/task_c_bo/postb_compiled_bundle_compact.json` | json | F0 | compact bundle(`task_c_bo_postb_compiled_bundle_compact.v1`): ref→bo_id 표·정규화 노트 |
|
||||
| `signals/signal_manifest.json` | json | S0(기록+재읽기 해시 대조) → **P3 L0**(진입 봉인; L2는 재독 금지) | signal 거래 매니페스트 — transaction_id `S5TX-[a-f0-9]{20}`, files[].file_sha256, downstream_read_sets. files[].path에는 `signals/` 접두 없음(붙여서 대조) |
|
||||
| `signals/**/*.json` (거래 산출 전량) | json | S0 → **P3 L0** | 정본 signal 번들 — `/tmp/s1/_signal_out`에 쓰고 `signals/` 접두로 바이트 그대로 반출. 파일명이 코드에 박힌 것은 SG-05/08/13 셋뿐, 나머지는 emitter 12종+registry가 결정. P3 소비 확인분: `legal_effect_routes.json`(SG-13, L0 조인 주근거+L2 route 보존 등식), `legal_relation_lifecycle_signals.json`(SG-05), `calculation_requirements.json`(SG-11), `procedural_posture_relief_signals.json`(SG-02, 빈 read set), `asset_right_state_signals.json`(SG-07, 빈 read set), `domain_signals/{domain_id}.json`(옵션) |
|
||||
| `signals/compatibility_views/{actio_case, case_liability, legal_effect}_signals.json` | json ×3 | S0 | 호환 뷰 — actio_case(사영원 없음), case_liability(SG-05·08 사영), legal_effect(SG-13 사영) |
|
||||
| `actio_case_signals.json` · `case_liability_signals.json` · `legal_effect_signals.json` (워크스페이스 루트) | json ×3 | S0 | 구 이름 별칭 — Part 3·4 최대 호환면, compatibility_views와 바이트 동일 |
|
||||
|
||||
### 6.3 Part 3 산출
|
||||
|
||||
| 위치 | 형태 | 생산 → 소비 | 비고 (스키마/역할) |
|
||||
|---|---|---|---|
|
||||
| `stage1_tmp/task_le/structure_seed_bundle.json` | json | L0 → L2 | seed bundle(`stage1_structure_seed_bundle.v1`): theta·structure_records·counts + signal_manifest_transaction_id 승계 — L0→L2 유일한 중간 계약 |
|
||||
| `quality_gates/stage1_part3_review_handoff.json` | json | L0 → L2(읽고 되씀) | 검토 핸드오프(`stage1_part3_review_handoff.v1`): OPEN → FINALIZED. review_items 근거 없는 감축 금지 |
|
||||
| `validation_assets/routing/part3_receipt.json` | json | L0 | P3-L0 실측 영수증(`stage1_part3_receipt.v1`) — "상수 PASS는 증거가 아니다". L2는 receipt 미작성 |
|
||||
| `legal_effect_structures.json` | json | L2(기록+재읽기 sha256 대조) → OUT | **Stage 1 최종 산출** — 법률효과 구조 색인(`stage1_legal_effect_structures.v1`): theta·structure_records·structure_index(by_domain_id/by_module/by_bo_id)·quality_gate(보존등식 3종). 워크스페이스 루트, canonical JSON |
|
||||
|
||||
## 7. 참조 전용·빌드타임 자산 (런타임 파일 접근 없음)
|
||||
|
||||
| 자산 | 물리 위치 | 형태/크기(B) | 인용처 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| `SKILL.md` | 경로 미명시(유일하게 접두 없는 인용) | md | P1·P2·P3 code-executor 보일러플레이트 주석("5장/5.2장", "§3.3 stdout 규약") | localdocs·code-executor 사용 규약 문서 |
|
||||
| `platform/schemas/domain_screening.schema.json` | 선행구축 트리(예: `선행구축/Default_Agent_Stage_1/platform/schemas/`) — **extension_research/Default_Agent에는 없음** | json | P1 T0-02 주석 | screening_policy/contract_guards const의 정본 — 값은 코드에 하드코딩, 런타임에 읽지 않음 |
|
||||
| `tools/build_default_agent_stage1.py` | `ver_8_yaml_candidates/Default_Agent_Stage_1/tools/` | py / 102,559 | P1 헤더(미러 규칙의 유일 예외) | Default_Agent 빌더 |
|
||||
| `routing/_build_extension_payload_declarations.py` | `ver_8_yaml_candidates/Default_Agent_Stage_1/routing/` | py / 8,842 | P2 F0 주석 | 확장 payload 선언표(공통표 #8)의 생성기 — 배포 시점 접이 |
|
||||
| `validation_assets/routing/_check_schema_keyword_support.py` | `ver_8_yaml_candidates/Default_Agent_Stage_1/validation_assets/routing/` | py / 8,233 | P2 A0 receipt 필드 | 키워드 지원 점검 스크립트 — receipt에 이름만 인용, 실행하지 않음 |
|
||||
| 전략·명세 문서(`stage_1_update_strategy.md`, `P1-T2_to_T9_update_strategy.md`, `Part_1/2_Improvement_Strategy_Claude_v1.md`, `stage_1_part_2_optimal_update_strategy_v.2.md`, `stage_1_part_3_개정_신전략서.md` 등) 및 조각 출처 YAML(`Task_A_client_goal_v4.yml` 등) | `v.7/` 및 `ver_8_yaml_candidates/` 일대 | md/yml | 각 YAML 헤더·코드 주석 | 정본 근거 설계 문서 — 런타임 미접근 |
|
||||
|
||||
## 8. 특기사항 (판독 중 확인된 사실)
|
||||
|
||||
1. **게이트 전용 자산**: `signal_registry.v2.json`·`s5_execution_contract.v2.json`은 P3에서 등재·해시·가독 검사만 받고 어느 태스크도 파싱하지 않음. P2 A0의 PART2_REQUIRED_ASSETS는 10종이며, 그중 A0 자신이 소비하는 4종(slice 스키마·fanout 스키마·공통 계약·조립 정책)을 제외한 후속 task용 6종(# R0/S0/F0 주석 표기분)은 A0에서 존재·해시 게이트만 수행(배포 요구 선언).
|
||||
2. **R0의 죽은 상수 2개**: `routing/domain_activation_manifest.json`·`Default_Agent/domains/_registry_index.json`은 P2 R0에 상수로만 선언되고 main에서 미사용(잔재).
|
||||
3. **P2 머리말·본문 모순**: "구 경로 `stage1_tmp/task_c_bo/**`는 쓰지 않는다(legacy_paths_forbidden)"고 하나 실제로는 stage_a_context·source_universe(P-1 복귀) + postb_* 3종이 그 경로를 계속 사용. 금지는 사실상 worker slice/seed 구 경로에만 해당.
|
||||
4. **`domains/_registry_index.json`은 runtime_manifest 미등재** — 교체 탐지는 SG-01 봉인(activation manifest의 registry_index_sha256) 하나가 담당(P3 주석 명시).
|
||||
5. **L2는 `signals/signal_manifest.json`을 재독하지 않음** — bundle의 signal_manifest_transaction_id를 승계(§4.3 입력 계약 밖).
|
||||
6. **P3 L1 부재는 의도적** — "판정 부류가 생기면 L0–L2 사이에 끼운다"(task_procedure 주석). P3는 IN→L0→L2→OUT 완전 직렬.
|
||||
7. **worker는 유일한 LLM-파일기록 task**(P2) — seed 파일 기록자는 워커 하나로 못박혀 있고 R0는 되쓰지 않음.
|
||||
8. **P3 YAML 헤더 24행 훼손 의심**("`# 137종 —`" 라벨 잔흔) 및 **code-executor Bearer 토큰 평문 하드코딩**(P2·P3 공통 구조, P3 48행 확인) — 배포 전 정리 필요.
|
||||
같은 회차의 YAML 측 작업(P2 R0 사문 상수 2줄 삭제 · legacy_paths 주석 한정)은 이 문서의 범위 밖이며 `stage_1_part_1_and_2_updated_yaml_analysis.md` 머리말과 v.2 §2-A 에 기록돼 있다.
|
||||
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
# Stage 1 Part 1·2·3 자산 배포 위치 총람
|
||||
|
||||
- 근거: `stage_1_part_1_v.8.yml`(6,668행) · `stage_1_part_2_v.8.yml`(3,315행) · `stage_1_part_3_v.8.yml`(1,038행) 전량 판독 + 배포 트리 실측 (2026-08-20)
|
||||
- 크기: 배포 원본 트리(`v.7/extension_research/Default_Agent/`)에서 실측한 바이트 수. 실행 중 생성 산출물은 사건마다 달라져 "실행 생성"으로 표기.
|
||||
- 표기: P1 = Part 1(사건개요파악·기초작업), P2 = Part 2(BO·시그널 생성), P3 = Part 3(법률효과구조 생성)
|
||||
|
||||
---
|
||||
|
||||
## 0. 배포 루트 3계층 (세 YAML 공통 규약)
|
||||
|
||||
| 계층 | 위치 | 성격 |
|
||||
|---|---|---|
|
||||
| ① 정적 자산 루트 (`ASSET_ROOT`) | localdocs 논리 접두 **`Default_Agent/`** ← 배포 원본 **`v.7/extension_research/Default_Agent/`** 트리(210파일, .DS_Store 제외)를 통째로 배포 | P2·P3 remedy 명문: "배포 원본 extension_research/Default_Agent 트리를 서버 Default_Agent/에 통째로 배포하고 runtime_manifest.json의 등재·sha256과 대조. **부분 복사 불허**" |
|
||||
| ② 사건 워크스페이스 루트 | localdocs 문서 루트 (clientInfo에 `{{__user_hash__}}`/`{{__workspace_hash__}}` 필수 — 빠지면 루트 경로를 봄) | 접두 없는 상대경로 전부: `client_meeting.md`, `BO.json`, `routing/`, `quality_gates/`, `signals/`, `runtime/`, `fanout/`, `stage1_tmp/`, `validation_assets/`, `evidence_*` … |
|
||||
| ③ 실행 샌드박스 | code-executor 컨테이너 `EXECUTION_ROOT=/tmp/s1` (R0만 `/tmp/s1_r0`) — 모듈 반입처 `_rt/`, S0 signal 패키지 `_sig/`·`_signal_out/` | 임시 스테이징. 배포 대상 아님. 실행 인자 계약 `--asset-root/--execution-root/--logical-root` (D-5 §2.4 0-c-2) |
|
||||
|
||||
**모듈 미러 규약**: localdocs가 `.py`를 서빙하지 않으므로 모든 런타임 `.py`는 **같은 디렉터리에 바이트 동일 `.txt` 미러**로 배포된다(유일 예외 = 빌더 `build_default_agent_stage1.py`). 반입 시 `Default_Agent/runtime_manifest.json`의 sha256과 대조하고 불일치면 실행 금지. 아래 표의 `.txt` 미러는 전부 `.py` 정본이 같은 디렉터리에 병존한다(크기 동일).
|
||||
|
||||
**runtime_manifest.json**: `stage1_runtime_manifest.v1`, 426건 등재. computations/ 등 Stage 1 Part 1~3 밖 자산도 등재되어 있으며 그 물리 실체는 `extension_research/선행구축/Default_Agent_Stage_1/`(1,322파일) 및 `ver_8_yaml_candidates/Default_Agent_Stage_1/`(560파일, 빌드·검증 산출 트리)에 있다. P1~P3 게이트는 각 Part가 선언한 필수 자산 목록에 대해서만 등재·sha256·가독을 검사한다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 공통자산 — 2개 Part 이상이 사용하는 사전배포 정적 자산 (`Default_Agent/`)
|
||||
|
||||
| 배포 위치 (`Default_Agent/` 이하) | 형태 | 크기(B) | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `runtime_manifest.json` | json | 66,526 | P1 D0 · P2 A0/R0/F0/S0 · P3 L0/L2 | 해시 장부(`stage1_runtime_manifest.v1`, entries[].path+sha256). 모든 모듈 반입·배포 게이트의 단일 근거. entries[].path는 `Default_Agent/` 접두를 뗀 상대경로 |
|
||||
| `domains/_registry_index.json` | json | 18,921 | P1 T0-02/T0-03/D0/T9 · P2 A0 · P3 L0/L2 | 도메인 registry 색인 정본(registry_version, entries[].domain_id/config_path/config_sha256). 원문 read_raw sha256이 스크리닝·활성 매니페스트·핸드오프에 봉인됨. **매니페스트 미등재 — SG-01 봉인(activation manifest의 registry_index_sha256)이 교체를 잡음**. P2 R0에는 상수로만 선언(미사용) |
|
||||
| `domains/{domain_id}/domain_config.json` | json ×26 | 2,468~17,324 (총 274,372) | P1 T0-03(후보만)/D0(전 26) · P2 A0 · P3 L0/L2(expected_runnable만) | 도메인별 config: 요건 슬롯·상대사실·증거 구성요소·항변·계산 바인딩·검토코드·structure_types 선언. registry index의 config_path만 따라 열람, config_sha256 사슬 대조. **LLM task(P1 T0-01·T1)는 직접 읽기 금지** |
|
||||
| `stage1_runtime/runtime_common.txt` | txt(py 미러) | 4,496 | P1 D0 · P2 A0/R0 · P3 L0/L2 | 런타임 공용 모듈. `/tmp/s1/_rt/*.py`로 실체화 후 sys.path 삽입 |
|
||||
| `stage1_runtime/schema_subset_validator.txt` | txt(py 미러) | 7,442 | P1 D0 · P2 A0/R0 · P3 L0/L2 | 닫힌 스키마 부분집합 검증기 — 산출물 스키마 검증의 공용 엔진 |
|
||||
| `stage1_runtime/registry_loader.txt` | txt(py 미러) | 6,404 | P1 D0 · P2 A0/R0 · P3 L0 | registry 적재기(load_registry). P3 L0은 compiler 의존 모듈로만 스테이징 |
|
||||
| `routing/evidence_component_union.md` | md | 17,593 | P1 T3(preflight) · P2 worker(어휘 참조) | 증거 구성요소 어휘 합집합(component_id + accepted_source_kinds + owner). `registry_component_ids`의 유일 허용 어휘 — 목록 밖 이름 생성 금지 |
|
||||
| `routing/extension_payload_key_declarations.v1.json` | json | 23,071 | P2 A0(게이트)/F0 · P3 L0 | BOType 합집합·확장 payload declared_key_union·legacy_alias_targets 선언표(`stage1_extension_payload_key_declarations.v1`). 생성기 `routing/_build_extension_payload_declarations.py`(배포 시점 접이, 런타임 미실행) |
|
||||
| `signals/signal_registry.v2.json` | json | 10,907 | P2 A0(게이트)/S0 · P3 L0(게이트만) | signal registry v2 — S0 스키마 $ref 폐포 walk의 출발점. P3에서는 배포 완전성 검사만 받고 파싱되지 않음 |
|
||||
| `contracts/signals/s5_execution_contract.v2.json` | json | 1,451 | P2 A0(게이트)/S0 · P3 L0(게이트만) | S5 실행 계약 — S0가 `/tmp/s1/_sig/contracts/`에 배치(모듈의 parents[1]/contracts 산술 재현). P3에서는 게이트 전용 |
|
||||
| `signals/adapters/sg01_activation_adapter.txt` | txt(py 미러) | 3,738 | P1 D0 · P2 S0 | SG-01 활성 어댑터 — D0 산출 매니페스트 자기검증(adapt_and_validate). 미러 위치는 `stage1_runtime/`이 아니라 `signals/adapters/`(YAML 헤더 명시) |
|
||||
| `signals/schemas/domain_activation_manifest.schema.json` | json | 3,535 | P1 D0(stage, 실패 시 경고) · P2 S0(registry가 결정하는 $ref 폐포에 포함 — 배포된 signal_registry.v2.json 등재 기준) | 활성 매니페스트 스키마 — D0 모듈은 직접 읽지 않음(어댑터가 검증 담당). §3의 폐포 17종 집계(28,476B)에 이 파일이 포함되므로 바이트 합산 시 중복 주의 |
|
||||
|
||||
## 2. Part 1 전용 정적 자산
|
||||
|
||||
| 배포 위치 (`Default_Agent/` 이하) | 형태 | 크기(B) | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `routing/activation_cue_digest.md` | md | 35,110 | T0-01(preflight)/T0-02 | 라우팅 단어 사전 — 26개 도메인 활성 단서(P/N/C/OVR)+GLOBAL_DEFAULTS. "사실 원천이 아니다". 머리말에 registry_version·registry_index sha256 → 스냅숏 낡음 감지 |
|
||||
| `platform/schemas/client_goal_domain_profiles.schema.json` | json | 13,082 | T1(preflight) | client_goal의 domain_profiles 칸 형태를 정하는 닫힌 스키마 — "형식만 정하고 내용은 만들지 않음" |
|
||||
| `platform/reference_catalogs/domain_ids.json` | json | 270 | T0-03 | 도메인 ID 카탈로그 — 후보 멤버십 검사 |
|
||||
| `platform/reference_catalogs/calculation_ids.json` | json | 1,139 | T0-03 | 계산 ID 카탈로그(entries[].calculation_id/status) — calc 바인딩 존재·ready 검사 |
|
||||
| `stage1_runtime/activation_gate.txt` | txt(py 미러) | 66,715 | D0 | **도메인 활성 판정 모듈 본체** — "판정은 이 안에서만 일어난다. 결정 필드는 execution_eligible 하나뿐". main(--asset-root/--execution-root/--logical-root) 호출 |
|
||||
| `platform/contracts/determinism_scope_contract.json` | json | 1,473 | (헤더 선행조건만) | 결정론 범위 계약 — P1 정적 자산 선행 조건 5종의 하나. task 본문 직접 등장 없음(모듈 내부 소비 추정) |
|
||||
| `validation_assets/routing/case_kind_domain_matrix.v2.json` | json | 72,969 | **읽기 금지** (T0-01·T1에 금지 명문) | 사건유형 이름을 담은 **오프라인 회귀 전용** 자산 — 런타임 입력 금지 |
|
||||
|
||||
## 3. Part 2 전용 정적 자산
|
||||
|
||||
| 배포 위치 (`Default_Agent/` 이하) | 형태 | 크기(B) | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `stage1_runtime/registry_validator.txt` | txt(py 미러) | 11,080 | A0 | registry 검증기(validate_registry) — overlay 4개 오류코드만 경성 |
|
||||
| `stage1_runtime/prompt_compiler.txt` | txt(py 미러) | 15,164 | A0 | 프롬프트 조립기 — FragmentSpec/collect_domain_fragments/compile_fragments, rank 10→50 합성, 상한 96,000B/24,000자 |
|
||||
| `stage1_runtime/domain_slice_compiler.txt` | txt(py 미러) | 32,300 | A0 | slice 컴파일러(compile_domain_slices) — 낡으면 PART2_COMPILER_STALE |
|
||||
| `stage1_runtime/domain_fanout_planner.txt` | txt(py 미러) | 12,282 | A0 | fan-out 계획기(build_fanout_plan) |
|
||||
| `stage1_runtime/stage_a_context_builder.txt` | txt(py 미러) | 25,885 | A0 | stage_a_context/source_universe_manifest 빌더(v3 세 builder 이식) |
|
||||
| `stage1_runtime/worker_output_validator.txt` | txt(py 미러) | 21,302 | A0(게이트)/R0 | worker seed 산출 검증기(validate_worker_output; schema·slice 주입). 반입 실패는 경고 강등 |
|
||||
| `stage1_runtime/prompt_composition_policy.json` | json | 1,715 | A0 | 프롬프트 조립 정책(rank 순서·상한) |
|
||||
| `stage1_runtime/bo_surface_projection_policy.v1.json` | json | 6,355 | A0(게이트)/R0/F0 | BO 투영 정책(`stage1_bo_surface_projection_policy.v1`) — f0_normalization·review_item_projection 규칙 정본 |
|
||||
| `platform/schemas/domain_slice.schema.v2.json` | json | 17,725 | A0 | slice 스키마 — F-3 능력검사(stage_b_domain_slice.domain_declarations·compiled_prompt.hash_kind 필수) |
|
||||
| `platform/schemas/domain_fanout_plan.schema.json` | json | 11,148 | A0 | fan-out 계획 스키마(build_fanout_plan에 주입) |
|
||||
| `platform/schemas/domain_seed_output.schema.v3.json` | json | 21,965 | A0(게이트)/worker(참조)/R0 | worker seed 산출 스키마 v3(additionalProperties:false 봉인) |
|
||||
| `domains/_common/common_worker_contract.md` | md | 3,766 | A0 | rank 10 공통 worker 계약 조각 |
|
||||
| `domains/{domain_id}/seed_prompt_overlay.md` | md ×25 | 1,026~5,095 (총 83,177) | A0 | 도메인별 프롬프트 overlay 조각 — config의 `prompt_overlay_ref`가 선언한 경로 추적(실패 시 경고). EC-00은 대신 `common_fragment.md`(1,850B) 보유 |
|
||||
| `signals/compiler/{common, projections, schema_validator, signal_compiler, signal_gate, transaction_writer, writer_boundary}.txt` | txt(py 미러) ×7 | 1,089~11,095 (총 37,276) | S0 | signal 컴파일러 모듈 — `/tmp/s1/_sig/pkg/signals/compiler/`로 실체화. **파일 기록 권한은 transaction_writer 하나**(canonical_writer_uniqueness) |
|
||||
| `signals/adapters/{s3_domain_seed_adapter, s3_envelope_migration_adapter, s4_calculation_adapter}.txt` | txt(py 미러) ×3 | 1,071~7,223 (총 9,578) | S0 | 어댑터 모듈(sg01은 공통표 참조 — S0 어댑터 4종 반입에 포함) |
|
||||
| `signals/emitters/{emitter_runtime, emit_sg02..emit_sg13}.txt` | txt(py 미러) ×13 | 287~7,687 (총 11,131) | S0 | 생성기(emitter) — SG-02~SG-13 12종 + 공용 런타임 |
|
||||
| `signals/schemas/*.json` (signal_manifest·domain_signal_envelope.v2·SG별 12종 등 15종) + `signals/_common/{signal_item, evidence_slot_status}.schema.json` 2종 | json ×17 | 1,133~3,535 (총 28,476) | S0 | registry 선언에서 출발한 **상대 $ref 폐포 17종** — 목록 상수화 금지(F-4c), registry가 동적으로 결정 |
|
||||
|
||||
## 4. Part 3 전용 정적 자산
|
||||
|
||||
| 배포 위치 (`Default_Agent/` 이하) | 형태 | 크기(B) | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `stage1_runtime/structure_index_compiler.txt` | txt(py 미러) | 27,309 | L0 | **구조 seed 컴파일 모듈**(compile_structure_seeds) — Θ 조립·구조 seed·signal 조인. "판정 규칙을 YAML에 쓰지 않는다" |
|
||||
| `stage1_runtime/structure_index_policy.v1.json` | json | 7,032 | L0/L2 | 구조 색인 정책(`stage1_structure_index_policy.v1`) — 불일치 시 PART3_POLICY_INVALID |
|
||||
| `platform/schemas/structure_seed_bundle.schema.json` | json | 9,128 | L0 | seed bundle 닫힌 스키마 — theta·admission_policy 인지 능력검사(PART3_STRUCTURE_SCHEMA_STALE) |
|
||||
| `platform/schemas/legal_effect_structures.schema.json` | json | 6,809 | L0(게이트만)/L2 | 최종 색인 닫힌 스키마 — by_module·by_bo_id 인지 능력검사(PART3_INDEX_SCHEMA_STALE) |
|
||||
| `domains/{domain_id}/structure_types.json` | json ×25 | 390~1,360 (총 21,006) | L0 | 도메인 사이드카 1 — 구조 유형 정의. structure_types 선언 있는 도메인만 반입, 부재·미등재는 경성 실패 |
|
||||
| `domains/{domain_id}/module_role_projection.json` | json ×25 | 382~1,196 (총 18,248) | L0 | 도메인 사이드카 2 — 모듈 역할 사영. 위와 동일 규율 |
|
||||
|
||||
## 5. 사건 입력 자산 (실행 전 사건 워크스페이스에 존재해야 함)
|
||||
|
||||
| 배포 위치 (워크스페이스 루트 이하) | 형태 | 크기 | 쓰는 task | 비고 (역할) |
|
||||
|---|---|---|---|---|
|
||||
| `client_meeting.md` | md | 사건별 | P1 T0-01/T0-02/T1/T3/T4 · P2 A0 | 상담록 — "유일한 사실 원천". source unit(MTG.*) 채번·재산출 대조, meeting_clause_ids의 원천 |
|
||||
| `evidence_all.json` | json | 사건별 | P1 T2 | 증거 문서 전체 배열 — 배열 순서 = ordinal 부여 기준(array_order, 법적 재정렬 금지) |
|
||||
|
||||
## 6. 실행 중 생성 산출물 (전부 사건 워크스페이스 루트 이하; 크기 = 실행 생성)
|
||||
|
||||
### 6.1 Part 1 산출 (생산 → 소비)
|
||||
|
||||
| 위치 | 형태 | 생산 → 소비 | 비고 (스키마/역할) |
|
||||
|---|---|---|---|
|
||||
| `routing/domain_screening_draft.json` | json | T0-01 → T0-02 | 스크리닝 개방형 초안(판단 4종). `stage1_domain_screening_draft.v1` |
|
||||
| `routing/domain_screening.json` | json | T0-02 → T0-03/T1/D0/T9 · **P2 A0** | 봉인된 닫힌 스키마 스크리닝(`stage1_domain_screening.v1`, 비판단 6종 부착). T9·P2가 원문 sha256 봉인 대조 |
|
||||
| `routing/candidate_profile_vocabulary.md` | md | T0-03 → T1 · **P2 A0**(부재 허용) | 후보 도메인 낱말 목록(E\|O\|V\|D\|R 줄, 예산 28,000B) — "registry 원문이 정본, 이 파일은 파생본" |
|
||||
| `client_goal.json` | json | T1 → (Part 1 내 소비 없음, 후속 스테이지용) | 고객 소송목적·당사자·사건군 구조화 + domain_profiles. D0 입력 6종에 불포함 |
|
||||
| `evidence_shard_plan.json` | json | T2 → T5/T6 | fan-out/배리어/stale 정책 플랜(`evidence_shard_plan.v1`). stdout의 dynamic_fanout을 오케스트레이터가 소비 |
|
||||
| `evidence_shards/E-{nnn}.json` | json ×N | T2 → T3/T4 (T5 발췌) | 문서별 단일 evidence shard — mapper가 풀 대신 자기 shard만 읽도록 분리 |
|
||||
| `evidence_indexed_parts/E-{nnn}.json` | json ×N | T3 → T4/T5 | B1 mapper part(`evidence_indexed_part.v4`) |
|
||||
| `evidence_event_candidate_parts/E-{nnn}.json` | json ×N | T4 → T6 | B2 mapper part(`evidence_event_candidate_part.v4`) |
|
||||
| `evidence_indexed.json` | json | T5 → D0/T9 · **P2 A0** | 최종 증거 authority catalog(`evidence_indexed.v3`) — 작성은 quality gate 단독 권한 |
|
||||
| `evidence_event_candidates.json` | json | T6 → D0/T9 · **P2 A0** | 최종 event/state candidate(`evidence_event_candidates.v1`) |
|
||||
| `stage1_tmp/quality_gate/finalized_evidence_id_manifest.json` | json | T5 → T6 | 확정 evidence id 집합 + dropped_aliases(`finalized_evidence_id_manifest.v1`) |
|
||||
| `stage1_tmp/quality_gate/B1_precheck.json` | json | T5 → T6/T8 | B1 결정적 검사·suspects(`B1_precheck.v1`) |
|
||||
| `stage1_tmp/quality_gate/B2_precheck.json` | json | T6 → T8 | B2 결정적 검사·suspects(`B2_precheck.v1`) |
|
||||
| `stage1_tmp/quality_gate/B12_exception_pack.json` | json | T6 → T7(preflight)/T8 | GB 판정용 compact exception pack(`B12_exception_pack.v1`) — T7의 유일 입력 |
|
||||
| `stage1_tmp/quality_gate/B12_adjudication_decisions.json` | json | T7 → T8 | exception별 LLM 판정(`B12_adjudication_decisions.v1`) |
|
||||
| `quality_gates/B1_evidence_indexed_gate.json` | json | T8 → D0/T9 | B1 최종 audit(`B1_quality_gate.v3`) |
|
||||
| `quality_gates/B2_event_candidates_gate.json` | json | T8 → D0/T9 | B2 최종 audit(`B2_quality_gate.v3`) |
|
||||
| `routing/domain_activation_manifest.json` | json | D0 → T9 · **P2 A0/S0 · P3 L0/L2** | 도메인 활성 확정 매니페스트 — 모듈 산출 바이트 그대로 업로드(재직렬화 금지). execution_eligible·expected_runnable_domain_ids·registry_index_sha256(SG-01 봉인) |
|
||||
| `quality_gates/stage1_part1_soft_gate_handoff.json` | json | T9 → OUT · **P2 A0** | soft gate handoff sidecar(`stage1_part1_soft_gate_handoff.v1`) — digest_guard 7종·활성봉인 교차검증·review 큐 |
|
||||
|
||||
### 6.2 Part 2 산출
|
||||
|
||||
| 위치 | 형태 | 생산 → 소비 | 비고 (스키마/역할) |
|
||||
|---|---|---|---|
|
||||
| `runtime/compiled_prompts/{domain_id}.md` | md ×도메인 | A0 → worker(preflight) | 도메인별 조립 프롬프트(rank 10→50 합성) — 재조립 금지. 워크스페이스+로컬 이중 기록 |
|
||||
| `runtime/domain_slices/{domain_id}.json` | json ×도메인 | A0 → worker/R0/S0 · **P3 L0(옵션)** | 도메인 slice(`task_c_bo_stage_b_domain_slice.v2`) — source_universe·allowed_legal_effect_bo_types의 원천 |
|
||||
| `runtime/domain_seed_outputs/{domain_id}.json` | json ×도메인 | worker → R0/S0 | worker seed(`task_c_bo_stage_b_domain_bo_seed.v3`) — **기록자는 워커 유일**(R0 되쓰기 금지) |
|
||||
| `fanout/domain_fanout_plan.json` | json | A0 → R0/S0 (+오케스트레이터 {{item}} 주입원) | fan-out 계획(`domain_fanout_plan.v1`) — task_instances[]가 worker 인스턴스 생성, barrier 기대집합=expected_runnable |
|
||||
| `stage1_tmp/task_c_bo/stage_a_context.json` | json | A0 → R0/F0 | stage_a_context(`task_c_bo_stage_a_context.v1`) — P-1 개정으로 구 경로 유지 |
|
||||
| `stage1_tmp/task_c_bo/source_universe_manifest.json` | json | A0 → R0/S0 | 원천 우주 매니페스트(evidence_index_set·event_candidate_ids·meeting_clause_ids) |
|
||||
| `validation_assets/routing/stage_receipt.json` | json | A0 | 스테이지 영수증(`stage1_stage_receipt.v2`) — schema_injection·deployment_gate 실측 기록 |
|
||||
| `stage1_tmp/task_c_bo/postb_seed_ledger.json` | json | R0 → F0 | 원장(`task_c_bo_postb_seed_ledger.v1`): 투영 ledger_candidates + deterministic_decisions |
|
||||
| `quality_gates/stage1_part2_exception_pack.json` | json | R0 → R1(preflight, 유일 입력)/F0 | 예외 pack(`stage1_part2_exception_pack.v1`) — budget 8후보/2,000자 |
|
||||
| `quality_gates/stage1_part2_review_handoff.json` | json | R0 → F0(읽고 되씀) | 검토 핸드오프(`stage1_part2_review_handoff.v1`): PENDING_FINALIZE → FINALIZED |
|
||||
| `stage1_tmp/task_c_bo/postb_adjudication_decisions.json` | json | R1 → F0 | R1 판정(`task_c_bo_postb_exception_adjudication.v1`) — 예외 없어도 no-exception 객체 필수 |
|
||||
| `BO.json` | json | F0(기록+재읽기) → S0 · **P3 L0/L2** | **최종 BO 배열**(bh1..bhN) — 워크스페이스 루트. P3 보존 등식의 BO 계수 원본. 무봉인 입력(P3 receipt에 관찰 기록) |
|
||||
| `stage1_tmp/task_c_bo/postb_compiled_bundle_compact.json` | json | F0 | compact bundle(`task_c_bo_postb_compiled_bundle_compact.v1`): ref→bo_id 표·정규화 노트 |
|
||||
| `signals/signal_manifest.json` | json | S0(기록+재읽기 해시 대조) → **P3 L0**(진입 봉인; L2는 재독 금지) | signal 거래 매니페스트 — transaction_id `S5TX-[a-f0-9]{20}`, files[].file_sha256, downstream_read_sets. files[].path에는 `signals/` 접두 없음(붙여서 대조) |
|
||||
| `signals/**/*.json` (거래 산출 전량) | json | S0 → **P3 L0** | 정본 signal 번들 — `/tmp/s1/_signal_out`에 쓰고 `signals/` 접두로 바이트 그대로 반출. 파일명이 코드에 박힌 것은 SG-05/08/13 셋뿐, 나머지는 emitter 12종+registry가 결정. P3 소비 확인분: `legal_effect_routes.json`(SG-13, L0 조인 주근거+L2 route 보존 등식), `legal_relation_lifecycle_signals.json`(SG-05), `calculation_requirements.json`(SG-11), `procedural_posture_relief_signals.json`(SG-02, 빈 read set), `asset_right_state_signals.json`(SG-07, 빈 read set), `domain_signals/{domain_id}.json`(옵션) |
|
||||
| `signals/compatibility_views/{actio_case, case_liability, legal_effect}_signals.json` | json ×3 | S0 | 호환 뷰 — actio_case(사영원 없음), case_liability(SG-05·08 사영), legal_effect(SG-13 사영) |
|
||||
| `actio_case_signals.json` · `case_liability_signals.json` · `legal_effect_signals.json` (워크스페이스 루트) | json ×3 | S0 | 구 이름 별칭 — Part 3·4 최대 호환면, compatibility_views와 바이트 동일 |
|
||||
|
||||
### 6.3 Part 3 산출
|
||||
|
||||
| 위치 | 형태 | 생산 → 소비 | 비고 (스키마/역할) |
|
||||
|---|---|---|---|
|
||||
| `stage1_tmp/task_le/structure_seed_bundle.json` | json | L0 → L2 | seed bundle(`stage1_structure_seed_bundle.v1`): theta·structure_records·counts + signal_manifest_transaction_id 승계 — L0→L2 유일한 중간 계약 |
|
||||
| `quality_gates/stage1_part3_review_handoff.json` | json | L0 → L2(읽고 되씀) | 검토 핸드오프(`stage1_part3_review_handoff.v1`): OPEN → FINALIZED. review_items 근거 없는 감축 금지 |
|
||||
| `validation_assets/routing/part3_receipt.json` | json | L0 | P3-L0 실측 영수증(`stage1_part3_receipt.v1`) — "상수 PASS는 증거가 아니다". L2는 receipt 미작성 |
|
||||
| `legal_effect_structures.json` | json | L2(기록+재읽기 sha256 대조) → OUT | **Stage 1 최종 산출** — 법률효과 구조 색인(`stage1_legal_effect_structures.v1`): theta·structure_records·structure_index(by_domain_id/by_module/by_bo_id)·quality_gate(보존등식 3종). 워크스페이스 루트, canonical JSON |
|
||||
|
||||
## 7. 참조 전용·빌드타임 자산 (런타임 파일 접근 없음)
|
||||
|
||||
| 자산 | 물리 위치 | 형태/크기(B) | 인용처 | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| `SKILL.md` | 경로 미명시(유일하게 접두 없는 인용) | md | P1·P2·P3 code-executor 보일러플레이트 주석("5장/5.2장", "§3.3 stdout 규약") | localdocs·code-executor 사용 규약 문서 |
|
||||
| `platform/schemas/domain_screening.schema.json` | 선행구축 트리(예: `선행구축/Default_Agent_Stage_1/platform/schemas/`) — **extension_research/Default_Agent에는 없음** | json | P1 T0-02 주석 | screening_policy/contract_guards const의 정본 — 값은 코드에 하드코딩, 런타임에 읽지 않음 |
|
||||
| `tools/build_default_agent_stage1.py` | `ver_8_yaml_candidates/Default_Agent_Stage_1/tools/` | py / 102,559 | P1 헤더(미러 규칙의 유일 예외) | Default_Agent 빌더 |
|
||||
| `routing/_build_extension_payload_declarations.py` | `ver_8_yaml_candidates/Default_Agent_Stage_1/routing/` | py / 8,842 | P2 F0 주석 | 확장 payload 선언표(공통표 #8)의 생성기 — 배포 시점 접이 |
|
||||
| `validation_assets/routing/_check_schema_keyword_support.py` | `ver_8_yaml_candidates/Default_Agent_Stage_1/validation_assets/routing/` | py / 8,233 | P2 A0 receipt 필드 | 키워드 지원 점검 스크립트 — receipt에 이름만 인용, 실행하지 않음 |
|
||||
| 전략·명세 문서(`stage_1_update_strategy.md`, `P1-T2_to_T9_update_strategy.md`, `Part_1/2_Improvement_Strategy_Claude_v1.md`, `stage_1_part_2_optimal_update_strategy_v.2.md`, `stage_1_part_3_개정_신전략서.md` 등) 및 조각 출처 YAML(`Task_A_client_goal_v4.yml` 등) | `v.7/` 및 `ver_8_yaml_candidates/` 일대 | md/yml | 각 YAML 헤더·코드 주석 | 정본 근거 설계 문서 — 런타임 미접근 |
|
||||
|
||||
## 8. 특기사항 (판독 중 확인된 사실)
|
||||
|
||||
1. **게이트 전용 자산**: `signal_registry.v2.json`·`s5_execution_contract.v2.json`은 P3에서 등재·해시·가독 검사만 받고 어느 태스크도 파싱하지 않음. P2 A0의 PART2_REQUIRED_ASSETS는 10종이며, 그중 A0 자신이 소비하는 4종(slice 스키마·fanout 스키마·공통 계약·조립 정책)을 제외한 후속 task용 6종(# R0/S0/F0 주석 표기분)은 A0에서 존재·해시 게이트만 수행(배포 요구 선언).
|
||||
2. **R0의 죽은 상수 2개**: `routing/domain_activation_manifest.json`·`Default_Agent/domains/_registry_index.json`은 P2 R0에 상수로만 선언되고 main에서 미사용(잔재).
|
||||
3. **P2 머리말·본문 모순**: "구 경로 `stage1_tmp/task_c_bo/**`는 쓰지 않는다(legacy_paths_forbidden)"고 하나 실제로는 stage_a_context·source_universe(P-1 복귀) + postb_* 3종이 그 경로를 계속 사용. 금지는 사실상 worker slice/seed 구 경로에만 해당.
|
||||
4. **`domains/_registry_index.json`은 runtime_manifest 미등재** — 교체 탐지는 SG-01 봉인(activation manifest의 registry_index_sha256) 하나가 담당(P3 주석 명시).
|
||||
5. **L2는 `signals/signal_manifest.json`을 재독하지 않음** — bundle의 signal_manifest_transaction_id를 승계(§4.3 입력 계약 밖).
|
||||
6. **P3 L1 부재는 의도적** — "판정 부류가 생기면 L0–L2 사이에 끼운다"(task_procedure 주석). P3는 IN→L0→L2→OUT 완전 직렬.
|
||||
7. **worker는 유일한 LLM-파일기록 task**(P2) — seed 파일 기록자는 워커 하나로 못박혀 있고 R0는 되쓰지 않음.
|
||||
8. **P3 YAML 헤더 24행 훼손 의심**("`# 137종 —`" 라벨 잔흔) 및 **code-executor Bearer 토큰 평문 하드코딩**(P2·P3 공통 구조, P3 48행 확인) — 배포 전 정리 필요.
|
||||
+10
-10
@@ -3,7 +3,7 @@
|
||||
- 문서 위치: `YAML_Prompts/1. Stage_1/v.7/extension_research/stage_1_part_1_and_2_updated_yaml_analysis.md`
|
||||
- 분석 대상 정본 2종
|
||||
- `ver_8_yaml_candidates/stage_1_part_1_v.8.yml` — 467,668 B / 6,667행 / sha256 `195b43edfaf1df1414acc118c17d544c…`
|
||||
- `ver_8_yaml_candidates/stage_1_part_2_v.8.yml` — **195,938 B / 3,315행 / sha256 `ec4c43027ad85195…`** (2026-08-19 BO 투영 회차 반영본. 직전 판은 193,933 B / 3,307행 / `73644c5620b1bfbc…` — `outdated/stage_1_part_2_v.8.pre_bo_projection.yml` 로 보존)
|
||||
- `ver_8_yaml_candidates/stage_1_part_2_v.8.yml` — **195,963 B / 3,315행 / sha256 `ec407309a5ab43f4…`** (2026-08-20 자산 정리 회차 반영본 — R0 사문 상수 2줄 삭제 · legacy_paths 주석 한정. 값 무변, 예행 산출 바이트 동일. 직전 판 195,938 B / `ec4c43027ad85195…` 는 `outdated/stage_1_part_2_v.8.pre_asset_triage_fix.yml`, 그 전 판은 `outdated/stage_1_part_2_v.8.pre_bo_projection.yml` 로 보존)
|
||||
- 근거 자료: `v.7/MEMORY.md` · `stage_1_part_1_개정작업_리포트.md` · `ver_8_yaml_candidates/part_1_remaining_update_report.md` · `stage_1_part_2_레지스트리기반개정완료_보고서.md` · `ver_8_yaml_candidates/8월12_to_16일작업압축요약본.md`(316,036 B) · `Default_Agent_Stage_1/handoffs/stage1_part_interface.v1.json`(34 인계면 선언표) · `stage_1_part_2_여전히남은문제해결방안.md`(v2) · `stage_1_part_2_여전히남은문제해결내역.md`
|
||||
- **Part 2 추가 개정 5회의 작업 내역서** — `stage_1_part_2_추가수정작업.md`(배포 완전성 게이트 F-1~F-7) · `stage_1_part_2_추가수정작업_더.md`(델타 30건 조립본 반영 · R0 라벨 해석) · `stage_1_part_2_추가수정작업_더더.md`(빌더 등록 · 상류 동기화) · `stage_1_part_2_추가수정작업_더더더.md`(스키마 2건 등록 · 예행 seed 보강) · `stage_1_part_2_여전히남은문제해결방안.md`(v2) + `stage_1_part_2_여전히남은문제해결내역.md`(BO 투영 — worker v3 산출이 `BO.json`·검토 handoff 에 닿는 경로 복원)
|
||||
- 실측 기준: 이 문서의 모든 수치·경로·키는 위 두 YAML 원문과 자산 트리를 **직접 파싱·해시**하여 얻은 것이다. 리포트 본문에서 옮겨 온 값은 §7 근거표에 출처를 적었고, 리포트와 실측이 갈린 곳은 그 자리에 명시했다.
|
||||
@@ -256,7 +256,7 @@ YAML이 참조하는 `Default_Agent/…` 자산은 **19개 리터럴**이고,
|
||||
| `stage1_runtime/schema_subset_validator.py` + `.txt` | 7,442 B | py + 미러 | D0 | 스키마 부분집합 검증기 |
|
||||
| `stage1_runtime/registry_loader.py` + `.txt` | 6,404 B | py + 미러 | D0 | registry 적재기 |
|
||||
| `signals/adapters/sg01_activation_adapter.py` + `.txt` | 3,738 B | py + 미러 | D0 | SG-01 어댑터. D0 산출의 자기검증 |
|
||||
| `validation_assets/routing/case_kind_domain_matrix.v2.json` | 72,969 B | json | **런타임 입력 금지** | 137 사건유형 이름을 담은 오프라인 회귀 전용. T0-01과 T1 두 프롬프트가 각각 읽기를 명시적으로 금지한다(192행 · 1,687행) |
|
||||
| `validation_assets/routing/case_kind_domain_matrix.v2.json` | 72,969 B (조립본 — 배포 원본 트리에서는 2026-08-20 제거) | json | **런타임 입력 금지** | 137 사건유형 이름을 담은 오프라인 회귀 전용. T0-01과 T1 두 프롬프트가 각각 읽기를 명시적으로 금지한다(192행 · 1,687행) |
|
||||
|
||||
Part 1 개정이 함께 만든 **검증·회귀 자산**(런타임 입력이 아니다).
|
||||
|
||||
@@ -335,9 +335,9 @@ Part 1 개정이 함께 만든 **검증·회귀 자산**(런타임 입력이 아
|
||||
|
||||
| # | task 명칭 | 실행기 / 설정 | 작업 목적 | 작업 내역 |
|
||||
|---|---|---|---|---|
|
||||
| P2-A0 | `Task_C_BO_A0_context_and_domain_slice_compiler` | code-executor · timeout 300 · 통합본 60–717행 | Part 1의 봉인된 산출을 받아 **도메인별 작업 재료를 컴파일하고 fan-out을 계획**한다 | 모듈 8종(`runtime_common` · `schema_subset_validator` · `registry_loader` · `registry_validator` · `prompt_compiler` · `domain_slice_compiler` · `domain_fanout_planner` · `stage_a_context_builder`)을 미러로 반입한다. 봉인 3해시를 검증한다. registry 26 config를 적재한다. `prompt_compiler.collect_domain_fragments(extra_specs=…)`로 Part 1의 어휘 사전을 도메인 프롬프트에 붙인다(조립 프롬프트 6,967 B → 24,942 B 실측). 슬라이스에 `domain_declarations` 7갈래를 투영한다. 스크리닝의 `candidates[].requested_calculation_domains`를 파싱해 도메인 `calculation_bindings`와 교집합하고, 교집합 밖은 `CALC_NOT_IN_BINDINGS` 리뷰로 남기며 `router_status`를 `READY_WITH_REVIEW`로 내린다. **도메인 상수를 두지 않는다**. 추가 개정 1회차로 `main()` 첫 문장이 `assert_deployment()`가 되었다 — 필수 자산 10 리터럴과 모듈 미러를 **한 벌로** 검사해(실측 18경로 — 다섯째 회차가 BO 투영 정책 자산을 목록에 더했다) 하나라도 빠지거나 해시가 어긋나면 `PART2_ASSET_DEPLOYMENT_INCOMPLETE`로 세운다. 이어 슬라이스 스키마가 `domain_declarations`와 `compiled_prompt.hash_kind`를 아는지 보고(`PART2_SLICE_SCHEMA_STALE`), 컴파일러 산출에 투영이 실제로 실려 나오는지 본다(`PART2_COMPILER_STALE` — 옛 판본은 알 수 없는 인자로 `TypeError`가 먼저 나므로 같은 코드에 `detail: signature_mismatch`를 붙인다). 프롬프트 오버레이 실패 4코드를 승격 대상으로 강제한다 |
|
||||
| P2-B | `Task_C_B_domain_worker_*` | LLM `google / gemini-3.1-flash-lite` · reasoning high · verbosity medium · `max_concurrency: 8` · cache 15m · preflight 2 · 통합본 718–847행 | 단일 도메인의 **BO seed 후보**를 만든다 | 읽는 것은 두 파일뿐 — 조립 프롬프트와 슬라이스. **프롬프트를 다시 조립하지 않는다.** 산출 최상위는 `stage_b_domain_bo_seed_output` 한 키, `schema_version`은 `task_c_bo_stage_b_domain_bo_seed.v3` 고정. 다섯 배열(`element_fact_candidates` · `opposing_fact_candidates` · `defense_candidates` · `calculation_requests` · `dependency_refs`) 이름은 스키마가 정한 것이다. `dependency_refs`는 연결만 남기고 의존 도메인의 결론을 복사하지 않는다. 자기검증 6항(최상위 단일 키, `domain_id`·`task_instance_id` 주입값 일치, `source_refs` ⊆ slice source_universe, `bo_type` ∈ `allowed_legal_effect_bo_types`, `registry_component_ids` ⊆ 합집합, 금지 키 `BO_ID`·`Evidence`·`EvidenceTitles`·`final_*` 부재). **결론을 내리지 않는다 — 후보만 남긴다** |
|
||||
| P2-R0 | `Task_C_BO_R0_seed_reducer_and_exception_planner` | code-executor · timeout 240 · 통합본 848–1,793행 | worker 산출 M개를 **결정론으로 합치고 예외를 좁힌다** | fan-out 계획의 기대집합과 실제 seed 집합을 **정확 일치**로 대조한다(누락·초과·중복 모두 실패). 모듈 4종(`runtime_common` · `schema_subset_validator` · `registry_loader` · `worker_output_validator`)을 반입해 `validate_worker_output`을 **실제로 호출**한다. 슬라이스의 `domain_declarations`로 두 대조를 걸어 `CALCULATION_DOMAIN_NOT_DECLARED`와 `EVIDENCE_SLOT_NOT_DECLARED`를 **review 등급**으로 남긴다. 산출은 셋이다 — seed ledger · 예외 pack · review handoff. **worker seed 파일은 읽기만 하고 다시 쓰지 않는다** — 구판의 제자리 재기록(`transport_metadata`·`handoff_guard` 주입)은 다섯째 회차에서 삭제됐고, 되쓰기와 함께 고아가 된 `_domain_label` · `DOMAIN_LABELS` · `_task_instance_id` · `digest_summary` 도 걷어냈다(R0 의 구 이름 B1~B5 의존 0). 앞 회차의 보강 — `try` 밖 자산 선검사 · `ensure_candidate_ref`(v3 봉인 스키마가 `candidate_ref`를 금지하므로 R0 가 순번에서 만든다) · v3 의 평평한 `source_refs` membership 대조 — 은 그대로다. 다섯째 회차의 처방은 다섯이다 — ① 투영 정책 자산을 `_verify_asset`으로 경성 반입한다(미등재·해시 불일치는 `PART2_ASSET_DEPLOYMENT_INCOMPLETE`, 판본 불일치는 `PART2_PROJECTION_POLICY_INVALID`) ② registry 근거 투영기 `project_to_bo_surface`가 v3 후보를 BO 호환면으로 투영한다 — 반환 키 **17개 고정**(입력 무관), registry 가 말하지 않는 칸은 만들지 않고 review 로 올린다. 투영본은 `projected_candidates`에 **별도 보관**하고 원장 루프가 그것을 읽는다(`seed_objects`는 worker 원본 유지). v2 잔재 `expand_candidate` · `_seed_payload` · `ALLOWED_SEED_KEYS` · `DOMAIN_PAYLOAD_CANON` · `_canon_payload` 는 제거 — 병합·정렬·예외 축소 헬퍼 7종(`_source_refs` · `_duplicate_key` · `_sort_key` · `_normalize_juristic` · `_compact_exception_payload` · `ensure_candidate_ref` · `validate_candidate`)은 한 줄도 고치지 않았다 ③ 검토 채널을 v3 두 키(후보별 `review_items` + 루트 `unknown_or_unrouted_reviews`)로 연결하고, 원본 `review_code`를 덧붙이기 키 `source_review_code`로, `reason`을 handoff `template_note`로 보존한다 ④ `validate_seed_object`가 status 를 v3 enum 5종 전체로 다룬다 — READY 계열 수용, `NO_SUPPORT`는 빈 후보 조건으로 수용 + review, `BLOCKED` · `FAILED` · enum 밖은 경성 중단 ⑤ 죽은 `slice_guard` 검사를 fan-out 계획 행의 `slice_sha256` · `compiled_prompt_sha256` ↔ worker echo 대조로 교체한다(`_seed_docs_from_plan`이 계획 행을 함께 보관). 파생 정합 하나 — 원장 flag 판정의 `{"event","state"}` 하드코딩도 슬라이스의 `allowed_legal_effect_bo_types`(registry 선언)로 교체됐다 |
|
||||
| P2-A0 | `Task_C_BO_A0_context_and_domain_slice_compiler` | code-executor · timeout 300 · 통합본 62–719행 | Part 1의 봉인된 산출을 받아 **도메인별 작업 재료를 컴파일하고 fan-out을 계획**한다 | 모듈 8종(`runtime_common` · `schema_subset_validator` · `registry_loader` · `registry_validator` · `prompt_compiler` · `domain_slice_compiler` · `domain_fanout_planner` · `stage_a_context_builder`)을 미러로 반입한다. 봉인 3해시를 검증한다. registry 26 config를 적재한다. `prompt_compiler.collect_domain_fragments(extra_specs=…)`로 Part 1의 어휘 사전을 도메인 프롬프트에 붙인다(조립 프롬프트 6,967 B → 24,942 B 실측). 슬라이스에 `domain_declarations` 7갈래를 투영한다. 스크리닝의 `candidates[].requested_calculation_domains`를 파싱해 도메인 `calculation_bindings`와 교집합하고, 교집합 밖은 `CALC_NOT_IN_BINDINGS` 리뷰로 남기며 `router_status`를 `READY_WITH_REVIEW`로 내린다. **도메인 상수를 두지 않는다**. 추가 개정 1회차로 `main()` 첫 문장이 `assert_deployment()`가 되었다 — 필수 자산 10 리터럴과 모듈 미러를 **한 벌로** 검사해(실측 18경로 — 다섯째 회차가 BO 투영 정책 자산을 목록에 더했다) 하나라도 빠지거나 해시가 어긋나면 `PART2_ASSET_DEPLOYMENT_INCOMPLETE`로 세운다. 이어 슬라이스 스키마가 `domain_declarations`와 `compiled_prompt.hash_kind`를 아는지 보고(`PART2_SLICE_SCHEMA_STALE`), 컴파일러 산출에 투영이 실제로 실려 나오는지 본다(`PART2_COMPILER_STALE` — 옛 판본은 알 수 없는 인자로 `TypeError`가 먼저 나므로 같은 코드에 `detail: signature_mismatch`를 붙인다). 프롬프트 오버레이 실패 4코드를 승격 대상으로 강제한다 |
|
||||
| P2-B | `Task_C_B_domain_worker_*` | LLM `google / gemini-3.1-flash-lite` · reasoning high · verbosity medium · `max_concurrency: 8` · cache 15m · preflight 2 · 통합본 720–849행 | 단일 도메인의 **BO seed 후보**를 만든다 | 읽는 것은 두 파일뿐 — 조립 프롬프트와 슬라이스. **프롬프트를 다시 조립하지 않는다.** 산출 최상위는 `stage_b_domain_bo_seed_output` 한 키, `schema_version`은 `task_c_bo_stage_b_domain_bo_seed.v3` 고정. 다섯 배열(`element_fact_candidates` · `opposing_fact_candidates` · `defense_candidates` · `calculation_requests` · `dependency_refs`) 이름은 스키마가 정한 것이다. `dependency_refs`는 연결만 남기고 의존 도메인의 결론을 복사하지 않는다. 자기검증 6항(최상위 단일 키, `domain_id`·`task_instance_id` 주입값 일치, `source_refs` ⊆ slice source_universe, `bo_type` ∈ `allowed_legal_effect_bo_types`, `registry_component_ids` ⊆ 합집합, 금지 키 `BO_ID`·`Evidence`·`EvidenceTitles`·`final_*` 부재). **결론을 내리지 않는다 — 후보만 남긴다** |
|
||||
| P2-R0 | `Task_C_BO_R0_seed_reducer_and_exception_planner` | code-executor · timeout 240 · 통합본 850–1,793행 | worker 산출 M개를 **결정론으로 합치고 예외를 좁힌다** | fan-out 계획의 기대집합과 실제 seed 집합을 **정확 일치**로 대조한다(누락·초과·중복 모두 실패). 모듈 4종(`runtime_common` · `schema_subset_validator` · `registry_loader` · `worker_output_validator`)을 반입해 `validate_worker_output`을 **실제로 호출**한다. 슬라이스의 `domain_declarations`로 두 대조를 걸어 `CALCULATION_DOMAIN_NOT_DECLARED`와 `EVIDENCE_SLOT_NOT_DECLARED`를 **review 등급**으로 남긴다. 산출은 셋이다 — seed ledger · 예외 pack · review handoff. **worker seed 파일은 읽기만 하고 다시 쓰지 않는다** — 구판의 제자리 재기록(`transport_metadata`·`handoff_guard` 주입)은 다섯째 회차에서 삭제됐고, 되쓰기와 함께 고아가 된 `_domain_label` · `DOMAIN_LABELS` · `_task_instance_id` · `digest_summary` 도 걷어냈다(R0 의 구 이름 B1~B5 의존 0). 앞 회차의 보강 — `try` 밖 자산 선검사 · `ensure_candidate_ref`(v3 봉인 스키마가 `candidate_ref`를 금지하므로 R0 가 순번에서 만든다) · v3 의 평평한 `source_refs` membership 대조 — 은 그대로다. 다섯째 회차의 처방은 다섯이다 — ① 투영 정책 자산을 `_verify_asset`으로 경성 반입한다(미등재·해시 불일치는 `PART2_ASSET_DEPLOYMENT_INCOMPLETE`, 판본 불일치는 `PART2_PROJECTION_POLICY_INVALID`) ② registry 근거 투영기 `project_to_bo_surface`가 v3 후보를 BO 호환면으로 투영한다 — 반환 키 **17개 고정**(입력 무관), registry 가 말하지 않는 칸은 만들지 않고 review 로 올린다. 투영본은 `projected_candidates`에 **별도 보관**하고 원장 루프가 그것을 읽는다(`seed_objects`는 worker 원본 유지). v2 잔재 `expand_candidate` · `_seed_payload` · `ALLOWED_SEED_KEYS` · `DOMAIN_PAYLOAD_CANON` · `_canon_payload` 는 제거 — 병합·정렬·예외 축소 헬퍼 7종(`_source_refs` · `_duplicate_key` · `_sort_key` · `_normalize_juristic` · `_compact_exception_payload` · `ensure_candidate_ref` · `validate_candidate`)은 한 줄도 고치지 않았다 ③ 검토 채널을 v3 두 키(후보별 `review_items` + 루트 `unknown_or_unrouted_reviews`)로 연결하고, 원본 `review_code`를 덧붙이기 키 `source_review_code`로, `reason`을 handoff `template_note`로 보존한다 ④ `validate_seed_object`가 status 를 v3 enum 5종 전체로 다룬다 — READY 계열 수용, `NO_SUPPORT`는 빈 후보 조건으로 수용 + review, `BLOCKED` · `FAILED` · enum 밖은 경성 중단 ⑤ 죽은 `slice_guard` 검사를 fan-out 계획 행의 `slice_sha256` · `compiled_prompt_sha256` ↔ worker echo 대조로 교체한다(`_seed_docs_from_plan`이 계획 행을 함께 보관). 파생 정합 하나 — 원장 flag 판정의 `{"event","state"}` 하드코딩도 슬라이스의 `allowed_legal_effect_bo_types`(registry 선언)로 교체됐다 |
|
||||
| P2-R1 | `Task_C_BO_R1_exception_adjudicator` | LLM · reasoning low · verbosity low · `max_iterations: 1` · cache 20m · preflight 1 · 통합본 1,794–1,896행 | R0이 non-deferrable로 판정한 **compact exception만 판정**한다 | pack 하나만 읽는다. 병합·최종 파일 작성·사실 창작을 하지 않는다. v3 3,621–3,723행과 바이트 동일(추가 개정 5회에서도 손대지 않았다) |
|
||||
| P2-F0 | `Task_C_BO_F0_final_bo_compiler_gate_writer` | code-executor · timeout 240 · 통합본 1,897–2,685행 | **최종 `BO.json`을 확정**하고 게이트를 쓴다 | PostB_3(final compiler) + PostB_4(final gate/writer) 통합. 입력은 전부 파일 계약(ledger · decisions · stage_a)이다. BOType 어휘를 하드코딩하지 않고 **registry 합집합**에서 해시 검증과 함께 만든다. 확장 payload 키를 `extension_payload_key_declarations.v1.json`과 대조해 미선언 키는 `EXTENSION_PAYLOAD_KEY_UNDECLARED`로 남긴다. R1 산출은 **조건부**로 요구한다(pack의 `exception_count`가 0이면 부재 허용). 다섯째 회차의 처방 둘 — ① 폴백 판정의 `bo_type not in {"event","state"}` 하드코딩을 registry 합집합 `bo_types`(5종)로 교체했다. `claim` · `communication` · `calculation_request` 를 선언한 도메인의 값이 `event`로 **침묵 덮어쓰기**되던 자리이며, 이제 빌드 루프와 검증 루프의 어휘가 같다 ② `_load_projection_policy`로 투영 정책을 반입해(`_load_declarations`와 같은 규율 — `runtime_manifest` sha 대조 후에만 사용) 정규화 기본값을 정책에서 읽고, `normalization_notes` 각 항목을 review handoff 의 `review_items`에도 올린다(`issue_type: schema_field_fallback` + `source_review_code`). Action 대체 체인(seed.Action → action_summary → Action_proposal)은 방어선으로 유지된다 |
|
||||
| P2-S0 | `Task_C_BO_S0_signal_bundle_writer` | code-executor · timeout 300 · 통합본 2,686–3,275행 | **정본 signal 거래 1건**을 기록한다 | 생성기·사영기·기록기를 여기서 만들지 않는다. 조립본 모듈 24종을 반입한다 — compiler 7(`common` · `projections` · `schema_validator` · `signal_compiler` · `signal_gate` · `transaction_writer` · `writer_boundary`) + adapter 4(`s3_domain_seed_adapter` · `s3_envelope_migration_adapter` · `s4_calculation_adapter` · `sg01_activation_adapter`) + emitter 13(`emitter_runtime` + `emit_sg02`~`emit_sg13`). 정본 기록기가 유일한지 검사한다(`S0_CANONICAL_WRITER_NOT_UNIQUE`). `transaction_id`는 `^S5TX-[a-f0-9]{20}$`. 슬라이스의 `emits_signals` 선언과 실제 방출을 대조해 선언 밖 방출은 `SIGNAL_EMISSION_NOT_DECLARED`로 남긴다(**선언보다 적게 나오는 것은 정상**이므로 그 방향은 세지 않는다). 기록 후 `signal_manifest.json`을 다시 읽어 해시 왕복 일치를 확인한다. 추가 개정으로 `signal_registry.v2.json` · `s5_execution_contract.v2.json` · `$ref` 폐포가 닿는 signal 스키마 17종을 `_verify_asset`으로 읽으면서 매니페스트 해시와 대조한다. 다섯째 회차에서는 배포 처방 문구(`PART2_DEPLOYMENT_REMEDY`)만 A0·R0 와 함께 배포 원본 `extension_research/Default_Agent` 기준으로 현행화됐다 |
|
||||
@@ -350,7 +350,7 @@ Part 1 개정이 함께 만든 **검증·회귀 자산**(런타임 입력이 아
|
||||
|---|---|---|---|
|
||||
| P2-A0 | `Task_C_BO_A0_…slice_compiler` | **Part 1 산출 6종** — `quality_gates/stage1_part1_soft_gate_handoff.json` · `routing/domain_activation_manifest.json` · `routing/domain_screening.json` · `evidence_indexed.json` · `evidence_event_candidates.json` · `routing/candidate_profile_vocabulary.md` + **사건 입력** `client_meeting.md` (md) + **자산** `runtime_manifest.json` · `domains/_registry_index.json` · `domains/_common/common_worker_contract.md` · `domains/<id>/domain_config.json` ×26 · `domains/<id>/seed_prompt_overlay.md` (config의 `prompt_overlay_ref`가 지목) · `stage1_runtime/prompt_composition_policy.json` · `platform/schemas/domain_slice.schema.v2.json` · `platform/schemas/domain_fanout_plan.schema.json` + 모듈 미러 8종(`.txt`) + **배포 게이트가 존재·해시만 확인하는 자산 6종**(`domain_seed_output.schema.v3.json` · `signals/signal_registry.v2.json` · `contracts/signals/s5_execution_contract.v2.json` · `routing/extension_payload_key_declarations.v1.json` · `stage1_runtime/worker_output_validator.txt` · `stage1_runtime/bo_surface_projection_policy.v1.json` — 하류 R0·F0·S0 이 쓸 것을 A0 가 미리 본다) | `runtime/domain_slices/<domain_id>.json` (json ×M, `task_c_bo_stage_b_domain_slice.v2`, 루트 키 `stage_b_domain_slice`) · `runtime/compiled_prompts/<domain_id>.md` (md ×M) · `fanout/domain_fanout_plan.json` (json, `domain_fanout_plan.v1`) · `stage1_tmp/task_c_bo/stage_a_context.json` (json, 루트 `stage_a_context`) · `stage1_tmp/task_c_bo/source_universe_manifest.json` (json) · `validation_assets/routing/stage_receipt.json` (json, `stage1_stage_receipt.v2`) |
|
||||
| P2-B | `Task_C_B_domain_worker_*` | `{{item.compiled_prompt_path}}` (md) · `{{item.slice_path}}` (json) — **둘뿐** | `{{item.expected_output_path}}` = `runtime/domain_seed_outputs/<domain_id>.json` (json, `task_c_bo_stage_b_domain_bo_seed.v3`) |
|
||||
| P2-R0 | `Task_C_BO_R0_…exception_planner` | `fanout/domain_fanout_plan.json` · `runtime/domain_slices/<id>.json` ×M · `runtime/domain_seed_outputs/<id>.json` ×M · `stage1_tmp/task_c_bo/stage_a_context.json` · `stage1_tmp/task_c_bo/source_universe_manifest.json` (json) + 자산 `platform/schemas/domain_seed_output.schema.v3.json` · `stage1_runtime/bo_surface_projection_policy.v1.json`(판본까지 검사) · `runtime_manifest.json` + 모듈 미러 4종 · **선언만 하고 읽지 않는 상수 2개**(`ACTIVATION_MANIFEST_PATH` · `REGISTRY_INDEX_PATH` — 각각 대입 1회뿐이고 read 0회). 추가 개정으로 seed 스키마와 검증기 미러는 `_verify_asset`이 **매니페스트 해시와 대조하며** 읽는다 | `stage1_tmp/task_c_bo/postb_seed_ledger.json` (json) · `quality_gates/stage1_part2_exception_pack.json` (json) · `quality_gates/stage1_part2_review_handoff.json` (json) — **셋뿐이다.** 구판의 worker seed 제자리 재기록은 다섯째 회차에서 삭제됐고, seed 파일은 worker 가 쓴 바이트 그대로 남는다 |
|
||||
| P2-R0 | `Task_C_BO_R0_…exception_planner` | `fanout/domain_fanout_plan.json` · `runtime/domain_slices/<id>.json` ×M · `runtime/domain_seed_outputs/<id>.json` ×M · `stage1_tmp/task_c_bo/stage_a_context.json` · `stage1_tmp/task_c_bo/source_universe_manifest.json` (json) + 자산 `platform/schemas/domain_seed_output.schema.v3.json` · `stage1_runtime/bo_surface_projection_policy.v1.json`(판본까지 검사) · `runtime_manifest.json` + 모듈 미러 4종 (구판의 사문 경로 상수 2개는 2026-08-20 자산 정리 회차에서 삭제됐다). 추가 개정으로 seed 스키마와 검증기 미러는 `_verify_asset`이 **매니페스트 해시와 대조하며** 읽는다 | `stage1_tmp/task_c_bo/postb_seed_ledger.json` (json) · `quality_gates/stage1_part2_exception_pack.json` (json) · `quality_gates/stage1_part2_review_handoff.json` (json) — **셋뿐이다.** 구판의 worker seed 제자리 재기록은 다섯째 회차에서 삭제됐고, seed 파일은 worker 가 쓴 바이트 그대로 남는다 |
|
||||
| P2-R1 | `Task_C_BO_R1_exception_adjudicator` | `quality_gates/stage1_part2_exception_pack.json` (json, preflight) | `stage1_tmp/task_c_bo/postb_adjudication_decisions.json` (json, **조건부**) |
|
||||
| P2-F0 | `Task_C_BO_F0_…gate_writer` | `stage1_tmp/task_c_bo/stage_a_context.json` · `postb_seed_ledger.json` · `postb_adjudication_decisions.json`(조건부) · `quality_gates/stage1_part2_review_handoff.json` · `stage1_part2_exception_pack.json` (json) + 자산 `routing/extension_payload_key_declarations.v1.json` · `stage1_runtime/bo_surface_projection_policy.v1.json`(`_load_projection_policy` — 매니페스트 sha 대조 후 사용) · `runtime_manifest.json` | **`BO.json`** (json) · `stage1_tmp/task_c_bo/postb_compiled_bundle_compact.json` (json) · `quality_gates/stage1_part2_review_handoff.json` (json, `FINALIZED`로 **갱신 재기록** — R0과 공동 기록자) |
|
||||
| P2-S0 | `Task_C_BO_S0_signal_bundle_writer` | `BO.json` · `routing/domain_activation_manifest.json` · `fanout/domain_fanout_plan.json` · `stage1_tmp/task_c_bo/source_universe_manifest.json` · `runtime/domain_slices/<id>.json` ×M (json) + 자산 `signals/signal_registry.v2.json` · `contracts/signals/s5_execution_contract.v2.json` · `runtime_manifest.json` + 모듈 미러 24종 | `signals/…` 아래 정본 signal 집합 — `signals/signal_manifest.json` 포함 + 호환 뷰 3종 `signals/compatibility_views/{actio_case,case_liability,legal_effect}_signals.json` + **루트 별칭 3종** `actio_case_signals.json` · `case_liability_signals.json` · `legal_effect_signals.json` (구 이름 호환면, 같은 바이트) |
|
||||
@@ -378,7 +378,7 @@ YAML이 참조하는 `Default_Agent/…` 자산은 **21개 리터럴**이다(다
|
||||
|
||||
| 배포 경로 (`Default_Agent/` 기준) | 크기 | 형태 | 쓰는 task | 역할 |
|
||||
|---|---|---|---|---|
|
||||
| `domains/_registry_index.json` | 18,921 B | json | A0 | registry 색인. 봉인 대조 대상. (R0에도 경로 상수가 있으나 읽지 않는다) |
|
||||
| `domains/_registry_index.json` | 18,921 B | json | A0 | registry 색인. 봉인 대조 대상 |
|
||||
| `domains/_common/common_worker_contract.md` | **3,766 B** | md | A0 | 공통 worker 계약문. 사건 종류 이름을 라우팅 키로 쓰지 않는다는 규율을 여기서 선언한다. 다섯째 회차가 출력 규칙 한 문장을 더했다 — 검토는 v3 두 키(`review_items` · `unknown_or_unrouted_reviews`)로만 보내고 `domain_review_queue`(오버레이에 남은 구 이름)는 금지, 방어 후보의 정본 키는 `defense_candidates`. rank 10 계약이 rank 30 오버레이를 이기므로 오버레이 25건 · 색인 · Part 1 봉인은 전부 바이트 무변이다 |
|
||||
| `domains/<id>/domain_config.json` ×26 | — | json | A0 | 8선언 가문 원문 (`element_slots` · `opposing_fact_slots` · `evidence_components` · `defense_map` · `calculation_bindings` · `emits_signals` · `structure_types` · `effect_projection`) |
|
||||
| `domains/<id>/seed_prompt_overlay.md` | — | md | A0 | 도메인 오버레이 산문. **파일명을 하드코딩하지 않고** config의 `prompt_overlay_ref`가 지목하는 것을 따른다 |
|
||||
@@ -560,7 +560,7 @@ Part 1이 만들어 **Part 2가 읽는** 파일은 여섯이다.
|
||||
| 12 | embedded python | AST 실패 0 · 미정의 이름 0 · 미사용 def 1(`clip`, v3 원문) |
|
||||
| 13 | 인계면 전수 대조 | PASS · finding 0 |
|
||||
| 14 | 스키마 미지원 키워드 | PASS · 3/3 |
|
||||
| 15 | 개별 6종 ↔ 통합본 | 불일치 0 (다섯째 회차 뒤 재대조 — P2-A0·R0·F0·S0 4종을 통합본 블록과 동기화한 뒤 블록 동일 재확인. R0 블록 946행) |
|
||||
| 15 | 개별 6종 ↔ 통합본 | 불일치 0 (다섯째 회차 뒤 재대조 — P2-A0·R0·F0·S0 4종을 통합본 블록과 동기화한 뒤 블록 동일 재확인. R0 블록 944행 — 2026-08-20 사문 상수 삭제 후 재동기화·재확인) |
|
||||
| 16 | 26 도메인 전수 compile (스키마 주입) | READY / slice_count 26 / 스키마 실패 0 |
|
||||
| 17 | `calculation_registry` · `computations/` 참조 | 0 · 0 |
|
||||
| 18 | `release_manifest` 전수 해시·크기 | **1,320항** · 불일치 **1** — `tools/build_default_agent_stage1.py`(장부 102,559 B vs 실물 102,997 B). 다섯째 회차의 빌더 제자리 수정(뿌리 6→10)이 조립본 장부에 미반영된 흔적으로, 이월 D-2 의 재생성 대상이다 |
|
||||
@@ -721,7 +721,7 @@ Part 2 개정은 독립 sub-agent 검증 3라운드에서 결함 10건을 닫았
|
||||
|
||||
| 주장 | 근거 |
|
||||
|---|---|
|
||||
| 두 통합본의 크기·행수·sha256 | 원문 바이트 재계산 — Part 1 467,668 B / 6,667행 / `195b43edfaf1df14…`, Part 2 **195,938 B / 3,315행 / `ec4c43027ad85195…`** |
|
||||
| 두 통합본의 크기·행수·sha256 | 원문 바이트 재계산 — Part 1 467,668 B / 6,667행 / `195b43edfaf1df14…`, Part 2 **195,963 B / 3,315행 / `ec407309a5ab43f4…`** |
|
||||
| YAML 구문 PASS · 최상위 키 `Agent` | `yaml.safe_load` 재실행 |
|
||||
| task 13 / 6 및 행 범위 | `- task_name:` 정규식 전수 추출 |
|
||||
| DAG 노드·edge | `task_procedure` 블록 원문 (Part 1 6,589–6,664행 · Part 2 **3,277–3,312행**) |
|
||||
@@ -754,7 +754,7 @@ Part 2 개정은 독립 sub-agent 검증 3라운드에서 결함 10건을 닫았
|
||||
| 심각도 | 건수 | 내용 |
|
||||
|---|---|---|
|
||||
| BLOCKER | 1 | §0 요약표가 Part 2의 사건 입력을 "없음"으로 적었다. Part 2 A0는 `client_meeting.md`를 `read_raw`로 직접 읽는다(통합본 515행). 같은 문서의 §3.3·§4.1과 자기모순이었다 |
|
||||
| MAJOR | 5 | ① R0의 **네 번째 산출** 누락 — worker seed 파일 M개를 제자리에서 다시 쓴다(`transport_metadata`·`handoff_guard` 주입) ② R0의 IN에 적은 `domain_activation_manifest.json`·`_registry_index.json`은 **선언만 하고 읽지 않는 상수**다(각 대입 1회·read 0회) ③ 스테이지 기본 LLM은 Part 1도 `openai / gpt-4o-2024-08-06`으로 같다 ④ T1의 `preflight` 플래그는 `false`다(화이트리스트만 선언) ⑤ 검사 20의 `__pycache__ 0`은 후보 오버레이 기준이고 정본 조립본에는 `.pyc` 3이 남아 있다 |
|
||||
| MAJOR | 5 | ① R0의 **네 번째 산출** 누락 — worker seed 파일 M개를 제자리에서 다시 쓴다(`transport_metadata`·`handoff_guard` 주입) ② R0의 IN에 적은 `domain_activation_manifest.json`·`_registry_index.json`은 **선언만 하고 읽지 않는 상수**다(각 대입 1회·read 0회 — 그 상수 2개는 2026-08-20 자산 정리 회차에서 삭제됐다) ③ 스테이지 기본 LLM은 Part 1도 `openai / gpt-4o-2024-08-06`으로 같다 ④ T1의 `preflight` 플래그는 `false`다(화이트리스트만 선언) ⑤ 검사 20의 `__pycache__ 0`은 후보 오버레이 기준이고 정본 조립본에는 `.pyc` 3이 남아 있다 |
|
||||
| MINOR | 8 | Part 1 행수 6,668 → **6,667**(리포트에서 옮겨 온 값이 실측과 달랐다) · `task_procedure` 행 범위가 스테이지 층 `prevs`/`nexts`를 삼켰다 · T5가 shard 원문을 조건부로 읽는다 · T3·T4의 `max_concurrency: 12` 누락 · §2.5 표의 행 구성 설명 · `source_copy_map.json`은 두 뿌리 바이트 동일 · 예행의 세 번째 한계(Part 1 code task 8종 중 5종만 실행) · 인계면 선언표의 누락 2줄(`client_meeting.md` 소비자에 Part 2 A0, seed 경로의 `also_written_by`) |
|
||||
|
||||
검증이 **깨끗하다고 확인한 것**도 기록해 둔다. task 13/6 전수가 세 표(소작업·IO·연결)에 모두 오른 것, DAG 노드·edge·와일드카드 토큰 전부 일치, §2.5·§3.5·§4.1·§4.3에 인용한 바이트 크기 44개(중복 제외) 전부 정확, 두 뿌리 대조 수치(528/7/23)와 미러 규약 실측, 인계면 34와 구간 분포, task별 행 범위와 v3 대비 바이트 동일성(Part 1 무변경 6종 + Part 2 R1), 그리고 26 도메인 투영 합계 일곱(162/85/112/83/73/267/53)이 `domains/*/domain_config.json` 전수 재계산으로 정확히 재현되는 것.
|
||||
|
||||
-2
@@ -65,8 +65,6 @@
|
||||
"registry_loader": "Default_Agent/stage1_runtime/registry_loader.txt",
|
||||
"worker_output_validator": "Default_Agent/stage1_runtime/worker_output_validator.txt",
|
||||
}
|
||||
ACTIVATION_MANIFEST_PATH = "routing/domain_activation_manifest.json"
|
||||
REGISTRY_INDEX_PATH = "Default_Agent/domains/_registry_index.json"
|
||||
|
||||
def _seed_docs_from_plan(plan):
|
||||
# v5 — 경로만이 아니라 계획 행 전체를 보관한다. validate_seed_object 가
|
||||
|
||||
+967
@@ -0,0 +1,967 @@
|
||||
# =============================================================================
|
||||
# P2-R0 / Task_C_BO_R0_seed_reducer_and_exception_planner — v4 (개정본)
|
||||
#
|
||||
# 원본 : Claude_YAML/Stage_1_Part_2_Claude_v3.yml 2827~3620행 (794행)
|
||||
# 근거 : stage_1_part_2_optimal_update_strategy_v.2.md §6.3 / stage_1_update_strategy.md §3.3
|
||||
#
|
||||
# v3 대비 변경 셋. 그 외는 무변경이다 — 병합·전역 출처 검증·예외 축소 로직은 손대지 않았다.
|
||||
# 1. seed 원천 교체
|
||||
# v3 는 SEED_INPUTS 의 {{prev.Task_C_BO_Stage_B_B*.json_output}} 다섯을 읽었다.
|
||||
# v4 는 A0 가 낸 fanout/domain_fanout_plan.json 의 task_instances[*].expected_output_path
|
||||
# 를 따라 읽는다. 정적 다섯 이름과 stage1_tmp 구 경로가 함께 사라진다.
|
||||
# 2. worker_output_validator 호출
|
||||
# seed 마다 slice·registry·activation_manifest 를 물려 검증한다.
|
||||
# domain_seed_output.schema.v3.json 을 주입한다 — 넘기지 않으면 검증이 조용히 건너뛰어진다.
|
||||
# 3. C-2 — meeting_only_evidence_gap 판정 확장 (P0 판정 B)
|
||||
# registry_component_ids 로 뒷받침된 seed 는 증거 유래로 인정한다.
|
||||
# 값이 비면 종전과 완전히 같으므로 승계 5도메인 등가가 깨지지 않는다.
|
||||
#
|
||||
# 무변경 확인
|
||||
# mcp code-executor / parameters 5키 / CANDIDATE_REF_RE / add_policy_review /
|
||||
# 전역 출처 universe 재검사 / 예외 축소 / postb_seed_ledger 구조
|
||||
# =============================================================================
|
||||
- task_name: Task_C_BO_R0_seed_reducer_and_exception_planner
|
||||
mcp: code-executor
|
||||
tool_name: run_code
|
||||
parameters:
|
||||
language: python
|
||||
requirements: httpx
|
||||
network: agent-network
|
||||
timeout: 240
|
||||
code: |-
|
||||
#!/usr/bin/env python3
|
||||
# Task_C_BO_R0_seed_reducer_and_exception_planner (v3)
|
||||
# publisher + domain_join + PostB_1 통합 결정적 reducer.
|
||||
# Spec: Part_2_Improvement_Strategy_Claude_v1.md §7 (defer policy = 개선전략서 X-2, pack 조건 = X-3)
|
||||
from __future__ import annotations
|
||||
import hashlib
|
||||
import itertools
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from typing import Any
|
||||
import httpx
|
||||
|
||||
LOCALDOCS_URL = "http://mcp-localdocs:8012/mcp"
|
||||
MCP_HEADERS = {"Content-Type": "application/json", "Accept": "application/json, text/event-stream"}
|
||||
CLIENT = httpx.Client(timeout=60)
|
||||
MSG_ID = itertools.count(10)
|
||||
JSON_DECODER = json.JSONDecoder()
|
||||
|
||||
# v4 — {{prev.Task_C_BO_Stage_B_B*}} 다섯을 걷어냈다.
|
||||
# worker 산출은 wildcard fan-out 인스턴스가 파일로 남기므로 경로로 읽는다.
|
||||
# v4 — seed 목록은 상수가 아니라 A0 의 fan-out 계획이 정한다.
|
||||
FANOUT_PLAN_PATH = "fanout/domain_fanout_plan.json"
|
||||
SLICE_DIR = "runtime/domain_slices"
|
||||
SEED_SCHEMA_PATH = "Default_Agent/platform/schemas/domain_seed_output.schema.v3.json"
|
||||
SEED_SCHEMA_VERSION = "task_c_bo_stage_b_domain_bo_seed.v3"
|
||||
SLICE_ROOT_KEY = "stage_b_domain_slice"
|
||||
# R-4 — 머리말이 약속한 worker_output_validator 를 실제로 부른다. 반입은 D0 규약 R-1~R-5.
|
||||
RUNTIME_MANIFEST = "Default_Agent/runtime_manifest.json"
|
||||
EXECUTION_ROOT = "/tmp/s1_r0"
|
||||
VALIDATOR_MIRRORS = {
|
||||
"runtime_common": "Default_Agent/stage1_runtime/runtime_common.txt",
|
||||
"schema_subset_validator": "Default_Agent/stage1_runtime/schema_subset_validator.txt",
|
||||
"registry_loader": "Default_Agent/stage1_runtime/registry_loader.txt",
|
||||
"worker_output_validator": "Default_Agent/stage1_runtime/worker_output_validator.txt",
|
||||
}
|
||||
ACTIVATION_MANIFEST_PATH = "routing/domain_activation_manifest.json"
|
||||
REGISTRY_INDEX_PATH = "Default_Agent/domains/_registry_index.json"
|
||||
|
||||
def _seed_docs_from_plan(plan):
|
||||
# v5 — 경로만이 아니라 계획 행 전체를 보관한다. validate_seed_object 가
|
||||
# slice_sha256 · compiled_prompt_sha256 기대값을 이 행에서 대조한다(R0-6).
|
||||
root = plan.get("domain_fanout_plan", plan)
|
||||
out = {}
|
||||
rows = {}
|
||||
for row in root.get("task_instances") or []:
|
||||
domain_id = row.get("domain_id")
|
||||
path = row.get("expected_output_path")
|
||||
if isinstance(domain_id, str) and isinstance(path, str) and domain_id and path:
|
||||
out[domain_id] = path
|
||||
rows[domain_id] = row
|
||||
if not out:
|
||||
raise RuntimeError("R0_FANOUT_PLAN_EMPTY")
|
||||
return out, rows
|
||||
# v4 — 계획이 정하는 두 목록. 상수가 아니므로 비워 두고 main 에서 내용만 채운다.
|
||||
# 재바인딩하지 않고 갱신만 하므로 아래 도우미들이 같은 객체를 본다.
|
||||
SEED_DOCS: dict[str, str] = {}
|
||||
PLAN_ROWS: dict[str, dict[str, Any]] = {}
|
||||
DOMAIN_ORDER: list[str] = []
|
||||
|
||||
# DOMAIN_ORDER 는 fan-out 계획의 등재 순서를 그대로 쓴다. 상수 순서를 두지 않는다.
|
||||
def _domain_order(seed_docs):
|
||||
return list(seed_docs.keys())
|
||||
# v5 — 구 이름 표(DOMAIN_LABELS)와 _domain_label 을 걷어냈다. 유일 소비처가 되쓰기
|
||||
# (R0-5 에서 삭제)의 transport_metadata 였다. 이로써 R0 에 구 명세서(B1~B5) 이름 의존이 없다.
|
||||
STAGE_A_PATH = "stage1_tmp/task_c_bo/stage_a_context.json"
|
||||
MANIFEST_PATH = "stage1_tmp/task_c_bo/source_universe_manifest.json"
|
||||
LEDGER_PATH = "stage1_tmp/task_c_bo/postb_seed_ledger.json"
|
||||
PACK_PATH = "quality_gates/stage1_part2_exception_pack.json"
|
||||
REVIEW_HANDOFF_PATH = "quality_gates/stage1_part2_review_handoff.json"
|
||||
# R0-1 — BO 투영 정책. 투영 규칙의 정본은 코드가 아니라 이 선언 자산이다.
|
||||
BO_PROJECTION_POLICY = "Default_Agent/stage1_runtime/bo_surface_projection_policy.v1.json"
|
||||
BO_PROJECTION_SCHEMA_VERSION = "stage1_bo_surface_projection_policy.v1"
|
||||
# v3 계약이 정본이다. 도메인 ID 는 registry 값(E-00 · EC-00 · X1 …)이고 구 이름도 아직 들어올 수 있으므로
|
||||
# 접두사는 도메인에 묶지 않고 형식만 본다 — 도메인 일치는 validate_candidate 의 prefix 검사가 맡는다.
|
||||
CANDIDATE_REF_RE = re.compile(r"^[A-Za-z][A-Za-z0-9_.-]{0,63}:[0-9]{3}$")
|
||||
REVIEW_ISSUE_ENUM = {
|
||||
"missing_source", "source_conflict", "cross_domain_merge_needed",
|
||||
"amount_or_date_uncertain", "legal_effect_uncertain", "review_required",
|
||||
"legal_theory_required", "near_duplicate_kept_separate",
|
||||
"meeting_only_evidence_gap", "schema_field_fallback", "prior_link_ambiguous",
|
||||
}
|
||||
DOWNSTREAM_OWNER_ENUM = {"publisher", "domain_join", "C0", "C1", "C2", "C3", "C5", "D", "E", "Stage2"}
|
||||
# v5 — ALLOWED_SEED_KEYS(v2 화이트리스트)를 걷어냈다. v3 후보 18필드와의 교집합이
|
||||
# extensions 하나뿐이라 워커 산출을 통째로 버리던 자리다(C-1). 원장 payload 의
|
||||
# 키 집합은 project_to_bo_surface 의 반환문이 유일한 정의다.
|
||||
|
||||
def _mid() -> int:
|
||||
return next(MSG_ID)
|
||||
|
||||
def _init() -> None:
|
||||
r = CLIENT.post(
|
||||
LOCALDOCS_URL,
|
||||
json={
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "initialize",
|
||||
"params": {
|
||||
"protocolVersion": "2025-03-26",
|
||||
"capabilities": {},
|
||||
"clientInfo": {
|
||||
"name": "task-c-bo-r0-seed-reducer-and-exception-planner",
|
||||
"version": "1.0",
|
||||
"user_id": "{{__user_hash__}}",
|
||||
"workspace_id": "{{__workspace_hash__}}",
|
||||
},
|
||||
},
|
||||
},
|
||||
headers=MCP_HEADERS,
|
||||
)
|
||||
r.raise_for_status()
|
||||
sid = r.headers.get("mcp-session-id")
|
||||
if sid:
|
||||
MCP_HEADERS["mcp-session-id"] = sid
|
||||
CLIENT.post(
|
||||
LOCALDOCS_URL,
|
||||
json={"jsonrpc": "2.0", "method": "notifications/initialized"},
|
||||
headers=MCP_HEADERS,
|
||||
).raise_for_status()
|
||||
|
||||
def _parse_mcp(text: str) -> Any:
|
||||
for line in text.strip().split("\n"):
|
||||
if line.startswith("data: "):
|
||||
try:
|
||||
return json.loads(line[6:])
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
return json.loads(text)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _call(name: str, args: dict[str, Any]) -> Any:
|
||||
r = CLIENT.post(
|
||||
LOCALDOCS_URL,
|
||||
json={"jsonrpc": "2.0", "id": _mid(), "method": "tools/call",
|
||||
"params": {"name": name, "arguments": args}},
|
||||
headers=MCP_HEADERS,
|
||||
)
|
||||
r.raise_for_status()
|
||||
payload = _parse_mcp(r.text)
|
||||
if not payload or "result" not in payload:
|
||||
raise RuntimeError(f"MCP {name} failed")
|
||||
return payload
|
||||
|
||||
def read_raw(name: str) -> str:
|
||||
# 재직렬화 없이 원문 그대로 돌려준다. 미러 해시 대조의 전제다.
|
||||
p = _call("read_docs", {"doc_names": [name]})
|
||||
text = (p["result"].get("content") or [{}])[0].get("text", "")
|
||||
if not text:
|
||||
raise RuntimeError("EMPTY_RESPONSE:%s" % name)
|
||||
try:
|
||||
outer = json.loads(text)
|
||||
except Exception:
|
||||
return text
|
||||
if isinstance(outer, str):
|
||||
return outer
|
||||
if isinstance(outer, dict) and "results" in outer:
|
||||
r0 = (outer.get("results") or [{}])[0]
|
||||
inner = r0.get("content")
|
||||
if inner is None:
|
||||
inner = r0.get("text")
|
||||
if not isinstance(inner, str) or not inner:
|
||||
raise RuntimeError("EMPTY_CONTENT:%s" % name)
|
||||
return inner
|
||||
raise RuntimeError("UNEXPECTED_READ_DOCS_ENVELOPE:%s" % name)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# F-4 — 자기 입력의 배포 무결성. A0 게이트가 앞에서 걸러 주지만 이 task 는
|
||||
# 개별 재실행이 가능하다(예행 하네스가 실제로 task 단위로 돌린다).
|
||||
# 매니페스트는 task 당 한 번만 읽는다. 호출마다 읽으면 S0 의 $ref 폐포 walk 에서만 19 회다.
|
||||
# ------------------------------------------------------------------
|
||||
PART2_DEPLOYMENT_REMEDY = (
|
||||
"배포 원본 extension_research/Default_Agent 트리를 서버 Default_Agent/ 에 통째로 배포하고 "
|
||||
"runtime_manifest.json 의 등재·sha256 과 대조해 결손 경로를 복원한다. 부분 복사는 허용되지 않는다.")
|
||||
_MANIFEST_MAP = None
|
||||
|
||||
|
||||
def _manifest_map():
|
||||
global _MANIFEST_MAP
|
||||
if _MANIFEST_MAP is None:
|
||||
_MANIFEST_MAP = {row["path"]: row["sha256"]
|
||||
for row in (json.loads(read_raw(RUNTIME_MANIFEST)).get("entries") or [])
|
||||
if isinstance(row, dict)}
|
||||
return _MANIFEST_MAP
|
||||
|
||||
|
||||
def _deployment_error(logical, detail, extra=None):
|
||||
payload = {"reason_code": "PART2_ASSET_DEPLOYMENT_INCOMPLETE", "path": logical,
|
||||
"detail": detail, "remedy": PART2_DEPLOYMENT_REMEDY}
|
||||
if extra:
|
||||
payload.update(extra)
|
||||
return RuntimeError(json.dumps(payload, ensure_ascii=False))
|
||||
|
||||
|
||||
def _verify_asset(logical: str) -> str:
|
||||
"""원문을 돌려준다. 반환값을 소비해야 읽기 횟수가 늘지 않는다."""
|
||||
body = read_raw(logical)
|
||||
want = _manifest_map().get(logical[len("Default_Agent/"):])
|
||||
if want is None:
|
||||
raise _deployment_error(logical, "unregistered")
|
||||
if want != hashlib.sha256(body.encode("utf-8")).hexdigest():
|
||||
raise _deployment_error(logical, "hash_mismatch", {"expected": want})
|
||||
return body
|
||||
|
||||
|
||||
def _assert_mirror_consistent(logical: str) -> None:
|
||||
"""F-4b — 부재는 통과(materialize_validator 의 기존 관용 유지). 미등재·불일치만 막는다.
|
||||
|
||||
예외 종류를 바꿔 try 를 뚫는 우회(SystemExit 등)는 쓰지 않는다. 그것은 __main__ 가드의
|
||||
stdout 출력과 예행 하네스의 단계 기록까지 건너뛴다. 판정을 try 밖으로 옮기는 것이 답이다.
|
||||
"""
|
||||
try:
|
||||
body = read_raw(logical)
|
||||
except Exception:
|
||||
return
|
||||
want = _manifest_map().get(logical[len("Default_Agent/"):])
|
||||
if want is None:
|
||||
raise _deployment_error(logical, "unregistered")
|
||||
if want != hashlib.sha256(body.encode("utf-8")).hexdigest():
|
||||
raise _deployment_error(logical, "hash_mismatch", {"expected": want})
|
||||
|
||||
|
||||
def materialize_validator() -> list[str]:
|
||||
"""worker_output_validator 와 그 의존 셋을 반입한다. 실패는 경고로 남기고 진행한다.
|
||||
|
||||
이 검증은 덧붙이는 층이다 — 반입이 안 되는 배포에서도 R0 본체는 돌아야 한다.
|
||||
"""
|
||||
import hashlib
|
||||
import os
|
||||
import pathlib
|
||||
rt = pathlib.Path(EXECUTION_ROOT) / "_rt"
|
||||
rt.mkdir(parents=True, exist_ok=True)
|
||||
manifest_doc = json.loads(read_raw(RUNTIME_MANIFEST))
|
||||
expected = {row["path"]: row["sha256"] for row in manifest_doc.get("entries") or []}
|
||||
staged: list[str] = []
|
||||
for name, logical in VALIDATOR_MIRRORS.items():
|
||||
body = read_raw(logical)
|
||||
raw = body.encode("utf-8")
|
||||
want = expected.get(logical[len("Default_Agent/"):])
|
||||
if want is None:
|
||||
raise RuntimeError("MODULE_MIRROR_UNREGISTERED:%s" % logical)
|
||||
if want != hashlib.sha256(raw).hexdigest():
|
||||
raise RuntimeError("MODULE_MIRROR_HASH_MISMATCH:%s" % logical)
|
||||
(rt / (name + ".py")).write_bytes(raw)
|
||||
staged.append(name)
|
||||
if str(rt) not in sys.path:
|
||||
sys.path.insert(0, str(rt))
|
||||
return staged
|
||||
|
||||
|
||||
def read_json_doc(path: str) -> Any:
|
||||
result = _call("read_docs", {"doc_names": [path]})
|
||||
content = result["result"].get("content", [])
|
||||
text = content[0].get("text", "") if content else ""
|
||||
try:
|
||||
parsed = json.loads(text)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise RuntimeError(f"Invalid read_docs envelope for {path}") from exc
|
||||
if isinstance(parsed, dict) and "results" in parsed:
|
||||
rows = parsed.get("results") or []
|
||||
if not rows or rows[0].get("error"):
|
||||
raise RuntimeError(f"read_docs failed for {path}: {rows[:1]}")
|
||||
inner = rows[0].get("content") or ""
|
||||
if isinstance(inner, str):
|
||||
try:
|
||||
return json.loads(inner)
|
||||
except json.JSONDecodeError:
|
||||
obj, end = JSON_DECODER.raw_decode(inner.strip())
|
||||
if inner.strip()[end:].strip():
|
||||
raise RuntimeError(f"{path}: non-json tail")
|
||||
return obj
|
||||
return inner
|
||||
return parsed
|
||||
|
||||
def write_doc(path: str, content: str) -> None:
|
||||
_call("write_file", {"path": path, "content": content, "overwrite": True})
|
||||
|
||||
|
||||
|
||||
def _dict(value: Any) -> dict[str, Any]:
|
||||
return value if isinstance(value, dict) else {}
|
||||
|
||||
def _list(value: Any) -> list[Any]:
|
||||
return value if isinstance(value, list) else []
|
||||
|
||||
def _strings(value: Any) -> list[str]:
|
||||
out: list[str] = []
|
||||
for item in _list(value):
|
||||
if item is None:
|
||||
continue
|
||||
text = str(item).strip()
|
||||
if text and text not in out:
|
||||
out.append(text)
|
||||
return out
|
||||
|
||||
def clip(value: Any, limit: int = 120) -> str:
|
||||
text = " ".join(str(value or "").split())
|
||||
return text if len(text) <= limit else text[:limit].rstrip() + "..."
|
||||
|
||||
# v4 — parse_llm_json 을 걷어냈다. worker 가 {{item.expected_output_path}} 에
|
||||
# strict JSON 파일을 직접 쓰므로 LLM 원문 관용 파싱 경로가 없어졌다.
|
||||
# salvage_notes 는 산출 스키마에 남지만 v4 에서는 항상 빈 목록이다 — 구제할 원문이 없다.
|
||||
# v5 — DOMAIN_PAYLOAD_CANON · _canon_payload 를 걷어냈다. canon 키가 구 이름(B1~B4)뿐이라
|
||||
# registry ID 26종 전부에서 no-op 였다(사문 코드). 확장 payload 는 워커 발행 형태 그대로 둔다.
|
||||
def ensure_candidate_ref(cand: dict[str, Any], domain_id: str, idx: int) -> dict[str, Any]:
|
||||
"""v3 워커 출력에는 candidate_ref 가 없다 — seed 스키마가 additionalProperties: false 로 봉인돼
|
||||
워커가 실을 수 없는 필드다. v3 이 주는 순번에서 R0 내부 식별자를 결정적으로 만든다.
|
||||
이미 실려 있으면(구 판본 산출) 그대로 둔다."""
|
||||
ref = cand.get("candidate_ref")
|
||||
if isinstance(ref, str) and ref:
|
||||
return cand
|
||||
out = dict(cand)
|
||||
out["candidate_ref"] = "%s:%03d" % (domain_id, idx + 1)
|
||||
return out
|
||||
|
||||
def project_to_bo_surface(cand: dict[str, Any], domain_id: str, universe: dict[str, set[str]],
|
||||
policy: dict[str, Any], allowed_bo_types: set[str],
|
||||
reviews: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
"""v3 후보를 BO 호환면으로 투영한다. 값의 정본은 registry 이고 규칙은 정책 파일이 선언한다.
|
||||
|
||||
전임자 둘(expand_candidate + _seed_payload)은 v2 키를 기본값으로 깔고 v2 화이트리스트로
|
||||
걸렀다. v3 후보를 넣으면 워커가 실은 값이 extensions 하나만 남았고, 그 결과 중복 판정 키
|
||||
여덟 성분이 전부 비어 사건 전체가 한 버킷으로 접혔다(C-1·C-2). 여기서는 v3 필드에서
|
||||
끌어오고, registry 가 말해 주지 않는 칸은 채우지 않고 reviews 에 올린다.
|
||||
반환 키 집합은 입력과 무관하게 고정이다 — 이 반환문이 원장 payload 키 집합의 유일한 정의다.
|
||||
"""
|
||||
ref = str(cand.get("candidate_ref"))
|
||||
|
||||
def note(issue_type: str, field: str, source: str) -> None:
|
||||
reviews.append({"issue_type": issue_type, "candidate_ref": ref,
|
||||
"field": field, "source": source})
|
||||
|
||||
refs = _strings(cand.get("source_refs"))
|
||||
evidence = sorted(set(refs) & universe["source_evidence_indexes"])
|
||||
events = sorted(set(refs) & universe["source_event_candidate_ids"])
|
||||
clauses = sorted(set(refs) & universe["source_meeting_clause_ids"])
|
||||
|
||||
norm = _dict(policy.get("f0_normalization"))
|
||||
bo_type = cand.get("bo_type")
|
||||
if allowed_bo_types and bo_type not in allowed_bo_types:
|
||||
note("legal_effect_uncertain", "BOType", "bo_type")
|
||||
|
||||
ext = dict(_dict(cand.get("extensions")))
|
||||
if not isinstance(ext.get("domain_payload"), dict):
|
||||
ext["domain_payload"] = {}
|
||||
domain_payload = _dict(ext.get("domain_payload"))
|
||||
|
||||
action_type = domain_payload.get("action_type")
|
||||
if not (isinstance(action_type, str) and action_type in set(_strings(norm.get("action_type_enum")))):
|
||||
# registry 근거가 없는 칸이다. 기본값은 선언이며 추정이 아니다 — 반드시 검토로 올린다.
|
||||
action_type = norm.get("action_type_default")
|
||||
note("schema_field_fallback", "ActionType", "policy_default")
|
||||
|
||||
effect_type_ids = sorted({str(e.get("type_id")).strip()
|
||||
for e in _list(cand.get("legal_effect_candidates"))
|
||||
if isinstance(e, dict) and str(e.get("type_id") or "").strip()})
|
||||
action_summary = domain_payload.get("action_summary")
|
||||
if isinstance(action_summary, str) and action_summary.strip():
|
||||
action = action_summary.strip()
|
||||
elif effect_type_ids:
|
||||
# 값은 registry token 이지 서술문이 아니다. Stage 2 는 review_handoff 의 action_source 를 함께 읽는다.
|
||||
action = "%s:%s" % (bo_type, effect_type_ids[0])
|
||||
note("schema_field_fallback", "Action", "legal_effect_type_id")
|
||||
else:
|
||||
action = str(bo_type)
|
||||
note("schema_field_fallback", "Action", "bo_type")
|
||||
|
||||
time_facts = [t for t in _list(cand.get("time_facts")) if isinstance(t, dict)]
|
||||
behavior_time = None
|
||||
time_text = None
|
||||
if time_facts:
|
||||
pick = sorted(time_facts, key=lambda t: (str(t.get("fact_type") or ""), str(t.get("value") or "")))[0]
|
||||
behavior_time = pick.get("value")
|
||||
time_text = pick.get("value")
|
||||
distinct_times = {str(t.get("value") or "").strip() for t in time_facts if str(t.get("value") or "").strip()}
|
||||
if len(distinct_times) > 1:
|
||||
note("amount_or_date_uncertain", "core_field_base.BehaviorTime", "time_facts")
|
||||
|
||||
object_refs = sorted(_strings(cand.get("object_refs")))
|
||||
|
||||
amount_facts = [a for a in _list(cand.get("amount_facts")) if isinstance(a, dict)]
|
||||
amount = None
|
||||
if amount_facts:
|
||||
pick = sorted(amount_facts, key=lambda a: (str(a.get("amount_type") or ""), str(a.get("decimal_value") or "")))[0]
|
||||
# v3 amount_facts 는 {amount_type, decimal_value, currency, source_refs} 닫힌 스키마다 —
|
||||
# value_text 필드가 없으므로 정책 규칙대로 decimal_value 원문을 그대로 쓴다.
|
||||
amount = {"value_text": pick.get("decimal_value"),
|
||||
"numeric_value": pick.get("decimal_value"),
|
||||
"currency": pick.get("currency")}
|
||||
distinct_amounts = {str(a.get("decimal_value") or "").strip() for a in amount_facts if str(a.get("decimal_value") or "").strip()}
|
||||
if len(distinct_amounts) > 1:
|
||||
note("amount_or_date_uncertain", "amount", "amount_facts")
|
||||
|
||||
return {
|
||||
"candidate_ref": ref,
|
||||
"source_domain": domain_id,
|
||||
"BOType": bo_type,
|
||||
"ActionType": action_type,
|
||||
"JuristicAct": _normalize_juristic(cand.get("juristic_act_type")),
|
||||
"Action": action,
|
||||
"Reason": None,
|
||||
"PriorAct": None,
|
||||
"ReasonRefs": [],
|
||||
"Legal_Keywords": effect_type_ids,
|
||||
"core_field_base": {"BehaviorTime": behavior_time, "TimeText": time_text,
|
||||
"Object": object_refs[0] if object_refs else None,
|
||||
"StatementType": bo_type},
|
||||
"amount": amount,
|
||||
"source_evidence_indexes": evidence,
|
||||
"provenance": {"source_event_candidate_ids": events,
|
||||
"source_meeting_clause_ids": clauses,
|
||||
"source_evidence_indexes": evidence,
|
||||
"source_domain": domain_id},
|
||||
"downstream_seed_refs": {},
|
||||
"extensions": ext,
|
||||
"registry_component_ids": _strings(cand.get("registry_component_ids")),
|
||||
}
|
||||
|
||||
def expand_review_item(item: Any, domain_id: str, idx: int) -> dict[str, Any]:
|
||||
"""v3 검토 항목(후보별 review_items · 루트 unknown_or_unrouted_reviews)을 handoff 항목형으로 사상한다.
|
||||
|
||||
구판은 v3 루트 13키에 없는 domain_review_queue 를 읽었다 — 봉인(additionalProperties: false)이
|
||||
워커에게 발행을 금지한 키라 워커 검토가 한 건도 도달하지 못했다(C-6). 사상 규칙은 정책
|
||||
review_item_projection 이 선언한다. 원본 코드는 덧붙이기 키 source_review_code 로 보존한다.
|
||||
"""
|
||||
src = _dict(item)
|
||||
raw_type = str(src.get("unresolved_type") or "").strip()
|
||||
raw_code = str(src.get("review_code") or "").strip()
|
||||
severity = src.get("severity") if src.get("severity") in ("SOFT_WARNING", "HARD_WARNING") else "SOFT_WARNING"
|
||||
return {
|
||||
"review_id": str(src.get("review_id") or f"{domain_id}:review:{idx:03d}"),
|
||||
"issue_type": raw_type if raw_type in REVIEW_ISSUE_ENUM else "review_required",
|
||||
"severity": severity,
|
||||
# 원본 review_code(v3 필수 키)를 잃지 않는다 — 정책 additive_keys 의 목적이 그것이다.
|
||||
"source_review_code": raw_code or raw_type or None,
|
||||
"reason": str(src.get("reason") or "").strip(),
|
||||
"source_refs": _strings(src.get("source_refs")),
|
||||
"recommended_downstream_owner": src.get("recommended_downstream_owner") or "Stage2",
|
||||
}
|
||||
|
||||
# ---------- 워커 출력 수용 검증 (v3 계약 정본 · 정책 status_policy · 계획 해시 대조) ----------
|
||||
def validate_seed_object(seed_obj: dict[str, Any], domain_id: str, plan_row: dict[str, Any], warnings: list[dict[str, Any]]) -> None:
|
||||
"""v3 seed 루트를 검증한다. status 는 v3 enum 5종을 정책 status_policy 로 가른다.
|
||||
|
||||
구판은 READY 계열 2종만 허용해 계약상 적법한 NO_SUPPORT 가 R0 전체를 중단시켰고(C-11),
|
||||
신선도는 워커가 실을 수 없는 transport_metadata.slice_guard 를 읽는 죽은 검사였다.
|
||||
신선도의 제 필드는 v3 루트의 slice_sha256 · compiled_prompt_sha256 이고(둘 다 required
|
||||
— 워커가 반드시 echo 한다), 기대값은 fan-out 계획 행이 든다.
|
||||
"""
|
||||
if seed_obj.get("schema_version") != SEED_SCHEMA_VERSION:
|
||||
raise ValueError(f"{domain_id}: seed schema_version mismatch")
|
||||
if seed_obj.get("domain_id") != domain_id:
|
||||
raise ValueError(f"{domain_id}: seed domain_id mismatch")
|
||||
status = seed_obj.get("status")
|
||||
if status in ("BLOCKED", "FAILED"):
|
||||
# 워커 실패 신호다. fail-open 은 활성화 판정의 원칙이고, 실패의 침묵 흡수는 금지 원칙이 막는다.
|
||||
raise ValueError(f"{domain_id}: worker reported {status}")
|
||||
if status == "NO_SUPPORT":
|
||||
# 적법한 "실을 것 없음". 후보가 있으면 상태·내용 모순이다.
|
||||
if _list(seed_obj.get("bo_seed_candidates")):
|
||||
raise ValueError(f"{domain_id}: NO_SUPPORT with non-empty bo_seed_candidates")
|
||||
elif status not in ("READY", "READY_WITH_REVIEW"):
|
||||
raise ValueError(f"{domain_id}: seed status outside v3 enum: {status!r}")
|
||||
for key in ("slice_sha256", "compiled_prompt_sha256"):
|
||||
want = plan_row.get(key)
|
||||
if isinstance(want, str) and want:
|
||||
if seed_obj.get(key) != want:
|
||||
raise ValueError(f"{domain_id}: stale seed output: {key} mismatch")
|
||||
else:
|
||||
warnings.append({"domain_id": domain_id, "warning": f"fanout plan carries no {key} expectation"})
|
||||
|
||||
def validate_candidate(cand: dict[str, Any], domain_id: str, idx: int) -> None:
|
||||
prefix = domain_id
|
||||
ref = cand.get("candidate_ref")
|
||||
if not isinstance(ref, str) or not CANDIDATE_REF_RE.fullmatch(ref):
|
||||
raise ValueError(f"{domain_id}.bo_seed_candidates[{idx}].candidate_ref invalid")
|
||||
if not ref.startswith(prefix + ":"):
|
||||
raise ValueError(f"{domain_id}.bo_seed_candidates[{idx}].candidate_ref prefix mismatch")
|
||||
for forbidden in ("BO_ID", "id", "Evidence", "EvidenceTitles"):
|
||||
if forbidden in cand:
|
||||
raise ValueError(f"{domain_id}.{ref}: final field {forbidden} is prohibited")
|
||||
if cand.get("Reason") is not None:
|
||||
raise ValueError(f"{domain_id}.{ref}: Reason must be null/absent")
|
||||
if cand.get("PriorAct") is not None:
|
||||
raise ValueError(f"{domain_id}.{ref}: PriorAct must be null/absent")
|
||||
if cand.get("ReasonRefs") not in ([], None):
|
||||
raise ValueError(f"{domain_id}.{ref}: ReasonRefs must be []/absent")
|
||||
|
||||
# ---------- PostB_1 이식: sort key / duplicate keys / schema risk ----------
|
||||
def _source_refs(seed: dict[str, Any]) -> dict[str, list[str]]:
|
||||
provenance = _dict(seed.get("provenance"))
|
||||
return {
|
||||
"source_evidence_indexes": _strings(seed.get("source_evidence_indexes") or provenance.get("source_evidence_indexes")),
|
||||
"source_event_candidate_ids": _strings(provenance.get("source_event_candidate_ids")),
|
||||
"source_meeting_clause_ids": _strings(provenance.get("source_meeting_clause_ids")),
|
||||
}
|
||||
|
||||
def _sort_key(seed: dict[str, Any]) -> dict[str, Any]:
|
||||
core = _dict(seed.get("core_field_base"))
|
||||
domain = seed.get("source_domain")
|
||||
juristic = _dict(seed.get("JuristicAct"))
|
||||
return {
|
||||
"BehaviorTime": core.get("BehaviorTime"),
|
||||
"domain_order": DOMAIN_ORDER.index(domain) if domain in DOMAIN_ORDER else len(DOMAIN_ORDER),
|
||||
"BOType": seed.get("BOType"),
|
||||
"ActionType": seed.get("ActionType"),
|
||||
"JuristicActLabel": juristic.get("label"),
|
||||
"Action": seed.get("Action"),
|
||||
"candidate_ref": seed.get("candidate_ref"),
|
||||
}
|
||||
|
||||
def _duplicate_key(seed: dict[str, Any]) -> tuple[Any, ...]:
|
||||
core = _dict(seed.get("core_field_base"))
|
||||
juristic = _dict(seed.get("JuristicAct"))
|
||||
refs = _source_refs(seed)
|
||||
return (
|
||||
tuple(sorted(refs["source_evidence_indexes"])),
|
||||
tuple(sorted(refs["source_event_candidate_ids"])),
|
||||
seed.get("BOType"),
|
||||
seed.get("ActionType"),
|
||||
juristic.get("label"),
|
||||
str(seed.get("Action") or "").strip(),
|
||||
str(core.get("BehaviorTime") or "").strip(),
|
||||
str(core.get("Object") or "").strip(),
|
||||
)
|
||||
|
||||
def _normalize_juristic(value: Any) -> Any:
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, dict):
|
||||
label = value.get("label")
|
||||
return {"label": str(label).strip()} if label not in (None, "") else {"label": None}
|
||||
text = str(value).strip()
|
||||
return {"label": text} if text else None
|
||||
|
||||
def _compact_exception_payload(seeds: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
compact = []
|
||||
for seed in seeds:
|
||||
compact.append({
|
||||
"candidate_ref": seed.get("candidate_ref"),
|
||||
"source_domain": seed.get("source_domain"),
|
||||
"BOType": seed.get("BOType"),
|
||||
"ActionType": seed.get("ActionType"),
|
||||
"JuristicAct": seed.get("JuristicAct"),
|
||||
"Action": seed.get("Action"),
|
||||
"core_field_base": seed.get("core_field_base"),
|
||||
"amount": seed.get("amount"),
|
||||
"source_refs": _source_refs(seed),
|
||||
})
|
||||
return compact
|
||||
|
||||
def main() -> None:
|
||||
_init()
|
||||
# F-4a — 자기 정적 입력. try 밖이어야 한다. 안에 넣으면 아래 except Exception 이
|
||||
# 삼켜 WORKER_VALIDATOR_UNAVAILABLE 경고로 강등되고 R0 이 계속 돈다.
|
||||
_seed_schema_body = _verify_asset(SEED_SCHEMA_PATH)
|
||||
# R0-1 — 투영 정책 반입 (F-4a 와 같은 규율: try 밖 경성). 정책이 없거나 낡았는데
|
||||
# 조용히 옛 규칙으로 도는 것이 이번 결손(v2 잔재)의 재발 경로다.
|
||||
projection_policy = _dict(json.loads(_verify_asset(BO_PROJECTION_POLICY)))
|
||||
if projection_policy.get("schema_version") != BO_PROJECTION_SCHEMA_VERSION:
|
||||
raise RuntimeError("PART2_PROJECTION_POLICY_INVALID")
|
||||
# F-4b — 미러 넷의 무결성. 부재는 통과시키고 미등재·불일치만 막는다.
|
||||
for _mirror in VALIDATOR_MIRRORS.values():
|
||||
_assert_mirror_consistent(_mirror)
|
||||
salvage_notes: list[dict[str, Any]] = []
|
||||
guard_warnings: list[dict[str, Any]] = []
|
||||
# v4 — seed 목록과 그 순서는 A0 의 fan-out 계획이 정한다. 이 파일은 목록을 만들지 않는다.
|
||||
worker_validator = None
|
||||
seed_schema = None
|
||||
try:
|
||||
materialize_validator()
|
||||
import worker_output_validator as worker_validator
|
||||
seed_schema = json.loads(_seed_schema_body)
|
||||
except Exception as exc:
|
||||
guard_warnings.append({"code": "WORKER_VALIDATOR_UNAVAILABLE", "message": str(exc)[:200]})
|
||||
worker_validator = None
|
||||
_docs, _rows = _seed_docs_from_plan(_dict(read_json_doc(FANOUT_PLAN_PATH)))
|
||||
SEED_DOCS.update(_docs)
|
||||
PLAN_ROWS.update(_rows)
|
||||
DOMAIN_ORDER.extend(_domain_order(SEED_DOCS))
|
||||
stage_a_outer = read_json_doc(STAGE_A_PATH)
|
||||
stage_a = _dict(_dict(stage_a_outer).get("stage_a_context") or stage_a_outer)
|
||||
if stage_a.get("schema_version") != "task_c_bo_stage_a_context.v1" or stage_a.get("status") != "READY":
|
||||
raise RuntimeError("Stage A context must be READY task_c_bo_stage_a_context.v1")
|
||||
manifest = _dict(read_json_doc(MANIFEST_PATH))
|
||||
universe = {
|
||||
"source_event_candidate_ids": set(_strings(manifest.get("event_candidate_ids"))),
|
||||
"source_evidence_indexes": set(_strings(manifest.get("evidence_index_set"))),
|
||||
"source_meeting_clause_ids": set(_strings(manifest.get("meeting_clause_ids"))),
|
||||
}
|
||||
if not universe["source_evidence_indexes"]:
|
||||
raise RuntimeError("source universe manifest has no evidence indexes")
|
||||
|
||||
# 1) 워커 출력 수용: 검증 -> 투영. 워커 seed 파일은 손대지 않는다 —
|
||||
# 선언표(stage1_part_interface.v1)가 기록자를 워커 하나로 정했다(R0-5).
|
||||
seed_objects: dict[str, dict[str, Any]] = {}
|
||||
projected_candidates: dict[str, list[dict[str, Any]]] = {}
|
||||
review_handoff_items: list[dict[str, Any]] = []
|
||||
allowed_bo_types_by_domain: dict[str, set[str]] = {}
|
||||
projection_review_counter = 0
|
||||
for domain_id in DOMAIN_ORDER:
|
||||
# v4 — worker 가 {{item.expected_output_path}} 에 자기 seed 를 직접 쓴다.
|
||||
# {{prev}} 원문 관용 파싱이 아니라 계획이 정한 경로에서 읽는다.
|
||||
outer = _dict(read_json_doc(SEED_DOCS[domain_id]))
|
||||
seed_obj = _dict(outer.get("stage_b_domain_bo_seed_output"))
|
||||
if not seed_obj:
|
||||
raise RuntimeError(f"{domain_id}: stage_b_domain_bo_seed_output missing")
|
||||
validate_seed_object(seed_obj, domain_id, PLAN_ROWS.get(domain_id) or {}, guard_warnings)
|
||||
# 슬라이스는 검증기 유무와 무관하게 읽는다 — worker_output_validator 와
|
||||
# BOType 허용 어휘(allowed_legal_effect_bo_types, registry 유래)가 이 값을 쓴다.
|
||||
try:
|
||||
slice_doc = read_json_doc("%s/%s.json" % (SLICE_DIR, domain_id))
|
||||
except Exception:
|
||||
slice_doc = None
|
||||
slice_root = _dict(_dict(slice_doc).get(SLICE_ROOT_KEY)) if isinstance(slice_doc, dict) else {}
|
||||
allowed_bo_types = set(_strings(slice_root.get("allowed_legal_effect_bo_types")))
|
||||
allowed_bo_types_by_domain[domain_id] = allowed_bo_types
|
||||
# R-4 — 스키마와 슬라이스를 실제로 넘긴다. 넘기지 않으면 검증이 조용히 건너뛰어진다.
|
||||
if worker_validator is not None:
|
||||
report = worker_validator.validate_worker_output(
|
||||
{"stage_b_domain_bo_seed_output": seed_obj},
|
||||
schema=seed_schema,
|
||||
expected_domain_id=domain_id,
|
||||
slice_document=slice_doc)
|
||||
for item in report.get("errors") or []:
|
||||
guard_warnings.append({"code": "WORKER_OUTPUT_ERROR", "domain_id": domain_id,
|
||||
"detail": item})
|
||||
for item in report.get("warnings") or []:
|
||||
guard_warnings.append({"code": "WORKER_OUTPUT_REVIEW", "domain_id": domain_id,
|
||||
"detail": item})
|
||||
cands = _list(seed_obj.get("bo_seed_candidates"))
|
||||
projected: list[dict[str, Any]] = []
|
||||
projection_reviews: list[dict[str, Any]] = []
|
||||
for idx, cand in enumerate(cands):
|
||||
if not isinstance(cand, dict):
|
||||
raise RuntimeError(f"{domain_id}.bo_seed_candidates[{idx}] must be object")
|
||||
cand = ensure_candidate_ref(cand, domain_id, idx)
|
||||
validate_candidate(cand, domain_id, idx)
|
||||
# membership 검사 — v3 의 평평한 source_refs 를 universe 와 대조 (hard BLOCK).
|
||||
# 이쪽을 보지 않으면 membership 게이트가 v3 산출에서는 통과만 하는 빈 검사가 된다.
|
||||
known_sources = (universe["source_event_candidate_ids"] | universe["source_meeting_clause_ids"]
|
||||
| universe["source_evidence_indexes"])
|
||||
ref_bad = [v for v in _strings(cand.get("source_refs")) if v not in known_sources]
|
||||
if ref_bad:
|
||||
raise RuntimeError(f"BLOCK: {domain_id}.{cand.get('candidate_ref')}: source_refs outside Stage A universe: {ref_bad}")
|
||||
projected.append(project_to_bo_surface(cand, domain_id, universe, projection_policy,
|
||||
allowed_bo_types, projection_reviews))
|
||||
# R0-5 — 되쓰기 없음. seed_objects 는 워커 원본 그대로다(S0 와 signal adapter 가
|
||||
# v3 적합 원본을 읽는다). 투영본은 projected_candidates 가 따로 든다(R0-2 배선).
|
||||
seed_objects[domain_id] = seed_obj
|
||||
projected_candidates[domain_id] = projected
|
||||
# R0-4 — v3 검토 채널: 후보별 review_items + 루트 unknown_or_unrouted_reviews.
|
||||
# list(...) 복사는 워커 원본 목록을 제자리 변형하지 않기 위한 것이다.
|
||||
worker_reviews = list(_list(seed_obj.get("unknown_or_unrouted_reviews")))
|
||||
for cand in _list(seed_obj.get("bo_seed_candidates")):
|
||||
worker_reviews.extend(_list(_dict(cand).get("review_items")))
|
||||
if seed_obj.get("status") == "NO_SUPPORT":
|
||||
worker_reviews.append({"review_id": f"{domain_id}:status:NO_SUPPORT",
|
||||
"review_code": "NO_SUPPORT",
|
||||
"unresolved_type": "review_required",
|
||||
"severity": "SOFT_WARNING",
|
||||
"reason": "worker reported NO_SUPPORT (nothing to carry for this domain)"})
|
||||
for idx, item in enumerate(worker_reviews, start=1):
|
||||
mapped = expand_review_item(item, domain_id, idx)
|
||||
refs = set(mapped.get("source_refs") or [])
|
||||
review_handoff_items.append({
|
||||
"review_id": mapped["review_id"],
|
||||
"source_domain": domain_id,
|
||||
"severity": mapped["severity"],
|
||||
"issue_type": mapped["issue_type"],
|
||||
"source_review_code": mapped.get("source_review_code"),
|
||||
"source_event_candidate_ids": sorted(refs & universe["source_event_candidate_ids"]),
|
||||
"source_evidence_indexes": sorted(refs & universe["source_evidence_indexes"]),
|
||||
"source_meeting_clause_ids": sorted(refs & universe["source_meeting_clause_ids"]),
|
||||
"downstream_owner": mapped["recommended_downstream_owner"] if mapped.get("recommended_downstream_owner") in DOWNSTREAM_OWNER_ENUM else "Stage2",
|
||||
"template_note": mapped.get("reason") or "후속 단계에서 해당 review 항목의 증거와 법률상 의미를 재검토한다.",
|
||||
})
|
||||
for note_item in projection_reviews:
|
||||
projection_review_counter += 1
|
||||
entry = {
|
||||
"review_id": "R0:projection:%03d" % projection_review_counter,
|
||||
"source_domain": domain_id,
|
||||
"severity": "SOFT_WARNING",
|
||||
"issue_type": note_item["issue_type"],
|
||||
"source_review_code": note_item.get("field"),
|
||||
"source_event_candidate_ids": [],
|
||||
"source_evidence_indexes": [],
|
||||
"source_meeting_clause_ids": [],
|
||||
"downstream_owner": "Stage2",
|
||||
"template_note": "투영 규칙이 채우지 못했거나 기본값을 적용한 칸이다: %s ← %s (%s)" % (
|
||||
note_item.get("field"), note_item.get("source"), note_item.get("candidate_ref")),
|
||||
}
|
||||
if note_item.get("field") == "Action":
|
||||
entry["action_source"] = note_item.get("source")
|
||||
review_handoff_items.append(entry)
|
||||
|
||||
# 2) ledger 구성 — 원장은 워커 원본이 아니라 투영본을 읽는다 (R0-2 배선).
|
||||
# 워커 원본에는 candidate_ref 가 없으므로(봉인 스키마) 원본을 넣으면 아래 검사에서 즉사한다.
|
||||
input_candidate_total = 0
|
||||
seeds: list[dict[str, Any]] = []
|
||||
for domain_id in DOMAIN_ORDER:
|
||||
projected = projected_candidates[domain_id]
|
||||
input_candidate_total += len(projected)
|
||||
seeds.extend(projected)
|
||||
if not seeds:
|
||||
raise RuntimeError("no seed candidate from Stage B workers")
|
||||
|
||||
seen_refs: set[str] = set()
|
||||
ledger_candidates: list[dict[str, Any]] = []
|
||||
deterministic_decisions: list[dict[str, Any]] = []
|
||||
exceptions: list[dict[str, Any]] = []
|
||||
duplicate_buckets: dict[tuple[Any, ...], list[dict[str, Any]]] = {}
|
||||
policy_review_counter = 0
|
||||
|
||||
def add_policy_review(domain_id: str, issue_type: str, refs: dict[str, list[str]], severity: str = "SOFT_WARNING") -> None:
|
||||
nonlocal policy_review_counter
|
||||
policy_review_counter += 1
|
||||
review_handoff_items.append({
|
||||
"review_id": f"R0:policy:{policy_review_counter:03d}",
|
||||
"source_domain": domain_id,
|
||||
"severity": severity,
|
||||
"issue_type": issue_type,
|
||||
"source_event_candidate_ids": refs.get("source_event_candidate_ids", []),
|
||||
"source_evidence_indexes": refs.get("source_evidence_indexes", []),
|
||||
"source_meeting_clause_ids": refs.get("source_meeting_clause_ids", []),
|
||||
"downstream_owner": "Stage2",
|
||||
"template_note": "결정적 defer 정책에 의해 보존된 검토 항목이다.",
|
||||
})
|
||||
|
||||
for seed in seeds:
|
||||
ref = seed.get("candidate_ref")
|
||||
if not isinstance(ref, str) or not CANDIDATE_REF_RE.fullmatch(ref):
|
||||
raise RuntimeError(f"invalid candidate_ref: {ref!r}")
|
||||
if ref in seen_refs:
|
||||
raise RuntimeError(f"duplicate candidate_ref: {ref}")
|
||||
seen_refs.add(ref)
|
||||
refs = _source_refs(seed)
|
||||
# hard BLOCK: universe 밖 ref는 soft-strip 이후에도 남아있으면 안 된다 (방어적 재검사)
|
||||
for key, values in refs.items():
|
||||
allowed = universe.get(key, set())
|
||||
outside = [v for v in values if allowed and v not in allowed]
|
||||
if outside:
|
||||
raise RuntimeError(f"{ref}: {key} outside Stage A universe: {outside}")
|
||||
flags: list[str] = []
|
||||
# 결정적 defer 정책 (개선전략서 X-2):
|
||||
# C-2 (P0 판정 B) — 증거 단계에서 붙은 registry 구성요소는 증거 유래 근거다.
|
||||
# _source_refs 가 seed 루트와 provenance 를 모두 보는 관례를 그대로 따른다.
|
||||
registry_components = [
|
||||
str(value)
|
||||
for value in (seed.get("registry_component_ids")
|
||||
or _dict(seed.get("provenance")).get("registry_component_ids")
|
||||
or [])
|
||||
if isinstance(value, str) and value
|
||||
]
|
||||
if not refs["source_evidence_indexes"] and not registry_components:
|
||||
flags.append("meeting_only_evidence_gap")
|
||||
add_policy_review(seed.get("source_domain"), "meeting_only_evidence_gap", refs)
|
||||
domain_allowed = allowed_bo_types_by_domain.get(str(seed.get("source_domain"))) or set()
|
||||
if (domain_allowed and seed.get("BOType") not in domain_allowed) or not seed.get("ActionType") or not (
|
||||
seed.get("Action") or _dict(_dict(seed.get("extensions")).get("domain_payload")).get("action_summary")
|
||||
):
|
||||
flags.append("schema_field_fallback")
|
||||
add_policy_review(seed.get("source_domain"), "schema_field_fallback", refs)
|
||||
link_candidates = _strings(_dict(seed.get("downstream_seed_refs")).get("prior_candidate_refs"))
|
||||
if len(link_candidates) > 1:
|
||||
flags.append("prior_link_ambiguous")
|
||||
add_policy_review(seed.get("source_domain"), "prior_link_ambiguous", refs)
|
||||
duplicate_buckets.setdefault(_duplicate_key(seed), []).append(seed)
|
||||
ledger_candidates.append({
|
||||
"candidate_ref": ref,
|
||||
"source_domain": seed.get("source_domain"),
|
||||
"seed_payload": seed,
|
||||
"source_refs": refs,
|
||||
"deterministic_sort_key": _sort_key(seed),
|
||||
"flags": flags,
|
||||
})
|
||||
|
||||
# exact duplicate: provenance union 무손실이므로 canonical merge (v2 규칙 계승)
|
||||
for bucket in duplicate_buckets.values():
|
||||
if len(bucket) <= 1:
|
||||
continue
|
||||
canonical = bucket[0].get("candidate_ref")
|
||||
duplicates = [item.get("candidate_ref") for item in bucket[1:]]
|
||||
deterministic_decisions.append({
|
||||
"decision_type": "EXACT_DUPLICATE_MERGE",
|
||||
"canonical_candidate_ref": canonical,
|
||||
"duplicate_candidate_refs": duplicates,
|
||||
"basis": "exact duplicate deterministic rule (provenance-lossless union)",
|
||||
})
|
||||
|
||||
# near duplicate: KEEP_SEPARATE + cluster id + review (LLM 금지 — defer 정책)
|
||||
near_buckets: dict[tuple[Any, ...], list[dict[str, Any]]] = {}
|
||||
for seed in seeds:
|
||||
refs = _source_refs(seed)
|
||||
key = (
|
||||
tuple(sorted(refs["source_evidence_indexes"])),
|
||||
tuple(sorted(refs["source_event_candidate_ids"])),
|
||||
seed.get("BOType"),
|
||||
seed.get("ActionType"),
|
||||
)
|
||||
near_buckets.setdefault(key, []).append(seed)
|
||||
near_cluster_count = 0
|
||||
pack_field_conflicts: list[dict[str, Any]] = []
|
||||
for bucket in near_buckets.values():
|
||||
if len(bucket) <= 1 or len({_duplicate_key(s) for s in bucket}) <= 1:
|
||||
continue
|
||||
near_cluster_count += 1
|
||||
cluster_id = f"near-dup-{near_cluster_count:03d}"
|
||||
cluster_refs = [str(s.get("candidate_ref")) for s in bucket]
|
||||
for item in ledger_candidates:
|
||||
if item["candidate_ref"] in cluster_refs:
|
||||
item.setdefault("near_dup_cluster_id", cluster_id)
|
||||
if "near_duplicate_kept_separate" not in item["flags"]:
|
||||
item["flags"].append("near_duplicate_kept_separate")
|
||||
add_policy_review(bucket[0].get("source_domain"), "near_duplicate_kept_separate",
|
||||
{"source_evidence_indexes": _source_refs(bucket[0])["source_evidence_indexes"],
|
||||
"source_event_candidate_ids": _source_refs(bucket[0])["source_event_candidate_ids"],
|
||||
"source_meeting_clause_ids": []})
|
||||
# non-deferrable 판정(X-3 4중 조건): 같은 near cluster에서 BehaviorTime 또는 amount가
|
||||
# 서로 다른 non-null 값으로 충돌하면 writer가 단일 값을 고를 수 없으므로 pack에 수록
|
||||
times = {str(_dict(s.get("core_field_base")).get("BehaviorTime")) for s in bucket if _dict(s.get("core_field_base")).get("BehaviorTime")}
|
||||
amounts = set()
|
||||
for s in bucket:
|
||||
av = s.get("amount")
|
||||
if isinstance(av, dict) and av.get("value_text"):
|
||||
amounts.add(str(av.get("value_text")))
|
||||
elif isinstance(av, str) and av.strip():
|
||||
amounts.add(av.strip())
|
||||
if len(times) > 1 or len(amounts) > 1:
|
||||
pack_field_conflicts.append({
|
||||
"exception_id": f"EX-FIELD-{len(pack_field_conflicts) + 1:03d}",
|
||||
"exception_type": "field_conflict",
|
||||
"candidate_refs": cluster_refs,
|
||||
"reason": "same-source candidates carry conflicting BehaviorTime/amount values",
|
||||
"conflicting_values": {"BehaviorTime": sorted(times), "amount": sorted(amounts)},
|
||||
"compact_candidate_payload": _compact_exception_payload(bucket),
|
||||
"allowed_decisions": ["KEEP_SEPARATE", "MERGE", "SPLIT", "DROP", "BLOCK_REVIEW"],
|
||||
"escalation_flag": True,
|
||||
})
|
||||
|
||||
exceptions.extend(pack_field_conflicts)
|
||||
has_exceptions = bool(exceptions)
|
||||
|
||||
# 3) conservation invariant (write 전)
|
||||
merged_absorbed = sum(len(_strings(d.get("duplicate_candidate_refs"))) for d in deterministic_decisions)
|
||||
if len(ledger_candidates) != input_candidate_total:
|
||||
raise RuntimeError(f"ledger candidate count {len(ledger_candidates)} != input candidates {input_candidate_total}")
|
||||
if len(seen_refs) != input_candidate_total:
|
||||
raise RuntimeError("candidate_ref conservation failed")
|
||||
|
||||
ledger = {
|
||||
"postb_seed_ledger": {
|
||||
"schema_version": "task_c_bo_postb_seed_ledger.v1",
|
||||
"status": "READY",
|
||||
"source_stage_a_created_at_utc": stage_a.get("created_at_utc"),
|
||||
"input_digests_sha256": stage_a.get("input_digests_sha256"),
|
||||
"source_universe": {
|
||||
"source_event_candidate_ids": sorted(universe["source_event_candidate_ids"]),
|
||||
"source_evidence_indexes": sorted(universe["source_evidence_indexes"]),
|
||||
"source_meeting_clause_ids": sorted(universe["source_meeting_clause_ids"]),
|
||||
},
|
||||
"stage_b_source_contract": {
|
||||
"schema_version": "task_c_bo_stage_b_bo_seed_universe.compat_from_r0.v1",
|
||||
"status": "READY",
|
||||
"compatibility_source": "r0_seed_reducer.direct_worker_outputs",
|
||||
},
|
||||
"ledger_candidates": sorted(ledger_candidates, key=lambda item: (
|
||||
item["deterministic_sort_key"].get("BehaviorTime") is None,
|
||||
item["deterministic_sort_key"].get("BehaviorTime") or "",
|
||||
item["deterministic_sort_key"].get("domain_order", 99),
|
||||
item["deterministic_sort_key"].get("BOType") or "",
|
||||
item["deterministic_sort_key"].get("ActionType") or "",
|
||||
item["deterministic_sort_key"].get("JuristicActLabel") or "",
|
||||
item["deterministic_sort_key"].get("Action") or "",
|
||||
item["deterministic_sort_key"].get("candidate_ref") or "",
|
||||
)),
|
||||
"deterministic_decisions": deterministic_decisions,
|
||||
"exception_pack": {
|
||||
"has_exceptions": has_exceptions,
|
||||
"clusters": [],
|
||||
"field_conflicts": pack_field_conflicts,
|
||||
"link_ambiguities": [],
|
||||
"schema_risks": [],
|
||||
},
|
||||
"audit_trace": {
|
||||
"removed_or_sidecar_fields": [],
|
||||
"source_membership_policy": "outside-universe source ref => hard BLOCK (defer 정책 §7)",
|
||||
"normalization_notes": salvage_notes + guard_warnings,
|
||||
},
|
||||
}
|
||||
}
|
||||
write_doc(LEDGER_PATH, json.dumps(ledger, ensure_ascii=False, indent=2))
|
||||
|
||||
pack = {
|
||||
"schema_version": "stage1_part2_exception_pack.v1",
|
||||
"has_exceptions": has_exceptions,
|
||||
"exception_count": len(exceptions),
|
||||
"exceptions": exceptions,
|
||||
"budget": {"max_candidates_per_exception": 8, "max_payload_chars_per_candidate": 2000},
|
||||
}
|
||||
write_doc(PACK_PATH, json.dumps(pack, ensure_ascii=False, indent=2))
|
||||
|
||||
handoff = {
|
||||
"schema_version": "stage1_part2_review_handoff.v1",
|
||||
"status": "PENDING_FINALIZE",
|
||||
"review_items": review_handoff_items,
|
||||
}
|
||||
write_doc(REVIEW_HANDOFF_PATH, json.dumps(handoff, ensure_ascii=False, indent=2))
|
||||
|
||||
print(json.dumps({
|
||||
"status": "READY",
|
||||
"message": "R0 seed reducer 완료: ledger/exception pack/review handoff 생성",
|
||||
"ledger_path": LEDGER_PATH,
|
||||
"exception_pack_path": PACK_PATH,
|
||||
"review_handoff_path": REVIEW_HANDOFF_PATH,
|
||||
"has_exceptions": has_exceptions,
|
||||
"exception_count": len(exceptions),
|
||||
"candidate_counts": {
|
||||
"input": input_candidate_total,
|
||||
"ledger": len(ledger_candidates),
|
||||
"exact_duplicate_absorbed": merged_absorbed,
|
||||
"near_dup_clusters": near_cluster_count,
|
||||
},
|
||||
"review_item_count": len(review_handoff_items),
|
||||
"salvage_count": len(salvage_notes),
|
||||
}, ensure_ascii=False))
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except Exception as exc:
|
||||
print(json.dumps({"status": "FAILED", "message": "R0 seed reducer 실패: downstream 진행 금지",
|
||||
"reason": str(exc)}, ensure_ascii=False))
|
||||
raise
|
||||
+3315
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -25,7 +25,9 @@
|
||||
# fan-out fanout/domain_fanout_plan.json domain_fanout_plan.v1
|
||||
# worker 이름 Task_C_B_domain_worker_* · 인스턴스 DOMAIN-<도메인ID>
|
||||
# 실행 인자 --asset-root · --execution-root · --logical-root
|
||||
# 구 경로 stage1_tmp/task_c_bo/** 는 쓰지 않는다(legacy_paths_forbidden).
|
||||
# 구 slice/seed 경로(stage1_tmp/task_c_bo/domain_slices|domain_seed_outputs)는 쓰지 않는다
|
||||
# (legacy_paths_forbidden). stage_a_context·source_universe_manifest(P-1 복귀)와
|
||||
# postb_* 3종은 stage1_tmp/task_c_bo/ 를 정본 경로로 유지한다.
|
||||
#
|
||||
# 모듈 반입 — Part 1 D0 규약 R-1~R-5 승계
|
||||
# .txt 미러를 read_raw 로 읽고 runtime_manifest.json 의 sha256 과 대조한 뒤
|
||||
@@ -890,8 +892,6 @@ Agent:
|
||||
"registry_loader": "Default_Agent/stage1_runtime/registry_loader.txt",
|
||||
"worker_output_validator": "Default_Agent/stage1_runtime/worker_output_validator.txt",
|
||||
}
|
||||
ACTIVATION_MANIFEST_PATH = "routing/domain_activation_manifest.json"
|
||||
REGISTRY_INDEX_PATH = "Default_Agent/domains/_registry_index.json"
|
||||
|
||||
def _seed_docs_from_plan(plan):
|
||||
# v5 — 경로만이 아니라 계획 행 전체를 보관한다. validate_seed_object 가
|
||||
|
||||
+21
-43
@@ -2262,6 +2262,25 @@ stage_1_2_3_assets_distribution_location.md`의 `§8. 특기사항 (판독 중
|
||||
|
||||
==================================
|
||||
|
||||
<only_tasks_to_perform>
|
||||
`problems_identified_in_detecting_assets_location_v.2.md`--`§2. 확정 작업 분류`의 `A. YAML 수정으로 해결`에서 `P2 L893–894 사문 상수 2줄 삭제`, `P2 L28 주석 1줄`
|
||||
`B. Default_Agent 자산 등재/삭제로 해결`에서 `**P1 자산 6종 manifest 등재**`, ``validation_assets/routing/case_kind_domain_matrix.v2.json` 제거` 작업들을 수행한다.
|
||||
</only_tasks_to_perform>
|
||||
|
||||
<method>
|
||||
1. <only_tasks_to_perform>에 기재된 작업을 수행한다.
|
||||
2. 작업 수행 후, sub-agent를 띄워 지시사항을 100% 정확히 준수하여 작업이 진행되었는지 검증한다. 이 검증을 통과할 때까지 작업수행-검증 과정을 반복한다.
|
||||
3. 검증 과정을 완전히 통과했을 때, 수정된 yaml 파일들은 overwrite하여 기존 위치에 저장하고, 기존 yaml들은 outdated 폴더로 옮긴다.
|
||||
4. `B. Default_Agent 자산 등재/삭제로 해결` 작업 수행 결과로 Default_Agent 폴더에 변화가 발생한 내용만을 `stage_1_2_3_assets_distribution_location.md` 동일 파일명으로 overwrite하여 저장하고 기존 파일은`stage_1_2_3_assets_distribution_location_old.md`로 파일명만 바꾸어서 유지한다.
|
||||
</method>
|
||||
|
||||
<global_constraints>
|
||||
- `v.7/CLAUDE.md`가 제시하는 Fable 5 행동 규칙을 준수한다.
|
||||
- 작업 완료 시 작업 내역을 압축 요약하여 `v.7/MEMORY.md`에 추가 기입한다.
|
||||
- MEMORY.md 기입 후 연결된 git repository에 commit한다.
|
||||
</global_constraints>
|
||||
|
||||
==================================
|
||||
|
||||
|
||||
|
||||
@@ -2273,34 +2292,8 @@ stage_1_2_3_assets_distribution_location.md`의 `§8. 특기사항 (판독 중
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Stage 1 - part 1|2|3 배포 폴더 위치 v.2 작성
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
stage_1_part_3_개정작업내역서.md
|
||||
stage_1_part_1_v.8.yml
|
||||
|
||||
|
||||
|
||||
--> stage 1 -- part 4 개정 작업 최적 워크플로우 탐구 --> 작업 명세서 작성
|
||||
--> stage 1 -- part 4 개정 --> 남은 작업 check --> 추가작업 명세서 생성 및 작업 수행 --> part 4 개정 마무리
|
||||
|
||||
--> stage 1 -- part 3 개정 작업 최적 워크플로우 탐구 --> 작업 명세서 생성
|
||||
--> stage 1 -- part 3 개정 --> 남은 작업 check --> 추가작업 명세서 생성 및 작업 수행 --> part 3 개정 마무리
|
||||
@@ -2309,21 +2302,6 @@ stage_1_part_1_v.8.yml
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user