diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/MEMORY.md b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/MEMORY.md index caee6507..8c01e501 100644 --- a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/MEMORY.md +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/MEMORY.md @@ -1474,3 +1474,26 @@ D-4 결정안 승계(Θ=expected_runnable 합집합 · order_key 3키 · by_modu 2. **회귀 시나리오는 자기 문서의 읽기 규율과 대조해야 한다.** `_verify_asset` 로 읽으라고 지시한 자산의 "내용만 변조" 회귀는 해시 게이트에 먼저 걸려 의미 검사에 도달하지 못한다 — 변조 회귀는 장부 동반/미동반 두 변종이 짝이다. 3. **용어 하나("활성")가 필수 회귀를 뒤집는다.** 정의역이 둘(`active` ⊊ `expected_runnable`) 있는 시스템에서는 집합 이름을 축약하지 말 것. 4. 문서 검증자는 편집 파급 검증에서 가장 세다 — 라운드 2~6 의 지적 전부가 "반영이 만든 새 모순"이었다. 반영 후 재검증을 생략하면 수정이 결함을 재생산한다. + + +--- + +## 2026-08-19 ㉓ — Part 3 신전략서 실행 완료: stage_1_part_3_v.8.yml 생성 (예행 3패스 · 회귀 24/24 · 적대 검증 2라운드) + +산출: 통합본 `ver_8_yaml_candidates/stage_1_part_3_v.8.yml`(52,878 B · task 2 · IN→L0→L2→OUT) + 조각 P3-L0/L2 v1, 배포 원본 신설 5종(`structure_index_compiler.py`+미러 · `structure_index_policy.v1.json` · 스키마 2 — 파일명 무판본·패턴만) + 사이드카 50 복사(조립본과 바이트 동일), `runtime_manifest` **371→426**(델타 55·기존 행 수정 0), 선언표 34→**45**(C-7 구 이름 소비자 제거·C-8 폐쇄), stage_chain·상위 전략서 2곳, 내역서 `stage_1_part_3_개정작업내역서.md`. P3-0a 는 사용자의 실행 지시를 승인으로 처리. + +### 핵심 실측 +- 예행 3패스(asset root = 배포 원본): pass1 6/45 · pass2 3/29 · **pass3 2/5 — `legal_effect_structures.json` 실생성**. Θ 4종·레코드 6((도메인,type_id) 쌍)·SG-13 6/6 부착·**BO 2/2 부착**(source_domain+Legal_Keywords 결정론 조인 — BO 투영 회차가 실은 registry 토큰이 여기서 회수됨)·보존 등식 셋(L2 가 config·SG-13·BO 원본에서 바깥 수 직접 계수)·역인덱스 셋(by_domain_id·by_module·by_bo_id). +- 26 도메인 합성: Θ 56 · 구조 73 · module 34 · 머리 4줄(rank1 money_claim×2 비병합) · 결정론. 계산 탐침: signal_id 조인·dangling 검토·미연결 형식화 각 실증. +- 회귀 L-a~L-s 22종 + 보충 2종 = 24/24(필수 8종 포함). 변조는 전부 사본 트리 — 배포 원본 무변. +- 선언표 검사기 finding 0(3 yaml 전수). 트리 210 파일·매니페스트 실재분 전수 일치·__pycache__ 0. + +### 검증 루프 (지적 5 → 0) +1차 MAJOR 2: ① 선언표 `client_meeting` 행이 **두 곳에 중복**(entry_inputs·handoffs)인데 절반만 갱신 — 검사기는 handoffs 만 읽으므로 기계 검증면 미반영 ② 도메인 봉투 부재가 침묵 스킵(실주행에서 감시 도메인 봉투 부재는 상시 경로) → `audit.input_gaps` 기록+L-k 단언. MINOR 3: L2 의 계약 밖 signal_manifest 읽기(→ L0 가 transaction_id 를 bundle 에 부착해 승계) · 합성/탐침 증적 미보존(→ SUPP 2종 영구 기록) · `Stage_1.Part_3` 약칭 잔존. 재검증 **지적 0건**. + +### 교훈 +1. **중복 선언 행은 전수 갱신 대상이다.** 같은 계약 문서 안에 같은 행이 두 배열에 있으면(entry_inputs·handoffs) 하나만 고친 갱신은 검사기가 읽는 쪽에 따라 무효가 된다 — 갱신 전에 대상 행을 grep 으로 전수 나열할 것. +2. **"실재하는 것만 읽는다"는 규칙에는 부재 기록이 한 벌이다.** 예행에서 전부 실재하는 입력은 부재 경로가 한 번도 발화하지 않아 침묵 스킵이 숨는다 — 부재가 상시인 실주행 조건을 회귀(L-k)로 강제해야 드러난다. +3. **하류가 상류 봉인값을 쓰려면 재독이 아니라 승계다.** L2 가 signal_manifest 를 다시 읽는 것은 계약 밖 읽기이자 봉인 우회 여지 — L0 가 검증한 값을 bundle 로 나르는 것이 계약에 맞다. +4. **검증 스크립트의 부산물도 배포 트리 오염원이다.** sys.path 반입이 만든 __pycache__ 가 트리에 두 번 생겼다 — 실측 스크립트에는 dont_write_bytecode 를 상수로 둘 것. +5. 검사기의 가시 범위에 맞춰 코드를 쓴다 — read_json 직호출 상수만 보는 U4 앞에서 간접 호출 래퍼는 "선언은 했으나 실측 불가"를 만든다(L0 read-plumbing 재작성으로 해소). diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-00/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-00/module_role_projection.json new file mode 100644 index 00000000..d779a742 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-00/module_role_projection.json @@ -0,0 +1,20 @@ +{ + "schema_version": "stage1_s2_module_role_projection.v1", + "domain_id": "E-00", + "legacy_projection_source": { + "path": "S_0_GPT/legacy/part4/structure_projection_contract.json", + "sha256": "9e615dda7e26e23fcaae381ed05763d16e4887909400277c9996919e09398398" + }, + "structure_type_to_projection": { + "general_legal_effect": { + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + }, + "default_projection": { + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW" + }, + "closure_status": "CLOSED_WITH_LOCAL_FILES" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-00/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-00/structure_types.json new file mode 100644 index 00000000..62f7677c --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-00/structure_types.json @@ -0,0 +1,20 @@ +{ + "schema_version": "stage1_s2_structure_types.v1", + "domain_id": "E-00", + "legacy_contract": { + "canonical_type_set_frozen": true, + "source": "1. Stage_1/v.7/extension_research/선행구축/S_0_GPT/legacy/part3/structure_type_contract.json" + }, + "entries": [ + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "legacy_source": "Part3 fallback", + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "admission_rule": "registered route only; E-00 unregistered material remains review" + } + ], + "noncanonical_preservation": "nonrouting_labels", + "ordering_preserved": true +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-01/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-01/module_role_projection.json new file mode 100644 index 00000000..8862a1f9 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-01/module_role_projection.json @@ -0,0 +1 @@ +{"default_projection":null,"domain_id":"E-01","mappings":[{"module":"juristic_act","role_projection":"act_party_object_roles","source":"s6_registered","structure_type":"juristic_act_validity"},{"module":"juristic_act","role_projection":"declarant_counterparty_roles","source":"s6_registered","structure_type":"declaration_defect"},{"module":"juristic_act","role_projection":"canceller_counterparty_third_party_roles","source":"s6_registered","structure_type":"cancellation_effect"},{"module":"agency","role_projection":"principal_agent_counterparty_roles","source":"s6_registered","structure_type":"unauthorized_agency"},{"module":"agency","role_projection":"principal_apparent_agent_relying_party_roles","source":"s6_registered","structure_type":"apparent_agency"},{"module":"juristic_act","role_projection":"condition_beneficiary_obligor_roles","source":"s6_registered","structure_type":"condition_term_effect"}],"missing_mapping_policy":{"emit_review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","silent_fallback_forbidden":true},"schema_version":"stage1_domain_module_role_projection.v1","status":"ACTIVE"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-01/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-01/structure_types.json new file mode 100644 index 00000000..e64325a8 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-01/structure_types.json @@ -0,0 +1 @@ +{"admission_rules":{"multiple_types_allowed":true,"nonregistered_type_review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","registered_membership_required":true,"silent_general_legal_effect_fallback_forbidden":true,"source_order_deduplicated":true},"domain_id":"E-01","schema_version":"stage1_domain_structure_types.v1","status":"ACTIVE","structure_types":[{"module":"juristic_act","priority_rank":71,"role_projection":"act_party_object_roles","type_id":"juristic_act_validity"},{"module":"juristic_act","priority_rank":72,"role_projection":"declarant_counterparty_roles","type_id":"declaration_defect"},{"module":"juristic_act","priority_rank":73,"role_projection":"canceller_counterparty_third_party_roles","type_id":"cancellation_effect"},{"module":"agency","priority_rank":74,"role_projection":"principal_agent_counterparty_roles","type_id":"unauthorized_agency"},{"module":"agency","priority_rank":75,"role_projection":"principal_apparent_agent_relying_party_roles","type_id":"apparent_agency"},{"module":"juristic_act","priority_rank":76,"role_projection":"condition_beneficiary_obligor_roles","type_id":"condition_term_effect"}]} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-02/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-02/module_role_projection.json new file mode 100644 index 00000000..96de5add --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-02/module_role_projection.json @@ -0,0 +1,17 @@ +{ + "schema_version": "s2_module_role_projection.v1", + "domain_id": "E-02", + "projections": [ + { + "type_id": "money_claim", + "module": "money_claim", + "role_projection": "claim_chain_ref" + }, + { + "type_id": "general_legal_effect", + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + ], + "closure_status": "CLOSED" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-02/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-02/structure_types.json new file mode 100644 index 00000000..b2275036 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-02/structure_types.json @@ -0,0 +1,23 @@ +{ + "schema_version": "s2_domain_structure_types.v1", + "domain_id": "E-02", + "types": [ + { + "type_id": "money_claim", + "priority_rank": 1, + "legacy_source": "B1_Money_Successor", + "module": "money_claim", + "role_projection": "claim_chain_ref", + "registered": true + }, + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "legacy_source": "B1_Money_Successor", + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "registered": true + } + ], + "fallback_policy": "unregistered_effect_type_review; silent_generalization_forbidden" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-03/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-03/module_role_projection.json new file mode 100644 index 00000000..6377e534 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-03/module_role_projection.json @@ -0,0 +1,22 @@ +{ + "schema_version": "s2_module_role_projection.v1", + "domain_id": "E-03", + "projections": [ + { + "type_id": "money_claim", + "module": "money_claim", + "role_projection": "claim_chain_ref" + }, + { + "type_id": "commercial_successor", + "module": "commercial_successor", + "role_projection": "claim_chain_ref" + }, + { + "type_id": "general_legal_effect", + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + ], + "closure_status": "CLOSED" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-03/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-03/structure_types.json new file mode 100644 index 00000000..2d03409a --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-03/structure_types.json @@ -0,0 +1,31 @@ +{ + "schema_version": "s2_domain_structure_types.v1", + "domain_id": "E-03", + "types": [ + { + "type_id": "money_claim", + "priority_rank": 1, + "legacy_source": "B1_Money_Successor", + "module": "money_claim", + "role_projection": "claim_chain_ref", + "registered": true + }, + { + "type_id": "commercial_successor", + "priority_rank": 2, + "legacy_source": "B1_Money_Successor", + "module": "commercial_successor", + "role_projection": "claim_chain_ref", + "registered": true + }, + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "legacy_source": "B1_Money_Successor", + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "registered": true + } + ], + "fallback_policy": "unregistered_effect_type_review; silent_generalization_forbidden" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-04/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-04/module_role_projection.json new file mode 100644 index 00000000..53b617d9 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-04/module_role_projection.json @@ -0,0 +1,30 @@ +{ + "schema_version": "stage1_domain_module_role_projection.v1", + "domain_id": "E-04", + "status": "ACTIVE", + "mappings": [ + { + "structure_type": "land_use_gain", + "module": "land_use_gain", + "role_projection": "legal_calculation_object", + "source": "legacy_preserved_or_additive_registered" + }, + { + "structure_type": "valuation", + "module": "valuation", + "role_projection": "legal_calculation_object", + "source": "legacy_preserved_or_additive_registered" + }, + { + "structure_type": "unjust_enrichment", + "module": "unjust_enrichment", + "role_projection": "restitution_roles", + "source": "legacy_preserved_or_additive_registered" + } + ], + "default_projection": null, + "missing_mapping_policy": { + "emit_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-04/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-04/structure_types.json new file mode 100644 index 00000000..467360c2 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-04/structure_types.json @@ -0,0 +1,33 @@ +{ + "schema_version": "stage1_domain_structure_types.v1", + "domain_id": "E-04", + "status": "ACTIVE", + "legacy_source_domain": "B3", + "structure_types": [ + { + "type_id": "land_use_gain", + "priority_rank": 5, + "module": "land_use_gain", + "role_projection": "legal_calculation_object" + }, + { + "type_id": "valuation", + "priority_rank": 6, + "module": "valuation", + "role_projection": "legal_calculation_object" + }, + { + "type_id": "unjust_enrichment", + "priority_rank": 12, + "module": "unjust_enrichment", + "role_projection": "restitution_roles" + } + ], + "admission_rules": { + "registered_membership_required": true, + "multiple_types_allowed": true, + "source_order_deduplicated": true, + "nonregistered_type_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_general_legal_effect_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-05/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-05/module_role_projection.json new file mode 100644 index 00000000..df963aaa --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-05/module_role_projection.json @@ -0,0 +1,42 @@ +{ + "schema_version": "stage1_domain_module_role_projection.v1", + "domain_id": "E-05", + "status": "ACTIVE", + "mappings": [ + { + "structure_type": "tort_liability", + "module": "tort", + "role_projection": "tort_liability_roles", + "source": "s3_registered" + }, + { + "structure_type": "joint_tort_liability", + "module": "tort", + "role_projection": "joint_tort_roles", + "source": "s3_registered" + }, + { + "structure_type": "vicarious_liability", + "module": "tort", + "role_projection": "employer_employee_roles", + "source": "s3_registered" + }, + { + "structure_type": "structure_liability", + "module": "tort", + "role_projection": "possessor_owner_roles", + "source": "s3_registered" + }, + { + "structure_type": "tort_damage_extent", + "module": "damages", + "role_projection": "damage_causation_roles", + "source": "s3_registered" + } + ], + "default_projection": null, + "missing_mapping_policy": { + "emit_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-05/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-05/structure_types.json new file mode 100644 index 00000000..279ae9ac --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-05/structure_types.json @@ -0,0 +1,44 @@ +{ + "schema_version": "stage1_domain_structure_types.v1", + "domain_id": "E-05", + "status": "ACTIVE", + "structure_types": [ + { + "type_id": "tort_liability", + "priority_rank": 20, + "module": "tort", + "role_projection": "tort_liability_roles" + }, + { + "type_id": "joint_tort_liability", + "priority_rank": 21, + "module": "tort", + "role_projection": "joint_tort_roles" + }, + { + "type_id": "vicarious_liability", + "priority_rank": 22, + "module": "tort", + "role_projection": "employer_employee_roles" + }, + { + "type_id": "structure_liability", + "priority_rank": 23, + "module": "tort", + "role_projection": "possessor_owner_roles" + }, + { + "type_id": "tort_damage_extent", + "priority_rank": 24, + "module": "damages", + "role_projection": "damage_causation_roles" + } + ], + "admission_rules": { + "registered_membership_required": true, + "multiple_types_allowed": true, + "source_order_deduplicated": true, + "nonregistered_type_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_general_legal_effect_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-06/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-06/module_role_projection.json new file mode 100644 index 00000000..bc5fb6ab --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-06/module_role_projection.json @@ -0,0 +1 @@ +{"default_projection":null,"domain_id":"E-06","mappings":[{"module":"professional_liability","role_projection":"professional_client_roles","source":"s6_registered","structure_type":"professional_duty_liability"},{"module":"medical_liability","role_projection":"patient_provider_roles","source":"s6_registered","structure_type":"medical_treatment_fault"},{"module":"medical_liability","role_projection":"patient_explainer_consent_roles","source":"s6_registered","structure_type":"medical_disclosure_duty"},{"module":"product_liability","role_projection":"injured_manufacturer_supplier_roles","source":"s6_registered","structure_type":"product_defect_liability"},{"module":"damages","role_projection":"conduct_damage_alternative_cause_roles","source":"s6_registered","structure_type":"professional_damage_causation"}],"missing_mapping_policy":{"emit_review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","silent_fallback_forbidden":true},"schema_version":"stage1_domain_module_role_projection.v1","status":"ACTIVE"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-06/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-06/structure_types.json new file mode 100644 index 00000000..8a063011 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-06/structure_types.json @@ -0,0 +1 @@ +{"admission_rules":{"multiple_types_allowed":true,"nonregistered_type_review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","registered_membership_required":true,"silent_general_legal_effect_fallback_forbidden":true,"source_order_deduplicated":true},"domain_id":"E-06","schema_version":"stage1_domain_structure_types.v1","status":"ACTIVE","structure_types":[{"module":"professional_liability","priority_rank":71,"role_projection":"professional_client_roles","type_id":"professional_duty_liability"},{"module":"medical_liability","priority_rank":72,"role_projection":"patient_provider_roles","type_id":"medical_treatment_fault"},{"module":"medical_liability","priority_rank":73,"role_projection":"patient_explainer_consent_roles","type_id":"medical_disclosure_duty"},{"module":"product_liability","priority_rank":74,"role_projection":"injured_manufacturer_supplier_roles","type_id":"product_defect_liability"},{"module":"damages","priority_rank":75,"role_projection":"conduct_damage_alternative_cause_roles","type_id":"professional_damage_causation"}]} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-07/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-07/module_role_projection.json new file mode 100644 index 00000000..57c8eda5 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-07/module_role_projection.json @@ -0,0 +1,32 @@ +{ + "schema_version": "s3_module_role_projection.v1", + "domain_id": "E-07", + "projections": [ + { + "type_id": "construction_payment_claim", + "module": "construction_contract", + "role_projection": "construction_payment_roles" + }, + { + "type_id": "construction_progress_settlement", + "module": "construction_contract", + "role_projection": "construction_progress_roles" + }, + { + "type_id": "construction_defect_remedy", + "module": "construction_defect", + "role_projection": "construction_defect_roles" + }, + { + "type_id": "construction_defect_setoff", + "module": "construction_defect", + "role_projection": "construction_setoff_roles" + }, + { + "type_id": "general_legal_effect", + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + ], + "closure_status": "CLOSED" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-07/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-07/structure_types.json new file mode 100644 index 00000000..c828ef77 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-07/structure_types.json @@ -0,0 +1,42 @@ +{ + "schema_version": "s3_domain_structure_types.v1", + "domain_id": "E-07", + "types": [ + { + "type_id": "construction_payment_claim", + "priority_rank": 1, + "module": "construction_contract", + "role_projection": "construction_payment_roles", + "registered": true + }, + { + "type_id": "construction_progress_settlement", + "priority_rank": 2, + "module": "construction_contract", + "role_projection": "construction_progress_roles", + "registered": true + }, + { + "type_id": "construction_defect_remedy", + "priority_rank": 3, + "module": "construction_defect", + "role_projection": "construction_defect_roles", + "registered": true + }, + { + "type_id": "construction_defect_setoff", + "priority_rank": 4, + "module": "construction_defect", + "role_projection": "construction_setoff_roles", + "registered": true + }, + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "registered": true + } + ], + "fallback_policy": "unregistered_effect_type_review; silent_generalization_forbidden" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-08/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-08/module_role_projection.json new file mode 100644 index 00000000..6bdbf53d --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-08/module_role_projection.json @@ -0,0 +1,37 @@ +{ + "schema_version": "s3_module_role_projection.v1", + "domain_id": "E-08", + "projections": [ + { + "type_id": "lease_deposit_return", + "module": "lease_contract", + "role_projection": "lease_deposit_return_roles" + }, + { + "type_id": "lease_rent_payment", + "module": "lease_contract", + "role_projection": "lease_rent_roles" + }, + { + "type_id": "lease_termination", + "module": "lease_lifecycle", + "role_projection": "lease_termination_roles" + }, + { + "type_id": "lease_delivery_concurrent_performance", + "module": "lease_lifecycle", + "role_projection": "lease_concurrent_performance_roles" + }, + { + "type_id": "lease_attached_property_purchase", + "module": "lease_contract", + "role_projection": "lease_purchase_claim_roles" + }, + { + "type_id": "general_legal_effect", + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + ], + "closure_status": "CLOSED" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-08/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-08/structure_types.json new file mode 100644 index 00000000..bf353e6d --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-08/structure_types.json @@ -0,0 +1,49 @@ +{ + "schema_version": "s3_domain_structure_types.v1", + "domain_id": "E-08", + "types": [ + { + "type_id": "lease_deposit_return", + "priority_rank": 1, + "module": "lease_contract", + "role_projection": "lease_deposit_return_roles", + "registered": true + }, + { + "type_id": "lease_rent_payment", + "priority_rank": 2, + "module": "lease_contract", + "role_projection": "lease_rent_roles", + "registered": true + }, + { + "type_id": "lease_termination", + "priority_rank": 3, + "module": "lease_lifecycle", + "role_projection": "lease_termination_roles", + "registered": true + }, + { + "type_id": "lease_delivery_concurrent_performance", + "priority_rank": 4, + "module": "lease_lifecycle", + "role_projection": "lease_concurrent_performance_roles", + "registered": true + }, + { + "type_id": "lease_attached_property_purchase", + "priority_rank": 5, + "module": "lease_contract", + "role_projection": "lease_purchase_claim_roles", + "registered": true + }, + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "registered": true + } + ], + "fallback_policy": "unregistered_effect_type_review; silent_generalization_forbidden" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-09/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-09/module_role_projection.json new file mode 100644 index 00000000..de5dd3d0 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-09/module_role_projection.json @@ -0,0 +1,17 @@ +{ + "schema_version": "s2_module_role_projection.v1", + "domain_id": "E-09", + "projections": [ + { + "type_id": "registry_invalidity", + "module": "registry_invalidity", + "role_projection": "linked_structures" + }, + { + "type_id": "general_legal_effect", + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + ], + "closure_status": "CLOSED" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-09/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-09/structure_types.json new file mode 100644 index 00000000..f72c8f5d --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-09/structure_types.json @@ -0,0 +1,23 @@ +{ + "schema_version": "s2_domain_structure_types.v1", + "domain_id": "E-09", + "types": [ + { + "type_id": "registry_invalidity", + "priority_rank": 4, + "legacy_source": "B2_Secured_Registry", + "module": "registry_invalidity", + "role_projection": "linked_structures", + "registered": true + }, + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "legacy_source": "B2_Secured_Registry", + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "registered": true + } + ], + "fallback_policy": "unregistered_effect_type_review; silent_generalization_forbidden" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-10/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-10/module_role_projection.json new file mode 100644 index 00000000..94cba1ee --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-10/module_role_projection.json @@ -0,0 +1,27 @@ +{ + "schema_version": "s2_module_role_projection.v1", + "domain_id": "E-10", + "projections": [ + { + "type_id": "secured_debt", + "module": "secured_property", + "role_projection": "linked_structures" + }, + { + "type_id": "registry_invalidity", + "module": "registry_invalidity", + "role_projection": "linked_structures" + }, + { + "type_id": "succession_notice_lien_asset_defense", + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures" + }, + { + "type_id": "general_legal_effect", + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + ], + "closure_status": "CLOSED" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-10/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-10/structure_types.json new file mode 100644 index 00000000..15b5eb66 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-10/structure_types.json @@ -0,0 +1,39 @@ +{ + "schema_version": "s2_domain_structure_types.v1", + "domain_id": "E-10", + "types": [ + { + "type_id": "secured_debt", + "priority_rank": 3, + "legacy_source": "B2_Secured_Registry", + "module": "secured_property", + "role_projection": "linked_structures", + "registered": true + }, + { + "type_id": "registry_invalidity", + "priority_rank": 4, + "legacy_source": "B2_Secured_Registry", + "module": "registry_invalidity", + "role_projection": "linked_structures", + "registered": true + }, + { + "type_id": "succession_notice_lien_asset_defense", + "priority_rank": 10, + "legacy_source": "B2_Secured_Registry", + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures", + "registered": true + }, + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "legacy_source": "B2_Secured_Registry", + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "registered": true + } + ], + "fallback_policy": "unregistered_effect_type_review; silent_generalization_forbidden" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-11/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-11/module_role_projection.json new file mode 100644 index 00000000..3d6f30b7 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-11/module_role_projection.json @@ -0,0 +1,30 @@ +{ + "schema_version": "stage1_domain_module_role_projection.v1", + "domain_id": "E-11", + "status": "ACTIVE", + "mappings": [ + { + "structure_type": "possession_vindication", + "module": "possession_vindication", + "role_projection": "linked_structures", + "source": "legacy_preserved_or_additive_registered" + }, + { + "structure_type": "land_use_gain", + "module": "land_use_gain", + "role_projection": "legal_calculation_object", + "source": "legacy_preserved_or_additive_registered" + }, + { + "structure_type": "succession_notice_lien_asset_defense", + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures", + "source": "legacy_preserved_or_additive_registered" + } + ], + "default_projection": null, + "missing_mapping_policy": { + "emit_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-11/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-11/structure_types.json new file mode 100644 index 00000000..33283354 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-11/structure_types.json @@ -0,0 +1,33 @@ +{ + "schema_version": "stage1_domain_structure_types.v1", + "domain_id": "E-11", + "status": "ACTIVE", + "legacy_source_domain": "B3", + "structure_types": [ + { + "type_id": "possession_vindication", + "priority_rank": 5, + "module": "possession_vindication", + "role_projection": "linked_structures" + }, + { + "type_id": "land_use_gain", + "priority_rank": 6, + "module": "land_use_gain", + "role_projection": "legal_calculation_object" + }, + { + "type_id": "succession_notice_lien_asset_defense", + "priority_rank": 10, + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures" + } + ], + "admission_rules": { + "registered_membership_required": true, + "multiple_types_allowed": true, + "source_order_deduplicated": true, + "nonregistered_type_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_general_legal_effect_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-12/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-12/module_role_projection.json new file mode 100644 index 00000000..f47f0735 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-12/module_role_projection.json @@ -0,0 +1 @@ +{"default_projection":null,"domain_id":"E-12","mappings":[{"module":"coownership","role_projection":"coowner_act_consent_roles","source":"s6_registered","structure_type":"coownership_governance"},{"module":"partition","role_projection":"partitioner_coowner_object_roles","source":"s6_registered","structure_type":"coownership_partition"},{"module":"boundary","role_projection":"adjacent_owner_parcel_boundary_roles","source":"s6_registered","structure_type":"boundary_determination"},{"module":"coownership","role_projection":"using_coowner_nonusing_coowner_roles","source":"s6_registered","structure_type":"exclusive_use_settlement"},{"module":"aggregate_building","role_projection":"management_body_unit_owner_roles","source":"s6_registered","structure_type":"aggregate_building_management"}],"missing_mapping_policy":{"emit_review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","silent_fallback_forbidden":true},"schema_version":"stage1_domain_module_role_projection.v1","status":"ACTIVE"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-12/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-12/structure_types.json new file mode 100644 index 00000000..411f90c1 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-12/structure_types.json @@ -0,0 +1 @@ +{"admission_rules":{"multiple_types_allowed":true,"nonregistered_type_review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","registered_membership_required":true,"silent_general_legal_effect_fallback_forbidden":true,"source_order_deduplicated":true},"domain_id":"E-12","schema_version":"stage1_domain_structure_types.v1","status":"ACTIVE","structure_types":[{"module":"coownership","priority_rank":71,"role_projection":"coowner_act_consent_roles","type_id":"coownership_governance"},{"module":"partition","priority_rank":72,"role_projection":"partitioner_coowner_object_roles","type_id":"coownership_partition"},{"module":"boundary","priority_rank":73,"role_projection":"adjacent_owner_parcel_boundary_roles","type_id":"boundary_determination"},{"module":"coownership","priority_rank":74,"role_projection":"using_coowner_nonusing_coowner_roles","type_id":"exclusive_use_settlement"},{"module":"aggregate_building","priority_rank":75,"role_projection":"management_body_unit_owner_roles","type_id":"aggregate_building_management"}]} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-13/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-13/module_role_projection.json new file mode 100644 index 00000000..765c6be4 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-13/module_role_projection.json @@ -0,0 +1,30 @@ +{ + "schema_version": "stage1_domain_module_role_projection.v1", + "domain_id": "E-13", + "status": "ACTIVE", + "mappings": [ + { + "structure_type": "fraudulent_transfer", + "module": "actio", + "role_projection": "actio_roles", + "source": "legacy_preserved_or_additive_registered" + }, + { + "structure_type": "preserved_claim", + "module": "actio", + "role_projection": "claim_chain_ref", + "source": "legacy_preserved_or_additive_registered" + }, + { + "structure_type": "actio_remedy_or_cap", + "module": "actio", + "role_projection": "linked_actio_structures", + "source": "legacy_preserved_or_additive_registered" + } + ], + "default_projection": null, + "missing_mapping_policy": { + "emit_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-13/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-13/structure_types.json new file mode 100644 index 00000000..bf2d8e55 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-13/structure_types.json @@ -0,0 +1,33 @@ +{ + "schema_version": "stage1_domain_structure_types.v1", + "domain_id": "E-13", + "status": "ACTIVE", + "legacy_source_domain": "B4", + "structure_types": [ + { + "type_id": "fraudulent_transfer", + "priority_rank": 7, + "module": "actio", + "role_projection": "actio_roles" + }, + { + "type_id": "preserved_claim", + "priority_rank": 8, + "module": "actio", + "role_projection": "claim_chain_ref" + }, + { + "type_id": "actio_remedy_or_cap", + "priority_rank": 9, + "module": "actio", + "role_projection": "linked_actio_structures" + } + ], + "admission_rules": { + "registered_membership_required": true, + "multiple_types_allowed": true, + "source_order_deduplicated": true, + "nonregistered_type_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_general_legal_effect_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-14/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-14/module_role_projection.json new file mode 100644 index 00000000..7cf90a05 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-14/module_role_projection.json @@ -0,0 +1,16 @@ +{ + "schema_version": "stage1_s3_module_role_projection.v1", + "domain_id": "E-14", + "structure_type_to_projection": { + "execution_linked_claim": { + "module": "execution_linked_claims", + "role_projection": "linked_execution_claims" + } + }, + "default_projection": { + "module": "unregistered_effect_review", + "role_projection": "unregistered_effect_roles", + "review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW" + }, + "closure_status": "CLOSED_WITH_LOCAL_FILES" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-14/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-14/structure_types.json new file mode 100644 index 00000000..e35a0bbe --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-14/structure_types.json @@ -0,0 +1,15 @@ +{ + "schema_version": "stage1_s3_structure_types.v1", + "domain_id": "E-14", + "entries": [ + { + "type_id": "execution_linked_claim", + "priority_rank": 14, + "module": "execution_linked_claims", + "role_projection": "linked_execution_claims", + "admission_rule": "source-backed SG-13 route and registered active domain required" + } + ], + "unregistered_effect_policy": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "ordering_integration_required": true +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-15/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-15/module_role_projection.json new file mode 100644 index 00000000..fc30a402 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-15/module_role_projection.json @@ -0,0 +1,24 @@ +{ + "schema_version": "stage1_s2_module_role_projection.v1", + "domain_id": "E-15", + "legacy_projection_source": { + "path": "S_0_GPT/legacy/part4/structure_projection_contract.json", + "sha256": "9e615dda7e26e23fcaae381ed05763d16e4887909400277c9996919e09398398" + }, + "structure_type_to_projection": { + "succession_notice_lien_asset_defense": { + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures" + }, + "general_legal_effect": { + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + }, + "default_projection": { + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW" + }, + "closure_status": "CLOSED_WITH_LOCAL_FILES" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-15/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-15/structure_types.json new file mode 100644 index 00000000..ad098332 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-15/structure_types.json @@ -0,0 +1,28 @@ +{ + "schema_version": "stage1_s2_structure_types.v1", + "domain_id": "E-15", + "legacy_contract": { + "canonical_type_set_frozen": true, + "source": "1. Stage_1/v.7/extension_research/선행구축/S_0_GPT/legacy/part3/structure_type_contract.json" + }, + "entries": [ + { + "type_id": "succession_notice_lien_asset_defense", + "priority_rank": 10, + "legacy_source": "B5", + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures", + "admission_rule": "domain payload or SG-13 candidate must be source-backed" + }, + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "legacy_source": "Part3 fallback", + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "admission_rule": "registered route only; E-00 unregistered material remains review" + } + ], + "noncanonical_preservation": "nonrouting_labels", + "ordering_preserved": true +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-16/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-16/module_role_projection.json new file mode 100644 index 00000000..219459ed --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-16/module_role_projection.json @@ -0,0 +1 @@ +{"default_projection":null,"domain_id":"E-16","mappings":[{"module":"negotiable_instrument","role_projection":"issuer_acceptor_holder_roles","source":"s6_registered","structure_type":"bill_primary_liability"},{"module":"negotiable_instrument","role_projection":"drawer_payee_holder_roles","source":"s6_registered","structure_type":"check_issuer_liability"},{"module":"negotiable_instrument","role_projection":"endorser_endorsee_holder_roles","source":"s6_registered","structure_type":"endorsement_holder_status"},{"module":"negotiable_instrument","role_projection":"presenter_drawee_recourse_party_roles","source":"s6_registered","structure_type":"presentment_recourse_liability"},{"module":"negotiable_instrument","role_projection":"grantor_completer_holder_roles","source":"s6_registered","structure_type":"blank_instrument_completion"},{"module":"negotiable_instrument","role_projection":"instrument_debtor_holder_cause_party_roles","source":"s6_registered","structure_type":"cause_relation_defense"}],"missing_mapping_policy":{"emit_review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","silent_fallback_forbidden":true},"schema_version":"stage1_domain_module_role_projection.v1","status":"ACTIVE"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-16/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-16/structure_types.json new file mode 100644 index 00000000..d80b4ecd --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-16/structure_types.json @@ -0,0 +1 @@ +{"admission_rules":{"multiple_types_allowed":true,"nonregistered_type_review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","registered_membership_required":true,"silent_general_legal_effect_fallback_forbidden":true,"source_order_deduplicated":true},"domain_id":"E-16","schema_version":"stage1_domain_structure_types.v1","status":"ACTIVE","structure_types":[{"module":"negotiable_instrument","priority_rank":71,"role_projection":"issuer_acceptor_holder_roles","type_id":"bill_primary_liability"},{"module":"negotiable_instrument","priority_rank":72,"role_projection":"drawer_payee_holder_roles","type_id":"check_issuer_liability"},{"module":"negotiable_instrument","priority_rank":73,"role_projection":"endorser_endorsee_holder_roles","type_id":"endorsement_holder_status"},{"module":"negotiable_instrument","priority_rank":74,"role_projection":"presenter_drawee_recourse_party_roles","type_id":"presentment_recourse_liability"},{"module":"negotiable_instrument","priority_rank":75,"role_projection":"grantor_completer_holder_roles","type_id":"blank_instrument_completion"},{"module":"negotiable_instrument","priority_rank":76,"role_projection":"instrument_debtor_holder_cause_party_roles","type_id":"cause_relation_defense"}]} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-17/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-17/module_role_projection.json new file mode 100644 index 00000000..e35426fa --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-17/module_role_projection.json @@ -0,0 +1,16 @@ +{ + "schema_version": "stage1_s3_module_role_projection.v1", + "domain_id": "E-17", + "structure_type_to_projection": { + "labor_wage_claim": { + "module": "labor_wage_claims", + "role_projection": "linked_labor_claims" + } + }, + "default_projection": { + "module": "unregistered_effect_review", + "role_projection": "unregistered_effect_roles", + "review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW" + }, + "closure_status": "CLOSED_WITH_LOCAL_FILES" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-17/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-17/structure_types.json new file mode 100644 index 00000000..cdef7075 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-17/structure_types.json @@ -0,0 +1,15 @@ +{ + "schema_version": "stage1_s3_structure_types.v1", + "domain_id": "E-17", + "entries": [ + { + "type_id": "labor_wage_claim", + "priority_rank": 17, + "module": "labor_wage_claims", + "role_projection": "linked_labor_claims", + "admission_rule": "source-backed SG-13 route and registered active domain required" + } + ], + "unregistered_effect_policy": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "ordering_integration_required": true +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-18/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-18/module_role_projection.json new file mode 100644 index 00000000..8626b772 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-18/module_role_projection.json @@ -0,0 +1 @@ +{"closure_status":"CLOSED_WITH_LOCAL_FILES","default_projection":{"module":"unregistered_effect_review","review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","role_projection":"unregistered_effect_roles"},"domain_id":"E-18","schema_version":"stage1_s6_module_role_projection.v1","structure_type_to_projection":{"org_resolution_status_relation":{"module":"org_resolution_status","role_projection":"resolution_status_roles"}}} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-18/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-18/structure_types.json new file mode 100644 index 00000000..6f1426be --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-18/structure_types.json @@ -0,0 +1 @@ +{"domain_id":"E-18","entries":[{"admission_rule":"source-backed SG-13 route and registered active domain required","module":"org_resolution_status","priority_rank":18,"role_projection":"resolution_status_roles","type_id":"org_resolution_status_relation"}],"ordering_integration_required":true,"schema_version":"stage1_s6_structure_types.v1","unregistered_effect_policy":"UNREGISTERED_EFFECT_TYPE_REVIEW"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-19/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-19/module_role_projection.json new file mode 100644 index 00000000..3eaae501 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-19/module_role_projection.json @@ -0,0 +1 @@ +{"closure_status":"CLOSED_WITH_LOCAL_FILES","default_projection":{"module":"unregistered_effect_review","review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","role_projection":"unregistered_effect_roles"},"domain_id":"E-19","schema_version":"stage1_s6_module_role_projection.v1","structure_type_to_projection":{"insurance_claim_relation":{"module":"insurance_claims","role_projection":"insurance_relation_roles"}}} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-19/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-19/structure_types.json new file mode 100644 index 00000000..38d32a96 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-19/structure_types.json @@ -0,0 +1 @@ +{"domain_id":"E-19","entries":[{"admission_rule":"source-backed SG-13 route and registered active domain required","module":"insurance_claims","priority_rank":19,"role_projection":"insurance_relation_roles","type_id":"insurance_claim_relation"}],"ordering_integration_required":true,"schema_version":"stage1_s6_structure_types.v1","unregistered_effect_policy":"UNREGISTERED_EFFECT_TYPE_REVIEW"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-20/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-20/module_role_projection.json new file mode 100644 index 00000000..84e2f602 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-20/module_role_projection.json @@ -0,0 +1 @@ +{"closure_status":"CLOSED_WITH_LOCAL_FILES","default_projection":{"module":"unregistered_effect_review","review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","role_projection":"unregistered_effect_roles"},"domain_id":"E-20","schema_version":"stage1_s6_module_role_projection.v1","structure_type_to_projection":{"ip_right_claim_relation":{"module":"ip_claims","role_projection":"ip_right_infringement_roles"}}} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-20/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-20/structure_types.json new file mode 100644 index 00000000..ce575573 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-20/structure_types.json @@ -0,0 +1 @@ +{"domain_id":"E-20","entries":[{"admission_rule":"source-backed SG-13 route and registered active domain required","module":"ip_claims","priority_rank":20,"role_projection":"ip_right_infringement_roles","type_id":"ip_right_claim_relation"}],"ordering_integration_required":true,"schema_version":"stage1_s6_structure_types.v1","unregistered_effect_policy":"UNREGISTERED_EFFECT_TYPE_REVIEW"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-21/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-21/module_role_projection.json new file mode 100644 index 00000000..212ce0da --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-21/module_role_projection.json @@ -0,0 +1 @@ +{"closure_status":"CLOSED_WITH_LOCAL_FILES","default_projection":{"module":"unregistered_effect_review","review_code":"UNREGISTERED_EFFECT_TYPE_REVIEW","role_projection":"unregistered_effect_roles"},"domain_id":"E-21","schema_version":"stage1_s6_module_role_projection.v1","structure_type_to_projection":{"media_personality_claim_relation":{"module":"media_personality_rights","role_projection":"publication_personality_roles"}}} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-21/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-21/structure_types.json new file mode 100644 index 00000000..25f421c8 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/E-21/structure_types.json @@ -0,0 +1 @@ +{"domain_id":"E-21","entries":[{"admission_rule":"source-backed SG-13 route and registered active domain required","module":"media_personality_rights","priority_rank":21,"role_projection":"publication_personality_roles","type_id":"media_personality_claim_relation"}],"ordering_integration_required":true,"schema_version":"stage1_s6_structure_types.v1","unregistered_effect_policy":"UNREGISTERED_EFFECT_TYPE_REVIEW"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X1/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X1/module_role_projection.json new file mode 100644 index 00000000..441d2771 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X1/module_role_projection.json @@ -0,0 +1,24 @@ +{ + "schema_version": "stage1_s2_module_role_projection.v1", + "domain_id": "X1", + "legacy_projection_source": { + "path": "S_0_GPT/legacy/part4/structure_projection_contract.json", + "sha256": "9e615dda7e26e23fcaae381ed05763d16e4887909400277c9996919e09398398" + }, + "structure_type_to_projection": { + "succession_notice_lien_asset_defense": { + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures" + }, + "general_legal_effect": { + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + }, + "default_projection": { + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW" + }, + "closure_status": "CLOSED_WITH_LOCAL_FILES" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X1/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X1/structure_types.json new file mode 100644 index 00000000..e82d3486 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X1/structure_types.json @@ -0,0 +1,28 @@ +{ + "schema_version": "stage1_s2_structure_types.v1", + "domain_id": "X1", + "legacy_contract": { + "canonical_type_set_frozen": true, + "source": "1. Stage_1/v.7/extension_research/선행구축/S_0_GPT/legacy/part3/structure_type_contract.json" + }, + "entries": [ + { + "type_id": "succession_notice_lien_asset_defense", + "priority_rank": 10, + "legacy_source": "B5", + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures", + "admission_rule": "domain payload or SG-13 candidate must be source-backed" + }, + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "legacy_source": "Part3 fallback", + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "admission_rule": "registered route only; E-00 unregistered material remains review" + } + ], + "noncanonical_preservation": "nonrouting_labels", + "ordering_preserved": true +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X2/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X2/module_role_projection.json new file mode 100644 index 00000000..d321f1f7 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X2/module_role_projection.json @@ -0,0 +1,24 @@ +{ + "schema_version": "stage1_domain_module_role_projection.v1", + "domain_id": "X2", + "status": "ACTIVE", + "mappings": [ + { + "structure_type": "asset_state", + "module": "asset_state", + "role_projection": "asset_state_projection", + "source": "legacy_preserved_or_additive_registered" + }, + { + "structure_type": "valuation", + "module": "valuation", + "role_projection": "legal_calculation_object", + "source": "legacy_preserved_or_additive_registered" + } + ], + "default_projection": null, + "missing_mapping_policy": { + "emit_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X2/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X2/structure_types.json new file mode 100644 index 00000000..d9b13b61 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X2/structure_types.json @@ -0,0 +1,27 @@ +{ + "schema_version": "stage1_domain_structure_types.v1", + "domain_id": "X2", + "status": "ACTIVE", + "legacy_source_domain": "B3", + "structure_types": [ + { + "type_id": "asset_state", + "priority_rank": 4, + "module": "asset_state", + "role_projection": "asset_state_projection" + }, + { + "type_id": "valuation", + "priority_rank": 6, + "module": "valuation", + "role_projection": "legal_calculation_object" + } + ], + "admission_rules": { + "registered_membership_required": true, + "multiple_types_allowed": true, + "source_order_deduplicated": true, + "nonregistered_type_review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW", + "silent_general_legal_effect_fallback_forbidden": true + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X3/module_role_projection.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X3/module_role_projection.json new file mode 100644 index 00000000..f1283412 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X3/module_role_projection.json @@ -0,0 +1,24 @@ +{ + "schema_version": "stage1_s2_module_role_projection.v1", + "domain_id": "X3", + "legacy_projection_source": { + "path": "S_0_GPT/legacy/part4/structure_projection_contract.json", + "sha256": "9e615dda7e26e23fcaae381ed05763d16e4887909400277c9996919e09398398" + }, + "structure_type_to_projection": { + "succession_notice_lien_asset_defense": { + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures" + }, + "general_legal_effect": { + "module": "legal_effect", + "role_projection": "legal_effect_roles" + } + }, + "default_projection": { + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "review_code": "UNREGISTERED_EFFECT_TYPE_REVIEW" + }, + "closure_status": "CLOSED_WITH_LOCAL_FILES" +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X3/structure_types.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X3/structure_types.json new file mode 100644 index 00000000..260bde4f --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/domains/X3/structure_types.json @@ -0,0 +1,28 @@ +{ + "schema_version": "stage1_s2_structure_types.v1", + "domain_id": "X3", + "legacy_contract": { + "canonical_type_set_frozen": true, + "source": "1. Stage_1/v.7/extension_research/선행구축/S_0_GPT/legacy/part3/structure_type_contract.json" + }, + "entries": [ + { + "type_id": "succession_notice_lien_asset_defense", + "priority_rank": 10, + "legacy_source": "B5", + "module": "succession_notice_lien_asset_defense", + "role_projection": "linked_structures", + "admission_rule": "domain payload or SG-13 candidate must be source-backed" + }, + { + "type_id": "general_legal_effect", + "priority_rank": 11, + "legacy_source": "Part3 fallback", + "module": "legal_effect", + "role_projection": "legal_effect_roles", + "admission_rule": "registered route only; E-00 unregistered material remains review" + } + ], + "noncanonical_preservation": "nonrouting_labels", + "ordering_preserved": true +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/platform/schemas/legal_effect_structures.schema.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/platform/schemas/legal_effect_structures.schema.json new file mode 100644 index 00000000..687e98d9 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/platform/schemas/legal_effect_structures.schema.json @@ -0,0 +1,150 @@ +{ + "$id": "https://schemas.liti-agent.local/stage1/part3/legal_effect_structures.schema.json", + "title": "stage1_legal_effect_structures.v1", + "description": "Part 3 L2 최종 산출 — 법률효과 구조와 역인덱스 셋(by_domain_id · by_module · by_bo_id). by_claim_form 은 만들지 않는다(claim-form 어휘가 registry 에 없다 — D-4 라). 열거를 하드코딩하지 않는다.", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "status", "expected_runnable_domain_ids", "theta", + "structure_records", "structure_index", "quality_gate", "created_by"], + "properties": { + "schema_version": {"const": "stage1_legal_effect_structures.v1"}, + "status": {"enum": ["READY", "READY_WITH_REVIEW"]}, + "registry_version": {"type": ["string", "null"]}, + "registry_index_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, + "activation_manifest_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, + "signal_manifest_transaction_id": {"type": "string", "pattern": "^S5TX-[a-f0-9]{20}$"}, + "expected_runnable_domain_ids": { + "type": "array", + "items": {"type": "string", "pattern": "^(?:(?:EC|E)-[A-Z0-9]{2,8}|X[A-Z0-9]{1,8})$"} + }, + "theta": { + "type": "array", + "items": {"type": "string", "pattern": "^[a-z][a-z0-9_]{1,127}$"} + }, + "structure_records": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["structure_id", "domain_id", "type_id", "priority_rank", "order_key", + "module", "role_projection", "admission_policy", "routes", "route_count", + "evidence_refs", "meeting_clause_refs", "calculation_request_refs", + "source_bo_ids", "review_codes", "review_required"], + "properties": { + "structure_id": {"type": "string", "pattern": "^LES-[A-Za-z0-9._:-]{2,64}-[a-z][a-z0-9_]{1,127}$"}, + "domain_id": {"type": "string", "pattern": "^(?:(?:EC|E)-[A-Z0-9]{2,8}|X[A-Z0-9]{1,8})$"}, + "type_id": {"type": "string", "pattern": "^[a-z][a-z0-9_]{1,127}$"}, + "priority_rank": {"type": ["integer", "null"]}, + "order_key": {"type": "array", "minItems": 3, "maxItems": 3}, + "module": {"type": ["string", "null"]}, + "role_projection": {"type": ["string", "null"]}, + "admission_policy": {"type": "string", "minLength": 1}, + "admission_rule": {"type": "string"}, + "registered_declared": {"type": "boolean"}, + "extension_key": {"type": "string"}, + "routes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["signal_id", "source_seed_id", "registered", "status"], + "properties": { + "signal_id": {"type": ["string", "null"]}, + "source_seed_id": {"type": ["string", "null"]}, + "registered": {"type": ["boolean", "null"]}, + "status": {"type": ["string", "null"]} + } + } + }, + "route_count": {"type": "integer", "minimum": 0}, + "evidence_refs": {"type": "array", "items": {"type": "string"}}, + "meeting_clause_refs": {"type": "array", "items": {"type": "string"}}, + "calculation_request_refs": {"type": "array", "items": {"type": "string"}}, + "source_bo_ids": {"type": "array", "items": {"type": "string"}}, + "review_codes": { + "type": "array", + "items": {"type": "string", "pattern": "^[A-Z][A-Z0-9_]{2,127}$"} + }, + "review_required": {"type": "boolean"} + } + } + }, + "structure_index": { + "type": "object", + "additionalProperties": false, + "required": ["by_domain_id", "by_module", "by_bo_id"], + "properties": { + "by_domain_id": { + "type": "object", + "additionalProperties": {"type": "array", "items": {"type": "string"}} + }, + "by_module": { + "type": "object", + "additionalProperties": {"type": "array", "items": {"type": "string"}} + }, + "by_bo_id": { + "type": "object", + "additionalProperties": {"type": "array", "items": {"type": "string"}} + } + } + }, + "quality_gate": { + "type": "object", + "additionalProperties": false, + "required": ["declaration_conservation", "route_conservation", "bo_conservation", + "review_queue"], + "properties": { + "declaration_conservation": { + "type": "object", + "additionalProperties": false, + "required": ["structure_records", "declared_total_from_config", "conservation_pass"], + "properties": { + "structure_records": {"type": "integer", "minimum": 0}, + "declared_total_from_config": {"type": "integer", "minimum": 0}, + "conservation_pass": {"type": "boolean"} + } + }, + "route_conservation": { + "type": "object", + "additionalProperties": false, + "required": ["routes_attached", "routes_unattached", "sg13_route_total_from_source", + "conservation_pass"], + "properties": { + "routes_attached": {"type": "integer", "minimum": 0}, + "routes_unattached": {"type": "integer", "minimum": 0}, + "sg13_route_total_from_source": {"type": "integer", "minimum": 0}, + "conservation_pass": {"type": "boolean"} + } + }, + "bo_conservation": { + "type": "object", + "additionalProperties": false, + "required": ["bo_attached", "bo_unattached", "bo_total_from_source", + "conservation_pass"], + "properties": { + "bo_attached": {"type": "integer", "minimum": 0}, + "bo_unattached": {"type": "integer", "minimum": 0}, + "bo_total_from_source": {"type": "integer", "minimum": 0}, + "conservation_pass": {"type": "boolean"} + } + }, + "review_queue": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["review_code", "severity"], + "properties": { + "review_code": {"type": "string", "pattern": "^[A-Z][A-Z0-9_]{2,127}$"}, + "severity": {"enum": ["SOFT_WARNING", "HARD_WARNING"]}, + "domain_id": {"type": ["string", "null"]}, + "structure_id": {"type": ["string", "null"]}, + "count": {"type": "integer", "minimum": 1} + } + } + } + } + }, + "created_by": {"const": "Task_C_LE_L2_final_structure_index_writer"} + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/platform/schemas/structure_seed_bundle.schema.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/platform/schemas/structure_seed_bundle.schema.json new file mode 100644 index 00000000..485bd566 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/platform/schemas/structure_seed_bundle.schema.json @@ -0,0 +1,331 @@ +{ + "$id": "https://schemas.liti-agent.local/stage1/part3/structure_seed_bundle.schema.json", + "title": "stage1_structure_seed_bundle.v1", + "description": "Part 3 L0 산출 — 구조 seed 묶음. 레코드는 Θ 의 (도메인, type_id) 쌍마다 하나. 열거를 하드코딩하지 않는다 — type_id·도메인 ID·검토 코드는 패턴만 강제한다(도메인 증설 시 스키마 무수정).", + "type": "object", + "additionalProperties": false, + "required": [ + "structure_seed_bundle" + ], + "properties": { + "structure_seed_bundle": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "status", + "expected_runnable_domain_ids", + "theta", + "structure_records", + "unattached_routes", + "unattached_bo", + "counts", + "created_by" + ], + "properties": { + "schema_version": { + "const": "stage1_structure_seed_bundle.v1" + }, + "status": { + "enum": [ + "READY", + "READY_WITH_REVIEW" + ] + }, + "registry_version": { + "type": [ + "string", + "null" + ] + }, + "expected_runnable_domain_ids": { + "type": "array", + "items": { + "type": "string", + "pattern": "^(?:(?:EC|E)-[A-Z0-9]{2,8}|X[A-Z0-9]{1,8})$" + } + }, + "theta": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]{1,127}$" + } + }, + "structure_records": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "structure_id", + "domain_id", + "type_id", + "priority_rank", + "order_key", + "module", + "role_projection", + "admission_policy", + "routes", + "route_count", + "evidence_refs", + "meeting_clause_refs", + "calculation_request_refs", + "source_bo_ids", + "review_codes", + "review_required" + ], + "properties": { + "structure_id": { + "type": "string", + "pattern": "^LES-[A-Za-z0-9._:-]{2,64}-[a-z][a-z0-9_]{1,127}$" + }, + "domain_id": { + "type": "string", + "pattern": "^(?:(?:EC|E)-[A-Z0-9]{2,8}|X[A-Z0-9]{1,8})$" + }, + "type_id": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]{1,127}$" + }, + "priority_rank": { + "type": [ + "integer", + "null" + ] + }, + "order_key": { + "type": "array", + "minItems": 3, + "maxItems": 3 + }, + "module": { + "type": [ + "string", + "null" + ] + }, + "role_projection": { + "type": [ + "string", + "null" + ] + }, + "admission_policy": { + "type": "string", + "minLength": 1 + }, + "admission_rule": { + "type": "string" + }, + "registered_declared": { + "type": "boolean" + }, + "extension_key": { + "type": "string" + }, + "routes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "signal_id", + "source_seed_id", + "registered", + "status" + ], + "properties": { + "signal_id": { + "type": [ + "string", + "null" + ] + }, + "source_seed_id": { + "type": [ + "string", + "null" + ] + }, + "registered": { + "type": [ + "boolean", + "null" + ] + }, + "status": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "route_count": { + "type": "integer", + "minimum": 0 + }, + "evidence_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "meeting_clause_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "calculation_request_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "source_bo_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "review_codes": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[A-Z][A-Z0-9_]{2,127}$" + } + }, + "review_required": { + "type": "boolean" + } + } + } + }, + "unattached_routes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "signal_id", + "type_id", + "reason" + ], + "properties": { + "signal_id": { + "type": [ + "string", + "null" + ] + }, + "type_id": { + "type": [ + "string", + "null" + ] + }, + "reason": { + "type": "string" + } + } + } + }, + "unattached_bo": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "bo_id", + "reason" + ], + "properties": { + "bo_id": { + "type": [ + "string", + "null" + ] + }, + "reason": { + "type": "string" + } + } + } + }, + "counts": { + "type": "object", + "additionalProperties": false, + "required": [ + "structure_records", + "declared_structure_types_total", + "sg13_route_total", + "routes_attached", + "routes_unattached", + "bo_total", + "bo_attached", + "bo_unattached", + "sg11_total", + "sg11_linked", + "sg11_unlinked" + ], + "properties": { + "structure_records": { + "type": "integer", + "minimum": 0 + }, + "declared_structure_types_total": { + "type": "integer", + "minimum": 0 + }, + "sg13_route_total": { + "type": "integer", + "minimum": 0 + }, + "routes_attached": { + "type": "integer", + "minimum": 0 + }, + "routes_unattached": { + "type": "integer", + "minimum": 0 + }, + "bo_total": { + "type": "integer", + "minimum": 0 + }, + "bo_attached": { + "type": "integer", + "minimum": 0 + }, + "bo_unattached": { + "type": "integer", + "minimum": 0 + }, + "sg11_total": { + "type": "integer", + "minimum": 0 + }, + "sg11_linked": { + "type": "integer", + "minimum": 0 + }, + "sg11_unlinked": { + "type": "integer", + "minimum": 0 + } + } + }, + "created_by": { + "const": "Task_C_LE_L0_structure_seed_reducer" + }, + "signal_manifest_transaction_id": { + "type": "string", + "pattern": "^S5TX-[a-f0-9]{20}$" + } + } + } + } +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/runtime_manifest.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/runtime_manifest.json index f749300a..aaded1ae 100644 --- a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/runtime_manifest.json +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/runtime_manifest.json @@ -824,6 +824,206 @@ "path": "contracts/signals/s5_execution_contract.v2.json", "sha256": "311ac8721ec297bc86e54c83f0866d61629bd99f15746f86bbbff32914d35e02" }, + { + "path": "domains/E-00/module_role_projection.json", + "sha256": "278ecdd4ac6c004f9994d6357ef439d089456a5e65bed0f74f49170ba3315932" + }, + { + "path": "domains/E-00/structure_types.json", + "sha256": "ae4a94fdbb0e2a8e0273a259e38c28774a3f2f24985878286f18a9ae05cbabaa" + }, + { + "path": "domains/E-01/module_role_projection.json", + "sha256": "cb263ca339f7b749a51b57fa12d915fda3644f09e648d15a84202651a23a84fb" + }, + { + "path": "domains/E-01/structure_types.json", + "sha256": "f2c423a0346a347292b3ca33d3a9f33a82d540e83cbb5f79bb8dae7161c68b26" + }, + { + "path": "domains/E-02/module_role_projection.json", + "sha256": "e21465cf806fb080d75f89526f9c142010c392ee87454a5a19248b9a80eb7c28" + }, + { + "path": "domains/E-02/structure_types.json", + "sha256": "e470dd3c96f2f9b8bfa6c2c97b05259281005a84b6eea24c38d322abdf16ad8e" + }, + { + "path": "domains/E-03/module_role_projection.json", + "sha256": "f693146dfb3ba2ac5fa6a6221c6b2dc7e32084acb06823b1f46f423a56546704" + }, + { + "path": "domains/E-03/structure_types.json", + "sha256": "70c579a03c41226e6383fe7b4aa5e60f4b0f5a723db30f6292dd2a0bde4d17bb" + }, + { + "path": "domains/E-04/module_role_projection.json", + "sha256": "4c4bd473a12ad1dfcc8c9392503cd057017385a21287a89cb7ea147f3cf7d2d6" + }, + { + "path": "domains/E-04/structure_types.json", + "sha256": "e8b15e9e5a39a488bf9ef660d69c7bc2db832248eb33788ba2ae54a9b5200e73" + }, + { + "path": "domains/E-05/module_role_projection.json", + "sha256": "7fabfa3893a138dccb4e5bc797444f5f999c0e51ec6b0c8fbe0211eff3f03a6c" + }, + { + "path": "domains/E-05/structure_types.json", + "sha256": "22707fbce849991c099a08885cac929d1ba842aa896945f9921c3214e4c701d0" + }, + { + "path": "domains/E-06/module_role_projection.json", + "sha256": "805b73b2b15cb720b62cd83455de85a67bda434255b69d588eb98f2527f88b71" + }, + { + "path": "domains/E-06/structure_types.json", + "sha256": "a6520f72813caeaf72d62fd63eca10a1f46fd4fb3ffd97f97f222f37c53e8663" + }, + { + "path": "domains/E-07/module_role_projection.json", + "sha256": "9920ed415f9768beb517100e97fa7d2eb862ca90ca83f802ea460f8f6bbf2445" + }, + { + "path": "domains/E-07/structure_types.json", + "sha256": "fd4946e24cacc3bcc74c7fee5ce7fca99d3e5f2339fe3a9d698c54e2626a6c01" + }, + { + "path": "domains/E-08/module_role_projection.json", + "sha256": "4a8c284b5d3bbf8ca224e9f08398e6f563b00cec6de72f5128acc4cd8425eced" + }, + { + "path": "domains/E-08/structure_types.json", + "sha256": "a7ee6782c6541d0c6f6f6107a1d3615c2e7003a979741f2afc9d5d686a59e51d" + }, + { + "path": "domains/E-09/module_role_projection.json", + "sha256": "ab93656808a832cfd73a6d75ed28d75e50e6cc66c67d59d765fcb8bbf638205f" + }, + { + "path": "domains/E-09/structure_types.json", + "sha256": "c374b8b912679cc765b152c58ecd8320898f947b799e44ca509aa622669d7f4c" + }, + { + "path": "domains/E-10/module_role_projection.json", + "sha256": "80f760d9d8516cc81ebe503a2967418c43e11f8b8410231081111483dfa6477d" + }, + { + "path": "domains/E-10/structure_types.json", + "sha256": "07be97d40e422e14e570574c4e1da875307fe487c39e2ba9862ffd4b1623b748" + }, + { + "path": "domains/E-11/module_role_projection.json", + "sha256": "0a55ce91b1845d64d085710110aec22bfcea66967ab5fce3a4acf5179faf65f1" + }, + { + "path": "domains/E-11/structure_types.json", + "sha256": "6e565bab389f59866a0eafa8b7b7ff89f90ef2363ced3d9a4240100d3b3c3b90" + }, + { + "path": "domains/E-12/module_role_projection.json", + "sha256": "207ef7d4a1300c12aa54cb1defa1110a6a9d18850d0fc4e144baebe6ff2b3c27" + }, + { + "path": "domains/E-12/structure_types.json", + "sha256": "ef97f4b0ed05637165bfb211fc9be0cb3bcf0523e6b5a645c007e8dc2825bea9" + }, + { + "path": "domains/E-13/module_role_projection.json", + "sha256": "412df6800be576d7f789bc7fc2045091eb9c49fd346e442ba42d6f29300f7313" + }, + { + "path": "domains/E-13/structure_types.json", + "sha256": "cc18073ca443e98a34e139c08d11121ceb7d4ecd366ad3b3d5cb65ddb53e36f7" + }, + { + "path": "domains/E-14/module_role_projection.json", + "sha256": "cead5634615b6b417390b37a948a050ea89cba37485bb79617bd1296c06829a5" + }, + { + "path": "domains/E-14/structure_types.json", + "sha256": "5b0025a720a7b9f1ad7c74ce8d79f0969b282690abc0e3171e28dbf41933153b" + }, + { + "path": "domains/E-15/module_role_projection.json", + "sha256": "873f921bbbc86fc07a0c1ecfcbcacee67b1d9592b2efd7319290a10e8c1ba018" + }, + { + "path": "domains/E-15/structure_types.json", + "sha256": "784ceabd17c6de6d95a30f52dd5fd4036946fbedc556f2bad536225057a0f5fe" + }, + { + "path": "domains/E-16/module_role_projection.json", + "sha256": "24ad172b32d4942be6f4031c582f928d3c6feb6e442027e3ee02700519744b11" + }, + { + "path": "domains/E-16/structure_types.json", + "sha256": "b0bb30602ec424d35359c1a676ccca2bb2eda4a676997753da44d1dbbcc1f0b3" + }, + { + "path": "domains/E-17/module_role_projection.json", + "sha256": "498e2320ad04a907680b8588ee1b1b9ee7487e131bece96a601979d60796f5a4" + }, + { + "path": "domains/E-17/structure_types.json", + "sha256": "d306dbdf583453d51f643eb8398920efb1bb5bfa82b3a600caa79f45f790b2eb" + }, + { + "path": "domains/E-18/module_role_projection.json", + "sha256": "b0699a793cdc52e6f74e9df3254f403858e83080be9e402bf3c7dae3cd8ffd0e" + }, + { + "path": "domains/E-18/structure_types.json", + "sha256": "ce4eae3a54bfe7ac31f16b657cc0a891580e025f7bfecb1812c015e7fd0c2500" + }, + { + "path": "domains/E-19/module_role_projection.json", + "sha256": "00950a8c76d4367ccd6dc000476c810df33e49b07fce124545e350530b008b99" + }, + { + "path": "domains/E-19/structure_types.json", + "sha256": "58b9503558bcab3fb7ae76532659d54694208d813197e97bac148d50795feb22" + }, + { + "path": "domains/E-20/module_role_projection.json", + "sha256": "7aef9706b50161693005ee61fc576a1562929fdf20830a3187fdda2a94fae8e3" + }, + { + "path": "domains/E-20/structure_types.json", + "sha256": "6766546fd61d3f46f0d0b71bc3c41d5c63a525954b2568d8003c9f5e90234074" + }, + { + "path": "domains/E-21/module_role_projection.json", + "sha256": "de6b0f29ad8100744a1a4fe8393a44a8a921d604b5244f832256450cb547722a" + }, + { + "path": "domains/E-21/structure_types.json", + "sha256": "b027ff04f21cc4a86c8285e2cde6f8fd23e0ff3a3aeb3fa61a9bd10142814e36" + }, + { + "path": "domains/X1/module_role_projection.json", + "sha256": "1bceacd99f408384fec9547262017d8c857dbdb58ae906446c45ce8f1e322920" + }, + { + "path": "domains/X1/structure_types.json", + "sha256": "3344a27beb548c7d0b083b6e442a8f70ca89ce02d22614fda83203d3ff53e7e9" + }, + { + "path": "domains/X2/module_role_projection.json", + "sha256": "9282422d06035a78b592c110c197c1afa58e78294566eecd2666f0c61820cd5f" + }, + { + "path": "domains/X2/structure_types.json", + "sha256": "f51c0404bab1c5f4506012460ba02faf2cee6c958d49ee353095366defacd2ec" + }, + { + "path": "domains/X3/module_role_projection.json", + "sha256": "93d3709c7d01132b82f0445d18eab7e666ea8d7fe2afe9b308bf87af5477be10" + }, + { + "path": "domains/X3/structure_types.json", + "sha256": "91f7ef0a971b519bd7fea8fb2efc61770afeb83b3a6ee774f153aea28a9de913" + }, { "path": "domains/_common/common_worker_contract.md", "sha256": "f133c54c5a9353ae14efc4d7a27d9bee18872b6727713a9a107778eef8990fb1" @@ -1104,6 +1304,14 @@ "path": "platform/schemas/domain_slice.schema.v2.json", "sha256": "212a405088e7cf7ba2c65528a1c716938c946df7fe3bae3256b613051ed31aa3" }, + { + "path": "platform/schemas/legal_effect_structures.schema.json", + "sha256": "e2879c7a6d7f163c0729e8b863c5ef79b1094482eace78e6b8e1c7d69ce201e3" + }, + { + "path": "platform/schemas/structure_seed_bundle.schema.json", + "sha256": "b7af9e422b6ac3876cffea39ec4f617eea76a631a57dfdfcd57d3785a83c667a" + }, { "path": "routing/extension_payload_key_declarations.v1.json", "sha256": "1684e13896bc9dfd0e7aa1a3b01354f58b2fa6ed00908bec6f861bce4b47235c" @@ -1460,6 +1668,18 @@ "path": "stage1_runtime/stage_a_context_builder.txt", "sha256": "68d984f9d565034c73721dc97c5aab0f9cdb8a8b46e1bf13eabd8c136ec4bcc0" }, + { + "path": "stage1_runtime/structure_index_compiler.py", + "sha256": "c400adfb7c58e340a17e67aebcdc4a7cf92c35c422f418451c79ce7c531d201f" + }, + { + "path": "stage1_runtime/structure_index_compiler.txt", + "sha256": "c400adfb7c58e340a17e67aebcdc4a7cf92c35c422f418451c79ce7c531d201f" + }, + { + "path": "stage1_runtime/structure_index_policy.v1.json", + "sha256": "823a7e734a7bc9433966a5629a5a0b153a067c92d8570072fa14a5c42bb722bd" + }, { "path": "stage1_runtime/worker_output_validator.py", "sha256": "e5b46f929082faf621731ffb8f4864ccb9bba461ab23caa56d1bcfe5b073fd9d" @@ -1486,6 +1706,6 @@ } ], "program_release_status": "STAGE1_NOT_RELEASE_READY", - "runtime_artifact_count": 371, + "runtime_artifact_count": 426, "schema_version": "stage1_runtime_manifest.v1" } diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/stage1_runtime/structure_index_compiler.py b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/stage1_runtime/structure_index_compiler.py new file mode 100644 index 00000000..3ee69f54 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/stage1_runtime/structure_index_compiler.py @@ -0,0 +1,529 @@ +#!/usr/bin/env python3 +"""structure_index_compiler — Stage 1 Part 3 구조 seed 조립기. + +정본 근거 + 전략 stage_1_part_3_개정_신전략서.md §2(D-4) · §4.2(L0-1~L0-8) + 정책 Default_Agent/stage1_runtime/structure_index_policy.v1.json + 계약 Θ = SG-01.expected_runnable_domain_ids 에 대한 domain_config.structure_types 합집합 + 구조 레코드 = (도메인, type_id) 쌍마다 하나 · 도메인 간 병합 금지 + 전순서 order_key = (priority_rank, registry_index entries 위치, type_id) + +이 모듈은 순수하다 — 파일을 읽지도 쓰지도 않는다. 호출자가 적재한 문서를 받아 +{structure_seed_bundle, review_items, audit} 를 돌려준다. 시각·난수를 쓰지 않으므로 +같은 입력이면 같은 출력이다(L-n). + +사건 종류 이름·도메인 목록·유형 열거를 고정하지 않는다(137종 일반성 §8.1). +""" +from __future__ import annotations + +from typing import Any + +SCHEMA_VERSION = "stage1_structure_seed_bundle.v1" +POLICY_SCHEMA_VERSION = "stage1_structure_index_policy.v1" + +# 검토 코드 — registry 선언(UNREGISTERED_EFFECT_TYPE_REVIEW)과 신전략서 §4.2 의 신설분. +REVIEW_UNREGISTERED = "UNREGISTERED_EFFECT_TYPE_REVIEW" +REVIEW_SLICE_DIVERGENCE = "PART3_SLICE_PROJECTION_DIVERGENCE" +REVIEW_SIDECAR_MISMATCH = "PART3_REGISTRY_SIDECAR_MISMATCH" +REVIEW_CROSS_DOMAIN = "PART3_EFFECT_TYPE_CROSS_DOMAIN" +REVIEW_CALC_DANGLING = "PART3_CALCULATION_REF_DANGLING" +REVIEW_BO_UNATTACHED = "PART3_BO_UNATTACHED" +REVIEW_BO_UNRESOLVED = "PART3_BO_DOMAIN_UNRESOLVED" + +SG13_ROUTE_RECORD_TYPE = "legal_effect_route" + + +def _strings(value: Any) -> list[str]: + if not isinstance(value, list): + return [] + return [item for item in value if isinstance(item, str) and item] + + +def _dict(value: Any) -> dict: + return value if isinstance(value, dict) else {} + + +# --------------------------------------------------------------------------- +# 사이드카 정규화 리더 — 방언 지도(신전략서 §1.2): 목록 키 3종 · 투영 키 3종 · 정책 자리 4갈래. +# 방언을 다 읽지 않은 리더는 결손을 만들어 낸다(구 전략서 §1.5 의 실패 기록) — +# 세 방언 전부를 인정하고, 세지 않은 필드를 공통 필드로 승격하지 않는다. +# --------------------------------------------------------------------------- +_LIST_KEYS = ("entries", "structure_types", "types") +_PROJECTION_KEYS = ("projections", "mappings", "structure_type_to_projection") +_FILE_POLICY_KEYS = ("admission_rules", "unregistered_effect_policy", "fallback_policy") + + +def read_sidecar_types(doc: Any) -> dict[str, Any]: + """structure_types.json 방언을 정규화한다. + + 반환: {"list_key": str|None, "schema_version": str|None, + "items": [{"type_id", "admission_rule"?, "registered"?}], + "file_policy_key": str|None, "file_policy": dict|None, + "legacy_contract_style": bool} + """ + root = _dict(doc) + list_key = None + rows: list[Any] = [] + for key in _LIST_KEYS: + if isinstance(root.get(key), list): + list_key = key + rows = root[key] + break + items = [] + for row in rows: + row = _dict(row) + type_id = row.get("type_id") or row.get("structure_type") or row.get("id") + if not isinstance(type_id, str) or not type_id: + continue + item: dict[str, Any] = {"type_id": type_id} + if isinstance(row.get("admission_rule"), str) and row.get("admission_rule"): + item["admission_rule"] = row["admission_rule"] + if isinstance(row.get("registered"), bool): + item["registered"] = row["registered"] + items.append(item) + file_policy_key = None + file_policy = None + for key in _FILE_POLICY_KEYS: + if root.get(key) is not None: + file_policy_key = key + file_policy = root[key] + break + legacy_style = file_policy_key is None and any( + key in root for key in ("legacy_contract", "noncanonical_preservation", "ordering_preserved")) + return {"list_key": list_key, + "schema_version": root.get("schema_version"), + "items": items, + "file_policy_key": file_policy_key, + "file_policy": file_policy, + "legacy_contract_style": legacy_style} + + +def read_sidecar_projection(doc: Any) -> dict[str, Any]: + """module_role_projection.json 방언을 정규화한다. + + 반환: {"projection_key": str|None, "mappings": {type_id: {"module", "role_projection"}}, + "default_projection": dict|None, "missing_mapping_policy": dict|None} + """ + root = _dict(doc) + mappings: dict[str, dict[str, Any]] = {} + projection_key = None + for key in _PROJECTION_KEYS: + value = root.get(key) + if isinstance(value, list): + projection_key = key + for row in value: + row = _dict(row) + type_id = row.get("structure_type") or row.get("type_id") + if isinstance(type_id, str) and type_id: + mappings[type_id] = {"module": row.get("module"), + "role_projection": row.get("role_projection")} + break + if isinstance(value, dict): + projection_key = key + for type_id, row in value.items(): + row = _dict(row) + if isinstance(type_id, str) and type_id: + mappings[type_id] = {"module": row.get("module"), + "role_projection": row.get("role_projection")} + break + default_projection = root.get("default_projection") + if not isinstance(default_projection, dict): + default_projection = None + missing_policy = root.get("missing_mapping_policy") + if not isinstance(missing_policy, dict): + missing_policy = None + return {"projection_key": projection_key, "mappings": mappings, + "default_projection": default_projection, + "missing_mapping_policy": missing_policy} + + +def admission_policy_for(sidecar_types: dict[str, Any], item: dict[str, Any]) -> str: + """두 단 정의(신전략서 §1.2) — 파일 단위 정책(3키 중 있는 것) → 없으면 항목 admission_rule. + + 73/73 이 채워지는 값이다. 어느 단도 없으면 빈 문자열이 아니라 명시 문자열을 남긴다 — + 없는 것을 있는 것처럼 채우지 않되, 부재 자체는 보이게 한다. + """ + key = sidecar_types.get("file_policy_key") + if key: + return "file:%s" % key + rule = item.get("admission_rule") + if isinstance(rule, str) and rule: + return "item:admission_rule" + return "absent" + + +def resolve_source_domains(value: Any, alias_targets: dict[str, Any], + known_domain_ids: set[str]) -> list[str]: + """BO provenance.source_domain 을 registry 도메인 ID 목록으로 해소한다(L0-7b ①). + + registry ID 면 [값]. 아니면 별칭표의 목록(다중 타깃 실재 — 단일 primary 개념 없음). + 별칭표에도 없으면 빈 목록 — 호출자가 PART3_BO_DOMAIN_UNRESOLVED 로 격리한다. + """ + if not isinstance(value, str) or not value: + return [] + if value in known_domain_ids: + return [value] + targets = _strings(_dict(alias_targets).get(value)) + return [d for d in targets if d in known_domain_ids] + + +# --------------------------------------------------------------------------- +# 본체 +# --------------------------------------------------------------------------- +def compile_structure_seeds(activation_manifest: Any, + registry_index: Any, + domain_configs: dict[str, Any], + domain_sidecars: dict[str, Any], + policy: Any, + alias_declarations: Any, + sg13_records: list[Any], + sg05_records: list[Any], + sg11_records: list[Any], + domain_envelopes: dict[str, Any], + bo_records: list[Any], + slice_documents: dict[str, Any]) -> dict[str, Any]: + """L0-1 ~ L0-8. 반환 dict 는 theta 와 order_key 를 반드시 싣는다(PART3_COMPILER_STALE 의 대조면).""" + policy_root = _dict(policy) + if policy_root.get("schema_version") != POLICY_SCHEMA_VERSION: + raise ValueError("PART3_POLICY_INVALID:%s" % policy_root.get("schema_version")) + + manifest_root = _dict(activation_manifest).get("domain_activation_manifest", + _dict(activation_manifest)) + expected_runnable = _strings(_dict(manifest_root).get("expected_runnable_domain_ids")) + if not expected_runnable: + raise ValueError("PART3_EXPECTED_RUNNABLE_EMPTY") + + index_root = _dict(_dict(registry_index).get("domain_registry_index", registry_index)) + index_entries = [row for row in (index_root.get("entries") or []) if isinstance(row, dict)] + index_position = {row.get("domain_id"): position + for position, row in enumerate(index_entries) + if isinstance(row.get("domain_id"), str)} + known_domain_ids = set(index_position) + + review_items: list[dict[str, Any]] = [] + audit: dict[str, Any] = {"sidecar_dialects": {}, "input_gaps": [], + "unlinked_sg11": [], "dangling_calculation_refs": {}} + + def review(code: str, severity: str, domain_id: str | None, detail: dict[str, Any]) -> None: + item = {"review_code": code, "severity": severity} + if domain_id is not None: + item["domain_id"] = domain_id + item.update(detail) + review_items.append(item) + + # ---------------- L0-1 · Θ 조립 ---------------- + declared_by_domain: dict[str, list[dict[str, Any]]] = {} + for domain_id in expected_runnable: + if domain_id not in known_domain_ids: + raise ValueError("PART3_DOMAIN_NOT_IN_REGISTRY:%s" % domain_id) + config_root = _dict(domain_configs.get(domain_id)) + rows = [row for row in (config_root.get("structure_types") or []) + if isinstance(row, dict) and isinstance(row.get("type_id"), str)] + declared_by_domain[domain_id] = rows + theta = sorted({row["type_id"] for rows in declared_by_domain.values() for row in rows}) + declaring_domains: dict[str, list[str]] = {} + for domain_id in expected_runnable: + for row in declared_by_domain[domain_id]: + declaring_domains.setdefault(row["type_id"], []).append(domain_id) + + # ---------------- L0-2c · 사이드카 교차 검증 (레코드 생성보다 앞 — admission_policy 재료) ---------------- + sidecar_norm: dict[str, dict[str, Any]] = {} + projection_norm: dict[str, dict[str, Any]] = {} + for domain_id in expected_runnable: + pair = _dict(domain_sidecars.get(domain_id)) + declared_ids = sorted({row["type_id"] for row in declared_by_domain[domain_id]}) + if not pair: + # 부재 규칙(신전략서 §5.5) — 선언 0 도메인의 부재만 정상이다. + if declared_ids: + raise ValueError("PART3_SIDECAR_ABSENT_FOR_DECLARING_DOMAIN:%s" % domain_id) + audit["sidecar_dialects"][domain_id] = {"absent": True, "declared": 0} + continue + types_doc = read_sidecar_types(pair.get("structure_types")) + projection_doc = read_sidecar_projection(pair.get("module_role_projection")) + sidecar_norm[domain_id] = types_doc + projection_norm[domain_id] = projection_doc + audit["sidecar_dialects"][domain_id] = { + "list_key": types_doc.get("list_key"), + "schema_version": types_doc.get("schema_version"), + "projection_key": projection_doc.get("projection_key"), + "file_policy_key": types_doc.get("file_policy_key"), + "legacy_contract_style": types_doc.get("legacy_contract_style"), + "item_count": len(types_doc.get("items") or []), + } + sidecar_ids = sorted({item["type_id"] for item in types_doc.get("items") or []}) + if sidecar_ids != declared_ids: + review(REVIEW_SIDECAR_MISMATCH, "HARD_WARNING", domain_id, { + "detail": "type_set_mismatch", + "config_only": sorted(set(declared_ids) - set(sidecar_ids)), + "sidecar_only": sorted(set(sidecar_ids) - set(declared_ids)), + }) + for type_id, mapping in sorted((projection_doc.get("mappings") or {}).items()): + config_row = next((row for row in declared_by_domain[domain_id] + if row["type_id"] == type_id), None) + if config_row is None: + continue + if (mapping.get("module") != config_row.get("module") + or mapping.get("role_projection") != config_row.get("role_projection")): + review(REVIEW_SIDECAR_MISMATCH, "HARD_WARNING", domain_id, { + "detail": "projection_mismatch", "type_id": type_id, + "config": {"module": config_row.get("module"), + "role_projection": config_row.get("role_projection")}, + "sidecar": mapping, + }) + + # ---------------- L0-2 · 구조 레코드 — (도메인, type_id) 쌍마다 하나 ---------------- + e13_extension_key = None + contract = _dict(policy_root.get("extension_key_rule")) + e13_extension_key = contract.get("extension_key") if isinstance( + contract.get("extension_key"), str) else None + e13_domain = contract.get("domain_id") if isinstance(contract.get("domain_id"), str) else None + + records: dict[tuple[str, str], dict[str, Any]] = {} + for domain_id in expected_runnable: + types_doc = sidecar_norm.get(domain_id, {"items": []}) + item_by_type = {item["type_id"]: item for item in types_doc.get("items") or []} + for row in declared_by_domain[domain_id]: + type_id = row["type_id"] + item = item_by_type.get(type_id, {}) + record: dict[str, Any] = { + "structure_id": "LES-%s-%s" % (domain_id, type_id), + "domain_id": domain_id, + "type_id": type_id, + "priority_rank": row.get("priority_rank"), + "order_key": [row.get("priority_rank"), index_position[domain_id], type_id], + "module": row.get("module"), + "role_projection": row.get("role_projection"), + "admission_policy": admission_policy_for(types_doc, item), + "routes": [], + "route_count": 0, + "evidence_refs": [], + "meeting_clause_refs": [], + "calculation_request_refs": [], + "source_bo_ids": [], + "review_codes": [], + "review_required": False, + } + if "admission_rule" in item: + record["admission_rule"] = item["admission_rule"] + if "registered" in item: + record["registered_declared"] = item["registered"] + if domain_id == e13_domain and e13_extension_key: + record["extension_key"] = e13_extension_key + if domain_id == "E-00": + # E-00 특칙 — 잔여 수집기 유래 구조는 검토 필수(신전략서 §4.2). + record["review_required"] = True + records[(domain_id, type_id)] = record + + # ---------------- L0-2b · 슬라이스 투영 정합 ---------------- + for domain_id in expected_runnable: + slice_doc = slice_documents.get(domain_id) + if slice_doc is None: + audit["input_gaps"].append({"kind": "slice_absent", "domain_id": domain_id}) + continue + slice_root = _dict(_dict(slice_doc).get("stage_b_domain_slice", slice_doc)) + declarations = _dict(slice_root.get("domain_declarations")) + slice_ids = sorted(_strings(declarations.get("structure_type_ids"))) + config_ids = sorted({row["type_id"] for row in declared_by_domain[domain_id]}) + if slice_ids != config_ids: + review(REVIEW_SLICE_DIVERGENCE, "HARD_WARNING", domain_id, { + "slice_only": sorted(set(slice_ids) - set(config_ids)), + "config_only": sorted(set(config_ids) - set(slice_ids)), + }) + + # ---------------- L0-3 · SG-13 조인 + L0-4 · 도메인 소속 ---------------- + routes = [_dict(row) for row in sg13_records + if _dict(row).get("record_type") == SG13_ROUTE_RECORD_TYPE] + attached_route_count = 0 + unattached_routes: list[dict[str, Any]] = [] + for route in routes: + details = _dict(route.get("details")) + type_id = details.get("type_id") + route_domains = _strings(route.get("domain_ids")) + route_domain = route_domains[0] if route_domains else None + registered = details.get("registered") + route_ref = { + "signal_id": route.get("signal_id"), + "source_seed_id": details.get("source_seed_id"), + "registered": registered if isinstance(registered, bool) else None, + "status": route.get("status"), + } + if not isinstance(type_id, str) or type_id not in theta: + # Θ 밖 — 버리지 않는다. default_projection 이 있으면 검토 항목에 실어 함께 나른다. + projection = None + if route_domain and route_domain in projection_norm: + projection = projection_norm[route_domain].get("default_projection") + review(REVIEW_UNREGISTERED, "HARD_WARNING", route_domain, { + "type_id": type_id, "signal_id": route.get("signal_id"), + "default_projection": projection, + }) + unattached_routes.append({"signal_id": route.get("signal_id"), + "type_id": type_id, "reason": "type_outside_theta"}) + continue + target_keys = [] + if route_domain and (route_domain, type_id) in records: + target_keys = [(route_domain, type_id)] + else: + # Θ 안이지만 자기 도메인이 선언하지 않은 유형 — 선언 도메인 전부에 붙이고 검토(L0-4). + target_keys = [(d, type_id) for d in declaring_domains.get(type_id, []) + if (d, type_id) in records] + if target_keys: + review(REVIEW_CROSS_DOMAIN, "HARD_WARNING", route_domain, { + "type_id": type_id, "signal_id": route.get("signal_id"), + "attached_to": ["%s:%s" % key for key in target_keys], + }) + if not target_keys: + unattached_routes.append({"signal_id": route.get("signal_id"), + "type_id": type_id, "reason": "no_declaring_domain"}) + review(REVIEW_UNREGISTERED, "HARD_WARNING", route_domain, { + "type_id": type_id, "signal_id": route.get("signal_id"), + "default_projection": None, + }) + continue + attached_route_count += 1 + for key in target_keys: + record = records[key] + record["routes"].append(dict(route_ref)) + for field in ("evidence_refs", "meeting_clause_refs"): + merged = set(record[field]) | set(_strings(route.get(field))) + record[field] = sorted(merged) + if registered is False: + # 붙은 채로 검토 꼬리표를 단다(L-m2 — 분할은 부착 여부로만 가른다). + if REVIEW_UNREGISTERED not in record["review_codes"]: + record["review_codes"].append(REVIEW_UNREGISTERED) + record["review_required"] = True + review(REVIEW_UNREGISTERED, "SOFT_WARNING", key[0], { + "type_id": type_id, "signal_id": route.get("signal_id"), + "detail": "registered_false_route_attached", + }) + declared_flag = record.get("registered_declared") + if isinstance(declared_flag, bool) and isinstance(registered, bool) \ + and declared_flag != registered: + # types 방언의 registered ↔ SG-13 registered 대조(L0-2c 둘째 갈래). + if REVIEW_SIDECAR_MISMATCH not in record["review_codes"]: + record["review_codes"].append(REVIEW_SIDECAR_MISMATCH) + record["review_required"] = True + review(REVIEW_SIDECAR_MISMATCH, "HARD_WARNING", key[0], { + "detail": "registered_flag_mismatch", "type_id": type_id, + "sidecar": declared_flag, "route": registered, + }) + + # ---------------- L0-5 · module 부여는 L0-2 에서 config 원문으로 끝났다 ---------------- + + # ---------------- L0-6 · 계산 조인 — SG-11 signal_id ↔ 도메인 봉투 calculation_refs ---------------- + # 봉투 부재는 침묵 스킵이 아니라 영수증 계수다(I-5 — expected_runnable 중 실재하는 것만 읽되 + # 부재를 기록한다). 실주행에서 감시 도메인 봉투가 없는 것은 상시 경로다. + for domain_id in expected_runnable: + if domain_id not in domain_envelopes: + audit["input_gaps"].append({"kind": "domain_envelope_absent", + "domain_id": domain_id}) + sg11_rows = [_dict(row) for row in sg11_records] + sg11_ids = {row.get("signal_id") for row in sg11_rows if isinstance(row.get("signal_id"), str)} + linked_sg11: set[str] = set() + for domain_id in expected_runnable: + envelope = _dict(_dict(domain_envelopes.get(domain_id)).get("domain_signal_envelope", + domain_envelopes.get(domain_id))) + refs = _strings(_dict(envelope).get("calculation_refs")) + if not refs: + continue + matched = sorted(set(refs) & sg11_ids) + dangling = sorted(set(refs) - sg11_ids) + if dangling: + audit["dangling_calculation_refs"][domain_id] = dangling + review(REVIEW_CALC_DANGLING, "HARD_WARNING", domain_id, {"dangling": dangling}) + if matched: + linked_sg11.update(matched) + for (record_domain, _type_id), record in records.items(): + if record_domain == domain_id: + merged = set(record["calculation_request_refs"]) | set(matched) + record["calculation_request_refs"] = sorted(merged) + # 봉투 참조에 연결되지 않은 SG-11(합성 id 포함)은 구조에 싣지 않되 형식화 기록(신전략서 L0-6). + audit["unlinked_sg11"] = sorted(sg11_ids - linked_sg11) + + # ---------------- L0-7 · SG-05 근거 refs (도메인 단위 합집합) ---------------- + for row in sg05_records: + row = _dict(row) + for domain_id in _strings(row.get("domain_ids")): + for (record_domain, _type_id), record in records.items(): + if record_domain == domain_id: + for field in ("evidence_refs", "meeting_clause_refs"): + merged = set(record[field]) | set(_strings(row.get(field))) + record[field] = sorted(merged) + + # ---------------- L0-7b · BO 부착 조인 ---------------- + alias_targets = _dict(_dict(alias_declarations).get("legacy_alias_targets")) + bo_rows = [_dict(row) for row in bo_records] + bo_attached: list[str] = [] + bo_unattached: list[dict[str, Any]] = [] + for bo in bo_rows: + bo_id = bo.get("BO_ID") or bo.get("id") + provenance = _dict(bo.get("provenance")) + source_domain = provenance.get("source_domain") + resolved = resolve_source_domains(source_domain, alias_targets, known_domain_ids) + if not resolved: + review(REVIEW_BO_UNRESOLVED, "HARD_WARNING", None, { + "bo_id": bo_id, "source_domain": source_domain, + }) + bo_unattached.append({"bo_id": bo_id, "reason": "source_domain_unresolved"}) + continue + keywords = _strings(bo.get("Legal_Keywords")) + attached_here = False + for domain_id in resolved: + for type_id in keywords: + record = records.get((domain_id, type_id)) + if record is not None: + attached_here = True + if isinstance(bo_id, str) and bo_id not in record["source_bo_ids"]: + record["source_bo_ids"].append(bo_id) + record["source_bo_ids"].sort() + if attached_here: + bo_attached.append(bo_id if isinstance(bo_id, str) else "") + else: + # 부착 실패는 침묵 금지(L0-7b ③). + review(REVIEW_BO_UNATTACHED, "HARD_WARNING", None, { + "bo_id": bo_id, "source_domain": source_domain, + "legal_keywords": keywords, "resolved_domains": resolved, + }) + bo_unattached.append({"bo_id": bo_id, "reason": "no_matching_structure"}) + + # ---------------- 정렬 · 검토 재료 반영 · 산출 ---------------- + ordered = sorted(records.values(), + key=lambda record: (record["order_key"][0] if isinstance( + record["order_key"][0], int) else 999, + record["order_key"][1], record["order_key"][2])) + for record in ordered: + record["route_count"] = len(record["routes"]) + record["routes"].sort(key=lambda ref: (str(ref.get("signal_id")), + str(ref.get("source_seed_id")))) + record["review_codes"].sort() + if record["review_codes"]: + record["review_required"] = True + + status = "READY_WITH_REVIEW" if review_items else "READY" + bundle = { + "schema_version": SCHEMA_VERSION, + "status": status, + "registry_version": index_root.get("registry_version"), + "expected_runnable_domain_ids": list(expected_runnable), + "theta": theta, + "structure_records": ordered, + "unattached_routes": sorted(unattached_routes, + key=lambda row: (str(row.get("signal_id")), + str(row.get("type_id")))), + "unattached_bo": sorted(bo_unattached, key=lambda row: str(row.get("bo_id"))), + "counts": { + "structure_records": len(ordered), + "declared_structure_types_total": sum( + len(rows) for rows in declared_by_domain.values()), + "sg13_route_total": len(routes), + "routes_attached": attached_route_count, + "routes_unattached": len(unattached_routes), + "bo_total": len(bo_rows), + "bo_attached": len(bo_attached), + "bo_unattached": len(bo_unattached), + "sg11_total": len(sg11_rows), + "sg11_linked": len(linked_sg11), + "sg11_unlinked": len(audit["unlinked_sg11"]), + }, + "created_by": "Task_C_LE_L0_structure_seed_reducer", + } + return {"structure_seed_bundle": bundle, "review_items": review_items, "audit": audit} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/stage1_runtime/structure_index_compiler.txt b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/stage1_runtime/structure_index_compiler.txt new file mode 100644 index 00000000..3ee69f54 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/stage1_runtime/structure_index_compiler.txt @@ -0,0 +1,529 @@ +#!/usr/bin/env python3 +"""structure_index_compiler — Stage 1 Part 3 구조 seed 조립기. + +정본 근거 + 전략 stage_1_part_3_개정_신전략서.md §2(D-4) · §4.2(L0-1~L0-8) + 정책 Default_Agent/stage1_runtime/structure_index_policy.v1.json + 계약 Θ = SG-01.expected_runnable_domain_ids 에 대한 domain_config.structure_types 합집합 + 구조 레코드 = (도메인, type_id) 쌍마다 하나 · 도메인 간 병합 금지 + 전순서 order_key = (priority_rank, registry_index entries 위치, type_id) + +이 모듈은 순수하다 — 파일을 읽지도 쓰지도 않는다. 호출자가 적재한 문서를 받아 +{structure_seed_bundle, review_items, audit} 를 돌려준다. 시각·난수를 쓰지 않으므로 +같은 입력이면 같은 출력이다(L-n). + +사건 종류 이름·도메인 목록·유형 열거를 고정하지 않는다(137종 일반성 §8.1). +""" +from __future__ import annotations + +from typing import Any + +SCHEMA_VERSION = "stage1_structure_seed_bundle.v1" +POLICY_SCHEMA_VERSION = "stage1_structure_index_policy.v1" + +# 검토 코드 — registry 선언(UNREGISTERED_EFFECT_TYPE_REVIEW)과 신전략서 §4.2 의 신설분. +REVIEW_UNREGISTERED = "UNREGISTERED_EFFECT_TYPE_REVIEW" +REVIEW_SLICE_DIVERGENCE = "PART3_SLICE_PROJECTION_DIVERGENCE" +REVIEW_SIDECAR_MISMATCH = "PART3_REGISTRY_SIDECAR_MISMATCH" +REVIEW_CROSS_DOMAIN = "PART3_EFFECT_TYPE_CROSS_DOMAIN" +REVIEW_CALC_DANGLING = "PART3_CALCULATION_REF_DANGLING" +REVIEW_BO_UNATTACHED = "PART3_BO_UNATTACHED" +REVIEW_BO_UNRESOLVED = "PART3_BO_DOMAIN_UNRESOLVED" + +SG13_ROUTE_RECORD_TYPE = "legal_effect_route" + + +def _strings(value: Any) -> list[str]: + if not isinstance(value, list): + return [] + return [item for item in value if isinstance(item, str) and item] + + +def _dict(value: Any) -> dict: + return value if isinstance(value, dict) else {} + + +# --------------------------------------------------------------------------- +# 사이드카 정규화 리더 — 방언 지도(신전략서 §1.2): 목록 키 3종 · 투영 키 3종 · 정책 자리 4갈래. +# 방언을 다 읽지 않은 리더는 결손을 만들어 낸다(구 전략서 §1.5 의 실패 기록) — +# 세 방언 전부를 인정하고, 세지 않은 필드를 공통 필드로 승격하지 않는다. +# --------------------------------------------------------------------------- +_LIST_KEYS = ("entries", "structure_types", "types") +_PROJECTION_KEYS = ("projections", "mappings", "structure_type_to_projection") +_FILE_POLICY_KEYS = ("admission_rules", "unregistered_effect_policy", "fallback_policy") + + +def read_sidecar_types(doc: Any) -> dict[str, Any]: + """structure_types.json 방언을 정규화한다. + + 반환: {"list_key": str|None, "schema_version": str|None, + "items": [{"type_id", "admission_rule"?, "registered"?}], + "file_policy_key": str|None, "file_policy": dict|None, + "legacy_contract_style": bool} + """ + root = _dict(doc) + list_key = None + rows: list[Any] = [] + for key in _LIST_KEYS: + if isinstance(root.get(key), list): + list_key = key + rows = root[key] + break + items = [] + for row in rows: + row = _dict(row) + type_id = row.get("type_id") or row.get("structure_type") or row.get("id") + if not isinstance(type_id, str) or not type_id: + continue + item: dict[str, Any] = {"type_id": type_id} + if isinstance(row.get("admission_rule"), str) and row.get("admission_rule"): + item["admission_rule"] = row["admission_rule"] + if isinstance(row.get("registered"), bool): + item["registered"] = row["registered"] + items.append(item) + file_policy_key = None + file_policy = None + for key in _FILE_POLICY_KEYS: + if root.get(key) is not None: + file_policy_key = key + file_policy = root[key] + break + legacy_style = file_policy_key is None and any( + key in root for key in ("legacy_contract", "noncanonical_preservation", "ordering_preserved")) + return {"list_key": list_key, + "schema_version": root.get("schema_version"), + "items": items, + "file_policy_key": file_policy_key, + "file_policy": file_policy, + "legacy_contract_style": legacy_style} + + +def read_sidecar_projection(doc: Any) -> dict[str, Any]: + """module_role_projection.json 방언을 정규화한다. + + 반환: {"projection_key": str|None, "mappings": {type_id: {"module", "role_projection"}}, + "default_projection": dict|None, "missing_mapping_policy": dict|None} + """ + root = _dict(doc) + mappings: dict[str, dict[str, Any]] = {} + projection_key = None + for key in _PROJECTION_KEYS: + value = root.get(key) + if isinstance(value, list): + projection_key = key + for row in value: + row = _dict(row) + type_id = row.get("structure_type") or row.get("type_id") + if isinstance(type_id, str) and type_id: + mappings[type_id] = {"module": row.get("module"), + "role_projection": row.get("role_projection")} + break + if isinstance(value, dict): + projection_key = key + for type_id, row in value.items(): + row = _dict(row) + if isinstance(type_id, str) and type_id: + mappings[type_id] = {"module": row.get("module"), + "role_projection": row.get("role_projection")} + break + default_projection = root.get("default_projection") + if not isinstance(default_projection, dict): + default_projection = None + missing_policy = root.get("missing_mapping_policy") + if not isinstance(missing_policy, dict): + missing_policy = None + return {"projection_key": projection_key, "mappings": mappings, + "default_projection": default_projection, + "missing_mapping_policy": missing_policy} + + +def admission_policy_for(sidecar_types: dict[str, Any], item: dict[str, Any]) -> str: + """두 단 정의(신전략서 §1.2) — 파일 단위 정책(3키 중 있는 것) → 없으면 항목 admission_rule. + + 73/73 이 채워지는 값이다. 어느 단도 없으면 빈 문자열이 아니라 명시 문자열을 남긴다 — + 없는 것을 있는 것처럼 채우지 않되, 부재 자체는 보이게 한다. + """ + key = sidecar_types.get("file_policy_key") + if key: + return "file:%s" % key + rule = item.get("admission_rule") + if isinstance(rule, str) and rule: + return "item:admission_rule" + return "absent" + + +def resolve_source_domains(value: Any, alias_targets: dict[str, Any], + known_domain_ids: set[str]) -> list[str]: + """BO provenance.source_domain 을 registry 도메인 ID 목록으로 해소한다(L0-7b ①). + + registry ID 면 [값]. 아니면 별칭표의 목록(다중 타깃 실재 — 단일 primary 개념 없음). + 별칭표에도 없으면 빈 목록 — 호출자가 PART3_BO_DOMAIN_UNRESOLVED 로 격리한다. + """ + if not isinstance(value, str) or not value: + return [] + if value in known_domain_ids: + return [value] + targets = _strings(_dict(alias_targets).get(value)) + return [d for d in targets if d in known_domain_ids] + + +# --------------------------------------------------------------------------- +# 본체 +# --------------------------------------------------------------------------- +def compile_structure_seeds(activation_manifest: Any, + registry_index: Any, + domain_configs: dict[str, Any], + domain_sidecars: dict[str, Any], + policy: Any, + alias_declarations: Any, + sg13_records: list[Any], + sg05_records: list[Any], + sg11_records: list[Any], + domain_envelopes: dict[str, Any], + bo_records: list[Any], + slice_documents: dict[str, Any]) -> dict[str, Any]: + """L0-1 ~ L0-8. 반환 dict 는 theta 와 order_key 를 반드시 싣는다(PART3_COMPILER_STALE 의 대조면).""" + policy_root = _dict(policy) + if policy_root.get("schema_version") != POLICY_SCHEMA_VERSION: + raise ValueError("PART3_POLICY_INVALID:%s" % policy_root.get("schema_version")) + + manifest_root = _dict(activation_manifest).get("domain_activation_manifest", + _dict(activation_manifest)) + expected_runnable = _strings(_dict(manifest_root).get("expected_runnable_domain_ids")) + if not expected_runnable: + raise ValueError("PART3_EXPECTED_RUNNABLE_EMPTY") + + index_root = _dict(_dict(registry_index).get("domain_registry_index", registry_index)) + index_entries = [row for row in (index_root.get("entries") or []) if isinstance(row, dict)] + index_position = {row.get("domain_id"): position + for position, row in enumerate(index_entries) + if isinstance(row.get("domain_id"), str)} + known_domain_ids = set(index_position) + + review_items: list[dict[str, Any]] = [] + audit: dict[str, Any] = {"sidecar_dialects": {}, "input_gaps": [], + "unlinked_sg11": [], "dangling_calculation_refs": {}} + + def review(code: str, severity: str, domain_id: str | None, detail: dict[str, Any]) -> None: + item = {"review_code": code, "severity": severity} + if domain_id is not None: + item["domain_id"] = domain_id + item.update(detail) + review_items.append(item) + + # ---------------- L0-1 · Θ 조립 ---------------- + declared_by_domain: dict[str, list[dict[str, Any]]] = {} + for domain_id in expected_runnable: + if domain_id not in known_domain_ids: + raise ValueError("PART3_DOMAIN_NOT_IN_REGISTRY:%s" % domain_id) + config_root = _dict(domain_configs.get(domain_id)) + rows = [row for row in (config_root.get("structure_types") or []) + if isinstance(row, dict) and isinstance(row.get("type_id"), str)] + declared_by_domain[domain_id] = rows + theta = sorted({row["type_id"] for rows in declared_by_domain.values() for row in rows}) + declaring_domains: dict[str, list[str]] = {} + for domain_id in expected_runnable: + for row in declared_by_domain[domain_id]: + declaring_domains.setdefault(row["type_id"], []).append(domain_id) + + # ---------------- L0-2c · 사이드카 교차 검증 (레코드 생성보다 앞 — admission_policy 재료) ---------------- + sidecar_norm: dict[str, dict[str, Any]] = {} + projection_norm: dict[str, dict[str, Any]] = {} + for domain_id in expected_runnable: + pair = _dict(domain_sidecars.get(domain_id)) + declared_ids = sorted({row["type_id"] for row in declared_by_domain[domain_id]}) + if not pair: + # 부재 규칙(신전략서 §5.5) — 선언 0 도메인의 부재만 정상이다. + if declared_ids: + raise ValueError("PART3_SIDECAR_ABSENT_FOR_DECLARING_DOMAIN:%s" % domain_id) + audit["sidecar_dialects"][domain_id] = {"absent": True, "declared": 0} + continue + types_doc = read_sidecar_types(pair.get("structure_types")) + projection_doc = read_sidecar_projection(pair.get("module_role_projection")) + sidecar_norm[domain_id] = types_doc + projection_norm[domain_id] = projection_doc + audit["sidecar_dialects"][domain_id] = { + "list_key": types_doc.get("list_key"), + "schema_version": types_doc.get("schema_version"), + "projection_key": projection_doc.get("projection_key"), + "file_policy_key": types_doc.get("file_policy_key"), + "legacy_contract_style": types_doc.get("legacy_contract_style"), + "item_count": len(types_doc.get("items") or []), + } + sidecar_ids = sorted({item["type_id"] for item in types_doc.get("items") or []}) + if sidecar_ids != declared_ids: + review(REVIEW_SIDECAR_MISMATCH, "HARD_WARNING", domain_id, { + "detail": "type_set_mismatch", + "config_only": sorted(set(declared_ids) - set(sidecar_ids)), + "sidecar_only": sorted(set(sidecar_ids) - set(declared_ids)), + }) + for type_id, mapping in sorted((projection_doc.get("mappings") or {}).items()): + config_row = next((row for row in declared_by_domain[domain_id] + if row["type_id"] == type_id), None) + if config_row is None: + continue + if (mapping.get("module") != config_row.get("module") + or mapping.get("role_projection") != config_row.get("role_projection")): + review(REVIEW_SIDECAR_MISMATCH, "HARD_WARNING", domain_id, { + "detail": "projection_mismatch", "type_id": type_id, + "config": {"module": config_row.get("module"), + "role_projection": config_row.get("role_projection")}, + "sidecar": mapping, + }) + + # ---------------- L0-2 · 구조 레코드 — (도메인, type_id) 쌍마다 하나 ---------------- + e13_extension_key = None + contract = _dict(policy_root.get("extension_key_rule")) + e13_extension_key = contract.get("extension_key") if isinstance( + contract.get("extension_key"), str) else None + e13_domain = contract.get("domain_id") if isinstance(contract.get("domain_id"), str) else None + + records: dict[tuple[str, str], dict[str, Any]] = {} + for domain_id in expected_runnable: + types_doc = sidecar_norm.get(domain_id, {"items": []}) + item_by_type = {item["type_id"]: item for item in types_doc.get("items") or []} + for row in declared_by_domain[domain_id]: + type_id = row["type_id"] + item = item_by_type.get(type_id, {}) + record: dict[str, Any] = { + "structure_id": "LES-%s-%s" % (domain_id, type_id), + "domain_id": domain_id, + "type_id": type_id, + "priority_rank": row.get("priority_rank"), + "order_key": [row.get("priority_rank"), index_position[domain_id], type_id], + "module": row.get("module"), + "role_projection": row.get("role_projection"), + "admission_policy": admission_policy_for(types_doc, item), + "routes": [], + "route_count": 0, + "evidence_refs": [], + "meeting_clause_refs": [], + "calculation_request_refs": [], + "source_bo_ids": [], + "review_codes": [], + "review_required": False, + } + if "admission_rule" in item: + record["admission_rule"] = item["admission_rule"] + if "registered" in item: + record["registered_declared"] = item["registered"] + if domain_id == e13_domain and e13_extension_key: + record["extension_key"] = e13_extension_key + if domain_id == "E-00": + # E-00 특칙 — 잔여 수집기 유래 구조는 검토 필수(신전략서 §4.2). + record["review_required"] = True + records[(domain_id, type_id)] = record + + # ---------------- L0-2b · 슬라이스 투영 정합 ---------------- + for domain_id in expected_runnable: + slice_doc = slice_documents.get(domain_id) + if slice_doc is None: + audit["input_gaps"].append({"kind": "slice_absent", "domain_id": domain_id}) + continue + slice_root = _dict(_dict(slice_doc).get("stage_b_domain_slice", slice_doc)) + declarations = _dict(slice_root.get("domain_declarations")) + slice_ids = sorted(_strings(declarations.get("structure_type_ids"))) + config_ids = sorted({row["type_id"] for row in declared_by_domain[domain_id]}) + if slice_ids != config_ids: + review(REVIEW_SLICE_DIVERGENCE, "HARD_WARNING", domain_id, { + "slice_only": sorted(set(slice_ids) - set(config_ids)), + "config_only": sorted(set(config_ids) - set(slice_ids)), + }) + + # ---------------- L0-3 · SG-13 조인 + L0-4 · 도메인 소속 ---------------- + routes = [_dict(row) for row in sg13_records + if _dict(row).get("record_type") == SG13_ROUTE_RECORD_TYPE] + attached_route_count = 0 + unattached_routes: list[dict[str, Any]] = [] + for route in routes: + details = _dict(route.get("details")) + type_id = details.get("type_id") + route_domains = _strings(route.get("domain_ids")) + route_domain = route_domains[0] if route_domains else None + registered = details.get("registered") + route_ref = { + "signal_id": route.get("signal_id"), + "source_seed_id": details.get("source_seed_id"), + "registered": registered if isinstance(registered, bool) else None, + "status": route.get("status"), + } + if not isinstance(type_id, str) or type_id not in theta: + # Θ 밖 — 버리지 않는다. default_projection 이 있으면 검토 항목에 실어 함께 나른다. + projection = None + if route_domain and route_domain in projection_norm: + projection = projection_norm[route_domain].get("default_projection") + review(REVIEW_UNREGISTERED, "HARD_WARNING", route_domain, { + "type_id": type_id, "signal_id": route.get("signal_id"), + "default_projection": projection, + }) + unattached_routes.append({"signal_id": route.get("signal_id"), + "type_id": type_id, "reason": "type_outside_theta"}) + continue + target_keys = [] + if route_domain and (route_domain, type_id) in records: + target_keys = [(route_domain, type_id)] + else: + # Θ 안이지만 자기 도메인이 선언하지 않은 유형 — 선언 도메인 전부에 붙이고 검토(L0-4). + target_keys = [(d, type_id) for d in declaring_domains.get(type_id, []) + if (d, type_id) in records] + if target_keys: + review(REVIEW_CROSS_DOMAIN, "HARD_WARNING", route_domain, { + "type_id": type_id, "signal_id": route.get("signal_id"), + "attached_to": ["%s:%s" % key for key in target_keys], + }) + if not target_keys: + unattached_routes.append({"signal_id": route.get("signal_id"), + "type_id": type_id, "reason": "no_declaring_domain"}) + review(REVIEW_UNREGISTERED, "HARD_WARNING", route_domain, { + "type_id": type_id, "signal_id": route.get("signal_id"), + "default_projection": None, + }) + continue + attached_route_count += 1 + for key in target_keys: + record = records[key] + record["routes"].append(dict(route_ref)) + for field in ("evidence_refs", "meeting_clause_refs"): + merged = set(record[field]) | set(_strings(route.get(field))) + record[field] = sorted(merged) + if registered is False: + # 붙은 채로 검토 꼬리표를 단다(L-m2 — 분할은 부착 여부로만 가른다). + if REVIEW_UNREGISTERED not in record["review_codes"]: + record["review_codes"].append(REVIEW_UNREGISTERED) + record["review_required"] = True + review(REVIEW_UNREGISTERED, "SOFT_WARNING", key[0], { + "type_id": type_id, "signal_id": route.get("signal_id"), + "detail": "registered_false_route_attached", + }) + declared_flag = record.get("registered_declared") + if isinstance(declared_flag, bool) and isinstance(registered, bool) \ + and declared_flag != registered: + # types 방언의 registered ↔ SG-13 registered 대조(L0-2c 둘째 갈래). + if REVIEW_SIDECAR_MISMATCH not in record["review_codes"]: + record["review_codes"].append(REVIEW_SIDECAR_MISMATCH) + record["review_required"] = True + review(REVIEW_SIDECAR_MISMATCH, "HARD_WARNING", key[0], { + "detail": "registered_flag_mismatch", "type_id": type_id, + "sidecar": declared_flag, "route": registered, + }) + + # ---------------- L0-5 · module 부여는 L0-2 에서 config 원문으로 끝났다 ---------------- + + # ---------------- L0-6 · 계산 조인 — SG-11 signal_id ↔ 도메인 봉투 calculation_refs ---------------- + # 봉투 부재는 침묵 스킵이 아니라 영수증 계수다(I-5 — expected_runnable 중 실재하는 것만 읽되 + # 부재를 기록한다). 실주행에서 감시 도메인 봉투가 없는 것은 상시 경로다. + for domain_id in expected_runnable: + if domain_id not in domain_envelopes: + audit["input_gaps"].append({"kind": "domain_envelope_absent", + "domain_id": domain_id}) + sg11_rows = [_dict(row) for row in sg11_records] + sg11_ids = {row.get("signal_id") for row in sg11_rows if isinstance(row.get("signal_id"), str)} + linked_sg11: set[str] = set() + for domain_id in expected_runnable: + envelope = _dict(_dict(domain_envelopes.get(domain_id)).get("domain_signal_envelope", + domain_envelopes.get(domain_id))) + refs = _strings(_dict(envelope).get("calculation_refs")) + if not refs: + continue + matched = sorted(set(refs) & sg11_ids) + dangling = sorted(set(refs) - sg11_ids) + if dangling: + audit["dangling_calculation_refs"][domain_id] = dangling + review(REVIEW_CALC_DANGLING, "HARD_WARNING", domain_id, {"dangling": dangling}) + if matched: + linked_sg11.update(matched) + for (record_domain, _type_id), record in records.items(): + if record_domain == domain_id: + merged = set(record["calculation_request_refs"]) | set(matched) + record["calculation_request_refs"] = sorted(merged) + # 봉투 참조에 연결되지 않은 SG-11(합성 id 포함)은 구조에 싣지 않되 형식화 기록(신전략서 L0-6). + audit["unlinked_sg11"] = sorted(sg11_ids - linked_sg11) + + # ---------------- L0-7 · SG-05 근거 refs (도메인 단위 합집합) ---------------- + for row in sg05_records: + row = _dict(row) + for domain_id in _strings(row.get("domain_ids")): + for (record_domain, _type_id), record in records.items(): + if record_domain == domain_id: + for field in ("evidence_refs", "meeting_clause_refs"): + merged = set(record[field]) | set(_strings(row.get(field))) + record[field] = sorted(merged) + + # ---------------- L0-7b · BO 부착 조인 ---------------- + alias_targets = _dict(_dict(alias_declarations).get("legacy_alias_targets")) + bo_rows = [_dict(row) for row in bo_records] + bo_attached: list[str] = [] + bo_unattached: list[dict[str, Any]] = [] + for bo in bo_rows: + bo_id = bo.get("BO_ID") or bo.get("id") + provenance = _dict(bo.get("provenance")) + source_domain = provenance.get("source_domain") + resolved = resolve_source_domains(source_domain, alias_targets, known_domain_ids) + if not resolved: + review(REVIEW_BO_UNRESOLVED, "HARD_WARNING", None, { + "bo_id": bo_id, "source_domain": source_domain, + }) + bo_unattached.append({"bo_id": bo_id, "reason": "source_domain_unresolved"}) + continue + keywords = _strings(bo.get("Legal_Keywords")) + attached_here = False + for domain_id in resolved: + for type_id in keywords: + record = records.get((domain_id, type_id)) + if record is not None: + attached_here = True + if isinstance(bo_id, str) and bo_id not in record["source_bo_ids"]: + record["source_bo_ids"].append(bo_id) + record["source_bo_ids"].sort() + if attached_here: + bo_attached.append(bo_id if isinstance(bo_id, str) else "") + else: + # 부착 실패는 침묵 금지(L0-7b ③). + review(REVIEW_BO_UNATTACHED, "HARD_WARNING", None, { + "bo_id": bo_id, "source_domain": source_domain, + "legal_keywords": keywords, "resolved_domains": resolved, + }) + bo_unattached.append({"bo_id": bo_id, "reason": "no_matching_structure"}) + + # ---------------- 정렬 · 검토 재료 반영 · 산출 ---------------- + ordered = sorted(records.values(), + key=lambda record: (record["order_key"][0] if isinstance( + record["order_key"][0], int) else 999, + record["order_key"][1], record["order_key"][2])) + for record in ordered: + record["route_count"] = len(record["routes"]) + record["routes"].sort(key=lambda ref: (str(ref.get("signal_id")), + str(ref.get("source_seed_id")))) + record["review_codes"].sort() + if record["review_codes"]: + record["review_required"] = True + + status = "READY_WITH_REVIEW" if review_items else "READY" + bundle = { + "schema_version": SCHEMA_VERSION, + "status": status, + "registry_version": index_root.get("registry_version"), + "expected_runnable_domain_ids": list(expected_runnable), + "theta": theta, + "structure_records": ordered, + "unattached_routes": sorted(unattached_routes, + key=lambda row: (str(row.get("signal_id")), + str(row.get("type_id")))), + "unattached_bo": sorted(bo_unattached, key=lambda row: str(row.get("bo_id"))), + "counts": { + "structure_records": len(ordered), + "declared_structure_types_total": sum( + len(rows) for rows in declared_by_domain.values()), + "sg13_route_total": len(routes), + "routes_attached": attached_route_count, + "routes_unattached": len(unattached_routes), + "bo_total": len(bo_rows), + "bo_attached": len(bo_attached), + "bo_unattached": len(bo_unattached), + "sg11_total": len(sg11_rows), + "sg11_linked": len(linked_sg11), + "sg11_unlinked": len(audit["unlinked_sg11"]), + }, + "created_by": "Task_C_LE_L0_structure_seed_reducer", + } + return {"structure_seed_bundle": bundle, "review_items": review_items, "audit": audit} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/stage1_runtime/structure_index_policy.v1.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/stage1_runtime/structure_index_policy.v1.json new file mode 100644 index 00000000..a96ac883 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/Default_Agent/stage1_runtime/structure_index_policy.v1.json @@ -0,0 +1,98 @@ +{ + "schema_version": "stage1_structure_index_policy.v1", + "status": "ACTIVE", + "purpose": "Part 3 구조 seed 조립·색인 규칙을 코드 밖에 선언한다. 값의 정본은 registry(domain_config.structure_types)이고, registry 가 말하지 않는 값은 만들지 않고 검토로 올린다. 선언의 목적문은 적대 검증의 오라클이다.", + "authority": { + "theta_source": "SG-01 domain_activation_manifest.expected_runnable_domain_ids", + "structure_type_source": "Default_Agent/domains//domain_config.json#structure_types", + "sidecar_source": "Default_Agent/domains//structure_types.json · module_role_projection.json", + "alias_source": "Default_Agent/routing/extension_payload_key_declarations.v1.json#legacy_alias_targets", + "case_kind_names_forbidden": true + }, + "theta_definition": { + "formula": "Θ(사건) = ⋃ { domain_config(d).structure_types[].type_id | d ∈ expected_runnable_domain_ids }", + "note": "active_domain_ids 가 아니다(D-3 넓은 정의). 좁히면 감시·상시 도메인의 효과가 전부 검토로 쓸려 들어가고 커버리지 등식은 그래도 통과한다 — 조용히 틀리는 경로다." + }, + "record_identity": { + "rule": "구조 레코드는 Θ 의 (도메인, type_id) 쌍마다 정확히 하나다. 도메인 간에 유형을 합치지 않는다.", + "structure_id": "LES--", + "note": "SG-13 route·BO 부착은 레코드 위에 붙는 근거이지 레코드 생성 주체가 아니다. 근거 없는 유형은 '선언됐으나 근거 없음'으로 보이고, 선언 0 도메인(EC-00)은 자연히 0 이다." + }, + "total_order": { + "order_key": [ + "그 도메인이 선언한 priority_rank", + "domains/_registry_index.json entries[] 의 도메인 위치", + "type_id" + ], + "note": "min(rank) 병합 금지 — 도메인 내부 rank 는 26/26 전부 엄격 오름차순이라 이 3키가 각 도메인의 선언 순서를 보존한다." + }, + "admission_policy": { + "definition": "두 단 — 그 도메인 사이드카의 파일 단위 정책 키(admission_rules · unregistered_effect_policy · fallback_policy 중 있는 것, 값 'file:<키>') → 없으면 항목 단위 admission_rule(값 'item:admission_rule') → 어느 단도 없으면 'absent'.", + "note": "admission_rule 은 entries 방언 13건에만 있는 선택 필드다 — 게이트 기준으로 쓰지 않는다. 원본 보존을 위해 있는 것만 admission_rule 필드로 함께 싣는다." + }, + "fallback_policy": { + "silent_general_legal_effect_fallback_forbidden": true, + "rule": "빈 입력은 structure_count 0 으로 기록한다. Θ 밖·registered:false 유형은 버리지도 일반화하지도 않고 UNREGISTERED_EFFECT_TYPE_REVIEW 를 붙인다. 사이드카 default_projection 이 있으면 그 투영을 검토 항목에 실어 나르되 검토 코드를 반드시 동반한다." + }, + "attachment_partition": { + "rule": "route 의 분할은 부착 여부로만 가른다 — 붙은(어떤 레코드에 근거로 실림) / 미부착(어느 레코드에도 닿지 못함). 검토 여부는 분할과 무관하다. registered:false 라도 type_id 가 Θ 안·선언 도메인이 있으면 붙은 채로 검토 꼬리표를 단다(이중 계상 금지)." + }, + "bo_attachment": { + "alias_resolution": "provenance.source_domain 이 registry 도메인 ID 면 [그 값], 아니면 legacy_alias_targets[값] 목록(다중 타깃 실재 — 단일 primary 개념 없음), 어디에도 없으면 PART3_BO_DOMAIN_UNRESOLVED 검토로 격리.", + "join": "해소된 모든 도메인 d 에 대해 t ∈ BO.Legal_Keywords 인 구조 레코드 (d, t) 에 source_bo_ids 로 부착을 시도한다.", + "silence_forbidden": "Legal_Keywords 가 비었거나 어느 (d, t) 에도 닿지 않는 BO 는 PART3_BO_UNATTACHED 검토로 싣는다.", + "purpose": "원본 review_code 와 마찬가지로 — BO 연결을 잃지 않기 위해서다. SG 층의 source_bo_ids 가 비어 있어도 이 조인이 BO↔구조 연결을 세운다." + }, + "sg11_join": { + "key": "SG-11 레코드의 signal_id (worker request_id 승계값 — details.request_id 는 보장되지 않는 키라 쓰지 않는다)", + "counterpart": "domain_signal_envelope.calculation_refs", + "unlinked_rule": "봉투 참조에 연결되지 않은 SG-11 레코드는 구조에 싣지 않되 영수증에 미연결 계수로 형식화 기록한다.", + "dangling_rule": "봉투에 있는데 SG-11 에 없는 참조는 PART3_CALCULATION_REF_DANGLING 검토." + }, + "extension_key_rule": { + "domain_id": "E-13", + "extension_key": "actio_case_signals.v2", + "note": "별도 매핑표를 만들지 않는다 — s5_execution_contract.v2.json 의 e13_extension_domains 선언을 그대로 싣는다." + }, + "conservation_equations": { + "declaration": "구조 레코드 수 == Σ(expected_runnable 도메인의 structure_types 개수) — 어긋나면 PART3_STRUCTURE_COUNT_BROKEN", + "route": "붙은 route 수 + 미부착 route 수 == SG-13 legal_effect_route 총수 — 어긋나면 PART3_ROUTE_CONSERVATION_BROKEN", + "bo": "부착 BO 수 + 미부착 BO 수 == BO.json 레코드 총수 — 어긋나면 PART3_BO_CONSERVATION_BROKEN", + "note": "세 등식 다 L2 가 원본 파일(domain_config · legal_effect_routes · BO.json)에서 직접 센 바깥 수와 비교한다. bundle 에 실린 수와 비교하면 항등식으로 퇴행한다." + }, + "structure_index": { + "indexes": [ + "by_domain_id", + "by_module", + "by_bo_id" + ], + "by_claim_form_forbidden": "claim-form 어휘가 registry 에 없고 (module, role_projection) 은 type_id 와 일대일이라 색인이 되지 못한다. 필요하면 registry 에 어휘를 새로 선언하는 일이며 Part 3 범위 밖이다." + }, + "review_codes": [ + "UNREGISTERED_EFFECT_TYPE_REVIEW", + "PART3_SLICE_PROJECTION_DIVERGENCE", + "PART3_REGISTRY_SIDECAR_MISMATCH", + "PART3_EFFECT_TYPE_CROSS_DOMAIN", + "PART3_CALCULATION_REF_DANGLING", + "PART3_BO_UNATTACHED", + "PART3_BO_DOMAIN_UNRESOLVED" + ], + "hard_error_codes": [ + "PART3_ASSET_DEPLOYMENT_INCOMPLETE", + "PART3_POLICY_INVALID", + "PART3_STRUCTURE_SCHEMA_STALE", + "PART3_COMPILER_STALE", + "PART3_INDEX_SCHEMA_STALE", + "PART3_SIGNAL_SEAL_FAILED", + "PART3_REGISTRY_INDEX_SEAL_FAILED", + "PART3_DOMAIN_NOT_IN_REGISTRY", + "PART3_STRUCTURE_COUNT_BROKEN", + "PART3_ROUTE_CONSERVATION_BROKEN", + "PART3_BO_CONSERVATION_BROKEN", + "PART3_FINAL_SCHEMA_VALIDATION_FAILED", + "PART3_EXPECTED_RUNNABLE_EMPTY", + "PART3_SIDECAR_ABSENT_FOR_DECLARING_DOMAIN" + ], + "e00_rule": "E-00(잔여 수집기)에서 온 구조 레코드는 review_required true 를 강제한다.", + "sidecar_absence_rule": "structure_types 선언이 0 인 도메인(오늘 EC-00 하나)의 사이드카 부재는 정상 — 스킵하고 영수증에 기록한다. 선언이 있는 도메인의 부재·미등재는 경성 실패다." +} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/stage_1_part_3_개정작업내역서.md b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/stage_1_part_3_개정작업내역서.md new file mode 100644 index 00000000..82a4385e --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/stage_1_part_3_개정작업내역서.md @@ -0,0 +1,58 @@ +# Stage 1 — Part 3 개정 작업 내역서 + +- 문서 판본: v1 (2026-08-19) +- 지시 원문: `stage_1_part_3_개정_신전략서.md` (§3 입력 계약 · §4 작업 명세 · §5 자산 · §6 실행 단계 · §7 검증 · §10 완료 판정) +- 판정 기준(완수): 실행 완주가 아니라 **의도한 결과물이 올바른 방식으로 생성 + 소작업 간 upstream–downstream consistency 유지**. +- P3-0a(D-4 승인): 사용자의 "신전략서를 실행하라"는 지시를 승인으로 처리하고 착수했다. +- 결과: **§4·§5 처방 전건 반영 + 회귀 22종 및 보충 실측 2종 전건 통과 + 적대적 sub-agent 검증 2라운드(1차 지적 5건 전부 반영 · 재검증 "지적 0건")** — Part 3 는 예행 전 사슬(3패스 11단계)에서 완수 기준을 충족했다. + +--- + +## 0. 요약 + +Part 3 작업명세서를 **registry 와 Part 1·2 실산출 계약만으로 새로 지었다**(구 Part 3 v2 무참조 — 제약 1). task 는 둘이다: `Task_C_LE_L0_structure_seed_reducer`(Θ 조립 → 구조 레코드 → SG-13·SG-11·BO 조인 → 검토) → `Task_C_LE_L2_final_structure_index_writer`(보존 등식 셋 → 역인덱스 셋 → 최종 기록). **L1 은 두지 않았다** — LLM 이 판정할 예외 부류가 없다(신전략서 §4.1). 조립·판정 로직은 신설 모듈 `structure_index_compiler` 에 있고 YAML 은 반입·게이트·봉인·기록만 한다. + +가장 중요한 실측: **예행 전 사슬에서 `legal_effect_structures.json` 이 실제로 선다** — Θ 4종 · 구조 레코드 6건(레코드는 (도메인, type_id) 쌍마다 하나) · SG-13 route 6/6 부착 · **BO 2/2 부착**(`provenance.source_domain` + `Legal_Keywords` 결정론 조인 — SG 층의 `source_bo_ids` 가 비어 있어도 BO↔구조 연결이 섬) · 보존 등식 셋 전부 성립(바깥 수는 L2 가 원본에서 직접 계수) · 역인덱스 셋(`by_domain_id` · `by_module` · `by_bo_id`). 26 도메인 합성 실측은 **Θ 56종 · 구조 73건 · module 34종 · 결정론**이다. + +## 1. 작업 분류 (method 1) + +**병렬(독립) 수행분** — 서로 파일이 겹치지 않음: 정책 자산 작성 · 스키마 2종 작성 · 컴파일러 모듈 작성 · 사이드카 50 복사. +**순차 수행분** — 상하류 의존: 매니페스트 등재(자산 확정 후, 원자적 1회) → L0/L2 yaml 조각 → 통합본 병합 → 선언표·stage_chain·상위 전략서 → 예행 3패스 → 회귀 → 검증 루프 → 내역서. + +## 2. 산출물 목록 + +| 파일 | 상태 | +| --- | --- | +| `ver_8_yaml_candidates/stage_1_part_3_v.8.yml` | **신규** (52,878 B · task 2 · `IN→L0→L2→OUT` · 선언 1벌) | +| `ver_8_yaml_candidates/P3-L0_structure_seed_reducer_v1.yml` · `P3-L2_final_structure_index_writer_v1.yml` | **신규** 조각 (통합본과 블록 동일) | +| `Default_Agent/stage1_runtime/structure_index_compiler.py` + `.txt` | **신규** (순수 모듈 — I/O·시각·난수 없음. 방언 3·3 정규화 리더 · Θ · 전순서 · 조인 · 검토) | +| `Default_Agent/stage1_runtime/structure_index_policy.v1.json` | **신규** (`stage1_structure_index_policy.v1` — Θ 정의 · 3키 전순서 · admission 2단 · 부착 분할 · BO 조인 · SG-11 키 · 등식 셋 · 코드 목록. 검증 오라클) | +| `Default_Agent/platform/schemas/structure_seed_bundle.schema.json` · `legal_effect_structures.schema.json` | **신규** (파일명 무판본 · 열거 하드코딩 없이 패턴 3종만) | +| `Default_Agent/domains//structure_types.json` · `module_role_projection.json` ×25 | **복사 배포** (조립본과 50/50 바이트 동일) | +| `Default_Agent/runtime_manifest.json` | 갱신 (**371 → 426** · 델타 정확히 55 · 기존 행 수정 0 · 왕복 보존) | +| `선행구축/.../handoffs/stage1_part_interface.v1.json` | 갱신 (신규 11줄 + 기존 갱신 — `handoff_count` 34→**45** · C-7 구 이름 3종 Part 3 소비자 제거 · C-8 `client_goal` 등재·`client_meeting` 소비자 · compact 직렬화 보존) | +| `선행구축/.../handoffs/stage1_stage_chain.v1.json` | 갱신 (Part 3 구간 — yaml·requires·produces·이관 완료 note) | +| `stage_1_update_strategy.md` | 갱신 두 곳 (§1 사슬 `S0→L0→L2` · §4.2 L1 부재 주석) | +| 예행 증거 | `/tmp/dry_p3/` (3패스 산출 전부) · 회귀 결과 scratchpad `part3_regression_results.json` | + +배포 트리 최종 210 파일(155+55) · 매니페스트 등재-실물(트리 실재 149건) 전수 해시 일치 · `__pycache__` 0. + +## 3. 검증 (method 3) + +**정적** — yaml parse PASS · 선언 1벌 · AST 미정의 이름 0 · 개별↔통합 블록 동일 · 비주석 금지어(Claude_YAML·구 signal 이름·case_kind matrix·조립본 경로) 0 · code-executor parameters 5키 · 선언표 검사기 **finding 0**(3 yaml 전수). + +**예행 3패스** (asset root = 배포 원본 `extension_research/Default_Agent` · 실행 루트 신선): pass1 PASS 6단계/45건 · seed 대역 3건 · pass2 PASS 3단계/29건 · **pass3 PASS 2단계/5건**. 산출 실측 — 최종 status READY · 봉인 승계(`S5TX-…`) · 레코드 6 · 게이트 3 전부 pass · handoff FINALIZED · 영수증(게이트 10 자산/실측·봉인 둘·조인 계수·SG-02/07 공백 형식화·사이드카 방언 지도·BO sha·전순서표). + +**회귀 22종(L-a~L-s) + 보충 2종 = 24/24 PASS.** 필수 8종(L-b·b2·c·d2·k·m2·p·q) 포함 전건 기대대로 발화. 변조는 전부 사본 트리/실행 루트에서 수행(배포 원본 무변). 보충: SUPP-synth26(Θ56·73·34·머리 4줄·결정론) · SUPP-calc-probe(정상 조인·dangling 검토·미연결 형식화). + +**적대적 sub-agent 2라운드**: 1차 지적 5건(MAJOR 2 — ① 선언표 `handoffs` 배열의 `client_meeting` 행 미갱신(중복 행 절반만 반영) ② 도메인 봉투 부재의 침묵 스킵(영수증 계수 부재) / MINOR 3 — L2 의 계약 밖 `signal_manifest` 읽기 · 합성/탐침 증적 미보존 · `Stage_1.Part_3` 약칭 잔존) — **전부 반영**(봉투 부재는 `audit.input_gaps` 기록 + L-k 단언, transaction_id 는 L0 가 bundle 에 부착해 L2 가 승계). 재검증: **"지적 0건"**(반영 5 + 파급 12 = 17건 실측 전건 통과). + +## 4. 한계 (정직 선언) + +- 예행은 LLM 대역 기반이다 — 실체 도메인 활성·실서버 실행은 범위 밖(행동 검증 **미측정** 명시, 신전략서 §7.1). +- 예행 Θ 는 4종에 그치므로 26 도메인 합성·계산 조인 탐침으로 따로 실측했다(§7.3 처방 그대로). +- P3-2 의 "정책·스키마 자기 검증" 별도 기록은 남기지 않았다 — 예행에서 두 스키마가 실주입 검증됐고(L0·L2 닫힌 스키마 통과) 회귀 L-b/L-b2 가 스키마 능력 검사의 발화를 실증한다. + +## 5. 이월 (조립본 동기화 회차 — 신전략서 §6.1) + +① Part 3 신설 자산 5종(+미러)·사이드카 등재의 조립본 반영 + 빌더 `PART3_ASSEMBLY_AUTHORED` 등록 + 사이드카 sweep 규칙(파일 반영과 등록은 한 벌) ② `release_manifest`·`source_copy_map` 재생성 ③ 신선 빌드의 Part 3 자산 재현 확인 ④ `dry_run_receipt` 정본화(Part 2 M-* + Part 3 L-* 합본) ⑤ `effect_projection.schema_ref` dangling 해소(registry 소유자). Part 2 의 D-1~D-6 과 한 벌로 처리한다. Part 3 실행 정합성 무영향은 배포 원본 단독 예행 전 사슬로 실증돼 있다. diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/stage_1_update_strategy.md b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/stage_1_update_strategy.md index 59577bd0..01f68846 100644 --- a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/stage_1_update_strategy.md +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/stage_1_update_strategy.md @@ -173,7 +173,7 @@ signal 파일명은 다음과 같다. SG-01 `domain_activation_manifest.json`, S └─▶ Fact_Ledger_base.json + writer report ──▶ Stage 2 의존: T0→{T1,D0} · {T5,T6,T8}→D0 · D0→T9 · T9→A0 · fanout_plan→B*→R0→R1→F0→S0 - S0→L0→L1→L2→P4-F0→F1→F2 + S0→L0→L2→P4-F0→F1→F2 (L1 은 두지 않는다 — stage_1_part_3_개정_신전략서.md §4.1) ``` LLM 호출 구조: Part 1은 스크리너 1 + Task_A 1 + 매퍼 2N + 조건부 판정(대개 즉시 종료). Part 2는 worker M개 + 조건부 판정. Part 3·4는 조건부 판정만. 순증 비용은 스크리너 1회와 활성 도메인 증가분이며, 상시 도메인과 감시 도메인은 낮은 등급 모델로 돈다. @@ -287,7 +287,7 @@ signal마다 받아들이는 조건이 registry에 선언되어 있으므로 그 ### 4.2 P3-L1 예외 판정 -무변경이다. 허용 결정 목록과 후보값 부분집합 규율을 유지하고, 예외 묶음에 동적 열거 목록이 동봉될 뿐이다. +(개정 실행에서 L1 은 두지 않는 것으로 확정됐다 — LLM 이 판정할 예외 부류가 없다. 되돌림 경로와 근거는 `stage_1_part_3_개정_신전략서.md` §4.1. 아래 원문은 기록으로 남긴다.) 무변경이다. 허용 결정 목록과 후보값 부분집합 규율을 유지하고, 예외 묶음에 동적 열거 목록이 동봉될 뿐이다. ### 4.3 P3-L2 최종 색인 기록 [개정] diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/ver_8_yaml_candidates/P3-L0_structure_seed_reducer_v1.yml b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/ver_8_yaml_candidates/P3-L0_structure_seed_reducer_v1.yml new file mode 100644 index 00000000..ac25d64a --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/ver_8_yaml_candidates/P3-L0_structure_seed_reducer_v1.yml @@ -0,0 +1,567 @@ +# ============================================================================= +# P3-L0 / Task_C_LE_L0_structure_seed_reducer — v1 (신설) +# +# 정본 근거 : stage_1_part_3_개정_신전략서.md §4.2 (L0-1 ~ L0-8) · §3 (I-1 ~ I-14) · §5 +# 계약 : Θ = SG-01.expected_runnable_domain_ids 의 domain_config.structure_types 합집합 +# 구조 레코드 = (도메인, type_id) 쌍마다 하나 · order_key 3키 전순서 +# 조립·판정 로직은 stage1_runtime/structure_index_compiler 모듈에 있다. +# 이 task 는 자산 반입 → 게이트 → 봉인 → 적재 → 모듈 호출 → 기록만 한다. +# 제약 1 : v.7/Claude_YAML 의 어떤 파일도 읽지 않는다. 구 Part 3 에 의존하지 않는다. +# 137종 : 사건 이름·도메인 목록·유형 열거를 코드에 두지 않는다. +# ============================================================================= + - task_name: Task_C_LE_L0_structure_seed_reducer + mcp: code-executor + tool_name: run_code + parameters: + language: python + requirements: "httpx" + network: "agent-network" + timeout: 240 + code: |- + #!/usr/bin/env python3 + # Task_C_LE_L0_structure_seed_reducer (v1) + # 0) 배포 게이트 -> 1) 모듈 반입 -> 2) 정책 반입 -> 3) 의미 검사 둘 -> + # 4) 진입 봉인 둘 -> 5) 입력 적재 -> 6) compile_structure_seeds -> + # 7) bundle · review handoff · receipt 기록 + import contextlib + import hashlib + import io + import itertools + import json + import pathlib + import re + import sys + + import httpx + + # ------------------------------------------------------------------ + # localdocs 보일러플레이트 (SKILL.md 5장 / 5.2장) — Part 2 A0 검증 완료본 복사. + # clientInfo 에 {{__user_hash__}} / {{__workspace_hash__}} 를 반드시 넣는다. + # ------------------------------------------------------------------ + TASK_NAME = "Task_C_LE_L0_structure_seed_reducer" + LOCALDOCS_URL = "http://mcp-localdocs:8012/mcp" + MCP_HEADERS = {"Content-Type": "application/json", + "Accept": "application/json, text/event-stream"} + CLIENT = httpx.Client(timeout=120) + MSG_ID_COUNTER = itertools.count(10) + + + def next_msg_id(): + return next(MSG_ID_COUNTER) + + + def _init(): + r = CLIENT.post(LOCALDOCS_URL, json={ + "jsonrpc": "2.0", "id": 1, "method": "initialize", + "params": {"protocolVersion": "2025-03-26", "capabilities": {}, + "clientInfo": {"name": TASK_NAME, "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): + for line in text.strip().split("\n"): + if line.startswith("data: "): + try: + return json.loads(line[6:]) + except Exception: + return None + try: + return json.loads(text) + except Exception: + return None + + + def _call(name, args, mid): + 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() + p = _parse_mcp(r.text) + if not p or "result" not in p: + raise RuntimeError("MCP_CALL_FAILED:%s" % name) + return p + + + def read_raw(name): + # 재직렬화 없이 원문 그대로. 봉인·미러 해시 대조의 전제다. + p = _call("read_docs", {"doc_names": [name]}, next_msg_id()) + 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) + + + def read_json(name): + raw = read_raw(name) + s = raw.strip() + try: + return json.loads(s) + except json.JSONDecodeError: + obj, _ = json.JSONDecoder().raw_decode(s) + return obj + + + def try_read_json(name): + try: + return read_json(name) + except Exception: + return None + + + def write_doc(path, content): + _call("write_file", {"path": path, "content": content, "overwrite": True}, + next_msg_id()) + + # ------------------------------------------------------------------ + # 실행 뿌리 — /tmp/s1 공유(신전략서 §4.2 도입부. 새 뿌리를 만들지 않는다). + # ------------------------------------------------------------------ + ASSET_ROOT = "Default_Agent/" + EXECUTION_ROOT = "/tmp/s1" + RT = pathlib.Path(EXECUTION_ROOT) / "_rt" + + MODULE_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", + "structure_index_compiler": "Default_Agent/stage1_runtime/structure_index_compiler.txt", + } + MODULES = ["runtime_common", "schema_subset_validator", "registry_loader", + "structure_index_compiler"] + RUNTIME_MANIFEST = "Default_Agent/runtime_manifest.json" + RUNTIME_MANIFEST_SCHEMA = "stage1_runtime_manifest.v1" + + # 정적 자산 (I-9 ~ I-14) + REGISTRY_INDEX = "Default_Agent/domains/_registry_index.json" + POLICY = "Default_Agent/stage1_runtime/structure_index_policy.v1.json" + POLICY_SCHEMA_VERSION = "stage1_structure_index_policy.v1" + ALIAS_DECLARATIONS = "Default_Agent/routing/extension_payload_key_declarations.v1.json" + SEED_SCHEMA = "Default_Agent/platform/schemas/structure_seed_bundle.schema.json" + INDEX_SCHEMA = "Default_Agent/platform/schemas/legal_effect_structures.schema.json" + + # 사건 산출물 (I-1 ~ I-8) — Part 1·2 가 낸 것만 읽는다. + SIGNAL_MANIFEST = "signals/signal_manifest.json" + SG13_PATH = "signals/legal_effect_routes.json" + SG05_PATH = "signals/legal_relation_lifecycle_signals.json" + SG11_PATH = "signals/calculation_requirements.json" + SG02_PATH = "signals/procedural_posture_relief_signals.json" + SG07_PATH = "signals/asset_right_state_signals.json" + DOMAIN_SIGNAL_DIR = "signals/domain_signals" + ACTIVATION_MANIFEST = "routing/domain_activation_manifest.json" + BO_PATH = "BO.json" + SLICE_DIR = "runtime/domain_slices" + + # 산출 + BUNDLE_PATH = "stage1_tmp/task_le/structure_seed_bundle.json" + HANDOFF_PATH = "quality_gates/stage1_part3_review_handoff.json" + RECEIPT_PATH = "validation_assets/routing/part3_receipt.json" + + # F-2 상당 — 배포 게이트가 한 벌로 검사하는 필수 자산 10 리터럴(신전략서 §5.5). + # 사이드카 50 은 여기 넣지 않는다 — expected_runnable 도메인 것만 읽는 시점에 + # _verify_asset 으로 지킨다. domains/_registry_index.json 은 매니페스트 등재 + # 대상이 아니므로 SG-01 봉인이 지킨다(I-11 · §1.10 규율). + PART3_REQUIRED_ASSETS = ( + SEED_SCHEMA, + INDEX_SCHEMA, + POLICY, + ALIAS_DECLARATIONS, + "Default_Agent/signals/signal_registry.v2.json", + "Default_Agent/contracts/signals/s5_execution_contract.v2.json", + "Default_Agent/stage1_runtime/structure_index_compiler.txt", + "Default_Agent/stage1_runtime/runtime_common.txt", + "Default_Agent/stage1_runtime/schema_subset_validator.txt", + "Default_Agent/stage1_runtime/registry_loader.txt", + ) + PART3_DEPLOYMENT_REMEDY = ( + "배포 원본 extension_research/Default_Agent 트리를 서버 Default_Agent/ 에 통째로 배포하고 " + "runtime_manifest.json 의 등재·sha256 과 대조해 결손 경로를 복원한다. 부분 복사는 허용되지 않는다.") + + TRANSACTION_ID_RE = re.compile(r"^S5TX-[a-f0-9]{20}$") + + ERRORS = [] + WARNINGS = [] + + + def sha_text(text): + return hashlib.sha256(text.encode("utf-8")).hexdigest() + + + def canonical(value): + return json.dumps(value, ensure_ascii=False, sort_keys=True, + separators=(",", ":")) + "\n" + + + # ------------------------------------------------------------------ + # 0) 배포 게이트 — 등재·sha256·가독을 한 벌로. 첫 실패에서 멈추지 않고 모은다. + # ------------------------------------------------------------------ + def assert_deployment(): + manifest = json.loads(read_raw(RUNTIME_MANIFEST)) + if manifest.get("schema_version") != RUNTIME_MANIFEST_SCHEMA: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_RUNTIME_MANIFEST_INVALID", "detail": "schema_version", + "expected": RUNTIME_MANIFEST_SCHEMA, "actual": manifest.get("schema_version"), + }, ensure_ascii=False)) + expected = {row["path"]: row["sha256"] + for row in (manifest.get("entries") or []) if isinstance(row, dict)} + unregistered, mismatch, unreadable = [], [], [] + for logical in sorted(set(list(MODULE_MIRRORS.values()) + list(PART3_REQUIRED_ASSETS))): + rel = logical[len(ASSET_ROOT):] + want = expected.get(rel) + if want is None: + unregistered.append(rel) + try: + body = read_raw(logical) + except Exception: + unreadable.append(rel) + continue + if want is not None and want != sha_text(body): + mismatch.append({"path": rel, "expected": want, "actual": sha_text(body)}) + if unregistered or mismatch or unreadable: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_ASSET_DEPLOYMENT_INCOMPLETE", + "message": "배포 원본에 Part 3 자산이 한 벌로 반영되지 않았다.", + "unregistered": unregistered, "hash_mismatch": mismatch, + "unreadable": unreadable, "remedy": PART3_DEPLOYMENT_REMEDY, + }, ensure_ascii=False)) + return manifest + + + _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": "PART3_ASSET_DEPLOYMENT_INCOMPLETE", "path": logical, + "detail": detail, "remedy": PART3_DEPLOYMENT_REMEDY} + if extra: + payload.update(extra) + return RuntimeError(json.dumps(payload, ensure_ascii=False)) + + + def _verify_asset(logical): + """원문을 돌려준다. 등재·해시 대조를 통과해야만 소비된다.""" + body = read_raw(logical) + want = _manifest_map().get(logical[len(ASSET_ROOT):]) + if want is None: + raise _deployment_error(logical, "unregistered") + if want != sha_text(body): + raise _deployment_error(logical, "hash_mismatch", {"expected": want}) + return body + + + # ------------------------------------------------------------------ + # 1) 모듈 반입 — R-1~R-5. + # ------------------------------------------------------------------ + def materialize_modules(): + RT.mkdir(parents=True, exist_ok=True) + expected = _manifest_map() + staged = [] + for name in MODULES: + logical = MODULE_MIRRORS[name] + raw = read_raw(logical).encode("utf-8") + want = expected.get(logical[len(ASSET_ROOT):]) + 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 + + + # ------------------------------------------------------------------ + # 3) 의미 검사 — 장부 검사만으로는 닫히지 않는다(Part 2 R-b/R-g2 교훈). + # 각 검사는 자기가 쓰는 산출물의 스키마만 본다. by_module 은 L2 몫이다. + # ------------------------------------------------------------------ + def assert_seed_schema_capability(seed_schema): + bundle_props = (((seed_schema.get("properties") or {}) + .get("structure_seed_bundle") or {}).get("properties") or {}) + record_props = ((((bundle_props.get("structure_records") or {}) + .get("items") or {}).get("properties") or {})) + missing = [] + if "theta" not in bundle_props: + missing.append("theta") + if "admission_policy" not in record_props: + missing.append("structure_records[].admission_policy") + if missing: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_STRUCTURE_SCHEMA_STALE", + "message": "seed 스키마가 Part 3 계약 필드를 모른다. 배포 원본의 스키마가 개정 전 판본이다.", + "missing": missing, "remedy": PART3_DEPLOYMENT_REMEDY, + }, ensure_ascii=False)) + + + def assert_compiler_capability(result): + bundle = (result or {}).get("structure_seed_bundle") or {} + records = bundle.get("structure_records") + bad = ("theta" not in bundle + or not isinstance(records, list) + or any("order_key" not in record for record in records + if isinstance(record, dict))) + if bad: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_COMPILER_STALE", + "message": "컴파일러 산출에 theta·order_key 가 실려 나오지 않는다. " + "배포 원본의 structure_index_compiler 가 개정 전 판본이다.", + "remedy": PART3_DEPLOYMENT_REMEDY, + }, ensure_ascii=False)) + + + # ------------------------------------------------------------------ + # 4) 진입 봉인 둘 (신전략서 §4.2-5) + # ------------------------------------------------------------------ + def verify_signal_seal(): + doc = read_json(SIGNAL_MANIFEST) + root = doc.get("signal_manifest", doc) if isinstance(doc, dict) else {} + transaction_id = root.get("transaction_id") + if not isinstance(transaction_id, str) or not TRANSACTION_ID_RE.match(transaction_id): + raise RuntimeError(json.dumps({ + "reason_code": "PART3_SIGNAL_SEAL_FAILED", "detail": "transaction_id", + "actual": transaction_id}, ensure_ascii=False)) + checked = 0 + for row in root.get("files") or []: + if not isinstance(row, dict): + continue + # files[].path 에는 signals/ 접두사가 없다(I-1 주의). 붙여서 대조한다. + rel = str(row.get("path") or "") + actual = sha_text(read_raw("signals/" + rel)) + if actual != row.get("file_sha256"): + raise RuntimeError(json.dumps({ + "reason_code": "PART3_SIGNAL_SEAL_FAILED", "detail": "file_sha256", + "path": rel, "expected": row.get("file_sha256"), "actual": actual, + }, ensure_ascii=False)) + checked += 1 + return {"transaction_id": transaction_id, "files_checked": checked, "root": root} + + + def verify_registry_index_seal(activation_root, index_raw): + declared = activation_root.get("registry_index_sha256") + actual = sha_text(index_raw) + if declared != actual: + # 전순서 둘째 키가 이 색인의 배열 위치에 걸려 있다. 매니페스트 등재 대상이 + # 아니므로 이 봉인만이 색인 교체를 잡는다(L-d2). + raise RuntimeError(json.dumps({ + "reason_code": "PART3_REGISTRY_INDEX_SEAL_FAILED", + "declared": declared, "actual": actual}, ensure_ascii=False)) + return actual + + + def main(): + gate_manifest = assert_deployment() + staged = materialize_modules() + import structure_index_compiler + + # 2) 정책 반입 — 판본 불일치는 PART3_POLICY_INVALID. + policy = json.loads(_verify_asset(POLICY)) + if policy.get("schema_version") != POLICY_SCHEMA_VERSION: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_POLICY_INVALID", + "expected": POLICY_SCHEMA_VERSION, + "actual": policy.get("schema_version")}, ensure_ascii=False)) + + # 3) 의미 검사 (입력 쪽) + seed_schema = json.loads(_verify_asset(SEED_SCHEMA)) + assert_seed_schema_capability(seed_schema) + + # 4) 진입 봉인 둘 + seal = verify_signal_seal() + activation_doc = read_json(ACTIVATION_MANIFEST) + activation_root = activation_doc.get("domain_activation_manifest", activation_doc) + index_raw = read_raw(REGISTRY_INDEX) + registry_index_sha = verify_registry_index_seal(activation_root, index_raw) + registry_index = json.loads(index_raw) + index_root = registry_index.get("domain_registry_index", registry_index) + + expected_runnable = [d for d in (activation_root.get("expected_runnable_domain_ids") or []) + if isinstance(d, str)] + + # 5) 입력 적재 + # I-9 domain_config — 무결성은 SG-01 봉인 -> _registry_index -> config_sha256 사슬. + config_sha = {row.get("domain_id"): row.get("config_sha256") + for row in (index_root.get("entries") or []) if isinstance(row, dict)} + domain_configs = {} + domain_sidecars = {} + for domain_id in expected_runnable: + raw = read_raw("Default_Agent/domains/%s/domain_config.json" % domain_id) + if config_sha.get(domain_id) and sha_text(raw) != config_sha[domain_id]: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_REGISTRY_INDEX_SEAL_FAILED", + "detail": "config_sha256", "domain_id": domain_id}, ensure_ascii=False)) + config = json.loads(raw) + domain_configs[domain_id] = config + config_root = config.get("domain_config", config) + declared = [row for row in (config_root.get("structure_types") or []) + if isinstance(row, dict)] + if declared: + # 사이드카 부재 규칙(§5.5) — 선언 있는 도메인의 부재·미등재는 경성 실패. + domain_sidecars[domain_id] = { + "structure_types": json.loads(_verify_asset( + "Default_Agent/domains/%s/structure_types.json" % domain_id)), + "module_role_projection": json.loads(_verify_asset( + "Default_Agent/domains/%s/module_role_projection.json" % domain_id)), + } + + alias_declarations = json.loads(_verify_asset(ALIAS_DECLARATIONS)) + + def records_of(doc): + if not isinstance(doc, dict): + return [] + return [row for row in (doc.get("records") or []) if isinstance(row, dict)] + + # 경로 상수를 read_json 에 직접 넘긴다 — 선언표 검사기(U4)가 읽기를 코드에서 + # 확인할 수 있는 형태다. 간접 호출로 감싸면 소비 선언이 실측 불가가 된다. + sg13_records = records_of(read_json(SG13_PATH)) + sg05_records = records_of(read_json(SG05_PATH)) + sg11_records = records_of(read_json(SG11_PATH)) + # 읽되 비어 있음을 정상 처리(§3) — 조인 코드를 두지 않고 형식화된 사실로 남긴다. + sg02_rows = records_of(read_json(SG02_PATH)) + sg07_rows = records_of(read_json(SG07_PATH)) + empty_read_set = [ + {"signal_id": "SG-02", "transform": "passthrough", "producer_count": 0, + "record_count": len(sg02_rows), + "reason": "closed schema declares no claim-form vocabulary"}, + {"signal_id": "SG-07", "transform": "passthrough", "producer_count": 0, + "record_count": len(sg07_rows), + "reason": "closed schema declares no claim-form vocabulary"}, + ] + + domain_envelopes = {} + for domain_id in expected_runnable: + doc = try_read_json("%s/%s.json" % (DOMAIN_SIGNAL_DIR, domain_id)) + if doc is not None: + domain_envelopes[domain_id] = doc + + bo_doc = try_read_json(BO_PATH) + bo_records = bo_doc if isinstance(bo_doc, list) else [] + bo_raw = read_raw(BO_PATH) if bo_doc is not None else "" + + slice_documents = {} + for domain_id in expected_runnable: + doc = try_read_json("%s/%s.json" % (SLICE_DIR, domain_id)) + if doc is not None: + slice_documents[domain_id] = doc + + # 6) 모듈 호출 — 판정 규칙을 이 파일에 쓰지 않는다. + try: + result = structure_index_compiler.compile_structure_seeds( + activation_doc, registry_index, domain_configs, domain_sidecars, + policy, alias_declarations, sg13_records, sg05_records, sg11_records, + domain_envelopes, bo_records, slice_documents) + except TypeError as exc: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_COMPILER_STALE", "detail": "signature_mismatch", + "signature_error": str(exc)[:200], + "remedy": PART3_DEPLOYMENT_REMEDY}, ensure_ascii=False)) + assert_compiler_capability(result) + + bundle = result["structure_seed_bundle"] + review_items = result["review_items"] + audit = result["audit"] + # 진입 봉인의 거래 식별자를 bundle 에 부착한다 — L2 는 signal_manifest 를 + # 다시 읽지 않고(§4.3 입력 계약 밖) 이 값을 승계한다. + bundle["signal_manifest_transaction_id"] = seal["transaction_id"] + + # 자기 산출을 닫힌 스키마로 검증한다. + import schema_subset_validator + schema_errors = schema_subset_validator.validate( + {"structure_seed_bundle": bundle}, seed_schema) + if schema_errors: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_FINAL_SCHEMA_VALIDATION_FAILED", + "stage": "L0", "errors": schema_errors[:10]}, ensure_ascii=False)) + + # 7) 기록 — bundle · handoff(OPEN) · receipt(실측값. 상수 PASS 금지). + write_doc(BUNDLE_PATH, canonical({"structure_seed_bundle": bundle})) + write_doc(HANDOFF_PATH, canonical({"stage1_part3_review_handoff": { + "schema_version": "stage1_part3_review_handoff.v1", + "status": "OPEN", + "review_items": review_items, + "counts": {"review_items": len(review_items)}, + "created_by": TASK_NAME, + }})) + order_table = ["%s|%s|%s|%s|%s" % ( + record.get("priority_rank"), record.get("domain_id"), + record.get("type_id"), record.get("module"), + record.get("admission_policy")) + for record in bundle.get("structure_records") or []] + write_doc(RECEIPT_PATH, canonical({ + "schema_version": "stage1_part3_receipt.v1", + "stage": "P3-L0", + "deployment_gate": { + "checked_count": len(set(list(MODULE_MIRRORS.values()) + + list(PART3_REQUIRED_ASSETS))), + "runtime_manifest_sha256": sha_text(read_raw(RUNTIME_MANIFEST)), + "runtime_artifact_count": gate_manifest.get("runtime_artifact_count"), + "schema_capability_checked": ["theta", "structure_records[].admission_policy"], + "compiler_output_checked": ["theta", "structure_records[].order_key"], + "policy_schema_version": policy.get("schema_version"), + "note": "무엇을 봤는지 적는다. 상수 PASS 는 증거가 아니다.", + }, + "entry_seals": { + "signal_manifest_transaction_id": seal["transaction_id"], + "signal_files_checked": seal["files_checked"], + "registry_index_sha256": registry_index_sha, + "config_sha256_chain_checked": len(domain_configs), + }, + "join_counts": bundle.get("counts"), + "empty_read_set_signals": empty_read_set, + "sidecar_dialects": audit.get("sidecar_dialects"), + "unlinked_sg11": audit.get("unlinked_sg11"), + "dangling_calculation_refs": audit.get("dangling_calculation_refs"), + "input_gaps": audit.get("input_gaps"), + "bo_input": {"sha256": sha_text(bo_raw) if bo_raw else None, + "record_count": len(bo_records), + "note": "BO.json 은 무봉인 입력이다 — signal 5종은 I-1 봉인, " + "registry 는 SG-01 봉인이 지키는 비대칭을 관찰로 남긴다."}, + "resolved_order_table": order_table, + "created_by": TASK_NAME, + })) + + return {"status": bundle.get("status"), + "modules": staged, + "expected_runnable_domain_ids": expected_runnable, + "theta_count": len(bundle.get("theta") or []), + "structure_record_count": len(bundle.get("structure_records") or []), + "review_item_count": len(review_items), + "counts": bundle.get("counts"), + "errors": ERRORS, "warnings": WARNINGS} + + + _sink = io.StringIO() + with contextlib.redirect_stdout(_sink): + _init() + RESULT = main() + print(json.dumps(RESULT, ensure_ascii=False)) diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/ver_8_yaml_candidates/P3-L2_final_structure_index_writer_v1.yml b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/ver_8_yaml_candidates/P3-L2_final_structure_index_writer_v1.yml new file mode 100644 index 00000000..30d2f53f --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/ver_8_yaml_candidates/P3-L2_final_structure_index_writer_v1.yml @@ -0,0 +1,420 @@ +# ============================================================================= +# P3-L2 / Task_C_LE_L2_final_structure_index_writer — v1 (신설) +# +# 정본 근거 : stage_1_part_3_개정_신전략서.md §4.3 · §2(D-4) +# 계약 : 구조 레코드 = Θ 의 (도메인, type_id) 쌍마다 하나 — 레코드 생성 주체는 +# registry 선언이지 SG-13·BO 가 아니다. +# 보존 등식 셋(선언·근거·BO) — 바깥 수는 이 task 가 원본 파일에서 직접 센다 +# (bundle 수와 비교하면 항등식으로 퇴행한다). +# 역인덱스 셋 by_domain_id · by_module · by_bo_id. by_claim_form 금지(D-4 라). +# 판정 파일은 없다 — L1 부재. F0 의 조건부 규칙을 흉내 내지 않는다(§4.1). +# ============================================================================= + - task_name: Task_C_LE_L2_final_structure_index_writer + mcp: code-executor + tool_name: run_code + parameters: + language: python + requirements: "httpx" + network: "agent-network" + timeout: 240 + code: |- + #!/usr/bin/env python3 + # Task_C_LE_L2_final_structure_index_writer (v1) + # 1) 게이트·정책·의미 검사 -> 2) bundle·handoff·원본 적재 -> + # 3) 보존 등식 셋(바깥 수 직접 계수) -> 4) 역인덱스 셋 -> + # 5) 닫힌 스키마 검증 -> 6) 기록·재읽기 -> 7) handoff FINALIZED + import contextlib + import hashlib + import io + import itertools + import json + import pathlib + import sys + + import httpx + + TASK_NAME = "Task_C_LE_L2_final_structure_index_writer" + LOCALDOCS_URL = "http://mcp-localdocs:8012/mcp" + MCP_HEADERS = {"Content-Type": "application/json", + "Accept": "application/json, text/event-stream"} + CLIENT = httpx.Client(timeout=120) + MSG_ID_COUNTER = itertools.count(10) + + + def next_msg_id(): + return next(MSG_ID_COUNTER) + + + def _init(): + r = CLIENT.post(LOCALDOCS_URL, json={ + "jsonrpc": "2.0", "id": 1, "method": "initialize", + "params": {"protocolVersion": "2025-03-26", "capabilities": {}, + "clientInfo": {"name": TASK_NAME, "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): + for line in text.strip().split("\n"): + if line.startswith("data: "): + try: + return json.loads(line[6:]) + except Exception: + return None + try: + return json.loads(text) + except Exception: + return None + + + def _call(name, args, mid): + 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() + p = _parse_mcp(r.text) + if not p or "result" not in p: + raise RuntimeError("MCP_CALL_FAILED:%s" % name) + return p + + + def read_raw(name): + p = _call("read_docs", {"doc_names": [name]}, next_msg_id()) + 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) + + + def read_json(name): + raw = read_raw(name) + s = raw.strip() + try: + return json.loads(s) + except json.JSONDecodeError: + obj, _ = json.JSONDecoder().raw_decode(s) + return obj + + + def write_doc(path, content): + _call("write_file", {"path": path, "content": content, "overwrite": True}, + next_msg_id()) + + ASSET_ROOT = "Default_Agent/" + EXECUTION_ROOT = "/tmp/s1" + RT = pathlib.Path(EXECUTION_ROOT) / "_rt" + + MODULE_MIRRORS = { + "runtime_common": "Default_Agent/stage1_runtime/runtime_common.txt", + "schema_subset_validator": "Default_Agent/stage1_runtime/schema_subset_validator.txt", + } + MODULES = ["runtime_common", "schema_subset_validator"] + RUNTIME_MANIFEST = "Default_Agent/runtime_manifest.json" + + POLICY = "Default_Agent/stage1_runtime/structure_index_policy.v1.json" + POLICY_SCHEMA_VERSION = "stage1_structure_index_policy.v1" + INDEX_SCHEMA = "Default_Agent/platform/schemas/legal_effect_structures.schema.json" + REGISTRY_INDEX = "Default_Agent/domains/_registry_index.json" + + BUNDLE_PATH = "stage1_tmp/task_le/structure_seed_bundle.json" + HANDOFF_PATH = "quality_gates/stage1_part3_review_handoff.json" + ACTIVATION_MANIFEST = "routing/domain_activation_manifest.json" + SG13_PATH = "signals/legal_effect_routes.json" + BO_PATH = "BO.json" + TARGET_PATH = "legal_effect_structures.json" + + PART3_DEPLOYMENT_REMEDY = ( + "배포 원본 extension_research/Default_Agent 트리를 서버 Default_Agent/ 에 통째로 배포하고 " + "runtime_manifest.json 의 등재·sha256 과 대조해 결손 경로를 복원한다. 부분 복사는 허용되지 않는다.") + + _MANIFEST_MAP = None + + + def sha_text(text): + return hashlib.sha256(text.encode("utf-8")).hexdigest() + + + def canonical(value): + return json.dumps(value, ensure_ascii=False, sort_keys=True, + separators=(",", ":")) + "\n" + + + 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": "PART3_ASSET_DEPLOYMENT_INCOMPLETE", "path": logical, + "detail": detail, "remedy": PART3_DEPLOYMENT_REMEDY} + if extra: + payload.update(extra) + return RuntimeError(json.dumps(payload, ensure_ascii=False)) + + + def _verify_asset(logical): + body = read_raw(logical) + want = _manifest_map().get(logical[len(ASSET_ROOT):]) + if want is None: + raise _deployment_error(logical, "unregistered") + if want != sha_text(body): + raise _deployment_error(logical, "hash_mismatch", {"expected": want}) + return body + + + def materialize_modules(): + RT.mkdir(parents=True, exist_ok=True) + expected = _manifest_map() + staged = [] + for name in MODULES: + logical = MODULE_MIRRORS[name] + raw = read_raw(logical).encode("utf-8") + want = expected.get(logical[len(ASSET_ROOT):]) + 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 assert_index_schema_capability(index_schema): + # 의미 검사(자기 스키마) — by_module · by_bo_id 를 아는가(PART3_INDEX_SCHEMA_STALE). + index_props = (((index_schema.get("properties") or {}) + .get("structure_index") or {}).get("properties") or {}) + missing = [key for key in ("by_module", "by_bo_id") if key not in index_props] + if missing: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_INDEX_SCHEMA_STALE", + "message": "색인 스키마가 by_module·by_bo_id 를 모른다. " + "배포 원본의 legal_effect_structures.schema.json 이 개정 전 판본이다.", + "missing": missing, "remedy": PART3_DEPLOYMENT_REMEDY, + }, ensure_ascii=False)) + + + def main(): + staged = materialize_modules() + import schema_subset_validator + + policy = json.loads(_verify_asset(POLICY)) + if policy.get("schema_version") != POLICY_SCHEMA_VERSION: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_POLICY_INVALID", + "expected": POLICY_SCHEMA_VERSION, + "actual": policy.get("schema_version")}, ensure_ascii=False)) + index_schema = json.loads(_verify_asset(INDEX_SCHEMA)) + assert_index_schema_capability(index_schema) + + # 입력은 전부 파일 계약. 판정 파일은 없다(L1 부재 — §4.1). + bundle_doc = read_json(BUNDLE_PATH) + bundle = bundle_doc.get("structure_seed_bundle", bundle_doc) + records = [row for row in (bundle.get("structure_records") or []) + if isinstance(row, dict)] + handoff_doc = read_json(HANDOFF_PATH) + handoff = handoff_doc.get("stage1_part3_review_handoff", handoff_doc) + activation_doc = read_json(ACTIVATION_MANIFEST) + activation_root = activation_doc.get("domain_activation_manifest", activation_doc) + expected_runnable = [d for d in (activation_root.get("expected_runnable_domain_ids") or []) + if isinstance(d, str)] + # ------------------------------------------------------------------ + # 보존 등식 셋 — 바깥 수를 원본에서 직접 센다. + # ------------------------------------------------------------------ + # (1) 선언 보존 — Σ(expected_runnable 도메인의 structure_types 개수). + # domain_config 무결성은 SG-01 봉인 -> _registry_index -> config_sha256 사슬 재사용. + index_raw = read_raw(REGISTRY_INDEX) + if activation_root.get("registry_index_sha256") != sha_text(index_raw): + raise RuntimeError(json.dumps({ + "reason_code": "PART3_REGISTRY_INDEX_SEAL_FAILED", + "stage": "L2"}, ensure_ascii=False)) + registry_index = json.loads(index_raw) + index_root = registry_index.get("domain_registry_index", registry_index) + config_sha = {row.get("domain_id"): row.get("config_sha256") + for row in (index_root.get("entries") or []) if isinstance(row, dict)} + declared_total = 0 + for domain_id in expected_runnable: + raw = read_raw("Default_Agent/domains/%s/domain_config.json" % domain_id) + if config_sha.get(domain_id) and sha_text(raw) != config_sha[domain_id]: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_REGISTRY_INDEX_SEAL_FAILED", + "detail": "config_sha256", "domain_id": domain_id}, ensure_ascii=False)) + config = json.loads(raw) + config_root = config.get("domain_config", config) + declared_total += len([row for row in (config_root.get("structure_types") or []) + if isinstance(row, dict)]) + declaration_pass = (len(records) == declared_total) + + # (2) 근거 보존 — SG-13 원본에서 legal_effect_route 총수를 직접 센다. + # 붙은 route 는 레코드에서 재계수한다(bundle counts 를 믿지 않는다). + sg13_doc = read_json(SG13_PATH) + sg13_total = len([row for row in (sg13_doc.get("records") or []) + if isinstance(row, dict) + and row.get("record_type") == "legal_effect_route"]) + attached_signal_ids = set() + for record in records: + for ref in record.get("routes") or []: + if isinstance(ref, dict) and isinstance(ref.get("signal_id"), str): + attached_signal_ids.add(ref["signal_id"]) + routes_unattached = len(bundle.get("unattached_routes") or []) + route_pass = (len(attached_signal_ids) + routes_unattached == sg13_total) + + # (3) BO 보존 — BO.json 원본에서 총수를 직접 센다. + bo_doc = read_json(BO_PATH) + bo_total = len(bo_doc) if isinstance(bo_doc, list) else 0 + attached_bo = set() + for record in records: + for bo_id in record.get("source_bo_ids") or []: + if isinstance(bo_id, str): + attached_bo.add(bo_id) + bo_unattached = len(bundle.get("unattached_bo") or []) + bo_pass = (len(attached_bo) + bo_unattached == bo_total) + + failures = [] + if not declaration_pass: + failures.append({"reason_code": "PART3_STRUCTURE_COUNT_BROKEN", + "records": len(records), "declared_total": declared_total}) + if not route_pass: + failures.append({"reason_code": "PART3_ROUTE_CONSERVATION_BROKEN", + "attached": len(attached_signal_ids), + "unattached": routes_unattached, "sg13_total": sg13_total}) + if not bo_pass: + failures.append({"reason_code": "PART3_BO_CONSERVATION_BROKEN", + "attached": len(attached_bo), + "unattached": bo_unattached, "bo_total": bo_total}) + if failures: + raise RuntimeError(json.dumps({"conservation_failures": failures}, + ensure_ascii=False)) + + # ------------------------------------------------------------------ + # 역인덱스 셋 — ID 목록만 담는다. 본문을 복제하지 않는다. + # ------------------------------------------------------------------ + by_domain_id = {} + by_module = {} + by_bo_id = {} + for record in records: + structure_id = record.get("structure_id") + by_domain_id.setdefault(record.get("domain_id"), []).append(structure_id) + if record.get("module"): + by_module.setdefault(record["module"], []).append(structure_id) + for bo_id in record.get("source_bo_ids") or []: + by_bo_id.setdefault(bo_id, []).append(structure_id) + for index in (by_domain_id, by_module, by_bo_id): + for key in index: + index[key] = sorted(set(index[key])) + + # 검토 재산정 — handoff 항목을 코드·심각도로 묶는다. review 는 근거 없이 줄지 않는다. + review_queue = [] + queue_keys = {} + for item in handoff.get("review_items") or []: + if not isinstance(item, dict): + continue + key = (item.get("review_code"), item.get("severity")) + if key in queue_keys: + queue_keys[key]["count"] += 1 + else: + row = {"review_code": key[0], "severity": key[1] or "SOFT_WARNING", + "count": 1} + queue_keys[key] = row + review_queue.append(row) + review_queue.sort(key=lambda row: (row["review_code"], row["severity"])) + status = "READY_WITH_REVIEW" if (review_queue or any( + record.get("review_required") for record in records)) else "READY" + + final_doc = { + "schema_version": "stage1_legal_effect_structures.v1", + "status": status, + "registry_version": bundle.get("registry_version"), + "registry_index_sha256": sha_text(index_raw), + "activation_manifest_sha256": sha_text(read_raw(ACTIVATION_MANIFEST)), + "signal_manifest_transaction_id": bundle.get("signal_manifest_transaction_id"), + "expected_runnable_domain_ids": expected_runnable, + "theta": bundle.get("theta") or [], + "structure_records": records, + "structure_index": {"by_domain_id": by_domain_id, + "by_module": by_module, + "by_bo_id": by_bo_id}, + "quality_gate": { + "declaration_conservation": { + "structure_records": len(records), + "declared_total_from_config": declared_total, + "conservation_pass": declaration_pass, + }, + "route_conservation": { + "routes_attached": len(attached_signal_ids), + "routes_unattached": routes_unattached, + "sg13_route_total_from_source": sg13_total, + "conservation_pass": route_pass, + }, + "bo_conservation": { + "bo_attached": len(attached_bo), + "bo_unattached": bo_unattached, + "bo_total_from_source": bo_total, + "conservation_pass": bo_pass, + }, + "review_queue": review_queue, + }, + "created_by": TASK_NAME, + } + + # 닫힌 스키마 검증 -> 기록 -> 재읽기. + schema_errors = schema_subset_validator.validate(final_doc, index_schema) + if schema_errors: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_FINAL_SCHEMA_VALIDATION_FAILED", + "stage": "L2", "errors": schema_errors[:10]}, ensure_ascii=False)) + text = canonical(final_doc) + write_doc(TARGET_PATH, text) + reread = read_raw(TARGET_PATH) + if sha_text(reread) != sha_text(text): + raise RuntimeError("PART3_WRITE_REREAD_MISMATCH") + + # handoff FINALIZED 갱신(공동 기록자). 항목을 줄이지 않는다. + handoff["status"] = "FINALIZED" + handoff["finalized_by"] = TASK_NAME + write_doc(HANDOFF_PATH, canonical({"stage1_part3_review_handoff": handoff})) + + return {"status": status, "modules": staged, + "structure_record_count": len(records), + "theta_count": len(bundle.get("theta") or []), + "index_bucket_counts": {"by_domain_id": len(by_domain_id), + "by_module": len(by_module), + "by_bo_id": len(by_bo_id)}, + "quality_gate_pass": {"declaration": declaration_pass, + "route": route_pass, "bo": bo_pass}, + "review_queue_count": len(review_queue)} + + + _sink = io.StringIO() + with contextlib.redirect_stdout(_sink): + _init() + RESULT = main() + print(json.dumps(RESULT, ensure_ascii=False)) diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/ver_8_yaml_candidates/stage_1_part_3_v.8.yml b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/ver_8_yaml_candidates/stage_1_part_3_v.8.yml new file mode 100644 index 00000000..2ebd6ad2 --- /dev/null +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/ver_8_yaml_candidates/stage_1_part_3_v.8.yml @@ -0,0 +1,1037 @@ +# ============================================================================= +# Liti-agent Stage 1 Part 3 v.8 — 법률효과 구조 · 통합 실행본 +# +# 정본 근거 +# 전략 : stage_1_part_3_개정_신전략서.md (D-4 결정안 §2 · 작업 명세 §4 · 자산 §5) +# 상위 계약 : stage_1_part_1_v.8.yml · stage_1_part_2_v.8.yml 의 실산출 +# 진입 계약 : signals/signal_manifest.json (downstream_read_sets.part3_L0 = +# SG-02 · SG-05 · SG-07 · SG-11 · SG-13) + SG-01 + BO.json +# +# 구성 — task 2종 (L1 은 두지 않는다 — LLM 이 판정할 예외 부류가 없다. 신전략서 §4.1) +# [신설] Task_C_LE_L0_structure_seed_reducer Θ 조립 · 구조 seed · 조인 · 검토 +# [신설] Task_C_LE_L2_final_structure_index_writer 보존 등식 셋 · 역인덱스 셋 · 최종 기록 +# +# 확정 계약 +# Θ SG-01.expected_runnable_domain_ids 의 domain_config.structure_types 합집합 +# 구조 레코드 (도메인, type_id) 쌍마다 하나 · 도메인 간 병합 금지 +# 전순서 (priority_rank, registry_index entries 위치, type_id) +# seed bundle stage1_tmp/task_le/structure_seed_bundle.json stage1_structure_seed_bundle.v1 +# 최종 산출 legal_effect_structures.json stage1_legal_effect_structures.v1 +# 역인덱스 by_domain_id · by_module · by_bo_id (by_claim_form 금지 — D-4 라) +# 정책 자산 Default_Agent/stage1_runtime/structure_index_policy.v1.json +# +# 제약 1 — v.7/Claude_YAML 의 어떤 파일도 읽지 않는다. 구 Part 3 명세에 의존하지 않는다. +# 137종 — 사건 이름·도메인 목록·유형 열거를 코드에 두지 않는다. +# 이 파일은 스테이지 하나다. 스테이지 선언 1벌 · task_procedure 1벌 · tasks 1벌. +# ============================================================================= +--- +Agent: + name: Liti-agent_Civil_Suit_Plaintiff_Stage_1_Part_3 + description: 민사소송 원고 송무 초지능 AI변호사 - Stage 1 Part 3 + version: v.2 + Stages: + - name: stage1_법률효과구조_생성 + description: 법률효과 구조 생성, 색인 작성 + llm_provider: openai + llm_model: gpt-4o-2024-08-06 + tools: + mcpServers: + localdocs: + type: streamable-http + url: http://mcp-localdocs:8012/mcp + description: Get the content of local documents + code-executor: + type: streamable-http + url: https://code-executor.mcp.eroomai.com/mcp + description: Run scripts of programming languages + headers: + Authorization: Bearer rR8OXqWrVZA1gFEo8oWfBkw2XgpWoGrrspw5ObsxTCM= + tasks: + - task_name: Task_C_LE_L0_structure_seed_reducer + mcp: code-executor + tool_name: run_code + parameters: + language: python + requirements: "httpx" + network: "agent-network" + timeout: 240 + code: |- + #!/usr/bin/env python3 + # Task_C_LE_L0_structure_seed_reducer (v1) + # 0) 배포 게이트 -> 1) 모듈 반입 -> 2) 정책 반입 -> 3) 의미 검사 둘 -> + # 4) 진입 봉인 둘 -> 5) 입력 적재 -> 6) compile_structure_seeds -> + # 7) bundle · review handoff · receipt 기록 + import contextlib + import hashlib + import io + import itertools + import json + import pathlib + import re + import sys + + import httpx + + # ------------------------------------------------------------------ + # localdocs 보일러플레이트 (SKILL.md 5장 / 5.2장) — Part 2 A0 검증 완료본 복사. + # clientInfo 에 {{__user_hash__}} / {{__workspace_hash__}} 를 반드시 넣는다. + # ------------------------------------------------------------------ + TASK_NAME = "Task_C_LE_L0_structure_seed_reducer" + LOCALDOCS_URL = "http://mcp-localdocs:8012/mcp" + MCP_HEADERS = {"Content-Type": "application/json", + "Accept": "application/json, text/event-stream"} + CLIENT = httpx.Client(timeout=120) + MSG_ID_COUNTER = itertools.count(10) + + + def next_msg_id(): + return next(MSG_ID_COUNTER) + + + def _init(): + r = CLIENT.post(LOCALDOCS_URL, json={ + "jsonrpc": "2.0", "id": 1, "method": "initialize", + "params": {"protocolVersion": "2025-03-26", "capabilities": {}, + "clientInfo": {"name": TASK_NAME, "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): + for line in text.strip().split("\n"): + if line.startswith("data: "): + try: + return json.loads(line[6:]) + except Exception: + return None + try: + return json.loads(text) + except Exception: + return None + + + def _call(name, args, mid): + 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() + p = _parse_mcp(r.text) + if not p or "result" not in p: + raise RuntimeError("MCP_CALL_FAILED:%s" % name) + return p + + + def read_raw(name): + # 재직렬화 없이 원문 그대로. 봉인·미러 해시 대조의 전제다. + p = _call("read_docs", {"doc_names": [name]}, next_msg_id()) + 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) + + + def read_json(name): + raw = read_raw(name) + s = raw.strip() + try: + return json.loads(s) + except json.JSONDecodeError: + obj, _ = json.JSONDecoder().raw_decode(s) + return obj + + + def try_read_json(name): + try: + return read_json(name) + except Exception: + return None + + + def write_doc(path, content): + _call("write_file", {"path": path, "content": content, "overwrite": True}, + next_msg_id()) + + # ------------------------------------------------------------------ + # 실행 뿌리 — /tmp/s1 공유(신전략서 §4.2 도입부. 새 뿌리를 만들지 않는다). + # ------------------------------------------------------------------ + ASSET_ROOT = "Default_Agent/" + EXECUTION_ROOT = "/tmp/s1" + RT = pathlib.Path(EXECUTION_ROOT) / "_rt" + + MODULE_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", + "structure_index_compiler": "Default_Agent/stage1_runtime/structure_index_compiler.txt", + } + MODULES = ["runtime_common", "schema_subset_validator", "registry_loader", + "structure_index_compiler"] + RUNTIME_MANIFEST = "Default_Agent/runtime_manifest.json" + RUNTIME_MANIFEST_SCHEMA = "stage1_runtime_manifest.v1" + + # 정적 자산 (I-9 ~ I-14) + REGISTRY_INDEX = "Default_Agent/domains/_registry_index.json" + POLICY = "Default_Agent/stage1_runtime/structure_index_policy.v1.json" + POLICY_SCHEMA_VERSION = "stage1_structure_index_policy.v1" + ALIAS_DECLARATIONS = "Default_Agent/routing/extension_payload_key_declarations.v1.json" + SEED_SCHEMA = "Default_Agent/platform/schemas/structure_seed_bundle.schema.json" + INDEX_SCHEMA = "Default_Agent/platform/schemas/legal_effect_structures.schema.json" + + # 사건 산출물 (I-1 ~ I-8) — Part 1·2 가 낸 것만 읽는다. + SIGNAL_MANIFEST = "signals/signal_manifest.json" + SG13_PATH = "signals/legal_effect_routes.json" + SG05_PATH = "signals/legal_relation_lifecycle_signals.json" + SG11_PATH = "signals/calculation_requirements.json" + SG02_PATH = "signals/procedural_posture_relief_signals.json" + SG07_PATH = "signals/asset_right_state_signals.json" + DOMAIN_SIGNAL_DIR = "signals/domain_signals" + ACTIVATION_MANIFEST = "routing/domain_activation_manifest.json" + BO_PATH = "BO.json" + SLICE_DIR = "runtime/domain_slices" + + # 산출 + BUNDLE_PATH = "stage1_tmp/task_le/structure_seed_bundle.json" + HANDOFF_PATH = "quality_gates/stage1_part3_review_handoff.json" + RECEIPT_PATH = "validation_assets/routing/part3_receipt.json" + + # F-2 상당 — 배포 게이트가 한 벌로 검사하는 필수 자산 10 리터럴(신전략서 §5.5). + # 사이드카 50 은 여기 넣지 않는다 — expected_runnable 도메인 것만 읽는 시점에 + # _verify_asset 으로 지킨다. domains/_registry_index.json 은 매니페스트 등재 + # 대상이 아니므로 SG-01 봉인이 지킨다(I-11 · §1.10 규율). + PART3_REQUIRED_ASSETS = ( + SEED_SCHEMA, + INDEX_SCHEMA, + POLICY, + ALIAS_DECLARATIONS, + "Default_Agent/signals/signal_registry.v2.json", + "Default_Agent/contracts/signals/s5_execution_contract.v2.json", + "Default_Agent/stage1_runtime/structure_index_compiler.txt", + "Default_Agent/stage1_runtime/runtime_common.txt", + "Default_Agent/stage1_runtime/schema_subset_validator.txt", + "Default_Agent/stage1_runtime/registry_loader.txt", + ) + PART3_DEPLOYMENT_REMEDY = ( + "배포 원본 extension_research/Default_Agent 트리를 서버 Default_Agent/ 에 통째로 배포하고 " + "runtime_manifest.json 의 등재·sha256 과 대조해 결손 경로를 복원한다. 부분 복사는 허용되지 않는다.") + + TRANSACTION_ID_RE = re.compile(r"^S5TX-[a-f0-9]{20}$") + + ERRORS = [] + WARNINGS = [] + + + def sha_text(text): + return hashlib.sha256(text.encode("utf-8")).hexdigest() + + + def canonical(value): + return json.dumps(value, ensure_ascii=False, sort_keys=True, + separators=(",", ":")) + "\n" + + + # ------------------------------------------------------------------ + # 0) 배포 게이트 — 등재·sha256·가독을 한 벌로. 첫 실패에서 멈추지 않고 모은다. + # ------------------------------------------------------------------ + def assert_deployment(): + manifest = json.loads(read_raw(RUNTIME_MANIFEST)) + if manifest.get("schema_version") != RUNTIME_MANIFEST_SCHEMA: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_RUNTIME_MANIFEST_INVALID", "detail": "schema_version", + "expected": RUNTIME_MANIFEST_SCHEMA, "actual": manifest.get("schema_version"), + }, ensure_ascii=False)) + expected = {row["path"]: row["sha256"] + for row in (manifest.get("entries") or []) if isinstance(row, dict)} + unregistered, mismatch, unreadable = [], [], [] + for logical in sorted(set(list(MODULE_MIRRORS.values()) + list(PART3_REQUIRED_ASSETS))): + rel = logical[len(ASSET_ROOT):] + want = expected.get(rel) + if want is None: + unregistered.append(rel) + try: + body = read_raw(logical) + except Exception: + unreadable.append(rel) + continue + if want is not None and want != sha_text(body): + mismatch.append({"path": rel, "expected": want, "actual": sha_text(body)}) + if unregistered or mismatch or unreadable: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_ASSET_DEPLOYMENT_INCOMPLETE", + "message": "배포 원본에 Part 3 자산이 한 벌로 반영되지 않았다.", + "unregistered": unregistered, "hash_mismatch": mismatch, + "unreadable": unreadable, "remedy": PART3_DEPLOYMENT_REMEDY, + }, ensure_ascii=False)) + return manifest + + + _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": "PART3_ASSET_DEPLOYMENT_INCOMPLETE", "path": logical, + "detail": detail, "remedy": PART3_DEPLOYMENT_REMEDY} + if extra: + payload.update(extra) + return RuntimeError(json.dumps(payload, ensure_ascii=False)) + + + def _verify_asset(logical): + """원문을 돌려준다. 등재·해시 대조를 통과해야만 소비된다.""" + body = read_raw(logical) + want = _manifest_map().get(logical[len(ASSET_ROOT):]) + if want is None: + raise _deployment_error(logical, "unregistered") + if want != sha_text(body): + raise _deployment_error(logical, "hash_mismatch", {"expected": want}) + return body + + + # ------------------------------------------------------------------ + # 1) 모듈 반입 — R-1~R-5. + # ------------------------------------------------------------------ + def materialize_modules(): + RT.mkdir(parents=True, exist_ok=True) + expected = _manifest_map() + staged = [] + for name in MODULES: + logical = MODULE_MIRRORS[name] + raw = read_raw(logical).encode("utf-8") + want = expected.get(logical[len(ASSET_ROOT):]) + 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 + + + # ------------------------------------------------------------------ + # 3) 의미 검사 — 장부 검사만으로는 닫히지 않는다(Part 2 R-b/R-g2 교훈). + # 각 검사는 자기가 쓰는 산출물의 스키마만 본다. by_module 은 L2 몫이다. + # ------------------------------------------------------------------ + def assert_seed_schema_capability(seed_schema): + bundle_props = (((seed_schema.get("properties") or {}) + .get("structure_seed_bundle") or {}).get("properties") or {}) + record_props = ((((bundle_props.get("structure_records") or {}) + .get("items") or {}).get("properties") or {})) + missing = [] + if "theta" not in bundle_props: + missing.append("theta") + if "admission_policy" not in record_props: + missing.append("structure_records[].admission_policy") + if missing: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_STRUCTURE_SCHEMA_STALE", + "message": "seed 스키마가 Part 3 계약 필드를 모른다. 배포 원본의 스키마가 개정 전 판본이다.", + "missing": missing, "remedy": PART3_DEPLOYMENT_REMEDY, + }, ensure_ascii=False)) + + + def assert_compiler_capability(result): + bundle = (result or {}).get("structure_seed_bundle") or {} + records = bundle.get("structure_records") + bad = ("theta" not in bundle + or not isinstance(records, list) + or any("order_key" not in record for record in records + if isinstance(record, dict))) + if bad: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_COMPILER_STALE", + "message": "컴파일러 산출에 theta·order_key 가 실려 나오지 않는다. " + "배포 원본의 structure_index_compiler 가 개정 전 판본이다.", + "remedy": PART3_DEPLOYMENT_REMEDY, + }, ensure_ascii=False)) + + + # ------------------------------------------------------------------ + # 4) 진입 봉인 둘 (신전략서 §4.2-5) + # ------------------------------------------------------------------ + def verify_signal_seal(): + doc = read_json(SIGNAL_MANIFEST) + root = doc.get("signal_manifest", doc) if isinstance(doc, dict) else {} + transaction_id = root.get("transaction_id") + if not isinstance(transaction_id, str) or not TRANSACTION_ID_RE.match(transaction_id): + raise RuntimeError(json.dumps({ + "reason_code": "PART3_SIGNAL_SEAL_FAILED", "detail": "transaction_id", + "actual": transaction_id}, ensure_ascii=False)) + checked = 0 + for row in root.get("files") or []: + if not isinstance(row, dict): + continue + # files[].path 에는 signals/ 접두사가 없다(I-1 주의). 붙여서 대조한다. + rel = str(row.get("path") or "") + actual = sha_text(read_raw("signals/" + rel)) + if actual != row.get("file_sha256"): + raise RuntimeError(json.dumps({ + "reason_code": "PART3_SIGNAL_SEAL_FAILED", "detail": "file_sha256", + "path": rel, "expected": row.get("file_sha256"), "actual": actual, + }, ensure_ascii=False)) + checked += 1 + return {"transaction_id": transaction_id, "files_checked": checked, "root": root} + + + def verify_registry_index_seal(activation_root, index_raw): + declared = activation_root.get("registry_index_sha256") + actual = sha_text(index_raw) + if declared != actual: + # 전순서 둘째 키가 이 색인의 배열 위치에 걸려 있다. 매니페스트 등재 대상이 + # 아니므로 이 봉인만이 색인 교체를 잡는다(L-d2). + raise RuntimeError(json.dumps({ + "reason_code": "PART3_REGISTRY_INDEX_SEAL_FAILED", + "declared": declared, "actual": actual}, ensure_ascii=False)) + return actual + + + def main(): + gate_manifest = assert_deployment() + staged = materialize_modules() + import structure_index_compiler + + # 2) 정책 반입 — 판본 불일치는 PART3_POLICY_INVALID. + policy = json.loads(_verify_asset(POLICY)) + if policy.get("schema_version") != POLICY_SCHEMA_VERSION: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_POLICY_INVALID", + "expected": POLICY_SCHEMA_VERSION, + "actual": policy.get("schema_version")}, ensure_ascii=False)) + + # 3) 의미 검사 (입력 쪽) + seed_schema = json.loads(_verify_asset(SEED_SCHEMA)) + assert_seed_schema_capability(seed_schema) + + # 4) 진입 봉인 둘 + seal = verify_signal_seal() + activation_doc = read_json(ACTIVATION_MANIFEST) + activation_root = activation_doc.get("domain_activation_manifest", activation_doc) + index_raw = read_raw(REGISTRY_INDEX) + registry_index_sha = verify_registry_index_seal(activation_root, index_raw) + registry_index = json.loads(index_raw) + index_root = registry_index.get("domain_registry_index", registry_index) + + expected_runnable = [d for d in (activation_root.get("expected_runnable_domain_ids") or []) + if isinstance(d, str)] + + # 5) 입력 적재 + # I-9 domain_config — 무결성은 SG-01 봉인 -> _registry_index -> config_sha256 사슬. + config_sha = {row.get("domain_id"): row.get("config_sha256") + for row in (index_root.get("entries") or []) if isinstance(row, dict)} + domain_configs = {} + domain_sidecars = {} + for domain_id in expected_runnable: + raw = read_raw("Default_Agent/domains/%s/domain_config.json" % domain_id) + if config_sha.get(domain_id) and sha_text(raw) != config_sha[domain_id]: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_REGISTRY_INDEX_SEAL_FAILED", + "detail": "config_sha256", "domain_id": domain_id}, ensure_ascii=False)) + config = json.loads(raw) + domain_configs[domain_id] = config + config_root = config.get("domain_config", config) + declared = [row for row in (config_root.get("structure_types") or []) + if isinstance(row, dict)] + if declared: + # 사이드카 부재 규칙(§5.5) — 선언 있는 도메인의 부재·미등재는 경성 실패. + domain_sidecars[domain_id] = { + "structure_types": json.loads(_verify_asset( + "Default_Agent/domains/%s/structure_types.json" % domain_id)), + "module_role_projection": json.loads(_verify_asset( + "Default_Agent/domains/%s/module_role_projection.json" % domain_id)), + } + + alias_declarations = json.loads(_verify_asset(ALIAS_DECLARATIONS)) + + def records_of(doc): + if not isinstance(doc, dict): + return [] + return [row for row in (doc.get("records") or []) if isinstance(row, dict)] + + # 경로 상수를 read_json 에 직접 넘긴다 — 선언표 검사기(U4)가 읽기를 코드에서 + # 확인할 수 있는 형태다. 간접 호출로 감싸면 소비 선언이 실측 불가가 된다. + sg13_records = records_of(read_json(SG13_PATH)) + sg05_records = records_of(read_json(SG05_PATH)) + sg11_records = records_of(read_json(SG11_PATH)) + # 읽되 비어 있음을 정상 처리(§3) — 조인 코드를 두지 않고 형식화된 사실로 남긴다. + sg02_rows = records_of(read_json(SG02_PATH)) + sg07_rows = records_of(read_json(SG07_PATH)) + empty_read_set = [ + {"signal_id": "SG-02", "transform": "passthrough", "producer_count": 0, + "record_count": len(sg02_rows), + "reason": "closed schema declares no claim-form vocabulary"}, + {"signal_id": "SG-07", "transform": "passthrough", "producer_count": 0, + "record_count": len(sg07_rows), + "reason": "closed schema declares no claim-form vocabulary"}, + ] + + domain_envelopes = {} + for domain_id in expected_runnable: + doc = try_read_json("%s/%s.json" % (DOMAIN_SIGNAL_DIR, domain_id)) + if doc is not None: + domain_envelopes[domain_id] = doc + + bo_doc = try_read_json(BO_PATH) + bo_records = bo_doc if isinstance(bo_doc, list) else [] + bo_raw = read_raw(BO_PATH) if bo_doc is not None else "" + + slice_documents = {} + for domain_id in expected_runnable: + doc = try_read_json("%s/%s.json" % (SLICE_DIR, domain_id)) + if doc is not None: + slice_documents[domain_id] = doc + + # 6) 모듈 호출 — 판정 규칙을 이 파일에 쓰지 않는다. + try: + result = structure_index_compiler.compile_structure_seeds( + activation_doc, registry_index, domain_configs, domain_sidecars, + policy, alias_declarations, sg13_records, sg05_records, sg11_records, + domain_envelopes, bo_records, slice_documents) + except TypeError as exc: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_COMPILER_STALE", "detail": "signature_mismatch", + "signature_error": str(exc)[:200], + "remedy": PART3_DEPLOYMENT_REMEDY}, ensure_ascii=False)) + assert_compiler_capability(result) + + bundle = result["structure_seed_bundle"] + review_items = result["review_items"] + audit = result["audit"] + # 진입 봉인의 거래 식별자를 bundle 에 부착한다 — L2 는 signal_manifest 를 + # 다시 읽지 않고(§4.3 입력 계약 밖) 이 값을 승계한다. + bundle["signal_manifest_transaction_id"] = seal["transaction_id"] + + # 자기 산출을 닫힌 스키마로 검증한다. + import schema_subset_validator + schema_errors = schema_subset_validator.validate( + {"structure_seed_bundle": bundle}, seed_schema) + if schema_errors: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_FINAL_SCHEMA_VALIDATION_FAILED", + "stage": "L0", "errors": schema_errors[:10]}, ensure_ascii=False)) + + # 7) 기록 — bundle · handoff(OPEN) · receipt(실측값. 상수 PASS 금지). + write_doc(BUNDLE_PATH, canonical({"structure_seed_bundle": bundle})) + write_doc(HANDOFF_PATH, canonical({"stage1_part3_review_handoff": { + "schema_version": "stage1_part3_review_handoff.v1", + "status": "OPEN", + "review_items": review_items, + "counts": {"review_items": len(review_items)}, + "created_by": TASK_NAME, + }})) + order_table = ["%s|%s|%s|%s|%s" % ( + record.get("priority_rank"), record.get("domain_id"), + record.get("type_id"), record.get("module"), + record.get("admission_policy")) + for record in bundle.get("structure_records") or []] + write_doc(RECEIPT_PATH, canonical({ + "schema_version": "stage1_part3_receipt.v1", + "stage": "P3-L0", + "deployment_gate": { + "checked_count": len(set(list(MODULE_MIRRORS.values()) + + list(PART3_REQUIRED_ASSETS))), + "runtime_manifest_sha256": sha_text(read_raw(RUNTIME_MANIFEST)), + "runtime_artifact_count": gate_manifest.get("runtime_artifact_count"), + "schema_capability_checked": ["theta", "structure_records[].admission_policy"], + "compiler_output_checked": ["theta", "structure_records[].order_key"], + "policy_schema_version": policy.get("schema_version"), + "note": "무엇을 봤는지 적는다. 상수 PASS 는 증거가 아니다.", + }, + "entry_seals": { + "signal_manifest_transaction_id": seal["transaction_id"], + "signal_files_checked": seal["files_checked"], + "registry_index_sha256": registry_index_sha, + "config_sha256_chain_checked": len(domain_configs), + }, + "join_counts": bundle.get("counts"), + "empty_read_set_signals": empty_read_set, + "sidecar_dialects": audit.get("sidecar_dialects"), + "unlinked_sg11": audit.get("unlinked_sg11"), + "dangling_calculation_refs": audit.get("dangling_calculation_refs"), + "input_gaps": audit.get("input_gaps"), + "bo_input": {"sha256": sha_text(bo_raw) if bo_raw else None, + "record_count": len(bo_records), + "note": "BO.json 은 무봉인 입력이다 — signal 5종은 I-1 봉인, " + "registry 는 SG-01 봉인이 지키는 비대칭을 관찰로 남긴다."}, + "resolved_order_table": order_table, + "created_by": TASK_NAME, + })) + + return {"status": bundle.get("status"), + "modules": staged, + "expected_runnable_domain_ids": expected_runnable, + "theta_count": len(bundle.get("theta") or []), + "structure_record_count": len(bundle.get("structure_records") or []), + "review_item_count": len(review_items), + "counts": bundle.get("counts"), + "errors": ERRORS, "warnings": WARNINGS} + + + _sink = io.StringIO() + with contextlib.redirect_stdout(_sink): + _init() + RESULT = main() + print(json.dumps(RESULT, ensure_ascii=False)) + + - task_name: Task_C_LE_L2_final_structure_index_writer + mcp: code-executor + tool_name: run_code + parameters: + language: python + requirements: "httpx" + network: "agent-network" + timeout: 240 + code: |- + #!/usr/bin/env python3 + # Task_C_LE_L2_final_structure_index_writer (v1) + # 1) 게이트·정책·의미 검사 -> 2) bundle·handoff·원본 적재 -> + # 3) 보존 등식 셋(바깥 수 직접 계수) -> 4) 역인덱스 셋 -> + # 5) 닫힌 스키마 검증 -> 6) 기록·재읽기 -> 7) handoff FINALIZED + import contextlib + import hashlib + import io + import itertools + import json + import pathlib + import sys + + import httpx + + TASK_NAME = "Task_C_LE_L2_final_structure_index_writer" + LOCALDOCS_URL = "http://mcp-localdocs:8012/mcp" + MCP_HEADERS = {"Content-Type": "application/json", + "Accept": "application/json, text/event-stream"} + CLIENT = httpx.Client(timeout=120) + MSG_ID_COUNTER = itertools.count(10) + + + def next_msg_id(): + return next(MSG_ID_COUNTER) + + + def _init(): + r = CLIENT.post(LOCALDOCS_URL, json={ + "jsonrpc": "2.0", "id": 1, "method": "initialize", + "params": {"protocolVersion": "2025-03-26", "capabilities": {}, + "clientInfo": {"name": TASK_NAME, "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): + for line in text.strip().split("\n"): + if line.startswith("data: "): + try: + return json.loads(line[6:]) + except Exception: + return None + try: + return json.loads(text) + except Exception: + return None + + + def _call(name, args, mid): + 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() + p = _parse_mcp(r.text) + if not p or "result" not in p: + raise RuntimeError("MCP_CALL_FAILED:%s" % name) + return p + + + def read_raw(name): + p = _call("read_docs", {"doc_names": [name]}, next_msg_id()) + 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) + + + def read_json(name): + raw = read_raw(name) + s = raw.strip() + try: + return json.loads(s) + except json.JSONDecodeError: + obj, _ = json.JSONDecoder().raw_decode(s) + return obj + + + def write_doc(path, content): + _call("write_file", {"path": path, "content": content, "overwrite": True}, + next_msg_id()) + + ASSET_ROOT = "Default_Agent/" + EXECUTION_ROOT = "/tmp/s1" + RT = pathlib.Path(EXECUTION_ROOT) / "_rt" + + MODULE_MIRRORS = { + "runtime_common": "Default_Agent/stage1_runtime/runtime_common.txt", + "schema_subset_validator": "Default_Agent/stage1_runtime/schema_subset_validator.txt", + } + MODULES = ["runtime_common", "schema_subset_validator"] + RUNTIME_MANIFEST = "Default_Agent/runtime_manifest.json" + + POLICY = "Default_Agent/stage1_runtime/structure_index_policy.v1.json" + POLICY_SCHEMA_VERSION = "stage1_structure_index_policy.v1" + INDEX_SCHEMA = "Default_Agent/platform/schemas/legal_effect_structures.schema.json" + REGISTRY_INDEX = "Default_Agent/domains/_registry_index.json" + + BUNDLE_PATH = "stage1_tmp/task_le/structure_seed_bundle.json" + HANDOFF_PATH = "quality_gates/stage1_part3_review_handoff.json" + ACTIVATION_MANIFEST = "routing/domain_activation_manifest.json" + SG13_PATH = "signals/legal_effect_routes.json" + BO_PATH = "BO.json" + TARGET_PATH = "legal_effect_structures.json" + + PART3_DEPLOYMENT_REMEDY = ( + "배포 원본 extension_research/Default_Agent 트리를 서버 Default_Agent/ 에 통째로 배포하고 " + "runtime_manifest.json 의 등재·sha256 과 대조해 결손 경로를 복원한다. 부분 복사는 허용되지 않는다.") + + _MANIFEST_MAP = None + + + def sha_text(text): + return hashlib.sha256(text.encode("utf-8")).hexdigest() + + + def canonical(value): + return json.dumps(value, ensure_ascii=False, sort_keys=True, + separators=(",", ":")) + "\n" + + + 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": "PART3_ASSET_DEPLOYMENT_INCOMPLETE", "path": logical, + "detail": detail, "remedy": PART3_DEPLOYMENT_REMEDY} + if extra: + payload.update(extra) + return RuntimeError(json.dumps(payload, ensure_ascii=False)) + + + def _verify_asset(logical): + body = read_raw(logical) + want = _manifest_map().get(logical[len(ASSET_ROOT):]) + if want is None: + raise _deployment_error(logical, "unregistered") + if want != sha_text(body): + raise _deployment_error(logical, "hash_mismatch", {"expected": want}) + return body + + + def materialize_modules(): + RT.mkdir(parents=True, exist_ok=True) + expected = _manifest_map() + staged = [] + for name in MODULES: + logical = MODULE_MIRRORS[name] + raw = read_raw(logical).encode("utf-8") + want = expected.get(logical[len(ASSET_ROOT):]) + 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 assert_index_schema_capability(index_schema): + # 의미 검사(자기 스키마) — by_module · by_bo_id 를 아는가(PART3_INDEX_SCHEMA_STALE). + index_props = (((index_schema.get("properties") or {}) + .get("structure_index") or {}).get("properties") or {}) + missing = [key for key in ("by_module", "by_bo_id") if key not in index_props] + if missing: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_INDEX_SCHEMA_STALE", + "message": "색인 스키마가 by_module·by_bo_id 를 모른다. " + "배포 원본의 legal_effect_structures.schema.json 이 개정 전 판본이다.", + "missing": missing, "remedy": PART3_DEPLOYMENT_REMEDY, + }, ensure_ascii=False)) + + + def main(): + staged = materialize_modules() + import schema_subset_validator + + policy = json.loads(_verify_asset(POLICY)) + if policy.get("schema_version") != POLICY_SCHEMA_VERSION: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_POLICY_INVALID", + "expected": POLICY_SCHEMA_VERSION, + "actual": policy.get("schema_version")}, ensure_ascii=False)) + index_schema = json.loads(_verify_asset(INDEX_SCHEMA)) + assert_index_schema_capability(index_schema) + + # 입력은 전부 파일 계약. 판정 파일은 없다(L1 부재 — §4.1). + bundle_doc = read_json(BUNDLE_PATH) + bundle = bundle_doc.get("structure_seed_bundle", bundle_doc) + records = [row for row in (bundle.get("structure_records") or []) + if isinstance(row, dict)] + handoff_doc = read_json(HANDOFF_PATH) + handoff = handoff_doc.get("stage1_part3_review_handoff", handoff_doc) + activation_doc = read_json(ACTIVATION_MANIFEST) + activation_root = activation_doc.get("domain_activation_manifest", activation_doc) + expected_runnable = [d for d in (activation_root.get("expected_runnable_domain_ids") or []) + if isinstance(d, str)] + # ------------------------------------------------------------------ + # 보존 등식 셋 — 바깥 수를 원본에서 직접 센다. + # ------------------------------------------------------------------ + # (1) 선언 보존 — Σ(expected_runnable 도메인의 structure_types 개수). + # domain_config 무결성은 SG-01 봉인 -> _registry_index -> config_sha256 사슬 재사용. + index_raw = read_raw(REGISTRY_INDEX) + if activation_root.get("registry_index_sha256") != sha_text(index_raw): + raise RuntimeError(json.dumps({ + "reason_code": "PART3_REGISTRY_INDEX_SEAL_FAILED", + "stage": "L2"}, ensure_ascii=False)) + registry_index = json.loads(index_raw) + index_root = registry_index.get("domain_registry_index", registry_index) + config_sha = {row.get("domain_id"): row.get("config_sha256") + for row in (index_root.get("entries") or []) if isinstance(row, dict)} + declared_total = 0 + for domain_id in expected_runnable: + raw = read_raw("Default_Agent/domains/%s/domain_config.json" % domain_id) + if config_sha.get(domain_id) and sha_text(raw) != config_sha[domain_id]: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_REGISTRY_INDEX_SEAL_FAILED", + "detail": "config_sha256", "domain_id": domain_id}, ensure_ascii=False)) + config = json.loads(raw) + config_root = config.get("domain_config", config) + declared_total += len([row for row in (config_root.get("structure_types") or []) + if isinstance(row, dict)]) + declaration_pass = (len(records) == declared_total) + + # (2) 근거 보존 — SG-13 원본에서 legal_effect_route 총수를 직접 센다. + # 붙은 route 는 레코드에서 재계수한다(bundle counts 를 믿지 않는다). + sg13_doc = read_json(SG13_PATH) + sg13_total = len([row for row in (sg13_doc.get("records") or []) + if isinstance(row, dict) + and row.get("record_type") == "legal_effect_route"]) + attached_signal_ids = set() + for record in records: + for ref in record.get("routes") or []: + if isinstance(ref, dict) and isinstance(ref.get("signal_id"), str): + attached_signal_ids.add(ref["signal_id"]) + routes_unattached = len(bundle.get("unattached_routes") or []) + route_pass = (len(attached_signal_ids) + routes_unattached == sg13_total) + + # (3) BO 보존 — BO.json 원본에서 총수를 직접 센다. + bo_doc = read_json(BO_PATH) + bo_total = len(bo_doc) if isinstance(bo_doc, list) else 0 + attached_bo = set() + for record in records: + for bo_id in record.get("source_bo_ids") or []: + if isinstance(bo_id, str): + attached_bo.add(bo_id) + bo_unattached = len(bundle.get("unattached_bo") or []) + bo_pass = (len(attached_bo) + bo_unattached == bo_total) + + failures = [] + if not declaration_pass: + failures.append({"reason_code": "PART3_STRUCTURE_COUNT_BROKEN", + "records": len(records), "declared_total": declared_total}) + if not route_pass: + failures.append({"reason_code": "PART3_ROUTE_CONSERVATION_BROKEN", + "attached": len(attached_signal_ids), + "unattached": routes_unattached, "sg13_total": sg13_total}) + if not bo_pass: + failures.append({"reason_code": "PART3_BO_CONSERVATION_BROKEN", + "attached": len(attached_bo), + "unattached": bo_unattached, "bo_total": bo_total}) + if failures: + raise RuntimeError(json.dumps({"conservation_failures": failures}, + ensure_ascii=False)) + + # ------------------------------------------------------------------ + # 역인덱스 셋 — ID 목록만 담는다. 본문을 복제하지 않는다. + # ------------------------------------------------------------------ + by_domain_id = {} + by_module = {} + by_bo_id = {} + for record in records: + structure_id = record.get("structure_id") + by_domain_id.setdefault(record.get("domain_id"), []).append(structure_id) + if record.get("module"): + by_module.setdefault(record["module"], []).append(structure_id) + for bo_id in record.get("source_bo_ids") or []: + by_bo_id.setdefault(bo_id, []).append(structure_id) + for index in (by_domain_id, by_module, by_bo_id): + for key in index: + index[key] = sorted(set(index[key])) + + # 검토 재산정 — handoff 항목을 코드·심각도로 묶는다. review 는 근거 없이 줄지 않는다. + review_queue = [] + queue_keys = {} + for item in handoff.get("review_items") or []: + if not isinstance(item, dict): + continue + key = (item.get("review_code"), item.get("severity")) + if key in queue_keys: + queue_keys[key]["count"] += 1 + else: + row = {"review_code": key[0], "severity": key[1] or "SOFT_WARNING", + "count": 1} + queue_keys[key] = row + review_queue.append(row) + review_queue.sort(key=lambda row: (row["review_code"], row["severity"])) + status = "READY_WITH_REVIEW" if (review_queue or any( + record.get("review_required") for record in records)) else "READY" + + final_doc = { + "schema_version": "stage1_legal_effect_structures.v1", + "status": status, + "registry_version": bundle.get("registry_version"), + "registry_index_sha256": sha_text(index_raw), + "activation_manifest_sha256": sha_text(read_raw(ACTIVATION_MANIFEST)), + "signal_manifest_transaction_id": bundle.get("signal_manifest_transaction_id"), + "expected_runnable_domain_ids": expected_runnable, + "theta": bundle.get("theta") or [], + "structure_records": records, + "structure_index": {"by_domain_id": by_domain_id, + "by_module": by_module, + "by_bo_id": by_bo_id}, + "quality_gate": { + "declaration_conservation": { + "structure_records": len(records), + "declared_total_from_config": declared_total, + "conservation_pass": declaration_pass, + }, + "route_conservation": { + "routes_attached": len(attached_signal_ids), + "routes_unattached": routes_unattached, + "sg13_route_total_from_source": sg13_total, + "conservation_pass": route_pass, + }, + "bo_conservation": { + "bo_attached": len(attached_bo), + "bo_unattached": bo_unattached, + "bo_total_from_source": bo_total, + "conservation_pass": bo_pass, + }, + "review_queue": review_queue, + }, + "created_by": TASK_NAME, + } + + # 닫힌 스키마 검증 -> 기록 -> 재읽기. + schema_errors = schema_subset_validator.validate(final_doc, index_schema) + if schema_errors: + raise RuntimeError(json.dumps({ + "reason_code": "PART3_FINAL_SCHEMA_VALIDATION_FAILED", + "stage": "L2", "errors": schema_errors[:10]}, ensure_ascii=False)) + text = canonical(final_doc) + write_doc(TARGET_PATH, text) + reread = read_raw(TARGET_PATH) + if sha_text(reread) != sha_text(text): + raise RuntimeError("PART3_WRITE_REREAD_MISMATCH") + + # handoff FINALIZED 갱신(공동 기록자). 항목을 줄이지 않는다. + handoff["status"] = "FINALIZED" + handoff["finalized_by"] = TASK_NAME + write_doc(HANDOFF_PATH, canonical({"stage1_part3_review_handoff": handoff})) + + return {"status": status, "modules": staged, + "structure_record_count": len(records), + "theta_count": len(bundle.get("theta") or []), + "index_bucket_counts": {"by_domain_id": len(by_domain_id), + "by_module": len(by_module), + "by_bo_id": len(by_bo_id)}, + "quality_gate_pass": {"declaration": declaration_pass, + "route": route_pass, "bo": bo_pass}, + "review_queue_count": len(review_queue)} + + + _sink = io.StringIO() + with contextlib.redirect_stdout(_sink): + _init() + RESULT = main() + print(json.dumps(RESULT, ensure_ascii=False)) + + task_procedure: + # L0 가 seed bundle 과 handoff 를 내고서야 L2 가 선다. 완전 직렬이다. + IN: + nexts: ["Task_C_LE_L0_structure_seed_reducer"] + wait_until: [] + + Task_C_LE_L0_structure_seed_reducer: + nexts: ["Task_C_LE_L2_final_structure_index_writer"] + wait_until: ["IN"] + + # L1 자리는 비워 둔다 — 판정 부류가 생기면 이 사이에 끼운다(신전략서 §4.1). + Task_C_LE_L2_final_structure_index_writer: + nexts: ["OUT"] + wait_until: ["Task_C_LE_L0_structure_seed_reducer"] + + OUT: + nexts: [] + wait_until: ["Task_C_LE_L2_final_structure_index_writer"] + + prevs: [] + nexts: [] diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/선행구축/Default_Agent_Stage_1/handoffs/stage1_part_interface.v1.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/선행구축/Default_Agent_Stage_1/handoffs/stage1_part_interface.v1.json index ed8b1b28..5bf34f85 100644 --- a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/선행구축/Default_Agent_Stage_1/handoffs/stage1_part_interface.v1.json +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/선행구축/Default_Agent_Stage_1/handoffs/stage1_part_interface.v1.json @@ -1 +1 @@ -{"authored_not_derived":"이 표는 계약이며 코드에서 뽑지 않았다. 코드에서 뽑으면 검사가 자기 자신을 확인하는 셈이 된다. 검사기(_check_stage1_interface.py)가 코드를 이 표와 대조한다.","checker":"validation_assets/routing/_check_stage1_interface.py","conventions":{"also_written_by":"선언된 생산자 외에 갱신을 허용하는 task. 생산자 위반으로 세지 않는다.","asset_paths_excluded":"Default_Agent/ 아래 정적 자산은 이 표의 대상이 아니다. 검사 10 이 따로 본다.","optional":"부재가 곧 실패는 아니지만 조건이 붙는다. note 를 읽는다.","path_is_pattern":" 자리는 런타임 값이다. 검사기는 접두·접미로 대조한다.","produced_by_module":"생산자 task 가 키 구성을 런타임 모듈에 위임할 때 그 모듈 경로. 필수 키 검사는 그 원문까지 함께 본다."},"entry_inputs":[{"consumer_tasks":["Task_A0_domain_screener_01","Task_A0_domain_screener_02","Task_A_client_goal","Task_B1_map_doc_*","Task_B2_map_events_*"],"note":"사건 입력. 어느 task 도 쓰지 않는다.","optional":false,"path":"client_meeting.md","path_is_pattern":false,"producer_task":null,"stage":"INPUT"},{"consumer_tasks":["Task_Evidence_shard_planner"],"note":"사건 입력. 어느 task 도 쓰지 않는다.","optional":false,"path":"evidence_all.json","path_is_pattern":false,"producer_task":null,"required_keys":["documents","source_files","total_count"],"stage":"INPUT"}],"handoff_count":34,"handoffs":[{"consumer_tasks":["Task_A0_domain_screener_01","Task_A0_domain_screener_02","Task_A_client_goal","Task_B1_map_doc_*","Task_B2_map_events_*"],"note":"사건 입력. 어느 task 도 쓰지 않는다.","optional":false,"path":"client_meeting.md","path_is_pattern":false,"producer_task":null,"stage":"INPUT"},{"consumer_tasks":["Task_Evidence_shard_planner"],"note":"사건 입력. 어느 task 도 쓰지 않는다.","optional":false,"path":"evidence_all.json","path_is_pattern":false,"producer_task":null,"required_keys":["documents","source_files","total_count"],"stage":"INPUT"},{"consumer_tasks":["Task_A0_domain_screener_02"],"note":"LLM 초안. 비판단 6종(schema_version·registry_version·registry_index_sha256·source_document_refs·screening_policy·contract_guards)을 담지 않는다. candidates 원소 키 구성은 닫힌 스키마의 후보 객체와 같아야 한다.","optional":false,"path":"routing/domain_screening_draft.json","path_is_pattern":false,"producer_task":"Task_A0_domain_screener_01","required_keys":["candidates","review_items","status","unmatched_issue_refs"],"root_key":"domain_screening_draft","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_A0_domain_screener_03","Task_A_client_goal","Task_D0_domain_activation_gate","Task_B2_SHA256_soft_gate_handoff_writer","Task_C_BO_A0_context_and_domain_slice_compiler"],"note":"screening_sha256 의 원문. 재직렬화 금지. Part 2 A0 는 봉인 원문 바이트와 별도로 candidates[].requested_calculation_domains 를 파싱해 슬라이스로 통과시킨다(R-2).","optional":false,"path":"routing/domain_screening.json","path_is_pattern":false,"producer_task":"Task_A0_domain_screener_02","required_keys":["candidates","contract_guards","registry_index_sha256","registry_version","review_items","schema_version","screening_policy","source_document_refs","status","unmatched_issue_refs"],"schema_version":"stage1_domain_screening.v1","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_A_client_goal"],"optional":false,"path":"routing/candidate_profile_vocabulary.md","path_is_pattern":false,"producer_task":"Task_A0_domain_screener_03","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B1_map_doc_*","Task_B1_quality_gate_evidence_indexed","Task_B2_quality_gate_event_candidates"],"optional":false,"path":"evidence_shard_plan.json","path_is_pattern":false,"producer_task":"Task_Evidence_shard_planner","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_D0_domain_activation_gate","Task_C_BO_A0_context_and_domain_slice_compiler"],"note":"T5 get_single_item 이 items[0] 을 통째로 싣는다. registry_component_ids 가 여기를 통과한다(C-1).","optional":false,"path":"evidence_indexed.json","path_is_pattern":false,"producer_task":"Task_B1_quality_gate_evidence_indexed","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_D0_domain_activation_gate","Task_C_BO_A0_context_and_domain_slice_compiler"],"optional":false,"path":"evidence_event_candidates.json","path_is_pattern":false,"producer_task":"Task_B2_quality_gate_event_candidates","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B2_quality_gate_event_candidates","Task_B12_gate_audit_finalizer"],"optional":false,"path":"stage1_tmp/quality_gate/B1_precheck.json","path_is_pattern":false,"producer_task":"Task_B1_quality_gate_evidence_indexed","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B2_quality_gate_event_candidates"],"optional":false,"path":"stage1_tmp/quality_gate/finalized_evidence_id_manifest.json","path_is_pattern":false,"producer_task":"Task_B1_quality_gate_evidence_indexed","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B12_gate_audit_finalizer"],"optional":false,"path":"stage1_tmp/quality_gate/B2_precheck.json","path_is_pattern":false,"producer_task":"Task_B2_quality_gate_event_candidates","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B12_gate_llm_adjudicator","Task_B12_gate_audit_finalizer"],"optional":false,"path":"stage1_tmp/quality_gate/B12_exception_pack.json","path_is_pattern":false,"producer_task":"Task_B2_quality_gate_event_candidates","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B12_gate_audit_finalizer"],"optional":false,"path":"stage1_tmp/quality_gate/B12_adjudication_decisions.json","path_is_pattern":false,"producer_task":"Task_B12_gate_llm_adjudicator","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_D0_domain_activation_gate","Task_B2_SHA256_soft_gate_handoff_writer"],"optional":false,"path":"quality_gates/B1_evidence_indexed_gate.json","path_is_pattern":false,"producer_task":"Task_B12_gate_audit_finalizer","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_D0_domain_activation_gate","Task_B2_SHA256_soft_gate_handoff_writer"],"optional":false,"path":"quality_gates/B2_event_candidates_gate.json","path_is_pattern":false,"producer_task":"Task_B12_gate_audit_finalizer","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B2_SHA256_soft_gate_handoff_writer","Task_C_BO_A0_context_and_domain_slice_compiler","Task_C_BO_S0_signal_bundle_writer"],"note":"D-3 확정: execution_eligible 이 유일한 결정 필드. active ⊆ eligible. D0 은 활성 판정을 activation_gate 모듈에 위임한다 — 필수 키는 그 모듈이 만든다.","optional":false,"path":"routing/domain_activation_manifest.json","path_is_pattern":false,"produced_by_module":"stage1_runtime/activation_gate.py","producer_task":"Task_D0_domain_activation_gate","required_keys":["active_domain_ids","conservation_gate","contract_guards","domain_entries","expected_runnable_domain_ids","fail_open_policy","monitor_domain_ids","registry_index_sha256","registry_version","required_calculation_domains","review_items","schema_version","screening_sha256","signal_id","status","supporting_domain_ids","unrouted_material"],"root_key":"domain_activation_manifest","schema_version":"stage1_domain_activation_manifest.v1","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_C_BO_A0_context_and_domain_slice_compiler"],"note":"루트 래핑 없이 쓴다. 소비자는 stage1_part1_soft_gate_handoff 래핑 유무 둘 다 받아야 한다. digest_guard 는 screening_sha256·activation_manifest_sha256·registry_index_sha256 셋을 담는다.","optional":false,"path":"quality_gates/stage1_part1_soft_gate_handoff.json","path_is_pattern":false,"producer_task":"Task_B2_SHA256_soft_gate_handoff_writer","required_keys":["digest_guard","handoff_status","review_items","schema_version","source_stage"],"schema_version":"stage1_part1_soft_gate_handoff.v1","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_F0_final_bo_compiler_gate_writer"],"note":"v3 1104행이 정한 경로다. 옮기지 않는다.","optional":false,"path":"stage1_tmp/task_c_bo/stage_a_context.json","path_is_pattern":false,"produced_by_module":"stage1_runtime/stage_a_context_builder.py","producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","required_keys":["created_at_utc","event_candidate_map","evidence_authority_map","input_digests_sha256","meeting_clause_map","schema_version","status"],"root_key":"stage_a_context","schema_version":"task_c_bo_stage_a_context.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_S0_signal_bundle_writer"],"note":"v1 세 목록은 소비자 계약이므로 유지한다. v2 가 더한 evidence_count·registry_index_sha256 은 덧붙이기다(P0 판정 C 형태).","optional":false,"path":"stage1_tmp/task_c_bo/source_universe_manifest.json","path_is_pattern":false,"produced_by_module":"stage1_runtime/stage_a_context_builder.py","producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","required_keys":["event_candidate_ids","evidence_index_set","meeting_clause_ids","schema_version"],"schema_version":"task_c_bo_source_universe_manifest.v2","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_B_domain_worker_*","Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_S0_signal_bundle_writer"],"note":"task_instances[*] 는 domain_id 와 expected_output_path 를 갖는다.","optional":false,"path":"fanout/domain_fanout_plan.json","path_is_pattern":false,"producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","required_keys":["schema_version","task_instances"],"root_key":"domain_fanout_plan","schema_version":"domain_fanout_plan.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_S0_signal_bundle_writer","Task_C_B_domain_worker_*"],"note":"R-1/R-2 로 domain_declarations 를 실은다. R0 는 worker 산출 검증에, S0 는 emits_signals 대조에 읽는다.","optional":false,"path":"runtime/domain_slices/.json","path_is_pattern":true,"producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","root_key":"stage_b_domain_slice","schema_version":"task_c_bo_stage_b_domain_slice.v2","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_B_domain_worker_*"],"note":"worker 는 이 프롬프트를 다시 만들지 않는다. compiled_prompt_sha256 이 일치해야 한다.","optional":false,"path":"runtime/compiled_prompts/.md","path_is_pattern":true,"producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","stage":"Stage_1.Part_2"},{"consumer_tasks":[],"note":"원인 분리 영수증. 동결기가 slice_sha256_by_domain 을 읽는다.","optional":false,"path":"validation_assets/routing/stage_receipt.json","path_is_pattern":false,"producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","required_keys":["activation_source","created_by","loader_mode","schema_injection","schema_version","slice_sha256_by_domain","stage","worker_mode"],"schema_version":"stage1_stage_receipt.v2","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_S0_signal_bundle_writer"],"optional":false,"path":"runtime/domain_seed_outputs/.json","path_is_pattern":true,"producer_task":"Task_C_B_domain_worker_*","root_key":"stage_b_domain_bo_seed_output","schema_version":"task_c_bo_stage_b_domain_bo_seed.v3","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_F0_final_bo_compiler_gate_writer"],"optional":false,"path":"stage1_tmp/task_c_bo/postb_seed_ledger.json","path_is_pattern":false,"producer_task":"Task_C_BO_R0_seed_reducer_and_exception_planner","root_key":"postb_seed_ledger","schema_version":"task_c_bo_postb_seed_ledger.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_R1_exception_adjudicator","Task_C_BO_F0_final_bo_compiler_gate_writer"],"note":"exception_count 가 R1 산출의 필수 여부를 정한다.","optional":false,"path":"quality_gates/stage1_part2_exception_pack.json","path_is_pattern":false,"producer_task":"Task_C_BO_R0_seed_reducer_and_exception_planner","stage":"Stage_1.Part_2"},{"also_written_by":["Task_C_BO_F0_final_bo_compiler_gate_writer"],"consumer_tasks":["Task_C_BO_F0_final_bo_compiler_gate_writer"],"note":"R0 가 만들고 F0 이 FINALIZED 로 갱신해 다시 쓴다. 공동 기록자다.","optional":false,"path":"quality_gates/stage1_part2_review_handoff.json","path_is_pattern":false,"producer_task":"Task_C_BO_R0_seed_reducer_and_exception_planner","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_F0_final_bo_compiler_gate_writer"],"note":"조건부. exception_pack 의 exception_count 가 0 보다 크면 필수이고 부재는 실패다. 0 이면 부재를 허용하되 R1_SKIPPED 로 남긴다.","optional":true,"path":"stage1_tmp/task_c_bo/postb_adjudication_decisions.json","path_is_pattern":false,"producer_task":"Task_C_BO_R1_exception_adjudicator","root_key":"postb_exception_adjudication","schema_version":"task_c_bo_postb_exception_adjudication.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_S0_signal_bundle_writer","Stage_1.Part_3","Stage_1.Part_4","Stage_2"],"note":"최대 호환면. 레코드 구조를 바꾸지 않는다.","optional":false,"path":"BO.json","path_is_pattern":false,"producer_task":"Task_C_BO_F0_final_bo_compiler_gate_writer","stage":"Stage_1.Part_2"},{"consumer_tasks":["Stage_1.Part_3"],"optional":false,"path":"stage1_tmp/task_c_bo/postb_compiled_bundle_compact.json","path_is_pattern":false,"producer_task":"Task_C_BO_F0_final_bo_compiler_gate_writer","schema_version":"task_c_bo_postb_compiled_bundle_compact.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Stage_1.Part_3","Stage_1.Part_4","Stage_2"],"note":"transaction_id 는 ^S5TX-[a-f0-9]{20}$. downstream_read_sets 가 하류 정본 집합을 선언한다.","optional":false,"path":"signals/signal_manifest.json","path_is_pattern":false,"producer_task":"Task_C_BO_S0_signal_bundle_writer","schema_version":"signal_manifest.v2","stage":"Stage_1.Part_2"},{"consumer_tasks":["Stage_1.Part_3","Stage_1.Part_4"],"note":"구 이름 호환면. signals/compatibility_views/ 의 같은 바이트다.","optional":false,"path":"actio_case_signals.json","path_is_pattern":false,"producer_task":"Task_C_BO_S0_signal_bundle_writer","schema_version":"actio_case_signals.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Stage_1.Part_3","Stage_1.Part_4"],"optional":false,"path":"case_liability_signals.json","path_is_pattern":false,"producer_task":"Task_C_BO_S0_signal_bundle_writer","schema_version":"case_liability_signals.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Stage_1.Part_3","Stage_1.Part_4"],"optional":false,"path":"legal_effect_signals.json","path_is_pattern":false,"producer_task":"Task_C_BO_S0_signal_bundle_writer","schema_version":"legal_effect_signals.v1","stage":"Stage_1.Part_2"}],"purpose":"Stage 1 각 Part 의 인계 파일을 한 곳에 선언한다. 생산자·소비자·루트 키·필수 키가 코드에 흩어져 있으면 어긋나도 아무도 모른다.","schema_version":"stage1_part_interface.v1","status":"ACTIVE"} +{"authored_not_derived":"이 표는 계약이며 코드에서 뽑지 않았다. 코드에서 뽑으면 검사가 자기 자신을 확인하는 셈이 된다. 검사기(_check_stage1_interface.py)가 코드를 이 표와 대조한다.","checker":"validation_assets/routing/_check_stage1_interface.py","conventions":{"also_written_by":"선언된 생산자 외에 갱신을 허용하는 task. 생산자 위반으로 세지 않는다.","asset_paths_excluded":"Default_Agent/ 아래 정적 자산은 이 표의 대상이 아니다. 검사 10 이 따로 본다.","optional":"부재가 곧 실패는 아니지만 조건이 붙는다. note 를 읽는다.","path_is_pattern":" 자리는 런타임 값이다. 검사기는 접두·접미로 대조한다.","produced_by_module":"생산자 task 가 키 구성을 런타임 모듈에 위임할 때 그 모듈 경로. 필수 키 검사는 그 원문까지 함께 본다."},"entry_inputs":[{"consumer_tasks":["Task_A0_domain_screener_01","Task_A0_domain_screener_02","Task_A_client_goal","Task_B1_map_doc_*","Task_B2_map_events_*","Task_C_BO_A0_context_and_domain_slice_compiler"],"note":"사건 입력. 어느 task 도 쓰지 않는다. Part 2 A0 가 read_raw 로 직접 읽는다(C-8 반영).","optional":false,"path":"client_meeting.md","path_is_pattern":false,"producer_task":null,"stage":"INPUT"},{"consumer_tasks":["Task_Evidence_shard_planner"],"note":"사건 입력. 어느 task 도 쓰지 않는다.","optional":false,"path":"evidence_all.json","path_is_pattern":false,"producer_task":null,"required_keys":["documents","source_files","total_count"],"stage":"INPUT"}],"handoff_count":45,"handoffs":[{"consumer_tasks":["Task_A0_domain_screener_01","Task_A0_domain_screener_02","Task_A_client_goal","Task_B1_map_doc_*","Task_B2_map_events_*","Task_C_BO_A0_context_and_domain_slice_compiler"],"note":"사건 입력. 어느 task 도 쓰지 않는다. Part 2 A0 가 read_raw 로 직접 읽는다(C-8 반영).","optional":false,"path":"client_meeting.md","path_is_pattern":false,"producer_task":null,"stage":"INPUT"},{"consumer_tasks":["Task_Evidence_shard_planner"],"note":"사건 입력. 어느 task 도 쓰지 않는다.","optional":false,"path":"evidence_all.json","path_is_pattern":false,"producer_task":null,"required_keys":["documents","source_files","total_count"],"stage":"INPUT"},{"consumer_tasks":["Task_A0_domain_screener_02"],"note":"LLM 초안. 비판단 6종(schema_version·registry_version·registry_index_sha256·source_document_refs·screening_policy·contract_guards)을 담지 않는다. candidates 원소 키 구성은 닫힌 스키마의 후보 객체와 같아야 한다.","optional":false,"path":"routing/domain_screening_draft.json","path_is_pattern":false,"producer_task":"Task_A0_domain_screener_01","required_keys":["candidates","review_items","status","unmatched_issue_refs"],"root_key":"domain_screening_draft","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_A0_domain_screener_03","Task_A_client_goal","Task_D0_domain_activation_gate","Task_B2_SHA256_soft_gate_handoff_writer","Task_C_BO_A0_context_and_domain_slice_compiler"],"note":"screening_sha256 의 원문. 재직렬화 금지. Part 2 A0 는 봉인 원문 바이트와 별도로 candidates[].requested_calculation_domains 를 파싱해 슬라이스로 통과시킨다(R-2).","optional":false,"path":"routing/domain_screening.json","path_is_pattern":false,"producer_task":"Task_A0_domain_screener_02","required_keys":["candidates","contract_guards","registry_index_sha256","registry_version","review_items","schema_version","screening_policy","source_document_refs","status","unmatched_issue_refs"],"schema_version":"stage1_domain_screening.v1","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_A_client_goal"],"optional":false,"path":"routing/candidate_profile_vocabulary.md","path_is_pattern":false,"producer_task":"Task_A0_domain_screener_03","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B1_map_doc_*","Task_B1_quality_gate_evidence_indexed","Task_B2_quality_gate_event_candidates"],"optional":false,"path":"evidence_shard_plan.json","path_is_pattern":false,"producer_task":"Task_Evidence_shard_planner","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_D0_domain_activation_gate","Task_C_BO_A0_context_and_domain_slice_compiler"],"note":"T5 get_single_item 이 items[0] 을 통째로 싣는다. registry_component_ids 가 여기를 통과한다(C-1).","optional":false,"path":"evidence_indexed.json","path_is_pattern":false,"producer_task":"Task_B1_quality_gate_evidence_indexed","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_D0_domain_activation_gate","Task_C_BO_A0_context_and_domain_slice_compiler"],"optional":false,"path":"evidence_event_candidates.json","path_is_pattern":false,"producer_task":"Task_B2_quality_gate_event_candidates","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B2_quality_gate_event_candidates","Task_B12_gate_audit_finalizer"],"optional":false,"path":"stage1_tmp/quality_gate/B1_precheck.json","path_is_pattern":false,"producer_task":"Task_B1_quality_gate_evidence_indexed","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B2_quality_gate_event_candidates"],"optional":false,"path":"stage1_tmp/quality_gate/finalized_evidence_id_manifest.json","path_is_pattern":false,"producer_task":"Task_B1_quality_gate_evidence_indexed","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B12_gate_audit_finalizer"],"optional":false,"path":"stage1_tmp/quality_gate/B2_precheck.json","path_is_pattern":false,"producer_task":"Task_B2_quality_gate_event_candidates","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B12_gate_llm_adjudicator","Task_B12_gate_audit_finalizer"],"optional":false,"path":"stage1_tmp/quality_gate/B12_exception_pack.json","path_is_pattern":false,"producer_task":"Task_B2_quality_gate_event_candidates","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B12_gate_audit_finalizer"],"optional":false,"path":"stage1_tmp/quality_gate/B12_adjudication_decisions.json","path_is_pattern":false,"producer_task":"Task_B12_gate_llm_adjudicator","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_D0_domain_activation_gate","Task_B2_SHA256_soft_gate_handoff_writer"],"optional":false,"path":"quality_gates/B1_evidence_indexed_gate.json","path_is_pattern":false,"producer_task":"Task_B12_gate_audit_finalizer","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_D0_domain_activation_gate","Task_B2_SHA256_soft_gate_handoff_writer"],"optional":false,"path":"quality_gates/B2_event_candidates_gate.json","path_is_pattern":false,"producer_task":"Task_B12_gate_audit_finalizer","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_B2_SHA256_soft_gate_handoff_writer","Task_C_BO_A0_context_and_domain_slice_compiler","Task_C_BO_S0_signal_bundle_writer","Task_C_LE_L0_structure_seed_reducer","Task_C_LE_L2_final_structure_index_writer"],"note":"D-3 확정: execution_eligible 이 유일한 결정 필드. active ⊆ eligible. D0 은 활성 판정을 activation_gate 모듈에 위임한다 — 필수 키는 그 모듈이 만든다.","optional":false,"path":"routing/domain_activation_manifest.json","path_is_pattern":false,"produced_by_module":"stage1_runtime/activation_gate.py","producer_task":"Task_D0_domain_activation_gate","required_keys":["active_domain_ids","conservation_gate","contract_guards","domain_entries","expected_runnable_domain_ids","fail_open_policy","monitor_domain_ids","registry_index_sha256","registry_version","required_calculation_domains","review_items","schema_version","screening_sha256","signal_id","status","supporting_domain_ids","unrouted_material"],"root_key":"domain_activation_manifest","schema_version":"stage1_domain_activation_manifest.v1","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_C_BO_A0_context_and_domain_slice_compiler"],"note":"루트 래핑 없이 쓴다. 소비자는 stage1_part1_soft_gate_handoff 래핑 유무 둘 다 받아야 한다. digest_guard 는 screening_sha256·activation_manifest_sha256·registry_index_sha256 셋을 담는다.","optional":false,"path":"quality_gates/stage1_part1_soft_gate_handoff.json","path_is_pattern":false,"producer_task":"Task_B2_SHA256_soft_gate_handoff_writer","required_keys":["digest_guard","handoff_status","review_items","schema_version","source_stage"],"schema_version":"stage1_part1_soft_gate_handoff.v1","stage":"Stage_1.Part_1"},{"consumer_tasks":["Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_F0_final_bo_compiler_gate_writer"],"note":"v3 1104행이 정한 경로다. 옮기지 않는다.","optional":false,"path":"stage1_tmp/task_c_bo/stage_a_context.json","path_is_pattern":false,"produced_by_module":"stage1_runtime/stage_a_context_builder.py","producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","required_keys":["created_at_utc","event_candidate_map","evidence_authority_map","input_digests_sha256","meeting_clause_map","schema_version","status"],"root_key":"stage_a_context","schema_version":"task_c_bo_stage_a_context.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_S0_signal_bundle_writer"],"note":"v1 세 목록은 소비자 계약이므로 유지한다. v2 가 더한 evidence_count·registry_index_sha256 은 덧붙이기다(P0 판정 C 형태).","optional":false,"path":"stage1_tmp/task_c_bo/source_universe_manifest.json","path_is_pattern":false,"produced_by_module":"stage1_runtime/stage_a_context_builder.py","producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","required_keys":["event_candidate_ids","evidence_index_set","meeting_clause_ids","schema_version"],"schema_version":"task_c_bo_source_universe_manifest.v2","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_B_domain_worker_*","Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_S0_signal_bundle_writer"],"note":"task_instances[*] 는 domain_id 와 expected_output_path 를 갖는다.","optional":false,"path":"fanout/domain_fanout_plan.json","path_is_pattern":false,"producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","required_keys":["schema_version","task_instances"],"root_key":"domain_fanout_plan","schema_version":"domain_fanout_plan.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_S0_signal_bundle_writer","Task_C_B_domain_worker_*","Task_C_LE_L0_structure_seed_reducer"],"note":"R-1/R-2 로 domain_declarations 를 실은다. R0 는 worker 산출 검증에, S0 는 emits_signals 대조에 읽는다.","optional":false,"path":"runtime/domain_slices/.json","path_is_pattern":true,"producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","root_key":"stage_b_domain_slice","schema_version":"task_c_bo_stage_b_domain_slice.v2","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_B_domain_worker_*"],"note":"worker 는 이 프롬프트를 다시 만들지 않는다. compiled_prompt_sha256 이 일치해야 한다.","optional":false,"path":"runtime/compiled_prompts/.md","path_is_pattern":true,"producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","stage":"Stage_1.Part_2"},{"consumer_tasks":[],"note":"원인 분리 영수증. 동결기가 slice_sha256_by_domain 을 읽는다.","optional":false,"path":"validation_assets/routing/stage_receipt.json","path_is_pattern":false,"producer_task":"Task_C_BO_A0_context_and_domain_slice_compiler","required_keys":["activation_source","created_by","loader_mode","schema_injection","schema_version","slice_sha256_by_domain","stage","worker_mode"],"schema_version":"stage1_stage_receipt.v2","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_R0_seed_reducer_and_exception_planner","Task_C_BO_S0_signal_bundle_writer"],"optional":false,"path":"runtime/domain_seed_outputs/.json","path_is_pattern":true,"producer_task":"Task_C_B_domain_worker_*","root_key":"stage_b_domain_bo_seed_output","schema_version":"task_c_bo_stage_b_domain_bo_seed.v3","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_F0_final_bo_compiler_gate_writer"],"optional":false,"path":"stage1_tmp/task_c_bo/postb_seed_ledger.json","path_is_pattern":false,"producer_task":"Task_C_BO_R0_seed_reducer_and_exception_planner","root_key":"postb_seed_ledger","schema_version":"task_c_bo_postb_seed_ledger.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_R1_exception_adjudicator","Task_C_BO_F0_final_bo_compiler_gate_writer"],"note":"exception_count 가 R1 산출의 필수 여부를 정한다.","optional":false,"path":"quality_gates/stage1_part2_exception_pack.json","path_is_pattern":false,"producer_task":"Task_C_BO_R0_seed_reducer_and_exception_planner","stage":"Stage_1.Part_2"},{"also_written_by":["Task_C_BO_F0_final_bo_compiler_gate_writer"],"consumer_tasks":["Task_C_BO_F0_final_bo_compiler_gate_writer"],"note":"R0 가 만들고 F0 이 FINALIZED 로 갱신해 다시 쓴다. 공동 기록자다.","optional":false,"path":"quality_gates/stage1_part2_review_handoff.json","path_is_pattern":false,"producer_task":"Task_C_BO_R0_seed_reducer_and_exception_planner","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_F0_final_bo_compiler_gate_writer"],"note":"조건부. exception_pack 의 exception_count 가 0 보다 크면 필수이고 부재는 실패다. 0 이면 부재를 허용하되 R1_SKIPPED 로 남긴다.","optional":true,"path":"stage1_tmp/task_c_bo/postb_adjudication_decisions.json","path_is_pattern":false,"producer_task":"Task_C_BO_R1_exception_adjudicator","root_key":"postb_exception_adjudication","schema_version":"task_c_bo_postb_exception_adjudication.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_BO_S0_signal_bundle_writer","Stage_1.Part_4","Stage_2","Task_C_LE_L0_structure_seed_reducer","Task_C_LE_L2_final_structure_index_writer"],"note":"최대 호환면. 레코드 구조를 바꾸지 않는다.","optional":false,"path":"BO.json","path_is_pattern":false,"producer_task":"Task_C_BO_F0_final_bo_compiler_gate_writer","stage":"Stage_1.Part_2"},{"consumer_tasks":[],"note":" Part 3 개정(신전략서)은 읽지 않는다 — 소비자는 Part 4 착수 시 재평가.","optional":false,"path":"stage1_tmp/task_c_bo/postb_compiled_bundle_compact.json","path_is_pattern":false,"producer_task":"Task_C_BO_F0_final_bo_compiler_gate_writer","schema_version":"task_c_bo_postb_compiled_bundle_compact.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Stage_1.Part_4","Stage_2","Task_C_LE_L0_structure_seed_reducer"],"note":"transaction_id 는 ^S5TX-[a-f0-9]{20}$. downstream_read_sets 가 하류 정본 집합을 선언한다.","optional":false,"path":"signals/signal_manifest.json","path_is_pattern":false,"producer_task":"Task_C_BO_S0_signal_bundle_writer","schema_version":"signal_manifest.v2","stage":"Stage_1.Part_2"},{"consumer_tasks":["Stage_1.Part_4"],"note":"구 이름 호환면. signals/compatibility_views/ 의 같은 바이트다. Part 3 는 더 이상 읽지 않는다 — 정본 집합(downstream_read_sets.part3_L0)으로 이관 완료(C-7).","optional":false,"path":"actio_case_signals.json","path_is_pattern":false,"producer_task":"Task_C_BO_S0_signal_bundle_writer","schema_version":"actio_case_signals.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Stage_1.Part_4"],"note":" Part 3 는 더 이상 읽지 않는다 — 정본 집합(downstream_read_sets.part3_L0)으로 이관 완료(C-7).","optional":false,"path":"case_liability_signals.json","path_is_pattern":false,"producer_task":"Task_C_BO_S0_signal_bundle_writer","schema_version":"case_liability_signals.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Stage_1.Part_4"],"note":" Part 3 는 더 이상 읽지 않는다 — 정본 집합(downstream_read_sets.part3_L0)으로 이관 완료(C-7).","optional":false,"path":"legal_effect_signals.json","path_is_pattern":false,"producer_task":"Task_C_BO_S0_signal_bundle_writer","schema_version":"legal_effect_signals.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_LE_L0_structure_seed_reducer","Task_C_LE_L2_final_structure_index_writer"],"note":"SG-13 — Part 3 효과 경로 원천. L2 는 근거 보존 등식의 바깥 수를 여기서 직접 센다.","optional":false,"path":"signals/legal_effect_routes.json","path_is_pattern":false,"produced_by_module":"signals/compiler/common.py","producer_task":"Task_C_BO_S0_signal_bundle_writer","required_keys":["schema_version","signal_id","status","records"],"schema_version":"stage1_signal_sg13.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_LE_L0_structure_seed_reducer"],"note":"SG-05 — 근거 refs 원자.","optional":false,"path":"signals/legal_relation_lifecycle_signals.json","path_is_pattern":false,"produced_by_module":"signals/compiler/common.py","producer_task":"Task_C_BO_S0_signal_bundle_writer","required_keys":["schema_version","signal_id","status","records"],"schema_version":"stage1_signal_sg05.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_LE_L0_structure_seed_reducer"],"note":"SG-11 — 조인 키는 레코드 signal_id(worker request_id 승계).","optional":false,"path":"signals/calculation_requirements.json","path_is_pattern":false,"produced_by_module":"signals/compiler/common.py","producer_task":"Task_C_BO_S0_signal_bundle_writer","required_keys":["schema_version","signal_id","status","records"],"schema_version":"stage1_signal_sg11.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_LE_L0_structure_seed_reducer"],"note":"SG-02 — 레코드 0 이 정상(생산자 없음). L0 는 조인 없이 형식화 기록만 한다.","optional":true,"path":"signals/procedural_posture_relief_signals.json","path_is_pattern":false,"produced_by_module":"signals/compiler/common.py","producer_task":"Task_C_BO_S0_signal_bundle_writer","required_keys":["schema_version","signal_id","status","records"],"schema_version":"stage1_signal_sg02.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_LE_L0_structure_seed_reducer"],"note":"SG-07 — 레코드 0 이 정상. SG-02 와 같은 처리.","optional":true,"path":"signals/asset_right_state_signals.json","path_is_pattern":false,"produced_by_module":"signals/compiler/common.py","producer_task":"Task_C_BO_S0_signal_bundle_writer","required_keys":["schema_version","signal_id","status","records"],"schema_version":"stage1_signal_sg07.v1","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_LE_L0_structure_seed_reducer"],"note":"expected_runnable 도메인 중 실재하는 것만 읽는다 — 부재는 영수증 계수.","optional":true,"path":"signals/domain_signals/.json","path_is_pattern":true,"produced_by_module":"signals/compiler/common.py","producer_task":"Task_C_BO_S0_signal_bundle_writer","root_key":"domain_signal_envelope","schema_version":"stage1_domain_signals.v2","stage":"Stage_1.Part_2"},{"consumer_tasks":["Task_C_LE_L2_final_structure_index_writer"],"note":"구조 seed — Θ·전순서·부착. 닫힌 스키마 platform/schemas/structure_seed_bundle.schema.json.","optional":false,"path":"stage1_tmp/task_le/structure_seed_bundle.json","path_is_pattern":false,"produced_by_module":"stage1_runtime/structure_index_compiler.py","producer_task":"Task_C_LE_L0_structure_seed_reducer","root_key":"structure_seed_bundle","schema_version":"stage1_structure_seed_bundle.v1","stage":"Stage_1.Part_3"},{"also_written_by":["Task_C_LE_L2_final_structure_index_writer"],"consumer_tasks":["Task_C_LE_L2_final_structure_index_writer"],"note":"검토 채널 — 예외 pack 은 두지 않는다(L1 부재). L2 가 FINALIZED 로 갱신.","optional":false,"path":"quality_gates/stage1_part3_review_handoff.json","path_is_pattern":false,"producer_task":"Task_C_LE_L0_structure_seed_reducer","root_key":"stage1_part3_review_handoff","schema_version":"stage1_part3_review_handoff.v1","stage":"Stage_1.Part_3"},{"consumer_tasks":[],"note":"Part 4 F0 · Stage 2 가 읽는다. task 이름은 Part 4 착수 시 기입.","optional":false,"path":"legal_effect_structures.json","path_is_pattern":false,"producer_task":"Task_C_LE_L2_final_structure_index_writer","required_keys":["schema_version","status","structure_records","structure_index","quality_gate"],"schema_version":"stage1_legal_effect_structures.v1","stage":"Stage_1.Part_3"},{"consumer_tasks":[],"note":"검증 전용. 소비 task 없음.","optional":false,"path":"validation_assets/routing/part3_receipt.json","path_is_pattern":false,"producer_task":"Task_C_LE_L0_structure_seed_reducer","schema_version":"stage1_part3_receipt.v1","stage":"Stage_1.Part_3"},{"consumer_tasks":[],"note":"T1 최종 산출. Part 3 이후 스테이지가 읽는다 — task 이름은 그 착수 시 기입(C-8 등재).","optional":false,"path":"client_goal.json","path_is_pattern":false,"producer_task":"Task_A_client_goal","stage":"Stage_1.Part_1"}],"purpose":"Stage 1 각 Part 의 인계 파일을 한 곳에 선언한다. 생산자·소비자·루트 키·필수 키가 코드에 흩어져 있으면 어긋나도 아무도 모른다.","schema_version":"stage1_part_interface.v1","status":"ACTIVE"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/선행구축/Default_Agent_Stage_1/handoffs/stage1_stage_chain.v1.json b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/선행구축/Default_Agent_Stage_1/handoffs/stage1_stage_chain.v1.json index 8eed17a3..57e0cd4f 100644 --- a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/선행구축/Default_Agent_Stage_1/handoffs/stage1_stage_chain.v1.json +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/선행구축/Default_Agent_Stage_1/handoffs/stage1_stage_chain.v1.json @@ -1 +1 @@ -{"enforcement":{"declared":true,"note":"강제와 선언은 다르다. 이 파일이 선언을 맡는다.","runtime_guard":"Task_C_BO_A0 가 봉인 세 해시를 대조하므로 Part 1 미수행 시 SEAL_FAILED 로 멈춘다."},"interface_table":"handoffs/stage1_part_interface.v1.json","purpose":"Part 1~4 의 실행 순서와 인계 파일을 선언한다. 지금은 각 통합본의 prevs/nexts 가 비어 있어 순서가 A0 의 파일 부재 실패로 사실상 강제될 뿐 선언되어 있지 않다.","schema_version":"stage1_stage_chain.v1","stages":[{"order":1,"part":"Stage_1.Part_1","produces":["routing/domain_activation_manifest.json","quality_gates/stage1_part1_soft_gate_handoff.json","routing/domain_screening.json","evidence_indexed.json","evidence_event_candidates.json"],"requires":["client_meeting.md","evidence_all.json"],"yaml":"stage_1_part_1_v.8.yml"},{"order":2,"part":"Stage_1.Part_2","produces":["BO.json","signals/signal_manifest.json","actio_case_signals.json","case_liability_signals.json","legal_effect_signals.json","stage1_tmp/task_c_bo/postb_compiled_bundle_compact.json"],"requires":["routing/domain_activation_manifest.json","quality_gates/stage1_part1_soft_gate_handoff.json","routing/domain_screening.json","evidence_indexed.json","evidence_event_candidates.json"],"yaml":"stage_1_part_2_v.8.yml"},{"note":"정본 signal 집합으로의 이관은 Part 3 개정의 몫이다.","order":3,"part":"Stage_1.Part_3","produces":[],"requires":["BO.json","signals/signal_manifest.json"],"yaml":"Stage_1_Part_3_Claude_v2.yml"},{"note":"같음.","order":4,"part":"Stage_1.Part_4","produces":[],"requires":["BO.json","signals/signal_manifest.json"],"yaml":"Stage_1_Part_4_Claude_v3.yml"}],"status":"ACTIVE"} +{"enforcement":{"declared":true,"note":"강제와 선언은 다르다. 이 파일이 선언을 맡는다.","runtime_guard":"Task_C_BO_A0 가 봉인 세 해시를 대조하므로 Part 1 미수행 시 SEAL_FAILED 로 멈춘다."},"interface_table":"handoffs/stage1_part_interface.v1.json","purpose":"Part 1~4 의 실행 순서와 인계 파일을 선언한다. 지금은 각 통합본의 prevs/nexts 가 비어 있어 순서가 A0 의 파일 부재 실패로 사실상 강제될 뿐 선언되어 있지 않다.","schema_version":"stage1_stage_chain.v1","stages":[{"order":1,"part":"Stage_1.Part_1","produces":["routing/domain_activation_manifest.json","quality_gates/stage1_part1_soft_gate_handoff.json","routing/domain_screening.json","evidence_indexed.json","evidence_event_candidates.json"],"requires":["client_meeting.md","evidence_all.json"],"yaml":"stage_1_part_1_v.8.yml"},{"order":2,"part":"Stage_1.Part_2","produces":["BO.json","signals/signal_manifest.json","actio_case_signals.json","case_liability_signals.json","legal_effect_signals.json","stage1_tmp/task_c_bo/postb_compiled_bundle_compact.json"],"requires":["routing/domain_activation_manifest.json","quality_gates/stage1_part1_soft_gate_handoff.json","routing/domain_screening.json","evidence_indexed.json","evidence_event_candidates.json"],"yaml":"stage_1_part_2_v.8.yml"},{"note":"정본 signal 집합(downstream_read_sets.part3_L0) 이관 완료. L1 없음 — 2 task 직렬.","order":3,"part":"Stage_1.Part_3","produces":["legal_effect_structures.json","stage1_tmp/task_le/structure_seed_bundle.json","quality_gates/stage1_part3_review_handoff.json","validation_assets/routing/part3_receipt.json"],"requires":["BO.json","signals/signal_manifest.json","routing/domain_activation_manifest.json"],"yaml":"stage_1_part_3_v.8.yml"},{"note":"같음.","order":4,"part":"Stage_1.Part_4","produces":[],"requires":["BO.json","signals/signal_manifest.json"],"yaml":"Stage_1_Part_4_Claude_v3.yml"}],"status":"ACTIVE"} diff --git a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/확장_최적워크플로우_연구_프롬프트.txt b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/확장_최적워크플로우_연구_프롬프트.txt index 41e97d9c..30f07b8c 100644 --- a/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/확장_최적워크플로우_연구_프롬프트.txt +++ b/Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.7/extension_research/확장_최적워크플로우_연구_프롬프트.txt @@ -2110,10 +2110,6 @@ MEMORY.md 파일에는 지금까지의 작업 내역들이 압축적으로 요 --> 이 기준을 prompt에 명시해야 한다. - - - - ┌────────────────────────────────────────────┐ │ │ │ 1st Execution of Update Strategy of Part 3 │ @@ -2125,21 +2121,21 @@ MEMORY.md 파일에는 지금까지의 작업 내역들이 압축적으로 요 -지금까지 stage 1 -- part 1|2 개정작업을 진행했다. -`stage_1_part_1_v.8.yml`, `stage_1_part_2_v.8.yml`를 검증하여 두 작업명세서가 모두 의도한 작업 과정을 실행하는 것을 확인했다. +지금까지 stage 1 -- part 1|2 개정작업을 진행하여 yaml 작업명세서 `stage_1_part_1_v.8.yml`와 `stage_1_part_2_v.8.yml`를 생성했다. +두 yaml 작업명세서는 검증을 통해 모두 의도한 작업 과정을 실행함을 확인했다. -이제 `stage_1_part_3_개정_신전략서.md`가 제시하는 방식을 실행하여 part 3 작업의 궁극적 목적(목표/목적물)을 '최소 작업으로 최고 품질로 달성'하는 원칙을 기반으로 두고 최적 워크플로우를 구성하여 작업명세서(yaml & related assets)를 개정 생성하고자 한다. +이제 `stage_1_part_3_개정_신전략서.md`가 제시하는 방식을 실행하여 part 3 작업의 궁극적 목적(목표/목적물)을 '최소 작업으로 최고 품질로 달성'하는 원칙을 달성하는 part 3 작업명세서(yaml & related assets)를 생성하고자 한다. 1. `stage_1_part_3_개정_신전략서.md`의 작업 내용들을 독립적으로 동시 실행가능한 task들과, 직렬로 sequential 방식으로 실행해야 할 task들로 분류한다. -2. 1의 결과를 바탕으로 독립 동시 실행 가능한 task들은 병렬로 동시 실행하고, sequential 방식으로 실행해야 하는 task들은 upstream-downstream 작업 consistency를 유지하면서 실행한다. -3. 2번 작업을 수행한 후 sub-agent를 띄워서 2번 작업이 `stage_1_part_3_개정_신전략서.md`가 지시하는 사항들을 100% 정확하게 준수하여 작업을 `완수`했는지 검증한다. Sub-agent가 100% 검증 통과라고 판정할 때까지, 2번 작업을 반복한다. +2. 1의 결과를 바탕으로 독립 동시 실행 가능한 task들은 병렬로 동시 실행하고, sequential 방식으로 실행해야 하는 task들은 upstream-downstream 작업 consistency를 유지하면서 실행하여 part 3의 yaml 작업명세서를 작성한다. +3. 2번 작업을 수행한 후 sub-agent를 띄워서 2번 작업이 `stage_1_part_3_개정_신전략서.md`가 지시하는 사항들을 100% 정확하게 준수하여 작업을 수행했는지 검증한다. Sub-agent가 100% 검증 통과라고 판정할 때까지, 2번 작업(yaml 작성 & 검증)을 반복한다. 4. 3번 작업이 완료되면, 작업 결과물 중 저장해야 할 자산들(assets)을 `extension_research/Default_Agent` 폴더에 배포 위치를 정확히 지켜서 저장하고, part 3 작업명세서를 `extension_research/ver_8_yaml_candidates/stage_1_part_3_v.8.yml`로 생성한다. 1. 작업 시, 기존 yaml 작업명세서('v.7/Claude_YAML'의 yaml 파일들)와 관련한 dependency는 완전히 제거한다. 즉, 기존 yaml 작업 명세서가 지시하는 내용에 전혀 의존하지 않도록 한다. -2. Stage 1 -- part 1|2 작업이 사용하는 자산들의 명칭과 배포 위치 그리고 포맷은 `extension_research/Default_Agent` 폴더에 저장되어 있으며, 앞으로 Part 3 개정 작업을 통해 생성될 Stage 1 (part 상관없이) 실행 시 사용될 모든 자산(md, .py, .txt, .json)들은 이 폴더에 정확한 배포 위치 서브 폴더에 저장한다. +2. Stage 1 -- part 1|2 작업이 사용하는 자산들의 명칭과 배포 위치 그리고 포맷은 `extension_research/Default_Agent` 폴더에 저장되어 있으며, 앞으로 개정 생성될 Part 3 yaml 작업명세서가 실행되어 생성될 모든 자산(md, .py, .txt, .json)들은 이 폴더의 정확한 배포 위치(서브 폴더)에 저장한다. 3. Liti-agent가 stage # yaml 작업명세서를 실행하여 작업을 `완수`했다는 표현을 사용할 때, `완수`의 기준은 단순히 yaml 작업명세서를 끝까지 실행 완주할 수 있다는 것이 아니다. Yaml 작업명세서를 실행했을 때, 원래 의도한 결과물들이 올바른 방식으로 생성되어야 하고, 소작업(sub-task)들의 upstream-downstream 간에 consistency(넘겨받은 파일을 올바로 읽고, handoff로 넘겨주는 파일도 정해진 포맷에 맞게 넘겨줌)를 유지하여 작업이 끝까지 이어진 경우를 작업이 `완수`되었다고 평가한다. 4. Stage 1 전체 작업에 대한 아래 내용을 절대 규칙으로 삼는다. @@ -2156,6 +2152,15 @@ MEMORY.md 파일에는 지금까지의 작업 내역들이 압축적으로 요 - yaml 작성을 할 때는 의 규칙을 엄격하게 준수하며, python code를 작성할 때는 가 제시하는 Python code 작성 규칙을 엄수한다. +================================== + + + + + +--> stage 1 -- part 3 개정 작업 최적 워크플로우 탐구 --> 작업 명세서 생성 +--> stage 1 -- part 3 개정 --> 남은 작업 check --> 추가작업 명세서 생성 및 작업 수행 --> part 3 개정 마무리 + @@ -2188,102 +2193,6 @@ MEMORY.md 파일에는 지금까지의 작업 내역들이 압축적으로 요 -┌────────────────────────────────────────────┐ -│ │ -│ 1st Execution of Update Strategy of Part 3 │ -│ │ -└────────────────────────────────────────────┘ - - -`stage_1_part_3_개정방안전략서.md`를 실행하여 stage 1 -- part 3 작업명세서를 개정한다. - - - -지금까지 stage 1 -- part 1|2 개정작업을 진행했다. -`stage_1_part_1_v.8.yml`, `stage_1_part_2_v.8.yml`를 검증하여 두 작업명세서가 모두 의도한 작업 과정을 실행하는 것을 확인했다. - -이제 `stage_1_part_3_개정방안전략서.md`가 제시하는 방식을 실행하여 part 3 작업명세서(yaml & related assets)를 개정하고자 한다. - - - -1. 구 part 3 yaml('v.7/Claude_YAML/Stage_1_Part_3_Claude_v2.yml')를 확인한다. -2. `stage_1_part_3_개정방안전략서.md`가 제시하는 개정 방법을 읽고, 독립 실행 가능한 task들과 sequential 작업이 필요한 task들로 분류한다. -3. 2번 과정에서 분류한 task들에 대해서 독립 실행 가능한 task들은 병렬로 작업을 수행하고, sequential 작업이 필요한 task들은 upstream-downstream consistency를 유지하면서 작업을 수행한다. 작업 수행 시 아래 제시한 를 준수한다. -4. 3번 작업 과정에서 얻은 결과물들은 기본적으로 `v.7/extension_research/ver_8_yaml_candidates` 폴더에 '정확한 배포 위치'로 저장하는 것을 원칙으로 한다. 작업 수행 과정에서 기존 stage 1 -- part 3의 개별 작업용 yaml 파일들, md 파일들, python code (.py|.txt)들을 수정하거나 재작성하면 기존 파일들은 outdated 폴더로 옮기고, 수정 및 재작성한 파일은 기존 파일들을 대체하는 방식으로 정확한 배포 위치에 생성한다. 신규 작성한 자산이 있다면 그 역시 정확한 배포 위치에 저장한다. -5. 작업을 완료하면 독립적으로 sub-agent를 띄워서 `stage_1_part_3_개정방안전략서.md`가 제시하는 개정 방법에 따라 작업이 100% 수행되었는지 검증한다. 만일 검증을 통과하지 못한 작업 내용이 존재하면 그 작업 내역만을 incremental 수정한다. 이 과정은 sub-agent의 검증을 통과할 때까지 반복한다. -6. 5번 검증까지 통과하여 작업을 완료하면 작업 내역서를 문서로 작성하여 'v.7/extension_research/stage_1_part_3_1차개정작업.md'로 생성한다. - - -1. 작업 시, 기존 yaml 작업명세서('v.7/Claude_YAML'의 yaml 파일들)와 관련한 dependency가 없도록 한다. 즉, 기존 yaml 작업 명세서가 지시하는 내용에 절대 의존하면 안된다. 새로 작성하는 yaml이나 자산들은 기존 작업명세서에서 지시하는 내용과는 별개로 독립적인 결과물이어야 한다. -2. Stage 1 -- part 1|2 작업이 사용하는 자산들의 명칭과 배포 위치 그리고 포맷들을 정확히 활용한다. -3. Stage 1 전체 작업에 대한 아래의 절대 규칙을 'conerstone'으로 삼는다. - -- Liti-agent는 대한민국 민사소송 사건종류 137종을 모두 다룰 수 있도록 개발되어야 한다. -- Stage 1 에서는 Liti-agent가 137종 중 그 어떤 사건을 다루더라도 `레지스트리 기반` 방식으로 사건 종류의 이름이 아니라 증거 구성요소·요건 슬롯·단서로 구조화된 정보를 확보하는 것을 목표로 한다. 이를 위해 사용할 자산들이 '법리 도메인, 계산 도메인, signal'이며 이에 대한 정의는 `v.7/extension_research/ensemble_v2.md`에 제시되어 있다. - - - - - - -- `v.7/CLAUDE.md`가 제시하는 Opus 5 행동 규칙을 준수한다. -- 작업 완료 시 작업 내역을 압축 요약하여 `v.7/MEMORY.md`에 추가 기입한다. -- yaml 작성을 할 때는 의 규칙을 엄격하게 준수하며, python code를 작성할 때는 가 제시하는 Python code 작성 규칙을 엄수한다. - - - - - - - - - - - - - - - - - - - ---> stage 1 -- part 3 개정 --> 남은 작업 check --> 추가작업 명세서 생성 및 작업 수행 --> part 3 개정 마무리 - - - - - -[다음] -- stage 1 -- part 2에서 더 개정할 작업이 남아있는가? -- if no -> 오늘 stage 1 -- part 2 개정 작업 결과물을 읽어들여서 `stage_1_part_1_and_2_updated_yaml_analysis.md`를 incremental update하여 `stage_1_part_1_and_2_updated_yaml_analysis.md`로 생성 (기존 파일은 `stage_1_part_1_and_2_updated_yaml_analysis_old.md`로 파일명을 바꿔서 outdated 폴더로 이송) -- `stage_1_part_1_and_2_updated_yaml_analysis.md` 내용을 기반으로 part 3 최적 개정 방식 탐구 - - 기존 stage_1_update_strategy.md가 제시한 part 3 개정 작업 내용 및 DAG 형식 참조 - - -Part 3 — 법률효과 구조 -P3-L0 -> P3-L1 -> P3-L2 -§4. Part 3 세부 워크플로우 - - §4.1 P3-L0 구조 seed 축약 [개정] - - §4.2 P3-L1 예외 판정 - - §4.3 P3-L2 최종 색인 기록 [개정] - -최적 개정 작업 전략서 작성 - - - - - - -┌─────────────────────────────┐ -│ Must Task │ -└─────────────────────────────┘ -MEMORY.md에 기록된 {{실측이 리포트와 갈린 곳 · 문서가 처음 기록한 것}}에 제시된 내용을 참조한 리포트는 파일명 마지막에 '_outdated'를 붙여서 남기고, {{실측이 리포트와 갈린 곳 · 문서가 처음 기록한 것}} 내용을 반영하여 기존 리포트에 반영하여 새 리포트를 동일한 파일명으로 생성하라. - - -=> 리포트에 반영하여, 리포트 개정 요망 - - ================================== ## 개정 작업에서 지켜야 할 절대적인 기준(cornerstone): @@ -2314,13 +2223,6 @@ Opus 5에 명시적으로 검증 작업을 시킬 때, 검증 100% 통과할 때 - - -[2] [1]의 md 문서를 기준으로 ---> stage 1 -- part 3 개정 작업 최적 워크플로우 탐구 --> 작업 명세서 생성 ---> stage 1 -- part 3 개정 --> 남은 작업 check --> 추가작업 명세서 생성 및 작업 수행 --> part 3 개정 마무리 - - [3] Stage 1 -- part 1, 2, 3 개정 작업 요약 기존 stage 1 -- part 1, 2 개정 작업 요약본에 stage 1 -- part 3 개정 작업본을 추가 입력하여 업데이트 @@ -2342,42 +2244,6 @@ Stage 1 -- part 1, 2, 3 개정 작업 요약 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Part 2 작업 검증 Part 3 개정 작업 리서치 Part 3 개정 yaml 작성 @@ -2387,6 +2253,13 @@ Part 4 개정 yaml 작성 --> 안종선이 step by step으로 실행하고, 결과물을 내가 체크하여 수정, 추후 다시 실행 --> stage 1 4개 yaml 파일들이 문제없이 실행되도록 완료 + + + +┌────────────────────────────────────────────┐ +│ Sketch of How to Update Stage 2 │ +└────────────────────────────────────────────┘ + [Stage 1 작업 내역들 + DAG + stage 2 작업 목표 + 기존 stage 2 yaml] 종합하여 stage 2 최적 워크플로우 탐구 --> 큰 덩어리: @@ -2412,10 +2285,14 @@ Part 4 개정 yaml 작성 -`stage_1_part_2_optimal_update_strategy.md`를 수행한다. + ========================================================================== +┌────────────────────────────────────────────┐ +│ Structure of Prompt │ +└────────────────────────────────────────────┘ + @@ -2463,98 +2340,6 @@ Part 4 개정 yaml 작성 -[질문] - 1. `registry_component_ids`를 `evidence_indexed` 내부의 항목으로 표현되도록 `evidence_indexed` json schema에 포함시키면 되나? -만일 답이 '예'라면, 'part_2_update_addition.md'의 "§1. `registry_component_ids`는 파일이 아니다"에 제시된 내용을 반영하여 작업을 실행하면 `registry_component_ids`를 `evidence_indexed` 내부의 항목으로 표현되게 하는가? - -2. `evidence_indexed`를 검증하는 json schema가 반드시 필요한가? 예, 아니오로 답하고 이유를 한 문단 이내로 설명하라. - - - - - - - - - - - - - - - - - - - -조건 -Stage 1 part 1 단일 yaml 파일 생성 -DAG 표현 정확히 기입 -Python code 표현 정확히 - - - -케이무크 작업 실행 계획 세우기 - - - - - - - - - - - - - - - - - - - -4 + 2 + 3 + 0.5 = 9.5 -1 + 1 + 0.5 + 0.5 = 3 - -12.5 1억 2천 5백 -총 2억 모음 --> tips 진행 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -