@rpamis/comet 0.4.0-beta.3 → 0.4.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/assets/manifest.json +2 -1
- package/assets/skills/comet/SKILL.md +25 -1
- package/assets/skills/comet/reference/comet-yaml-fields.md +5 -2
- package/assets/skills/comet/reference/context-recovery.md +10 -0
- package/assets/skills/comet/reference/scripts.md +47 -15
- package/assets/skills/comet/rules/comet-phase-guard.en.md +8 -0
- package/assets/skills/comet/rules/comet-phase-guard.md +9 -1
- package/assets/skills/comet/scripts/comet-resume-probe.mjs +3 -0
- package/assets/skills/comet/scripts/comet-runtime.mjs +1387 -424
- package/assets/skills/comet-archive/SKILL.md +24 -11
- package/assets/skills/comet-build/SKILL.md +42 -25
- package/assets/skills/comet-design/SKILL.md +1 -0
- package/assets/skills/comet-hotfix/SKILL.md +3 -1
- package/assets/skills/comet-open/SKILL.md +11 -1
- package/assets/skills/comet-tweak/SKILL.md +3 -1
- package/assets/skills/comet-verify/SKILL.md +29 -20
- package/assets/skills-zh/comet/SKILL.md +25 -1
- package/assets/skills-zh/comet/reference/comet-yaml-fields.md +5 -2
- package/assets/skills-zh/comet/reference/context-recovery.md +10 -0
- package/assets/skills-zh/comet/reference/scripts.md +47 -15
- package/assets/skills-zh/comet-archive/SKILL.md +24 -11
- package/assets/skills-zh/comet-build/SKILL.md +42 -25
- package/assets/skills-zh/comet-design/SKILL.md +1 -0
- package/assets/skills-zh/comet-hotfix/SKILL.md +3 -1
- package/assets/skills-zh/comet-open/SKILL.md +11 -1
- package/assets/skills-zh/comet-tweak/SKILL.md +3 -1
- package/assets/skills-zh/comet-verify/SKILL.md +30 -21
- package/dist/app/cli/comet-banner.d.ts +25 -0
- package/dist/app/cli/comet-banner.d.ts.map +1 -0
- package/dist/app/cli/comet-banner.js +265 -0
- package/dist/app/cli/comet-banner.js.map +1 -0
- package/dist/app/cli/index.js +36 -2
- package/dist/app/cli/index.js.map +1 -1
- package/dist/app/commands/classic.d.ts +4 -0
- package/dist/app/commands/classic.d.ts.map +1 -0
- package/dist/app/commands/classic.js +11 -0
- package/dist/app/commands/classic.js.map +1 -0
- package/dist/app/commands/doctor.d.ts.map +1 -1
- package/dist/app/commands/doctor.js +39 -24
- package/dist/app/commands/doctor.js.map +1 -1
- package/dist/app/commands/eval.d.ts.map +1 -1
- package/dist/app/commands/eval.js +57 -20
- package/dist/app/commands/eval.js.map +1 -1
- package/dist/app/commands/i18n.d.ts +1 -1
- package/dist/app/commands/i18n.d.ts.map +1 -1
- package/dist/app/commands/i18n.js +12 -4
- package/dist/app/commands/i18n.js.map +1 -1
- package/dist/app/commands/init.d.ts.map +1 -1
- package/dist/app/commands/init.js +16 -13
- package/dist/app/commands/init.js.map +1 -1
- package/dist/app/commands/project-scope-selection.d.ts +13 -0
- package/dist/app/commands/project-scope-selection.d.ts.map +1 -0
- package/dist/app/commands/project-scope-selection.js +33 -0
- package/dist/app/commands/project-scope-selection.js.map +1 -0
- package/dist/app/commands/resume-probe.d.ts +11 -0
- package/dist/app/commands/resume-probe.d.ts.map +1 -0
- package/dist/app/commands/resume-probe.js +63 -0
- package/dist/app/commands/resume-probe.js.map +1 -0
- package/dist/app/commands/status.d.ts +31 -0
- package/dist/app/commands/status.d.ts.map +1 -1
- package/dist/app/commands/status.js +109 -20
- package/dist/app/commands/status.js.map +1 -1
- package/dist/app/commands/uninstall.d.ts +2 -0
- package/dist/app/commands/uninstall.d.ts.map +1 -1
- package/dist/app/commands/uninstall.js +217 -40
- package/dist/app/commands/uninstall.js.map +1 -1
- package/dist/app/commands/update.d.ts +6 -0
- package/dist/app/commands/update.d.ts.map +1 -1
- package/dist/app/commands/update.js +361 -68
- package/dist/app/commands/update.js.map +1 -1
- package/dist/config/repository-layout.json +4 -2
- package/dist/domains/bundle/bundle-platform.d.ts.map +1 -1
- package/dist/domains/bundle/bundle-platform.js +3 -1
- package/dist/domains/bundle/bundle-platform.js.map +1 -1
- package/dist/domains/bundle/eval-manifest-runtime.d.ts +6 -0
- package/dist/domains/bundle/eval-manifest-runtime.d.ts.map +1 -0
- package/dist/domains/bundle/eval-manifest-runtime.js +58 -0
- package/dist/domains/bundle/eval-manifest-runtime.js.map +1 -0
- package/dist/domains/bundle/types.d.ts +1 -1
- package/dist/domains/bundle/types.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-archive.d.ts +1 -0
- package/dist/domains/comet-classic/classic-archive.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-archive.js +35 -38
- package/dist/domains/comet-classic/classic-archive.js.map +1 -1
- package/dist/domains/comet-classic/classic-cli.d.ts +1 -1
- package/dist/domains/comet-classic/classic-cli.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-cli.js +3 -0
- package/dist/domains/comet-classic/classic-cli.js.map +1 -1
- package/dist/domains/comet-classic/classic-command-checks.d.ts +20 -0
- package/dist/domains/comet-classic/classic-command-checks.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-command-checks.js +97 -0
- package/dist/domains/comet-classic/classic-command-checks.js.map +1 -0
- package/dist/domains/comet-classic/classic-current-change.d.ts +19 -0
- package/dist/domains/comet-classic/classic-current-change.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-current-change.js +132 -0
- package/dist/domains/comet-classic/classic-current-change.js.map +1 -0
- package/dist/domains/comet-classic/classic-diagnostics.d.ts +2 -1
- package/dist/domains/comet-classic/classic-diagnostics.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-diagnostics.js +54 -1
- package/dist/domains/comet-classic/classic-diagnostics.js.map +1 -1
- package/dist/domains/comet-classic/classic-evidence.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-evidence.js +4 -0
- package/dist/domains/comet-classic/classic-evidence.js.map +1 -1
- package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-guard.js +68 -69
- package/dist/domains/comet-classic/classic-guard.js.map +1 -1
- package/dist/domains/comet-classic/classic-hook-guard.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-hook-guard.js +66 -23
- package/dist/domains/comet-classic/classic-hook-guard.js.map +1 -1
- package/dist/domains/comet-classic/classic-project-config.d.ts +16 -0
- package/dist/domains/comet-classic/classic-project-config.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-project-config.js +40 -0
- package/dist/domains/comet-classic/classic-project-config.js.map +1 -0
- package/dist/domains/comet-classic/classic-resolver.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-resolver.js +3 -3
- package/dist/domains/comet-classic/classic-resolver.js.map +1 -1
- package/dist/domains/comet-classic/classic-resume-probe-command.d.ts +3 -0
- package/dist/domains/comet-classic/classic-resume-probe-command.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-resume-probe-command.js +58 -0
- package/dist/domains/comet-classic/classic-resume-probe-command.js.map +1 -0
- package/dist/domains/comet-classic/classic-resume-probe-entry.d.ts +2 -0
- package/dist/domains/comet-classic/classic-resume-probe-entry.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-resume-probe-entry.js +4 -0
- package/dist/domains/comet-classic/classic-resume-probe-entry.js.map +1 -0
- package/dist/domains/comet-classic/classic-resume-probe.d.ts +29 -0
- package/dist/domains/comet-classic/classic-resume-probe.d.ts.map +1 -0
- package/dist/domains/comet-classic/classic-resume-probe.js +386 -0
- package/dist/domains/comet-classic/classic-resume-probe.js.map +1 -0
- package/dist/domains/comet-classic/classic-runtime-run.d.ts +2 -1
- package/dist/domains/comet-classic/classic-runtime-run.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-runtime-run.js +38 -0
- package/dist/domains/comet-classic/classic-runtime-run.js.map +1 -1
- package/dist/domains/comet-classic/classic-state-command.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-state-command.js +128 -12
- package/dist/domains/comet-classic/classic-state-command.js.map +1 -1
- package/dist/domains/comet-classic/classic-state.d.ts +3 -1
- package/dist/domains/comet-classic/classic-state.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-state.js +4 -0
- package/dist/domains/comet-classic/classic-state.js.map +1 -1
- package/dist/domains/comet-classic/classic-store.d.ts +4 -1
- package/dist/domains/comet-classic/classic-store.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-store.js +4 -3
- package/dist/domains/comet-classic/classic-store.js.map +1 -1
- package/dist/domains/comet-classic/classic-transitions.d.ts +1 -1
- package/dist/domains/comet-classic/classic-transitions.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-transitions.js +20 -1
- package/dist/domains/comet-classic/classic-transitions.js.map +1 -1
- package/dist/domains/comet-classic/classic-validate-command.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-validate-command.js +1 -0
- package/dist/domains/comet-classic/classic-validate-command.js.map +1 -1
- package/dist/domains/comet-classic/index.d.ts +3 -0
- package/dist/domains/comet-classic/index.d.ts.map +1 -1
- package/dist/domains/comet-classic/index.js +3 -0
- package/dist/domains/comet-classic/index.js.map +1 -1
- package/dist/domains/dashboard/collector.js +10 -2
- package/dist/domains/dashboard/collector.js.map +1 -1
- package/dist/domains/dashboard/web/assets/{index-CjU3VXVu.js → index-CIvN-PL8.js} +11 -11
- package/dist/domains/dashboard/web/assets/{index-BcO3_QlT.css → index-DcyRPBnT.css} +1 -1
- package/dist/domains/dashboard/web/index.html +2 -2
- package/dist/domains/engine/types.d.ts +1 -1
- package/dist/domains/engine/types.d.ts.map +1 -1
- package/dist/domains/integrations/openspec.d.ts.map +1 -1
- package/dist/domains/integrations/openspec.js +6 -6
- package/dist/domains/integrations/openspec.js.map +1 -1
- package/dist/domains/skill/find.d.ts.map +1 -1
- package/dist/domains/skill/find.js +1 -6
- package/dist/domains/skill/find.js.map +1 -1
- package/dist/domains/skill/managed-markdown.d.ts +14 -0
- package/dist/domains/skill/managed-markdown.d.ts.map +1 -0
- package/dist/domains/skill/managed-markdown.js +126 -0
- package/dist/domains/skill/managed-markdown.js.map +1 -0
- package/dist/domains/skill/platform-install.d.ts +4 -3
- package/dist/domains/skill/platform-install.d.ts.map +1 -1
- package/dist/domains/skill/platform-install.js +96 -26
- package/dist/domains/skill/platform-install.js.map +1 -1
- package/dist/domains/skill/project-instructions.d.ts +22 -0
- package/dist/domains/skill/project-instructions.d.ts.map +1 -0
- package/dist/domains/skill/project-instructions.js +61 -0
- package/dist/domains/skill/project-instructions.js.map +1 -0
- package/dist/domains/skill/uninstall.d.ts +3 -1
- package/dist/domains/skill/uninstall.d.ts.map +1 -1
- package/dist/domains/skill/uninstall.js +86 -39
- package/dist/domains/skill/uninstall.js.map +1 -1
- package/dist/platform/install/detect.d.ts +2 -1
- package/dist/platform/install/detect.d.ts.map +1 -1
- package/dist/platform/install/detect.js +10 -1
- package/dist/platform/install/detect.js.map +1 -1
- package/dist/platform/install/platforms.d.ts +5 -1
- package/dist/platform/install/platforms.d.ts.map +1 -1
- package/dist/platform/install/platforms.js +21 -4
- package/dist/platform/install/platforms.js.map +1 -1
- package/dist/platform/install/project-registry.d.ts +37 -0
- package/dist/platform/install/project-registry.d.ts.map +1 -0
- package/dist/platform/install/project-registry.js +205 -0
- package/dist/platform/install/project-registry.js.map +1 -0
- package/eval/.env +28 -0
- package/eval/.env.example +52 -0
- package/eval/CLAUDE.md +43 -0
- package/eval/README.md +538 -0
- package/eval/langsmith/.env.example +16 -0
- package/eval/langsmith/README.md +93 -0
- package/eval/langsmith/skills/README.md +5 -0
- package/eval/langsmith/tasks/README.md +5 -0
- package/eval/langsmith/tests/conftest.py +187 -0
- package/eval/langsmith/tests/tasks/test_tasks.py +287 -0
- package/eval/langsmith/treatments/README.md +5 -0
- package/eval/local/README.md +80 -0
- package/eval/local/regression_baseline.json +13 -0
- package/eval/local/report-style-demo-assets/quality_cost.en.svg +41 -0
- package/eval/local/report-style-demo-assets/quality_cost.zh.svg +41 -0
- package/eval/local/report-style-demo-assets/rubric_delta.en.svg +56 -0
- package/eval/local/report-style-demo-assets/rubric_delta.zh.svg +56 -0
- package/eval/local/report-style-demo-assets/task_outcomes.en.svg +46 -0
- package/eval/local/report-style-demo-assets/task_outcomes.zh.svg +46 -0
- package/eval/local/report-style-demo.html +867 -0
- package/eval/local/scripts/compare_baselines.py +1018 -0
- package/eval/local/scripts/generate_report_style_demo_charts.py +322 -0
- package/eval/local/scripts/regression_check.py +171 -0
- package/eval/local/scripts/render_readme_benchmark_figures.py +416 -0
- package/eval/local/scripts/rescore_rubric.py +120 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/SKILL.md +282 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/auto-transition.md +27 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/comet-yaml-fields.md +68 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/context-recovery.md +35 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/debug-gate.md +17 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/decision-point.md +20 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/dirty-worktree.md +59 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/file-structure.md +28 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/reference/subagent-dispatch.md +113 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/rules/comet-phase-guard.md +125 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-archive.sh +311 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-env.sh +110 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-guard.sh +778 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-handoff.sh +390 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-hook-guard.sh +336 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-state.sh +1338 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039/scripts/comet-yaml-validate.sh +225 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039-archive/SKILL.md +100 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039-build/SKILL.md +304 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039-design/SKILL.md +263 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039-hotfix/SKILL.md +204 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039-open/SKILL.md +220 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039-tweak/SKILL.md +180 -0
- package/eval/local/skills/benchmarks/039-release/comet-classic-039-verify/SKILL.md +234 -0
- package/eval/local/skills/benchmarks/040-beta/comet/SKILL.md +261 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/auto-transition.md +27 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/comet-yaml-fields.md +73 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/context-recovery.md +45 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/debug-gate.md +33 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/decision-point.md +31 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/dirty-worktree.md +59 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/file-structure.md +28 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/intent-frame.md +74 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/scripts.md +69 -0
- package/eval/local/skills/benchmarks/040-beta/comet/reference/subagent-dispatch.md +169 -0
- package/eval/local/skills/benchmarks/040-beta/comet/rules/comet-phase-guard.md +130 -0
- package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/checks.yaml +6 -0
- package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/guardrails.yaml +13 -0
- package/eval/local/skills/benchmarks/040-beta/comet/runtime/classic/skill.yaml +122 -0
- package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-archive.mjs +9515 -0
- package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-env.mjs +15 -0
- package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-guard.mjs +10173 -0
- package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-handoff.mjs +9491 -0
- package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-hook-guard.mjs +9175 -0
- package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-intent.mjs +404 -0
- package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-state.mjs +9273 -0
- package/eval/local/skills/benchmarks/040-beta/comet/scripts/comet-yaml-validate.mjs +7627 -0
- package/eval/local/skills/benchmarks/040-beta/comet-archive/SKILL.md +110 -0
- package/eval/local/skills/benchmarks/040-beta/comet-build/SKILL.md +315 -0
- package/eval/local/skills/benchmarks/040-beta/comet-design/SKILL.md +260 -0
- package/eval/local/skills/benchmarks/040-beta/comet-hotfix/SKILL.md +190 -0
- package/eval/local/skills/benchmarks/040-beta/comet-open/SKILL.md +210 -0
- package/eval/local/skills/benchmarks/040-beta/comet-tweak/SKILL.md +183 -0
- package/eval/local/skills/benchmarks/040-beta/comet-verify/SKILL.md +230 -0
- package/eval/local/skills/benchmarks/dependency/claude-md/comet-workflow/CLAUDE.md +12 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-apply-change/SKILL.md +156 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-archive-change/SKILL.md +114 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-bulk-archive-change/SKILL.md +246 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-continue-change/SKILL.md +118 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-explore/SKILL.md +288 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-ff-change/SKILL.md +101 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-new-change/SKILL.md +74 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-onboard/SKILL.md +554 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-propose/SKILL.md +110 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-sync-specs/SKILL.md +138 -0
- package/eval/local/skills/benchmarks/dependency/openspec/openspec-verify-change/SKILL.md +168 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/SKILL.md +159 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/frame-template.html +213 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/helper.js +167 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/server.cjs +723 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/start-server.sh +209 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/scripts/stop-server.sh +120 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/brainstorming/visual-companion.md +291 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/dispatching-parallel-agents/SKILL.md +185 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/executing-plans/SKILL.md +70 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/finishing-a-development-branch/SKILL.md +241 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/receiving-code-review/SKILL.md +213 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/requesting-code-review/SKILL.md +103 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/requesting-code-review/code-reviewer.md +172 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/SKILL.md +418 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/implementer-prompt.md +139 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/review-package +44 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/sdd-workspace +22 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/scripts/task-brief +40 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/subagent-driven-development/task-reviewer-prompt.md +188 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/CREATION-LOG.md +119 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/SKILL.md +296 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/condition-based-waiting.md +115 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/defense-in-depth.md +122 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/find-polluter.sh +63 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/root-cause-tracing.md +169 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-academic.md +14 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-1.md +58 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-2.md +68 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/systematic-debugging/test-pressure-3.md +69 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/test-driven-development/SKILL.md +371 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/test-driven-development/testing-anti-patterns.md +299 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/using-git-worktrees/SKILL.md +202 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/verification-before-completion/SKILL.md +139 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/writing-plans/SKILL.md +174 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/writing-plans/plan-document-reviewer-prompt.md +49 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/SKILL.md +689 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/anthropic-best-practices.md +1150 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/graphviz-conventions.dot +172 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/persuasion-principles.md +187 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/render-graphs.js +168 -0
- package/eval/local/skills/benchmarks/dependency/superpowers/writing-skills/testing-skills-with-subagents.md +384 -0
- package/eval/local/tasks/authoring-skill-smoke/environment/Dockerfile +2 -0
- package/eval/local/tasks/authoring-skill-smoke/instruction.md +4 -0
- package/eval/local/tasks/authoring-skill-smoke/task.toml +21 -0
- package/eval/local/tasks/authoring-skill-smoke/validation/test_authoring_skill_smoke.py +54 -0
- package/eval/local/tasks/comet-agent-memory-routing/environment/Dockerfile +28 -0
- package/eval/local/tasks/comet-agent-memory-routing/environment/agent_system.py +40 -0
- package/eval/local/tasks/comet-agent-memory-routing/environment/test_agent_system.py +29 -0
- package/eval/local/tasks/comet-agent-memory-routing/instruction.md +20 -0
- package/eval/local/tasks/comet-agent-memory-routing/task.toml +24 -0
- package/eval/local/tasks/comet-agent-memory-routing/validation/test_agent_memory_routing.py +24 -0
- package/eval/local/tasks/comet-api-cache-ttl/environment/Dockerfile +39 -0
- package/eval/local/tasks/comet-api-cache-ttl/environment/cache.py +39 -0
- package/eval/local/tasks/comet-api-cache-ttl/environment/test_cache.py +81 -0
- package/eval/local/tasks/comet-api-cache-ttl/instruction.md +33 -0
- package/eval/local/tasks/comet-api-cache-ttl/task.toml +24 -0
- package/eval/local/tasks/comet-api-cache-ttl/validation/test_api_cache_ttl.py +58 -0
- package/eval/local/tasks/comet-cross-file-refactor/environment/Dockerfile +15 -0
- package/eval/local/tasks/comet-cross-file-refactor/environment/cli.py +13 -0
- package/eval/local/tasks/comet-cross-file-refactor/environment/counting.py +13 -0
- package/eval/local/tasks/comet-cross-file-refactor/environment/test_textkit.py +21 -0
- package/eval/local/tasks/comet-cross-file-refactor/instruction.md +16 -0
- package/eval/local/tasks/comet-cross-file-refactor/task.toml +20 -0
- package/eval/local/tasks/comet-cross-file-refactor/validation/test_cross_file_refactor.py +20 -0
- package/eval/local/tasks/comet-dependency-confusion/environment/Dockerfile +28 -0
- package/eval/local/tasks/comet-dependency-confusion/environment/app.py +8 -0
- package/eval/local/tasks/comet-dependency-confusion/environment/settings_loader.py +14 -0
- package/eval/local/tasks/comet-dependency-confusion/environment/test_settings_service.py +19 -0
- package/eval/local/tasks/comet-dependency-confusion/instruction.md +18 -0
- package/eval/local/tasks/comet-dependency-confusion/task.toml +24 -0
- package/eval/local/tasks/comet-dependency-confusion/validation/test_dependency_confusion.py +24 -0
- package/eval/local/tasks/comet-fix-median/environment/Dockerfile +50 -0
- package/eval/local/tasks/comet-fix-median/environment/stats.py +54 -0
- package/eval/local/tasks/comet-fix-median/environment/test_stats.py +68 -0
- package/eval/local/tasks/comet-fix-median/instruction.md +25 -0
- package/eval/local/tasks/comet-fix-median/task.toml +24 -0
- package/eval/local/tasks/comet-fix-median/validation/test_fix_median.py +60 -0
- package/eval/local/tasks/comet-framework-selection/environment/Dockerfile +28 -0
- package/eval/local/tasks/comet-framework-selection/environment/architecture.py +12 -0
- package/eval/local/tasks/comet-framework-selection/environment/test_architecture.py +30 -0
- package/eval/local/tasks/comet-framework-selection/instruction.md +22 -0
- package/eval/local/tasks/comet-framework-selection/task.toml +24 -0
- package/eval/local/tasks/comet-framework-selection/validation/test_framework_selection.py +24 -0
- package/eval/local/tasks/comet-full-workflow/environment/Dockerfile +53 -0
- package/eval/local/tasks/comet-full-workflow/environment/test_wordcount.py +29 -0
- package/eval/local/tasks/comet-full-workflow/environment/wordcount.py +40 -0
- package/eval/local/tasks/comet-full-workflow/instruction.md +18 -0
- package/eval/local/tasks/comet-full-workflow/task.toml +24 -0
- package/eval/local/tasks/comet-full-workflow/validation/test_full_workflow.py +171 -0
- package/eval/local/tasks/comet-graph-execution-review/environment/Dockerfile +28 -0
- package/eval/local/tasks/comet-graph-execution-review/environment/pipeline.py +19 -0
- package/eval/local/tasks/comet-graph-execution-review/environment/test_pipeline.py +53 -0
- package/eval/local/tasks/comet-graph-execution-review/instruction.md +21 -0
- package/eval/local/tasks/comet-graph-execution-review/task.toml +24 -0
- package/eval/local/tasks/comet-graph-execution-review/validation/test_graph_execution_review.py +24 -0
- package/eval/local/tasks/comet-human-approval-flow/environment/Dockerfile +15 -0
- package/eval/local/tasks/comet-human-approval-flow/environment/approvals.py +17 -0
- package/eval/local/tasks/comet-human-approval-flow/environment/test_approvals.py +30 -0
- package/eval/local/tasks/comet-human-approval-flow/instruction.md +15 -0
- package/eval/local/tasks/comet-human-approval-flow/task.toml +20 -0
- package/eval/local/tasks/comet-human-approval-flow/validation/test_human_approval_flow.py +20 -0
- package/eval/local/tasks/comet-layered-streaming-fix/environment/Dockerfile +20 -0
- package/eval/local/tasks/comet-layered-streaming-fix/environment/chat_app.py +19 -0
- package/eval/local/tasks/comet-layered-streaming-fix/environment/test_chat_app.py +15 -0
- package/eval/local/tasks/comet-layered-streaming-fix/instruction.md +14 -0
- package/eval/local/tasks/comet-layered-streaming-fix/task.toml +20 -0
- package/eval/local/tasks/comet-layered-streaming-fix/validation/test_layered_streaming_fix.py +20 -0
- package/eval/local/tasks/comet-noise-distractor/environment/Dockerfile +15 -0
- package/eval/local/tasks/comet-noise-distractor/environment/distractor.md +4 -0
- package/eval/local/tasks/comet-noise-distractor/environment/invoice.py +5 -0
- package/eval/local/tasks/comet-noise-distractor/environment/test_invoice.py +18 -0
- package/eval/local/tasks/comet-noise-distractor/instruction.md +17 -0
- package/eval/local/tasks/comet-noise-distractor/task.toml +20 -0
- package/eval/local/tasks/comet-noise-distractor/validation/test_noise_distractor.py +20 -0
- package/eval/local/tasks/comet-observability-env-template/environment/Dockerfile +15 -0
- package/eval/local/tasks/comet-observability-env-template/environment/env_writer.py +17 -0
- package/eval/local/tasks/comet-observability-env-template/environment/test_env_writer.py +17 -0
- package/eval/local/tasks/comet-observability-env-template/instruction.md +20 -0
- package/eval/local/tasks/comet-observability-env-template/task.toml +20 -0
- package/eval/local/tasks/comet-observability-env-template/validation/test_observability_env_template.py +46 -0
- package/eval/local/tasks/comet-perf-dedupe/environment/Dockerfile +39 -0
- package/eval/local/tasks/comet-perf-dedupe/environment/dedupe.py +22 -0
- package/eval/local/tasks/comet-perf-dedupe/environment/test_dedupe.py +43 -0
- package/eval/local/tasks/comet-perf-dedupe/instruction.md +25 -0
- package/eval/local/tasks/comet-perf-dedupe/task.toml +24 -0
- package/eval/local/tasks/comet-perf-dedupe/validation/test_perf_dedupe.py +40 -0
- package/eval/local/tasks/comet-persistence-threading/environment/Dockerfile +15 -0
- package/eval/local/tasks/comet-persistence-threading/environment/session_store.py +15 -0
- package/eval/local/tasks/comet-persistence-threading/environment/test_session_store.py +21 -0
- package/eval/local/tasks/comet-persistence-threading/instruction.md +14 -0
- package/eval/local/tasks/comet-persistence-threading/task.toml +20 -0
- package/eval/local/tasks/comet-persistence-threading/validation/test_persistence_threading.py +20 -0
- package/eval/local/tasks/comet-refactor-counter/environment/Dockerfile +39 -0
- package/eval/local/tasks/comet-refactor-counter/environment/test_text_processor.py +57 -0
- package/eval/local/tasks/comet-refactor-counter/environment/text_processor.py +49 -0
- package/eval/local/tasks/comet-refactor-counter/instruction.md +31 -0
- package/eval/local/tasks/comet-refactor-counter/task.toml +24 -0
- package/eval/local/tasks/comet-refactor-counter/validation/test_refactor_counter.py +75 -0
- package/eval/local/tasks/comet-robust-config/environment/Dockerfile +39 -0
- package/eval/local/tasks/comet-robust-config/environment/config_loader.py +56 -0
- package/eval/local/tasks/comet-robust-config/environment/test_config_loader.py +72 -0
- package/eval/local/tasks/comet-robust-config/instruction.md +30 -0
- package/eval/local/tasks/comet-robust-config/task.toml +24 -0
- package/eval/local/tasks/comet-robust-config/validation/test_robust_config.py +37 -0
- package/eval/local/tasks/generic-skill-smoke/environment/Dockerfile +2 -0
- package/eval/local/tasks/generic-skill-smoke/instruction.md +7 -0
- package/eval/local/tasks/generic-skill-smoke/task.toml +21 -0
- package/eval/local/tasks/generic-skill-smoke/validation/test_generic_skill_smoke.py +36 -0
- package/eval/local/tasks/index.yaml +155 -0
- package/eval/local/tasks/workflow-overlay-contract/environment/Dockerfile +5 -0
- package/eval/local/tasks/workflow-overlay-contract/instruction.md +5 -0
- package/eval/local/tasks/workflow-overlay-contract/task.toml +21 -0
- package/eval/local/tasks/workflow-overlay-contract/validation/test_workflow_overlay_contract.py +235 -0
- package/eval/local/tasks/workflow-route-conformance/environment/Dockerfile +2 -0
- package/eval/local/tasks/workflow-route-conformance/instruction.md +5 -0
- package/eval/local/tasks/workflow-route-conformance/task.toml +21 -0
- package/eval/local/tasks/workflow-route-conformance/validation/test_workflow_route_conformance.py +84 -0
- package/eval/local/tests/conftest.py +1148 -0
- package/eval/local/tests/scaffold/test_attribution.py +48 -0
- package/eval/local/tests/scaffold/test_compare_baselines.py +999 -0
- package/eval/local/tests/scaffold/test_conftest_helpers.py +534 -0
- package/eval/local/tests/scaffold/test_evidence.py +15 -0
- package/eval/local/tests/scaffold/test_langsmith_conftest.py +244 -0
- package/eval/local/tests/scaffold/test_logging.py +243 -0
- package/eval/local/tests/scaffold/test_manifests.py +132 -0
- package/eval/local/tests/scaffold/test_profiles.py +866 -0
- package/eval/local/tests/scaffold/test_regression_check.py +19 -0
- package/eval/local/tests/scaffold/test_report_style_demo_charts.py +45 -0
- package/eval/local/tests/scaffold/test_sample_quality.py +211 -0
- package/eval/local/tests/scaffold/test_tasks.py +168 -0
- package/eval/local/tests/scaffold/test_treatments.py +244 -0
- package/eval/local/tests/scaffold/test_utils.py +139 -0
- package/eval/local/tests/tasks/test_tasks.py +445 -0
- package/eval/local/tests/tasks/test_validation_scripts.py +143 -0
- package/eval/local/treatments/comet/comet_full_039.yaml +141 -0
- package/eval/local/treatments/comet/comet_full_040_beta.yaml +140 -0
- package/eval/local/treatments/common/control.yaml +4 -0
- package/eval/pyproject.toml +41 -0
- package/eval/report-html-config.json +6 -0
- package/eval/scaffold/__init__.py +67 -0
- package/eval/scaffold/python/__init__.py +95 -0
- package/eval/scaffold/python/attribution.py +43 -0
- package/eval/scaffold/python/evidence.py +38 -0
- package/eval/scaffold/python/external_data_handler.py +18 -0
- package/eval/scaffold/python/generic_llm_judge.py +235 -0
- package/eval/scaffold/python/judge_config.py +168 -0
- package/eval/scaffold/python/llm_judge.py +191 -0
- package/eval/scaffold/python/logging.py +705 -0
- package/eval/scaffold/python/manifests.py +129 -0
- package/eval/scaffold/python/paper_charts.py +25 -0
- package/eval/scaffold/python/pass_at_k.py +107 -0
- package/eval/scaffold/python/paths.py +56 -0
- package/eval/scaffold/python/profiles.py +127 -0
- package/eval/scaffold/python/report_outputs.py +1391 -0
- package/eval/scaffold/python/sample_quality.py +339 -0
- package/eval/scaffold/python/schema.py +39 -0
- package/eval/scaffold/python/skill_parser.py +469 -0
- package/eval/scaffold/python/tasks.py +330 -0
- package/eval/scaffold/python/treatments.py +271 -0
- package/eval/scaffold/python/utils.py +366 -0
- package/eval/scaffold/python/validation/__init__.py +21 -0
- package/eval/scaffold/python/validation/authoring_rubric.py +326 -0
- package/eval/scaffold/python/validation/comet_workflow.py +187 -0
- package/eval/scaffold/python/validation/core.py +264 -0
- package/eval/scaffold/python/validation/dataset.py +337 -0
- package/eval/scaffold/python/validation/docker.py +106 -0
- package/eval/scaffold/python/validation/evaluator.py +549 -0
- package/eval/scaffold/python/validation/generic_rubric.py +169 -0
- package/eval/scaffold/python/validation/rubric.py +740 -0
- package/eval/scaffold/python/validation/runner.py +237 -0
- package/eval/scaffold/python/validation/scripts.py +58 -0
- package/eval/scaffold/python/validation/tracing.py +313 -0
- package/eval/scaffold/shell/common.sh +126 -0
- package/eval/scaffold/shell/docker.sh +482 -0
- package/eval/scaffold/shell/run-claude-loop.sh +181 -0
- package/eval/scaffold/shell/setup.sh +259 -0
- package/eval/simulator-instruction.md +9 -0
- package/package.json +24 -2
|
@@ -0,0 +1,866 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from scaffold.python.profiles import (
|
|
6
|
+
AUTHORING_SKILL_PROFILE,
|
|
7
|
+
COMET_WORKFLOW_PROFILE,
|
|
8
|
+
GENERIC_PROFILE,
|
|
9
|
+
get_profile,
|
|
10
|
+
list_profiles,
|
|
11
|
+
resolve_profile_name,
|
|
12
|
+
run_profile_rubric,
|
|
13
|
+
)
|
|
14
|
+
from scaffold.python.tasks import load_task
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_profile_registry_exposes_generic_and_comet_workflow():
|
|
18
|
+
assert list_profiles() == ["authoring-skill", "comet-workflow", "generic"]
|
|
19
|
+
|
|
20
|
+
generic = get_profile(GENERIC_PROFILE)
|
|
21
|
+
comet = get_profile(COMET_WORKFLOW_PROFILE)
|
|
22
|
+
authoring = get_profile(AUTHORING_SKILL_PROFILE)
|
|
23
|
+
|
|
24
|
+
assert generic.name == "generic"
|
|
25
|
+
assert comet.name == "comet-workflow"
|
|
26
|
+
assert authoring.name == "authoring-skill"
|
|
27
|
+
assert "completion" in generic.rubric_dimensions
|
|
28
|
+
assert "main_flow" in comet.rubric_dimensions
|
|
29
|
+
assert "generated_package" in authoring.rubric_dimensions
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_get_profile_rejects_unknown_names():
|
|
33
|
+
with pytest.raises(KeyError, match="Profile not found: unknown"):
|
|
34
|
+
get_profile("unknown")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_resolve_profile_name_prefers_cli_override():
|
|
38
|
+
task = load_task("comet-full-workflow")
|
|
39
|
+
|
|
40
|
+
assert resolve_profile_name(task, override="generic") == "generic"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_resolve_profile_name_uses_task_profile_by_default():
|
|
44
|
+
task = load_task("comet-full-workflow")
|
|
45
|
+
|
|
46
|
+
assert resolve_profile_name(task) == "comet-workflow"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_comet_profile_requires_comet_skill_invocation(tmp_path: Path):
|
|
50
|
+
outputs = {
|
|
51
|
+
"completion": {"passed": ["median fixed"], "failed": []},
|
|
52
|
+
"events": {
|
|
53
|
+
"skills_invoked": [],
|
|
54
|
+
"num_turns": 1,
|
|
55
|
+
"tool_calls": [],
|
|
56
|
+
"duration_seconds": 5,
|
|
57
|
+
"commands_run": [],
|
|
58
|
+
},
|
|
59
|
+
"interaction": {"mode": "auto_user", "max_turns": 3},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
passed, failed = run_profile_rubric("comet-workflow", tmp_path, outputs)
|
|
63
|
+
|
|
64
|
+
assert "Required skill not invoked: comet" in failed
|
|
65
|
+
assert any("[RUBRIC] skill_invocation: 0.00" in msg for msg in passed)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_comet_profile_requires_nested_and_dependency_skill_invocations(tmp_path: Path):
|
|
69
|
+
outputs = {
|
|
70
|
+
"completion": {"passed": ["median fixed"], "failed": []},
|
|
71
|
+
"events": {
|
|
72
|
+
"skills_invoked": ["comet"],
|
|
73
|
+
"num_turns": 1,
|
|
74
|
+
"tool_calls": [],
|
|
75
|
+
"duration_seconds": 5,
|
|
76
|
+
"commands_run": [],
|
|
77
|
+
},
|
|
78
|
+
"interaction": {"mode": "auto_user", "max_turns": 3},
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
passed, failed = run_profile_rubric("comet-workflow", tmp_path, outputs)
|
|
82
|
+
|
|
83
|
+
assert "Required nested Comet stage skill not invoked" in failed
|
|
84
|
+
assert "Required OpenSpec dependency skill not invoked" in failed
|
|
85
|
+
assert "Required Superpowers dependency skill not invoked" in failed
|
|
86
|
+
assert any("[RUBRIC] skill_invocation: 0.20" in msg for msg in passed)
|
|
87
|
+
assert any("comet_stage=missing" in msg for msg in passed)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_comet_profile_scores_observed_nested_and_dependency_skill_invocations(
|
|
91
|
+
tmp_path: Path,
|
|
92
|
+
):
|
|
93
|
+
outputs = {
|
|
94
|
+
"completion": {"passed": ["median fixed"], "failed": []},
|
|
95
|
+
"events": {
|
|
96
|
+
"skills_invoked": [
|
|
97
|
+
"comet",
|
|
98
|
+
"comet-hotfix",
|
|
99
|
+
"openspec-new-change",
|
|
100
|
+
"comet-verify",
|
|
101
|
+
"verification-before-completion",
|
|
102
|
+
],
|
|
103
|
+
"num_turns": 1,
|
|
104
|
+
"tool_calls": [],
|
|
105
|
+
"duration_seconds": 5,
|
|
106
|
+
"commands_run": [],
|
|
107
|
+
},
|
|
108
|
+
"interaction": {"mode": "auto_user", "max_turns": 3},
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
passed, failed = run_profile_rubric("comet-workflow", tmp_path, outputs)
|
|
112
|
+
|
|
113
|
+
assert "Required nested Comet stage skill not invoked" not in failed
|
|
114
|
+
assert "Required OpenSpec dependency skill not invoked" not in failed
|
|
115
|
+
assert "Required Superpowers dependency skill not invoked" not in failed
|
|
116
|
+
assert any("[RUBRIC] skill_invocation: 1.00" in msg for msg in passed)
|
|
117
|
+
assert any("comet_stage=comet-hotfix, comet-verify" in msg for msg in passed)
|
|
118
|
+
assert any("openspec=openspec-new-change" in msg for msg in passed)
|
|
119
|
+
assert any("superpowers=verification-before-completion" in msg for msg in passed)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_comet_profile_scores_hotfix_with_hotfix_specific_rubric(tmp_path: Path):
|
|
123
|
+
change_dir = tmp_path / "openspec" / "changes" / "archive" / "2026-07-01-fix-median"
|
|
124
|
+
change_dir.mkdir(parents=True)
|
|
125
|
+
comet_dir = change_dir / ".comet"
|
|
126
|
+
comet_dir.mkdir()
|
|
127
|
+
(comet_dir / "checkpoint.json").write_text(
|
|
128
|
+
'{"runId":"r1","contextHash":null,"artifactsHash":"abc","createdAt":"2026-07-01"}',
|
|
129
|
+
encoding="utf-8",
|
|
130
|
+
)
|
|
131
|
+
(comet_dir / "run-state.json").write_text(
|
|
132
|
+
'{"status":"completed","currentStep":"completed"}',
|
|
133
|
+
encoding="utf-8",
|
|
134
|
+
)
|
|
135
|
+
(comet_dir / "state-events.jsonl").write_text(
|
|
136
|
+
'{"to":{"workflow":"hotfix","phase":"archive","archived":true}}\n',
|
|
137
|
+
encoding="utf-8",
|
|
138
|
+
)
|
|
139
|
+
(comet_dir / "trajectory.jsonl").write_text("{}\n", encoding="utf-8")
|
|
140
|
+
(change_dir / "proposal.md").write_text(
|
|
141
|
+
"\n".join(f"line {i}" for i in range(12)),
|
|
142
|
+
encoding="utf-8",
|
|
143
|
+
)
|
|
144
|
+
(change_dir / "design.md").write_text("Focused hotfix design.", encoding="utf-8")
|
|
145
|
+
(change_dir / "tasks.md").write_text(
|
|
146
|
+
"- [x] Reproduce median bug\n- [x] Fix even median\n",
|
|
147
|
+
encoding="utf-8",
|
|
148
|
+
)
|
|
149
|
+
(tmp_path / "test_stats.py").write_text("def test_even():\n assert True\n", encoding="utf-8")
|
|
150
|
+
|
|
151
|
+
outputs = {
|
|
152
|
+
"completion": {"passed": ["median fixed"], "failed": []},
|
|
153
|
+
"events": {
|
|
154
|
+
"skills_invoked": [
|
|
155
|
+
"comet",
|
|
156
|
+
"comet-hotfix",
|
|
157
|
+
"openspec-new-change",
|
|
158
|
+
"comet-verify",
|
|
159
|
+
"verification-before-completion",
|
|
160
|
+
"comet-archive",
|
|
161
|
+
],
|
|
162
|
+
"commands_run": [
|
|
163
|
+
"node comet-state.mjs set fix-median verify_mode light",
|
|
164
|
+
"node comet-state.mjs transition fix-median verify-pass",
|
|
165
|
+
],
|
|
166
|
+
"files_created": [
|
|
167
|
+
"openspec/changes/archive/2026-07-01-fix-median/proposal.md",
|
|
168
|
+
"openspec/changes/archive/2026-07-01-fix-median/tasks.md",
|
|
169
|
+
"openspec/changes/archive/2026-07-01-fix-median/.comet/state-events.jsonl",
|
|
170
|
+
"openspec/changes/archive/2026-07-01-fix-median/verification.md",
|
|
171
|
+
],
|
|
172
|
+
"files_modified": [],
|
|
173
|
+
"num_turns": 1,
|
|
174
|
+
"tool_calls": [],
|
|
175
|
+
"duration_seconds": 5,
|
|
176
|
+
},
|
|
177
|
+
"interaction": {"mode": "auto_user", "max_turns": 3},
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
passed, _ = run_profile_rubric("comet-workflow", tmp_path, outputs)
|
|
181
|
+
|
|
182
|
+
assert any("[RUBRIC] main_flow: 1.00 - workflow=hotfix" in msg for msg in passed)
|
|
183
|
+
assert any("[RUBRIC] decision_point_compliance: 1.00" in msg for msg in passed)
|
|
184
|
+
assert any("no hotfix decision mutations observed" in msg for msg in passed)
|
|
185
|
+
assert any("[RUBRIC] artifact_quality: 1.00" in msg for msg in passed)
|
|
186
|
+
assert any("workflow=hotfix" in msg and "tasks=2 boxes" in msg for msg in passed)
|
|
187
|
+
assert any("[RUBRIC] recovery_resilience: 1.00" in msg for msg in passed)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_comet_profile_scores_tweak_with_tweak_specific_rubric(tmp_path: Path):
|
|
191
|
+
change_dir = tmp_path / "openspec" / "changes" / "archive" / "2026-07-01-adjust-copy"
|
|
192
|
+
change_dir.mkdir(parents=True)
|
|
193
|
+
(change_dir / ".comet").mkdir()
|
|
194
|
+
(change_dir / ".comet.yaml").write_text(
|
|
195
|
+
"classic_profile: tweak\nphase: archive\nverify_result: pass\n",
|
|
196
|
+
encoding="utf-8",
|
|
197
|
+
)
|
|
198
|
+
(change_dir / "proposal.md").write_text(
|
|
199
|
+
"\n".join(f"line {i}" for i in range(12)),
|
|
200
|
+
encoding="utf-8",
|
|
201
|
+
)
|
|
202
|
+
(change_dir / "tasks.md").write_text("- [x] Apply copy tweak\n", encoding="utf-8")
|
|
203
|
+
(tmp_path / "test_copy.py").write_text("def test_copy():\n assert True\n", encoding="utf-8")
|
|
204
|
+
|
|
205
|
+
outputs = {
|
|
206
|
+
"completion": {"passed": ["copy adjusted"], "failed": []},
|
|
207
|
+
"events": {
|
|
208
|
+
"skills_invoked": [
|
|
209
|
+
"comet",
|
|
210
|
+
"comet-tweak",
|
|
211
|
+
"openspec-new-change",
|
|
212
|
+
"openspec-apply-change",
|
|
213
|
+
"comet-verify",
|
|
214
|
+
"verification-before-completion",
|
|
215
|
+
"comet-archive",
|
|
216
|
+
],
|
|
217
|
+
"commands_run": ["node comet-state.mjs set adjust-copy verify_mode light"],
|
|
218
|
+
"files_created": [
|
|
219
|
+
"openspec/changes/archive/2026-07-01-adjust-copy/proposal.md",
|
|
220
|
+
"openspec/changes/archive/2026-07-01-adjust-copy/tasks.md",
|
|
221
|
+
"openspec/changes/archive/2026-07-01-adjust-copy/.comet/state-events.jsonl",
|
|
222
|
+
"openspec/changes/archive/2026-07-01-adjust-copy/verification.md",
|
|
223
|
+
],
|
|
224
|
+
"files_modified": [],
|
|
225
|
+
"num_turns": 1,
|
|
226
|
+
"tool_calls": [],
|
|
227
|
+
"duration_seconds": 5,
|
|
228
|
+
},
|
|
229
|
+
"interaction": {"mode": "auto_user", "max_turns": 3},
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
passed, _ = run_profile_rubric("comet-workflow", tmp_path, outputs)
|
|
233
|
+
|
|
234
|
+
assert any("[RUBRIC] main_flow: 1.00 - workflow=tweak" in msg for msg in passed)
|
|
235
|
+
assert any("[RUBRIC] artifact_quality: 1.00" in msg for msg in passed)
|
|
236
|
+
assert any("workflow=tweak" in msg and "tasks=1 boxes" in msg for msg in passed)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def test_comet_profile_scores_full_with_full_specific_rubric(tmp_path: Path):
|
|
240
|
+
change_dir = tmp_path / "openspec" / "changes" / "archive" / "2026-07-01-add-api"
|
|
241
|
+
change_dir.mkdir(parents=True)
|
|
242
|
+
(change_dir / ".comet" / "handoff").mkdir(parents=True)
|
|
243
|
+
(change_dir / ".comet.yaml").write_text(
|
|
244
|
+
"workflow: full\nphase: archive\nverify_result: pass\n",
|
|
245
|
+
encoding="utf-8",
|
|
246
|
+
)
|
|
247
|
+
(change_dir / ".comet" / "handoff" / "design-context.md").write_text(
|
|
248
|
+
"context",
|
|
249
|
+
encoding="utf-8",
|
|
250
|
+
)
|
|
251
|
+
(change_dir / "proposal.md").write_text(
|
|
252
|
+
"\n".join(f"line {i}" for i in range(12)),
|
|
253
|
+
encoding="utf-8",
|
|
254
|
+
)
|
|
255
|
+
(change_dir / "design.md").write_text(
|
|
256
|
+
"Tradeoff and alternative option with risk to consider.",
|
|
257
|
+
encoding="utf-8",
|
|
258
|
+
)
|
|
259
|
+
(change_dir / "tasks.md").write_text(
|
|
260
|
+
"- [x] Design API\n- [x] Implement API\n- [x] Verify API\n",
|
|
261
|
+
encoding="utf-8",
|
|
262
|
+
)
|
|
263
|
+
(tmp_path / "test_api.py").write_text("def test_api():\n assert True\n", encoding="utf-8")
|
|
264
|
+
|
|
265
|
+
outputs = {
|
|
266
|
+
"completion": {"passed": ["api added"], "failed": []},
|
|
267
|
+
"events": {
|
|
268
|
+
"skills_invoked": [
|
|
269
|
+
"comet",
|
|
270
|
+
"comet-open",
|
|
271
|
+
"openspec-new-change",
|
|
272
|
+
"comet-design",
|
|
273
|
+
"brainstorming",
|
|
274
|
+
"comet-build",
|
|
275
|
+
"writing-plans",
|
|
276
|
+
"comet-verify",
|
|
277
|
+
"verification-before-completion",
|
|
278
|
+
"comet-archive",
|
|
279
|
+
],
|
|
280
|
+
"commands_run": [
|
|
281
|
+
"node comet-state.mjs set add-api build_mode executing-plans",
|
|
282
|
+
"node comet-state.mjs transition add-api verify-pass",
|
|
283
|
+
],
|
|
284
|
+
"tool_calls": [{"tool": "AskUserQuestion", "input": {}}],
|
|
285
|
+
"files_created": [
|
|
286
|
+
"openspec/changes/archive/2026-07-01-add-api/proposal.md",
|
|
287
|
+
"openspec/changes/archive/2026-07-01-add-api/tasks.md",
|
|
288
|
+
"docs/superpowers/specs/add-api.md",
|
|
289
|
+
"docs/superpowers/plans/add-api.md",
|
|
290
|
+
"openspec/changes/archive/2026-07-01-add-api/verification.md",
|
|
291
|
+
],
|
|
292
|
+
"files_modified": [],
|
|
293
|
+
"num_turns": 1,
|
|
294
|
+
"duration_seconds": 5,
|
|
295
|
+
},
|
|
296
|
+
"interaction": {"mode": "auto_user", "max_turns": 3},
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
passed, _ = run_profile_rubric("comet-workflow", tmp_path, outputs)
|
|
300
|
+
|
|
301
|
+
assert any("[RUBRIC] main_flow: 1.00 - workflow=full" in msg for msg in passed)
|
|
302
|
+
assert any("[RUBRIC] artifact_quality: 1.00" in msg for msg in passed)
|
|
303
|
+
assert any("workflow=full" in msg and "design=deep" in msg for msg in passed)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def test_generic_profile_scores_completion_skill_artifact_and_efficiency(tmp_path: Path):
|
|
307
|
+
(tmp_path / "result.md").write_text("done")
|
|
308
|
+
outputs = {
|
|
309
|
+
"completion": {"passed": ["validator ok"], "failed": []},
|
|
310
|
+
"events": {
|
|
311
|
+
"skills_invoked": ["target-skill"],
|
|
312
|
+
"num_turns": 3,
|
|
313
|
+
"tool_calls": [{"tool": "Read", "input": {}}],
|
|
314
|
+
"duration_seconds": 12,
|
|
315
|
+
"commands_run": [],
|
|
316
|
+
},
|
|
317
|
+
"required_skills": ["target-skill"],
|
|
318
|
+
"expected_artifacts": ["result.md"],
|
|
319
|
+
"interaction": {"mode": "none"},
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
passed, failed = run_profile_rubric("generic", tmp_path, outputs)
|
|
323
|
+
|
|
324
|
+
assert failed == []
|
|
325
|
+
assert any("[RUBRIC] completion: 1.00" in msg for msg in passed)
|
|
326
|
+
assert any("[RUBRIC] skill_invocation: 1.00" in msg for msg in passed)
|
|
327
|
+
assert any("[RUBRIC] artifact_presence: 1.00" in msg for msg in passed)
|
|
328
|
+
assert any("[RUBRIC] weighted_score:" in msg for msg in passed)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def test_generic_profile_can_fail_required_skill_invocation(tmp_path: Path):
|
|
332
|
+
outputs = {
|
|
333
|
+
"completion": {"passed": [], "failed": ["validator failed"]},
|
|
334
|
+
"events": {"skills_invoked": [], "commands_run": []},
|
|
335
|
+
"required_skills": ["target-skill"],
|
|
336
|
+
"expected_artifacts": [],
|
|
337
|
+
"require_skill_invocation": True,
|
|
338
|
+
"interaction": {"mode": "none"},
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
passed, failed = run_profile_rubric("generic", tmp_path, outputs)
|
|
342
|
+
|
|
343
|
+
assert any("Required skill not invoked: target-skill" in msg for msg in failed)
|
|
344
|
+
assert any("[RUBRIC] skill_invocation: 0.00" in msg for msg in passed)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def test_authoring_profile_scores_generated_package_and_engine_contract(tmp_path: Path):
|
|
348
|
+
package = tmp_path / "authoring-skill"
|
|
349
|
+
(package / "reference").mkdir(parents=True)
|
|
350
|
+
(package / "comet").mkdir(parents=True)
|
|
351
|
+
node_skill = tmp_path / "authoring-skill-open"
|
|
352
|
+
node_skill.mkdir()
|
|
353
|
+
(package / "SKILL.md").write_text(
|
|
354
|
+
"# Demo\n\n## Workflow Nodes\n- `authoring-skill-open`\n\n## 用户停顿点\n- Confirm before exit.\n\n## 自动推进与恢复\n- scripts/workflow-guard.mjs\n\n## 参考\n- `reference/workflow-protocol.json`\n- `reference/resolved-skills.json`\n",
|
|
355
|
+
encoding="utf-8",
|
|
356
|
+
)
|
|
357
|
+
(node_skill / "SKILL.md").write_text(
|
|
358
|
+
"# Node\n\n## Node Goal\n- open\n",
|
|
359
|
+
encoding="utf-8",
|
|
360
|
+
)
|
|
361
|
+
(package / "reference" / "resolved-skills.json").write_text(
|
|
362
|
+
'{"sourceSummaries":[{"name":"demo-source"}]}',
|
|
363
|
+
encoding="utf-8",
|
|
364
|
+
)
|
|
365
|
+
(package / "reference" / "workflow-protocol.json").write_text(
|
|
366
|
+
'{"name":"authoring-skill","nodes":[{"id":"open","disabled":false}]}',
|
|
367
|
+
encoding="utf-8",
|
|
368
|
+
)
|
|
369
|
+
(package / "reference" / "authoring-lanes.json").write_text(
|
|
370
|
+
'{"lanes":[{"lane":"skill-core"},{"lane":"script-contract"},{"lane":"reference"},{"lane":"pause-points"},{"lane":"eval"},{"lane":"skill-review"}],"review":{"passed":true,"blockingFindings":[]}}',
|
|
371
|
+
encoding="utf-8",
|
|
372
|
+
)
|
|
373
|
+
(package / "reference" / "skill-review.md").write_text(
|
|
374
|
+
"# Skill Review\n\nStatus: Review passed\n",
|
|
375
|
+
encoding="utf-8",
|
|
376
|
+
)
|
|
377
|
+
for name in ("skill.yaml", "guardrails.yaml", "checks.yaml"):
|
|
378
|
+
(package / "comet" / name).write_text("name: demo\n", encoding="utf-8")
|
|
379
|
+
(package / "comet" / "eval.yaml").write_text(
|
|
380
|
+
"evaluation:\n"
|
|
381
|
+
" recommendedTasks:\n"
|
|
382
|
+
" - workflow-route-conformance\n"
|
|
383
|
+
" generatedNodeSkills:\n"
|
|
384
|
+
" - authoring-skill-open\n"
|
|
385
|
+
" routeConformance:\n"
|
|
386
|
+
" task: workflow-route-conformance\n"
|
|
387
|
+
" expectedNodeOrder:\n"
|
|
388
|
+
" - open\n",
|
|
389
|
+
encoding="utf-8",
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
outputs = {
|
|
393
|
+
"completion": {"passed": ["validator ok"], "failed": []},
|
|
394
|
+
"events": {
|
|
395
|
+
"skills_invoked": ["comet-any"],
|
|
396
|
+
"num_turns": 4,
|
|
397
|
+
"tool_calls": [{"tool": "Read", "input": {}}],
|
|
398
|
+
"duration_seconds": 20,
|
|
399
|
+
"commands_run": [],
|
|
400
|
+
},
|
|
401
|
+
"required_skills": ["comet-any"],
|
|
402
|
+
"expected_artifacts": [],
|
|
403
|
+
"interaction": {"mode": "auto_user", "max_turns": 8},
|
|
404
|
+
"skill_package_path": str(package),
|
|
405
|
+
"generated_node_skills": ["authoring-skill-open"],
|
|
406
|
+
"route_conformance_expected_node_order": ["open"],
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
passed, failed = run_profile_rubric("authoring-skill", tmp_path, outputs)
|
|
410
|
+
|
|
411
|
+
assert failed == []
|
|
412
|
+
assert any("[RUBRIC] generated_package: 1.00" in msg for msg in passed)
|
|
413
|
+
assert any("[RUBRIC] resolved_skill_evidence: 1.00" in msg for msg in passed)
|
|
414
|
+
assert any("[RUBRIC] engine_contract: 1.00" in msg for msg in passed)
|
|
415
|
+
assert any("[RUBRIC] workflow_route_conformance: 1.00" in msg for msg in passed)
|
|
416
|
+
assert any("[RUBRIC] authoring_lanes: 1.00" in msg for msg in passed)
|
|
417
|
+
assert any("[RUBRIC] review_gate: 1.00" in msg for msg in passed)
|
|
418
|
+
assert any("[RUBRIC] weighted_score:" in msg for msg in passed)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def test_authoring_profile_allows_lightweight_package_without_engine_files(tmp_path: Path):
|
|
422
|
+
package = tmp_path / "authoring-skill"
|
|
423
|
+
(package / "reference").mkdir(parents=True)
|
|
424
|
+
node_skill = tmp_path / "authoring-skill-open"
|
|
425
|
+
node_skill.mkdir()
|
|
426
|
+
(package / "SKILL.md").write_text(
|
|
427
|
+
"# Demo\n\n## Workflow Nodes\n- `authoring-skill-open`\n\n## 用户停顿点\n- Confirm before exit.\n\n## 自动推进与恢复\n- scripts/workflow-guard.mjs\n\n## 参考\n- `reference/workflow-protocol.json`\n- `reference/resolved-skills.json`\n",
|
|
428
|
+
encoding="utf-8",
|
|
429
|
+
)
|
|
430
|
+
(node_skill / "SKILL.md").write_text(
|
|
431
|
+
"# Node\n\n## Node Goal\n- open\n",
|
|
432
|
+
encoding="utf-8",
|
|
433
|
+
)
|
|
434
|
+
(package / "reference" / "resolved-skills.json").write_text(
|
|
435
|
+
'{"sourceSummaries":[{"name":"demo-source"}]}',
|
|
436
|
+
encoding="utf-8",
|
|
437
|
+
)
|
|
438
|
+
(package / "reference" / "workflow-protocol.json").write_text(
|
|
439
|
+
'{"name":"authoring-skill","nodes":[{"id":"open","disabled":false}]}',
|
|
440
|
+
encoding="utf-8",
|
|
441
|
+
)
|
|
442
|
+
(package / "reference" / "authoring-lanes.json").write_text(
|
|
443
|
+
'{"lanes":[{"lane":"skill-core"},{"lane":"script-contract"},{"lane":"reference"},{"lane":"pause-points"},{"lane":"eval"},{"lane":"skill-review"}],"review":{"passed":true,"blockingFindings":[]}}',
|
|
444
|
+
encoding="utf-8",
|
|
445
|
+
)
|
|
446
|
+
(package / "reference" / "skill-review.md").write_text(
|
|
447
|
+
"# Skill Review\n\nStatus: Review passed\n",
|
|
448
|
+
encoding="utf-8",
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
outputs = {
|
|
452
|
+
"completion": {"passed": ["validator ok"], "failed": []},
|
|
453
|
+
"events": {
|
|
454
|
+
"skills_invoked": ["comet-any"],
|
|
455
|
+
"num_turns": 2,
|
|
456
|
+
"tool_calls": [],
|
|
457
|
+
"duration_seconds": 10,
|
|
458
|
+
"commands_run": [],
|
|
459
|
+
},
|
|
460
|
+
"required_skills": ["comet-any"],
|
|
461
|
+
"expected_artifacts": [],
|
|
462
|
+
"interaction": {"mode": "auto_user", "max_turns": 8},
|
|
463
|
+
"skill_package_path": str(package),
|
|
464
|
+
"generated_node_skills": ["authoring-skill-open"],
|
|
465
|
+
"route_conformance_expected_node_order": ["open"],
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
passed, failed = run_profile_rubric("authoring-skill", tmp_path, outputs)
|
|
469
|
+
|
|
470
|
+
assert failed == []
|
|
471
|
+
assert any("[RUBRIC] engine_contract: 1.00 - Engine disabled for lightweight package" in msg for msg in passed)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
# ---------------------------------------------------------------------------
|
|
475
|
+
# N/A dimension scoring tests
|
|
476
|
+
# ---------------------------------------------------------------------------
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def test_generic_rubric_na_dimensions_emit_na_format(tmp_path: Path):
|
|
480
|
+
"""When required_skills and expected_artifacts are empty, those dimensions
|
|
481
|
+
should emit N/A instead of a numeric score."""
|
|
482
|
+
outputs = {
|
|
483
|
+
"completion": {"passed": ["ok"], "failed": []},
|
|
484
|
+
"events": {
|
|
485
|
+
"skills_invoked": [],
|
|
486
|
+
"num_turns": 1,
|
|
487
|
+
"tool_calls": [],
|
|
488
|
+
"duration_seconds": 5,
|
|
489
|
+
"commands_run": [],
|
|
490
|
+
},
|
|
491
|
+
"required_skills": [],
|
|
492
|
+
"expected_artifacts": [],
|
|
493
|
+
"interaction": {"mode": "none"},
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
passed, failed = run_profile_rubric("generic", tmp_path, outputs)
|
|
497
|
+
|
|
498
|
+
assert any("[RUBRIC] skill_invocation: N/A -" in msg for msg in passed)
|
|
499
|
+
assert any("[RUBRIC] artifact_presence: N/A -" in msg for msg in passed)
|
|
500
|
+
# Numeric dimensions should still have scores.
|
|
501
|
+
assert any("[RUBRIC] completion: 1.00" in msg for msg in passed)
|
|
502
|
+
assert any("[RUBRIC] efficiency:" in msg for msg in passed)
|
|
503
|
+
assert not any("skill_invocation: 0.50" in msg for msg in passed)
|
|
504
|
+
assert not any("artifact_presence: 0.50" in msg for msg in passed)
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def test_generic_rubric_skips_na_dimensions_from_weighted_score(tmp_path: Path):
|
|
508
|
+
"""The weighted score should only average over applicable dimensions,
|
|
509
|
+
not dilute with 0.5 for unconfigured ones."""
|
|
510
|
+
outputs_all_na = {
|
|
511
|
+
"completion": {"passed": ["ok"], "failed": []},
|
|
512
|
+
"events": {
|
|
513
|
+
"skills_invoked": [],
|
|
514
|
+
"num_turns": 1,
|
|
515
|
+
"tool_calls": [],
|
|
516
|
+
"duration_seconds": 5,
|
|
517
|
+
"commands_run": [],
|
|
518
|
+
},
|
|
519
|
+
"required_skills": [],
|
|
520
|
+
"expected_artifacts": [],
|
|
521
|
+
"interaction": {"mode": "none"},
|
|
522
|
+
}
|
|
523
|
+
outputs_with_skills = {
|
|
524
|
+
"completion": {"passed": ["ok"], "failed": []},
|
|
525
|
+
"events": {
|
|
526
|
+
"skills_invoked": ["target-skill"],
|
|
527
|
+
"num_turns": 1,
|
|
528
|
+
"tool_calls": [],
|
|
529
|
+
"duration_seconds": 5,
|
|
530
|
+
"commands_run": [],
|
|
531
|
+
},
|
|
532
|
+
"required_skills": ["target-skill"],
|
|
533
|
+
"expected_artifacts": ["result.md"],
|
|
534
|
+
"interaction": {"mode": "none"},
|
|
535
|
+
}
|
|
536
|
+
(tmp_path / "result.md").write_text("done")
|
|
537
|
+
|
|
538
|
+
passed_na, _ = run_profile_rubric("generic", tmp_path, outputs_all_na)
|
|
539
|
+
passed_full, _ = run_profile_rubric("generic", tmp_path, outputs_with_skills)
|
|
540
|
+
|
|
541
|
+
def _extract_weighted(passed_list: list[str]) -> float:
|
|
542
|
+
for msg in passed_list:
|
|
543
|
+
if "[RUBRIC] weighted_score:" in msg:
|
|
544
|
+
return float(msg.split("weighted_score:")[1].strip())
|
|
545
|
+
return 0.0
|
|
546
|
+
|
|
547
|
+
score_na = _extract_weighted(passed_na)
|
|
548
|
+
score_full = _extract_weighted(passed_full)
|
|
549
|
+
|
|
550
|
+
# Both should produce valid scores between 0 and 1.
|
|
551
|
+
assert 0.0 <= score_na <= 1.0
|
|
552
|
+
assert 0.0 <= score_full <= 1.0
|
|
553
|
+
# When all checks pass and no N/A dimensions, score should be 1.0.
|
|
554
|
+
assert score_full == 1.00
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def test_generic_rubric_with_required_skills_scores_numeric(tmp_path: Path):
|
|
558
|
+
"""When required_skills is configured, skill_invocation should be numeric."""
|
|
559
|
+
outputs = {
|
|
560
|
+
"completion": {"passed": ["ok"], "failed": []},
|
|
561
|
+
"events": {
|
|
562
|
+
"skills_invoked": ["target-skill"],
|
|
563
|
+
"num_turns": 1,
|
|
564
|
+
"tool_calls": [],
|
|
565
|
+
"duration_seconds": 5,
|
|
566
|
+
"commands_run": [],
|
|
567
|
+
},
|
|
568
|
+
"required_skills": ["target-skill"],
|
|
569
|
+
"expected_artifacts": [],
|
|
570
|
+
"interaction": {"mode": "none"},
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
passed, _ = run_profile_rubric("generic", tmp_path, outputs)
|
|
574
|
+
|
|
575
|
+
assert any("[RUBRIC] skill_invocation: 1.00" in msg for msg in passed)
|
|
576
|
+
assert any("[RUBRIC] artifact_presence: N/A -" in msg for msg in passed)
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def test_comet_control_marks_workflow_dimensions_not_applicable(tmp_path: Path):
|
|
580
|
+
"""CONTROL should score business completion without requiring Comet Skill use."""
|
|
581
|
+
outputs = {
|
|
582
|
+
"treatment_name": "CONTROL",
|
|
583
|
+
"business_completion": {"passed": ["sentence_feature"], "failed": []},
|
|
584
|
+
"workflow_completion": {"passed": [], "failed": ["tests_exist: No test files found"]},
|
|
585
|
+
"events": {
|
|
586
|
+
"skills_invoked": [],
|
|
587
|
+
"num_turns": 2,
|
|
588
|
+
"tool_calls": [],
|
|
589
|
+
"duration_seconds": 5,
|
|
590
|
+
"commands_run": [],
|
|
591
|
+
},
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
passed, failed = run_profile_rubric("comet-workflow", tmp_path, outputs)
|
|
595
|
+
|
|
596
|
+
assert failed == []
|
|
597
|
+
assert any("[RUBRIC] main_flow: N/A -" in msg for msg in passed)
|
|
598
|
+
assert any("[RUBRIC] gate_guard: N/A -" in msg for msg in passed)
|
|
599
|
+
assert any("[RUBRIC] skill_invocation: N/A -" in msg for msg in passed)
|
|
600
|
+
assert any("[RUBRIC] spec_drift: N/A -" in msg for msg in passed)
|
|
601
|
+
assert any("[RUBRIC] business_completion: 1.00" in msg for msg in passed)
|
|
602
|
+
assert any("[RUBRIC] workflow_completion: N/A -" in msg for msg in passed)
|
|
603
|
+
assert any("[RUBRIC] efficiency:" in msg for msg in passed)
|
|
604
|
+
assert any("[RUBRIC] weighted_score: 1.00" in msg for msg in passed)
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
def test_comet_profile_splits_business_and_workflow_completion(tmp_path: Path):
|
|
608
|
+
outputs = {
|
|
609
|
+
"business_completion": {
|
|
610
|
+
"passed": ["sentence_feature"],
|
|
611
|
+
"failed": ["business_rule: failed"],
|
|
612
|
+
},
|
|
613
|
+
"workflow_completion": {
|
|
614
|
+
"passed": ["openspec_artifacts"],
|
|
615
|
+
"failed": ["tests_exist: No test files found"],
|
|
616
|
+
},
|
|
617
|
+
"events": {
|
|
618
|
+
"skills_invoked": [
|
|
619
|
+
"comet",
|
|
620
|
+
"comet-hotfix",
|
|
621
|
+
"openspec-new-change",
|
|
622
|
+
"verification-before-completion",
|
|
623
|
+
],
|
|
624
|
+
"commands_run": [],
|
|
625
|
+
"files_created": [],
|
|
626
|
+
"files_modified": [],
|
|
627
|
+
"num_turns": 1,
|
|
628
|
+
"tool_calls": [],
|
|
629
|
+
"duration_seconds": 5,
|
|
630
|
+
},
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
passed, _ = run_profile_rubric("comet-workflow", tmp_path, outputs)
|
|
634
|
+
|
|
635
|
+
assert any("[RUBRIC] business_completion: 0.50" in msg for msg in passed)
|
|
636
|
+
assert any("[RUBRIC] workflow_completion: 0.50" in msg for msg in passed)
|
|
637
|
+
assert not any("[RUBRIC] completion:" in msg for msg in passed)
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
# ---------------------------------------------------------------------------
|
|
641
|
+
# LLM judge prompt tests
|
|
642
|
+
# ---------------------------------------------------------------------------
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
def test_generic_llm_judge_prompt_includes_custom_criteria(tmp_path: Path):
|
|
646
|
+
"""The judge prompt should include rubric_criteria from task config."""
|
|
647
|
+
from scaffold.python.generic_llm_judge import _build_generic_judge_prompt
|
|
648
|
+
|
|
649
|
+
(tmp_path / "output.txt").write_text("hello world")
|
|
650
|
+
outputs = {
|
|
651
|
+
"completion": {"passed": ["ok"], "failed": []},
|
|
652
|
+
"rubric_criteria": [
|
|
653
|
+
"The function handles edge cases",
|
|
654
|
+
"Error messages are user-friendly",
|
|
655
|
+
],
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
prompt = _build_generic_judge_prompt(tmp_path, outputs)
|
|
659
|
+
|
|
660
|
+
assert "The function handles edge cases" in prompt
|
|
661
|
+
assert "Error messages are user-friendly" in prompt
|
|
662
|
+
assert "custom_0" in prompt
|
|
663
|
+
assert "custom_1" in prompt
|
|
664
|
+
assert "task_completion" in prompt
|
|
665
|
+
assert "output_quality" in prompt
|
|
666
|
+
assert "instruction_adherence" in prompt
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
def test_generic_llm_judge_prompt_without_custom_criteria(tmp_path: Path):
|
|
670
|
+
"""Without custom criteria, prompt should have exactly 3 standard dimensions."""
|
|
671
|
+
from scaffold.python.generic_llm_judge import _build_generic_judge_prompt
|
|
672
|
+
|
|
673
|
+
(tmp_path / "output.txt").write_text("hello world")
|
|
674
|
+
outputs = {"completion": {"passed": ["ok"], "failed": []}}
|
|
675
|
+
|
|
676
|
+
prompt = _build_generic_judge_prompt(tmp_path, outputs)
|
|
677
|
+
|
|
678
|
+
assert "EXACTLY 3 lines" in prompt
|
|
679
|
+
assert "custom_0" not in prompt
|
|
680
|
+
assert "task_completion" in prompt
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
def test_generic_llm_judge_collects_workspace_files(tmp_path: Path):
|
|
684
|
+
"""The artifact collector should find non-hidden files."""
|
|
685
|
+
from scaffold.python.generic_llm_judge import _collect_workspace_artifacts
|
|
686
|
+
|
|
687
|
+
(tmp_path / "result.md").write_text("# Result\nDone")
|
|
688
|
+
(tmp_path / "src").mkdir()
|
|
689
|
+
(tmp_path / "src" / "main.py").write_text("print('hello')")
|
|
690
|
+
(tmp_path / ".git").mkdir()
|
|
691
|
+
(tmp_path / ".git" / "config").write_text("ignored")
|
|
692
|
+
|
|
693
|
+
artifacts = _collect_workspace_artifacts(tmp_path)
|
|
694
|
+
|
|
695
|
+
assert "result.md" in artifacts
|
|
696
|
+
assert str(Path("src") / "main.py") in artifacts
|
|
697
|
+
assert ".git" not in artifacts
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
def test_judge_env_requires_explicit_judge_model(monkeypatch):
|
|
701
|
+
"""LLM judge must not silently reuse the subject model."""
|
|
702
|
+
from scaffold.python.judge_config import build_judge_invocation
|
|
703
|
+
|
|
704
|
+
monkeypatch.setenv("ANTHROPIC_MODEL", "subject-model")
|
|
705
|
+
monkeypatch.delenv("BENCH_JUDGE_MODEL", raising=False)
|
|
706
|
+
|
|
707
|
+
try:
|
|
708
|
+
build_judge_invocation()
|
|
709
|
+
except ValueError as exc:
|
|
710
|
+
assert "BENCH_JUDGE_MODEL" in str(exc)
|
|
711
|
+
else:
|
|
712
|
+
raise AssertionError("expected missing BENCH_JUDGE_MODEL to fail")
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
def test_judge_env_maps_independent_provider(monkeypatch):
|
|
716
|
+
"""Judge subprocess env should use BENCH_JUDGE_* instead of subject ANTHROPIC_*."""
|
|
717
|
+
from scaffold.python.judge_config import build_judge_invocation
|
|
718
|
+
|
|
719
|
+
monkeypatch.setenv("ANTHROPIC_MODEL", "subject-model")
|
|
720
|
+
monkeypatch.setenv("ANTHROPIC_BASE_URL", "https://subject.example")
|
|
721
|
+
monkeypatch.setenv("ANTHROPIC_AUTH_TOKEN", "subject-token")
|
|
722
|
+
monkeypatch.setenv("ANTHROPIC_API_KEY", "subject-key")
|
|
723
|
+
monkeypatch.setenv("BENCH_JUDGE_MODEL", "judge-model")
|
|
724
|
+
monkeypatch.setenv("BENCH_JUDGE_BASE_URL", "https://judge.example")
|
|
725
|
+
monkeypatch.setenv("BENCH_JUDGE_AUTH_TOKEN", "judge-token")
|
|
726
|
+
|
|
727
|
+
invocation = build_judge_invocation()
|
|
728
|
+
|
|
729
|
+
assert invocation.model_flag == ["--model", "judge-model"]
|
|
730
|
+
assert invocation.env["ANTHROPIC_MODEL"] == "judge-model"
|
|
731
|
+
assert invocation.env["ANTHROPIC_BASE_URL"] == "https://judge.example"
|
|
732
|
+
assert invocation.env["ANTHROPIC_AUTH_TOKEN"] == "judge-token"
|
|
733
|
+
assert "ANTHROPIC_API_KEY" not in invocation.env
|
|
734
|
+
assert "subject-model" not in invocation.env.values()
|
|
735
|
+
assert "subject-token" not in invocation.env.values()
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
def test_judge_provider_uses_direct_http_when_base_url_is_configured(monkeypatch):
|
|
739
|
+
"""Dedicated judge providers should not require Claude CLI compatibility."""
|
|
740
|
+
import json
|
|
741
|
+
from unittest.mock import patch
|
|
742
|
+
|
|
743
|
+
from scaffold.python.judge_config import run_judge_prompt
|
|
744
|
+
|
|
745
|
+
monkeypatch.setenv("BENCH_JUDGE_MODEL", "judge-model")
|
|
746
|
+
monkeypatch.setenv("BENCH_JUDGE_BASE_URL", "https://judge.example/api/anthropic")
|
|
747
|
+
monkeypatch.setenv("BENCH_JUDGE_AUTH_TOKEN", "judge-token")
|
|
748
|
+
|
|
749
|
+
class FakeResponse:
|
|
750
|
+
def __enter__(self):
|
|
751
|
+
return self
|
|
752
|
+
|
|
753
|
+
def __exit__(self, *_args):
|
|
754
|
+
return False
|
|
755
|
+
|
|
756
|
+
def read(self):
|
|
757
|
+
return json.dumps(
|
|
758
|
+
{
|
|
759
|
+
"content": [
|
|
760
|
+
{
|
|
761
|
+
"type": "text",
|
|
762
|
+
"text": "[RUBRIC-JUDGE] task_completion: 1.00 - ok",
|
|
763
|
+
}
|
|
764
|
+
]
|
|
765
|
+
}
|
|
766
|
+
).encode("utf-8")
|
|
767
|
+
|
|
768
|
+
with patch("urllib.request.urlopen", return_value=FakeResponse()) as urlopen:
|
|
769
|
+
output = run_judge_prompt("score this")
|
|
770
|
+
|
|
771
|
+
request = urlopen.call_args.args[0]
|
|
772
|
+
assert request.full_url == "https://judge.example/api/anthropic/v1/messages"
|
|
773
|
+
assert request.headers["Authorization"] == "Bearer judge-token"
|
|
774
|
+
assert json.loads(request.data.decode("utf-8"))["model"] == "judge-model"
|
|
775
|
+
assert output == "[RUBRIC-JUDGE] task_completion: 1.00 - ok"
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
def test_comet_llm_judge_reports_skipped_without_success_status(monkeypatch, tmp_path: Path):
|
|
779
|
+
"""Missing judge config should be visible and not reported as successful."""
|
|
780
|
+
from scaffold.python.llm_judge import judge_messages
|
|
781
|
+
|
|
782
|
+
change = tmp_path / "openspec" / "changes" / "demo"
|
|
783
|
+
change.mkdir(parents=True)
|
|
784
|
+
(change / "proposal.md").write_text("proposal")
|
|
785
|
+
monkeypatch.setenv("BENCH_LLM_JUDGE", "1")
|
|
786
|
+
monkeypatch.setenv("ANTHROPIC_MODEL", "subject-model")
|
|
787
|
+
monkeypatch.delenv("BENCH_JUDGE_MODEL", raising=False)
|
|
788
|
+
|
|
789
|
+
messages = judge_messages(tmp_path)
|
|
790
|
+
|
|
791
|
+
assert messages == [
|
|
792
|
+
"[RUBRIC-JUDGE] status: skipped - BENCH_JUDGE_MODEL is required when BENCH_LLM_JUDGE=1"
|
|
793
|
+
]
|
|
794
|
+
assert not any("enabled_and_successful" in msg for msg in messages)
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
def test_comet_profile_does_not_mark_skipped_judge_successful(monkeypatch, tmp_path: Path):
|
|
798
|
+
"""Profile rubric should not add success status when judge config is missing."""
|
|
799
|
+
from scaffold.python.profiles import run_profile_rubric
|
|
800
|
+
|
|
801
|
+
change = tmp_path / "openspec" / "changes" / "demo"
|
|
802
|
+
change.mkdir(parents=True)
|
|
803
|
+
(change / "proposal.md").write_text("proposal")
|
|
804
|
+
monkeypatch.setenv("BENCH_LLM_JUDGE", "1")
|
|
805
|
+
monkeypatch.setenv("ANTHROPIC_MODEL", "subject-model")
|
|
806
|
+
monkeypatch.delenv("BENCH_JUDGE_MODEL", raising=False)
|
|
807
|
+
|
|
808
|
+
passed, _ = run_profile_rubric(
|
|
809
|
+
"comet-workflow",
|
|
810
|
+
tmp_path,
|
|
811
|
+
{"completion": {"passed": ["ok"], "failed": []}},
|
|
812
|
+
)
|
|
813
|
+
|
|
814
|
+
assert any("[RUBRIC-JUDGE] status: skipped" in msg for msg in passed)
|
|
815
|
+
assert not any("[RUBRIC-JUDGE] status: enabled_and_successful" in msg for msg in passed)
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
def test_generic_llm_judge_parses_output(tmp_path: Path):
|
|
819
|
+
"""judge_generic_artifacts should parse [RUBRIC-JUDGE] lines correctly."""
|
|
820
|
+
from unittest.mock import patch
|
|
821
|
+
from scaffold.python.generic_llm_judge import judge_generic_artifacts
|
|
822
|
+
|
|
823
|
+
mock_output = (
|
|
824
|
+
"[RUBRIC-JUDGE] task_completion: 0.80 - output present and mostly correct\n"
|
|
825
|
+
"[RUBRIC-JUDGE] output_quality: 0.90 - well-structured code\n"
|
|
826
|
+
"[RUBRIC-JUDGE] instruction_adherence: 1.00 - all constraints followed\n"
|
|
827
|
+
)
|
|
828
|
+
outputs = {"completion": {"passed": [], "failed": []}}
|
|
829
|
+
|
|
830
|
+
with patch(
|
|
831
|
+
"scaffold.python.generic_llm_judge._run_judge",
|
|
832
|
+
return_value=mock_output,
|
|
833
|
+
):
|
|
834
|
+
scores = judge_generic_artifacts(tmp_path, outputs)
|
|
835
|
+
|
|
836
|
+
assert scores["task_completion"] == (0.80, "output present and mostly correct")
|
|
837
|
+
assert scores["output_quality"] == (0.90, "well-structured code")
|
|
838
|
+
assert scores["instruction_adherence"] == (1.00, "all constraints followed")
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def test_generic_llm_judge_parses_custom_dimensions(tmp_path: Path):
|
|
842
|
+
"""Custom rubric criteria should produce custom_N dimensions in output."""
|
|
843
|
+
from unittest.mock import patch
|
|
844
|
+
from scaffold.python.generic_llm_judge import judge_generic_artifacts
|
|
845
|
+
|
|
846
|
+
mock_output = (
|
|
847
|
+
"[RUBRIC-JUDGE] task_completion: 1.00 - done\n"
|
|
848
|
+
"[RUBRIC-JUDGE] output_quality: 0.80 - good\n"
|
|
849
|
+
"[RUBRIC-JUDGE] instruction_adherence: 1.00 - ok\n"
|
|
850
|
+
"[RUBRIC-JUDGE] custom_0: 0.90 - handles edge cases well\n"
|
|
851
|
+
"[RUBRIC-JUDGE] custom_1: 0.70 - error messages could improve\n"
|
|
852
|
+
)
|
|
853
|
+
outputs = {
|
|
854
|
+
"completion": {"passed": [], "failed": []},
|
|
855
|
+
"rubric_criteria": ["edge cases", "error messages"],
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
with patch(
|
|
859
|
+
"scaffold.python.generic_llm_judge._run_judge",
|
|
860
|
+
return_value=mock_output,
|
|
861
|
+
):
|
|
862
|
+
scores = judge_generic_artifacts(tmp_path, outputs)
|
|
863
|
+
|
|
864
|
+
assert "custom_0" in scores
|
|
865
|
+
assert "custom_1" in scores
|
|
866
|
+
assert scores["custom_0"] == (0.90, "handles edge cases well")
|