productfoo 0.0.0-stage → 1.0.1
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/LICENSE +201 -0
- package/README.md +338 -2
- package/bin/foo +3 -0
- package/bin/foo.mjs +42 -0
- package/commands/bug.md +31 -0
- package/commands/discovery.md +28 -0
- package/commands/ideate.md +27 -0
- package/commands/init.md +28 -0
- package/commands/pitch.md +27 -0
- package/commands/preview.md +25 -0
- package/commands/research.md +31 -0
- package/commands/roast.md +27 -0
- package/commands/spec.md +30 -0
- package/config/pricing.yaml +198 -0
- package/config/routing-policy.yaml +171 -0
- package/dist-public/src/activeModel.d.ts +83 -0
- package/dist-public/src/activeModel.js +331 -0
- package/dist-public/src/agentAdapters.d.ts +122 -0
- package/dist-public/src/agentAdapters.js +178 -0
- package/dist-public/src/agentState.d.ts +43 -0
- package/dist-public/src/agentState.js +177 -0
- package/dist-public/src/bugCapsule.d.ts +94 -0
- package/dist-public/src/bugCapsule.js +227 -0
- package/dist-public/src/bugCapture.d.ts +26 -0
- package/dist-public/src/bugCapture.js +251 -0
- package/dist-public/src/bugOwnerLog.d.ts +93 -0
- package/dist-public/src/bugOwnerLog.js +304 -0
- package/dist-public/src/bugReportStore.d.ts +48 -0
- package/dist-public/src/bugReportStore.js +860 -0
- package/dist-public/src/bugSpecContext.d.ts +7 -0
- package/dist-public/src/bugSpecContext.js +129 -0
- package/dist-public/src/channelFreshness.d.ts +25 -0
- package/dist-public/src/channelFreshness.js +194 -0
- package/dist-public/src/cli.d.ts +30 -0
- package/dist-public/src/cli.js +1667 -0
- package/dist-public/src/cliArgs.d.ts +7 -0
- package/dist-public/src/cliArgs.js +44 -0
- package/dist-public/src/codeCatalog.d.ts +41 -0
- package/dist-public/src/codeCatalog.js +197 -0
- package/dist-public/src/commandContract.d.ts +84 -0
- package/dist-public/src/commandContract.js +390 -0
- package/dist-public/src/commandUsage.d.ts +3 -0
- package/dist-public/src/commandUsage.js +30 -0
- package/dist-public/src/commands/agent.d.ts +60 -0
- package/dist-public/src/commands/agent.js +1353 -0
- package/dist-public/src/commands/asp.d.ts +8 -0
- package/dist-public/src/commands/asp.js +669 -0
- package/dist-public/src/commands/evalCmd.d.ts +4 -0
- package/dist-public/src/commands/evalCmd.js +405 -0
- package/dist-public/src/commands/login.d.ts +25 -0
- package/dist-public/src/commands/login.js +94 -0
- package/dist-public/src/commands/loop.d.ts +16 -0
- package/dist-public/src/commands/loop.js +619 -0
- package/dist-public/src/commands/reconcile.d.ts +41 -0
- package/dist-public/src/commands/reconcile.js +292 -0
- package/dist-public/src/commands/runtime.d.ts +1 -0
- package/dist-public/src/commands/runtime.js +36 -0
- package/dist-public/src/commands/scanRedact.d.ts +8 -0
- package/dist-public/src/commands/scanRedact.js +266 -0
- package/dist-public/src/commands/setup.d.ts +28 -0
- package/dist-public/src/commands/setup.js +398 -0
- package/dist-public/src/commands/shared.d.ts +17 -0
- package/dist-public/src/commands/shared.js +147 -0
- package/dist-public/src/commands/source.d.ts +1 -0
- package/dist-public/src/commands/source.js +134 -0
- package/dist-public/src/commands/specCmd.d.ts +24 -0
- package/dist-public/src/commands/specCmd.js +794 -0
- package/dist-public/src/commands/update.d.ts +61 -0
- package/dist-public/src/commands/update.js +244 -0
- package/dist-public/src/comprehensionSignal.d.ts +20 -0
- package/dist-public/src/comprehensionSignal.js +166 -0
- package/dist-public/src/conductor/diversity.d.ts +48 -0
- package/dist-public/src/conductor/diversity.js +423 -0
- package/dist-public/src/conductor/engine.d.ts +7 -0
- package/dist-public/src/conductor/engine.js +295 -0
- package/dist-public/src/conductor/families/ideate.d.ts +2 -0
- package/dist-public/src/conductor/families/ideate.js +255 -0
- package/dist-public/src/conductor/families/interview.d.ts +2 -0
- package/dist-public/src/conductor/families/interview.js +39 -0
- package/dist-public/src/conductor/families/specSwarm.d.ts +2 -0
- package/dist-public/src/conductor/families/specSwarm.js +146 -0
- package/dist-public/src/conductor/familyDelivery.d.ts +6 -0
- package/dist-public/src/conductor/familyDelivery.js +37 -0
- package/dist-public/src/conductor/familyPackArtifact.d.ts +4 -0
- package/dist-public/src/conductor/familyPackArtifact.js +260 -0
- package/dist-public/src/conductor/ideateDecision.d.ts +6 -0
- package/dist-public/src/conductor/ideateDecision.js +237 -0
- package/dist-public/src/conductor/pack.d.ts +26 -0
- package/dist-public/src/conductor/pack.js +75 -0
- package/dist-public/src/conductor/types.d.ts +111 -0
- package/dist-public/src/conductor/types.js +7 -0
- package/dist-public/src/configPath.d.ts +2 -0
- package/dist-public/src/configPath.js +7 -0
- package/dist-public/src/discoveryArtifacts.d.ts +54 -0
- package/dist-public/src/discoveryArtifacts.js +467 -0
- package/dist-public/src/discoveryCommand.d.ts +127 -0
- package/dist-public/src/discoveryCommand.js +2148 -0
- package/dist-public/src/discoveryConnections.d.ts +339 -0
- package/dist-public/src/discoveryConnections.js +613 -0
- package/dist-public/src/discoveryDocs.d.ts +129 -0
- package/dist-public/src/discoveryDocs.js +577 -0
- package/dist-public/src/discoveryEvidence.d.ts +59 -0
- package/dist-public/src/discoveryEvidence.js +198 -0
- package/dist-public/src/discoveryFireflies.d.ts +25 -0
- package/dist-public/src/discoveryFireflies.js +551 -0
- package/dist-public/src/discoveryGmail.d.ts +12 -0
- package/dist-public/src/discoveryGmail.js +466 -0
- package/dist-public/src/discoveryGong.d.ts +12 -0
- package/dist-public/src/discoveryGong.js +491 -0
- package/dist-public/src/discoveryLearningRouting.d.ts +90 -0
- package/dist-public/src/discoveryLearningRouting.js +405 -0
- package/dist-public/src/discoveryMatching.d.ts +26 -0
- package/dist-public/src/discoveryMatching.js +73 -0
- package/dist-public/src/discoveryOutlook.d.ts +12 -0
- package/dist-public/src/discoveryOutlook.js +492 -0
- package/dist-public/src/discoveryProcess.d.ts +221 -0
- package/dist-public/src/discoveryProcess.js +703 -0
- package/dist-public/src/discoveryProof.d.ts +143 -0
- package/dist-public/src/discoveryProof.js +529 -0
- package/dist-public/src/discoveryProviders.d.ts +152 -0
- package/dist-public/src/discoveryProviders.js +756 -0
- package/dist-public/src/discoveryReadiness.d.ts +219 -0
- package/dist-public/src/discoveryReadiness.js +672 -0
- package/dist-public/src/discoveryReconcile.d.ts +57 -0
- package/dist-public/src/discoveryReconcile.js +424 -0
- package/dist-public/src/discoverySlack.d.ts +12 -0
- package/dist-public/src/discoverySlack.js +452 -0
- package/dist-public/src/discoverySources.d.ts +56 -0
- package/dist-public/src/discoverySources.js +322 -0
- package/dist-public/src/discoverySync.d.ts +52 -0
- package/dist-public/src/discoverySync.js +151 -0
- package/dist-public/src/discoverySynthesis.d.ts +57 -0
- package/dist-public/src/discoverySynthesis.js +215 -0
- package/dist-public/src/discoveryTeams.d.ts +12 -0
- package/dist-public/src/discoveryTeams.js +516 -0
- package/dist-public/src/discoveryZoom.d.ts +12 -0
- package/dist-public/src/discoveryZoom.js +523 -0
- package/dist-public/src/elicitationSurface.d.ts +13 -0
- package/dist-public/src/elicitationSurface.js +77 -0
- package/dist-public/src/errorReport.d.ts +99 -0
- package/dist-public/src/errorReport.js +443 -0
- package/dist-public/src/errorTaxonomy.d.ts +84 -0
- package/dist-public/src/errorTaxonomy.js +189 -0
- package/dist-public/src/evalCalibration.d.ts +82 -0
- package/dist-public/src/evalCalibration.js +169 -0
- package/dist-public/src/evalChecks.d.ts +21 -0
- package/dist-public/src/evalChecks.js +295 -0
- package/dist-public/src/evalCompile.d.ts +56 -0
- package/dist-public/src/evalCompile.js +58 -0
- package/dist-public/src/evalImprove.d.ts +60 -0
- package/dist-public/src/evalImprove.js +175 -0
- package/dist-public/src/evalJudge.d.ts +47 -0
- package/dist-public/src/evalJudge.js +143 -0
- package/dist-public/src/evalLabels.d.ts +100 -0
- package/dist-public/src/evalLabels.js +287 -0
- package/dist-public/src/evalRecord.d.ts +68 -0
- package/dist-public/src/evalRecord.js +165 -0
- package/dist-public/src/evalRoast.d.ts +88 -0
- package/dist-public/src/evalRoast.js +249 -0
- package/dist-public/src/evidenceIntake.d.ts +66 -0
- package/dist-public/src/evidenceIntake.js +356 -0
- package/dist-public/src/feedback.d.ts +78 -0
- package/dist-public/src/feedback.js +294 -0
- package/dist-public/src/firefliesClient.d.ts +106 -0
- package/dist-public/src/firefliesClient.js +258 -0
- package/dist-public/src/firstMoveTensions.d.ts +10 -0
- package/dist-public/src/firstMoveTensions.js +93 -0
- package/dist-public/src/gitRun.d.ts +21 -0
- package/dist-public/src/gitRun.js +50 -0
- package/dist-public/src/githubReconcile.d.ts +94 -0
- package/dist-public/src/githubReconcile.js +205 -0
- package/dist-public/src/gmailNango.d.ts +131 -0
- package/dist-public/src/gmailNango.js +329 -0
- package/dist-public/src/gongNango.d.ts +118 -0
- package/dist-public/src/gongNango.js +308 -0
- package/dist-public/src/grammarGate.d.ts +13 -0
- package/dist-public/src/grammarGate.js +72 -0
- package/dist-public/src/harnessGates.d.ts +65 -0
- package/dist-public/src/harnessGates.js +168 -0
- package/dist-public/src/humanSurfaceEval.d.ts +19 -0
- package/dist-public/src/humanSurfaceEval.js +156 -0
- package/dist-public/src/ideate.d.ts +43 -0
- package/dist-public/src/ideate.js +255 -0
- package/dist-public/src/ideateContext.d.ts +11 -0
- package/dist-public/src/ideateContext.js +83 -0
- package/dist-public/src/index.d.ts +2 -0
- package/dist-public/src/index.js +4 -0
- package/dist-public/src/initCommand.d.ts +25 -0
- package/dist-public/src/initCommand.js +558 -0
- package/dist-public/src/interviewGate.d.ts +25 -0
- package/dist-public/src/interviewGate.js +126 -0
- package/dist-public/src/jsonFile.d.ts +2 -0
- package/dist-public/src/jsonFile.js +22 -0
- package/dist-public/src/loopBudget.d.ts +182 -0
- package/dist-public/src/loopBudget.js +494 -0
- package/dist-public/src/loopContracts.d.ts +35 -0
- package/dist-public/src/loopContracts.js +364 -0
- package/dist-public/src/machineState.d.ts +1 -0
- package/dist-public/src/machineState.js +9 -0
- package/dist-public/src/notionNango.d.ts +93 -0
- package/dist-public/src/notionNango.js +279 -0
- package/dist-public/src/orchestrationResult.d.ts +11 -0
- package/dist-public/src/orchestrationResult.js +73 -0
- package/dist-public/src/outlookNango.d.ts +124 -0
- package/dist-public/src/outlookNango.js +327 -0
- package/dist-public/src/packetCorrections.d.ts +40 -0
- package/dist-public/src/packetCorrections.js +172 -0
- package/dist-public/src/packetGlossary.d.ts +6 -0
- package/dist-public/src/packetGlossary.js +42 -0
- package/dist-public/src/packetIndex.d.ts +54 -0
- package/dist-public/src/packetIndex.js +744 -0
- package/dist-public/src/packetIndexEntry.d.ts +3 -0
- package/dist-public/src/packetIndexEntry.js +128 -0
- package/dist-public/src/packetIndexServe.d.ts +13 -0
- package/dist-public/src/packetIndexServe.js +113 -0
- package/dist-public/src/packetIndexWorker.d.ts +7 -0
- package/dist-public/src/packetIndexWorker.js +45 -0
- package/dist-public/src/packetLifecycle.d.ts +30 -0
- package/dist-public/src/packetLifecycle.js +127 -0
- package/dist-public/src/packetReconcile.d.ts +73 -0
- package/dist-public/src/packetReconcile.js +386 -0
- package/dist-public/src/packetStatus.d.ts +125 -0
- package/dist-public/src/packetStatus.js +770 -0
- package/dist-public/src/packetValidation.d.ts +17 -0
- package/dist-public/src/packetValidation.js +333 -0
- package/dist-public/src/packetVerify.d.ts +73 -0
- package/dist-public/src/packetVerify.js +303 -0
- package/dist-public/src/packetWrite.d.ts +52 -0
- package/dist-public/src/packetWrite.js +448 -0
- package/dist-public/src/pitch.d.ts +38 -0
- package/dist-public/src/pitch.js +154 -0
- package/dist-public/src/processMemo.d.ts +8 -0
- package/dist-public/src/processMemo.js +23 -0
- package/dist-public/src/productDetect.d.ts +30 -0
- package/dist-public/src/productDetect.js +376 -0
- package/dist-public/src/profile.d.ts +62 -0
- package/dist-public/src/profile.js +334 -0
- package/dist-public/src/questionModel.d.ts +46 -0
- package/dist-public/src/questionModel.js +74 -0
- package/dist-public/src/questionText.d.ts +7 -0
- package/dist-public/src/questionText.js +38 -0
- package/dist-public/src/redactConfig.d.ts +2 -0
- package/dist-public/src/redactConfig.js +11 -0
- package/dist-public/src/redactEngine.d.ts +59 -0
- package/dist-public/src/redactEngine.js +509 -0
- package/dist-public/src/redactGate.d.ts +63 -0
- package/dist-public/src/redactGate.js +209 -0
- package/dist-public/src/repoRead.d.ts +29 -0
- package/dist-public/src/repoRead.js +160 -0
- package/dist-public/src/research.d.ts +242 -0
- package/dist-public/src/research.js +1314 -0
- package/dist-public/src/researchCompletion.d.ts +34 -0
- package/dist-public/src/researchCompletion.js +123 -0
- package/dist-public/src/researchExecution.d.ts +47 -0
- package/dist-public/src/researchExecution.js +309 -0
- package/dist-public/src/researchFormat.d.ts +21 -0
- package/dist-public/src/researchFormat.js +77 -0
- package/dist-public/src/researchGate.d.ts +86 -0
- package/dist-public/src/researchGate.js +1036 -0
- package/dist-public/src/researchReceipt.d.ts +76 -0
- package/dist-public/src/researchReceipt.js +148 -0
- package/dist-public/src/researchRender.d.ts +2 -0
- package/dist-public/src/researchRender.js +267 -0
- package/dist-public/src/researchSigningKey.d.ts +19 -0
- package/dist-public/src/researchSigningKey.js +95 -0
- package/dist-public/src/riskClassify.d.ts +42 -0
- package/dist-public/src/riskClassify.js +149 -0
- package/dist-public/src/routines.d.ts +42 -0
- package/dist-public/src/routines.js +269 -0
- package/dist-public/src/routingPolicy.d.ts +172 -0
- package/dist-public/src/routingPolicy.js +646 -0
- package/dist-public/src/secretInput.d.ts +8 -0
- package/dist-public/src/secretInput.js +89 -0
- package/dist-public/src/selfCheck.d.ts +7 -0
- package/dist-public/src/selfCheck.js +473 -0
- package/dist-public/src/selfCheckCache.d.ts +29 -0
- package/dist-public/src/selfCheckCache.js +147 -0
- package/dist-public/src/severityClass.d.ts +15 -0
- package/dist-public/src/severityClass.js +22 -0
- package/dist-public/src/skillClientPolicy.d.ts +8 -0
- package/dist-public/src/skillClientPolicy.js +16 -0
- package/dist-public/src/skillLocal.d.ts +98 -0
- package/dist-public/src/skillLocal.js +463 -0
- package/dist-public/src/skillTreeDigest.d.ts +9 -0
- package/dist-public/src/skillTreeDigest.js +64 -0
- package/dist-public/src/slackNango.d.ts +62 -0
- package/dist-public/src/slackNango.js +208 -0
- package/dist-public/src/social/arxiv.d.ts +19 -0
- package/dist-public/src/social/arxiv.js +96 -0
- package/dist-public/src/social/github.d.ts +2 -0
- package/dist-public/src/social/github.js +78 -0
- package/dist-public/src/social/hackernews.d.ts +2 -0
- package/dist-public/src/social/hackernews.js +67 -0
- package/dist-public/src/social/index.d.ts +10 -0
- package/dist-public/src/social/index.js +79 -0
- package/dist-public/src/social/reddit.d.ts +2 -0
- package/dist-public/src/social/reddit.js +125 -0
- package/dist-public/src/social/types.d.ts +73 -0
- package/dist-public/src/social/types.js +61 -0
- package/dist-public/src/social/xml.d.ts +10 -0
- package/dist-public/src/social/xml.js +49 -0
- package/dist-public/src/social/youtube.d.ts +7 -0
- package/dist-public/src/social/youtube.js +217 -0
- package/dist-public/src/sourceIngress.d.ts +488 -0
- package/dist-public/src/sourceIngress.js +1651 -0
- package/dist-public/src/specAfter.d.ts +187 -0
- package/dist-public/src/specAfter.js +814 -0
- package/dist-public/src/specBudget.d.ts +124 -0
- package/dist-public/src/specBudget.js +424 -0
- package/dist-public/src/specDecisionSignals.d.ts +38 -0
- package/dist-public/src/specDecisionSignals.js +121 -0
- package/dist-public/src/specLinkedCommits.d.ts +7 -0
- package/dist-public/src/specLinkedCommits.js +107 -0
- package/dist-public/src/specSections.d.ts +105 -0
- package/dist-public/src/specSections.js +718 -0
- package/dist-public/src/statusGlyphs.d.ts +18 -0
- package/dist-public/src/statusGlyphs.js +75 -0
- package/dist-public/src/swarmCommand.d.ts +10 -0
- package/dist-public/src/swarmCommand.js +96 -0
- package/dist-public/src/teamsNango.d.ts +114 -0
- package/dist-public/src/teamsNango.js +301 -0
- package/dist-public/src/tokenStore.d.ts +10 -0
- package/dist-public/src/tokenStore.js +77 -0
- package/dist-public/src/trustEnvelope.d.ts +78 -0
- package/dist-public/src/trustEnvelope.js +392 -0
- package/dist-public/src/untrustedText.d.ts +6 -0
- package/dist-public/src/untrustedText.js +20 -0
- package/dist-public/src/updateNotice.d.ts +41 -0
- package/dist-public/src/updateNotice.js +290 -0
- package/dist-public/src/vendorYaml.d.ts +1 -0
- package/dist-public/src/vendorYaml.js +7374 -0
- package/dist-public/src/workflowRunActuals.d.ts +67 -0
- package/dist-public/src/workflowRunActuals.js +184 -0
- package/dist-public/src/zendeskDiscovery.d.ts +12 -0
- package/dist-public/src/zendeskDiscovery.js +513 -0
- package/dist-public/src/zendeskNango.d.ts +131 -0
- package/dist-public/src/zendeskNango.js +344 -0
- package/dist-public/src/zoomNango.d.ts +106 -0
- package/dist-public/src/zoomNango.js +351 -0
- package/docs/CHANGELOG.md +32 -0
- package/docs/THIRD_PARTY_NOTICES.md +36 -0
- package/package.json +71 -4
- package/schemas/bug-capsule-receipt.schema.json +54 -0
- package/schemas/bug-capsule.schema.json +189 -0
- package/schemas/discovery-evidence-envelope.schema.json +79 -0
- package/schemas/discovery-processing-receipt.schema.json +71 -0
- package/schemas/discovery-service-contract.schema.json +189 -0
- package/skills/AGENTS.md +32 -0
- package/skills/README.md +287 -0
- package/skills/bug/SKILL.md +49 -0
- package/skills/build-preview-spec/SKILL.md +103 -0
- package/skills/capture-external-artifact/SKILL.md +23 -0
- package/skills/capture-external-artifact/agents/openai.yaml +4 -0
- package/skills/capture-external-artifact/references/extractor-libraries.md +27 -0
- package/skills/check-spec-health/SKILL.md +45 -0
- package/skills/check-spec-health/agents/openai.yaml +4 -0
- package/skills/competitive-positioning/SKILL.md +86 -0
- package/skills/competitive-positioning/agents/openai.yaml +4 -0
- package/skills/cpo-lens/SKILL.md +398 -0
- package/skills/cpo-lens/agents/openai.yaml +4 -0
- package/skills/create-prd/SKILL.md +26 -0
- package/skills/create-prd/agents/openai.yaml +4 -0
- package/skills/customer-discovery/SKILL.md +192 -0
- package/skills/design-system/SKILL.md +49 -0
- package/skills/design-system/agents/openai.yaml +4 -0
- package/skills/discussion-guide/SKILL.md +75 -0
- package/skills/discussion-guide/agents/openai.yaml +4 -0
- package/skills/firecrawl-research-papers/SKILL.md +96 -0
- package/skills/firecrawl-research-papers/agents/openai.yaml +4 -0
- package/skills/foo-roast/SKILL.md +325 -0
- package/skills/generate-gtm-brief/SKILL.md +41 -0
- package/skills/generate-gtm-brief/agents/openai.yaml +4 -0
- package/skills/generate-gtm-brief/references/gtm-brief-template.md +56 -0
- package/skills/gong-quotes/SKILL.md +43 -0
- package/skills/gong-quotes/agents/openai.yaml +4 -0
- package/skills/grill-me/SKILL.md +27 -0
- package/skills/grill-me/agents/openai.yaml +4 -0
- package/skills/ideate/SKILL.md +180 -0
- package/skills/ideate/references/family-packs.md +5 -0
- package/skills/initiative-tracker/SKILL.md +23 -0
- package/skills/initiative-tracker/agents/openai.yaml +4 -0
- package/skills/interop-review/SKILL.md +25 -0
- package/skills/interop-review/agents/openai.yaml +4 -0
- package/skills/interview-me/SKILL.md +404 -0
- package/skills/interview-me/agents/openai.yaml +4 -0
- package/skills/loop-library-audit/SKILL.md +123 -0
- package/skills/pitch/SKILL.md +110 -0
- package/skills/pitch/references/opportunity-assessment.md +136 -0
- package/skills/pitch/references/prfaq-template.md +54 -0
- package/skills/pmm-release-briefing/SKILL.md +27 -0
- package/skills/pmm-release-briefing/agents/openai.yaml +4 -0
- package/skills/pmm-release-briefing/references/variant-generalized.md +16 -0
- package/skills/positioning-messaging/SKILL.md +70 -0
- package/skills/positioning-messaging/agents/openai.yaml +4 -0
- package/skills/positioning-messaging/references/guest-insights.md +1400 -0
- package/skills/preview-swarm/SKILL.md +418 -0
- package/skills/preview-swarm/agents/openai.yaml +4 -0
- package/skills/preview-swarm/references/html-effectiveness-build-previews.md +168 -0
- package/skills/product-copywriting/SKILL.md +127 -0
- package/skills/product-copywriting/agents/openai.yaml +4 -0
- package/skills/product-copywriting/references/foo-voice.md +26 -0
- package/skills/product-shape-interview/SKILL.md +219 -0
- package/skills/product-shape-interview/agents/openai.yaml +4 -0
- package/skills/ready-for-release/SKILL.md +39 -0
- package/skills/ready-for-release/agents/openai.yaml +4 -0
- package/skills/redact-transcripts/SKILL.md +23 -0
- package/skills/redact-transcripts/agents/openai.yaml +4 -0
- package/skills/research-brief/SKILL.md +48 -0
- package/skills/research-brief/agents/openai.yaml +4 -0
- package/skills/research-refresh/SKILL.md +63 -0
- package/skills/research-refresh/references/worked-cases.md +44 -0
- package/skills/review-loop/SKILL.md +200 -0
- package/skills/review-spec/SKILL.md +32 -0
- package/skills/review-spec/agents/openai.yaml +4 -0
- package/skills/rfc-from-research/SKILL.md +42 -0
- package/skills/rfc-from-research/agents/openai.yaml +4 -0
- package/skills/rfc-from-research/references/rfc-pattern.md +69 -0
- package/skills/skill-registry.yaml +810 -0
- package/skills/spec-cleanup/SKILL.md +103 -0
- package/skills/spec-cleanup/agents/openai.yaml +4 -0
- package/skills/spec-swarm/SKILL.md +87 -0
- package/skills/spec-swarm/agents/openai.yaml +4 -0
- package/skills/spec-swarm/template/SKILL.template.md +94 -0
- package/skills/spec-swarm/template/personas/accessibility-inclusion.md +40 -0
- package/skills/spec-swarm/template/personas/ai-technical-pm.md +69 -0
- package/skills/spec-swarm/template/personas/analytics-engineering.md +39 -0
- package/skills/spec-swarm/template/personas/applied-ai-eval.md +64 -0
- package/skills/spec-swarm/template/personas/business-gm-pm.md +67 -0
- package/skills/spec-swarm/template/personas/consumer-craft-pm.md +68 -0
- package/skills/spec-swarm/template/personas/content-design.md +40 -0
- package/skills/spec-swarm/template/personas/cpo.md +42 -0
- package/skills/spec-swarm/template/personas/data-science.md +42 -0
- package/skills/spec-swarm/template/personas/developer-experience.md +65 -0
- package/skills/spec-swarm/template/personas/dx-product.md +70 -0
- package/skills/spec-swarm/template/personas/field.md +43 -0
- package/skills/spec-swarm/template/personas/finance-cfo.md +40 -0
- package/skills/spec-swarm/template/personas/growth-pm.md +67 -0
- package/skills/spec-swarm/template/personas/platform-pm.md +67 -0
- package/skills/spec-swarm/template/personas/pmm.md +43 -0
- package/skills/spec-swarm/template/personas/principal-product-designer.md +42 -0
- package/skills/spec-swarm/template/personas/product-ops-program.md +41 -0
- package/skills/spec-swarm/template/personas/qa-release.md +41 -0
- package/skills/spec-swarm/template/personas/responsible-ai-safety.md +64 -0
- package/skills/spec-swarm/template/personas/security-privacy-legal.md +40 -0
- package/skills/spec-swarm/template/personas/strategy-competitive.md +41 -0
- package/skills/spec-swarm/template/personas/technical-architect.md +42 -0
- package/skills/spec-swarm/template/personas/technical-lead.md +43 -0
- package/skills/spec-swarm/template/personas/user-research.md +41 -0
- package/skills/spec-swarm-accessibility-inclusion/SKILL.md +95 -0
- package/skills/spec-swarm-accessibility-inclusion/agents/openai.yaml +4 -0
- package/skills/spec-swarm-ai-technical-pm/SKILL.md +124 -0
- package/skills/spec-swarm-analytics-engineering/SKILL.md +94 -0
- package/skills/spec-swarm-analytics-engineering/agents/openai.yaml +4 -0
- package/skills/spec-swarm-applied-ai-eval/SKILL.md +120 -0
- package/skills/spec-swarm-business-gm-pm/SKILL.md +122 -0
- package/skills/spec-swarm-consumer-craft-pm/SKILL.md +122 -0
- package/skills/spec-swarm-content-design/SKILL.md +95 -0
- package/skills/spec-swarm-content-design/agents/openai.yaml +4 -0
- package/skills/spec-swarm-cpo/SKILL.md +94 -0
- package/skills/spec-swarm-cpo/agents/openai.yaml +4 -0
- package/skills/spec-swarm-data-science/SKILL.md +95 -0
- package/skills/spec-swarm-data-science/agents/openai.yaml +4 -0
- package/skills/spec-swarm-developer-experience/SKILL.md +121 -0
- package/skills/spec-swarm-dx-product/SKILL.md +126 -0
- package/skills/spec-swarm-field/SKILL.md +96 -0
- package/skills/spec-swarm-field/agents/openai.yaml +4 -0
- package/skills/spec-swarm-finance-cfo/SKILL.md +95 -0
- package/skills/spec-swarm-finance-cfo/agents/openai.yaml +4 -0
- package/skills/spec-swarm-growth-pm/SKILL.md +122 -0
- package/skills/spec-swarm-platform-pm/SKILL.md +122 -0
- package/skills/spec-swarm-pmm/SKILL.md +96 -0
- package/skills/spec-swarm-pmm/agents/openai.yaml +4 -0
- package/skills/spec-swarm-principal-product-designer/SKILL.md +95 -0
- package/skills/spec-swarm-principal-product-designer/agents/openai.yaml +4 -0
- package/skills/spec-swarm-product-ops-program/SKILL.md +96 -0
- package/skills/spec-swarm-product-ops-program/agents/openai.yaml +4 -0
- package/skills/spec-swarm-qa-release/SKILL.md +96 -0
- package/skills/spec-swarm-qa-release/agents/openai.yaml +4 -0
- package/skills/spec-swarm-responsible-ai-safety/SKILL.md +120 -0
- package/skills/spec-swarm-security-privacy-legal/SKILL.md +95 -0
- package/skills/spec-swarm-security-privacy-legal/agents/openai.yaml +4 -0
- package/skills/spec-swarm-strategy-competitive/SKILL.md +96 -0
- package/skills/spec-swarm-strategy-competitive/agents/openai.yaml +4 -0
- package/skills/spec-swarm-technical-architect/SKILL.md +95 -0
- package/skills/spec-swarm-technical-architect/agents/openai.yaml +4 -0
- package/skills/spec-swarm-technical-lead/SKILL.md +96 -0
- package/skills/spec-swarm-technical-lead/agents/openai.yaml +4 -0
- package/skills/spec-swarm-user-research/SKILL.md +95 -0
- package/skills/spec-swarm-user-research/agents/openai.yaml +4 -0
- package/skills/strategy-check/SKILL.md +170 -0
- package/skills/strategy-check/agents/openai.yaml +4 -0
- package/skills/study-digest/SKILL.md +41 -0
- package/skills/synthetic-customer/SKILL.md +68 -0
- package/skills/update-cli-spec/SKILL.md +69 -0
- package/skills/update-cli-spec/agents/openai.yaml +4 -0
- package/skills/voc-researcher/SKILL.md +45 -0
- package/skills/voc-researcher/agents/openai.yaml +4 -0
- package/skills-lock.json +35 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// error-instrumentation-v0 T-001 (R-001, R-002, D-001): what kind of failure was
|
|
2
|
+
// that, actually?
|
|
3
|
+
//
|
|
4
|
+
// Before this module, `main()` bucketed EVERY nonzero exit as "command_error", so
|
|
5
|
+
// `foo swarm` typed without an argument — which prints a correct usage line and
|
|
6
|
+
// exits 1 — was recorded identically to an unhandled crash. Across 14,492 events
|
|
7
|
+
// the field only ever held "none" or "command_error", and not one genuine crash
|
|
8
|
+
// was ever distinguishable. The dashboard cried wolf; the owner learned to ignore it.
|
|
9
|
+
//
|
|
10
|
+
// Three outcomes were collapsed into one. They are not the same thing:
|
|
11
|
+
//
|
|
12
|
+
// usage_error the human mistyped. foo printed usage. Nothing is broken.
|
|
13
|
+
// gate_block a boundary (B1/B2/B4) refused by design. The product WORKED.
|
|
14
|
+
// command_error something genuinely, unexpectedly failed. THIS is worth waking someone for.
|
|
15
|
+
//
|
|
16
|
+
// Only the last one should ever page a human. That is the whole point of the file.
|
|
17
|
+
//
|
|
18
|
+
// D-001: the code is a BOUNDED SYMBOL, never free text. It crosses the wire, where
|
|
19
|
+
// productfoo's disclosure promises metadata only — so it must never be able to carry a path,
|
|
20
|
+
// an argument, a filename, or user content. Adding a code means adding it to ErrorCode
|
|
21
|
+
// below, on purpose, where it can be read and reviewed. Rich detail (message, stack)
|
|
22
|
+
// stays in the local event log, which never leaves the machine.
|
|
23
|
+
import { createHash } from "node:crypto";
|
|
24
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
25
|
+
/** Does a failure of this class deserve a human's attention at 3am? */
|
|
26
|
+
export function pages(errorClass) {
|
|
27
|
+
return errorClass === "command_error" || errorClass === "io_error";
|
|
28
|
+
}
|
|
29
|
+
const failureScopes = new AsyncLocalStorage();
|
|
30
|
+
let unscopedPending;
|
|
31
|
+
/** Give one top-level invocation its own mark across every awaited dispatch path. */
|
|
32
|
+
export function runWithFailureScope(operation) {
|
|
33
|
+
return failureScopes.run({}, operation);
|
|
34
|
+
}
|
|
35
|
+
/** Record what kind of failure just happened. Called at the failure site. */
|
|
36
|
+
export function markFailure(mark) {
|
|
37
|
+
const scope = failureScopes.getStore();
|
|
38
|
+
if (scope)
|
|
39
|
+
scope.pending = mark;
|
|
40
|
+
else
|
|
41
|
+
unscopedPending = mark;
|
|
42
|
+
}
|
|
43
|
+
/** Take the mark and clear it. Cleared on read so it can never bleed into the next run. */
|
|
44
|
+
export function consumeFailure() {
|
|
45
|
+
const scope = failureScopes.getStore();
|
|
46
|
+
const mark = scope ? scope.pending : unscopedPending;
|
|
47
|
+
if (scope)
|
|
48
|
+
scope.pending = undefined;
|
|
49
|
+
else
|
|
50
|
+
unscopedPending = undefined;
|
|
51
|
+
return mark;
|
|
52
|
+
}
|
|
53
|
+
/** Drop any mark. Called at the start of each run so a prior command can't contaminate this one. */
|
|
54
|
+
export function resetFailure() {
|
|
55
|
+
const scope = failureScopes.getStore();
|
|
56
|
+
if (scope)
|
|
57
|
+
scope.pending = undefined;
|
|
58
|
+
else
|
|
59
|
+
unscopedPending = undefined;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* "You invoked this wrong" — thrown rather than returned. Same meaning as failWith: a typo.
|
|
63
|
+
* Throw this instead of a bare Error and the failure classifies itself correctly.
|
|
64
|
+
*/
|
|
65
|
+
export class UsageError extends Error {
|
|
66
|
+
errorCode;
|
|
67
|
+
constructor(message, errorCode = "E_BAD_FLAG") {
|
|
68
|
+
super(message);
|
|
69
|
+
this.name = "UsageError";
|
|
70
|
+
this.errorCode = errorCode;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A boundary refused by design — B1 safety, B2 spec identity, B4 autonomy, a default-deny
|
|
75
|
+
* policy. THE PRODUCT IS WORKING. It exits nonzero because it stopped you on purpose, and it
|
|
76
|
+
* must never, ever page anyone.
|
|
77
|
+
*/
|
|
78
|
+
export class GateBlock extends Error {
|
|
79
|
+
errorCode;
|
|
80
|
+
constructor(message, errorCode = "E_GATE_BLOCKED") {
|
|
81
|
+
super(message);
|
|
82
|
+
this.name = "GateBlock";
|
|
83
|
+
this.errorCode = errorCode;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The thing you asked for does not exist — a packet dir, a loop id, a file. Nonzero, but not
|
|
88
|
+
* a defect: foo worked, the target just isn't there. Classifies as `not_found`, which never
|
|
89
|
+
* pages. Thrown rather than returned so the caller doesn't thread a special return value out.
|
|
90
|
+
*/
|
|
91
|
+
export class NotFoundError extends Error {
|
|
92
|
+
errorCode;
|
|
93
|
+
constructor(message, errorCode = "E_PACKET_NOT_FOUND") {
|
|
94
|
+
super(message);
|
|
95
|
+
this.name = "NotFoundError";
|
|
96
|
+
this.errorCode = errorCode;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// productfoo throws from 255 places. Most are genuine faults, but two families are not, and both
|
|
100
|
+
// were being reported as crashes until a dogfood run caught them:
|
|
101
|
+
//
|
|
102
|
+
// "work missing — usage: foo spec <work>" — a typo. The command printed its usage.
|
|
103
|
+
// "loop(s) without an agreed budget: L-001" — B4 refusing. The product WORKED.
|
|
104
|
+
//
|
|
105
|
+
// Converting all 255 call sites is not realistic, so new and converted code throws UsageError
|
|
106
|
+
// or GateBlock (checked first, below) and these patterns bridge the rest. They are deliberately
|
|
107
|
+
// narrow: a usage line and a named boundary are unmistakable, and anything we are not sure
|
|
108
|
+
// about stays `command_error` and pages. A false "typo" hides a real bug; a false "bug" only
|
|
109
|
+
// pings someone. When in doubt, ping.
|
|
110
|
+
const LOOKS_LIKE_USAGE = /\busage: foo\b|\bunknown foo command\b/i;
|
|
111
|
+
const LOOKS_LIKE_GATE = /without an agreed budget|default-deny|\bB[124]\b (?:safety|boundary|blocks)/i;
|
|
112
|
+
/**
|
|
113
|
+
* Classify a thrown error that nothing marked. An `E*` errno (ENOENT, EACCES) is the
|
|
114
|
+
* filesystem or network failing under us; a typo and a gate refusal are not failures at all;
|
|
115
|
+
* anything else is a genuine unexpected fault, and gets someone's attention.
|
|
116
|
+
*/
|
|
117
|
+
export function classifyThrown(error) {
|
|
118
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
119
|
+
const stack = error instanceof Error ? error.stack : undefined;
|
|
120
|
+
// The command said what it was. Believe it.
|
|
121
|
+
if (error instanceof UsageError)
|
|
122
|
+
return { errorClass: "usage_error", errorCode: error.errorCode, message, stack };
|
|
123
|
+
if (error instanceof GateBlock)
|
|
124
|
+
return { errorClass: "gate_block", errorCode: error.errorCode, message, stack };
|
|
125
|
+
if (error instanceof NotFoundError)
|
|
126
|
+
return { errorClass: "not_found", errorCode: error.errorCode, message, stack };
|
|
127
|
+
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
128
|
+
if (typeof code === "string" && /^E[A-Z]+$/.test(code)) {
|
|
129
|
+
return { errorClass: "io_error", errorCode: "E_IO", message, stack };
|
|
130
|
+
}
|
|
131
|
+
if (LOOKS_LIKE_GATE.test(message))
|
|
132
|
+
return { errorClass: "gate_block", errorCode: "E_GATE_BLOCKED", message, stack };
|
|
133
|
+
if (LOOKS_LIKE_USAGE.test(message))
|
|
134
|
+
return { errorClass: "usage_error", errorCode: "E_BAD_FLAG", message, stack };
|
|
135
|
+
return { errorClass: "command_error", errorCode: "E_UNKNOWN", message, stack };
|
|
136
|
+
}
|
|
137
|
+
// The one frame that says WHERE a failure came from, reduced to something safe to fingerprint
|
|
138
|
+
// AND stable across the people who hit the same bug. Three reductions, each load-bearing:
|
|
139
|
+
//
|
|
140
|
+
// - the absolute path is dropped to a basename — a stack names `/Users/taylor/...`, and the
|
|
141
|
+
// whole point of the disclosure promise is that a tester's home directory is not ours;
|
|
142
|
+
// - :line:col is dropped — the same bug drifts a few lines between releases, and a
|
|
143
|
+
// fingerprint that changes every version cannot say "this is the same bug, still";
|
|
144
|
+
// - only the first real frame is kept — deeper frames are shared plumbing that would make
|
|
145
|
+
// unrelated failures collide.
|
|
146
|
+
//
|
|
147
|
+
// What remains is `functionName (basename.js)`: enough to tell two bugs apart, free of any
|
|
148
|
+
// path, argument, or user content — the same content-free bar the bounded error code meets.
|
|
149
|
+
function fingerprintFrame(stack) {
|
|
150
|
+
if (!stack)
|
|
151
|
+
return null;
|
|
152
|
+
const m = stack.split(/\r?\n/).map(line => /^\s*at\s+(\S+)\s+\(([^)]+)\)/.exec(line)).find(Boolean);
|
|
153
|
+
if (!m)
|
|
154
|
+
return null;
|
|
155
|
+
const file = m[2].split(/[\\/]/).pop()?.replace(/:\d+:\d+$/, "") ?? m[2];
|
|
156
|
+
return `${m[1]} (${file})`;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* A stable, privacy-safe grouping key for a failure: the bounded code plus the normalized
|
|
160
|
+
* origin frame. Two failures with the same code AND the same frame are the same bug — which
|
|
161
|
+
* is what lets the digest tell "one bug hit nine people" apart from "nine unrelated
|
|
162
|
+
* E_UNKNOWNs in the same command".
|
|
163
|
+
*
|
|
164
|
+
* It is a one-way hash of content-free inputs (a bounded code and a `fn (basename)` string —
|
|
165
|
+
* no path, no line, no argument, no message), so it is safe on the metadata-only wire.
|
|
166
|
+
*
|
|
167
|
+
* NO STACK MEANS NO FINGERPRINT. This used to hash a `<no-stack>` sentinel instead, and the
|
|
168
|
+
* comment defended it as degrading "deterministically ... rather than collapsing at random".
|
|
169
|
+
* It had it exactly backwards: hashing a constant does not spread stackless failures out, it
|
|
170
|
+
* funnels EVERY one of them that shares a code into a single identity. In production that
|
|
171
|
+
* produced `3b07a3cdfb33` = sha256("E_UNKNOWN\n<no-stack>") on eight unrelated commands at
|
|
172
|
+
* once — asp reconcile, self check, self gate, research gate, asp validate, research
|
|
173
|
+
* validate, commands validate, reconcile — which the console then drew as ONE bug, named
|
|
174
|
+
* after whichever row happened to sort first, with the blast radius of all eight.
|
|
175
|
+
*
|
|
176
|
+
* It also silently broke the join to error reports: a report fingerprints WITH a stack and
|
|
177
|
+
* these rows fingerprinted WITHOUT one, so the two could never match. 0 of 140 did. Every
|
|
178
|
+
* stack the console displayed came from a fallback that guessed by error code, which is how
|
|
179
|
+
* `foo redact` came to show a "work-item missing" crash from specCmd.js.
|
|
180
|
+
*
|
|
181
|
+
* Returning undefined is the honest answer: callers already group by command + code when
|
|
182
|
+
* there is no fingerprint, which keeps unrelated commands apart instead of fusing them.
|
|
183
|
+
*/
|
|
184
|
+
export function errorFingerprint(errorCode, stack) {
|
|
185
|
+
const frame = fingerprintFrame(stack);
|
|
186
|
+
if (!frame)
|
|
187
|
+
return undefined;
|
|
188
|
+
return createHash("sha256").update(`${errorCode}\n${frame}`).digest("hex").slice(0, 12);
|
|
189
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { EvalJudgeSpec } from "./evalRecord.js";
|
|
2
|
+
export declare const CALIBRATION_LABEL_COUNT = 30;
|
|
3
|
+
export declare const CALIBRATION_MIN_RATE = 0.9;
|
|
4
|
+
export declare const CALIBRATION_MIN_FAIL_LABELS = 10;
|
|
5
|
+
export type OwnerLabel = {
|
|
6
|
+
/** Content hash of the labelled artifact — the corpus itself stays private. */
|
|
7
|
+
artifact: string;
|
|
8
|
+
verdict: "pass" | "fail";
|
|
9
|
+
/** True only for labels given blind (no critique context, anonymised). */
|
|
10
|
+
blind: boolean;
|
|
11
|
+
labeled_at: string;
|
|
12
|
+
/** Free-text capture note: actionable description, no root-cause analysis. */
|
|
13
|
+
note?: string;
|
|
14
|
+
/** How the label was given; a dispute relabel supersedes by later append. */
|
|
15
|
+
origin?: "capture" | "dispute";
|
|
16
|
+
/** For a relabel: what surfaced the dispute. */
|
|
17
|
+
provenance?: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A blind dispute relabel that disagreed with the judge (or refined an earlier
|
|
21
|
+
* label): a refinement signal for the record's criterion or the judge prompt,
|
|
22
|
+
* never a gate input — the relabel already replaced the scored label.
|
|
23
|
+
*/
|
|
24
|
+
export type DisputeSignal = {
|
|
25
|
+
/** Content hash of the disputed artifact (private corpus pointer). */
|
|
26
|
+
artifact: string;
|
|
27
|
+
/** The owner's blind relabel — supersedes the original by later append. */
|
|
28
|
+
owner_verdict: "pass" | "fail";
|
|
29
|
+
/** The judge sample's verdict on the same artifact, when one exists. */
|
|
30
|
+
judge_verdict?: "pass" | "fail";
|
|
31
|
+
/** The owner's note, when one accompanied the relabel. */
|
|
32
|
+
note?: string;
|
|
33
|
+
};
|
|
34
|
+
export type JudgeSample = {
|
|
35
|
+
artifact: string;
|
|
36
|
+
verdict: "pass" | "fail";
|
|
37
|
+
/** Verdict from the order-swapped second call, when taken. */
|
|
38
|
+
swapped_verdict?: "pass" | "fail";
|
|
39
|
+
};
|
|
40
|
+
export type CalibrationReport = {
|
|
41
|
+
schema_version: "0.1";
|
|
42
|
+
/** hash(effective prompt protocol, judge prompt, judge model) — the validity key. */
|
|
43
|
+
judge_key: string;
|
|
44
|
+
labels: {
|
|
45
|
+
total: number;
|
|
46
|
+
pass: number;
|
|
47
|
+
fail: number;
|
|
48
|
+
non_blind_excluded: number;
|
|
49
|
+
};
|
|
50
|
+
tpr: number | null;
|
|
51
|
+
tnr: number | null;
|
|
52
|
+
/** Share of double-called samples where the order swap flipped the verdict. */
|
|
53
|
+
flip_rate: number | null;
|
|
54
|
+
/** The gate: min(TPR, TNR) ≥ bar AND label floors met, on blind labels only. */
|
|
55
|
+
certified: boolean;
|
|
56
|
+
reasons: string[];
|
|
57
|
+
/** Dispute relabels — refinement signals, reported but never gating. */
|
|
58
|
+
disputes: DisputeSignal[];
|
|
59
|
+
/**
|
|
60
|
+
* Cohen's kappa over the blind labels that have a judge sample —
|
|
61
|
+
* chance-corrected owner/judge agreement. Diagnostic only: `certified`
|
|
62
|
+
* never consults it, and the gate is untouched by it.
|
|
63
|
+
*/
|
|
64
|
+
kappa: number | null;
|
|
65
|
+
};
|
|
66
|
+
export declare function judgeKey(judge: Pick<EvalJudgeSpec, "prompt" | "model">): string;
|
|
67
|
+
/**
|
|
68
|
+
* Score a judge's samples against the owner's labels. Non-blind labels are
|
|
69
|
+
* excluded from the measurement, never silently: the report counts them.
|
|
70
|
+
* Loop-round rulings arrive with blind:false and therefore can never certify
|
|
71
|
+
* a judge (D-007).
|
|
72
|
+
*/
|
|
73
|
+
export declare function computeCalibration(judge: Pick<EvalJudgeSpec, "prompt" | "model">, labels: OwnerLabel[], samples: JudgeSample[]): CalibrationReport;
|
|
74
|
+
/**
|
|
75
|
+
* May this judge gate a run? Only with a certified report whose key matches
|
|
76
|
+
* the judge's current effective prompt+model — an edited judge is an uncalibrated judge
|
|
77
|
+
* until re-validated (against the same labels; no new labeling needed).
|
|
78
|
+
*/
|
|
79
|
+
export declare function judgeMayGate(judge: Pick<EvalJudgeSpec, "prompt" | "model">, report: CalibrationReport | undefined): {
|
|
80
|
+
allowed: boolean;
|
|
81
|
+
reason: string;
|
|
82
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { JUDGE_PROMPT_PROTOCOL } from "./evalJudge.js";
|
|
3
|
+
// Judge calibration (foo-eval-system-v0 R-003). A judge's verdicts count only
|
|
4
|
+
// after a blind, binary, owner-labelled validation clears the bar — and the
|
|
5
|
+
// bar is per-class: min(TPR, TNR), with a floor on real-failure labels, so an
|
|
6
|
+
// always-pass judge cannot clear it on a good-artifact corpus. Calibration is
|
|
7
|
+
// keyed to hash(effective prompt protocol, judge prompt, judge model): any drift voids it.
|
|
8
|
+
export const CALIBRATION_LABEL_COUNT = 30;
|
|
9
|
+
export const CALIBRATION_MIN_RATE = 0.9;
|
|
10
|
+
export const CALIBRATION_MIN_FAIL_LABELS = 10;
|
|
11
|
+
export function judgeKey(judge) {
|
|
12
|
+
return createHash("sha256").update(JUDGE_PROMPT_PROTOCOL).update("\u0000").update(judge.prompt).update("\u0000").update(judge.model).digest("hex");
|
|
13
|
+
}
|
|
14
|
+
const round = (value) => Math.round(value * 1000) / 1000;
|
|
15
|
+
/**
|
|
16
|
+
* Cohen's kappa over the blind∩sampled agreement set. po is the observed
|
|
17
|
+
* agreement; pe is what two independent raters would agree on by chance,
|
|
18
|
+
* from BOTH marginals of the same set — the owner-label distribution and
|
|
19
|
+
* the judge-verdict distribution. Null when the set is empty or pe === 1
|
|
20
|
+
* (a single class: nothing left for chance to explain away). Diagnostic
|
|
21
|
+
* only — the gate never reads it.
|
|
22
|
+
*/
|
|
23
|
+
function cohenKappa(counts) {
|
|
24
|
+
const { agree, total, ownerPass, judgePass } = counts;
|
|
25
|
+
if (total === 0)
|
|
26
|
+
return null;
|
|
27
|
+
const po = agree / total;
|
|
28
|
+
const ownerFail = total - ownerPass;
|
|
29
|
+
const judgeFail = total - judgePass;
|
|
30
|
+
const pe = (ownerPass * judgePass + ownerFail * judgeFail) / (total * total);
|
|
31
|
+
if (pe === 1)
|
|
32
|
+
return null;
|
|
33
|
+
return round((po - pe) / (1 - pe));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Score a judge's samples against the owner's labels. Non-blind labels are
|
|
37
|
+
* excluded from the measurement, never silently: the report counts them.
|
|
38
|
+
* Loop-round rulings arrive with blind:false and therefore can never certify
|
|
39
|
+
* a judge (D-007).
|
|
40
|
+
*/
|
|
41
|
+
export function computeCalibration(judge, labels, samples) {
|
|
42
|
+
const blind = labels.filter((label) => label.blind);
|
|
43
|
+
const nonBlindExcluded = labels.length - blind.length;
|
|
44
|
+
const byArtifact = new Map(samples.map((sample) => [sample.artifact, sample]));
|
|
45
|
+
let truePass = 0;
|
|
46
|
+
let falseFail = 0;
|
|
47
|
+
let trueFail = 0;
|
|
48
|
+
let falsePass = 0;
|
|
49
|
+
let doubleCalled = 0;
|
|
50
|
+
let flipped = 0;
|
|
51
|
+
let unsampled = 0;
|
|
52
|
+
let kappaAgree = 0;
|
|
53
|
+
let kappaTotal = 0;
|
|
54
|
+
let ownerPassCount = 0;
|
|
55
|
+
let judgePassCount = 0;
|
|
56
|
+
for (const label of blind) {
|
|
57
|
+
const sample = byArtifact.get(label.artifact);
|
|
58
|
+
if (!sample) {
|
|
59
|
+
unsampled += 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
kappaTotal += 1;
|
|
63
|
+
if (label.verdict === "pass")
|
|
64
|
+
ownerPassCount += 1;
|
|
65
|
+
if (sample.verdict === "pass")
|
|
66
|
+
judgePassCount += 1;
|
|
67
|
+
if (label.verdict === sample.verdict)
|
|
68
|
+
kappaAgree += 1;
|
|
69
|
+
if (sample.swapped_verdict !== undefined) {
|
|
70
|
+
doubleCalled += 1;
|
|
71
|
+
if (sample.swapped_verdict !== sample.verdict)
|
|
72
|
+
flipped += 1;
|
|
73
|
+
}
|
|
74
|
+
if (label.verdict === "pass") {
|
|
75
|
+
if (sample.verdict === "pass")
|
|
76
|
+
truePass += 1;
|
|
77
|
+
else
|
|
78
|
+
falseFail += 1;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
if (sample.verdict === "fail")
|
|
82
|
+
trueFail += 1;
|
|
83
|
+
else
|
|
84
|
+
falsePass += 1;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const passLabels = truePass + falseFail;
|
|
88
|
+
const failLabels = trueFail + falsePass;
|
|
89
|
+
const tpr = passLabels > 0 ? round(truePass / passLabels) : null;
|
|
90
|
+
const tnr = failLabels > 0 ? round(trueFail / failLabels) : null;
|
|
91
|
+
const flipRate = doubleCalled > 0 ? round(flipped / doubleCalled) : null;
|
|
92
|
+
const reasons = [];
|
|
93
|
+
const measured = passLabels + failLabels;
|
|
94
|
+
if (measured < CALIBRATION_LABEL_COUNT) {
|
|
95
|
+
reasons.push(`Only ${measured} blind labels measured; certification needs ${CALIBRATION_LABEL_COUNT}.`);
|
|
96
|
+
}
|
|
97
|
+
if (failLabels < CALIBRATION_MIN_FAIL_LABELS) {
|
|
98
|
+
reasons.push(`Only ${failLabels} fail-class labels; the floor is ${CALIBRATION_MIN_FAIL_LABELS} — without real failures the false-pass rate is unmeasured.`);
|
|
99
|
+
}
|
|
100
|
+
if (tpr !== null && tpr < CALIBRATION_MIN_RATE) {
|
|
101
|
+
reasons.push(`TPR ${tpr} is below the ${CALIBRATION_MIN_RATE} bar.`);
|
|
102
|
+
}
|
|
103
|
+
if (tnr !== null && tnr < CALIBRATION_MIN_RATE) {
|
|
104
|
+
reasons.push(`TNR ${tnr} is below the ${CALIBRATION_MIN_RATE} bar.`);
|
|
105
|
+
}
|
|
106
|
+
if (unsampled > 0) {
|
|
107
|
+
reasons.push(`${unsampled} blind label(s) have no judge sample yet.`);
|
|
108
|
+
}
|
|
109
|
+
if (nonBlindExcluded > 0) {
|
|
110
|
+
reasons.push(`${nonBlindExcluded} non-blind label(s) excluded from measurement (loop rulings are provisional signal, never calibration).`);
|
|
111
|
+
}
|
|
112
|
+
const certified = measured >= CALIBRATION_LABEL_COUNT &&
|
|
113
|
+
failLabels >= CALIBRATION_MIN_FAIL_LABELS &&
|
|
114
|
+
tpr !== null &&
|
|
115
|
+
tnr !== null &&
|
|
116
|
+
Math.min(tpr, tnr) >= CALIBRATION_MIN_RATE &&
|
|
117
|
+
unsampled === 0;
|
|
118
|
+
const disputes = blind
|
|
119
|
+
.filter((label) => label.origin === "dispute")
|
|
120
|
+
.map((label) => {
|
|
121
|
+
const sample = byArtifact.get(label.artifact);
|
|
122
|
+
return {
|
|
123
|
+
artifact: label.artifact,
|
|
124
|
+
owner_verdict: label.verdict,
|
|
125
|
+
...(sample ? { judge_verdict: sample.verdict } : {}),
|
|
126
|
+
...(label.note ? { note: label.note } : {}),
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
schema_version: "0.1",
|
|
131
|
+
judge_key: judgeKey(judge),
|
|
132
|
+
labels: { total: blind.length, pass: passLabels, fail: failLabels, non_blind_excluded: nonBlindExcluded },
|
|
133
|
+
tpr,
|
|
134
|
+
tnr,
|
|
135
|
+
flip_rate: flipRate,
|
|
136
|
+
certified,
|
|
137
|
+
reasons,
|
|
138
|
+
disputes,
|
|
139
|
+
kappa: cohenKappa({
|
|
140
|
+
agree: kappaAgree,
|
|
141
|
+
total: kappaTotal,
|
|
142
|
+
ownerPass: ownerPassCount,
|
|
143
|
+
judgePass: judgePassCount,
|
|
144
|
+
}),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* May this judge gate a run? Only with a certified report whose key matches
|
|
149
|
+
* the judge's current effective prompt+model — an edited judge is an uncalibrated judge
|
|
150
|
+
* until re-validated (against the same labels; no new labeling needed).
|
|
151
|
+
*/
|
|
152
|
+
export function judgeMayGate(judge, report) {
|
|
153
|
+
if (!report) {
|
|
154
|
+
return { allowed: false, reason: "No calibration report — the judge runs advisory-only." };
|
|
155
|
+
}
|
|
156
|
+
if (report.judge_key !== judgeKey(judge)) {
|
|
157
|
+
return {
|
|
158
|
+
allowed: false,
|
|
159
|
+
reason: "The judge's prompt, request protocol, or model changed since calibration — re-run the blind validation with fresh judge samples against the existing labels before it gates.",
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (!report.certified) {
|
|
163
|
+
return {
|
|
164
|
+
allowed: false,
|
|
165
|
+
reason: `Calibration did not certify: ${report.reasons.join(" ")}`,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return { allowed: true, reason: "Certified against the owner's blind labels." };
|
|
169
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type EvalCheckSeverity = "fail" | "warn";
|
|
2
|
+
export type EvalCheckFinding = {
|
|
3
|
+
check: string;
|
|
4
|
+
line: number;
|
|
5
|
+
phrase: string;
|
|
6
|
+
message: string;
|
|
7
|
+
severity: EvalCheckSeverity;
|
|
8
|
+
};
|
|
9
|
+
export type EvalChecksResult = {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
findings: EvalCheckFinding[];
|
|
12
|
+
};
|
|
13
|
+
export type EvalCheckRequest = {
|
|
14
|
+
id: string;
|
|
15
|
+
params?: Record<string, unknown>;
|
|
16
|
+
};
|
|
17
|
+
export declare const DETERMINISTIC_CHECK_IDS: readonly string[];
|
|
18
|
+
/** Run the requested deterministic checks over an artifact's markdown. */
|
|
19
|
+
export declare function runDeterministicChecks(artifactText: string, checks: EvalCheckRequest[], options?: {
|
|
20
|
+
strict?: boolean;
|
|
21
|
+
}): EvalChecksResult;
|