Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
591b162
fix(chat): separate model identity, request provenance and work activity
loopx-agent Oct 17, 2026
193488b
test(chat): cover model defaults and continuous attached history
loopx-agent Oct 17, 2026
e4b2863
docs(chat): document conversation defaults and presentation boundaries
loopx-agent Oct 17, 2026
dfedffe
fix(chat): preserve native tool text and folded exit-code observations
loopx-agent Oct 17, 2026
f1492b7
docs(chat): qualify native tool history and show packaged before-afte…
loopx-agent Oct 17, 2026
cdbd17e
Merge current main for chat delivery qualification
loopx-agent Oct 17, 2026
7106fec
refactor(chat): isolate native transport and settle review debt
loopx-agent Oct 17, 2026
ba32f8a
fix(chat): unify running-turn instructions in the conversation composer
loopx-agent Oct 17, 2026
fa7aa24
Merge current main for composer input qualification
loopx-agent Oct 17, 2026
dd71de6
fix(chat): admit explicit same-session queued turns
loopx-agent Oct 17, 2026
87f2a7b
fix(chat): separate queued sends from explicit turn steering
loopx-agent Oct 17, 2026
3940c5e
Merge current Chat provider and research reader source
loopx-agent Oct 17, 2026
0cec1c0
fix(chat): carry advertised reasoning choices through native sessions
loopx-agent Oct 17, 2026
b402380
fix(chat): separate observed models from new conversation settings
loopx-agent Oct 17, 2026
5d3b2b8
docs(chat): qualify advertised reasoning selection and readback
loopx-agent Oct 17, 2026
f585f07
fix(chat): preserve endpoint readiness errors for setting requests
loopx-agent Oct 17, 2026
089c211
fix(chat): keep pending model and effort choices together on readback
loopx-agent Oct 17, 2026
24843b6
Merge remote-tracking branch 'origin/main' into codex/chat-observabil…
loopx-agent Oct 17, 2026
ce256ff
fix(chat): keep optional model settings out of the opening viewport
loopx-agent Oct 17, 2026
978ea4a
docs(chat): explain current model readback and optional settings
loopx-agent Oct 17, 2026
5860e15
Merge current main for Chat conversation qualification
loopx-agent Oct 17, 2026
3ef5291
Merge current main without dropping native chat and configuration owners
loopx-agent Oct 17, 2026
263cc55
fix(chat): keep narrow menus visible and recover undispatched drafts
loopx-agent Oct 17, 2026
de608bc
docs(chat): qualify narrow readback and draft recovery boundaries
loopx-agent Oct 17, 2026
0b40def
test(chat): qualify explicit steering alongside ordinary queued sends
loopx-agent Oct 17, 2026
50dab01
fix(chat): reconcile completed replies and steering with stored history
loopx-agent Oct 17, 2026
65122b5
Merge concurrent Chat qualification and preserve stored conversation …
loopx-agent Oct 17, 2026
97cd79d
fix(chat): deduplicate queued readback and retain observed response o…
loopx-agent Oct 17, 2026
588c87f
fix(chat): expose read-only recovery after confirmed delivery
loopx-agent Oct 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions apps/presentation/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"smoke:benchmark-study": "rm -rf node_modules/.cache/loopx-benchmark-study-smoke && tsc --ignoreConfig --target ES2022 --module NodeNext --moduleResolution NodeNext --skipLibCheck --strict --resolveJsonModule --outDir node_modules/.cache/loopx-benchmark-study-smoke smoke/benchmark-study-contract-smoke.ts src/data/benchmark-study.ts && node node_modules/.cache/loopx-benchmark-study-smoke/smoke/benchmark-study-contract-smoke.js",
"smoke:benchmark-study-browser": "node ../../../examples/dashboard-benchmark-study-browser-smoke.mjs",
"smoke:capability-configuration": "rm -rf node_modules/.cache/loopx-capability-configuration-smoke && tsc --ignoreConfig --target ES2022 --module NodeNext --moduleResolution NodeNext --types node --skipLibCheck --strict --outDir node_modules/.cache/loopx-capability-configuration-smoke smoke/capability-configuration-smoke.ts src/data/capability-configuration.ts && node node_modules/.cache/loopx-capability-configuration-smoke/smoke/capability-configuration-smoke.js",
"smoke:chat-model-menu": "vite build --ssr smoke/chat-model-menu-smoke.mjs --outDir node_modules/.cache/chat-model-menu --emptyOutDir && node node_modules/.cache/chat-model-menu/chat-model-menu-smoke.js",
"smoke:chat-route": "tsc --ignoreConfig --target ES2022 --module ES2022 --moduleResolution Bundler --ignoreDeprecations 6.0 --skipLibCheck --strict --rootDir ../../.. --outDir node_modules/.cache/loopx-chat-route-smoke smoke/chat-route-smoke.ts src/data/chat-model.ts src/vite-env.d.ts && node node_modules/.cache/loopx-chat-route-smoke/apps/presentation/dashboard/smoke/chat-route-smoke.js",
"smoke:chat-stream-stall": "vite build --ssr smoke/chat-stream-stall-smoke.ts --outDir node_modules/.cache/loopx-chat-stream-stall --emptyOutDir && node node_modules/.cache/loopx-chat-stream-stall/chat-stream-stall-smoke.js",
"smoke:chat-turn-acceptance-retry": "vite build --ssr smoke/chat-turn-acceptance-retry-smoke.ts --outDir node_modules/.cache/loopx-chat-turn-acceptance-retry --emptyOutDir && node node_modules/.cache/loopx-chat-turn-acceptance-retry/chat-turn-acceptance-retry-smoke.js",
Expand All @@ -38,10 +39,10 @@
"smoke:home-route": "rm -rf /tmp/loopx-home-route-smoke && tsc --ignoreConfig --target ES2022 --module CommonJS --moduleResolution Node --ignoreDeprecations 6.0 --skipLibCheck --strict --outDir /tmp/loopx-home-route-smoke smoke/home-route-smoke.ts && node /tmp/loopx-home-route-smoke/home-route-smoke.js",
"smoke:delegation-preflight": "rm -rf node_modules/.cache/loopx-delegation-preflight-smoke && tsc --ignoreConfig --target ES2022 --module NodeNext --moduleResolution NodeNext --jsx react-jsx --skipLibCheck --strict --rootDir . --outDir node_modules/.cache/loopx-delegation-preflight-smoke smoke/delegation-preflight-smoke.tsx src/data/delegation-preflight.ts src/features/personal-workspace/delegation-preflight-status.tsx && node node_modules/.cache/loopx-delegation-preflight-smoke/smoke/delegation-preflight-smoke.js",
"smoke:delegation-preflight-browser": "node --experimental-strip-types smoke/delegation-preflight-browser-smoke.mjs",
"smoke:personal-workspace": "npm run smoke:conversation-history-order && npm run smoke:goal-order && npm run smoke:goal-activity && npm run smoke:proposal-recency && node src/features/personal-workspace/conversation-order.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/steering-recovery.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/runtime-readiness.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/attention-notifications.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/since-you-looked.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/goal-suggestions.test.mjs && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/font-token.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:personal-workspace": "npm run smoke:chat-model-menu && npm run smoke:conversation-history-order && npm run smoke:goal-order && npm run smoke:goal-activity && npm run smoke:proposal-recency && node src/features/personal-workspace/conversation-order.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/steering-recovery.test.mjs src/features/personal-workspace/composer-keyboard.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/runtime-readiness.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/attention-notifications.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/since-you-looked.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/goal-suggestions.test.mjs && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/font-token.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:workspace-locale": "LOOPX_PERSONAL_WORKSPACE_SCENARIO=workspace-locale node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:personal-workspace-packaged": "npm run smoke:conversation-history-order && npm run smoke:goal-order && npm run smoke:goal-activity && npm run smoke:proposal-recency && node src/features/personal-workspace/conversation-order.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/steering-recovery.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/runtime-readiness.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/attention-notifications.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/since-you-looked.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/goal-suggestions.test.mjs && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/font-token.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && node ../../../examples/personal-workspace-browser/server-startup.test.mjs && LOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node ../../../examples/personal-workspace-browser-smoke.mjs && LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node smoke/team-evidence-return-smoke.mjs && LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node smoke/team-feedback-recovery-smoke.mjs && LOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node smoke/goal-workspace-craft-browser-smoke.mjs",
"smoke:personal-workspace-packaged:catalog": "npm run smoke:conversation-history-order && npm run smoke:goal-order && npm run smoke:goal-activity && npm run smoke:proposal-recency && node src/features/personal-workspace/conversation-order.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/steering-recovery.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/runtime-readiness.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/attention-notifications.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/since-you-looked.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/goal-suggestions.test.mjs && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/font-token.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && node ../../../examples/personal-workspace-browser/server-startup.test.mjs && LOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:personal-workspace-packaged": "npm run smoke:chat-model-menu && npm run smoke:conversation-history-order && npm run smoke:goal-order && npm run smoke:goal-activity && npm run smoke:proposal-recency && node src/features/personal-workspace/conversation-order.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/steering-recovery.test.mjs src/features/personal-workspace/composer-keyboard.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/runtime-readiness.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/attention-notifications.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/since-you-looked.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/goal-suggestions.test.mjs && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/font-token.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && node ../../../examples/personal-workspace-browser/server-startup.test.mjs && LOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node ../../../examples/personal-workspace-browser-smoke.mjs && LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node smoke/team-evidence-return-smoke.mjs && LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node smoke/team-feedback-recovery-smoke.mjs && LOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node smoke/goal-workspace-craft-browser-smoke.mjs",
"smoke:personal-workspace-packaged:catalog": "npm run smoke:chat-model-menu && npm run smoke:conversation-history-order && npm run smoke:goal-order && npm run smoke:goal-activity && npm run smoke:proposal-recency && node src/features/personal-workspace/conversation-order.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/steering-recovery.test.mjs src/features/personal-workspace/composer-keyboard.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/runtime-readiness.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/attention-notifications.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/since-you-looked.test.mjs && node --no-warnings --experimental-strip-types --test src/features/personal-workspace/goal-suggestions.test.mjs && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/font-token.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && node ../../../examples/personal-workspace-browser/server-startup.test.mjs && LOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:personal-workspace-packaged:team": "LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node smoke/team-evidence-return-smoke.mjs && LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node smoke/team-feedback-recovery-smoke.mjs",
"smoke:personal-workspace-packaged:craft": "LOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node smoke/goal-workspace-craft-browser-smoke.mjs",
"smoke:todo-resume-condition": "rm -rf /tmp/loopx-todo-resume-condition-smoke && tsc --ignoreConfig --target ES2022 --module commonjs --moduleResolution node --ignoreDeprecations 6.0 --skipLibCheck --strict --outDir /tmp/loopx-todo-resume-condition-smoke smoke/todo-resume-condition-smoke.ts src/features/personal-workspace/todo-resume-condition.ts && node /tmp/loopx-todo-resume-condition-smoke/smoke/todo-resume-condition-smoke.js",
Expand All @@ -61,7 +62,7 @@
"smoke:task-board-scroll": "node smoke/task-board-scroll-smoke.mjs",
"smoke:usage-progress": "tsc --ignoreConfig --target ES2022 --module ESNext --moduleResolution Bundler --allowImportingTsExtensions --types vite/client --resolveJsonModule --esModuleInterop --jsx react-jsx --skipLibCheck --strict --noEmit smoke/usage-progress-smoke.ts src/features/personal-workspace/personal-workspace-model.ts && vite build --ssr smoke/usage-progress-smoke.ts --outDir node_modules/.cache/loopx-usage-progress-smoke --emptyOutDir && node node_modules/.cache/loopx-usage-progress-smoke/usage-progress-smoke.js",
"smoke:action-review-plan": "tsc --noEmit --ignoreConfig --target ES2022 --module ES2022 --moduleResolution Bundler --skipLibCheck --strict smoke/action-review-plan-smoke.ts src/vite-env.d.ts && vite build --ssr smoke/action-review-plan-smoke.ts --outDir node_modules/.cache/loopx-action-review-plan --emptyOutDir && node node_modules/.cache/loopx-action-review-plan/action-review-plan-smoke.js",
"smoke:attention-details": "tsc --ignoreConfig --target ES2022 --module CommonJS --moduleResolution Node --ignoreDeprecations 6.0 --resolveJsonModule --esModuleInterop --jsx react-jsx --skipLibCheck --strict --outDir /tmp/loopx-attention-details-smoke smoke/attention-details-smoke.ts && NODE_PATH=\"$PWD/node_modules\" node /tmp/loopx-attention-details-smoke/apps/presentation/dashboard/smoke/attention-details-smoke.js",
"smoke:attention-details": "tsc --noEmit --ignoreConfig --target ES2022 --module ES2022 --moduleResolution Bundler --allowImportingTsExtensions --resolveJsonModule --esModuleInterop --jsx react-jsx --skipLibCheck --strict --types vite/client smoke/attention-details-smoke.ts && vite build --ssr smoke/attention-details-smoke.ts --outDir node_modules/.cache/loopx-attention-details --emptyOutDir && node node_modules/.cache/loopx-attention-details/attention-details-smoke.js",
"smoke:delivery-review": "tsc --ignoreConfig --target ES2022 --module NodeNext --moduleResolution NodeNext --skipLibCheck --strict --rootDir src --outDir node_modules/.cache/delivery-review src/data/delivery-review.ts src/data/goal-work-map.ts src/data/goal-acceptance-observation.ts src/features/personal-workspace/delivery-review-copy.ts && node smoke/delivery-review-smoke.mjs",
"smoke:team-artifact-comparison": "tsc --noEmit && vite build --ssr smoke/team-artifact-comparison-smoke.mjs --outDir node_modules/.cache/team-comparison --emptyOutDir && node node_modules/.cache/team-comparison/team-artifact-comparison-smoke.js",
"smoke:team-report": "vite build --ssr smoke/team-report-smoke.mjs --outDir node_modules/.cache/team-report --emptyOutDir && node node_modules/.cache/team-report/team-report-smoke.js",
Expand Down
11 changes: 9 additions & 2 deletions apps/presentation/dashboard/smoke/attention-details-smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ function assert(condition: unknown, message: string): asserts condition {
const source = {
index: 1, todo_id: "todo_gate_one", done: false, status: "open", text: "Review change",
task_class: "user_gate", note: "The chosen direction needs review", evidence: "review:bounded-check",
blocks_agent: "worker-one", unblocks_todo_id: "todo_target",
created_by: "request-author", blocks_agent: "worker-one", unblocks_todo_id: "todo_target",
decision_scope: { schema_version: "decision_scope_v0", kind: "direction", granularity: "action", scope_key: "route-one" },
};
// Production Zod parse must preserve the public projection facts before mapping.
const details = attentionDetails(todoItemSchema.parse(source));
assert(details.reason === source.note && details.evidence === source.evidence, "reason/evidence survived schema");
assert(details.blocksAgent === "worker-one" && details.unblocksTodoId === "todo_target", "exact relationships survive schema");
assert(details.createdBy === "request-author" && details.boundAgent === null, "request provenance is not inferred from the recipient");
assert(details.decisionScope?.scopeKey === "route-one", "scope survives schema");
assert(details.interaction === "decision", "typed user gate is decision");
const row: WorkspaceAttention = { blocking: true, goalId: "goal-one", todoId: "todo_gate_one", sourceId: "source-a", text: source.text, details };
Expand Down Expand Up @@ -96,16 +97,21 @@ assert(longModel.userTodos[0]?.details?.evidence === source.evidence, "App decis
const markup = renderToStaticMarkup(createElement(WorkspaceI18nProvider, null, createElement(AttentionDetailCard, { item: longModel.userTodos[0] })));
assert(markup.includes("Publish version 2.0 to stable only after acceptance."), "rendered App detail contains object beyond compact label");
assert(markup.includes(source.evidence), "rendered App detail contains evidence");
assert(markup.includes("Agent request-author") && markup.includes("Agent worker-one"), "creator and reply recipient are visible without diagnostics");
const unknownCreator = renderToStaticMarkup(createElement(WorkspaceI18nProvider, null,
createElement(AttentionDetailCard, { item: {...row, details: attentionDetails({...source, created_by: null})} })));
assert(unknownCreator.includes("Requesting Agent not recorded") && !unknownCreator.includes("From Agent worker-one"), "legacy rows do not invent the creator from blocks_agent");

// Exercise the actual compact project_asset -> same QueueItem.user_todos join,
// not a fixture that already supplies a complete body to attentionDetails.
const canonical = todoItemSchema.parse({...source, role: "user", task_class: "user_action",
updated_at: "2026-10-01T06:00:00Z", text: longRequest,
note: "Only a learning review; expires at 2026-10-01T07:00:00Z."});
const compact = todoItemSchema.parse({...canonical, text: `${longRequest.slice(0, 217)}...`, note: null, evidence: null});
const compact = todoItemSchema.parse({...canonical, text: `${longRequest.slice(0, 217)}...`, note: null, evidence: null, created_by: null});
const joined = attentionDetailsFromSnapshot(compact, [canonical], row.goalId);
assert(joined.requestText === longRequest && joined.reason === canonical.note && joined.evidence === canonical.evidence, "same revision restores full display content");
assert(joined.interaction === "user_action" && joined.lifecycle === "open", "enrichment cannot reclassify a user action as a gate");
assert(joined.createdBy === "request-author", "same-snapshot content includes canonical author provenance");
const joinedMarkup = renderToStaticMarkup(createElement(WorkspaceI18nProvider, null,
createElement(AttentionDetailCard, {item: {...row, text: compact.text, details: joined}})));
assert(joinedMarkup.includes("Publish version 2.0 to stable only after acceptance.")
Expand All @@ -118,6 +124,7 @@ for (const candidates of [[], [canonical, canonical], [{...canonical, goal_id: "
const rejected = attentionDetailsFromSnapshot(compact, candidates, row.goalId);
assert(rejected.requestText === null && rejected.reason === null, "missing/conflicting details remain summary-only");
assert(rejected.lifecycle === "open" && rejected.interaction === "user_action", "failed enrichment preserves selected lifecycle and authority");
assert(rejected.createdBy === null, "a failed join cannot import another snapshot's creator");
}
const authoritySource = {...canonical, blocks_agent: "different-agent", decision_scope: {kind: "trade", granularity: "goal", scope_key: "different"}};
const displayOnly = attentionDetailsFromSnapshot(compact, [authoritySource], row.goalId);
Expand Down
Loading
Loading