fix: gate trusted records on durable runtime
This commit is contained in:
@@ -847,6 +847,7 @@ function normalizePort(port) {
|
||||
}
|
||||
|
||||
function trustedM3LiveEvidenceFrom(summary) {
|
||||
if (!isDurableRuntimeReady(summary)) return null;
|
||||
const candidates = [
|
||||
summary?.m3TrustedLoop,
|
||||
summary?.m3HardwareLoop,
|
||||
@@ -858,6 +859,28 @@ function trustedM3LiveEvidenceFrom(summary) {
|
||||
return candidates.find(hasTrustedM3LiveEvidence) ?? null;
|
||||
}
|
||||
|
||||
function liveRecordTone(record, live) {
|
||||
const runtimeSummary = runtimeSummaryFrom(live);
|
||||
return isDurableRuntimeReady(runtimeSummary) && hasTrustedM3LiveEvidence(record) ? "dev-live" : "blocked";
|
||||
}
|
||||
|
||||
function liveRecordDurabilityBlocker(live) {
|
||||
const runtimeSummary = runtimeSummaryFrom(live);
|
||||
if (isDurableRuntimeReady(runtimeSummary)) return null;
|
||||
if (runtimeSummary?.durable !== true) {
|
||||
return "runtime.durable=false;只读 audit/evidence 不能标为 durable ready 或 DEV-LIVE。";
|
||||
}
|
||||
return `runtime durable adapter 未 ready(status=${runtimeSummary?.status ?? "unknown"});可信记录保持 BLOCKED。`;
|
||||
}
|
||||
|
||||
function isDurableRuntimeReady(summary) {
|
||||
if (!summary || typeof summary !== "object") return false;
|
||||
if (summary.durable !== true) return false;
|
||||
if (summary.ready === false) return false;
|
||||
if (summary.liveRuntimeEvidence !== true) return false;
|
||||
return !["blocked", "degraded", "failed"].includes(String(summary.status ?? "").toLowerCase());
|
||||
}
|
||||
|
||||
function hasTrustedM3LiveEvidence(candidate) {
|
||||
if (!candidate || typeof candidate !== "object") return false;
|
||||
if (candidate.dryRun === true || candidate.fixture === true || candidate.sourceKind === "SOURCE" || candidate.sourceKind === "DRY-RUN") return false;
|
||||
@@ -1053,7 +1076,7 @@ function auditRecordCards(live) {
|
||||
tone: "source"
|
||||
}));
|
||||
} else {
|
||||
cards.push(...liveEvents.map((event) => auditCard(event, hasTrustedM3LiveEvidence(event) ? "dev-live" : "blocked")));
|
||||
cards.push(...liveEvents.map((event) => auditCard(event, liveRecordTone(event, live), liveRecordDurabilityBlocker(live))));
|
||||
}
|
||||
} else {
|
||||
cards.push(liveFailureCard("audit.event.query", live.audit.error));
|
||||
@@ -1082,7 +1105,7 @@ function evidenceRecordCards(live) {
|
||||
tone: "source"
|
||||
}));
|
||||
} else {
|
||||
cards.push(...liveRecords.map((record) => evidenceCard(record, hasTrustedM3LiveEvidence(record) ? "dev-live" : "blocked")));
|
||||
cards.push(...liveRecords.map((record) => evidenceCard(record, liveRecordTone(record, live), liveRecordDurabilityBlocker(live))));
|
||||
}
|
||||
} else {
|
||||
cards.push(liveFailureCard("evidence.record.query", live.evidence.error));
|
||||
@@ -1099,11 +1122,12 @@ function evidenceRecordCards(live) {
|
||||
return cards;
|
||||
}
|
||||
|
||||
function auditCard(event, tone) {
|
||||
function auditCard(event, tone, durabilityBlocker = null) {
|
||||
return infoCard({
|
||||
title: event.auditId,
|
||||
detail: [
|
||||
sourceKindLabel(tone),
|
||||
durabilityBlocker,
|
||||
tone === "blocked" ? "只读 audit 缺少 M3 patch-panel live report / operation / trace / evidence 绑定" : null,
|
||||
recordField("action", event.action),
|
||||
recordField("target", event.targetId),
|
||||
@@ -1115,11 +1139,12 @@ function auditCard(event, tone) {
|
||||
});
|
||||
}
|
||||
|
||||
function evidenceCard(record, tone) {
|
||||
function evidenceCard(record, tone, durabilityBlocker = null) {
|
||||
return infoCard({
|
||||
title: record.evidenceId,
|
||||
detail: [
|
||||
sourceKindLabel(tone),
|
||||
durabilityBlocker,
|
||||
tone === "blocked" ? "只读 evidence 缺少 M3 patch-panel live report / operation / trace / audit 绑定" : null,
|
||||
recordKindLabel(record.kind ?? "record"),
|
||||
recordField("operation", record.operationId),
|
||||
|
||||
@@ -52,6 +52,7 @@ const requiredTrustedRecordTerms = Object.freeze([
|
||||
"conversationId、traceId 和 messageId",
|
||||
"provider/model/trace/conversation",
|
||||
"失败原因=",
|
||||
"runtime.durable=false;只读 audit/evidence 不能标为 durable ready 或 DEV-LIVE。",
|
||||
"只读 audit 缺少 M3 patch-panel live report / operation / trace / evidence 绑定",
|
||||
"只读 evidence 缺少 M3 patch-panel live report / operation / trace / audit 绑定",
|
||||
"当前显示 SOURCE 回退,不能冒充 DEV-LIVE"
|
||||
@@ -128,6 +129,13 @@ assert.match(app, /function auditRecordCards/);
|
||||
assert.match(app, /function evidenceRecordCards/);
|
||||
assert.match(app, /function auditCard/);
|
||||
assert.match(app, /function evidenceCard/);
|
||||
assert.match(app, /function liveRecordTone/);
|
||||
assert.match(app, /function liveRecordDurabilityBlocker/);
|
||||
assert.match(app, /function isDurableRuntimeReady/);
|
||||
assert.match(app, /runtimeSummary\?\.durable !== true/);
|
||||
assert.match(app, /summary\.liveRuntimeEvidence !== true/);
|
||||
assert.match(app, /auditCard\(event, liveRecordTone\(event, live\), liveRecordDurabilityBlocker\(live\)\)/);
|
||||
assert.match(app, /evidenceCard\(record, liveRecordTone\(record, live\), liveRecordDurabilityBlocker\(live\)\)/);
|
||||
assert.match(app, /function recordGroup/);
|
||||
assert.match(app, /function recordField/);
|
||||
assert.match(app, /function sourceKindLabel/);
|
||||
|
||||
Reference in New Issue
Block a user