新增市場情報 review decision writer postwrite smoke
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
This commit is contained in:
@@ -646,6 +646,9 @@
|
||||
<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 CLI gate" data-market-intel-sample-candidate-queue-review-decision-writer>
|
||||
<i class="fas fa-terminal" aria-hidden="true"></i>
|
||||
</button>
|
||||
@@ -992,6 +995,7 @@
|
||||
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 sampleCandidateQueueReviewDecisionWriter = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-review-decision-writer]') : null;
|
||||
const sampleReviewEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_review') }}";
|
||||
const sampleReviewEvaluateEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_review_evaluate') }}";
|
||||
@@ -1013,6 +1017,7 @@
|
||||
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 sampleCandidateQueueReviewDecisionWriterEndpoint = "{{ url_for('market_intel_review.market_intel_manual_sample_candidate_queue_review_decision_writer_status') }}";
|
||||
const schedulerMeta = schedulerRoot ? schedulerRoot.querySelector('[data-market-intel-scheduler-meta]') : null;
|
||||
const schedulerBody = schedulerRoot ? schedulerRoot.querySelector('[data-market-intel-scheduler-body]') : null;
|
||||
@@ -3738,6 +3743,117 @@
|
||||
}
|
||||
};
|
||||
|
||||
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 renderCandidateQueueReviewDecisionWriter = data => {
|
||||
const blockers = (data.blocked_reasons || []).join(' / ');
|
||||
const summary = data.statement_summary || {};
|
||||
@@ -5399,6 +5515,9 @@
|
||||
if (sampleCandidateQueueReviewDecisionPreflight) {
|
||||
sampleCandidateQueueReviewDecisionPreflight.addEventListener('click', loadCandidateQueueReviewDecisionPreflight);
|
||||
}
|
||||
if (sampleCandidateQueueReviewDecisionPostwriteSmoke) {
|
||||
sampleCandidateQueueReviewDecisionPostwriteSmoke.addEventListener('click', loadCandidateQueueReviewDecisionPostwriteSmoke);
|
||||
}
|
||||
if (sampleCandidateQueueReviewDecisionWriter) {
|
||||
sampleCandidateQueueReviewDecisionWriter.addEventListener('click', loadCandidateQueueReviewDecisionWriter);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user