create-principles-disciple 1.145.12 → 1.145.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/_release/product-identity.json +2 -2
  2. package/codex-adapter/package.json +1 -1
  3. package/console/dist/server/models/ActivationsConsoleModel.d.ts +3 -1
  4. package/console/dist/server/models/ActivationsConsoleModel.js +38 -4
  5. package/console/dist/server/models/ApprovalsConsoleModel.js +56 -7
  6. package/console/dist/server/models/ApprovalsGroupedConsoleModel.d.ts +12 -0
  7. package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +70 -13
  8. package/console/dist/server/routes/approvals-grouped.js +5 -2
  9. package/console/dist/shared/prompt-injection-contract.d.ts +58 -5
  10. package/console/dist/ui/i18n/en.json +25 -1
  11. package/console/dist/ui/i18n/zh-CN.json +25 -1
  12. package/console/dist/ui/pages/activation/ActivationPage.js +39 -1
  13. package/console/dist/ui/pages/focus/FocusPage.js +70 -28
  14. package/console/dist/ui/utils/validators.js +70 -11
  15. package/console/dist/web/assets/app.js +24 -24
  16. package/host-runtime/dist/index.d.ts +1 -0
  17. package/host-runtime/dist/index.js +4 -0
  18. package/host-runtime/dist/prompt-injection-budget-observation.d.ts +176 -0
  19. package/host-runtime/dist/prompt-injection-budget-observation.js +449 -0
  20. package/host-runtime/dist/prompt-injection-projection.d.ts +16 -0
  21. package/host-runtime/dist/prompt-injection-projection.js +18 -3
  22. package/host-runtime/dist/prompt-injection-status.d.ts +28 -1
  23. package/host-runtime/dist/prompt-injection-status.js +21 -7
  24. package/host-runtime/package.json +1 -1
  25. package/package.json +1 -1
  26. package/pd-cli/dist/commands/runtime-activation.d.ts +3 -1
  27. package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
  28. package/pd-cli/dist/commands/runtime-activation.js +5 -3
  29. package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
  30. package/pd-cli/package.json +1 -1
  31. package/plugin/dist/bundle.js +288 -288
  32. package/release-manager/package.json +1 -1
  33. package/workbuddy-adapter/package.json +1 -1
