Files
trex-core/docs/srs/Integration/req-123_cost-basis-canonical-parse-and-safe-sync-seeding.md
T

15 KiB

req-123: cost-basis canonical parse 및 WAC unavailable 안전 sync seed

  • Status: Approved
  • Type: Integration
  • Priority: High
  • Owner: trex-core-dev

Intent

  • portfolio-hub의 기존 GET /v1/portfolios/{portfolio_id}/holdings/cost-basis 응답에서 canonical field인 cost_basis_per_unit을 trex-core PortfolioHubReadAdapter.get_cost_basis()가 우선 해석하도록 하여 정상 HTTP 200 응답이 None으로 degrade되는 consumer contract defect를 수정한다.
  • legacy alias는 실제 호환 필요성이 확인되는 경우에만 낮은 우선순위 fallback으로 유지하고, canonical field의 invalid 값을 legacy 값으로 조용히 은폐하지 않는다.
  • broker 수량이 양수인데 WAC/avg_price가 unavailable한 inactive-slot onboarding에서 불완전한 live write를 방지한다. Discovery 승인 결정에 따라 live path는 fail-closed이며, dry-run은 진단과 no-write preview를 제공한다.
  • 본 REQ는 dcy-038의 consumer hotfix 요구사항만 다루며 portfolio-hub producer API 변경, 인증·토큰·설정 변경, DB migration/direct edit, sync --live 실행, 배포를 포함하지 않는다.

Requirement

  1. PortfolioHubReadAdapter.get_cost_basis(portfolio_id)는 successful JSON object response에서 cost_basis_per_unit을 canonical WAC source로 먼저 검사하고, 유효한 양의 수치이면 float 값으로 반환해야 한다.
  2. canonical key가 없을 때에만 승인된 legacy alias를 정해진 순서로 검사할 수 있다. 현재 지원 alias는 avg_cost → wac → cost_basis이며 순차 적용한다. canonical key가 response에 존재하지만 null, non-numeric, 0, negative 또는 허용 범위 밖이면 legacy 값으로 fallback masking하지 않는다.
  3. cost-basis 결과는 최소한 다음 상태를 구분해 reconcile/operator surface가 sanitized reason을 표시할 수 있어야 한다: valid canonical/legacy value, field missing/null, malformed/non-numeric/invalid value, non-2xx response, transport/timeout failure, unexpected response shape. 기존 호출부 호환성이 필요한 경우 Optional[float] port를 유지하되, unavailable reason은 reconcile-local result/diagnostic으로 보존한다.
  4. canonical WAC가 유효하면 sync --dry-run의 after.avg_price와 seeded_avg_price=true가 해당 값과 일치해야 하며, 실제 DB slot/warning write는 발생하지 않아야 한다. 승인된 live candidate도 동일한 source value를 사용해야 한다.
  5. broker_qty > 0인 inactive slot onboarding에서 WAC/avg_price가 unavailable이면 dry-run은 after.avg_price=null, seeded_avg_price=false, sanitized source/absence reason 및 no-write preview를 제공해야 한다. 이 경우 inactive→holding 전이와 qty/status/avg_price write를 dry-run에서 수행하지 않아야 한다.
  6. 동일 조건의 live sync path는 Discovery에서 승인된 fail-closed 정책을 적용해야 한다. 즉 status, qty, avg_price를 모두 기록하지 않고 non-zero failure로 중단하며, 평균가 없는 inactive→holding 전이를 허용하지 않는다. 기존 double-ack/live gate와 별도로 이 no-write barrier를 유지한다.
  7. cost-basis port가 연결되지 않았거나 transport failure인 기존 graceful-degrade 경로와, canonical response parsing/validation failure 경로를 operator reason 및 테스트에서 구분해야 한다. unavailable을 정상적인 0 또는 빈 잔고로 해석하지 않아야 한다.
  8. sync diagnostics/logging은 비밀 없이 portfolio_id/slot_id/symbol의 허용된 식별자, dry_run 또는 live mode, seeded_avg_price, cost-basis source(canonical/legacy/none), sanitized absence reason, no-write/fail-closed 결과를 판별 가능하게 해야 한다. token, credential payload, account number 등은 출력·로그·fixture에 포함하지 않는다.
  9. response-contract 및 regression test는 adapter→reconcile→CLI/output 경로를 고정해야 한다. canonical payload, legacy payload(채택 시), canonical-invalid+legacy-present, missing/null, malformed, non-2xx/transport failure, current holding update, positive broker qty unavailable WAC의 dry-run no-write와 live no-write를 각각 검증해야 한다.
  10. 관련 baseline 문서(docs/interface-contract.md, docs/runtime-flows.md, docs/operations.md)와 REQ/Batch/verification/release 문서는 portfolio-hub existing response contract, WAC absence semantics, dry-run diagnostics, fail-closed barrier, observability, rollback 및 release gate를 구현 결과와 일치하게 기술해야 한다.

