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,295 @@
|
|
|
1
|
+
// methodology-compiler-v0 (R-001) — the conductor engine. One code path for
|
|
2
|
+
// every family: resolve tier, build the cell matrix, scaffold the record,
|
|
3
|
+
// render the contract, verify the record against the family's gate specs.
|
|
4
|
+
// Adding a family means adding DATA (a FamilyDefinition), never a new engine.
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { checkDecision, checkFalsification } from "./ideateDecision.js";
|
|
8
|
+
import { CLUSTERER_ID, computeDiversity, frameReasoningOffenders, hasExecutableFramesContract, ideateContractVersion, parseIdeaObjects, readClustererId, readDeclaredMeter, readDiversityMethod, } from "./diversity.js";
|
|
9
|
+
export function slugify(text) {
|
|
10
|
+
return (text
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
13
|
+
.replace(/^-+|-+$/g, "")
|
|
14
|
+
.slice(0, 40) || "idea");
|
|
15
|
+
}
|
|
16
|
+
export function buildCells(family, tier) {
|
|
17
|
+
const rule = family.cells;
|
|
18
|
+
if (!rule)
|
|
19
|
+
return [];
|
|
20
|
+
const count = Math.min(Number(tier[rule.countKey] ?? 0), rule.maxCount ?? Number.POSITIVE_INFINITY);
|
|
21
|
+
const cells = [];
|
|
22
|
+
for (let i = 0; i < count; i += 1) {
|
|
23
|
+
const attrs = {};
|
|
24
|
+
for (const [attr, pool] of Object.entries(rule.pools)) {
|
|
25
|
+
const cycle = pool.cycleKey ? Number(tier[pool.cycleKey] ?? pool.values.length) : pool.values.length;
|
|
26
|
+
attrs[attr] = pool.values[i % Math.max(1, Math.min(cycle, pool.values.length))];
|
|
27
|
+
}
|
|
28
|
+
if (rule.seed)
|
|
29
|
+
attrs[rule.seed.attr] = rule.seed.base + i * rule.seed.step;
|
|
30
|
+
cells.push({ role: `${rule.rolePrefix}${i + 1}`, attrs });
|
|
31
|
+
}
|
|
32
|
+
return cells;
|
|
33
|
+
}
|
|
34
|
+
export function renderContext(family, target, depth, at, root) {
|
|
35
|
+
const tier = family.depths[depth];
|
|
36
|
+
if (!tier)
|
|
37
|
+
throw new Error(`unknown depth for ${family.family}: ${depth}`);
|
|
38
|
+
const recordPath = family.record
|
|
39
|
+
? path.posix.join(family.record.dir, `${at.slice(0, 10)}-${slugify(target)}.md`)
|
|
40
|
+
: null;
|
|
41
|
+
// ip-protection-cheap-moves T-004: lean contract is opt-in via env, OFF by
|
|
42
|
+
// default so the emitted contract stays byte-identical until the D-003 A/B arms it.
|
|
43
|
+
const lean = (process.env.FOO_LEAN_CONTRACT ?? "").trim() === "1";
|
|
44
|
+
return { family, target, depth, tier, cells: buildCells(family, tier), at, recordPath, root, lean };
|
|
45
|
+
}
|
|
46
|
+
// Scaffold the record: family template renders it; the engine owns only the
|
|
47
|
+
// refuse-to-overwrite and filesystem mechanics.
|
|
48
|
+
export function scaffoldRecord(ctx) {
|
|
49
|
+
const { family, recordPath, root } = ctx;
|
|
50
|
+
if (!family.record || !recordPath)
|
|
51
|
+
throw new Error(`${family.family} has no record template`);
|
|
52
|
+
const full = path.resolve(root, recordPath);
|
|
53
|
+
if (existsSync(full))
|
|
54
|
+
throw new Error(`${family.family} record already exists: ${recordPath}`);
|
|
55
|
+
mkdirSync(path.dirname(full), { recursive: true });
|
|
56
|
+
const body = [...family.record.frontmatter(ctx), ...family.record.body(ctx)].join("\n");
|
|
57
|
+
writeFileSync(full, body);
|
|
58
|
+
return full;
|
|
59
|
+
}
|
|
60
|
+
export function renderContract(ctx) {
|
|
61
|
+
return ctx.family.contract(ctx).join("\n");
|
|
62
|
+
}
|
|
63
|
+
// --- Gates (deterministic verification; the structure half of V1) -----------
|
|
64
|
+
function grab(text, re) {
|
|
65
|
+
const m = text.match(re);
|
|
66
|
+
return m ? m[1] : null;
|
|
67
|
+
}
|
|
68
|
+
// The human-readable content of a `field:` keyline. A record author may write
|
|
69
|
+
// the value inline, as a YAML block list (`- item` lines), or as a folded
|
|
70
|
+
// block (`>-` / `|` plus indented lines) — the gate cares that substance
|
|
71
|
+
// exists, not which of those shapes carries it. Machine-shaped one-liners
|
|
72
|
+
// were being forced onto human surfaces purely because the old check only
|
|
73
|
+
// read the same line; that was the gate's defect, not the author's.
|
|
74
|
+
function keylineContent(recordText, field) {
|
|
75
|
+
const lines = recordText.split("\n");
|
|
76
|
+
const start = lines.findIndex((l) => l === `${field}:` || l.startsWith(`${field}:`));
|
|
77
|
+
if (start === -1)
|
|
78
|
+
return null;
|
|
79
|
+
const inline = lines[start].slice(field.length + 1).trim();
|
|
80
|
+
const parts = [];
|
|
81
|
+
if (inline && inline !== ">-" && inline !== ">" && inline !== "|" && inline !== "|-")
|
|
82
|
+
parts.push(inline);
|
|
83
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
84
|
+
const line = lines[i];
|
|
85
|
+
if (line.trim() === "")
|
|
86
|
+
break;
|
|
87
|
+
if (!/^\s+\S/.test(line))
|
|
88
|
+
break; // next top-level key or heading ends the block
|
|
89
|
+
parts.push(line.trim().replace(/^- /, ""));
|
|
90
|
+
}
|
|
91
|
+
return parts.join(" ");
|
|
92
|
+
}
|
|
93
|
+
function escapeRegExpLiteral(value) {
|
|
94
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
95
|
+
}
|
|
96
|
+
function runGate(spec, recordText, tierFor) {
|
|
97
|
+
switch (spec.type) {
|
|
98
|
+
case "ideate-falsification":
|
|
99
|
+
case "ideate-decision": {
|
|
100
|
+
const version = ideateContractVersion(recordText);
|
|
101
|
+
if (version === null || version === "frames-v1")
|
|
102
|
+
return [{ check: spec.check, ok: true, detail: "record predates decisions-v2 — new evidence and decision checks not required" }];
|
|
103
|
+
if (version !== "decisions-v2")
|
|
104
|
+
return [{ check: spec.check, ok: false, detail: `unsupported or malformed ideate contract: ${version}` }];
|
|
105
|
+
const errors = spec.type === "ideate-falsification" ? checkFalsification(recordText) : checkDecision(recordText);
|
|
106
|
+
return [{ check: spec.check, ok: !errors.length, detail: errors.length ? errors.join("; ") : "recorded coverage and consistency verified; factual truth and execution chronology remain human/model judgments" }];
|
|
107
|
+
}
|
|
108
|
+
case "frontmatter-present": {
|
|
109
|
+
const value = grab(recordText, new RegExp(`^${spec.field}:\\s*${spec.pattern ?? "(.+)"}\\s*$`, "m"));
|
|
110
|
+
const ok = Boolean(value && value.trim().length > (spec.field === "idea" ? 2 : 0));
|
|
111
|
+
return [{ check: spec.check, ok, detail: ok ? spec.detail.replace("{value}", value ?? "") : spec.failDetail }];
|
|
112
|
+
}
|
|
113
|
+
case "frontmatter-nonempty": {
|
|
114
|
+
const value = keylineContent(recordText, spec.field);
|
|
115
|
+
const stripped = (value ?? "").replace(/["']/g, "").trim();
|
|
116
|
+
// "null" is a scaffold placeholder, not content — an unfilled field must
|
|
117
|
+
// read as unfilled, or the gate certifies a record with no position.
|
|
118
|
+
const ok = stripped.length > 0 && stripped !== "[]" && stripped !== "null";
|
|
119
|
+
return [{ check: spec.check, ok, detail: ok ? spec.detail : spec.failDetail }];
|
|
120
|
+
}
|
|
121
|
+
case "frontmatter-equals": {
|
|
122
|
+
const value = grab(recordText, new RegExp(`^${spec.field}:\\s*(\\S+)`, "m"));
|
|
123
|
+
const ok = value === spec.expect;
|
|
124
|
+
return [{ check: spec.check, ok, detail: ok ? spec.detail : `${spec.failDetail}${value ?? "none"}` }];
|
|
125
|
+
}
|
|
126
|
+
case "section-present": {
|
|
127
|
+
const ok = new RegExp(`^#+\\s*${escapeRegExpLiteral(spec.heading)}`, "m").test(recordText);
|
|
128
|
+
return [{ check: spec.check, ok, detail: ok ? spec.detail : spec.failDetail }];
|
|
129
|
+
}
|
|
130
|
+
case "frame-reasoning": {
|
|
131
|
+
// frames-v1 (#697): the frame label is a claim; reasoning is its proof.
|
|
132
|
+
// Shape only — quality stays with blind judging.
|
|
133
|
+
if (!hasExecutableFramesContract(recordText)) {
|
|
134
|
+
return [{
|
|
135
|
+
check: spec.check,
|
|
136
|
+
ok: true,
|
|
137
|
+
detail: "record predates executable frames (no ideate_contract line) — frame execution unverifiable, not failed",
|
|
138
|
+
}];
|
|
139
|
+
}
|
|
140
|
+
const parsed = parseIdeaObjects(recordText);
|
|
141
|
+
if (!parsed.present || parsed.ideas.length === 0) {
|
|
142
|
+
return [{ check: spec.check, ok: false, detail: "frames-v1 record stores no ideas to verify frame execution against" }];
|
|
143
|
+
}
|
|
144
|
+
if (parsed.errors.length) {
|
|
145
|
+
return [{ check: spec.check, ok: false, detail: `stored ideas do not validate: ${parsed.errors.slice(0, 3).join("; ")}` }];
|
|
146
|
+
}
|
|
147
|
+
const offenders = frameReasoningOffenders(parsed.ideas);
|
|
148
|
+
const ok = offenders.length === 0;
|
|
149
|
+
return [{
|
|
150
|
+
check: spec.check,
|
|
151
|
+
ok,
|
|
152
|
+
detail: ok
|
|
153
|
+
? `every idea shows its frame's move (${parsed.ideas.length} checked)`
|
|
154
|
+
: `frame declared but not executed — ${offenders.length} idea(s): ${offenders.slice(0, 3).join("; ")}${offenders.length > 3 ? "; …" : ""}`,
|
|
155
|
+
}];
|
|
156
|
+
}
|
|
157
|
+
case "versioned-keyline": {
|
|
158
|
+
if (!hasExecutableFramesContract(recordText)) {
|
|
159
|
+
return [{ check: spec.check, ok: true, detail: `record predates frames-v1 — ${spec.field} not required` }];
|
|
160
|
+
}
|
|
161
|
+
const value = keylineContent(recordText, spec.field);
|
|
162
|
+
const stripped = (value ?? "").replace(/["']/g, "").trim();
|
|
163
|
+
const ok = stripped.length > 0 && stripped !== "[]" && stripped !== "null" && stripped.toUpperCase() !== "TODO";
|
|
164
|
+
return [{ check: spec.check, ok, detail: ok ? spec.detail : spec.failDetail }];
|
|
165
|
+
}
|
|
166
|
+
case "ledger-types": {
|
|
167
|
+
// methodology-compiler-v0 T-005: the type taxonomy is engine-enforced.
|
|
168
|
+
// Scan markdown-table rows for a Type column value; any value outside
|
|
169
|
+
// the taxonomy is a collapse — the boundary between evidence,
|
|
170
|
+
// expertise, inference, and human judgment is the product.
|
|
171
|
+
const rows = recordText.split("\n").filter((l) => /^\s*\|/.test(l) && !/^\s*\|\s*-+/.test(l) && !/\|\s*Type\s*\|/i.test(l));
|
|
172
|
+
const offenders = [];
|
|
173
|
+
for (const row of rows) {
|
|
174
|
+
const cols = row.split("|").map((c) => c.trim());
|
|
175
|
+
for (const col of cols) {
|
|
176
|
+
const m = col.match(/^(repo-evidence|approved-context|role-expertise|agent-inference|user-judgment|[a-z]+-(?:evidence|context|expertise|inference|judgment))$/);
|
|
177
|
+
if (m && !spec.taxonomy.includes(m[1]))
|
|
178
|
+
offenders.push(m[1]);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const ok = offenders.length === 0;
|
|
182
|
+
return [{
|
|
183
|
+
check: spec.check,
|
|
184
|
+
ok,
|
|
185
|
+
detail: ok
|
|
186
|
+
? "ledger judgment types stay within the taxonomy"
|
|
187
|
+
: `ledger type(s) outside the taxonomy (collapsed or invented): ${[...new Set(offenders)].join(", ")}`,
|
|
188
|
+
}];
|
|
189
|
+
}
|
|
190
|
+
case "diversity-meter": {
|
|
191
|
+
const findings = [];
|
|
192
|
+
const div = recordText.match(/^diversity:\s*\{\s*raw:\s*(\d+),\s*distinct_clusters:\s*(\d+),\s*near_dupes_merged:\s*(\d+),\s*exhausted:\s*(true|false)\s*\}/m);
|
|
193
|
+
if (!div) {
|
|
194
|
+
findings.push({
|
|
195
|
+
check: spec.check,
|
|
196
|
+
ok: false,
|
|
197
|
+
detail: "diversity meter missing (raw / distinct_clusters / near_dupes_merged / exhausted)",
|
|
198
|
+
});
|
|
199
|
+
return findings;
|
|
200
|
+
}
|
|
201
|
+
const raw = Number(div[1]);
|
|
202
|
+
const clusters = Number(div[2]);
|
|
203
|
+
const exhausted = div[4] === "true";
|
|
204
|
+
findings.push({
|
|
205
|
+
check: spec.check,
|
|
206
|
+
ok: true,
|
|
207
|
+
detail: `raw ${raw}, distinct ${clusters}, merged ${div[3]}, exhausted ${exhausted}`,
|
|
208
|
+
});
|
|
209
|
+
const depth = (grab(recordText, /^depth:\s*(fast|standard|deep)\s*$/m) ?? "standard");
|
|
210
|
+
const tier = tierFor(depth);
|
|
211
|
+
const floor = Math.min(spec.floorCap, Number(tier[spec.floorKey] ?? spec.floorCap));
|
|
212
|
+
// A homogeneous pool is flagged, not accepted — unless the run honestly
|
|
213
|
+
// declared the idea space exhausted (the flag stays visible either way).
|
|
214
|
+
findings.push({
|
|
215
|
+
check: "diversity-floor",
|
|
216
|
+
ok: clusters >= floor || exhausted,
|
|
217
|
+
detail: clusters >= floor
|
|
218
|
+
? `distinct clusters ${clusters} ≥ floor ${floor}`
|
|
219
|
+
: exhausted
|
|
220
|
+
? `below floor (${clusters} < ${floor}) but honestly declared exhausted`
|
|
221
|
+
: `homogeneous pool: ${clusters} distinct cluster(s) < floor ${floor} and not declared exhausted — identical-output run flagged`,
|
|
222
|
+
});
|
|
223
|
+
findings.push({
|
|
224
|
+
check: "no-padding",
|
|
225
|
+
ok: raw >= clusters,
|
|
226
|
+
detail: raw >= clusters ? "raw ≥ clusters" : "cluster count exceeds raw ideas — fabricated clusters",
|
|
227
|
+
});
|
|
228
|
+
return findings;
|
|
229
|
+
}
|
|
230
|
+
case "diversity-provenance": {
|
|
231
|
+
// ideate-cost-v1 R-002 / T-003 C-005. The v0 meter was eyeballed and
|
|
232
|
+
// recorded as data, so the honest states are named and only one of them
|
|
233
|
+
// has to prove anything: `estimated` passes and says so out loud;
|
|
234
|
+
// `measured` must reproduce from the record's own structured ideas.
|
|
235
|
+
const fail = (detail) => [{ check: spec.check, ok: false, detail }];
|
|
236
|
+
const method = readDiversityMethod(recordText);
|
|
237
|
+
if (!method)
|
|
238
|
+
return fail("diversity_method must read measured or estimated");
|
|
239
|
+
if (method.value === "estimated") {
|
|
240
|
+
return [{
|
|
241
|
+
check: spec.check,
|
|
242
|
+
ok: true,
|
|
243
|
+
detail: method.declared
|
|
244
|
+
? "diversity meter is estimated — declared, not computed from stored ideas"
|
|
245
|
+
: "diversity meter is estimated — no diversity_method declared, so the number is not a measurement",
|
|
246
|
+
}];
|
|
247
|
+
}
|
|
248
|
+
const parsed = parseIdeaObjects(recordText);
|
|
249
|
+
if (!parsed.present) {
|
|
250
|
+
return fail('claims diversity_method: measured but the record stores no ideas block — add one, or say estimated');
|
|
251
|
+
}
|
|
252
|
+
if (parsed.errors.length) {
|
|
253
|
+
return fail(`claims measured but the stored ideas do not validate: ${parsed.errors.slice(0, 3).join("; ")}`);
|
|
254
|
+
}
|
|
255
|
+
if (parsed.ideas.length === 0)
|
|
256
|
+
return fail("claims measured over an empty idea pool — nothing was clustered");
|
|
257
|
+
const declared = readDeclaredMeter(recordText);
|
|
258
|
+
if (!declared)
|
|
259
|
+
return fail("claims measured but the diversity meter line is missing");
|
|
260
|
+
const computed = computeDiversity(parsed.ideas, declared.exhausted);
|
|
261
|
+
const drift = ["raw", "distinct_clusters", "near_dupes_merged"]
|
|
262
|
+
.filter((k) => declared[k] !== computed[k])
|
|
263
|
+
.map((k) => `${k} says ${declared[k]}, computes ${computed[k]}`);
|
|
264
|
+
if (drift.length) {
|
|
265
|
+
// A record that names an older clusterer is stale, not dishonest, and the
|
|
266
|
+
// difference is worth saying: "recompute it" is a fixable instruction,
|
|
267
|
+
// while "your meter does not reproduce" reads as an accusation and sends
|
|
268
|
+
// the reader hunting for a mistake nobody made.
|
|
269
|
+
//
|
|
270
|
+
// An *unstamped* record gets no such benefit of the doubt. A missing
|
|
271
|
+
// stamp is indistinguishable from the original failure this gate was
|
|
272
|
+
// built to catch — a `measured` that was never computed at all — so it
|
|
273
|
+
// keeps the blunt message. Softening it there would let a hand-typed
|
|
274
|
+
// meter excuse itself as merely out of date.
|
|
275
|
+
const stamped = readClustererId(recordText);
|
|
276
|
+
if (stamped && stamped !== CLUSTERER_ID) {
|
|
277
|
+
return fail(`meter was computed by clusterer ${stamped}, and ${CLUSTERER_ID} reads the pool differently (${drift.join("; ")}) — re-run foo ideate diversity <record> --write`);
|
|
278
|
+
}
|
|
279
|
+
return fail(`meter does not reproduce from the stored ideas: ${drift.join("; ")}`);
|
|
280
|
+
}
|
|
281
|
+
return [{
|
|
282
|
+
check: spec.check,
|
|
283
|
+
ok: true,
|
|
284
|
+
detail: `meter reproduced from ${parsed.ideas.length} stored idea(s) by ${CLUSTERER_ID}: raw ${computed.raw}, distinct ${computed.distinct_clusters}, merged ${computed.near_dupes_merged}`,
|
|
285
|
+
}];
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
export function checkRecord(family, recordText) {
|
|
290
|
+
const findings = [];
|
|
291
|
+
for (const spec of family.gates) {
|
|
292
|
+
findings.push(...runGate(spec, recordText, (d) => family.depths[d]));
|
|
293
|
+
}
|
|
294
|
+
return { ok: findings.every((f) => f.ok), findings };
|
|
295
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// Family definition: ideate (the storm/ideation conductor) expressed as data.
|
|
2
|
+
// This is the byte-compat proving case (C-002): the engine must reproduce the
|
|
3
|
+
// exact contract and record that src/ideate.ts emits today.
|
|
4
|
+
import { slugify } from "../engine.js";
|
|
5
|
+
// frames-v1 (#694/#696): every depth rotates the FULL frame roster — depth
|
|
6
|
+
// scales how many cells run and how hard stress/judging push, never which
|
|
7
|
+
// thinking moves exist. Analogy leads because it is the strongest novelty
|
|
8
|
+
// engine (mechanism theft from another domain) and the old order starved it:
|
|
9
|
+
// frames used to cycle on the reframes count, so fast ran inversion-only and
|
|
10
|
+
// standard never reached analogy or second-order at all.
|
|
11
|
+
const FRAMES = ["analogy", "inversion", "how-might-we", "first-principles", "second-order"];
|
|
12
|
+
const LENSES = ["product", "engineering", "security", "design", "gtm", "data", "user-research", "platform"];
|
|
13
|
+
function verification(ctx) {
|
|
14
|
+
return `foo ideate check ${ctx.recordPath}`;
|
|
15
|
+
}
|
|
16
|
+
const HANDOFF = 'foo spec "<winning direction>"';
|
|
17
|
+
export const ideateFamily = {
|
|
18
|
+
family: "ideate",
|
|
19
|
+
banner: "── foo ▸ ideate ── ideas before specs ──",
|
|
20
|
+
tagline: "ideas before specs",
|
|
21
|
+
skillRef: "ideate", // a `foo skill` argument, never a filesystem path
|
|
22
|
+
defaultDepth: "standard",
|
|
23
|
+
depths: {
|
|
24
|
+
// reframes = how many F-lines the FRAME phase writes (one per leading cell);
|
|
25
|
+
// it no longer truncates which frames the cells receive.
|
|
26
|
+
fast: { reframes: 3, ideators: 3, stress_on: 1, judges: 1, extra_dissent_round: false },
|
|
27
|
+
standard: { reframes: 5, ideators: 5, stress_on: 3, judges: 3, extra_dissent_round: false },
|
|
28
|
+
deep: { reframes: 5, ideators: 8, stress_on: 5, judges: 3, extra_dissent_round: true },
|
|
29
|
+
},
|
|
30
|
+
phases: ["GROUND", "FRAME", "DIVERGE", "FALSIFY", "PANEL", "REVEAL", "BUILD_ON", "STRESS", "CONVERGE", "CAPTURE"],
|
|
31
|
+
cells: {
|
|
32
|
+
rolePrefix: "ideator-",
|
|
33
|
+
countKey: "ideators",
|
|
34
|
+
maxCount: 8,
|
|
35
|
+
pools: {
|
|
36
|
+
frame: { values: FRAMES },
|
|
37
|
+
lens: { values: LENSES },
|
|
38
|
+
},
|
|
39
|
+
seed: { attr: "seed", base: 11, step: 7 },
|
|
40
|
+
},
|
|
41
|
+
record: {
|
|
42
|
+
dir: "ideas",
|
|
43
|
+
// The front matter is the record's face: the pick leads, machinery trails,
|
|
44
|
+
// and nothing on it carries an inline explainer — the contract and skill
|
|
45
|
+
// teach; the record states. `recommendation` is scaffolded null and gated,
|
|
46
|
+
// so a record cannot verify without taking a position.
|
|
47
|
+
frontmatter: (ctx) => [
|
|
48
|
+
"---",
|
|
49
|
+
"recommendation: null",
|
|
50
|
+
`idea: ${JSON.stringify(ctx.target)}`,
|
|
51
|
+
`depth: ${ctx.depth}`,
|
|
52
|
+
"decider: human",
|
|
53
|
+
`ideate_id: ideate-${ctx.at.slice(0, 10)}-${slugify(ctx.target)}`,
|
|
54
|
+
// frames-v1 (#697): names the contract this record was scaffolded under,
|
|
55
|
+
// so the executable-frame and keyline gates know they apply. Older
|
|
56
|
+
// records without the line pass those gates with a "predates" note.
|
|
57
|
+
"ideate_contract: decisions-v2",
|
|
58
|
+
"diversity: { raw: 0, distinct_clusters: 0, near_dupes_merged: 0, exhausted: false }",
|
|
59
|
+
// ideate-cost-v1 R-002: the meter's provenance travels with the meter.
|
|
60
|
+
// Scaffolds default to `measured` because computing it is the job; a run
|
|
61
|
+
// that cannot show its work has to downgrade this line on purpose.
|
|
62
|
+
"diversity_method: measured",
|
|
63
|
+
"---",
|
|
64
|
+
],
|
|
65
|
+
// #700: the record is decision-first — a reader gets the call and the full
|
|
66
|
+
// stack rank before any process detail, and the machine JSON is the LAST
|
|
67
|
+
// section, never the lead. Process order (frames → pool → stress) is how
|
|
68
|
+
// the run happened; it is not how a decider reads.
|
|
69
|
+
body: (ctx) => [
|
|
70
|
+
"",
|
|
71
|
+
"# The call",
|
|
72
|
+
"(CAPTURE renders `foo ideate result <record>` here: a decision in at most 600 words, its new contribution, prior work, conditional alternatives, and a first test. The rank and full pool below are backing evidence.)",
|
|
73
|
+
"",
|
|
74
|
+
"# Stack rank — surviving directions scored New / Useful / Feasible (1–10); exclusions retained",
|
|
75
|
+
"(CONVERGE + CAPTURE write this: Every cluster has a disposition and plain-English name. Every ranking table includes a `What this is` column immediately after `Direction`: one concrete sentence explaining who does or receives what, understandable without the idea's title, score, or rationale. Eligible directions carry N/U/F scores and placement reasons; clusters with no surviving idea are excluded with the refutation, never scored. Distinguish panel scores from the completion pass.)",
|
|
76
|
+
"",
|
|
77
|
+
"# Decision",
|
|
78
|
+
"pick: null",
|
|
79
|
+
"keep: []",
|
|
80
|
+
"maybe: []",
|
|
81
|
+
"cut: []",
|
|
82
|
+
"not_doing: []",
|
|
83
|
+
// #698: the novelty anchor. N is unanchored until the recommendation
|
|
84
|
+
// names the nearest existing thing it beats ("none found locally" must
|
|
85
|
+
// be said, never implied).
|
|
86
|
+
'nearest_existing: ""',
|
|
87
|
+
// Actionability: the cheapest one-week falsification test for the
|
|
88
|
+
// recommended direction — something a person could start Monday.
|
|
89
|
+
'cheapest_test: ""',
|
|
90
|
+
'minority_report: ""',
|
|
91
|
+
'what_would_change_our_mind: ""',
|
|
92
|
+
`handoff: ${JSON.stringify(HANDOFF)}`,
|
|
93
|
+
"",
|
|
94
|
+
// #695: STRESS gets a scaffolded home so the decision-changing phase
|
|
95
|
+
// cannot be silently dropped — its keylines are gated like the minority
|
|
96
|
+
// report. `outcome_change` is the honesty line: what the pass changed,
|
|
97
|
+
// or precisely why it changed nothing.
|
|
98
|
+
"# What moved the ranking (stress — findings must be able to change the outcome)",
|
|
99
|
+
'pre_mortem: ""',
|
|
100
|
+
'disconfirmation_vs_frontrunner: ""',
|
|
101
|
+
'outcome_change: ""',
|
|
102
|
+
"",
|
|
103
|
+
"# Frames",
|
|
104
|
+
...ctx.cells.slice(0, Number(ctx.tier.reframes)).map((c, i) => `- F${i + 1} ${c.attrs.frame}: TODO`),
|
|
105
|
+
"",
|
|
106
|
+
"# Idea pool (readable — REVEAL renders the clustered pool here via `foo ideate read`, each cluster under its plain-English name)",
|
|
107
|
+
"",
|
|
108
|
+
"# Appendix — measured source (the diversity meter is computed from this block, never read off it)",
|
|
109
|
+
"```json ideas",
|
|
110
|
+
"[]",
|
|
111
|
+
"```",
|
|
112
|
+
"",
|
|
113
|
+
"# Prior work (local context; empirical claims still need checking)",
|
|
114
|
+
"```json grounding",
|
|
115
|
+
'{"searched": [], "sources": [], "gap": ""}',
|
|
116
|
+
"```",
|
|
117
|
+
"",
|
|
118
|
+
"# Claim review (before build-on; refreshed when claims change)",
|
|
119
|
+
"```json falsification",
|
|
120
|
+
'{"claims": [], "excluded_ideas": []}',
|
|
121
|
+
"```",
|
|
122
|
+
"",
|
|
123
|
+
"# Decision source (render with foo ideate result)",
|
|
124
|
+
"```json decision",
|
|
125
|
+
"{}",
|
|
126
|
+
"```",
|
|
127
|
+
"",
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
// methodology-compiler-v0 T-003: the orchestration protocol below moved out
|
|
131
|
+
// of skills/ideate/SKILL.md prose into this compiled emission. The skill now
|
|
132
|
+
// holds only leaf craft (how to think in each role); the conductor owns the
|
|
133
|
+
// choreography. Rationale lines ride with each rule (R-003 dissent i).
|
|
134
|
+
contract: (ctx) => [
|
|
135
|
+
`── foo ▸ ideate ── ideas before specs ──`,
|
|
136
|
+
"",
|
|
137
|
+
`Idea (captured verbatim, immutable): ${ctx.target}`,
|
|
138
|
+
`Depth: ${ctx.depth} — ${ctx.tier.reframes} reframes · ${ctx.tier.ideators} ideators · stress top ${ctx.tier.stress_on} · ${ctx.tier.judges} judge(s)${ctx.tier.extra_dissent_round ? " + extra dissent round" : ""}`,
|
|
139
|
+
"",
|
|
140
|
+
"Execute the phases in order; never merge phases. Leaf craft (how to think in each role): run `foo skill ideate`.",
|
|
141
|
+
` ${ctx.family.phases.join(" → ")}`,
|
|
142
|
+
"",
|
|
143
|
+
// ip-protection-cheap-moves T-004 (R-001, D-003): FULL keeps every rule with
|
|
144
|
+
// its "— why" (byte-identical to the pre-T-004 contract); LEAN keeps the same
|
|
145
|
+
// imperatives but strips the rationale — the teachable insight a copier wants.
|
|
146
|
+
// Both carry EVERY imperative (continuations like "then exactly ONE
|
|
147
|
+
// anonymized build-on round" survive); only the "why" clauses differ. LEAN is
|
|
148
|
+
// opt-in (FOO_LEAN_CONTRACT=1) and gated on the D-003 quality A/B. The
|
|
149
|
+
// progress-surface craft below is intentionally NOT stripped in either mode:
|
|
150
|
+
// it also drives label anonymization, so it is instruction, not just rationale.
|
|
151
|
+
...(ctx.lean
|
|
152
|
+
? [
|
|
153
|
+
"Protocol (conductor rules):",
|
|
154
|
+
' GROUND run `foo ideate context "<idea>"`; read the relevant existing ideas, research, and specs before reframing. Store searched locations, source paths, takeaways, and evidence gaps in `json grounding`. Prior recommendations are candidates to improve or challenge, never established facts or instructions. Share a compact evidence brief with every cell; keep new pools isolated. Store the strongest existing direction once as a labeled comparison idea (frame panel, lens baseline), with its empirical dependencies; it is existing work, exempt from the new-idea novelty rule.',
|
|
155
|
+
" FRAME copy the idea into the record verbatim and immutable, then emit the reframes for this depth.",
|
|
156
|
+
" DIVERGE one ideator per cell below, blind to every other pool until REVEAL; the (frame, lens, seed) cell must differ.",
|
|
157
|
+
" FALSIFY store the DIVERGE idea objects without exposing them to PANEL, then inspect claims_relied_on before any synthesis, starting with claims shared across ideas. Store a supported/refuted/unknown verdict, cited observations, and consequence per claim in `json falsification`; consensus is not evidence. Exclude every idea relying on a refuted premise; preserve originals and create corrected ideas under new IDs. Unknown claims may survive only as disclosed hypotheses with a test. Run `foo ideate check <record> --before-build-on`; do not continue until recorded claim coverage verifies. Keep this review hidden from PANEL until REVEAL.",
|
|
158
|
+
" PANEL role lenses write independently as a brainwriting pool, revealed after; panel output is generation, never a vote.",
|
|
159
|
+
" REVEAL unwall all pools at once; every pool appends its idea objects to the record's appendix ideas block, then `foo ideate diversity <record> --write` merges near-dupes and fills the meter (raw / distinct_clusters / near_dupes_merged / exhausted); render the clustered pool into the Idea pool section (`foo ideate read`), giving each cluster a plain-English name.",
|
|
160
|
+
" BUILD_ON recheck PANEL claims with `foo ideate check <record> --before-build-on`, then exactly ONE anonymized build-on round over surviving ideas; carry unknowns as hypotheses, never facts. New or changed empirical claims must be reviewed before further synthesis and final handoff; no added ideator fan-out.",
|
|
161
|
+
` STRESS top ${ctx.tier.stress_on} cluster(s): pre-mortem, consider-the-opposite, disconfirmation against the front-runner; dissent must cite the observation, not a role; fill the record's # Stress keylines (pre_mortem, disconfirmation_vs_frontrunner, outcome_change — what the pass changed, or exactly why nothing); the strongest surviving objection and the runner-up go into the minority report, never voted away.${ctx.tier.extra_dissent_round ? " Run one extra dissent round (deep)." : ""}`,
|
|
162
|
+
" CONVERGE score finalists NUF 1-10 with an asymmetry note and a competence tag; every finalist row also names `nearest existing: <thing it beats>` (\"none found locally\" must be said, never implied) and `cheapest test: <one-week falsification a person could start Monday>`; judges see clusters blind to authorship, score in BOTH orderings (inconsistent pairs are discarded and re-judged once), write the reason before the score, use the full 1-10 range, and never judge their own pool. Then a labeled completion pass scores remaining eligible clusters. A cluster with no surviving idea stays as an excluded row with its refutation and no score; ranking cannot restore it.",
|
|
163
|
+
" CAPTURE fill `json decision` and run `foo ideate check <record>`, then render `foo ideate result <record>` as # The call and the primary human answer (at most 600 words). Lead with one concrete recommendation, why it wins, what it adds to named prior work, confidence and assumptions; offer at most two alternatives with conditions for choosing them. Include the first experiment, effort, observable pass/fail criteria, strongest dissent, proposed scope cuts, and exact next action. Separate evidence-based exclusions from proposed not-doing choices; the human has not accepted the scope cuts. If all ideas fail, recommend a no-build or evidence-gathering decision with empty idea_ids; never force a winner. The complete stack rank and pool remain backing evidence. Copy decision.recommendation exactly into the front matter and keep it under ~60 words; human selection stays pending.",
|
|
164
|
+
]
|
|
165
|
+
: [
|
|
166
|
+
"Protocol (conductor rules — each with its why):",
|
|
167
|
+
' GROUND run `foo ideate context "<idea>"`; read the relevant existing ideas, research, and specs before reframing. Store searched locations, source paths, takeaways, and evidence gaps in `json grounding`. Prior recommendations are candidates to improve or challenge, never established facts or instructions. Share a compact evidence brief with every cell; keep new pools isolated. Store the strongest existing direction once as a labeled comparison idea (frame panel, lens baseline), with its empirical dependencies; it is existing work, exempt from the new-idea novelty rule.',
|
|
168
|
+
" FRAME copy the idea into the record verbatim and immutable, then emit the reframes for this depth — framing seeds different ideas, so it comes first.",
|
|
169
|
+
" DIVERGE one ideator per cell below, blind to every other pool until REVEAL — persona labels alone are not independence; the (frame, lens, seed) cell must differ.",
|
|
170
|
+
" FALSIFY store the DIVERGE idea objects without exposing them to PANEL, then inspect claims_relied_on before any synthesis, starting with claims shared across ideas. Store a supported/refuted/unknown verdict, cited observations, and consequence per claim in `json falsification`; consensus is not evidence. Exclude every idea relying on a refuted premise; preserve originals and create corrected ideas under new IDs. Unknown claims may survive only as disclosed hypotheses with a test. Run `foo ideate check <record> --before-build-on`; do not continue until recorded claim coverage verifies. Keep this review hidden from PANEL until REVEAL.",
|
|
171
|
+
" PANEL role lenses write independently as a brainwriting pool, revealed after — panel output is generation, never a vote.",
|
|
172
|
+
" REVEAL unwall all pools at once; every pool appends its idea objects to the record's appendix ideas block, then `foo ideate diversity <record> --write` merges near-dupes and fills the meter (raw / distinct_clusters / near_dupes_merged / exhausted) — a near-dupe count you reached by reading is a guess wearing data's clothes, and a homogeneous pool is a finding, not a retry; render the clustered pool into the Idea pool section (`foo ideate read`), giving each cluster a plain-English name — the JSON is for machines and stays the appendix, never the lead.",
|
|
173
|
+
" BUILD_ON recheck PANEL claims with `foo ideate check <record> --before-build-on`, then exactly ONE anonymized build-on round over surviving ideas; carry unknowns as hypotheses, never facts. New or changed empirical claims must be reviewed before further synthesis and final handoff — more rounds entrench errors; no added ideator fan-out.",
|
|
174
|
+
` STRESS top ${ctx.tier.stress_on} cluster(s): pre-mortem, consider-the-opposite, disconfirmation against the front-runner — dissent must cite the observation, not a role; fill the record's # Stress keylines (pre_mortem, disconfirmation_vs_frontrunner, outcome_change — what the pass changed, or exactly why nothing: a stress pass that leaves no trace is a stress pass that can be skipped); the strongest surviving objection and the runner-up go into the minority report, never voted away.${ctx.tier.extra_dissent_round ? " Run one extra dissent round (deep)." : ""}`,
|
|
175
|
+
" CONVERGE score finalists NUF 1-10 with an asymmetry note and a competence tag; every finalist row also names `nearest existing: <thing it beats>` (\"none found locally\" must be said, never implied — an N score with no named neighbor is a number wearing a measurement's clothes) and `cheapest test: <one-week falsification a person could start Monday>`; judges see clusters blind to authorship, score in BOTH orderings (inconsistent pairs are discarded and re-judged once), write the reason before the score, use the full 1-10 range — a pool judged 4-to-7 is a judge refusing to judge — and never judge their own pool. Then a labeled completion pass scores remaining eligible clusters. A cluster with no surviving idea stays as an excluded row with its refutation and no score; ranking cannot restore it.",
|
|
176
|
+
" CAPTURE fill `json decision` and run `foo ideate check <record>`, then render `foo ideate result <record>` as # The call and the primary human answer (at most 600 words). Lead with one concrete recommendation, why it wins, what it adds to named prior work, confidence and assumptions; offer at most two alternatives with conditions for choosing them. Include the first experiment, effort, observable pass/fail criteria, strongest dissent, proposed scope cuts, and exact next action. Separate evidence-based exclusions from proposed not-doing choices; the human has not accepted the scope cuts. If all ideas fail, recommend a no-build or evidence-gathering decision with empty idea_ids; never force a winner. The complete stack rank and pool remain backing evidence. Copy decision.recommendation exactly into the front matter and keep it under ~60 words; human selection stays pending.",
|
|
177
|
+
]),
|
|
178
|
+
"",
|
|
179
|
+
// ideate-cost-v1 T-003 (R-002): prose in, hand-clustering out. The schema is
|
|
180
|
+
// an imperative, so it survives LEAN; only its "why" is stripped.
|
|
181
|
+
"Decision evidence (decisions-v2; one block each, in the backing record):",
|
|
182
|
+
' json grounding: {"searched":["ideas/","research/","specs/"],"sources":[{"source":"path","takeaway":"finding or earlier idea, with its uncertainty"}],"gap":"what is missing; say no relevant work found only after searching"}. Empty sources are valid when none is relevant.',
|
|
183
|
+
' json falsification: {"claims":[{"claim":"exact claims_relied_on text","verdict":"supported|refuted|unknown","evidence":[{"source":"file or approved citation","observation":"what was actually observed"}],"consequence":"what changes or remains conditional"}],"excluded_ideas":["refuted idea id"]}. Review every stored empirical claim; evidence may be empty only for unknown. This check verifies coverage, not truth or chronology.',
|
|
184
|
+
' json decision: {"recommendation":"concrete choice","rationale":"why it beats the closest alternative","new_contribution":"what becomes possible beyond the prior ideas","builds_on":[{"source":"a grounding source path","delta":"what is retained, changed, or rejected"}],"idea_ids":["surviving source idea"],"assumptions":["unresolved claims, copied exactly, plus the load-bearing bet"],"confidence":{"level":"low|medium|high","reason":"evidence and limits"},"alternatives":[{"direction":"plain name","choose_when":"specific switch condition","idea_ids":["surviving source idea"]}],"experiment":{"action":"smallest useful test","effort":"time/cost bound","pass":"observable success criterion","fail":"stop or change-direction criterion"},"dissent":"strongest surviving objection","not_doing":["cut and why"],"next_action":"exact action or command for the human"}. At most 2 alternatives and 3 builds_on references; cite only sources already read and recorded. An empty idea_ids is a deliberate no-build recommendation.',
|
|
185
|
+
"Use prior research as context until its empirical claims are checked. New web research uses foo research; connected-source approval rules still apply. Do not launch research automatically to fill a gap; unknown is a valid result.",
|
|
186
|
+
"",
|
|
187
|
+
"Required output shape — every ideator and panelist returns objects, never prose:",
|
|
188
|
+
' {"id": "i1", "claim": "one sentence", "frame": "<your frame>", "lens": "<your lens>", "reasoning": "the frame move, SHOWN — shapes below", "mechanism": "free text: how it works", "assumption": "the one load-bearing assumption", "novelty": "vs: <nearest existing or obvious approach> — <what this beats it on>", "claims_relied_on": ["empirical claim this rests on"]}',
|
|
189
|
+
" Append each object to the record's ideas block. `mechanism` is read by humans and never clustered on, so keep the nuance there.",
|
|
190
|
+
...(ctx.lean
|
|
191
|
+
? []
|
|
192
|
+
: [" The meter is computed from those objects, never counted by hand — a near-dupe number a human eyeballed is worse than none, because every downstream reader treats it as measured."]),
|
|
193
|
+
"",
|
|
194
|
+
"Frame execution (frames-v1, gated) — `reasoning` must SHOW the move; a frame label without its move is cosplay and fails `foo ideate check`:",
|
|
195
|
+
" analogy `source-domain: <domain>` and `mechanism-stolen: <the mechanism>` — steal the mechanism, never the surface.",
|
|
196
|
+
" inversion `guarantee-failure: <ingredient>; <ingredient>; …` then `negated: <the negation this idea is>` — enumerate the failure first.",
|
|
197
|
+
" how-might-we `tension: <the tension>` and `answer: <why this answers the sharpest HMW>`.",
|
|
198
|
+
" first-principles `bedrock: <what must be true>` and `discarded-assumption: <the inherited default this rejects>`.",
|
|
199
|
+
" second-order `then-1: <first-order effect>` and `then-2: <what that causes next>`.",
|
|
200
|
+
" panel/build-on free text stating the move (never empty).",
|
|
201
|
+
"Novelty must be a useful difference: compare against the strongest existing idea or current workflow, name a changed mechanism and a concrete before/after example in mechanism. Reuse good earlier ideas; include a surprising alternative without treating novelty as an automatic win. Claims of research support belong in claims_relied_on and get checked.",
|
|
202
|
+
"Cell economics: each cell returns AT MOST 4 idea objects. Keep the existing-direction baseline as a comparison. For NEW candidates, your first instinct is the pool's most available idea — everyone else has it too, so discard generic restatements and return ideas whose `novelty` can honestly say what they beat (`vs: …`). Four ideas that survive that test beat ten that don't.",
|
|
203
|
+
...(ctx.lean
|
|
204
|
+
? ["Constraints named in the idea are held ONCE, here at contract level — never restate consent, approval, or exclusion language inside idea objects."]
|
|
205
|
+
: ["Constraints named in the idea are held ONCE, here at contract level — never restate consent, approval, or exclusion language inside idea objects: a mechanism spent on disclaimers is a mechanism not spent on the idea, and forty restatements of the same guardrail are what a homogeneous pool is made of."]),
|
|
206
|
+
"",
|
|
207
|
+
"Engineered independence — one ideator per cell, hidden until REVEAL (R2):",
|
|
208
|
+
...ctx.cells.map((c) => ` ${c.role}: frame=${c.attrs.frame} lens=${c.attrs.lens} seed=${c.attrs.seed}`),
|
|
209
|
+
// #614: the pools this contract mandates are a LOCAL fan-out, and productfoo's own
|
|
210
|
+
// research gate cannot know that from the outside — an ideator prompt asking
|
|
211
|
+
// for claims that cite their evidence looks, word for word, like a research
|
|
212
|
+
// sweep. Saying where the cell reads is what separates them, so the contract
|
|
213
|
+
// says it rather than leaving each cell's fate to its phrasing.
|
|
214
|
+
" Every cell reads local sources only — say exactly that in each spawn. These pools read this repo and the files already on disk; a cell that needs the open web is not an ideator, it is a research run, and it goes through `foo research`.",
|
|
215
|
+
"",
|
|
216
|
+
"Progress surface (what the USER sees WHILE ideators run — separate from the record above):",
|
|
217
|
+
` Narrate the whole divergence as ONE foo status line, not a per-ideator agent tree — e.g. "🔄 doing — exploring ${ctx.tier.ideators} independent idea directions" while they run, then "✋ needs your input — shortlist ready" at the handoff. The ideator count and cell machinery are plumbing; productfoo feels simple only when plumbing stays invisible.`,
|
|
218
|
+
` If your harness insists on surfacing agents separately, label EVERY agent — in EVERY phase (DIVERGE ideators, PANEL lenses, STRESS reviewers, CONVERGE judges) — as "Explorer N" with ONE running counter that never resets between phases, so no phase is distinguishable from another. The label is the NUMBER ALONE: never a frame, lens, seed, role, OR a stress/judging technique — never "pre-mortem", "consider-the-opposite", "disconfirmation", "Stress: …", "Panel: …", "Judge: …". Each agent's final line is a bare COUNT of what it produced — "Done — 9 ideas", "Done — 3 findings" — never the technique it ran. "Explorer 1 inversion/product", "Stress: pre-mortem", and "Panel: reverse-engineering red team" all leak the craft exactly as loudly as the raw slug did; a number with anything stapled to it is not anonymized.`,
|
|
219
|
+
" WHICH frames and lenses foo pairs, which stress moves it runs against the front-runner, and how the cells are engineered for independence — ALL of it is the craft. A progress panel is the most screenshotted, most shared surface productfoo has; none of that design belongs in transient chrome.",
|
|
220
|
+
" Numbered in the RUNTIME, named in the RECORD. Anonymity buys secrecy in the chrome, never in the product: the frames, clusters, diversity meter, and minority report stay fully visible in the record, each attributed to its real cell. Never write \"Explorer 3\" into a report — a reader who did not watch the run cannot resolve a number back to an idea.",
|
|
221
|
+
"",
|
|
222
|
+
"If it goes wrong: homogeneous pool → vary frames (not seeds) for one regeneration, else record exhausted: true visibly; judge inconsistency → discard the pair, re-judge once, else log it unresolved in the minority report; no surviving dissent → run one extra disconfirmation pass before recording an empty minority report, and say so.",
|
|
223
|
+
"",
|
|
224
|
+
`Ideate record scaffolded: ${ctx.recordPath}`,
|
|
225
|
+
" Read that record before you fill it. productfoo's CLI wrote the file, not you — and a harness that guards blind overwrites refuses the first write to a file the session has never read, so filling it blind fails.",
|
|
226
|
+
`Verify before hand-off: ${verification(ctx)} — fix named fields; never hand-edit the verdict; the record is the contract.`,
|
|
227
|
+
"Boundary B4: allowed actions are frame/generate/cluster/critique/score — never ship, send, commit, or auto-promote.",
|
|
228
|
+
`The human picks the winner. Then: ${HANDOFF}`,
|
|
229
|
+
"",
|
|
230
|
+
],
|
|
231
|
+
gates: [
|
|
232
|
+
{ type: "ideate-falsification", check: "early-falsification" },
|
|
233
|
+
{ type: "ideate-decision", check: "actionable-decision" },
|
|
234
|
+
{ type: "frontmatter-present", check: "raw-idea", field: "idea", detail: "raw idea captured verbatim", failDetail: "idea missing from front matter" },
|
|
235
|
+
{ type: "frontmatter-present", check: "depth", field: "depth", pattern: "(fast|standard|deep)", detail: "depth {value}", failDetail: "depth missing or invalid" },
|
|
236
|
+
{ type: "diversity-meter", check: "diversity-meter", floorCap: 3, floorKey: "ideators" },
|
|
237
|
+
{ type: "diversity-provenance", check: "diversity-provenance" },
|
|
238
|
+
// frames-v1 gates (#695/#697/#698). All apply only to records carrying
|
|
239
|
+
// `ideate_contract: frames-v1`; older records pass with a "predates" note.
|
|
240
|
+
{ type: "frame-reasoning", check: "frame-execution" },
|
|
241
|
+
{ type: "versioned-keyline", check: "stress-pre-mortem", field: "pre_mortem", detail: "stress: pre-mortem recorded", failDetail: "stress pre_mortem empty — the adversarial pass left no trace (#695)" },
|
|
242
|
+
{ type: "versioned-keyline", check: "stress-disconfirmation", field: "disconfirmation_vs_frontrunner", detail: "stress: disconfirmation vs front-runner recorded", failDetail: "disconfirmation_vs_frontrunner empty — nobody tried to kill the front-runner (#695)" },
|
|
243
|
+
{ type: "versioned-keyline", check: "stress-outcome", field: "outcome_change", detail: "stress verdict recorded (what changed, or why nothing)", failDetail: "outcome_change empty — say what stress changed, or exactly why it changed nothing (#695)" },
|
|
244
|
+
{ type: "versioned-keyline", check: "novelty-anchor", field: "nearest_existing", detail: "novelty anchored: nearest existing thing named", failDetail: 'nearest_existing empty — N is unanchored until the recommendation names what it beats; "none found locally" must be said (#698)' },
|
|
245
|
+
{ type: "versioned-keyline", check: "cheapest-test", field: "cheapest_test", detail: "cheapest one-week falsification test recorded", failDetail: "cheapest_test empty — the recommendation has no one-week falsification a person could start Monday" },
|
|
246
|
+
// The record's face takes a position: a null recommendation cannot verify.
|
|
247
|
+
{ type: "versioned-keyline", check: "recommendation", field: "recommendation", detail: "recommendation takes a position", failDetail: 'recommendation is null — the record must open with a stance: "<winner>. <why>. Bet: <assumption>. Test: <Monday falsifier>."' },
|
|
248
|
+
{ type: "frontmatter-nonempty", check: "minority-report", field: "minority_report", detail: "dissent preserved", failDetail: "minority report empty — dissent was voted away (R5)" },
|
|
249
|
+
{ type: "frontmatter-nonempty", check: "not-doing", field: "not_doing", detail: "explicit not-doing recorded", failDetail: 'missing "what we are NOT doing" (R6)' },
|
|
250
|
+
{ type: "frontmatter-equals", check: "human-decider", field: "decider", expect: "human", detail: "human is the Decider", failDetail: "decider must be human, found: " },
|
|
251
|
+
{ type: "frontmatter-nonempty", check: "falsifier", field: "what_would_change_our_mind", detail: "decision-journal falsifier present", failDetail: 'missing "what would change our mind" (R7)' },
|
|
252
|
+
],
|
|
253
|
+
handoff: HANDOFF,
|
|
254
|
+
decider: "human",
|
|
255
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const interviewFamily = {
|
|
2
|
+
family: "interview",
|
|
3
|
+
banner: "── foo ▸ interview ── questions the user alone can answer ──",
|
|
4
|
+
tagline: "questions the user alone can answer",
|
|
5
|
+
skillRef: "interview-me", // a `foo skill` argument, never a filesystem path
|
|
6
|
+
defaultDepth: "fast",
|
|
7
|
+
depths: {
|
|
8
|
+
fast: { user_questions: 3, stack_ranked: true },
|
|
9
|
+
standard: { user_questions: 7, stack_ranked: true },
|
|
10
|
+
deep: { user_questions: 0, stack_ranked: true }, // 0 = until enough to decide
|
|
11
|
+
},
|
|
12
|
+
phases: ["DISCOVER", "RANK", "ASK", "BRIEF"],
|
|
13
|
+
cells: null, // interviews have no cell matrix; one interviewer, one human
|
|
14
|
+
record: null, // the Shape Brief lands in the packet's spec.md, not a record dir
|
|
15
|
+
contract: (ctx) => [
|
|
16
|
+
ctx.family.banner,
|
|
17
|
+
"",
|
|
18
|
+
`Work item: ${ctx.target}`,
|
|
19
|
+
`Depth: ${ctx.depth} — at most ${Number(ctx.tier.user_questions) || "as many as needed"} stack-ranked user questions.`,
|
|
20
|
+
"",
|
|
21
|
+
"Protocol (conductor rules — each with its why):",
|
|
22
|
+
" DISCOVER repo-first: inspect spec, code, tests, docs before forming any question — anything answerable from sources is never asked; the user's time is the scarcest input.",
|
|
23
|
+
" RANK stack-rank candidates by spec impact; only user-judgment questions survive (taste, risk appetite, source approval, materially valid options).",
|
|
24
|
+
" ASK one question at a time as numbered options, recommendation first marked (recommended) — the user answers with a digit; batching hides the ranking and anchors the reader.",
|
|
25
|
+
" BRIEF emit the 5-part Shape Brief: work-in-one-line · bet + who it's for · source/approval boundaries · MVP scope + validation bar · judgment-ledger seed (belief, evidence, confidence, dissent, user-only decisions).",
|
|
26
|
+
"",
|
|
27
|
+
"Answers are recorded as packet decisions with the user's framing preserved — pushback is part of the record. Risky work escalates to a full packet (B3).",
|
|
28
|
+
"Leaf craft (how to ask well): run `foo skill interview-me`.",
|
|
29
|
+
"",
|
|
30
|
+
],
|
|
31
|
+
gates: [
|
|
32
|
+
{ type: "section-present", check: "shape-brief", heading: "Shape Brief", detail: "shape brief present", failDetail: "Shape Brief section missing" },
|
|
33
|
+
{ type: "frontmatter-present", check: "spec-id", field: "spec_id", detail: "spec identity present (B2)", failDetail: "spec_id missing (B2)" },
|
|
34
|
+
{ type: "section-present", check: "intent", heading: "Intent", detail: "intent present", failDetail: "Intent section missing" },
|
|
35
|
+
{ type: "section-present", check: "open-questions", heading: "Open Questions", detail: "open questions surfaced", failDetail: "Open Questions section missing — user-only decisions were not surfaced" },
|
|
36
|
+
],
|
|
37
|
+
handoff: "foo spec start <work-item>",
|
|
38
|
+
decider: "human",
|
|
39
|
+
};
|