@@ -399,7 +399,45 @@ export function ActivationPage() {
399
399
  const ordinaryActive = activeActivations.filter(record => !pendingRuleCode.includes(record) && !safetyAlerts.includes(record));
400
400
  const inactiveActivations = activations.filter((a) => a.status === "inactive");
401
401
  const neverActivatedCount = activations.filter((a) => a.activatedAt === null).length;
402
- return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.activation.eyebrow") }), _jsx(ShinyText, { as: "h1", className: "text-[29px] font-semibold tracking-tight text-ink mb-2", duration: 4.5, brightness: 0.5, disabled: activeActivations.length === 0, children: t("pages.activation.title") }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[760px] leading-relaxed mb-7", children: t("pages.activation.subtitle") }), _jsxs("div", { className: "text-sm leading-relaxed text-ink-2 mb-7 px-[18px] py-[14px] bg-panel border border-line rounded-[6px]", role: "status", "aria-live": "polite", children: [_jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: activeActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryActive") }), " ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: inactiveActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryInactive") }), neverActivatedCount > 0 && (_jsxs(_Fragment, { children: [" ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-amber tabular-nums", children: neverActivatedCount }), " ", _jsx("span", { className: "text-amber", children: t("pages.activation.summaryNeverActivated") })] }))] }), _jsx(CapabilityBoundaryDeclaration, {}), activeActivations.some(record => record.action === 'code_tool_hook_live_activate') && _jsx("div", { className: "mt-4 flex justify-end", children: _jsx(Button, { variant: "destructive", onClick: () => void handleEmergencyPause(), children: t('pages.activation.pauseAll') }) }), degradedNote && (_jsx("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", children: degradedNote })), receiptDegraded && (_jsxs("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", "data-testid": "receipt-counts-degraded", children: [receiptCoverage !== null && (_jsx("span", { className: "block font-medium text-ink-3", children: t(getReceiptSourceStatusLabelKey(receiptCoverage.sourceStatus)) })), t("pages.activation.receiptsUnavailable", { reason: receiptDegraded.reason }), receiptDegraded.nextAction && (_jsx("span", { className: "mt-1 block font-mono text-[12px]", children: receiptDegraded.nextAction }))] })), receiptCounts !== null && receiptCoverage !== null && (_jsx("div", { className: "mt-4 bg-surface/60 border-l-2 border-line px-3 py-2", "data-testid": "receipt-counts-coverage", children: _jsx(ReceiptCoverageDisclosure, { coverage: receiptCoverage }) })), pendingRuleCode.length > 0 && _jsxs("section", { className: "mt-8", "aria-labelledby": "section-pending-rulecode", children: [_jsx(SectionTitle, { id: "section-pending-rulecode", children: t('pages.activation.pendingRules') }), _jsx("p", { className: "mb-3 text-[12px] text-ink-3", children: t('pages.activation.pendingRulesDescription') }), _jsx("div", { className: "space-y-[14px]", children: pendingRuleCode.map(record => _jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId)) })] }), safetyAlerts.length > 0 && _jsxs("section", { className: "mt-8", "aria-labelledby": "section-safety-alerts", children: [_jsx(SectionTitle, { id: "section-safety-alerts", children: t('pages.activation.safetyAlerts') }), _jsx("p", { className: "mb-3 text-[12px] text-danger", children: t('pages.activation.safetyAlertsDescription') }), _jsx("div", { className: "space-y-[14px]", children: safetyAlerts.map(record => _jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId)) })] }), _jsxs("section", { className: "mt-8", "aria-labelledby": "section-active", children: [_jsx(SectionTitle, { id: "section-active", children: t("pages.activation.sectionActive") }), ordinaryActive.length > 0 ? (_jsx("div", { className: "space-y-[14px]", children: ordinaryActive.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: receiptCounts !== null && !receiptCountsUntrustworthy ? (Object.hasOwn(receiptCounts, record.principleId) ? receiptCounts[record.principleId] : null) : undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3", children: t("pages.activation.emptyActive") }))] }), inactiveActivations.length > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-inactive", children: [_jsx(SectionTitle, { id: "section-inactive", children: t("pages.activation.sectionInactive") }), _jsx("div", { className: "space-y-[14px]", children: inactiveActivations.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: receiptCounts !== null && !receiptCountsUntrustworthy ? (Object.hasOwn(receiptCounts, record.principleId) ? receiptCounts[record.principleId] : null) : undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId))) })] })), neverActivatedCount > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-never-activated", children: [_jsx(SectionTitle, { id: "section-never-activated", children: t("pages.activation.sectionNeverActivated") }), _jsx("div", { className: "space-y-[10px]", children: activations
402
+ return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.activation.eyebrow") }), _jsx(ShinyText, { as: "h1", className: "text-[29px] font-semibold tracking-tight text-ink mb-2", duration: 4.5, brightness: 0.5, disabled: activeActivations.length === 0, children: t("pages.activation.title") }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[760px] leading-relaxed mb-7", children: t("pages.activation.subtitle") }), _jsxs("div", { className: "text-sm leading-relaxed text-ink-2 mb-7 px-[18px] py-[14px] bg-panel border border-line rounded-[6px]", role: "status", "aria-live": "polite", children: [_jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: activeActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryActive") }), " ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: inactiveActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryInactive") }), neverActivatedCount > 0 && (_jsxs(_Fragment, { children: [" ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-amber tabular-nums", children: neverActivatedCount }), " ", _jsx("span", { className: "text-amber", children: t("pages.activation.summaryNeverActivated") })] }))] }), _jsx(CapabilityBoundaryDeclaration, {}), activeActivations.some(record => record.action === 'code_tool_hook_live_activate') && _jsx("div", { className: "mt-4 flex justify-end", children: _jsx(Button, { variant: "destructive", onClick: () => void handleEmergencyPause(), children: t('pages.activation.pauseAll') }) }), degradedNote && (_jsx("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", children: degradedNote })), receiptDegraded && (_jsxs("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", "data-testid": "receipt-counts-degraded", children: [receiptCoverage !== null && (_jsx("span", { className: "block font-medium text-ink-3", children: t(getReceiptSourceStatusLabelKey(receiptCoverage.sourceStatus)) })), t("pages.activation.receiptsUnavailable", { reason: receiptDegraded.reason }), receiptDegraded.nextAction && (_jsx("span", { className: "mt-1 block font-mono text-[12px]", children: receiptDegraded.nextAction }))] })), receiptCounts !== null && receiptCoverage !== null && (_jsx("div", { className: "mt-4 bg-surface/60 border-l-2 border-line px-3 py-2", "data-testid": "receipt-counts-coverage", children: _jsx(ReceiptCoverageDisclosure, { coverage: receiptCoverage }) })), pendingRuleCode.length > 0 && _jsxs("section", { className: "mt-8", "aria-labelledby": "section-pending-rulecode", children: [_jsx(SectionTitle, { id: "section-pending-rulecode", children: t('pages.activation.pendingRules') }), _jsx("p", { className: "mb-3 text-[12px] text-ink-3", children: t('pages.activation.pendingRulesDescription') }), _jsx("div", { className: "space-y-[14px]", children: pendingRuleCode.map(record => _jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId)) })] }), safetyAlerts.length > 0 && _jsxs("section", { className: "mt-8", "aria-labelledby": "section-safety-alerts", children: [_jsx(SectionTitle, { id: "section-safety-alerts", children: t('pages.activation.safetyAlerts') }), _jsx("p", { className: "mb-3 text-[12px] text-danger", children: t('pages.activation.safetyAlertsDescription') }), _jsx("div", { className: "space-y-[14px]", children: safetyAlerts.map(record => _jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId)) })] }), _jsxs("section", { className: "mt-8", "aria-labelledby": "section-active", children: [_jsx(SectionTitle, { id: "section-active", children: t("pages.activation.sectionActive") }), (() => {
403
+ const route = activationsData?.promptInjectionRoute;
404
+ if (route?.status !== "confirmed")
405
+ return null;
406
+ // The "observed" copy names a source + window. Only a CONFIRMED
407
+ // observation carries those facts; a usable observation can itself
408
+ // be the runtime's fallback (no trusted host capacity), and showing
409
+ // window=0 with a host-window label would be a fabricated claim.
410
+ if (route.budgetCapacityStatus === "confirmed"
411
+ && route.budgetObservedAt !== undefined
412
+ && route.budgetContextWindowTokens !== undefined) {
413
+ return (_jsx("p", { className: "mb-3 text-[12px] text-ink-3", "data-testid": "activation-budget-observed-note", children: t("pages.activation.budgetObservedNote", {
414
+ defaultValue: "注入状态中的预算数字取自最近一次运行时观测(来源 {{source}},上下文 {{window}} tokens,观测于 {{observedAt}}),并非实时确认值。",
415
+ source: route.budgetCapacitySource === "pi_catalog_exact"
416
+ ? t("pages.focus.budgetCapacitySourcePiCatalog", { defaultValue: "模型目录精确匹配" })
417
+ : t("pages.focus.budgetCapacitySourceHostWindow", { defaultValue: "宿主有效上下文窗口" }),
418
+ window: route.budgetContextWindowTokens,
419
+ observedAt: route.budgetObservedAt,
420
+ }) }));
421
+ }
422
+ if (route.budgetCapacityStatus === "unknown" && route.budgetFallbackReason !== undefined) {
423
+ const observedSuffix = route.budgetObservedAt !== undefined
424
+ // The runtime's own most recent injection ALSO fell back — the
425
+ // reason is that observation's, not a console-only guess.
426
+ ? t("pages.focus.promptBudgetFallbackObservedSuffix", {
427
+ defaultValue: ";运行时最近一次观测于 {{observedAt}}",
428
+ observedAt: route.budgetObservedAt,
429
+ })
430
+ : "";
431
+ return (_jsx("p", { className: "mb-3 text-[12px] text-ink-3", "data-testid": "activation-budget-fallback-note", children: t("pages.activation.budgetFallbackNote", {
432
+ defaultValue: "注入状态按固定回退预算估算({{reason}}{{observed}})。",
433
+ reason: t(`pages.focus.budgetFallbackReason.${route.budgetFallbackReason}`, {
434
+ defaultValue: route.budgetFallbackReason,
435
+ }),
436
+ observed: observedSuffix,
437
+ }) }));
438
+ }
439
+ return null;
440
+ })(), ordinaryActive.length > 0 ? (_jsx("div", { className: "space-y-[14px]", children: ordinaryActive.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: receiptCounts !== null && !receiptCountsUntrustworthy ? (Object.hasOwn(receiptCounts, record.principleId) ? receiptCounts[record.principleId] : null) : undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3", children: t("pages.activation.emptyActive") }))] }), inactiveActivations.length > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-inactive", children: [_jsx(SectionTitle, { id: "section-inactive", children: t("pages.activation.sectionInactive") }), _jsx("div", { className: "space-y-[14px]", children: inactiveActivations.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], receiptCount: receiptCounts !== null && !receiptCountsUntrustworthy ? (Object.hasOwn(receiptCounts, record.principleId) ? receiptCounts[record.principleId] : null) : undefined, onDisable: handleDisable, disabling: disablingIds.has(record.activationId), onChanged: () => void loadData() }, record.activationId))) })] })), neverActivatedCount > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-never-activated", children: [_jsx(SectionTitle, { id: "section-never-activated", children: t("pages.activation.sectionNeverActivated") }), _jsx("div", { className: "space-y-[10px]", children: activations
403
441
  .filter((a) => a.activatedAt === null)
