-
+ aria-required="true"
+ invalid={Boolean(state.sprintIdError && (state.touchedFields.sprintId || state.hasAttemptedSubmit))}
+ placeholder="Select sprint"
+ options={[
+ { value: "", label: "Select sprint", disabled: true },
+ ...sprints.map((sprint) => ({ value: sprint.id, label: sprint.name })),
+ ]}
+ />
+ {presentation.requiresHuman && humanIntervention?.title && (
+
+ {humanIntervention.title}
+
+ )}
{presentation.stages.map((stage, index) => )}
diff --git a/dashboard/src/v2/lib/__tests__/cinematic-quick-actions.test.ts b/dashboard/src/v2/lib/__tests__/cinematic-quick-actions.test.ts
index 3dec0f73c9..5753fb86e3 100644
--- a/dashboard/src/v2/lib/__tests__/cinematic-quick-actions.test.ts
+++ b/dashboard/src/v2/lib/__tests__/cinematic-quick-actions.test.ts
@@ -3,6 +3,7 @@ import {
buildCinematicQuickActions,
isInitialProjectCreateAppQuickaction,
} from "../cinematic-quick-actions.js";
+import type { DashboardFeatureFlagMap } from "../dashboard-feature-flags.js";
const ALL_LABELS = [
"Create Web App",
@@ -14,12 +15,18 @@ const ALL_LABELS = [
"Sprint Progress",
"What’s Failing?",
"Plan Next Steps",
- "Add Nodes Workflow",
- "Add Dashboard",
"Create Skill",
"List Skills",
];
+const buildFeatureFlags = (overrides: Partial = {}): DashboardFeatureFlagMap => ({
+ nodes: true,
+ "custom-dashboards": true,
+ "chat-nodes-workflow-quick-action": false,
+ "chat-custom-dashboard-quick-action": false,
+ ...overrides,
+});
+
describe("cinematic quick action view model", () => {
it("builds the complete catalog-driven action set for an eligible project", () => {
const actions = buildCinematicQuickActions({
@@ -36,7 +43,7 @@ describe("cinematic quick action view model", () => {
{ appKind: "portfolio" },
{ appKind: "game" },
]);
- expect(actions.filter(({ actionType }) => actionType === "send_prompt")).toHaveLength(8);
+ expect(actions.filter(({ actionType }) => actionType === "send_prompt")).toHaveLength(6);
expect(new Set(actions.map(({ id }) => id))).toHaveLength(actions.length);
expect(new Set(actions.map(({ zone }) => zone))).toEqual(new Set(["create", "insight", "workflow"]));
});
@@ -64,4 +71,34 @@ describe("cinematic quick action view model", () => {
canCreateInitialAppQuickactions: true,
})).toEqual([]);
});
+
+ it("shows gated workflow actions only when both action and surface flags are enabled", () => {
+ const build = (featureFlags: DashboardFeatureFlagMap) => buildCinematicQuickActions({
+ hasProject: true,
+ initialEligibilityLoaded: false,
+ canCreateInitialAppQuickactions: false,
+ featureFlags,
+ }).map(({ label }) => label);
+
+ expect(build(buildFeatureFlags())).not.toEqual(expect.arrayContaining([
+ "Add Nodes Workflow",
+ "Add Dashboard",
+ ]));
+ expect(build(buildFeatureFlags({
+ "chat-nodes-workflow-quick-action": true,
+ "chat-custom-dashboard-quick-action": true,
+ }))).toEqual(expect.arrayContaining([
+ "Add Nodes Workflow",
+ "Add Dashboard",
+ ]));
+ expect(build(buildFeatureFlags({
+ nodes: false,
+ "custom-dashboards": false,
+ "chat-nodes-workflow-quick-action": true,
+ "chat-custom-dashboard-quick-action": true,
+ }))).not.toEqual(expect.arrayContaining([
+ "Add Nodes Workflow",
+ "Add Dashboard",
+ ]));
+ });
});
diff --git a/dashboard/src/v2/lib/cinematic-quick-actions.ts b/dashboard/src/v2/lib/cinematic-quick-actions.ts
index e9dadaed2d..8876278e44 100644
--- a/dashboard/src/v2/lib/cinematic-quick-actions.ts
+++ b/dashboard/src/v2/lib/cinematic-quick-actions.ts
@@ -1,5 +1,11 @@
import type { DashboardCreateAppQuickactionKind } from "../types.js";
import { CREATE_APP_QUICKACTION_CATALOG } from "../../../../src/domain/chat/create-app-quickaction-catalog.js";
+import {
+ isDashboardFeatureEnabled,
+ resolveDashboardFeatureFlags,
+ type DashboardFeatureFlagMap,
+ type DashboardFeatureId,
+} from "./dashboard-feature-flags.js";
export type CinematicQuickActionZone = "create" | "insight" | "workflow";
@@ -27,7 +33,16 @@ const INITIAL_ONLY_APP_KINDS = new Set([
"game",
]);
-const PROMPT_QUICK_ACTIONS = [
+type PromptQuickAction = {
+ id: string;
+ label: string;
+ zone: "insight" | "workflow";
+ prompt: string;
+ feature?: DashboardFeatureId;
+ requiredSurfaceFeature?: DashboardFeatureId;
+};
+
+const PROMPT_QUICK_ACTIONS: readonly PromptQuickAction[] = [
{
id: "status-report",
label: "Status Report",
@@ -57,12 +72,16 @@ const PROMPT_QUICK_ACTIONS = [
label: "Add Nodes Workflow",
zone: "workflow",
prompt: "Help me add a project-scoped Nodes workflow. Inspect the current project and propose the workflow before making changes.",
+ feature: "chat-nodes-workflow-quick-action",
+ requiredSurfaceFeature: "nodes",
},
{
id: "add-dashboard",
label: "Add Dashboard",
zone: "workflow",
prompt: "Help me add a project dashboard. Inspect the current project and propose the most useful dashboard configuration.",
+ feature: "chat-custom-dashboard-quick-action",
+ requiredSurfaceFeature: "custom-dashboards",
},
{
id: "create-skill",
@@ -82,6 +101,7 @@ export interface CinematicQuickActionOptions {
hasProject: boolean;
initialEligibilityLoaded: boolean;
canCreateInitialAppQuickactions: boolean;
+ featureFlags?: DashboardFeatureFlagMap;
}
export function isInitialProjectCreateAppQuickaction(kind: DashboardCreateAppQuickactionKind): boolean {
@@ -107,11 +127,17 @@ export function buildCinematicQuickActions(options: CinematicQuickActionOptions)
animationDelay: `${index * 0.18}s`,
}));
- const promptActions: CinematicQuickAction[] = PROMPT_QUICK_ACTIONS.map((action, index) => ({
- ...action,
- actionType: "send_prompt",
- animationDelay: `${(createActions.length + index) * 0.18}s`,
- }));
+ const featureFlags = options.featureFlags ?? resolveDashboardFeatureFlags();
+ const promptActions: CinematicQuickAction[] = PROMPT_QUICK_ACTIONS
+ .filter((action) => (
+ (!action.feature || isDashboardFeatureEnabled(action.feature, featureFlags))
+ && (!action.requiredSurfaceFeature || isDashboardFeatureEnabled(action.requiredSurfaceFeature, featureFlags))
+ ))
+ .map(({ feature: _feature, requiredSurfaceFeature: _requiredSurfaceFeature, ...action }, index) => ({
+ ...action,
+ actionType: "send_prompt",
+ animationDelay: `${(createActions.length + index) * 0.18}s`,
+ }));
return [...createActions, ...promptActions];
}
diff --git a/dashboard/src/v2/lib/dashboard-feature-flags.ts b/dashboard/src/v2/lib/dashboard-feature-flags.ts
index 3e27e6550f..dd95b76340 100644
--- a/dashboard/src/v2/lib/dashboard-feature-flags.ts
+++ b/dashboard/src/v2/lib/dashboard-feature-flags.ts
@@ -1,4 +1,9 @@
-export const DASHBOARD_FEATURE_IDS = ["nodes", "custom-dashboards"] as const;
+export const DASHBOARD_FEATURE_IDS = [
+ "nodes",
+ "custom-dashboards",
+ "chat-nodes-workflow-quick-action",
+ "chat-custom-dashboard-quick-action",
+] as const;
export type DashboardFeatureId = typeof DASHBOARD_FEATURE_IDS[number];
@@ -15,8 +20,15 @@ export interface DashboardFeatureFlagSource {
export const DASHBOARD_FEATURE_ENV_KEYS: Record = {
nodes: "VITE_CODEUX_FEATURE_NODES",
"custom-dashboards": "VITE_CODEUX_FEATURE_CUSTOM_DASHBOARDS",
+ "chat-nodes-workflow-quick-action": "VITE_CODEUX_FEATURE_CHAT_NODES_WORKFLOW_QUICK_ACTION",
+ "chat-custom-dashboard-quick-action": "VITE_CODEUX_FEATURE_CHAT_CUSTOM_DASHBOARD_QUICK_ACTION",
};
+const DEVELOPMENT_DISCOVERY_FEATURES = new Set([
+ "nodes",
+ "custom-dashboards",
+]);
+
const ENABLED_VALUES = new Set(["1", "true", "yes", "on", "enabled"]);
const DISABLED_VALUES = new Set(["0", "false", "no", "off", "disabled"]);
@@ -48,6 +60,8 @@ const readDashboardFeatureFlagSource = (): DashboardFeatureFlagSource => {
values: {
nodes: env[DASHBOARD_FEATURE_ENV_KEYS.nodes],
"custom-dashboards": env[DASHBOARD_FEATURE_ENV_KEYS["custom-dashboards"]],
+ "chat-nodes-workflow-quick-action": env[DASHBOARD_FEATURE_ENV_KEYS["chat-nodes-workflow-quick-action"]],
+ "chat-custom-dashboard-quick-action": env[DASHBOARD_FEATURE_ENV_KEYS["chat-custom-dashboard-quick-action"]],
},
prerequisites: {
nodeFlowBackend: env.VITE_CODEUX_NODE_FLOW_BACKEND,
@@ -59,18 +73,12 @@ const readDashboardFeatureFlagSource = (): DashboardFeatureFlagSource => {
export const resolveDashboardFeatureFlags = (
source: DashboardFeatureFlagSource = readDashboardFeatureFlagSource(),
): DashboardFeatureFlagMap => {
- // Development is the feature-discovery environment: every flagged surface must
- // remain reachable even when a checked-in/local env file disables it for a
- // production bundle. Outside development, explicit values still control the
- // feature and omitted values remain disabled by default.
- if (source.devMode) {
- return DASHBOARD_FEATURE_IDS.reduce((flags, feature) => {
+ return DASHBOARD_FEATURE_IDS.reduce((flags, feature) => {
+ if (source.devMode && DEVELOPMENT_DISCOVERY_FEATURES.has(feature)) {
flags[feature] = true;
return flags;
- }, {} as DashboardFeatureFlagMap);
- }
+ }
- return DASHBOARD_FEATURE_IDS.reduce((flags, feature) => {
const explicitValue = parseDashboardFeatureFlagValue(source.values?.[feature]);
if (feature === "nodes") {
const backendReady = parseDashboardFeatureFlagValue(source.prerequisites?.nodeFlowBackend) === true;
diff --git a/dashboard/src/v2/lib/live-session-view-model.ts b/dashboard/src/v2/lib/live-session-view-model.ts
index ef747dc7ea..400782d637 100644
--- a/dashboard/src/v2/lib/live-session-view-model.ts
+++ b/dashboard/src/v2/lib/live-session-view-model.ts
@@ -28,6 +28,7 @@ import {
deriveTaskCiStatusPresentation,
type CiStatusPresentation,
} from "./ci-status-presentation.js";
+import { findActiveTaskHumanIntervention } from "./workflow-status-presentation.js";
export type LiveSessionTaskFilter = "All" | "Running" | "Completed" | "Failed" | "Pending";
@@ -63,6 +64,7 @@ export interface LiveSessionTaskCardItem {
events: ExecutionRuntimeEventSummary[];
invocations: ExecutionInvocationRecord[];
ciPresentation: CiStatusPresentation | null;
+ humanIntervention: ExecutionAttentionItemSummary | null;
isRerunning: boolean;
isForceCompleting: boolean;
forceCompleteError: string | null;
@@ -627,6 +629,12 @@ export function deriveLiveSessionTaskCardItems(input: LiveSessionTaskCardStateIn
attentionItems: ciAttentionItems,
sprintRunId: latestDispatch?.sprintRunId ?? null,
});
+ const humanIntervention = findActiveTaskHumanIntervention(input.attentionItems ?? [], {
+ recordId: task.record_id,
+ taskKey: task.id,
+ sprintId: task.sprint_id,
+ dispatchId: latestDispatch?.id,
+ });
return {
key: taskRuntimeId,
@@ -636,6 +644,7 @@ export function deriveLiveSessionTaskCardItems(input: LiveSessionTaskCardStateIn
events: taskEvents,
invocations: taskInvocations,
ciPresentation,
+ humanIntervention,
isRerunning: input.rerunningIds.has(taskRuntimeId),
isForceCompleting: input.forceCompletePendingIds.has(taskRuntimeId),
forceCompleteError: input.forceCompleteErrorByTaskId.get(taskRuntimeId) || null,
diff --git a/dashboard/src/v2/lib/overview-streams.ts b/dashboard/src/v2/lib/overview-streams.ts
index 88150f2b87..2ff0a263a5 100644
--- a/dashboard/src/v2/lib/overview-streams.ts
+++ b/dashboard/src/v2/lib/overview-streams.ts
@@ -1,4 +1,53 @@
+import type { ExecutionAttentionItemSummary, ExecutionDashboardSnapshot, ExecutionTaskDispatchSummary, SubtaskMergeIndicator } from "../../types.js";
import type { Sprint, Task } from "../types.js";
+import {
+ deriveTaskCiStatusPresentation,
+ type CiStatusPresentation,
+} from "./ci-status-presentation.js";
+import { findActiveTaskHumanIntervention } from "./workflow-status-presentation.js";
+
+const MERGE_INDICATORS = new Set([
+ "CI",
+ "AUTOMERGE",
+ "MERGED",
+ "MERGE_BLOCKED",
+ "MERGE_CONFLICT",
+ "PR_ONLY",
+ "QA_PENDING",
+]);
+
+const normalizeMergeIndicator = (value: string | null): SubtaskMergeIndicator | undefined => (
+ value && MERGE_INDICATORS.has(value as SubtaskMergeIndicator)
+ ? value as SubtaskMergeIndicator
+ : undefined
+);
+
+const dispatchRecency = (dispatch: ExecutionTaskDispatchSummary): string => (
+ dispatch.finishedAt
+ || dispatch.startedAt
+ || dispatch.claimedAt
+ || dispatch.queuedAt
+ || ""
+);
+
+const latestTaskDispatch = (
+ task: Task,
+ dispatches: readonly ExecutionTaskDispatchSummary[],
+): ExecutionTaskDispatchSummary | null => {
+ let latest: ExecutionTaskDispatchSummary | null = null;
+ for (const dispatch of dispatches) {
+ if (
+ dispatch.sprintId !== task.sprintId
+ || (dispatch.taskId !== task.recordId && dispatch.taskKey !== task.id)
+ ) {
+ continue;
+ }
+ if (!latest || dispatchRecency(dispatch).localeCompare(dispatchRecency(latest)) >= 0) {
+ latest = dispatch;
+ }
+ }
+ return latest;
+};
/**
* Derives active sprint IDs from a list of sprints.
@@ -17,3 +66,60 @@ export function filterTasksToActiveSprints(tasks: Task[], activeSprintIds: Set activeSprintIds.has(task.sprintId));
}
+
+/**
+ * Projects the same task CI/merge evidence used by the Tasks and Live surfaces
+ * into the compact Overview task rows. The execution snapshot is realtime, so
+ * this keeps the interactive workflow badge on the current PR/CI/merge stage
+ * instead of falling back to the persisted task lifecycle alone.
+ */
+export function deriveOverviewTaskCiPresentations(
+ tasks: readonly Task[],
+ execution: ExecutionDashboardSnapshot | undefined,
+): Map {
+ const presentations = new Map();
+ if (!execution) {
+ return presentations;
+ }
+
+ for (const task of tasks) {
+ const latestDispatch = latestTaskDispatch(task, execution.taskDispatches);
+ const presentation = deriveTaskCiStatusPresentation({
+ task: {
+ record_id: task.recordId,
+ id: task.id,
+ sprint_id: task.sprintId,
+ merge_indicator: normalizeMergeIndicator(task.mergeIndicator),
+ is_merged: task.isMerged,
+ pr_url: latestDispatch?.prUrl ?? undefined,
+ },
+ events: execution.recentEvents,
+ attentionItems: execution.attentionItems,
+ });
+ if (presentation) {
+ presentations.set(task.recordId, presentation);
+ }
+ }
+
+ return presentations;
+}
+
+export function deriveOverviewTaskHumanInterventions(
+ tasks: readonly Task[],
+ execution: ExecutionDashboardSnapshot | undefined,
+): Map {
+ const interventions = new Map();
+ if (!execution) return interventions;
+
+ for (const task of tasks) {
+ const latestDispatch = latestTaskDispatch(task, execution.taskDispatches);
+ const intervention = findActiveTaskHumanIntervention(execution.attentionItems, {
+ recordId: task.recordId,
+ taskKey: task.id,
+ sprintId: task.sprintId,
+ dispatchId: latestDispatch?.id,
+ });
+ if (intervention) interventions.set(task.recordId, intervention);
+ }
+ return interventions;
+}
diff --git a/dashboard/src/v2/lib/tasks/task-board-view-model.ts b/dashboard/src/v2/lib/tasks/task-board-view-model.ts
index 6ea0fd32c7..f9330c9016 100644
--- a/dashboard/src/v2/lib/tasks/task-board-view-model.ts
+++ b/dashboard/src/v2/lib/tasks/task-board-view-model.ts
@@ -18,6 +18,7 @@ import { buildLiveTaskEnrichmentMap, type LiveTaskEnrichment } from "./live-task
import { buildTaskCardViewModel, type TaskCardViewModel } from "./task-card-view-model.js";
import { STATUS_CFG } from "../tasks-constants.js";
import { formatDuration } from "../format-duration.js";
+import { findActiveTaskHumanIntervention } from "../workflow-status-presentation.js";
export interface TaskBoardViewModelOptions {
tasks: Task[];
@@ -116,6 +117,7 @@ function attentionMatchesTaskRecord(item: ExecutionAttentionItemSummary, task: T
interface TaskCiSource {
presentation: CiStatusPresentation | null;
+ humanIntervention: ExecutionAttentionItemSummary | null;
signature: string;
}
@@ -136,6 +138,11 @@ function buildTaskCiSource(args: {
};
const events = args.events.filter((event) => eventMatchesTaskRecord(event, args.task));
const attentionItems = args.attentionItems.filter((item) => attentionMatchesTaskRecord(item, args.task));
+ const humanIntervention = findActiveTaskHumanIntervention(args.attentionItems, {
+ recordId: args.task.recordId,
+ taskKey: args.task.id,
+ sprintId: args.task.sprintId,
+ });
const presentation = deriveTaskCiStatusPresentation({
task: evidence,
events,
@@ -164,8 +171,15 @@ function buildTaskCiSource(args: {
resolvedAt: item.resolvedAt,
payload: item.payload,
})).sort((left, right) => left.id.localeCompare(right.id)),
+ humanIntervention: humanIntervention ? {
+ id: humanIntervention.id,
+ ownerType: humanIntervention.ownerType,
+ status: humanIntervention.status,
+ assignedWorkerEndpointId: humanIntervention.assignedWorkerEndpointId,
+ updatedAt: humanIntervention.updatedAt,
+ } : null,
});
- return { presentation, signature };
+ return { presentation, humanIntervention, signature };
}
function buildTaskSignature(task: Task): string {
@@ -450,6 +464,7 @@ export function buildTaskBoardViewModel(options: TaskBoardViewModelOptions): Tas
reusableViewModel ?? buildTaskCardViewModel(task, taskLookup, liveEnrichment, {
taskPullRequestsEnabled,
ciStatusPresentation: ciSource.presentation,
+ humanIntervention: ciSource.humanIntervention,
ciStatusSourceSignature: ciSource.signature,
})
);
diff --git a/dashboard/src/v2/lib/tasks/task-card-view-model.ts b/dashboard/src/v2/lib/tasks/task-card-view-model.ts
index f8e449b8ea..6c6131a615 100644
--- a/dashboard/src/v2/lib/tasks/task-card-view-model.ts
+++ b/dashboard/src/v2/lib/tasks/task-card-view-model.ts
@@ -1,3 +1,4 @@
+import type { ExecutionAttentionItemSummary } from "../../../types.js";
import type { Task, TaskStatus, TaskExecutorType } from "../../types.js";
import type { CiStatusPresentation } from "../ci-status-presentation.js";
import { type LiveTaskEnrichment } from "./live-task-enrichment.js";
@@ -22,6 +23,7 @@ export interface TaskCardViewModel {
dependencyActionLabel?: string;
qaReviewLabel?: string;
ciStatusPresentation?: CiStatusPresentation | null;
+ humanIntervention?: ExecutionAttentionItemSummary | null;
ciStatusSourceSignature?: string;
optimisticSavingLabel?: string | null;
dragStateLabel?: string;
@@ -50,6 +52,7 @@ export interface TaskCardActionDescriptor {
export interface TaskCardViewModelOptions {
taskPullRequestsEnabled?: boolean;
ciStatusPresentation?: CiStatusPresentation | null;
+ humanIntervention?: ExecutionAttentionItemSummary | null;
ciStatusSourceSignature?: string;
}
@@ -231,6 +234,7 @@ export function buildTaskCardViewModel(
dependencyActionLabel: buildDependencyActionLabel(dependencyIndicators),
qaReviewLabel: task.latestReview ? undefined : "QA no review",
ciStatusPresentation: options.ciStatusPresentation ?? null,
+ humanIntervention: options.humanIntervention ?? null,
ciStatusSourceSignature: options.ciStatusSourceSignature ?? "",
optimisticSavingLabel: task.isOptimistic ? "Saving task changes" : null,
dragStateLabel: task.isOptimistic
diff --git a/dashboard/src/v2/lib/workflow-status-presentation.ts b/dashboard/src/v2/lib/workflow-status-presentation.ts
index 68f76e14b2..bb6869d1b4 100644
--- a/dashboard/src/v2/lib/workflow-status-presentation.ts
+++ b/dashboard/src/v2/lib/workflow-status-presentation.ts
@@ -1,4 +1,5 @@
import type { SprintReviewSummary } from "../types.js";
+import type { ExecutionAttentionItemSummary } from "../../types.js";
import type {
CiStatusPresentation,
CiWorkflowState,
@@ -20,20 +21,89 @@ export interface WorkflowStatusPresentation {
tone: "pending" | "active" | "successful" | "failed" | "qa_changes";
label: string;
accessibleLabel: string;
+ requiresHuman: boolean;
stages: [WorkflowStage, WorkflowStage, WorkflowStage, WorkflowStage, WorkflowStage, WorkflowStage];
}
+export interface WorkflowHumanInterventionEvidence {
+ ownerType: string | null;
+ status?: string | null;
+ assignedWorkerEndpointId?: string | null;
+ title?: string | null;
+}
+
+export interface WorkflowTaskIdentity {
+ recordId?: string | null;
+ taskKey?: string | null;
+ sprintId?: string | null;
+ dispatchId?: string | null;
+}
+
export interface WorkflowStatusPresentationInput {
scope: "task" | "sprint";
status: string;
review?: SprintReviewSummary | null;
ciPresentation?: CiStatusPresentation | null;
+ humanIntervention?: WorkflowHumanInterventionEvidence | null;
}
function normalizeStatus(value: string): string {
return value.trim().toLowerCase().replaceAll("-", "_").replaceAll(" ", "_");
}
+const ACTIVE_ATTENTION_STATUSES = new Set(["open", "claimed"]);
+const HUMAN_ATTENTION_OWNERS = new Set(["human", "user"]);
+
+/**
+ * Human-needed is intentionally narrower than generic attention: the item must
+ * still be active, explicitly human-owned, and explicitly unassigned. A
+ * sprint-run intervention summary is not sufficient evidence because that
+ * contract omits status/assignment and may be synthesized from lifecycle
+ * events such as a manual pause or runtime error.
+ */
+export function isActiveHumanIntervention(
+ intervention: WorkflowHumanInterventionEvidence | null | undefined,
+): boolean {
+ if (!intervention) return false;
+ const ownerType = normalizeStatus(intervention.ownerType ?? "");
+ const status = intervention.status == null ? null : normalizeStatus(intervention.status);
+ const hasExplicitWorkerAssignment = Object.prototype.hasOwnProperty.call(
+ intervention,
+ "assignedWorkerEndpointId",
+ );
+ return HUMAN_ATTENTION_OWNERS.has(ownerType)
+ && status !== null
+ && ACTIVE_ATTENTION_STATUSES.has(status)
+ && hasExplicitWorkerAssignment
+ && intervention.assignedWorkerEndpointId === null;
+}
+
+function attentionTaskIds(item: ExecutionAttentionItemSummary): string[] {
+ const ids = [item.taskId];
+ for (const key of ["taskId", "taskKey"] as const) {
+ const value = item.payload?.[key];
+ if (typeof value === "string") ids.push(value);
+ }
+ return ids.flatMap((value) => value?.trim() ? [value.trim()] : []);
+}
+
+export function findActiveTaskHumanIntervention(
+ attentionItems: readonly ExecutionAttentionItemSummary[] | undefined,
+ identity: WorkflowTaskIdentity,
+): ExecutionAttentionItemSummary | null {
+ const taskIds = new Set(
+ [identity.recordId, identity.taskKey].flatMap((value) => value?.trim() ? [value.trim()] : []),
+ );
+ if (taskIds.size === 0 && !identity.dispatchId) return null;
+
+ return attentionItems?.find((item) => {
+ if (!isActiveHumanIntervention(item)) return false;
+ if (identity.sprintId && item.sprintId && item.sprintId !== identity.sprintId) return false;
+ if (identity.dispatchId && item.dispatchId === identity.dispatchId) return true;
+ return attentionTaskIds(item).some((taskId) => taskIds.has(taskId));
+ }) ?? null;
+}
+
function fallbackCiStep(id: CiWorkflowStep["id"], workflowCompleted: boolean): CiWorkflowStep {
const labels = workflowCompleted
? {
@@ -190,27 +260,31 @@ export function deriveWorkflowStatusPresentation(
] as WorkflowStatusPresentation["stages"];
const failed = stages.some((stage) => stage.state === "failed");
const active = stages.some((stage) => stage.state === "in_progress");
- const state: CiWorkflowState = failed
+ const requiresHuman = isActiveHumanIntervention(input.humanIntervention);
+ const state: CiWorkflowState = requiresHuman || failed
? "failed"
: active
? "in_progress"
: stages[5].state === "successful"
? "successful"
: "pending";
- const label = displayLabel(stages);
+ const label = requiresHuman ? "Human needed" : displayLabel(stages);
const qaChangesRequested = stages.some((stage) => (
stage.id === "qa" && stage.state === "failed" && stage.statusLabel === "Changes requested"
));
return {
scope: input.scope,
state,
- tone: qaChangesRequested
+ tone: requiresHuman
+ ? "failed"
+ : qaChangesRequested
? "qa_changes"
: state === "in_progress"
? "active"
: state,
label,
- accessibleLabel: `${label}. ${stages.map((stage) => `${stage.label}: ${stage.statusLabel}`).join(". ")}.`,
+ accessibleLabel: `${label}. ${requiresHuman && input.humanIntervention?.title ? `${input.humanIntervention.title}. ` : ""}${stages.map((stage) => `${stage.label}: ${stage.statusLabel}`).join(". ")}.`,
+ requiresHuman,
stages,
};
}
diff --git a/docs-web/architecture/card-ci-status-projection.md b/docs-web/architecture/card-ci-status-projection.md
index cb56b3137c..ab282ab03a 100644
--- a/docs-web/architecture/card-ci-status-projection.md
+++ b/docs-web/architecture/card-ci-status-projection.md
@@ -24,7 +24,9 @@ Review gating remains separate from CI failure presentation. A main-merge `revie
The dashboard combines that evidence with lifecycle and latest-review state in one durable six-stage delivery flow on Task, Live, Sprint gallery, Sprint ledger, and Overview cards: **Coding**, **Pull request**, **QA**, **CI**, **Merge**, and **Completion**. CI evidence enriches the middle stages but is optional, so a Sprints refresh without historical gate events cannot unmount or flash away the badge. A durably completed workflow settles missing historical PR, checks, and merge projections as successful rather than showing contradictory pending stages. A newer successful observation replaces stale failure, while active matching CI attention restores the failure state.
-The bright interactive badge opens a circular rail with motion-safe animated dotted connectors. When a review exists, an animated chevron joins the workflow card to an adjacent review card. Requested changes use the blue pencil and **QA edits** treatment even when failed-check evidence also exists; red is reserved for actual provider/runtime and workflow failures. Live replaces its separate task lifecycle and QA badges, while Task, Sprint, and Overview surfaces keep their surrounding lifecycle context and replace the standalone QA/CI disclosures. While a sprint is running, the sprint badge stays on Coding and ignores child-task gate aggregation; each task badge continues showing its own PR, QA, CI, and Merge transitions.
+Active, task-matched human-only attention has presentation precedence over the ordinary lifecycle and gate summary: the trigger becomes red **Human needed** while its disclosure retains all six stages. Explicit attention-item evidence is required: status is `open` or `claimed`, owner is human/user, and worker assignment is explicitly empty. Cleared, machine-owned, worker-assigned, sibling-task, and sibling-sprint attention does not. Sprint-run summaries alone never qualify because they omit status and assignment and may come from generic pause/error events.
+
+The bright interactive badge opens one viewport-positioned interaction region without a visible outer card. Its opaque Delivery flow card contains the circular rail; a floating responsive arrow points to an independent opaque QA review card when a review exists. Requested changes use the blue pencil and **QA edits** treatment even when failed-check evidence also exists; red identifies actual provider/runtime/workflow failures and explicit **Human needed** intervention. Live replaces its separate task lifecycle and QA badges, while Task, Sprint, and Overview surfaces keep their surrounding lifecycle context and replace the standalone QA/CI disclosures. While a sprint is running, the sprint badge stays on Coding and ignores child-task gate aggregation unless active human-only intervention takes precedence; each task badge continues showing its own PR, QA, CI, and Merge transitions.
The deterministic dashboard integration suite replays these outcomes across all four card renderings, including keyboard-only QA details, collapsed follow-up specifications, Escape focus restoration, unrelated-event isolation, and unchanged snapshot replay. It mocks runtime boundaries and does not invoke Docker, provider CLIs, Git hosting, or a live database.
diff --git a/docs-web/architecture/dashboard-architecture.md b/docs-web/architecture/dashboard-architecture.md
index d22a526ecd..a18fe1942e 100644
--- a/docs-web/architecture/dashboard-architecture.md
+++ b/docs-web/architecture/dashboard-architecture.md
@@ -156,6 +156,8 @@ Key tokens (defined in `styles.css`):
Components prefer **design tokens over hardcoded values**. New components should reuse existing tokens rather than introducing one-offs.
+User-visible single-choice fields use the shared `AvantgardeSelect` trigger/listbox primitive instead of browser-native selects. This keeps option surfaces aligned with Warm Void in both themes while preserving labels, descriptions, disabled and busy states, keyboard navigation, compact layouts, and focus restoration. Disabled options remain visible but are skipped by pointer and keyboard selection. The older native Select wrapper is retained only for isolated compatibility tests and has no production callers.
+
## Accessibility
- Every interactive element is keyboard-reachable.
diff --git a/docs-web/content/docs/architecture-card-ci-status-projection.mdx b/docs-web/content/docs/architecture-card-ci-status-projection.mdx
index f3fdda121d..daa1c7856c 100644
--- a/docs-web/content/docs/architecture-card-ci-status-projection.mdx
+++ b/docs-web/content/docs/architecture-card-ci-status-projection.mdx
@@ -24,7 +24,9 @@ Review gating remains separate from CI failure presentation. A main-merge `revie
The dashboard combines that evidence with lifecycle and latest-review state in one durable six-stage delivery flow on Task, Live, Sprint gallery, Sprint ledger, and Overview cards: **Coding**, **Pull request**, **QA**, **CI**, **Merge**, and **Completion**. CI evidence enriches the middle stages but is optional, so a Sprints refresh without historical gate events cannot unmount or flash away the badge. A durably completed workflow settles missing historical PR, checks, and merge projections as successful rather than showing contradictory pending stages. A newer successful observation replaces stale failure, while active matching CI attention restores the failure state.
-The bright interactive badge opens a circular rail with motion-safe animated dotted connectors. When a review exists, an animated chevron joins the workflow card to an adjacent review card. Requested changes use the blue pencil and **QA edits** treatment even when failed-check evidence also exists; red is reserved for actual provider/runtime and workflow failures. Live replaces its separate task lifecycle and QA badges, while Task, Sprint, and Overview surfaces keep their surrounding lifecycle context and replace the standalone QA/CI disclosures. While a sprint is running, the sprint badge stays on Coding and ignores child-task gate aggregation; each task badge continues showing its own PR, QA, CI, and Merge transitions.
+Active, task-matched human-only attention has presentation precedence over the ordinary lifecycle and gate summary: the trigger becomes red **Human needed** while its disclosure retains all six stages. Explicit attention-item evidence is required: status is `open` or `claimed`, owner is human/user, and worker assignment is explicitly empty. Cleared, machine-owned, worker-assigned, sibling-task, and sibling-sprint attention does not. Sprint-run summaries alone never qualify because they omit status and assignment and may come from generic pause/error events.
+
+The bright interactive badge opens one viewport-positioned interaction region without a visible outer card. Its opaque Delivery flow card contains the circular rail; a floating responsive arrow points to an independent opaque QA review card when a review exists. Requested changes use the blue pencil and **QA edits** treatment even when failed-check evidence also exists; red identifies actual provider/runtime/workflow failures and explicit **Human needed** intervention. Live replaces its separate task lifecycle and QA badges, while Task, Sprint, and Overview surfaces keep their surrounding lifecycle context and replace the standalone QA/CI disclosures. While a sprint is running, the sprint badge stays on Coding and ignores child-task gate aggregation unless active human-only intervention takes precedence; each task badge continues showing its own PR, QA, CI, and Merge transitions.
The deterministic dashboard integration suite replays these outcomes across all four card renderings, including keyboard-only QA details, collapsed follow-up specifications, Escape focus restoration, unrelated-event isolation, and unchanged snapshot replay. It mocks runtime boundaries and does not invoke Docker, provider CLIs, Git hosting, or a live database.
diff --git a/docs-web/content/docs/architecture-dashboard-architecture.mdx b/docs-web/content/docs/architecture-dashboard-architecture.mdx
index 7f96cb046b..079fb28f09 100644
--- a/docs-web/content/docs/architecture-dashboard-architecture.mdx
+++ b/docs-web/content/docs/architecture-dashboard-architecture.mdx
@@ -156,6 +156,8 @@ Key tokens (defined in `styles.css`):
Components prefer **design tokens over hardcoded values**. New components should reuse existing tokens rather than introducing one-offs.
+User-visible single-choice fields use the shared `AvantgardeSelect` trigger/listbox primitive instead of browser-native selects. This keeps option surfaces aligned with Warm Void in both themes while preserving labels, descriptions, disabled and busy states, keyboard navigation, compact layouts, and focus restoration. Disabled options remain visible but are skipped by pointer and keyboard selection. The older native Select wrapper is retained only for isolated compatibility tests and has no production callers.
+
## Accessibility
- Every interactive element is keyboard-reachable.
diff --git a/docs-web/content/docs/developer-feature-flags.mdx b/docs-web/content/docs/developer-feature-flags.mdx
index 32db0fa626..c0eeb79db6 100644
--- a/docs-web/content/docs/developer-feature-flags.mdx
+++ b/docs-web/content/docs/developer-feature-flags.mdx
@@ -4,20 +4,22 @@ Dashboard feature flags hide unfinished dashboard surfaces without deleting thei
Flags live in `dashboard/src/v2/lib/dashboard-feature-flags.ts`. They are resolved at dashboard bundle time through Vite `import.meta.env` values:
-- Development and test builds enable all flagged unfinished features by default.
-- Production builds disable flagged unfinished features by default.
-- Explicit env values override the mode default.
+- Development builds always enable the `nodes` and `custom-dashboards` discovery surfaces so those in-progress pages remain available for local testing.
+- Production builds disable unfinished surfaces by default; explicit env values enable or disable them.
+- Cinematic quick-action flags default to disabled in every mode and require an explicit env opt-in. Their underlying surface flag must also be enabled.
-Supported values are `true`, `1`, `yes`, `on`, `enabled`, `false`, `0`, `no`, `off`, and `disabled`. Empty or unrecognized values fall back to the mode default.
+Supported values are `true`, `1`, `yes`, `on`, `enabled`, `false`, `0`, `no`, `off`, and `disabled`. Empty or unrecognized values fall back to the flag's documented default. Development mode intentionally overrides disabled values only for the two discovery surfaces.
## Current Flags
| Feature | Env variable | Development default | Production default | Scope |
| --- | --- | --- | --- | --- |
-| `nodes` | `VITE_CODEUX_FEATURE_NODES` | enabled | disabled | Hides the unfinished `/nodes` surface from route registration, shared navigation, route prefetch, and the guided dashboard tour. |
+| `nodes` | `VITE_CODEUX_FEATURE_NODES` | enabled | disabled | Requires `VITE_CODEUX_NODE_FLOW_BACKEND` and `VITE_CODEUX_AUTOMATION_SECURITY` to also be enabled in production. |
| `custom-dashboards` | `VITE_CODEUX_FEATURE_CUSTOM_DASHBOARDS` | enabled | disabled | Hides the unfinished `/custom-dashboards` surface from route registration, shared navigation, route prefetch, and the guided dashboard tour. |
+| `chat-nodes-workflow-quick-action` | `VITE_CODEUX_FEATURE_CHAT_NODES_WORKFLOW_QUICK_ACTION` | disabled | disabled | Shows **Add Nodes Workflow** only when this flag and `nodes` are both enabled. |
+| `chat-custom-dashboard-quick-action` | `VITE_CODEUX_FEATURE_CHAT_CUSTOM_DASHBOARD_QUICK_ACTION` | disabled | disabled | Shows **Add Dashboard** only when this flag and `custom-dashboards` are both enabled. |
-When a feature is disabled, its page module remains in source for local development and tests, but the route is not added to the TanStack route tree. Direct navigation falls through to the dashboard not-found route.
+When Nodes or either production prerequisite is disabled, its route is omitted from the route tree, navigation, and route prefetch. Development keeps the surface reachable for local integration testing. This discovery override does not expose either cinematic workflow quick action; each action remains hidden until its dedicated opt-in flag is enabled.
## Adding a Flag
@@ -26,5 +28,5 @@ When a feature is disabled, its page module remains in source for local developm
3. Gate route registration in `dashboard/src/main.tsx`.
4. Gate route prefetch entries in `dashboard/src/v2/router/route-prefetch.ts`.
5. Gate guided tour steps or other entry points that reference the hidden surface.
-6. Add focused tests for default behavior, explicit overrides, and every hidden entry point.
+6. Choose whether the flag is a development discovery surface or a default-off capability, then add focused tests for mode defaults, explicit overrides, prerequisites, and every hidden entry point.
7. Update this page and the matching canonical `docs/` page.
diff --git a/docs-web/content/docs/developer-settings-reference.mdx b/docs-web/content/docs/developer-settings-reference.mdx
index 7311a72b46..0566447c2f 100644
--- a/docs-web/content/docs/developer-settings-reference.mdx
+++ b/docs-web/content/docs/developer-settings-reference.mdx
@@ -143,7 +143,7 @@ Project and sprint settings own design guidance:
}
```
-The backend catalog always includes `none`, the built-in `Code UX` styleguide, additional default styleguides, and a small tech-stack guidance catalog. Saved selections resolve to a known default or custom id; invalid ids fall back to `none`. `hideDefaultStyleguides` only affects presentation and does not remove backend defaults. Existing and imported projects inherit `none`; new local and new remote project initialization writes an explicit project override for the Code UX styleguide. Planning and Project Setup prompts resolve selected entries from effective project settings and omit inactive `none` catalog entries. Project Setup prompts also include a setup-only styling investigation notice whenever the styleguide selection is `none`, including when tech-stack guidance is also `none`.
+The backend catalog always includes `none`, the built-in `Code UX` styleguide, additional default styleguides, and a small tech-stack guidance catalog. Saved selections resolve to a known default or custom id; invalid ids fall back to `none`. `hideDefaultStyleguides` only affects presentation and does not remove backend defaults. Every imported, new local, and new remote project writes explicit `none` project overrides for both selections; create-time selected ids are normalized to `none`, while unrelated custom catalogs and visibility settings are preserved. Planning and Project Setup prompts resolve selected entries from effective project settings and omit inactive `none` catalog entries. Project Setup prompts also include a setup-only styling investigation notice whenever the styleguide selection is `none`, including when tech-stack guidance is also `none`.
The dashboard Guidance panel manages this block through the normal settings save flows. System scope edits `system.defaults.designGuidance`; project scope edits the active project override. Built-in catalog entries can be selected but cannot be edited or deleted. Custom entries can be added, edited, and deleted; deleting a selected custom entry clears that selector back to `none`.
diff --git a/docs-web/content/docs/user-dashboard-chat.mdx b/docs-web/content/docs/user-dashboard-chat.mdx
index a3d3647244..07d88aa92b 100644
--- a/docs-web/content/docs/user-dashboard-chat.mdx
+++ b/docs-web/content/docs/user-dashboard-chat.mdx
@@ -17,17 +17,17 @@ Markdown links use the dashboard's theme-aware signal colors across thread messa
While the Project Manager is genuinely idle, the 3D stage can show one short ambient cue at a time: a greeting, wink, curious glance, dance beat, or a text-labelled humming cue with decorative notes. Returning to the page produces a welcome-back cue only after the stage was hidden or idle for at least 30 seconds, so quick tab changes stay quiet. Sending, Project Manager work, errors, hidden pages, and reduced-motion mode stop these cue timers and the stage's continuous decorative drift. The static mood caption, connection status, and unrelated background-activity count remain visible and truthful. Ambient cue text is visible but is not repeatedly announced as a live status update.
-The 3D stage enters its Project Manager working state only while the selected thread awaits that agent's reply or a running `dashboard_reply`/`worker_reply` invocation belongs to the same resolved agent preset. Only the newest matching running invocation owns the foreground work tool and transient progress bubble. Other agents' replies and unrelated task, planning, QA, or CI invocations remain truthful background activity; they can keep a background thought cue and count visible, but they do not make the Project Manager show a thinking expression, work tool, active caption, progress bubble, or busy-only quick-action state. Sending a message keeps its separate routing state until the awaited reply or matching invocation is visible.
+The 3D stage enters its Project Manager working state only while the selected thread awaits that agent's reply or a running `dashboard_reply`/`worker_reply` invocation belongs to the same resolved agent preset. That authoritative busy state owns the foreground work tool, including the interval before an invocation record becomes visible; only the newest matching running invocation owns the transient transcript progress bubble. Other agents' replies and unrelated task, planning, QA, or CI invocations remain truthful background activity; they can keep a background thought cue and count visible, but they do not make the Project Manager show a thinking expression, work tool, active caption, progress bubble, or busy-only quick-action state. Sending a message keeps its separate routing state until the awaited reply or matching invocation is visible.
The thought area turns known runtime fields into compact cues for container startup, provider work, planning, QA review, completion, and errors. Current stage cues come only from running records or the selected thread's awaited reply; old completed or failed invocations are not presented as live activity. A delegated-work cue stays visible while the Project Manager remains idle, and an active Project Manager cue takes precedence while retaining a count of other activity. The phase is shown directly without `Background` or provider-name prefixes. Its workplace-safe quote is keyed by stable agent, provider, phase, and runtime context and stays unchanged for at least twenty seconds. Delegated work uses 72 original agency and project-management jokes about coworker handoffs, meetings, scope creep, client feedback, and ticket rituals. The runtime shuffles the deck by context, uses every line before reshuffling, and avoids immediate repeats. Reduced-motion mode keeps the status text while stopping its decorative dots.
-For the full lifecycle of a matching running Project Manager reply invocation, including startup before its first transcript turn, the avatar rotates through five work tools every seven seconds: Power screwdriver (`screwdriver`), Jackhammer (`jackhammer`), Open-end wrench (`wrench`), Claw hammer (`hammer`), and Welding torch (`torch`). The matching invocation id chooses a deterministic initial tool, then rotation follows catalog order without immediately repeating; a replacement invocation starts its own deterministic sequence and terminal state removes the tool immediately. Awaited-thread fallback without a matching invocation and background work never equip a runtime-selected tool because invocation ownership is resolved before tool selection. Reduced motion keeps the initial tool static without a rotation timer. Maintainers can pin a valid catalog identifier with `/chat?stageTool=` for design review, including while activity is inactive; missing or unsupported values leave normal runtime selection in place. Reduced-motion and WebGL fallback surfaces keep the visible tool label and accessible avatar description.
+For the full lifecycle of active Project Manager reply work, including an awaited selected-thread reply before its invocation is visible and startup before its first transcript turn, the avatar rotates through five work tools every seven seconds: Power screwdriver (`screwdriver`), Jackhammer (`jackhammer`), Open-end wrench (`wrench`), Claw hammer (`hammer`), and Welding torch (`torch`). The foreground activity id—normally the matching invocation id or selected thread id—chooses a deterministic initial tool, then rotation follows catalog order without immediately repeating; replacing that active reply context starts its own deterministic sequence and leaving the Project Manager busy state removes the tool immediately. Background work never equips a runtime-selected tool. Reduced motion keeps the initial tool static without a rotation timer. Maintainers can pin a valid catalog identifier with `/chat?stageTool=` for design review, including while activity is inactive; missing or unsupported values leave normal runtime selection in place. Reduced-motion and WebGL fallback surfaces keep the visible tool label and accessible avatar description.
While that matching invocation runs, the latest exchange also shows a transient progress bubble with an explicit **In progress** label, the latest non-empty persisted assistant update eligible for display, and a deduplicated tool count. Tool-call/result pairs with the same call id count once; reasoning, injected context, user prompts, raw tool payloads, and unknown internal turns are not used as the interim prose. Zero-message startup fetches the persisted transcript and shows **Preparing the first progress update…** with `0 tools used` until an eligible assistant turn exists.
-The bubble is a polite live status projection only. It does not create or persist a thread message and remains separate from the durable Threads transcript and final Project Manager reply. It refreshes when the running invocation's message count, last-message time, or general update time changes, including same-length telemetry rewrites. During a same-invocation refresh, or after a non-fatal transcript-fetch failure, the last accepted update and count stay visible; if no fetch has succeeded, the startup placeholder stays visible. Superseded requests are cancelled and late responses are ignored. The bubble and work tool clear on invocation replacement, completion, failure, disappearance, project change, a later thread selection, or loss of matching Project Manager ownership. The first-send handoff from a new conversation to the thread it creates is retained, but interim text cannot follow later navigation or duplicate the stored final reply. This behavior projects persisted invocation records; it does not promise backend streaming or message delivery.
+The bubble is a polite live status projection only. It does not create or persist a thread message and remains separate from the durable Threads transcript and final Project Manager reply. It refreshes when the running invocation's message count, last-message time, or general update time changes, including same-length telemetry rewrites. During a same-invocation refresh, or after a non-fatal transcript-fetch failure, the last accepted update and count stay visible; if no fetch has succeeded, the startup placeholder stays visible. Superseded requests are cancelled and late responses are ignored. The progress bubble clears on invocation replacement, completion, failure, disappearance, project change, a later thread selection, or loss of matching Project Manager ownership; the separate work tool remains present whenever the Project Manager busy state is still true. The first-send handoff from a new conversation to the thread it creates is retained, but interim text cannot follow later navigation or duplicate the stored final reply. This behavior projects persisted invocation records; it does not promise backend streaming or message delivery.
-On compact layouts, the latest exchange remains inside the stage above the composer and scrolls within that bounded region, so replies and active progress appear without moving the whole stage. The progress bubble is also height-bounded and scrolls long prose internally; long words wrap, while wide code and tables scroll horizontally. At wider breakpoints its maximum width is 680px on LG, 780px on XL, and 880px on 2XL; at 2XL it can reach 220px high with 17px/36px prose. The separate desktop thought bubble remains compact, shifts farther left at XL/2XL, and keeps visible spacing around its two-dot tail so it does not crowd the larger avatar or reply column. With motion enabled, the bubble animates on first appearance and eligible interim-message changes while the selected tool rotates every seven seconds. Reduced motion removes those transitions, tool rotation, and thought dots, but preserves the static tool label, **In progress**, interim or startup text, and tool count. Those visible labels remain the authoritative activity signal, including under the static SVG/WebGL-failure fallback.
+On compact layouts, the latest exchange remains inside the stage above the composer and scrolls within that bounded region, so replies and active progress appear without moving the whole stage. The durable reply is right-aligned in a narrower desktop column, capped between 560px and 680px at wider breakpoints, and uses compact 12–13px prose so it stays clear of the avatar. The progress bubble is also height-bounded and scrolls long prose internally; long words wrap, while wide code and tables scroll horizontally. At wider breakpoints its maximum width is 680px on LG, 780px on XL, and 880px on 2XL; at 2XL it can reach 220px high with 17px/36px prose. The separate desktop thought bubble remains compact and horizontally centered directly above the avatar, with visible spacing around its two-dot tail. With motion enabled, the progress bubble animates on first appearance and eligible interim-message changes while the selected tool rotates every seven seconds. Reduced motion removes those transitions, tool rotation, and thought dots, but preserves the static tool label, **In progress**, interim or startup text, and tool count. Those visible labels remain the authoritative activity signal, including under the static SVG/WebGL-failure fallback.
When a text-to-speech model or API is active under **Settings -> AI Models**, 3D Chat reads new Project Manager replies aloud. A compact control dock beneath the avatar identity holds the microphone and agent mute/unmute buttons, outside the composer. Voice defaults on, shows synthesis activity, and can be muted immediately. The preference is remembered per project in the current browser; opening an existing thread does not replay its latest historical message. Long replies start with the first ready sentence while a bounded two-chunk lookahead is synthesized, then continue through every chunk in transcript order. Muting, changing threads or Chat mode, leaving the page, or starting another replay cancels pending speech and releases the active audio. If synthesis or browser playback fails, playback stops and the accessible voice or transcript status reports the error without hiding the written reply.
@@ -105,9 +105,9 @@ After you send a message, the thread transcript updates from the server's return
While a reply or invocation container is active, the visible status line uses light deterministic humor instead of static `Initializing` or `Working` copy. These messages are keyed by the active agent, provider/model, and phase, and they remain stable for at least five seconds so live regions do not churn during rapid refreshes. The funny line is a UI adjunct only; it does not replace the actual agent reply, invocation status, or stored transcript.
-In 3D Chat, the complete idle set is the five create-app actions together with **Status Report**, **Sprint Progress**, **What’s Failing?**, **Plan Next Steps**, **Add Nodes Workflow**, **Add Dashboard**, **Create Skill**, and **List Skills**. The create-app buttons use the typed detached quicksprint path described above. The other eight buttons are normal chat actions: they immediately send their fixed informational or workflow prompt through the selected project's routed Thread and do not create detached app planning. Neither path inserts into, replaces, or clears text already in the composer.
+In 3D Chat, the default idle set is the five create-app actions together with **Status Report**, **Sprint Progress**, **What’s Failing?**, **Plan Next Steps**, **Create Skill**, and **List Skills**. The create-app buttons use the typed detached quicksprint path described above. The other six buttons are normal chat actions: they immediately send their fixed informational or workflow prompt through the selected project's routed Thread and do not create detached app planning. Neither path inserts into, replaces, or clears text already in the composer. **Add Nodes Workflow** and **Add Dashboard** are hidden by default; each requires both its dedicated quick-action feature flag and the corresponding Nodes or custom-dashboard surface flag.
-On desktop the controls are sorted into subtle **Create**, **Project pulse**, and **Workflows** clusters contained inside the left side of the stage. Each category wraps its small content-width chips together, keeping Sprint Progress and Plan Next Steps with Project pulse and keeping Add Dashboard, Create Skill, and List Skills with Workflows. Small offsets, extra whitespace, and gentle staggered drift keep the composition interesting without clipping controls or crowding the avatar. On mobile the controls retain the same category order in horizontally scrollable two-row groups. Neutral chip surfaces and distinct colored icon tiles make the actions easier to scan without giving every action the same green emphasis. Labels stay on one line. Every control is a keyboard-reachable button with a visible focus state, and Enter or Space activates it. Reduced-motion mode stops the quickaction floating animation (along with the stage's other decorative motion) without removing actions or status text. The whole group hides without a selected project and while chat is sending, working, or showing an error; all five create-app actions also remain hidden until initial-project eligibility has loaded and passed.
+On desktop the enabled controls are sorted into subtle **Create**, **Project pulse**, and **Workflows** clusters contained inside the left side of the stage. Each category wraps its small content-width chips together, keeping Sprint Progress and Plan Next Steps with Project pulse and keeping Create Skill and List Skills with Workflows. Small offsets, extra whitespace, and gentle staggered drift keep the composition interesting without clipping controls or crowding the avatar. On mobile the controls retain the same category order in horizontally scrollable two-row groups. Neutral chip surfaces and distinct colored icon tiles make the actions easier to scan without giving every action the same green emphasis. Labels stay on one line. Every control is a keyboard-reachable button with a visible focus state, and Enter or Space activates it. Reduced-motion mode stops the quickaction floating animation (along with the stage's other decorative motion) without removing actions or status text. The whole group hides without a selected project and while chat is sending, working, or showing an error; all five create-app actions also remain hidden until initial-project eligibility has loaded and passed.
Planning messages can include a rich sprint status card. When Code UX can match the message to loaded live project data, the card is backed by the current task records and execution snapshot, so it updates as tasks move from queued to running, completed, failed, blocked, or quota-waiting. It shows the sprint key/name, request/task/run materialization, overall progress such as `0/7 · 0%`, queued task count, and a compact task list. If either task records or the execution snapshot are still loading, the chat keeps the generic planning status card until both live records are available for the active project.
diff --git a/docs-web/content/docs/user-dashboard-live-session.mdx b/docs-web/content/docs/user-dashboard-live-session.mdx
index b425369ec1..85c7938af3 100644
--- a/docs-web/content/docs/user-dashboard-live-session.mdx
+++ b/docs-web/content/docs/user-dashboard-live-session.mdx
@@ -38,7 +38,7 @@ Live task cards can show a compact 5-star self-reflection badge when the task sn
## Delivery workflow and QA review details
-Live task cards use one bright delivery workflow badge in place of the former task lifecycle, QA, and CI badges. The badge remains mounted throughout Coding → Pull request → QA → CI → Merge → Completion. Lifecycle and review state provide the durable base; persisted CI evidence enriches the middle stages when available.
+Live task cards use one bright delivery workflow badge in place of the former task lifecycle, QA, and CI badges. The badge remains mounted throughout Coding → Pull request → QA → CI → Merge → Completion. Lifecycle and review state provide the durable base; persisted CI evidence enriches the middle stages when available. Active task-matched human-only intervention changes the trigger to red **Human needed** while retaining the six-stage detail; resolved, worker-owned, system-owned, worker-assigned, and unrelated attention does not.
| Presentation | Meaning |
| --- | --- |
@@ -47,7 +47,7 @@ Live task cards use one bright delivery workflow badge in place of the former ta
| Blue pencil, **QA edits** / **QA changes requested** | QA completed successfully and requested changes. This is an actionable review outcome, not a provider failure. |
| Red X, **QA failed** | The QA provider run failed, errored, or was cancelled before returning a usable verdict. It does not mean QA requested code changes. |
-Hovering, focusing, or activating the badge opens an opaque, viewport-positioned workflow card, so content beneath it cannot bleed through. Six circles on the left are joined by animated dotted connectors to make the delivery sequence immediately scannable. When review data exists, an animated chevron links the workflow card to an adjacent opaque QA review card containing the outcome, summary, findings, fix instructions, target task key, reviewer, reviewed time, and generated follow-up tasks. `Escape` restores focus to the exact workflow or QA-chevron trigger that opened the surface. Reduced motion stops connector and chevron animation without removing state.
+Hovering, focusing, or activating the badge opens one viewport-positioned interaction region without a visible outer card. Its independent opaque Delivery flow card uses six circles joined by animated dotted connectors. When review data exists, a floating responsive arrow links it to an independent opaque QA review card containing the outcome, summary, findings, fix instructions, target task key, reviewer, reviewed time, and generated follow-up tasks. `Escape` restores focus to the exact workflow or QA trigger that opened the region. Reduced motion stops connector and arrow animation without removing state.
Generated follow-up task specifications are collapsed initially, so long prompts do not dominate the review. Each **Follow-up task N** button exposes `aria-expanded` and can be toggled with the keyboard or touch. Expansion reveals the generated title, description, priority, dependency task keys (or **None**), and full Markdown prompt in a bounded scrolling area. The card uses one column on constrained screens, may split summary and findings on wider screens, clamps to the viewport, and scrolls vertically when needed. Reduced motion removes spinner, pulse, rotation, and transition movement without removing labels, borders, focus rings, expanded content, or state semantics.
@@ -64,7 +64,7 @@ The workflow badge summarizes the same six stages on Sprints, Tasks, Overview, a
The four first-class workflow states are `pending`, `in_progress`, `successful`, and `failed`. Pending uses a neutral clock, `in_progress` is presented as running with the signal-colored progress treatment, `successful` uses a green check, and `failed` uses a red X. Failed wins over in progress, in progress wins over pending, and pending wins over successful when the overall badge is derived from the three steps.
-The red X is reserved for an actual provider/runtime or workflow failure. A requested-change verdict is blue, not red. A review blocker is not a CI failure: CI remains passed and Merge reads **Waiting for review**. A merge conflict belongs to Merge and remains distinct from **CI failed**.
+The red X identifies an actual provider/runtime or workflow failure, or explicit active **Human needed** intervention. A requested-change verdict is blue, not red. A review blocker is not a CI failure: CI remains passed and Merge reads **Waiting for review**. A merge conflict belongs to Merge and remains distinct from **CI failed**.
The badge does not poll per card. Task feature-PR gates are persisted as `ci_gate_status` task-run events, and Live narrows them to the selected sprint and latest dispatch's sprint run before choosing the newest matching event by creation time and event ID. Unresolved CI repair attention is combined while `open` or `claimed`; persisted task merge metadata is durable fallback evidence.
diff --git a/docs-web/content/docs/user-dashboard-overview.mdx b/docs-web/content/docs/user-dashboard-overview.mdx
index a50f8736fc..730f281489 100644
--- a/docs-web/content/docs/user-dashboard-overview.mdx
+++ b/docs-web/content/docs/user-dashboard-overview.mdx
@@ -77,11 +77,11 @@ The Overview telemetry rail combines cross-project runtime health with selected-
The Overview queue follows the same selected sprint scope as the Live page. If a sprint is selected in the top navigation, the queue shows only the active attention items returned by the selected-sprint live snapshot; unrelated sprint blockers are not reconstructed in the browser. Overview renders the queue read-only, so claim, resolve, and dismiss actions remain on the Live page.
-Overview active-stream task rows use the shared bright delivery workflow badge instead of a standalone QA badge. Open it to inspect Coding → Pull request → QA → CI → Merge → Completion. When a review exists, the animated chevron reveals the adjacent QA review card; requested edits stay blue, and reduced motion keeps every state visible while stopping connector and chevron animation.
+Overview active-stream task rows use the shared bright delivery workflow badge instead of a standalone QA badge. The badge combines each task's persisted lifecycle, review, and merge state with task-scoped realtime CI events and attention, matching the projection used on Tasks and Live. Open it to inspect the current Coding → Pull request → QA → CI → Merge → Completion stage. Active task-matched human-only attention appears as red **Human needed**; resolved, machine-owned, worker-assigned, and unrelated items do not override the stage. When a review exists, the responsive arrow floats between the independent workflow and QA cards; requested edits stay blue, and reduced motion keeps every state visible while stopping connector and arrow animation.
## Loading behavior
-Overview requests a compact active-sprint task feed instead of downloading historical task prompts, reviews, ratings, and CI evidence. The top-bar counters share that request, and the telemetry rail reuses the page's execution snapshot instead of issuing a duplicate Live request. Full task details still load when a workflow needs them, including the Tasks page and an opened global search.
+Overview requests a compact active-sprint task feed instead of downloading historical task prompts, reviews, and ratings. The top-bar counters share that request, while Active Streams and the telemetry rail reuse the page's realtime execution snapshot for current task-scoped CI/merge evidence instead of issuing a duplicate Live request. Full task details still load when a workflow needs them, including the Tasks page and an opened global search.
The wide seven-day analytics snapshot refreshes every 30 seconds on Overview rather than on each execution heartbeat. The dedicated Stats page remains realtime for operators actively inspecting telemetry.
diff --git a/docs-web/content/docs/user-dashboard-projects.mdx b/docs-web/content/docs/user-dashboard-projects.mdx
index 70b5ebe341..fb946213cb 100644
--- a/docs-web/content/docs/user-dashboard-projects.mdx
+++ b/docs-web/content/docs/user-dashboard-projects.mdx
@@ -47,6 +47,8 @@ Click the dashed **Add Project** card to open the shared modal in local-import m
Click **New Project** on the Projects page to initialize a new repository through the same modal. New project initialization does not scaffold application source files in the dashboard; it sends `new-local` or `new-remote` initialization data to the backend repository creation flow.
+Imported and newly initialized projects always start with Tech Stack Guidance and Styleguide set to **None** at project scope. This creation default is independent of system-level or caller-provided guidance selections; choose reusable guidance after creation from the top bar or Settings -> Guidance.
+
New project creation always writes an explicit project techstack override. New local projects additionally receive `git.githubMode: LOCAL`; new remote projects do not. To set up a web app, desktop app, online shop, portfolio, or game in an eligible initial project, use the matching create-app quickaction in Chat Threads beside the composer. Those quickactions operate in the selected project, create a chat thread when needed, and launch the matching detached quicksprint without opening the new-project modal. All five disappear once the seed repository changes.
Code UX persists whether a project was imported or initialized as a new local/remote repository. Initial-app quickactions are eligible only while a persisted new project is still a clean, one-commit seed containing exactly `README.md` and the Code UX `.gitignore`. Additional files, commits, setup artifacts, dirty state, missing checkouts, or inspection failures disable eligibility; imported and legacy projects are never inferred to be new from their source type or age.
@@ -67,7 +69,7 @@ On save, Code UX:
1. Imports or initializes the repository through the backend project creation flow.
2. Initialises `/.code-ux/` with project-local subdirectories (settings, sprints, agents, memory).
-3. Applies only the settings overrides appropriate to the source: local git mode for imported local projects, explicit techstack for new apps, and both for new local apps.
+3. Pins both reusable guidance selections to **None**, then applies source-specific overrides: local git mode for imported local projects, explicit project classification techstack for new apps, and both source-specific overrides for new local apps.
4. Reads any external settings hints (Jules / Gemini / Codex / Claude / Qwen / OpenCode CLI auth) and pre-populates provider settings.
For imported projects, setup techstack detection inspects dependency manifests, especially `package.json`, plus lockfiles and framework config files. When the detection is valid, Code UX adds the stack to the system catalog if needed and writes the project selection to `techstack.selectedTechstackId`. Invalid or empty detections are ignored without blocking other selected setup artifacts, so imported projects are not classified until evidence or an operator assigns them.
diff --git a/docs-web/content/docs/user-dashboard-settings.mdx b/docs-web/content/docs/user-dashboard-settings.mdx
index 333f0f2d4e..badf9d77f0 100644
--- a/docs-web/content/docs/user-dashboard-settings.mdx
+++ b/docs-web/content/docs/user-dashboard-settings.mdx
@@ -20,7 +20,7 @@ Switch scope with the selector at the top:
The sticky command/status bar keeps the System/Project selector, project availability or inheritance context, active panel, and the Reset Project / Save Changes actions visible together while you scroll. Smart Find stays compact by showing only the search field until you type; active searches then show result status and match-preview chips while the exact category total remains available to assistive technology.
-On desktop, categories stay visible in the left rail. On smaller screens, the command bar shows one compact current-category button instead of the full rail. Open it to use the same Smart Find-filtered category list and match previews in a drawer. Arrow keys move between categories, Enter or Space selects one, and Escape closes the drawer and restores focus to the category button.
+On desktop, categories stay visible in the left rail and the active settings content starts at the top of the right workspace. Labels and linked controls within a setting row also align from the top when either side wraps onto multiple lines. On smaller screens, the command bar shows one compact current-category button instead of the full rail. Open it to use the same Smart Find-filtered category list and match previews in a drawer. Arrow keys move between categories, Enter or Space selects one, and Escape closes the drawer and restores focus to the category button.
The last selected **System** or **Project** scope is remembered in the local database as part of system runtime settings. Changing only that selector is saved immediately and does not save unrelated draft edits in the active settings form.
diff --git a/docs-web/content/docs/user-dashboard-sprints.mdx b/docs-web/content/docs/user-dashboard-sprints.mdx
index 8bdf1ee790..c35d61c68d 100644
--- a/docs-web/content/docs/user-dashboard-sprints.mdx
+++ b/docs-web/content/docs/user-dashboard-sprints.mdx
@@ -16,9 +16,9 @@ Sprints are viewed either in a visual organic cell gallery or a dense ledger for
### Sprint attention indicators
-Failed execution keeps the red gallery-cell perimeter and pulsing exclamation indicator labelled **Sprint execution failed**. A sprint genuinely waiting on a person instead shows an amber person and visible `zZZ` cue labelled **Sprint waiting for human intervention**, positioned exactly 10px above the gallery cell without a red perimeter. Failure takes precedence if both states are available.
+Failed gallery cells rely on the interactive delivery workflow badge for their visible and accessible failure state. They do not add a duplicate **Execution failed** banner, red perimeter, or static outer failure ring. A sprint genuinely waiting on a person instead shows an amber person and visible `zZZ` cue labelled **Sprint waiting for human intervention**, positioned exactly 10px above the gallery cell without a red perimeter.
-When reduced motion is enabled, optional attention motion stops while the indicator, visible context, and semantic label remain. The waiting cue is limited to human-owned active intervention. Worker- and system-owned items—including merge conflicts a worker can resolve—do not show **Waiting for you**, a separate merge-conflict badge, or a human-attention border. Their operational state remains available through the interactive workflow details.
+When reduced motion is enabled, optional attention motion stops while the waiting indicator, visible context, and semantic label remain. The waiting cue is limited to human-owned active intervention. Worker- and system-owned items—including merge conflicts a worker can resolve—do not show **Waiting for you**, a separate merge-conflict badge, or a human-attention border. Failed and worker-owned operational state remains available through the interactive workflow details.
## Delivery workflow and QA review details
@@ -31,13 +31,13 @@ Sprint cells and ledger rows keep their sprint lifecycle status and use one brig
| Blue pencil, **QA edits** / **QA changes requested** | QA completed successfully and requested changes. This is an actionable review outcome, not a provider failure. |
| Red X, **QA failed** | The QA provider run failed, errored, or was cancelled before returning a usable verdict. It does not mean QA requested code changes. |
-Hovering, focusing, or activating the badge opens an opaque viewport-positioned workflow card with Coding → Pull request → QA → CI → Merge → Completion, preventing sprint content from bleeding through. Six circles are joined by motion-safe animated dotted connectors. When review data exists, an animated chevron links an adjacent opaque QA review card with the outcome, summary, findings, fix instructions, reviewer metadata, and collapsed follow-up specifications. `Escape` restores focus to the exact trigger that opened it.
+Hovering, focusing, or activating the badge opens one viewport-positioned interaction region without a visible outer card. The independent opaque Delivery flow card shows Coding → Pull request → QA → CI → Merge → Completion, and six circles are joined by motion-safe animated dotted connectors. When review data exists, a floating responsive arrow links an independent opaque QA review card with the outcome, summary, findings, fix instructions, reviewer metadata, and collapsed follow-up specifications. `Escape` restores focus to the exact trigger that opened it.
Generated follow-up task specifications are collapsed initially, so long prompts do not dominate the review. Each **Follow-up task N** button exposes `aria-expanded` and can be toggled with the keyboard or touch. Expansion reveals the generated title, description, priority, dependency task keys (or **None**), and full Markdown prompt in a bounded scrolling area. The card uses one column on constrained screens, may split summary and findings on wider screens, clamps to the viewport, and scrolls vertically when needed. Reduced motion removes spinner, pulse, rotation, and transition movement without removing labels, borders, focus rings, expanded content, or state semantics.
## Six-stage delivery flow
-The workflow badge summarizes six stages shared by Sprints, Tasks, Overview, and Live:
+The workflow badge summarizes six stages shared by Sprints, Tasks, Overview, and Live. Sprint-run intervention summaries do not override this workflow trigger because they may represent a generic pause or runtime error; genuinely human-waiting sprints retain the separate amber waiting cue described above:
1. **Coding** — waiting, active, paused, complete, or failed.
2. **Pull request** — waiting, creating, missing, or ready.
@@ -48,7 +48,7 @@ The workflow badge summarizes six stages shared by Sprints, Tasks, Overview, and
The four first-class workflow states are `pending`, `in_progress`, `successful`, and `failed`. Pending uses a neutral clock, `in_progress` is presented as running with the signal-colored progress treatment, `successful` uses a green check, and `failed` uses a red X. A sprint aggregates the newest state for each task workflow plus the final feature-to-default-branch merge workflow. Failed wins over in progress, in progress wins over pending, and pending wins over successful, both for each step and for the overall badge.
-The red X is reserved for an actual provider/runtime or workflow failure. Requested QA edits use the bright blue pencil treatment even when failed-check evidence is also present. A review blocker remains pending, and a merge conflict belongs to Merge rather than CI.
+The red X identifies an actual provider/runtime or workflow failure, or explicit active **Human needed** intervention. Requested QA edits use the bright blue pencil treatment even when failed-check evidence is also present. A review blocker remains pending, and a merge conflict belongs to Merge rather than CI.
These badges do not poll per card. Task feature-PR gates are persisted as `ci_gate_status` task-run events, final feature-to-default-branch gates as `main_merge_gate_status` sprint-run events, and unresolved CI repair attention remains active while its item is `open` or `claimed`. For each task or main-merge entity, the projection selects the newest matching event by creation time and then event ID; the sprint presentation aggregates those latest entity states. Persisted task merge metadata is used only as durable fallback evidence when no matching event is available.
diff --git a/docs-web/content/docs/user-dashboard-styleguides-and-tech-stacks.mdx b/docs-web/content/docs/user-dashboard-styleguides-and-tech-stacks.mdx
index 2b1b3ec113..00664df69c 100644
--- a/docs-web/content/docs/user-dashboard-styleguides-and-tech-stacks.mdx
+++ b/docs-web/content/docs/user-dashboard-styleguides-and-tech-stacks.mdx
@@ -38,9 +38,9 @@ This does not delete built-in styleguides or clear the saved selection. If a hid
## Project Defaults
-Existing projects and imported local or Git projects default both guidance selections to **None**. They do not inherit the Code UX visual styleguide automatically.
+Every imported, new local, and new remote project starts with both guidance selections explicitly set to **None**. Project creation does not inherit system-level selections or accept a create-time selection for either catalog.
-New local and new remote projects get an explicit project override selecting the generic Code UX styleguide. Tech-stack guidance remains **None** unless the project creation flow or an operator selects one.
+Custom catalog entries and the default-styleguide visibility preference are preserved during creation. After adding the project, select reusable guidance from the top bar or Settings -> Guidance when the project needs it.
## Sprint Selector Actions
diff --git a/docs-web/content/docs/user-dashboard-tasks.mdx b/docs-web/content/docs/user-dashboard-tasks.mdx
index d899309f99..c96babf819 100644
--- a/docs-web/content/docs/user-dashboard-tasks.mdx
+++ b/docs-web/content/docs/user-dashboard-tasks.mdx
@@ -37,7 +37,7 @@ When a worker reports a task-run self-reflection rating, the shared rating badge
## Delivery workflow and QA review details
-Task cards use the shared bright delivery workflow badge in place of the standalone QA and CI badges. The task lifecycle label remains visible beside it, while the badge itself always exposes Coding → Pull request → QA → CI → Merge → Completion. Lifecycle and review state keep the badge durable when CI evidence is absent or refreshing.
+Task cards use the shared bright delivery workflow badge in place of the standalone QA and CI badges. The task lifecycle label remains visible beside it, while the badge itself always exposes Coding → Pull request → QA → CI → Merge → Completion. Lifecycle and review state keep the badge durable when CI evidence is absent or refreshing. An open or claimed task-matched human/user intervention with no worker assignment takes precedence as a red **Human needed** trigger; clearing or handing the item to automation restores the ordinary workflow stage.
| Presentation | Meaning |
| --- | --- |
@@ -46,7 +46,7 @@ Task cards use the shared bright delivery workflow badge in place of the standal
| Blue pencil, **QA edits** / **QA changes requested** | QA completed successfully and requested changes. This is an actionable review outcome, not a provider failure. |
| Red X, **QA failed** | The QA provider run failed, errored, or was cancelled before returning a usable verdict. It does not mean QA requested code changes. |
-Hovering, focusing, or activating the badge opens an opaque, viewport-positioned workflow card. Six circles on the left are connected by motion-safe animated dots. When review data exists, an animated chevron reveals an adjacent opaque QA review card with the outcome, summary, findings, fix instructions, target task key, reviewer, reviewed time, and generated follow-up tasks. `Escape` closes the surface and restores focus to the exact workflow or QA-chevron trigger that opened it; outside pointer or touch input dismisses it.
+Hovering, focusing, or activating the badge opens one viewport-positioned interaction region without a visible outer card. Its opaque Delivery flow card contains six circles connected by motion-safe animated dots. When review data exists, a floating responsive arrow points to an independent opaque QA review card with the outcome, summary, findings, fix instructions, target task key, reviewer, reviewed time, and generated follow-up tasks. `Escape` closes the region and restores focus to the exact workflow or QA trigger that opened it; outside pointer or touch input dismisses it.
Generated follow-up task specifications are collapsed initially, so long prompts do not dominate the review. Each **Follow-up task N** button exposes `aria-expanded` and can be toggled with the keyboard or touch. Expansion reveals the generated title, description, priority, dependency task keys (or **None**), and full Markdown prompt in a bounded scrolling area. The card uses one column on constrained screens, may split summary and findings on wider screens, clamps to the viewport, and scrolls vertically when needed. Reduced motion removes spinner, pulse, rotation, and transition movement without removing labels, borders, focus rings, expanded content, or state semantics.
@@ -63,7 +63,7 @@ The workflow badge summarizes six stages shared by Sprints, Tasks, Overview, and
The four first-class workflow states are `pending`, `in_progress`, `successful`, and `failed`. Pending uses a neutral clock, `in_progress` is presented as running with the signal-colored progress treatment, `successful` uses a green check, and `failed` uses a red X. Failed wins over in progress, in progress wins over pending, and pending wins over successful when the overall badge is derived from the three steps.
-The red X is reserved for an actual provider/runtime or workflow failure. Requested QA edits use the bright blue pencil treatment, not failure red. A review blocker is not a CI failure: CI remains passed and Merge reads **Waiting for review**. A merge conflict belongs to Merge and remains distinct from **CI failed**.
+The red X identifies an actual provider/runtime or workflow failure, or explicit active **Human needed** intervention. Requested QA edits use the bright blue pencil treatment, not failure red. A review blocker is not a CI failure: CI remains passed and Merge reads **Waiting for review**. A merge conflict belongs to Merge and remains distinct from **CI failed**.
These badges do not poll per card. Task feature-PR gates are persisted as `ci_gate_status` task-run events, and unresolved CI repair attention remains active while its item is `open` or `claimed`. The card projection selects the newest matching task event by creation time and then event ID, combines it with active attention, and uses persisted task merge metadata only as durable fallback evidence when no matching event is available.
diff --git a/docs-web/developer/feature-flags.md b/docs-web/developer/feature-flags.md
index 32db0fa626..c0eeb79db6 100644
--- a/docs-web/developer/feature-flags.md
+++ b/docs-web/developer/feature-flags.md
@@ -4,20 +4,22 @@ Dashboard feature flags hide unfinished dashboard surfaces without deleting thei
Flags live in `dashboard/src/v2/lib/dashboard-feature-flags.ts`. They are resolved at dashboard bundle time through Vite `import.meta.env` values:
-- Development and test builds enable all flagged unfinished features by default.
-- Production builds disable flagged unfinished features by default.
-- Explicit env values override the mode default.
+- Development builds always enable the `nodes` and `custom-dashboards` discovery surfaces so those in-progress pages remain available for local testing.
+- Production builds disable unfinished surfaces by default; explicit env values enable or disable them.
+- Cinematic quick-action flags default to disabled in every mode and require an explicit env opt-in. Their underlying surface flag must also be enabled.
-Supported values are `true`, `1`, `yes`, `on`, `enabled`, `false`, `0`, `no`, `off`, and `disabled`. Empty or unrecognized values fall back to the mode default.
+Supported values are `true`, `1`, `yes`, `on`, `enabled`, `false`, `0`, `no`, `off`, and `disabled`. Empty or unrecognized values fall back to the flag's documented default. Development mode intentionally overrides disabled values only for the two discovery surfaces.
## Current Flags
| Feature | Env variable | Development default | Production default | Scope |
| --- | --- | --- | --- | --- |
-| `nodes` | `VITE_CODEUX_FEATURE_NODES` | enabled | disabled | Hides the unfinished `/nodes` surface from route registration, shared navigation, route prefetch, and the guided dashboard tour. |
+| `nodes` | `VITE_CODEUX_FEATURE_NODES` | enabled | disabled | Requires `VITE_CODEUX_NODE_FLOW_BACKEND` and `VITE_CODEUX_AUTOMATION_SECURITY` to also be enabled in production. |
| `custom-dashboards` | `VITE_CODEUX_FEATURE_CUSTOM_DASHBOARDS` | enabled | disabled | Hides the unfinished `/custom-dashboards` surface from route registration, shared navigation, route prefetch, and the guided dashboard tour. |
+| `chat-nodes-workflow-quick-action` | `VITE_CODEUX_FEATURE_CHAT_NODES_WORKFLOW_QUICK_ACTION` | disabled | disabled | Shows **Add Nodes Workflow** only when this flag and `nodes` are both enabled. |
+| `chat-custom-dashboard-quick-action` | `VITE_CODEUX_FEATURE_CHAT_CUSTOM_DASHBOARD_QUICK_ACTION` | disabled | disabled | Shows **Add Dashboard** only when this flag and `custom-dashboards` are both enabled. |
-When a feature is disabled, its page module remains in source for local development and tests, but the route is not added to the TanStack route tree. Direct navigation falls through to the dashboard not-found route.
+When Nodes or either production prerequisite is disabled, its route is omitted from the route tree, navigation, and route prefetch. Development keeps the surface reachable for local integration testing. This discovery override does not expose either cinematic workflow quick action; each action remains hidden until its dedicated opt-in flag is enabled.
## Adding a Flag
@@ -26,5 +28,5 @@ When a feature is disabled, its page module remains in source for local developm
3. Gate route registration in `dashboard/src/main.tsx`.
4. Gate route prefetch entries in `dashboard/src/v2/router/route-prefetch.ts`.
5. Gate guided tour steps or other entry points that reference the hidden surface.
-6. Add focused tests for default behavior, explicit overrides, and every hidden entry point.
+6. Choose whether the flag is a development discovery surface or a default-off capability, then add focused tests for mode defaults, explicit overrides, prerequisites, and every hidden entry point.
7. Update this page and the matching canonical `docs/` page.
diff --git a/docs-web/developer/settings-reference.md b/docs-web/developer/settings-reference.md
index 7311a72b46..0566447c2f 100644
--- a/docs-web/developer/settings-reference.md
+++ b/docs-web/developer/settings-reference.md
@@ -143,7 +143,7 @@ Project and sprint settings own design guidance:
}
```
-The backend catalog always includes `none`, the built-in `Code UX` styleguide, additional default styleguides, and a small tech-stack guidance catalog. Saved selections resolve to a known default or custom id; invalid ids fall back to `none`. `hideDefaultStyleguides` only affects presentation and does not remove backend defaults. Existing and imported projects inherit `none`; new local and new remote project initialization writes an explicit project override for the Code UX styleguide. Planning and Project Setup prompts resolve selected entries from effective project settings and omit inactive `none` catalog entries. Project Setup prompts also include a setup-only styling investigation notice whenever the styleguide selection is `none`, including when tech-stack guidance is also `none`.
+The backend catalog always includes `none`, the built-in `Code UX` styleguide, additional default styleguides, and a small tech-stack guidance catalog. Saved selections resolve to a known default or custom id; invalid ids fall back to `none`. `hideDefaultStyleguides` only affects presentation and does not remove backend defaults. Every imported, new local, and new remote project writes explicit `none` project overrides for both selections; create-time selected ids are normalized to `none`, while unrelated custom catalogs and visibility settings are preserved. Planning and Project Setup prompts resolve selected entries from effective project settings and omit inactive `none` catalog entries. Project Setup prompts also include a setup-only styling investigation notice whenever the styleguide selection is `none`, including when tech-stack guidance is also `none`.
The dashboard Guidance panel manages this block through the normal settings save flows. System scope edits `system.defaults.designGuidance`; project scope edits the active project override. Built-in catalog entries can be selected but cannot be edited or deleted. Custom entries can be added, edited, and deleted; deleting a selected custom entry clears that selector back to `none`.
diff --git a/docs-web/user/dashboard/chat.md b/docs-web/user/dashboard/chat.md
index a3d3647244..07d88aa92b 100644
--- a/docs-web/user/dashboard/chat.md
+++ b/docs-web/user/dashboard/chat.md
@@ -17,17 +17,17 @@ Markdown links use the dashboard's theme-aware signal colors across thread messa
While the Project Manager is genuinely idle, the 3D stage can show one short ambient cue at a time: a greeting, wink, curious glance, dance beat, or a text-labelled humming cue with decorative notes. Returning to the page produces a welcome-back cue only after the stage was hidden or idle for at least 30 seconds, so quick tab changes stay quiet. Sending, Project Manager work, errors, hidden pages, and reduced-motion mode stop these cue timers and the stage's continuous decorative drift. The static mood caption, connection status, and unrelated background-activity count remain visible and truthful. Ambient cue text is visible but is not repeatedly announced as a live status update.
-The 3D stage enters its Project Manager working state only while the selected thread awaits that agent's reply or a running `dashboard_reply`/`worker_reply` invocation belongs to the same resolved agent preset. Only the newest matching running invocation owns the foreground work tool and transient progress bubble. Other agents' replies and unrelated task, planning, QA, or CI invocations remain truthful background activity; they can keep a background thought cue and count visible, but they do not make the Project Manager show a thinking expression, work tool, active caption, progress bubble, or busy-only quick-action state. Sending a message keeps its separate routing state until the awaited reply or matching invocation is visible.
+The 3D stage enters its Project Manager working state only while the selected thread awaits that agent's reply or a running `dashboard_reply`/`worker_reply` invocation belongs to the same resolved agent preset. That authoritative busy state owns the foreground work tool, including the interval before an invocation record becomes visible; only the newest matching running invocation owns the transient transcript progress bubble. Other agents' replies and unrelated task, planning, QA, or CI invocations remain truthful background activity; they can keep a background thought cue and count visible, but they do not make the Project Manager show a thinking expression, work tool, active caption, progress bubble, or busy-only quick-action state. Sending a message keeps its separate routing state until the awaited reply or matching invocation is visible.
The thought area turns known runtime fields into compact cues for container startup, provider work, planning, QA review, completion, and errors. Current stage cues come only from running records or the selected thread's awaited reply; old completed or failed invocations are not presented as live activity. A delegated-work cue stays visible while the Project Manager remains idle, and an active Project Manager cue takes precedence while retaining a count of other activity. The phase is shown directly without `Background` or provider-name prefixes. Its workplace-safe quote is keyed by stable agent, provider, phase, and runtime context and stays unchanged for at least twenty seconds. Delegated work uses 72 original agency and project-management jokes about coworker handoffs, meetings, scope creep, client feedback, and ticket rituals. The runtime shuffles the deck by context, uses every line before reshuffling, and avoids immediate repeats. Reduced-motion mode keeps the status text while stopping its decorative dots.
-For the full lifecycle of a matching running Project Manager reply invocation, including startup before its first transcript turn, the avatar rotates through five work tools every seven seconds: Power screwdriver (`screwdriver`), Jackhammer (`jackhammer`), Open-end wrench (`wrench`), Claw hammer (`hammer`), and Welding torch (`torch`). The matching invocation id chooses a deterministic initial tool, then rotation follows catalog order without immediately repeating; a replacement invocation starts its own deterministic sequence and terminal state removes the tool immediately. Awaited-thread fallback without a matching invocation and background work never equip a runtime-selected tool because invocation ownership is resolved before tool selection. Reduced motion keeps the initial tool static without a rotation timer. Maintainers can pin a valid catalog identifier with `/chat?stageTool=` for design review, including while activity is inactive; missing or unsupported values leave normal runtime selection in place. Reduced-motion and WebGL fallback surfaces keep the visible tool label and accessible avatar description.
+For the full lifecycle of active Project Manager reply work, including an awaited selected-thread reply before its invocation is visible and startup before its first transcript turn, the avatar rotates through five work tools every seven seconds: Power screwdriver (`screwdriver`), Jackhammer (`jackhammer`), Open-end wrench (`wrench`), Claw hammer (`hammer`), and Welding torch (`torch`). The foreground activity id—normally the matching invocation id or selected thread id—chooses a deterministic initial tool, then rotation follows catalog order without immediately repeating; replacing that active reply context starts its own deterministic sequence and leaving the Project Manager busy state removes the tool immediately. Background work never equips a runtime-selected tool. Reduced motion keeps the initial tool static without a rotation timer. Maintainers can pin a valid catalog identifier with `/chat?stageTool=` for design review, including while activity is inactive; missing or unsupported values leave normal runtime selection in place. Reduced-motion and WebGL fallback surfaces keep the visible tool label and accessible avatar description.
While that matching invocation runs, the latest exchange also shows a transient progress bubble with an explicit **In progress** label, the latest non-empty persisted assistant update eligible for display, and a deduplicated tool count. Tool-call/result pairs with the same call id count once; reasoning, injected context, user prompts, raw tool payloads, and unknown internal turns are not used as the interim prose. Zero-message startup fetches the persisted transcript and shows **Preparing the first progress update…** with `0 tools used` until an eligible assistant turn exists.
-The bubble is a polite live status projection only. It does not create or persist a thread message and remains separate from the durable Threads transcript and final Project Manager reply. It refreshes when the running invocation's message count, last-message time, or general update time changes, including same-length telemetry rewrites. During a same-invocation refresh, or after a non-fatal transcript-fetch failure, the last accepted update and count stay visible; if no fetch has succeeded, the startup placeholder stays visible. Superseded requests are cancelled and late responses are ignored. The bubble and work tool clear on invocation replacement, completion, failure, disappearance, project change, a later thread selection, or loss of matching Project Manager ownership. The first-send handoff from a new conversation to the thread it creates is retained, but interim text cannot follow later navigation or duplicate the stored final reply. This behavior projects persisted invocation records; it does not promise backend streaming or message delivery.
+The bubble is a polite live status projection only. It does not create or persist a thread message and remains separate from the durable Threads transcript and final Project Manager reply. It refreshes when the running invocation's message count, last-message time, or general update time changes, including same-length telemetry rewrites. During a same-invocation refresh, or after a non-fatal transcript-fetch failure, the last accepted update and count stay visible; if no fetch has succeeded, the startup placeholder stays visible. Superseded requests are cancelled and late responses are ignored. The progress bubble clears on invocation replacement, completion, failure, disappearance, project change, a later thread selection, or loss of matching Project Manager ownership; the separate work tool remains present whenever the Project Manager busy state is still true. The first-send handoff from a new conversation to the thread it creates is retained, but interim text cannot follow later navigation or duplicate the stored final reply. This behavior projects persisted invocation records; it does not promise backend streaming or message delivery.
-On compact layouts, the latest exchange remains inside the stage above the composer and scrolls within that bounded region, so replies and active progress appear without moving the whole stage. The progress bubble is also height-bounded and scrolls long prose internally; long words wrap, while wide code and tables scroll horizontally. At wider breakpoints its maximum width is 680px on LG, 780px on XL, and 880px on 2XL; at 2XL it can reach 220px high with 17px/36px prose. The separate desktop thought bubble remains compact, shifts farther left at XL/2XL, and keeps visible spacing around its two-dot tail so it does not crowd the larger avatar or reply column. With motion enabled, the bubble animates on first appearance and eligible interim-message changes while the selected tool rotates every seven seconds. Reduced motion removes those transitions, tool rotation, and thought dots, but preserves the static tool label, **In progress**, interim or startup text, and tool count. Those visible labels remain the authoritative activity signal, including under the static SVG/WebGL-failure fallback.
+On compact layouts, the latest exchange remains inside the stage above the composer and scrolls within that bounded region, so replies and active progress appear without moving the whole stage. The durable reply is right-aligned in a narrower desktop column, capped between 560px and 680px at wider breakpoints, and uses compact 12–13px prose so it stays clear of the avatar. The progress bubble is also height-bounded and scrolls long prose internally; long words wrap, while wide code and tables scroll horizontally. At wider breakpoints its maximum width is 680px on LG, 780px on XL, and 880px on 2XL; at 2XL it can reach 220px high with 17px/36px prose. The separate desktop thought bubble remains compact and horizontally centered directly above the avatar, with visible spacing around its two-dot tail. With motion enabled, the progress bubble animates on first appearance and eligible interim-message changes while the selected tool rotates every seven seconds. Reduced motion removes those transitions, tool rotation, and thought dots, but preserves the static tool label, **In progress**, interim or startup text, and tool count. Those visible labels remain the authoritative activity signal, including under the static SVG/WebGL-failure fallback.
When a text-to-speech model or API is active under **Settings -> AI Models**, 3D Chat reads new Project Manager replies aloud. A compact control dock beneath the avatar identity holds the microphone and agent mute/unmute buttons, outside the composer. Voice defaults on, shows synthesis activity, and can be muted immediately. The preference is remembered per project in the current browser; opening an existing thread does not replay its latest historical message. Long replies start with the first ready sentence while a bounded two-chunk lookahead is synthesized, then continue through every chunk in transcript order. Muting, changing threads or Chat mode, leaving the page, or starting another replay cancels pending speech and releases the active audio. If synthesis or browser playback fails, playback stops and the accessible voice or transcript status reports the error without hiding the written reply.
@@ -105,9 +105,9 @@ After you send a message, the thread transcript updates from the server's return
While a reply or invocation container is active, the visible status line uses light deterministic humor instead of static `Initializing` or `Working` copy. These messages are keyed by the active agent, provider/model, and phase, and they remain stable for at least five seconds so live regions do not churn during rapid refreshes. The funny line is a UI adjunct only; it does not replace the actual agent reply, invocation status, or stored transcript.
-In 3D Chat, the complete idle set is the five create-app actions together with **Status Report**, **Sprint Progress**, **What’s Failing?**, **Plan Next Steps**, **Add Nodes Workflow**, **Add Dashboard**, **Create Skill**, and **List Skills**. The create-app buttons use the typed detached quicksprint path described above. The other eight buttons are normal chat actions: they immediately send their fixed informational or workflow prompt through the selected project's routed Thread and do not create detached app planning. Neither path inserts into, replaces, or clears text already in the composer.
+In 3D Chat, the default idle set is the five create-app actions together with **Status Report**, **Sprint Progress**, **What’s Failing?**, **Plan Next Steps**, **Create Skill**, and **List Skills**. The create-app buttons use the typed detached quicksprint path described above. The other six buttons are normal chat actions: they immediately send their fixed informational or workflow prompt through the selected project's routed Thread and do not create detached app planning. Neither path inserts into, replaces, or clears text already in the composer. **Add Nodes Workflow** and **Add Dashboard** are hidden by default; each requires both its dedicated quick-action feature flag and the corresponding Nodes or custom-dashboard surface flag.
-On desktop the controls are sorted into subtle **Create**, **Project pulse**, and **Workflows** clusters contained inside the left side of the stage. Each category wraps its small content-width chips together, keeping Sprint Progress and Plan Next Steps with Project pulse and keeping Add Dashboard, Create Skill, and List Skills with Workflows. Small offsets, extra whitespace, and gentle staggered drift keep the composition interesting without clipping controls or crowding the avatar. On mobile the controls retain the same category order in horizontally scrollable two-row groups. Neutral chip surfaces and distinct colored icon tiles make the actions easier to scan without giving every action the same green emphasis. Labels stay on one line. Every control is a keyboard-reachable button with a visible focus state, and Enter or Space activates it. Reduced-motion mode stops the quickaction floating animation (along with the stage's other decorative motion) without removing actions or status text. The whole group hides without a selected project and while chat is sending, working, or showing an error; all five create-app actions also remain hidden until initial-project eligibility has loaded and passed.
+On desktop the enabled controls are sorted into subtle **Create**, **Project pulse**, and **Workflows** clusters contained inside the left side of the stage. Each category wraps its small content-width chips together, keeping Sprint Progress and Plan Next Steps with Project pulse and keeping Create Skill and List Skills with Workflows. Small offsets, extra whitespace, and gentle staggered drift keep the composition interesting without clipping controls or crowding the avatar. On mobile the controls retain the same category order in horizontally scrollable two-row groups. Neutral chip surfaces and distinct colored icon tiles make the actions easier to scan without giving every action the same green emphasis. Labels stay on one line. Every control is a keyboard-reachable button with a visible focus state, and Enter or Space activates it. Reduced-motion mode stops the quickaction floating animation (along with the stage's other decorative motion) without removing actions or status text. The whole group hides without a selected project and while chat is sending, working, or showing an error; all five create-app actions also remain hidden until initial-project eligibility has loaded and passed.
Planning messages can include a rich sprint status card. When Code UX can match the message to loaded live project data, the card is backed by the current task records and execution snapshot, so it updates as tasks move from queued to running, completed, failed, blocked, or quota-waiting. It shows the sprint key/name, request/task/run materialization, overall progress such as `0/7 · 0%`, queued task count, and a compact task list. If either task records or the execution snapshot are still loading, the chat keeps the generic planning status card until both live records are available for the active project.
diff --git a/docs-web/user/dashboard/live-session.md b/docs-web/user/dashboard/live-session.md
index b425369ec1..85c7938af3 100644
--- a/docs-web/user/dashboard/live-session.md
+++ b/docs-web/user/dashboard/live-session.md
@@ -38,7 +38,7 @@ Live task cards can show a compact 5-star self-reflection badge when the task sn
## Delivery workflow and QA review details
-Live task cards use one bright delivery workflow badge in place of the former task lifecycle, QA, and CI badges. The badge remains mounted throughout Coding → Pull request → QA → CI → Merge → Completion. Lifecycle and review state provide the durable base; persisted CI evidence enriches the middle stages when available.
+Live task cards use one bright delivery workflow badge in place of the former task lifecycle, QA, and CI badges. The badge remains mounted throughout Coding → Pull request → QA → CI → Merge → Completion. Lifecycle and review state provide the durable base; persisted CI evidence enriches the middle stages when available. Active task-matched human-only intervention changes the trigger to red **Human needed** while retaining the six-stage detail; resolved, worker-owned, system-owned, worker-assigned, and unrelated attention does not.
| Presentation | Meaning |
| --- | --- |
@@ -47,7 +47,7 @@ Live task cards use one bright delivery workflow badge in place of the former ta
| Blue pencil, **QA edits** / **QA changes requested** | QA completed successfully and requested changes. This is an actionable review outcome, not a provider failure. |
| Red X, **QA failed** | The QA provider run failed, errored, or was cancelled before returning a usable verdict. It does not mean QA requested code changes. |
-Hovering, focusing, or activating the badge opens an opaque, viewport-positioned workflow card, so content beneath it cannot bleed through. Six circles on the left are joined by animated dotted connectors to make the delivery sequence immediately scannable. When review data exists, an animated chevron links the workflow card to an adjacent opaque QA review card containing the outcome, summary, findings, fix instructions, target task key, reviewer, reviewed time, and generated follow-up tasks. `Escape` restores focus to the exact workflow or QA-chevron trigger that opened the surface. Reduced motion stops connector and chevron animation without removing state.
+Hovering, focusing, or activating the badge opens one viewport-positioned interaction region without a visible outer card. Its independent opaque Delivery flow card uses six circles joined by animated dotted connectors. When review data exists, a floating responsive arrow links it to an independent opaque QA review card containing the outcome, summary, findings, fix instructions, target task key, reviewer, reviewed time, and generated follow-up tasks. `Escape` restores focus to the exact workflow or QA trigger that opened the region. Reduced motion stops connector and arrow animation without removing state.
Generated follow-up task specifications are collapsed initially, so long prompts do not dominate the review. Each **Follow-up task N** button exposes `aria-expanded` and can be toggled with the keyboard or touch. Expansion reveals the generated title, description, priority, dependency task keys (or **None**), and full Markdown prompt in a bounded scrolling area. The card uses one column on constrained screens, may split summary and findings on wider screens, clamps to the viewport, and scrolls vertically when needed. Reduced motion removes spinner, pulse, rotation, and transition movement without removing labels, borders, focus rings, expanded content, or state semantics.
@@ -64,7 +64,7 @@ The workflow badge summarizes the same six stages on Sprints, Tasks, Overview, a
The four first-class workflow states are `pending`, `in_progress`, `successful`, and `failed`. Pending uses a neutral clock, `in_progress` is presented as running with the signal-colored progress treatment, `successful` uses a green check, and `failed` uses a red X. Failed wins over in progress, in progress wins over pending, and pending wins over successful when the overall badge is derived from the three steps.
-The red X is reserved for an actual provider/runtime or workflow failure. A requested-change verdict is blue, not red. A review blocker is not a CI failure: CI remains passed and Merge reads **Waiting for review**. A merge conflict belongs to Merge and remains distinct from **CI failed**.
+The red X identifies an actual provider/runtime or workflow failure, or explicit active **Human needed** intervention. A requested-change verdict is blue, not red. A review blocker is not a CI failure: CI remains passed and Merge reads **Waiting for review**. A merge conflict belongs to Merge and remains distinct from **CI failed**.
The badge does not poll per card. Task feature-PR gates are persisted as `ci_gate_status` task-run events, and Live narrows them to the selected sprint and latest dispatch's sprint run before choosing the newest matching event by creation time and event ID. Unresolved CI repair attention is combined while `open` or `claimed`; persisted task merge metadata is durable fallback evidence.
diff --git a/docs-web/user/dashboard/overview.md b/docs-web/user/dashboard/overview.md
index 19af9b77ba..d8ad367464 100644
--- a/docs-web/user/dashboard/overview.md
+++ b/docs-web/user/dashboard/overview.md
@@ -77,11 +77,11 @@ The Overview telemetry rail combines cross-project runtime health with selected-
The Overview queue follows the same selected sprint scope as the Live page. If a sprint is selected in the top navigation, the queue shows only the active attention items returned by the selected-sprint live snapshot; unrelated sprint blockers are not reconstructed in the browser. Overview renders the queue read-only, so claim, resolve, and dismiss actions remain on the Live page.
-Overview active-stream task rows use the shared bright delivery workflow badge instead of a standalone QA badge. Open it to inspect Coding → Pull request → QA → CI → Merge → Completion. When a review exists, the animated chevron reveals the adjacent QA review card; requested edits stay blue, and reduced motion keeps every state visible while stopping connector and chevron animation.
+Overview active-stream task rows use the shared bright delivery workflow badge instead of a standalone QA badge. The badge combines each task's persisted lifecycle, review, and merge state with task-scoped realtime CI events and attention, matching the projection used on Tasks and Live. Open it to inspect the current Coding → Pull request → QA → CI → Merge → Completion stage. Active task-matched human-only attention appears as red **Human needed**; resolved, machine-owned, worker-assigned, and unrelated items do not override the stage. When a review exists, the responsive arrow floats between the independent workflow and QA cards; requested edits stay blue, and reduced motion keeps every state visible while stopping connector and arrow animation.
## Loading behavior
-Overview requests a compact active-sprint task feed instead of downloading historical task prompts, reviews, ratings, and CI evidence. The top-bar counters share that request, and the telemetry rail reuses the page's execution snapshot instead of issuing a duplicate Live request. Full task details still load when a workflow needs them, including the Tasks page and an opened global search.
+Overview requests a compact active-sprint task feed instead of downloading historical task prompts, reviews, and ratings. The top-bar counters share that request, while Active Streams and the telemetry rail reuse the page's realtime execution snapshot for current task-scoped CI/merge evidence instead of issuing a duplicate Live request. Full task details still load when a workflow needs them, including the Tasks page and an opened global search.
The wide seven-day analytics snapshot refreshes every 30 seconds on Overview rather than on each execution heartbeat. The dedicated Stats page remains realtime for operators actively inspecting telemetry.
diff --git a/docs-web/user/dashboard/projects.md b/docs-web/user/dashboard/projects.md
index 91cec3f179..9245930a31 100644
--- a/docs-web/user/dashboard/projects.md
+++ b/docs-web/user/dashboard/projects.md
@@ -47,6 +47,8 @@ Click the dashed **Add Project** card to open the shared modal in local-import m
Click **New Project** on the Projects page to initialize a new repository through the same modal. New project initialization does not scaffold application source files in the dashboard; it sends `new-local` or `new-remote` initialization data to the backend repository creation flow.
+Imported and newly initialized projects always start with Tech Stack Guidance and Styleguide set to **None** at project scope. This creation default is independent of system-level or caller-provided guidance selections; choose reusable guidance after creation from the top bar or Settings -> Guidance.
+
New project creation always writes an explicit project techstack override. New local projects additionally receive `git.githubMode: LOCAL`; new remote projects do not. To set up a web app, desktop app, online shop, portfolio, or game in an eligible initial project, use the matching create-app quickaction in Chat Threads beside the composer. Those quickactions operate in the selected project, create a chat thread when needed, and launch the matching detached quicksprint without opening the new-project modal. All five disappear once the seed repository changes.
Code UX persists whether a project was imported or initialized as a new local/remote repository. Initial-app quickactions are eligible only while a persisted new project is still a clean, one-commit seed containing exactly `README.md` and the Code UX `.gitignore`. Additional files, commits, setup artifacts, dirty state, missing checkouts, or inspection failures disable eligibility; imported and legacy projects are never inferred to be new from their source type or age.
@@ -67,7 +69,7 @@ On save, Code UX:
1. Imports or initializes the repository through the backend project creation flow.
2. Initialises `/.code-ux/` with project-local subdirectories (settings, sprints, agents, memory).
-3. Applies only the settings overrides appropriate to the source: local git mode for imported local projects, explicit techstack for new apps, and both for new local apps.
+3. Pins both reusable guidance selections to **None**, then applies source-specific overrides: local git mode for imported local projects, explicit project classification techstack for new apps, and both source-specific overrides for new local apps.
4. Reads any external settings hints (Jules / Gemini / Codex / Claude / Qwen / OpenCode CLI auth) and pre-populates provider settings.
For imported projects, setup techstack detection inspects dependency manifests, especially `package.json`, plus lockfiles and framework config files. When the detection is valid, Code UX adds the stack to the system catalog if needed and writes the project selection to `techstack.selectedTechstackId`. Invalid or empty detections are ignored without blocking other selected setup artifacts, so imported projects are not classified until evidence or an operator assigns them.
diff --git a/docs-web/user/dashboard/settings.md b/docs-web/user/dashboard/settings.md
index 44fefeb508..74f280e782 100644
--- a/docs-web/user/dashboard/settings.md
+++ b/docs-web/user/dashboard/settings.md
@@ -20,7 +20,7 @@ Switch scope with the selector at the top:
The sticky command/status bar keeps the System/Project selector, project availability or inheritance context, active panel, and the Reset Project / Save Changes actions visible together while you scroll. Smart Find stays compact by showing only the search field until you type; active searches then show result status and match-preview chips while the exact category total remains available to assistive technology.
-On desktop, categories stay visible in the left rail. On smaller screens, the command bar shows one compact current-category button instead of the full rail. Open it to use the same Smart Find-filtered category list and match previews in a drawer. Arrow keys move between categories, Enter or Space selects one, and Escape closes the drawer and restores focus to the category button.
+On desktop, categories stay visible in the left rail and the active settings content starts at the top of the right workspace. Labels and linked controls within a setting row also align from the top when either side wraps onto multiple lines. On smaller screens, the command bar shows one compact current-category button instead of the full rail. Open it to use the same Smart Find-filtered category list and match previews in a drawer. Arrow keys move between categories, Enter or Space selects one, and Escape closes the drawer and restores focus to the category button.
The last selected **System** or **Project** scope is remembered in the local database as part of system runtime settings. Changing only that selector is saved immediately and does not save unrelated draft edits in the active settings form.
diff --git a/docs-web/user/dashboard/sprints.md b/docs-web/user/dashboard/sprints.md
index 728639ef8f..b7fa41361c 100644
--- a/docs-web/user/dashboard/sprints.md
+++ b/docs-web/user/dashboard/sprints.md
@@ -16,9 +16,9 @@ Sprints are viewed either in a visual organic cell gallery or a dense ledger for
### Sprint attention indicators
-Failed execution keeps the red gallery-cell perimeter and pulsing exclamation indicator labelled **Sprint execution failed**. A sprint genuinely waiting on a person instead shows an amber person and visible `zZZ` cue labelled **Sprint waiting for human intervention**, positioned exactly 10px above the gallery cell without a red perimeter. Failure takes precedence if both states are available.
+Failed gallery cells rely on the interactive delivery workflow badge for their visible and accessible failure state. They do not add a duplicate **Execution failed** banner, red perimeter, or static outer failure ring. A sprint genuinely waiting on a person instead shows an amber person and visible `zZZ` cue labelled **Sprint waiting for human intervention**, positioned exactly 10px above the gallery cell without a red perimeter.
-When reduced motion is enabled, optional attention motion stops while the indicator, visible context, and semantic label remain. The waiting cue is limited to human-owned active intervention. Worker- and system-owned items—including merge conflicts a worker can resolve—do not show **Waiting for you**, a separate merge-conflict badge, or a human-attention border. Their operational state remains available through the interactive workflow details.
+When reduced motion is enabled, optional attention motion stops while the waiting indicator, visible context, and semantic label remain. The waiting cue is limited to human-owned active intervention. Worker- and system-owned items—including merge conflicts a worker can resolve—do not show **Waiting for you**, a separate merge-conflict badge, or a human-attention border. Failed and worker-owned operational state remains available through the interactive workflow details.
## Delivery workflow and QA review details
@@ -31,13 +31,13 @@ Sprint cells and ledger rows keep their sprint lifecycle status and use one brig
| Blue pencil, **QA edits** / **QA changes requested** | QA completed successfully and requested changes. This is an actionable review outcome, not a provider failure. |
| Red X, **QA failed** | The QA provider run failed, errored, or was cancelled before returning a usable verdict. It does not mean QA requested code changes. |
-Hovering, focusing, or activating the badge opens an opaque viewport-positioned workflow card with Coding → Pull request → QA → CI → Merge → Completion, preventing sprint content from bleeding through. Six circles are joined by motion-safe animated dotted connectors. When review data exists, an animated chevron links an adjacent opaque QA review card with the outcome, summary, findings, fix instructions, reviewer metadata, and collapsed follow-up specifications. `Escape` restores focus to the exact trigger that opened it.
+Hovering, focusing, or activating the badge opens one viewport-positioned interaction region without a visible outer card. The independent opaque Delivery flow card shows Coding → Pull request → QA → CI → Merge → Completion, and six circles are joined by motion-safe animated dotted connectors. When review data exists, a floating responsive arrow links an independent opaque QA review card with the outcome, summary, findings, fix instructions, reviewer metadata, and collapsed follow-up specifications. `Escape` restores focus to the exact trigger that opened it.
Generated follow-up task specifications are collapsed initially, so long prompts do not dominate the review. Each **Follow-up task N** button exposes `aria-expanded` and can be toggled with the keyboard or touch. Expansion reveals the generated title, description, priority, dependency task keys (or **None**), and full Markdown prompt in a bounded scrolling area. The card uses one column on constrained screens, may split summary and findings on wider screens, clamps to the viewport, and scrolls vertically when needed. Reduced motion removes spinner, pulse, rotation, and transition movement without removing labels, borders, focus rings, expanded content, or state semantics.
## Six-stage delivery flow
-The workflow badge summarizes six stages shared by Sprints, Tasks, Overview, and Live:
+The workflow badge summarizes six stages shared by Sprints, Tasks, Overview, and Live. Sprint-run intervention summaries do not override this workflow trigger because they may represent a generic pause or runtime error; genuinely human-waiting sprints retain the separate amber waiting cue described above:
1. **Coding** — waiting, active, paused, complete, or failed.
2. **Pull request** — waiting, creating, missing, or ready.
@@ -48,7 +48,7 @@ The workflow badge summarizes six stages shared by Sprints, Tasks, Overview, and
The four first-class workflow states are `pending`, `in_progress`, `successful`, and `failed`. Pending uses a neutral clock, `in_progress` is presented as running with the signal-colored progress treatment, `successful` uses a green check, and `failed` uses a red X. A sprint aggregates the newest state for each task workflow plus the final feature-to-default-branch merge workflow. Failed wins over in progress, in progress wins over pending, and pending wins over successful, both for each step and for the overall badge.
-The red X is reserved for an actual provider/runtime or workflow failure. Requested QA edits use the bright blue pencil treatment even when failed-check evidence is also present. A review blocker remains pending, and a merge conflict belongs to Merge rather than CI.
+The red X identifies an actual provider/runtime or workflow failure, or explicit active **Human needed** intervention. Requested QA edits use the bright blue pencil treatment even when failed-check evidence is also present. A review blocker remains pending, and a merge conflict belongs to Merge rather than CI.
These badges do not poll per card. Task feature-PR gates are persisted as `ci_gate_status` task-run events, final feature-to-default-branch gates as `main_merge_gate_status` sprint-run events, and unresolved CI repair attention remains active while its item is `open` or `claimed`. For each task or main-merge entity, the projection selects the newest matching event by creation time and then event ID; the sprint presentation aggregates those latest entity states. Persisted task merge metadata is used only as durable fallback evidence when no matching event is available.
diff --git a/docs-web/user/dashboard/styleguides-and-tech-stacks.md b/docs-web/user/dashboard/styleguides-and-tech-stacks.md
index 7262adec46..4746730ded 100644
--- a/docs-web/user/dashboard/styleguides-and-tech-stacks.md
+++ b/docs-web/user/dashboard/styleguides-and-tech-stacks.md
@@ -38,9 +38,9 @@ This does not delete built-in styleguides or clear the saved selection. If a hid
## Project Defaults
-Existing projects and imported local or Git projects default both guidance selections to **None**. They do not inherit the Code UX visual styleguide automatically.
+Every imported, new local, and new remote project starts with both guidance selections explicitly set to **None**. Project creation does not inherit system-level selections or accept a create-time selection for either catalog.
-New local and new remote projects get an explicit project override selecting the generic Code UX styleguide. Tech-stack guidance remains **None** unless the project creation flow or an operator selects one.
+Custom catalog entries and the default-styleguide visibility preference are preserved during creation. After adding the project, select reusable guidance from the top bar or Settings -> Guidance when the project needs it.
## Sprint Selector Actions
diff --git a/docs-web/user/dashboard/tasks.md b/docs-web/user/dashboard/tasks.md
index d899309f99..c96babf819 100644
--- a/docs-web/user/dashboard/tasks.md
+++ b/docs-web/user/dashboard/tasks.md
@@ -37,7 +37,7 @@ When a worker reports a task-run self-reflection rating, the shared rating badge
## Delivery workflow and QA review details
-Task cards use the shared bright delivery workflow badge in place of the standalone QA and CI badges. The task lifecycle label remains visible beside it, while the badge itself always exposes Coding → Pull request → QA → CI → Merge → Completion. Lifecycle and review state keep the badge durable when CI evidence is absent or refreshing.
+Task cards use the shared bright delivery workflow badge in place of the standalone QA and CI badges. The task lifecycle label remains visible beside it, while the badge itself always exposes Coding → Pull request → QA → CI → Merge → Completion. Lifecycle and review state keep the badge durable when CI evidence is absent or refreshing. An open or claimed task-matched human/user intervention with no worker assignment takes precedence as a red **Human needed** trigger; clearing or handing the item to automation restores the ordinary workflow stage.
| Presentation | Meaning |
| --- | --- |
@@ -46,7 +46,7 @@ Task cards use the shared bright delivery workflow badge in place of the standal
| Blue pencil, **QA edits** / **QA changes requested** | QA completed successfully and requested changes. This is an actionable review outcome, not a provider failure. |
| Red X, **QA failed** | The QA provider run failed, errored, or was cancelled before returning a usable verdict. It does not mean QA requested code changes. |
-Hovering, focusing, or activating the badge opens an opaque, viewport-positioned workflow card. Six circles on the left are connected by motion-safe animated dots. When review data exists, an animated chevron reveals an adjacent opaque QA review card with the outcome, summary, findings, fix instructions, target task key, reviewer, reviewed time, and generated follow-up tasks. `Escape` closes the surface and restores focus to the exact workflow or QA-chevron trigger that opened it; outside pointer or touch input dismisses it.
+Hovering, focusing, or activating the badge opens one viewport-positioned interaction region without a visible outer card. Its opaque Delivery flow card contains six circles connected by motion-safe animated dots. When review data exists, a floating responsive arrow points to an independent opaque QA review card with the outcome, summary, findings, fix instructions, target task key, reviewer, reviewed time, and generated follow-up tasks. `Escape` closes the region and restores focus to the exact workflow or QA trigger that opened it; outside pointer or touch input dismisses it.
Generated follow-up task specifications are collapsed initially, so long prompts do not dominate the review. Each **Follow-up task N** button exposes `aria-expanded` and can be toggled with the keyboard or touch. Expansion reveals the generated title, description, priority, dependency task keys (or **None**), and full Markdown prompt in a bounded scrolling area. The card uses one column on constrained screens, may split summary and findings on wider screens, clamps to the viewport, and scrolls vertically when needed. Reduced motion removes spinner, pulse, rotation, and transition movement without removing labels, borders, focus rings, expanded content, or state semantics.
@@ -63,7 +63,7 @@ The workflow badge summarizes six stages shared by Sprints, Tasks, Overview, and
The four first-class workflow states are `pending`, `in_progress`, `successful`, and `failed`. Pending uses a neutral clock, `in_progress` is presented as running with the signal-colored progress treatment, `successful` uses a green check, and `failed` uses a red X. Failed wins over in progress, in progress wins over pending, and pending wins over successful when the overall badge is derived from the three steps.
-The red X is reserved for an actual provider/runtime or workflow failure. Requested QA edits use the bright blue pencil treatment, not failure red. A review blocker is not a CI failure: CI remains passed and Merge reads **Waiting for review**. A merge conflict belongs to Merge and remains distinct from **CI failed**.
+The red X identifies an actual provider/runtime or workflow failure, or explicit active **Human needed** intervention. Requested QA edits use the bright blue pencil treatment, not failure red. A review blocker is not a CI failure: CI remains passed and Merge reads **Waiting for review**. A merge conflict belongs to Merge and remains distinct from **CI failed**.
These badges do not poll per card. Task feature-PR gates are persisted as `ci_gate_status` task-run events, and unresolved CI repair attention remains active while its item is `open` or `claimed`. The card projection selects the newest matching task event by creation time and then event ID, combines it with active attention, and uses persisted task merge metadata only as durable fallback evidence when no matching event is available.
diff --git a/docs/architecture/card-ci-status-projection.md b/docs/architecture/card-ci-status-projection.md
index ddb64fd89e..eed15322d7 100644
--- a/docs/architecture/card-ci-status-projection.md
+++ b/docs/architecture/card-ci-status-projection.md
@@ -31,7 +31,9 @@ A review-only `review_blocked` main-merge event does not produce a failed CI sta
The dashboard expands this compact persisted state with project-scoped execution evidence at each page boundary, then combines it with lifecycle and latest-review state in a durable six-stage delivery projection: Coding, Pull request, QA, CI, Merge, and Completion. Tasks and Live derive task-scoped pull-request, checks, and merge steps; the Sprint gallery and ledger share the sprint-scoped aggregation. CI evidence enriches the middle stages but is optional, so a refresh that omits historical gate events cannot unmount or flash away the workflow badge. A durably completed workflow settles missing historical PR, checks, and merge projections as successful instead of displaying contradictory pending stages. Every stage uses outcome text in addition to its icon and tone.
-The shared `WorkflowStatusBadge` renders the six stages as a circular rail with motion-safe dotted connectors. When a review exists, an animated chevron joins the workflow card to an adjacent review card. Requested changes use the blue `QA edits` treatment even when failed-check evidence also exists; red is reserved for actual provider/runtime and workflow failures. Live replaces its separate task lifecycle and QA badges with this projection, while Task, Sprint, and Overview surfaces retain their surrounding lifecycle context and replace standalone QA/CI disclosures. A running sprint deliberately suppresses task-level gate aggregation so its badge remains on Coding instead of flipping as different child tasks enter PR, CI, or Merge; task cards continue showing those individual transitions.
+Active, task-matched human-only attention has presentation precedence over the ordinary lifecycle and gate summary: the trigger becomes red **Human needed** while its disclosure retains all six workflow stages. This predicate requires explicit attention-item evidence: status must be `open` or `claimed`, ownership must be `human`/`user`, and the worker-assignment field must be explicitly `null`. Resolved, dismissed, expired, worker-owned, system-owned, worker-assigned, sibling-task, and sibling-sprint attention never activates this override. Sprint-run intervention summaries do not qualify because they omit status and assignment and may be synthesized from lifecycle events such as manual pause or runtime error.
+
+The shared `WorkflowStatusBadge` renders the six stages as a circular rail with motion-safe dotted connectors. Its viewport-positioned interaction region has no outer visual card; the opaque Delivery flow card, floating responsive arrow, and optional opaque QA review card are independent siblings inside that one focus/hover/dismissal boundary. Requested changes use the blue `QA edits` treatment even when failed-check evidence also exists; red is reserved for actual provider/runtime/workflow failures and explicit **Human needed** intervention. Live replaces its separate task lifecycle and QA badges with this projection, while Task, Sprint, and Overview surfaces retain their surrounding lifecycle context and replace standalone QA/CI disclosures. A running sprint deliberately suppresses task-level gate aggregation so its badge remains on Coding instead of flipping as different child tasks enter PR, CI, or Merge; an active human-only intervention remains the higher-priority exception.
Cross-surface integration coverage lives in `tests/dashboard/v2/qa-ci-card-status.integration.test.tsx`. Its deterministic fixture exercises pull-request creation, running checks, failure, recovery, active attention precedence, unrelated-event isolation, reconnect replay, and keyboard-only QA/CI disclosures across Task, Live, Sprint gallery, and Sprint ledger cards without Docker, provider CLIs, Git hosting, or a database.
diff --git a/docs/dashboard/dashboard-guide.md b/docs/dashboard/dashboard-guide.md
index 9708c9a99f..684b51598a 100644
--- a/docs/dashboard/dashboard-guide.md
+++ b/docs/dashboard/dashboard-guide.md
@@ -375,8 +375,9 @@ Legacy runtime:
- Live attention resolve/dismiss dialogs are portaled to a viewport-fixed overlay, preserve viewport position after confirmation, use action-specific tones, and return focus without scrolling the page when the originating queue row disappears.
- The Live attention queue, Invocation Feed, and Execution Runtime panels share a compact sidebar feed language with smaller type, subtle row backgrounds, bounded scroll regions, explicit empty states, and narrow colored left rails for status/severity distinction.
- The Live page Git / CI / PR panel now uses compact status metric tiles plus state-specific iconography for PR and CI rows, including animated indicators for active CI states (`IN_PROGRESS`, `QUEUED`, `PENDING`, `QUOTA`) with reduced-motion fallback (`motion-reduce:animate-none`)
-- Live task cards, Sprint gallery/ledger entries, Task cards, and Overview active-stream rows use one bright delivery workflow badge. Its viewport-positioned card shows Coding → Pull request → QA → CI → Merge → Completion on a circular rail with motion-safe dotted connectors. Live uses it in place of the former lifecycle and QA badges; the other surfaces use it in place of standalone QA/CI disclosures. The badge remains mounted when a refreshed Sprints execution snapshot has no CI events, using lifecycle/review state as the durable base and enriching PR/CI/Merge when evidence returns.
-- When a persisted QA review exists, the workflow surface reveals an adjacent review card through an animated chevron. `changes_requested` keeps the bright blue pencil/`QA edits` treatment across the trigger, QA stage, connector, and review card; provider/runtime failures remain red. Hover, focus, activation, touch dismissal, exact-trigger focus restoration, collapsed follow-up specifications, and reduced-motion fallbacks share one contract.
+- Live task cards, Sprint gallery/ledger entries, Task cards, and Overview active-stream rows use one bright delivery workflow badge. Its viewport-positioned interaction region contains an independent Delivery flow card showing Coding → Pull request → QA → CI → Merge → Completion, plus a floating responsive arrow and independent QA card when review data exists; there is no duplicate outer overlay surface. Live uses it in place of the former lifecycle and QA badges; the other surfaces use it in place of standalone QA/CI disclosures. The badge remains mounted when a refreshed Sprints execution snapshot has no CI events, using lifecycle/review state as the durable base and enriching PR/CI/Merge when evidence returns.
+- Active task-matched human/user attention overrides the ordinary workflow summary with a red **Human needed** trigger only while the item is open/claimed and has no worker assignment. Resolved, dismissed, worker/system-owned, worker-assigned, and unrelated attention falls back to the normal lifecycle/QA/CI stage.
+- When a persisted QA review exists, a floating responsive arrow links the independent Delivery flow and review cards. `changes_requested` keeps the bright blue pencil/`QA edits` treatment across the trigger, QA stage, connector, and review card; provider/runtime failures and explicit active **Human needed** intervention use red. Hover, focus, activation, touch dismissal, exact-trigger focus restoration, collapsed follow-up specifications, and reduced-motion fallbacks share one contract.
- Live telemetry and runtime panels expose loading, empty, reconnecting, disconnected, pending, warning, and error states through named regions, polite status/log live regions, and assertive alerts only for blocking disconnect/error states. Dense runtime strings such as branches, PR titles, workflow names, provider/model labels, connection keys, and event snippets wrap inside their panels to avoid page-level horizontal overflow.
- The Sprint ledger keeps sorting, filtering, list-window changes, row selection, per-row menus, and bulk actions accessible with and without motion. Filtered select-all acts on the current filtered result set, selections are pruned when filters hide rows, rows expose stable `aria-selected`/`aria-busy` states with selected and pending badges, and each ledger action emits one concise live outcome with visible and selected counts. Pending bulk controls show a visible disabled reason, reference that reason with `aria-describedby`, suppress duplicate activation, and destructive bulk delete uses the shared hold-to-confirm dialog with a target-specific title and focus restoration to the delete trigger or ledger fallback.
- Creating a new sprint automatically updates the active sprint selection to that new sprint
diff --git a/docs/dashboard/design-system-chat.md b/docs/dashboard/design-system-chat.md
index ee455410da..1171e9a460 100644
--- a/docs/dashboard/design-system-chat.md
+++ b/docs/dashboard/design-system-chat.md
@@ -53,13 +53,13 @@ The chat page opens in a cinematic "3D Chat" stage (`components/chat/cinematic/C
- **Runtime activity cues**: the thought area classifies persisted invocation facts into container startup (no provider linkage or messages yet), provider work, planning, QA review, completion, or error. Only running records are eligible for the stage's current foreground/background display, so historical completion and failure rows do not look current. The compact status shows the phase directly, without `Background` or provider-name prefixes, and pairs it with a deterministic quote in an atomic polite live region. Copy is keyed by stable agent, provider, phase, and invocation/thread context and changes at most once per twenty-second bucket. Active delegated work draws from an original 72-line agency/project-management catalog covering delegation, meetings, scope creep, feedback rituals, tickets, and coworker handoffs. A seeded shuffled deck varies the order by runtime context, presents every line once before reshuffling, and prevents immediate repeats while remaining stable inside a display bucket. When Project Manager work and background work overlap, the Project Manager cue leads and a compact count of other active work remains visible. Reduced motion removes the animated activity dots without removing any status text.
- **Alive by state, never faked**: `use-agent-mood.ts` maps real runtime state to expressions — `nod` while routing a send, `thinking` + a cloud thought bubble while a reply is being prepared (starting → working phases), `excited` for 2,600 ms when a reply lands, `sad` on errors, `curious` while the user types, and idle decay to `bored` after 90,000 ms then `sleepy` after 240,000 ms; engagement wakes it. When motion is allowed and the user is not engaged, a non-sleepy idle stage advances through wink, dance, labelled humming, curious, and greeting cues after 12,000 ms gaps, showing each for 2,800 ms. A welcome-back greeting requires at least 30,000 ms away or idle. The latest Project Manager reply may temporarily override only idle/listening presentation with a validated `agentEffect`; errors, message routing, and active Project Manager work retain precedence.
- **Window-level gaze**: on the stage the avatar uses `pointerTracking="window"` — it watches the cursor anywhere on the page and releases back to idle drift ~3s after the mouse stops. Other surfaces (Agents page) keep the hover-only default.
-- **Latest exchange spotlight**: the stage shows only the current beat — the newest agent reply as one glass speech bubble (markdown + widgets; long replies scroll *inside* the bubble) plus up to two user messages sent after it. Only the newest running `dashboard_reply` or `worker_reply` invocation whose `agentPresetId` matches the resolved Project Manager preset may add an ephemeral progress bubble after that exchange. The bubble has a visible **In progress** label, the latest non-empty persisted assistant prose whose normalized kind is absent or `assistant`, and a deduplicated tool-call count. Reasoning, injected context, user turns, tool payloads, and unknown internal message kinds never become its prose; paired `tool_call`/`tool_result` turns share `toolCallId`, while providers without one fall back to the persisted message id. Before the first eligible assistant turn it shows a startup placeholder and `0 tools used`. This atomic polite status is a transient projection only: it is separate from the durable thread transcript and final reply, never persists a conversation message, and disappears before the stored final reply is staged so final text is not duplicated. On mobile, the latest exchange stays inside the stage above the composer and scrolls within that bounded region, so replies and active progress appear without scrolling the whole stage. A "Full conversation · N messages" link jumps to Threads for history. Quick actions use the open space beside the avatar while the bubble owns the right side. An empty idle thread shows a scripted greeting with suggestion chips that send directly without changing the composer.
-- **Invocation-feedback lifecycle**: zero-message startup still fetches the selected invocation transcript and renders the placeholder immediately. The feedback hook refetches when the selected invocation's `messageCount`, `lastMessageAt`, or `updatedAt` changes; all three are refresh keys because a persisted telemetry rewrite can change content or metadata without changing length. A same-invocation refresh keeps the last safe message and tool count visible while loading. A non-fatal transcript-fetch failure also keeps that last snapshot (or the startup placeholder when no snapshot exists) instead of turning background transcript availability into a stage failure. Invocation replacement or disappearance, terminal status, project change, resolved-preset change, and a later user-selected thread change clear the projection and work tool immediately. The first-send transition from `new-thread` to its newly created thread is the one retained context handoff. Superseded requests are aborted, and request generations reject late responses so stale project or invocation data cannot repopulate the stage.
-- **Progress-bubble scale and overflow**: the bubble animates on first appearance and eligible interim-message changes when motion is allowed. It remains height-bounded with its own vertical scrolling (`min(30vh, 280px)` on compact screens, `160px` at medium, `170px` at extra-large, and `220px` at 2XL); its maximum width is `720px` by default, `680px` at LG, `780px` at XL, and `880px` at 2XL. Progress prose scales from 14px/28px line height through 15–16px on large screens to 17px/36px at 2XL; long words wrap, while code blocks and tables scroll horizontally inside the bubble. The latest-exchange log keeps a four-unit gap between durable reply, pending user turns, and transient progress. The separate activity thought bubble stays compact (`208px` on desktop), moves farther left of the larger avatar at XL/2XL, and retains space between its card and two-dot tail so neither activity copy nor decoration crowds the avatar or progress surface.
+- **Latest exchange spotlight**: the stage shows only the current beat — the newest agent reply as one glass speech bubble (markdown + widgets; long replies scroll *inside* the bubble) plus up to two user messages sent after it. The durable reply bubble is right-aligned inside a narrower right-side column so it cannot cover the avatar; it is capped at 620px by default, 560px at LG, 620px at XL, and 680px at 2XL, with compact 12–13px prose. Only the newest running `dashboard_reply` or `worker_reply` invocation whose `agentPresetId` matches the resolved Project Manager preset may add an ephemeral progress bubble after that exchange. The progress bubble has a visible **In progress** label, the latest non-empty persisted assistant prose whose normalized kind is absent or `assistant`, and a deduplicated tool-call count. Reasoning, injected context, user turns, tool payloads, and unknown internal message kinds never become its prose; paired `tool_call`/`tool_result` turns share `toolCallId`, while providers without one fall back to the persisted message id. Before the first eligible assistant turn it shows a startup placeholder and `0 tools used`. This atomic polite status is a transient projection only: it is separate from the durable thread transcript and final reply, never persists a conversation message, and disappears before the stored final reply is staged so final text is not duplicated. On mobile, the latest exchange stays inside the stage above the composer and scrolls within that bounded region, so replies and active progress appear without scrolling the whole stage. A "Full conversation · N messages" link jumps to Threads for history. Quick actions use the open space beside the avatar while the bubble owns the right side. An empty idle thread shows a scripted greeting with suggestion chips that send directly without changing the composer.
+- **Invocation-feedback lifecycle**: zero-message startup still fetches the selected invocation transcript and renders the placeholder immediately. The feedback hook refetches when the selected invocation's `messageCount`, `lastMessageAt`, or `updatedAt` changes; all three are refresh keys because a persisted telemetry rewrite can change content or metadata without changing length. A same-invocation refresh keeps the last safe message and tool count visible while loading. A non-fatal transcript-fetch failure also keeps that last snapshot (or the startup placeholder when no snapshot exists) instead of turning background transcript availability into a stage failure. Invocation replacement or disappearance, terminal status, project change, resolved-preset change, and a later user-selected thread change clear the transcript projection immediately. The work tool follows the separate authoritative Project Manager busy state and remains present while an awaited reply or matching reply invocation is still active. The first-send transition from `new-thread` to its newly created thread is the one retained context handoff. Superseded requests are aborted, and request generations reject late responses so stale project or invocation data cannot repopulate the stage.
+- **Progress-bubble scale and overflow**: the progress bubble animates on first appearance and eligible interim-message changes when motion is allowed. It remains height-bounded with its own vertical scrolling (`min(30vh, 280px)` on compact screens, `160px` at medium, `170px` at extra-large, and `220px` at 2XL); its maximum width is `720px` by default, `680px` at LG, `780px` at XL, and `880px` at 2XL. Progress prose scales from 14px/28px line height through 15–16px on large screens to 17px/36px at 2XL; long words wrap, while code blocks and tables scroll horizontally inside the bubble. The latest-exchange log keeps a four-unit gap between durable reply, pending user turns, and transient progress. The separate activity thought bubble stays compact (`220px` on desktop), remains horizontally centered directly above the avatar, and retains space between its card and two-dot tail so neither activity copy nor decoration crowds the avatar or progress surface.
- **Floating composer**: a bottom-center glass pill shared with the Threads data flow — Enter sends, first send auto-creates the thread, ArrowUp/Down recalls history.
- **Expressions catalog**: the avatar vocabulary (SVG + WebGL, kept in sync) now includes `curious`, `thinking`, `excited`, `laughing`, `surprised`, `wink`, `dance`, and `proud` in addition to the original eight.
-- **Work tools**: for the full lifecycle of a matching running Project Manager reply invocation, including container startup before the first transcript turn, the bot pulls an animated 3D work tool from its toolbox beside itself. The exact `AgentSceneTool` identifiers are `screwdriver` (spinning bit), `jackhammer` (piston/chisel), `wrench` (ratcheting swing), `hammer` (tapping swing), and `torch` (flickering welding tip). The stage uses the selected invocation id as the activity key, derives a deterministic initial catalog position from it, and advances in catalog order every 7,000 ms without an immediate repeat; replacing the invocation restarts selection predictably and terminal state removes the tool immediately. Reduced motion keeps that invocation's initial tool static and starts no rotation timer. `?stageTool=` pins a valid tool for design review even while runtime activity is inactive; an absent or unsupported value does not override normal selection. Awaited-thread fallback without a matching invocation and background project execution never equip a runtime-selected tool because invocation ownership is resolved before the work-tool hook is activated.
-- **Idle quick actions**: the complete eligible 13-action stage set is **Create Web App**, **Create Desktop App**, **Create Onlineshop**, **Create Portfolio**, **Create Game**, **Status Report**, **Sprint Progress**, **What’s Failing?**, **Plan Next Steps**, **Add Nodes Workflow**, **Add Dashboard**, **Create Skill**, and **List Skills**. Desktop sorts them into subtle **Create**, **Project pulse**, and **Workflows** clusters contained entirely within the left stage viewbox. Each category uses a compact wrapping cluster, so Sprint Progress and Plan Next Steps remain beside the other Project pulse controls while Add Dashboard, Create Skill, and List Skills remain beside the other Workflows controls. Content-width neutral chips use small horizontal/vertical offsets, generous gaps, and staggered gentle drift to avoid both full-width controls and a mechanically aligned matrix while maintaining a whitespace buffer before the avatar. Mobile keeps the same category order in orderly content-width two-row horizontal groups. Each chip has a distinct colored icon tile for recognition while its card surface and interaction states remain consistent. Labels stay on one line, every action is a native keyboard-reachable button with a visible focus ring, and the floating animation stops under reduced motion. The five create-app actions dispatch typed `create_app` metadata and launch detached `Plan & Start` quicksprints; the eight informational and workflow actions send their catalog prompt through normal project chat without inserting into, replacing, or clearing the composer draft. All five create-app actions remain hidden until initial-project eligibility has loaded and is true; the other eight project actions remain available whenever the stage is idle. The full group hides without a selected project and while sending, working, or showing an error.
+- **Work tools**: for the full lifecycle of active Project Manager reply work, including an awaited selected-thread reply before its invocation record is visible and container startup before the first transcript turn, the bot pulls an animated 3D work tool from its toolbox beside itself. The exact `AgentSceneTool` identifiers are `screwdriver` (spinning bit), `jackhammer` (piston/chisel), `wrench` (ratcheting swing), `hammer` (tapping swing), and `torch` (flickering welding tip). The stage uses the foreground activity cue id—normally the matching invocation id or selected thread id—as the activity key, derives a deterministic initial catalog position from it, and advances in catalog order every 7,000 ms without an immediate repeat; replacing the active reply context restarts selection predictably and leaving the Project Manager busy state removes the tool immediately. Reduced motion keeps that activity's initial tool static and starts no rotation timer. `?stageTool=` pins a valid tool for design review even while runtime activity is inactive; an absent or unsupported value does not override normal selection. Background project execution never equips a runtime-selected tool because it does not activate the Project Manager busy state.
+- **Idle quick actions**: the default eligible 11-action stage set is **Create Web App**, **Create Desktop App**, **Create Onlineshop**, **Create Portfolio**, **Create Game**, **Status Report**, **Sprint Progress**, **What’s Failing?**, **Plan Next Steps**, **Create Skill**, and **List Skills**. **Add Nodes Workflow** and **Add Dashboard** remain registered but hidden by dedicated default-off dashboard feature flags; each also requires its underlying `nodes` or `custom-dashboards` surface flag. Desktop sorts enabled actions into subtle **Create**, **Project pulse**, and **Workflows** clusters contained entirely within the left stage viewbox. Each category uses a compact wrapping cluster, so Sprint Progress and Plan Next Steps remain beside the other Project pulse controls while Create Skill and List Skills remain together in Workflows. Content-width neutral chips use small horizontal/vertical offsets, generous gaps, and staggered gentle drift to avoid both full-width controls and a mechanically aligned matrix while maintaining a whitespace buffer before the avatar. Mobile keeps the same category order in orderly content-width two-row horizontal groups. Each chip has a distinct colored icon tile for recognition while its card surface and interaction states remain consistent. Labels stay on one line, every action is a native keyboard-reachable button with a visible focus ring, and the floating animation stops under reduced motion. The five create-app actions dispatch typed `create_app` metadata and launch detached `Plan & Start` quicksprints; the six default informational and workflow actions send their catalog prompt through normal project chat without inserting into, replacing, or clearing the composer draft. All five create-app actions remain hidden until initial-project eligibility has loaded and is true; enabled project actions remain available whenever the stage is idle. The full group hides without a selected project and while sending, working, or showing an error.
- **Reduced motion and fallback**: either the resolved reduced-motion preference or explicit `fallbackMode` selects the static SVG bot instead of creating a WebGL context. Aurora, thinking dots, quick-action float, drift, pointer gaze, tool motion, progress-bubble entrance/update transitions, and response choreography stop. A selected work tool remains named in a visible static label and the fallback container's accessible image label. The thought bubble keeps its phase/quote text, the progress bubble keeps **In progress**, prose or startup placeholder, and the tool-count text, and these visible labels remain the authoritative activity signal. If WebGL renderer construction fails, the same SVG semantics apply. A response effect still exposes its validated semantic emotion and caption (or `Feeling .`), so the reaction remains understandable without movement.
### Project Manager response-effect contract
diff --git a/docs/dashboard/design-system-overview.md b/docs/dashboard/design-system-overview.md
index ce6bc716e3..1582776487 100644
--- a/docs/dashboard/design-system-overview.md
+++ b/docs/dashboard/design-system-overview.md
@@ -28,6 +28,7 @@ The overview page acts as a centralized "Polished Operational Command Surface."
- Overview pages must preserve a named route landmark and named operational regions for metric cards, primary work sections, and live telemetry. `HeaderStats` and `OverviewTelemetry` are the reference source areas for overview metric and telemetry semantics.
- Loading metric decks use polite `role="status"` with `aria-busy`; loaded metric groups use named `region` containers. Avoid announcing decorative counters or background animation as separate content.
- Overview telemetry distinguishes urgency: loading, empty, pending, running, and timeline updates are polite, while project/transport failures that block trust in the telemetry rail are alerts. Timeline feeds use a named `role="log"` so updates are discoverable without replacing the whole page context.
+- Active Streams feeds each task's persisted lifecycle, review, merge indicator, and task-scoped realtime CI events/attention into the shared workflow projection used by Tasks and Live. The interactive badge must therefore show the current Coding → Pull request → QA → CI → Merge → Completion stage rather than a lifecycle-only fallback, and evidence from another task must never leak into the row.
- The selected-sprint attention queue in Overview must use the shared attention row presentation from the Live runtime surface. It should inherit status/severity tones, markdown summary rendering, and list semantics from that shared component, while omitting claim/resolve/dismiss actions.
- Dense runtime labels such as project names, sprint keys, provider/model labels, branch names, workflow names, and event snippets must wrap inside their cards or rails. Do not rely on hover-only truncation for operational values.
- The Warm Void visual language remains restrained: neutral glass surfaces for Overview structure, theme-specific signal utilities for primary active/focus/running states, and Ember/status tones only for intervention, warning, error, and destructive states. Stats uses a stricter solid-surface Warm Void variant for dense analytics and System administration; see [Stats & Analytics Design System](./design-system-stats.md).
diff --git a/docs/dashboard/design-system-settings.md b/docs/dashboard/design-system-settings.md
index 43650b9fbe..202fc660ac 100644
--- a/docs/dashboard/design-system-settings.md
+++ b/docs/dashboard/design-system-settings.md
@@ -78,7 +78,7 @@ This document defines the visual patterns and rules for the Settings workspace.
* Primary Settings actions use `--accent-action` with `--accent-on-solid`; light presets use a white foreground and dark presets use warm-void text where required for contrast. Do not invert actions to theme-neutral black/white slabs. Neutral buttons remain surface-toned, domain-colored Configure actions remain neutral except for their icon/hover detail, and destructive actions retain the status-red treatment.
* The System/Project selection is a database-backed runtime preference (`runtime.lastActiveScope`). Scope changes save that preference from the last saved system settings snapshot, so toggling the selector must not implicitly persist unrelated dirty form fields.
* The unified command/status bar must not use a long page-level card or pill background behind the scope controls. The child scope selector, context chips, and active-panel status own their tokenized borders, glass fills, focus rings, wrapping, and reduced-motion-safe saved/dirty cues.
-* `SettingsPage` owns the unified sticky command/status bar at `top-16` and renders `SettingsContentPanels` with its reusable active-panel strip suppressed. `SettingsContentPanels` may still render that sticky strip by default when used outside the full Settings page. The desktop `SettingsCategoryRail` remains `lg:sticky lg:top-16`; page content starts below the unified bar so the rail, command/status bar, and active panel do not overlap.
+* `SettingsPage` owns the unified sticky command/status bar at `top-16` and renders `SettingsContentPanels` with its reusable active-panel strip suppressed. `SettingsContentPanels` may still render that sticky strip by default when used outside the full Settings page. The desktop `SettingsCategoryRail` remains `lg:sticky lg:top-16`; page content starts below the unified bar so the rail, command/status bar, and active panel do not overlap. The right-side active category pane and shared toggle-linked control slots stay top-aligned instead of vertically centering against taller neighboring content.
* Below `lg`, the full category rail is replaced by `SettingsCategoryPicker` at the start of the command/status bar. Its compact trigger identifies the current category and active Smart Find match count, then opens the shared category rail in a focus-trapped drawer. The drawer retains filtered categories, match previews, arrow-key movement, selected/pending/disabled semantics, Escape-to-close, and focus restoration. Category selection closes the drawer; an unavailable category switch keeps the drawer open with the visible disabled reason.
* Save and background reload paths must preserve dirty drafts until the affected scope has actually saved or reset. If system settings save while project settings are dirty, project draft values remain mounted and are not replaced by an effective-settings refresh; failed project saves leave the draft visible for correction.
* Google Drive mount controls remain mounted with the scoped draft through save and reset. Helper copy identifies the fixed `/mnt/code-ux/google-drive` container path, Docker-only behavior, and read-only default without exposing the configured host path outside its editable field.
diff --git a/docs/dashboard/design-system-shared-primitives.md b/docs/dashboard/design-system-shared-primitives.md
index 78cc9d462b..7e22786a57 100644
--- a/docs/dashboard/design-system-shared-primitives.md
+++ b/docs/dashboard/design-system-shared-primitives.md
@@ -36,7 +36,7 @@ The goal is to ensure all primitives align with the signal-and-ember operational
1. **Buttons**: Should utilize `--elevation-raised` (for primary), `--accent-focus-ring`, and consistent proportional padding across all variants. Signal buttons use white foreground text in light mode and the existing dark foreground in dark mode to preserve contrast across the theme-specific signal colors. For responsive buttons containing dynamic text (e.g., pending states), avoid `whitespace-nowrap` as it causes horizontal overflow on mobile screens. Instead, apply `min-w-0` to the button, wrap the text in a `span` with `truncate min-w-0`, and add `shrink-0` to any adjacent icons. When implementing custom single-choice button groups, use standard ARIA radiogroup semantics by applying `role="radiogroup"` to the wrapper and `role="radio"` with `aria-checked` to the individual choice options.
Button pending, success, and error overlays use `controlFeedback` and fixed feedback slots so the accessible name, visible label, and hit target do not change while icons or spinners appear. Pending buttons keep their original label visible and in the DOM, expose `aria-busy="true"`, suppress activation for native `disabled`, `aria-disabled`, pending states, and same-tick duplicate async clicks, and only pin inline width after a real measurement is available. Icon-only buttons keep fixed square dimensions. Controls that launch async work set native `disabled` or `aria-disabled`, expose `aria-busy` where the control itself is pending, and provide a nearby status message for disabled recovery. Native-disabled controls must stay inert; `aria-disabled` on shared controls is normalized to suppress activation. Use `disabledReason`, `title`, `aria-describedby`, or visible helper text when the operator needs a durable recovery reason; reason text must describe the control without becoming part of its accessible name.
2. **Cards**: Built on `--surface-glass`, bordered by `--border-hairline`, and grounded by `--elevation-base`. They should not be nested unless the inner element is explicitly a card.
-3. **Inputs & Selects**: Inputs use `--fill-muted` and `--border-hairline`. Focus states should strictly use `--accent-focus-ring`. Error and valid states override the border but maintain the structural radius and use tokenized `controlFeedback` timing. Shared inputs reveal `errorText` after blur/focusout, explicit `forceValidation`, or a caller-provided invalid ARIA state, and route visible error copy through `inlineValidation`; helper text remains available until the error is active, then the active error owns both `aria-describedby` and `aria-errormessage`. When an invalid input or select receives focus for correction, ownership may temporarily return to helper text so the operator keeps recovery guidance; if the error condition remains on blur/focusout, the error reclaims `aria-describedby` and `aria-errormessage`. Selects follow the same helper/error ownership and suppress changes while native-disabled or `aria-disabled`. Shared select triggers expose stable `aria-expanded`, `aria-controls`, selected state, and disabled state while their overlays animate independently with `enterExit`.
+3. **Inputs & Selects**: Inputs use `--fill-muted` and `--border-hairline`. Focus states should strictly use `--accent-focus-ring`. Error and valid states override the border but maintain the structural radius and use tokenized `controlFeedback` timing. Shared inputs reveal `errorText` after blur/focusout, explicit `forceValidation`, or a caller-provided invalid ARIA state, and route visible error copy through `inlineValidation`; helper text remains available until the error is active, then the active error owns both `aria-describedby` and `aria-errormessage`. When an invalid input or select receives focus for correction, ownership may temporarily return to helper text so the operator keeps recovery guidance; if the error condition remains on blur/focusout, the error reclaims `aria-describedby` and `aria-errormessage`. User-visible single-choice fields must use `AvantgardeSelect`; do not add native `