Skill 통합 아키텍처
⚠ 부분 SUPERSEDED (2026-06, D-index-45/46/47). design-era (D-index-11~15) 의 통합 설계다. 유효한 것: atomic
propose_deal_closure1-transaction 원칙 (§2, 실구현됨) · 3-layer error model (§4) · schema authority immutable (§5, 실제는frozen_enums_hash+SCHEMA_CONTRACT_DRIFTgate 로 강화 — schema-catalog § frozen-enum). 달라진 것:
- ingest → artifact 적재는 design-era
ingest_financial_model_xlsx가 아니라propose_artifacts_from_ingest(dataroom sidecar glob → typed artifact + citation +_provenancestamp). artifact-first judgment layer (D-index-45) 가 당시엔 없던 본질.- pmc 8-agent / cross-deal SQL (§3, §6) 은
portfolio_kpi·risk_alert·valuation테이블을 가정하나 이들은 아직 phase-1 stub (미적재) — schema-catalog § stubs.- skill ownership 의 실 분배 경로 = D-index-47 universal-base mirror + vertical-gate (skill-ownership). MCP byte-delivery skill discovery 는 infeasible 판명.
아래는 server-side 설계 의도 기록으로 보존. 현행 도구 카탈로그 = /services/index § MCP 도구 카탈로그.
ingest · ic · pmc 3 skill 이 index MCP 서비스와 어떻게 통합되는가의 본격 설계. 본 페이지는 /ops/decisions D-index-11~15 의 implementation 가이드 + /services/index/skill-evolution 의 진화 path 의 server-side counterpart.
5-axis 정합
| Axis | 핵심 명시 |
|---|---|
| 본질 | skill = workflow (LLM-heavy authoring), index = persistence (typed fact SoT). 둘의 boundary 가 명시적이고 protected |
| 결과 | 3 deal (Iippo / Sentry / Canopy) 의 Phase 0 acceptance 8 test 모두 PASS — IRR ±1pp 일치, 펀드별 IRR 독립 산출, citation roundtrip |
| 퀄리티 | atomic propose_deal_closure 1 transaction, idempotency_key UUIDv5, 3-layer 에러 모델, schema authority immutable |
| 안전 | graceful degradation (index 죽어도 markdown 산출 유지), partial failure 차단 (all-or-rollback), Korean OCR worst-case 차단 (xlsx vision 만 label, PDF 거부) |
| 혁신 | cross-deal aggregate (fund NAV / portfolio risk heatmap / sector KPI benchmark) — ic/dd/vc 가 못 하는 영역. time-travel query 자연 |
3 skill 통합 매트릭스
| skill | 변경 정도 | 핵심 결정 | 산출물 |
|---|---|---|---|
| ingest | 변경 0 | 이중 path. dataroom markdown clone 만 (discovery phase). index 는 자체 ingest_financial_model_xlsx MCP tool 보유 — post-convergence, typed schema 강제. vision_ingest.py orthogonal | (그대로) |
| ic | 5th mode 추가, ~280-350 lines | --push-to-index = FINALIZE 평행 track (sequential 아님). Step 5.5 (gate_memo.sh PASS 후, postmortem_stub 이전). atomic propose_deal_closure 단일 batch | SKILL.md Rule 25 + Step 5.5 + gate_memo.sh dispatch + 보조 scripts |
| pmc | 신규 greenfield + 2 skill 흡수 | portfolio-management + investor-relations 3-phase deprecate. 8 sub-agent (ic 19 < pmc 8). Trigger 3-tier (scheduled + event + manual). postmortem 2-track | SKILL.md + 8 sub-agent + references/ + scripts/ + pmc/ folder convention |
1. ingest skill 통합 — 이중 path
원칙
ingest skill 은 수정하지 않음. 이유:
- 본질 분리: ingest = “dataroom 의 모든 확장자를 agent-readable markdown 으로” (discovery, all-files, vision-optional). index ingest = “재무 모델 xlsx 를 typed driver tree 로” (post-convergence, single-type, schema-strict).
- 재발 risk 차단: ingest 가 typed schema 책임 가지면 deal 별로 다른 xlsx 모양에 대응하느라 generic ingest 기능이 distort.
- vision_ingest.py orthogonal: ingest skill 의 vision 은 dataroom 의 정성 정보 (IR PDF / 회사 자료 PPTX) 의 vision. index 의 ingest 는 xlsx sheet 의 label inference 만 vision (수치는 mechanical).
Boundary
회사 IR pack 받음
↓
dataroom/{IR_v1.pdf, 회사소개.pptx, 3FS_model.xlsx, ...}
↓ /ingest (변경 없음)
↓
dataroom/{IR_v1_pdf.md, 회사소개_pptx.md, 3FS_model_xlsx.md, ...} ← markdown clone (모두)
↓
/ic 실행 (Research squad 가 markdown clone 만 읽음)
↓
ic/finance/3fs_base/v{N}.xlsx 산출 (회사 모델 위 AXE 가정 overlay)
↓ /ic --push-to-index (선택, 5th mode)
↓
index.ingest_financial_model_xlsx(deal_id, ic/finance/3fs_base/v{N}.xlsx blob)
↓ Anthropic Sonnet (label inference) + calamine (cell value)
↓
financial_model + financial_driver + financial_driver_value DB 적재정합 룰 (D-index-15 B-index-vision-boundary-rule)
| Input | Vision 허용 | Mechanical 강제 |
|---|---|---|
| dataroom 의 PDF (IR pack 등) | ✅ ingest skill (markdown clone 만) | (markdown 만 산출) |
| dataroom 의 PPTX | ✅ ingest skill (markdown clone 만) | (markdown 만 산출) |
| ic/finance/*.xlsx | sheet/row label inference 만 | numeric cell value 는 calamine 강제 |
| ic/finance/*.xlsx 의 PDF embed | ❌ vision X | (지원 안 함) |
| dataroom PDF 직접 index 적재 | ❌ 차단 — ingest_financial_model_xlsx 가 PDF blob 거부 | — |
→ “5,941원 → 5,941엔” Korean OCR 오인식이 DB authoritative cell 이 되는 worst-case 영구 차단.
2. ic skill 통합 — 5th mode (--push-to-index)
4 mode → 5 mode
기존: 진화 후 (D-index-11):
/ic /ic
├─ INITIAL (v1 full run) ├─ INITIAL (v1 full run)
├─ REVISION (v{N}→v{N+1}) ├─ REVISION (v{N}→v{N+1})
├─ APPEND (§17 entry) ├─ APPEND (§17 entry)
└─ FINALIZE (ic/final/ lock) ├─ FINALIZE (ic/final/ lock)
└─ --push-to-index ← 신규, FINALIZE 평행 track왜 FINALIZE 와 평행 (sequential 아님)?
- FINALIZE = OneDrive deliverable lifecycle (
ic/final/v{N}.{md,pdf}lock) --push-to-index= DB lifecycle (typed fact persistence)- 두 lifecycle 이 같은 commit 에 묶이면 partial failure 시 rollback 모호 (PDF 만 lock 되고 DB 미반영 / DB 만 적재되고 PDF 미생성)
- 평행 track = 한 쪽 실패가 다른 쪽 blocking 안 함. 양쪽 모두 retry-safe
Step 5.5 위치
Step 0 : dataroom md clone + ctx sync (PR-O 4-mode dispatch 의 Mode 0)
Step 1-4 : 19-agent orchestration (proponent / premortem_critic / devils / qa / ...)
Step 5 : gate_memo.sh chain (citation_trace / xlsx_integrity / check_arithmetic / check_exit_matrix)
↓ PASS
humanize Stage 4 (humanize-corrector sub-agent)
↓
pdf_quality gate (check_pdf_quality.py)
↓
Step 5.5 : ← 신규. --push-to-index 플래그 detect 시 발동
├─ idempotency_key = UUIDv5(deal_id, f"{version}::{content_sha256}::{actor_email}")
├─ payload 수집 (financial_model xlsx blob + ic_decision + fund_investments[] +
│ dd_findings[] + exit_matrix_leaves[] + risk_alerts[])
├─ POST /index/mcp propose_deal_closure (단일 atomic call, [D-index-13](/ops/decisions))
├─ 응답: { model_id, decision_id, ... } 또는 { error.code: "IDEMPOTENCY_CONFLICT", context: ... }
└─ ic/index_push_state/v{N}.json local checkpoint
Step 6 : postmortem_stub.py 자동 호출 (ic skill 잔존 책임)
Step 7 : FINALIZE 가능 (별도 invocation, ic/final/ lock + render)Atomic propose_deal_closure (D-index-13)
개별 propose tool 6+ round-trip 금지 — partial failure 시 inconsistent state:
// ❌ 잘못된 패턴
POST /propose_financial_model → 200 (commit)
POST /propose_ic_decision → 200 (commit)
POST /propose_fund_investment[0] → 200 (commit)
POST /propose_fund_investment[1] → 500 ← FAIL — rollback 불가 (3 commit 됐음)
POST /propose_dd_finding[] → never reached// ✅ atomic 패턴
POST /propose_deal_closure {
"deal_id": "iippo",
"version": 8,
"idempotency_key": "uuid-v5-...",
"financial_model": { xlsx_blob, meta },
"ic_decision": { memo_pdf_url, irr_7metric, voting },
"fund_investments": [
{ fund: "axe_ia_001", round: "Pre-A RCPS 1호", committed: 99998912, ... },
{ fund: "axe_ia_002", round: "Pre-A RCPS 2호", committed: 100000000, ... }
],
"dd_findings": [...],
"exit_matrix_leaves": [...],
"risk_alerts": [...]
}
↓ index 측 1 PostgreSQL transaction (SERIALIZABLE isolation)
↓ 모두 INSERT or ROLLBACK
→ 200 { model_id, decision_id, fund_investment_ids: [...], ... }
또는 409 { error.code: "IDEMPOTENCY_CONFLICT", context.prior_actor, prior_ts }Idempotency (D-index-13)
# ic skill gate_memo.sh 가 매 호출 동일 input 으로 동일 key 생성
idempotency_key = uuid5(
namespace=deal_id,
name=f"{version}::{sha256(memo_v{N}.md + finance_xlsx_hashes)}::{actor_email}"
)idempotency_record테이블 (hive 패턴 1:1 미러) — PK = idempotency_key, TTL = 24h- 2번째 동일 key call → 409 + 1차 응답 cached body 반환 (silent re-insert 안 됨)
- 다른 input → 다른 key → 정상 처리
gate_memo.sh 4 Python check 의 phased migration
D-index-11 의 결정. 즉시 deprecate 아닌 phased:
| Script | 현재 (ic skill) | M7 Phase 1 | M7 Phase 2 |
|---|---|---|---|
citation_trace.py | local WARN | local (memo prose audit, 유지) | local (영구 유지 — index 영역 외) |
check_arithmetic.py | local WARN | local (memo prose audit, 유지) | local (영구 유지) |
xlsx_integrity.py | local WARN | 이중 gate — local 가벼운 pre-flight + index validate_financial_model DB trigger | DB trigger 만 (local script archive) |
check_exit_matrix.py | local WARN | 이중 gate — local + index trigger 가 결과 캐시 (dead_leaf / concentration flag) | DB trigger 만 |
backward compat 100% — --push-to-index 미사용 시 기존 4 script 그대로 동작.
REVISION mode 와의 상호작용
v7 작성 + --push-to-index → financial_model v7 row DB
↓
v7 → v8 REVISION (사용자 피드백 반영)
↓
v8 --push-to-index → financial_model v8 row DB (UNIQUE (deal_id, version) 새 row)
↓
audit_trail 에 v7 supersede 이벤트 + v8 propose 이벤트 모두 보존
↓
last-write-wins (v8 이 "current"), 단 v7 도 time-travel query 가능3. pmc skill 통합 — greenfield + 2 skill 흡수
상세 = skill-evolution § pmc — 본 페이지는 server-side touchpoint.
Trigger 3-tier
1. SCHEDULED (launchd daily 09:00 KST, 매월 첫 영업일 fire)
/pmc --quarterly --deal-code <CODE> --push-to-index
↓
- 지난 분기 KPI 스냅샷 (board pack ingest 또는 index prior 조회)
- board_pack draft (markdown + PDF render)
- LP quarterly letter draft
- index.portfolio_kpi + index.valuation propose
2. EVENT (red alert 자동 fire)
pmc/scripts/risk_monitor.py (launchd 5분 polling)
↓ runway < 6M / 핵심 인력 이탈 / burn_spike > 30% 등 감지
↓
/pmc --alert --deal-code <CODE> --kind <runway_under_6m|key_personnel|...>
↓ index.risk_alert propose (severity=red, raised_at=now)
↓ Teams bot notification (operator + deal partner)
3. MANUAL
/pmc --postmortem-fill --deal-code <CODE> --timepoint <t_3m|t_6m|t_12m|t_24m|exit>
/pmc --board-pack --deal-code <CODE> --quarter <YYYY-Q[1-4]>
/pmc --lp-letter --fund <axe_ia_001> --quarter <YYYY-Q[1-4]>Postmortem 2-track (D-index-12)
ic skill (investment phase — 책임 유지):
postmortem_stub.py (gate_memo.sh PASS 시 stub 생성, idempotent)
postmortem_reminder.py (launchd daily 09:00 KST, target_date ±7일 미완 macOS notification)
references/postmortem-cadence.md (spec SoT)
pmc skill (portfolio care phase — 신규):
scripts/postmortem_fill_interactive.py (yaml interactive fill, 5 시점)
scripts/render_postmortem.py (ic 에서 이관)
--push-to-index → index.postmortem propose
references/postmortem-cadence.md (ic 의 file 을 symlink — single SoT)같은 yaml file (ic/_recap/{DEAL}_postmortem.yaml) 을 양쪽이 다른 동작으로 다룸:
- ic = stub 생성 + reminder
- pmc = fill (yaml 채움) + render (1-pager) + push (index DB)
8 sub-agent (ic 19 < pmc 8 — lighter)
| Sub-agent | 역할 | LLM model |
|---|---|---|
| 1. data-fetcher | dataroom board pack PDF / 회사 KPI 자료 / index prior 조회 | Sonnet |
| 2. kpi-extractor | raw data → normalized snapshot (MRR/ARR/churn/runway/…) | Sonnet |
| 3. risk-alerter | portfolio-management 5 신호 vs 실측 비교 → red/yellow flag | Sonnet |
| 4. valuation-updater | last-round / mark-to-market / DCF 중 선택 + NAV 계산 | Opus |
| 5. exit-signal-analyzer | IPO / M&A / Secondary 체크리스트 진행도 평가 | Sonnet |
| 6. board-pack-drafter | KPI + risk + valuation → markdown board deck | Opus |
| 7. lp-comm-drafter | board pack → LP quarterly letter | Opus |
| 8. index-payload-composer | 위 산출물 → propose_*_snapshot JSON payloads | Sonnet |
3-phase deprecation (D-index-12)
Phase 0 (즉시, M7 시작 시):
portfolio-management SKILL.md 에 deprecation notice
investor-relations SKILL.md 에 deprecation notice
pmc SKILL.md skeleton 등록 (frontmatter + references/ placeholder)
Phase 1 (M7 Phase 1 launch + 첫 quarterly cycle 실행 후):
portfolio-management KPI 표 → pmc/references/kpi-catalog.md copy + cross-link
investor-relations LP 보고 구조 → pmc/references/ir-lifecycle.md copy
Phase 2 (3개월 후):
portfolio-management / investor-relations SKILL.md disable
Blueprint search/suggest 에서 pmc 로 redirect
legacy 사용처 grep → pmc 로 갱신
Phase 3 (6개월 후):
완전 archive (.deprecated/ 이동)
pmc 가 context 에 fully absorbed4. 3-layer error model (D-index-14)
skill → index 모든 통신 에러는 일관 3-layer 표현 — 양파껍질 (D-bp-mcp-1) 의 “진단 불가, 모든 401 같은 메시지” 영구 차단.
L1 — HTTP (RFC 9728)
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://axe.axelabs.ai/index/mcp",
error="invalid_token",
error_description="Token aud claim missing index app_id_uri"
Content-Type: application/jsonL2 — MCP body (structured)
{
"error": {
"code": "FINANCIAL_MODEL_CONFLICT",
"message": "financial_model (deal=iippo, version=7) already proposed",
"context": {
"prior_actor": "[email protected]",
"prior_ts": "2026-05-06T10:00:00Z",
"idempotency_key": "uuid-v5-...",
"existing_model_id": "uuid-mdl-..."
}
}
}L3 — skill handler
# ic skill 의 lib/index_client.py (또는 pmc 의 동형)
def propose_deal_closure(deal_id, version, payload):
resp = mcp_call("propose_deal_closure", {...})
match resp.error.code:
case "IDEMPOTENCY_CONFLICT":
# 기존 propose 표시 + retry 차단
print(f"⚠ Already proposed by {resp.context.prior_actor}")
print(f" Open ctx review queue: ...")
return existing_response_from_cache
case "VALIDATION_WARNING":
# ctx review 사용자 confirm 요청
return prompt_user_confirm(resp.context.detail)
case "SCHEMA_NOT_FOUND":
print(f"⚠ index schema {resp.context.schema_id} not found")
print(f" Run: axe deploy index --register-schemas")
return None
case "SERVICE_UNAVAILABLE":
# 로컬 drafts 보존 + retry 안내
save_to_local_drafts(payload)
return None
case "CITATION_RESOLVE_FAILED":
# cached value + warning chip
return resp.context.cached_value_with_warningIndexError Rust enum SoT
// src/index/error_model.rs
pub enum IndexError {
IdempotencyConflict { prior_actor: String, prior_ts: String, idempotency_key: Uuid },
ValidationWarning { check: String, detail: String },
SchemaNotFound { schema_id: String },
CitationResolveFailed { citation_kind: String, reason: String },
FinancialModelLocked { model_id: Uuid, locked_at: DateTime<Utc> },
DslSyntaxError { formula: String, position: usize, suggestion: String },
UnknownEnum { field: String, value: String, allowed: Vec<String> },
DealNotFound { deal_id: String },
FundEntityNotFound { fund_entity_id: String },
ServiceUnavailable { reason: String },
RateLimitExceeded { limit: u32, window: String },
InsufficientScope { required: String, granted: Vec<String> },
}
impl From<IndexError> for McpErrorResponse {
fn from(e: IndexError) -> Self {
// deterministic (code, message, context) mapping
}
}unit test 가 모든 case 의 wire-level response 검증 — silent fallback 절대 금지.
5. Schema authority immutable (D-index-15)
DSL grammar + enum 은 service code 에만, skill 측 override 불가:
| 항목 | 위치 | 변경 절차 |
|---|---|---|
| DSL grammar (10 operator) | src/index/dsl/grammar.pest | service code SoT |
risk_alert.kind enum 5종 | src/index/schemas.rs | service code SoT |
instrument enum 5종 | src/index/schemas.rs | service code SoT |
fund_investment.status enum 6종 | src/index/schemas.rs | service code SoT |
exit_matrix_leaf.path enum 6종 | src/index/schemas.rs | service code SoT |
ic skill 의 scenario_deltas.yaml 이 DSL syntax error 또는 unknown enum 값 emit 시:
// ic skill 호출
POST /ingest_financial_model_xlsx { deal_id: "iippo", xlsx_blob: "..." }
↓ index 측 validation
↓
{
"error": {
"code": "DSL_SYNTAX_ERROR",
"message": "Formula parse failed at position 23",
"context": {
"formula": "revenue[y0] * (1 + 0.85)", // wrong — should reference driver
"position": 23,
"suggestion": "revenue[y0] * (1 + revenue_growth_y1)",
"doc": "https://docs.axelabs.ai/services/index/financial-model#dsl-formula"
}
}
}
↓
ic skill → ctx review queue 에 highlighted error + 정정 예시 표시 → 사용자 수정 후 confirmenum value 추가는 coordination PR 강제:
src/index/schemas.rsSoT 수정 + 새 case 추가/index/schemasenvelope@1.0→@2.0version bump- Blueprint
artifact_schema자동 mirror (다음 fetch cycle) - ic / pmc skill 의 yaml validator 갱신
- 모두 같은 PR 또는 ordered PR chain
silent 추가 금지 — frame KSME accounting_standard enum 영구 freeze 패턴 (D-frame-fund-ksme-policy-check) 의 index domain 확장.
6. Cross-deal aggregate — pmc 만의 본질 (혁신 axis)
ic / dd / vc 가 deal-by-deal 시점. pmc 는 fund × portfolio × sector × time 4축 aggregate. LP 보고의 backbone.
Fund-level quarterly NAV
SELECT
fi.fund_entity_id,
DATE_TRUNC('quarter', v.asof_date) AS quarter,
SUM(v.nav_krw) AS total_nav,
SUM(v.unrealized_krw) AS total_unrealized,
SUM(v.realized_krw) AS total_realized,
COUNT(DISTINCT v.deal_id) AS portfolio_size
FROM index.valuation v
JOIN index.fund_investment fi ON v.fund_investment_id = fi.id
WHERE fi.fund_entity_id = 'axe_ia_001'
AND v.asof_date >= '2025-01-01'
GROUP BY fi.fund_entity_id, DATE_TRUNC('quarter', v.asof_date)
ORDER BY quarter DESC;Portfolio risk heatmap
SELECT
d.deal_code,
tc.brand_name,
COUNT(*) FILTER (WHERE ra.severity = 'red') AS red_count,
COUNT(*) FILTER (WHERE ra.severity = 'yellow') AS yellow_count,
STRING_AGG(DISTINCT ra.kind, ', ') AS active_alerts
FROM index.deal d
JOIN index.target_company tc ON d.target_company_id = tc.id
LEFT JOIN index.fund_investment fi ON d.id = fi.deal_id
LEFT JOIN index.risk_alert ra ON d.id = ra.deal_id AND ra.resolved_at IS NULL
WHERE fi.fund_entity_id = 'axe_ia_001'
GROUP BY d.id, tc.brand_name
ORDER BY red_count DESC, yellow_count DESC;Sector KPI benchmark
SELECT
tc.sector,
DATE_TRUNC('quarter', k.asof_date) AS quarter,
AVG(k.value) FILTER (WHERE k.kind = 'burn_multiple') AS avg_burn_multiple,
AVG(k.value) FILTER (WHERE k.kind = 'runway_months') AS avg_runway,
AVG(k.value) FILTER (WHERE k.kind = 'churn_monthly') AS avg_churn,
COUNT(DISTINCT k.deal_id) AS sample_size
FROM index.portfolio_kpi k
JOIN index.deal d ON k.deal_id = d.id
JOIN index.target_company tc ON d.target_company_id = tc.id
WHERE k.asof_date >= '2025-01-01'
GROUP BY tc.sector, DATE_TRUNC('quarter', k.asof_date)
ORDER BY tc.sector, quarter DESC;→ pmc/cross_deal/{fund_quarterly_nav_report.md, portfolio_risk_heatmap.xlsx, sector_kpi_benchmark.md, fund_irr_projection.md} 자동 생성.
→ LP 보고서의 정량 backbone — 매 분기 산출 시간 days → minutes.
7. 3 worst-case integration risks + 차단
Risk 1 — Schema drift (퀄리티 axis)
시나리오: ic 의 scenario_deltas/v7.yaml 의 revenue_growth_y1: 1.85 (multiplier) 를 index 가 0.85 (percentage) 로 해석 → IRR 산출 wrong → LP audit fail.
차단:
- DSL grammar 가 service code hardcoded (D-index-15)
- ingest tool 이 syntax error 시
DSL_SYNTAX_ERROR+ explicit suggestion + doc link - Phase 0 acceptance A2 (
compute_outputs ±1pp 일치) 가 매 PR 검증 B-index-integration-fixtures가 Iippo/Sentry/Canopy 3 deal regression
Risk 2 — Korean OCR worst-case (안전 axis)
시나리오: dataroom IR PDF 의 “5,941원” → “5,941엔” (yen, 1000x off) 오인식 → 영구 DB 적재 → IRR -2pp.
차단:
ingest_financial_model_xlsx의 input validation: PDF blob 거부 (B-index-vision-boundary-rule)- xlsx 만 vision 보조 — sheet/row label inference 만, numeric value 는 calamine 강제
- Phase 0 acceptance A2 ±1pp tolerance 가 catch
- ic skill 잔존
citation_trace.py가 memo prose 숫자 trace 강제 (PDF 출처 명시)
Risk 3 — pmc ↔ ic 동시 propose race (안전 axis)
시나리오: PCC #6 trigger fire + 동시에 pmc 가 Q4 KPI propose → 같은 (deal_id, kind, asof_date) 두 row → audit_trail 충돌.
차단:
record_kpi_snapshotMCP tool 의 UPSERT (UNIQUE (deal_id, kind, asof_date))updated_at > now - 6h시 warn modal (사용자 의도 확인)- pmc skill rule:
portfolio_kpi_snapshot.updated_at > (now - 6h)시 propose 보류 - audit_trail 에 양쪽 모두 기록 +
is_override=trueflag
8. 양파껍질 재발 차단 — 21 항목 운영 체크포인트
mcp-server-checklist § 8 의 운영 14 → 21 항목으로 확장 (B-index-mcp-checklist-extension):
| # | 검증 | 명령 | 정답 |
|---|---|---|---|
| 17 | skill idempotency | 2× call same propose_deal_closure(idempotency_key=X) | 2nd call 409 + context.prior_actor. silent re-insert 0 |
| 18 | citation resolver roundtrip | ic memo citation {kind:"index.financial_output", ...} → resolve → DB query value | floating-point epsilon (0.001 percent) 이내 일치 |
| 19 | cross-skill conflict detect | pmc + ic 동시 record_kpi_snapshot(같은 deal, kind, asof_date, 다른 value) | audit_trail 양쪽 기록 + last-write-wins + warning modal |
| 20 | graceful degradation | docker stop index-mcp 후 ic --push-to-index | MCP timeout (3s) 후 markdown-only fallback + warning banner. memo 정상 render |
| 21 | schema evolution | index 에 financial_output.tax_adjusted_irr 새 field 추가. 기존 ic skill 호출 | Blueprint /schemas mirror 자동 갱신. 기존 artifact citation resolve 정상. ic skill 다음 run 시 새 field 옵션 사용 |
axe test index --accept-gate 통합 명령 + 24h production monitor (error rate under 0.1 percent, citation cache hit over 95 percent).
9. 변경 분량 추정
| 영역 | Phase 0 | Phase 1 | Phase 2 |
|---|---|---|---|
| ic skill 변경 | — | ~280-350 lines (SKILL.md Rule 25 + Step 5.5 + gate_memo.sh dispatch + scripts) | — |
| pmc skill 신규 | SKILL.md skeleton (~150 lines) | 8 sub-agent + references/ (~500 lines) + scripts/ (~300 lines) | render templates + cross-deal SQL |
| portfolio-management deprecation | notice 추가 (~10 lines) | KPI 표 → kpi-catalog.md copy | SKILL.md disable |
| investor-relations deprecation | notice 추가 (~10 lines) | LP 구조 → ir-lifecycle.md copy | SKILL.md disable |
| index Rust 코드 | error_model.rs + integration fixtures (~1500 lines) | propose_deal_closure + idempotency_record (~800 lines) | cross-deal SQL views + pmc tools (~600 lines) |
| Blueprint client | lib/index_client.py skill 측 wrapper (~200 lines) | citation resolver (citations/index.ts) (~300 lines) | UI integration |
| docs | 본 페이지 + skill-evolution.mdx update | financial-model.mdx + schema-catalog.mdx update | pmc-specific section 추가 |
총 추정: Phase 0 ~ 2,000 lines, Phase 1 ~ 2,500 lines, Phase 2 ~ 1,500 lines. 6 weeks Phase 0+1, 12 weeks total (M7 완료).
관련 페이지
- /services/index — 서비스 main
- /services/index/financial-model — 6-table SoT + 3 deal worked example
- /services/index/schema-catalog — 14 schemas spec
- /services/index/skill-evolution — 5 skill → service 진화 (본 페이지의 자매)
- /ops/decisions D-index-11~15 — 5 신규 결정
- /ops/backlog — 본 페이지의 M7 implementation 항목 (
B-ic-push-mode-impl외 9 항목) - /architecture/mcp-server-checklist — 21 운영 체크포인트 (B-index-mcp-checklist-extension 후)
- /architecture/artifacts — Blueprint artifact + citation kind
index.*(D-index-6 mirror)