HighlightSections = new();
+ private string SchemaVersion = "n/a";
+ private string SourceJson = "n/a";
+ private string GeneratedAt = "n/a";
+ private string SectionCountLabel = "0";
+ private string RenderedSectionCountLabel = "0";
+ private string HealthLabel = "DATA_MISSING";
+ private Color HealthColor = Color.Warning;
+ private string ReportPath = "n/a";
+
+ protected override async Task OnInitializedAsync()
+ {
+ ReportPath = Path.GetFullPath(Path.Combine(Environment.ContentRootPath, "..", "..", "..", "Temp", "operational_report.json"));
+
+ var report = OperationalReportLoader.Load(ReportPath);
+ SchemaVersion = report.SchemaVersion;
+ SourceJson = report.SourceJson;
+ GeneratedAt = report.GeneratedAt;
+ Sections.AddRange(report.Sections);
+
+ HighlightSections.Clear();
+ HighlightSections.AddRange(Sections.Take(4));
+
+ SectionCountLabel = report.SectionCount.ToString();
+ RenderedSectionCountLabel = Sections.Count.ToString();
+ HealthLabel = Sections.Count > 0 ? "PASS" : "DATA_MISSING";
+ HealthColor = Sections.Count > 0 ? Color.Success : Color.Warning;
+ }
+}
diff --git a/src/dotnet/QuantEngine.Web/Components/Pages/Weather.razor b/src/dotnet/QuantEngine.Web/Components/Pages/Weather.razor
deleted file mode 100644
index f437e5e..0000000
--- a/src/dotnet/QuantEngine.Web/Components/Pages/Weather.razor
+++ /dev/null
@@ -1,64 +0,0 @@
-@page "/weather"
-@attribute [StreamRendering]
-
-Weather
-
-Weather
-
-This component demonstrates showing data.
-
-@if (forecasts == null)
-{
- Loading...
-}
-else
-{
-
-
-
- | Date |
- Temp. (C) |
- Temp. (F) |
- Summary |
-
-
-
- @foreach (var forecast in forecasts)
- {
-
- | @forecast.Date.ToShortDateString() |
- @forecast.TemperatureC |
- @forecast.TemperatureF |
- @forecast.Summary |
-
- }
-
-
-}
-
-@code {
- private WeatherForecast[]? forecasts;
-
- protected override async Task OnInitializedAsync()
- {
- // Simulate asynchronous loading to demonstrate streaming rendering
- await Task.Delay(500);
-
- var startDate = DateOnly.FromDateTime(DateTime.Now);
- var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
- forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
- {
- Date = startDate.AddDays(index),
- TemperatureC = Random.Shared.Next(-20, 55),
- Summary = summaries[Random.Shared.Next(summaries.Length)]
- }).ToArray();
- }
-
- private class WeatherForecast
- {
- public DateOnly Date { get; set; }
- public int TemperatureC { get; set; }
- public string? Summary { get; set; }
- public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
- }
-}
diff --git a/tools/run_release_dag_v1.py b/tools/run_release_dag_v1.py
index 67d1894..38bec03 100644
--- a/tools/run_release_dag_v1.py
+++ b/tools/run_release_dag_v1.py
@@ -23,6 +23,7 @@ def _release_commands() -> list[list[str]]:
_cmd("tools/validate_specs.py"),
_cmd("tools/validate_active_manifest.py", "--manifest", "runtime/active_artifact_manifest.yaml", "--strict"),
_cmd("tools/validate_report_packet_sync_v1.py", "--packet", "Temp/final_decision_packet_active.json", "--report", "Temp/operational_report.json"),
+ _cmd("tools/validate_report_section_completeness_v1.py"),
_cmd("tools/validate_field_dictionary.py"),
_cmd("tools/validate_number_provenance_strict_v3.py", "--ledger", "Temp/number_provenance_ledger_v4.json", "--report", "Temp/operational_report.md"),
_cmd("tools/validate_low_capability_pack_v1.py", "--context", "Temp/final_context_for_llm_v4.yaml", "--contract", "spec/46_low_capability_execution_pack.yaml"),
diff --git a/tools/validate_report_section_completeness_v1.py b/tools/validate_report_section_completeness_v1.py
index dcff732..fa6dc1b 100644
--- a/tools/validate_report_section_completeness_v1.py
+++ b/tools/validate_report_section_completeness_v1.py
@@ -38,6 +38,20 @@ REPORT_SECTION_ORDER = [
"rule_lifecycle_governance_report",
]
+MISSING_DATA_TOKEN = "DATA_MISSING — 하네스 업데이트 필요"
+
+
+def _missing_category(section_name: str) -> str:
+ if section_name in {"fundamental_quality_gate_v1", "horizon_allocation_lock_v1", "smart_money_liquidity_gate_v1"}:
+ return "core_signal_gap"
+ if section_name in {"benchmark_relative_harness_table", "index_relative_health_table", "entry_freshness_gate_table", "sell_value_preservation_gate_table", "watch_release_checklist"}:
+ return "market_gate_gap"
+ if section_name in {"engine_feedback_loop_report", "prediction_evaluation_improvement_report", "performance_readiness_summary"}:
+ return "performance_gate_gap"
+ if section_name in {"alpha_lead_table", "anti_distribution_table", "profit_preservation_table", "smart_cash_raise_table", "execution_quality_table", "sell_priority_decision_table"}:
+ return "decision_table_gap"
+ return "other_gap"
+
def main() -> int:
ap = argparse.ArgumentParser()
@@ -62,6 +76,21 @@ def main() -> int:
missing = [n for n in REPORT_SECTION_ORDER if n not in present]
empty = [n for n in REPORT_SECTION_ORDER if n in present and n not in non_empty]
err_names = [e["section"] for e in section_errors if isinstance(e, dict)]
+ missing_data_rows = []
+ for section in sections_list:
+ if not isinstance(section, dict):
+ continue
+ name = str(section.get("name") or "")
+ markdown = str(section.get("markdown") or "")
+ if not name or name == "section_processing_errors":
+ continue
+ if MISSING_DATA_TOKEN not in markdown:
+ continue
+ missing_data_rows.append({
+ "section": name,
+ "category": _missing_category(name),
+ "missing_line_count": sum(1 for line in markdown.splitlines() if MISSING_DATA_TOKEN in line),
+ })
# 결과 출력
print(f"REPORT_SECTION_ORDER 기준: {len(REPORT_SECTION_ORDER)}개 섹션 검사")
@@ -99,8 +128,21 @@ def main() -> int:
out = ROOT / "Temp" / "report_section_completeness.json"
out.write_text(json.dumps(result, indent=2, ensure_ascii=False), encoding="utf-8")
+ inventory_out = ROOT / "Temp" / "missing_data_inventory_v1.json"
+ inventory_result = {
+ "validator": "validate_report_section_completeness_v1",
+ "section_count": len(sections_list),
+ "missing_section_count": len(missing_data_rows),
+ "categories": {},
+ "sections": missing_data_rows,
+ }
+ for row in missing_data_rows:
+ cat = row["category"]
+ inventory_result["categories"][cat] = inventory_result["categories"].get(cat, 0) + 1
+ inventory_out.write_text(json.dumps(inventory_result, indent=2, ensure_ascii=False), encoding="utf-8")
print(f"\nREPORT_SECTION_COMPLETENESS: gate={result['gate']} missing={len(missing)} empty={len(empty)} section_errors={len(section_errors)}")
print(f"OUTPUT: {out}")
+ print(f"MISSING_DATA_INVENTORY: sections={len(missing_data_rows)} OUTPUT: {inventory_out}")
if missing:
return 1