mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-10 12:37:55 +01:00
test(evals): state team runtime fixture provenance accurately
Record original and effective package identities, distinguish preserved non-runtime fields from rewritten sidecar bytes, and document one-shot supervisor bootstrap with non-overwrite coverage. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
5dc8314e39
commit
c619ebbb7b
2 files changed
+23
-3
No files matched your search
@@ -18,10 +18,18 @@ it("serves a derived runtime-only catalog while preserving shipped roles, permis
|
||||
const result = await normalizeTeamRuntimeCatalog({ repositoryRoot, temporaryRoot, team, adapters });
|
||||
expect(result.originalContentHash).toBe(team.contentHash);
|
||||
expect(result.effectiveContentHash).not.toBe(team.contentHash);
|
||||
expect(result.originalPackage).toEqual({ id: team.id, key: team.key, packageName: original.packageName, version: original.packageVersion, contentHash: team.contentHash });
|
||||
expect(result.effectivePackage).toEqual({ ...result.originalPackage, contentHash: result.effectiveContentHash });
|
||||
expect(result.nonRuntimeFilesUnchanged).toBe(true);
|
||||
expect(result.nonRuntimeSidecarFieldsUnchanged).toBe(true);
|
||||
const sidecar = YAML.parse(await readFile(path.join(teamRuntimeCatalogRoot(temporaryRoot), team.path, ".paperclip.yaml"), "utf8"));
|
||||
expect(sidecar.agents.cto.permissions).toEqual({ canCreateAgents: true });
|
||||
for (const slug of team.agentSlugs) expect(sidecar.agents[slug].adapter).toEqual({ type: "paperclip_runner", config: adapterConfig });
|
||||
expect(result.team.requiredSkills).toEqual(team.requiredSkills);
|
||||
const sidecarPath = path.join(teamRuntimeCatalogRoot(temporaryRoot), team.path, ".paperclip.yaml");
|
||||
const beforeBootstrap = await readFile(sidecarPath);
|
||||
await expect(teamRuntimeCatalogServerEnvironment({ executionIds: ["chat-features.runner-opencode.local.teams.install-team"], temporaryRoot, repositoryRoot })).rejects.toThrow();
|
||||
expect((await readFile(sidecarPath)).equals(beforeBootstrap)).toBe(true);
|
||||
await expect(normalizeTeamRuntimeCatalog({ repositoryRoot, temporaryRoot, team: { ...team, contentHash: "foreign" }, adapters })).rejects.toThrow("exact unmodified");
|
||||
} finally { await rm(temporaryRoot, { recursive: true, force: true }); }
|
||||
});
|
||||
@@ -10,7 +10,11 @@ import { reviewedChatExecutionIds } from "../chat-runtime-profile.js";
|
||||
const selectedIds = reviewedChatExecutionIds("teams.install-team");
|
||||
export const teamRuntimeCatalogRoot = (temporaryRoot: string) => path.join(temporaryRoot, "team-runtime-catalog");
|
||||
|
||||
/** Only the disposable installer fixture uses this catalog and native default. */
|
||||
/** Only the disposable installer fixture uses this catalog and native default.
|
||||
* One-shot supervisor setup: server.ts constructs this environment once, and its
|
||||
* child-server restarts reuse it. Recreating the supervisor in the same attempt
|
||||
* root is unsupported and fails closed rather than replacing a normalized copy.
|
||||
*/
|
||||
export async function teamRuntimeCatalogServerEnvironment(input: { executionIds: string[]; temporaryRoot: string; repositoryRoot: string }) {
|
||||
if (!input.executionIds.some(id => selectedIds.includes(id))) return {};
|
||||
if (input.executionIds.length !== 1) throw new Error("Team runtime catalog requires its isolated execution");
|
||||
@@ -20,7 +24,7 @@ export async function teamRuntimeCatalogServerEnvironment(input: { executionIds:
|
||||
return { PAPERCLIP_TEAMS_CATALOG_DIR: target, PAPERCLIP_TEAMS_CATALOG_DEFAULT_ADAPTER_TYPE: "paperclip_runner" };
|
||||
}
|
||||
|
||||
/** Add runtime/account metadata only; all shipped team files remain byte-identical. */
|
||||
/** Add runtime/account metadata only; preserve other file bytes and non-runtime sidecar fields. */
|
||||
export async function normalizeTeamRuntimeCatalog(input: { temporaryRoot: string; repositoryRoot: string; team: CatalogTeam; adapters: Record<string, { adapterType: string; adapterConfig: Record<string, unknown> }> }) {
|
||||
const packageDir = teamRuntimeCatalogRoot(input.temporaryRoot);
|
||||
const original = JSON.parse(await readFile(path.join(input.repositoryRoot, "packages/teams-catalog/generated/catalog.json"), "utf8"));
|
||||
@@ -52,5 +56,13 @@ export async function normalizeTeamRuntimeCatalog(input: { temporaryRoot: string
|
||||
const withoutRuntime = (team: CatalogTeam) => ({ ...team, contentHash: "", fileCount: 0, files: team.files.filter(file => file.path !== ".paperclip.yaml") });
|
||||
if (!isDeepStrictEqual(withoutRuntime(effective), withoutRuntime(source)) || effective.contentHash === source.contentHash || built.manifest.teams.some(team => team.id !== source.id && !isDeepStrictEqual(team, original.teams.find((row: CatalogTeam) => row.id === team.id)))) throw new Error("Derived catalog changed non-runtime team metadata");
|
||||
await writeFile(path.join(packageDir, "generated/catalog.json"), JSON.stringify(built.manifest, null, 2) + "\n");
|
||||
return { originalContentHash: source.contentHash, effectiveContentHash: effective.contentHash, originalFilesUnchanged: true, team: effective };
|
||||
return {
|
||||
originalPackage: { id: source.id, key: source.key, packageName: original.packageName, version: original.packageVersion, contentHash: source.contentHash },
|
||||
effectivePackage: { id: effective.id, key: effective.key, packageName: built.manifest.packageName, version: built.manifest.packageVersion, contentHash: effective.contentHash },
|
||||
originalContentHash: source.contentHash,
|
||||
effectiveContentHash: effective.contentHash,
|
||||
nonRuntimeFilesUnchanged: true,
|
||||
nonRuntimeSidecarFieldsUnchanged: true,
|
||||
team: effective,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user