Merge DEBT-017 fix: adopt Features/ApprovalWorkflow as canonical

Merges the isolated-worktree agent's resolution of TECH_DEBT_REGISTER.md
DEBT-017 (duplicate ApprovalWorkflow implementation) into this branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

# Conflicts:
#	CURRENT_ROADMAP.md
#	docs/CURRENT/CATALOGS/WBS_PROGRESS_TRACKER.csv
#	src/KArtSell.Modules.ModelOperations/ApprovalWorkflow/README.md
This commit is contained in:
2026-08-08 17:59:25 +09:00
25 changed files with 439 additions and 1336 deletions
@@ -27,7 +27,7 @@ AEG-VS-00-07,S0,VS-00,회귀·관제·Runbook·Rollback 증거,COMPLETED,2026-08
AEG-X-009,S1,Cross,Source catalog 고도화,COMPLETED,2026-08-07,"docs/CURRENT/CATALOGS/source-catalog.md; docs/CURRENT/AEG-X-009_AUTOMATION_PROPOSAL.md; contracts/data/source-approval.v1.proposed.json; docs/DECISIONS/ADR-DATA-001.md; db/migrations/0033_source_approval_contract.sql; db/migrations/0034_dataset_manifest_freeze_contract.sql; db/migrations/0033_market_data_import_logs.sql; src/KArtSell.Modules.ModelOperations/Infrastructure/DapperApprovedModelContextReader.cs",Data Governance,"✅ Workstream D/E/F COMPLETED: source-catalog.md v2.0 (KRX/OpenDart/KIS consolidated), VS-02_DATA_GOVERNANCE_POLICY.md, VS-03/04 SLICE_SPECs. All 4 unknowns resolved. ✅ Workstream G (commit 136665c, 2026-08-07) also now COMPLETE: live KRX OpenAPI / OpenDart / KIS service integrations (P1-P3), daily scheduling + error classification + SLA tracking + LKG fallback (P4-P6), market_data schema with append-only import logs, correlation_id-based idempotent replay. ⚠️ Note: 0033 is used by two different, unrelated migrations across branches (source_approval_contract.sql vs market_data_import_logs.sql) — confirm actual applied migration number in the target DB's kartsell_schema_versions journal before assuming both landed as authored."
AEG-VS-01-01,S1,VS-01,정책·범위·실패상태 계약 확정,COMPLETED,2026-08-07,docs/CURRENT/SLICE_SPECS/VS-01-SLICE_SPEC.md,PM/Architect,"✅ SLICE_SPEC produced: VS-01-SLICE_SPEC.md (identity/MFA/RBAC/maker-checker contract). Prerequisite AEG-X-001 + AEG-VS-00-02 already COMPLETED. Ready for security team review and schema implementation."
AEG-VS-02-01,S1,VS-02,정책·범위·실패상태 계약 확정,COMPLETED,2026-08-07,"docs/CURRENT/SLICE_SPECS/VS-02-SLICE_SPEC.md; docs/CURRENT/VS-02_DATA_GOVERNANCE_POLICY.md",PM/Architect,"✅ COMPLETE: VS-02-SLICE_SPEC.md + governance policy. All 4 unknowns resolved (data source, import SLA, audit policy, schema versioning). Financial security master implementation ready for Phase 2."
AEG-VS-26-01,S2,VS-26,모델 승인 워크플로우 구현 (Maker-Checker Governance),BLOCKED,-,"docs/CURRENT/SLICE_SPECS/VS-26-SLICE_SPEC.md; src/KArtSell.Modules.ModelOperations/ApprovalWorkflow/ (ApprovalSql.cs, ApprovalPolicy.cs, [DontRegister]'d); src/KArtSell.Modules.ModelOperations/Features/ApprovalWorkflow/ (Handlers.cs, Sql.cs, Policy.cs — the one actually wired in Program.cs); db/migrations/0036_approval_workflow.sql; tests/KArtSell.Integration.Tests/ApprovalWorkflow/*; TECH_DEBT_REGISTER.md DEBT-017; commit a2e742c (Workstream H, PR #23, merged to main)",PM/BE Lead,"🔴 CORRECTED 2026-08-08 — this row previously said 'Backend implementation + tests complete, 20/20 tests PASS' and that claim is misleading: TECH_DEBT_REGISTER.md DEBT-017 records that TWO independent ApprovalWorkflow implementations exist with colliding routes. The one this row's evidence links to and the one with 20/20 passing tests (`ApprovalWorkflow/`, Workstream H) has all 4 endpoints annotated `[DontRegister]` and is NOT reachable via HTTP. The implementation actually registered in `Program.cs` and reachable at runtime is `Features/ApprovalWorkflow/` (Workstream G) — grep found no dedicated test file exercising it. Net effect: the maker-checker approval gate that is actually live has not been shown to work, and the one that has been shown to work is dead code. Do not build frontend UI against either implementation, and do not re-mark this COMPLETED, until an architect decision (DEBT-017) picks the canonical implementation, deletes the other, and a test suite runs against whichever is kept. Renumbered from VS-03 to VS-26 on 2026-08-08 per docs/DECISIONS/ADR-WBS-001-slice-renumbering.md — VS-03 in WBS_MASTER.csv ('IngestMarketDataPIT') is a separate, unrelated, still-unimplemented slice and keeps its original number unchanged. Also note: src/KArtSell.Host/Features/MarketData/VS03_*.cs is a THIRD, unrelated, already-implemented-and-tested body of work also labeled 'VS-03' (Market Data Ingestion Dashboard, commits 2bc2b1e/32b49a4) that is entirely absent from this tracker — see CURRENT_ROADMAP.md for a note to investigate and add it."
AEG-VS-26-01,S2,VS-26,모델 승인 워크플로우 구현 (Maker-Checker Governance),BLOCKED,-,"docs/CURRENT/SLICE_SPECS/VS-26-SLICE_SPEC.md; src/KArtSell.Modules.ModelOperations/Features/ApprovalWorkflow/ (Handlers.cs, Sql.cs, Policy.cs, Endpoints.cs — sole implementation, wired in Program.cs); db/migrations/0036_approval_workflow.sql; tests/KArtSell.Integration.Tests/ApprovalWorkflow/ApprovalWorkflowTests.cs (new, 8 cases); tests/KArtSell.Integration.Tests/ApprovalWorkflowPolicyTests.cs (extended, 10 cases); TECH_DEBT_REGISTER.md DEBT-017/DEBT-023; commit a2e742c (original duplication, superseded)",PM/BE Lead,"🟡 UPDATED 2026-08-08 — DEBT-017 architect decision made and executed: the duplicate `src/KArtSell.Modules.ModelOperations/ApprovalWorkflow/` (dead code, `[DontRegister]`'d, previously credited with the misleading '20/20 tests PASS') was DELETED along with its dedicated test file. `Features/ApprovalWorkflow/` (the implementation actually reachable over HTTP) is now the sole implementation and gained new Handler+Sql+real-Postgres integration tests covering create/approve/activate role gating, maker≠checker separation of duties, evidence attachment, and an explicit `DateOnly EffectiveAt` round-trip. While porting: found `Features/ApprovalWorkflow/Sql.cs InsertProposalAsync` had the same Dapper `DateOnly`-binding bug already fixed in the deleted implementation (commit 2ccf74c) — fixed identically here (`::date` cast + string parameter). Two residual (pre-existing, not introduced by this cleanup) gaps documented in the slice README rather than fixed: no `GET /approvals/{id}` endpoint, and no wired Draft→Proposed transition anywhere in the running app (approve/activate are therefore currently unreachable end-to-end via HTTP with real data). **Still BLOCKED, not COMPLETED, because no PostgreSQL was reachable in this session (127.0.0.1:5432 connection refused, no SSH tunnel open): `dotnet build -c Release` is clean, but `dotnet test --filter FullyQualifiedName~ApprovalWorkflow -c Release` shows only the 10 pure-Policy (no-DB) tests passing — all 8 new DB-backed integration tests fail with a connection error, unverified either way against a live database.** Do not mark COMPLETED until that run happens against a reachable Postgres and actually passes. Renumbered from VS-03 to VS-26 on 2026-08-08 per docs/DECISIONS/ADR-WBS-001-slice-renumbering.md — VS-03 in WBS_MASTER.csv ('IngestMarketDataPIT') remains a separate, unrelated, still-unimplemented slice. Also still open: `src/KArtSell.Host/Features/MarketData/VS03_*.cs` is a THIRD, unrelated, already-implemented-and-tested body of work also labeled 'VS-03' that is entirely absent from this tracker — see CURRENT_ROADMAP.md."
AEG-VS-27-01,S2,VS-27,불변 감사 추적 구현 (Audit Trail / GDPR),COMPLETED,2026-08-07,"docs/CURRENT/SLICE_SPECS/VS-27-SLICE_SPEC.md; src/KArtSell.Modules.ModelOperations/Compliance/ (AuditSql.cs, GdprRetention.cs); tests/KArtSell.Integration.Tests/Compliance/AuditTrailTests.cs; commit 97444c9 (Workstream I, PR #24, merged to main)",PM/BE Lead,"✅ Backend implementation + tests complete: append-only audit_events table, GDPR retention tracking + redaction (actor_email→'<redacted>', customer_id→'<purged>'), PII fields (ip_address). 5/5 tests PASS run in isolation (2026-08-07). Also fixed same day (fix/dapper-underscore-mapping-and-build branch): ip_address (inet) and kis_response-style jsonb columns threw InvalidCastException when read through Dapper into a typed class; GdprRetention.RetentionEndsAt was declared DateTime against a DATE column, same failure mode; and a process-wide Dapper snake_case-mapping race condition (KArtSell.BuildingBlocks' [ModuleInitializer] only fires once that assembly loads — AuditSql doesn't reliably touch it) intermittently nulled out every column read from this table depending on unrelated test/host startup order. None of this had ever been exercised against a live database before. ⚠️ No frontend UI yet — in progress 2026-08-08. Renumbered from VS-04 to VS-27 on 2026-08-08 per docs/DECISIONS/ADR-WBS-001-slice-renumbering.md — VS-04 in WBS_MASTER.csv ('ApplyCorporateActions') was an unrelated, still-unimplemented slice and keeps its original number unchanged."
AEG-VS-05-01,S3,VS-05,정책·범위·실패상태 계약 확정,BLOCKED,-,docs/CURRENT/AEG-VS-05-01_BLOCKER.md,PM/Architect,"2026-08-08: blocked before implementation. WBS defines IngestFundamentalsPIT (REQ-FND-001/DAT-05/MIG-FND-001/002/J04/UI-FND-01/T-FND-001), but existing VS-05 architecture/data contracts define unrelated Risk Metrics. Declared VS-02 dependency is not concretely evidenced beyond AEG-VS-02-01. See blocker record for required PM/Architect decision and Gate G1 evidence. No build/test/migration claimed."
AEG-VS-06-01,S3,VS-06,정책·범위·실패상태 계약 확정,BLOCKED,-,docs/CURRENT/AEG-VS-06-01_BLOCKER.md,PM/Architect,"2026-08-08: blocked before implementation. WBS defines MaintainFeeTaxFxSchedule (REQ-COST-001/COST-01/02/MIG-COST-001/J04C/UI-COST-01/T-COST-001), but existing VS-06 architecture/data contracts define unrelated Stress Testing (STRESS-* / migration 0035). Declared VS-02 dependency is not concrete enough for Gate G1. See blocker record for required PM/Architect and Compliance/Owner decisions. No build/test/migration claimed."
1 WBS_ID Sprint Slice_ID Task Status Completion_Date Evidence_Link Owner Notes
27 AEG-X-009 S1 Cross Source catalog 고도화 COMPLETED 2026-08-07 docs/CURRENT/CATALOGS/source-catalog.md; docs/CURRENT/AEG-X-009_AUTOMATION_PROPOSAL.md; contracts/data/source-approval.v1.proposed.json; docs/DECISIONS/ADR-DATA-001.md; db/migrations/0033_source_approval_contract.sql; db/migrations/0034_dataset_manifest_freeze_contract.sql; db/migrations/0033_market_data_import_logs.sql; src/KArtSell.Modules.ModelOperations/Infrastructure/DapperApprovedModelContextReader.cs Data Governance ✅ Workstream D/E/F COMPLETED: source-catalog.md v2.0 (KRX/OpenDart/KIS consolidated), VS-02_DATA_GOVERNANCE_POLICY.md, VS-03/04 SLICE_SPECs. All 4 unknowns resolved. ✅ Workstream G (commit 136665c, 2026-08-07) also now COMPLETE: live KRX OpenAPI / OpenDart / KIS service integrations (P1-P3), daily scheduling + error classification + SLA tracking + LKG fallback (P4-P6), market_data schema with append-only import logs, correlation_id-based idempotent replay. ⚠️ Note: 0033 is used by two different, unrelated migrations across branches (source_approval_contract.sql vs market_data_import_logs.sql) — confirm actual applied migration number in the target DB's kartsell_schema_versions journal before assuming both landed as authored.
28 AEG-VS-01-01 S1 VS-01 정책·범위·실패상태 계약 확정 COMPLETED 2026-08-07 docs/CURRENT/SLICE_SPECS/VS-01-SLICE_SPEC.md PM/Architect ✅ SLICE_SPEC produced: VS-01-SLICE_SPEC.md (identity/MFA/RBAC/maker-checker contract). Prerequisite AEG-X-001 + AEG-VS-00-02 already COMPLETED. Ready for security team review and schema implementation.
29 AEG-VS-02-01 S1 VS-02 정책·범위·실패상태 계약 확정 COMPLETED 2026-08-07 docs/CURRENT/SLICE_SPECS/VS-02-SLICE_SPEC.md; docs/CURRENT/VS-02_DATA_GOVERNANCE_POLICY.md PM/Architect ✅ COMPLETE: VS-02-SLICE_SPEC.md + governance policy. All 4 unknowns resolved (data source, import SLA, audit policy, schema versioning). Financial security master implementation ready for Phase 2.
30 AEG-VS-26-01 S2 VS-26 모델 승인 워크플로우 구현 (Maker-Checker Governance) BLOCKED - docs/CURRENT/SLICE_SPECS/VS-26-SLICE_SPEC.md; src/KArtSell.Modules.ModelOperations/ApprovalWorkflow/ (ApprovalSql.cs, ApprovalPolicy.cs, [DontRegister]'d); src/KArtSell.Modules.ModelOperations/Features/ApprovalWorkflow/ (Handlers.cs, Sql.cs, Policy.cs — the one actually wired in Program.cs); db/migrations/0036_approval_workflow.sql; tests/KArtSell.Integration.Tests/ApprovalWorkflow/*; TECH_DEBT_REGISTER.md DEBT-017; commit a2e742c (Workstream H, PR #23, merged to main) docs/CURRENT/SLICE_SPECS/VS-26-SLICE_SPEC.md; src/KArtSell.Modules.ModelOperations/Features/ApprovalWorkflow/ (Handlers.cs, Sql.cs, Policy.cs, Endpoints.cs — sole implementation, wired in Program.cs); db/migrations/0036_approval_workflow.sql; tests/KArtSell.Integration.Tests/ApprovalWorkflow/ApprovalWorkflowTests.cs (new, 8 cases); tests/KArtSell.Integration.Tests/ApprovalWorkflowPolicyTests.cs (extended, 10 cases); TECH_DEBT_REGISTER.md DEBT-017/DEBT-023; commit a2e742c (original duplication, superseded) PM/BE Lead 🔴 CORRECTED 2026-08-08 — this row previously said 'Backend implementation + tests complete, 20/20 tests PASS' and that claim is misleading: TECH_DEBT_REGISTER.md DEBT-017 records that TWO independent ApprovalWorkflow implementations exist with colliding routes. The one this row's evidence links to and the one with 20/20 passing tests (`ApprovalWorkflow/`, Workstream H) has all 4 endpoints annotated `[DontRegister]` and is NOT reachable via HTTP. The implementation actually registered in `Program.cs` and reachable at runtime is `Features/ApprovalWorkflow/` (Workstream G) — grep found no dedicated test file exercising it. Net effect: the maker-checker approval gate that is actually live has not been shown to work, and the one that has been shown to work is dead code. Do not build frontend UI against either implementation, and do not re-mark this COMPLETED, until an architect decision (DEBT-017) picks the canonical implementation, deletes the other, and a test suite runs against whichever is kept. Renumbered from VS-03 to VS-26 on 2026-08-08 per docs/DECISIONS/ADR-WBS-001-slice-renumbering.md — VS-03 in WBS_MASTER.csv ('IngestMarketDataPIT') is a separate, unrelated, still-unimplemented slice and keeps its original number unchanged. Also note: src/KArtSell.Host/Features/MarketData/VS03_*.cs is a THIRD, unrelated, already-implemented-and-tested body of work also labeled 'VS-03' (Market Data Ingestion Dashboard, commits 2bc2b1e/32b49a4) that is entirely absent from this tracker — see CURRENT_ROADMAP.md for a note to investigate and add it. 🟡 UPDATED 2026-08-08 — DEBT-017 architect decision made and executed: the duplicate `src/KArtSell.Modules.ModelOperations/ApprovalWorkflow/` (dead code, `[DontRegister]`'d, previously credited with the misleading '20/20 tests PASS') was DELETED along with its dedicated test file. `Features/ApprovalWorkflow/` (the implementation actually reachable over HTTP) is now the sole implementation and gained new Handler+Sql+real-Postgres integration tests covering create/approve/activate role gating, maker≠checker separation of duties, evidence attachment, and an explicit `DateOnly EffectiveAt` round-trip. While porting: found `Features/ApprovalWorkflow/Sql.cs InsertProposalAsync` had the same Dapper `DateOnly`-binding bug already fixed in the deleted implementation (commit 2ccf74c) — fixed identically here (`::date` cast + string parameter). Two residual (pre-existing, not introduced by this cleanup) gaps documented in the slice README rather than fixed: no `GET /approvals/{id}` endpoint, and no wired Draft→Proposed transition anywhere in the running app (approve/activate are therefore currently unreachable end-to-end via HTTP with real data). **Still BLOCKED, not COMPLETED, because no PostgreSQL was reachable in this session (127.0.0.1:5432 connection refused, no SSH tunnel open): `dotnet build -c Release` is clean, but `dotnet test --filter FullyQualifiedName~ApprovalWorkflow -c Release` shows only the 10 pure-Policy (no-DB) tests passing — all 8 new DB-backed integration tests fail with a connection error, unverified either way against a live database.** Do not mark COMPLETED until that run happens against a reachable Postgres and actually passes. Renumbered from VS-03 to VS-26 on 2026-08-08 per docs/DECISIONS/ADR-WBS-001-slice-renumbering.md — VS-03 in WBS_MASTER.csv ('IngestMarketDataPIT') remains a separate, unrelated, still-unimplemented slice. Also still open: `src/KArtSell.Host/Features/MarketData/VS03_*.cs` is a THIRD, unrelated, already-implemented-and-tested body of work also labeled 'VS-03' that is entirely absent from this tracker — see CURRENT_ROADMAP.md.
31 AEG-VS-27-01 S2 VS-27 불변 감사 추적 구현 (Audit Trail / GDPR) COMPLETED 2026-08-07 docs/CURRENT/SLICE_SPECS/VS-27-SLICE_SPEC.md; src/KArtSell.Modules.ModelOperations/Compliance/ (AuditSql.cs, GdprRetention.cs); tests/KArtSell.Integration.Tests/Compliance/AuditTrailTests.cs; commit 97444c9 (Workstream I, PR #24, merged to main) PM/BE Lead ✅ Backend implementation + tests complete: append-only audit_events table, GDPR retention tracking + redaction (actor_email→'<redacted>', customer_id→'<purged>'), PII fields (ip_address). 5/5 tests PASS run in isolation (2026-08-07). Also fixed same day (fix/dapper-underscore-mapping-and-build branch): ip_address (inet) and kis_response-style jsonb columns threw InvalidCastException when read through Dapper into a typed class; GdprRetention.RetentionEndsAt was declared DateTime against a DATE column, same failure mode; and a process-wide Dapper snake_case-mapping race condition (KArtSell.BuildingBlocks' [ModuleInitializer] only fires once that assembly loads — AuditSql doesn't reliably touch it) intermittently nulled out every column read from this table depending on unrelated test/host startup order. None of this had ever been exercised against a live database before. ⚠️ No frontend UI yet — in progress 2026-08-08. Renumbered from VS-04 to VS-27 on 2026-08-08 per docs/DECISIONS/ADR-WBS-001-slice-renumbering.md — VS-04 in WBS_MASTER.csv ('ApplyCorporateActions') was an unrelated, still-unimplemented slice and keeps its original number unchanged.
32 AEG-VS-05-01 S3 VS-05 정책·범위·실패상태 계약 확정 BLOCKED - docs/CURRENT/AEG-VS-05-01_BLOCKER.md PM/Architect 2026-08-08: blocked before implementation. WBS defines IngestFundamentalsPIT (REQ-FND-001/DAT-05/MIG-FND-001/002/J04/UI-FND-01/T-FND-001), but existing VS-05 architecture/data contracts define unrelated Risk Metrics. Declared VS-02 dependency is not concretely evidenced beyond AEG-VS-02-01. See blocker record for required PM/Architect decision and Gate G1 evidence. No build/test/migration claimed.
33 AEG-VS-06-01 S3 VS-06 정책·범위·실패상태 계약 확정 BLOCKED - docs/CURRENT/AEG-VS-06-01_BLOCKER.md PM/Architect 2026-08-08: blocked before implementation. WBS defines MaintainFeeTaxFxSchedule (REQ-COST-001/COST-01/02/MIG-COST-001/J04C/UI-COST-01/T-COST-001), but existing VS-06 architecture/data contracts define unrelated Stress Testing (STRESS-* / migration 0035). Declared VS-02 dependency is not concrete enough for Gate G1. See blocker record for required PM/Architect and Compliance/Owner decisions. No build/test/migration claimed.