fix(ci): require lifecycle dashboard profiles (#19)

This commit is contained in:
Vincent Koc 2026-04-29 22:57:26 -07:00 committed by GitHub
parent 24370b0e49
commit 634bdb1492
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 61 additions and 7 deletions

View File

@ -227,6 +227,10 @@ jobs:
ref: ${{ steps.openclaw-track.outputs.ref }}
path: openclaw
- run: node scripts/sync-fixtures.mjs --materialize
- name: Install OpenClaw lifecycle dependencies
run: |
corepack enable
pnpm --dir openclaw install --frozen-lockfile --ignore-scripts
- name: Fetch main dashboard baseline
if: ${{ steps.openclaw-track.outputs.track != 'latest' }}
run: |
@ -244,7 +248,7 @@ jobs:
node scripts/cold-import-readiness.mjs --openclaw ./openclaw
node scripts/workspace-plan.mjs --openclaw ./openclaw
node scripts/platform-probes.mjs --openclaw ./openclaw
node scripts/import-loop-profile.mjs
node scripts/import-loop-profile.mjs --openclaw ./openclaw --runs 3
node scripts/profile-contract-runtime.mjs --openclaw ./openclaw --runs 3
node scripts/compare-runtime-profile.mjs
node scripts/check-ci-policy.mjs

View File

@ -86,6 +86,11 @@ jobs:
exit 1
done < /tmp/crabpot-dependabot-files.txt
- name: Install OpenClaw lifecycle dependencies
run: |
corepack enable
pnpm --dir openclaw install --frozen-lockfile --ignore-scripts
- name: Refresh compatibility reports
env:
CRABPOT_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
@ -102,7 +107,7 @@ jobs:
node scripts/cold-import-readiness.mjs --openclaw ./openclaw
node scripts/workspace-plan.mjs --openclaw ./openclaw
node scripts/platform-probes.mjs --openclaw ./openclaw
node scripts/import-loop-profile.mjs
node scripts/import-loop-profile.mjs --openclaw ./openclaw --runs 3
node scripts/profile-contract-runtime.mjs --openclaw ./openclaw --runs 3
node scripts/compare-runtime-profile.mjs
node scripts/check-ci-policy.mjs

View File

@ -105,6 +105,10 @@ jobs:
- name: Run runtime profile policy
run: node scripts/compare-runtime-profile.mjs ${{ inputs.strict_perf && '--strict' || '' }}
- run: node scripts/check-contract-coverage.mjs --openclaw ./openclaw
- name: Install OpenClaw lifecycle dependencies
run: |
corepack enable
pnpm --dir openclaw install --frozen-lockfile --ignore-scripts
- name: Write report artifacts
if: always()
@ -117,7 +121,7 @@ jobs:
node scripts/workspace-plan.mjs --openclaw ./openclaw
node scripts/platform-probes.mjs --openclaw ./openclaw
node scripts/check-generated-surface-fixture.mjs --openclaw ./openclaw
node scripts/import-loop-profile.mjs
node scripts/import-loop-profile.mjs --openclaw ./openclaw --runs "${PROFILE_RUNS}"
node scripts/profile-contract-runtime.mjs --openclaw ./openclaw --runs "${PROFILE_RUNS}"
node scripts/compare-runtime-profile.mjs ${{ inputs.strict_perf && '--strict' || '' }}
node scripts/check-ci-policy.mjs ${{ inputs.strict_contract && '--strict' || '' }}

View File

@ -82,6 +82,12 @@ jobs:
- if: ${{ steps.select.outputs.run == 'true' }}
run: node scripts/run-static-suite.mjs --openclaw ./openclaw --policy dashboard --profile-runs 3 --plugin-inspector-smoke
- name: Install OpenClaw lifecycle dependencies
if: ${{ steps.select.outputs.run == 'true' }}
run: |
corepack enable
pnpm --dir openclaw install --frozen-lockfile --ignore-scripts
- name: Fetch main dashboard baseline
if: ${{ steps.select.outputs.run == 'true' && matrix.track != 'latest' }}
run: |
@ -102,7 +108,7 @@ jobs:
node scripts/workspace-plan.mjs --openclaw ./openclaw
node scripts/platform-probes.mjs --openclaw ./openclaw
node scripts/check-generated-surface-fixture.mjs --openclaw ./openclaw
node scripts/import-loop-profile.mjs
node scripts/import-loop-profile.mjs --openclaw ./openclaw --runs 3
node scripts/profile-contract-runtime.mjs --openclaw ./openclaw --runs 3
node scripts/compare-runtime-profile.mjs
node scripts/check-ci-policy.mjs

View File

@ -32,7 +32,9 @@ async function main() {
openclawPath: args.openclawPath,
runs: args.runs,
});
const errors = validateImportLoopProfile(report);
const errors = validateImportLoopProfile(report, {
requireOpenClawLifecycle: Boolean(args.openclawPath),
});
if (args.write) {
await writeImportLoopProfile(report);
@ -114,8 +116,12 @@ export async function buildImportLoopProfile(options = {}) {
});
}
export function validateImportLoopProfile(report) {
return pluginInspector.validateImportLoopProfile(report);
export function validateImportLoopProfile(report, options = {}) {
const errors = pluginInspector.validateImportLoopProfile(report);
if (options.requireOpenClawLifecycle && (report.summary?.openClawLifecycleCount ?? 0) < 1) {
errors.push("OpenClaw lifecycle profile requested but no import+activate samples were captured");
}
return errors;
}
export async function writeImportLoopProfile(report, options = {}) {

View File

@ -51,6 +51,9 @@ test("default check workflow uploads policy and summary reports", async () => {
assert.match(workflow, /node scripts\/run-static-suite\.mjs --openclaw \.\/openclaw --policy dashboard --profile-runs 3 --plugin-inspector-smoke/);
assert.match(workflow, /node scripts\/check-ci-policy\.mjs/);
assert.match(workflow, /node scripts\/write-ci-summary\.mjs/);
const dashboardBlock = workflow.slice(workflow.indexOf(" dashboard:"));
assert.match(dashboardBlock, /pnpm --dir openclaw install --frozen-lockfile --ignore-scripts/);
assert.match(dashboardBlock, /node scripts\/import-loop-profile\.mjs --openclaw \.\/openclaw --runs 3/);
assert.match(workflow, /--baseline-data \.crabpot\/baseline\/main-dashboard-data\.json/);
assert.match(workflow, /node scripts\/update-readme-summary\.mjs \$\{baseline_arg\}/);
assert.match(workflow, /chore\(readme\): update crabpot dashboard \[skip ci\]/);
@ -84,6 +87,8 @@ test("track dashboard workflow refreshes branch dashboards by OpenClaw track", a
assert.match(workflow, /node scripts\/resolve-openclaw-track\.mjs --track "\$\{\{ matrix\.track \}\}" --github-output/);
assert.match(workflow, /ref: \$\{\{ steps\.openclaw-track\.outputs\.ref \}\}/);
assert.match(workflow, /node scripts\/run-static-suite\.mjs --openclaw \.\/openclaw --policy dashboard --profile-runs 3 --plugin-inspector-smoke/);
assert.match(workflow, /pnpm --dir openclaw install --frozen-lockfile --ignore-scripts/);
assert.match(workflow, /node scripts\/import-loop-profile\.mjs --openclaw \.\/openclaw --runs 3/);
assert.match(workflow, /node scripts\/update-track-metadata\.mjs --track "\$\{\{ matrix\.track \}\}"/);
assert.match(workflow, /origin\/main:reports\/crabpot-dashboard-data\.json/);
assert.match(workflow, /node scripts\/update-readme-summary\.mjs \$\{baseline_arg\}/);
@ -154,6 +159,8 @@ test("dependabot auto-merge refreshes reports after fixture pin updates", async
assert.match(workflow, /node scripts\/sync-fixtures\.mjs --materialize/);
assert.match(workflow, /node scripts\/resolve-openclaw-track\.mjs --branch "\$\{\{ github\.event\.pull_request\.base\.ref \}\}" --github-output/);
assert.match(workflow, /node scripts\/generate-report\.mjs --openclaw \.\/openclaw/);
assert.match(workflow, /pnpm --dir openclaw install --frozen-lockfile --ignore-scripts/);
assert.match(workflow, /node scripts\/import-loop-profile\.mjs --openclaw \.\/openclaw --runs 3/);
assert.match(workflow, /node scripts\/update-track-metadata\.mjs/);
assert.match(workflow, /--baseline-data \.crabpot\/baseline\/main-dashboard-data\.json/);
assert.match(workflow, /node scripts\/update-readme-summary\.mjs \$\{baseline_arg\}/);
@ -176,6 +183,13 @@ test("manual workflow enforces strict runtime profile policy before best-effort
assert.ok(policySteps.some((step) => step.includes("node scripts/profile-contract-runtime.mjs --openclaw ./openclaw-head")));
});
test("manual workflow writes OpenClaw lifecycle import profile artifacts", async () => {
const workflow = await readWorkflow(".github/workflows/openclaw-ref-compat.yml");
assert.match(workflow, /pnpm --dir openclaw install --frozen-lockfile --ignore-scripts/);
assert.match(workflow, /node scripts\/import-loop-profile\.mjs --openclaw \.\/openclaw --runs "\$\{PROFILE_RUNS\}"/);
});
test("manual workflow keeps isolated execution artifacts and failure policy wired", async () => {
const workflow = await readWorkflow(".github/workflows/openclaw-ref-compat.yml");

View File

@ -69,3 +69,18 @@ test("import loop markdown surfaces OpenClaw lifecycle phases when present", ()
assert.match(markdown, /OpenClaw Activate/);
assert.match(markdown, /p50OpenClawImportMs/);
});
test("import loop validation fails requested OpenClaw lifecycle profiles without lifecycle samples", () => {
const errors = validateImportLoopProfile(
{
summary: {
openClawLifecycleCount: 0,
},
},
{ requireOpenClawLifecycle: true },
);
assert.deepEqual(errors, [
"OpenClaw lifecycle profile requested but no import+activate samples were captured",
]);
});