feat: 리밸런싱 엔진 V1 + GAS 버그 수정 (2026-06-13)

주요 변경:
- tools/build_rebalance_engine_v1.py: REBALANCE_ENGINE_V1 신규
  * account_snapshot 직접 합산(_build_snap_position_map) → 소수주 분리 행 병합
  * 레짐 소스 macro.REGIME_PRELIM 최우선 (GAS 와 동일)
- src/gas_adapter_parts/gdf_06_rebalance.gs: runRebalanceSheet_() 신규
  * Logger.log / getSpreadsheet_() 로 run_all 연동 수정
- src/gas_adapter_parts/gdc_01_fetch_fundamentals.gs
  * _mergePositionRecord_(): 소수주 중복 행 합산 신규
  * parseInt → parseFloat (qty, availQty)
- src/gas_adapter_parts/gdf_01_price_metrics.gs
  * 미보유 종목 SELL_READY → WATCH_EXIT_SIGNAL
- spec/41_release_dag.yaml: build_rebalance_sheet 노드 추가 (step_count 63)
- spec/51_formula_lifecycle_registry.yaml: REBALANCE_ENGINE_V1 등록

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 13:20:14 +09:00
commit ee3e799de1
1474 changed files with 176087 additions and 0 deletions
@@ -0,0 +1,25 @@
# ADR-0001 Adopt active artifact manifest
## Context
Temp contains multiple artifact versions and the runtime must read only one active path per artifact key.
## Decision
Use `runtime/active_artifact_manifest.yaml` as the only runtime selection source.
See `spec/09_decision_flow.yaml` and `tools/validate_active_manifest.py` for the runtime gate and selection checks.
## Alternatives
- Scan Temp directly
- Pick latest timestamp
## Consequences
- Deterministic runtime file selection
- Lower stale-read risk
## Rollback
Restore prior manifest only if validation fails.
## Affected files
- runtime/active_artifact_manifest.yaml
- spec/09_decision_flow.yaml
- tools/validate_active_manifest.py
+22
View File
@@ -0,0 +1,22 @@
# ADR-0002 Authority matrix
## Context
Output fields need a single declared owner to prevent duplicate writers.
## Decision
Maintain a governance authority matrix and output-field owner ledger.
## Alternatives
- Embed ownership in ad hoc notes
## Consequences
- Ownership collision checks become explicit
- Review is easier for numeric outputs
## Rollback
Keep the prior ledger alongside the new one.
## Affected files
- governance/authority_matrix.yaml
- spec/03_formulas/output_field_owner_ledger.yaml
+23
View File
@@ -0,0 +1,23 @@
# ADR-0003 Baseline metrics
## Context
Refactor progress needs a fixed baseline.
## Decision
Record repository baseline metrics as build output.
See `tools/validate_calibration_registry_v1.py` and `spec/08_scoring_rules.yaml` for baseline-linked validation context.
## Alternatives
- Report metrics manually in review notes
## Consequences
- Delta tracking becomes deterministic
## Rollback
Regenerate from a prior commit if needed.
## Affected files
- Temp/refactor_baseline_metrics_v1.json
- tools/validate_calibration_registry_v1.py
- spec/08_scoring_rules.yaml
+21
View File
@@ -0,0 +1,21 @@
# ADR-0004 Rule lifecycle
## Context
Rule proliferation needs a lifecycle policy.
## Decision
Use proposed -> shadow -> active -> deprecated -> removed.
## Alternatives
- Free-form status labels
## Consequences
- Deprecation is explicit
- Active router reference checks become possible
## Rollback
Downgrade the rule to shadow if needed.
## Affected files
- governance/rule_lifecycle.yaml
@@ -0,0 +1,22 @@
# ADR-0005 Formula domain split
## Context
The monolithic formula registry needs domain separation.
## Decision
Split formulas by domain and build a normalized registry.
## Alternatives
- Keep a single registry file
## Consequences
- Review scope is reduced
- Formula ownership is easier to track
## Rollback
Rebuild normalized registry from the monolith.
## Affected files
- spec/formulas/*
- spec/03_formulas/formula_registry.normalized.yaml
@@ -0,0 +1,24 @@
# ADR-0006 Final decision packet
## Context
The renderer needs a single canonical packet.
## Decision
Use a versioned final decision packet as the only render input.
See `spec/07_output_schema.yaml` and `tools/validate_report_packet_sync_v1.py` for the canonical packet/render contract.
## Alternatives
- Read many Temp files directly
## Consequences
- Provenance checks become centralized
## Rollback
Keep the previous packet version available.
## Affected files
- Temp/final_decision_packet_v3.json
- Temp/final_decision_packet_active.json
- spec/07_output_schema.yaml
- tools/validate_report_packet_sync_v1.py
+20
View File
@@ -0,0 +1,20 @@
# ADR-0007 Shadow ledger
## Context
Blocked items still need visible computed values.
## Decision
Separate executable order table from shadow ledger.
## Alternatives
- Hide blocked numbers
## Consequences
- User review is preserved
## Rollback
Show the prior packet alongside the new ledger if needed.
## Affected files
- spec/outputs/shadow_ledger_contract.yaml
+20
View File
@@ -0,0 +1,20 @@
# ADR-0008 Renderer contract
## Context
Low-capability LLM rendering needs a closed contract.
## Decision
Fix the input packet, section order, and numeric copy rules.
## Alternatives
- Free-form narrative generation
## Consequences
- Lower hallucination risk
## Rollback
Use the prior prompt only if schema validation fails.
## Affected files
- prompts/low_capability_report_renderer.md
+20
View File
@@ -0,0 +1,20 @@
# ADR-0009 Number provenance audit
## Context
Every investment number must be traceable.
## Decision
Require source_ref and formula_id for investment numbers.
## Alternatives
- Allow implicit report numbers
## Consequences
- Ungrounded numbers are detectable
## Rollback
Rebuild the report from a provenance-backed packet.
## Affected files
- tools/validate_number_provenance_v2.py
@@ -0,0 +1,20 @@
# ADR-0010 Change request template
## Context
Rule and formula changes need structured evidence.
## Decision
Use a mandatory change-request template for active changes.
## Alternatives
- Free-form change notes
## Consequences
- Rollback and testing become explicit
## Rollback
Reject changes that lack the required fields.
## Affected files
- governance/change_request_template.yaml
+19
View File
@@ -0,0 +1,19 @@
# ADR-0011: QEDD 방법론 채택
## 상태
준비됨 (Proposed)
## 배경
퀀트 엔진의 복잡도가 증가함에 따라, 저성능 LLM에서도 동일한 투자 결론을 재현하고 운영 안정성을 확보하기 위한 결정론적 개발 방법론이 필요함.
## 결정
QEDD(Quant Evidence-Driven Deterministic Development) 방법론을 채택함.
1. 모든 판단 로직은 YAML 계약(spec)에 근거함.
2. 모든 수치 계산은 Python Canonical 엔진에서만 수행함.
3. GAS는 데이터 수집 및 입출력 어댑터 역할로 축소함.
4. LLM은 이미 계산된 패킷을 복사하여 렌더링하는 역할만 수행함 (Math 금지).
## 결과
- 운영 보고서의 숫자 신뢰도 100% 확보.
- 저성능 모델에서도 판단 번복 없는 안정적인 운영 가능.
- 아키텍처 경계 위반 자동 차단.
+44
View File
@@ -0,0 +1,44 @@
schema_version: adr_index.v1
adr_count: 10
entries:
- adr_id: ADR-0001
title: Adopt active artifact manifest
status: accepted
path: governance/adr/0001-adopt-active-artifact-manifest.md
- adr_id: ADR-0002
title: Adopt authority matrix
status: accepted
path: governance/adr/0002-authority-matrix.md
- adr_id: ADR-0003
title: Freeze baseline metrics
status: accepted
path: governance/adr/0003-baseline-metrics.md
- adr_id: ADR-0004
title: Introduce rule lifecycle policy
status: accepted
path: governance/adr/0004-rule-lifecycle.md
- adr_id: ADR-0005
title: Split formula registry by domain
status: accepted
path: governance/adr/0005-formula-domain-split.md
- adr_id: ADR-0006
title: Make final decision packet canonical
status: accepted
path: governance/adr/0006-final-decision-packet.md
- adr_id: ADR-0007
title: Mandatory shadow ledger
status: accepted
path: governance/adr/0007-shadow-ledger.md
- adr_id: ADR-0008
title: Low capability renderer contract
status: accepted
path: governance/adr/0008-renderer-contract.md
- adr_id: ADR-0009
title: Number provenance audit
status: accepted
path: governance/adr/0009-number-provenance.md
- adr_id: ADR-0010
title: Change request template
status: accepted
path: governance/adr/0010-change-request-template.md
+12
View File
@@ -0,0 +1,12 @@
schema_version: agents_index.v1
source: AGENTS.md
purpose: Compact index for operator rules migrated out of AGENTS.md.
rule_files:
- governance/rules/00_core_locks.yaml
- governance/rules/01_harness_contract.yaml
- governance/rules/02_portfolio_policy.yaml
- governance/rules/03_order_grammar.yaml
- governance/rules/04_reporting_contract.yaml
- governance/rules/05_migration_hashes.yaml
hash_manifest: governance/agents_rule_hashes.yaml
hash_algorithm: sha256
+18
View File
@@ -0,0 +1,18 @@
schema_version: agents_rule_hashes.v1
hash_algorithm: sha256
generated_from: governance/agents_index.yaml
files:
- path: governance/rules/00_core_locks.yaml
sha256: b3c3d7ce05beb9e8b0945d98a0a1a55276254acef246c13f8c3a110f14f57ff4
- path: governance/rules/01_harness_contract.yaml
sha256: a093ddafa4a1b624ee44e4a98a63ce196ad452572fb27418c7e82b9b5edafc5a
- path: governance/rules/02_portfolio_policy.yaml
sha256: 47f6f33602482213523e6fdfa191309a34b805fc7acbe4aa84f475ece899a8ad
- path: governance/rules/03_order_grammar.yaml
sha256: cbcde916be0929cb1ba7fdbe9922c4445e375ea5d39654d96b86e1e80313cca9
- path: governance/rules/04_reporting_contract.yaml
sha256: 6ec102fcd3f8c50325ca793b8709200ec688526673405f594e5a03c137300f7b
- path: governance/rules/05_migration_hashes.yaml
sha256: fed17361105a22161e974b9503a5908c8d332f66b19503a6d6a4d12ceabaef75
- path: AGENTS.md
sha256: 8d7748597bb248c46db6089cd09da8d4af3f7eadc55243f8afaf4aebaea82fcf
+10
View File
@@ -0,0 +1,10 @@
formula_id: FORMULA_AUTHORITY_MATRIX_V1
generated_at: '2026-06-06T00:00:00+09:00'
owned_output_field_pct: 100.0
authority_collision_count: 0
manual_override_field_count: 0
source:
formula_owner_coverage: Temp/formula_owner_coverage_v1.json
output_field_collision: Temp/output_field_owner_collision_v1.json
output_field_ledger: spec/03_formulas/output_field_owner_ledger.yaml
field_dictionary: spec/12_field_dictionary.yaml
+18
View File
@@ -0,0 +1,18 @@
change_request_template_version: v1.0
proposal_metadata:
proposal_id: "CR-YYYYMMDD-NAME"
author: "quant_architect"
created_at: "YYYY-MM-DD"
rationale:
why: "State the reason for this change request"
expected_edge: "Describe the expected analytical edge or performance lift"
risk: "Outline potential failure modes and risk exposure changes"
dependencies:
data_dependency: "List of workbook columns or API data sources required"
verification:
tests:
- "List unit/regression tests or golden cases that validate this change"
rollback_plan: "Actionable rollback steps if the change fails verification"
outcome_metrics:
expected_t5_pass_rate_pct: 60.0
expected_expectancy: 0.10
@@ -0,0 +1,18 @@
change_request_template_version: v1.0
proposal_metadata:
proposal_id: "CR-0001"
author: "quant_architect"
created_at: "2026-06-03"
rationale:
why: "Example change request placeholder"
expected_edge: "improved provenance visibility"
risk: "none"
dependencies:
data_dependency: "existing methodology todo"
verification:
tests:
- "validate_final_decision_packet"
rollback_plan: "revert packet builder"
outcome_metrics:
expected_t5_pass_rate_pct: 60.0
expected_expectancy: 0.10
@@ -0,0 +1,18 @@
change_request_template_version: v1.0
proposal_metadata:
proposal_id: "CR-20260607-SAMPLE"
author: "quant_architect"
created_at: "2026-06-07"
rationale:
why: "Integrate property and metamorphic invariants"
expected_edge: "Stable execution decisions"
risk: "Increase computation time slightly"
dependencies:
data_dependency: "spec/property_invariants.yaml"
verification:
tests:
- "validate_property_invariants"
rollback_plan: "Remove validate_property_invariants from DAG"
outcome_metrics:
expected_t5_pass_rate_pct: 65.0
expected_expectancy: 0.12
@@ -0,0 +1,205 @@
schema_version: gas_logic_migration_ledger.v1
source: governance/gas_logic_migration_ledger_v1.yaml
authored: 2026-06-10
total_findings: 15
classification_summary:
decision_logic: 4
score_logic: 5
price_qty_logic: 4
pure_mapping: 1
display_text: 1
unclassified_findings: 0
# Canonical classification of GAS thin-adapter findings identified by
# validate_gas_thin_adapter_v1.py. Each finding is classified by what type
# of logic it contains and paired with a migration_action.
findings:
- id: F01
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
line: 186
text: "SP_TAKE_PROFIT: 10, // Profit_Pct >= 10% (익절 후보)"
classification: score_logic
migration_action: REGISTER_SP_TAKE_PROFIT
target_file: formulas/score_thresholds_v1.py
status: TODO
- id: F02
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
line: 656
text: "priceBasis = Number.isFinite(tp2Price) ? \"TAKE_PROFIT_TIER2_PRICE\" : \"PRIOR_CLOSE_X_0.998\";"
classification: price_qty_logic
migration_action: MIGRATE_PRICEBASIS_TO_PYTHON
target_file: formulas/price_basis_v1.py
status: TODO
blocking_on: F03 F04 (same function, migrate together)
- id: F03
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
line: 665
text: "priceBasis = Number.isFinite(tp2Price) ? \"TAKE_PROFIT_TIER2_PRICE\" : \"PRIOR_CLOSE_X_0.998\";"
classification: price_qty_logic
migration_action: MIGRATE_PRICEBASIS_TO_PYTHON
target_file: formulas/price_basis_v1.py
status: TODO
blocking_on: F02 F04
- id: F04
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
line: 674
text: "priceBasis = Number.isFinite(tp1Price) ? \"TAKE_PROFIT_TIER1_PRICE\" : \"PRIOR_CLOSE_X_0.998\";"
classification: price_qty_logic
migration_action: MIGRATE_PRICEBASIS_TO_PYTHON
target_file: formulas/price_basis_v1.py
status: TODO
- id: F05
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
line: 678
text: "action = \"TAKE_PROFIT_TIER1\";"
classification: decision_logic
migration_action: MIGRATE_DECISIONS_ROUTING
target_file: formulas/execution_decision_v1.py
status: TODO
- id: F06
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
line: 683
text: "priceBasis = Number.isFinite(tp1Price) ? \"TAKE_PROFIT_TIER1_PRICE\" : \"PRIOR_CLOSE_X_0.998\";"
classification: price_qty_logic
migration_action: MIGRATE_PRICEBASIS_TO_PYTHON
target_file: formulas/price_basis_v1.py
status: TODO
- id: F07
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
line: 1577
text: "score += THRESHOLDS[\"SP_TAKE_PROFIT\"];"
classification: score_logic
migration_action: MIGRATE_SCORE_CALCULATION
target_file: formulas/score_thresholds_v1.py
status: TODO
- id: F08
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
line: 1578
text: "breakdown.push(`take_profit:+${THRESHOLDS[\"SP_TAKE_PROFIT\"]}`)"
classification: display_text
migration_action: DISPLAY_TEXT_PASSTHROUGH
notes: display_text stays in GAS adapter as rendering concern
status: KEEP_IN_GAS
- id: F09
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
line: 2164
text: "TAKE_PROFIT_BASE: 10,"
classification: score_logic
migration_action: REGISTER_TAKE_PROFIT_BASE
target_file: formulas/score_thresholds_v1.py
status: TODO
- id: F10
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
line: 1335
text: "return { [\"decisions\"]: routes, traces: traces, lock: true };"
classification: decision_logic
migration_action: MIGRATE_DECISIONS_ROUTING
target_file: formulas/routing_decision_v1.py
status: TODO
- id: F11
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
line: 1360
text: "if (holding && holding.stopBreach) return 'STOP_LOSS';"
classification: decision_logic
migration_action: MIGRATE_STOP_BREACH_DECISION
target_file: formulas/stop_loss_gate_v1.py
status: TODO
- id: F12
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
line: 2128
text: "[\"distribution_risk_score\"]: Math.min(100, Math.max(0, score)),"
classification: score_logic
migration_action: DELETE_DISTRIBUTION_RISK_GAS
target_file: formulas/distribution_risk_v1.py
status: TODO
notes: Python canonical (build_distribution_risk_v1.py) already exists; GAS version is duplicate
- id: F13
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
line: 2132
text: "formula_id: 'DISTRIBUTION_RISK_SCORE_V1'"
classification: pure_mapping
migration_action: DELETE_DISTRIBUTION_RISK_GAS
status: TODO
notes: formula_id tag stays with Python canonical; remove from GAS
- id: F14
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
line: 2214
text: "[\"late_chase_risk_score\"]: Math.min(100, Math.max(0, Math.round(lateChaseRisk))),"
classification: score_logic
migration_action: DELETE_LATE_CHASE_RISK_GAS
target_file: formulas/late_chase_risk_v1.py
status: TODO
notes: Python canonical (build_alpha_lead_table_v1.py) computes late_chase_risk; GAS version is duplicate
- id: F15
file: src/gas_adapter_parts/gdf_04_execution_quality.gs
line: 479
text: "if (bqRow.breakout_quality_gate === 'BLOCKED_LATE_CHASE' || alphaRow[\"late_chase_risk_score\"] >= 70)"
classification: decision_logic
migration_action: MIGRATE_LATE_CHASE_GATE
target_file: formulas/late_chase_gate_v1.py
status: TODO
# Migration action summary (9 actions)
migration_actions:
- action_id: REGISTER_SP_TAKE_PROFIT
findings: [F01]
description: Register SP_TAKE_PROFIT threshold (value=10) in Python score_thresholds canonical
priority: LOW
- action_id: REGISTER_TAKE_PROFIT_BASE
findings: [F09]
description: Register TAKE_PROFIT_BASE threshold (value=10) in Python score_thresholds canonical
priority: LOW
- action_id: DELETE_DISTRIBUTION_RISK_GAS
findings: [F12, F13]
description: Remove distribution_risk_score calculation from gdf_03; Python canonical exists
priority: HIGH
blocker: verify build_distribution_risk_v1.py output matches GAS output before delete
- action_id: DELETE_LATE_CHASE_RISK_GAS
findings: [F14]
description: Remove late_chase_risk_score from gdf_03; Python canonical in alpha_lead_table_v1
priority: HIGH
blocker: verify parity before delete
- action_id: MIGRATE_PRICEBASIS_TO_PYTHON
findings: [F02, F03, F04, F06]
description: priceBasis string selection (TIER1/TIER2 or PRIOR_CLOSE_X_0.998) → Python canonical
priority: MEDIUM
- action_id: MIGRATE_SCORE_CALCULATION
findings: [F07]
description: score += THRESHOLDS["SP_TAKE_PROFIT"] pattern → Python canonical scorer
priority: MEDIUM
- action_id: MIGRATE_STOP_BREACH_DECISION
findings: [F11]
description: holding.stopBreach → STOP_LOSS decision → Python canonical stop_loss_gate
priority: HIGH
notes: critical path — must match validate_stop_loss_policy_v1 spec
- action_id: MIGRATE_DECISIONS_ROUTING
findings: [F05, F10]
description: TAKE_PROFIT_TIER1 action assignment and routing lock decision → Python canonical
priority: MEDIUM
- action_id: MIGRATE_LATE_CHASE_GATE
findings: [F15]
description: BLOCKED_LATE_CHASE gate check (threshold 70) → Python canonical gate formula
priority: HIGH
blocker: late_chase_risk_score must come from Python before GAS gate can be removed
+8
View File
@@ -0,0 +1,8 @@
schema_version: rule_lifecycle.v1
states:
- shadow
- evidence
- active
- retire
transition_policy:
require_change_request: true
+9
View File
@@ -0,0 +1,9 @@
schema_version: agents_rule.v1
rule_id: CORE_LOCKS_V1
title: Core locks and no-hallucination rules
summary:
- Use spec/13_formula_registry.yaml for all prices, stops, targets, quantities.
- Do not invent prices, quantities, or formulas.
- If harness data is missing, print DATA_MISSING — 하네스 업데이트 필요.
- Preserve transparency for blocked items; never hide computed fields.
- Use only registered formulas and source-of-truth artifacts.
@@ -0,0 +1,8 @@
schema_version: agents_rule.v1
rule_id: HARNESS_CONTRACT_V1
title: Harness and validation contract
summary:
- Harness output must be validated before it is trusted.
- LLM must not override harness verdicts.
- Source-of-truth precedence follows runtime manifest and schema contracts.
- Live T+20 readiness cannot be faked from replay data.
@@ -0,0 +1,8 @@
schema_version: agents_rule.v1
rule_id: PORTFOLIO_POLICY_V1
title: Portfolio policy contract
summary:
- Heat, cash floor, stop loss, TP, and sell priority come from specs only.
- Do not bypass hard stops with narrative justification.
- For multiple sell candidates, show sell priority table first.
- Keep blocked positions transparent in shadow ledger outputs.
+8
View File
@@ -0,0 +1,8 @@
schema_version: agents_rule.v1
rule_id: ORDER_GRAMMAR_V1
title: HTS order grammar
summary:
- Single numeric price per order row.
- No multi-condition conjunctions in order text.
- Normalize all prices to KRX tick units.
- Remove stale TP prices when TP1 already triggered.
@@ -0,0 +1,8 @@
schema_version: agents_rule.v1
rule_id: REPORTING_CONTRACT_V1
title: Reporting and provenance contract
summary:
- All rendered numbers require provenance tags.
- Reports must keep source and runtime artifact references explicit.
- Narrative must not soften or override numeric gates.
- Output schema and final packets are authoritative.
@@ -0,0 +1,8 @@
schema_version: agents_rule.v1
rule_id: RULE_HASH_MIGRATION_V1
title: Rule hash migration map
summary:
- AGENTS.md is the index only.
- Rule files carry the detailed instructions.
- Hash each rule file and track the set in governance/agents_index.yaml.
- Update hashes whenever rule files change.
@@ -0,0 +1,10 @@
# Weekly Engine Review
## Engine Health
## Data Quality
## Formula Parity
## Outcome Drift
## Active Rule Changes
## Emergency Patch Notes
## Normal Patch Notes