mirror of
https://github.com/openclaw/clawhub.git
synced 2026-08-14 00:47:57 +00:00
test: resume interrupted CLAW-603 Test proof
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
name: CLAW-603 Permanent Test Claim and Native Proof
|
||||
name: CLAW-603 One-Time Permanent Test Claim Recovery
|
||||
|
||||
# Branch-only operator proof. This file is never merged; main retains the hourly production sync.
|
||||
# Branch-only continuation of interrupted proof run 30608116457. This file is never merged;
|
||||
# main retains the hourly production sync.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
confirm_recovery:
|
||||
description: Type resume-30608116457 to continue the exact interrupted Test proof
|
||||
required: true
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
group: claw-603-permanent-test-proof
|
||||
@@ -16,14 +22,15 @@ jobs:
|
||||
if: >-
|
||||
github.ref == 'refs/heads/pe/claw-603-final-proof' &&
|
||||
github.actor == 'Patrick-Erichsen' &&
|
||||
github.triggering_actor == 'Patrick-Erichsen'
|
||||
github.triggering_actor == 'Patrick-Erichsen' &&
|
||||
inputs.confirm_recovery == 'resume-30608116457'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
environment:
|
||||
name: Test
|
||||
env:
|
||||
CONVEX_DEPLOY_KEY: ${{ secrets.CONVEX_DEPLOY_KEY }}
|
||||
DEPLOY_SHA: c1f6ba2f07b5fc084a31286a54e23e7bce404780
|
||||
DEPLOY_SHA: 73eb44cd70ff6c2759e5cf4748a84c7a8949a37f
|
||||
EXPECTED_CATALOG_SCAN_ATTEMPTS: 9
|
||||
EXPECTED_NATIVE_SCAN_JOBS: 16
|
||||
EXPECTED_NATIVE_SCAN_UPDATED_AT_SUM: 28554932587800
|
||||
@@ -200,6 +207,17 @@ jobs:
|
||||
.scanAdmissionEnabled == false
|
||||
' proof/claw-603/claim-control-enabled.json >/dev/null
|
||||
|
||||
CLAWHUB_CLAIM_PROOF_OUTPUT="proof/claw-603/claim-lifecycle.json" \
|
||||
bun scripts/skills-sh-catalog/claw-603-claim-recovery.ts \
|
||||
> proof/claw-603/claim-lifecycle-stdout.json
|
||||
jq -e '
|
||||
.ok == true and
|
||||
.target.productionWrites == 0 and
|
||||
.paidScans == 0 and
|
||||
.scansPlanned == 0 and
|
||||
.scansAdmitted == 0
|
||||
' proof/claw-603/claim-lifecycle.json >/dev/null
|
||||
|
||||
post_mirror \
|
||||
'{"operation":"verify-activate","reason":"CLAW-603 permanent Test claim precondition"}' \
|
||||
proof/claw-603/claim-activation.json
|
||||
@@ -210,16 +228,6 @@ jobs:
|
||||
.trendingSnapshot.status == "ready"
|
||||
' proof/claw-603/claim-activation.json >/dev/null
|
||||
|
||||
bun scripts/skills-sh-catalog/claw-603-claim-proof.ts \
|
||||
> proof/claw-603/claim-lifecycle-stdout.json
|
||||
jq -e '
|
||||
.ok == true and
|
||||
.target.productionWrites == 0 and
|
||||
.paidScans == 0 and
|
||||
.scansPlanned == 0 and
|
||||
.scansAdmitted == 0
|
||||
' proof/claw-603/claim-lifecycle.json >/dev/null
|
||||
|
||||
native_skill_id="$(
|
||||
jq -r '
|
||||
.restoration.restoredSource.skills[] |
|
||||
@@ -353,14 +361,15 @@ jobs:
|
||||
always() &&
|
||||
github.ref == 'refs/heads/pe/claw-603-final-proof' &&
|
||||
github.actor == 'Patrick-Erichsen' &&
|
||||
github.triggering_actor == 'Patrick-Erichsen'
|
||||
github.triggering_actor == 'Patrick-Erichsen' &&
|
||||
inputs.confirm_recovery == 'resume-30608116457'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
environment:
|
||||
name: Test
|
||||
env:
|
||||
CONVEX_DEPLOY_KEY: ${{ secrets.CONVEX_DEPLOY_KEY }}
|
||||
DEPLOY_SHA: c1f6ba2f07b5fc084a31286a54e23e7bce404780
|
||||
DEPLOY_SHA: 73eb44cd70ff6c2759e5cf4748a84c7a8949a37f
|
||||
EXPECTED_CATALOG_SCAN_ATTEMPTS: 9
|
||||
EXPECTED_NATIVE_SCAN_JOBS: 16
|
||||
EXPECTED_NATIVE_SCAN_UPDATED_AT_SUM: 28554932587800
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
assertControlledMirrorRecoveryMetadata,
|
||||
assertControlledProofBookmark,
|
||||
buildControlledCandidateContent,
|
||||
classifyClaimRecoveryState,
|
||||
} from "./claw-603-claim-proof-helpers";
|
||||
|
||||
describe("CLAW-603 claim proof candidate content", () => {
|
||||
it("binds cached markdown to the exact controlled candidate after validating the pinned file hash", () => {
|
||||
const content = "# HTML\n";
|
||||
const result = buildControlledCandidateContent({
|
||||
mirror: {
|
||||
digest: {
|
||||
externalId: "patrick-erichsen/skills/html",
|
||||
slug: "html",
|
||||
displayName: "HTML",
|
||||
githubPath: "skills/html",
|
||||
},
|
||||
detail: {
|
||||
path: "skills/html/SKILL.md",
|
||||
content,
|
||||
},
|
||||
},
|
||||
expectedExternalId: "patrick-erichsen/skills/html",
|
||||
expectedPath: "skills/html",
|
||||
expectedFileHash: "50361c318c6720f33fe0e061bd4bc97e0fcc7d135b676701a9a2ef626e830339",
|
||||
candidateCommit: "a".repeat(40),
|
||||
candidateContentHash: "b".repeat(64),
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
slug: "html",
|
||||
displayName: "HTML",
|
||||
path: "skills/html",
|
||||
skillMarkdownPath: "skills/html/SKILL.md",
|
||||
skillMarkdown: content,
|
||||
contentHash: "b".repeat(64),
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects markdown that is not the exact pinned controlled source", () => {
|
||||
expect(() =>
|
||||
buildControlledCandidateContent({
|
||||
mirror: {
|
||||
digest: {
|
||||
externalId: "patrick-erichsen/skills/html",
|
||||
slug: "html",
|
||||
displayName: "HTML",
|
||||
githubPath: "skills/html",
|
||||
},
|
||||
detail: {
|
||||
path: "skills/html/SKILL.md",
|
||||
content: "# changed\n",
|
||||
},
|
||||
},
|
||||
expectedExternalId: "patrick-erichsen/skills/html",
|
||||
expectedPath: "skills/html",
|
||||
expectedFileHash: "50361c318c6720f33fe0e061bd4bc97e0fcc7d135b676701a9a2ef626e830339",
|
||||
candidateCommit: "a".repeat(40),
|
||||
candidateContentHash: "b".repeat(64),
|
||||
}),
|
||||
).toThrow("controlled candidate markdown hash mismatch");
|
||||
});
|
||||
|
||||
it("requires every replayed mirror field to match the captured recovery fixture", () => {
|
||||
const mirror = {
|
||||
digest: {
|
||||
externalId: "patrick-erichsen/skills/html",
|
||||
sourceType: "github",
|
||||
upstreamSourceType: "controlled-github",
|
||||
owner: "patrick-erichsen",
|
||||
repo: "skills",
|
||||
slug: "html",
|
||||
displayName: "HTML",
|
||||
sourceUrl: "https://www.skills.sh/patrick-erichsen/skills/html",
|
||||
canonicalRepoUrl: "https://github.com/patrick-erichsen/skills",
|
||||
githubPath: "skills/html",
|
||||
upstreamInstalls: 123,
|
||||
upstreamScanners: { socket: { status: "unavailable" } },
|
||||
inferredCategories: ["other"],
|
||||
inferredTopics: [],
|
||||
inferredCategoryConfidence: "low",
|
||||
inferredTopicConfidence: "low",
|
||||
inferredClassifierVersion: "taxonomy-v1",
|
||||
inferredTopicClassifierVersion: "topic-v1",
|
||||
inferredInputHash: "input",
|
||||
inferredTopicInputHash: "topic-input",
|
||||
inferredAt: 1234,
|
||||
},
|
||||
detail: {
|
||||
contentKind: "skill-md",
|
||||
path: "skills/html/SKILL.md",
|
||||
content: "# HTML\n",
|
||||
contentBytes: 7,
|
||||
sourceBytes: 7,
|
||||
sourceFileCount: 1,
|
||||
truncated: false,
|
||||
},
|
||||
};
|
||||
const expected = {
|
||||
digest: { ...mirror.digest },
|
||||
detail: {
|
||||
contentKind: "skill-md",
|
||||
path: "skills/html/SKILL.md",
|
||||
contentSha256: "50361c318c6720f33fe0e061bd4bc97e0fcc7d135b676701a9a2ef626e830339",
|
||||
contentBytes: 7,
|
||||
sourceBytes: 7,
|
||||
sourceFileCount: 1,
|
||||
truncated: false,
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => assertControlledMirrorRecoveryMetadata({ mirror, expected })).not.toThrow();
|
||||
expect(() =>
|
||||
assertControlledMirrorRecoveryMetadata({
|
||||
mirror: {
|
||||
...mirror,
|
||||
digest: { ...mirror.digest, upstreamInstalls: 124 },
|
||||
},
|
||||
expected,
|
||||
}),
|
||||
).toThrow("controlled mirror recovery metadata mismatch");
|
||||
});
|
||||
|
||||
it("accepts only the exact Bookmark created by the interrupted proof", () => {
|
||||
const expected = {
|
||||
id: "stars:proof",
|
||||
skillId: "skills:html",
|
||||
userId: "users:owner",
|
||||
createdAt: 1234,
|
||||
hourlyStatsRecordedAt: 1234,
|
||||
};
|
||||
|
||||
expect(() =>
|
||||
assertControlledProofBookmark({
|
||||
star: {
|
||||
_id: "stars:proof",
|
||||
skillId: "skills:html",
|
||||
userId: "users:owner",
|
||||
createdAt: 1234,
|
||||
hourlyStatsRecordedAt: 1234,
|
||||
},
|
||||
expected,
|
||||
currentSkillStars: 1,
|
||||
baselineSkillStars: 0,
|
||||
}),
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
assertControlledProofBookmark({
|
||||
star: {
|
||||
_id: "stars:someone-else",
|
||||
skillId: "skills:html",
|
||||
userId: "users:owner",
|
||||
createdAt: 1234,
|
||||
hourlyStatsRecordedAt: 1234,
|
||||
},
|
||||
expected,
|
||||
currentSkillStars: 1,
|
||||
baselineSkillStars: 0,
|
||||
}),
|
||||
).toThrow("controlled proof Bookmark does not match the interrupted proof");
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
expected: "candidate-pending",
|
||||
mirrorCommit: "b",
|
||||
nativeCommit: "b",
|
||||
pendingCandidate: true,
|
||||
proofBookmark: true,
|
||||
},
|
||||
{
|
||||
expected: "native-restored",
|
||||
mirrorCommit: "b",
|
||||
nativeCommit: "a",
|
||||
pendingCandidate: false,
|
||||
proofBookmark: true,
|
||||
},
|
||||
{
|
||||
expected: "mirror-restored-candidate-pending",
|
||||
mirrorCommit: "a",
|
||||
nativeCommit: "b",
|
||||
pendingCandidate: true,
|
||||
proofBookmark: true,
|
||||
},
|
||||
{
|
||||
expected: "mirror-restored",
|
||||
mirrorCommit: "a",
|
||||
nativeCommit: "a",
|
||||
pendingCandidate: false,
|
||||
proofBookmark: true,
|
||||
},
|
||||
{
|
||||
expected: "complete",
|
||||
mirrorCommit: "a",
|
||||
nativeCommit: "a",
|
||||
pendingCandidate: false,
|
||||
proofBookmark: false,
|
||||
},
|
||||
])("recognizes the retry-safe recovery phase $expected", (fixture) => {
|
||||
expect(
|
||||
classifyClaimRecoveryState({
|
||||
...fixture,
|
||||
restoredCommit: "a",
|
||||
contaminatingCommit: "b",
|
||||
}),
|
||||
).toBe(fixture.expected);
|
||||
});
|
||||
|
||||
it("rejects recovery state outside the exact monotonic path", () => {
|
||||
expect(() =>
|
||||
classifyClaimRecoveryState({
|
||||
mirrorCommit: "b",
|
||||
nativeCommit: "a",
|
||||
pendingCandidate: true,
|
||||
proofBookmark: true,
|
||||
restoredCommit: "a",
|
||||
contaminatingCommit: "b",
|
||||
}),
|
||||
).toThrow("controlled claim recovery state is not resumable");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,234 @@
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
type ControlledMirrorState = {
|
||||
digest?: {
|
||||
externalId?: string;
|
||||
sourceType?: string;
|
||||
upstreamSourceType?: string;
|
||||
owner?: string;
|
||||
repo?: string;
|
||||
slug?: string;
|
||||
displayName?: string;
|
||||
sourceUrl?: string;
|
||||
canonicalRepoUrl?: string;
|
||||
githubPath?: string;
|
||||
upstreamInstalls?: number;
|
||||
upstreamScanners?: unknown;
|
||||
inferredCategories?: unknown;
|
||||
inferredTopics?: unknown;
|
||||
inferredCategoryConfidence?: string;
|
||||
inferredTopicConfidence?: string;
|
||||
inferredClassifierVersion?: string;
|
||||
inferredTopicClassifierVersion?: string;
|
||||
inferredInputHash?: string;
|
||||
inferredTopicInputHash?: string;
|
||||
inferredAt?: number;
|
||||
summary?: string;
|
||||
};
|
||||
detail?: {
|
||||
contentKind?: string;
|
||||
path?: string;
|
||||
content?: string;
|
||||
contentBytes?: number;
|
||||
sourceBytes?: number;
|
||||
sourceFileCount?: number;
|
||||
truncated?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
type ControlledMirrorRecoveryMetadata = {
|
||||
digest: {
|
||||
externalId: unknown;
|
||||
sourceType: unknown;
|
||||
upstreamSourceType: unknown;
|
||||
owner: unknown;
|
||||
repo: unknown;
|
||||
slug: unknown;
|
||||
displayName: unknown;
|
||||
sourceUrl: unknown;
|
||||
canonicalRepoUrl: unknown;
|
||||
githubPath: unknown;
|
||||
upstreamInstalls: unknown;
|
||||
upstreamScanners: unknown;
|
||||
inferredCategories: unknown;
|
||||
inferredTopics: unknown;
|
||||
inferredCategoryConfidence: unknown;
|
||||
inferredTopicConfidence: unknown;
|
||||
inferredClassifierVersion: unknown;
|
||||
inferredTopicClassifierVersion: unknown;
|
||||
inferredInputHash: unknown;
|
||||
inferredTopicInputHash: unknown;
|
||||
inferredAt: unknown;
|
||||
};
|
||||
detail: {
|
||||
contentKind: unknown;
|
||||
path: unknown;
|
||||
contentSha256: string;
|
||||
contentBytes: unknown;
|
||||
sourceBytes: unknown;
|
||||
sourceFileCount: unknown;
|
||||
truncated: unknown;
|
||||
};
|
||||
};
|
||||
|
||||
export function assertControlledMirrorRecoveryMetadata(args: {
|
||||
mirror: ControlledMirrorState;
|
||||
expected: ControlledMirrorRecoveryMetadata;
|
||||
}) {
|
||||
const { digest, detail } = args.mirror;
|
||||
if (!digest || !detail || typeof detail.content !== "string") {
|
||||
throw new Error("controlled mirror recovery metadata is incomplete");
|
||||
}
|
||||
const actual: ControlledMirrorRecoveryMetadata = {
|
||||
digest: {
|
||||
externalId: digest.externalId,
|
||||
sourceType: digest.sourceType,
|
||||
upstreamSourceType: digest.upstreamSourceType,
|
||||
owner: digest.owner,
|
||||
repo: digest.repo,
|
||||
slug: digest.slug,
|
||||
displayName: digest.displayName,
|
||||
sourceUrl: digest.sourceUrl,
|
||||
canonicalRepoUrl: digest.canonicalRepoUrl,
|
||||
githubPath: digest.githubPath,
|
||||
upstreamInstalls: digest.upstreamInstalls,
|
||||
upstreamScanners: digest.upstreamScanners,
|
||||
inferredCategories: digest.inferredCategories,
|
||||
inferredTopics: digest.inferredTopics,
|
||||
inferredCategoryConfidence: digest.inferredCategoryConfidence,
|
||||
inferredTopicConfidence: digest.inferredTopicConfidence,
|
||||
inferredClassifierVersion: digest.inferredClassifierVersion,
|
||||
inferredTopicClassifierVersion: digest.inferredTopicClassifierVersion,
|
||||
inferredInputHash: digest.inferredInputHash,
|
||||
inferredTopicInputHash: digest.inferredTopicInputHash,
|
||||
inferredAt: digest.inferredAt,
|
||||
},
|
||||
detail: {
|
||||
contentKind: detail.contentKind,
|
||||
path: detail.path,
|
||||
contentSha256: createHash("sha256").update(detail.content).digest("hex"),
|
||||
contentBytes: detail.contentBytes,
|
||||
sourceBytes: detail.sourceBytes,
|
||||
sourceFileCount: detail.sourceFileCount,
|
||||
truncated: detail.truncated,
|
||||
},
|
||||
};
|
||||
if (JSON.stringify(actual) !== JSON.stringify(args.expected)) {
|
||||
throw new Error("controlled mirror recovery metadata mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
export function assertControlledProofBookmark(args: {
|
||||
star: {
|
||||
_id?: string;
|
||||
skillId?: string;
|
||||
userId?: string;
|
||||
createdAt?: number;
|
||||
hourlyStatsRecordedAt?: number;
|
||||
} | null;
|
||||
expected: {
|
||||
id: string;
|
||||
skillId: string;
|
||||
userId: string;
|
||||
createdAt: number;
|
||||
hourlyStatsRecordedAt: number;
|
||||
};
|
||||
currentSkillStars: number;
|
||||
baselineSkillStars: number;
|
||||
}) {
|
||||
const { star, expected } = args;
|
||||
if (
|
||||
!star ||
|
||||
star._id !== expected.id ||
|
||||
star.skillId !== expected.skillId ||
|
||||
star.userId !== expected.userId ||
|
||||
star.createdAt !== expected.createdAt ||
|
||||
star.hourlyStatsRecordedAt !== expected.hourlyStatsRecordedAt ||
|
||||
args.currentSkillStars !== args.baselineSkillStars + 1
|
||||
) {
|
||||
throw new Error("controlled proof Bookmark does not match the interrupted proof");
|
||||
}
|
||||
}
|
||||
|
||||
export function classifyClaimRecoveryState(args: {
|
||||
mirrorCommit: string;
|
||||
nativeCommit: string;
|
||||
pendingCandidate: boolean;
|
||||
proofBookmark: boolean;
|
||||
restoredCommit: string;
|
||||
contaminatingCommit: string;
|
||||
}) {
|
||||
if (
|
||||
args.mirrorCommit === args.contaminatingCommit &&
|
||||
args.nativeCommit === args.contaminatingCommit &&
|
||||
args.pendingCandidate &&
|
||||
args.proofBookmark
|
||||
) {
|
||||
return "candidate-pending" as const;
|
||||
}
|
||||
if (
|
||||
args.mirrorCommit === args.contaminatingCommit &&
|
||||
args.nativeCommit === args.restoredCommit &&
|
||||
!args.pendingCandidate &&
|
||||
args.proofBookmark
|
||||
) {
|
||||
return "native-restored" as const;
|
||||
}
|
||||
if (
|
||||
args.mirrorCommit === args.restoredCommit &&
|
||||
args.nativeCommit === args.contaminatingCommit &&
|
||||
args.pendingCandidate &&
|
||||
args.proofBookmark
|
||||
) {
|
||||
return "mirror-restored-candidate-pending" as const;
|
||||
}
|
||||
if (
|
||||
args.mirrorCommit === args.restoredCommit &&
|
||||
args.nativeCommit === args.restoredCommit &&
|
||||
!args.pendingCandidate
|
||||
) {
|
||||
return args.proofBookmark ? ("mirror-restored" as const) : ("complete" as const);
|
||||
}
|
||||
throw new Error("controlled claim recovery state is not resumable");
|
||||
}
|
||||
|
||||
export function buildControlledCandidateContent(args: {
|
||||
mirror: ControlledMirrorState;
|
||||
expectedExternalId: string;
|
||||
expectedPath: string;
|
||||
expectedFileHash: string;
|
||||
candidateCommit: string;
|
||||
candidateContentHash: string;
|
||||
}) {
|
||||
const { digest, detail } = args.mirror;
|
||||
if (
|
||||
digest?.externalId !== args.expectedExternalId ||
|
||||
digest.githubPath !== args.expectedPath ||
|
||||
detail?.path !== `${args.expectedPath}/SKILL.md` ||
|
||||
typeof detail.content !== "string"
|
||||
) {
|
||||
throw new Error("controlled candidate source does not match the exact fixture");
|
||||
}
|
||||
if (!/^[0-9a-f]{40}$/.test(args.candidateCommit)) {
|
||||
throw new Error("controlled candidate commit is invalid");
|
||||
}
|
||||
if (!/^[0-9a-f]{64}$/.test(args.candidateContentHash)) {
|
||||
throw new Error("controlled candidate content hash is invalid");
|
||||
}
|
||||
const fileHash = createHash("sha256").update(detail.content).digest("hex");
|
||||
if (fileHash !== args.expectedFileHash) {
|
||||
throw new Error("controlled candidate markdown hash mismatch");
|
||||
}
|
||||
if (!digest.slug || !digest.displayName) {
|
||||
throw new Error("controlled candidate display metadata is incomplete");
|
||||
}
|
||||
return {
|
||||
slug: digest.slug,
|
||||
displayName: digest.displayName,
|
||||
...(digest.summary ? { summary: digest.summary } : {}),
|
||||
path: args.expectedPath,
|
||||
skillMarkdownPath: detail.path,
|
||||
skillMarkdown: detail.content,
|
||||
contentHash: args.candidateContentHash,
|
||||
};
|
||||
}
|
||||
@@ -2,20 +2,25 @@
|
||||
|
||||
/* oxlint-disable typescript/no-explicit-any -- Test-only proof decodes live Convex JSON. */
|
||||
|
||||
import { execFile } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import { appendFile, writeFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import { buildControlledCandidateContent } from "./claw-603-claim-proof-helpers";
|
||||
|
||||
const EXTERNAL_ID = "patrick-erichsen/skills/html";
|
||||
const REPO = "patrick-erichsen/skills";
|
||||
const PATH = "skills/html";
|
||||
const COMMIT_A = "050daba89f6b6636470add5cb300aac46a412cf8";
|
||||
const HASH_A = "a47adb2c1ac33c088f664b5187971b63d2b958a7b9f01516d26005ca941a108f";
|
||||
const FILE_HASH_A = "42d2e89358ea927441dfede45c3b0cf89a21603bc7c32246f098d24a9cbea1ff";
|
||||
const COMMIT_B = "1111111111111111111111111111111111111111";
|
||||
const HASH_B = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
|
||||
const COMMIT_C = "2222222222222222222222222222222222222222";
|
||||
const HASH_C = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";
|
||||
const PUBLIC_SITE = "https://academic-chihuahua-392.convex.site";
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
function requireEnv(name: string) {
|
||||
const value = process.env[name]?.trim();
|
||||
@@ -28,20 +33,13 @@ function assert(value: unknown, message: string): asserts value {
|
||||
}
|
||||
|
||||
async function runCommand(command: string[]) {
|
||||
const child = Bun.spawn(command, {
|
||||
const [executable, ...args] = command;
|
||||
assert(executable, "command executable is required");
|
||||
const { stdout } = await execFileAsync(executable, args, {
|
||||
cwd: process.cwd(),
|
||||
env: process.env,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
maxBuffer: 100 * 1024 * 1024,
|
||||
});
|
||||
const [stdout, stderr, exitCode] = await Promise.all([
|
||||
new Response(child.stdout).text(),
|
||||
new Response(child.stderr).text(),
|
||||
child.exited,
|
||||
]);
|
||||
if (exitCode !== 0) {
|
||||
throw new Error(`${command.join(" ")} failed: ${stderr.trim() || stdout.trim()}`);
|
||||
}
|
||||
return stdout.trim();
|
||||
}
|
||||
|
||||
@@ -66,7 +64,7 @@ async function fetchCapture(url: string, init?: RequestInit) {
|
||||
const startedAt = performance.now();
|
||||
const response = await fetch(url, init);
|
||||
const text = await response.text();
|
||||
let body: unknown = text;
|
||||
let body: any = text;
|
||||
try {
|
||||
body = JSON.parse(text);
|
||||
} catch {}
|
||||
@@ -270,6 +268,29 @@ async function applyNativeSnapshot(
|
||||
});
|
||||
}
|
||||
|
||||
async function cacheControlledPendingCandidateContent(
|
||||
source: Record<string, any>,
|
||||
mirror: Record<string, any>,
|
||||
commit: string,
|
||||
contentHash: string,
|
||||
) {
|
||||
const html = source.skills.find((skill: Record<string, any>) => skill.githubPath === PATH);
|
||||
assert(html?.githubPendingCandidateId, "controlled native candidate is not pending");
|
||||
const discovered = buildControlledCandidateContent({
|
||||
mirror,
|
||||
expectedExternalId: EXTERNAL_ID,
|
||||
expectedPath: PATH,
|
||||
expectedFileHash: FILE_HASH_A,
|
||||
candidateCommit: commit,
|
||||
candidateContentHash: contentHash,
|
||||
});
|
||||
return await runConvex("githubSkillSync:upsertGitHubSkillCandidateContentInternal", {
|
||||
candidateId: html.githubPendingCandidateId,
|
||||
discovered,
|
||||
commit,
|
||||
});
|
||||
}
|
||||
|
||||
function mirrorRow(
|
||||
state: Record<string, any>,
|
||||
commit: string,
|
||||
@@ -456,6 +477,14 @@ const correctedObservation = await observeCorrectedMirror(
|
||||
const sourceAfterFailure = await sourceState();
|
||||
const correctedClaim = await applyClaimedSnapshot(sourceAfterFailure, COMMIT_B, HASH_B);
|
||||
await writeCheckpoint("corrected-claim-pending", { correctedClaim });
|
||||
const correctedPendingSource = await sourceState();
|
||||
const correctedContent = await cacheControlledPendingCandidateContent(
|
||||
correctedPendingSource,
|
||||
mirrorBefore,
|
||||
COMMIT_B,
|
||||
HASH_B,
|
||||
);
|
||||
await writeCheckpoint("corrected-claim-content-cached", { correctedContent });
|
||||
const retryMirror = await readMirror();
|
||||
assert(retryMirror.digest?.claimStatus === "pending", "corrected claim did not become pending");
|
||||
assert(retryMirror.digest?.claimAttempt === 2, "corrected claim attempt was not two");
|
||||
@@ -500,6 +529,14 @@ assert(
|
||||
|
||||
const nativeFollowup = await applyNativeSnapshot(nativePromoted, COMMIT_C, HASH_C);
|
||||
await writeCheckpoint("native-followup-pending", { nativeFollowup });
|
||||
const nativeFollowupPendingSource = await sourceState();
|
||||
const nativeFollowupContent = await cacheControlledPendingCandidateContent(
|
||||
nativeFollowupPendingSource,
|
||||
promotedMirror,
|
||||
COMMIT_C,
|
||||
HASH_C,
|
||||
);
|
||||
await writeCheckpoint("native-followup-content-cached", { nativeFollowupContent });
|
||||
const followupFailure = await runConvex("skillsShClaims:applyTestVerdictInternal", {
|
||||
externalId: EXTERNAL_ID,
|
||||
phase: "native-followup",
|
||||
@@ -532,6 +569,14 @@ const restorationPass = await runConvex("skillsShClaims:applyTestVerdictInternal
|
||||
confirm: "pass-skills-sh-test-native-followup",
|
||||
});
|
||||
await writeCheckpoint("native-restoration-passed", { restorationPass });
|
||||
const restorationPendingSource = await sourceState();
|
||||
const restorationContent = await cacheControlledPendingCandidateContent(
|
||||
restorationPendingSource,
|
||||
promotedMirror,
|
||||
COMMIT_A,
|
||||
HASH_A,
|
||||
);
|
||||
await writeCheckpoint("native-restoration-content-cached", { restorationContent });
|
||||
const restoredSource = await sourceState();
|
||||
const restoredHtml = restoredSource.skills.find(
|
||||
(skill: Record<string, any>) => skill.githubPath === PATH,
|
||||
@@ -635,7 +680,13 @@ const proof = {
|
||||
aliasAfterFollowupFailure,
|
||||
installAfterFollowupFailure,
|
||||
},
|
||||
restoration: { restoration, restorationPass, restoredSource, restoredObservation },
|
||||
restoration: {
|
||||
restoration,
|
||||
restorationPass,
|
||||
restorationContent,
|
||||
restoredSource,
|
||||
restoredObservation,
|
||||
},
|
||||
final: {
|
||||
finalMirror,
|
||||
finalAlias,
|
||||
|
||||
@@ -0,0 +1,452 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/* oxlint-disable typescript/no-explicit-any -- Test-only recovery decodes live Convex JSON. */
|
||||
|
||||
import { execFile } from "node:child_process";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import {
|
||||
assertControlledMirrorRecoveryMetadata,
|
||||
assertControlledProofBookmark,
|
||||
buildControlledCandidateContent,
|
||||
classifyClaimRecoveryState,
|
||||
} from "./claw-603-claim-proof-helpers";
|
||||
|
||||
const EXTERNAL_ID = "patrick-erichsen/skills/html";
|
||||
const REPO = "patrick-erichsen/skills";
|
||||
const PATH = "skills/html";
|
||||
const COMMIT_A = "050daba89f6b6636470add5cb300aac46a412cf8";
|
||||
const HASH_A = "a47adb2c1ac33c088f664b5187971b63d2b958a7b9f01516d26005ca941a108f";
|
||||
const FILE_HASH_A = "42d2e89358ea927441dfede45c3b0cf89a21603bc7c32246f098d24a9cbea1ff";
|
||||
const COMMIT_B = "1111111111111111111111111111111111111111";
|
||||
const HASH_B = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
|
||||
const PREVIOUS_PROOF_RUN = 30608116457;
|
||||
const PUBLIC_SITE = "https://academic-chihuahua-392.convex.site";
|
||||
const RECOVERY_SNAPSHOT_ID = "claw-603-claim-recovery:30608116457";
|
||||
const PROOF_BOOKMARK = {
|
||||
id: "w17aeppjxks4v38af24a897fd98bkvfp",
|
||||
skillId: "kd712b24dhkftgq5pt88gctehx8b6g9v",
|
||||
userId: "kn746c8fb39xg3pachtrd40fgd8akgxr",
|
||||
createdAt: 1785477444440,
|
||||
hourlyStatsRecordedAt: 1785477444440,
|
||||
};
|
||||
const EXPECTED_MIRROR_RECOVERY_METADATA = {
|
||||
digest: {
|
||||
externalId: EXTERNAL_ID,
|
||||
sourceType: "github",
|
||||
upstreamSourceType: "controlled-github",
|
||||
owner: "patrick-erichsen",
|
||||
repo: "skills",
|
||||
slug: "html",
|
||||
displayName: "HTML Artifact Chooser",
|
||||
sourceUrl: "https://www.skills.sh/patrick-erichsen/skills/html",
|
||||
canonicalRepoUrl: "https://github.com/patrick-erichsen/skills",
|
||||
githubPath: PATH,
|
||||
upstreamInstalls: 123,
|
||||
upstreamScanners: {
|
||||
genAgentTrustHub: { status: "unavailable" },
|
||||
snyk: { status: "unavailable" },
|
||||
socket: { status: "unavailable" },
|
||||
},
|
||||
inferredCategories: ["other"],
|
||||
inferredTopics: [],
|
||||
inferredCategoryConfidence: "low",
|
||||
inferredTopicConfidence: "low",
|
||||
inferredClassifierVersion: "taxonomy-prototype-v9",
|
||||
inferredTopicClassifierVersion: "topic-prototype-v1",
|
||||
inferredInputHash: "5cd78db114746ff695441cc98f9560f0ac09876ccfaecff572ddfe07039f7045",
|
||||
inferredTopicInputHash: "0f0d55bfc10574035d704c182e7054da83f1240d30185e8486cf928e58475ec7",
|
||||
inferredAt: 1784788731652,
|
||||
},
|
||||
detail: {
|
||||
contentKind: "skill-md",
|
||||
path: "skills/html/SKILL.md",
|
||||
contentSha256: FILE_HASH_A,
|
||||
contentBytes: 5688,
|
||||
sourceBytes: 5688,
|
||||
sourceFileCount: 1,
|
||||
truncated: false,
|
||||
},
|
||||
};
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
function requireEnv(name: string) {
|
||||
const value = process.env[name]?.trim();
|
||||
if (!value) throw new Error(`${name} is required`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function assert(value: unknown, message: string): asserts value {
|
||||
if (!value) throw new Error(message);
|
||||
}
|
||||
|
||||
async function runCommand(command: string[]) {
|
||||
const [executable, ...args] = command;
|
||||
assert(executable, "command executable is required");
|
||||
const { stdout } = await execFileAsync(executable, args, {
|
||||
cwd: process.cwd(),
|
||||
env: process.env,
|
||||
maxBuffer: 100 * 1024 * 1024,
|
||||
});
|
||||
return stdout.trim();
|
||||
}
|
||||
|
||||
async function runConvex(functionName: string, args: Record<string, unknown>) {
|
||||
const output = await runCommand([
|
||||
"bunx",
|
||||
"convex",
|
||||
"run",
|
||||
"--no-push",
|
||||
functionName,
|
||||
JSON.stringify(args),
|
||||
]);
|
||||
return JSON.parse(output) as Record<string, any>;
|
||||
}
|
||||
|
||||
async function runInline(query: string) {
|
||||
const output = await runCommand(["bunx", "convex", "run", "--no-push", "--inline-query", query]);
|
||||
return JSON.parse(output) as Record<string, any>;
|
||||
}
|
||||
|
||||
const operatorToken = requireEnv("CLAWHUB_TEST_OPERATOR_TOKEN");
|
||||
const mirrorGateUrl = requireEnv("CLAWHUB_TEST_MIRROR_GATE_URL");
|
||||
const outputPath = resolve(
|
||||
process.env.CLAWHUB_CLAIM_PROOF_OUTPUT?.trim() || "claw-603-claim-recovery.json",
|
||||
);
|
||||
|
||||
async function postMirror(body: Record<string, unknown>) {
|
||||
const response = await fetch(mirrorGateUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
Authorization: `Bearer ${operatorToken}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const text = await response.text();
|
||||
assert(response.status === 200, `mirror ${String(body.operation)} returned ${response.status}`);
|
||||
return JSON.parse(text) as Record<string, any>;
|
||||
}
|
||||
|
||||
async function sourceState() {
|
||||
return await runInline(`
|
||||
const source = await ctx.db.query("githubSkillSources")
|
||||
.withIndex("by_repo", q => q.eq("repo", "${REPO}"))
|
||||
.unique();
|
||||
if (!source) return null;
|
||||
const skills = await ctx.db.query("skills")
|
||||
.withIndex("by_github_source", q => q.eq("githubSourceId", source._id))
|
||||
.collect();
|
||||
const candidates = [];
|
||||
for (const skill of skills) {
|
||||
if (skill.githubPendingCandidateId) {
|
||||
candidates.push(await ctx.db.get(skill.githubPendingCandidateId));
|
||||
}
|
||||
}
|
||||
return {source, skills, candidates};
|
||||
`);
|
||||
}
|
||||
|
||||
async function queueState() {
|
||||
return await runInline(`
|
||||
const requests = await ctx.db.query("skillScanRequests").take(1001);
|
||||
const jobs = await ctx.db.query("securityScanJobs").take(1001);
|
||||
return {
|
||||
requestIds: requests.map(row => row._id).sort(),
|
||||
jobIds: jobs.map(row => row._id).sort(),
|
||||
// Candidate promotion and mirror processing do not write scan jobs; this detects any
|
||||
// out-of-contract mutation even when the bounded queue identities stay unchanged.
|
||||
jobUpdatedAtSum: jobs.reduce((sum, row) => sum + row.updatedAt, 0),
|
||||
requestsTruncated: requests.length > 1000,
|
||||
jobsTruncated: jobs.length > 1000,
|
||||
};
|
||||
`);
|
||||
}
|
||||
|
||||
async function proofBookmarkState() {
|
||||
return await runInline(`
|
||||
const star = await ctx.db.query("stars")
|
||||
.withIndex("by_skill_user", q => q
|
||||
.eq("skillId", "${PROOF_BOOKMARK.skillId}")
|
||||
.eq("userId", "${PROOF_BOOKMARK.userId}"))
|
||||
.unique();
|
||||
const skill = await ctx.db.get("${PROOF_BOOKMARK.skillId}");
|
||||
return {star, skill};
|
||||
`);
|
||||
}
|
||||
|
||||
function mirrorRow(state: Record<string, any>) {
|
||||
const { digest, detail } = state;
|
||||
assert(digest && detail, "controlled mirror row and detail are required");
|
||||
// skillsShMirror.rowValidator has no summary field; searchable summary text is derived from
|
||||
// the exact detail content below rather than copied as independent mirror metadata.
|
||||
assert(digest.summary === undefined, "controlled mirror has unsupported summary metadata");
|
||||
return {
|
||||
externalId: digest.externalId,
|
||||
sourceType: digest.sourceType,
|
||||
upstreamSourceType: digest.upstreamSourceType,
|
||||
owner: digest.owner,
|
||||
repo: digest.repo,
|
||||
slug: digest.slug,
|
||||
displayName: digest.displayName,
|
||||
sourceUrl: digest.sourceUrl,
|
||||
canonicalRepoUrl: digest.canonicalRepoUrl,
|
||||
githubPath: digest.githubPath,
|
||||
githubCommit: COMMIT_A,
|
||||
sourceContentHash: HASH_A,
|
||||
upstreamInstalls: digest.upstreamInstalls,
|
||||
upstreamScanners: digest.upstreamScanners,
|
||||
inferredCategories: digest.inferredCategories,
|
||||
inferredTopics: digest.inferredTopics,
|
||||
inferredCategoryConfidence: digest.inferredCategoryConfidence,
|
||||
inferredTopicConfidence: digest.inferredTopicConfidence,
|
||||
inferredClassifierVersion: digest.inferredClassifierVersion,
|
||||
inferredTopicClassifierVersion: digest.inferredTopicClassifierVersion,
|
||||
inferredInputHash: digest.inferredInputHash,
|
||||
inferredTopicInputHash: digest.inferredTopicInputHash,
|
||||
inferredAt: digest.inferredAt,
|
||||
detail: {
|
||||
contentKind: detail.contentKind,
|
||||
path: detail.path,
|
||||
content: detail.content,
|
||||
contentBytes: detail.contentBytes,
|
||||
sourceBytes: detail.sourceBytes,
|
||||
sourceFileCount: detail.sourceFileCount,
|
||||
truncated: detail.truncated,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function restoreMirror(state: Record<string, any>) {
|
||||
const run = await runConvex("skillsShMirror:startRunInternal", {
|
||||
actor: "CLAW-603 permanent Test claim recovery",
|
||||
reason: "restore exact controlled mirror after completed claim proof",
|
||||
snapshotId: RECOVERY_SNAPSHOT_ID,
|
||||
sourceTotal: 1,
|
||||
sourcePageSize: 1,
|
||||
sourceMeasuredAt: new Date().toISOString(),
|
||||
sourceRequests: 0,
|
||||
sourceDurationMs: 0,
|
||||
});
|
||||
const leaseToken = `claw-603-claim-recovery-${Date.now()}`;
|
||||
await runConvex("skillsShMirror:claimBatchLeaseInternal", {
|
||||
runId: run.runId,
|
||||
page: 0,
|
||||
offset: 0,
|
||||
leaseToken,
|
||||
});
|
||||
const processed = await runConvex("skillsShMirror:processBatchInternal", {
|
||||
runId: run.runId,
|
||||
page: 0,
|
||||
offset: 0,
|
||||
leaseToken,
|
||||
pageLength: 1,
|
||||
hasMore: false,
|
||||
sourceTotal: 1,
|
||||
sourceRequests: 0,
|
||||
sourceBytes: 0,
|
||||
rows: [mirrorRow(state)],
|
||||
});
|
||||
const canceled = await runConvex("skillsShMirror:cancelRunInternal", {
|
||||
runId: run.runId,
|
||||
actor: "CLAW-603 permanent Test claim recovery",
|
||||
reason: "exact controlled row recovery complete",
|
||||
confirm: "cancel-skills-sh-mirror-test-run",
|
||||
});
|
||||
return { run, processed, canceled };
|
||||
}
|
||||
|
||||
const startedAt = new Date().toISOString();
|
||||
const statusBefore = await postMirror({ operation: "status" });
|
||||
const activeRuns = statusBefore.runs.filter((run: Record<string, any>) =>
|
||||
["running", "paused", "reconciling"].includes(run.status),
|
||||
);
|
||||
assert(activeRuns.length === 0, "skills.sh mirror recovery requires no active run");
|
||||
const [mirrorBefore, sourceBefore, bookmarkBefore, queuesBefore, isolationBefore] =
|
||||
await Promise.all([
|
||||
postMirror({ operation: "read", externalId: EXTERNAL_ID }),
|
||||
sourceState(),
|
||||
proofBookmarkState(),
|
||||
queueState(),
|
||||
runConvex("skillsShMirror:getIsolationInternal", {}),
|
||||
]);
|
||||
assert(
|
||||
!queuesBefore.requestsTruncated && !queuesBefore.jobsTruncated,
|
||||
"scan queues were truncated",
|
||||
);
|
||||
assert(mirrorBefore.digest?.claimStatus === "promoted", "controlled claim is not promoted");
|
||||
assert(
|
||||
mirrorBefore.digest?.publicVisible === false,
|
||||
"controlled claimed row is unexpectedly public",
|
||||
);
|
||||
assert(sourceBefore?.source?.repo === REPO, "controlled native source is missing");
|
||||
const htmlBefore = sourceBefore.skills.find(
|
||||
(skill: Record<string, any>) => skill.githubPath === PATH,
|
||||
);
|
||||
assert(htmlBefore, "controlled native source is missing the HTML skill");
|
||||
const proofBookmarkPresent = bookmarkBefore.star !== null;
|
||||
const recoveryPhase = classifyClaimRecoveryState({
|
||||
mirrorCommit: mirrorBefore.digest.githubCommit,
|
||||
nativeCommit: htmlBefore.githubCurrentCommit,
|
||||
pendingCandidate: Boolean(htmlBefore.githubPendingCandidateId),
|
||||
proofBookmark: proofBookmarkPresent,
|
||||
restoredCommit: COMMIT_A,
|
||||
contaminatingCommit: COMMIT_B,
|
||||
});
|
||||
assert(
|
||||
mirrorBefore.digest.sourceContentHash ===
|
||||
(mirrorBefore.digest.githubCommit === COMMIT_A ? HASH_A : HASH_B),
|
||||
"controlled mirror residue hash mismatch",
|
||||
);
|
||||
assert(
|
||||
htmlBefore.githubCurrentContentHash ===
|
||||
(htmlBefore.githubCurrentCommit === COMMIT_A ? HASH_A : HASH_B),
|
||||
"controlled native residue hash mismatch",
|
||||
);
|
||||
const pending = sourceBefore.candidates.find(
|
||||
(candidate: Record<string, any>) => candidate?._id === htmlBefore.githubPendingCandidateId,
|
||||
);
|
||||
assertControlledMirrorRecoveryMetadata({
|
||||
mirror: mirrorBefore,
|
||||
expected: EXPECTED_MIRROR_RECOVERY_METADATA,
|
||||
});
|
||||
if (proofBookmarkPresent) {
|
||||
assertControlledProofBookmark({
|
||||
star: bookmarkBefore.star,
|
||||
expected: PROOF_BOOKMARK,
|
||||
currentSkillStars: bookmarkBefore.skill?.statsStars,
|
||||
baselineSkillStars: 0,
|
||||
});
|
||||
} else {
|
||||
assert(bookmarkBefore.skill?.statsStars === 0, "controlled Bookmark count is not restored");
|
||||
}
|
||||
|
||||
let discovered: ReturnType<typeof buildControlledCandidateContent> | null = null;
|
||||
if (htmlBefore.githubCurrentCommit === COMMIT_B) {
|
||||
assert(pending?.githubCommit === COMMIT_A, "restoration candidate commit mismatch");
|
||||
assert(pending?.githubContentHash === HASH_A, "restoration candidate hash mismatch");
|
||||
assert(pending?.scanStatus === "clean", "restoration candidate verdict is not clean");
|
||||
assert(pending?.lifecycleStatus === "pending", "restoration candidate is not pending");
|
||||
discovered = buildControlledCandidateContent({
|
||||
mirror: mirrorBefore,
|
||||
expectedExternalId: EXTERNAL_ID,
|
||||
expectedPath: PATH,
|
||||
expectedFileHash: FILE_HASH_A,
|
||||
candidateCommit: COMMIT_A,
|
||||
candidateContentHash: HASH_A,
|
||||
});
|
||||
if (pending.skillMarkdown !== undefined) {
|
||||
assert(
|
||||
pending.skillMarkdownPath === discovered.skillMarkdownPath &&
|
||||
pending.skillMarkdown === discovered.skillMarkdown,
|
||||
"cached restoration candidate content mismatch",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mirrorRecovery =
|
||||
mirrorBefore.digest.githubCommit === COMMIT_B
|
||||
? await restoreMirror(mirrorBefore)
|
||||
: { skipped: true, reason: "mirror already restored" };
|
||||
let contentRecovery: Record<string, any> = {
|
||||
skipped: true,
|
||||
reason: "native candidate already restored",
|
||||
};
|
||||
if (discovered) {
|
||||
contentRecovery = await runConvex("githubSkillSync:upsertGitHubSkillCandidateContentInternal", {
|
||||
candidateId: pending._id,
|
||||
discovered,
|
||||
commit: COMMIT_A,
|
||||
});
|
||||
assert(contentRecovery.promoted === true, "cached restoration candidate did not promote");
|
||||
}
|
||||
const restoredSource = await sourceState();
|
||||
const restoredHtml = restoredSource.skills.find(
|
||||
(skill: Record<string, any>) => skill.githubPath === PATH,
|
||||
);
|
||||
assert(restoredHtml?.githubCurrentCommit === COMMIT_A, "native source commit was not restored");
|
||||
assert(restoredHtml?.githubCurrentContentHash === HASH_A, "native source hash was not restored");
|
||||
assert(!restoredHtml?.githubPendingCandidateId, "native source still has a pending candidate");
|
||||
|
||||
const starRestoration = proofBookmarkPresent
|
||||
? await runConvex("stars:removeStarInternal", {
|
||||
userId: PROOF_BOOKMARK.userId,
|
||||
skillId: PROOF_BOOKMARK.skillId,
|
||||
})
|
||||
: { skipped: true, reason: "proof Bookmark already restored" };
|
||||
if (proofBookmarkPresent) {
|
||||
assert(starRestoration.unstarred === true, "exact proof Bookmark was not removed");
|
||||
}
|
||||
const [
|
||||
mirrorAfter,
|
||||
sourceAfter,
|
||||
bookmarkAfter,
|
||||
queuesAfter,
|
||||
isolationAfter,
|
||||
alias,
|
||||
installResponse,
|
||||
] = await Promise.all([
|
||||
postMirror({ operation: "read", externalId: EXTERNAL_ID }),
|
||||
sourceState(),
|
||||
proofBookmarkState(),
|
||||
queueState(),
|
||||
runConvex("skillsShMirror:getIsolationInternal", {}),
|
||||
runConvex("skillsShMirrorPublic:getByRoute", {
|
||||
owner: "patrick-erichsen",
|
||||
repo: "skills",
|
||||
slug: "html",
|
||||
}),
|
||||
fetch(`${PUBLIC_SITE}/api/v1/skills-sh/${EXTERNAL_ID}/install`).then(async (response) => ({
|
||||
status: response.status,
|
||||
body: (await response.json()) as Record<string, any>,
|
||||
})),
|
||||
]);
|
||||
const htmlAfter = sourceAfter.skills.find(
|
||||
(skill: Record<string, any>) => skill.githubPath === PATH,
|
||||
);
|
||||
assert(mirrorAfter.digest?.claimStatus === "promoted", "restored mirror claim changed");
|
||||
assert(mirrorAfter.digest?.githubCommit === COMMIT_A, "restored mirror commit mismatch");
|
||||
assert(mirrorAfter.digest?.sourceContentHash === HASH_A, "restored mirror hash mismatch");
|
||||
assert(mirrorAfter.digest?.publicVisible === false, "restored claimed mirror became public");
|
||||
assert(htmlAfter?.githubCurrentCommit === COMMIT_A, "final native commit mismatch");
|
||||
assert(htmlAfter?.githubCurrentContentHash === HASH_A, "final native hash mismatch");
|
||||
assert(bookmarkAfter.star === null, "controlled proof Bookmark still exists");
|
||||
assert(bookmarkAfter.skill?.statsStars === 0, "controlled Bookmark count was not restored");
|
||||
assert(alias.kind === "redirect", "restored compatibility route is not a redirect");
|
||||
assert(installResponse.status === 200, "restored compatibility install failed");
|
||||
assert(installResponse.body?.github?.commit === COMMIT_A, "restored install commit mismatch");
|
||||
assert(installResponse.body?.github?.contentHash === HASH_A, "restored install hash mismatch");
|
||||
assert(JSON.stringify(queuesAfter) === JSON.stringify(queuesBefore), "scan queues changed");
|
||||
assert(
|
||||
JSON.stringify(isolationAfter) === JSON.stringify(isolationBefore),
|
||||
"scan isolation changed",
|
||||
);
|
||||
|
||||
const proof = {
|
||||
ok: true,
|
||||
startedAt,
|
||||
completedAt: new Date().toISOString(),
|
||||
target: { environment: "permanent Test", productionWrites: 0 },
|
||||
resumedFromProofRun: PREVIOUS_PROOF_RUN,
|
||||
recoveryPhase,
|
||||
recoveryBoundary: "exact pending commit-A candidate content cache and normal promotion",
|
||||
restoration: {
|
||||
contentRecovery,
|
||||
restoredSource,
|
||||
mirrorRecovery,
|
||||
restoredObservation: mirrorAfter,
|
||||
},
|
||||
bookmarkBefore,
|
||||
final: { mirrorAfter, sourceAfter, bookmarkAfter, alias, installResponse, starRestoration },
|
||||
isolationBefore,
|
||||
isolationAfter,
|
||||
queuesBefore,
|
||||
queuesAfter,
|
||||
scansPlanned: 0,
|
||||
scansAdmitted: 0,
|
||||
paidScans: 0,
|
||||
};
|
||||
await writeFile(outputPath, `${JSON.stringify(proof, null, 2)}\n`, "utf8");
|
||||
process.stdout.write(`${JSON.stringify(proof)}\n`);
|
||||
Reference in New Issue
Block a user