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
2 changes: 1 addition & 1 deletion apps/presentation/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"smoke:status-sources": "rm -rf /tmp/loopx-status-source-smoke && tsc --ignoreConfig --target ES2022 --module CommonJS --moduleResolution Node --ignoreDeprecations 6.0 --skipLibCheck --strict --resolveJsonModule --esModuleInterop --outDir /tmp/loopx-status-source-smoke smoke/status-source-catalog-smoke.ts src/data/ssh-host-catalog.ts src/data/status-source-catalog.ts src/data/local-status-query.ts src/data/status.ts && NODE_PATH=\"$PWD/node_modules\" node /tmp/loopx-status-source-smoke/apps/presentation/dashboard/smoke/status-source-catalog-smoke.js",
"smoke:task-board-scroll": "node smoke/task-board-scroll-smoke.mjs",
"smoke:usage-progress": "rm -rf /tmp/loopx-usage-progress-smoke && tsc --ignoreConfig --target ES2022 --module CommonJS --moduleResolution Node --ignoreDeprecations 6.0 --resolveJsonModule --esModuleInterop --skipLibCheck --strict --outDir /tmp/loopx-usage-progress-smoke smoke/usage-progress-smoke.ts src/features/personal-workspace/personal-workspace-model.ts && node /tmp/loopx-usage-progress-smoke/apps/presentation/dashboard/smoke/usage-progress-smoke.js",
"smoke:action-review-plan": "tsc --ignoreConfig --target ES2022 --module ES2022 --moduleResolution Bundler --skipLibCheck --strict --outDir .local/action-review-plan-smoke smoke/action-review-plan-smoke.ts src/features/personal-workspace/action-review-plan.ts src/vite-env.d.ts && node .local/action-review-plan-smoke/smoke/action-review-plan-smoke.js",
"smoke:action-review-plan": "rm -rf .local/action-review-plan-smoke && tsc --ignoreConfig --target ES2022 --module ES2022 --moduleResolution Bundler --skipLibCheck --strict --rootDir ../../.. --outDir .local/action-review-plan-smoke smoke/action-review-plan-smoke.ts ../../../loopx/control_plane/presentation/action_review_plan.ts src/vite-env.d.ts && node .local/action-review-plan-smoke/apps/presentation/dashboard/smoke/action-review-plan-smoke.js",
"smoke:attention-details": "tsc --ignoreConfig --target ES2022 --module CommonJS --moduleResolution Node --ignoreDeprecations 6.0 --resolveJsonModule --esModuleInterop --skipLibCheck --strict --outDir /tmp/loopx-attention-details-smoke smoke/attention-details-smoke.ts && NODE_PATH=\"$PWD/node_modules\" node /tmp/loopx-attention-details-smoke/apps/presentation/dashboard/smoke/attention-details-smoke.js"
},
"dependencies": {
Expand Down
43 changes: 42 additions & 1 deletion apps/presentation/dashboard/smoke/action-review-plan-smoke.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { compileActionReviewPlan, isStaleActionFailure } from "../src/features/personal-workspace/action-review-plan.js";
import {
compileActionReviewPlan,
isStaleActionFailure,
} from "../../../../loopx/control_plane/presentation/action_review_plan.js";
import { typedActionProposalSchema, type TypedActionProposal } from "../src/data/chat.js";

const proposal: TypedActionProposal = {
Expand Down Expand Up @@ -62,3 +65,41 @@ check(isStaleActionFailure({ error_code: "action_stale" }), "Typed stale errors
check(isStaleActionFailure({ error_code: "action_conflict" }), "Typed conflicts offer refresh");
check(isStaleActionFailure({ proposal: { status: "stale" } }), "Typed stale proposal survives error wrapping");
check(!isStaleActionFailure({ error_code: "canonical_action_failed", error: "conflict with unrelated external service" }), "Error wording cannot classify source state");

const operationProposal = typedActionProposalSchema.parse({
...proposal,
proposal_id: "operation-1",
action_kind: "operation.execute",
permission_classification: "protected",
status: "gated",
normalized_parameters: {
projection: {
schema_version: "loopx_operation_projection_v0",
title: "Review simulated order",
subtitle: "Bound Goal Channel request",
focus: "BUY 1 SYNTH @ 10 TEST",
fields: [{ label: "Order", value: "Limit · GTC" }],
warning: "Simulation only.",
simulated: true,
},
},
operation: {
schema_version: "loopx_operation_envelope_v0",
lifecycle_state: "awaiting_confirmation",
operation_id: "operation-1",
confirmation_digest: "confirmation-1",
payload_digest: "payload-1",
projection_digest: "projection-1",
expires_at: "2026-01-02T00:00:00Z",
delivery: null,
confirmation: null,
claim: null,
outcome: null,
result_delivery: null,
},
});
const operationPlan = compileActionReviewPlan(operationProposal);
check(operationPlan.interaction === "gated", "Operation execution keeps its authenticated human gate");
check(operationPlan.operationFrame?.kind === "confirmation", "Dashboard consumes the shared confirmation frame");
check(operationPlan.operationFrame?.interactionMode === "confirm_reject", "The shared frame preserves confirm/reject interaction");
check(operationPlan.operationFrame?.content.fields[0]?.value === "Limit · GTC", "The shared frame preserves bounded projection fields");

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const dashboard = source("../../views/dashboard-page.tsx");
const tasks = source("./goal-tasks-view.tsx");
const status = source("../../data/status.ts");
const chatData = source("../../data/chat.ts");
const actionReview = source("./action-review-plan.ts");
const actionReview = source("../../../../../../loopx/control_plane/presentation/action_review_plan.ts");

assert.match(model, /kind: "todo"/, "Todo has its own drawer selection");
for (const field of ["dependencies", "nextTransition", "ownerLabel", "todoId", "taskClass"]) {
Expand Down Expand Up @@ -97,7 +97,8 @@ assert.match(page, /function operationProposalFields/, "Operation details have a
assert.doesNotMatch(page.match(/function operationProposalFields[\s\S]*?\n\}/)?.[0] ?? "", /authorized_principals|payload_digest|parameters\.payload/, "Operation details do not expose private authority or inline payloads");
assert.match(page, /t\("proposal\.primary\.operationGroup"\)/, "Operation confirmation routes users to the bound group");
assert.match(chatData, /result_delivery:/, "Dashboard retains operation result-delivery readback");
assert.match(actionReview, /operation\.execute" \|\| proposal\.operation\?\.result_delivery != null/, "An operation is not complete in the Dashboard until result delivery is verified");
assert.match(actionReview, /proposal\.action_kind !== "operation\.execute" \|\| objectValue\(objectValue\(proposal\.operation\)\?\.result_delivery\) !== null/, "An operation is not complete in the Dashboard until result delivery is verified");
assert.match(page, /reviewPlan\.operationFrame/, "Dashboard operation details consume the shared TS review frame");
assert.match(page, /operation\.execute" && proposal\.status === "applied"/, "Dashboard restores terminal operation receipts from the canonical action store");
assert.match(page, /proposal\.action_kind !== "operation\.execute"[\s\S]*reviewPlan\.interaction !== "completed"/, "Pending operation result-card readback remains visible instead of becoming a generic apply error");
assert.match(drawer, /selection\.item\.actionKind !== "operation\.execute"/, "Dashboard hides generic local controls for authenticated group operations");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ActionReviewPlan } from "./action-review-plan-types";
import type { ActionReviewPlan } from "../../../../../../loopx/control_plane/presentation/action_review_plan.js";
import type { GoalAcceptanceObservation } from "../../data/goal-acceptance-observation";
import type { AttentionDetails } from "./attention-details";
import type { WorkspaceLoadError } from "../../data/workspace-progressive-status";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { compileActionReviewPlan, isStaleActionFailure } from "./action-review-plan";
import {
compileActionReviewPlan,
isStaleActionFailure,
} from "../../../../../../loopx/control_plane/presentation/action_review_plan.js";
import { refreshAttention } from "./attention-details";
import { useEffect, useMemo, useRef, useState, type ClipboardEvent as ReactClipboardEvent } from "react";
import { AlertCircle, Bot, CalendarClock, FileText, ListPlus, MessageCircleQuestion, Paperclip, Plus, RefreshCw, Send, X } from "lucide-react";
Expand Down Expand Up @@ -485,42 +488,40 @@
}));
}

function operationProposalFields(proposal: TypedActionProposal, t: WorkspaceTranslate) {
const projection = proposal.normalized_parameters.projection;
const safeProjection = projection && typeof projection === "object"
? projection as Record<string, unknown>
: {};
const projectedFields = Array.isArray(safeProjection.fields)
? safeProjection.fields.flatMap((field, index) => {
if (!field || typeof field !== "object") return [];
const item = field as Record<string, unknown>;
if (typeof item.label !== "string" || typeof item.value !== "string") return [];
return [{ key: `projection:${index}`, label: item.label, value: item.value }];
}).slice(0, 8)
: [];
function operationProposalFields(
proposal: TypedActionProposal,
reviewPlan: ReturnType<typeof compileActionReviewPlan>,
t: WorkspaceTranslate,
) {
const frame = reviewPlan.operationFrame;
const projectedFields = frame?.content.fields.map((field, index) => ({
key: `projection:${index}`,
label: field.label,
value: field.value,
})).slice(0, 8) ?? [];
return [
{
key: "operation_state",
label: t("proposal.field.operationState"),
value: proposal.operation?.lifecycle_state ?? proposal.status,
value: frame?.lifecycleState ?? proposal.status,
},
...(proposal.operation?.lifecycle_state === "outcome_observed" ? [{
...(frame?.kind === "result" ? [{
key: "result_delivery",
label: t("proposal.field.resultDelivery"),
value: proposal.operation.result_delivery
value: frame.resultDeliveryVerified
? t("proposal.resultDelivery.verified")
: t("proposal.resultDelivery.pending"),
}] : []),
...projectedFields,
...(typeof safeProjection.warning === "string" ? [{
...(frame ? [{
key: "warning",
label: t("proposal.field.confirmationBoundary"),
value: safeProjection.warning,
value: frame.content.warning,
}] : []),
...(proposal.operation?.expires_at ? [{
...(frame ? [{
key: "expires_at",
label: t("proposal.field.expiresAt"),
value: proposal.operation.expires_at,
value: frame.expiresAt,
}] : []),
].slice(0, 10);
}
Expand Down Expand Up @@ -553,11 +554,8 @@
const target = typeof proposal.normalized_parameters.target === "string"
? proposal.normalized_parameters.target
: "";
const operationProjection = proposal.normalized_parameters.projection;
const operationTitle = operationProjection && typeof operationProjection === "object"
&& typeof (operationProjection as Record<string, unknown>).title === "string"
? String((operationProjection as Record<string, unknown>).title)
: proposal.summary;
const operationFrame = reviewPlan.operationFrame;
const operationTitle = operationFrame?.content.title ?? proposal.summary;
const localizedSummary = proposal.action_kind === "operation.execute"
? operationTitle
: proposal.action_kind === "goal.create"
Expand All @@ -577,7 +575,7 @@
actionKind: proposal.action_kind,
reviewPlan,
fields: proposal.action_kind === "operation.execute"
? operationProposalFields(proposal, t)
? operationProposalFields(proposal, reviewPlan, t)
: proposalFields(proposal.normalized_parameters, t),
goalId: typeof proposal.normalized_parameters.goal_id === "string" ? proposal.normalized_parameters.goal_id : undefined,
impact: proposal.action_kind === "operation.execute"
Expand All @@ -601,10 +599,10 @@
summary: String(proposal.gate.summary ?? t("proposal.gate.default")),
} : undefined,
primaryLabel: proposal.action_kind === "operation.execute"
? proposal.operation?.lifecycle_state === "outcome_observed"
? proposal.operation.result_delivery
? operationFrame?.kind === "result"
? operationFrame.resultDeliveryVerified
? t("proposal.primary.operationResultVerified")
: t("proposal.primary.operationResultPending")

Check warning on line 605 in apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=huangruiteng_loopx&issues=AaCeDq8VuNydAlqVaBBB&open=AaCeDq8VuNydAlqVaBBB&pullRequest=4364
: t("proposal.primary.operationGroup")

Check warning on line 606 in apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=huangruiteng_loopx&issues=AaCeDq8VuNydAlqVaBBA&open=AaCeDq8VuNydAlqVaBBA&pullRequest=4364
: proposal.action_kind === "goal.create" ? t("proposal.primary.goalCreate")
: proposal.action_kind === "goal.lifecycle" && lifecycleOperation === "stop"
Expand Down
Loading