fix(rectification): collect dated events, then distinguish with conflict probes

Empty ledgers stay in natural-language collection. After the first dated
event, dasha conflict probes reverse-infer 前事 and block offer until
answered. Unique-minute confirmation stays closed at a representative
time; adopt reverse-verifies remaining probes. Records BUG-348–351.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-22 10:37:40 +08:00
co-authored by Cursor
parent 92558ee61d
commit 9873ba420a
41 changed files with 2371 additions and 310 deletions
@@ -89,7 +89,7 @@ function RectificationCandidateCards({
<section className="rectification-candidates" aria-label="生时校正候选时间">
<div className="rectification-candidates-heading">
<strong></strong>
<span></span>
<span></span>
<span></span>
</div>
<div className="rectification-candidate-list">
@@ -740,7 +740,7 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
&& Boolean(message.turnId)
&& Boolean(message.text)
))?.renderKey;
const latestOfferMessage = [...messages]
const latestSettledAssistant = [...messages]
.reverse()
.find((message) => (
message.role === "assistant"
@@ -748,27 +748,29 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
&& !message.failed
&& Boolean(message.text)
));
const showSelectionCards = Boolean(
candidateResult?.selectionAllowed
&& !candidateResult.selectedTime
&& latestOfferMessage
&& turnOfferedSelection(latestOfferMessage)
&& !busy
&& regeneratingMessageKey === null,
);
const offeredSelectionOnce = messages.some(turnOfferedSelection);
const offeredThisTurn = Boolean(latestSettledAssistant && turnOfferedSelection(latestSettledAssistant));
const showChoiceCards = Boolean(
choiceCard
&& latestOfferMessage
&& !showSelectionCards
&& latestSettledAssistant
&& !offeredThisTurn
&& !busy
&& !readonly
&& regeneratingMessageKey === null,
);
const selectionCardMessageKey = showSelectionCards && latestOfferMessage
? latestOfferMessage.renderKey
const showSelectionCards = Boolean(
candidateResult?.selectionAllowed
&& offeredSelectionOnce
&& latestSettledAssistant
&& !showChoiceCards
&& !busy
&& regeneratingMessageKey === null,
);
const selectionCardMessageKey = showSelectionCards && latestSettledAssistant
? latestSettledAssistant.renderKey
: undefined;
const choiceCardMessageKey = showChoiceCards && latestOfferMessage
? latestOfferMessage.renderKey
const choiceCardMessageKey = showChoiceCards && latestSettledAssistant
? latestSettledAssistant.renderKey
: undefined;
const canSend = !busy && !readonly && !regeneratingMessageKey;
@@ -882,7 +884,7 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
{savedTime && (
<div className="rectification-saved-wrap">
<p className="rectification-saved" role="status">
{savedStatus === "confirmed" ? "已确认校正时间" : "当前排盘时间(代表性候选,还不能确认唯一分钟)"}{savedTime}使
{savedStatus === "confirmed" ? "已确认校正时间" : "当前排盘时间(代表性时间,本会话不确认唯一分钟)"}{savedTime}使
</p>
{savedStatus === "accepted" && onStartConsultation && (
<div className="rectification-consult-handoff">
@@ -72,7 +72,13 @@ export function ConfirmationGateDisclosure({
<details className="technique-audit">
<summary>
<small>{gate.confirmation_allowed ? "已允许" : "未允许"}</small>
<small>
{gate.confirmation_allowed
? "已允许"
: gate.unique_minute_path === "closed_at_representative"
? "以代表性时间收口"
: "未允许"}
</small>
</summary>
<div className="technique-audit-panel">
<table>