e7913dbde6
ci / backend (push) Failing after 2s
ci / static (push) Failing after 9s
Build & Test with Secrets / build (push) Failing after 1s
deploy / deploy (push) Successful in 3m32s
Build & Test with Secrets / security-scan (push) Failing after 10s
deploy / notify (push) Successful in 1s
ci / frontend (push) Successful in 4m47s
ci / publish (push) Has been skipped
Build & Test with Secrets / frontend (push) Successful in 4m42s
Build & Test with Secrets / notification (push) Failing after 1s
Track B: Evidence Collection (Parallel execution) B1: PII Redaction Policy Tests (6 tests) - Tests for SSN, Email, CreditCard, ApiKey redaction - Pattern-based sanitization validation - Location: tests/KArtSell.ArchitectureTests/PiiRedactionTests.cs B3: VS-00 SLICE_SPEC + Platform Governance (1 document) - User story, non-goals, state transitions - RBAC constraints, data contracts - Governance gates (data approval workflows) - Location: docs/CURRENT/SLICE_SPECS/VS-00-SLICE_SPEC.md B4: Platform DATA_CONTRACT v1.0 (1 document) - PIT envelope pattern (published_at, correlation_id, revision) - Table schemas with DQ rules - Lineage and compliance requirements - Location: contracts/data/platform-data-contract.v1.json B5: Pure Policy Unit Tests (13 tests) - SellPriorityPolicy: Priority sorting, bounds validation (6 tests) - ModelStateTransitionPolicy: Linear state machine (3 tests) - MonotonicityPolicy: Confidence/threshold monotonicity (4 tests) - Location: tests/KArtSell.ModelOperations.UnitTests/PolicyTests.cs Test Results: 249/253 PASS + 4 SKIP - Architecture: 12/12 (includes 6 PII tests) - ModelOperations Unit: 54/54 (includes 13 Policy tests) - SignalEngine Unit: 18/18 - Integration: 165/169 (4 skip) Status: All evidence items collected and tested locally Next: Track A (Host deployment recovery) + Track C (WBS update) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
221 lines
11 KiB
JSON
221 lines
11 KiB
JSON
{
|
||
"version": "1.0",
|
||
"date": "2026-08-06",
|
||
"owner": "Platform Architecture",
|
||
"description": "Master data contract for K-ArtSell Aegis v16.0 - defines schema, PIT rules, and DQ lineage",
|
||
"governance": "AGENTS.md v16.0 compliant; all tables MUST follow PIT envelope pattern",
|
||
|
||
"pit_envelope": {
|
||
"description": "Point-in-Time data consistency model",
|
||
"columns": {
|
||
"published_at": {
|
||
"type": "timestamp",
|
||
"nullable": false,
|
||
"default": "now()",
|
||
"purpose": "Record publication timestamp for historical querying"
|
||
},
|
||
"correlation_id": {
|
||
"type": "uuid",
|
||
"nullable": false,
|
||
"purpose": "Trace changes across modules (Outbox→Inbox)"
|
||
},
|
||
"revision": {
|
||
"type": "integer",
|
||
"nullable": false,
|
||
"default": 1,
|
||
"purpose": "Track revision count (immutable + versioning)"
|
||
}
|
||
},
|
||
"query_pattern": "SELECT * FROM table WHERE published_at <= @cutoff AND status = 'active' ORDER BY published_at DESC LIMIT 1"
|
||
},
|
||
|
||
"tables": [
|
||
{
|
||
"name": "model_operations.models",
|
||
"owner": "ModelOperations Module",
|
||
"purpose": "Master record of AI models (lifecycle: Freeze→Mature→Score→Diagnose→Hypothesis→Challenger→Validate→Review→Manual)",
|
||
"columns": {
|
||
"model_id": {"type": "uuid", "nullable": false, "key": "primary", "example": "00000000-0000-0000-0000-000000000001"},
|
||
"name": {"type": "varchar(255)", "nullable": false, "example": "GARCH-Vol-Predictor-v1"},
|
||
"status": {"type": "varchar(50)", "nullable": false, "enum": ["Freeze", "Mature", "Score", "Diagnose", "Hypothesis", "Challenger", "Validate", "Review", "ManualActivation"], "dq_rule": "Must be exact enum value (case-sensitive)"},
|
||
"version": {"type": "integer", "nullable": false, "dq_rule": "Increment on each state transition"},
|
||
"created_at": {"type": "timestamp", "nullable": false},
|
||
"created_by": {"type": "varchar(255)", "nullable": false, "dq_rule": "Must match authenticated user"},
|
||
"published_at": {"type": "timestamp", "nullable": false, "pit": true},
|
||
"correlation_id": {"type": "uuid", "nullable": false, "pit": true},
|
||
"revision": {"type": "integer", "nullable": false, "pit": true}
|
||
},
|
||
"constraints": {
|
||
"no_update": "All changes are new rows (append-only)",
|
||
"no_delete": "Soft delete via status change only",
|
||
"uniqueness": "Only one 'active' revision per model_id at any cutoff time"
|
||
}
|
||
},
|
||
{
|
||
"name": "signal_engine.signals",
|
||
"owner": "SignalEngine Module",
|
||
"purpose": "Trading signals generated from model scoring",
|
||
"columns": {
|
||
"signal_id": {"type": "uuid", "nullable": false, "key": "primary"},
|
||
"model_id": {"type": "uuid", "nullable": false, "foreign_key": "model_operations.models(model_id)", "dq_rule": "Must reference valid model at published_at cutoff"},
|
||
"portfolio_id": {"type": "uuid", "nullable": false},
|
||
"signal_type": {"type": "varchar(50)", "nullable": false, "enum": ["BUY", "SELL", "HOLD"], "dq_rule": "Exact enum value"},
|
||
"confidence_score": {"type": "decimal(5,4)", "nullable": false, "dq_rule": "0.0000 ≤ score ≤ 1.0000"},
|
||
"issued_at": {"type": "timestamp", "nullable": false},
|
||
"expires_at": {"type": "timestamp", "nullable": true, "dq_rule": "If present, must be > issued_at"},
|
||
"published_at": {"type": "timestamp", "nullable": false, "pit": true},
|
||
"correlation_id": {"type": "uuid", "nullable": false, "pit": true},
|
||
"revision": {"type": "integer", "nullable": false, "pit": true}
|
||
},
|
||
"constraints": {
|
||
"referential_integrity": "model_id must exist at published_at ≤ signal's published_at",
|
||
"temporal_validity": "issued_at must be ≤ published_at"
|
||
}
|
||
},
|
||
{
|
||
"name": "market_data.prices",
|
||
"owner": "KRX API Integration",
|
||
"purpose": "Daily OHLCV (Open, High, Low, Close, Volume) from Korea Exchange",
|
||
"columns": {
|
||
"price_id": {"type": "uuid", "nullable": false, "key": "primary"},
|
||
"symbol": {"type": "varchar(10)", "nullable": false, "dq_rule": "KRX stock code (6 digits for KOSPI, e.g., '005930' for Samsung)"},
|
||
"trade_date": {"type": "date", "nullable": false, "dq_rule": "Business day only (Mon-Fri, excluding holidays)"},
|
||
"open_price": {"type": "decimal(15,2)", "nullable": false, "dq_rule": "> 0"},
|
||
"high_price": {"type": "decimal(15,2)", "nullable": false, "dq_rule": "≥ close_price"},
|
||
"low_price": {"type": "decimal(15,2)", "nullable": false, "dq_rule": "≤ close_price"},
|
||
"close_price": {"type": "decimal(15,2)", "nullable": false, "dq_rule": "> 0"},
|
||
"volume": {"type": "bigint", "nullable": false, "dq_rule": "≥ 0; typically > 1000 shares for liquid stocks"},
|
||
"source": {"type": "varchar(50)", "nullable": false, "default": "KRX_OPENAPI", "dq_rule": "Immutable source attribution"},
|
||
"published_at": {"type": "timestamp", "nullable": false, "pit": true},
|
||
"correlation_id": {"type": "uuid", "nullable": false, "pit": true},
|
||
"revision": {"type": "integer", "nullable": false, "pit": true}
|
||
},
|
||
"constraints": {
|
||
"unique_per_day": "(symbol, trade_date) is unique",
|
||
"price_ordering": "low_price ≤ open_price, close_price ≤ high_price",
|
||
"no_future_dates": "trade_date ≤ today()"
|
||
},
|
||
"sla": {
|
||
"availability": "99.5%",
|
||
"latency": "< 100ms (cached)",
|
||
"freshness": "T+1 (end of business day)"
|
||
}
|
||
},
|
||
{
|
||
"name": "portfolio.holdings",
|
||
"owner": "Portfolio Module",
|
||
"purpose": "User portfolio: assets owned, quantities, cost basis",
|
||
"columns": {
|
||
"holding_id": {"type": "uuid", "nullable": false, "key": "primary"},
|
||
"portfolio_id": {"type": "uuid", "nullable": false},
|
||
"symbol": {"type": "varchar(10)", "nullable": false},
|
||
"quantity": {"type": "decimal(15,4)", "nullable": false, "dq_rule": "> 0; fractional shares allowed"},
|
||
"cost_basis": {"type": "decimal(15,2)", "nullable": false, "dq_rule": "> 0 if quantity > 0"},
|
||
"acquisition_date": {"type": "date", "nullable": false, "dq_rule": "≤ today()"},
|
||
"published_at": {"type": "timestamp", "nullable": false, "pit": true},
|
||
"correlation_id": {"type": "uuid", "nullable": false, "pit": true},
|
||
"revision": {"type": "integer", "nullable": false, "pit": true}
|
||
},
|
||
"constraints": {
|
||
"logical_consistency": "If quantity = 0, holding is logically 'sold' (soft delete)",
|
||
"cost_relationship": "total_cost = quantity × cost_basis (must reconcile with transactions)"
|
||
}
|
||
},
|
||
{
|
||
"name": "audit.events",
|
||
"owner": "Observability Module",
|
||
"purpose": "Immutable event log for compliance and troubleshooting",
|
||
"columns": {
|
||
"event_id": {"type": "uuid", "nullable": false, "key": "primary"},
|
||
"event_type": {"type": "varchar(100)", "nullable": false, "enum": ["ModelActivated", "SignalIssued", "TradingExecuted", "ApprovalRequested"], "dq_rule": "Exact enum"},
|
||
"correlation_id": {"type": "uuid", "nullable": false, "pit": true, "dq_rule": "Links back to originating command"},
|
||
"actor_id": {"type": "uuid", "nullable": false, "dq_rule": "User/service that triggered event"},
|
||
"action": {"type": "text", "nullable": true, "dq_rule": "Serialized command payload (sanitized of PII)"},
|
||
"result": {"type": "varchar(50)", "nullable": false, "enum": ["Success", "Failure", "Pending"]},
|
||
"occurred_at": {"type": "timestamp", "nullable": false, "dq_rule": "Event time (not insertion time)"},
|
||
"published_at": {"type": "timestamp", "nullable": false, "pit": true},
|
||
"revision": {"type": "integer", "nullable": false, "pit": true, "default": 1}
|
||
},
|
||
"constraints": {
|
||
"immutable": "No updates allowed (INSERT ONLY)",
|
||
"retention": "Kept for minimum 7 years (regulatory requirement)"
|
||
}
|
||
}
|
||
],
|
||
|
||
"data_quality_rules": {
|
||
"by_source": {
|
||
"KRX_API": {
|
||
"availability_sla": "99.5%",
|
||
"completeness": "No null prices, volumes",
|
||
"accuracy": "Must match official KRX reporting",
|
||
"timeliness": "T+1 (end of business day)",
|
||
"fallback": "Use cached last-known-good (LKG) if API fails"
|
||
},
|
||
"OpenDart_API": {
|
||
"availability_sla": "99.0%",
|
||
"completeness": "Filing date, report type, corp_code must be non-null",
|
||
"accuracy": "Must match official FSS (Financial Supervisory Service) repository",
|
||
"timeliness": "T+2 (regulatory reporting)",
|
||
"fallback": "Queue for retry (Hangfire job with exponential backoff)"
|
||
},
|
||
"User_Input": {
|
||
"availability_sla": "95.0% (user-provided, best effort)",
|
||
"completeness": "Validated at API boundary (FastEndpoints validator)",
|
||
"accuracy": "User's responsibility; audit trail required",
|
||
"timeliness": "Real-time (synchronous)",
|
||
"validation": "Qty ≥ 0, price ≥ 0, date ≤ today()"
|
||
},
|
||
"Computed_Fields": {
|
||
"availability_sla": "99.9% (auto-computed)",
|
||
"completeness": "Guaranteed (computed from base fields)",
|
||
"accuracy": "Deterministic (same input → same output)",
|
||
"timeliness": "Refresh on event (Outbox→Inbox trigger)",
|
||
"formula": "portfolio_value = SUM(qty × market_price) for active holdings"
|
||
}
|
||
}
|
||
},
|
||
|
||
"lineage_and_dependencies": {
|
||
"shadow_run": {
|
||
"inputs": ["models", "prices", "holdings"],
|
||
"outputs": ["shadow_run_results"],
|
||
"duration": "252+ trading days",
|
||
"sla": "99.9% completion (auto-retry on transient failures)"
|
||
},
|
||
"signal_generation": {
|
||
"inputs": ["models (Mature+)", "prices"],
|
||
"outputs": ["signals"],
|
||
"trigger": "Hangfire job (daily 09:00 KST)",
|
||
"sla": "< 1 minute latency"
|
||
},
|
||
"portfolio_rebalance": {
|
||
"inputs": ["signals", "holdings", "prices"],
|
||
"outputs": ["rebalance_recommendations"],
|
||
"trigger": "User request or scheduled (weekly)",
|
||
"approval": "Maker-checker (2-level approval)"
|
||
}
|
||
},
|
||
|
||
"compliance_and_security": {
|
||
"gdpr_rules": [
|
||
"User PII (name, email, SSN) must be redacted in logs",
|
||
"Audit trail must be immutable (audit.events is INSERT ONLY)",
|
||
"Right to erasure: Soft delete via status field (logical delete, not physical)",
|
||
"Data retention: Portfolio data kept for 5 years; audit kept for 7 years"
|
||
],
|
||
"pci_dss_rules": [
|
||
"Credit card data NEVER stored (payment via third-party provider)",
|
||
"All financial data encrypted at rest (PostgreSQL pgcrypto)",
|
||
"API calls use HTTPS + TLS 1.2+ only",
|
||
"No API key logging (masked in audit trail)"
|
||
],
|
||
"audit_requirements": [
|
||
"All mutations (INSERT, UPDATE, soft-DELETE) logged to audit.events",
|
||
"correlation_id traces change across services",
|
||
"actor_id identifies responsible user/service",
|
||
"action field captures sanitized command (PII redacted)"
|
||
]
|
||
}
|
||
}
|