Files
PaperClipAI/tests/runner-e2e/chat-full-catalog-testops-manifest.test.mjs
T
DottaandPaperclip 48b57e0c94 test(evals): pin held scenario repairs and await Cloud return (#19188)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - Protected TestOps runs admit one immutable catalog source.
> - Three held scenario observers now have reviewed, locally qualified
repairs.
> - A separate Cloud recovery test started its heading wait before the
Cloud return.
> - This PR pins the qualified successor and corrects that test
boundary.
> - It changes no product behavior, model, execution budget, or private
evidence protocol.

## Linked Issues or Issue Description

Refs: #19155, #19093, #19095, #19112.

The next candidate retains the reviewed skill, company-secret, and
team-install observer repairs. It adds a narrow timeline v9 correction:
a recorded task identifier can be the subject of its actual
reassignment. The real timeline attempt remains failed; the diagnostic
correction is not a regrade or a new native pass. Earlier failed
attempts stay retained; a source pin and component tests do not
establish a native pass.

The Cloud recovery fixture failed both direct-task variants in the first
CI attempt of #19155. Its five-second heading check started before the
external Cloud roundtrip ended. The failure image already showed the
expected task shortly afterward. One unchanged local direct-task control
passed. The single authorized CI recovery also passed; this did not
establish a reliable boundary. This PR waits for one handoff and the
exact return URL before the original heading check.

## What Changed

- Pin source `5aef4bffa2b106f2066bf2485338798f04a702bd`, tree
`464be838a448c728d44e2d5593b9d7faea266663`.
- Update the two manifest target literals and expected pin test literal.
Bind the exact v9 descriptor snapshot and its one changed timeline
oracle leaf.
- Add the reviewed two-line Cloud return readiness witness. Keep the
original five-second heading assertion and existing overall test limit.
- Use descriptor
`744a566faaa90b8048fff526e0a30b7475b86c2de88d697783f8da9e02f70e20`. Keep
the launcher, all private helpers, 244 identities, requests, setup,
human/native counts, clocks, profile, model, retry policy, permissions,
and the 196/244 gate unchanged.

## Verification

- Current infrastructure worktree: **131 pin, admission, selection,
streaming, API, and reconciliation controls passed**.
- The fixture owner ran the exact patched Cloud spec: **all five real
auth cases passed** in 37.4s. A six-second Cloud hold passed the
unchanged heading check after return. Missing handoff and missing return
controls rejected. This PR's fresh master base is verified by
current-head CI, not credited from the earlier run.
- Fresh v9 source qualification: **268 focused timeline controls**, the
242-declaration gate, fresh server declarations, and full E2E typecheck
passed under local Node **26.4.0**. The preceding held-helper
qualification (239 Node controls and one offline Chromium route control)
remains evidence for the byte-identical unaffected helper closures. The
original browser sandbox failure is retained. Actual AWS Node and model
configuration remain unchanged.
- All 506 registered SDK input Git blobs and registry
`efa70621e9fb42aa185f7ee616a1a726aa3eccb367e67e28817cedf26ef2ade8` equal
the prior qualified source. No new SDK build or runtime refresh.
- All 75 private protocol files, production trees, YAML, lockfile,
launcher, identities, counts, clocks, and sourceFiles declarations equal
the prior source. Only the timeline descriptor oracle advances v8 to v9.
- Prior head `ce18f2bd52ed00ce750302f63aecc4167a3daff3` finished CI with
43 passed, one expected skip, four originating runner interruptions, and
a failed dependent verify aggregate. Two logs show runner shutdown
signals; two annotations show lost runner communication. No assertion
failure was observed. Those outcomes are retained; no unchanged recovery
was requested.
- Required fresh current-head CI, genuine review, thread clearance, and
Root's exact-diff acceptance are pending. No merge or new paid run is
authorized by this PR's publication.
- The earlier 3 PASS / 7 FAIL uniform attempt and all later original
outcomes remain unchanged. No new native pass or whole-catalog readiness
claim is made.

## Risks

The source remains a frozen candidate with unmerged catalog repairs. A
real measured run is still required. The readiness witness requires both
a real handoff and the exact task URL; it does not extend the heading
timeout, bypass auth, skip a case, or change production code. The active
measurement on the previous pin is not altered.

## Model Used

OpenAI GPT-6.1 (`gpt-6.1-sol`), with reasoning, code execution, and
repository tools. The host did not expose a context-window size.

## 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 for and linked related public PRs above
- [x] I have linked public PRs and described the issue
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change
- [x] Relevant local pin tests passed; source and fixture qualification
scope is stated above
- [x] I have updated the expected pin test and the observed fixture
boundary
- [x] Owning source metadata and this description document the change
- [x] I have considered and documented the risks
- [ ] All current-head infrastructure CI gates are green
- [ ] Greptile is 5/5 with no unresolved material findings
- [x] I will address reviewer comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-04 23:14:14 -06:00

369 lines
14 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { createHash } from 'node:crypto';
import { readFileSync, readdirSync } from 'node:fs';
import { createRequire } from 'node:module';
import { catalogTargetSha, catalogManifestSha256, fullCatalogPlanName, fullCatalogCases, validateFullCatalogManifest } from './chat-full-catalog-testops-manifest.mjs';
const { parseDocument } = createRequire(import.meta.url)('yaml');
const bytes = readFileSync(new URL('./chat-full-catalog-testops-manifest.json', import.meta.url));
const manifest = JSON.parse(bytes);
const row = id => fullCatalogCases.find(value => value.key === id);
test('the manifest joins all244 source YAML scenarios without importing a domain or fabricating a result', () => {
const directory = new URL('./chat-scenarios/', import.meta.url);
const scenarios = readdirSync(directory).filter(file => file.endsWith('.yaml') && file !== 'defaults.yaml').flatMap(file => {
const parsed = parseDocument(readFileSync(new URL(file, directory), 'utf8'), { uniqueKeys: true });
assert.deepEqual(parsed.errors, []);
return parsed.toJS().scenarios;
});
assert.equal(scenarios.length, 244);
assert.equal(fullCatalogCases.length, 244);
assert.deepEqual(fullCatalogCases.map(value => value.key).sort(), scenarios.map(value => value.id).sort());
for (const scenario of scenarios) {
const actual = row(scenario.id);
const override = field => manifest.source.repairMetadata.changedFields.find(change => change.key === scenario.id && change.field === field);
for (const [field, original] of [['originalQuery', scenario.query], ['originalContext', scenario.context], ['expectedOutcome', scenario.expected_outcome]]) {
const change = override(field);
if (change) { assert.equal(change.previous, original); assert.equal(actual[field], change.current); }
else assert.equal(actual[field], original);
}
assert.ok(!Object.hasOwn(actual, 'status') && !Object.hasOwn(actual, 'passed'));
}
});
test('legacy aliases preserve existing TestOps identities while execution uses actual legacy task IDs', () => {
for (const task of ['create-backlog', 'delegate-announcement']) {
const actual = row(`tasks.${task}`);
assert.equal(actual.scenario, task);
assert.equal(actual.executionId, `chat-features.runner-opencode.local.${task}`);
assert.equal(actual.fullName, `paperclip.Product E2E.chat-features.tasks.${task}`);
assert.deepEqual(actual.aliases, [`paperclip.Product E2E.chat-features.${task}`]);
}
});
test('source bounds retain legacy and pilot runs, native zero turn policy and original finite attempts', () => {
for (const [id, minimum, maximum, attempt, checks] of [
['tasks.create-backlog', 1, 1, 420000, 10], ['tasks.delegate-announcement', 3, 3, 420000, 15],
['instance-operations.restart-service', 1, 1, 420000, 9], ['projects.project-defaults', 3, 3, 660000, 11],
['projects.project-work', 1, 3, 300000, 15],
]) {
const actual = row(id);
assert.deepEqual([actual.minimumRuns, actual.maximumRuns, actual.attemptTimeoutMs, actual.checks], [minimum, maximum, attempt, checks]);
assert.equal(actual.turnTimeoutMs, id.startsWith('tasks.') ? 120000 : 0);
}
assert.equal(row('access.sign-in').maximumRuns, 0);
assert.equal(row('assistant-connections.use-scoped-client').maximumRuns, 0);
assert.equal(fullCatalogCases.filter(value => value.turnTimeoutMs === 0).length, 242);
});
test('definition gaps and private prerequisites remain explicit instead of inferred runnable passes', () => {
assert.deepEqual(fullCatalogCases.filter(value => value.coverageGaps.length).map(value => value.key), [
'access.invite-teammate', 'access.manage-membership', 'activity.routine-audit', 'agents.restore-instructions', 'budgets-costs.subscription-fees',
]);
assert.equal(fullCatalogCases.filter(value => value.requiredCredentials.length).length, 18);
assert.equal(fullCatalogCases.filter(value => value.externalInput !== null).length, 37);
assert.equal(row('skills.enable-for-agent').coverageGaps.length, 0);
});
test('surface evidence declarations never manufacture a generic final screenshot for boundary cases', () => {
assert.equal(row('agent-chat.chat-disabled').screenshot, 'runtime-disabled-agent-chat.png');
for (const id of ['access.sign-in', 'onboarding.choose-first-runtime', 'onboarding.new-instance', 'onboarding.resume-wizard', 'assistant-connections.use-scoped-client']) {
assert.equal(row(id).screenshot, null);
assert.match(row(id).evidenceReadiness, /requires-final-state\.png/);
}
assert.equal(row('projects.project-work').screenshot, 'final-state.png');
assert.ok(manifest.source.requiredOriginalPassEvidence.includes('final-state.png'));
});
test('source identities and descriptor provenance are stable, deeply frozen and deterministic', () => {
assert.equal(catalogTargetSha, manifest.targetSha);
assert.equal(catalogManifestSha256, createHash('sha256').update(bytes).digest('hex'));
assert.equal(fullCatalogPlanName, 'Chat feature catalog — OpenCode 1017 (candidate)');
assert.equal(new Set(fullCatalogCases.map(value => value.fullName)).size, 244);
assert.equal(manifest.source.scenarioFiles.length, 35);
assert.equal(manifest.metadataSourceSha, 'de0941835cc8f0d01c982574ee258e110babdbeb');
assert.throws(() => { fullCatalogCases[0].coverageGaps.push('changed'); }, TypeError);
assert.throws(() => { fullCatalogCases[0].maximumRuns = 999; }, TypeError);
assert.ok(!bytes.toString().match(/sk-or-v1-[a-f0-9]{32,}/));
});
test('foreign identity, duplicated case and changed run-bound metadata are rejected by the pure loader', () => {
const copy = () => structuredClone(manifest);
const foreign = copy(); foreign.cases[0].executionId = 'chat-features.other.local.case';
assert.throws(() => validateFullCatalogManifest(foreign), /row_invalid/);
const duplicate = copy(); duplicate.cases[1] = duplicate.cases[0];
assert.throws(() => validateFullCatalogManifest(duplicate), /identity_conflict/);
const bounds = copy(); bounds.cases[0].minimumRuns = bounds.cases[0].maximumRuns + 1;
assert.throws(() => validateFullCatalogManifest(bounds), /row_invalid/);
});
test('repair source metadata binds the corrected candidate and explicit changed definitions', () => {
const repair = manifest.source.repairMetadata;
assert.equal(repair.baseTargetSha, '3b66c3c144360ddf32714a0742fd774b8ceafb16');
assert.equal(repair.previousTargetSha, 'ab2019e976076ec0eb60b026844f3d9211cb0208');
assert.equal(manifest.targetSha, '5aef4bffa2b106f2066bf2485338798f04a702bd');
assert.equal(repair.definitionSourceSha, manifest.metadataSourceSha);
assert.equal(repair.candidateDescriptorSnapshot, 'fixtures/chat-repair-candidate-descriptors.json');
const descriptorBytes = readFileSync(new URL(repair.candidateDescriptorSnapshot, import.meta.url));
assert.equal(createHash('sha256').update(descriptorBytes).digest('hex'), repair.candidateDescriptorSha256);
const declarations = JSON.parse(descriptorBytes);
assert.equal(declarations.length, 242);
assert.equal(new Set(declarations.map(value => value.scenarioId)).size, 242);
assert.deepEqual(repair.changedFields.map(value => [value.key, value.field]), [
[
"activity.work-timeline",
"sourceFiles"
],
[
"activity.work-timeline",
"oracleVersion"
],
[
"activity.work-timeline",
"expectedOutcome"
],
[
"agents.choose-primary",
"sourceFiles"
],
[
"app-permissions.ask-before-action",
"sourceFiles"
],
[
"app-permissions.ask-before-action",
"oracleVersion"
],
[
"app-permissions.test-as-agent",
"sourceFiles"
],
[
"app-permissions.test-as-agent",
"oracleVersion"
],
[
"app-permissions.test-as-agent",
"originalContext"
],
[
"app-permissions.test-as-agent",
"expectedOutcome"
],
[
"cli-operations.choose-cli-context",
"sourceFiles"
],
[
"cli-operations.choose-cli-context",
"oracleVersion"
],
[
"companies.agent-observability",
"sourceFiles"
],
[
"companies.configure-decision-model",
"sourceFiles"
],
[
"companies.fast-responses",
"sourceFiles"
],
[
"companies.fast-responses",
"originalQuery"
],
[
"companies.prompt-injection-guard",
"sourceFiles"
],
[
"goals.create-goal-tree",
"oracleVersion"
],
[
"goals.create-goal-tree",
"expectedOutcome"
],
[
"navigation-preferences.dismiss-announcement",
"sourceFiles"
],
[
"navigation-preferences.dismiss-announcement",
"oracleVersion"
],
[
"questions-and-approvals.duplicate-answer",
"oracleVersion"
],
[
"questions-and-approvals.formal-hire-revision",
"sourceFiles"
],
[
"questions-and-approvals.formal-hire-revision",
"oracleVersion"
],
[
"questions-and-approvals.multi-part-question",
"oracleVersion"
],
[
"questions-and-approvals.reject-and-revise",
"sourceFiles"
],
[
"questions-and-approvals.reject-and-revise",
"oracleVersion"
],
[
"questions-and-approvals.review-plan",
"sourceFiles"
],
[
"questions-and-approvals.review-plan",
"oracleVersion"
],
[
"secrets.configure-company-secret",
"sourceFiles"
],
[
"secrets.configure-company-secret",
"oracleVersion"
],
[
"secrets.personal-secret",
"sourceFiles"
],
[
"secrets.personal-secret",
"oracleVersion"
],
[
"skills.author-skill",
"sourceFiles"
],
[
"skills.author-skill",
"oracleVersion"
],
[
"skills.author-skill",
"expectedOutcome"
],
[
"skills.enable-for-agent",
"sourceFiles"
],
[
"skills.explicit-restriction",
"sourceFiles"
],
[
"skills.find-and-install",
"sourceFiles"
],
[
"skills.fork-read-only",
"sourceFiles"
],
[
"skills.review-update",
"sourceFiles"
],
[
"skills.studio-test",
"sourceFiles"
],
[
"skills.studio-test",
"oracleVersion"
],
[
"skills.studio-test",
"maximumRuns"
],
[
"teams.configure-team",
"sourceFiles"
],
[
"teams.configure-team",
"oracleVersion"
],
[
"connection-setup.secure-api-key",
"oracleVersion"
],
[
"secrets.least-scope-delivery",
"oracleVersion"
],
[
"secrets.secret-proposal",
"oracleVersion"
],
[
"secrets.vault-reference",
"oracleVersion"
],
[
"teams.install-team",
"oracleVersion"
]
]);
for (const change of repair.changedFields) {
assert.deepEqual(row(change.key)[change.field], change.current);
assert.notDeepEqual(change.current, change.previous);
}
assert.equal(repair.descriptorChanges.length, 49);
assert.equal(new Set(repair.descriptorChanges.map(change => change.key)).size, 33);
assert.deepEqual([...new Set(repair.descriptorChanges.map(change => change.field))].sort(), ['expectedRunCount', 'minimumRunCount', 'oracleVersion', 'setupPolicy', 'sourceFiles']);
for (const change of repair.descriptorChanges) {
assert.notDeepEqual(change.current, change.previous);
const declaration = declarations.find(value => value.scenarioId === change.key);
assert.ok(declaration);
assert.deepEqual(change.current, declaration[change.field]);
if (Object.hasOwn(row(change.key), change.field)) assert.deepEqual(row(change.key)[change.field], change.current);
}
assert.deepEqual(repair.changedDefinitionFiles.map(value => value.path), [
'tests/runner-e2e/chat-scenarios/companies.yaml', 'tests/runner-e2e/chat-scenarios/goals.yaml', 'tests/runner-e2e/chat-scenarios/skills.yaml', 'tests/runner-e2e/chat-scenarios/app-permissions.yaml', 'tests/runner-e2e/chat-scenarios/activity.yaml',
]);
assert.ok(repair.changedDefinitionFiles.every(value => /^[a-f0-9]{64}$/.test(value.sha256)));
for (const declaration of declarations) {
const value = row(declaration.scenarioId);
assert.deepEqual(value.sourceFiles, declaration.sourceFiles);
assert.equal(value.oracleVersion, declaration.oracleVersion);
assert.equal(value.minimumRuns, declaration.minimumRunCount ?? declaration.expectedRunCount);
assert.equal(value.maximumRuns, declaration.expectedRunCount);
assert.equal(value.declaredTurnTimeoutMs, declaration.turnTimeoutMs);
assert.equal(value.attemptTimeoutMs, declaration.attemptTimeoutMs);
}
assert.deepEqual(repair.changedFields.filter(change => ['minimumRuns', 'maximumRuns'].includes(change.field)), [{ key: 'skills.studio-test', field: 'maximumRuns', previous: 2, current: 3 }]);
assert.deepEqual(repair.runtimeConditions.studio144Accounting, { key: 'skills.studio-test', previousMinimumRuns: 2, previousMaximumRuns: 2, minimumRuns: 2, maximumRuns: 3, requiredActualAcceptedRuns: 3, originalAttemptTimeoutMs: 540000, humanMessages: 1, condition: 'Initial CEO + real Studio worker + exactly one source-bound completion delivery;2-run no-delivery positive is rejected.' });
assert.equal(repair.runtimeConditions.toolGuidance106.corePRUnmerged, false);
assert.equal(repair.runtimeConditions.sdkPublicProof.scannerAndCanaryCertificatesUnchanged, true);
assert.equal(repair.runtimeConditions.sdkPublicProof.sourceInputsChanged, true);
assert.equal(repair.runtimeConditions.sdkPublicProof.registrySha256, "efa70621e9fb42aa185f7ee616a1a726aa3eccb367e67e28817cedf26ef2ade8");
assert.equal(repair.runtimeConditions.sdkPublicProof.plugin558StillHeld, true);
assert.equal(repair.runtimeConditions.sdkPublicProof.expectedLockSha256, "54a81b2ed3f1f85eaa085c034560ac248e384db34fbc7aba8c5a3846c29b3ce8");
assert.equal(repair.runtimeConditions.sdkPublicProof.runtimeCompilerParserZodIdentitiesUnchanged, true);
assert.equal(repair.runtimeConditions.toolProposal487.corePRUnmerged, false);
assert.deepEqual(repair.runtimeConditions.toolProposal487.replay, {
"corePR": 18742,
"coreHead": "61996a96dd09e90a5788e8711a94fc5ae631f425",
"corePRUnmerged": false,
"condition": "A new Ask-first request only for an authenticated later same-person human intent after the prior decline; same-intent retry and derived or foreign sources remain denied. No approval/execution authority change.",
"acceptedDirectSources": [
"issue.comment",
"issue.comment.reopen"
],
"actualPostAssertionPGCasesPassed": 2
});
});