feat(awooop): surface telegram verifier receipts
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 39s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped

This commit is contained in:
Your Name
2026-07-02 21:47:47 +08:00
parent f165555a92
commit c3442ebe41
3 changed files with 254 additions and 1 deletions

View File

@@ -252,6 +252,34 @@ type LogConsumerReadbackPayload = {
} | null;
};
type TelegramPostApplyVerifierPayload = {
status?: string | null;
active_blockers?: string[] | null;
rollups?: {
telegram_alert_learning_context_post_apply_verifier_ready?: boolean | null;
context_receipt_count?: number | null;
verified_context_receipt_count?: number | null;
verified_target_count?: number | null;
target_count?: number | null;
verified_ai_agent_context_receipt_count?: number | null;
post_apply_verifier_ref_count?: number | null;
metadata_only_receipt_count?: number | null;
raw_payload_included_count?: number | null;
secret_value_read_count?: number | null;
runtime_write_performed_count?: number | null;
telegram_send_performed_count?: number | null;
failed_context_receipt_count?: number | null;
verified_targets?: string[] | null;
} | null;
operation_boundaries?: {
raw_payload_included?: boolean | null;
secret_value_collection_allowed?: boolean | null;
runtime_target_write_performed?: boolean | null;
telegram_send_performed?: boolean | null;
github_api_used?: boolean | null;
} | null;
};
type PanelMode = "full" | "compact";
type Tone = "ok" | "warn" | "neutral";
type WorkFilter = "all" | "completed" | "active" | "pending" | "blocked";
@@ -376,6 +404,23 @@ async function fetchLogConsumerReadback(): Promise<LogConsumerReadbackPayload |
}
}
async function fetchTelegramPostApplyVerifier(): Promise<TelegramPostApplyVerifierPayload | null> {
const controller = new AbortController();
const timeout = window.setTimeout(() => controller.abort(), 12_000);
try {
const response = await fetch(`${API_BASE}/api/v1/agents/telegram-alert-learning-context-post-apply-verifier`, {
cache: "no-store",
signal: controller.signal,
});
if (!response.ok) return null;
return (await response.json()) as TelegramPostApplyVerifierPayload;
} catch {
return null;
} finally {
window.clearTimeout(timeout);
}
}
export function AutonomousRuntimeReceiptPanel({
mode = "full",
}: {
@@ -386,6 +431,7 @@ export function AutonomousRuntimeReceiptPanel({
const [payload, setPayload] = useState<RuntimeControlPayload | null>(null);
const [priorityPayload, setPriorityPayload] = useState<PriorityWorkOrderPayload | null>(null);
const [consumerPayload, setConsumerPayload] = useState<LogConsumerReadbackPayload | null>(null);
const [telegramVerifierPayload, setTelegramVerifierPayload] = useState<TelegramPostApplyVerifierPayload | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const [updatedAt, setUpdatedAt] = useState<Date | null>(null);
@@ -393,14 +439,16 @@ export function AutonomousRuntimeReceiptPanel({
const refresh = useCallback(async () => {
setLoading(true);
const [next, priority, consumer] = await Promise.all([
const [next, priority, consumer, telegramVerifier] = await Promise.all([
fetchRuntimeControl(),
fetchPriorityWorkOrder(),
fetchLogConsumerReadback(),
fetchTelegramPostApplyVerifier(),
]);
setPayload(next);
setPriorityPayload(priority);
setConsumerPayload(consumer);
setTelegramVerifierPayload(telegramVerifier);
setError(next === null);
setUpdatedAt(next ? new Date() : null);
setLoading(false);
@@ -415,6 +463,7 @@ export function AutonomousRuntimeReceiptPanel({
const hasRuntimeReadback = payload !== null;
const hasPriorityReadback = priorityPayload !== null;
const hasConsumerReadback = consumerPayload !== null;
const hasTelegramVerifierReadback = telegramVerifierPayload !== null;
const readback = payload?.runtime_receipt_readback;
const ledger = readback?.autonomous_execution_loop_ledger;
const traceLedger = readback?.trace_ledger;
@@ -434,8 +483,13 @@ export function AutonomousRuntimeReceiptPanel({
const rollups = payload?.rollups ?? {};
const consumerRollups = consumerPayload?.rollups ?? {};
const consumerBlockers = consumerPayload?.active_blockers ?? [];
const telegramVerifierRollups = telegramVerifierPayload?.rollups ?? {};
const telegramVerifierBlockers = telegramVerifierPayload?.active_blockers ?? [];
const consumerReady = consumerRollups.controlled_consumer_readback_ready === true
|| consumerPayload?.status === "controlled_writeback_consumer_readback_ready";
const telegramPostApplyVerifierReady =
telegramVerifierRollups.telegram_alert_learning_context_post_apply_verifier_ready === true
|| telegramVerifierPayload?.status === "telegram_alert_learning_context_post_apply_verified";
const runtimeTargetWritePerformed = consumerRollups.runtime_target_write_performed === true
|| consumerPayload?.controlled_consume?.runtime_target_write_performed === true
|| consumerPayload?.operation_boundaries?.runtime_target_write_performed === true
@@ -887,6 +941,121 @@ export function AutonomousRuntimeReceiptPanel({
icon: Rocket,
},
];
const telegramVerifierCards = [
{
key: "status",
label: t("postApplyVerifier.status"),
value: !hasTelegramVerifierReadback
? t("states.loading")
: telegramPostApplyVerifierReady
? t("states.closed")
: t("states.open"),
detail: t("postApplyVerifier.statusDetail"),
icon: ShieldCheck,
tone: !hasTelegramVerifierReadback
? "neutral" as Tone
: telegramPostApplyVerifierReady ? "ok" as Tone : "warn" as Tone,
},
{
key: "contexts",
label: t("postApplyVerifier.contexts"),
value: readbackRatio(
telegramVerifierRollups.verified_context_receipt_count,
telegramVerifierRollups.context_receipt_count,
hasTelegramVerifierReadback
),
detail: t("postApplyVerifier.contextsDetail"),
icon: ListChecks,
tone: !hasTelegramVerifierReadback
? "neutral" as Tone
: toNumber(telegramVerifierRollups.failed_context_receipt_count) === 0
&& toNumber(telegramVerifierRollups.verified_context_receipt_count) > 0
? "ok" as Tone
: "warn" as Tone,
},
{
key: "targets",
label: t("postApplyVerifier.targets"),
value: readbackRatio(
telegramVerifierRollups.verified_target_count,
telegramVerifierRollups.target_count,
hasTelegramVerifierReadback
),
detail: t("postApplyVerifier.targetsDetail"),
icon: Database,
tone: !hasTelegramVerifierReadback
? "neutral" as Tone
: toNumber(telegramVerifierRollups.verified_target_count) === toNumber(telegramVerifierRollups.target_count)
&& toNumber(telegramVerifierRollups.target_count) > 0
? "ok" as Tone
: "warn" as Tone,
},
{
key: "aiAgent",
label: t("postApplyVerifier.aiAgent"),
value: readbackNumber(
telegramVerifierRollups.verified_ai_agent_context_receipt_count,
hasTelegramVerifierReadback
),
detail: t("postApplyVerifier.aiAgentDetail"),
icon: Rocket,
tone: !hasTelegramVerifierReadback
? "neutral" as Tone
: toNumber(telegramVerifierRollups.verified_ai_agent_context_receipt_count) > 0
? "ok" as Tone
: "warn" as Tone,
},
{
key: "refs",
label: t("postApplyVerifier.refs"),
value: readbackNumber(
telegramVerifierRollups.post_apply_verifier_ref_count,
hasTelegramVerifierReadback
),
detail: t("postApplyVerifier.refsDetail"),
icon: Gauge,
tone: !hasTelegramVerifierReadback
? "neutral" as Tone
: toNumber(telegramVerifierRollups.post_apply_verifier_ref_count) > 0
? "ok" as Tone
: "warn" as Tone,
},
{
key: "boundaries",
label: t("postApplyVerifier.boundaries"),
value: readbackRatio(
telegramVerifierRollups.raw_payload_included_count,
telegramVerifierRollups.secret_value_read_count,
hasTelegramVerifierReadback
),
detail: t("postApplyVerifier.boundariesDetail", {
runtime: readbackNumber(telegramVerifierRollups.runtime_write_performed_count, hasTelegramVerifierReadback),
telegram: readbackNumber(telegramVerifierRollups.telegram_send_performed_count, hasTelegramVerifierReadback),
}),
icon: TriangleAlert,
tone: !hasTelegramVerifierReadback
? "neutral" as Tone
: toNumber(telegramVerifierRollups.raw_payload_included_count) === 0
&& toNumber(telegramVerifierRollups.secret_value_read_count) === 0
&& telegramVerifierPayload?.operation_boundaries?.github_api_used !== true
? "ok" as Tone
: "warn" as Tone,
},
{
key: "blockers",
label: t("postApplyVerifier.blockers"),
value: readbackNumber(telegramVerifierBlockers.length, hasTelegramVerifierReadback),
detail: !hasTelegramVerifierReadback
? t("states.loading")
: telegramVerifierBlockers.length > 0
? telegramVerifierBlockers[0]
: t("postApplyVerifier.noBlockers"),
icon: TriangleAlert,
tone: !hasTelegramVerifierReadback
? "neutral" as Tone
: telegramVerifierBlockers.length > 0 ? "warn" as Tone : "ok" as Tone,
},
];
const visibleWorkItems = orderedWorkItems.filter((item) => matchesWorkFilter(item, workFilter));
const orderedCompleted = orderedWorkItems.filter((item) => item.status === "completed").length;
const orderedActive = orderedWorkItems.filter((item) => (
@@ -1032,6 +1201,54 @@ export function AutonomousRuntimeReceiptPanel({
);
})}
</div>
<div
data-testid="telegram-alert-post-apply-verifier-readback"
className="border-t border-[#e0ddd4] bg-white"
>
<div className="flex flex-wrap items-start justify-between gap-3 px-4 py-3">
<div className="min-w-0">
<div className="flex items-center gap-2">
<ShieldCheck className="h-4 w-4 text-[#87867f]" aria-hidden="true" />
<h4 className="text-sm font-semibold text-[#141413]">{t("postApplyVerifier.title")}</h4>
</div>
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
{t("postApplyVerifier.subtitle")}
</p>
</div>
<span className={cn("inline-flex border px-2 py-0.5 text-xs font-semibold", toneClass(
!hasTelegramVerifierReadback
? "neutral"
: telegramPostApplyVerifierReady ? "ok" : "warn"
))}>
{!hasTelegramVerifierReadback
? t("states.loading")
: telegramVerifierPayload?.status ?? "--"}
</span>
</div>
<div className="grid gap-px border-t border-[#e0ddd4] bg-[#e0ddd4] md:grid-cols-3 xl:grid-cols-7">
{telegramVerifierCards.map((card) => {
const Icon = card.icon;
return (
<div key={card.key} className="bg-white px-4 py-3">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-xs font-semibold text-[#77736a]">{card.label}</p>
<p className="mt-2 truncate font-mono text-lg font-semibold text-[#141413]">
{card.value}
</p>
</div>
<span className={cn("flex h-8 w-8 shrink-0 items-center justify-center border", toneClass(card.tone))}>
<Icon className="h-4 w-4" aria-hidden="true" />
</span>
</div>
<p className="mt-1 line-clamp-2 text-xs leading-5 text-[#5f5b52]">
{card.detail}
</p>
</div>
);
})}
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-px bg-[#e0ddd4] md:grid-cols-5 xl:grid-cols-12">