Skip to content

Commit 0103cb2

Browse files
test: use neutral references in chat hiring evals (#13752)
## Thinking Path > - Paperclip helps people manage agents and their work. > - The agent chat hiring eval checks delegation, saved output, and worker reuse. > - It asks a worker to include a unique reference in each document. > - The open wording let the worker choose a credential-style label. > - The existing redactor removed that reference and failed the coordination check. > - This PR specifies a neutral reference line while keeping the same grading checks. ## Linked Issues or Issue Description Refs #13741. **What happened?** The Codex hiring eval saved a checklist with `Tracking token: [REDACTED]`. The runner treats the chosen label as credential syntax. The previous prompt only asked for the identifier and did not choose its label. This tests a redaction boundary unrelated to hiring and reuse. **Expected behavior** The coordination fixture requests ordinary business content with a neutral reference label. The grader still requires the exact identifier in the saved output. **Steps to reproduce** Run `agent-chat-hardening.runner-codex.local.hire-delegate-reuse` with the previous fixture. The retained failing attempt is in [campaign 35617045456](https://github.com/paperclipai/paperclip/actions/runs/35617045456). ## What Changed - Request `Reference: ...` in the checklist and review documents. - Increment the hardening suite definition to version 5 and record the reference format. - Document the fixture boundary. Production redaction and all grading checks stay unchanged. ## Verification - `pnpm test:e2e:runner:typecheck` passed. - `pnpm test:e2e:runner:unit` passed: 424 tests in 37 files. - The catalog lists exactly the Codex and Claude local hiring cells for the selected case. - [Live campaign 35620731321](https://github.com/paperclipai/paperclip/actions/runs/35620731321) passed both selected local cells on `d8d7afe21`: native Codex (`gpt-5.6-sol`) and Claude (`claude-sonnet-5`). Both passed on attempt 1, including cleanup. [Published eval report](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-35620731321-1/). - Inspected saved evidence: each provider preserved both exact reference lines, used the same hired worker for checklist and review, and completed the final status query. Definition version 5 and hash `2c1c9f754c049c3e7cafd6c8d0a137e7ca06d546ce1e7b07ad5b7823f0f28db9` distinguish these results from the prior prompt. - [PR CI 35620741101](https://github.com/paperclipai/paperclip/actions/runs/35620741101): full build, type checks, and test partitions passed. One unrelated Telegram integration test initially failed because two random fixture company IDs produced the same seven-character issue prefix. The failed shard passed on one retry; no test code was changed. All latest-head merge checks are green. - Greptile reviewed `d8d7afe21` at 5/5 with no review threads. ## Risks The live models can still fail the coordination workflow. This change does not qualify or change credential-redaction policy. Earlier failed attempts remain part of the evidence; the new fixture has a distinct definition version. ## Model Used OpenAI Codex, GPT-6, with repository tools and code execution. The exact deployment model ID and context window are not exposed in this task. ## 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 - [x] All Paperclip CI gates are green - [x] 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>
1 parent 9d19f98 commit 0103cb2

3 files changed

Lines changed: 8 additions & 3 deletions

File tree

tests/runner-e2e/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ recorded separately. The suite uses production permission defaults and prompts.
161161
Only hiring and cross-task status/review enable the opt-in native API tools.
162162
Hiring uses a personal managed AI connection and verifies the hired worker's
163163
actual execution account. This is not an onboarding-default qualification.
164+
The hiring checklist and review request a `Reference: ...` line. This gives the
165+
fixture marker a neutral label instead of leaving the agent to choose credential
166+
syntax such as `Tracking token: ...`. Exact marker, authorship, worker reuse,
167+
and saved-output checks remain required. This case tests coordination, not
168+
credential-redaction policy.
164169

165170
Stop during startup and Stop during an active response are separate boundaries.
166171
The native active-response case requires a recorded provider turn start; generic

tests/runner-e2e/catalog.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ export const runnerSuites: readonly RunnerSuiteFixture[] = [
959959
environments: [localEnvironment, daytonaWarmEnvironment], tasks: chatHardeningTasks, expectedMatrixSize: 18,
960960
excludedExecutionIds: ["runner-codex", "runner-acpx-claude"].flatMap(profile =>
961961
["stop-startup-new-resume", "hire-delegate-reuse", "blocked-status-review"].map(task => `agent-chat-hardening.${profile}.daytona.${task}`)),
962-
definitionMetadata: { version: 4, permissions: "production-defaults", instructions: "production", grading: "durable-state-and-source-evidence", scheduling: "explicit-only", restartMemory: "required-after-restart", statusEvidence: "structured-current-blocker-and-active-run-count", readOnlyState: "public-mutation-contract-and-relations" },
962+
definitionMetadata: { version: 5, permissions: "production-defaults", instructions: "production", grading: "durable-state-and-source-evidence", scheduling: "explicit-only", restartMemory: "required-after-restart", statusEvidence: "structured-current-blocker-and-active-run-count", readOnlyState: "public-mutation-contract-and-relations", hiringReference: "neutral-document-reference-line" },
963963
},
964964
...(process.env.PAPERCLIP_RUNNER_E2E_CONNECTION_REVIEWS === "1" ? [connectionReviewSuite] : []),
965965
{

tests/runner-e2e/chat-hardening.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,15 +125,15 @@ export async function runChatHardeningFlow(context: {
125125
try {
126126
if (execution.task.id === "hire-delegate-reuse") {
127127
const hireName = `Morgan Reviewer ${nonce}`;
128-
await turn(`Hire exactly one teammate named ${hireName}, reporting to you, using your native runner, model, and available AI connection. Have that teammate write a concise launch checklist as a saved Paperclip document containing ${marker}. Put the work in one assigned task in ${project.name}. Link it here and let the teammate complete it.`, 2);
128+
await turn(`Hire exactly one teammate named ${hireName}, reporting to you, using your native runner, model, and available AI connection. Have that teammate write a concise launch checklist as a saved Paperclip document with the line "Reference: ${marker}". Put the work in one assigned task in ${project.name}. Link it here and let the teammate complete it.`, 2);
129129
const first = (await tasks())[0]!;
130130
expect(first).toBeTruthy();
131131
const firstOutput = await output(first.id, marker);
132132
const account = f.aiConnection!;
133133
const hired = assertChatHire({ agents: await agents(), leadId: f.agent.id, hireName,
134134
connectionId: account.connectionId, binding: account.binding, taskIds: [first.id], tasks: await tasks(), runs: await allRuns() });
135135
expect((firstOutput as Document).createdByAgentId).toBe(hired.id);
136-
await turn(`Have the existing ${hireName} review the checklist on ${first.identifier} and write a separate saved review document containing REVIEW${marker}. Create one review task in ${project.name}, assigned to that same teammate. Include the actual checklist in the handoff so they can review it. Preserve the original checklist and task.`, 4);
136+
await turn(`Have the existing ${hireName} review the checklist on ${first.identifier} and write a separate saved review document with the line "Reference: REVIEW${marker}". Create one review task in ${project.name}, assigned to that same teammate. Include the actual checklist in the handoff so they can review it. Preserve the original checklist and task.`, 4);
137137
const observed = await tasks();
138138
const second = observed.find(task => task.id !== first.id)!;
139139
expect(second).toBeTruthy();

0 commit comments

Comments
 (0)