mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-23 17:33:51 +02:00
## Thinking Path > - Paperclip is the open source app that people use to manage AI agents for work. > - Product E2E campaigns check user journeys across agent profiles and environments. > - Readers use the campaign history and reports to inspect results and retained evidence. > - The reports showed image summaries, many unselected suites, and a long sticky index. > - Individual case cards also showed routine diagnostics before the visual evidence. > - This pull request adds text summaries, feature filters, folding case indexes, and simpler cards. > - A local preview uses retained public data so designers can change reports without another paid campaign. ## Linked Issues or Issue Description **Current behavior** The report is hard to scan as the journey catalog grows. Suite links can point into hidden results. Case indexes do not show whether a case passed across its configurations. Design changes also need a realistic local preview. **Proposed behavior** Show the selected campaign as text. Link journeys to current feature-map capabilities. Add folding case indexes with status indicators, reliable section links, and a back-to-top control. Keep failed outcomes visible and put routine diagnostics under Test details. Render retained public campaign data with local templates. **Reason and benefit** Readers can find a feature or failed case faster. Designers can iterate against real retained data without starting an application instance or using provider credentials. **Breaking changes** No result schema or grading change. The report stops embedding the generated summary PNG. The publisher still produces that artifact for existing consumers. Related work: #12889 added the existing matrix browser. #12846 concerns the public image publication boundary. This PR changes report presentation and local preview behavior. ## What Changed - Replace image summaries with shared HTML suite summaries on the history and campaign pages. - Show selected executions and preserve missing results for selected cells. - Add explicit journey-to-capability associations, feature filters, and a coverage view with unmapped journeys. - Add folding case indexes, section case lists, and red, green, or amber status indicators across matching configurations. - Fix anchor navigation through filters and add a floating back-to-top control. - Simplify case cards. Keep failure reasons visible. Fold routine checks, billing, and context into Test details. - Add an original-image link to the gallery. - Add a local preview utility with public data caching and offline mode. Document the direct Node command. - Test manifest-listed evidence, rejection of unlisted files and encoded traversal, cache reuse, and offline misses with a real loopback server and a stub downloader. ## Verification - Focused report, history, and preview tests: 75 passed in 6 files. - Report Playwright spec: 4 passed in Chrome with a standalone config that does not start the application server. - `node scripts/check-maps.mjs`: passed. - `git diff --check`: passed. - Manually checked retained campaign reports, feature filters, folding indexes, failure links, card details, gallery links, mobile layout, and keyboard navigation. - `pnpm build`: passed. - `pnpm -r typecheck`: passed. - `pnpm test:e2e:runner:typecheck`: passed. - `pnpm test:run`: stopped after 15 native session database cases failed. The local Postgres package first lacked dynamic-library links. After link hydration, the same cases still failed. A direct `initdb` check then reported `could not create semaphores: No space left on device` and identified the macOS semaphore limit. The complete local suite has not passed. - `pnpm test:e2e:runner:unit`: 3,250 passed, 6 failed, 2 skipped. All six failures reproduced against unchanged `origin/master` report sources with the same installed dependencies. They concern Copilot admission and its Daytona image input, plus the launcher test that runs those assertions. No report or history test failed. - No live provider evaluation was run for this presentation change. - CI on `b1a9c06823` first failed browser shard 3/8. The agent-chat split-handoff test reached cleanup, where cancelling a run returned HTTP 500 from a Postgres deadlock. Cleanup did not restore the experiment setting, and a later test failed its initial setting check. This shard does not contain the report spec. One targeted rerun passed, and that full workflow then passed. This shows recovery; no production fix was made for the deadlock. The later preview-test commit requires its own fresh checks. To review the design, run `node --watch --import ./cli/node_modules/tsx/dist/loader.mjs tests/runner-e2e/preview.ts`. Open the history address printed by the command, then open a campaign. The README covers offline mode and cache refresh. ## Risks - Feature associations use the current map. They describe linked scenarios, not proof that a whole capability is covered. Historical grades remain unchanged. - New or unfamiliar cases remain unmapped until their assertions are inspected. - The preview needs the public history host on first access. Offline mode requires cached files. It binds to the loopback interface and serves manifest-listed public evidence. - Hiding routine diagnostics adds one disclosure step. Failed or incomplete outcomes remain visible. This is report polish. It does not duplicate planned core work in `ROADMAP.md`. ## Model Used OpenAI Codex, GPT-6 family, with reasoning, tool use, code execution, and browser automation. The exact serving model ID and context window are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
118 lines
6.6 KiB
TypeScript
118 lines
6.6 KiB
TypeScript
import { fileURLToPath } from "node:url";
|
|
import { featureIndex } from "../../scripts/feature-map.mjs";
|
|
import type { ReportExecution } from "./report-catalog.js";
|
|
|
|
export const journeyFeatureMap = featureIndex(fileURLToPath(new URL("../../", import.meta.url)));
|
|
export const journeyFeatures = journeyFeatureMap.sections.flatMap((section) =>
|
|
section.features.map((feature) => ({ ...feature, section: section.title })),
|
|
);
|
|
const capabilities = new Map(journeyFeatures.flatMap((feature) =>
|
|
feature.capabilities.map((capability) => [capability.id, { ...capability, feature }] as const),
|
|
));
|
|
const associations = new Map<string, readonly string[]>();
|
|
|
|
function associate(suites: readonly string[], cases: Record<string, readonly string[]>) {
|
|
for (const [caseId, ids] of Object.entries(cases)) {
|
|
for (const id of ids) if (!capabilities.has(id)) throw new Error(`Unknown journey capability: ${id}`);
|
|
for (const suite of suites) associations.set(`${suite}/${caseId}`, ids);
|
|
}
|
|
}
|
|
|
|
associate(["core-compatibility", "openrouter-model-breadth", "extended-harnesses", "grok-qualification", "grok-subscription-qualification"], {
|
|
"message-marker": ["runs-adapters/runs"],
|
|
"hello-complete": ["runs-adapters/runs"],
|
|
"plan-revise-accept": ["questions-and-approvals/plan-review"],
|
|
"plan-approve-complete": ["questions-and-approvals/plan-review"],
|
|
"ask-question": ["questions-and-approvals/questions"],
|
|
"question-resume-complete": ["questions-and-approvals/questions", "questions-and-approvals/continuation"],
|
|
});
|
|
associate(["local-session-integrity", "extended-harnesses", "grok-qualification", "grok-subscription-qualification"], {
|
|
"structured-question-resume": ["questions-and-approvals/continuation", "runs-adapters/session"],
|
|
"structured-question-restart-resume": ["questions-and-approvals/continuation", "runs-adapters/session"],
|
|
});
|
|
associate(["question-resume"], {
|
|
"question-answer-resume": ["questions-and-approvals/questions", "questions-and-approvals/continuation"],
|
|
});
|
|
associate(["continuation"], {
|
|
"answer-updates-scope": ["questions-and-approvals/questions", "questions-and-approvals/continuation"],
|
|
"clarification-not-approval": ["questions-and-approvals/questions", "questions-and-approvals/confirmations"],
|
|
"revision-preserves-approval": ["questions-and-approvals/plan-review"],
|
|
"completed-action-resume": ["questions-and-approvals/continuation"],
|
|
"question-tool-documentation": ["questions-and-approvals/questions"],
|
|
"provider-question-bridge": ["questions-and-approvals/questions", "questions-and-approvals/continuation"],
|
|
});
|
|
associate(["first-task", "confirmation-replies", "completion-updates"], Object.fromEntries([
|
|
"interview-first-response", "clear-task-first-response", "ambiguous-task-first-response",
|
|
"plain-message-first-response", "plan-first-response", "interview-plan-accept",
|
|
"task-card-accept", "accept-while-running", "task-reply-accept", "clarify-propose-accept",
|
|
"revise-accept", "reject-no-execution",
|
|
].map((id) => [id, ["onboarding/first-task"]])));
|
|
associate(["first-task"], { "ordinary-task-control": ["tasks/completion"] });
|
|
associate(["confirmation-replies"], {
|
|
"confirmation-ambiguous": ["questions-and-approvals/confirmations", "questions-and-approvals/audience"],
|
|
"unanswered-question-return": ["questions-and-approvals/dismiss-and-reopen", "questions-and-approvals/continuation"],
|
|
});
|
|
associate(["agent-chat", "agent-chat-hardening", "grok-qualification", "grok-subscription-qualification", "stock-harness"], {
|
|
"create-backlog": ["tasks/create"],
|
|
"reassign-task": ["tasks/properties"],
|
|
"continuity-restart": ["agent-chat/history", "runs-adapters/session"],
|
|
"new-session": ["agent-chat/history", "runs-adapters/session"],
|
|
"stop-new-resume": ["steering/stop-and-pause", "runs-adapters/session"],
|
|
"stop-startup-new-resume": ["steering/stop-and-pause", "runs-adapters/session"],
|
|
"plan-handoff": ["agent-chat/handoff", "questions-and-approvals/plan-review"],
|
|
"clarify-reuse": ["projects/task-context"],
|
|
"multi-repository": ["projects/repositories"],
|
|
"hire-delegate-reuse": ["agents/hire", "task-coordination/delegation"],
|
|
"committed-send-retry": ["recovery/unknown-outcome"],
|
|
});
|
|
associate(["agent-chat-qualification"], {
|
|
"active-reassignment": ["tasks/properties"],
|
|
"worker-crash-retry": ["recovery/source-action"],
|
|
});
|
|
associate(["agent-chat-stories"], {
|
|
"enable-disable-resume": ["agent-chat/history"],
|
|
"followup-while-running": ["steering/queue"],
|
|
"revise-while-running": ["steering/steer"],
|
|
});
|
|
associate(["completion-updates"], Object.fromEntries([
|
|
"handoff-completion-idle", "handoff-completion-busy", "handoff-completion-multiple", "handoff-completion-restart",
|
|
].map((id) => [id, ["agent-chat/handoff", "tasks/completion"]])));
|
|
associate(["everyday-workflows", "native-connection-guidance", "grok-qualification", "grok-subscription-qualification"], {
|
|
"build-revise": ["documents-artifacts/work-products"],
|
|
"delegate-feedback": ["task-coordination/delegation", "steering/steer"],
|
|
"agent-review-handoff": ["task-coordination/signoff"],
|
|
"hire-reuse": ["agents/hire", "task-coordination/delegation"],
|
|
"service-approve": ["questions-and-approvals/tool-review", "app-permissions/action-policy"],
|
|
"service-decline": ["questions-and-approvals/tool-review", "app-permissions/action-policy"],
|
|
"connection-decline": ["connection-setup/task-request"],
|
|
"provider-decline": ["connection-setup/task-request"],
|
|
"provider-second": ["connection-setup/task-request"],
|
|
"provider-native": ["connection-setup/task-request"],
|
|
"agentmail-setup": ["connection-setup/task-request"],
|
|
"recover-controller": ["recovery/user-continuation", "documents-artifacts/work-products"],
|
|
"stop-redirect": ["steering/stop-and-pause"],
|
|
"create-skill-studio": ["skills/authoring"],
|
|
});
|
|
associate(["hiring-templates"], { "hire-coder-template-reuse": ["agents/hire", "task-coordination/delegation"] });
|
|
associate(["task-workspaces"], {
|
|
"task-directory-repository-resume": ["workspaces/binding", "workspaces/provisioning", "projects/repositories"],
|
|
});
|
|
associate(["task-titles"], {
|
|
"prompt-title-standard": ["tasks/create"],
|
|
"prompt-title-ask": ["tasks/create"],
|
|
"preserve-explicit-title": ["tasks/create"],
|
|
});
|
|
associate(["pi-controls", "native-active-stop"], {
|
|
"pending-permission-stop": ["steering/stop-and-pause"],
|
|
"same-turn-steering": ["steering/steer"],
|
|
});
|
|
|
|
export function journeyCapabilities(execution: Pick<ReportExecution, "suite" | "task">) {
|
|
return (associations.get(`${execution.suite.id}/${execution.task.id}`) ?? [])
|
|
.map((id) => capabilities.get(id)!);
|
|
}
|
|
|
|
export function journeyFeatureIds(execution: Pick<ReportExecution, "suite" | "task">) {
|
|
return [...new Set(journeyCapabilities(execution).map((capability) => capability.feature.id))];
|
|
}
|