Files
ewoooc/templates/market_intel/disabled.html
OoO 73ec78e8ab
All checks were successful
CD Pipeline / deploy (push) Successful in 1m29s
[V10.356] add market intel catalog record final closeout gate
2026-05-21 10:05:59 +08:00

11659 lines
733 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "ewoooc_base.html" %}
{% block title %}市場情報EwoooC{% endblock %}
{% block extra_css %}
<style>
.market-intel-status {
display: grid;
gap: 1rem;
min-width: 0;
max-width: 100%;
}
.market-intel-panel {
box-sizing: border-box;
min-width: 0;
max-width: 100%;
overflow: hidden;
border: 1px solid var(--momo-border, #d8c8aa);
border-radius: 8px;
background:
radial-gradient(circle at 1px 1px, rgba(120, 83, 44, 0.16) 1px, transparent 1.35px),
var(--momo-paper, #f8f2e7);
background-size: 10px 10px, auto;
box-shadow: var(--momo-shadow-sm, 0 8px 18px rgba(72, 49, 28, 0.08));
padding: 1.25rem;
}
.market-intel-title {
color: var(--momo-ink, #30251b);
font-size: 1.35rem;
font-weight: 800;
margin: 0;
}
.market-intel-muted {
color: var(--momo-muted, #756a5b);
margin: 0;
overflow-wrap: anywhere;
}
.market-intel-flags {
display: grid;
gap: 0.75rem;
grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
margin-top: 1rem;
min-width: 0;
}
.market-intel-flag {
min-width: 0;
border-left: 3px solid var(--momo-accent, #c8752d);
background: rgba(255, 250, 241, 0.84);
padding: 0.8rem 0.9rem;
}
.market-intel-flag span {
color: var(--momo-muted, #756a5b);
display: block;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0;
}
.market-intel-flag strong {
color: var(--momo-ink, #30251b);
font-family: "JetBrains Mono", monospace;
font-size: 1rem;
}
.market-intel-preview-head {
align-items: center;
display: flex;
gap: 0.75rem;
justify-content: space-between;
margin-bottom: 1rem;
}
.market-intel-preview-title {
color: var(--momo-ink, #30251b);
font-size: 1rem;
font-weight: 800;
margin: 0;
}
.market-intel-icon-button {
align-items: center;
background: rgba(255, 250, 241, 0.9);
border: 1px solid var(--momo-border, #d8c8aa);
border-radius: 8px;
color: var(--momo-ink, #30251b);
display: inline-flex;
height: 2.25rem;
justify-content: center;
width: 2.25rem;
}
.market-intel-icon-button:hover {
background: rgba(201, 117, 45, 0.12);
color: var(--momo-accent-700, #8f4530);
}
.market-intel-preview-meta {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1rem;
}
.market-intel-pill {
min-width: 0;
background: rgba(255, 250, 241, 0.82);
border: 1px solid rgba(120, 83, 44, 0.14);
border-radius: 8px;
color: var(--momo-muted, #756a5b);
font-family: "JetBrains Mono", monospace;
font-size: 0.78rem;
font-weight: 700;
overflow-wrap: anywhere;
padding: 0.35rem 0.5rem;
}
.market-intel-empty {
background: rgba(255, 250, 241, 0.72);
border: 1px dashed rgba(120, 83, 44, 0.28);
border-radius: 8px;
color: var(--momo-muted, #756a5b);
padding: 1rem;
}
.market-intel-candidate-list {
display: grid;
gap: 0.75rem;
min-width: 0;
}
.market-intel-candidate {
min-width: 0;
background: rgba(255, 250, 241, 0.82);
border: 1px solid rgba(120, 83, 44, 0.14);
border-left: 3px solid var(--momo-accent, #c8752d);
border-radius: 8px;
padding: 0.8rem 0.9rem;
}
.market-intel-candidate a {
color: var(--momo-ink, #30251b);
font-weight: 800;
text-decoration: none;
word-break: break-word;
}
.market-intel-candidate small {
color: var(--momo-muted, #756a5b);
display: block;
margin-top: 0.35rem;
}
.market-intel-operation-list {
display: grid;
gap: 0.75rem;
min-width: 0;
}
.market-intel-operation {
min-width: 0;
background: rgba(255, 250, 241, 0.82);
border: 1px solid rgba(120, 83, 44, 0.14);
border-left: 3px solid var(--momo-accent, #c8752d);
border-radius: 8px;
padding: 0.8rem 0.9rem;
}
.market-intel-operation strong {
color: var(--momo-ink, #30251b);
display: block;
font-family: "JetBrains Mono", monospace;
font-size: 0.92rem;
word-break: break-word;
}
.market-intel-operation small {
color: var(--momo-muted, #756a5b);
display: block;
margin-top: 0.35rem;
}
.market-intel-check-list {
display: grid;
gap: 0.6rem;
min-width: 0;
}
.market-intel-deploy-grid {
display: grid;
gap: 0.9rem;
grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
margin-top: 1rem;
min-width: 0;
}
.market-intel-deploy-section-title {
color: var(--momo-muted, #756a5b);
font-family: "JetBrains Mono", monospace;
font-size: 0.78rem;
font-weight: 800;
margin: 0 0 0.55rem;
}
.market-intel-check {
align-items: center;
background: rgba(255, 250, 241, 0.82);
border: 1px solid rgba(120, 83, 44, 0.14);
border-radius: 8px;
color: var(--momo-muted, #756a5b);
display: flex;
gap: 0.65rem;
justify-content: space-between;
min-width: 0;
padding: 0.65rem 0.75rem;
}
.market-intel-check div {
min-width: 0;
}
.market-intel-check strong {
color: var(--momo-ink, #30251b);
font-family: "JetBrains Mono", monospace;
font-size: 0.84rem;
word-break: break-word;
}
.market-intel-check small {
color: var(--momo-muted, #756a5b);
display: block;
line-height: 1.45;
margin-top: 0.25rem;
overflow-wrap: anywhere;
}
.market-intel-check span {
color: var(--momo-muted, #756a5b);
font-family: "JetBrains Mono", monospace;
font-size: 0.78rem;
font-weight: 800;
white-space: nowrap;
}
.market-intel-control-row {
align-items: stretch;
display: grid;
gap: 0.75rem;
grid-template-columns: minmax(0, 1fr) auto;
min-width: 0;
}
.market-intel-control-actions {
align-content: flex-start;
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
justify-content: flex-end;
min-width: 0;
max-width: min(34rem, 100%);
}
.market-intel-json-input {
background: rgba(255, 250, 241, 0.9);
border: 1px solid var(--momo-border, #d8c8aa);
border-radius: 8px;
color: var(--momo-ink, #30251b);
font-family: "JetBrains Mono", monospace;
font-size: 0.82rem;
line-height: 1.55;
min-width: 0;
outline: none;
padding: 0.75rem;
resize: vertical;
width: 100%;
}
.market-intel-json-input:focus {
border-color: var(--momo-accent, #c8752d);
box-shadow: 0 0 0 3px rgba(201, 117, 45, 0.14);
}
@media (max-width: 760px) {
.market-intel-preview-head,
.market-intel-check,
.market-intel-control-row {
align-items: flex-start;
flex-direction: column;
}
.market-intel-control-row {
grid-template-columns: 1fr;
}
.market-intel-control-actions {
justify-content: flex-start;
max-width: 100%;
}
.market-intel-panel {
padding: 1rem;
}
.market-intel-check span {
max-width: 100%;
overflow-wrap: anywhere;
white-space: normal;
}
}
</style>
{% endblock %}
{% block ewooo_content %}
<section class="market-intel-status">
<div class="market-intel-panel">
<p class="market-intel-muted momo-mono mb-2">MARKET INTEL / {{ status.phase }}</p>
<h1 class="market-intel-title">市場情報尚未啟用</h1>
<p class="market-intel-muted mt-2">目前只載入安全骨架;爬蟲、正式寫入與排程都尚未掛載。</p>
<div class="market-intel-flags">
<div class="market-intel-flag">
<span>模組開關</span>
<strong>{{ 'ON' if status.enabled else 'OFF' }}</strong>
</div>
<div class="market-intel-flag">
<span>爬蟲開關</span>
<strong>{{ 'ON' if status.crawler_enabled else 'OFF' }}</strong>
</div>
<div class="market-intel-flag">
<span>資料寫入</span>
<strong>{{ 'ON' if status.write_enabled else 'OFF' }}</strong>
</div>
<div class="market-intel-flag">
<span>排程掛載</span>
<strong>{{ 'ON' if status.scheduler_attached else 'OFF' }}</strong>
</div>
<div class="market-intel-flag">
<span>DB 寫入許可</span>
<strong>{{ 'ON' if status.database_write_allowed else 'OFF' }}</strong>
</div>
<div class="market-intel-flag">
<span>已註冊 Adapter</span>
<strong>{{ adapter_count|default(0) }}</strong>
</div>
<div class="market-intel-flag">
<span>手動 Fetch</span>
<strong>{{ 'ON' if manual_fetch_allowed|default(false) else 'OFF' }}</strong>
</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-preview>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">CANDIDATE PREVIEW / SAFE</p>
<h2 class="market-intel-preview-title">候選預覽</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理候選預覽" data-market-intel-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-preview-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-preview-body>
<div class="market-intel-empty">讀取候選預覽中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-writer>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">SEED WRITER / DRY RUN</p>
<h2 class="market-intel-preview-title">平台種子寫入預覽</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理寫入預覽" data-market-intel-writer-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-writer-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-writer-body>
<div class="market-intel-empty">讀取寫入預覽中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-cli>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">SEED CLI / TRANSACTION PREVIEW</p>
<h2 class="market-intel-preview-title">Seed CLI 交易預覽</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理交易預覽" data-market-intel-cli-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-cli-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-cli-body>
<div class="market-intel-empty">讀取交易預覽中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-db-probe>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">DB SCHEMA / READ ONLY PROBE</p>
<h2 class="market-intel-preview-title">正式 DB Schema 探針</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理 DB 探針" data-market-intel-db-probe-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-db-probe-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-db-probe-body>
<div class="market-intel-empty">讀取 DB 探針中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-seed-diff>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">PLATFORM SEED / READ ONLY DIFF</p>
<h2 class="market-intel-preview-title">平台 Seed DB 差異探針</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理 Seed 差異" data-market-intel-seed-diff-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-seed-diff-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-seed-diff-body>
<div class="market-intel-empty">讀取 Seed 差異探針中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-legacy-bridge>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">LEGACY SOURCE / BRIDGE PREVIEW</p>
<h2 class="market-intel-preview-title">既有資料橋接預覽</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理橋接預覽" data-market-intel-legacy-bridge-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-legacy-bridge-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-legacy-bridge-body>
<div class="market-intel-empty">讀取既有資料橋接預覽中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-mcp-readiness>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MCP / READINESS PREVIEW</p>
<h2 class="market-intel-preview-title">MCP 整合就緒度</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理 MCP 就緒度" data-market-intel-mcp-readiness-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-mcp-readiness-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-mcp-readiness-body>
<div class="market-intel-empty">讀取 MCP 整合就緒度中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-mcp-preflight>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MCP / EXTERNAL DEPLOY PREFLIGHT</p>
<h2 class="market-intel-preview-title">外部 MCP 部署預檢</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理 MCP 部署預檢" data-market-intel-mcp-preflight-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-mcp-preflight-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-mcp-preflight-body>
<div class="market-intel-empty">讀取 MCP 部署預檢中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-mcp-activation>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MCP / ACTIVATION RUNBOOK</p>
<h2 class="market-intel-preview-title">MCP 啟用 Runbook</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理 MCP 啟用 Runbook" data-market-intel-mcp-activation-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-mcp-activation-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-mcp-activation-body>
<div class="market-intel-empty">讀取 MCP 啟用 Runbook 中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-mcp-fetch-gate>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MCP / FETCH GATE</p>
<h2 class="market-intel-preview-title">人工 Fetch 安全閘門</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理人工 Fetch 安全閘門" data-market-intel-mcp-fetch-gate-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-mcp-fetch-gate-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-mcp-fetch-gate-body>
<div class="market-intel-empty">讀取人工 Fetch 安全閘門中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-manual-sample>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MANUAL SAMPLE / FETCH PLAN</p>
<h2 class="market-intel-preview-title">人工樣本 Fetch 計畫</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理人工樣本 Fetch 計畫" data-market-intel-manual-sample-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-manual-sample-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-manual-sample-body>
<div class="market-intel-empty">讀取人工樣本 Fetch 計畫中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-sample-acceptance>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MANUAL SAMPLE / ACCEPTANCE</p>
<h2 class="market-intel-preview-title">樣本結果驗收契約</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理樣本結果驗收契約" data-market-intel-sample-acceptance-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-sample-acceptance-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-sample-acceptance-body>
<div class="market-intel-empty">讀取樣本結果驗收契約中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-sample-review>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MANUAL SAMPLE / REVIEW</p>
<h2 class="market-intel-preview-title">樣本結果審核預覽</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理樣本結果審核預覽" data-market-intel-sample-review-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-sample-review-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-sample-review-body>
<div class="market-intel-empty">讀取樣本結果審核預覽中...</div>
</div>
<div class="market-intel-control-row mt-3">
<textarea class="market-intel-json-input" rows="5" spellcheck="false" data-market-intel-sample-review-input placeholder="sample result JSON"></textarea>
<div class="market-intel-control-actions" data-market-intel-sample-review-actions-rail>
<button class="market-intel-icon-button" type="button" title="審核 sample result JSON" data-market-intel-sample-review-evaluate>
<i class="fas fa-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生候選活動 handoff" data-market-intel-sample-candidate-handoff>
<i class="fas fa-arrow-right" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生候選審核 queue 草案" data-market-intel-sample-candidate-queue-draft>
<i class="fas fa-clipboard-list" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue 寫入送審 gate" data-market-intel-sample-candidate-queue-approval>
<i class="fas fa-shield-halved" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue transaction preview" data-market-intel-sample-candidate-queue-transaction>
<i class="fas fa-code" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue writer CLI gate" data-market-intel-sample-candidate-queue-writer>
<i class="fas fa-terminal" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue writer preflight" data-market-intel-sample-candidate-queue-preflight>
<i class="fas fa-database" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue writer post-write smoke" data-market-intel-sample-candidate-queue-postwrite-smoke>
<i class="fas fa-search" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue writer operator drill" data-market-intel-sample-candidate-queue-operator-drill>
<i class="fas fa-list-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue writer run package" data-market-intel-sample-candidate-queue-run-package>
<i class="fas fa-box-archive" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue writer run readiness" data-market-intel-sample-candidate-queue-run-readiness>
<i class="fas fa-clipboard-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="審核 queue writer run receipt" data-market-intel-sample-candidate-queue-run-receipt>
<i class="fas fa-receipt" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="收尾 queue writer run closeout" data-market-intel-sample-candidate-queue-run-closeout>
<i class="fas fa-flag-checkered" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review handoff" data-market-intel-sample-candidate-queue-review-handoff>
<i class="fas fa-handshake" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review inventory" data-market-intel-sample-candidate-queue-review-inventory>
<i class="fas fa-eye" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review decision 草案" data-market-intel-sample-candidate-queue-review-decision>
<i class="fas fa-scale-balanced" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review decision 批准 gate" data-market-intel-sample-candidate-queue-review-decision-approval>
<i class="fas fa-shield-halved" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review decision transaction preview" data-market-intel-sample-candidate-queue-review-decision-transaction>
<i class="fas fa-code-branch" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review decision writer preflight" data-market-intel-sample-candidate-queue-review-decision-preflight>
<i class="fas fa-database" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review decision writer post-write smoke" data-market-intel-sample-candidate-queue-review-decision-postwrite-smoke>
<i class="fas fa-search" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review decision writer operator drill" data-market-intel-sample-candidate-queue-review-decision-operator-drill>
<i class="fas fa-list-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review decision writer run package" data-market-intel-sample-candidate-queue-review-decision-run-package>
<i class="fas fa-box-archive" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review decision writer run readiness" data-market-intel-sample-candidate-queue-review-decision-run-readiness>
<i class="fas fa-clipboard-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review decision writer CLI gate" data-market-intel-sample-candidate-queue-review-decision-writer>
<i class="fas fa-terminal" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="審核 queue review decision writer run receipt" data-market-intel-sample-candidate-queue-review-decision-run-receipt>
<i class="fas fa-receipt" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="收尾 queue review decision writer run closeout" data-market-intel-sample-candidate-queue-review-decision-run-closeout>
<i class="fas fa-flag-checkered" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review decision post-closeout inventory" data-market-intel-sample-candidate-queue-review-decision-post-closeout-inventory>
<i class="fas fa-clipboard-list" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="封存 queue review completion archive" data-market-intel-sample-candidate-queue-review-completion-archive>
<i class="fas fa-archive" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="整理 queue review archive summary" data-market-intel-sample-candidate-queue-review-archive-summary>
<i class="fas fa-file-lines" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary preflight" data-market-intel-sample-candidate-queue-review-ai-summary-preflight>
<i class="fas fa-robot" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review AI summary run package" data-market-intel-sample-candidate-queue-review-ai-summary-run-package>
<i class="fas fa-box-open" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="驗收 queue review AI summary output receipt" data-market-intel-sample-candidate-queue-review-ai-summary-output-receipt>
<i class="fas fa-file-circle-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary persistence preflight" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-preflight>
<i class="fas fa-file-pen" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review AI summary persistence transaction preview" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-transaction>
<i class="fas fa-code-branch" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary persistence writer preflight" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-writer-preflight>
<i class="fas fa-database" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review AI summary persistence run package" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-run-package>
<i class="fas fa-box-archive" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary persistence run readiness" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-run-readiness>
<i class="fas fa-clipboard-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="審核 queue review AI summary persistence run receipt" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-run-receipt>
<i class="fas fa-receipt" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="收尾 queue review AI summary persistence run closeout" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-run-closeout>
<i class="fas fa-flag-checkered" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary Telegram dispatch gate" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-gate>
<i class="fas fa-paper-plane" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review AI summary Telegram dispatch run package" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-run-package>
<i class="fas fa-envelope-open-text" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary Telegram dispatch run readiness" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-run-readiness>
<i class="fas fa-user-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="審核 queue review AI summary Telegram dispatch run receipt" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-run-receipt>
<i class="fas fa-receipt" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="收尾 queue review AI summary Telegram dispatch closeout" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-closeout>
<i class="fas fa-flag-checkered" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="封存 queue review AI summary Telegram dispatch archive" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-archive>
<i class="fas fa-folder-tree" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="整理 queue review AI summary Telegram dispatch archive summary" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-archive-summary>
<i class="fas fa-file-lines" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="整理 queue review AI summary Telegram dispatch report input" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-input>
<i class="fas fa-chart-simple" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review AI summary Telegram dispatch report run package" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-run-package>
<i class="fas fa-box-open" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary Telegram dispatch report run readiness" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-run-readiness>
<i class="fas fa-clipboard-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="審核 queue review AI summary Telegram dispatch report run receipt" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-run-receipt>
<i class="fas fa-receipt" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="收尾 queue review AI summary Telegram dispatch report closeout" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-closeout>
<i class="fas fa-flag-checkered" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="封存 queue review AI summary Telegram dispatch report archive" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-archive>
<i class="fas fa-box-archive" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="整理 queue review AI summary Telegram dispatch report archive summary" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-archive-summary>
<i class="fas fa-file-signature" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="整理 queue review AI summary Telegram dispatch report catalog handoff" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-handoff>
<i class="fas fa-table-list" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="整理 queue review AI summary Telegram dispatch report catalog index" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-index>
<i class="fas fa-list-ol" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary Telegram dispatch report catalog write preflight" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-write-preflight>
<i class="fas fa-file-shield" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary Telegram dispatch report catalog record write gate" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-write>
<i class="fas fa-database" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue review AI summary Telegram dispatch report catalog record run package" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-run-package>
<i class="fas fa-box" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="檢查 queue review AI summary Telegram dispatch report catalog record run readiness" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-run-readiness>
<i class="fas fa-clipboard-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="審核 queue review AI summary Telegram dispatch report catalog record run receipt" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-run-receipt>
<i class="fas fa-receipt" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="審核 queue review AI summary Telegram dispatch report catalog record commit gate" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-commit>
<i class="fas fa-lock" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="收尾 queue review AI summary Telegram dispatch report catalog record closeout gate" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-closeout>
<i class="fas fa-flag-checkered" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="封存 queue review AI summary Telegram dispatch report catalog record archive gate" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-archive>
<i class="fas fa-box-archive" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="整理 queue review AI summary Telegram dispatch report catalog record archive summary gate" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-archive-summary>
<i class="fas fa-file-signature" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="收尾 queue review AI summary Telegram dispatch report catalog record final closeout gate" data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-final-closeout>
<i class="fas fa-circle-check" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-scheduler>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">SCHEDULER / ATTACH PLAN</p>
<h2 class="market-intel-preview-title">排程掛載計畫</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理排程掛載計畫" data-market-intel-scheduler-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-scheduler-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-scheduler-body>
<div class="market-intel-empty">讀取排程掛載計畫中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-match-review>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MATCH REVIEW / PLAN</p>
<h2 class="market-intel-preview-title">商品比對審核計畫</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理商品比對審核計畫" data-market-intel-match-review-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-match-review-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-match-review-body>
<div class="market-intel-empty">讀取商品比對審核計畫中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-opportunity>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">OPPORTUNITY / THREAT PLAN</p>
<h2 class="market-intel-preview-title">市場機會與威脅計畫</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理市場機會與威脅計畫" data-market-intel-opportunity-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-opportunity-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-opportunity-body>
<div class="market-intel-empty">讀取市場機會與威脅計畫中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-opportunity-scoring>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">OPPORTUNITY / SCORING MODEL</p>
<h2 class="market-intel-preview-title">機會威脅分數模型</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理機會威脅分數模型" data-market-intel-opportunity-scoring-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-opportunity-scoring-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-opportunity-scoring-body>
<div class="market-intel-empty">讀取機會威脅分數模型中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-opportunity-evidence>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">OPPORTUNITY / EVIDENCE BUNDLE</p>
<h2 class="market-intel-preview-title">機會威脅證據包</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理機會威脅證據包" data-market-intel-opportunity-evidence-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-opportunity-evidence-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-opportunity-evidence-body>
<div class="market-intel-empty">讀取機會威脅證據包中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-opportunity-alert>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">OPPORTUNITY / ALERT CANDIDATE</p>
<h2 class="market-intel-preview-title">機會威脅告警候選</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理機會威脅告警候選" data-market-intel-opportunity-alert-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-opportunity-alert-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-opportunity-alert-body>
<div class="market-intel-empty">讀取機會威脅告警候選中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-migration>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MIGRATION / BLUEPRINT</p>
<h2 class="market-intel-preview-title">Schema migration 草案</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理 migration 草案" data-market-intel-migration-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-migration-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-migration-body>
<div class="market-intel-empty">讀取 migration 草案中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-migration-drill>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MIGRATION / APPLY DRILL</p>
<h2 class="market-intel-preview-title">Migration 套用演練</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理 migration 套用演練" data-market-intel-migration-drill-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-migration-drill-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-migration-drill-body>
<div class="market-intel-empty">讀取 migration 套用演練中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-catalog-review>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MIGRATION / CATALOG REVIEW</p>
<h2 class="market-intel-preview-title">正式 DB catalog 判讀</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理正式 DB catalog 判讀" data-market-intel-catalog-review-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-catalog-review-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-catalog-review-body>
<div class="market-intel-empty">讀取正式 DB catalog 判讀中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-live-smoke>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">MIGRATION / LIVE SMOKE</p>
<h2 class="market-intel-preview-title">正式 DB 只讀 smoke</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理正式 DB 只讀 smoke" data-market-intel-live-smoke-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-live-smoke-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-live-smoke-body>
<div class="market-intel-empty">讀取正式 DB 只讀 smoke 中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-live-inventory>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">DB INVENTORY / READ ONLY</p>
<h2 class="market-intel-preview-title">正式 DB 庫存總覽</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理正式 DB 庫存總覽" data-market-intel-live-inventory-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-live-inventory-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-live-inventory-body>
<div class="market-intel-empty">讀取正式 DB 庫存總覽中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-approval>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">WRITE APPROVAL / RUNBOOK</p>
<h2 class="market-intel-preview-title">正式寫入批准檢查</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理批准檢查" data-market-intel-approval-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-approval-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-approval-body>
<div class="market-intel-empty">讀取批准檢查中...</div>
</div>
</div>
<div class="market-intel-panel" data-market-intel-deploy>
<div class="market-intel-preview-head">
<div>
<p class="market-intel-muted momo-mono mb-1">DEPLOYMENT / READINESS</p>
<h2 class="market-intel-preview-title">推版準備檢查</h2>
</div>
<button class="market-intel-icon-button" type="button" title="重新整理推版準備" data-market-intel-deploy-refresh>
<i class="fas fa-rotate-right" aria-hidden="true"></i>
</button>
</div>
<div class="market-intel-preview-meta" data-market-intel-deploy-meta>
<span class="market-intel-pill">loading</span>
</div>
<div data-market-intel-deploy-body>
<div class="market-intel-empty">讀取推版準備中...</div>
</div>
</div>
</section>
{% endblock %}
{% block extra_js %}
<script>
(function () {
const root = document.querySelector('[data-market-intel-preview]');
const writerRoot = document.querySelector('[data-market-intel-writer]');
const cliRoot = document.querySelector('[data-market-intel-cli]');
const dbProbeRoot = document.querySelector('[data-market-intel-db-probe]');
const seedDiffRoot = document.querySelector('[data-market-intel-seed-diff]');
const legacyBridgeRoot = document.querySelector('[data-market-intel-legacy-bridge]');
const mcpReadinessRoot = document.querySelector('[data-market-intel-mcp-readiness]');
const mcpPreflightRoot = document.querySelector('[data-market-intel-mcp-preflight]');
const mcpActivationRoot = document.querySelector('[data-market-intel-mcp-activation]');
const mcpFetchGateRoot = document.querySelector('[data-market-intel-mcp-fetch-gate]');
const manualSampleRoot = document.querySelector('[data-market-intel-manual-sample]');
const sampleAcceptanceRoot = document.querySelector('[data-market-intel-sample-acceptance]');
const sampleReviewRoot = document.querySelector('[data-market-intel-sample-review]');
const schedulerRoot = document.querySelector('[data-market-intel-scheduler]');
const matchReviewRoot = document.querySelector('[data-market-intel-match-review]');
const opportunityRoot = document.querySelector('[data-market-intel-opportunity]');
const opportunityScoringRoot = document.querySelector('[data-market-intel-opportunity-scoring]');
const opportunityEvidenceRoot = document.querySelector('[data-market-intel-opportunity-evidence]');
const opportunityAlertRoot = document.querySelector('[data-market-intel-opportunity-alert]');
const migrationRoot = document.querySelector('[data-market-intel-migration]');
const migrationDrillRoot = document.querySelector('[data-market-intel-migration-drill]');
const catalogReviewRoot = document.querySelector('[data-market-intel-catalog-review]');
const liveSmokeRoot = document.querySelector('[data-market-intel-live-smoke]');
const liveInventoryRoot = document.querySelector('[data-market-intel-live-inventory]');
const approvalRoot = document.querySelector('[data-market-intel-approval]');
const deployRoot = document.querySelector('[data-market-intel-deploy]');
if (!root && !writerRoot && !cliRoot && !dbProbeRoot && !seedDiffRoot && !legacyBridgeRoot && !mcpReadinessRoot && !mcpPreflightRoot && !mcpActivationRoot && !mcpFetchGateRoot && !manualSampleRoot && !sampleAcceptanceRoot && !sampleReviewRoot && !schedulerRoot && !matchReviewRoot && !opportunityRoot && !opportunityScoringRoot && !opportunityEvidenceRoot && !opportunityAlertRoot && !migrationRoot && !migrationDrillRoot && !catalogReviewRoot && !liveSmokeRoot && !liveInventoryRoot && !approvalRoot && !deployRoot) return;
const meta = root ? root.querySelector('[data-market-intel-preview-meta]') : null;
const body = root ? root.querySelector('[data-market-intel-preview-body]') : null;
const refresh = root ? root.querySelector('[data-market-intel-refresh]') : null;
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '';
const endpoint = "{{ url_for('market_intel.market_intel_candidate_preview') }}?fetch=false&limit=20";
const writerMeta = writerRoot ? writerRoot.querySelector('[data-market-intel-writer-meta]') : null;
const writerBody = writerRoot ? writerRoot.querySelector('[data-market-intel-writer-body]') : null;
const writerRefresh = writerRoot ? writerRoot.querySelector('[data-market-intel-writer-refresh]') : null;
const writerEndpoint = "{{ url_for('market_intel.market_intel_platform_seed_writer_plan') }}";
const cliMeta = cliRoot ? cliRoot.querySelector('[data-market-intel-cli-meta]') : null;
const cliBody = cliRoot ? cliRoot.querySelector('[data-market-intel-cli-body]') : null;
const cliRefresh = cliRoot ? cliRoot.querySelector('[data-market-intel-cli-refresh]') : null;
const cliEndpoint = "{{ url_for('market_intel.market_intel_seed_writer_cli_status') }}";
const dbProbeMeta = dbProbeRoot ? dbProbeRoot.querySelector('[data-market-intel-db-probe-meta]') : null;
const dbProbeBody = dbProbeRoot ? dbProbeRoot.querySelector('[data-market-intel-db-probe-body]') : null;
const dbProbeRefresh = dbProbeRoot ? dbProbeRoot.querySelector('[data-market-intel-db-probe-refresh]') : null;
const dbProbeEndpoint = "{{ url_for('market_intel.market_intel_schema_db_probe') }}?execute=false";
const seedDiffMeta = seedDiffRoot ? seedDiffRoot.querySelector('[data-market-intel-seed-diff-meta]') : null;
const seedDiffBody = seedDiffRoot ? seedDiffRoot.querySelector('[data-market-intel-seed-diff-body]') : null;
const seedDiffRefresh = seedDiffRoot ? seedDiffRoot.querySelector('[data-market-intel-seed-diff-refresh]') : null;
const seedDiffEndpoint = "{{ url_for('market_intel.market_intel_platform_seed_db_diff') }}?execute=false";
const legacyBridgeMeta = legacyBridgeRoot ? legacyBridgeRoot.querySelector('[data-market-intel-legacy-bridge-meta]') : null;
const legacyBridgeBody = legacyBridgeRoot ? legacyBridgeRoot.querySelector('[data-market-intel-legacy-bridge-body]') : null;
const legacyBridgeRefresh = legacyBridgeRoot ? legacyBridgeRoot.querySelector('[data-market-intel-legacy-bridge-refresh]') : null;
const legacyBridgeEndpoint = "{{ url_for('market_intel.market_intel_legacy_source_bridge') }}?execute=false&limit=5";
const mcpReadinessMeta = mcpReadinessRoot ? mcpReadinessRoot.querySelector('[data-market-intel-mcp-readiness-meta]') : null;
const mcpReadinessBody = mcpReadinessRoot ? mcpReadinessRoot.querySelector('[data-market-intel-mcp-readiness-body]') : null;
const mcpReadinessRefresh = mcpReadinessRoot ? mcpReadinessRoot.querySelector('[data-market-intel-mcp-readiness-refresh]') : null;
const mcpReadinessEndpoint = "{{ url_for('market_intel.market_intel_mcp_readiness') }}?execute=false&timeout=3";
const mcpPreflightMeta = mcpPreflightRoot ? mcpPreflightRoot.querySelector('[data-market-intel-mcp-preflight-meta]') : null;
const mcpPreflightBody = mcpPreflightRoot ? mcpPreflightRoot.querySelector('[data-market-intel-mcp-preflight-body]') : null;
const mcpPreflightRefresh = mcpPreflightRoot ? mcpPreflightRoot.querySelector('[data-market-intel-mcp-preflight-refresh]') : null;
const mcpPreflightEndpoint = "{{ url_for('market_intel.market_intel_mcp_deploy_preflight') }}";
const mcpActivationMeta = mcpActivationRoot ? mcpActivationRoot.querySelector('[data-market-intel-mcp-activation-meta]') : null;
const mcpActivationBody = mcpActivationRoot ? mcpActivationRoot.querySelector('[data-market-intel-mcp-activation-body]') : null;
const mcpActivationRefresh = mcpActivationRoot ? mcpActivationRoot.querySelector('[data-market-intel-mcp-activation-refresh]') : null;
const mcpActivationEndpoint = "{{ url_for('market_intel.market_intel_mcp_activation_runbook') }}";
const mcpFetchGateMeta = mcpFetchGateRoot ? mcpFetchGateRoot.querySelector('[data-market-intel-mcp-fetch-gate-meta]') : null;
const mcpFetchGateBody = mcpFetchGateRoot ? mcpFetchGateRoot.querySelector('[data-market-intel-mcp-fetch-gate-body]') : null;
const mcpFetchGateRefresh = mcpFetchGateRoot ? mcpFetchGateRoot.querySelector('[data-market-intel-mcp-fetch-gate-refresh]') : null;
const mcpFetchGateEndpoint = "{{ url_for('market_intel.market_intel_mcp_fetch_gate') }}?fetch=false&execute=false";
const manualSampleMeta = manualSampleRoot ? manualSampleRoot.querySelector('[data-market-intel-manual-sample-meta]') : null;
const manualSampleBody = manualSampleRoot ? manualSampleRoot.querySelector('[data-market-intel-manual-sample-body]') : null;
const manualSampleRefresh = manualSampleRoot ? manualSampleRoot.querySelector('[data-market-intel-manual-sample-refresh]') : null;
const manualSampleEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_plan') }}";
const sampleAcceptanceMeta = sampleAcceptanceRoot ? sampleAcceptanceRoot.querySelector('[data-market-intel-sample-acceptance-meta]') : null;
const sampleAcceptanceBody = sampleAcceptanceRoot ? sampleAcceptanceRoot.querySelector('[data-market-intel-sample-acceptance-body]') : null;
const sampleAcceptanceRefresh = sampleAcceptanceRoot ? sampleAcceptanceRoot.querySelector('[data-market-intel-sample-acceptance-refresh]') : null;
const sampleAcceptanceEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_acceptance') }}";
const sampleReviewMeta = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-review-meta]') : null;
const sampleReviewBody = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-review-body]') : null;
const sampleReviewRefresh = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-review-refresh]') : null;
const sampleReviewInput = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-review-input]') : null;
const sampleReviewEvaluate = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-review-evaluate]') : null;
const sampleCandidateHandoff = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-handoff]') : null;
const sampleCandidateQueueDraft = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-draft]') : null;
const sampleCandidateQueueApproval = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-approval]') : null;
const sampleCandidateQueueTransaction = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-transaction]') : null;
const sampleCandidateQueueWriter = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-writer]') : null;
const sampleCandidateQueuePreflight = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-preflight]') : null;
const sampleCandidateQueuePostwriteSmoke = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-postwrite-smoke]') : null;
const sampleCandidateQueueOperatorDrill = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-operator-drill]') : null;
const sampleCandidateQueueRunPackage = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-run-package]') : null;
const sampleCandidateQueueRunReadiness = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-run-readiness]') : null;
const sampleCandidateQueueRunReceipt = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-run-receipt]') : null;
const sampleCandidateQueueRunCloseout = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-run-closeout]') : null;
const sampleCandidateQueueReviewHandoff = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-handoff]') : null;
const sampleCandidateQueueReviewInventory = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-inventory]') : null;
const sampleCandidateQueueReviewDecision = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision]') : null;
const sampleCandidateQueueReviewDecisionApproval = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-approval]') : null;
const sampleCandidateQueueReviewDecisionTransaction = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-transaction]') : null;
const sampleCandidateQueueReviewDecisionPreflight = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-preflight]') : null;
const sampleCandidateQueueReviewDecisionPostwriteSmoke = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-postwrite-smoke]') : null;
const sampleCandidateQueueReviewDecisionOperatorDrill = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-operator-drill]') : null;
const sampleCandidateQueueReviewDecisionRunPackage = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-run-package]') : null;
const sampleCandidateQueueReviewDecisionRunReadiness = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-run-readiness]') : null;
const sampleCandidateQueueReviewDecisionWriter = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-writer]') : null;
const sampleCandidateQueueReviewDecisionRunReceipt = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-run-receipt]') : null;
const sampleCandidateQueueReviewDecisionRunCloseout = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-run-closeout]') : null;
const sampleCandidateQueueReviewDecisionPostCloseoutInventory = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-post-closeout-inventory]') : null;
const sampleCandidateQueueReviewCompletionArchive = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-completion-archive]') : null;
const sampleCandidateQueueReviewArchiveSummary = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-archive-summary]') : null;
const sampleCandidateQueueReviewAiSummaryPreflight = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-preflight]') : null;
const sampleCandidateQueueReviewAiSummaryRunPackage = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-run-package]') : null;
const sampleCandidateQueueReviewAiSummaryOutputReceipt = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-output-receipt]') : null;
const sampleCandidateQueueReviewAiSummaryPersistencePreflight = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-preflight]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTransaction = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-transaction]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceWriterPreflight = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-writer-preflight]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceRunPackage = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-run-package]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceRunReadiness = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-run-readiness]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceRunReceipt = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-run-receipt]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceRunCloseout = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-run-closeout]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchGate = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-gate]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunPackage = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-run-package]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReadiness = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-run-readiness]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReceipt = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-run-receipt]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchCloseout = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-closeout]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchive = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-archive]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveSummary = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-archive-summary]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportInput = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-input]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunPackage = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-run-package]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReadiness = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-run-readiness]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReceipt = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-run-receipt]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCloseout = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-closeout]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchive = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-archive]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveSummary = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-archive-summary]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogHandoff = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-handoff]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogIndex = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-index]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogWritePreflight = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-write-preflight]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordWrite = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-write]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunPackage = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-run-package]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReadiness = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-run-readiness]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReceipt = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-run-receipt]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCommit = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-commit]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCloseout = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-closeout]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchive = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-archive]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveSummary = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-archive-summary]') : null;
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordFinalCloseout = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-ai-summary-persistence-telegram-dispatch-report-catalog-record-final-closeout]') : null;
const sampleReviewEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_review') }}";
const sampleReviewEvaluateEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_review_evaluate') }}";
const sampleCandidateHandoffEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_handoff') }}";
const sampleCandidateQueueDraftEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_draft') }}";
const sampleCandidateQueueApprovalEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_approval') }}";
const sampleCandidateQueueTransactionEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_transaction') }}";
const sampleCandidateQueueWriterEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_status') }}";
const sampleCandidateQueuePreflightEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_preflight') }}";
const sampleCandidateQueuePostwriteSmokeEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_postwrite_smoke') }}";
const sampleCandidateQueueOperatorDrillEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_operator_drill') }}";
const sampleCandidateQueueRunPackageEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_run_package') }}";
const sampleCandidateQueueRunReadinessEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_run_readiness') }}";
const sampleCandidateQueueRunReceiptEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_run_receipt') }}";
const sampleCandidateQueueRunCloseoutEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_run_closeout') }}";
const sampleCandidateQueueReviewHandoffEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_review_handoff') }}";
const sampleCandidateQueueReviewInventoryEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_inventory') }}";
const sampleCandidateQueueReviewDecisionEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision') }}";
const sampleCandidateQueueReviewDecisionApprovalEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_approval') }}";
const sampleCandidateQueueReviewDecisionTransactionEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_transaction') }}";
const sampleCandidateQueueReviewDecisionPreflightEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_writer_preflight') }}";
const sampleCandidateQueueReviewDecisionPostwriteSmokeEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_writer_postwrite_smoke') }}";
const sampleCandidateQueueReviewDecisionOperatorDrillEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_writer_operator_drill') }}";
const sampleCandidateQueueReviewDecisionRunPackageEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_writer_run_package') }}";
const sampleCandidateQueueReviewDecisionRunReadinessEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_writer_run_readiness') }}";
const sampleCandidateQueueReviewDecisionWriterEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_writer_status') }}";
const sampleCandidateQueueReviewDecisionRunReceiptEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_writer_run_receipt') }}";
const sampleCandidateQueueReviewDecisionRunCloseoutEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_writer_run_closeout') }}";
const sampleCandidateQueueReviewDecisionPostCloseoutInventoryEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_post_closeout_inventory') }}";
const sampleCandidateQueueReviewCompletionArchiveEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_completion_archive') }}";
const sampleCandidateQueueReviewArchiveSummaryEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_archive_summary') }}";
const sampleCandidateQueueReviewAiSummaryPreflightEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_preflight') }}";
const sampleCandidateQueueReviewAiSummaryRunPackageEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_run_package') }}";
const sampleCandidateQueueReviewAiSummaryOutputReceiptEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_output_receipt') }}";
const sampleCandidateQueueReviewAiSummaryPersistencePreflightEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_preflight') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTransactionEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_transaction') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceWriterPreflightEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_writer_preflight') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceRunPackageEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_run_package') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceRunReadinessEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_run_readiness') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceRunReceiptEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_run_receipt') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceRunCloseoutEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_run_closeout') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchGateEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_gate') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunPackageEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_run_package') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReadinessEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_run_readiness') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReceiptEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_run_receipt') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchCloseoutEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_closeout') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_archive') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveSummaryEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_archive_summary') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportInputEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_input') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunPackageEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_run_package') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReadinessEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_run_readiness') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReceiptEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_run_receipt') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCloseoutEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_closeout') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_archive') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveSummaryEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_archive_summary') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogHandoffEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_handoff') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogIndexEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_index') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogWritePreflightEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_write_preflight') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordWriteEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_write') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunPackageEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_run_package') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReadinessEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_run_readiness') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReceiptEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_run_receipt') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCommitEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_commit') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCloseoutEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_closeout') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_archive') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveSummaryEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_archive_summary') }}";
const sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordFinalCloseoutEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_ai_summary_persistence_telegram_dispatch_report_catalog_record_final_closeout') }}";
const schedulerMeta = schedulerRoot ? schedulerRoot.querySelector('[data-market-intel-scheduler-meta]') : null;
const schedulerBody = schedulerRoot ? schedulerRoot.querySelector('[data-market-intel-scheduler-body]') : null;
const schedulerRefresh = schedulerRoot ? schedulerRoot.querySelector('[data-market-intel-scheduler-refresh]') : null;
const schedulerEndpoint = "{{ url_for('market_intel.market_intel_scheduler_plan') }}";
const matchReviewMeta = matchReviewRoot ? matchReviewRoot.querySelector('[data-market-intel-match-review-meta]') : null;
const matchReviewBody = matchReviewRoot ? matchReviewRoot.querySelector('[data-market-intel-match-review-body]') : null;
const matchReviewRefresh = matchReviewRoot ? matchReviewRoot.querySelector('[data-market-intel-match-review-refresh]') : null;
const matchReviewEndpoint = "{{ url_for('market_intel.market_intel_match_review_plan') }}";
const opportunityMeta = opportunityRoot ? opportunityRoot.querySelector('[data-market-intel-opportunity-meta]') : null;
const opportunityBody = opportunityRoot ? opportunityRoot.querySelector('[data-market-intel-opportunity-body]') : null;
const opportunityRefresh = opportunityRoot ? opportunityRoot.querySelector('[data-market-intel-opportunity-refresh]') : null;
const opportunityEndpoint = "{{ url_for('market_intel.market_intel_opportunity_plan') }}";
const opportunityScoringMeta = opportunityScoringRoot ? opportunityScoringRoot.querySelector('[data-market-intel-opportunity-scoring-meta]') : null;
const opportunityScoringBody = opportunityScoringRoot ? opportunityScoringRoot.querySelector('[data-market-intel-opportunity-scoring-body]') : null;
const opportunityScoringRefresh = opportunityScoringRoot ? opportunityScoringRoot.querySelector('[data-market-intel-opportunity-scoring-refresh]') : null;
const opportunityScoringEndpoint = "{{ url_for('market_intel.market_intel_opportunity_scoring_plan') }}";
const opportunityEvidenceMeta = opportunityEvidenceRoot ? opportunityEvidenceRoot.querySelector('[data-market-intel-opportunity-evidence-meta]') : null;
const opportunityEvidenceBody = opportunityEvidenceRoot ? opportunityEvidenceRoot.querySelector('[data-market-intel-opportunity-evidence-body]') : null;
const opportunityEvidenceRefresh = opportunityEvidenceRoot ? opportunityEvidenceRoot.querySelector('[data-market-intel-opportunity-evidence-refresh]') : null;
const opportunityEvidenceEndpoint = "{{ url_for('market_intel.market_intel_opportunity_evidence_plan') }}";
const opportunityAlertMeta = opportunityAlertRoot ? opportunityAlertRoot.querySelector('[data-market-intel-opportunity-alert-meta]') : null;
const opportunityAlertBody = opportunityAlertRoot ? opportunityAlertRoot.querySelector('[data-market-intel-opportunity-alert-body]') : null;
const opportunityAlertRefresh = opportunityAlertRoot ? opportunityAlertRoot.querySelector('[data-market-intel-opportunity-alert-refresh]') : null;
const opportunityAlertEndpoint = "{{ url_for('market_intel.market_intel_opportunity_alert_plan') }}";
const migrationMeta = migrationRoot ? migrationRoot.querySelector('[data-market-intel-migration-meta]') : null;
const migrationBody = migrationRoot ? migrationRoot.querySelector('[data-market-intel-migration-body]') : null;
const migrationRefresh = migrationRoot ? migrationRoot.querySelector('[data-market-intel-migration-refresh]') : null;
const migrationEndpoint = "{{ url_for('market_intel.market_intel_migration_blueprint') }}";
const migrationDrillMeta = migrationDrillRoot ? migrationDrillRoot.querySelector('[data-market-intel-migration-drill-meta]') : null;
const migrationDrillBody = migrationDrillRoot ? migrationDrillRoot.querySelector('[data-market-intel-migration-drill-body]') : null;
const migrationDrillRefresh = migrationDrillRoot ? migrationDrillRoot.querySelector('[data-market-intel-migration-drill-refresh]') : null;
const migrationDrillEndpoint = "{{ url_for('market_intel.market_intel_migration_apply_drill') }}?execute=false";
const catalogReviewMeta = catalogReviewRoot ? catalogReviewRoot.querySelector('[data-market-intel-catalog-review-meta]') : null;
const catalogReviewBody = catalogReviewRoot ? catalogReviewRoot.querySelector('[data-market-intel-catalog-review-body]') : null;
const catalogReviewRefresh = catalogReviewRoot ? catalogReviewRoot.querySelector('[data-market-intel-catalog-review-refresh]') : null;
const catalogReviewEndpoint = "{{ url_for('market_intel.market_intel_migration_catalog_review') }}?execute=false";
const liveSmokeMeta = liveSmokeRoot ? liveSmokeRoot.querySelector('[data-market-intel-live-smoke-meta]') : null;
const liveSmokeBody = liveSmokeRoot ? liveSmokeRoot.querySelector('[data-market-intel-live-smoke-body]') : null;
const liveSmokeRefresh = liveSmokeRoot ? liveSmokeRoot.querySelector('[data-market-intel-live-smoke-refresh]') : null;
const liveSmokeEndpoint = "{{ url_for('market_intel.market_intel_migration_live_smoke') }}?execute=false";
const liveInventoryMeta = liveInventoryRoot ? liveInventoryRoot.querySelector('[data-market-intel-live-inventory-meta]') : null;
const liveInventoryBody = liveInventoryRoot ? liveInventoryRoot.querySelector('[data-market-intel-live-inventory-body]') : null;
const liveInventoryRefresh = liveInventoryRoot ? liveInventoryRoot.querySelector('[data-market-intel-live-inventory-refresh]') : null;
const liveInventoryEndpoint = "{{ url_for('market_intel.market_intel_live_db_inventory') }}?execute=false";
const approvalMeta = approvalRoot ? approvalRoot.querySelector('[data-market-intel-approval-meta]') : null;
const approvalBody = approvalRoot ? approvalRoot.querySelector('[data-market-intel-approval-body]') : null;
const approvalRefresh = approvalRoot ? approvalRoot.querySelector('[data-market-intel-approval-refresh]') : null;
const approvalEndpoint = "{{ url_for('market_intel.market_intel_write_approval_runbook') }}";
const deployMeta = deployRoot ? deployRoot.querySelector('[data-market-intel-deploy-meta]') : null;
const deployBody = deployRoot ? deployRoot.querySelector('[data-market-intel-deploy-body]') : null;
const deployRefresh = deployRoot ? deployRoot.querySelector('[data-market-intel-deploy-refresh]') : null;
const deployEndpoint = "{{ url_for('market_intel.market_intel_deployment_readiness') }}";
const escapeHtml = value => String(value == null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
const renderMeta = data => {
meta.innerHTML = [
`candidates=${data.candidate_count || 0}`,
`fetch=${data.fetch_requested ? 'true' : 'false'}`,
`manual=${data.manual_fetch_allowed ? 'on' : 'off'}`,
`db_write=${data.database_write_allowed ? 'on' : 'off'}`,
`scheduler=${data.scheduler_attached ? 'on' : 'off'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderBody = data => {
if (!data.candidates || data.candidates.length === 0) {
const status = (data.run_statuses || []).map(item => `${item.platform_code}:${item.status}`).join(' / ');
body.innerHTML = `<div class="market-intel-empty">目前沒有候選連結。${status ? `狀態:${escapeHtml(status)}` : ''}</div>`;
return;
}
body.innerHTML = `<div class="market-intel-candidate-list">${
data.candidates.map(item => `
<article class="market-intel-candidate">
<a href="${escapeHtml(item.href)}" target="_blank" rel="noopener noreferrer">${escapeHtml(item.text || item.href)}</a>
<small>${escapeHtml(item.platform_code)} / ${escapeHtml(item.confidence_band)} / score=${escapeHtml(item.score)}</small>
</article>
`).join('')
}</div>`;
};
const loadPreview = async () => {
if (!meta || !body) return;
body.innerHTML = '<div class="market-intel-empty">讀取候選預覽中...</div>';
try {
const response = await fetch(endpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderMeta(data);
renderBody(data);
} catch (error) {
meta.innerHTML = '<span class="market-intel-pill">error</span>';
body.innerHTML = `<div class="market-intel-empty">候選預覽讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderWriterMeta = data => {
writerMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`operations=${data.operation_count || 0}`,
`schema=${data.schema_smoke && data.schema_smoke.passed ? 'pass' : 'fail'}`,
`writes=${data.writes_executed ? 'executed' : 'blocked'}`,
`db_write=${data.database_write_allowed ? 'on' : 'off'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderWriterBody = data => {
const reasons = (data.blocked_reasons || []).join(' / ');
const operations = (data.operations || []).slice(0, 6);
if (operations.length === 0) {
writerBody.innerHTML = `<div class="market-intel-empty">沒有 upsert 預覽。${reasons ? `阻擋:${escapeHtml(reasons)}` : ''}</div>`;
return;
}
writerBody.innerHTML = `
<div class="market-intel-empty mb-3">正式寫入仍被阻擋。${reasons ? `阻擋:${escapeHtml(reasons)}` : ''}</div>
<div class="market-intel-operation-list">${
operations.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.lookup && item.lookup.code ? item.lookup.code : item.table)}</strong>
<small>${escapeHtml(item.operation)} / ${escapeHtml(item.table)} / ${escapeHtml(item.write_status)}</small>
</article>
`).join('')
}</div>
`;
};
const loadWriter = async () => {
if (!writerMeta || !writerBody) return;
writerBody.innerHTML = '<div class="market-intel-empty">讀取寫入預覽中...</div>';
try {
const response = await fetch(writerEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderWriterMeta(data);
renderWriterBody(data);
} catch (error) {
writerMeta.innerHTML = '<span class="market-intel-pill">error</span>';
writerBody.innerHTML = `<div class="market-intel-empty">寫入預覽讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCliMeta = data => {
const preview = data.transaction_preview || {};
cliMeta.innerHTML = [
`mode=${preview.mode || data.mode || 'unknown'}`,
`exit=${data.exit_code == null ? 'n/a' : data.exit_code}`,
`statements=${preview.statement_count || 0}`,
`session=${data.database_session_created ? 'yes' : 'no'}`,
`commit=${data.database_commit_executed ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderCliBody = data => {
const preview = data.transaction_preview || {};
const statements = (preview.statements || []).slice(0, 6);
const blockers = (data.blocked_reasons || []).join(' / ');
if (!statements.length) {
cliBody.innerHTML = `<div class="market-intel-empty">沒有交易預覽。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>`;
return;
}
cliBody.innerHTML = `
<div class="market-intel-empty mb-3">只產生 transaction preview沒有 DB session、沒有 transaction、沒有 commit。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-operation-list">${
statements.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.idempotency_key || item.table)}</strong>
<small>${escapeHtml(item.operation)} / ${escapeHtml(item.table)} / ${escapeHtml(item.diff_status)} / hash=${escapeHtml(item.parameter_payload_hash)}</small>
</article>
`).join('')
}</div>
`;
};
const loadCli = async () => {
if (!cliMeta || !cliBody) return;
cliBody.innerHTML = '<div class="market-intel-empty">讀取交易預覽中...</div>';
try {
const response = await fetch(cliEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderCliMeta(data);
renderCliBody(data);
} catch (error) {
cliMeta.innerHTML = '<span class="market-intel-pill">error</span>';
cliBody.innerHTML = `<div class="market-intel-empty">交易預覽讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderDbProbeMeta = data => {
dbProbeMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`execute=${data.execute_requested ? 'true' : 'false'}`,
`query=${data.read_only_query_executed ? 'yes' : 'no'}`,
`tables=${(data.expected_tables || []).length}`,
`missing=${(data.missing_tables || []).length}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderDbProbeBody = data => {
const statuses = (data.table_statuses || []).slice(0, 8);
const blockers = (data.blocked_reasons || []).join(' / ');
dbProbeBody.innerHTML = `
<div class="market-intel-empty mb-3">預設只顯示 planned不自動查正式 DB人工 smoke 時才可明確開啟只讀查詢參數。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-check-list">${
statuses.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.table)}</strong>
<small>${data.read_only_query_executed ? 'read_only_catalog_query' : 'planned_no_db_connection'}</small>
</div>
<span>${item.exists ? 'EXISTS' : 'PENDING'}</span>
</div>
`).join('')
}</div>
`;
};
const loadDbProbe = async () => {
if (!dbProbeMeta || !dbProbeBody) return;
dbProbeBody.innerHTML = '<div class="market-intel-empty">讀取 DB 探針中...</div>';
try {
const response = await fetch(dbProbeEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderDbProbeMeta(data);
renderDbProbeBody(data);
} catch (error) {
dbProbeMeta.innerHTML = '<span class="market-intel-pill">error</span>';
dbProbeBody.innerHTML = `<div class="market-intel-empty">DB 探針讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderSeedDiffMeta = data => {
seedDiffMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`execute=${data.execute_requested ? 'true' : 'false'}`,
`query=${data.read_only_query_executed ? 'yes' : 'no'}`,
`expected=${data.expected_seed_count || 0}`,
`missing=${(data.missing_codes || []).length}`,
`changed=${(data.changed_codes || []).length}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderSeedDiffBody = data => {
const diffs = (data.seed_diffs || []).slice(0, 8);
const blockers = (data.blocked_reasons || []).join(' / ');
seedDiffBody.innerHTML = `
<div class="market-intel-empty mb-3">預設只顯示 seed 差異 planned不自動查正式 DB人工 smoke 時才可明確開啟只讀查詢參數。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-check-list">${
diffs.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.code)}</strong>
<small>${escapeHtml(item.diff_status || 'unknown')}</small>
</div>
<span>${item.exists ? 'EXISTS' : 'PENDING'}</span>
</div>
`).join('')
}</div>
`;
};
const loadSeedDiff = async () => {
if (!seedDiffMeta || !seedDiffBody) return;
seedDiffBody.innerHTML = '<div class="market-intel-empty">讀取 Seed 差異探針中...</div>';
try {
const response = await fetch(seedDiffEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderSeedDiffMeta(data);
renderSeedDiffBody(data);
} catch (error) {
seedDiffMeta.innerHTML = '<span class="market-intel-pill">error</span>';
seedDiffBody.innerHTML = `<div class="market-intel-empty">Seed 差異探針讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderLegacyBridgeMeta = data => {
legacyBridgeMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`execute=${data.execute_requested ? 'true' : 'false'}`,
`query=${data.read_only_query_executed ? 'yes' : 'no'}`,
`sources=${data.existing_source_count || 0}/${data.source_count || 0}`,
`rows=${data.total_existing_rows || 0}`,
`writes=${data.writes_executed ? 'executed' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderLegacyBridgeBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const sources = data.source_summaries || [];
const operations = data.bridge_operations || [];
const controls = data.duplicate_controls || [];
const renderSource = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.table)}</strong>
<small>${escapeHtml(item.description || '')}</small>
<small>target=${escapeHtml((item.planned_targets || []).join(' / '))}</small>
</div>
<span>${item.exists ? escapeHtml(item.row_count || 0) : 'PENDING'}</span>
</div>
`;
const renderOperation = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.source_table)}${escapeHtml(item.target_table)}</strong>
<small>${escapeHtml(item.operation)} / ${escapeHtml(item.write_status)}</small>
<small>dedupe=${escapeHtml(item.dedupe_key)}</small>
</article>
`;
const renderControl = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.rule)}</small>
</div>
<span>RULE</span>
</div>
`;
legacyBridgeBody.innerHTML = `
<div class="market-intel-empty mb-3">這裡只盤點既有資料來源與導入規則,不搬資料、不寫 market_*。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-legacy-sources>
<p class="market-intel-deploy-section-title">SOURCE TABLES</p>
<div class="market-intel-check-list">${
sources.length
? sources.map(renderSource).join('')
: '<div class="market-intel-empty">尚未提供來源摘要。</div>'
}</div>
</div>
<div data-market-intel-legacy-operations>
<p class="market-intel-deploy-section-title">BRIDGE OPERATIONS</p>
<div class="market-intel-operation-list">${
operations.length
? operations.map(renderOperation).join('')
: '<div class="market-intel-empty">尚未提供橋接操作。</div>'
}</div>
</div>
<div data-market-intel-legacy-controls>
<p class="market-intel-deploy-section-title">DUPLICATE CONTROLS</p>
<div class="market-intel-check-list">${
controls.length
? controls.map(renderControl).join('')
: '<div class="market-intel-empty">尚未提供去重規則。</div>'
}</div>
</div>
</div>
`;
};
const loadLegacyBridge = async () => {
if (!legacyBridgeMeta || !legacyBridgeBody) return;
legacyBridgeBody.innerHTML = '<div class="market-intel-empty">讀取既有資料橋接預覽中...</div>';
try {
const response = await fetch(legacyBridgeEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderLegacyBridgeMeta(data);
renderLegacyBridgeBody(data);
} catch (error) {
legacyBridgeMeta.innerHTML = '<span class="market-intel-pill">error</span>';
legacyBridgeBody.innerHTML = `<div class="market-intel-empty">既有資料橋接預覽讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderMcpReadinessMeta = data => {
mcpReadinessMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`router=${data.router_enabled ? 'on' : 'off'}`,
`external=${data.external_mcp_complete ? 'complete' : 'pending'}`,
`internal=${data.internal_mcp_complete ? 'complete' : 'pending'}`,
`market_tools=${data.market_intel_tool_count || 0}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderMcpReadinessBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const servers = data.server_statuses || [];
const checks = Object.entries(data.readiness_checks || {});
const expectedTools = data.expected_market_intel_tools || [];
const registeredCallers = data.registered_callers || [];
const toolContract = data.mcp_tool_contract || {};
const contractTools = toolContract.tools || [];
const telemetry = data.telemetry || {};
mcpReadinessBody.innerHTML = `
<div class="market-intel-empty mb-3">目前只做 MCP readiness planned preview不自動呼叫外部平台、不建立 DB session、不寫入 telemetry。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-mcp-servers>
<p class="market-intel-deploy-section-title">EXTERNAL MCP SERVERS</p>
<div class="market-intel-check-list">${
servers.length
? servers.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.server)}</strong>
<small>${escapeHtml(item.base_url || 'not configured')}</small>
<small>${escapeHtml(item.status || '')}</small>
</div>
<span>${item.healthy ? 'HEALTHY' : item.configured ? 'PENDING' : 'MISSING'}</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供 MCP server 狀態。</div>'
}</div>
</div>
<div data-market-intel-mcp-checks>
<p class="market-intel-deploy-section-title">READINESS CHECKS</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供 readiness checks。</div>'
}</div>
</div>
<div data-market-intel-mcp-tools>
<p class="market-intel-deploy-section-title">INTERNAL TOOL CONTRACT</p>
<div class="market-intel-check-list">
<div class="market-intel-check">
<div>
<strong>registered_callers</strong>
<small>${escapeHtml(registeredCallers.join(' / ') || 'none')}</small>
</div>
<span>${registeredCallers.length}</span>
</div>
<div class="market-intel-check">
<div>
<strong>market_intel_contract</strong>
<small>${escapeHtml((toolContract.blocked_reasons || []).join(' / ') || 'ready')}</small>
</div>
<span>${toolContract.contract_ready ? 'READY' : 'PENDING'}</span>
</div>
<div class="market-intel-check">
<div>
<strong>expected_tool_names</strong>
<small>${escapeHtml(expectedTools.join(' / ') || 'none')}</small>
</div>
<span>${escapeHtml(data.market_intel_tool_count || 0)}</span>
</div>
<div class="market-intel-check">
<div>
<strong>mcp_calls telemetry</strong>
<small>${escapeHtml(telemetry.mode || 'unknown')} / table=${telemetry.table_exists ? 'exists' : 'pending'}</small>
</div>
<span>${telemetry.read_only_query_executed ? 'QUERY' : 'PLANNED'}</span>
</div>
${contractTools.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.name)}</strong>
<small>${escapeHtml(item.server)} / ${escapeHtml((item.router_tools || []).join(' + '))}</small>
</div>
<span>${item.router_tools_whitelisted ? 'ALLOW' : 'BLOCK'}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadMcpReadiness = async () => {
if (!mcpReadinessMeta || !mcpReadinessBody) return;
mcpReadinessBody.innerHTML = '<div class="market-intel-empty">讀取 MCP 整合就緒度中...</div>';
try {
const response = await fetch(mcpReadinessEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderMcpReadinessMeta(data);
renderMcpReadinessBody(data);
} catch (error) {
mcpReadinessMeta.innerHTML = '<span class="market-intel-pill">error</span>';
mcpReadinessBody.innerHTML = `<div class="market-intel-empty">MCP 就緒度讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderMcpPreflightMeta = data => {
const missingRequiredEnv = (data.env_statuses || []).filter(item => item.required && !item.present).length;
mcpPreflightMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_to_start_stack ? 'yes' : 'no'}`,
`compose=${data.compose_file_present ? 'present' : 'missing'}`,
`missing_env=${missingRequiredEnv}`,
`docker=${data.docker_command_executed ? 'executed' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderMcpPreflightBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const envs = data.env_statuses || [];
const services = data.service_statuses || [];
const ports = data.port_statuses || [];
const fallback = data.fallback_plan || [];
const renderCheck = (key, label, status) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(key)}</strong>
<small>${escapeHtml(label || '')}</small>
</div>
<span>${escapeHtml(status)}</span>
</div>
`;
mcpPreflightBody.innerHTML = `
<div class="market-intel-empty mb-3">這裡只做外部 MCP 部署預檢,不執行 docker、SSH、DB role 建立或 crawler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-mcp-preflight-env>
<p class="market-intel-deploy-section-title">ENV GATES</p>
<div class="market-intel-check-list">${
envs.map(item => renderCheck(
item.name,
item.required ? 'required' : 'optional',
item.present ? 'SET' : 'MISSING'
)).join('')
}</div>
</div>
<div data-market-intel-mcp-preflight-services>
<p class="market-intel-deploy-section-title">COMPOSE SERVICES</p>
<div class="market-intel-check-list">${
services.map(item => renderCheck(
item.service,
data.compose_path || '',
item.declared ? 'DECLARED' : 'MISSING'
)).join('')
}</div>
</div>
<div data-market-intel-mcp-preflight-ports>
<p class="market-intel-deploy-section-title">LOCALHOST PORTS</p>
<div class="market-intel-check-list">${
ports.map(item => renderCheck(
`localhost:${item.port}`,
item.localhost_only ? '127.0.0.1 only' : 'not localhost only',
item.localhost_only ? 'SAFE' : 'BLOCK'
)).join('')
}</div>
</div>
<div data-market-intel-mcp-preflight-fallback>
<p class="market-intel-deploy-section-title">FALLBACK</p>
<div class="market-intel-check-list">${
fallback.map(item => renderCheck(
item.key,
item.label,
'READY'
)).join('')
}</div>
</div>
</div>
`;
};
const loadMcpPreflight = async () => {
if (!mcpPreflightMeta || !mcpPreflightBody) return;
mcpPreflightBody.innerHTML = '<div class="market-intel-empty">讀取 MCP 部署預檢中...</div>';
try {
const response = await fetch(mcpPreflightEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderMcpPreflightMeta(data);
renderMcpPreflightBody(data);
} catch (error) {
mcpPreflightMeta.innerHTML = '<span class="market-intel-pill">error</span>';
mcpPreflightBody.innerHTML = `<div class="market-intel-empty">MCP 部署預檢讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderMcpActivationMeta = data => {
mcpActivationMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_operator_activation ? 'yes' : 'no'}`,
`stages=${(data.stages || []).length}`,
`blocked=${(data.blocked_reasons || []).length}`,
`docker=${data.docker_command_executed ? 'executed' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderMcpActivationBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const stages = data.stages || [];
const fallback = data.fallback_plan || [];
const safety = Object.entries(data.safety_contract || {});
const renderStage = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
<small>gate=${escapeHtml(item.gate)} / status=${escapeHtml(item.status)}</small>
${item.command_preview ? `<small>${escapeHtml(item.command_preview)}</small>` : ''}
${item.notes ? `<small>${escapeHtml(item.notes)}</small>` : ''}
</article>
`;
const renderCheck = (key, label, status) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(key)}</strong>
<small>${escapeHtml(label || '')}</small>
</div>
<span>${escapeHtml(status)}</span>
</div>
`;
mcpActivationBody.innerHTML = `
<div class="market-intel-empty mb-3">這是 MCP 啟用順序預覽;不寫 env、不執行 docker/SSH、不建立 DB role、不開 router。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-mcp-activation-stages>
<p class="market-intel-deploy-section-title">ACTIVATION STAGES</p>
<div class="market-intel-operation-list">${
stages.length
? stages.map(renderStage).join('')
: '<div class="market-intel-empty">尚未提供啟用步驟。</div>'
}</div>
</div>
<div data-market-intel-mcp-activation-safety>
<p class="market-intel-deploy-section-title">SAFETY CONTRACT</p>
<div class="market-intel-check-list">${
safety.length
? safety.map(([key, value]) => renderCheck(key, '', value ? 'YES' : 'NO')).join('')
: '<div class="market-intel-empty">尚未提供安全合約。</div>'
}</div>
</div>
<div data-market-intel-mcp-activation-fallback>
<p class="market-intel-deploy-section-title">FALLBACK</p>
<div class="market-intel-check-list">${
fallback.length
? fallback.map(item => renderCheck(item.key, item.label, 'READY')).join('')
: '<div class="market-intel-empty">尚未提供備援方案。</div>'
}</div>
</div>
</div>
`;
};
const loadMcpActivation = async () => {
if (!mcpActivationMeta || !mcpActivationBody) return;
mcpActivationBody.innerHTML = '<div class="market-intel-empty">讀取 MCP 啟用 Runbook 中...</div>';
try {
const response = await fetch(mcpActivationEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderMcpActivationMeta(data);
renderMcpActivationBody(data);
} catch (error) {
mcpActivationMeta.innerHTML = '<span class="market-intel-pill">error</span>';
mcpActivationBody.innerHTML = `<div class="market-intel-empty">MCP 啟用 Runbook 讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderMcpFetchGateMeta = data => {
mcpFetchGateMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`fetch=${data.fetch_requested ? 'true' : 'false'}`,
`gate=${data.manual_fetch_gate_open ? 'open' : 'blocked'}`,
`network=${data.network_request_allowed ? 'allow' : 'block'}`,
`blocked=${(data.blocked_reasons || []).length}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderMcpFetchGateBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.gate_checks || {});
const sequence = data.required_sequence || [];
const readiness = data.mcp_readiness_summary || {};
mcpFetchGateBody.innerHTML = `
<div class="market-intel-empty mb-3">人工 fetch 目前先由 MCP gate 接管;頁面預設只做 planned preview不抓外站、不寫 DB、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-mcp-fetch-gate-checks>
<p class="market-intel-deploy-section-title">FETCH GATE CHECKS</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供 fetch gate checks。</div>'
}</div>
</div>
<div data-market-intel-mcp-fetch-gate-sequence>
<p class="market-intel-deploy-section-title">REQUIRED SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.length
? sequence.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>REQUIRED</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供啟用順序。</div>'
}</div>
</div>
<div data-market-intel-mcp-fetch-gate-readiness>
<p class="market-intel-deploy-section-title">READINESS SUMMARY</p>
<div class="market-intel-check-list">
<div class="market-intel-check">
<div>
<strong>router</strong>
<small>${escapeHtml(readiness.mode || 'unknown')}</small>
</div>
<span>${readiness.router_enabled ? 'ON' : 'OFF'}</span>
</div>
<div class="market-intel-check">
<div>
<strong>external_mcp</strong>
<small>${escapeHtml((readiness.blocked_reasons || []).join(' / ') || 'ready')}</small>
</div>
<span>${readiness.external_mcp_complete ? 'READY' : 'PENDING'}</span>
</div>
</div>
</div>
</div>
`;
};
const loadMcpFetchGate = async () => {
if (!mcpFetchGateMeta || !mcpFetchGateBody) return;
mcpFetchGateBody.innerHTML = '<div class="market-intel-empty">讀取人工 Fetch 安全閘門中...</div>';
try {
const response = await fetch(mcpFetchGateEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderMcpFetchGateMeta(data);
renderMcpFetchGateBody(data);
} catch (error) {
mcpFetchGateMeta.innerHTML = '<span class="market-intel-pill">error</span>';
mcpFetchGateBody.innerHTML = `<div class="market-intel-empty">人工 Fetch 安全閘門讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderManualSampleMeta = data => {
manualSampleMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_manual_sample_fetch ? 'yes' : 'no'}`,
`platforms=${data.platform_count || 0}`,
`sources=${data.sample_source_total || 0}`,
`network=${data.external_network_executed ? 'executed' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderManualSampleBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.gate_checks || {});
const platforms = data.sample_platforms || [];
const sequence = data.operator_sequence || [];
const fallback = data.fallback_plan || [];
const boundaries = data.safe_boundaries || [];
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderNamedItem = (item, status) => {
const normalized = typeof item === 'string' ? { key: item, label: item } : (item || {});
return `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(normalized.key || normalized.label || 'item')}</strong>
<small>${escapeHtml(normalized.label || normalized.key || '')}</small>
</div>
<span>${escapeHtml(normalized.status || status || 'required').toUpperCase()}</span>
</div>
`;
};
const renderPlatform = item => {
const firstSource = (item.selected_sources || [])[0] || {};
return `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.priority)}. ${escapeHtml(item.platform_code)}</strong>
<small>${escapeHtml(firstSource.name || item.platform_name)} / interval=${escapeHtml(item.request_interval_sec)}s / timeout=${escapeHtml(item.timeout_sec)}s</small>
</div>
<span>${escapeHtml(item.network_status || 'not_executed').toUpperCase()}</span>
</div>
`;
};
manualSampleBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只規劃第一次人工樣本 fetchAPI/UI 不抓外站、不寫 DB、不建立 crawler run、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-manual-sample-checks>
<p class="market-intel-deploy-section-title">SAMPLE GATES</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供 sample gate。</div>'
}</div>
</div>
<div data-market-intel-manual-sample-platforms>
<p class="market-intel-deploy-section-title">SAMPLE PLATFORMS</p>
<div class="market-intel-check-list">${
platforms.length
? platforms.map(renderPlatform).join('')
: '<div class="market-intel-empty">尚未提供平台樣本。</div>'
}</div>
</div>
<div data-market-intel-manual-sample-sequence>
<p class="market-intel-deploy-section-title">OPERATOR SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.length
? sequence.map(item => renderNamedItem(item, 'required')).join('')
: '<div class="market-intel-empty">尚未提供人工順序。</div>'
}</div>
</div>
<div data-market-intel-manual-sample-fallback>
<p class="market-intel-deploy-section-title">FALLBACK</p>
<div class="market-intel-check-list">${
fallback.length
? fallback.map(item => renderNamedItem(item, 'ready')).join('')
: '<div class="market-intel-empty">尚未提供備援方案。</div>'
}</div>
</div>
<div data-market-intel-manual-sample-boundaries>
<p class="market-intel-deploy-section-title">BOUNDARIES</p>
<div class="market-intel-check-list">${
boundaries.length
? boundaries.map(item => renderNamedItem(item, 'required')).join('')
: '<div class="market-intel-empty">尚未提供安全邊界。</div>'
}</div>
</div>
</div>
`;
};
const loadManualSample = async () => {
if (!manualSampleMeta || !manualSampleBody) return;
manualSampleBody.innerHTML = '<div class="market-intel-empty">讀取人工樣本 Fetch 計畫中...</div>';
try {
const response = await fetch(manualSampleEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderManualSampleMeta(data);
renderManualSampleBody(data);
} catch (error) {
manualSampleMeta.innerHTML = '<span class="market-intel-pill">error</span>';
manualSampleBody.innerHTML = `<div class="market-intel-empty">人工樣本 Fetch 計畫讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderSampleAcceptanceMeta = data => {
sampleAcceptanceMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`contract=${data.contract_ready ? 'ready' : 'blocked'}`,
`loaded=${data.sample_result_loaded ? 'yes' : 'no'}`,
`accepted=${data.sample_result_accepted ? 'yes' : 'no'}`,
`import=${data.candidate_import_allowed ? 'allow' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderSampleAcceptanceBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.gate_checks || {});
const acceptance = data.acceptance_checks || [];
const reject = data.reject_conditions || [];
const decisions = data.operator_decisions || [];
const sequence = data.promotion_sequence || [];
const boundaries = data.safe_boundaries || [];
const thresholds = data.acceptance_thresholds || {};
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderNamedItem = (item, status) => {
const normalized = typeof item === 'string' ? { key: item, label: item } : (item || {});
return `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(normalized.key || normalized.label || 'item')}</strong>
<small>${escapeHtml(normalized.label || normalized.key || '')}</small>
</div>
<span>${escapeHtml(normalized.status || status || 'required').toUpperCase()}</span>
</div>
`;
};
sampleAcceptanceBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只定義 sample fetch 回來後的驗收契約;不載入 sample result、不抓外站、不寫 DB、不建立候選活動。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">required_fields=${escapeHtml((data.required_result_fields || []).length)} / diagnostics=${escapeHtml((data.required_diagnostic_fields || []).length)} / min_candidates=${escapeHtml(thresholds.minimum_campaign_candidates || 0)} / bands=${escapeHtml((thresholds.accepted_candidate_bands || []).join('/'))}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-sample-acceptance-checks>
<p class="market-intel-deploy-section-title">CONTRACT GATES</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供 contract gate。</div>'
}</div>
</div>
<div data-market-intel-sample-acceptance-fields>
<p class="market-intel-deploy-section-title">REQUIRED FIELDS</p>
<div class="market-intel-check-list">${
(data.required_result_fields || []).map(item => renderNamedItem(String(item), 'required')).join('')
|| '<div class="market-intel-empty">尚未提供欄位契約。</div>'
}</div>
</div>
<div data-market-intel-sample-acceptance-rules>
<p class="market-intel-deploy-section-title">ACCEPTANCE RULES</p>
<div class="market-intel-check-list">${
acceptance.length
? acceptance.map(item => renderNamedItem(item, 'not_evaluated')).join('')
: '<div class="market-intel-empty">尚未提供驗收規則。</div>'
}</div>
</div>
<div data-market-intel-sample-acceptance-reject>
<p class="market-intel-deploy-section-title">REJECT CONDITIONS</p>
<div class="market-intel-check-list">${
reject.length
? reject.map(item => renderNamedItem(item, 'reject')).join('')
: '<div class="market-intel-empty">尚未提供拒收條件。</div>'
}</div>
</div>
<div data-market-intel-sample-acceptance-decisions>
<p class="market-intel-deploy-section-title">OPERATOR DECISIONS</p>
<div class="market-intel-check-list">${
decisions.length
? decisions.map(item => renderNamedItem(item, item.write_status || 'blocked')).join('')
: '<div class="market-intel-empty">尚未提供人工決策。</div>'
}</div>
</div>
<div data-market-intel-sample-acceptance-sequence>
<p class="market-intel-deploy-section-title">PROMOTION SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.length
? sequence.map(item => renderNamedItem(String(item), 'required')).join('')
: '<div class="market-intel-empty">尚未提供升級順序。</div>'
}</div>
</div>
<div data-market-intel-sample-acceptance-boundaries>
<p class="market-intel-deploy-section-title">BOUNDARIES</p>
<div class="market-intel-check-list">${
boundaries.length
? boundaries.map(item => renderNamedItem(String(item), 'required')).join('')
: '<div class="market-intel-empty">尚未提供安全邊界。</div>'
}</div>
</div>
</div>
`;
};
const loadSampleAcceptance = async () => {
if (!sampleAcceptanceMeta || !sampleAcceptanceBody) return;
sampleAcceptanceBody.innerHTML = '<div class="market-intel-empty">讀取樣本結果驗收契約中...</div>';
try {
const response = await fetch(sampleAcceptanceEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderSampleAcceptanceMeta(data);
renderSampleAcceptanceBody(data);
} catch (error) {
sampleAcceptanceMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleAcceptanceBody.innerHTML = `<div class="market-intel-empty">樣本結果驗收契約讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderSampleReviewMeta = data => {
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`loaded=${data.sample_result_loaded ? 'yes' : 'no'}`,
`reviewed=${data.sample_result_reviewed ? 'yes' : 'no'}`,
`result=${data.review_result || 'planned'}`,
`import=${data.candidate_import_allowed ? 'open' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderSampleReviewBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = data.review_checks || [];
const findings = data.review_findings || [];
const candidates = data.candidate_summary || {};
const actions = data.operator_next_actions || [];
const boundaries = data.safe_boundaries || [];
const renderCheck = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key || 'check')}</strong>
<small>${escapeHtml(item.label || '')}</small>
</div>
<span>${escapeHtml(item.status || 'planned').toUpperCase()}</span>
</div>
`;
const renderNamedItem = (item, status) => {
const normalized = typeof item === 'string' ? { key: item, label: item } : (item || {});
return `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(normalized.key || normalized.label || 'item')}</strong>
<small>${escapeHtml(normalized.label || normalized.key || '')}</small>
</div>
<span>${escapeHtml(normalized.severity || normalized.write_status || status || 'blocked').toUpperCase()}</span>
</div>
`;
};
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只用純函式審核人工 sample result目前預設不載入結果、不抓外站、不存檔、不寫 DB、不建立候選活動。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">candidate_count=${escapeHtml(candidates.candidate_count || 0)} / accepted=${escapeHtml(candidates.accepted_candidate_count || 0)} / bands=${escapeHtml((candidates.accepted_candidate_bands || []).join('/'))}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-sample-review-checks>
<p class="market-intel-deploy-section-title">REVIEW CHECKS</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未載入 sample result審核檢查維持 planned。</div>'
}</div>
</div>
<div data-market-intel-sample-review-findings>
<p class="market-intel-deploy-section-title">FINDINGS</p>
<div class="market-intel-check-list">${
findings.length
? findings.map(item => renderNamedItem(item, 'block')).join('')
: '<div class="market-intel-empty">目前沒有審核發現;尚未載入結果時代表未評估。</div>'
}</div>
</div>
<div data-market-intel-sample-review-actions>
<p class="market-intel-deploy-section-title">NEXT ACTIONS</p>
<div class="market-intel-check-list">${
actions.length
? actions.map(item => renderNamedItem(item, item.write_status || 'blocked')).join('')
: '<div class="market-intel-empty">尚未提供下一步。</div>'
}</div>
</div>
<div data-market-intel-sample-review-boundaries>
<p class="market-intel-deploy-section-title">BOUNDARIES</p>
<div class="market-intel-check-list">${
boundaries.length
? boundaries.map(item => renderNamedItem(String(item), 'required')).join('')
: '<div class="market-intel-empty">尚未提供安全邊界。</div>'
}</div>
</div>
</div>
`;
};
const loadSampleReview = async () => {
if (!sampleReviewMeta || !sampleReviewBody) return;
sampleReviewBody.innerHTML = '<div class="market-intel-empty">讀取樣本結果審核預覽中...</div>';
try {
const response = await fetch(sampleReviewEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderSampleReviewMeta(data);
renderSampleReviewBody(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">樣本結果審核預覽讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const evaluateSampleReview = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 sample result 中...</div>';
try {
const response = await fetch(sampleReviewEvaluateEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderSampleReviewMeta(data);
renderSampleReviewBody(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">樣本結果審核失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateHandoff = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const summary = data.handoff_summary || {};
const candidates = data.candidates || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`handoff=${data.handoff_ready ? 'ready' : 'blocked'}`,
`candidates=${summary.candidate_count || 0}`,
`persisted=${data.candidate_handoff_persisted ? 'yes' : 'no'}`,
`import=${data.candidate_import_allowed ? 'open' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生候選活動 handoff preview不保存 payload、不建立活動、不寫 market_*。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-operation-list">${
candidates.length
? candidates.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.candidate_text || item.candidate_url)}</strong>
<small>${escapeHtml(item.platform_code)} / ${escapeHtml(item.confidence_band)} / score=${escapeHtml(item.score)} / ${escapeHtml(item.write_status)}</small>
<small>${escapeHtml(item.candidate_url)}</small>
</article>
`).join('')
: '<div class="market-intel-empty">目前沒有可交接候選;請先讓 sample result 通過審核。</div>'
}</div>
`;
};
const loadCandidateHandoff = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生候選 handoff 預覽中...</div>';
try {
const response = await fetch(sampleCandidateHandoffEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateHandoff(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">候選 handoff 產生失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueDraft = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const summary = data.queue_summary || {};
const queueItems = data.queue_items || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`queue=${data.queue_draft_ready ? 'ready' : 'blocked'}`,
`items=${summary.queue_item_count || 0}`,
`persisted=${data.review_queue_persisted ? 'yes' : 'no'}`,
`import=${data.candidate_import_allowed ? 'open' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生候選審核 queue 草案;不建立正式 queue、不寫 DB、不自動核准候選。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-operation-list">${
queueItems.length
? queueItems.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.candidate_text || item.candidate_url)}</strong>
<small>${escapeHtml(item.platform_code)} / ${escapeHtml(item.confidence_band)} / score=${escapeHtml(item.score)} / priority=${escapeHtml(item.review_priority)} / ${escapeHtml(item.review_state)}</small>
<small>${escapeHtml(item.write_status)} / approval=${item.approval_required ? 'required' : 'none'}</small>
<small>${escapeHtml(item.candidate_url)}</small>
</article>
`).join('')
: '<div class="market-intel-empty">目前沒有可建立草案的候選;請先產生通過審核的 handoff。</div>'
}</div>
`;
};
const loadCandidateQueueDraft = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生候選審核 queue 草案中...</div>';
try {
const response = await fetch(sampleCandidateQueueDraftEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueDraft(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">候選審核 queue 草案產生失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueApproval = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const summary = data.approval_summary || {};
const gates = data.approval_gates || [];
const rows = (data.queue_write_preview || {}).rows || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`target=${summary.target_table || 'unknown'}`,
`rows=${summary.row_preview_count || 0}`,
`gates=${summary.gates_passed || 0}/${summary.gate_count || 0}`,
`write=${data.review_queue_write_allowed ? 'open' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只做 queue 寫入送審 gate不建立 approval record、不寫 market_alert_review_queue、不開 DB transaction。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-check-list mb-3">${
gates.length
? gates.map(item => renderNamedItem(item, item.passed ? 'pass' : 'block')).join('')
: '<div class="market-intel-empty">尚未產生 gate。</div>'
}</div>
<div class="market-intel-operation-list">${
rows.length
? rows.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.alert_candidate_id)}</strong>
<small>${escapeHtml(item.review_state)} / ${escapeHtml(item.priority_lane)} / ${escapeHtml(item.threshold_level)} / score=${escapeHtml(item.total_score)}</small>
<small>${escapeHtml(item.dedupe_key)} / ${escapeHtml(item.write_status)}</small>
</article>
`).join('')
: '<div class="market-intel-empty">目前沒有可送審的 queue row preview。</div>'
}</div>
`;
};
const loadCandidateQueueApproval = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue 寫入送審 gate 中...</div>';
try {
const response = await fetch(sampleCandidateQueueApprovalEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueApproval(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue 寫入送審 gate 檢查失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueTransaction = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const summary = data.transaction_summary || {};
const statements = data.statements || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`target=${summary.target_table || 'unknown'}`,
`statements=${summary.statement_count || 0}`,
`conflict=${summary.conflict_policy || 'none'}`,
`ready=${data.transaction_ready ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生 transaction preview不開 DB connection、不開 transaction、不 commit、不建立 approval record。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-operation-list">${
statements.length
? statements.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.idempotency_key)}</strong>
<small>${escapeHtml(item.operation)} / ${escapeHtml(item.table)} / ${escapeHtml(item.write_status)}</small>
<small>${escapeHtml(item.sql_shape)}</small>
<small>payload=${escapeHtml(item.parameter_payload_hash)}</small>
</article>
`).join('')
: '<div class="market-intel-empty">目前沒有可檢查的 transaction statement。</div>'
}</div>
`;
};
const loadCandidateQueueTransaction = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue transaction preview 中...</div>';
try {
const response = await fetch(sampleCandidateQueueTransactionEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueTransaction(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue transaction preview 產生失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueWriter = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const summary = data.transaction_preview_summary || {};
const gates = data.approval_gates || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_real_write ? 'yes' : 'no'}`,
`statements=${summary.statement_count || 0}`,
`execute=${data.execute_requested ? 'yes' : 'no'}`,
`apply=${data.apply_real_write_requested ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 CLI writer gate不讀取 token、不開 DB connection、不寫 queue。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
</div>
`).join('')
}</div>
`;
};
const loadCandidateQueueWriter = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue writer CLI gate 中...</div>';
try {
const response = await fetch(sampleCandidateQueueWriterEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueWriter(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue writer CLI gate 檢查失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueuePreflight = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const columns = data.mapped_insert_columns || [];
const missing = data.missing_insert_columns || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`schema=${data.schema_ready ? 'ready' : 'blocked'}`,
`mapped=${columns.length}`,
`missing=${missing.length}`,
`dedupe=${data.dedupe_unique_index_present ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡檢查 payload 與 queue table 欄位相容性;頁面預設不連 DB、不寫 queue。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-operation-list">
<article class="market-intel-operation">
<strong>mapped insert columns</strong>
<small>${escapeHtml(columns.join(', ') || 'none')}</small>
</article>
<article class="market-intel-operation">
<strong>missing columns</strong>
<small>${escapeHtml(missing.join(', ') || 'none')}</small>
</article>
<article class="market-intel-operation">
<strong>unmapped payload keys</strong>
<small>${escapeHtml((data.unmapped_payload_keys || []).join(', ') || 'none')}</small>
</article>
</div>
`;
};
const loadCandidateQueuePreflight = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue writer preflight 中...</div>';
try {
const response = await fetch(sampleCandidateQueuePreflightEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueuePreflight(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue writer preflight 檢查失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueuePostwriteSmoke = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const found = data.found_dedupe_keys || [];
const missing = data.missing_dedupe_keys || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`passed=${data.postwrite_smoke_passed ? 'yes' : 'no'}`,
`expected=${data.expected_dedupe_key_count || 0}`,
`found=${data.found_count || 0}`,
`missing=${data.missing_count || 0}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只做 CLI 寫入後的 queue row 只讀驗證;頁面預設不連 DB、不寫 queue。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-operation-list">
<article class="market-intel-operation">
<strong>found dedupe keys</strong>
<small>${escapeHtml(found.join(', ') || 'none')}</small>
</article>
<article class="market-intel-operation">
<strong>missing dedupe keys</strong>
<small>${escapeHtml(missing.join(', ') || 'none')}</small>
</article>
<article class="market-intel-operation">
<strong>read-only status</strong>
<small>query=${data.read_only_query_executed ? 'yes' : 'no'} / write=${data.database_write_executed ? 'yes' : 'no'} / commit=${data.database_commit_executed ? 'yes' : 'no'}</small>
</article>
</div>
`;
};
const loadCandidateQueuePostwriteSmoke = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue writer post-write smoke 中...</div>';
try {
const response = await fetch(sampleCandidateQueuePostwriteSmokeEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueuePostwriteSmoke(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue writer post-write smoke 檢查失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueOperatorDrill = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const commands = data.command_sequence || [];
const gates = data.gates || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.operator_drill_ready ? 'yes' : 'no'}`,
`commands=${commands.length}`,
`api_cli=${data.api_executes_cli ? 'yes' : 'no'}`,
`db_write=${data.database_write_executed ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生操作員演練順序API/UI 不讀 token、不執行 CLI、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-check-list mb-3">${
gates.map(gate => `
<div class="market-intel-check">
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
</div>
`).join('')
}</div>
<div class="market-intel-operation-list">${
commands.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.step)}. ${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
<small>${escapeHtml(item.command_shape)}</small>
<small>db_write=${item.executes_database ? 'yes' : 'no'}</small>
</article>
`).join('')
}</div>
`;
};
const loadCandidateQueueOperatorDrill = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue writer operator drill 中...</div>';
try {
const response = await fetch(sampleCandidateQueueOperatorDrillEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueOperatorDrill(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue writer operator drill 產生失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueRunPackage = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const manifest = data.payload_manifest || {};
const artifacts = data.required_artifacts || [];
const commands = data.command_bundle || [];
const signoff = data.operator_signoff || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.package_ready ? 'yes' : 'no'}`,
`payloads=${manifest.payload_count || 0}`,
`api_file=${data.api_writes_file ? 'yes' : 'no'}`,
`db_write=${data.database_write_executed ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理正式 CLI 小流量寫入前的證據包與命令包API/UI 不產檔、不讀 token、不執行 CLI、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">manifest=${escapeHtml((manifest.manifest_hash || '').slice(0, 16) || 'none')} / dedupe=${escapeHtml((manifest.dedupe_keys || []).join(', ') || 'none')}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">REQUIRED ARTIFACTS</p>
<div class="market-intel-operation-list">${
artifacts.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
<small>${escapeHtml(item.path_shape)}</small>
<small>created_by_api=${item.created_by_api ? 'yes' : 'no'}</small>
</article>
`).join('') || '<div class="market-intel-empty">尚未提供 artifacts。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMAND BUNDLE</p>
<div class="market-intel-operation-list">${
commands.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.step)}. ${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.command_shape)}</small>
<small>db_write=${item.executes_database ? 'yes' : 'no'}</small>
</article>
`).join('') || '<div class="market-intel-empty">尚未提供 commands。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR SIGNOFF</p>
<div class="market-intel-check-list">${
signoff.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`signoff_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>REQUIRED</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 signoff。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueRunPackage = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue writer run package 中...</div>';
try {
const response = await fetch(sampleCandidateQueueRunPackageEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueRunPackage(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue writer run package 產生失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueRunReadiness = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const evidence = data.operator_evidence_summary || {};
const packageSummary = data.run_package_summary || {};
const gates = data.gates || [];
const steps = data.next_operator_steps || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`cli_ready=${data.ready_for_cli_operator_run ? 'yes' : 'no'}`,
`api_write=${data.ready_for_api_database_write ? 'yes' : 'no'}`,
`payloads=${packageSummary.payload_count || 0}`,
`paths=${evidence.artifact_path_count || 0}`,
`token_api=${evidence.approval_token_submitted_to_api ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查正式 CLI 小流量寫入前的操作員證據API/UI 不讀 token、不執行 CLI、不產檔、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">manifest=${escapeHtml((packageSummary.manifest_hash || '').slice(0, 16) || 'none')} / artifacts=${escapeHtml(packageSummary.required_artifact_count || 0)} / commands=${escapeHtml(packageSummary.command_count || 0)}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">READINESS GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 readiness gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">EVIDENCE SUMMARY</p>
<div class="market-intel-check-list">
${[
['reviewed_sample_json_path_recorded', evidence.reviewed_sample_json_path_recorded],
['backup_artifact_path_recorded', evidence.backup_artifact_path_recorded],
['preflight_artifact_path_recorded', evidence.preflight_artifact_path_recorded],
['migration_live_smoke_passed', evidence.migration_live_smoke_passed],
['operator_acknowledged_shell_only_token', evidence.operator_acknowledged_shell_only_token],
['approval_token_submitted_to_api', evidence.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(key)}</strong>
</div>
<span>${value ? 'YES' : 'NO'}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NEXT STEPS</p>
<div class="market-intel-check-list">${
steps.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>MANUAL</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供下一步。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueRunReadiness = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result
? parsed
: { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue writer run readiness 中...</div>';
try {
const response = await fetch(sampleCandidateQueueRunReadinessEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueRunReadiness(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue writer run readiness 檢查失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueRunReceipt = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const writer = data.writer_output_summary || {};
const smoke = data.postwrite_smoke_summary || {};
const evidence = data.operator_evidence_summary || {};
const gates = data.gates || [];
const steps = data.next_operator_steps || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`receipt=${data.receipt_passed ? 'pass' : 'blocked'}`,
`writer=${writer.mode || 'missing'}`,
`smoke=${smoke.postwrite_smoke_passed ? 'pass' : 'blocked'}`,
`api_write=${data.ready_for_api_database_write ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 CLI 寫入後的 writer output 與 post-write smoke receiptAPI/UI 不讀 token、不執行 CLI、不連 DB、不補寫 queue。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">expected=${escapeHtml((data.expected_dedupe_keys || []).join(', ') || 'none')} / observed=${escapeHtml((writer.observed_dedupe_keys || []).join(', ') || 'none')} / found=${escapeHtml((smoke.found_dedupe_keys || []).join(', ') || 'none')}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">RECEIPT GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 receipt gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITER / SMOKE</p>
<div class="market-intel-check-list">
${[
['writer_committed', writer.database_commit_executed],
['writer_dedupe_match', writer.dedupe_keys_match_expected],
['writer_token_key_detected', writer.approval_token_key_detected],
['smoke_read_only', smoke.read_only_query_executed],
['smoke_passed', smoke.postwrite_smoke_passed],
['smoke_dedupe_match', smoke.dedupe_keys_match_expected]
].map(([key, value]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(key)}</strong>
</div>
<span>${value ? 'YES' : 'NO'}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARTIFACT EVIDENCE</p>
<div class="market-intel-check-list">
${[
['writer_output_json_path_recorded', evidence.writer_output_json_path_recorded],
['postwrite_smoke_json_path_recorded', evidence.postwrite_smoke_json_path_recorded],
['operator_confirmed_no_token_in_artifacts', evidence.operator_confirmed_no_token_in_artifacts],
['approval_token_submitted_to_api', evidence.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(key)}</strong>
</div>
<span>${value ? 'YES' : 'NO'}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NEXT STEPS</p>
<div class="market-intel-check-list">${
steps.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>MANUAL</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供下一步。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueRunReceipt = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result
? parsed
: { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue writer run receipt 中...</div>';
try {
const response = await fetch(sampleCandidateQueueRunReceiptEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueRunReceipt(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue writer run receipt 審核失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueRunCloseout = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const receipt = data.receipt_summary || {};
const closeout = data.operator_closeout_summary || {};
const promotion = data.promotion_gate || {};
const gates = data.gates || [];
const steps = data.next_operator_steps || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`closeout=${data.closeout_passed ? 'pass' : 'blocked'}`,
`receipt=${receipt.receipt_passed ? 'pass' : 'blocked'}`,
`next=${promotion.allowed ? 'manual' : 'hold'}`,
`api_write=${data.ready_for_api_database_write ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只做 run receipt 後的 closeout gate通過後也只代表可進人工 queue review / read-only inventory不代表 API/UI 可寫 DB 或掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">CLOSEOUT GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 closeout gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RECEIPT SUMMARY</p>
<div class="market-intel-check-list">
${[
['receipt_passed', receipt.receipt_passed],
['dedupe_keys', receipt.expected_dedupe_key_count || 0],
['writer_match', receipt.writer_dedupe_keys_match_expected],
['smoke_match', receipt.postwrite_smoke_dedupe_keys_match_expected],
['safe_boundaries_complete', receipt.safe_boundaries_complete]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${typeof value === 'boolean' ? (value ? 'YES' : 'NO') : escapeHtml(value)}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR CLOSEOUT</p>
<div class="market-intel-check-list">
${[
['closeout_artifact_path_recorded', closeout.closeout_artifact_path_recorded],
['operator_confirmed_queue_review_next', closeout.operator_confirmed_queue_review_next],
['operator_confirmed_no_scheduler_attach', closeout.operator_confirmed_no_scheduler_attach],
['operator_confirmed_no_api_db_write', closeout.operator_confirmed_no_api_db_write],
['approval_token_submitted_to_api', closeout.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${value ? 'YES' : 'NO'}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION / NEXT</p>
<div class="market-intel-check-list">
<div class="market-intel-check">
<div>
<strong>${escapeHtml(promotion.next_manual_phase || 'manual_phase')}</strong>
<small>requires_operator_approval=${promotion.requires_operator_approval ? 'yes' : 'no'}</small>
</div>
<span>${promotion.allowed ? 'ALLOW' : 'HOLD'}</span>
</div>
${steps.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>MANUAL</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueRunCloseout = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result
? parsed
: { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">收尾 queue writer run closeout 中...</div>';
try {
const response = await fetch(sampleCandidateQueueRunCloseoutEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueRunCloseout(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue writer run closeout 收尾失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewHandoff = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const closeout = data.closeout_summary || {};
const operator = data.operator_handoff_summary || {};
const contract = data.review_contract || {};
const gates = data.gates || [];
const steps = data.next_operator_steps || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`handoff=${data.handoff_ready ? 'ready' : 'blocked'}`,
`closeout=${closeout.closeout_passed ? 'pass' : 'blocked'}`,
`expected=${(data.expected_dedupe_keys || []).length}`,
`api_write=${data.ready_for_api_database_write ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生人工 queue review handoff不查 DB、不更新 review_state、不補寫 queue、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">expected dedupe keys${escapeHtml((data.expected_dedupe_keys || []).join(', ') || 'none')}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">HANDOFF GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 handoff gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">REVIEW CONTRACT</p>
<div class="market-intel-check-list">
<div class="market-intel-check">
<div>
<strong>expected_review_state</strong>
<small>${escapeHtml(contract.expected_review_state || 'needs_review')}</small>
</div>
<span>MANUAL</span>
</div>
${(contract.required_columns || []).map(item => `
<div class="market-intel-check">
<div><strong>${escapeHtml(item)}</strong></div>
<span>FIELD</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['operator_confirmed_queue_review_next', operator.operator_confirmed_queue_review_next],
['operator_confirmed_no_scheduler_attach', operator.operator_confirmed_no_scheduler_attach],
['operator_confirmed_no_api_db_write', operator.operator_confirmed_no_api_db_write],
['approval_token_submitted_to_api', operator.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${value ? 'YES' : 'NO'}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NEXT STEPS</p>
<div class="market-intel-check-list">${
steps.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>MANUAL</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供下一步。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewHandoff = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result
? parsed
: { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review handoff 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewHandoffEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewHandoff(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review handoff 產生失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewInventory = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const operator = data.operator_inventory_summary || {};
const table = data.alert_review_queue_table || {};
const smoke = data.postwrite_smoke_summary || {};
const live = data.live_inventory_summary || {};
const gates = data.gates || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`inventory=${data.review_inventory_ready ? 'ready' : 'blocked'}`,
`read_only=${data.read_only_query_executed ? 'yes' : 'no'}`,
`found=${(data.found_dedupe_keys || []).length}`,
`api_update=${data.api_updates_review_state ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只做 queue review inventory 只讀交接檢查;不更新 review_state、不補寫 queue、不讀 token、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">expected${escapeHtml((data.expected_dedupe_keys || []).join(', ') || 'none')} / found${escapeHtml((data.found_dedupe_keys || []).join(', ') || 'none')}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">INVENTORY GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 inventory gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">QUEUE TABLE</p>
<div class="market-intel-check-list">
${[
['table_exists', table.exists],
['row_count', table.row_count ?? 'n/a'],
['table_status', table.status || 'not_reported'],
['postwrite_mode', smoke.mode || 'planned'],
['smoke_passed', smoke.postwrite_smoke_passed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">LIVE INVENTORY</p>
<div class="market-intel-check-list">
${[
['live_mode', live.mode || 'planned'],
['summary_ready', live.summary_ready],
['total_rows', live.total_rows ?? 'n/a'],
['operator_read_only', operator.operator_confirmed_inventory_read_only],
['approval_token_submitted_to_api', operator.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ROWS</p>
<div class="market-intel-check-list">${
(data.row_summaries || []).map(row => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(row.dedupe_key || 'unknown')}</strong>
<small>${escapeHtml(row.priority_lane || 'n/a')} / score=${escapeHtml(String(row.total_score ?? 'n/a'))}</small>
</div>
<span>${escapeHtml(row.review_state || 'unknown')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未執行只讀 row inventory。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewInventory = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review inventory 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewInventoryEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewInventory(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review inventory 檢查失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecision = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const operator = data.operator_decision_summary || {};
const contract = data.decision_contract || {};
const gates = data.gates || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`decision=${data.decision_ready ? 'ready' : 'blocked'}`,
`proposed=${operator.proposed_review_decision || 'none'}`,
`rows=${(data.decision_rows || []).length}`,
`api_update=${data.api_updates_review_state ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生人工 queue review decision 草案;不更新 review_state、不寫 decision record、不讀 token、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">DECISION GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 decision gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CONTRACT</p>
<div class="market-intel-check-list">
<div class="market-intel-check">
<div><strong>expected_current_state</strong></div>
<span>${escapeHtml(contract.expected_current_state || 'needs_review')}</span>
</div>
${(contract.allowed_next_states || []).map(item => `
<div class="market-intel-check">
<div><strong>${escapeHtml(item)}</strong></div>
<span>ALLOW</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['reviewer_id', operator.reviewer_id || 'missing'],
['decision_notes_present', operator.decision_notes_present],
['manual_decision_only', operator.operator_confirmed_manual_decision_only],
['approval_token_submitted_to_api', operator.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">DECISION ROWS</p>
<div class="market-intel-check-list">${
(data.decision_rows || []).map(row => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(row.dedupe_key || 'unknown')}</strong>
<small>${escapeHtml(row.current_review_state || 'unknown')} -> ${escapeHtml(row.proposed_review_state || 'none')}</small>
</div>
<span>${escapeHtml(row.write_status || 'preview')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未產生 decision rows。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecision = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review decision 草案中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecision(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision 草案失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionApproval = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const operator = data.operator_approval_summary || {};
const summary = data.approval_summary || {};
const contract = data.approval_contract || {};
const gates = data.approval_gates || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`approval=${data.approval_ready ? 'ready' : 'blocked'}`,
`rows=${(data.decision_update_preview || []).length}`,
`api_update=${data.api_updates_review_state ? 'yes' : 'no'}`,
`cli_ready=${data.ready_for_cli_decision_writer ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 queue review decision 批准 gate不更新 review_state、不寫 decision record、不讀 token、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">APPROVAL GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 approval gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">APPROVAL SUMMARY</p>
<div class="market-intel-check-list">
${[
['target_table', summary.target_table || data.target_table || 'unknown'],
['row_preview_count', summary.row_preview_count ?? 0],
['manual_required', summary.manual_approval_required],
['api_write_allowed', summary.api_write_allowed],
['next_stage', contract.next_stage || 'not_ready']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['payload_reviewed', operator.operator_confirmed_decision_payload_reviewed],
['cli_only_apply', operator.operator_confirmed_decision_apply_requires_cli],
['not_api_update', operator.operator_confirmed_review_state_update_is_not_api],
['notes_present', operator.decision_approval_notes_present],
['approval_token_submitted_to_api', operator.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">UPDATE PREVIEW</p>
<div class="market-intel-check-list">${
(data.decision_update_preview || []).map(row => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(row.dedupe_key || 'unknown')}</strong>
<small>${escapeHtml(row.expected_current_review_state || 'unknown')} -> ${escapeHtml(row.approved_next_review_state || 'none')}</small>
</div>
<span>${escapeHtml(row.write_status || 'preview')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未產生 update preview。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionApproval = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review decision 批准 gate 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionApprovalEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionApproval(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision 批准 gate 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionTransaction = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const operator = data.operator_transaction_summary || {};
const summary = data.transaction_preview_summary || {};
const contract = data.transaction_contract || {};
const gates = data.transaction_gates || [];
const statements = data.statements || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`transaction=${data.transaction_ready ? 'ready' : 'blocked'}`,
`statements=${summary.statement_count || 0}`,
`api_update=${data.api_updates_review_state ? 'yes' : 'no'}`,
`cli_required=${summary.manual_cli_required ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生 queue review decision transaction preview不更新 review_state、不開 DB connection、不讀 token、不執行 CLI、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">TRANSACTION GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 transaction gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CONTRACT</p>
<div class="market-intel-check-list">
${[
['target_table', summary.target_table || data.target_table || 'unknown'],
['expected_current_state', contract.expected_current_state || 'needs_review'],
['next_stage', contract.next_stage || 'not_ready'],
['api_write_allowed', summary.api_write_allowed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['payload_reviewed', operator.operator_confirmed_transaction_payload_reviewed],
['cli_only_transaction', operator.operator_confirmed_cli_only_transaction],
['not_api_update', operator.operator_confirmed_review_state_update_is_not_api],
['notes_present', operator.decision_transaction_notes_present],
['approval_token_submitted_to_api', operator.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">STATEMENTS</p>
<div class="market-intel-check-list">${
statements.map(row => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(row.idempotency_key || row.lookup?.dedupe_key || 'unknown')}</strong>
<small>${escapeHtml(row.expected_current_review_state || 'unknown')} -> ${escapeHtml(row.next_review_state || 'none')}</small>
</div>
<span>${escapeHtml(row.write_status || 'preview')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未產生 transaction statements。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionTransaction = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review decision transaction preview 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionTransactionEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionTransaction(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision transaction preview 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionPreflight = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const summary = data.statement_summary || {};
const payloads = summary.review_state_updates || [];
const contract = data.update_contract || {};
const catalog = data.catalog_probe_plan || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`payload=${data.preflight_payload_ready ? 'ready' : 'blocked'}`,
`statements=${summary.statement_count || 0}`,
`query=${data.read_only_query_executed ? 'yes' : 'no'}`,
`db_write=${data.database_write_executed ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 review_state writer preflightAPI/UI 不讀 token、不連 DB、不更新 review_state、不 commit、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">PREFLIGHT GATES</p>
<div class="market-intel-check-list">${
(data.preflight_gates || []).map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 preflight gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CONTRACT</p>
<div class="market-intel-check-list">
${[
['target_table', contract.target_table || data.target_table || 'unknown'],
['operation', contract.statement_type || data.target_operation || 'unknown'],
['lookup', contract.lookup || 'dedupe_key'],
['current_state', contract.expected_current_review_state || 'needs_review'],
['allowed_next_states', (contract.allowed_next_states || []).join(', ') || 'none']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CATALOG PLAN</p>
<div class="market-intel-check-list">
${[
['mode', catalog.mode || 'planned_only'],
['required_columns', (catalog.required_columns || []).join(', ') || 'none'],
['unique_lookup', catalog.required_unique_lookup || 'dedupe_key'],
['connection_opened', catalog.database_connection_opened],
['query_executed', catalog.read_only_query_executed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PAYLOAD</p>
<div class="market-intel-check-list">${
payloads.map(row => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(row.dedupe_key || row.idempotency_key || 'unknown')}</strong>
<small>${escapeHtml(row.expected_current_review_state || 'unknown')} -> ${escapeHtml(row.next_review_state || 'none')}</small>
</div>
<span>${escapeHtml(row.operation || 'update')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 review_state update payload。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITE FLAGS</p>
<div class="market-intel-check-list">
${[
['api_updates_review_state', data.api_updates_review_state],
['review_state_update_executed', data.review_state_update_executed],
['database_write', data.database_write_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionPreflight = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review decision writer preflight 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionPreflightEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionPreflight(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision writer preflight 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionPostwriteSmoke = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const rows = data.row_summaries || [];
const mismatches = data.state_mismatches || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`passed=${data.postwrite_smoke_passed ? 'yes' : 'no'}`,
`expected=${data.expected_dedupe_key_count || 0}`,
`found=${data.found_count || 0}`,
`mismatch=${data.state_mismatch_count || 0}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只做 review_state writer post-write 只讀驗證API/UI 不讀 token、不更新 review_state、不 commit、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">EXPECTED UPDATES</p>
<div class="market-intel-check-list">${
(data.expected_review_state_updates || []).map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.dedupe_key || 'unknown')}</strong>
<small>${escapeHtml(item.expected_current_review_state || 'unknown')} -> ${escapeHtml(item.expected_review_state || 'none')}</small>
</div>
<span>${escapeHtml(item.parameter_payload_hash || 'preview')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 review_state update payload。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">READ-ONLY RESULT</p>
<div class="market-intel-check-list">
${[
['read_only_query', data.read_only_query_executed],
['db_connection', data.database_connection_opened],
['api_updates_review_state', data.api_updates_review_state],
['review_state_update_executed', data.review_state_update_executed],
['database_write', data.database_write_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
<div class="market-intel-deploy-grid mt-3">
<div>
<p class="market-intel-deploy-section-title">ROWS</p>
<div class="market-intel-check-list">${
rows.map(row => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(row.dedupe_key || 'unknown')}</strong>
<small>${escapeHtml(row.review_state || 'unknown')}</small>
</div>
<span>${escapeHtml(row.updated_at || 'pending')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未執行只讀查詢或查無 row。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">MISMATCH</p>
<div class="market-intel-check-list">${
mismatches.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.dedupe_key || 'unknown')}</strong>
<small>${escapeHtml(item.expected_review_state || 'none')} / ${escapeHtml(item.actual_review_state || 'none')}</small>
</div>
<span>CHECK</span>
</div>
`).join('') || '<div class="market-intel-empty">目前沒有 state mismatch。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionPostwriteSmoke = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review decision writer post-write smoke 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionPostwriteSmokeEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionPostwriteSmoke(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision writer post-write smoke 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionOperatorDrill = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const commands = data.command_sequence || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.operator_drill_ready ? 'yes' : 'no'}`,
`statements=${(data.statement_summary || {}).statement_count || 0}`,
`api_write=${data.api_updates_review_state ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 review_state writer 的人工操作 drillAPI/UI 不讀 token、不執行 CLI、不更新 review_state。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">OPERATOR GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未產生 drill gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMAND ORDER</p>
<div class="market-intel-check-list">${
commands.map(command => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`${command.step}. ${command.key}`)}</strong>
<small>${escapeHtml(command.command_shape || '')}</small>
</div>
<span>${command.executes_database ? 'DB' : 'NO DB'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未產生命令順序。</div>'
}</div>
</div>
</div>
<div class="market-intel-deploy-grid mt-3">
<div>
<p class="market-intel-deploy-section-title">INPUTS</p>
<div class="market-intel-check-list">${
Object.entries(data.input_summaries || {}).map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供輸入摘要。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITE FLAGS</p>
<div class="market-intel-check-list">
${[
['api_executes_cli', data.api_executes_cli],
['api_reads_token', data.api_reads_approval_token],
['api_updates_review_state', data.api_updates_review_state],
['review_state_update_executed', data.review_state_update_executed],
['database_write', data.database_write_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionOperatorDrill = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review decision writer operator drill 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionOperatorDrillEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionOperatorDrill(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision writer operator drill 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionRunPackage = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.package_gates || [];
const manifest = data.payload_manifest || {};
const artifacts = data.required_artifacts || [];
const commands = data.command_bundle || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`package=${data.package_ready ? 'ready' : 'blocked'}`,
`payloads=${manifest.payload_count || 0}`,
`artifact=${data.package_artifact_created ? 'created' : 'preview'}`,
`api_write=${data.api_updates_review_state ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生 review_state writer run package 預覽API/UI 不寫檔、不讀 token、不執行 CLI、不更新 review_state。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">PACKAGE GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未產生 package gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PAYLOAD MANIFEST</p>
<div class="market-intel-check-list">
${[
['payload_count', manifest.payload_count || 0],
['manifest_hash', manifest.manifest_hash || 'none'],
['dedupe_keys', (manifest.dedupe_keys || []).join(', ') || 'none'],
['allowed_next_states', (manifest.allowed_next_states || []).join(', ') || 'none']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
<div class="market-intel-deploy-grid mt-3">
<div>
<p class="market-intel-deploy-section-title">ARTIFACTS</p>
<div class="market-intel-check-list">${
artifacts.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.path_shape || '')}</small>
</div>
<span>${item.created_by_api ? 'API' : 'MANUAL'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 artifact 清單。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMANDS</p>
<div class="market-intel-check-list">${
commands.map(command => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`${command.step}. ${command.key}`)}</strong>
<small>${escapeHtml(command.command_shape || '')}</small>
</div>
<span>${command.executes_database ? 'DB' : 'NO DB'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未產生命令 bundle。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITE FLAGS</p>
<div class="market-intel-check-list">
${[
['api_writes_file', data.api_writes_file],
['api_executes_cli', data.api_executes_cli],
['api_reads_token', data.api_reads_approval_token],
['api_updates_review_state', data.api_updates_review_state],
['database_write', data.database_write_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionRunPackage = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review decision writer run package 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionRunPackageEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionRunPackage(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision writer run package 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionRunReadiness = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const evidence = data.operator_evidence_summary || {};
const packageSummary = data.run_package_summary || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`cli_ready=${data.ready_for_cli_operator_run ? 'yes' : 'no'}`,
`api_update=${data.ready_for_api_review_state_update ? 'yes' : 'no'}`,
`payloads=${packageSummary.payload_count || 0}`,
`paths=${evidence.artifact_path_count || 0}`,
`token_api=${evidence.approval_token_submitted_to_api ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 review_state CLI 更新前的操作員證據API/UI 不讀 token、不執行 CLI、不產檔、不更新 review_state。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">manifest=${escapeHtml((packageSummary.manifest_hash || '').slice(0, 16) || 'none')} / artifacts=${escapeHtml(packageSummary.required_artifact_count || 0)} / commands=${escapeHtml(packageSummary.command_count || 0)}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">READINESS GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 readiness gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">EVIDENCE</p>
<div class="market-intel-check-list">
${[
['review_state_transaction_json_path_recorded', evidence.review_state_transaction_json_path_recorded],
['backup_artifact_path_recorded', evidence.backup_artifact_path_recorded],
['preflight_artifact_path_recorded', evidence.preflight_artifact_path_recorded],
['preflight_only', evidence.operator_confirmed_review_state_preflight_only],
['shell_only_token', evidence.operator_acknowledged_shell_only_token],
['approval_token_submitted_to_api', evidence.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${value ? 'YES' : 'NO'}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITE FLAGS</p>
<div class="market-intel-check-list">
${[
['api_executes_cli', data.api_executes_cli],
['api_reads_token', data.api_reads_approval_token],
['api_updates_review_state', data.api_updates_review_state],
['review_state_update_executed', data.review_state_update_executed],
['database_write', data.database_write_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionRunReadiness = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review decision writer run readiness 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionRunReadinessEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionRunReadiness(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision writer run readiness 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionRunReceipt = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const writer = data.writer_output_summary || {};
const smoke = data.postwrite_smoke_summary || {};
const evidence = data.operator_evidence_summary || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`receipt=${data.receipt_passed ? 'pass' : 'blocked'}`,
`writer=${writer.mode || 'missing'}`,
`smoke=${smoke.postwrite_smoke_passed ? 'pass' : 'blocked'}`,
`api_update=${data.ready_for_api_review_state_update ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 review_state CLI 更新後的 writer output 與 post-write smoke receiptAPI/UI 不讀 token、不執行 CLI、不連 DB、不補更新 review_state。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">expected=${escapeHtml((data.expected_dedupe_keys || []).join(', ') || 'none')} / writer=${escapeHtml((writer.observed_dedupe_keys || []).join(', ') || 'none')} / smoke=${escapeHtml((smoke.found_dedupe_keys || []).join(', ') || 'none')}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">RECEIPT GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 receipt gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITER / SMOKE</p>
<div class="market-intel-check-list">
${[
['writer_committed', writer.database_commit_executed],
['writer_review_state_update', writer.review_state_update_executed],
['writer_dedupe_match', writer.dedupe_keys_match_expected],
['writer_token_key_detected', writer.approval_token_key_detected],
['smoke_read_only', smoke.read_only_query_executed],
['smoke_verified', smoke.review_state_update_verified],
['smoke_state_mismatch', smoke.state_mismatch_count || 0]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARTIFACT EVIDENCE</p>
<div class="market-intel-check-list">
${[
['writer_output_json_path_recorded', evidence.writer_output_json_path_recorded],
['postwrite_smoke_json_path_recorded', evidence.postwrite_smoke_json_path_recorded],
['operator_confirmed_no_token_in_artifacts', evidence.operator_confirmed_no_token_in_artifacts],
['approval_token_submitted_to_api', evidence.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${value ? 'YES' : 'NO'}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionRunReceipt = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review decision writer run receipt 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionRunReceiptEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionRunReceipt(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision writer run receipt 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionRunCloseout = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const receipt = data.receipt_summary || {};
const closeout = data.operator_closeout_summary || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`closeout=${data.closeout_passed ? 'pass' : 'blocked'}`,
`receipt=${receipt.receipt_passed ? 'pass' : 'blocked'}`,
`updates=${receipt.expected_review_state_update_count || 0}`,
`api_update=${data.ready_for_api_review_state_update ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只收尾 review_state writer run closeoutAPI/UI 不讀 token、不執行 CLI、不連 DB、不更新 review_state、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">CLOSEOUT GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 closeout gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RECEIPT SUMMARY</p>
<div class="market-intel-check-list">
${[
['target_operation', receipt.target_operation || 'unknown'],
['receipt_passed', receipt.receipt_passed],
['safe_boundaries_complete', receipt.safe_boundaries_complete],
['writer_review_state_update', receipt.writer_review_state_update_executed],
['smoke_review_state_verified', receipt.postwrite_smoke_review_state_verified],
['api_updates_review_state', receipt.api_updates_review_state]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR CLOSEOUT</p>
<div class="market-intel-check-list">
${[
['closeout_artifact_path_recorded', closeout.closeout_artifact_path_recorded],
['review_state_closeout_next', closeout.operator_confirmed_review_state_closeout_next],
['inventory_read_only', closeout.operator_confirmed_post_closeout_inventory_read_only],
['no_scheduler_attach', closeout.operator_confirmed_no_scheduler_attach],
['no_api_db_write', closeout.operator_confirmed_no_api_db_write],
['approval_token_submitted_to_api', closeout.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${value ? 'YES' : 'NO'}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionRunCloseout = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">收尾 queue review decision writer run closeout 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionRunCloseoutEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionRunCloseout(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision writer run closeout 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionPostCloseoutInventory = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const closeout = data.closeout_summary || {};
const smoke = data.postwrite_smoke_summary || {};
const table = data.alert_review_queue_table || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`inventory=${data.post_closeout_inventory_ready ? 'pass' : 'blocked'}`,
`closeout=${closeout.closeout_passed ? 'pass' : 'blocked'}`,
`query=${data.read_only_query_executed ? 'yes' : 'no'}`,
`api_update=${data.ready_for_api_review_state_update ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 review_state closeout 後的只讀 inventory / smokeAPI/UI 不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">expected=${escapeHtml((data.expected_dedupe_keys || []).join(', ') || 'none')} / found=${escapeHtml((data.found_dedupe_keys || []).join(', ') || 'none')} / missing=${escapeHtml((data.missing_dedupe_keys || []).join(', ') || 'none')}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">INVENTORY GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 inventory gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">READ-ONLY RESULT</p>
<div class="market-intel-check-list">
${[
['table_exists', table.exists],
['table_rows', table.row_count == null ? 'n/a' : table.row_count],
['smoke_passed', smoke.postwrite_smoke_passed],
['review_state_verified', smoke.review_state_update_verified],
['state_mismatch_count', smoke.state_mismatch_count || 0],
['db_write', data.database_write_executed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ROW SNAPSHOT</p>
<div class="market-intel-check-list">${
(data.row_summaries || []).slice(0, 6).map(row => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(row.dedupe_key || 'unknown')}</strong>
<small>${escapeHtml(row.review_state || 'unknown')} / score=${escapeHtml(row.total_score == null ? 'n/a' : row.total_score)}</small>
</div>
<span>${escapeHtml(row.priority_lane || 'ROW')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未載入 row snapshot。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionPostCloseoutInventory = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review decision post-closeout inventory 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionPostCloseoutInventoryEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionPostCloseoutInventory(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision post-closeout inventory 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewCompletionArchive = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const manifest = data.archive_manifest || {};
const inventory = manifest.inventory || {};
const artifactPaths = manifest.artifact_paths || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`archive=${data.review_completion_archive_ready ? 'pass' : 'blocked'}`,
`manifest=${data.archive_manifest_ready ? 'ready' : 'draft'}`,
`rows=${data.row_summary_count || 0}`,
`api_write=${data.ready_for_api_database_write ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 review completion archive manifestAPI/UI 不寫檔、不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">ARCHIVE GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 archive gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">MANIFEST</p>
<div class="market-intel-check-list">
${[
['expected_keys', inventory.expected_dedupe_key_count || 0],
['found_keys', inventory.found_dedupe_key_count || 0],
['missing_keys', inventory.missing_dedupe_key_count || 0],
['row_snapshot', inventory.row_summary_count || 0],
['state_mismatch', inventory.state_mismatch_count || 0],
['archive_file_written', data.archive_file_written]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARTIFACT PATHS</p>
<div class="market-intel-check-list">
${Object.entries(artifactPaths).map(([key, value]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(key)}</strong>
<small>${escapeHtml(value || 'missing')}</small>
</div>
<span>${value ? 'SET' : 'MISS'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 artifact path。</div>'}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewCompletionArchive = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review completion archive 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewCompletionArchiveEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewCompletionArchive(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review completion archive 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewArchiveSummary = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const sections = data.summary_sections || [];
const artifactPaths = data.artifact_paths || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`summary=${data.archive_summary_ready ? 'ready' : 'blocked'}`,
`llm=${data.llm_call_executed ? 'called' : 'blocked'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`,
`rows=${data.row_summary_count || 0}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 archive summary inputAPI/UI 不呼叫 LLM、不派送 Telegram、不寫檔、不讀 token、不執行 CLI、不更新 review_state、不寫 DB、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">SUMMARY GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 summary gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">SUMMARY SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(section => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(section.key || 'section')}</strong>
<small>${escapeHtml((section.facts || []).join(' / '))}</small>
</div>
<span>INPUT</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未產生 summary section。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['ai_summary_generated', data.ai_summary_generated],
['llm_call_executed', data.llm_call_executed],
['telegram_dispatched', data.telegram_dispatched],
['summary_file_written', data.summary_file_written],
['database_write_executed', data.database_write_executed],
['archive_summary_path', artifactPaths.archive_summary_artifact_path || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewArchiveSummary = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review archive summary 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewArchiveSummaryEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewArchiveSummary(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review archive summary 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPreflight = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const routePolicy = data.model_route_policy || {};
const cascade = routePolicy.primary_cascade || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`preflight=${data.ai_summary_preflight_ready ? 'ready' : 'blocked'}`,
`manual_ollama=${data.ready_for_manual_ollama_summary_run ? 'ready' : 'blocked'}`,
`llm=${data.llm_call_executed ? 'called' : 'blocked'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 AI summary preflight後續摘要必須 Ollama-firstGemini 只能在 Ollama cascade 全失敗後備援。API/UI 不呼叫模型、不派送 Telegram、不寫檔、不讀 token、不寫 DB、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">PREFLIGHT GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 preflight gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">MODEL ROUTE</p>
<div class="market-intel-check-list">
${[
['primary_policy', routePolicy.primary_policy || 'missing'],
['fallback_policy', routePolicy.fallback_policy || 'missing'],
['forbidden_node', routePolicy.app_host_forbidden_as_ollama_node || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
${cascade.map(node => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(node.label || node.key || 'ollama')}</strong>
<small>${escapeHtml(node.host || '')}</small>
</div>
<span>OLLAMA</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['ready_for_ai_summary_generation', data.ready_for_ai_summary_generation],
['ready_for_llm_call', data.ready_for_llm_call],
['ready_for_telegram_dispatch', data.ready_for_telegram_dispatch],
['ai_summary_generated', data.ai_summary_generated],
['llm_call_executed', data.llm_call_executed],
['ollama_call_executed', data.ollama_call_executed],
['gemini_call_executed', data.gemini_call_executed],
['telegram_dispatched', data.telegram_dispatched],
['summary_file_written', data.summary_file_written],
['database_write_executed', data.database_write_executed],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPreflight = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary preflight 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewAiSummaryPreflightEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPreflight(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary preflight 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryRunPackage = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const prompt = data.prompt_contract || {};
const schema = data.summary_output_schema || {};
const routePolicy = data.model_route_policy || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`package=${data.ai_summary_run_package_ready ? 'ready' : 'blocked'}`,
`manual_ollama=${data.ready_for_manual_ollama_summary_run ? 'ready' : 'blocked'}`,
`llm=${data.llm_call_executed ? 'called' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生手動 Ollama 摘要任務包 contractAPI/UI 不呼叫模型、不寫 run package、不派送 Telegram、不更新 review_state、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">RUN PACKAGE GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 run package gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMPT CONTRACT</p>
<div class="market-intel-check-list">
${[
['contract', prompt.contract_version || 'missing'],
['language', prompt.language || 'missing'],
['primary_policy', routePolicy.primary_policy || 'missing'],
['fallback_policy', routePolicy.fallback_policy || 'missing'],
['schema', schema.schema_version || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['ready_for_ai_summary_generation', data.ready_for_ai_summary_generation],
['api_executes_llm', data.api_executes_llm],
['llm_call_executed', data.llm_call_executed],
['ollama_call_executed', data.ollama_call_executed],
['gemini_call_executed', data.gemini_call_executed],
['telegram_dispatched', data.telegram_dispatched],
['run_package_file_written', data.run_package_file_written],
['summary_file_written', data.summary_file_written],
['database_write_executed', data.database_write_executed],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryRunPackage = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review AI summary run package 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewAiSummaryRunPackageEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryRunPackage(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary run package 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryOutputReceipt = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const validation = data.summary_output_validation || {};
const routePolicy = data.model_route_policy || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`receipt=${data.ai_summary_output_receipt_ready ? 'ready' : 'blocked'}`,
`schema=${data.summary_output_schema_valid ? 'pass' : 'blocked'}`,
`refs=${data.summary_output_evidence_refs_grounded ? 'pass' : 'blocked'}`,
`llm=${data.llm_call_executed ? 'called' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只驗收人工 Ollama 摘要輸出API/UI 不呼叫模型、不寫 receipt、不派送 Telegram、不更新 review_state、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">RECEIPT GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 output receipt gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OUTPUT VALIDATION</p>
<div class="market-intel-check-list">
${[
['missing_fields', (validation.missing_fields || []).join(', ') || 'none'],
['empty_fields', (validation.empty_fields || []).join(', ') || 'none'],
['evidence_refs', (validation.evidence_refs || []).join(', ') || 'none'],
['route_accepted', validation.model_route_accepted],
['primary_policy', routePolicy.primary_policy || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['api_executes_llm', data.api_executes_llm],
['llm_call_executed', data.llm_call_executed],
['ollama_call_executed', data.ollama_call_executed],
['gemini_call_executed', data.gemini_call_executed],
['telegram_dispatched', data.telegram_dispatched],
['summary_receipt_file_written', data.summary_receipt_file_written],
['summary_file_written', data.summary_file_written],
['database_write_executed', data.database_write_executed],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryOutputReceipt = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">驗收 queue review AI summary output receipt 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewAiSummaryOutputReceiptEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryOutputReceipt(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary output receipt 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistencePreflight = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const contract = data.summary_persistence_contract || {};
const record = data.summary_record_preview || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`preflight=${data.summary_persistence_preflight_ready ? 'ready' : 'blocked'}`,
`transaction=${data.ready_for_summary_transaction_preview ? 'ready' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 AI summary persistence preflight後續若要落地 metadata_json 必須另開 transaction preview 與 CLI-only writer gate。API/UI 不寫 DB、不派送 Telegram、不呼叫模型。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">PERSISTENCE GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 persistence preflight gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">TARGET CONTRACT</p>
<div class="market-intel-check-list">
${[
['target_table', contract.target_table || 'missing'],
['target_column', contract.target_column || 'missing'],
['json_path', (contract.target_json_path || []).join('.') || 'missing'],
['planned_updates', contract.planned_update_count || 0],
['api_write_allowed', contract.api_write_allowed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">SUMMARY RECORD</p>
<div class="market-intel-check-list">
${[
['payload_hash', record.payload_hash || 'missing'],
['headline', record.headline || 'missing'],
['findings', record.key_finding_count || 0],
['risks', record.risk_flag_count || 0],
['actions', record.recommended_action_count || 0],
['evidence_refs', (record.evidence_refs || []).join(', ') || 'none']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['api_executes_llm', data.api_executes_llm],
['llm_call_executed', data.llm_call_executed],
['telegram_dispatched', data.telegram_dispatched],
['summary_persistence_preflight_file_written', data.summary_persistence_preflight_file_written],
['summary_persistence_record_written', data.summary_persistence_record_written],
['metadata_patch_written', data.metadata_patch_written],
['database_write_executed', data.database_write_executed],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistencePreflight = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary persistence preflight 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewAiSummaryPersistencePreflightEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistencePreflight(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary persistence preflight 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTransaction = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const summary = data.transaction_summary || {};
const statements = data.statements || [];
const rollback = data.rollback_plan || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`transaction=${data.summary_persistence_transaction_ready ? 'ready' : 'blocked'}`,
`statements=${data.statement_count || 0}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生 AI summary persistence transaction preview正式 metadata_json 寫入必須另開 CLI writer gate。API/UI 不開 DB、不寫檔、不派送 Telegram、不呼叫模型。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">TRANSACTION GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 transaction gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">SUMMARY</p>
<div class="market-intel-check-list">
${[
['target_table', summary.target_table || 'missing'],
['target_column', summary.target_column || 'missing'],
['metadata_key', summary.metadata_key || 'missing'],
['statement_count', summary.statement_count || 0],
['api_write_allowed', summary.api_write_allowed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">STATEMENTS</p>
<div class="market-intel-check-list">${
statements.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.statement_type || 'UPDATE')}</strong>
<small>${escapeHtml((item.where && item.where.dedupe_key) || 'missing')}</small>
</div>
<span>${item.execute_in_api ? 'WRITE' : 'PREVIEW'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未產生 statement preview。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ROLLBACK</p>
<div class="market-intel-check-list">${
rollback.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.required ? 'REQUIRED' : 'OPTIONAL'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 rollback plan。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTransaction = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review AI summary persistence transaction preview 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewAiSummaryPersistenceTransactionEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTransaction(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary persistence transaction 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceWriterPreflight = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const contract = data.writer_preflight_contract || {};
const statements = data.statement_payloads || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`preflight=${data.summary_persistence_writer_preflight_ready ? 'ready' : 'blocked'}`,
`run_package=${data.ready_for_summary_persistence_run_package ? 'ready' : 'blocked'}`,
`statements=${data.statement_count || 0}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 AI summary persistence writer preflight正式 metadata_json 寫入仍需未來 CLI-only run package。API/UI 不讀 token、不執行 CLI、不開 DB、不寫檔、不派送 Telegram。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">WRITER PREFLIGHT GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 writer preflight gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITER CONTRACT</p>
<div class="market-intel-check-list">
${[
['target_table', contract.target_table || 'missing'],
['target_column', contract.target_column || 'missing'],
['json_path', (contract.target_json_path || []).join('.') || 'missing'],
['manual_cli_required', contract.manual_cli_required],
['api_write_allowed', contract.api_write_allowed],
['backup_required', contract.requires_metadata_json_backup],
['postwrite_smoke', contract.requires_postwrite_smoke]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">STATEMENT PAYLOADS</p>
<div class="market-intel-check-list">${
statements.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.statement_type || 'UPDATE')}</strong>
<small>${escapeHtml(item.dedupe_key || 'missing')}</small>
</div>
<span>${item.execute_in_api ? 'WRITE' : 'CLI'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未載入 statement payload。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['api_executes_cli', data.api_executes_cli],
['api_reads_approval_token', data.api_reads_approval_token],
['api_writes_database', data.api_writes_database],
['summary_persistence_writer_preflight_file_written', data.summary_persistence_writer_preflight_file_written],
['database_connection_opened', data.database_connection_opened],
['database_write_executed', data.database_write_executed],
['telegram_dispatched', data.telegram_dispatched],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceWriterPreflight = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary persistence writer preflight 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewAiSummaryPersistenceWriterPreflightEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceWriterPreflight(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary persistence writer preflight 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceRunPackage = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.package_gates || [];
const manifest = data.payload_manifest || {};
const artifacts = data.required_artifacts || [];
const commands = data.command_bundle || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`package=${data.package_ready ? 'ready' : 'blocked'}`,
`readiness=${data.ready_for_summary_persistence_run_readiness ? 'ready' : 'blocked'}`,
`payloads=${manifest.payload_count || 0}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生 AI summary persistence run package preview正式 metadata_json 寫入仍需後續 operator readiness 與 CLI receipt。API/UI 不讀 token、不執行 CLI、不開 DB、不寫檔、不派送 Telegram。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">PACKAGE GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 run package gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PAYLOAD MANIFEST</p>
<div class="market-intel-check-list">
${[
['payload_count', manifest.payload_count || 0],
['manifest_hash', manifest.manifest_hash || 'missing'],
['summary_hash', manifest.summary_payload_hash || 'missing'],
['dedupe_keys', (manifest.dedupe_keys || []).join(', ') || 'none']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">REQUIRED ARTIFACTS</p>
<div class="market-intel-check-list">${
artifacts.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.path_shape || '')}</small>
</div>
<span>${item.created_by_api ? 'API' : 'OPERATOR'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未列出 artifacts。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMAND BUNDLE</p>
<div class="market-intel-check-list">${
commands.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.command_shape || '')}</small>
</div>
<span>${item.executed ? 'EXECUTED' : item.executes_database ? 'CLI DB' : 'PREP'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 command bundle。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['api_executes_cli', data.api_executes_cli],
['api_reads_approval_token', data.api_reads_approval_token],
['api_writes_database', data.api_writes_database],
['package_artifact_created', data.package_artifact_created],
['summary_persistence_run_package_file_written', data.summary_persistence_run_package_file_written],
['database_connection_opened', data.database_connection_opened],
['database_write_executed', data.database_write_executed],
['telegram_dispatched', data.telegram_dispatched],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceRunPackage = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review AI summary persistence run package 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewAiSummaryPersistenceRunPackageEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceRunPackage(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary persistence run package 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceRunReadiness = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const summary = data.run_package_summary || {};
const operator = data.operator_ai_summary_persistence_run_readiness || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`readiness=${data.run_readiness_ready ? 'ready' : 'blocked'}`,
`payloads=${summary.payload_count || 0}`,
`operator_artifacts=${operator.artifact_path_count || 0}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 AI summary persistence operator readinessAPI/UI 不讀 token、不執行 CLI、不開 DB、不寫 metadata_json、不派送 Telegram。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">READINESS GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 readiness gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PACKAGE SUMMARY</p>
<div class="market-intel-check-list">
${[
['package_ready', summary.package_ready],
['payload_count', summary.payload_count || 0],
['command_count', summary.command_count || 0],
['writer_command_present', summary.writer_command_present],
['manifest_hash', summary.manifest_hash || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR EVIDENCE</p>
<div class="market-intel-check-list">
${[
['run_package_path', operator.ai_summary_persistence_run_package_artifact_path || 'missing'],
['writer_preflight_path', operator.ai_summary_persistence_writer_preflight_artifact_path || 'missing'],
['backup_path', operator.metadata_json_backup_artifact_path || 'missing'],
['postwrite_smoke_path', operator.ai_summary_persistence_postwrite_smoke_artifact_path || 'missing'],
['token_submitted_to_api', operator.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['api_executes_cli', data.api_executes_cli],
['api_reads_approval_token', data.api_reads_approval_token],
['api_writes_database', data.api_writes_database],
['run_readiness_file_written', data.run_readiness_file_written],
['database_connection_opened', data.database_connection_opened],
['database_write_executed', data.database_write_executed],
['telegram_dispatched', data.telegram_dispatched],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceRunReadiness = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary persistence run readiness 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceRunReadinessEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceRunReadiness(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary persistence run readiness 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceRunReceipt = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const readiness = data.run_readiness_summary || {};
const writer = data.writer_output_summary || {};
const smoke = data.postwrite_smoke_summary || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`receipt=${data.run_receipt_passed ? 'passed' : 'blocked'}`,
`closeout=${data.ready_for_summary_persistence_closeout ? 'ready' : 'blocked'}`,
`statements=${data.statement_count || 0}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 AI summary persistence CLI 寫入後的回執API/UI 不讀 token、不執行 CLI、不開 DB、不寫 metadata_json、不派送 Telegram。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">RECEIPT GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 receipt gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUN READINESS</p>
<div class="market-intel-check-list">
${[
['run_ready', readiness.ready_for_cli_operator_run],
['payload_count', readiness.payload_count || 0],
['expected_keys', (readiness.expected_dedupe_keys || []).join(', ') || 'none'],
['summary_hash', readiness.expected_summary_payload_hash || 'missing'],
['commands_executed', readiness.commands_executed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITER OUTPUT</p>
<div class="market-intel-check-list">
${[
['provided', writer.provided],
['mode', writer.mode || 'missing'],
['metadata_update', writer.metadata_json_update_executed],
['dedupe_match', writer.dedupe_keys_match_expected],
['hash_match', writer.summary_payload_hash_matches_expected],
['token_key', writer.approval_token_key_detected]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">POST-WRITE SMOKE</p>
<div class="market-intel-check-list">
${[
['provided', smoke.provided],
['mode', smoke.mode || 'missing'],
['read_only', smoke.read_only_query_executed],
['metadata_verified', smoke.metadata_json_update_verified],
['dedupe_match', smoke.dedupe_keys_match_expected],
['db_write', smoke.database_write_executed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['api_executes_cli', data.api_executes_cli],
['api_reads_approval_token', data.api_reads_approval_token],
['api_writes_database', data.api_writes_database],
['run_receipt_file_written', data.run_receipt_file_written],
['database_connection_opened', data.database_connection_opened],
['database_write_executed', data.database_write_executed],
['telegram_dispatched', data.telegram_dispatched],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceRunReceipt = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary persistence run receipt 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceRunReceiptEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceRunReceipt(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary persistence run receipt 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceRunCloseout = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const receipt = data.receipt_summary || {};
const operator = data.operator_closeout_summary || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`closeout=${data.closeout_passed ? 'passed' : 'blocked'}`,
`telegram_gate=${data.ready_for_summary_persistence_telegram_dispatch_gate ? 'ready' : 'blocked'}`,
`statements=${data.statement_count || 0}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只收尾 AI summary persistence receipt後續 Telegram dispatch 必須另開 gate。API/UI 不讀 token、不執行 CLI、不開 DB、不寫 metadata_json、不派送 Telegram。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">CLOSEOUT GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 closeout gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RECEIPT SUMMARY</p>
<div class="market-intel-check-list">
${[
['receipt_passed', receipt.receipt_passed],
['closeout_ready', receipt.ready_for_summary_persistence_closeout],
['expected_keys', receipt.expected_dedupe_key_count || 0],
['writer_metadata', receipt.writer_metadata_json_update_executed],
['smoke_verified', receipt.postwrite_smoke_metadata_json_verified],
['safe_boundaries', receipt.safe_boundaries_complete]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR CLOSEOUT</p>
<div class="market-intel-check-list">
${[
['closeout_artifact', operator.closeout_artifact_path_recorded],
['closeout_confirmed', operator.operator_confirmed_summary_persistence_closeout],
['telegram_separate_gate', operator.operator_confirmed_telegram_dispatch_requires_separate_gate],
['no_api_db_write', operator.operator_confirmed_no_api_db_write],
['no_telegram_dispatch', operator.operator_confirmed_no_telegram_dispatch],
['token_submitted', operator.approval_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['allowed', promotion.allowed],
['next_phase', promotion.next_manual_phase || 'blocked'],
['requires_real_db_write', promotion.requires_real_db_write],
['requires_scheduler_attach', promotion.requires_scheduler_attach],
['telegram_separate_gate', promotion.telegram_dispatch_requires_separate_gate]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['api_executes_cli', data.api_executes_cli],
['api_reads_approval_token', data.api_reads_approval_token],
['api_writes_database', data.api_writes_database],
['closeout_file_written', data.closeout_file_written],
['database_connection_opened', data.database_connection_opened],
['database_write_executed', data.database_write_executed],
['telegram_dispatched', data.telegram_dispatched],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceRunCloseout = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">收尾 queue review AI summary persistence run closeout 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceRunCloseoutEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceRunCloseout(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary persistence run closeout 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchGate = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const closeout = data.closeout_summary || {};
const operator = data.operator_telegram_dispatch_gate_summary || {};
const contract = data.telegram_message_contract || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`dispatch_gate=${data.telegram_dispatch_gate_passed ? 'passed' : 'blocked'}`,
`run_package=${data.ready_for_summary_persistence_telegram_dispatch_run_package ? 'ready' : 'blocked'}`,
`statements=${data.statement_count || 0}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 AI summary Telegram dispatch gateAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不派送 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">DISPATCH GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 dispatch gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CLOSEOUT SOURCE</p>
<div class="market-intel-check-list">
${[
['closeout_passed', closeout.closeout_passed],
['telegram_gate_ready', closeout.ready_for_summary_persistence_telegram_dispatch_gate],
['expected_keys', closeout.expected_dedupe_key_count || 0],
['summary_hash', closeout.expected_summary_payload_hash || 'missing'],
['metadata_smoke', closeout.postwrite_smoke_metadata_json_verified],
['safe_boundaries', closeout.safe_boundaries_complete]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">MESSAGE CONTRACT</p>
<div class="market-intel-check-list">
${[
['source', `${contract.source_column || 'metadata'}:${(contract.source_json_path || []).join('.')}`],
['channel', contract.target_channel || 'manual_gate'],
['format', contract.message_format || 'unknown'],
['max_chars', contract.max_message_chars || 0],
['evidence_refs', contract.requires_evidence_refs],
['api_dispatches', contract.api_dispatches_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR GATE</p>
<div class="market-intel-check-list">
${[
['artifact_path', operator.telegram_dispatch_gate_artifact_path_recorded],
['dispatch_gate', operator.operator_confirmed_summary_persistence_telegram_dispatch_gate],
['message_reviewed', operator.operator_confirmed_telegram_message_reviewed],
['manual_run_package', operator.operator_confirmed_dispatch_requires_manual_run_package],
['channel_label', operator.telegram_channel_label_recorded],
['token_submitted', operator.forbidden_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION / NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['allowed', promotion.allowed],
['next_phase', promotion.next_manual_phase || 'blocked'],
['ready_for_telegram_dispatch', data.ready_for_telegram_dispatch],
['api_dispatches_telegram', data.api_dispatches_telegram],
['telegram_dispatched', data.telegram_dispatched],
['database_write_executed', data.database_write_executed],
['scheduler_attached', data.scheduler_attached],
['dispatch_gate_file_written', data.telegram_dispatch_gate_file_written]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchGate = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary Telegram dispatch gate 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchGateEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchGate(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch gate 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunPackage = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.package_gates || [];
const manifest = data.message_package_manifest || {};
const gate = data.telegram_dispatch_gate_summary || {};
const operator = data.operator_telegram_dispatch_run_package || {};
const commands = data.command_bundle || [];
const artifacts = data.required_artifacts || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`package=${data.telegram_dispatch_run_package_ready ? 'ready' : 'blocked'}`,
`readiness=${data.ready_for_summary_persistence_telegram_dispatch_run_readiness ? 'ready' : 'blocked'}`,
`commands=${commands.length}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生 AI summary Telegram dispatch run package previewAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不派送 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">PACKAGE GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 package gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">MESSAGE MANIFEST</p>
<div class="market-intel-check-list">
${[
['channel', manifest.target_channel || 'manual_gate'],
['format', manifest.message_format || 'unknown'],
['dedupe_keys', manifest.expected_dedupe_key_count || 0],
['summary_hash', manifest.expected_summary_payload_hash || 'missing'],
['manifest_hash', manifest.manifest_hash || 'missing'],
['api_dispatches', manifest.api_dispatches_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMAND PLAN</p>
<div class="market-intel-check-list">
${commands.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`${item.step}. ${item.key}`)}</strong>
<small>${escapeHtml(item.command_shape || '')}</small>
</div>
<span>${item.executed ? 'DONE' : (item.executes_telegram ? 'MANUAL' : 'PLAN')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 command bundle。</div>'}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARTIFACTS</p>
<div class="market-intel-check-list">
${artifacts.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.path_shape || '')}</small>
</div>
<span>${item.created_by_api ? 'API' : 'OPERATOR'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 artifact checklist。</div>'}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">SOURCE / NO-SIDE-EFFECTS</p>
<div class="market-intel-check-list">
${[
['gate_passed', gate.telegram_dispatch_gate_passed],
['gate_side_effects_clear', gate.side_effects_clear],
['operator_package', operator.operator_confirmed_ai_summary_telegram_dispatch_run_package],
['manual_only', operator.operator_confirmed_dispatch_is_manual_only],
['ready_for_telegram_dispatch', data.ready_for_telegram_dispatch],
['api_dispatches_telegram', data.api_dispatches_telegram],
['run_package_file_written', data.telegram_dispatch_run_package_file_written],
['telegram_dispatched', data.telegram_dispatched],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunPackage = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review AI summary Telegram dispatch run package 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunPackageEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunPackage(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch run package 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReadiness = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const packageSummary = data.telegram_dispatch_run_package_summary || {};
const operator = data.operator_telegram_dispatch_run_readiness || {};
const boundary = data.manual_dispatch_boundary || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`readiness=${data.telegram_dispatch_run_readiness_ready ? 'ready' : 'blocked'}`,
`manual=${data.ready_for_manual_telegram_dispatch ? 'ready' : 'blocked'}`,
`receipt=${data.ready_for_summary_persistence_telegram_dispatch_run_receipt ? 'ready' : 'blocked'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查人工 Telegram dispatch readinessAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不派送 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">READINESS GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 readiness gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUN PACKAGE</p>
<div class="market-intel-check-list">
${[
['package_ready', packageSummary.package_ready],
['channel', packageSummary.target_channel || 'manual_gate'],
['format', packageSummary.message_format || 'unknown'],
['dedupe_keys', packageSummary.expected_dedupe_key_count || 0],
['summary_hash', packageSummary.expected_summary_payload_hash || 'missing'],
['manual_command', packageSummary.manual_dispatch_command_present],
['commands_executed', packageSummary.commands_executed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR EVIDENCE</p>
<div class="market-intel-check-list">
${[
['artifact_paths', operator.artifact_path_count || 0],
['run_readiness', operator.operator_confirmed_ai_summary_telegram_dispatch_run_readiness],
['message_preview', operator.operator_confirmed_message_preview_reviewed],
['manual_command', operator.operator_confirmed_manual_dispatch_command_reviewed],
['token_shell_only', operator.operator_confirmed_telegram_token_shell_only],
['receipt_required', operator.operator_confirmed_dispatch_receipt_required],
['token_leak', operator.forbidden_token_submitted_to_api]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">MANUAL BOUNDARY</p>
<div class="market-intel-check-list">
${[
['api_may_dispatch_telegram', boundary.api_may_dispatch_telegram],
['operator_shell_required', boundary.operator_shell_required],
['telegram_token_shell_only', boundary.telegram_token_shell_only],
['requires_message_preview_review', boundary.requires_message_preview_review],
['requires_dispatch_receipt', boundary.requires_dispatch_receipt],
['api_dispatches_telegram', data.api_dispatches_telegram],
['telegram_dispatched', data.telegram_dispatched],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReadiness = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary Telegram dispatch run readiness 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReadinessEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReadiness(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch run readiness 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReceipt = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const readiness = data.telegram_dispatch_run_readiness_summary || {};
const receipt = data.telegram_dispatch_receipt_summary || {};
const operator = data.operator_telegram_dispatch_run_receipt || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`receipt=${data.telegram_dispatch_run_receipt_passed ? 'passed' : 'blocked'}`,
`closeout=${data.ready_for_summary_persistence_telegram_dispatch_closeout ? 'ready' : 'blocked'}`,
`message=${receipt.message_id || 'missing'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核人工 Telegram dispatch receiptAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">RECEIPT GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 receipt gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUN READINESS</p>
<div class="market-intel-check-list">
${[
['readiness_ready', readiness.run_readiness_ready],
['manual_dispatch', readiness.ready_for_manual_telegram_dispatch],
['channel', readiness.target_channel || 'manual_gate'],
['format', readiness.message_format || 'unknown'],
['dedupe_keys', readiness.expected_dedupe_key_count || 0],
['summary_hash', readiness.expected_summary_payload_hash || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">TELEGRAM RECEIPT</p>
<div class="market-intel-check-list">
${[
['provided', receipt.provided],
['mode', receipt.mode || 'missing'],
['ok', receipt.ok],
['message_id', receipt.message_id || 'missing'],
['chat_id', receipt.chat_id || 'missing'],
['channel', receipt.telegram_channel_label || 'missing'],
['hash_match', receipt.summary_payload_hash_matches_expected],
['token_key_detected', receipt.approval_or_telegram_token_key_detected]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR / API BOUNDARY</p>
<div class="market-intel-check-list">
${[
['receipt_artifact', operator.telegram_dispatch_receipt_artifact_path_recorded],
['message_preview', operator.telegram_message_preview_artifact_path_recorded],
['operator_receipt', operator.operator_confirmed_telegram_dispatch_receipt],
['message_id_recorded', operator.operator_confirmed_message_id_recorded],
['no_token', operator.operator_confirmed_no_token_in_receipt],
['api_dispatches_telegram', data.api_dispatches_telegram],
['telegram_dispatched_by_api', data.telegram_dispatched],
['scheduler_attached', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReceipt = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary Telegram dispatch run receipt 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReceiptEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReceipt(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch run receipt 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchCloseout = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const receipt = data.telegram_dispatch_run_receipt_summary || {};
const operator = data.operator_telegram_dispatch_closeout || {};
const audit = data.dispatch_audit_summary || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`closeout=${data.telegram_dispatch_closeout_passed ? 'passed' : 'blocked'}`,
`archive=${data.ready_for_summary_persistence_telegram_dispatch_archive ? 'ready' : 'blocked'}`,
`message=${audit.message_id || 'missing'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理人工 Telegram dispatch closeoutAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">CLOSEOUT GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 closeout gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUN RECEIPT</p>
<div class="market-intel-check-list">
${[
['provided', receipt.provided],
['mode', receipt.mode || 'missing'],
['receipt_passed', receipt.receipt_passed],
['ready_closeout', receipt.ready_for_summary_persistence_telegram_dispatch_closeout],
['message_id', receipt.message_id || 'missing'],
['channel', receipt.telegram_channel_label || 'missing'],
['hash_match', receipt.summary_payload_hash_matches_expected],
['safe_boundaries', receipt.safe_boundaries_complete]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">DISPATCH AUDIT</p>
<div class="market-intel-check-list">
${[
['manual_dispatch_proven', audit.manual_dispatch_proven],
['api_dispatch_blocked', audit.api_dispatch_blocked],
['duplicate_ruled_out', audit.duplicate_dispatch_ruled_out],
['receipt_archived', audit.receipt_archived],
['monitoring', audit.post_closeout_monitoring_confirmed],
['chat_id', audit.chat_id || 'missing'],
['summary_hash', audit.summary_payload_hash || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR CLOSEOUT</p>
<div class="market-intel-check-list">
${[
['closeout_artifact', operator.telegram_dispatch_closeout_artifact_path_recorded],
['receipt_artifact', operator.telegram_dispatch_receipt_artifact_path_recorded],
['closeout_confirmed', operator.operator_confirmed_telegram_dispatch_closeout],
['receipt_archived', operator.operator_confirmed_receipt_archived],
['message_visible', operator.operator_confirmed_message_visible],
['no_duplicate', operator.operator_confirmed_no_duplicate_dispatch],
['no_token', operator.operator_confirmed_no_token_in_artifacts],
['no_api_dispatch', operator.operator_confirmed_no_api_telegram_dispatch],
['no_db_llm_scheduler', operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchCloseout = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review AI summary Telegram dispatch closeout 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchCloseoutEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchCloseout(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch closeout 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchive = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const closeout = data.telegram_dispatch_closeout_summary || {};
const manifest = data.telegram_dispatch_archive_manifest || {};
const message = manifest.telegram_message || {};
const paths = manifest.artifact_paths || {};
const operator = data.operator_telegram_dispatch_archive || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`archive=${data.telegram_dispatch_archive_ready ? 'ready' : 'blocked'}`,
`manifest=${data.archive_manifest_ready ? 'ready' : 'blocked'}`,
`message=${message.message_id || 'missing'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理人工 Telegram dispatch archive manifestAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">ARCHIVE GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 archive gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CLOSEOUT SUMMARY</p>
<div class="market-intel-check-list">
${[
['provided', closeout.provided],
['mode', closeout.mode || 'missing'],
['closeout_passed', closeout.closeout_passed],
['ready_archive', closeout.ready_for_summary_persistence_telegram_dispatch_archive],
['statement_count', closeout.statement_count || 0],
['side_effects_clear', closeout.side_effects_clear]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARCHIVE MANIFEST</p>
<div class="market-intel-check-list">
${[
['message_id', message.message_id || 'missing'],
['chat_id', message.chat_id || 'missing'],
['channel', message.telegram_channel_label || 'missing'],
['hash_match', message.summary_payload_hash_matches_expected],
['receipt_path', paths.telegram_dispatch_receipt_artifact_path || 'missing'],
['closeout_path', paths.telegram_dispatch_closeout_artifact_path || 'missing'],
['archive_path', paths.telegram_dispatch_archive_artifact_path || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR ARCHIVE</p>
<div class="market-intel-check-list">
${[
['archive_confirmed', operator.operator_confirmed_telegram_dispatch_archive],
['read_only', operator.operator_confirmed_archive_is_read_only],
['receipt_archived', operator.operator_confirmed_receipt_archived],
['message_id_archived', operator.operator_confirmed_message_id_archived],
['audit_archived', operator.operator_confirmed_dispatch_audit_archived],
['monitoring', operator.operator_confirmed_post_closeout_monitoring],
['no_duplicate', operator.operator_confirmed_no_duplicate_dispatch],
['no_token', operator.operator_confirmed_no_token_in_artifacts],
['no_api_dispatch', operator.operator_confirmed_no_api_telegram_dispatch],
['no_db_llm_scheduler', operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchive = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review AI summary Telegram dispatch archive 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchive(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch archive 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveSummary = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const archive = data.telegram_dispatch_archive_summary || {};
const message = archive.message || {};
const audit = archive.dispatch_audit || {};
const operator = data.operator_telegram_dispatch_archive_summary || {};
const sections = data.telegram_dispatch_archive_summary_sections || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`summary=${data.telegram_dispatch_archive_summary_ready ? 'ready' : 'blocked'}`,
`report=${data.ready_for_summary_persistence_telegram_dispatch_report_input ? 'ready' : 'blocked'}`,
`message=${message.message_id || 'missing'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 Telegram dispatch archive summary inputAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">SUMMARY GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 archive summary gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARCHIVE INPUT</p>
<div class="market-intel-check-list">
${[
['provided', archive.provided],
['mode', archive.mode || 'missing'],
['archive_ready', archive.telegram_dispatch_archive_ready],
['manifest_ready', archive.archive_manifest_ready],
['statement_count', archive.statement_count || 0],
['side_effects_clear', archive.side_effects_clear]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">MESSAGE / AUDIT</p>
<div class="market-intel-check-list">
${[
['message_id', message.message_id || 'missing'],
['chat_id', message.chat_id || 'missing'],
['channel', message.telegram_channel_label || 'missing'],
['hash_match', message.summary_payload_hash_matches_expected],
['manual_dispatch', audit.manual_dispatch_proven],
['api_blocked', audit.api_dispatch_blocked],
['duplicate_ruled_out', audit.duplicate_dispatch_ruled_out],
['monitoring', audit.post_closeout_monitoring_confirmed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">SUMMARY SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(section => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(section.key || 'section')}</strong>
<small>${escapeHtml((section.facts || []).join(' / '))}</small>
</div>
<span>INPUT</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 summary sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR SUMMARY</p>
<div class="market-intel-check-list">
${[
['summary_confirmed', operator.operator_confirmed_telegram_dispatch_archive_summary],
['read_only', operator.operator_confirmed_summary_is_read_only],
['artifacts_reviewed', operator.operator_confirmed_message_and_artifacts_reviewed],
['audit_reviewed', operator.operator_confirmed_dispatch_audit_reviewed],
['separate_report_gate', operator.operator_confirmed_report_input_requires_separate_gate],
['no_token', operator.operator_confirmed_no_token_in_artifacts],
['no_api_dispatch', operator.operator_confirmed_no_api_telegram_dispatch],
['no_db_llm_scheduler', operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach],
['summary_path', operator.telegram_dispatch_archive_summary_artifact_path || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveSummary = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review AI summary Telegram dispatch archive summary 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveSummaryEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveSummary(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch archive summary 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportInput = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const summary = data.telegram_dispatch_archive_summary_input || {};
const message = summary.message || {};
const audit = summary.dispatch_audit || {};
const operator = data.operator_telegram_dispatch_report_input || {};
const sections = data.telegram_dispatch_report_input_sections || [];
const contract = data.telegram_dispatch_report_input_contract || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`report_input=${data.telegram_dispatch_report_input_ready ? 'ready' : 'blocked'}`,
`run_package=${data.ready_for_market_intel_report_run_package ? 'ready' : 'blocked'}`,
`message=${message.message_id || 'missing'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 Telegram dispatch report inputAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">REPORT INPUT GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 report input gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARCHIVE SUMMARY INPUT</p>
<div class="market-intel-check-list">
${[
['provided', summary.provided],
['mode', summary.mode || 'missing'],
['summary_ready', summary.telegram_dispatch_archive_summary_ready],
['report_ready', summary.ready_for_summary_persistence_telegram_dispatch_report_input],
['statement_count', summary.statement_count || 0],
['side_effects_clear', summary.side_effects_clear]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">REPORT CONTRACT</p>
<div class="market-intel-check-list">
${[
['contract', contract.contract_version || 'missing'],
['family', contract.target_report_family || 'missing'],
['language', contract.language || 'missing'],
['required_sections', (contract.required_sections || []).join(', ') || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">MESSAGE / AUDIT</p>
<div class="market-intel-check-list">
${[
['message_id', message.message_id || 'missing'],
['chat_id', message.chat_id || 'missing'],
['channel', message.telegram_channel_label || 'missing'],
['hash_match', message.summary_payload_hash_matches_expected],
['manual_dispatch', audit.manual_dispatch_proven],
['api_blocked', audit.api_dispatch_blocked],
['duplicate_ruled_out', audit.duplicate_dispatch_ruled_out],
['monitoring', audit.post_closeout_monitoring_confirmed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">REPORT SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(section => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(section.key || 'section')}</strong>
<small>${escapeHtml((section.facts || []).join(' / '))}</small>
</div>
<span>REPORT</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 report sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR REPORT INPUT</p>
<div class="market-intel-check-list">
${[
['report_confirmed', operator.operator_confirmed_telegram_dispatch_report_input],
['read_only', operator.operator_confirmed_report_input_is_read_only],
['archive_summary_reviewed', operator.operator_confirmed_archive_summary_reviewed],
['sections_reviewed', operator.operator_confirmed_report_sections_reviewed],
['separate_report_gate', operator.operator_confirmed_report_generation_requires_separate_gate],
['no_token', operator.operator_confirmed_no_token_in_report_input],
['no_api_dispatch', operator.operator_confirmed_no_api_telegram_dispatch],
['no_db_llm_scheduler', operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach],
['report_input_path', operator.telegram_dispatch_report_input_artifact_path || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportInput = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review AI summary Telegram dispatch report input 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportInputEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportInput(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report input 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunPackage = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const inputSummary = data.telegram_dispatch_report_input_summary || {};
const evidence = inputSummary.evidence_refs || {};
const runPackage = data.telegram_dispatch_report_run_package || {};
const sections = data.telegram_dispatch_report_run_package_sections || [];
const operator = data.operator_telegram_dispatch_report_run_package || {};
const boundaries = runPackage.execution_boundaries || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`package=${data.telegram_dispatch_report_run_package_ready ? 'ready' : 'blocked'}`,
`readiness=${data.ready_for_market_intel_report_run_readiness ? 'ready' : 'blocked'}`,
`report=${data.ready_for_report_generation ? 'generated' : 'blocked'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 Telegram dispatch report run packageAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">REPORT RUN PACKAGE GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 run package gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">REPORT INPUT SUMMARY</p>
<div class="market-intel-check-list">
${[
['provided', inputSummary.provided],
['mode', inputSummary.mode || 'missing'],
['input_ready', inputSummary.telegram_dispatch_report_input_ready],
['run_package_ready', inputSummary.ready_for_market_intel_report_run_package],
['contract', inputSummary.report_contract_version || 'missing'],
['family', inputSummary.target_report_family || 'missing'],
['statement_count', inputSummary.statement_count || 0],
['side_effects_clear', inputSummary.side_effects_clear]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUN PACKAGE CONTRACT</p>
<div class="market-intel-check-list">
${[
['contract', runPackage.contract_version || 'missing'],
['source_contract', runPackage.source_contract_version || 'missing'],
['family', runPackage.target_report_family || 'missing'],
['language', runPackage.language || 'missing'],
['required_sections', (runPackage.required_package_sections || []).join(', ') || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PACKAGE SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(section => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(section.key || 'section')}</strong>
<small>${escapeHtml((section.facts || []).join(' / '))}</small>
</div>
<span>PACKAGE</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 run package sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">EVIDENCE / BOUNDARY</p>
<div class="market-intel-check-list">
${[
['message_id', evidence.message_id || 'missing'],
['chat_id', evidence.chat_id || 'missing'],
['channel', evidence.telegram_channel_label || 'missing'],
['summary_hash', evidence.summary_payload_hash || 'missing'],
['api_generates_report', boundaries.api_generates_report],
['api_writes_report_file', boundaries.api_writes_report_file],
['api_calls_llm', boundaries.api_calls_llm],
['api_dispatches_telegram', boundaries.api_dispatches_telegram],
['api_writes_database', boundaries.api_writes_database],
['api_attaches_scheduler', boundaries.api_attaches_scheduler]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR PACKAGE</p>
<div class="market-intel-check-list">
${[
['package_confirmed', operator.operator_confirmed_telegram_dispatch_report_run_package],
['read_only', operator.operator_confirmed_report_run_package_is_read_only],
['input_reviewed', operator.operator_confirmed_report_input_reviewed],
['package_reviewed', operator.operator_confirmed_report_package_reviewed],
['readiness_gate', operator.operator_confirmed_report_generation_requires_readiness_gate],
['no_token', operator.operator_confirmed_no_token_in_report_run_package],
['no_api_dispatch', operator.operator_confirmed_no_api_telegram_dispatch],
['no_db_llm_scheduler', operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach],
['package_path', operator.telegram_dispatch_report_run_package_artifact_path || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunPackage = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review AI summary Telegram dispatch report run package 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunPackageEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunPackage(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report run package 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReadiness = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const packageSummary = data.telegram_dispatch_report_run_package_summary || {};
const evidence = packageSummary.evidence_refs || {};
const manifest = data.report_generation_readiness_manifest || {};
const command = manifest.manual_generation_command || {};
const boundaries = manifest.execution_boundaries || {};
const operator = data.operator_telegram_dispatch_report_run_readiness || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`readiness=${data.telegram_dispatch_report_run_readiness_ready ? 'ready' : 'blocked'}`,
`manual_report=${data.ready_for_manual_report_generation ? 'ready' : 'blocked'}`,
`report=${data.ready_for_report_generation ? 'generated' : 'blocked'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 Telegram dispatch report run readinessAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">REPORT RUN READINESS GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 readiness gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUN PACKAGE SUMMARY</p>
<div class="market-intel-check-list">
${[
['provided', packageSummary.provided],
['mode', packageSummary.mode || 'missing'],
['package_ready', packageSummary.telegram_dispatch_report_run_package_ready],
['readiness_ready', packageSummary.ready_for_market_intel_report_run_readiness],
['contract', packageSummary.package_contract_version || 'missing'],
['family', packageSummary.target_report_family || 'missing'],
['statement_count', packageSummary.statement_count || 0],
['side_effects_clear', packageSummary.side_effects_clear]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">READINESS MANIFEST</p>
<div class="market-intel-check-list">
${[
['manifest', manifest.manifest_version || 'missing'],
['source_contract', manifest.source_contract_version || 'missing'],
['family', manifest.target_report_family || 'missing'],
['language', manifest.language || 'missing'],
['intended_artifacts', (manifest.intended_report_artifacts || []).join(', ') || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">MANUAL REPORT COMMAND</p>
<div class="market-intel-check-list">
${[
['key', command.key || 'missing'],
['executes_report_generation', command.executes_report_generation],
['executes_database', command.executes_database],
['executes_telegram', command.executes_telegram],
['executed_by_api', command.executed_by_api],
['command_shape', command.command_shape || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">EVIDENCE / BOUNDARY</p>
<div class="market-intel-check-list">
${[
['message_id', evidence.message_id || 'missing'],
['chat_id', evidence.chat_id || 'missing'],
['channel', evidence.telegram_channel_label || 'missing'],
['summary_hash', evidence.summary_payload_hash || 'missing'],
['api_generates_report', boundaries.api_generates_report],
['api_writes_report_file', boundaries.api_writes_report_file],
['api_calls_llm', boundaries.api_calls_llm],
['api_dispatches_telegram', boundaries.api_dispatches_telegram],
['api_writes_database', boundaries.api_writes_database],
['api_attaches_scheduler', boundaries.api_attaches_scheduler]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR READINESS</p>
<div class="market-intel-check-list">
${[
['readiness_confirmed', operator.operator_confirmed_telegram_dispatch_report_run_readiness],
['package_reviewed', operator.operator_confirmed_report_run_package_reviewed],
['contract_reviewed', operator.operator_confirmed_report_contract_reviewed],
['manual_only', operator.operator_confirmed_report_generation_is_manual_only],
['receipt_required', operator.operator_confirmed_report_output_requires_receipt],
['no_token', operator.operator_confirmed_no_token_in_report_readiness],
['no_api_generation', operator.operator_confirmed_no_api_report_generation],
['no_db_llm_scheduler', operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach],
['readiness_path', operator.telegram_dispatch_report_run_readiness_artifact_path || 'missing'],
['output_path', operator.report_output_artifact_path || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReadiness = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary Telegram dispatch report run readiness 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReadinessEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReadiness(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report run readiness 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReceipt = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const readiness = data.telegram_dispatch_report_run_readiness_summary || {};
const receipt = data.telegram_dispatch_report_run_receipt_summary || {};
const operator = data.operator_telegram_dispatch_report_run_receipt || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`receipt=${data.telegram_dispatch_report_run_receipt_passed ? 'pass' : 'blocked'}`,
`closeout=${data.ready_for_market_intel_report_closeout ? 'ready' : 'blocked'}`,
`report=${data.ready_for_report_generation ? 'generated' : 'blocked'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 Telegram dispatch report run receiptAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">REPORT RUN RECEIPT GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 receipt gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">READINESS SUMMARY</p>
<div class="market-intel-check-list">
${[
['provided', readiness.provided],
['mode', readiness.mode || 'missing'],
['readiness_ready', readiness.telegram_dispatch_report_run_readiness_ready],
['receipt_ready', readiness.ready_for_market_intel_report_run_receipt],
['manual_report', readiness.ready_for_manual_report_generation],
['manifest', readiness.manifest_version || 'missing'],
['family', readiness.target_report_family || 'missing'],
['side_effects_clear', readiness.side_effects_clear]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">REPORT RECEIPT</p>
<div class="market-intel-check-list">
${[
['provided', receipt.provided],
['mode', receipt.mode || 'missing'],
['generated', receipt.report_generated],
['family', receipt.target_report_family || 'missing'],
['language', receipt.language || 'missing'],
['summary_hash_match', receipt.summary_payload_hash_matches_expected],
['sections_present', receipt.required_report_sections_present],
['artifact_path', receipt.report_output_artifact_path || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUNTIME BOUNDARY</p>
<div class="market-intel-check-list">
${[
['generated_by_api', receipt.generated_by_api],
['api_writes_file', receipt.api_writes_file],
['api_calls_llm', receipt.api_calls_llm],
['api_dispatches_telegram', receipt.api_dispatches_telegram],
['api_writes_database', receipt.api_writes_database],
['scheduler_attached', receipt.scheduler_attached],
['token_key_detected', receipt.approval_or_telegram_token_key_detected]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR RECEIPT</p>
<div class="market-intel-check-list">
${[
['package_path', operator.telegram_dispatch_report_run_package_artifact_path_recorded],
['readiness_path', operator.telegram_dispatch_report_run_readiness_artifact_path_recorded],
['output_path', operator.report_output_artifact_path_recorded],
['receipt_path', operator.report_run_receipt_artifact_path_recorded],
['receipt_confirmed', operator.operator_confirmed_report_run_receipt],
['hash_confirmed', operator.operator_confirmed_report_output_hash_matched],
['sections_reviewed', operator.operator_confirmed_report_sections_reviewed],
['no_api_generation', operator.operator_confirmed_no_api_report_generation],
['no_db_llm_scheduler', operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReceipt = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary Telegram dispatch report run receipt 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReceiptEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReceipt(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report run receipt 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCloseout = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const receipt = data.telegram_dispatch_report_run_receipt_summary || {};
const operator = data.operator_telegram_dispatch_report_closeout || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`closeout=${data.telegram_dispatch_report_closeout_passed ? 'pass' : 'blocked'}`,
`archive=${data.ready_for_market_intel_report_archive ? 'ready' : 'blocked'}`,
`report=${data.ready_for_report_generation ? 'generated' : 'blocked'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只收尾 Telegram dispatch report closeoutAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">REPORT CLOSEOUT GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 closeout gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RECEIPT SUMMARY</p>
<div class="market-intel-check-list">
${[
['provided', receipt.provided],
['mode', receipt.mode || 'missing'],
['receipt_passed', receipt.receipt_passed],
['closeout_ready', receipt.ready_for_market_intel_report_closeout],
['family', receipt.target_report_family || 'missing'],
['language', receipt.language || 'missing'],
['report_path', receipt.report_output_artifact_path || 'missing'],
['summary_hash_match', receipt.summary_payload_hash_matches_expected],
['sections_present', receipt.required_report_sections_present]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR CLOSEOUT</p>
<div class="market-intel-check-list">
${[
['closeout_path', operator.report_closeout_artifact_path_recorded],
['receipt_path', operator.report_run_receipt_artifact_path_recorded],
['output_path', operator.report_output_artifact_path_recorded],
['closeout_confirmed', operator.operator_confirmed_report_closeout],
['receipt_archived', operator.operator_confirmed_report_receipt_archived],
['hash_confirmed', operator.operator_confirmed_report_output_hash_matched],
['sections_reviewed', operator.operator_confirmed_report_sections_reviewed],
['archive_separate_gate', operator.operator_confirmed_report_archive_requires_separate_gate],
['no_token_or_runtime_side_effect', operator.operator_confirmed_no_token_in_report_closeout && operator.operator_confirmed_no_api_report_generation && operator.operator_confirmed_no_api_telegram_dispatch && operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUNTIME BOUNDARY</p>
<div class="market-intel-check-list">
${[
['api_writes_file', data.api_writes_file],
['api_calls_llm', data.api_executes_llm],
['api_dispatches_telegram', data.api_dispatches_telegram],
['api_writes_database', data.api_writes_database],
['database_write', data.database_write_executed],
['scheduler_attached', data.scheduler_attached],
['report_file_written', data.report_file_written],
['closeout_file_written', data.report_closeout_file_written]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['allowed', promotion.allowed],
['next_phase', promotion.next_manual_phase || 'missing'],
['requires_operator_approval', promotion.requires_operator_approval],
['archive_separate_gate', promotion.report_archive_requires_separate_gate],
['api_must_not_generate_report', promotion.api_must_not_generate_report],
['api_must_not_dispatch_telegram', promotion.api_must_not_dispatch_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCloseout = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">收尾 queue review AI summary Telegram dispatch report closeout 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCloseoutEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCloseout(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report closeout 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchive = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const closeout = data.telegram_dispatch_report_closeout_summary || {};
const operator = data.operator_telegram_dispatch_report_archive || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`archive=${data.telegram_dispatch_report_archive_passed ? 'pass' : 'blocked'}`,
`summary=${data.ready_for_market_intel_report_archive_summary ? 'ready' : 'blocked'}`,
`file=${data.report_archive_file_written ? 'written' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 Telegram dispatch report archiveAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">REPORT ARCHIVE GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 archive gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CLOSEOUT SUMMARY</p>
<div class="market-intel-check-list">
${[
['provided', closeout.provided],
['mode', closeout.mode || 'missing'],
['closeout_passed', closeout.closeout_passed],
['archive_ready', closeout.ready_for_market_intel_report_archive],
['next_phase', closeout.promotion_next_manual_phase || 'missing'],
['family', closeout.target_report_family || 'missing'],
['report_path', closeout.report_output_artifact_path || 'missing'],
['summary_hash_match', closeout.summary_payload_hash_matches_expected],
['sections_present', closeout.required_report_sections_present]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR ARCHIVE</p>
<div class="market-intel-check-list">
${[
['archive_path', operator.report_archive_artifact_path_recorded],
['closeout_path', operator.report_closeout_artifact_path_recorded],
['receipt_path', operator.report_run_receipt_artifact_path_recorded],
['output_path', operator.report_output_artifact_path_recorded],
['archive_confirmed', operator.operator_confirmed_report_archive],
['closeout_archived', operator.operator_confirmed_report_closeout_archived],
['receipt_archived', operator.operator_confirmed_report_receipt_archived],
['output_archived', operator.operator_confirmed_report_output_archived],
['hash_confirmed', operator.operator_confirmed_report_output_hash_matched],
['manifest_retention', operator.operator_confirmed_archive_manifest_reviewed && operator.operator_confirmed_archive_retention_policy_recorded]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUNTIME BOUNDARY</p>
<div class="market-intel-check-list">
${[
['api_writes_file', data.api_writes_file],
['archive_file_written', data.report_archive_file_written],
['api_calls_llm', data.api_executes_llm],
['api_dispatches_telegram', data.api_dispatches_telegram],
['api_writes_database', data.api_writes_database],
['database_write', data.database_write_executed],
['scheduler_attached', data.scheduler_attached],
['report_file_written', data.report_file_written]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['allowed', promotion.allowed],
['next_phase', promotion.next_manual_phase || 'missing'],
['requires_operator_approval', promotion.requires_operator_approval],
['summary_separate_gate', promotion.report_archive_summary_requires_separate_gate],
['api_must_not_write_archive_file', promotion.api_must_not_write_archive_file],
['api_must_not_dispatch_telegram', promotion.api_must_not_dispatch_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchive = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary Telegram dispatch report archive 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchive(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report archive 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveSummary = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const summary = data.telegram_dispatch_report_archive_summary || {};
const operator = data.operator_telegram_dispatch_report_archive_summary || {};
const sections = data.telegram_dispatch_report_archive_summary_sections || [];
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`summary=${data.telegram_dispatch_report_archive_summary_passed ? 'pass' : 'blocked'}`,
`catalog=${data.ready_for_market_intel_report_catalog_handoff ? 'ready' : 'blocked'}`,
`file=${data.report_archive_summary_file_written ? 'written' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 Telegram dispatch report archive summaryAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫檔、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">REPORT ARCHIVE SUMMARY GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 archive summary gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">SUMMARY SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml((item.facts || []).join(' / '))}</small>
</div>
<span>READY</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 summary sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARCHIVE SUMMARY</p>
<div class="market-intel-check-list">
${[
['provided', summary.provided],
['mode', summary.mode || 'missing'],
['archive_passed', summary.archive_passed],
['report_family', summary.target_report_family || 'missing'],
['report_path', summary.report_output_artifact_path || 'missing'],
['hash_match', summary.summary_payload_hash_matches_expected],
['sections_present', summary.required_report_sections_present],
['retention_recorded', summary.operator_confirmed_archive_retention_policy_recorded]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR SUMMARY</p>
<div class="market-intel-check-list">
${[
['summary_path', operator.report_archive_summary_artifact_path || 'missing'],
['archive_path', operator.report_archive_artifact_path_recorded],
['closeout_path', operator.report_closeout_artifact_path_recorded],
['receipt_path', operator.report_run_receipt_artifact_path_recorded],
['output_path', operator.report_output_artifact_path_recorded],
['summary_confirmed', operator.operator_confirmed_report_archive_summary],
['catalog_handoff_gate', operator.operator_confirmed_report_catalog_handoff_requires_separate_gate],
['runtime_clear', operator.operator_confirmed_no_token_in_report_archive_summary && operator.operator_confirmed_no_api_report_generation && operator.operator_confirmed_no_api_file_write && operator.operator_confirmed_no_api_telegram_dispatch && operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['allowed', promotion.allowed],
['next_phase', promotion.next_manual_phase || 'missing'],
['catalog_handoff_separate_gate', promotion.report_catalog_handoff_requires_separate_gate],
['api_must_not_generate_report', promotion.api_must_not_generate_report],
['api_must_not_write_summary_file', promotion.api_must_not_write_summary_file],
['api_must_not_dispatch_telegram', promotion.api_must_not_dispatch_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveSummary = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review AI summary Telegram dispatch report archive summary 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveSummaryEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveSummary(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report archive summary 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogHandoff = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const summary = data.telegram_dispatch_report_archive_summary || {};
const operator = data.operator_telegram_dispatch_report_catalog_handoff || {};
const sections = data.telegram_dispatch_report_catalog_handoff_sections || [];
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`handoff=${data.telegram_dispatch_report_catalog_handoff_passed ? 'pass' : 'blocked'}`,
`index=${data.ready_for_market_intel_report_catalog_index ? 'ready' : 'blocked'}`,
`catalog=${data.catalog_record_written ? 'written' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 Telegram dispatch report catalog handoffAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫 catalog record、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">CATALOG HANDOFF GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 catalog handoff gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">HANDOFF SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml((item.facts || []).join(' / '))}</small>
</div>
<span>READY</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 handoff sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARCHIVE SUMMARY</p>
<div class="market-intel-check-list">
${[
['provided', summary.provided],
['mode', summary.mode || 'missing'],
['summary_passed', summary.archive_summary_passed],
['report_family', summary.target_report_family || 'missing'],
['report_hash', summary.report_output_hash || 'missing'],
['section_count', summary.section_count || 0],
['catalog_ready', summary.ready_for_market_intel_report_catalog_handoff]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR HANDOFF</p>
<div class="market-intel-check-list">
${[
['handoff_path', operator.report_catalog_handoff_artifact_path || 'missing'],
['summary_path', operator.report_archive_summary_artifact_path_recorded],
['archive_path', operator.report_archive_artifact_path_recorded],
['output_path', operator.report_output_artifact_path_recorded],
['catalog_key', operator.catalog_record_key_recorded],
['catalog_family', operator.catalog_family_recorded],
['index_gate', operator.operator_confirmed_report_catalog_index_requires_separate_gate],
['runtime_clear', operator.operator_confirmed_no_token_in_report_catalog_handoff && operator.operator_confirmed_no_api_report_generation && operator.operator_confirmed_no_api_file_write && operator.operator_confirmed_no_api_telegram_dispatch && operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['allowed', promotion.allowed],
['next_phase', promotion.next_manual_phase || 'missing'],
['catalog_index_separate_gate', promotion.report_catalog_index_requires_separate_gate],
['write_preflight_separate_gate', promotion.report_catalog_write_preflight_requires_separate_gate],
['api_must_not_write_catalog_record', promotion.api_must_not_write_catalog_record],
['api_must_not_dispatch_telegram', promotion.api_must_not_dispatch_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogHandoff = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review AI summary Telegram dispatch report catalog handoff 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogHandoffEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogHandoff(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog handoff 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogIndex = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const handoff = data.telegram_dispatch_report_catalog_handoff || {};
const operator = data.operator_telegram_dispatch_report_catalog_index || {};
const sections = data.telegram_dispatch_report_catalog_index_sections || [];
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`index=${data.telegram_dispatch_report_catalog_index_passed ? 'pass' : 'blocked'}`,
`write_preflight=${data.ready_for_market_intel_report_catalog_write_preflight ? 'ready' : 'blocked'}`,
`catalog=${data.catalog_record_written ? 'written' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理 Telegram dispatch report catalog indexAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫 catalog record、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">CATALOG INDEX GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 catalog index gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">INDEX SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml((item.facts || []).join(' / '))}</small>
</div>
<span>READY</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 index sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CATALOG HANDOFF</p>
<div class="market-intel-check-list">
${[
['provided', handoff.provided],
['mode', handoff.mode || 'missing'],
['handoff_passed', handoff.catalog_handoff_passed],
['report_family', handoff.target_report_family || 'missing'],
['report_hash', handoff.report_output_hash || 'missing'],
['section_count', handoff.section_count || 0],
['index_ready', handoff.ready_for_market_intel_report_catalog_index]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR INDEX</p>
<div class="market-intel-check-list">
${[
['index_path', operator.report_catalog_index_artifact_path || 'missing'],
['handoff_path', operator.report_catalog_handoff_artifact_path_recorded],
['summary_path', operator.report_archive_summary_artifact_path_recorded],
['output_path', operator.report_output_artifact_path_recorded],
['catalog_key', operator.catalog_record_key_recorded],
['catalog_family', operator.catalog_family_recorded],
['index_key', operator.catalog_index_key_recorded],
['write_preflight_gate', operator.operator_confirmed_report_catalog_write_preflight_requires_separate_gate],
['runtime_clear', operator.operator_confirmed_no_token_in_report_catalog_index && operator.operator_confirmed_no_api_report_generation && operator.operator_confirmed_no_api_file_write && operator.operator_confirmed_no_api_catalog_record_write && operator.operator_confirmed_no_api_telegram_dispatch && operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['allowed', promotion.allowed],
['next_phase', promotion.next_manual_phase || 'missing'],
['write_preflight_separate_gate', promotion.report_catalog_write_preflight_requires_separate_gate],
['record_write_separate_gate', promotion.report_catalog_record_write_requires_separate_gate],
['api_must_not_write_index_file', promotion.api_must_not_write_catalog_index_file],
['api_must_not_write_catalog_record', promotion.api_must_not_write_catalog_record]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogIndex = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">整理 queue review AI summary Telegram dispatch report catalog index 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogIndexEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogIndex(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog index 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogWritePreflight = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const index = data.telegram_dispatch_report_catalog_index || {};
const operator = data.operator_telegram_dispatch_report_catalog_write_preflight || {};
const sections = data.telegram_dispatch_report_catalog_write_preflight_sections || [];
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`preflight=${data.telegram_dispatch_report_catalog_write_preflight_passed ? 'pass' : 'blocked'}`,
`record_write=${data.ready_for_market_intel_report_catalog_record_write ? 'ready' : 'blocked'}`,
`catalog=${data.catalog_record_written ? 'written' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 Telegram dispatch report catalog write preflightAPI/UI 不讀 token、不呼叫 LLM、不開 DB、不寫 catalog record、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">WRITE PREFLIGHT GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 write preflight gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PREFLIGHT SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml((item.facts || []).join(' / '))}</small>
</div>
<span>READY</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 preflight sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CATALOG INDEX</p>
<div class="market-intel-check-list">
${[
['provided', index.provided],
['mode', index.mode || 'missing'],
['index_passed', index.catalog_index_passed],
['report_family', index.target_report_family || 'missing'],
['report_hash', index.report_output_hash || 'missing'],
['section_count', index.section_count || 0],
['preflight_ready', index.ready_for_market_intel_report_catalog_write_preflight]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR PREFLIGHT</p>
<div class="market-intel-check-list">
${[
['preflight_path', operator.report_catalog_write_preflight_artifact_path || 'missing'],
['index_path', operator.report_catalog_index_artifact_path_recorded],
['handoff_path', operator.report_catalog_handoff_artifact_path_recorded],
['output_path', operator.report_output_artifact_path_recorded],
['catalog_key', operator.catalog_record_key_recorded],
['catalog_family', operator.catalog_family_recorded],
['index_key', operator.catalog_index_key_recorded],
['record_schema', operator.catalog_record_schema_recorded],
['record_write_gate', operator.operator_confirmed_report_catalog_record_write_requires_separate_gate],
['runtime_clear', operator.operator_confirmed_no_token_in_report_catalog_write_preflight && operator.operator_confirmed_no_api_report_generation && operator.operator_confirmed_no_api_file_write && operator.operator_confirmed_no_api_catalog_record_write && operator.operator_confirmed_no_api_telegram_dispatch && operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['allowed', promotion.allowed],
['next_phase', promotion.next_manual_phase || 'missing'],
['requires_real_db_write', promotion.requires_real_db_write],
['record_write_separate_gate', promotion.report_catalog_record_write_requires_separate_gate],
['commit_separate_gate', promotion.report_catalog_record_commit_requires_separate_gate],
['api_must_not_write_catalog_record', promotion.api_must_not_write_catalog_record]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogWritePreflight = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary Telegram dispatch report catalog write preflight 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogWritePreflightEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogWritePreflight(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog write preflight 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordWrite = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const preflight = data.telegram_dispatch_report_catalog_write_preflight || {};
const operator = data.operator_telegram_dispatch_report_catalog_record_write || {};
const sections = data.telegram_dispatch_report_catalog_record_write_sections || [];
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`record_write=${data.telegram_dispatch_report_catalog_record_write_passed ? 'pass' : 'blocked'}`,
`cli=${data.ready_for_market_intel_report_catalog_record_cli_run ? 'ready' : 'blocked'}`,
`catalog=${data.catalog_record_written ? 'written' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 Telegram dispatch report catalog record write gateAPI/UI 不讀 token、不開 DB、不寫 catalog record、不產報表、不補發 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">RECORD WRITE GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 record write gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RECORD WRITE SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml((item.facts || []).join(' / '))}</small>
</div>
<span>READY</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 record write sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITE PREFLIGHT</p>
<div class="market-intel-check-list">
${[
['provided', preflight.provided],
['mode', preflight.mode || 'missing'],
['preflight_passed', preflight.catalog_write_preflight_passed],
['record_write_ready', preflight.ready_for_market_intel_report_catalog_record_write],
['report_family', preflight.target_report_family || 'missing'],
['report_hash', preflight.report_output_hash || 'missing'],
['schema_recorded', preflight.catalog_record_schema_recorded]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR RECORD WRITE</p>
<div class="market-intel-check-list">
${[
['record_write_path', operator.report_catalog_record_write_artifact_path || 'missing'],
['preflight_path', operator.report_catalog_write_preflight_artifact_path_recorded],
['index_path', operator.report_catalog_index_artifact_path_recorded],
['output_path', operator.report_output_artifact_path_recorded],
['catalog_key', operator.catalog_record_key_recorded],
['record_schema', operator.catalog_record_schema_recorded],
['backup', operator.catalog_record_backup_artifact_path_recorded],
['dry_run', operator.catalog_record_write_dry_run_artifact_path_recorded],
['commit_gate', operator.operator_confirmed_report_catalog_record_commit_requires_separate_gate],
['runtime_clear', operator.operator_confirmed_no_token_in_report_catalog_record_write && operator.operator_confirmed_no_api_file_write && operator.operator_confirmed_no_api_catalog_record_write && operator.operator_confirmed_no_api_telegram_dispatch && operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['allowed', promotion.allowed],
['next_phase', promotion.next_manual_phase || 'missing'],
['requires_cli_run', promotion.requires_cli_run],
['requires_real_db_write', promotion.requires_real_db_write],
['run_package_gate', promotion.report_catalog_record_run_package_requires_separate_gate],
['commit_gate', promotion.report_catalog_record_commit_requires_separate_gate],
['api_must_not_write_database', promotion.api_must_not_write_database]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordWrite = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary Telegram dispatch report catalog record write gate 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordWriteEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordWrite(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog record write gate 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunPackage = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const recordWrite = data.telegram_dispatch_report_catalog_record_write || {};
const operator = data.operator_telegram_dispatch_report_catalog_record_run_package || {};
const sections = data.telegram_dispatch_report_catalog_record_run_package_sections || [];
const command = data.command_bundle || {};
const manifest = data.payload_manifest || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`run_package=${data.telegram_dispatch_report_catalog_record_run_package_passed ? 'pass' : 'blocked'}`,
`readiness=${data.ready_for_market_intel_report_catalog_record_run_readiness ? 'ready' : 'blocked'}`,
`cli=${data.catalog_record_cli_executed ? 'executed' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只產生 Telegram dispatch report catalog record run package 預覽API/UI 不讀 token、不寫檔、不執行 CLI、不開 DB、不寫 catalog record、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">RUN PACKAGE GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 run package gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUN PACKAGE SECTIONS</p>
<div class="market-intel-check-list">${
sections.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml((item.facts || []).join(' / '))}</small>
</div>
<span>READY</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 run package sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RECORD WRITE</p>
<div class="market-intel-check-list">
${[
['provided', recordWrite.provided],
['mode', recordWrite.mode || 'missing'],
['record_write_passed', recordWrite.catalog_record_write_passed],
['cli_ready', recordWrite.ready_for_market_intel_report_catalog_record_cli_run],
['report_family', recordWrite.target_report_family || 'missing'],
['report_hash', recordWrite.report_output_hash || 'missing'],
['dry_run', recordWrite.catalog_record_write_dry_run_artifact_path_recorded]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PACKAGE INPUT</p>
<div class="market-intel-check-list">
${[
['package_path', operator.report_catalog_record_run_package_artifact_path || 'missing'],
['write_gate_path', operator.report_catalog_record_write_artifact_path_recorded],
['manifest_path', operator.catalog_record_payload_manifest_path_recorded],
['backup', operator.catalog_record_backup_artifact_path_recorded],
['dry_run', operator.catalog_record_write_dry_run_artifact_path_recorded],
['cli_command', operator.catalog_record_cli_command_recorded],
['runtime_clear', operator.operator_confirmed_no_token_in_report_catalog_record_run_package && operator.operator_confirmed_no_api_file_write && operator.operator_confirmed_no_api_catalog_record_write && operator.operator_confirmed_no_api_telegram_dispatch && operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMAND / PROMOTION</p>
<div class="market-intel-check-list">
${[
['script', command.script_path || 'missing'],
['api_must_not_execute', command.api_must_not_execute_command],
['manifest_execute_in_api', manifest.execute_in_api],
['next_phase', promotion.next_manual_phase || 'missing'],
['run_readiness_gate', promotion.report_catalog_record_run_readiness_requires_separate_gate],
['commit_gate', promotion.report_catalog_record_commit_requires_separate_gate]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunPackage = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue review AI summary Telegram dispatch report catalog record run package 預覽中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunPackageEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunPackage(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog record run package 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReadiness = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const runPackage = data.telegram_dispatch_report_catalog_record_run_package || {};
const operator = data.operator_telegram_dispatch_report_catalog_record_run_readiness || {};
const manifest = data.catalog_record_run_readiness_manifest || {};
const command = manifest.manual_cli_run_command || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`readiness=${data.telegram_dispatch_report_catalog_record_run_readiness_passed ? 'pass' : 'blocked'}`,
`operator_cli=${data.ready_for_cli_operator_run ? 'ready' : 'blocked'}`,
`api_cli=${data.api_executes_cli ? 'executed' : 'blocked'}`,
`db=${data.database_write_executed ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 Telegram dispatch report catalog record run readinessAPI/UI 不讀 token、不寫檔、不執行 CLI、不開 DB、不寫 catalog record、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">READINESS GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 run readiness gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUN PACKAGE</p>
<div class="market-intel-check-list">
${[
['provided', runPackage.provided],
['mode', runPackage.mode || 'missing'],
['package_passed', runPackage.catalog_record_run_package_passed],
['record_family', runPackage.record_family || 'missing'],
['statement_count', runPackage.statement_count || 0],
['report_hash', runPackage.report_output_hash || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR EVIDENCE</p>
<div class="market-intel-check-list">
${[
['readiness_path', operator.report_catalog_record_run_readiness_artifact_path || 'missing'],
['run_package_path', operator.report_catalog_record_run_package_artifact_path_recorded],
['manifest_path', operator.catalog_record_payload_manifest_path_recorded],
['backup', operator.catalog_record_backup_artifact_path_recorded],
['dry_run', operator.catalog_record_write_dry_run_artifact_path_recorded],
['receipt_path', operator.catalog_record_run_receipt_artifact_path_recorded],
['smoke_path', operator.catalog_record_postwrite_smoke_artifact_path_recorded]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CLI BOUNDARY</p>
<div class="market-intel-check-list">
${[
['manifest', manifest.manifest_version || 'missing'],
['script', command.script_path || 'missing'],
['executed_by_api', command.executed_by_api],
['approval_env', command.requires_approval_env_var || 'missing'],
['operator_shell_only', operator.operator_confirmed_one_time_token_shell_only],
['runtime_clear', operator.operator_confirmed_no_token_in_report_catalog_record_run_readiness && operator.operator_confirmed_no_api_file_write && operator.operator_confirmed_no_api_catalog_record_write && operator.operator_confirmed_no_api_telegram_dispatch && operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['next_phase', promotion.next_manual_phase || 'missing'],
['requires_cli', promotion.requires_cli_run],
['requires_db_write', promotion.requires_real_db_write],
['receipt_gate', promotion.report_catalog_record_run_receipt_requires_separate_gate],
['commit_gate', promotion.report_catalog_record_commit_requires_separate_gate]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReadiness = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review AI summary Telegram dispatch report catalog record run readiness 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReadinessEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReadiness(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog record run readiness 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReceipt = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const readiness = data.telegram_dispatch_report_catalog_record_run_readiness || {};
const writer = data.telegram_dispatch_report_catalog_record_run_receipt_writer || {};
const smoke = data.telegram_dispatch_report_catalog_record_run_receipt_postwrite_smoke || {};
const operator = data.operator_telegram_dispatch_report_catalog_record_run_receipt || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`receipt=${data.telegram_dispatch_report_catalog_record_run_receipt_passed ? 'pass' : 'blocked'}`,
`writer=${writer.catalog_record_written ? 'written' : 'blocked'}`,
`smoke=${smoke.postwrite_smoke_passed ? 'pass' : 'blocked'}`,
`api_db=${data.api_writes_database ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核外部 CLI 回貼的 Telegram dispatch report catalog record run receiptAPI/UI 不讀 token、不寫檔、不執行 CLI、不開 DB、不寫 catalog record、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">RECEIPT GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 run receipt gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">READINESS</p>
<div class="market-intel-check-list">
${[
['provided', readiness.provided],
['mode', readiness.mode || 'missing'],
['passed', readiness.run_readiness_passed],
['record_family', readiness.record_family || 'missing'],
['statement_count', readiness.statement_count || 0],
['expected_hash', readiness.expected_summary_payload_hash || 'missing']
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITER OUTPUT</p>
<div class="market-intel-check-list">
${[
['mode', writer.mode || 'missing'],
['cli_executed', writer.catalog_record_cli_executed],
['record_written', writer.catalog_record_written],
['db_write', writer.database_write_executed],
['commit', writer.database_commit_executed],
['hash_match', writer.summary_payload_hash_matches_expected]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">POSTWRITE SMOKE</p>
<div class="market-intel-check-list">
${[
['mode', smoke.mode || 'missing'],
['read_only', smoke.read_only_query_executed],
['smoke_passed', smoke.postwrite_smoke_passed],
['record_found', smoke.catalog_record_found],
['hash_match', smoke.summary_payload_hash_matches_expected],
['db_write', smoke.database_write_executed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['receipt_path', operator.report_catalog_record_run_receipt_artifact_path || 'missing'],
['readiness_path', operator.report_catalog_record_run_readiness_artifact_path_recorded],
['writer_path', operator.catalog_record_writer_output_artifact_path_recorded],
['smoke_path', operator.catalog_record_postwrite_smoke_artifact_path_recorded],
['commit_gate', operator.operator_confirmed_catalog_record_commit_requires_separate_gate],
['runtime_clear', operator.operator_confirmed_no_token_in_report_catalog_record_run_receipt && operator.operator_confirmed_no_api_file_write && operator.operator_confirmed_no_api_cli_execution && operator.operator_confirmed_no_api_catalog_record_write && operator.operator_confirmed_no_api_telegram_dispatch && operator.operator_confirmed_no_api_db_write && operator.operator_confirmed_no_llm_call && operator.operator_confirmed_no_scheduler_attach]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['next_phase', promotion.next_manual_phase || 'missing'],
['commit_gate', promotion.report_catalog_record_commit_requires_separate_gate],
['api_write', promotion.api_must_not_write_database],
['api_cli', promotion.api_must_not_execute_cli],
['api_catalog_record', promotion.api_must_not_write_catalog_record]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReceipt = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary Telegram dispatch report catalog record run receipt 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReceiptEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReceipt(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog record run receipt 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCommit = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const receipt = data.telegram_dispatch_report_catalog_record_run_receipt || {};
const operator = data.operator_telegram_dispatch_report_catalog_record_commit || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`commit=${data.telegram_dispatch_report_catalog_record_commit_passed ? 'pass' : 'blocked'}`,
`receipt=${receipt.run_receipt_passed ? 'pass' : 'blocked'}`,
`writer_commit=${receipt.writer_database_commit_executed ? 'seen' : 'missing'}`,
`api_db=${data.api_writes_database ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 Telegram dispatch report catalog record commit gateAPI/UI 不讀 token、不寫檔、不執行 CLI、不開 DB、不寫 catalog record、不執行 commit、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">COMMIT GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 commit gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUN RECEIPT</p>
<div class="market-intel-check-list">
${[
['provided', receipt.provided],
['mode', receipt.mode || 'missing'],
['passed', receipt.run_receipt_passed],
['record_key', receipt.writer_catalog_record_key || 'missing'],
['statement_count', receipt.writer_statement_count || 0],
['hash_match', receipt.writer_hash_match]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMIT EVIDENCE</p>
<div class="market-intel-check-list">
${[
['writer_db_write', receipt.writer_database_write_executed],
['writer_commit', receipt.writer_database_commit_executed],
['writer_rollback', receipt.writer_database_rollback_executed],
['smoke_read_only', receipt.smoke_read_only_query_executed],
['smoke_passed', receipt.smoke_postwrite_smoke_passed],
['smoke_db_write', receipt.smoke_database_write_executed]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['commit_path', operator.report_catalog_record_commit_artifact_path || 'missing'],
['receipt_path', operator.report_catalog_record_run_receipt_artifact_path_recorded],
['backup_path', operator.catalog_record_backup_artifact_path_recorded],
['commit_gate', operator.operator_confirmed_report_catalog_record_commit_gate],
['db_commit_seen', operator.operator_confirmed_catalog_record_db_commit_observed],
['closeout_gate', operator.operator_confirmed_catalog_record_closeout_requires_separate_gate]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUNTIME</p>
<div class="market-intel-check-list">
${[
['api_file', data.api_writes_file],
['api_cli', data.api_executes_cli],
['api_db', data.api_writes_database],
['db_write', data.database_write_executed],
['commit_exec', data.catalog_record_commit_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['next_phase', promotion.next_manual_phase || 'missing'],
['closeout_gate', promotion.report_catalog_record_closeout_requires_separate_gate],
['api_commit', promotion.api_must_not_commit_catalog_record],
['api_write', promotion.api_must_not_write_database],
['api_catalog_record', promotion.api_must_not_write_catalog_record]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCommit = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary Telegram dispatch report catalog record commit gate 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCommitEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCommit(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog record commit gate 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCloseout = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const commit = data.telegram_dispatch_report_catalog_record_commit || {};
const operator = data.operator_telegram_dispatch_report_catalog_record_closeout || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`closeout=${data.telegram_dispatch_report_catalog_record_closeout_passed ? 'pass' : 'blocked'}`,
`commit=${commit.commit_passed ? 'pass' : 'blocked'}`,
`writer_commit=${commit.writer_database_commit_executed ? 'seen' : 'missing'}`,
`api_db=${data.api_writes_database ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 Telegram dispatch report catalog record closeout gateAPI/UI 不讀 token、不寫檔、不執行 CLI、不開 DB、不寫 catalog record、不執行 commit、不派 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">CLOSEOUT GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 closeout gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMIT</p>
<div class="market-intel-check-list">
${[
['provided', commit.provided],
['mode', commit.mode || 'missing'],
['passed', commit.commit_passed],
['record_key', commit.writer_catalog_record_key || 'missing'],
['statement_count', commit.writer_statement_count || 0],
['hash_match', commit.writer_hash_match]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMIT EVIDENCE</p>
<div class="market-intel-check-list">
${[
['db_commit', commit.writer_database_commit_executed],
['smoke_read_only', commit.smoke_read_only_query_executed],
['smoke_passed', commit.smoke_postwrite_smoke_passed],
['operator_commit', commit.operator_commit_gate],
['operator_db_seen', commit.operator_db_commit_observed],
['closeout_gate', commit.operator_closeout_requires_separate_gate]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['closeout_path', operator.report_catalog_record_closeout_artifact_path || 'missing'],
['commit_path', operator.report_catalog_record_commit_artifact_path_recorded],
['receipt_path', operator.report_catalog_record_run_receipt_artifact_path_recorded],
['backup_path', operator.catalog_record_backup_artifact_path_recorded],
['closeout_gate', operator.operator_confirmed_report_catalog_record_closeout_gate],
['archive_gate', operator.operator_confirmed_catalog_record_archive_requires_separate_gate]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUNTIME</p>
<div class="market-intel-check-list">
${[
['api_file', data.api_writes_file],
['api_cli', data.api_executes_cli],
['api_db', data.api_writes_database],
['db_write', data.database_write_executed],
['closeout_exec', data.catalog_record_closeout_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['next_phase', promotion.next_manual_phase || 'missing'],
['archive_gate', promotion.report_catalog_record_archive_requires_separate_gate],
['api_commit', promotion.api_must_not_commit_catalog_record],
['api_write', promotion.api_must_not_write_database],
['api_telegram', promotion.api_must_not_dispatch_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCloseout = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary Telegram dispatch report catalog record closeout gate 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCloseoutEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCloseout(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog record closeout gate 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchive = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const closeout = data.telegram_dispatch_report_catalog_record_closeout || {};
const operator = data.operator_telegram_dispatch_report_catalog_record_archive || {};
const promotion = data.promotion_gate || {};
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`archive=${data.telegram_dispatch_report_catalog_record_archive_passed ? 'pass' : 'blocked'}`,
`closeout=${closeout.closeout_passed ? 'pass' : 'blocked'}`,
`summary=${data.ready_for_market_intel_report_catalog_record_archive_summary ? 'ready' : 'blocked'}`,
`api_file=${data.api_writes_file ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 Telegram dispatch report catalog record archive gateAPI/UI 不讀 token、不產報表、不寫檔、不執行 CLI、不開 DB、不寫 catalog record、不執行 commit、不派 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">ARCHIVE GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 archive gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">CLOSEOUT</p>
<div class="market-intel-check-list">
${[
['provided', closeout.provided],
['mode', closeout.mode || 'missing'],
['passed', closeout.closeout_passed],
['record_key', closeout.writer_catalog_record_key || 'missing'],
['archive_ready', closeout.ready_for_market_intel_report_catalog_record_archive],
['safe_boundaries', closeout.safe_boundaries_complete]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['archive_path', operator.report_catalog_record_archive_artifact_path || 'missing'],
['closeout_path', operator.report_catalog_record_closeout_artifact_path_recorded],
['commit_path', operator.report_catalog_record_commit_artifact_path_recorded],
['receipt_path', operator.report_catalog_record_run_receipt_artifact_path_recorded],
['archive_gate', operator.operator_confirmed_report_catalog_record_archive_gate],
['summary_gate', operator.operator_confirmed_catalog_record_archive_summary_requires_separate_gate]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUNTIME</p>
<div class="market-intel-check-list">
${[
['api_report', data.ready_for_report_generation],
['api_file', data.api_writes_file],
['api_cli', data.api_executes_cli],
['api_db', data.api_writes_database],
['archive_exec', data.catalog_record_archive_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['next_phase', promotion.next_manual_phase || 'missing'],
['summary_gate', promotion.report_catalog_record_archive_summary_requires_separate_gate],
['api_commit', promotion.api_must_not_commit_catalog_record],
['api_write', promotion.api_must_not_write_database],
['api_telegram', promotion.api_must_not_dispatch_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchive = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary Telegram dispatch report catalog record archive gate 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchive(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog record archive gate 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveSummary = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const archive = data.telegram_dispatch_report_catalog_record_archive || {};
const operator = data.operator_telegram_dispatch_report_catalog_record_archive_summary || {};
const promotion = data.promotion_gate || {};
const sections = data.telegram_dispatch_report_catalog_record_archive_summary_sections || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`summary=${data.telegram_dispatch_report_catalog_record_archive_summary_passed ? 'pass' : 'blocked'}`,
`archive=${archive.archive_passed ? 'pass' : 'blocked'}`,
`final=${data.ready_for_market_intel_report_catalog_record_final_closeout ? 'ready' : 'blocked'}`,
`file=${data.catalog_record_archive_summary_file_written ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 Telegram dispatch report catalog record archive summary gateAPI/UI 不讀 token、不產報表、不寫檔、不執行 CLI、不開 DB、不寫 catalog record、不執行 commit、不派 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">SUMMARY GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 archive summary gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARCHIVE</p>
<div class="market-intel-check-list">
${[
['provided', archive.provided],
['mode', archive.mode || 'missing'],
['passed', archive.archive_passed],
['record_key', archive.writer_catalog_record_key || 'missing'],
['summary_ready', archive.ready_for_market_intel_report_catalog_record_archive_summary],
['safe_boundaries', archive.safe_boundaries_complete]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">SECTIONS</p>
<div class="market-intel-operation-list">${
sections.map(section => `
<article class="market-intel-operation">
<strong>${escapeHtml(section.key || 'section')}</strong>
<small>${escapeHtml((section.facts || []).join(' / '))}</small>
</article>
`).join('') || '<div class="market-intel-empty">尚未提供 summary sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['summary_path', operator.report_catalog_record_archive_summary_artifact_path || 'missing'],
['archive_path', operator.report_catalog_record_archive_artifact_path_recorded],
['closeout_path', operator.report_catalog_record_closeout_artifact_path_recorded],
['traceability', operator.operator_confirmed_catalog_record_traceability_reviewed],
['summary_gate', operator.operator_confirmed_report_catalog_record_archive_summary_gate],
['final_gate', operator.operator_confirmed_catalog_record_final_closeout_requires_separate_gate]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUNTIME</p>
<div class="market-intel-check-list">
${[
['api_report', data.ready_for_report_generation],
['api_file', data.api_writes_file],
['api_cli', data.api_executes_cli],
['api_db', data.api_writes_database],
['summary_exec', data.catalog_record_archive_summary_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['next_phase', promotion.next_manual_phase || 'missing'],
['final_gate', promotion.report_catalog_record_final_closeout_requires_separate_gate],
['api_commit', promotion.api_must_not_commit_catalog_record],
['api_write', promotion.api_must_not_write_database],
['api_telegram', promotion.api_must_not_dispatch_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveSummary = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary Telegram dispatch report catalog record archive summary gate 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveSummaryEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveSummary(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog record archive summary gate 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordFinalCloseout = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const gates = data.gates || [];
const summary = data.telegram_dispatch_report_catalog_record_archive_summary || {};
const operator = data.operator_telegram_dispatch_report_catalog_record_final_closeout || {};
const promotion = data.promotion_gate || {};
const sections = data.telegram_dispatch_report_catalog_record_final_closeout_sections || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`closeout=${data.telegram_dispatch_report_catalog_record_final_closeout_passed ? 'pass' : 'blocked'}`,
`summary=${summary.archive_summary_passed ? 'pass' : 'blocked'}`,
`complete=${data.market_intel_report_catalog_record_pipeline_complete ? 'yes' : 'blocked'}`,
`file=${data.catalog_record_final_closeout_file_written ? 'written' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只審核 Telegram dispatch report catalog record final closeout gateAPI/UI 不讀 token、不產報表、不寫檔、不執行 CLI、不開 DB、不寫 catalog record、不執行 commit、不派 Telegram、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">FINAL GATES</p>
<div class="market-intel-check-list">${
gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 final closeout gate。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">ARCHIVE SUMMARY</p>
<div class="market-intel-check-list">
${[
['provided', summary.provided],
['mode', summary.mode || 'missing'],
['passed', summary.archive_summary_passed],
['record_key', summary.writer_catalog_record_key || 'missing'],
['sections', summary.summary_sections_complete],
['safe_boundaries', summary.safe_boundaries_complete]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">SECTIONS</p>
<div class="market-intel-operation-list">${
sections.map(section => `
<article class="market-intel-operation">
<strong>${escapeHtml(section.key || 'section')}</strong>
<small>${escapeHtml((section.facts || []).join(' / '))}</small>
</article>
`).join('') || '<div class="market-intel-empty">尚未提供 final closeout sections。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR</p>
<div class="market-intel-check-list">
${[
['final_path', operator.report_catalog_record_final_closeout_artifact_path || 'missing'],
['summary_path', operator.report_catalog_record_archive_summary_artifact_path_recorded],
['traceability', operator.operator_confirmed_catalog_record_traceability_reviewed],
['pipeline', operator.operator_confirmed_catalog_record_pipeline_complete],
['no_followup', operator.operator_confirmed_no_pending_catalog_record_followup],
['read_only', operator.operator_confirmed_catalog_record_final_closeout_read_only]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">RUNTIME</p>
<div class="market-intel-check-list">
${[
['api_report', data.ready_for_report_generation],
['api_file', data.api_writes_file],
['api_cli', data.api_executes_cli],
['api_db', data.api_writes_database],
['final_exec', data.catalog_record_final_closeout_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">PROMOTION</p>
<div class="market-intel-check-list">
${[
['next_phase', promotion.next_manual_phase || 'missing'],
['terminal', promotion.terminal_gate],
['api_commit', promotion.api_must_not_commit_catalog_record],
['api_write', promotion.api_must_not_write_database],
['api_telegram', promotion.api_must_not_dispatch_telegram]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordFinalCloseout = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">審核 queue review AI summary Telegram dispatch report catalog record final closeout gate 中...</div>';
try {
const response = await fetch(`${sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordFinalCloseoutEndpoint}?execute=false&apply_real_write=false`, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordFinalCloseout(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review AI summary Telegram dispatch report catalog record final closeout gate 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCandidateQueueReviewDecisionWriter = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const summary = data.statement_summary || {};
const command = data.command_bundle || {};
const gates = data.approval_gates || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_real_write ? 'yes' : 'no'}`,
`statements=${summary.statement_count || 0}`,
`api_update=${data.api_updates_review_state ? 'yes' : 'no'}`,
`impl=${data.writer_implementation_enabled ? 'enabled' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只檢查 queue review decision writer CLI gateAPI/UI 不讀 token、不執行 CLI、不連 DB、不更新 review_state。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">WRITER GATES</p>
<div class="market-intel-check-list">${
gates.map(gate => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(gate.key)}</strong>
<small>${escapeHtml(gate.label)}</small>
</div>
<span>${gate.passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 writer gates。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMAND SHAPE</p>
<div class="market-intel-check-list">
${[
['script_path', data.script_path || 'unknown'],
['env_var', data.approval_env_var || 'unknown'],
['dry_run', command.dry_run_command || 'not_ready'],
['api_must_not_execute', command.api_must_not_execute_command]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">WRITE FLAGS</p>
<div class="market-intel-check-list">
${[
['execute_requested', data.execute_requested],
['apply_real_write', data.apply_real_write_requested],
['token_present', data.approval_token_present],
['token_valid', data.approval_token_valid],
['db_write', data.database_write_executed],
['commit', data.database_commit_executed],
['scheduler', data.scheduler_attached]
].map(([key, value]) => `
<div class="market-intel-check">
<div><strong>${escapeHtml(key)}</strong></div>
<span>${escapeHtml(String(value))}</span>
</div>
`).join('')}
</div>
</div>
<div>
<p class="market-intel-deploy-section-title">STATEMENTS</p>
<div class="market-intel-check-list">${
(summary.review_state_updates || []).map(row => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(row.dedupe_key || row.idempotency_key || 'unknown')}</strong>
<small>${escapeHtml(row.expected_current_review_state || 'unknown')} -> ${escapeHtml(row.next_review_state || 'none')}</small>
</div>
<span>${escapeHtml(row.write_status || 'blocked')}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 review_state update statements。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueReviewDecisionWriter = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
const body = parsed && parsed.sample_result ? parsed : { sample_result: parsed };
sampleReviewBody.innerHTML = '<div class="market-intel-empty">檢查 queue review decision writer CLI gate 中...</div>';
try {
const response = await fetch(sampleCandidateQueueReviewDecisionWriterEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(body)
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueReviewDecisionWriter(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue review decision writer CLI gate 失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderSchedulerMeta = data => {
schedulerMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_to_attach_scheduler ? 'yes' : 'no'}`,
`jobs=${data.job_count || 0}`,
`scheduler=${data.scheduler_attached ? 'on' : 'off'}`,
`crawler=${data.crawler_job_started ? 'started' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderSchedulerBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.gate_checks || {});
const jobs = data.jobs || [];
const sequence = data.attach_sequence || [];
const fallback = data.fallback_plan || [];
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderJob = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)} / ${escapeHtml(item.cadence)}</small>
<small>${escapeHtml(item.entrypoint)} / max=${escapeHtml(item.max_runtime_minutes)}m</small>
<small>network=${item.requires_external_network ? 'yes' : 'no'} / write=${item.requires_database_write ? 'yes' : 'no'}</small>
</article>
`;
const renderPlanItem = (item, status) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key || status)}</strong>
<small>${escapeHtml(item.label || item)}</small>
</div>
<span>${escapeHtml(status).toUpperCase()}</span>
</div>
`;
schedulerBody.innerHTML = `
<div class="market-intel-empty mb-3">這是排程掛載計畫,不會從 API 註冊 job、不啟動 crawler、不連外、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-scheduler-checks>
<p class="market-intel-deploy-section-title">SCHEDULER GATES</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供排程 gate。</div>'
}</div>
</div>
<div data-market-intel-scheduler-jobs>
<p class="market-intel-deploy-section-title">PLANNED JOBS</p>
<div class="market-intel-operation-list">${
jobs.length
? jobs.map(renderJob).join('')
: '<div class="market-intel-empty">尚未提供排程 job。</div>'
}</div>
</div>
<div data-market-intel-scheduler-sequence>
<p class="market-intel-deploy-section-title">ATTACH SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.length
? sequence.map(item => renderPlanItem(item, 'required')).join('')
: '<div class="market-intel-empty">尚未提供掛載順序。</div>'
}</div>
</div>
<div data-market-intel-scheduler-fallback>
<p class="market-intel-deploy-section-title">FALLBACK</p>
<div class="market-intel-check-list">${
fallback.length
? fallback.map(item => renderPlanItem(item, 'ready')).join('')
: '<div class="market-intel-empty">尚未提供備援方案。</div>'
}</div>
</div>
</div>
`;
};
const loadScheduler = async () => {
if (!schedulerMeta || !schedulerBody) return;
schedulerBody.innerHTML = '<div class="market-intel-empty">讀取排程掛載計畫中...</div>';
try {
const response = await fetch(schedulerEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderSchedulerMeta(data);
renderSchedulerBody(data);
} catch (error) {
schedulerMeta.innerHTML = '<span class="market-intel-pill">error</span>';
schedulerBody.innerHTML = `<div class="market-intel-empty">排程掛載計畫讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderMatchReviewMeta = data => {
const thresholds = data.thresholds || {};
matchReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_review_queue ? 'yes' : 'no'}`,
`signals=${(data.scoring_signals || []).length}`,
`auto_confirm=${thresholds.auto_confirm_enabled ? 'on' : 'off'}`,
`writes=${data.writes_executed ? 'executed' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderMatchReviewBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.gate_checks || {});
const signals = data.scoring_signals || [];
const actions = data.review_actions || [];
const sequence = data.operator_sequence || [];
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderSignal = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
<small>weight=${escapeHtml(item.weight)} / ${escapeHtml(item.source)}</small>
</article>
`;
const renderAction = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${item.requires_operator ? 'HITL' : 'AUTO'}</span>
</div>
`;
matchReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">商品比對目前只建立審核規則與 HITL 流程;不建立 queue、不自動確認、不寫 DB、不呼叫外部 MCP。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-match-review-checks>
<p class="market-intel-deploy-section-title">MATCH GATES</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供比對 gate。</div>'
}</div>
</div>
<div data-market-intel-match-review-signals>
<p class="market-intel-deploy-section-title">SCORING SIGNALS</p>
<div class="market-intel-operation-list">${
signals.length
? signals.map(renderSignal).join('')
: '<div class="market-intel-empty">尚未提供比對訊號。</div>'
}</div>
</div>
<div data-market-intel-match-review-actions>
<p class="market-intel-deploy-section-title">REVIEW ACTIONS</p>
<div class="market-intel-check-list">${
actions.length
? actions.map(renderAction).join('')
: '<div class="market-intel-empty">尚未提供審核動作。</div>'
}</div>
</div>
<div data-market-intel-match-review-sequence>
<p class="market-intel-deploy-section-title">OPERATOR SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.length
? sequence.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>REQUIRED</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供操作順序。</div>'
}</div>
</div>
</div>
`;
};
const loadMatchReview = async () => {
if (!matchReviewMeta || !matchReviewBody) return;
matchReviewBody.innerHTML = '<div class="market-intel-empty">讀取商品比對審核計畫中...</div>';
try {
const response = await fetch(matchReviewEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderMatchReviewMeta(data);
renderMatchReviewBody(data);
} catch (error) {
matchReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
matchReviewBody.innerHTML = `<div class="market-intel-empty">商品比對審核計畫讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderOpportunityMeta = data => {
opportunityMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_opportunity_queue ? 'yes' : 'no'}`,
`rules=${data.rule_count || 0}`,
`alerts=${data.threat_alert_dispatched ? 'sent' : 'blocked'}`,
`ai=${data.ai_summary_generated ? 'generated' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderOpportunityBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.gate_checks || {});
const rules = data.rules || [];
const sequence = data.operator_sequence || [];
const severity = Object.entries(data.severity_policy || {});
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderRule = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)} / severity=${escapeHtml(item.severity)}</small>
<small>${escapeHtml((item.minimum_evidence || []).join(' + '))}</small>
<small>${escapeHtml(item.action_hint)}</small>
</article>
`;
opportunityBody.innerHTML = `
<div class="market-intel-empty mb-3">目前只建立機會與威脅判讀規則;不建立 queue、不派送 Telegram、不產生 AI 摘要、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-opportunity-checks>
<p class="market-intel-deploy-section-title">OPPORTUNITY GATES</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供機會判讀 gate。</div>'
}</div>
</div>
<div data-market-intel-opportunity-rules>
<p class="market-intel-deploy-section-title">RULES</p>
<div class="market-intel-operation-list">${
rules.length
? rules.map(renderRule).join('')
: '<div class="market-intel-empty">尚未提供規則。</div>'
}</div>
</div>
<div data-market-intel-opportunity-severity>
<p class="market-intel-deploy-section-title">SEVERITY POLICY</p>
<div class="market-intel-check-list">${
severity.length
? severity.map(([key, label]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(key)}</strong>
<small>${escapeHtml(label)}</small>
</div>
<span>POLICY</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供分級策略。</div>'
}</div>
</div>
<div data-market-intel-opportunity-sequence>
<p class="market-intel-deploy-section-title">OPERATOR SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.length
? sequence.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>REQUIRED</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供操作順序。</div>'
}</div>
</div>
</div>
`;
};
const loadOpportunity = async () => {
if (!opportunityMeta || !opportunityBody) return;
opportunityBody.innerHTML = '<div class="market-intel-empty">讀取市場機會與威脅計畫中...</div>';
try {
const response = await fetch(opportunityEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderOpportunityMeta(data);
renderOpportunityBody(data);
} catch (error) {
opportunityMeta.innerHTML = '<span class="market-intel-pill">error</span>';
opportunityBody.innerHTML = `<div class="market-intel-empty">市場機會與威脅計畫讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderOpportunityScoringMeta = data => {
opportunityScoringMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_scoring_job ? 'yes' : 'no'}`,
`dimensions=${data.dimension_count || 0}`,
`weight=${data.total_weight || 0}`,
`score=${data.score_calculation_executed ? 'executed' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderOpportunityScoringBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.gate_checks || {});
const dimensions = data.dimensions || [];
const thresholds = data.thresholds || [];
const evidenceTables = data.required_evidence_tables || [];
const sequence = data.operator_sequence || [];
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderDimension = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)} / ${escapeHtml(item.weight)}%</strong>
<small>${escapeHtml(item.label)}</small>
<small>${escapeHtml((item.evidence || []).join(' + '))}</small>
<small>${escapeHtml(item.calculation)}</small>
</article>
`;
opportunityScoringBody.innerHTML = `
<div class="market-intel-empty mb-3">目前只定義機會與威脅分數模型;不計分、不建立 queue、不派送 Telegram、不產生 AI 摘要、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-opportunity-scoring-checks>
<p class="market-intel-deploy-section-title">SCORING GATES</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供分數 gate。</div>'
}</div>
</div>
<div data-market-intel-opportunity-scoring-dimensions>
<p class="market-intel-deploy-section-title">DIMENSIONS</p>
<div class="market-intel-operation-list">${
dimensions.length
? dimensions.map(renderDimension).join('')
: '<div class="market-intel-empty">尚未提供分數欄位。</div>'
}</div>
</div>
<div data-market-intel-opportunity-scoring-thresholds>
<p class="market-intel-deploy-section-title">THRESHOLDS</p>
<div class="market-intel-check-list">${
thresholds.length
? thresholds.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.level)}</strong>
<small>${escapeHtml(item.action)}</small>
</div>
<span>${escapeHtml(item.minimum_score)}+</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供門檻。</div>'
}</div>
</div>
<div data-market-intel-opportunity-scoring-evidence>
<p class="market-intel-deploy-section-title">EVIDENCE TABLES</p>
<div class="market-intel-check-list">${
evidenceTables.length
? evidenceTables.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item)}</strong>
</div>
<span>REQUIRED</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供 evidence tables。</div>'
}</div>
</div>
<div data-market-intel-opportunity-scoring-sequence>
<p class="market-intel-deploy-section-title">OPERATOR SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.length
? sequence.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>REQUIRED</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供操作順序。</div>'
}</div>
</div>
</div>
`;
};
const loadOpportunityScoring = async () => {
if (!opportunityScoringMeta || !opportunityScoringBody) return;
opportunityScoringBody.innerHTML = '<div class="market-intel-empty">讀取機會威脅分數模型中...</div>';
try {
const response = await fetch(opportunityScoringEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderOpportunityScoringMeta(data);
renderOpportunityScoringBody(data);
} catch (error) {
opportunityScoringMeta.innerHTML = '<span class="market-intel-pill">error</span>';
opportunityScoringBody.innerHTML = `<div class="market-intel-empty">機會威脅分數模型讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderOpportunityEvidenceMeta = data => {
opportunityEvidenceMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_evidence_bundle ? 'yes' : 'no'}`,
`sections=${data.section_count || 0}`,
`query=${data.evidence_query_executed ? 'yes' : 'no'}`,
`bundle=${data.evidence_bundle_created ? 'created' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderOpportunityEvidenceBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.gate_checks || {});
const sections = data.sections || [];
const gates = data.escalation_gates || [];
const tables = data.required_market_tables || [];
const sequence = data.operator_sequence || [];
const contract = data.bundle_contract || {};
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderSection = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
<small>${escapeHtml((item.source_tables || []).join(' + '))}</small>
<small>${escapeHtml((item.required_fields || []).join(' / '))}</small>
</article>
`;
opportunityEvidenceBody.innerHTML = `
<div class="market-intel-empty mb-3">目前只定義 evidence bundle contract不查 DB、不產生 sample evidence、不建立 alert candidate、不派送 Telegram、不產生 AI 摘要。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">dedupe=${escapeHtml(contract.dedupe_key || '')} / freshness=${escapeHtml(contract.freshness_window_hours || 'n/a')}h</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-opportunity-evidence-checks>
<p class="market-intel-deploy-section-title">EVIDENCE GATES</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供 evidence gate。</div>'
}</div>
</div>
<div data-market-intel-opportunity-evidence-sections>
<p class="market-intel-deploy-section-title">BUNDLE SECTIONS</p>
<div class="market-intel-operation-list">${
sections.length
? sections.map(renderSection).join('')
: '<div class="market-intel-empty">尚未提供 evidence section。</div>'
}</div>
</div>
<div data-market-intel-opportunity-evidence-escalation>
<p class="market-intel-deploy-section-title">ESCALATION GATES</p>
<div class="market-intel-check-list">${
gates.length
? gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${escapeHtml((item.required_for || []).join('/'))}</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供升級 gate。</div>'
}</div>
</div>
<div data-market-intel-opportunity-evidence-tables>
<p class="market-intel-deploy-section-title">REQUIRED TABLES</p>
<div class="market-intel-check-list">${
tables.length
? tables.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item)}</strong>
</div>
<span>REQUIRED</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供 required tables。</div>'
}</div>
</div>
<div data-market-intel-opportunity-evidence-sequence>
<p class="market-intel-deploy-section-title">OPERATOR SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.length
? sequence.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>REQUIRED</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供操作順序。</div>'
}</div>
</div>
</div>
`;
};
const loadOpportunityEvidence = async () => {
if (!opportunityEvidenceMeta || !opportunityEvidenceBody) return;
opportunityEvidenceBody.innerHTML = '<div class="market-intel-empty">讀取機會威脅證據包中...</div>';
try {
const response = await fetch(opportunityEvidenceEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderOpportunityEvidenceMeta(data);
renderOpportunityEvidenceBody(data);
} catch (error) {
opportunityEvidenceMeta.innerHTML = '<span class="market-intel-pill">error</span>';
opportunityEvidenceBody.innerHTML = `<div class="market-intel-empty">機會威脅證據包讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderOpportunityAlertMeta = data => {
opportunityAlertMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_alert_candidates ? 'yes' : 'no'}`,
`channels=${data.channel_count || 0}`,
`review=${data.review_state_count || 0}`,
`queue_contract=${data.review_queue_contract_defined ? 'defined' : 'missing'}`,
`telegram=${data.telegram_dispatched ? 'sent' : 'blocked'}`,
`llm=${data.llm_call_executed ? 'called' : 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderOpportunityAlertBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.gate_checks || {});
const channels = data.channels || [];
const gates = data.alert_gates || [];
const throttle = data.throttle_policy || {};
const reviewStates = data.review_states || [];
const reviewActions = data.review_actions || [];
const queueContract = data.review_queue_contract || {};
const queueIndexes = data.review_queue_indexes || [];
const priorityLanes = data.review_priority_lanes || [];
const approval = data.approval_policy || {};
const sequence = data.operator_sequence || [];
const payload = data.payload_contract || {};
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderChannel = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)} / minimum=${escapeHtml(item.minimum_level)}</small>
<small>approval=${item.requires_operator_approval ? 'required' : 'not_required'} / target=${escapeHtml(item.dispatch_target)}</small>
</article>
`;
const renderReviewState = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)} / ${escapeHtml(item.description)}</small>
</div>
<span>${item.dispatch_allowed ? 'DISPATCH' : 'BLOCK'}</span>
</div>
`;
const renderReviewAction = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml((item.from || []).join(' / '))}${escapeHtml(item.to)}</small>
<small>reason=${item.requires_reason ? 'required' : 'optional'}</small>
</article>
`;
const renderPriorityLane = item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)} / threshold=${escapeHtml(item.minimum_threshold)}</small>
<small>max_age=${escapeHtml(item.max_age_hours)}h</small>
</article>
`;
const renderQueueIndex = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml((item.columns || []).join(' / '))} · ${escapeHtml(item.purpose)}</small>
</div>
<span>PLANNED</span>
</div>
`;
opportunityAlertBody.innerHTML = `
<div class="market-intel-empty mb-3">目前只定義告警候選、人工審核流程與審核佇列資料契約;不建立 alert queue、不建立 review queue、不建立 review table、不執行審核動作、不派送 Telegram、不呼叫 LLM、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">dedupe=${escapeHtml(throttle.dedupe_window_hours || 'n/a')}h / telegram_daily=${escapeHtml(throttle.max_telegram_candidates_per_day || 0)} / ai_digest=${escapeHtml(throttle.max_ai_briefing_items_per_digest || 0)}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-opportunity-alert-checks>
<p class="market-intel-deploy-section-title">ALERT GATES</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供告警 gate。</div>'
}</div>
</div>
<div data-market-intel-opportunity-alert-channels>
<p class="market-intel-deploy-section-title">CHANNELS</p>
<div class="market-intel-operation-list">${
channels.length
? channels.map(renderChannel).join('')
: '<div class="market-intel-empty">尚未提供 channel。</div>'
}</div>
</div>
<div data-market-intel-opportunity-alert-escalation>
<p class="market-intel-deploy-section-title">ESCALATION</p>
<div class="market-intel-check-list">${
gates.length
? gates.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${escapeHtml((item.required_for || []).join('/'))}</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供升級 gate。</div>'
}</div>
</div>
<div data-market-intel-opportunity-alert-payload>
<p class="market-intel-deploy-section-title">PAYLOAD CONTRACT</p>
<div class="market-intel-check-list">
<div class="market-intel-check">
<div>
<strong>required_fields</strong>
<small>${escapeHtml((payload.required_fields || []).join(' / '))}</small>
</div>
<span>REQUIRED</span>
</div>
<div class="market-intel-check">
<div>
<strong>forbidden_fields</strong>
<small>${escapeHtml((payload.forbidden_fields || []).join(' / '))}</small>
</div>
<span>BLOCKED</span>
</div>
</div>
</div>
<div data-market-intel-opportunity-alert-review>
<p class="market-intel-deploy-section-title">REVIEW STATES</p>
<div class="market-intel-check-list">${
reviewStates.length
? reviewStates.map(renderReviewState).join('')
: '<div class="market-intel-empty">尚未提供審核狀態。</div>'
}</div>
</div>
<div data-market-intel-opportunity-alert-actions>
<p class="market-intel-deploy-section-title">REVIEW ACTIONS</p>
<div class="market-intel-operation-list">${
reviewActions.length
? reviewActions.map(renderReviewAction).join('')
: '<div class="market-intel-empty">尚未提供審核操作。</div>'
}</div>
</div>
<div data-market-intel-opportunity-alert-queue-contract>
<p class="market-intel-deploy-section-title">REVIEW QUEUE CONTRACT</p>
<div class="market-intel-check-list">
<div class="market-intel-check">
<div>
<strong>${escapeHtml(queueContract.table_name || 'market_alert_review_queue')}</strong>
<small>pk=${escapeHtml(queueContract.primary_key || 'id')}</small>
</div>
<span>PREVIEW</span>
</div>
<div class="market-intel-check">
<div>
<strong>required_fields</strong>
<small>${escapeHtml((queueContract.required_fields || []).join(' / '))}</small>
</div>
<span>REQUIRED</span>
</div>
<div class="market-intel-check">
<div>
<strong>audit_fields</strong>
<small>${escapeHtml((queueContract.audit_fields || []).join(' / '))}</small>
</div>
<span>AUDIT</span>
</div>
</div>
</div>
<div data-market-intel-opportunity-alert-priority-lanes>
<p class="market-intel-deploy-section-title">PRIORITY LANES</p>
<div class="market-intel-operation-list">${
priorityLanes.length
? priorityLanes.map(renderPriorityLane).join('')
: '<div class="market-intel-empty">尚未提供優先級 lane。</div>'
}</div>
</div>
<div data-market-intel-opportunity-alert-queue-indexes>
<p class="market-intel-deploy-section-title">QUEUE INDEXES</p>
<div class="market-intel-check-list">${
queueIndexes.length
? queueIndexes.map(renderQueueIndex).join('')
: '<div class="market-intel-empty">尚未提供索引規劃。</div>'
}</div>
</div>
<div data-market-intel-opportunity-alert-approval>
<p class="market-intel-deploy-section-title">APPROVAL POLICY</p>
<div class="market-intel-check-list">${
Object.entries(approval).map(([key, value]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(key)}</strong>
</div>
<span>${value ? 'REQUIRED' : 'BLOCK'}</span>
</div>
`).join('')
}</div>
</div>
<div data-market-intel-opportunity-alert-sequence>
<p class="market-intel-deploy-section-title">OPERATOR SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.length
? sequence.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`step_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>REQUIRED</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供操作順序。</div>'
}</div>
</div>
</div>
`;
};
const loadOpportunityAlert = async () => {
if (!opportunityAlertMeta || !opportunityAlertBody) return;
opportunityAlertBody.innerHTML = '<div class="market-intel-empty">讀取機會威脅告警候選中...</div>';
try {
const response = await fetch(opportunityAlertEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderOpportunityAlertMeta(data);
renderOpportunityAlertBody(data);
} catch (error) {
opportunityAlertMeta.innerHTML = '<span class="market-intel-pill">error</span>';
opportunityAlertBody.innerHTML = `<div class="market-intel-empty">機會威脅告警候選讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderMigrationMeta = data => {
const seedWriter = data.command_plan && data.command_plan.seed_writer_command
? data.command_plan.seed_writer_command
: {};
migrationMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`tables=${data.table_count || 0}`,
`file=${data.file_created ? 'created' : 'preview'}`,
`executed=${data.migration_executed ? 'yes' : 'no'}`,
`additive=${data.safety_checks && data.safety_checks.forward_sql_additive_only ? 'yes' : 'no'}`,
`seed_script=${seedWriter.script_created ? 'created' : 'missing'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderMigrationBody = data => {
const operations = (data.table_operations || []).slice(0, 8);
const blockers = (data.blocked_reasons || []).join(' / ');
const commands = data.command_plan || {};
const migrationCommand = commands.migration_apply_command || {};
const seedCommand = commands.seed_writer_command || {};
migrationBody.innerHTML = `
<div class="market-intel-empty mb-3">
建議檔名:${escapeHtml(data.suggested_filename || '')}${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}
</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-migration-tables>
<p class="market-intel-deploy-section-title">TABLE DRAFT</p>
<div class="market-intel-operation-list">${
operations.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.table)}</strong>
<small>${escapeHtml(item.operation)} / ${escapeHtml(item.write_status)}</small>
</article>
`).join('')
}</div>
</div>
<div data-market-intel-migration-commands>
<p class="market-intel-deploy-section-title">COMMAND DESIGN</p>
<div class="market-intel-check-list">
<div class="market-intel-check">
<div>
<strong>migration_apply_command</strong>
<small>${escapeHtml(migrationCommand.command || '')}</small>
</div>
<span>${migrationCommand.executed ? 'EXECUTED' : 'BLOCKED'}</span>
</div>
<div class="market-intel-check">
<div>
<strong>seed_writer_command</strong>
<small>${escapeHtml(seedCommand.command || '')}</small>
<small>${escapeHtml(seedCommand.notes || '')}</small>
</div>
<span>${seedCommand.executed ? 'EXECUTED' : seedCommand.script_created ? 'SCRIPT' : 'DESIGN'}</span>
</div>
</div>
</div>
</div>
`;
};
const loadMigration = async () => {
if (!migrationMeta || !migrationBody) return;
migrationBody.innerHTML = '<div class="market-intel-empty">讀取 migration 草案中...</div>';
try {
const response = await fetch(migrationEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderMigrationMeta(data);
renderMigrationBody(data);
} catch (error) {
migrationMeta.innerHTML = '<span class="market-intel-pill">error</span>';
migrationBody.innerHTML = `<div class="market-intel-empty">migration 草案讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderMigrationDrillMeta = data => {
migrationDrillMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`schema=${data.schema_state || 'unknown'}`,
`probe=${data.read_only_query_executed ? 'read-only' : 'planned'}`,
`review=${data.drill_ready_for_operator_review ? 'ready' : 'blocked'}`,
`apply=${data.ready_to_apply_migration ? 'yes' : 'manual'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderMigrationDrillBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.checks || {});
const preApply = data.pre_apply_checklist || [];
const postApply = data.post_apply_verification || [];
const rollback = data.rollback_drill || {};
const risks = data.risk_register || [];
const commands = data.manual_commands || {};
const schema = data.schema_db_probe_summary || {};
const seedDiff = data.platform_seed_db_diff_summary || {};
const renderStep = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key || item.label || 'step')}</strong>
<small>${escapeHtml(item.label || item.key || '')}</small>
</div>
<span>${escapeHtml(item.status || 'required').toUpperCase()}</span>
</div>
`;
migrationDrillBody.innerHTML = `
<div class="market-intel-empty mb-3">此演練只集中正式 migration 前的只讀探測、人工套用清單與回滾演練API 不執行 psql、不寫 DB、不跑 rollback、不重啟容器。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">schema_missing=${escapeHtml((schema.missing_tables || []).length)} / seed_missing=${escapeHtml((seedDiff.missing_codes || []).length)} / command=${escapeHtml(commands.migration_apply || '')}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-migration-drill-checks>
<p class="market-intel-deploy-section-title">DRILL CHECKS</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供 drill check。</div>'
}</div>
</div>
<div data-market-intel-migration-drill-preapply>
<p class="market-intel-deploy-section-title">PRE-APPLY</p>
<div class="market-intel-check-list">${
preApply.length
? preApply.map(renderStep).join('')
: '<div class="market-intel-empty">尚未提供套用前清單。</div>'
}</div>
</div>
<div data-market-intel-migration-drill-postapply>
<p class="market-intel-deploy-section-title">POST-APPLY</p>
<div class="market-intel-check-list">${
postApply.length
? postApply.map(renderStep).join('')
: '<div class="market-intel-empty">尚未提供套用後驗證。</div>'
}</div>
</div>
<div data-market-intel-migration-drill-rollback>
<p class="market-intel-deploy-section-title">ROLLBACK DRILL</p>
<div class="market-intel-check-list">
<div class="market-intel-check">
<div>
<strong>${escapeHtml(rollback.mode || 'rollback_drill')}</strong>
<small>${escapeHtml(rollback.manual_command_shape || '')}</small>
</div>
<span>${rollback.rollback_executed ? 'EXECUTED' : 'MANUAL'}</span>
</div>
${(rollback.fallback_first || []).map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`fallback_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>FIRST</span>
</div>
`).join('')}
</div>
</div>
<div data-market-intel-migration-drill-risks>
<p class="market-intel-deploy-section-title">RISK REGISTER</p>
<div class="market-intel-check-list">${
risks.length
? risks.map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
</div>
<span>${escapeHtml(item.severity || 'medium').toUpperCase()}</span>
</div>
`).join('')
: '<div class="market-intel-empty">尚未提供風險清單。</div>'
}</div>
</div>
</div>
`;
};
const loadMigrationDrill = async () => {
if (!migrationDrillMeta || !migrationDrillBody) return;
migrationDrillBody.innerHTML = '<div class="market-intel-empty">讀取 migration 套用演練中...</div>';
try {
const response = await fetch(migrationDrillEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderMigrationDrillMeta(data);
renderMigrationDrillBody(data);
} catch (error) {
migrationDrillMeta.innerHTML = '<span class="market-intel-pill">error</span>';
migrationDrillBody.innerHTML = `<div class="market-intel-empty">migration 套用演練讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderCatalogReviewMeta = data => {
catalogReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`catalog=${data.catalog_state || 'unknown'}`,
`risk=${data.risk_level || 'info'}`,
`tables=${data.table_catalog ? `${data.table_catalog.existing_count || 0}/${data.table_catalog.expected_count || 0}` : '0/0'}`,
`apply=${data.apply_path || 'blocked'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderCatalogReviewBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.safe_checks || {});
const tableCatalog = data.table_catalog || {};
const seedCatalog = data.seed_catalog || {};
const findings = data.findings || [];
const nextSteps = data.operator_next_steps || [];
const probeTargets = data.manual_probe_targets || [];
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderNamedItem = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key || item.label || 'item')}</strong>
<small>${escapeHtml(item.label || item.key || '')}</small>
</div>
<span>${escapeHtml(item.status || item.severity || 'review').toUpperCase()}</span>
</div>
`;
catalogReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只判讀正式 DB catalog 與 platform seed diff 的只讀結果API 不執行 migration、不寫 DB、不跑 rollback、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">tables=${escapeHtml(tableCatalog.existing_count || 0)}/${escapeHtml(tableCatalog.expected_count || 0)} / missing=${escapeHtml(tableCatalog.missing_count || 0)} / seed_missing=${escapeHtml((seedCatalog.missing_codes || []).length)} / seed_changed=${escapeHtml((seedCatalog.changed_codes || []).length)}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-catalog-review-checks>
<p class="market-intel-deploy-section-title">SAFE CHECKS</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供 safety checks。</div>'
}</div>
</div>
<div data-market-intel-catalog-review-findings>
<p class="market-intel-deploy-section-title">CATALOG FINDINGS</p>
<div class="market-intel-check-list">${
findings.length
? findings.map(renderNamedItem).join('')
: '<div class="market-intel-empty">尚未提供 catalog finding。</div>'
}</div>
</div>
<div data-market-intel-catalog-review-tables>
<p class="market-intel-deploy-section-title">TABLE STATUS</p>
<div class="market-intel-check-list">${
(tableCatalog.table_statuses || []).slice(0, 8).map(item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.table)}</strong>
</div>
<span>${item.exists ? 'EXISTS' : 'MISSING'}</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 table status。</div>'
}</div>
</div>
<div data-market-intel-catalog-review-next>
<p class="market-intel-deploy-section-title">NEXT STEPS</p>
<div class="market-intel-check-list">${
nextSteps.length
? nextSteps.map(renderNamedItem).join('')
: '<div class="market-intel-empty">尚未提供下一步。</div>'
}</div>
</div>
<div data-market-intel-catalog-review-probes>
<p class="market-intel-deploy-section-title">READ-ONLY PROBES</p>
<div class="market-intel-check-list">${
probeTargets.length
? probeTargets.map(item => renderNamedItem({ key: item, label: item, status: 'manual' })).join('')
: '<div class="market-intel-empty">尚未提供 probe targets。</div>'
}</div>
</div>
</div>
`;
};
const loadCatalogReview = async () => {
if (!catalogReviewMeta || !catalogReviewBody) return;
catalogReviewBody.innerHTML = '<div class="market-intel-empty">讀取正式 DB catalog 判讀中...</div>';
try {
const response = await fetch(catalogReviewEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderCatalogReviewMeta(data);
renderCatalogReviewBody(data);
} catch (error) {
catalogReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
catalogReviewBody.innerHTML = `<div class="market-intel-empty">正式 DB catalog 判讀讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderLiveSmokeMeta = data => {
liveSmokeMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`result=${data.smoke_result || 'planned'}`,
`catalog=${data.catalog_state || 'unknown'}`,
`passed=${data.live_smoke_passed ? 'yes' : 'no'}`,
`writes=${data.database_write_executed ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderLiveSmokeBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.safety_checks || {});
const summary = data.catalog_review_summary || {};
const tableCatalog = summary.table_catalog || {};
const seedCatalog = summary.seed_catalog || {};
const findings = summary.findings || [];
const steps = data.operator_next_steps || [];
const targets = data.manual_probe_targets || [];
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderNamedItem = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key || item.label || 'item')}</strong>
<small>${escapeHtml(item.label || item.key || '')}</small>
</div>
<span>${escapeHtml(item.status || item.severity || 'manual').toUpperCase()}</span>
</div>
`;
liveSmokeBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡預設不跑正式 DB 探測;操作員手動啟動只讀 smoke 模式時,只讀查 catalog / seed diff不執行 migration、不寫 DB、不跑 rollback。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">tables=${escapeHtml(tableCatalog.existing_count || 0)}/${escapeHtml(tableCatalog.expected_count || 0)} / seed_missing=${escapeHtml((seedCatalog.missing_codes || []).length)} / seed_changed=${escapeHtml((seedCatalog.changed_codes || []).length)} / tolerated_seed_error=${data.seed_probe_error_tolerated ? 'yes' : 'no'}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-live-smoke-checks>
<p class="market-intel-deploy-section-title">SMOKE CHECKS</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供 smoke checks。</div>'
}</div>
</div>
<div data-market-intel-live-smoke-findings>
<p class="market-intel-deploy-section-title">FINDINGS</p>
<div class="market-intel-check-list">${
findings.length
? findings.map(renderNamedItem).join('')
: '<div class="market-intel-empty">尚未提供 findings。</div>'
}</div>
</div>
<div data-market-intel-live-smoke-next>
<p class="market-intel-deploy-section-title">NEXT STEPS</p>
<div class="market-intel-check-list">${
steps.length
? steps.map(renderNamedItem).join('')
: '<div class="market-intel-empty">尚未提供下一步。</div>'
}</div>
</div>
<div data-market-intel-live-smoke-targets>
<p class="market-intel-deploy-section-title">MANUAL TARGETS</p>
<div class="market-intel-check-list">${
targets.length
? targets.map(item => renderNamedItem({ key: item, label: item, status: 'manual' })).join('')
: '<div class="market-intel-empty">尚未提供 targets。</div>'
}</div>
</div>
</div>
`;
};
const loadLiveSmoke = async () => {
if (!liveSmokeMeta || !liveSmokeBody) return;
liveSmokeBody.innerHTML = '<div class="market-intel-empty">讀取正式 DB 只讀 smoke 中...</div>';
try {
const response = await fetch(liveSmokeEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderLiveSmokeMeta(data);
renderLiveSmokeBody(data);
} catch (error) {
liveSmokeMeta.innerHTML = '<span class="market-intel-pill">error</span>';
liveSmokeBody.innerHTML = `<div class="market-intel-empty">正式 DB 只讀 smoke 讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderLiveInventoryMeta = data => {
liveInventoryMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`execute=${data.execute_requested ? 'true' : 'false'}`,
`query=${data.read_only_query_executed ? 'yes' : 'no'}`,
`tables=${(data.existing_tables || []).length}/${(data.expected_tables || []).length}`,
`rows=${data.total_rows || 0}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderLiveInventoryBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.safety_checks || {});
const tables = data.table_statuses || [];
const platformRows = data.platform_breakdown || [];
const campaignRows = data.campaign_status_breakdown || [];
const productRows = data.product_activity_summary || [];
const matchRows = data.match_status_breakdown || [];
const alertRows = data.alert_review_state_breakdown || [];
const crawlerRows = data.crawler_run_summary || [];
const renderCheck = ([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`;
const renderTable = item => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.table)}</strong>
</div>
<span>${item.row_count == null ? escapeHtml(item.status || 'planned').toUpperCase() : escapeHtml(item.row_count)}</span>
</div>
`;
const renderRow = (label, detail, status) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(label)}</strong>
<small>${escapeHtml(detail)}</small>
</div>
<span>${escapeHtml(status)}</span>
</div>
`;
liveInventoryBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡預設只顯示 planned操作員手動啟動只讀庫存模式時只查 market_* count / group by不寫 DB、不跑 migration、不掛 scheduler。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">summary_ready=${data.summary_ready ? 'yes' : 'no'} / missing=${escapeHtml((data.missing_tables || []).length)} / total_rows=${escapeHtml(data.total_rows || 0)}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-live-inventory-checks>
<p class="market-intel-deploy-section-title">SAFETY CHECKS</p>
<div class="market-intel-check-list">${
checks.length
? checks.map(renderCheck).join('')
: '<div class="market-intel-empty">尚未提供 safety checks。</div>'
}</div>
</div>
<div data-market-intel-live-inventory-tables>
<p class="market-intel-deploy-section-title">TABLE COUNTS</p>
<div class="market-intel-check-list">${
tables.length
? tables.map(renderTable).join('')
: '<div class="market-intel-empty">尚未提供 table count。</div>'
}</div>
</div>
<div data-market-intel-live-inventory-platforms>
<p class="market-intel-deploy-section-title">PLATFORMS</p>
<div class="market-intel-check-list">${
platformRows.length
? platformRows.map(item => renderRow(item.code, item.name || '', item.enabled ? 'ON' : 'OFF')).join('')
: '<div class="market-intel-empty">尚未載入平台資料。</div>'
}</div>
</div>
<div data-market-intel-live-inventory-campaigns>
<p class="market-intel-deploy-section-title">CAMPAIGNS</p>
<div class="market-intel-check-list">${
campaignRows.length
? campaignRows.map(item => renderRow(item.platform_code, item.status || 'unknown', item.campaign_count || 0)).join('')
: '<div class="market-intel-empty">尚未有活動資料。</div>'
}</div>
</div>
<div data-market-intel-live-inventory-products>
<p class="market-intel-deploy-section-title">PRODUCTS</p>
<div class="market-intel-check-list">${
productRows.length
? productRows.map(item => renderRow(item.platform_code, `active=${item.is_active ? 'yes' : 'no'} / latest=${item.latest_seen_at || 'n/a'}`, item.product_count || 0)).join('')
: '<div class="market-intel-empty">尚未有活動商品資料。</div>'
}</div>
</div>
<div data-market-intel-live-inventory-matches>
<p class="market-intel-deploy-section-title">MATCHES</p>
<div class="market-intel-check-list">${
matchRows.length
? matchRows.map(item => renderRow(item.match_status || 'unknown', `avg=${item.avg_match_score || 0}`, item.match_count || 0)).join('')
: '<div class="market-intel-empty">尚未有商品比對資料。</div>'
}</div>
</div>
<div data-market-intel-live-inventory-alerts>
<p class="market-intel-deploy-section-title">ALERT QUEUE</p>
<div class="market-intel-check-list">${
alertRows.length
? alertRows.map(item => renderRow(item.review_state || 'unknown', item.priority_lane || 'watch', item.alert_count || 0)).join('')
: '<div class="market-intel-empty">尚未有告警審核佇列資料。</div>'
}</div>
</div>
<div data-market-intel-live-inventory-crawler>
<p class="market-intel-deploy-section-title">CRAWLER RUNS</p>
<div class="market-intel-check-list">${
crawlerRows.length
? crawlerRows.map(item => renderRow(item.platform_code || 'all', `${item.status || 'unknown'} / dry=${item.dry_run ? 'yes' : 'no'}`, item.run_count || 0)).join('')
: '<div class="market-intel-empty">尚未有 crawler run 資料。</div>'
}</div>
</div>
</div>
`;
};
const loadLiveInventory = async () => {
if (!liveInventoryMeta || !liveInventoryBody) return;
liveInventoryBody.innerHTML = '<div class="market-intel-empty">讀取正式 DB 庫存總覽中...</div>';
try {
const response = await fetch(liveInventoryEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderLiveInventoryMeta(data);
renderLiveInventoryBody(data);
} catch (error) {
liveInventoryMeta.innerHTML = '<span class="market-intel-pill">error</span>';
liveInventoryBody.innerHTML = `<div class="market-intel-empty">正式 DB 庫存總覽讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderApprovalMeta = data => {
approvalMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.ready_for_real_write ? 'yes' : 'no'}`,
`gates=${(data.approval_gates || []).length}`,
`blocked=${(data.blocked_reasons || []).length}`,
`db_commit=${data.database_commit_executed ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderApprovalBody = data => {
const gates = data.approval_gates || [];
const sequence = (data.operator_sequence || []).slice(0, 6);
const rollback = data.rollback_plan || [];
const renderNamedItem = (item, status) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(item.key || item.label || 'item')}</strong>
<small>${escapeHtml(item.label || item.key || '')}</small>
</div>
<span>${escapeHtml(status).toUpperCase()}</span>
</div>
`;
approvalBody.innerHTML = `
<div class="market-intel-empty mb-3">正式寫入尚未批准;目前沒有 DB session、沒有 commit、沒有 scheduler attach。</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-approval-gates>
<p class="market-intel-deploy-section-title">APPROVAL GATES</p>
<div class="market-intel-check-list">${
gates.map(item => renderNamedItem(item, item.passed ? 'pass' : 'block')).join('')
}</div>
</div>
<div data-market-intel-approval-sequence>
<p class="market-intel-deploy-section-title">OPERATOR SEQUENCE</p>
<div class="market-intel-check-list">${
sequence.map(item => renderNamedItem(item, 'pending')).join('')
}</div>
</div>
<div data-market-intel-approval-rollback>
<p class="market-intel-deploy-section-title">ROLLBACK</p>
<div class="market-intel-check-list">${
rollback.map(item => renderNamedItem(item, 'ready')).join('')
}</div>
</div>
</div>
`;
};
const loadApproval = async () => {
if (!approvalMeta || !approvalBody) return;
approvalBody.innerHTML = '<div class="market-intel-empty">讀取批准檢查中...</div>';
try {
const response = await fetch(approvalEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderApprovalMeta(data);
renderApprovalBody(data);
} catch (error) {
approvalMeta.innerHTML = '<span class="market-intel-pill">error</span>';
approvalBody.innerHTML = `<div class="market-intel-empty">批准檢查讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderDeployMeta = data => {
deployMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`deployed=${data.production_deployed ? 'yes' : 'no'}`,
`commit=${data.git_committed ? 'yes' : 'no'}`,
`push=${data.git_pushed ? 'yes' : 'no'}`,
`ready=${data.ready_for_production_deploy ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
};
const renderDeployBody = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const checks = Object.entries(data.checks || {});
const steps = data.required_manual_steps || [];
const fallback = data.fallback_plan || [];
const boundaries = data.safe_deploy_boundaries || [];
const smokeTargets = data.production_smoke_targets || [];
const renderItem = (item, fallbackStatus) => {
const normalized = typeof item === 'string' ? { key: item, label: item } : (item || {});
const status = normalized.status || fallbackStatus || 'required';
return `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(normalized.key || normalized.label || 'item')}</strong>
<small>${escapeHtml(normalized.label || normalized.key || '')}</small>
${normalized.trigger ? `<small>trigger=${escapeHtml(normalized.trigger)}</small>` : ''}
</div>
<span>${escapeHtml(status).toUpperCase()}</span>
</div>
`;
};
deployBody.innerHTML = `
<div class="market-intel-empty mb-3">API 不執行推版;需由操作員依 app-only SOP 完成備份、同步、重啟與正式 smoke。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-check-list">${
checks.map(([name, passed]) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(name)}</strong>
</div>
<span>${passed ? 'PASS' : 'BLOCK'}</span>
</div>
`).join('')
}</div>
<div class="market-intel-deploy-grid">
<div data-market-intel-deploy-steps>
<p class="market-intel-deploy-section-title">MANUAL STEPS</p>
<div class="market-intel-check-list">${
steps.length
? steps.map(item => renderItem(item, 'pending')).join('')
: '<div class="market-intel-empty">尚未提供人工步驟。</div>'
}</div>
</div>
<div data-market-intel-deploy-fallback>
<p class="market-intel-deploy-section-title">備援方案</p>
<div class="market-intel-check-list">${
fallback.length
? fallback.map(item => renderItem(item, 'ready')).join('')
: '<div class="market-intel-empty">尚未提供備援方案。</div>'
}</div>
</div>
<div data-market-intel-deploy-boundaries>
<p class="market-intel-deploy-section-title">DEPLOY BOUNDARIES</p>
<div class="market-intel-check-list">${
boundaries.length
? boundaries.map(item => renderItem(item, 'required')).join('')
: '<div class="market-intel-empty">尚未提供部署邊界。</div>'
}</div>
</div>
<div data-market-intel-deploy-smoke>
<p class="market-intel-deploy-section-title">SMOKE TARGETS</p>
<div class="market-intel-check-list">${
smokeTargets.length
? smokeTargets.map(item => renderItem(String(item), 'required')).join('')
: '<div class="market-intel-empty">尚未提供 smoke 目標。</div>'
}</div>
</div>
</div>
`;
};
const loadDeploy = async () => {
if (!deployMeta || !deployBody) return;
deployBody.innerHTML = '<div class="market-intel-empty">讀取推版準備中...</div>';
try {
const response = await fetch(deployEndpoint, { credentials: 'same-origin' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
renderDeployMeta(data);
renderDeployBody(data);
} catch (error) {
deployMeta.innerHTML = '<span class="market-intel-pill">error</span>';
deployBody.innerHTML = `<div class="market-intel-empty">推版準備讀取失敗:${escapeHtml(error.message)}</div>`;
}
};
if (refresh) {
refresh.addEventListener('click', loadPreview);
}
if (writerRefresh) {
writerRefresh.addEventListener('click', loadWriter);
}
if (cliRefresh) {
cliRefresh.addEventListener('click', loadCli);
}
if (dbProbeRefresh) {
dbProbeRefresh.addEventListener('click', loadDbProbe);
}
if (seedDiffRefresh) {
seedDiffRefresh.addEventListener('click', loadSeedDiff);
}
if (legacyBridgeRefresh) {
legacyBridgeRefresh.addEventListener('click', loadLegacyBridge);
}
if (mcpReadinessRefresh) {
mcpReadinessRefresh.addEventListener('click', loadMcpReadiness);
}
if (mcpPreflightRefresh) {
mcpPreflightRefresh.addEventListener('click', loadMcpPreflight);
}
if (mcpActivationRefresh) {
mcpActivationRefresh.addEventListener('click', loadMcpActivation);
}
if (mcpFetchGateRefresh) {
mcpFetchGateRefresh.addEventListener('click', loadMcpFetchGate);
}
if (manualSampleRefresh) {
manualSampleRefresh.addEventListener('click', loadManualSample);
}
if (sampleAcceptanceRefresh) {
sampleAcceptanceRefresh.addEventListener('click', loadSampleAcceptance);
}
if (sampleReviewRefresh) {
sampleReviewRefresh.addEventListener('click', loadSampleReview);
}
if (sampleReviewEvaluate) {
sampleReviewEvaluate.addEventListener('click', evaluateSampleReview);
}
if (sampleCandidateHandoff) {
sampleCandidateHandoff.addEventListener('click', loadCandidateHandoff);
}
if (sampleCandidateQueueDraft) {
sampleCandidateQueueDraft.addEventListener('click', loadCandidateQueueDraft);
}
if (sampleCandidateQueueApproval) {
sampleCandidateQueueApproval.addEventListener('click', loadCandidateQueueApproval);
}
if (sampleCandidateQueueTransaction) {
sampleCandidateQueueTransaction.addEventListener('click', loadCandidateQueueTransaction);
}
if (sampleCandidateQueueWriter) {
sampleCandidateQueueWriter.addEventListener('click', loadCandidateQueueWriter);
}
if (sampleCandidateQueuePreflight) {
sampleCandidateQueuePreflight.addEventListener('click', loadCandidateQueuePreflight);
}
if (sampleCandidateQueuePostwriteSmoke) {
sampleCandidateQueuePostwriteSmoke.addEventListener('click', loadCandidateQueuePostwriteSmoke);
}
if (sampleCandidateQueueOperatorDrill) {
sampleCandidateQueueOperatorDrill.addEventListener('click', loadCandidateQueueOperatorDrill);
}
if (sampleCandidateQueueRunPackage) {
sampleCandidateQueueRunPackage.addEventListener('click', loadCandidateQueueRunPackage);
}
if (sampleCandidateQueueRunReadiness) {
sampleCandidateQueueRunReadiness.addEventListener('click', loadCandidateQueueRunReadiness);
}
if (sampleCandidateQueueRunReceipt) {
sampleCandidateQueueRunReceipt.addEventListener('click', loadCandidateQueueRunReceipt);
}
if (sampleCandidateQueueRunCloseout) {
sampleCandidateQueueRunCloseout.addEventListener('click', loadCandidateQueueRunCloseout);
}
if (sampleCandidateQueueReviewHandoff) {
sampleCandidateQueueReviewHandoff.addEventListener('click', loadCandidateQueueReviewHandoff);
}
if (sampleCandidateQueueReviewInventory) {
sampleCandidateQueueReviewInventory.addEventListener('click', loadCandidateQueueReviewInventory);
}
if (sampleCandidateQueueReviewDecision) {
sampleCandidateQueueReviewDecision.addEventListener('click', loadCandidateQueueReviewDecision);
}
if (sampleCandidateQueueReviewDecisionApproval) {
sampleCandidateQueueReviewDecisionApproval.addEventListener('click', loadCandidateQueueReviewDecisionApproval);
}
if (sampleCandidateQueueReviewDecisionTransaction) {
sampleCandidateQueueReviewDecisionTransaction.addEventListener('click', loadCandidateQueueReviewDecisionTransaction);
}
if (sampleCandidateQueueReviewDecisionPreflight) {
sampleCandidateQueueReviewDecisionPreflight.addEventListener('click', loadCandidateQueueReviewDecisionPreflight);
}
if (sampleCandidateQueueReviewDecisionPostwriteSmoke) {
sampleCandidateQueueReviewDecisionPostwriteSmoke.addEventListener('click', loadCandidateQueueReviewDecisionPostwriteSmoke);
}
if (sampleCandidateQueueReviewDecisionOperatorDrill) {
sampleCandidateQueueReviewDecisionOperatorDrill.addEventListener('click', loadCandidateQueueReviewDecisionOperatorDrill);
}
if (sampleCandidateQueueReviewDecisionRunPackage) {
sampleCandidateQueueReviewDecisionRunPackage.addEventListener('click', loadCandidateQueueReviewDecisionRunPackage);
}
if (sampleCandidateQueueReviewDecisionRunReadiness) {
sampleCandidateQueueReviewDecisionRunReadiness.addEventListener('click', loadCandidateQueueReviewDecisionRunReadiness);
}
if (sampleCandidateQueueReviewDecisionWriter) {
sampleCandidateQueueReviewDecisionWriter.addEventListener('click', loadCandidateQueueReviewDecisionWriter);
}
if (sampleCandidateQueueReviewDecisionRunReceipt) {
sampleCandidateQueueReviewDecisionRunReceipt.addEventListener('click', loadCandidateQueueReviewDecisionRunReceipt);
}
if (sampleCandidateQueueReviewDecisionRunCloseout) {
sampleCandidateQueueReviewDecisionRunCloseout.addEventListener('click', loadCandidateQueueReviewDecisionRunCloseout);
}
if (sampleCandidateQueueReviewDecisionPostCloseoutInventory) {
sampleCandidateQueueReviewDecisionPostCloseoutInventory.addEventListener('click', loadCandidateQueueReviewDecisionPostCloseoutInventory);
}
if (sampleCandidateQueueReviewCompletionArchive) {
sampleCandidateQueueReviewCompletionArchive.addEventListener('click', loadCandidateQueueReviewCompletionArchive);
}
if (sampleCandidateQueueReviewArchiveSummary) {
sampleCandidateQueueReviewArchiveSummary.addEventListener('click', loadCandidateQueueReviewArchiveSummary);
}
if (sampleCandidateQueueReviewAiSummaryPreflight) {
sampleCandidateQueueReviewAiSummaryPreflight.addEventListener('click', loadCandidateQueueReviewAiSummaryPreflight);
}
if (sampleCandidateQueueReviewAiSummaryRunPackage) {
sampleCandidateQueueReviewAiSummaryRunPackage.addEventListener('click', loadCandidateQueueReviewAiSummaryRunPackage);
}
if (sampleCandidateQueueReviewAiSummaryOutputReceipt) {
sampleCandidateQueueReviewAiSummaryOutputReceipt.addEventListener('click', loadCandidateQueueReviewAiSummaryOutputReceipt);
}
if (sampleCandidateQueueReviewAiSummaryPersistencePreflight) {
sampleCandidateQueueReviewAiSummaryPersistencePreflight.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistencePreflight);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTransaction) {
sampleCandidateQueueReviewAiSummaryPersistenceTransaction.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTransaction);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceWriterPreflight) {
sampleCandidateQueueReviewAiSummaryPersistenceWriterPreflight.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceWriterPreflight);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceRunPackage) {
sampleCandidateQueueReviewAiSummaryPersistenceRunPackage.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceRunPackage);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceRunReadiness) {
sampleCandidateQueueReviewAiSummaryPersistenceRunReadiness.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceRunReadiness);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceRunReceipt) {
sampleCandidateQueueReviewAiSummaryPersistenceRunReceipt.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceRunReceipt);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceRunCloseout) {
sampleCandidateQueueReviewAiSummaryPersistenceRunCloseout.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceRunCloseout);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchGate) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchGate.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchGate);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunPackage) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunPackage.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunPackage);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReadiness) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReadiness.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReadiness);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReceipt) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReceipt.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchRunReceipt);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchCloseout) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchCloseout.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchCloseout);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchive) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchive.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchive);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveSummary) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveSummary.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchArchiveSummary);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportInput) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportInput.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportInput);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunPackage) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunPackage.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunPackage);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReadiness) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReadiness.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReadiness);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReceipt) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReceipt.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportRunReceipt);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCloseout) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCloseout.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCloseout);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchive) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchive.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchive);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveSummary) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveSummary.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportArchiveSummary);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogHandoff) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogHandoff.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogHandoff);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogIndex) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogIndex.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogIndex);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogWritePreflight) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogWritePreflight.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogWritePreflight);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordWrite) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordWrite.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordWrite);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunPackage) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunPackage.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunPackage);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReadiness) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReadiness.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReadiness);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReceipt) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReceipt.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordRunReceipt);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCommit) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCommit.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCommit);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCloseout) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCloseout.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordCloseout);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchive) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchive.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchive);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveSummary) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveSummary.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordArchiveSummary);
}
if (sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordFinalCloseout) {
sampleCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordFinalCloseout.addEventListener('click', loadCandidateQueueReviewAiSummaryPersistenceTelegramDispatchReportCatalogRecordFinalCloseout);
}
if (schedulerRefresh) {
schedulerRefresh.addEventListener('click', loadScheduler);
}
if (matchReviewRefresh) {
matchReviewRefresh.addEventListener('click', loadMatchReview);
}
if (opportunityRefresh) {
opportunityRefresh.addEventListener('click', loadOpportunity);
}
if (opportunityScoringRefresh) {
opportunityScoringRefresh.addEventListener('click', loadOpportunityScoring);
}
if (opportunityEvidenceRefresh) {
opportunityEvidenceRefresh.addEventListener('click', loadOpportunityEvidence);
}
if (opportunityAlertRefresh) {
opportunityAlertRefresh.addEventListener('click', loadOpportunityAlert);
}
if (migrationRefresh) {
migrationRefresh.addEventListener('click', loadMigration);
}
if (migrationDrillRefresh) {
migrationDrillRefresh.addEventListener('click', loadMigrationDrill);
}
if (catalogReviewRefresh) {
catalogReviewRefresh.addEventListener('click', loadCatalogReview);
}
if (liveSmokeRefresh) {
liveSmokeRefresh.addEventListener('click', loadLiveSmoke);
}
if (liveInventoryRefresh) {
liveInventoryRefresh.addEventListener('click', loadLiveInventory);
}
if (approvalRefresh) {
approvalRefresh.addEventListener('click', loadApproval);
}
if (deployRefresh) {
deployRefresh.addEventListener('click', loadDeploy);
}
loadPreview();
loadWriter();
loadCli();
loadDbProbe();
loadSeedDiff();
loadLegacyBridge();
loadMcpReadiness();
loadMcpPreflight();
loadMcpActivation();
loadMcpFetchGate();
loadManualSample();
loadSampleAcceptance();
loadSampleReview();
loadScheduler();
loadMatchReview();
loadOpportunity();
loadOpportunityScoring();
loadOpportunityEvidence();
loadOpportunityAlert();
loadMigration();
loadMigrationDrill();
loadCatalogReview();
loadLiveSmoke();
loadLiveInventory();
loadApproval();
loadDeploy();
})();
</script>
{% endblock %}