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,423 @@
|
|
|
1
|
+
// ideate-cost-v1 (R-002, T-003) — the diversity meter, computed.
|
|
2
|
+
//
|
|
3
|
+
// The v0 run had the orchestrator read 70 markdown ideas and hand-cluster them;
|
|
4
|
+
// the recorded `near_dupes_merged: 38` was a number a human eyeballed while
|
|
5
|
+
// reading, and every downstream consumer treated it as measured. That is worse
|
|
6
|
+
// than no number. So ideator/panelist output becomes a validated object, and
|
|
7
|
+
// merging becomes deterministic code over those objects: same ideas in, same
|
|
8
|
+
// meter out, reproducible by anyone holding the record.
|
|
9
|
+
//
|
|
10
|
+
// RISK-002: `mechanism` is free text that survives the schema so nuance is not
|
|
11
|
+
// flattened — it is read by humans and NEVER enters the clustering feature set.
|
|
12
|
+
// One idea, as an ideator or panelist returns it.
|
|
13
|
+
import { parse as parseYaml } from "../vendorYaml.js";
|
|
14
|
+
// Which clusterer produced a meter. Stamped into the record next to the meter
|
|
15
|
+
// so a reader can tell a number computed by today's code from one computed by
|
|
16
|
+
// an older, weaker one — and so the provenance gate can say "recompute this"
|
|
17
|
+
// instead of "your arithmetic is wrong" when the algorithm moves under a record.
|
|
18
|
+
//
|
|
19
|
+
// v1 was set-Jaccard over unweighted tokens at 0.5. Bump this whenever a change
|
|
20
|
+
// would move the meter on the same pool.
|
|
21
|
+
//
|
|
22
|
+
// v3 (#693): v2 clustered on claim + assumption + relied-on facts, which reads
|
|
23
|
+
// TOPIC diversity — one move repeated across twenty spend categories scored as
|
|
24
|
+
// twenty clusters, because each category's rare nouns drove the vectors apart
|
|
25
|
+
// while the shared move lived in fields the clusterer never saw. v3 adds the
|
|
26
|
+
// frames-v1 `reasoning` field to the feature set: the reasoning carries the
|
|
27
|
+
// move (the failure ingredients enumerated, the source domain named), so two
|
|
28
|
+
// ideas making the same move now share the vocabulary that actually matters.
|
|
29
|
+
// On pre-frames-v1 pools reasoning is empty and v3 computes exactly what v2
|
|
30
|
+
// computed, so old measured records still reproduce.
|
|
31
|
+
export const CLUSTERER_ID = "idf-cosine-v3-moves";
|
|
32
|
+
// Two ideas are the same idea when their weighted feature vectors point this
|
|
33
|
+
// close to the same direction. Held here so the number is auditable rather than
|
|
34
|
+
// implicit, and calibrated against a real pool rather than picked by taste — see
|
|
35
|
+
// the note on `similarity` below for the measurement.
|
|
36
|
+
export const NEAR_DUPE_THRESHOLD = 0.25;
|
|
37
|
+
// A floor under every token's IDF weight. Pure IDF has a degenerate case that
|
|
38
|
+
// matters here: when EVERY idea in the pool rests on the same fact, that fact
|
|
39
|
+
// appears in every document, so IDF calls it uninformative and starves the very
|
|
40
|
+
// signal that makes the pool homogeneous — a pool that is 100% one move would
|
|
41
|
+
// read as maximally diverse, which is the #613 failure wearing a new hat. The
|
|
42
|
+
// floor keeps universally-shared content contributing. Measured across both
|
|
43
|
+
// cases: 0.4 is the smallest floor that collapses a fully convergent pool to one
|
|
44
|
+
// cluster while leaving unrelated ideas apart and holding precision at 0.98 on
|
|
45
|
+
// the real 47-idea pool.
|
|
46
|
+
const IDF_FLOOR = 0.4;
|
|
47
|
+
// How much harder a shared empirical dependency counts than a shared ordinary
|
|
48
|
+
// word. Two ideators who independently leaned on the same observed fact are
|
|
49
|
+
// usually making the same move; two who both said "harness" are not.
|
|
50
|
+
const RELIED_WEIGHT = 3;
|
|
51
|
+
// v3: how much a shared reasoning token counts. The reasoning field carries the
|
|
52
|
+
// move itself, so it sits between ordinary prose (1) and a shared empirical
|
|
53
|
+
// dependency (3): strong evidence of the same move, weaker than the same fact.
|
|
54
|
+
const REASONING_WEIGHT = 2;
|
|
55
|
+
const STOPWORDS = new Set([
|
|
56
|
+
"a", "an", "and", "are", "as", "at", "be", "but", "by", "can", "for", "from", "has", "have", "in", "into",
|
|
57
|
+
"is", "it", "its", "not", "of", "on", "or", "so", "that", "the", "their", "then", "there", "they", "this",
|
|
58
|
+
"to", "was", "we", "were", "when", "which", "will", "with", "you", "your",
|
|
59
|
+
]);
|
|
60
|
+
// Light suffix folding so "pin"/"pinning", "invoke"/"invocation" and
|
|
61
|
+
// "dependency"/"dependencies" are one feature. Deliberately crude: a real
|
|
62
|
+
// stemmer is a dependency, and the failure mode we care about (the same
|
|
63
|
+
// mechanism described in two vocabularies) is mostly carried by rare nouns that
|
|
64
|
+
// survive this untouched.
|
|
65
|
+
const SUFFIXES = ["ing", "edly", "ed", "es", "s", "ly", "ment", "tion", "ance", "ence"];
|
|
66
|
+
function stem(word) {
|
|
67
|
+
for (const suffix of SUFFIXES) {
|
|
68
|
+
if (word.length - suffix.length >= 4 && word.endsWith(suffix))
|
|
69
|
+
return word.slice(0, -suffix.length);
|
|
70
|
+
}
|
|
71
|
+
return word;
|
|
72
|
+
}
|
|
73
|
+
function tokens(text) {
|
|
74
|
+
return text
|
|
75
|
+
.toLowerCase()
|
|
76
|
+
.split(/[^a-z0-9]+/)
|
|
77
|
+
.filter((t) => t.length > 2 && !STOPWORDS.has(t))
|
|
78
|
+
.map(stem);
|
|
79
|
+
}
|
|
80
|
+
// The clustering feature set: what the idea says (claim), what it rests on
|
|
81
|
+
// (assumption), and which empirical claims it relies on — the last weighted
|
|
82
|
+
// `RELIED_WEIGHT` times heavier and, unlike v1, sharing one namespace with the
|
|
83
|
+
// prose. v1 namespaced relied-on tokens as `relied:<t>`, which meant the fact
|
|
84
|
+
// "interactive is Boolean(process.stdout.isTTY)" in one idea's `claims_relied_on`
|
|
85
|
+
// could never match the same fact stated in another idea's `claim`. That is
|
|
86
|
+
// precisely the match we need, so the namespace is gone; IDF now does the job
|
|
87
|
+
// namespacing was there for, by starving common words of weight.
|
|
88
|
+
//
|
|
89
|
+
// `mechanism`, `frame`, and `lens` remain deliberately absent: mechanism is the
|
|
90
|
+
// nuance we promised not to cluster on (RISK-002), and frame/lens are the cell
|
|
91
|
+
// the idea came from, so including them would make independence look like
|
|
92
|
+
// similarity. `reasoning` (v3) is the exception that proves the rule: it holds
|
|
93
|
+
// the MOVE, not the nuance, and the move is exactly what the meter must read.
|
|
94
|
+
export function featureSet(idea) {
|
|
95
|
+
const feats = new Map();
|
|
96
|
+
const add = (t, weight) => feats.set(t, (feats.get(t) ?? 0) + weight);
|
|
97
|
+
for (const t of tokens(idea.claim))
|
|
98
|
+
add(t, 1);
|
|
99
|
+
for (const t of tokens(idea.assumption))
|
|
100
|
+
add(t, 1);
|
|
101
|
+
// v3 (#693): the reasoning content joins the feature set — it is where the
|
|
102
|
+
// move lives. The frames-v1 shape LABELS ("guarantee-failure:", "bedrock:")
|
|
103
|
+
// are stripped first: every idea in the same frame carries the same labels,
|
|
104
|
+
// so leaving them in would make sharing a frame look like sharing a move.
|
|
105
|
+
for (const t of tokens((idea.reasoning ?? "").replace(/\b[a-z][a-z0-9-]*:/gi, " ")))
|
|
106
|
+
add(t, REASONING_WEIGHT);
|
|
107
|
+
for (const claim of idea.claims_relied_on)
|
|
108
|
+
for (const t of tokens(claim))
|
|
109
|
+
add(t, RELIED_WEIGHT);
|
|
110
|
+
return feats;
|
|
111
|
+
}
|
|
112
|
+
// Inverse document frequency across the pool being measured. This is what makes
|
|
113
|
+
// the meter read ideas rather than wordcounts: in a pool about productfoo's CLI, every
|
|
114
|
+
// idea says "foo" and "command", so those carry almost no weight, while
|
|
115
|
+
// "isTTY" or "invocation" — said by only the ideators who found the same
|
|
116
|
+
// mechanism — carry a lot.
|
|
117
|
+
//
|
|
118
|
+
// Note the consequence, which is a property of the measure and not a bug: IDF is
|
|
119
|
+
// computed over the pool, so similarity is a fact about ideas *in this pool*,
|
|
120
|
+
// not an absolute. Adding ideas can move existing pair scores. The meter is a
|
|
121
|
+
// statement about a pool, and it is recomputed whole, so this stays coherent —
|
|
122
|
+
// but it is why a meter must be recomputed rather than incrementally patched.
|
|
123
|
+
function inverseDocumentFrequency(pool) {
|
|
124
|
+
const documentCount = new Map();
|
|
125
|
+
for (const feats of pool) {
|
|
126
|
+
for (const t of feats.keys())
|
|
127
|
+
documentCount.set(t, (documentCount.get(t) ?? 0) + 1);
|
|
128
|
+
}
|
|
129
|
+
const idf = new Map();
|
|
130
|
+
for (const [t, df] of documentCount)
|
|
131
|
+
idf.set(t, Math.log((pool.length + 1) / (df + 0.5)) + IDF_FLOOR);
|
|
132
|
+
return idf;
|
|
133
|
+
}
|
|
134
|
+
function cosine(a, b, idf) {
|
|
135
|
+
let dot = 0;
|
|
136
|
+
let normA = 0;
|
|
137
|
+
let normB = 0;
|
|
138
|
+
for (const [t, weight] of a) {
|
|
139
|
+
const w = weight * (idf.get(t) ?? 0);
|
|
140
|
+
normA += w * w;
|
|
141
|
+
const other = b.get(t);
|
|
142
|
+
if (other !== undefined)
|
|
143
|
+
dot += w * other * (idf.get(t) ?? 0);
|
|
144
|
+
}
|
|
145
|
+
for (const [t, weight] of b) {
|
|
146
|
+
const w = weight * (idf.get(t) ?? 0);
|
|
147
|
+
normB += w * w;
|
|
148
|
+
}
|
|
149
|
+
if (normA === 0 || normB === 0)
|
|
150
|
+
return 0;
|
|
151
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
152
|
+
}
|
|
153
|
+
// Similarity of two ideas *within a pool*. The pool argument is required because
|
|
154
|
+
// the weighting is IDF — see above. `similarityIn` is the honest signature;
|
|
155
|
+
// `similarity` keeps the old two-argument shape for callers measuring a single
|
|
156
|
+
// pair, by treating the pair as its own pool.
|
|
157
|
+
//
|
|
158
|
+
// Calibration (2026-07-24, the 47-idea pool from the run that filed #613, whose
|
|
159
|
+
// four convergent clusters were identified by reading all 47): v1's Jaccard-at-
|
|
160
|
+
// 0.5 merged 0 of 78 same-idea pairs — and the same-pair and different-pair
|
|
161
|
+
// score distributions overlapped under that feature set, so *no* threshold could
|
|
162
|
+
// have separated them. This measure does: at 0.25 it recovers the clusters with
|
|
163
|
+
// precision 0.98 and recall 0.77, and it reads a fully convergent pool as one
|
|
164
|
+
// cluster rather than as maximum diversity.
|
|
165
|
+
export function similarityIn(a, b, pool) {
|
|
166
|
+
const feats = pool.map(featureSet);
|
|
167
|
+
return cosine(featureSet(a), featureSet(b), inverseDocumentFrequency(feats));
|
|
168
|
+
}
|
|
169
|
+
export function similarity(a, b) {
|
|
170
|
+
return similarityIn(a, b, [a, b]);
|
|
171
|
+
}
|
|
172
|
+
// Average-linkage agglomerative clustering: repeatedly merge the two closest
|
|
173
|
+
// clusters, where distance between clusters is the mean similarity across all
|
|
174
|
+
// their member pairs, until nothing is closer than NEAR_DUPE_THRESHOLD.
|
|
175
|
+
//
|
|
176
|
+
// v1 used single linkage, on the reasoning that near-dupe is transitive. Under a
|
|
177
|
+
// measure sensitive enough to actually find near-dupes, it isn't: single linkage
|
|
178
|
+
// chains, so one lucky link between two genuinely different ideas fuses their
|
|
179
|
+
// whole clusters. Measured on the #613 pool, single linkage at this threshold
|
|
180
|
+
// collapsed 47 ideas into 15 clusters and fused two distinct attractors into one
|
|
181
|
+
// blob of 14 (precision 0.40). Average linkage on the same pool and threshold
|
|
182
|
+
// gives 23 clusters at precision 0.98, and degrades gracefully as the threshold
|
|
183
|
+
// moves rather than falling off a cliff.
|
|
184
|
+
//
|
|
185
|
+
// That asymmetry is deliberate: over-merging invents convergence that is not
|
|
186
|
+
// there, which is the failure this meter exists to prevent. When the clusterer
|
|
187
|
+
// is unsure, it should leave two ideas apart and let a reader find the overlap.
|
|
188
|
+
//
|
|
189
|
+
// The result does not depend on the order the ideators happened to report in — a
|
|
190
|
+
// meter that moves when you shuffle the input is not a measurement — so ties are
|
|
191
|
+
// broken on idea id, not on position.
|
|
192
|
+
export function computeDiversity(ideas, exhausted = false) {
|
|
193
|
+
// Feature vectors and the pool's IDF are computed once, not per pair: the
|
|
194
|
+
// comparison is O(n²) and rebuilding the weighting inside it would be O(n³).
|
|
195
|
+
const feats = ideas.map(featureSet);
|
|
196
|
+
const idf = inverseDocumentFrequency(feats);
|
|
197
|
+
const n = ideas.length;
|
|
198
|
+
const pair = Array.from({ length: n }, () => new Array(n).fill(0));
|
|
199
|
+
for (let i = 0; i < n; i += 1) {
|
|
200
|
+
for (let j = i + 1; j < n; j += 1) {
|
|
201
|
+
pair[i][j] = pair[j][i] = cosine(feats[i], feats[j], idf);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Clusters as index lists, in first-appearance order. `members` is kept sorted
|
|
205
|
+
// by original index so cluster contents render in pool order.
|
|
206
|
+
let groups = ideas.map((_, i) => [i]);
|
|
207
|
+
const meanSimilarity = (a, b) => {
|
|
208
|
+
let total = 0;
|
|
209
|
+
for (const i of a)
|
|
210
|
+
for (const j of b)
|
|
211
|
+
total += pair[i][j];
|
|
212
|
+
return total / (a.length * b.length);
|
|
213
|
+
};
|
|
214
|
+
for (;;) {
|
|
215
|
+
let best = -1;
|
|
216
|
+
let bestX = -1;
|
|
217
|
+
let bestY = -1;
|
|
218
|
+
for (let x = 0; x < groups.length; x += 1) {
|
|
219
|
+
for (let y = x + 1; y < groups.length; y += 1) {
|
|
220
|
+
const value = meanSimilarity(groups[x], groups[y]);
|
|
221
|
+
if (value < NEAR_DUPE_THRESHOLD)
|
|
222
|
+
continue;
|
|
223
|
+
// Strictly-greater keeps the first pair on a tie, and because groups are
|
|
224
|
+
// held in first-appearance order that first pair is a function of the
|
|
225
|
+
// ideas, not of the order they arrived in.
|
|
226
|
+
if (value > best) {
|
|
227
|
+
best = value;
|
|
228
|
+
bestX = x;
|
|
229
|
+
bestY = y;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (bestX === -1)
|
|
234
|
+
break;
|
|
235
|
+
const merged = [...groups[bestX], ...groups[bestY]].sort((a, b) => a - b);
|
|
236
|
+
groups = groups.filter((_, i) => i !== bestX && i !== bestY);
|
|
237
|
+
groups.push(merged);
|
|
238
|
+
groups.sort((a, b) => a[0] - b[0]);
|
|
239
|
+
}
|
|
240
|
+
const clusters = groups.map((group) => group.map((i) => ideas[i].id));
|
|
241
|
+
return {
|
|
242
|
+
raw: ideas.length,
|
|
243
|
+
distinct_clusters: clusters.length,
|
|
244
|
+
// The whole definition, stated once: a merge is an idea that did not earn
|
|
245
|
+
// its own cluster. Nothing here is a judgment call.
|
|
246
|
+
near_dupes_merged: ideas.length - clusters.length,
|
|
247
|
+
exhausted,
|
|
248
|
+
clusters,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
// --- Record I/O ---------------------------------------------------------------
|
|
252
|
+
// The structured pool lives in the record inside a fenced block so the record
|
|
253
|
+
// stays one human-readable file and still carries its own show-your-work.
|
|
254
|
+
export const IDEAS_FENCE_OPEN = "```json ideas";
|
|
255
|
+
const IDEAS_BLOCK = /```json ideas\s*\n([\s\S]*?)```/;
|
|
256
|
+
const REQUIRED_TEXT = ["id", "claim", "frame", "lens", "mechanism", "assumption", "novelty"];
|
|
257
|
+
// Validation is presence-and-shape only. It refuses prose where an object
|
|
258
|
+
// belongs; it does not grade the idea — that is what the panel is for.
|
|
259
|
+
export function parseIdeaObjects(recordText) {
|
|
260
|
+
const block = recordText.match(IDEAS_BLOCK);
|
|
261
|
+
if (!block)
|
|
262
|
+
return { ideas: [], errors: [], present: false };
|
|
263
|
+
let parsed;
|
|
264
|
+
try {
|
|
265
|
+
parsed = JSON.parse(block[1].trim() || "[]");
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
return { ideas: [], errors: [`ideas block is not valid JSON: ${err.message}`], present: true };
|
|
269
|
+
}
|
|
270
|
+
if (!Array.isArray(parsed))
|
|
271
|
+
return { ideas: [], errors: ["ideas block must be a JSON array"], present: true };
|
|
272
|
+
const errors = [];
|
|
273
|
+
const ideas = [];
|
|
274
|
+
const seen = new Set();
|
|
275
|
+
parsed.forEach((entry, i) => {
|
|
276
|
+
const at = `idea[${i}]`;
|
|
277
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
278
|
+
errors.push(`${at}: not an object`);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const obj = entry;
|
|
282
|
+
const missing = REQUIRED_TEXT.filter((f) => typeof obj[f] !== "string" || obj[f].trim() === "");
|
|
283
|
+
if (missing.length)
|
|
284
|
+
errors.push(`${at}: missing or empty ${missing.join(", ")}`);
|
|
285
|
+
const relied = obj.claims_relied_on;
|
|
286
|
+
if (!Array.isArray(relied) || relied.some((c) => typeof c !== "string")) {
|
|
287
|
+
errors.push(`${at}: claims_relied_on must be an array of strings (use [] when the idea rests on none)`);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (missing.length)
|
|
291
|
+
return;
|
|
292
|
+
const id = String(obj.id);
|
|
293
|
+
if (seen.has(id))
|
|
294
|
+
errors.push(`${at}: duplicate id ${id}`);
|
|
295
|
+
seen.add(id);
|
|
296
|
+
ideas.push({
|
|
297
|
+
id,
|
|
298
|
+
claim: String(obj.claim),
|
|
299
|
+
frame: String(obj.frame),
|
|
300
|
+
lens: String(obj.lens),
|
|
301
|
+
// Lenient on purpose: pre-frames-v1 records have no reasoning field, and
|
|
302
|
+
// the provenance gate must keep reproducing their meters. Presence is
|
|
303
|
+
// enforced by the frame-reasoning gate, only on frames-v1 records.
|
|
304
|
+
reasoning: typeof obj.reasoning === "string" ? obj.reasoning : "",
|
|
305
|
+
mechanism: String(obj.mechanism),
|
|
306
|
+
assumption: String(obj.assumption),
|
|
307
|
+
novelty: String(obj.novelty),
|
|
308
|
+
claims_relied_on: relied,
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
return { ideas, errors, present: true };
|
|
312
|
+
}
|
|
313
|
+
export const DIVERSITY_METER_LINE = /^diversity:\s*\{\s*raw:\s*(\d+),\s*distinct_clusters:\s*(\d+),\s*near_dupes_merged:\s*(\d+),\s*exhausted:\s*(true|false)\s*\}/m;
|
|
314
|
+
export function readDeclaredMeter(recordText) {
|
|
315
|
+
const m = recordText.match(DIVERSITY_METER_LINE);
|
|
316
|
+
if (!m)
|
|
317
|
+
return null;
|
|
318
|
+
return {
|
|
319
|
+
raw: Number(m[1]),
|
|
320
|
+
distinct_clusters: Number(m[2]),
|
|
321
|
+
near_dupes_merged: Number(m[3]),
|
|
322
|
+
exhausted: m[4] === "true",
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
// Absent reads as `estimated`: an older record never claimed to have computed
|
|
326
|
+
// anything, and the gate's job is to refuse a FALSE `measured`, not to
|
|
327
|
+
// retroactively fail records that were honest about being eyeballed.
|
|
328
|
+
export function readDiversityMethod(recordText) {
|
|
329
|
+
const m = recordText.match(/^diversity_method:\s*(\S+)/m);
|
|
330
|
+
if (!m)
|
|
331
|
+
return { value: "estimated", declared: false };
|
|
332
|
+
const value = m[1].trim();
|
|
333
|
+
if (value !== "measured" && value !== "estimated")
|
|
334
|
+
return null;
|
|
335
|
+
return { value, declared: true };
|
|
336
|
+
}
|
|
337
|
+
// Which clusterer computed the meter in this record, if it said. Absent means
|
|
338
|
+
// "older than the stamp" — which, for a `measured` record, is the same practical
|
|
339
|
+
// state as stale: the number was computed, but not by this code.
|
|
340
|
+
export function readClustererId(recordText) {
|
|
341
|
+
const m = recordText.match(/^diversity_clusterer:\s*(\S+)/m);
|
|
342
|
+
return m ? m[1].trim() : null;
|
|
343
|
+
}
|
|
344
|
+
export function clustererLine() {
|
|
345
|
+
return `diversity_clusterer: ${CLUSTERER_ID}`;
|
|
346
|
+
}
|
|
347
|
+
export function meterLine(meter) {
|
|
348
|
+
return `diversity: { raw: ${meter.raw}, distinct_clusters: ${meter.distinct_clusters}, near_dupes_merged: ${meter.near_dupes_merged}, exhausted: ${meter.exhausted} }`;
|
|
349
|
+
}
|
|
350
|
+
// --- frames-v1: executable frames (#697) --------------------------------------
|
|
351
|
+
// The contract version a record was scaffolded under. Gates that this version
|
|
352
|
+
// introduces (frame-reasoning, stress evidence, novelty anchor, cheapest test)
|
|
353
|
+
// apply only to records that carry the line — a record honest about being older
|
|
354
|
+
// is never retroactively failed.
|
|
355
|
+
export const IDEATE_CONTRACT_VERSION = "frames-v1";
|
|
356
|
+
export function ideateFrontmatter(record) {
|
|
357
|
+
const frontmatter = record.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/)?.[1];
|
|
358
|
+
if (frontmatter === undefined)
|
|
359
|
+
return {};
|
|
360
|
+
try {
|
|
361
|
+
const value = parseYaml(frontmatter);
|
|
362
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
export function ideateContractVersion(record) {
|
|
369
|
+
const value = ideateFrontmatter(record);
|
|
370
|
+
if (value === null)
|
|
371
|
+
return "invalid";
|
|
372
|
+
if (!Object.hasOwn(value, "ideate_contract"))
|
|
373
|
+
return null;
|
|
374
|
+
return typeof value.ideate_contract === "string" ? value.ideate_contract : "invalid";
|
|
375
|
+
}
|
|
376
|
+
export function hasExecutableFramesContract(recordText) {
|
|
377
|
+
const version = ideateContractVersion(recordText);
|
|
378
|
+
return version === IDEATE_CONTRACT_VERSION || version === "decisions-v2";
|
|
379
|
+
}
|
|
380
|
+
// The checkable SHAPE of each frame's move. Shape, never quality: an inversion
|
|
381
|
+
// that cannot show the failure it negated did not run inversion, whatever its
|
|
382
|
+
// label says — but how good the negation is stays with blind judging.
|
|
383
|
+
const FRAME_SHAPES = {
|
|
384
|
+
analogy: {
|
|
385
|
+
tags: [/source-domain:/i, /mechanism-stolen:/i],
|
|
386
|
+
hint: "reasoning must contain `source-domain:` and `mechanism-stolen:`",
|
|
387
|
+
},
|
|
388
|
+
inversion: {
|
|
389
|
+
tags: [/guarantee-failure:/i, /negated:/i],
|
|
390
|
+
hint: "reasoning must contain `guarantee-failure: <ingredient>; <ingredient>` then `negated:`",
|
|
391
|
+
},
|
|
392
|
+
"how-might-we": {
|
|
393
|
+
tags: [/tension:/i, /answer:/i],
|
|
394
|
+
hint: "reasoning must contain `tension:` and `answer:`",
|
|
395
|
+
},
|
|
396
|
+
"first-principles": {
|
|
397
|
+
tags: [/bedrock:/i, /discarded-assumption:/i],
|
|
398
|
+
hint: "reasoning must contain `bedrock:` and `discarded-assumption:`",
|
|
399
|
+
},
|
|
400
|
+
"second-order": {
|
|
401
|
+
tags: [/then-1:/i, /then-2:/i],
|
|
402
|
+
hint: "reasoning must contain `then-1:` and `then-2:`",
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
// Free-text frames (panel lenses, build-on, custom) still owe a shown move,
|
|
406
|
+
// just not a tagged one.
|
|
407
|
+
const MIN_FREE_REASONING = 20;
|
|
408
|
+
export function frameReasoningOffenders(ideas) {
|
|
409
|
+
const offenders = [];
|
|
410
|
+
for (const idea of ideas) {
|
|
411
|
+
const shape = FRAME_SHAPES[idea.frame.trim().toLowerCase()];
|
|
412
|
+
const reasoning = (idea.reasoning ?? "").trim();
|
|
413
|
+
if (shape) {
|
|
414
|
+
const missing = shape.tags.filter((t) => !t.test(reasoning));
|
|
415
|
+
if (missing.length)
|
|
416
|
+
offenders.push(`${idea.id} (${idea.frame}): ${shape.hint}`);
|
|
417
|
+
}
|
|
418
|
+
else if (reasoning.length < MIN_FREE_REASONING) {
|
|
419
|
+
offenders.push(`${idea.id} (${idea.frame}): reasoning must state the move (free text, not empty)`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return offenders;
|
|
423
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Cell, Depth, FamilyDefinition, GateResult, RenderContext, Tier } from "./types.js";
|
|
2
|
+
export declare function slugify(text: string): string;
|
|
3
|
+
export declare function buildCells(family: FamilyDefinition, tier: Tier): Cell[];
|
|
4
|
+
export declare function renderContext(family: FamilyDefinition, target: string, depth: Depth, at: string, root: string): RenderContext;
|
|
5
|
+
export declare function scaffoldRecord(ctx: RenderContext): string;
|
|
6
|
+
export declare function renderContract(ctx: RenderContext): string;
|
|
7
|
+
export declare function checkRecord(family: FamilyDefinition, recordText: string): GateResult;
|