mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-04 19:28:46 +01:00
## Thinking Path > - Paperclip manages agent work through tasks, projects, and routines. > - Daily QA must exercise the staging app through normal browser and API surfaces. > - A schedule must create real work and retain its result and history. > - Pausing that schedule must prevent the next invocation. > - The routine journey in #18652 passed in QA, while its separate completion journey has not passed. > - This PR delivers the routine test independently and preserves its measured flow and assertions. ## Linked Issues or Issue Description Refs: #18652. This is the routine-only delivery from that PR. The original completion implementation and its failed attempts remain on #18652. ## What Changed - Add the target-independent `routine-scheduled-run` journey with one native run and seven required checks. - Start from the measured routine source `ac4efb7c6f4782ea806661683c656fd2b4cc3189`. Keep its request, seven success assertions, one native-run limit, and 65-second pause check. - Bound each observed GET by the original remaining journey deadline. Preserve the normal API timeout for other callers. Keep the original routine error if final trigger disabling also fails, save a closed secondary receipt, and fail an otherwise successful journey when disabling fails. - Narrow the shared output-reader type to its one-argument GET capability without changing its runtime code. - Register only this case in the catalog, types, feature associations, dispatcher, and definition hash. Keep the strict catalog expectation in sync. - Retain the real Routines component controls and the existing project-flow coverage for the shared browser helper. - Document resource cleanup and the 65-second pause observation. Preserve the current routine map content. ## Verification - The original source passed [QA staging run 41567574185](https://pages.paperclip.ing/evals-qa-smoke-41567574185-1/). TestOps launch 1657 / result 3431 maps to case 718. All seven checks and five phases passed. One scheduler-bound native run, saved output attribution, the full pause window, and cleanup were verified. - Current source `8f62137f130f59fd3e39276e3d60185ddff24517` passed [fresh QA staging run 41582706162](https://pages.paperclip.ing/evals-qa-smoke-41582706162-1/) against Core `09162fe893b464dd2ccdafd14bd3ef1611202a86`. TestOps launch 1855. All seven checks, five phases, and all three workflow jobs passed. The run used one scheduler-bound native turn and observed 65.352 seconds after pause and completion. Canonical evidence collection and normal cleanup completed, with no active operations and the owned agent terminal. - This fresh pass covers the reviewed deadline and failure-reporting changes in the current source. The earlier ac4 pass and the byte-preserving b940 extraction remain historical records under their original conditions; neither failed attempts nor prior source conditions are regraded. - Causal controls: six assertions failed on the old behavior, then all 62 focused controls passed after the repair. Local: 834 related support tests, 41 shared chat/output-reader tests, and 26 unchanged real component controls passed. Runner E2E typecheck, recursive typecheck, build, maps, token gates, and `git diff --check` passed. The temporary output-reader type mismatch exposed by typecheck was corrected by narrowing the capability type. - The first restricted build/typecheck invocations failed because local tsx IPC was denied. A restricted support run also lacked the report CLI output. The same source passed with normal owned local IPC allowed; the original logs remain retained. - The original head's hosted e2e shard 2/8 failed at the unchanged mobile preference frame-count test: expected more than five frames, observed five. The cause is unknown. Its original log remains retained; it is not labeled a proven flake. No CI rerun was requested. - Current-head full CI run 41580423918, attempt 1, passed. The fresh review is 5/5 with zero unresolved threads. The broad local suite was not repeated. The earlier full local run recorded in #18643 had four failures and did not reach 164 serialized groups; this PR does not claim an all-local pass. - Prior failed routine attempts remain recorded. They exposed composer focus, collapsed schedule controls, pending browser events, and Markdown serialization problems. The measured later pass does not regrade those attempts. ## Risks - The shared browser-event helper also serves task creation and project creation. Its regression tests and existing consumers remain included. - The staging pass qualifies the captured source and configuration. The coordinator retains source merging, daily pinning, and plan selection. - The repository test and the unpassed completion test are not registered by this PR. ## Model Used OpenAI GPT-6 through Codex, with tool use and code execution. The exact deployment ID and context window are not exposed by 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 issue/PR references) --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
139 lines
8.3 KiB
TypeScript
139 lines
8.3 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(["product-journeys"], {
|
|
"routine-scheduled-run": ["routines/definition", "routines/triggers", "routines/history", "routines/management"],
|
|
"file-input-answer": ["documents-artifacts/attachments", "documents-artifacts/documents"],
|
|
"inbox-triage": ["inbox-search/views", "inbox-search/triage"], "task-create": ["tasks/create"], "ask-question": ["questions-and-approvals/questions"],
|
|
"question-answer-resume": ["questions-and-approvals/questions", "questions-and-approvals/continuation"],
|
|
"followup-while-running": ["steering/queue"],
|
|
"hire-delegate-reuse": ["agents/hire", "documents-artifacts/documents"],
|
|
"project-task-context": ["projects/lifecycle", "projects/task-context", "tasks/create"],
|
|
"task-properties": ["tasks/properties"], "task-document-persistence": ["documents-artifacts/documents"], "task-search-filter": ["tasks/organize"], "cloud-onboarding": ["onboarding/first-task"] });
|
|
associate(["antigravity-agent-journey"], {
|
|
"saved-subscription-two-turn": ["agents/hire", "agents/instructions", "runs-adapters/validation", "runs-adapters/session",
|
|
"tasks/create", "tasks/completion", "documents-artifacts/attachments", "documents-artifacts/work-products"],
|
|
});
|
|
associate(["core-compatibility", "openrouter-model-breadth", "extended-harnesses", "grok-qualification", "grok-subscription-qualification", "kimi-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", "kimi-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(["feedback-persistence"], {
|
|
"complaint-and-suggestion": ["activity/agent-commentary"],
|
|
});
|
|
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", "kimi-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(["kimi-qualification"], {
|
|
"file-edit-validate": ["documents-artifacts/work-products"],
|
|
"native-write-permission-stop": ["steering/stop-and-pause", "questions-and-approvals/tool-review"],
|
|
"native-write-provider-loss": ["recovery/diagnosis", "questions-and-approvals/tool-review"],
|
|
});
|
|
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))];
|
|
}
|