Acceptance Criteria

  1. Given {\"current_quantity\": 5.0, \"cost_basis_per_unit\": 124580.0}인 HTTP 200 response, When get_cost_basis()를 호출하면, Then 124580.0을 반환하고 요청 경로가 /v1/portfolios/{portfolio_id}/holdings/cost-basis임을 contract test가 고정한다.
  2. Given canonical field가 없고 승인된 legacy fixture가 있는 response, When adapter가 parsing하면, Then 명시된 legacy 우선순위에 따라 값이 반환된다. Given canonical field가 invalid하고 legacy 값이 함께 있으면, When parsing하면, Then legacy로 masking하지 않고 invalid/unavailable reason을 반환한다.
  3. Given canonical field가 null/missing/non-numeric/0/negative 또는 response shape가 object가 아닌 경우, When adapter/reconcile가 처리하면, Then 정상 WAC seed로 취급하지 않고 케이스별 sanitized reason을 기록·반환한다.
  4. Given cost-basis endpoint가 non-2xx 또는 transport/timeout failure를 반환하는 경우, When sync 경로가 처리하면, Then parsing failure와 구분되는 unavailable reason을 내고 credential/token/raw response 비밀을 노출하지 않는다.
  5. Given inactive slot과 broker_qty=5, canonical WAC 124580.0인 경우, When sync --dry-run을 실행하면, Then preview의 after.status=holding, after.qty=5, after.avg_price=124580.0, seeded_avg_price=true를 표시하되 slot/warning write count는 0이다.
  6. Given inactive slot과 broker_qty>0, WAC가 unavailable인 경우, When sync --dry-run을 실행하면, Then inactive→holding 전이 및 qty/status/avg_price write를 하지 않고 avg_price=null, seeded_avg_price=false, reason 및 no-write preview를 표시한다.
  7. Given 동일한 positive broker holding/WAC unavailable 조건과 live path, When reconcile/sync가 실행되면, Then non-zero failure로 종료하고 status, qty, avg_price, warning clear를 포함한 write가 모두 0이며 inactive→holding 전이가 일어나지 않는다.
  8. Given 이미 HOLDING인 slot의 broker 수량 정합 업데이트, When sync/reconcile가 처리하면, Then 기존 의도된 current-holding update와 warning semantics가 유지되고 canonical WAC가 있으면 avg_price seed 값이 일관되게 적용된다.
  9. Given adapter/application/CLI regression suite를 실행하면, Then canonical contract, alias precedence, unavailable reason, dry-run no-write, live fail-closed, current holding regression, output/log redaction 및 seeded_avg_price 관측성 검증이 모두 통과한다.
  10. Given release candidate를 운영에 반영하려는 경우, When release gate를 점검하면, Then targeted regression 및 independent QC PASS, dry-run evidence, explicit release approval, 단일 대상 live 실행 승인, rollback 명령/기준과 post-release monitoring plan이 없이는 배포 또는 sync --live를 시작하지 않는다.

Impacted Area

  • Docs:
    • docs/interface-contract.md — portfolio-hub existing cost-basis response의 canonical field와 legacy compatibility 경계
    • docs/runtime-flows.md — sync/reconcile WAC seed 및 unavailable fail-closed/no-write 흐름
    • docs/operations.md — dry-run diagnostics, operator reason, observability, rollback/release gate
    • docs/discovery/dcy-038_20260716_cost-basis-response-contract-and-safe-sync-seeding.md
  • Modules:
    • trex_core/adapters/portfolio/hub_read.py — get_cost_basis() canonical/legacy parse와 unavailable 분류
    • trex_core/application/reconciliation.py — WAC unavailable no-write barrier, dry-run result 및 failure semantics
    • trex_core/runtime/cli.py 또는 현재 sync output 경계 — sanitized diagnostics와 non-zero failure
    • 기존 warning/observability 호출부 — fail-closed 시 warning clear/write 차단 및 식별 가능한 로그
  • Tests:
    • tests/adapters/portfolio/test_hub_read.py — HTTP response contract와 precedence/validation regression
    • tests/application/test_sync.py 및 관련 reconcile/CLI test — dry-run no-write, live fail-closed, diagnostics/output regression

Notes

  • Source Discovery: docs/discovery/dcy-038_20260716_cost-basis-response-contract-and-safe-sync-seeding.md.
  • Producer source of truth: portfolio-hub existing HoldingsCostBasisResponse.cost_basis_per_unit; 이 REQ에서는 producer endpoint/schema/auth를 수정하지 않는다.
  • Discovery confirmation: Justin Ko, 2026-07-16 22:44:20 KST. 승인 내용은 REQ drafting을 허용하며 sync --live, DB 변경, token/config 변경 또는 배포 승인을 의미하지 않는다.
  • OQ-2 Answered(2026-07-16): Producer 확인 결과, 현재 producer/fixture는 canonical HoldingsCostBasisResponse.cost_basis_per_unit을 기준으로 하고, 호환성 사유로 avg_cost → wac → cost_basis fallback을 유지한다. 단, canonical key가 유효하지 않으면 legacy fallback을 허용하지 않는다.
  • OQ-3 Answered(2026-07-16): 기존 Optional[float] port를 유지한다. unavailable reason은 reconcile-local 진단 구조에서 seeded_avg_price, source(canonical/legacy/none), reason을 분리해 노출한다.
  • Rollback은 consumer hotfix의 코드/문서 revert와 release 이전 candidate 철회를 의미한다. 이미 운영에 기록된 slot을 자동으로 직접 수정하거나 DB migration으로 복구하는 범위는 포함하지 않으며, 별도 승인된 운영 절차로만 다룬다.
  • Dependencies: existing REQ-105 sync contract, dcy-034의 WAC seed 범위, dcy-037의 broker truth/credential 변경은 재설계하지 않고 현재 baseline과 회귀 확인만 한다.
  • No live action: 구현·QC·release approval 전 sync --live, production sync, deployment, credential/token/config access는 금지한다.

Change Log

CHG-20260716-01

  • Date: 2026-07-16
  • Author: delivery-runner

Change Summary

  • dcy-038 confirmed Discovery의 consumer hotfix 범위를 단일 Integration REQ 초안으로 분해했다.
  • canonical cost_basis_per_unit 우선 parsing, legacy alias 정책, WAC unavailable fail-closed sync, dry-run diagnostics, response-contract/regression test, observability 및 rollback/release gate를 요구사항과 AC로 고정했다.

Acceptance Criteria Delta

  • Added: AC-1~10 전부 신규.
  • Updated: 없음.
  • Removed: 없음.

Impacted Area Delta

  • hub_read.py, reconciliation.py, sync CLI/output, 관련 adapter/application tests 및 runtime/interface/operations baseline 문서를 영향 범위로 명시했다.
  • portfolio-hub API/schema/auth, token/config, DB migration/direct edit, live sync, deployment는 명시적으로 제외했다.

Delivery Trace Delta

  • Batches: none (draft only; suggest-batch-reqs 이후 편성).
  • Releases: none (별도 release approval gate 대상).

Revalidation Impact

  • Reverification Needed: yes — confirm-req 전 legacy producer 증거, diagnostic result seam, source-level no-write 경계를 재검토하고 구현/QC에서 AC별 재검증한다.
  • Existing Implementation Invalidated: no — 현재 구현의 canonical-field parsing gap과 WAC unavailable live-write risk를 후속 hotfix requirement로 명시한다.
  • Status Recommendation: Proposed
  • Follow-up Action: OQ-2/OQ-3이 이 문서에서 Answered로 전환되었으나, implementation에서 reason enum/출력 형식 고정은 설계 단계에서 재확인한다.

Validation Plan

  • adapter HTTP fake/fixture로 canonical field와 alias precedence를 검증하고, canonical-invalid에서 legacy fallback 금지(차단) 및 canonical-absent에서 legacy fallback 동작을 함께 검증한다.
  • application/CLI recording double로 dry-run/live write count, fail-closed no-write, seeded_avg_price, source, reason 분리 표시를 검증한다.
  • targeted suite와 independent QC rerun 결과를 Batch verification에 AC별로 기록한다.

CHG-20260716-02

  • Date: 2026-07-16
  • Author: delivery-runner

Change Summary

  • OQ-2/OQ-3을 본 REQ에서 답변 상태로 확정한다.
  • OQ-2: canonical-absent fallback alias 순서 및 canonical-invalid/no-valid canonical 값 처리 우선순위를 Requirement/AC/Notes에 고정한다.
  • OQ-3: Optional[float] 시그니처 유지 + unavailable reason을 reconcile-local 진단으로 분리 표기( seeded_avg_price, source, reason )하도록 변경한다.

Acceptance Criteria Delta

  • Added: AC-2/AC-3의 canonical-invalid/legacy precedence 경로 재정의(유효성 규칙 및 canonical masking 금지).
  • Updated: 없음.
  • Removed: 없음.

Impacted Area Delta

  • trex_core/adapters/portfolio/hub_read.py, trex_core/application/reconciliation.py, tests/adapters/portfolio/test_hub_read.py, tests/application/test_sync.py, docs/interface-contract.md 문안에 OQ 결정 반영.

Delivery Trace Delta

  • Batches: none (draft/confirm 단계).
  • Releases: none (별도 release approval gate 대상).

Revalidation Impact

  • Reverification Needed: yes — batch design에서 reason enum/표시 고정값, AC-별 regression test matrix 보강 및 independent QC rerun을 통해 재검증한다.
  • Existing Implementation Invalidated: no.
  • Status Recommendation: Proposed.
  • Follow-up Action: 확인된 OQ 반영 후 confirm-req 재평가에서 pass 되면 suggest-batch-reqs 진행.

CHG-20260716-03

  • Date: 2026-07-16
  • Author: trex-dev-lead

Change Summary

  • confirm-req 게이트에서 dcy-038 승인 근거(제한범위/구조/결정사항)를 기준으로 REQ-123을 Approved로 전환하고, 다음 배치 인계만 선행한다.
  • 구현/검증/배포는 이 상태 전이 이후 trex-core-dev가 suggest-batch-reqs에서 생성되는 BAT-058로 진행한다.

Acceptance Criteria Delta

  • Added: StagePilot 상태 transition 근거(확정 OQ 0개, OQ-1/BLA no-write 정책 승인, scope non-goals 고정)을 confirm 증빙으로 고정.
  • Updated: none.
  • Removed: none.

Impacted Area Delta

  • StagePilot state: docs/srs/index REQ-123 status 및 문서 연계 준비.
  • Implementation trace: batch planning 경로로 이동.

Delivery Trace Delta

  • Next: BAT-058 (dcy-038, dcy-038-based hotfix) 생성 후 implementation 단계로 이관.
  • Scope: implementation은 REQ-123 AC-1~10 + no-write 리스크 관리 포함.

Revalidation Impact

  • Reverification Needed: yes (batch implementation/verification 단계).
  • Existing Implementation Invalidated: no.
  • Status Recommendation: Approved.
  • Follow-up Action: suggest-batch-reqs 완료 후 implementation/handoff.