Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions apps/presentation/dashboard/smoke/team-plan-proposal-smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
typedActionKindSchema,
typedActionProposalSchema,
} from "../src/data/chat.js";
import { teamPlanFields, teamPlanGoalId, teamPlanLaneCount } from "../src/features/personal-workspace/team-plan-preview.js";
import { teamPlanAssignments, teamPlanFields, teamPlanGapReason, teamPlanGoalId, teamPlanLaneCount, teamPlanReceiptGapLanes } from "../src/features/personal-workspace/team-plan-preview.js";

const GOAL_ID = "team-plan-smoke-goal";

Expand Down Expand Up @@ -132,6 +132,10 @@ const translate = (key: string, values?: Record<string, string | number>) => {
"proposal.teamPlan.acceptanceShort": "acceptance",
"proposal.teamPlan.gapLane": "unstaffed",
"proposal.teamPlan.laneUnstaffed": "staffing gap, no first Todo",
"proposal.teamPlan.appliedGapLane": "{lane} ({agent}) stayed unstaffed: {reason}",
"proposal.teamPlan.advisory": "planning context",
"proposal.teamPlan.gapReason.agentNotRegistered": "the Agent is not registered for this Goal",
"proposal.teamPlan.gapReason.actionKindNotSupported": "this host does not ship that action kind",
};
const template = table[key] ?? key;
return Object.entries(values ?? {}).reduce(
Expand All @@ -153,19 +157,46 @@ check(
"a ready lane shows its first bounded Todo, its priority and its acceptance signal",
);
check(
gapLane?.value.startsWith("unstaffed · agent_not_registered") === true
gapLane?.value.startsWith("unstaffed · the Agent is not registered for this Goal") === true
&& gapLane?.value.includes("Independently review the intake") === true,
"a gap lane says it is unstaffed, names the reason and keeps the work it did not staff",
);
check(byKey.get("lane_gaps")?.value === "lane_review: agent_not_registered", "the gap summary joins lane and reason");
check(byKey.get("quota_envelope")?.value === "slots: 4 · window: 1d", "the quota envelope is shown as data");
check(!byKey.has("lane_gaps"), "the preview does not repeat a gap already shown with its task");
check(byKey.get("quota_envelope")?.value === "slots: 4 · window: 1d · planning context", "quota is labeled as planning context");
check(
byKey.get("stop_condition")?.value === "every lane reports a typed outcome or a stated gap",
byKey.get("stop_condition")?.value === "every lane reports a typed outcome or a stated gap · planning context",
"the stop condition is shown",
);
check(
fields.some((field) => field.value.includes("agent-") === true && field.value.includes("ready") === true) === false,
"the card never renders a lane as already created",
);

// Confirming the plan replaces the preview facts with the apply receipt, so
// the readback has to carry the same lane identity: a partial application that
// reported only a count left the owner unable to name what was missing.
const partialReceipt = {
outcome: "team_plan_partially_applied",
gap_count: 1,
gap_lanes: [
{ lane_id: "lane_review", agent_id: "agent-reviewer", reason_code: "agent_not_registered" },
],
};
const appliedGaps = teamPlanReceiptGapLanes(partialReceipt, { plan });
check(appliedGaps[0].task === "Independently review the intake", "pending work keeps the admitted task label");
const assignments = teamPlanAssignments({ lanes: [{ lane_id: "lane_backend", agent_id: "receipt-owner" }] }, { plan });
check(assignments.length === 1 && assignments[0].agentId === "receipt-owner" && assignments[0].task === "Implement the bounded intake", "only receipted tasks are assigned; the receipt owns the assignee");
check(teamPlanAssignments(null, { plan }).length === 0, "the preview alone never establishes assignment");
check(appliedGaps.length === 1 && appliedGaps[0].laneId === "lane_review", "the apply receipt names the lane that stayed unstaffed");
check(teamPlanGapReason("future_reason", translate as never) === "future_reason", "unknown host reasons stay explicit");
check(
teamPlanReceiptGapLanes({ outcome: "team_plan_applied" }).length === 0,
"a plan that staffed every lane reports no gap lanes",
);
check(
teamPlanReceiptGapLanes(null).length === 0
&& teamPlanReceiptGapLanes({ gap_lanes: [{ agent_id: "agent-reviewer" }] }).length === 0,
"a receipt without the field, or without a lane, reports no gap lanes",
);

if (process.exitCode !== 1) console.log("team plan proposal smoke ok");
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import type {
import type { LarkGoalConnection } from "../../data/chat";
import { localizedAttentionAge, localizedGoalState, localizedSessionStatus, useWorkspaceI18n } from "./i18n";
import { formatCostUsd, formatDurationMs, formatTokenCount, formatUsageValue } from "./personal-workspace-model";
import { TeamPlanResult } from "./team-plan-result";
import { todoResumeWhenFromMessage } from "./personal-workspace-router";

function subagentModelRequest(include: boolean, model: string, effort: string) {
Expand Down Expand Up @@ -265,6 +266,7 @@ export function ContextDrawer({ agents, attentionHistory = [], onSelectAttention
: selection.kind === "todo" ? t("drawer.taskDetails")
: selection.kind === "run" ? t("drawer.runDetails")
: selection.kind === "output" ? t("drawer.titleOutput")
: selection.kind === "proposal" && selection.item.actionKind === "team.plan" && selection.item.status === "applied" ? t("proposal.teamPlan.resultTitle")
: selection.kind === "proposal" ? t(selection.item.status === "applied" ? "drawer.titleProposalApplied" : "drawer.titleProposalConfirm")
: selection.kind === "schedule" ? (selection.item.scheduleKind === "heartbeat" ? "Heartbeat" : t("drawer.titleSchedule"))
: t("drawer.goalDetails");
Expand All @@ -276,6 +278,7 @@ export function ContextDrawer({ agents, attentionHistory = [], onSelectAttention
: selection.kind === "output" ? selection.item.goalTitle ?? t("drawer.currentGoal")
: selection.kind === "goal" ? selection.item.title
: selection.kind === "schedule" ? t("drawer.goalAutoRun")
: selection.kind === "proposal" && selection.item.status === "applied" && selection.item.actionKind === "team.plan" ? selection.item.goalId ?? t("drawer.currentGoal")
: selection.item.goalId ? t("drawer.goalChanges") : t("drawer.managerChanges");
const selectedGoalRun = selection.kind === "goal"
? runs.find((run) => run.goalId === selection.item.goalId && Boolean(run.sessionId))
Expand Down Expand Up @@ -959,22 +962,22 @@ export function ContextDrawer({ agents, attentionHistory = [], onSelectAttention

{selection.kind === "proposal" ? (
<>
<section className="personal-proposal-card">
{selection.item.actionKind === "team.plan" && selection.item.status === "applied" ? <TeamPlanResult proposal={selection.item} t={t} /> : <section className="personal-proposal-card">
<small>{selection.item.actionKind} · {selection.item.status}</small>
<h3>{selection.item.title}</h3>
<p>{selection.item.impact}</p>
{selection.item.reviewPlan ? <p className="personal-proposal-explainer" data-action-review={selection.item.reviewPlan.interaction}>{selection.item.actionKind === "operation.execute" && selection.item.status === "gated"
{selection.item.reviewPlan && selection.item.actionKind !== "team.plan" ? <p className="personal-proposal-explainer" data-action-review={selection.item.reviewPlan.interaction}>{selection.item.actionKind === "operation.execute" && selection.item.status === "gated"
? t("actionReview.operation_group_confirmation")
: selection.item.actionKind === "operation.execute" && selection.item.reviewPlan.reason === "readback_unverified"
? t("actionReview.operation_result_delivery_pending")
: t(`actionReview.${selection.item.reviewPlan.reason}`)}</p> : null}
{selection.item.status === "ready" ? <p className="personal-proposal-explainer">{t("drawer.proposalExplainer")}</p> : null}
{selection.item.status === "ready" && selection.item.actionKind !== "team.plan" ? <p className="personal-proposal-explainer">{t("drawer.proposalExplainer")}</p> : null}
<dl>{selection.item.fields.map((field) => <div key={field.key}><dt>{field.label}</dt><dd>{field.value}</dd></div>)}</dl>
</section>
{selection.item.status === "applied" ? <p className={`personal-proposal-state ${selection.item.actionKind === "operation.execute" && selection.item.reviewPlan?.reason === "readback_unverified" ? "is-gated" : "is-applied"}`}><Check size={16} />{selection.item.actionKind === "operation.execute" ? selection.item.primaryLabel : t("drawer.proposalApplied")}</p> : null}
{selection.item.status === "applied" && selection.item.actionKind !== "operation.execute" && selection.item.goalId ? <button className="personal-primary-action" onClick={() => { const goalId = selection.item.goalId!; onClose(); void callbacks.onOpenGoal?.(goalId); }} type="button"><ExternalLink size={16} />{selection.item.actionKind === "goal.create" ? t("drawer.proposalEnterGoal") : t("drawer.proposalViewGoal")}</button> : null}
</section>}
{selection.item.status === "applied" && selection.item.actionKind !== "team.plan" ? <p className={`personal-proposal-state ${selection.item.actionKind === "operation.execute" && selection.item.reviewPlan?.reason === "readback_unverified" ? "is-gated" : "is-applied"}`}><Check size={16} />{selection.item.actionKind === "operation.execute" ? selection.item.primaryLabel : t("drawer.proposalApplied")}</p> : null}
{selection.item.status === "applied" && selection.item.actionKind !== "operation.execute" && selection.item.goalId ? <button className="personal-primary-action" onClick={() => { const goalId = selection.item.goalId!; onClose(); void callbacks.onOpenGoal?.(goalId); }} type="button"><ExternalLink size={16} />{selection.item.actionKind === "goal.create" ? t("drawer.proposalEnterGoal") : t(selection.item.actionKind === "team.plan" ? "proposal.teamPlan.openGoal" : "drawer.proposalViewGoal")}</button> : null}
{selection.item.status === "stale" ? <p className="personal-proposal-state is-stale">{t("drawer.proposalStale")}</p> : null}
{selection.item.status === "error" ? <div className="personal-proposal-state is-error"><span>{selection.item.reviewPlan?.reason === "readback_unverified" ? t("actionReview.readback_unverified") : t("drawer.proposalApplyFailed")}</span>{selection.item.errorMessage ? <small>{selection.item.errorMessage}</small> : null}<small>{t("drawer.proposalApplyFailedHint")}</small></div> : null}
{selection.item.status === "error" ? <div className="personal-proposal-state is-error"><span>{selection.item.reviewPlan?.reason === "readback_unverified" ? t("actionReview.readback_unverified") : t("drawer.proposalApplyFailed")}</span>{selection.item.errorMessage ? <small>{selection.item.errorMessage}</small> : null}<small>{t(selection.item.actionKind === "team.plan" ? "proposal.teamPlan.retryHint" : "drawer.proposalApplyFailedHint")}</small></div> : null}
{selection.item.status === "rejected" ? <p className="personal-proposal-state is-error">{t("drawer.proposalRejected")}</p> : null}
{selection.item.status === "deferred" ? <p className="personal-proposal-state is-gated">{t("drawer.proposalDeferred")}</p> : null}
{selection.item.status === "gated" ? <div className="personal-proposal-state is-gated"><span><strong>{selection.item.actionKind === "operation.execute" ? selection.item.primaryLabel : t("drawer.gateRequiresHost")}</strong>{selection.item.actionKind === "operation.execute" ? selection.item.impact : t("drawer.gateRequiresHostDescription")}</span>{selection.item.gate?.nextAction ? <small>{selection.item.gate.nextAction}</small> : null}</div> : null}
Expand All @@ -992,7 +995,7 @@ export function ContextDrawer({ agents, attentionHistory = [], onSelectAttention
);
})() : null}
{!readOnly && selection.item.workspaceCandidates?.length ? <div className="personal-workspace-candidates" aria-label={t("drawer.workspaceCandidates")}>{selection.item.workspaceCandidates.map((candidate) => <button key={candidate.workspaceRef} onClick={() => void callbacks.onSelectWorkspaceCandidate?.(selection.item, candidate.workspaceRef)} type="button"><strong>{candidate.label}</strong><small>{candidate.workspaceRef}</small></button>)}</div> : null}
{!readOnly && selection.item.actionKind !== "operation.execute" && selection.item.status === "error" ? <button className="personal-primary-action" onClick={() => void callbacks.onTransitionProposal?.(selection.item, "regenerate")} type="button"><RotateCcw size={17} />{t("drawer.proposalRegenerate")}</button> : !readOnly && selection.item.actionKind !== "operation.execute" && selection.item.status !== "gated" ? <button className="personal-primary-action" disabled={!['ready', 'deferred'].includes(selection.item.status) || selection.item.reviewPlan?.canApply === false} onClick={() => void callbacks.onApplyProposal?.(selection.item)} type="button"><Check size={17} />{selection.item.status === "applying" ? t("drawer.applying") : selection.item.primaryLabel ?? t("drawer.apply")}</button> : null}
{!readOnly && selection.item.actionKind !== "operation.execute" && selection.item.status === "error" ? <button className="personal-primary-action" onClick={() => void (selection.item.actionKind === "team.plan" ? callbacks.onApplyProposal?.(selection.item) : callbacks.onTransitionProposal?.(selection.item, "regenerate"))} type="button"><RotateCcw size={17} />{t(selection.item.actionKind === "team.plan" ? "proposal.teamPlan.retry" : "drawer.proposalRegenerate")}</button> : !readOnly && selection.item.actionKind !== "operation.execute" && selection.item.status !== "gated" && !(selection.item.actionKind === "team.plan" && selection.item.status === "applied") ? <button className="personal-primary-action" disabled={!['ready', 'deferred'].includes(selection.item.status) || selection.item.reviewPlan?.canApply === false} onClick={() => void callbacks.onApplyProposal?.(selection.item)} type="button"><Check size={17} />{selection.item.status === "applying" ? t("drawer.applying") : selection.item.primaryLabel ?? t("drawer.apply")}</button> : null}
{!readOnly && selection.item.actionKind !== "operation.execute" && (["stale", "gated", "rejected"].includes(selection.item.status) || (selection.item.status === "ready" && selection.item.reviewPlan?.canApply === false)) ? <button className="personal-secondary-action" onClick={() => void callbacks.onTransitionProposal?.(selection.item, "regenerate")} type="button"><RotateCcw size={16} />{t("drawer.proposalRecheck")}</button> : null}
{!readOnly && selection.item.actionKind !== "operation.execute" && ["ready", "gated"].includes(selection.item.status) ? <div className="personal-drawer-action-grid"><button className="personal-secondary-action" onClick={() => void callbacks.onTransitionProposal?.(selection.item, "defer")} type="button">{t("drawer.proposalDefer")}</button><button className="personal-secondary-action" onClick={() => void callbacks.onTransitionProposal?.(selection.item, "reject")} type="button">{t("drawer.decisionReject")}</button></div> : null}
{!["applied", "applying"].includes(selection.item.status) ? <button className="personal-secondary-action" onClick={onClose} type="button">{t("drawer.proposalClose")}</button> : null}
Expand Down
Loading