404
442
  .map((record) => (_jsxs("article", { className: "relative pl-[22px] py-[14px] pr-[18px] bg-panel border border-amber/20 border-l-[3px] border-l-amber rounded-[6px]", children: [_jsxs("div", { className: "text-ink-2 text-sm leading-relaxed", children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.activation.neverActivatedCard") }), " ", "\u2014 ", record.action, " \u00B7 ", getChannelLabel(record.channel, t), _jsx("span", { className: "ml-2 font-mono text-[11px] text-ink-4", children: record.principleId })] }), _jsxs(Link, { to: "/debt", className: "inline-flex items-center mt-2 text-gov text-[13px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: [t("pages.activation.viewDebt"), " \u2192"] })] }, record.activationId))) })] })), _jsx("footer", { className: "mt-12 pt-6 border-t border-line text-ink-3 text-[13px]", children: t("pages.activation.footer") })] }) }));
405
443
  }
@@ -402,7 +402,7 @@ function PendingReviewCard({ group, actionsLockedReason, onDecisionApplied, prom
402
402
  ? "border-green/40 bg-green/10 text-green"
403
403
  : "border-line bg-surface/80 text-ink-3"}`, role: "status", "data-testid": `decided-banner-${group.principleId}`, children: decidedOutcome === "approved"
404
404
  ? t("pages.focus.decidedApproved", { defaultValue: "已批准 ✓ 正在写入生效记录…" })
405
- : t("pages.focus.decidedRejected", { defaultValue: "已拒绝" }) })), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: "inline-flex items-center border border-line rounded-[2px] px-[7px] py-1 font-mono text-[11px] text-ink-3 bg-surface/80 uppercase", children: channelLabel }), isReversible && (_jsx("span", { className: "inline-flex items-center border border-amber/35 text-amber rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: primaryChannel === "prompt" ? t("pages.focus.tagReversible") : t("pages.focus.tagLowRisk") }))] }), _jsx("div", { className: "mt-[14px] mb-2 font-semibold text-ink leading-snug", "data-testid": `candidate-title-${group.principleId}`, children: readingLayout.title }), readingLayout.body !== null && (_jsx("div", { className: "mb-2 text-[15px] leading-relaxed text-ink whitespace-pre-wrap break-words", "data-testid": `candidate-body-${group.principleId}`, children: readingLayout.body })), group.artifactUnavailable === true && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `artifact-unavailable-${group.principleId}`, children: t("pages.focus.artifactUnavailableNote") })), unlinkedCandidateNote && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `unlinked-candidate-${group.principleId}`, children: t("pages.focus.unlinkedCandidateNote") })), _jsx("div", { className: "mt-2 px-3 py-2 bg-surface/60 border-l-2 border-gov text-ink-3 text-[13px] leading-snug", children: t("pages.focus.evidenceSummary", { count: group.records.length }) }), actionsLocked && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", "data-testid": `pending-actions-locked-${group.principleId}`, children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: actionsLockedReason }), _jsx(Link, { to: "/settings", "data-testid": `pending-actions-locked-settings-${group.principleId}`, className: "mt-2 inline-flex items-center border border-line text-ink bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.ownerDecision.goSettingsCta") })] })), decidedOutcome === null && primaryChannel === "prompt" && promptInjection?.truncated === true && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 px-3 py-2 text-[12.5px] text-amber", "data-testid": `approve-queue-badge-${group.principleId}`, children: [promptInjection.productionRotates === true && group.fitsPromptBudget === true && group.promptBudgetTierFit === "model_dependent"
405
+ : t("pages.focus.decidedRejected", { defaultValue: "已拒绝" }) })), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: "inline-flex items-center border border-line rounded-[2px] px-[7px] py-1 font-mono text-[11px] text-ink-3 bg-surface/80 uppercase", children: channelLabel }), isReversible && (_jsx("span", { className: "inline-flex items-center border border-amber/35 text-amber rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: primaryChannel === "prompt" ? t("pages.focus.tagReversible") : t("pages.focus.tagLowRisk") }))] }), _jsx("div", { className: "mt-[14px] mb-2 font-semibold text-ink leading-snug", "data-testid": `candidate-title-${group.principleId}`, children: readingLayout.title }), readingLayout.body !== null && (_jsx("div", { className: "mb-2 text-[15px] leading-relaxed text-ink whitespace-pre-wrap break-words", "data-testid": `candidate-body-${group.principleId}`, children: readingLayout.body })), group.artifactUnavailable === true && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `artifact-unavailable-${group.principleId}`, children: t("pages.focus.artifactUnavailableNote") })), unlinkedCandidateNote && (_jsx("div", { className: "mb-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `unlinked-candidate-${group.principleId}`, children: t("pages.focus.unlinkedCandidateNote") })), _jsx("div", { className: "mt-2 px-3 py-2 bg-surface/60 border-l-2 border-gov text-ink-3 text-[13px] leading-snug", children: t("pages.focus.evidenceSummary", { count: group.records.length }) }), actionsLocked && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", "data-testid": `pending-actions-locked-${group.principleId}`, children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: actionsLockedReason }), _jsx(Link, { to: "/settings", "data-testid": `pending-actions-locked-settings-${group.principleId}`, className: "mt-2 inline-flex items-center border border-line text-ink bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.ownerDecision.goSettingsCta") })] })), decidedOutcome === null && primaryChannel === "prompt" && promptInjection?.truncated === true && promptInjection.capacityStatus !== "unconfirmed" && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 px-3 py-2 text-[12.5px] text-amber", "data-testid": `approve-queue-badge-${group.principleId}`, children: [promptInjection.productionRotates === true && group.fitsPromptBudget === true && group.promptBudgetTierFit === "model_dependent"
406
406
  ? t("pages.focus.approveQueueBadgeRotationModelDependent", {
407
407
  defaultValue: "批准后可能排队:提示词注入位已满({{used}}/{{budget}} 字符)。这条原则的篇幅在较小上下文模型的注入预算内装不下,轮到它时也未必进入提示词——是否生效取决于当时模型的上限。",
408
408
  used: promptInjection.usedChars,
@@ -430,25 +430,56 @@ function PendingReviewCard({ group, actionsLockedReason, onDecisionApplied, prom
430
430
  full: promptInjection.fullRenderChars !== undefined
431
431
  ? t("pages.focus.promptScopeFullRender", { count: promptInjection.fullRenderChars })
432
432
  : "",
433
- }), promptInjection.hostKind !== undefined ? ` · ${promptInjection.hostKind === "openclaw" ? "OpenClaw" : promptInjection.hostKind === "workbuddy" ? "WorkBuddy" : "Codex"}` : "", ` · ${promptInjection.budgetCapacityStatus === "confirmed"
434
- ? t("pages.focus.promptBudgetModelAwareNote", {
435
- defaultValue: "预算按已确认的模型上下文解析({{window}} tokens)",
436
- window: promptInjection.budgetContextWindowTokens ?? 0,
437
- })
438
- : t("pages.focus.promptBudgetFallbackNote", {
439
- defaultValue: "按固定回退预算估算(控制台未绑定运行时模型{{reason}})",
440
- reason: promptInjection.budgetFallbackReason !== undefined
441
- ? t("pages.focus.promptBudgetFallbackReasonSuffix", {
442
- defaultValue: ",原因: {{code}}",
443
- // The raw bounded code stays the default: it is the
444
- // grep-able identifier shared with events/logs. Locales
445
- // may override via pages.focus.budgetFallbackReason.<code>.
446
- code: t(`pages.focus.budgetFallbackReason.${promptInjection.budgetFallbackReason}`, {
433
+ }), promptInjection.hostKind !== undefined ? ` · ${promptInjection.hostKind === "openclaw" ? "OpenClaw" : promptInjection.hostKind === "workbuddy" ? "WorkBuddy" : "Codex"}` : "", ` · ${
434
+ // A "confirmed" claim is only renderable when the window is
435
+ // present: a payload missing it must not print "0 tokens".
436
+ promptInjection.budgetCapacityStatus === "confirmed" && promptInjection.budgetContextWindowTokens !== undefined
437
+ ? promptInjection.budgetObservedAt !== undefined
438
+ // PRI-1017: the budget comes from the workspace's most
439
+ // recent RUNTIME OBSERVATION (the last real injection) —
440
+ // say so, with source + window + observation time. Never
441
+ // present a past observation as a live confirmation.
442
+ ? t("pages.focus.promptBudgetObservedNote", {
443
+ defaultValue: "预算取自最近一次运行时观测(来源 {{source}},上下文 {{window}} tokens,观测于 {{observedAt}})",
444
+ source: promptInjection.budgetCapacitySource === "pi_catalog_exact"
445
+ ? t("pages.focus.budgetCapacitySourcePiCatalog", { defaultValue: "模型目录精确匹配" })
446
+ : t("pages.focus.budgetCapacitySourceHostWindow", { defaultValue: "宿主有效上下文窗口" }),
447
+ window: promptInjection.budgetContextWindowTokens,
448
+ observedAt: promptInjection.budgetObservedAt,
449
+ })
450
+ : t("pages.focus.promptBudgetModelAwareNote", {
451
+ defaultValue: "预算按已确认的模型上下文解析({{window}} tokens)",
452
+ window: promptInjection.budgetContextWindowTokens,
453
+ })
454
+ : promptInjection.budgetObservedAt !== undefined
455
+ // PRI-1017: a fallback that still carries an observation
456
+ // timestamp IS the runtime's own honest fallback (the last
457
+ // injection resolved 2000 with a reason). Saying "console
458
+ // not bound to the runtime model" here would be false — the
459
+ // console DID use the runtime's last observation.
460
+ ? t("pages.focus.promptBudgetFallbackObservedNote", {
461
+ defaultValue: "运行时最近一次观测未确认宿主容量,预算按固定回退估算({{reason}},观测于 {{observedAt}})",
462
+ reason: promptInjection.budgetFallbackReason !== undefined
463
+ ? t(`pages.focus.budgetFallbackReason.${promptInjection.budgetFallbackReason}`, {
447
464
  defaultValue: promptInjection.budgetFallbackReason,
448
- }),
449
- })
450
- : "",
451
- })}`] })] })), group.revisionReviewUnavailable === true && _jsx("p", { role: "alert", className: "mt-3 text-danger", children: t("pages.focus.revisionReviewUnavailable") }), group.revisionReview !== undefined && (_jsxs("div", { className: "mt-3 border border-line p-3 text-[12.5px]", "data-testid": `revision-intent-review-${group.principleId}`, children: [_jsx("p", { children: t("pages.focus.revisionIntentReview", { defaultValue: "修订复核:确认新正文保留触发条件、行动要求和必要例外,并与沿用意图一致。" }) }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.oldStatement }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.newStatement }), _jsx("dl", { className: "mt-2", children: Object.entries(group.revisionReview.intentFields).map(([key, value]) => _jsxs("div", { children: [_jsx("dt", { children: t(`pages.focus.intentField.${key}`, { defaultValue: key }) }), _jsx("dd", { children: value })] }, key)) }), _jsxs("label", { className: "mt-2 flex gap-2", children: [_jsx("input", { type: "checkbox", checked: intentReviewed, onChange: (event) => setIntentReviewed(event.target.checked) }), t("pages.focus.revisionIntentConfirmed", { defaultValue: "我已核对上述意图与新正文一致" })] })] })), _jsxs("div", { className: "flex gap-2 mt-4 flex-wrap items-center", children: [_jsx("button", { type: "button", onClick: handleApprove, disabled: decisionDisabled || (group.revisionReviewUnavailable === true || (group.revisionReview !== undefined && !intentReviewed)), "data-testid": `approve-btn-${group.principleId}`, className: "inline-flex items-center border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: actionLoading ? t("common.loading") + "…" : t("pages.focus.approveAction", { defaultValue: "批准" }) }), _jsx("button", { type: "button", onClick: () => { setShowEditInput((v) => !v); setShowRejectInput(false); }, disabled: decisionDisabled, "data-testid": `edit-btn-${group.principleId}`, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.editAction", { defaultValue: "替换待审版本" }) }), _jsx("button", { type: "button", onClick: () => { setShowRejectInput((v) => !v); setShowEditInput(false); }, disabled: decisionDisabled, "data-testid": `reject-btn-${group.principleId}`, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.rejectAction", { defaultValue: "拒绝" }) }), _jsx(Link, { to: "/pain", className: "inline-flex items-center text-gov text-[12.5px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.viewFullChain") })] }), showRejectInput && (_jsxs("div", { className: "mt-3 p-3 border border-danger/20 rounded-[var(--radius-md)]", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.rejectReasonLabel", { defaultValue: "拒绝原因(必填)" }) }), _jsx("textarea", { value: rejectReason, onChange: (e) => setRejectReason(e.target.value), "data-testid": `reject-reason-${group.principleId}`, placeholder: t("pages.focus.rejectReasonPlaceholder", { defaultValue: "请说明拒绝原因" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[80px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: handleReject, disabled: !rejectReason.trim() || actionLoading, "data-testid": `confirm-reject-${group.principleId}`, className: "inline-flex items-center border border-danger text-danger bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-danger/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: t("pages.focus.confirmReject", { defaultValue: "确认拒绝" }) }), _jsx("button", { type: "button", onClick: () => { setShowRejectInput(false); setRejectReason(""); }, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.cancelAction", { defaultValue: "取消" }) })] })] })), showEditInput && (_jsxs("div", { className: "mt-3 p-3 border border-gov/20 rounded-[var(--radius-md)]", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.editReasonLabel", { defaultValue: "替换原因(必填)" }) }), _jsxs("div", { className: "mb-2 text-ink-4 text-[12px] font-mono", children: [t("pages.focus.currentArtifactLabel", { defaultValue: "当前工件" }), ": ", currentArtifactId] }), _jsx("input", { type: "text", value: newArtifactId, onChange: (e) => setNewArtifactId(e.target.value), "data-testid": `edit-new-artifact-${group.principleId}`, placeholder: t("pages.focus.editNewArtifactPlaceholder", { defaultValue: "输入新的已验证工件 ID" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] mb-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", "aria-label": t("pages.focus.editNewArtifactPlaceholder", { defaultValue: "输入新的已验证工件 ID" }) }), _jsx("textarea", { value: editReason, onChange: (e) => setEditReason(e.target.value), "data-testid": `edit-reason-${group.principleId}`, placeholder: t("pages.focus.editReasonPlaceholder", { defaultValue: "请说明为什么需要替换这份待审版本" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[80px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: handleEdit, disabled: !editReason.trim() || !newArtifactId.trim() || actionLoading, "data-testid": `confirm-edit-${group.principleId}`, className: "inline-flex items-center border border-gov text-gov bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-gov/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: t("pages.focus.confirmEdit", { defaultValue: "确认替换" }) }), _jsx("button", { type: "button", onClick: () => { setShowEditInput(false); setEditReason(""); setNewArtifactId(""); }, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.cancelAction", { defaultValue: "取消" }) })] })] }))] }));
465
+ })
466
+ : "unknown",
467
+ observedAt: promptInjection.budgetObservedAt,
468
+ })
469
+ : t("pages.focus.promptBudgetFallbackNote", {
470
+ defaultValue: "按固定回退预算估算(控制台未绑定运行时模型{{reason}})",
471
+ reason: promptInjection.budgetFallbackReason !== undefined
472
+ ? t("pages.focus.promptBudgetFallbackReasonSuffix", {
473
+ defaultValue: ",原因: {{code}}",
474
+ // The raw bounded code stays the default: it is the
475
+ // grep-able identifier shared with events/logs. Locales
476
+ // may override via pages.focus.budgetFallbackReason.<code>.
477
+ code: t(`pages.focus.budgetFallbackReason.${promptInjection.budgetFallbackReason}`, {
478
+ defaultValue: promptInjection.budgetFallbackReason,
479
+ }),
480
+ })
481
+ : "",
482
+ })}`] })] })), group.revisionReviewUnavailable === true && _jsx("p", { role: "alert", className: "mt-3 text-danger", children: t("pages.focus.revisionReviewUnavailable") }), group.revisionReview !== undefined && (_jsxs("div", { className: "mt-3 border border-line p-3 text-[12.5px]", "data-testid": `revision-intent-review-${group.principleId}`, children: [_jsx("p", { children: t("pages.focus.revisionIntentReview", { defaultValue: "修订复核:确认新正文保留触发条件、行动要求和必要例外,并与沿用意图一致。" }) }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.oldStatement }), _jsx("pre", { className: "mt-2 max-h-32 overflow-auto whitespace-pre-wrap", children: group.revisionReview.newStatement }), _jsx("dl", { className: "mt-2", children: Object.entries(group.revisionReview.intentFields).map(([key, value]) => _jsxs("div", { children: [_jsx("dt", { children: t(`pages.focus.intentField.${key}`, { defaultValue: key }) }), _jsx("dd", { children: value })] }, key)) }), _jsxs("label", { className: "mt-2 flex gap-2", children: [_jsx("input", { type: "checkbox", checked: intentReviewed, onChange: (event) => setIntentReviewed(event.target.checked) }), t("pages.focus.revisionIntentConfirmed", { defaultValue: "我已核对上述意图与新正文一致" })] })] })), _jsxs("div", { className: "flex gap-2 mt-4 flex-wrap items-center", children: [_jsx("button", { type: "button", onClick: handleApprove, disabled: decisionDisabled || (group.revisionReviewUnavailable === true || (group.revisionReview !== undefined && !intentReviewed)), "data-testid": `approve-btn-${group.principleId}`, className: "inline-flex items-center border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: actionLoading ? t("common.loading") + "…" : t("pages.focus.approveAction", { defaultValue: "批准" }) }), _jsx("button", { type: "button", onClick: () => { setShowEditInput((v) => !v); setShowRejectInput(false); }, disabled: decisionDisabled, "data-testid": `edit-btn-${group.principleId}`, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.editAction", { defaultValue: "替换待审版本" }) }), _jsx("button", { type: "button", onClick: () => { setShowRejectInput((v) => !v); setShowEditInput(false); }, disabled: decisionDisabled, "data-testid": `reject-btn-${group.principleId}`, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.rejectAction", { defaultValue: "拒绝" }) }), _jsx(Link, { to: "/pain", className: "inline-flex items-center text-gov text-[12.5px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.focus.viewFullChain") })] }), showRejectInput && (_jsxs("div", { className: "mt-3 p-3 border border-danger/20 rounded-[var(--radius-md)]", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.rejectReasonLabel", { defaultValue: "拒绝原因(必填)" }) }), _jsx("textarea", { value: rejectReason, onChange: (e) => setRejectReason(e.target.value), "data-testid": `reject-reason-${group.principleId}`, placeholder: t("pages.focus.rejectReasonPlaceholder", { defaultValue: "请说明拒绝原因" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[80px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: handleReject, disabled: !rejectReason.trim() || actionLoading, "data-testid": `confirm-reject-${group.principleId}`, className: "inline-flex items-center border border-danger text-danger bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-danger/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: t("pages.focus.confirmReject", { defaultValue: "确认拒绝" }) }), _jsx("button", { type: "button", onClick: () => { setShowRejectInput(false); setRejectReason(""); }, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.cancelAction", { defaultValue: "取消" }) })] })] })), showEditInput && (_jsxs("div", { className: "mt-3 p-3 border border-gov/20 rounded-[var(--radius-md)]", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.editReasonLabel", { defaultValue: "替换原因(必填)" }) }), _jsxs("div", { className: "mb-2 text-ink-4 text-[12px] font-mono", children: [t("pages.focus.currentArtifactLabel", { defaultValue: "当前工件" }), ": ", currentArtifactId] }), _jsx("input", { type: "text", value: newArtifactId, onChange: (e) => setNewArtifactId(e.target.value), "data-testid": `edit-new-artifact-${group.principleId}`, placeholder: t("pages.focus.editNewArtifactPlaceholder", { defaultValue: "输入新的已验证工件 ID" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] mb-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", "aria-label": t("pages.focus.editNewArtifactPlaceholder", { defaultValue: "输入新的已验证工件 ID" }) }), _jsx("textarea", { value: editReason, onChange: (e) => setEditReason(e.target.value), "data-testid": `edit-reason-${group.principleId}`, placeholder: t("pages.focus.editReasonPlaceholder", { defaultValue: "请说明为什么需要替换这份待审版本" }), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[80px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: handleEdit, disabled: !editReason.trim() || !newArtifactId.trim() || actionLoading, "data-testid": `confirm-edit-${group.principleId}`, className: "inline-flex items-center border border-gov text-gov bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-gov/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: t("pages.focus.confirmEdit", { defaultValue: "确认替换" }) }), _jsx("button", { type: "button", onClick: () => { setShowEditInput(false); setEditReason(""); setNewArtifactId(""); }, className: "inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors", children: t("pages.focus.cancelAction", { defaultValue: "取消" }) })] })] }))] }));
452
483
  }
453
484
  function StagnationSignalCard({ signal }) {
454
485
  const { t } = useTranslation();
@@ -775,15 +806,26 @@ export function FocusPage({ featureFlags }) {
775
806
  return null;
776
807
  return (_jsxs("div", { className: "mb-4 rounded-[3px] border border-amber/40 bg-amber/5 px-3 py-2 text-[12.5px] leading-relaxed text-amber", "data-testid": "prompt-capacity-unconfirmed-banner", children: [_jsx("p", { children: t("pages.focus.promptCapacityUnconfirmed", {
777
808
  defaultValue: "当前宿主容量未确认:本工作区适用的宿主会走不同的注入路由,以下数字未绑定具体宿主。",
778
- }) }), _jsx("ul", { className: "mt-1 list-disc pl-5", children: (unconfirmed.perHost ?? []).map((entry) => (_jsx("li", { "data-testid": `prompt-capacity-perhost-${entry.hostKind}`, children: t("pages.focus.promptCapacityPerHostEntry", {
779
- host: entry.hostKind === "openclaw" ? "OpenClaw" : entry.hostKind === "workbuddy" ? "WorkBuddy" : "Codex",
780
- billing: entry.route === "shared_render"
781
- ? t("pages.focus.promptCapacitySharedRoute")
782
- : t("pages.focus.promptCapacityListRoute"),
783
- used: entry.usedChars,
784
- budget: unconfirmed.budget,
785
- full: entry.truncated ? t("pages.focus.promptCapacityPerHostFull") : "",
786
- }) }, entry.hostKind))) }), unconfirmed.nextAction !== undefined && (_jsx("p", { className: "mt-1 text-ink-2", children: unconfirmed.nextAction })), _jsxs("div", { className: "mt-2 flex gap-2", children: [["openclaw", "codex", "workbuddy"].map((host) => (_jsx("button", { type: "button", onClick: () => setPromptTargetHost(host), "data-testid": `prompt-capacity-pick-${host}`, className: `inline-flex items-center border rounded-[3px] px-[10px] py-[4px] transition-colors ${promptTargetHost === host ? "border-amber bg-amber/10" : "border-line hover:border-line-2"}`, children: t("pages.focus.promptCapacityViewAsHost", { host: host === "openclaw" ? "OpenClaw" : host === "workbuddy" ? "WorkBuddy" : "Codex" }) }, host))), promptTargetHost !== null && (_jsx("button", { type: "button", onClick: () => setPromptTargetHost(null), "data-testid": "prompt-capacity-pick-clear", className: "inline-flex items-center border border-line rounded-[3px] px-[10px] py-[4px] hover:border-line-2", children: t("pages.focus.promptCapacityClearHost", { defaultValue: "清除选择" }) }))] })] }));
809
+ }) }), _jsx("ul", { className: "mt-1 list-disc pl-5", children: (unconfirmed.perHost ?? []).map((entry) => (_jsxs("li", { "data-testid": `prompt-capacity-perhost-${entry.hostKind}`, children: [t("pages.focus.promptCapacityPerHostEntry", {
810
+ host: entry.hostKind === "openclaw" ? "OpenClaw" : entry.hostKind === "workbuddy" ? "WorkBuddy" : "Codex",
811
+ billing: entry.route === "shared_render"
812
+ ? t("pages.focus.promptCapacitySharedRoute")
813
+ : t("pages.focus.promptCapacityListRoute"),
814
+ used: entry.usedChars,
815
+ // PRI-1017: each host shows ITS OWN budget basis (runtime
816
+ // observation or its own honest fallback) — never the
817
+ // shared headline number.
818
+ budget: entry.budget ?? unconfirmed.budget,
819
+ full: entry.truncated ? t("pages.focus.promptCapacityPerHostFull") : "",
820
+ observed: entry.budgetObservedAt !== undefined
821
+ ? t("pages.focus.promptCapacityPerHostObserved", {
822
+ defaultValue: "(预算来自该宿主最近一次运行时观测,观测于 {{observedAt}})",
823
+ observedAt: entry.budgetObservedAt,
824
+ })
825
+ : "",
826
+ }), entry.budgetFallbackReason !== undefined && (_jsxs("span", { "data-testid": `prompt-capacity-perhost-reason-${entry.hostKind}`, children: [" · ", t(`pages.focus.budgetFallbackReason.${entry.budgetFallbackReason}`, {
827
+ defaultValue: entry.budgetFallbackReason,
828
+ })] }))] }, entry.hostKind))) }), unconfirmed.nextAction !== undefined && (_jsx("p", { className: "mt-1 text-ink-2", children: unconfirmed.nextAction })), _jsxs("div", { className: "mt-2 flex gap-2", children: [["openclaw", "codex", "workbuddy"].map((host) => (_jsx("button", { type: "button", onClick: () => setPromptTargetHost(host), "data-testid": `prompt-capacity-pick-${host}`, className: `inline-flex items-center border rounded-[3px] px-[10px] py-[4px] transition-colors ${promptTargetHost === host ? "border-amber bg-amber/10" : "border-line hover:border-line-2"}`, children: t("pages.focus.promptCapacityViewAsHost", { host: host === "openclaw" ? "OpenClaw" : host === "workbuddy" ? "WorkBuddy" : "Codex" }) }, host))), promptTargetHost !== null && (_jsx("button", { type: "button", onClick: () => setPromptTargetHost(null), "data-testid": "prompt-capacity-pick-clear", className: "inline-flex items-center border border-line rounded-[3px] px-[10px] py-[4px] hover:border-line-2", children: t("pages.focus.promptCapacityClearHost", { defaultValue: "清除选择" }) }))] })] }));
787
829
  })(), groupedAvailable && pendingGroups.map((group) => (_jsx(PendingReviewCard, { group: group, actionsLockedReason: ownerActionsLockedReason ?? undefined, promptInjection: groupedData.promptInjection, promptTargetHost: promptTargetHost ?? undefined, onDecisionApplied: () => { void loadData(); } }, group.principleId)))] }), _jsxs("section", { "aria-label": t("pages.focus.ownerAttention.sectionTitle"), className: "mb-7", "data-testid": "owner-attention-section", children: [_jsxs("div", { className: "flex items-baseline gap-2 mb-3", children: [_jsx(SectionTitle, { children: t("pages.focus.ownerAttention.sectionTitle") }), ownerInbox !== null && ownerInboxError === null && (_jsx("span", { className: "font-mono text-ink-4 text-[12px]", "data-testid": "owner-attention-counts", children: `· ${t("pages.focus.ownerAttention.blockedCount", { count: ownerInbox.groups.blocked.length })} · ${t("pages.focus.ownerAttention.recoveryCount", { count: inboxRecovery.length })}` }))] }), ownerInboxError !== null && (_jsx("p", { className: "text-ink-4 text-[12.5px]", children: t("pages.focus.ownerInbox.loadError") })), ownerInbox !== null && ownerInboxError === null && (_jsxs(_Fragment, { children: [ownerInbox.groups.blocked.length === 0
788
830
  && inboxRecovery.length === 0
789
831
  && unmatchedInboxDecisions.length === 0 && (_jsx("p", { className: "text-ink-4 text-[13px]", children: t("pages.focus.ownerAttention.empty") })), unmatchedInboxDecisions.length > 0 && (_jsx("p", { className: "mb-2 text-ink-4 text-[12px] leading-relaxed", "data-testid": "owner-attention-unmatched-note", children: t("pages.focus.ownerAttention.unmatchedTitle") })), unmatchedInboxDecisions.map((item) => (_jsx(InboxItem, { item: item, t: t, note: t("pages.focus.ownerAttention.unmatchedItemNote") }, item.principleId))), inboxBlockedIndividual.map((item) => (_jsx(InboxItem, { item: item, t: t }, item.principleId))), inboxRecovery.map((item) => (_jsx(InboxItem, { item: item, t: t }, item.principleId))), inboxBlockedAggregate.length > 0 && (_jsxs("p", { className: "mt-2 text-ink-4 text-[12.5px] leading-relaxed", "data-testid": "owner-attention-aggregate-notice", children: [t("pages.focus.ownerAttention.blockedAggregate", { count: inboxBlockedAggregate.length }), " ", _jsx(Link, { to: "/principles", className: "text-gov hover:underline", children: t("pages.focus.ownerInbox.viewLibrary") })] })), ownerInbox.historicalUnknown.count > 0 && (_jsxs("p", { className: "text-ink-4 text-[12.5px] leading-relaxed mt-2", "data-testid": "owner-inbox-aggregate-notice", children: [ownerInbox.historicalUnknown.reasonText, " ", _jsx(Link, { to: "/principles", className: "text-gov hover:underline", children: t("pages.focus.ownerInbox.viewLibrary") })] }))] }))] }), experienceMode && experienceData !== null ? (_jsx(ExperienceSummaryCard, { snapshot: experienceData })) : !experienceMode ? (_jsxs("div", { className: "mb-7 px-[18px] py-[14px] bg-panel border border-line rounded-[6px]", children: [_jsx("div", { className: "flex items-center gap-2 mb-1", children: _jsx("span", { className: `inline-flex items-center rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase ${governanceState === "owner_review_ready" ? "bg-gov/10 text-gov border border-gov/20"
@@ -66,6 +66,30 @@ function isGovernanceTimestamp(value) {
66
66
  function hasOwnFields(value, fields) {
67
67
  return fields.every(field => Object.hasOwn(value, field));
68
68
  }
69
+ const PROMPT_BUDGET_FALLBACK_REASONS = new Set([
70
+ 'host_capacity_absent',
71
+ 'host_capacity_source_untrusted',
72
+ 'host_capacity_invalid_value',
73
+ 'catalog_unavailable',
74
+ 'model_identity_absent',
75
+ 'catalog_no_exact_match',
76
+ 'catalog_no_match_for_model_id',
77
+ 'catalog_ambiguous_model_id',
78
+ 'catalog_provider_absent',
79
+ 'catalog_metadata_invalid',
80
+ // PRI-1017: console-side bounded code — a runtime observation exists but
81
+ // is too old to be presented as the current budget.
82
+ 'runtime_budget_observation_stale',
83
+ ]);
84
+ function isPromptBudgetFallbackReason(value) {
85
+ return isString(value) && PROMPT_BUDGET_FALLBACK_REASONS.has(value);
86
+ }
87
+ function isPromptBudgetCapacitySource(value) {
88
+ return value === 'host_effective_window' || value === 'pi_catalog_exact' || value === 'legacy_fallback';
89
+ }
90
+ function isPromptBudgetCapacityStatus(value) {
91
+ return value === 'confirmed' || value === 'unknown';
92
+ }
69
93
  function isStringEnum(value, allowed) {
70
94
  return typeof value === 'string' && allowed.has(value);
71
95
  }
@@ -1163,6 +1187,24 @@ export function validateActivations(v) {
1163
1187
  summary.nextAction = route.nextAction;
1164
1188
  if (Object.hasOwn(route, 'globalReason') && isString(route.globalReason))
1165
1189
  summary.globalReason = route.globalReason;
1190
+ // PRI-1017: runtime budget observation timestamp the per-row budget
1191
+ // figures were computed under (additive, drop-on-invalid).
1192
+ if (Object.hasOwn(route, 'budgetObservedAt') && isString(route.budgetObservedAt) && route.budgetObservedAt.length > 0 && Number.isFinite(Date.parse(route.budgetObservedAt))) {
1193
+ summary.budgetObservedAt = route.budgetObservedAt;
1194
+ }
1195
+ if (Object.hasOwn(route, 'budgetCapacitySource') && isPromptBudgetCapacitySource(route.budgetCapacitySource)) {
1196
+ summary.budgetCapacitySource = route.budgetCapacitySource;
1197
+ }
1198
+ if (Object.hasOwn(route, 'budgetCapacityStatus') && isPromptBudgetCapacityStatus(route.budgetCapacityStatus)) {
1199
+ summary.budgetCapacityStatus = route.budgetCapacityStatus;
1200
+ }
1201
+ if (Object.hasOwn(route, 'budgetContextWindowTokens') && typeof route.budgetContextWindowTokens === 'number'
1202
+ && Number.isInteger(route.budgetContextWindowTokens) && route.budgetContextWindowTokens > 0) {
1203
+ summary.budgetContextWindowTokens = route.budgetContextWindowTokens;
1204
+ }
1205
+ if (Object.hasOwn(route, 'budgetFallbackReason') && isPromptBudgetFallbackReason(route.budgetFallbackReason)) {
1206
+ summary.budgetFallbackReason = route.budgetFallbackReason;
1207
+ }
1166
1208
  result.promptInjectionRoute = summary;
1167
1209
  }
1168
1210
  }
@@ -1817,25 +1859,23 @@ export function validatePromptInjectionBudgetStatus(v) {
1817
1859
  // SPEC-PD-MODEL-AWARE-PROMPT-BUDGET-001 §7: budget provenance, additive +
1818
1860
  // drop-on-invalid. Absent behaves as the legacy fixed-budget view
1819
1861
  // (pre-SPEC server compat).
1820
- if (Object.hasOwn(v, 'budgetCapacitySource')
1821
- && (v.budgetCapacitySource === 'host_effective_window' || v.budgetCapacitySource === 'pi_catalog_exact'
1822
- || v.budgetCapacitySource === 'legacy_fallback')) {
1862
+ if (Object.hasOwn(v, 'budgetCapacitySource') && isPromptBudgetCapacitySource(v.budgetCapacitySource)) {
1823
1863
  result.budgetCapacitySource = v.budgetCapacitySource;
1824
1864
  }
1825
- if (Object.hasOwn(v, 'budgetFallbackReason')
1826
- && (v.budgetFallbackReason === 'host_capacity_absent' || v.budgetFallbackReason === 'host_capacity_source_untrusted'
1827
- || v.budgetFallbackReason === 'host_capacity_invalid_value' || v.budgetFallbackReason === 'catalog_unavailable'
1828
- || v.budgetFallbackReason === 'model_identity_absent' || v.budgetFallbackReason === 'catalog_no_exact_match'
1829
- || v.budgetFallbackReason === 'catalog_no_match_for_model_id' || v.budgetFallbackReason === 'catalog_ambiguous_model_id'
1830
- || v.budgetFallbackReason === 'catalog_provider_absent' || v.budgetFallbackReason === 'catalog_metadata_invalid')) {
1865
+ if (Object.hasOwn(v, 'budgetFallbackReason') && isPromptBudgetFallbackReason(v.budgetFallbackReason)) {
1831
1866
  result.budgetFallbackReason = v.budgetFallbackReason;
1832
1867
  }
1833
- if (Object.hasOwn(v, 'budgetCapacityStatus') && (v.budgetCapacityStatus === 'confirmed' || v.budgetCapacityStatus === 'unknown')) {
1868
+ if (Object.hasOwn(v, 'budgetCapacityStatus') && isPromptBudgetCapacityStatus(v.budgetCapacityStatus)) {
1834
1869
  result.budgetCapacityStatus = v.budgetCapacityStatus;
1835
1870
  }
1836
1871
  if (Object.hasOwn(v, 'budgetContextWindowTokens') && typeof v.budgetContextWindowTokens === 'number' && Number.isInteger(v.budgetContextWindowTokens) && v.budgetContextWindowTokens > 0) {
1837
1872
  result.budgetContextWindowTokens = v.budgetContextWindowTokens;
1838
1873
  }
1874
+ // PRI-1017: observation timestamp — a PAST runtime fact, never a live
1875
+ // claim. Present-but-invalid drops (rc-1/rc-2), never propagated.
1876
+ if (Object.hasOwn(v, 'budgetObservedAt') && isString(v.budgetObservedAt) && v.budgetObservedAt.length > 0 && Number.isFinite(Date.parse(v.budgetObservedAt))) {
1877
+ result.budgetObservedAt = v.budgetObservedAt;
1878
+ }
1839
1879
  if (Object.hasOwn(v, 'perHost') && Array.isArray(v.perHost)) {
1840
1880
  // rc-4: validate every element, not just "is array".
1841
1881
  const perHost = [];
@@ -1849,7 +1889,26 @@ export function validatePromptInjectionBudgetStatus(v) {
1849
1889
  || typeof hostTruncated !== 'boolean') {
1850
1890
  return null;
1851
1891
  }
1852
- perHost.push({ hostKind, route, usedChars: hostUsed, truncated: hostTruncated });
1892
+ const forecast = { hostKind, route, usedChars: hostUsed, truncated: hostTruncated };
1893
+ // PRI-1017: per-host budget basis (additive, drop-on-invalid). Absent
1894
+ // behaves as the pre-PRI-1017 payload where the headline budget was
1895
+ // shared — the UI must not present one host's window as another's.
1896
+ if (Object.hasOwn(entry, 'budget') && typeof entry.budget === 'number' && Number.isInteger(entry.budget) && entry.budget > 0) {
1897
+ forecast.budget = entry.budget;
1898
+ }
1899
+ if (Object.hasOwn(entry, 'budgetCapacitySource') && isPromptBudgetCapacitySource(entry.budgetCapacitySource)) {
1900
+ forecast.budgetCapacitySource = entry.budgetCapacitySource;
1901
+ }
1902
+ if (Object.hasOwn(entry, 'budgetCapacityStatus') && isPromptBudgetCapacityStatus(entry.budgetCapacityStatus)) {
1903
+ forecast.budgetCapacityStatus = entry.budgetCapacityStatus;
1904
+ }
1905
+ if (Object.hasOwn(entry, 'budgetObservedAt') && isString(entry.budgetObservedAt) && entry.budgetObservedAt.length > 0 && Number.isFinite(Date.parse(entry.budgetObservedAt))) {
1906
+ forecast.budgetObservedAt = entry.budgetObservedAt;
1907
+ }
1908
+ if (Object.hasOwn(entry, 'budgetFallbackReason') && isPromptBudgetFallbackReason(entry.budgetFallbackReason)) {
1909
+ forecast.budgetFallbackReason = entry.budgetFallbackReason;
1910
+ }
1911
+ perHost.push(forecast);
1853
1912
  }
1854
1913
  result.perHost = perHost;
1855
1914
  }