Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub (part 2)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/use-available-models.ts +58 -0
- lib/utils.ts +40 -0
- lib/validation/index.ts +29 -0
- next.config.mjs +68 -0
- package-lock.json +0 -0
- package.json +90 -0
- postcss.config.mjs +8 -0
- product-eval/.claude-plugin/marketplace.json +16 -0
- product-eval/.claude-plugin/plugin.json +19 -0
- product-eval/.codex-plugin/plugin.json +36 -0
- product-eval/.gitignore +12 -0
- product-eval/CONNECTORS.md +21 -0
- product-eval/DATA-CONTRACT.md +149 -0
- product-eval/LICENSE +21 -0
- product-eval/README.md +156 -0
- product-eval/evals/checks/validate_plugin.py +286 -0
- product-eval/evals/trigger/calibrate.json +90 -0
- product-eval/evals/trigger/critique.json +90 -0
- product-eval/evals/trigger/decision-readiness.json +82 -0
- product-eval/evals/trigger/design-test.json +82 -0
- product-eval/evals/trigger/discover-sources.json +86 -0
- product-eval/evals/trigger/drift-check.json +26 -0
- product-eval/evals/trigger/gather-evidence.json +82 -0
- product-eval/evals/trigger/pressure-test.json +23 -0
- product-eval/evals/trigger/prioritize-backlog.json +23 -0
- product-eval/evals/trigger/scorecard.json +82 -0
- product-eval/evals/trigger/start.json +102 -0
- product-eval/evals/trigger/synthesize.json +28 -0
- product-eval/evals/trigger/to-build-brief.json +90 -0
- product-eval/evals/trigger/write-brief.json +26 -0
- product-eval/evals/triggering.json +33 -0
- product-eval/examples/README.md +39 -0
- product-eval/examples/activation-q3/context.md +13 -0
- product-eval/examples/activation-q3/decisions-log.md +34 -0
- product-eval/examples/activation-q3/evidence/E1.md +17 -0
- product-eval/examples/activation-q3/evidence/E10.md +17 -0
- product-eval/examples/activation-q3/evidence/E11.md +17 -0
- product-eval/examples/activation-q3/evidence/E12.md +19 -0
- product-eval/examples/activation-q3/evidence/E2.md +17 -0
- product-eval/examples/activation-q3/evidence/E3.md +17 -0
- product-eval/examples/activation-q3/evidence/E4.md +17 -0
- product-eval/examples/activation-q3/evidence/E5.md +17 -0
- product-eval/examples/activation-q3/evidence/E6.md +17 -0
- product-eval/examples/activation-q3/evidence/E7.md +17 -0
- product-eval/examples/activation-q3/evidence/E8.md +17 -0
- product-eval/examples/activation-q3/evidence/E9.md +17 -0
- product-eval/examples/activation-q3/identities.md +25 -0
- product-eval/examples/activation-q3/scorecard.html +305 -0
- product-eval/examples/activation-q3/scores.md +41 -0
- product-eval/examples/activation-q3/themes.md +57 -0
lib/use-available-models.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use client"
|
| 2 |
+
|
| 3 |
+
import { useCallback, useEffect, useState } from "react"
|
| 4 |
+
import { fetchModelsFromProvider, setDeploymentModel, setDiscoveredBrowserModel, type AISettings } from "@/lib/ai-settings"
|
| 5 |
+
import { sanitizeModels, type AvailableModel } from "@/lib/model-selection"
|
| 6 |
+
|
| 7 |
+
/** Shared registry for settings and the main UI. Discovery never changes selection. */
|
| 8 |
+
export function useAvailableModels(settings: AISettings) {
|
| 9 |
+
const [models, setModels] = useState<AvailableModel[]>([])
|
| 10 |
+
const [defaultModel, setDefaultModel] = useState("")
|
| 11 |
+
const [loading, setLoading] = useState(false)
|
| 12 |
+
const [error, setError] = useState<string | null>(null)
|
| 13 |
+
const [revision, setRevision] = useState(0)
|
| 14 |
+
const refresh = useCallback(() => setRevision(n => n + 1), [])
|
| 15 |
+
|
| 16 |
+
useEffect(() => {
|
| 17 |
+
setModels([])
|
| 18 |
+
setDefaultModel("")
|
| 19 |
+
setDiscoveredBrowserModel("")
|
| 20 |
+
}, [settings.apiKey, settings.provider, settings.customBaseUrl])
|
| 21 |
+
|
| 22 |
+
useEffect(() => {
|
| 23 |
+
let cancelled = false
|
| 24 |
+
setLoading(true)
|
| 25 |
+
setError(null)
|
| 26 |
+
const timer = setTimeout(async () => {
|
| 27 |
+
try {
|
| 28 |
+
if (settings.apiKey.trim()) {
|
| 29 |
+
const items = await fetchModelsFromProvider(settings.provider, settings.apiKey.trim(), settings.customBaseUrl)
|
| 30 |
+
if (!cancelled) {
|
| 31 |
+
const available = sanitizeModels(items)
|
| 32 |
+
setModels(available)
|
| 33 |
+
setDiscoveredBrowserModel(available[0]?.id || "")
|
| 34 |
+
}
|
| 35 |
+
} else {
|
| 36 |
+
const response = await fetch("/api/v1/llm/models", { cache: "no-store" })
|
| 37 |
+
if (!response.ok) throw new Error(response.status === 401 ? "Sign in to retrieve models." : "Could not retrieve the provider model list.")
|
| 38 |
+
const data = await response.json()
|
| 39 |
+
if (!cancelled) {
|
| 40 |
+
setDeploymentModel(data.defaultModel || data.models?.[0]?.id || "")
|
| 41 |
+
setDefaultModel(data.defaultModel || "")
|
| 42 |
+
setModels(sanitizeModels(data.models, data.defaultModel))
|
| 43 |
+
setError(data.discoveryStatus === "available" ? null :
|
| 44 |
+
data.discoveryStatus === "auth_error" ? "Model provider authentication failed. Check OPENAI_API in deployment secrets." :
|
| 45 |
+
!data.configured ? "No model provider configured. Set OPENAI_URL, OPENAI_MODEL and OPENAI_API in the deployment environment." :
|
| 46 |
+
`Could not retrieve the provider model list. Using configured default model: ${data.defaultModel || "none"}`)
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
} catch {
|
| 50 |
+
if (!cancelled) setError("Could not retrieve the provider model list. Your selected model is unchanged.")
|
| 51 |
+
} finally {
|
| 52 |
+
if (!cancelled) setLoading(false)
|
| 53 |
+
}
|
| 54 |
+
}, 300)
|
| 55 |
+
return () => { cancelled = true; clearTimeout(timer) }
|
| 56 |
+
}, [settings.apiKey, settings.provider, settings.customBaseUrl, revision])
|
| 57 |
+
return { models, defaultModel, loading, error, refresh }
|
| 58 |
+
}
|
lib/utils.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { clsx, type ClassValue } from 'clsx'
|
| 2 |
+
import { twMerge } from 'tailwind-merge'
|
| 3 |
+
import { useState, useEffect } from 'react'
|
| 4 |
+
import type { TextBlock } from '@/components/tile-card'
|
| 5 |
+
|
| 6 |
+
export function cn(...inputs: ClassValue[]) {
|
| 7 |
+
return twMerge(clsx(inputs))
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
/**
|
| 11 |
+
* Returns the platform modifier key symbol: '⌘' on macOS/iOS, 'Ctrl' elsewhere.
|
| 12 |
+
* Starts as '⌘' on the server (SSR) and corrects on the client after mount.
|
| 13 |
+
*/
|
| 14 |
+
export function useModKey(): string {
|
| 15 |
+
const [mod, setMod] = useState('⌘')
|
| 16 |
+
useEffect(() => {
|
| 17 |
+
const isMac = /Mac|iPhone|iPad|iPod/.test(navigator.platform)
|
| 18 |
+
if (!isMac) setMod('Ctrl')
|
| 19 |
+
}, [])
|
| 20 |
+
return mod
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
/**
|
| 24 |
+
* Returns the set of block IDs that are "connected" to the hovered block,
|
| 25 |
+
* based on shared category or influencedBy relationships.
|
| 26 |
+
* Used by tiling-area and kanban-area for the connection-hover dimming effect.
|
| 27 |
+
*/
|
| 28 |
+
export function getRelatedIds(hoveredId: string, blocks: TextBlock[]): Set<string> {
|
| 29 |
+
const hovered = blocks.find(b => b.id === hoveredId)
|
| 30 |
+
if (!hovered) return new Set()
|
| 31 |
+
|
| 32 |
+
const related = new Set<string>([hoveredId])
|
| 33 |
+
blocks.forEach(b => {
|
| 34 |
+
if (b.id === hoveredId) return
|
| 35 |
+
const hoveredPointsToB = hovered.influencedBy?.includes(b.id) ?? false
|
| 36 |
+
const bPointsToHovered = b.influencedBy?.includes(hoveredId) ?? false
|
| 37 |
+
if (hoveredPointsToB || bPointsToHovered) related.add(b.id)
|
| 38 |
+
})
|
| 39 |
+
return related
|
| 40 |
+
}
|
lib/validation/index.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { KNOWLEDGE_EDGE_TYPES, KNOWLEDGE_NODE_KINDS, type EvidenceRecord, type HypothesisRecord, type KnowledgeEdge, type KnowledgeNode, type SynthesisResult, type Workspace } from "../domain/types"
|
| 2 |
+
import { canPromote, qualificationForScore, scoreHypothesis } from "../scoring/hypothesis"
|
| 3 |
+
export interface ValidationResult { valid:boolean; errors:string[] }
|
| 4 |
+
const result=(errors:string[]):ValidationResult=>({valid:errors.length===0,errors})
|
| 5 |
+
export function validateNode(n:KnowledgeNode){const e:string[]=[];if(!n?.id)e.push("node id required");if(!KNOWLEDGE_NODE_KINDS.includes(n?.kind))e.push("invalid node kind");if(!n?.workspaceId)e.push("workspace required");if(!n?.title)e.push("title required");if(!n?.provenance?.origin||!n.provenance.createdAt)e.push("provenance required");if(!Number.isInteger(n?.version)||n.version<1)e.push("positive version required");return result(e)}
|
| 6 |
+
export function validateEdge(e:KnowledgeEdge,nodeIds?:Set<string>){const x:string[]=[];if(!e?.id||!e.sourceId||!e.targetId)x.push("edge identity/endpoints required");if(!KNOWLEDGE_EDGE_TYPES.includes(e?.type))x.push("invalid edge type");if(e.sourceId===e.targetId)x.push("self edge prohibited");if(nodeIds&&(!nodeIds.has(e.sourceId)||!nodeIds.has(e.targetId)))x.push("unresolved endpoint");if(!e?.provenance?.origin)x.push("edge provenance required");return result(x)}
|
| 7 |
+
export function validateEvidence(e:EvidenceRecord){const x:string[]=[];if(!e.id||!e.workspaceId||!e.claim.trim())x.push("evidence identity/claim required");if(!Number.isInteger(e.strength)||e.strength<1||e.strength>5)x.push("strength must be 1..5");if(!Number.isFinite(e.weight)||e.weight<0)x.push("non-negative weight required");if(!e.sourceType)x.push("source type required");if(!e.ingestedAt||!e.provenance?.origin)x.push("evidence provenance required");return result(x)}
|
| 8 |
+
export function validateTheme(n:KnowledgeNode){const x=validateNode(n).errors;if(n.kind!=="theme")x.push("theme kind required");if(typeof n.metadata.clusterKey!=="string")x.push("clusterKey required");return result(x)}
|
| 9 |
+
export function validateSynthesis(s:SynthesisResult){const x:string[]=[];if(!/^S\d{3}$/.test(s.synthesisType))x.push("invalid synthesis type");if(!s.inputHash||!s.runId||!s.provenance?.origin)x.push("hash/run/provenance required");if(!Array.isArray(s.derivedFrom)||!Array.isArray(s.unknowns)||!Array.isArray(s.generatedHypotheses))x.push("synthesis arrays required");if(s.generationConfidence<0||s.generationConfidence>100)x.push("generation confidence out of range");return result(x)}
|
| 10 |
+
export function validateHypothesis(h:HypothesisRecord){const x:string[]=[];if(!h.id||!h.statement.trim()||!h.hypothesisType)x.push("hypothesis identity/statement/type required");if(h.evidenceScore< -100||h.evidenceScore>100)x.push("score out of range");if(h.confidence<0||h.confidence>100)x.push("confidence out of range");if(h.qualification!==qualificationForScore(h.evidenceScore))x.push("qualification mismatch");return result(x)}
|
| 11 |
+
export function validateExperiment(n:KnowledgeNode){const x=validateNode(n).errors;if(n.kind!=="experiment")x.push("experiment kind required");if(!n.metadata.threshold&&!n.metadata.passThreshold)x.push("experiment threshold required");return result(x)}
|
| 12 |
+
export function validateDecision(n:KnowledgeNode){const x=validateNode(n).errors;if(n.kind!=="decision")x.push("decision kind required");if(!n.metadata.rationale)x.push("decision rationale required");return result(x)}
|
| 13 |
+
export function validateBrainPromotion(w:Workspace){const x:string[]=[];for(const h of w.hypotheses.filter(h=>w.brain.promotedIds.includes(h.id)))if(!canPromote(h))x.push(`${h.id}: promotion gates not met`);return result(x)}
|
| 14 |
+
export function validateAdjudications(w: Workspace): ValidationResult {
|
| 15 |
+
const errors: string[] = [], ids = new Set<string>()
|
| 16 |
+
const evidenceIds = new Set(w.evidence.flatMap(e => [e.id,...(e.aliases || [])]))
|
| 17 |
+
for (const a of w.adjudications || []) {
|
| 18 |
+
if (!a || !a.id || ids.has(a.id)) { errors.push("invalid/duplicate adjudication identity"); continue }
|
| 19 |
+
ids.add(a.id)
|
| 20 |
+
if (!w.hypotheses.some(h=>h.id===a.hypothesisId) || !evidenceIds.has(a.evidenceId)) errors.push(`adjudication ${a.id}: unresolved target`)
|
| 21 |
+
if (!["supports","contradicts","neutral","uncertain"].includes(a.relation) || !["direct","indirect","contextual"].includes(a.directness)) errors.push(`adjudication ${a.id}: invalid interpretation`)
|
| 22 |
+
if (![a.relevance,a.confidence].every(n=>Number.isFinite(n)&&n>=0&&n<=100)) errors.push(`adjudication ${a.id}: invalid interpretation certainty`)
|
| 23 |
+
if (!a.inputHash || !a.runId || !a.provider || !a.promptVersion || !a.schemaVersion || !Number.isFinite(Date.parse(a.createdAt)) || !Array.isArray(a.sourceEvidenceIds) || !Array.isArray(a.semanticContextIds)) errors.push(`adjudication ${a.id}: provenance required`)
|
| 24 |
+
}
|
| 25 |
+
return result(errors)
|
| 26 |
+
}
|
| 27 |
+
export function validateWorkspace(w:Workspace):ValidationResult{const errors:string[]=[];if(w.schemaVersion!==1)errors.push("unsupported schema");const ids=new Set(w.nodes.map(n=>n.id));for(const n of w.nodes)errors.push(...validateNode(n).errors.map(e=>`node ${n.id}: ${e}`));for(const e of w.edges)errors.push(...validateEdge(e,ids).errors.map(x=>`edge ${e.id}: ${x}`));const evid=new Set(w.evidence.map(e=>e.id));for(const e of w.evidence)errors.push(...validateEvidence(e).errors.map(x=>`evidence ${e.id}: ${x}`));for(const h of w.hypotheses){errors.push(...validateHypothesis(h).errors.map(x=>`hypothesis ${h.id}: ${x}`));for(const id of[...h.supportingEvidence,...h.contradictingEvidence])if(!evid.has(id))errors.push(`hypothesis ${h.id}: missing evidence ${id}`);const recomputed=scoreHypothesis(h,w.evidence,Date.parse(h.lastEvaluatedAt??w.updatedAt));if(recomputed.evidenceScore!==h.evidenceScore)errors.push(`hypothesis ${h.id}: score mismatch`)}for(const s of w.syntheses)errors.push(...validateSynthesis(s).errors.map(x=>`synthesis ${s.id}: ${x}`));errors.push(...validateBrainPromotion(w).errors,...validateAdjudications(w).errors);return result(errors)}
|
| 28 |
+
export const validateGitSnapshot=(w:Workspace)=>validateWorkspace(w)
|
| 29 |
+
export function validateWorkflowContracts(w:Workspace){const x:string[]=[];for(const t of w.researchTasks){if(!t.question||!t.objective||!Array.isArray(t.hypothesisIds))x.push(`task ${t.id}: invalid contract`);if(t.attempts>t.maxAttempts)x.push(`task ${t.id}: attempts exceeded`)}return result(x)}
|
next.config.mjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/** @type {import('next').NextConfig} */
|
| 2 |
+
const nextConfig = {
|
| 3 |
+
output: "standalone",
|
| 4 |
+
typescript: {
|
| 5 |
+
// Build errors are intentionally ignored — see CLAUDE.md
|
| 6 |
+
ignoreBuildErrors: true,
|
| 7 |
+
},
|
| 8 |
+
images: {
|
| 9 |
+
unoptimized: true,
|
| 10 |
+
},
|
| 11 |
+
async headers() {
|
| 12 |
+
return [
|
| 13 |
+
{
|
| 14 |
+
// Apply security headers to every route
|
| 15 |
+
source: "/(.*)",
|
| 16 |
+
headers: [
|
| 17 |
+
{
|
| 18 |
+
// Prevent framing (clickjacking)
|
| 19 |
+
key: "X-Frame-Options",
|
| 20 |
+
value: "DENY",
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
// Stop MIME-type sniffing
|
| 24 |
+
key: "X-Content-Type-Options",
|
| 25 |
+
value: "nosniff",
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
// Limit referrer info sent to third-party origins
|
| 29 |
+
key: "Referrer-Policy",
|
| 30 |
+
value: "strict-origin-when-cross-origin",
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
// Permissions policy — disable features the app doesn't use
|
| 34 |
+
key: "Permissions-Policy",
|
| 35 |
+
value: "camera=(), microphone=(), geolocation=()",
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
// Content Security Policy
|
| 39 |
+
// - default-src self: everything defaults to same-origin
|
| 40 |
+
// - script-src: Next.js needs 'unsafe-inline' + 'unsafe-eval' in dev;
|
| 41 |
+
// nonces are the proper fix but require custom server — this is the
|
| 42 |
+
// pragmatic baseline for a static/Vercel deployment.
|
| 43 |
+
// - connect-src: https: allows any user-configured custom endpoint
|
| 44 |
+
// - img-src: data URIs for inline images, blob for canvas exports
|
| 45 |
+
// - style-src unsafe-inline: Tailwind injects inline styles at runtime
|
| 46 |
+
key: "Content-Security-Policy",
|
| 47 |
+
value: [
|
| 48 |
+
"default-src 'self'",
|
| 49 |
+
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cloud.umami.is",
|
| 50 |
+
"style-src 'self' 'unsafe-inline'",
|
| 51 |
+
// Allow all HTTPS so user-configured custom base URLs (arbitrary
|
| 52 |
+
// OpenAI-compatible endpoints) are not blocked by CSP. Enumerating
|
| 53 |
+
// specific provider domains is incompatible with a custom-URL feature.
|
| 54 |
+
// http://localhost:* covers local providers (Ollama, LM Studio, vLLM).
|
| 55 |
+
"connect-src 'self' https: http://localhost:*",
|
| 56 |
+
"img-src 'self' data: blob: https://i.ytimg.com",
|
| 57 |
+
"font-src 'self' data:",
|
| 58 |
+
"frame-src https://www.youtube-nocookie.com https://www.youtube.com",
|
| 59 |
+
"frame-ancestors 'none'",
|
| 60 |
+
].join("; "),
|
| 61 |
+
},
|
| 62 |
+
],
|
| 63 |
+
},
|
| 64 |
+
]
|
| 65 |
+
},
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
export default nextConfig
|
package-lock.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "nodepad",
|
| 3 |
+
"version": "0.1.0",
|
| 4 |
+
"private": true,
|
| 5 |
+
"scripts": {
|
| 6 |
+
"dev": "next dev",
|
| 7 |
+
"build": "next build",
|
| 8 |
+
"start": "next start",
|
| 9 |
+
"lint": "eslint .",
|
| 10 |
+
"test": "tsx --test tests/**/*.test.ts",
|
| 11 |
+
"test:registry": "tsx --test tests/synthesis-registry.test.ts",
|
| 12 |
+
"validate:fixture": "tsx scripts/validate-fixture.ts",
|
| 13 |
+
"heartbeat": "tsx worker/heartbeat.ts",
|
| 14 |
+
"dev:all": "sh -c 'next dev & tsx worker/heartbeat.ts; wait'",
|
| 15 |
+
"test:predeploy:unit": "tsx --import ./scripts/predeploy-env.ts --test tests/**/*.test.ts",
|
| 16 |
+
"test:predeploy:smoke": "tsx scripts/predeploy-smoke.ts",
|
| 17 |
+
"test:predeploy:docker": "tsx scripts/predeploy-docker.ts",
|
| 18 |
+
"test:predeploy": "tsx scripts/predeploy.ts"
|
| 19 |
+
},
|
| 20 |
+
"dependencies": {
|
| 21 |
+
"@hookform/resolvers": "^3.9.1",
|
| 22 |
+
"@radix-ui/react-accordion": "1.2.12",
|
| 23 |
+
"@radix-ui/react-alert-dialog": "1.1.15",
|
| 24 |
+
"@radix-ui/react-aspect-ratio": "1.1.8",
|
| 25 |
+
"@radix-ui/react-avatar": "1.1.11",
|
| 26 |
+
"@radix-ui/react-checkbox": "1.3.3",
|
| 27 |
+
"@radix-ui/react-collapsible": "1.1.12",
|
| 28 |
+
"@radix-ui/react-context-menu": "2.2.16",
|
| 29 |
+
"@radix-ui/react-dialog": "1.1.15",
|
| 30 |
+
"@radix-ui/react-dropdown-menu": "2.1.16",
|
| 31 |
+
"@radix-ui/react-hover-card": "1.1.15",
|
| 32 |
+
"@radix-ui/react-label": "2.1.8",
|
| 33 |
+
"@radix-ui/react-menubar": "1.1.16",
|
| 34 |
+
"@radix-ui/react-navigation-menu": "1.2.14",
|
| 35 |
+
"@radix-ui/react-popover": "1.1.15",
|
| 36 |
+
"@radix-ui/react-progress": "1.1.8",
|
| 37 |
+
"@radix-ui/react-radio-group": "1.3.8",
|
| 38 |
+
"@radix-ui/react-scroll-area": "1.2.10",
|
| 39 |
+
"@radix-ui/react-select": "2.2.6",
|
| 40 |
+
"@radix-ui/react-separator": "1.1.8",
|
| 41 |
+
"@radix-ui/react-slider": "1.3.6",
|
| 42 |
+
"@radix-ui/react-slot": "1.2.4",
|
| 43 |
+
"@radix-ui/react-switch": "1.2.6",
|
| 44 |
+
"@radix-ui/react-tabs": "1.1.13",
|
| 45 |
+
"@radix-ui/react-toast": "1.2.15",
|
| 46 |
+
"@radix-ui/react-toggle": "1.1.10",
|
| 47 |
+
"@radix-ui/react-toggle-group": "1.1.11",
|
| 48 |
+
"@radix-ui/react-tooltip": "1.2.8",
|
| 49 |
+
"@tailwindcss/typography": "^0.5.19",
|
| 50 |
+
"@types/d3": "^7.4.3",
|
| 51 |
+
"autoprefixer": "^10.4.20",
|
| 52 |
+
"class-variance-authority": "^0.7.1",
|
| 53 |
+
"clsx": "^2.1.1",
|
| 54 |
+
"cmdk": "1.1.1",
|
| 55 |
+
"d3": "^7.9.0",
|
| 56 |
+
"date-fns": "4.1.0",
|
| 57 |
+
"embla-carousel-react": "8.6.0",
|
| 58 |
+
"framer-motion": "^11.18.0",
|
| 59 |
+
"input-otp": "1.4.2",
|
| 60 |
+
"lucide-react": "^0.564.0",
|
| 61 |
+
"next": "^16.2.2",
|
| 62 |
+
"next-themes": "^0.4.6",
|
| 63 |
+
"react": "19.2.4",
|
| 64 |
+
"react-day-picker": "9.13.2",
|
| 65 |
+
"react-dom": "19.2.4",
|
| 66 |
+
"react-hook-form": "^7.54.1",
|
| 67 |
+
"react-markdown": "^10.1.0",
|
| 68 |
+
"react-resizable-panels": "^2.1.7",
|
| 69 |
+
"recharts": "2.15.0",
|
| 70 |
+
"remark-gfm": "^4.0.1",
|
| 71 |
+
"sonner": "^1.7.1",
|
| 72 |
+
"tailwind-merge": "^3.3.1",
|
| 73 |
+
"vaul": "^1.1.2",
|
| 74 |
+
"zod": "^3.24.1"
|
| 75 |
+
},
|
| 76 |
+
"devDependencies": {
|
| 77 |
+
"@tailwindcss/postcss": "^4.2.0",
|
| 78 |
+
"@types/node": "^22",
|
| 79 |
+
"@types/react": "19.2.14",
|
| 80 |
+
"@types/react-dom": "19.2.3",
|
| 81 |
+
"eslint": "^9.39.5",
|
| 82 |
+
"eslint-config-next": "^16.3.8",
|
| 83 |
+
"postcss": "^8.5",
|
| 84 |
+
"shadcn": "^4.0.0",
|
| 85 |
+
"tailwindcss": "^4.2.0",
|
| 86 |
+
"tsx": "^4.23.15",
|
| 87 |
+
"tw-animate-css": "1.3.3",
|
| 88 |
+
"typescript": "5.7.3"
|
| 89 |
+
}
|
| 90 |
+
}
|
postcss.config.mjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/** @type {import('postcss-load-config').Config} */
|
| 2 |
+
const config = {
|
| 3 |
+
plugins: {
|
| 4 |
+
'@tailwindcss/postcss': {},
|
| 5 |
+
},
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
export default config
|
product-eval/.claude-plugin/marketplace.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "product-eval-marketplace",
|
| 3 |
+
"owner": {
|
| 4 |
+
"name": "Narek Gevorgyan"
|
| 5 |
+
},
|
| 6 |
+
"plugins": [
|
| 7 |
+
{
|
| 8 |
+
"name": "product-eval",
|
| 9 |
+
"source": "./",
|
| 10 |
+
"version": "0.14.2",
|
| 11 |
+
"description": "Evidence-gated product decisions: scope product context and evidence, then rank opportunities, decide on one bet, pressure-test plans, and write briefs/specs/scorecards.",
|
| 12 |
+
"homepage": "https://github.com/sparkline-ventures/product-eval",
|
| 13 |
+
"repository": "https://github.com/sparkline-ventures/product-eval"
|
| 14 |
+
}
|
| 15 |
+
]
|
| 16 |
+
}
|
product-eval/.claude-plugin/plugin.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "product-eval",
|
| 3 |
+
"version": "0.14.2",
|
| 4 |
+
"description": "Evidence-gated product decisions that start by scoping product context, evidence sources, and the desired deliverable before ranking opportunities, deciding on bets, pressure-testing plans, or writing outputs. Keeps evidence gathering, problem framing, Value/Confidence scoring, readiness gates, and audit files behind a simpler user experience.",
|
| 5 |
+
"author": {
|
| 6 |
+
"name": "Narek Gevorgyan"
|
| 7 |
+
},
|
| 8 |
+
"license": "MIT",
|
| 9 |
+
"homepage": "https://github.com/sparkline-ventures/product-eval",
|
| 10 |
+
"repository": "https://github.com/sparkline-ventures/product-eval",
|
| 11 |
+
"keywords": [
|
| 12 |
+
"product-management",
|
| 13 |
+
"prioritization",
|
| 14 |
+
"evidence",
|
| 15 |
+
"roadmap",
|
| 16 |
+
"decision-readiness",
|
| 17 |
+
"pressure-test"
|
| 18 |
+
]
|
| 19 |
+
}
|
product-eval/.codex-plugin/plugin.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "product-eval",
|
| 3 |
+
"version": "0.14.2",
|
| 4 |
+
"description": "Evidence-gated product decisions that start by scoping product context, evidence sources, and the desired deliverable before ranking opportunities, deciding on bets, pressure-testing plans, or writing outputs.",
|
| 5 |
+
"author": {
|
| 6 |
+
"name": "Narek Gevorgyan"
|
| 7 |
+
},
|
| 8 |
+
"license": "MIT",
|
| 9 |
+
"homepage": "https://github.com/sparkline-ventures/product-eval",
|
| 10 |
+
"repository": "https://github.com/sparkline-ventures/product-eval",
|
| 11 |
+
"keywords": [
|
| 12 |
+
"product-management",
|
| 13 |
+
"prioritization",
|
| 14 |
+
"evidence",
|
| 15 |
+
"roadmap",
|
| 16 |
+
"decision-readiness",
|
| 17 |
+
"pressure-test"
|
| 18 |
+
],
|
| 19 |
+
"skills": "./skills/",
|
| 20 |
+
"interface": {
|
| 21 |
+
"displayName": "product-eval",
|
| 22 |
+
"shortDescription": "Scoped, evidence-gated product decisions",
|
| 23 |
+
"longDescription": "Set up product context and evidence sources, then rank opportunities, decide whether one bet is ready, pressure-test plans, and write briefs, build briefs, or scorecards from scoped product evidence.",
|
| 24 |
+
"developerName": "Narek Gevorgyan",
|
| 25 |
+
"category": "Productivity",
|
| 26 |
+
"capabilities": [
|
| 27 |
+
"Interactive",
|
| 28 |
+
"Write"
|
| 29 |
+
],
|
| 30 |
+
"defaultPrompt": [
|
| 31 |
+
"Set up product-eval for my product.",
|
| 32 |
+
"Help me decide what to build next.",
|
| 33 |
+
"Help me prepare a decision report."
|
| 34 |
+
]
|
| 35 |
+
}
|
| 36 |
+
}
|
product-eval/.gitignore
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# OS / editor cruft
|
| 2 |
+
.DS_Store
|
| 3 |
+
|
| 4 |
+
# Python
|
| 5 |
+
__pycache__/
|
| 6 |
+
*.pyc
|
| 7 |
+
.venv/
|
| 8 |
+
|
| 9 |
+
# Note: product-eval.plugin (the built package) is intentionally committed.
|
| 10 |
+
# evals/checks/validate_plugin.py verifies it byte-matches the source tree,
|
| 11 |
+
# so rebuild it after any change: rm -f product-eval.plugin && \
|
| 12 |
+
# zip -r -X -q /tmp/pe.plugin . -x '*.plugin' && mv /tmp/pe.plugin product-eval.plugin
|
product-eval/CONNECTORS.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Connectors
|
| 2 |
+
|
| 3 |
+
This plugin is tool-agnostic in spirit: it works in terms of **evidence source categories**, and uses whatever you connect in each. Nothing is required, `discover-sources` detects what's available, CSV/upload is a universal fallback, and the plugin honestly caps decision confidence by the sources you actually have.
|
| 4 |
+
|
| 5 |
+
The full category → example-tool mapping lives in `skills/discover-sources/references/source-catalog.md`. Summary:
|
| 6 |
+
|
| 7 |
+
| Category | Example tools | Evidence role |
|
| 8 |
+
|---|---|---|
|
| 9 |
+
| Product / behavioral analytics | Amplitude, PostHog, Mixpanel, GA4 | first-party quantitative (strongest) |
|
| 10 |
+
| Reliability / logs / errors | Datadog, Sentry, New Relic | first-party quantitative |
|
| 11 |
+
| Support / tickets | Zendesk, Intercom, Freshdesk | ticket clusters |
|
| 12 |
+
| Voice of customer / calls | Fireflies, Gong, churn & NPS surveys | transcripts / surveys |
|
| 13 |
+
| CRM / sales | Salesforce, HubSpot | PFRs, lost-deal reasons |
|
| 14 |
+
| Feedback / idea mgmt | Productboard, Canny, Aha! | feature requests |
|
| 15 |
+
| Reviews / app stores | G2, Capterra, App/Play Store | third-party qualitative |
|
| 16 |
+
| Community | Reddit, Hacker News, Discord | third-party qualitative |
|
| 17 |
+
| Market / SEO / demand | Semrush, Ahrefs, SimilarWeb | market signal |
|
| 18 |
+
| Issue trackers / changelogs | GitHub, GitLab | bug/feature signal + freshness checks |
|
| 19 |
+
| Identity (CDP) | Segment, RudderStack | resolves the same user/account across the above |
|
| 20 |
+
|
| 21 |
+
Connect any subset. The more first-party quantitative sources you connect (analytics, logs) and the more source-type diversity you have, the higher the confidence ceiling the plugin can reach.
|
product-eval/DATA-CONTRACT.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Data Contract
|
| 2 |
+
|
| 3 |
+
The file shapes every skill reads and writes inside an investigation scope at `.product-eval/<scope>/`. Keeping these stable is what lets skills hand off reliably. Files are markdown with YAML front-matter (or YAML lists), human-readable and machine-parseable.
|
| 4 |
+
|
| 5 |
+
All paths below are relative to `.product-eval/<scope>/`, except `.product-eval/calibration.yml`, which is workspace-level. Exact computed fields (`weight`, `confidence`, `value`) are stored for audit, calibration, and scorecards. User-facing output should lead with bands and verdicts, not bare point estimates.
|
| 6 |
+
|
| 7 |
+
## context.md (front-matter)
|
| 8 |
+
```yaml
|
| 9 |
+
---
|
| 10 |
+
scope: tula-q3-eval
|
| 11 |
+
job: evaluate # explore | evaluate | validate | pressure-test | draft
|
| 12 |
+
stage: evaluate # sets the crispness bar: explore = lenient, evaluate/validate = strict
|
| 13 |
+
product: "one-line description"
|
| 14 |
+
north_star: "metric"
|
| 15 |
+
personas: [admin, end_user, buyer]
|
| 16 |
+
updated: 2026-06-26
|
| 17 |
+
---
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
## evidence/<id>.md (one file per item)
|
| 21 |
+
```yaml
|
| 22 |
+
---
|
| 23 |
+
id: E1
|
| 24 |
+
claim: "state the pain, not the solution"
|
| 25 |
+
source_type: product_analytics # taxonomy below
|
| 26 |
+
source_ref: "Amplitude › Activation funnel"
|
| 27 |
+
persona: [client]
|
| 28 |
+
funnel_stage: activation
|
| 29 |
+
impact_type: activation
|
| 30 |
+
strength: 5 # 1-5 (evidence-quality rubric)
|
| 31 |
+
recency_days: 20
|
| 32 |
+
weight: 12 # computed: base-by-strength × recency factor (evidence-quality rubric)
|
| 33 |
+
person_id: null
|
| 34 |
+
account_id: acct_acme # if identity-resolved
|
| 35 |
+
corroborated_by: [E2]
|
| 36 |
+
stale: false # true if a changelog/release supersedes it
|
| 37 |
+
---
|
| 38 |
+
optional quote / notes
|
| 39 |
+
```
|
| 40 |
+
`source_type` taxonomy: product_analytics, support_ticket, sales_call, churn_survey, customer_interview, internal_data, internal_observation, feature_request, app_review, community_post, social_media, competitor_analysis, market_research, blog_or_article.
|
| 41 |
+
|
| 42 |
+
## identities.md (list)
|
| 43 |
+
```yaml
|
| 44 |
+
- entity: acct_acme
|
| 45 |
+
grain: account # person | account
|
| 46 |
+
matched_records: [intercom:org_812, hubspot:acct_55, amplitude:grp_acme]
|
| 47 |
+
method: email_domain # email | user_id | email_domain | fuzzy
|
| 48 |
+
match_confidence: high # high | medium | low
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
## themes.md (list)
|
| 52 |
+
```yaml
|
| 53 |
+
- id: T1
|
| 54 |
+
name: "problem-framed, 5-10 words"
|
| 55 |
+
members: [E1, E2]
|
| 56 |
+
personas: [client]
|
| 57 |
+
distinct_accounts: 9
|
| 58 |
+
total_weight: 19
|
| 59 |
+
source_types: [product_analytics, support_ticket]
|
| 60 |
+
trend: up # emerging | up | flat | down | regression
|
| 61 |
+
corroboration: cross-source
|
| 62 |
+
contradictions: []
|
| 63 |
+
confidence: 67 # computed (scoring-framework Confidence formula)
|
| 64 |
+
confidence_band: moderate # low | moderate | high; preferred for chat output
|
| 65 |
+
gaps: ["spam vs ignored?", "funnel confound: agency-abandoned projects"]
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
## scores.md (list)
|
| 69 |
+
```yaml
|
| 70 |
+
- problem: T1
|
| 71 |
+
value: 72 # 0-100 (scoring-framework: persona + funnel + frequency + competitive)
|
| 72 |
+
value_inputs: {persona: 15, funnel: 22, frequency: 25, competitive: 10}
|
| 73 |
+
value_band: high # low | moderate | high; preferred for chat output
|
| 74 |
+
confidence: 67 # 0-100 (scoring-framework Confidence formula)
|
| 75 |
+
confidence_band: moderate # low | moderate | high; preferred for chat output
|
| 76 |
+
recommendation: "Run a research sprint" # ranking tier from the score-to-recommendation matrix
|
| 77 |
+
rationale: "short reasoning"
|
| 78 |
+
override: null # {field, to, reason} if a human overrides
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
## decisions-log.md (append-only entries)
|
| 82 |
+
```yaml
|
| 83 |
+
- date: 2026-06-26
|
| 84 |
+
item: T1
|
| 85 |
+
event: readiness # readiness | override | critique | drift | doc
|
| 86 |
+
verdict: "Run a research sprint"
|
| 87 |
+
confidence: 67
|
| 88 |
+
confidence_band: moderate
|
| 89 |
+
evidence: [E1, E2]
|
| 90 |
+
open: ["spam vs ignored", "funnel confound"]
|
| 91 |
+
contested: []
|
| 92 |
+
note: "short note"
|
| 93 |
+
outcome: # optional; appended later once the bet has closed, read by calibrate
|
| 94 |
+
problem_was_real: confirmed # confirmed | refuted | partial (the calibration target)
|
| 95 |
+
solution_outcome: succeeded # succeeded | failed | mixed (context only, does not tune constants)
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
`outcome` is added to a `readiness` entry only when the result is known (often a quarter later). `calibrate` reads it to score the constants: it tunes against `problem_was_real`, never `solution_outcome`. See the calibrate reference.
|
| 99 |
+
|
| 100 |
+
## calibration.yml (workspace-level, optional)
|
| 101 |
+
|
| 102 |
+
Lives at `.product-eval/calibration.yml`, workspace/product level, **not** per-scope. Overrides the shipped scoring defaults for this team/product; written by `calibrate`, read by the scoring skills on top of the defaults (anything omitted → shipped default). Schema in the calibrate reference. Absent → the universal defaults apply.
|
| 103 |
+
|
| 104 |
+
## Computed fields, single sources of truth
|
| 105 |
+
- `strength` (1-5) and `weight`, `skills/decision-readiness/references/evidence-quality.md`.
|
| 106 |
+
- `confidence` (0-100), `skills/prioritize-backlog/references/scoring-framework.md` (the Confidence formula); stored exactly, displayed as `confidence_band` (Low/Moderate/High) with an optional bounded ±10 logged adjustment, and overridable via `.product-eval/calibration.yml`.
|
| 107 |
+
- `value` (0-100) and the recommendation matrix, same scoring-framework reference; store exact `value`, display `value_band` in chat.
|
| 108 |
+
|
| 109 |
+
Keep these schemas **additive**: skills may add fields, but must not rename or remove the ones above.
|
| 110 |
+
|
| 111 |
+
## Validation (preflight conformance check)
|
| 112 |
+
|
| 113 |
+
Skills trust each other's files. A malformed `evidence/`, `themes.md`, or `scores.md` must fail **loudly**, not degrade a downstream skill silently. So every consuming skill runs this preflight on the files it is about to read, and if any check fails it **stops and reports the exact file, field, and violation** rather than guessing past it or proceeding on a partial read. The checks are mechanical (no judgement), so a team can also run them as a script; this section is the single source of truth for what "conformant" means.
|
| 114 |
+
|
| 115 |
+
**Band rule (used everywhere):** `band(x)` = Low if `x < 40`, Moderate if `40 <= x <= 69`, High if `x >= 70`. A stored `*_band` that disagrees with its stored number is a violation.
|
| 116 |
+
|
| 117 |
+
**`evidence/<id>.md`**
|
| 118 |
+
- Required keys present: `id`, `claim`, `source_type`, `strength`, `weight`, `stale`.
|
| 119 |
+
- `id` is unique across the folder and matches the filename (`E1` in `E1.md`).
|
| 120 |
+
- `source_type` is in the taxonomy above; `strength` is an integer 1 to 5; `weight` is a number `>= 0`; `recency_days` (if present) is a non-negative integer; `stale` is a boolean.
|
| 121 |
+
- Every id in `corroborated_by` / `contradicts` resolves to a real evidence file.
|
| 122 |
+
- `person_id` / `account_id`, when not null, resolve to an entity in `identities.md`.
|
| 123 |
+
|
| 124 |
+
**`themes.md`**
|
| 125 |
+
- Each theme has a unique `id`, a `name`, and a non-empty `members` list; every member resolves to a real evidence id.
|
| 126 |
+
- `total_weight` equals the sum of member weights within rounding tolerance (`+/- 1`).
|
| 127 |
+
- `source_types` is a subset of the taxonomy and is consistent with the members' source types.
|
| 128 |
+
- `confidence` is present (0 to 100) and `confidence_band` satisfies the band rule.
|
| 129 |
+
- Every id in `contradictions` resolves to a real evidence id.
|
| 130 |
+
|
| 131 |
+
**`scores.md`**
|
| 132 |
+
- Each entry's `problem` resolves to a theme id in `themes.md`.
|
| 133 |
+
- `value` is 0 to 100 and `value_inputs` (`persona + funnel + frequency + competitive`) sums to `value`.
|
| 134 |
+
- `value_band` and `confidence_band` satisfy the band rule.
|
| 135 |
+
- `confidence` equals the same item's `confidence` in `themes.md` (one source of truth; readiness reads, it does not recompute a different number).
|
| 136 |
+
- `recommendation` is one of the four verdicts (Decide now / Run a research sprint / Do not commit yet / Deprioritize) and matches what the score-to-recommendation matrix produces from (`value`, `confidence`), unless `override` is set and carries a reason.
|
| 137 |
+
- `override` is null or has `{field, to, reason}`.
|
| 138 |
+
|
| 139 |
+
**`decisions-log.md`**
|
| 140 |
+
- Append-only: existing entries are never edited or deleted, only added to.
|
| 141 |
+
- Each entry has `date`, `item`, `event`, `verdict`; `verdict` is in the four-verdict vocabulary; `event` is one of readiness / override / critique / drift / doc.
|
| 142 |
+
- Every id in `evidence` / `contested` resolves to a real evidence id; `confidence_band` satisfies the band rule.
|
| 143 |
+
- If `outcome` is present: `problem_was_real` is one of confirmed / refuted / partial, and `solution_outcome` (if present) is one of succeeded / failed / mixed.
|
| 144 |
+
|
| 145 |
+
**Cross-file**
|
| 146 |
+
- Every theme referenced by `scores.md` and `decisions-log.md` exists in `themes.md`.
|
| 147 |
+
- `context.md` front-matter is present and has at least `scope`, `job`, `stage`.
|
| 148 |
+
|
| 149 |
+
A passing preflight means the files are structurally sound and internally consistent; it does **not** vouch for whether the evidence is true. These checks are also implemented as an optional script, `scripts/validate_scope.py` (run `python scripts/validate_scope.py .product-eval/<scope>/`; needs PyYAML, exits non-zero on any violation), for CI or a pre-commit hook. `examples/activation-q3/` is a conformant fixture to test the checks against.
|
product-eval/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2026 Narek Gevorgyan
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
product-eval/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# product-eval
|
| 2 |
+
|
| 3 |
+
**Find what's worth building next, with the evidence to prove it.**
|
| 4 |
+
|
| 5 |
+

|
| 6 |
+
|
| 7 |
+
product-eval discovers and analyzes real customer problems from the tools where they already live: support tickets (Zendesk), CRM (Salesforce, HubSpot), issue trackers (Jira), product analytics, and reviews. It weighs the evidence, ranks what matters, and builds a prioritized, evidence-backed narrative of the problem worth solving.
|
| 8 |
+
|
| 9 |
+
When a bet is ready, hand it off: export a brief or decision memo, or pass a build spec straight to a wireframing tool or an AI coding agent like Codex or Claude Code to ship an MVP. It runs in both Claude Code and Codex, and keeps the rigor (evidence weighting, readiness gates, audit files) behind a simple, outcome-first chat.
|
| 10 |
+
|
| 11 |
+
It helps you answer four practical questions:
|
| 12 |
+
|
| 13 |
+
- **Rank opportunities:** what should we build next?
|
| 14 |
+
- **Decide on one bet:** is this worth building now, or do we need more proof?
|
| 15 |
+
- **Pressure-test a plan:** where is this roadmap, PRD, or strategy weak before we commit?
|
| 16 |
+
- **Write the output:** turn an approved decision into a brief, decision memo, build spec, or visual scorecard.
|
| 17 |
+
|
| 18 |
+
The plugin keeps the rigor behind the scenes: it can discover available sources, gather and weight evidence, synthesize themes into buildable problems, score Value and Confidence, check decision readiness, and produce decision artifacts. Users should not need to choose those internal steps directly; they can describe the outcome they want.
|
| 19 |
+
|
| 20 |
+
## Install
|
| 21 |
+
|
| 22 |
+

|
| 23 |
+
|
| 24 |
+
**Cowork:** open the `.plugin` file. It renders as an installable card; click to add it.
|
| 25 |
+
|
| 26 |
+
**Claude Code:** add this directory or its hosting repo as a plugin marketplace, then install:
|
| 27 |
+
|
| 28 |
+
```text
|
| 29 |
+
/plugin marketplace add <path-or-repo>
|
| 30 |
+
/plugin install product-eval
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
**Codex:** this source is Codex-compatible through `.codex-plugin/plugin.json`. For Codex marketplace installation, place or symlink this folder as `<marketplace-root>/plugins/product-eval`, make sure that marketplace root is registered with Codex, then install `product-eval` from that marketplace. This repo cleanup does not create or edit global Codex marketplace config such as `~/.agents/plugins/marketplace.json`.
|
| 34 |
+
|
| 35 |
+
**Quick install (either tool, no marketplace):** clone this repo and run `./install.sh`. It symlinks the 14 skills into `~/.claude/skills` and `~/.agents/skills`, so a later `git pull` keeps them current. In Codex, invoke a skill explicitly with `$<skill-name>` (for example `$start`).
|
| 36 |
+
|
| 37 |
+
After installing, start by setting up the product context and decision:
|
| 38 |
+
|
| 39 |
+
- "Set up product-eval for my product."
|
| 40 |
+
- "Help me decide what to build next."
|
| 41 |
+
- "Help me prepare a decision report."
|
| 42 |
+
- "Pressure-test this Q3 roadmap using the evidence in our current scope."
|
| 43 |
+
|
| 44 |
+
On first run, product-eval should ask for the product, target users, decision goal, scope/time horizon, available evidence sources, and the metric or business constraint that should shape the recommendation. It should not rank a vague area like "onboarding" or judge a bet like "SSO" until the product context and evidence plan are clear, unless you explicitly ask for an outside-in first pass with a lower confidence ceiling.
|
| 45 |
+
|
| 46 |
+
Each step should end with a **Next move** that points toward delivery: upload the evidence, rank the candidates, run the readiness call, pressure-test the plan, write the decision memo, render the scorecard, or hand a build brief to Codex/design.
|
| 47 |
+
|
| 48 |
+
## 60-second demo
|
| 49 |
+
|
| 50 |
+
Point it at your customer signal and ask for the outcome. For example, hand it a support-ticket export in Codex:
|
| 51 |
+
|
| 52 |
+
> "These are our support tickets. Can you analyze them?"
|
| 53 |
+
|
| 54 |
+
product-eval runs the full chain (gather and weight evidence, synthesize themes, score Value and Confidence, run the readiness gate) and returns a ranked shortlist with a verdict on each.
|
| 55 |
+
|
| 56 |
+

|
| 57 |
+
|
| 58 |
+
Ask for a scorecard and it builds a self-contained, shareable HTML dashboard:
|
| 59 |
+
|
| 60 |
+
> "Can you build a scorecard?"
|
| 61 |
+
|
| 62 |
+

|
| 63 |
+
|
| 64 |
+
No data of your own? It also works top-down from a domain ("research the observability tooling space and tell me what's worth building"), reasoning from public signal and stating the resulting confidence ceiling. You can also open a ready-made example with zero setup: `examples/activation-q3/scorecard.html`.
|
| 65 |
+
|
| 66 |
+
## Outcome Modes
|
| 67 |
+
|
| 68 |
+
### Rank Opportunities
|
| 69 |
+
|
| 70 |
+
Use this when you have a product area, evidence pile, or backlog and want a ranked shortlist. The plugin gathers or reads evidence, turns themes into buildable problem statements, scores each item by Value and Confidence, and returns a ranked table with the best next move.
|
| 71 |
+
|
| 72 |
+
### Decide On One Bet
|
| 73 |
+
|
| 74 |
+
Use this when you have one idea or problem and need a yes/no readiness call. The output leads with one of three outcomes:
|
| 75 |
+
|
| 76 |
+
- **Decide now:** enough credible, diverse evidence to commit.
|
| 77 |
+
- **Run a research sprint:** promising, but one specific proof gap should be closed first.
|
| 78 |
+
- **Do not commit yet:** evidence is too weak, vague, stale, or single-source.
|
| 79 |
+
|
| 80 |
+
Evidence math is kept visible for audit, but the decision is presented as a banded verdict rather than false precision.
|
| 81 |
+
|
| 82 |
+
### Pressure-Test A Plan
|
| 83 |
+
|
| 84 |
+
Use this when a roadmap, PRD, strategy, or bet already exists and you want the weak spots surfaced before committing. The output is blocking issues, suggestions, strengths, and a ready / needs-fixes / not-ready verdict.
|
| 85 |
+
|
| 86 |
+
### Write The Output
|
| 87 |
+
|
| 88 |
+
Use this after a decision has enough evidence or when you need a decision artifact:
|
| 89 |
+
|
| 90 |
+
- **Opportunity Brief:** persuade and align humans around the problem, why now, impact, and ask.
|
| 91 |
+
- **Decision Memo:** force a specific yes/no or option choice with criteria, metrics, tradeoffs, and deadline.
|
| 92 |
+
- **Build Brief:** hand an approved decision to a code or design agent with testable requirements.
|
| 93 |
+
- **Scorecard:** render ranked opportunities and verdicts as a shareable HTML dashboard.
|
| 94 |
+
|
| 95 |
+
Use **critique** when you want an independent adversarial read of findings, a problem statement, a brief, or an FAQ. Use **pressure-test** when you already have a roadmap, PRD, plan, or bet and want to find the weak spots before committing.
|
| 96 |
+
|
| 97 |
+
## Decision Model
|
| 98 |
+
|
| 99 |
+
A decision passes a two-stage gate:
|
| 100 |
+
|
| 101 |
+
1. **Sufficiency gate:** blocks if evidence weight is too low, all evidence is weak, evidence comes from only one independent source type, or the problem statement is vague.
|
| 102 |
+
2. **Confidence verdict:** combines evidence weight, source diversity, contradictions, and Value into a recommendation.
|
| 103 |
+
|
| 104 |
+
The chat output should show **bands first**: Low / Moderate / High Confidence and the resulting verdict. Exact Value and Confidence numbers are stored in `.product-eval/<scope>/` files for audit, calibration, and scorecards.
|
| 105 |
+
|
| 106 |
+
## State: `.product-eval/<scope>/`
|
| 107 |
+
|
| 108 |
+
All investigation state lives inside the user's project repo so it versions with code and can be reviewed in pull requests. Each investigation gets its own scope:
|
| 109 |
+
|
| 110 |
+
```text
|
| 111 |
+
.product-eval/
|
| 112 |
+
<scope>/
|
| 113 |
+
context.md business context: product, north star, personas
|
| 114 |
+
sources.md discovered sources, coverage, confidence ceiling
|
| 115 |
+
evidence/ one file per evidence item
|
| 116 |
+
identities.md resolved person/account map across sources
|
| 117 |
+
themes.md problem-framed themes with gaps and confidence
|
| 118 |
+
scores.md exact Value + Confidence numbers for audit
|
| 119 |
+
decisions-log.md append-only verdicts, overrides, drift, docs
|
| 120 |
+
snapshots/ timestamped copies for drift checks
|
| 121 |
+
docs/ briefs and decision memos
|
| 122 |
+
build/ agent-ready build/design briefs
|
| 123 |
+
calibration.yml optional workspace-level scoring overrides
|
| 124 |
+
```
|
| 125 |
+
|
| 126 |
+
If `.product-eval/<scope>/` does not exist, the first run creates or proposes a short scope name. Skills degrade gracefully when files or sources are missing and state the resulting confidence ceiling.
|
| 127 |
+
|
| 128 |
+
## Validation
|
| 129 |
+
|
| 130 |
+
Run the plugin/package checks:
|
| 131 |
+
|
| 132 |
+
```text
|
| 133 |
+
python3 evals/checks/validate_plugin.py
|
| 134 |
+
```
|
| 135 |
+
|
| 136 |
+
Run the scope fixture validator after installing its dependency:
|
| 137 |
+
|
| 138 |
+
```text
|
| 139 |
+
python3 -m pip install -r scripts/requirements.txt
|
| 140 |
+
python3 scripts/validate_scope.py examples/activation-q3
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
## Design Principles
|
| 144 |
+
|
| 145 |
+
- **Outcome-first UX.** Users ask for Rank, Decide, Pressure-test, or Write; internal skills do the routing.
|
| 146 |
+
- **Evidence as described, not ground truth.** The plugin rates credibility, diversity, and recency. It does not prove that every cited number is objectively true.
|
| 147 |
+
- **Honest ceilings.** Every verdict states the maximum confidence the connected or provided sources allow and how to raise it.
|
| 148 |
+
- **Evidence is weighted, not counted.** Strong first-party findings outweigh many weak anecdotes.
|
| 149 |
+
- **Plain files, no daemon.** Skills read and write markdown/YAML under `.product-eval/<scope>/`; git provides history.
|
| 150 |
+
|
| 151 |
+
## Roadmap
|
| 152 |
+
|
| 153 |
+
- Calibration and reality-testing against more closed decisions.
|
| 154 |
+
- Trigger eval hardening for the outcome modes and scorecard.
|
| 155 |
+
- Cross-scope portfolio view: a roll-up of what is decided, waiting on evidence, or drifting across investigations.
|
| 156 |
+
- Scale-out clustering for large evidence corpora when map-reduce synthesis is not enough.
|
product-eval/evals/checks/validate_plugin.py
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Validate product-eval plugin source, evals, and packaged artifact."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import json
|
| 7 |
+
import re
|
| 8 |
+
import sys
|
| 9 |
+
import zipfile
|
| 10 |
+
from pathlib import Path
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
ROOT = Path(__file__).resolve().parents[2]
|
| 14 |
+
PACKAGE = ROOT / "product-eval.plugin"
|
| 15 |
+
PARENT_PACKAGE = ROOT.parent / "product-eval.plugin"
|
| 16 |
+
CLAUDE_MANIFEST = ROOT / ".claude-plugin" / "plugin.json"
|
| 17 |
+
CLAUDE_MARKETPLACE = ROOT / ".claude-plugin" / "marketplace.json"
|
| 18 |
+
CODEX_MANIFEST = ROOT / ".codex-plugin" / "plugin.json"
|
| 19 |
+
EXCLUDED_PATH_PREFIXES = (
|
| 20 |
+
"skills/critique/",
|
| 21 |
+
"evals/trigger/critique.json",
|
| 22 |
+
"evals/checks/validate_plugin.py",
|
| 23 |
+
)
|
| 24 |
+
IGNORED_SOURCE_NAMES = {".DS_Store", "product-eval.plugin"}
|
| 25 |
+
LEGACY_PM_PATHS = (
|
| 26 |
+
".pm/context",
|
| 27 |
+
".pm/sources",
|
| 28 |
+
".pm/evidence",
|
| 29 |
+
".pm/identities",
|
| 30 |
+
".pm/themes",
|
| 31 |
+
".pm/scores",
|
| 32 |
+
".pm/decisions-log",
|
| 33 |
+
".pm/snapshots",
|
| 34 |
+
)
|
| 35 |
+
ALLOWED_FRONTMATTER = {"name", "description", "license", "allowed-tools", "metadata"}
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def fail(message: str) -> None:
|
| 39 |
+
print(f"ERROR: {message}", file=sys.stderr)
|
| 40 |
+
raise SystemExit(1)
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def load_json(path: Path):
|
| 44 |
+
try:
|
| 45 |
+
with path.open("r", encoding="utf-8") as handle:
|
| 46 |
+
return json.load(handle)
|
| 47 |
+
except Exception as exc: # noqa: BLE001 - validation script should report exact file.
|
| 48 |
+
fail(f"invalid JSON in {path.relative_to(ROOT)}: {exc}")
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def read_archive_json(archive: zipfile.ZipFile, path: str):
|
| 52 |
+
try:
|
| 53 |
+
return json.loads(archive.read(path))
|
| 54 |
+
except Exception as exc: # noqa: BLE001 - package validator should report exact file.
|
| 55 |
+
fail(f"packaged {path} missing or invalid: {exc}")
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def manifest_identity(payload: dict, label: str) -> tuple[str, str]:
|
| 59 |
+
name = payload.get("name")
|
| 60 |
+
version = payload.get("version")
|
| 61 |
+
if not isinstance(name, str) or not name.strip():
|
| 62 |
+
fail(f"{label} missing name")
|
| 63 |
+
if not isinstance(version, str) or not version.strip():
|
| 64 |
+
fail(f"{label} missing version")
|
| 65 |
+
return name, version
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def marketplace_entry(payload: dict, label: str, expected_name: str) -> dict:
|
| 69 |
+
plugins = payload.get("plugins")
|
| 70 |
+
if not isinstance(plugins, list) or not plugins:
|
| 71 |
+
fail(f"{label} missing plugins array")
|
| 72 |
+
for entry in plugins:
|
| 73 |
+
if isinstance(entry, dict) and entry.get("name") == expected_name:
|
| 74 |
+
return entry
|
| 75 |
+
if len(plugins) == 1 and isinstance(plugins[0], dict):
|
| 76 |
+
return plugins[0]
|
| 77 |
+
fail(f"{label} missing plugin entry for {expected_name!r}")
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def validate_identity(label: str, name: str, version: str, expected_name: str, expected_version: str) -> None:
|
| 81 |
+
if name != expected_name:
|
| 82 |
+
fail(f"{label} name mismatch: {name!r} != {expected_name!r}")
|
| 83 |
+
if version != expected_version:
|
| 84 |
+
fail(f"{label} version mismatch: {version!r} != {expected_version!r}")
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def validate_json() -> None:
|
| 88 |
+
for path in sorted((ROOT / "evals").rglob("*.json")):
|
| 89 |
+
load_json(path)
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def validate_manifest_identity() -> None:
|
| 93 |
+
if not CODEX_MANIFEST.exists():
|
| 94 |
+
fail("missing .codex-plugin/plugin.json")
|
| 95 |
+
|
| 96 |
+
claude_manifest = load_json(CLAUDE_MANIFEST)
|
| 97 |
+
codex_manifest = load_json(CODEX_MANIFEST)
|
| 98 |
+
marketplace = load_json(CLAUDE_MARKETPLACE)
|
| 99 |
+
|
| 100 |
+
expected_name, expected_version = manifest_identity(
|
| 101 |
+
claude_manifest, ".claude-plugin/plugin.json"
|
| 102 |
+
)
|
| 103 |
+
if ROOT.name != expected_name:
|
| 104 |
+
fail(f"plugin folder name {ROOT.name!r} does not match manifest name {expected_name!r}")
|
| 105 |
+
|
| 106 |
+
codex_name, codex_version = manifest_identity(codex_manifest, ".codex-plugin/plugin.json")
|
| 107 |
+
validate_identity(
|
| 108 |
+
".codex-plugin/plugin.json",
|
| 109 |
+
codex_name,
|
| 110 |
+
codex_version,
|
| 111 |
+
expected_name,
|
| 112 |
+
expected_version,
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
entry = marketplace_entry(
|
| 116 |
+
marketplace, ".claude-plugin/marketplace.json", expected_name
|
| 117 |
+
)
|
| 118 |
+
entry_name = entry.get("name")
|
| 119 |
+
entry_version = entry.get("version")
|
| 120 |
+
validate_identity(
|
| 121 |
+
".claude-plugin/marketplace.json plugin entry",
|
| 122 |
+
entry_name,
|
| 123 |
+
entry_version,
|
| 124 |
+
expected_name,
|
| 125 |
+
expected_version,
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
def validate_route_coverage() -> None:
|
| 130 |
+
skills = sorted(path.parent.name for path in (ROOT / "skills").glob("*/SKILL.md"))
|
| 131 |
+
triggering = load_json(ROOT / "evals" / "triggering.json")
|
| 132 |
+
listed = sorted(triggering.get("skills", []))
|
| 133 |
+
if listed != skills:
|
| 134 |
+
fail(f"triggering.json skills do not match source skills: listed={listed}, source={skills}")
|
| 135 |
+
|
| 136 |
+
trigger_files = sorted(path.stem for path in (ROOT / "evals" / "trigger").glob("*.json"))
|
| 137 |
+
if trigger_files != skills:
|
| 138 |
+
fail(f"per-skill trigger evals do not match source skills: evals={trigger_files}, source={skills}")
|
| 139 |
+
|
| 140 |
+
for skill in skills:
|
| 141 |
+
cases = load_json(ROOT / "evals" / "trigger" / f"{skill}.json")
|
| 142 |
+
if not isinstance(cases, list) or not cases:
|
| 143 |
+
fail(f"missing trigger cases for {skill}")
|
| 144 |
+
positives = [case for case in cases if case.get("should_trigger") is True]
|
| 145 |
+
negatives = [case for case in cases if case.get("should_trigger") is False]
|
| 146 |
+
if not positives or not negatives:
|
| 147 |
+
fail(f"{skill} trigger eval must include positive and negative cases")
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def parse_simple_frontmatter(path: Path) -> dict[str, str]:
|
| 151 |
+
text = path.read_text(encoding="utf-8")
|
| 152 |
+
if not text.startswith("---\n"):
|
| 153 |
+
fail(f"{path.relative_to(ROOT)} missing YAML frontmatter")
|
| 154 |
+
end = text.find("\n---", 4)
|
| 155 |
+
if end == -1:
|
| 156 |
+
fail(f"{path.relative_to(ROOT)} has unterminated YAML frontmatter")
|
| 157 |
+
|
| 158 |
+
data: dict[str, str] = {}
|
| 159 |
+
for raw_line in text[4:end].splitlines():
|
| 160 |
+
line = raw_line.strip()
|
| 161 |
+
if not line or line.startswith("#"):
|
| 162 |
+
continue
|
| 163 |
+
if ":" not in line:
|
| 164 |
+
fail(f"{path.relative_to(ROOT)} has unsupported frontmatter line: {raw_line!r}")
|
| 165 |
+
key, value = line.split(":", 1)
|
| 166 |
+
key = key.strip()
|
| 167 |
+
if key not in ALLOWED_FRONTMATTER:
|
| 168 |
+
fail(f"{path.relative_to(ROOT)} has unexpected frontmatter key {key!r}")
|
| 169 |
+
data[key] = value.strip().strip('"').strip("'")
|
| 170 |
+
return data
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def validate_skill_frontmatter() -> None:
|
| 174 |
+
for skill_md in sorted((ROOT / "skills").glob("*/SKILL.md")):
|
| 175 |
+
rel = skill_md.relative_to(ROOT)
|
| 176 |
+
frontmatter = parse_simple_frontmatter(skill_md)
|
| 177 |
+
name = frontmatter.get("name")
|
| 178 |
+
description = frontmatter.get("description")
|
| 179 |
+
if not name:
|
| 180 |
+
fail(f"{rel} missing name")
|
| 181 |
+
if not re.fullmatch(r"[a-z0-9-]{1,64}", name):
|
| 182 |
+
fail(f"{rel} has invalid skill name {name!r}")
|
| 183 |
+
if name != skill_md.parent.name:
|
| 184 |
+
fail(f"{rel} name {name!r} does not match folder {skill_md.parent.name!r}")
|
| 185 |
+
if not description:
|
| 186 |
+
fail(f"{rel} missing description")
|
| 187 |
+
if "<" in description or ">" in description:
|
| 188 |
+
fail(f"{rel} description contains angle brackets")
|
| 189 |
+
if len(description) > 1024:
|
| 190 |
+
fail(f"{rel} description is too long ({len(description)} chars)")
|
| 191 |
+
lower_description = description.lower()
|
| 192 |
+
if "do not trigger" in lower_description or "deprecated" in lower_description:
|
| 193 |
+
fail(f"{rel} is still packaged as a routable skill but its description says not to trigger it")
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
def validate_pm_paths() -> None:
|
| 197 |
+
for path in sorted(ROOT.rglob("*")):
|
| 198 |
+
if not path.is_file():
|
| 199 |
+
continue
|
| 200 |
+
rel = path.relative_to(ROOT).as_posix()
|
| 201 |
+
if rel.startswith(EXCLUDED_PATH_PREFIXES):
|
| 202 |
+
continue
|
| 203 |
+
if path.name in IGNORED_SOURCE_NAMES:
|
| 204 |
+
continue
|
| 205 |
+
try:
|
| 206 |
+
text = path.read_text(encoding="utf-8")
|
| 207 |
+
except UnicodeDecodeError:
|
| 208 |
+
continue
|
| 209 |
+
for legacy in LEGACY_PM_PATHS:
|
| 210 |
+
if legacy in text:
|
| 211 |
+
fail(f"legacy unscoped path {legacy!r} found in {rel}")
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def source_files() -> set[str]:
|
| 215 |
+
files: set[str] = set()
|
| 216 |
+
for path in ROOT.rglob("*"):
|
| 217 |
+
if not path.is_file():
|
| 218 |
+
continue
|
| 219 |
+
if path.name in IGNORED_SOURCE_NAMES:
|
| 220 |
+
continue
|
| 221 |
+
files.add(path.relative_to(ROOT).as_posix())
|
| 222 |
+
return files
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def validate_package() -> None:
|
| 226 |
+
if PARENT_PACKAGE.exists():
|
| 227 |
+
fail(f"stale parent-level product-eval.plugin exists at {PARENT_PACKAGE}")
|
| 228 |
+
if not PACKAGE.exists():
|
| 229 |
+
fail("product-eval.plugin is missing")
|
| 230 |
+
|
| 231 |
+
source = source_files()
|
| 232 |
+
with zipfile.ZipFile(PACKAGE) as archive:
|
| 233 |
+
packaged_files = {
|
| 234 |
+
name
|
| 235 |
+
for name in archive.namelist()
|
| 236 |
+
if not name.endswith("/")
|
| 237 |
+
and Path(name).name not in IGNORED_SOURCE_NAMES
|
| 238 |
+
}
|
| 239 |
+
missing = sorted(source - packaged_files)
|
| 240 |
+
extra = sorted(packaged_files - source)
|
| 241 |
+
if missing or extra:
|
| 242 |
+
fail(f"package/source file mismatch: missing={missing}, extra={extra}")
|
| 243 |
+
|
| 244 |
+
for rel in sorted(source):
|
| 245 |
+
if archive.read(rel) != (ROOT / rel).read_bytes():
|
| 246 |
+
fail(f"package/source content mismatch: {rel}")
|
| 247 |
+
|
| 248 |
+
packaged_claude_manifest = read_archive_json(archive, ".claude-plugin/plugin.json")
|
| 249 |
+
packaged_codex_manifest = read_archive_json(archive, ".codex-plugin/plugin.json")
|
| 250 |
+
packaged_marketplace = read_archive_json(archive, ".claude-plugin/marketplace.json")
|
| 251 |
+
|
| 252 |
+
source_manifest = load_json(CLAUDE_MANIFEST)
|
| 253 |
+
expected_name, expected_version = manifest_identity(
|
| 254 |
+
source_manifest, ".claude-plugin/plugin.json"
|
| 255 |
+
)
|
| 256 |
+
for label, payload in (
|
| 257 |
+
("packaged .claude-plugin/plugin.json", packaged_claude_manifest),
|
| 258 |
+
("packaged .codex-plugin/plugin.json", packaged_codex_manifest),
|
| 259 |
+
):
|
| 260 |
+
name, version = manifest_identity(payload, label)
|
| 261 |
+
validate_identity(label, name, version, expected_name, expected_version)
|
| 262 |
+
|
| 263 |
+
packaged_entry = marketplace_entry(
|
| 264 |
+
packaged_marketplace, "packaged .claude-plugin/marketplace.json", expected_name
|
| 265 |
+
)
|
| 266 |
+
validate_identity(
|
| 267 |
+
"packaged .claude-plugin/marketplace.json plugin entry",
|
| 268 |
+
packaged_entry.get("name"),
|
| 269 |
+
packaged_entry.get("version"),
|
| 270 |
+
expected_name,
|
| 271 |
+
expected_version,
|
| 272 |
+
)
|
| 273 |
+
|
| 274 |
+
|
| 275 |
+
def main() -> None:
|
| 276 |
+
validate_json()
|
| 277 |
+
validate_manifest_identity()
|
| 278 |
+
validate_route_coverage()
|
| 279 |
+
validate_skill_frontmatter()
|
| 280 |
+
validate_pm_paths()
|
| 281 |
+
validate_package()
|
| 282 |
+
print("product-eval validation passed")
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
if __name__ == "__main__":
|
| 286 |
+
main()
|
product-eval/evals/trigger/calibrate.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"query": "the confidence numbers feel too generous lately, can we tune the thresholds against these 8 past launches where we already know how they turned out",
|
| 4 |
+
"should_trigger": true
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"query": "our model keeps flashing Go on stuff that later flopped. here are 12 shipped bets with what actually happened, fix the weights so it stops doing that",
|
| 8 |
+
"should_trigger": true
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"query": "i think the gate cutoff is too loose. check it against past calls and tell me what number to move it to",
|
| 12 |
+
"should_trigger": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"query": "validate the scoring against calibration/cases.md and flag where the verdict didn't match the real outcome",
|
| 16 |
+
"should_trigger": true
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"query": "we've got a sheet of 15 old feature decisions with their actual results. use them to see if our evidence weights are even right",
|
| 20 |
+
"should_trigger": true
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"query": "the crispness bar feels off, sanity-check it against the problems we actually shipped vs the ones we killed",
|
| 24 |
+
"should_trigger": true
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"query": "three things it scored Research turned out great. that's a false-negative pattern, right? adjust the constants",
|
| 28 |
+
"should_trigger": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"query": "backtest the scoring formula on our 2025 launches and recommend new threshold values",
|
| 32 |
+
"should_trigger": true
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"query": "are the diversity factors and the gate threshold actually calibrated? here are 10 past decisions with known outcomes to test against",
|
| 36 |
+
"should_trigger": true
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"query": "i don't trust the confidence math anymore. we have a stack of past bets and their outcomes, figure out where the scoring is systematically wrong",
|
| 40 |
+
"should_trigger": true
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"query": "is it worth building SSO before our enterprise push, and do we even have enough data to make that call yet?",
|
| 44 |
+
"should_trigger": false
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"query": "does the SSO bet have enough evidence behind it to greenlight, and what's still missing?",
|
| 48 |
+
"should_trigger": false
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"query": "the confidence score on this one opportunity looks way too high. is it actually ready to decide or not?",
|
| 52 |
+
"should_trigger": false
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"query": "rank these 8 feature ideas by what's most worth doing, we've got analytics plus support data",
|
| 56 |
+
"should_trigger": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"query": "review our north-star and activation metrics for the month and flag what moved",
|
| 60 |
+
"should_trigger": false
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"query": "our activation rate dropped 4 points last week, dig into the numbers and tell me why",
|
| 64 |
+
"should_trigger": false
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"query": "poke holes in our Q3 roadmap before the leadership review on friday",
|
| 68 |
+
"should_trigger": false
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"query": "grade how crisp this problem statement is: 'onboarding is bad'",
|
| 72 |
+
"should_trigger": false
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"query": "has our top opportunity drifted since last month, did confidence actually improve or are we just spinning?",
|
| 76 |
+
"should_trigger": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"query": "pull the recurring complaints from zendesk, our g2 reviews, and the churn survey and grade how solid each signal is",
|
| 80 |
+
"should_trigger": false
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"query": "turn this pile of 30 user interview transcripts into the top themes ranked by how often they came up",
|
| 84 |
+
"should_trigger": false
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"query": "build me a scorecard of this quarter's product metrics with the trends called out for the exec review",
|
| 88 |
+
"should_trigger": false
|
| 89 |
+
}
|
| 90 |
+
]
|
product-eval/evals/trigger/critique.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"query": "grade how crisp this problem statement is: 'onboarding is bad'",
|
| 4 |
+
"should_trigger": true
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"query": "is this one-liner actually sharp enough to take into a brief? 'we need better reporting'",
|
| 8 |
+
"should_trigger": true
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"query": "poke holes in the findings from our churn investigation before I write them up",
|
| 12 |
+
"should_trigger": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"query": "red-team this FAQ we drafted for the SSO opportunity brief, attack the weak answers",
|
| 16 |
+
"should_trigger": true
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"query": "is this crisp enough? 'users want a faster dashboard' - score it and tell me what's missing",
|
| 20 |
+
"should_trigger": true
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"query": "before we move from evidence to scoring, can someone fresh tear into our themes handoff and flag what's not ready",
|
| 24 |
+
"should_trigger": true
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"query": "put these findings in front of a skeptical customer, a CFO, and an engineer and see where they fall apart",
|
| 28 |
+
"should_trigger": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"query": "gate this opportunity brief before it advances to the decision stage, don't rubber-stamp it",
|
| 32 |
+
"should_trigger": true
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"query": "my one-liner is 'reduce friction in checkout' - how tight is it and can you rewrite it sharper",
|
| 36 |
+
"should_trigger": true
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"query": "give the conclusions in this synthesis doc a fresh adversarial read from someone who wasn't in the room",
|
| 40 |
+
"should_trigger": true
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"query": "does this problem statement sit at the right altitude and actually name a persona, or is it mush?",
|
| 44 |
+
"should_trigger": true
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"query": "poke holes in our Q3 roadmap before the leadership review on friday",
|
| 48 |
+
"should_trigger": false
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"query": "stress-test our whole go-to-market plan for the enterprise tier before we commit to it",
|
| 52 |
+
"should_trigger": false
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"query": "adversarially pressure-test this PRD and the bet behind it before we green-light the sprint",
|
| 56 |
+
"should_trigger": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"query": "let's brainstorm some new directions for our analytics product, i want a sharp thinking partner",
|
| 60 |
+
"should_trigger": false
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"query": "be my sparring partner and help me explore the problem space around activation, throw ideas at me",
|
| 64 |
+
"should_trigger": false
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"query": "is it worth building SSO before our enterprise push? do we even have the data to call it?",
|
| 68 |
+
"should_trigger": false
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"query": "synthesize the evidence we just pulled into the main problem-themes",
|
| 72 |
+
"should_trigger": false
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"query": "i have a pile of 30 user-interview transcripts in a folder, pull out the main themes and insights for me",
|
| 76 |
+
"should_trigger": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"query": "here are our raw survey responses and a stack of support tickets, make sense of them into findings",
|
| 80 |
+
"should_trigger": false
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"query": "pull the recurring complaints from zendesk, our g2 reviews, and the churn survey and grade how solid each signal is",
|
| 84 |
+
"should_trigger": false
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"query": "reprioritize the roadmap into now/next/later now that the SSO bet jumped the queue",
|
| 88 |
+
"should_trigger": false
|
| 89 |
+
}
|
| 90 |
+
]
|
product-eval/evals/trigger/decision-readiness.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"query": "is it worth building SSO before our enterprise push? do we even have the data to call it?",
|
| 4 |
+
"should_trigger": true
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"query": "do we have enough evidence to greenlight the in-app notifications rebuild, or are we just guessing?",
|
| 8 |
+
"should_trigger": true
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"query": "are we ready to commit to the billing rework? tell me what's still missing before i say yes",
|
| 12 |
+
"should_trigger": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"query": "we've got ~40 intercom tickets and an amplitude drop-off chart pointing at onboarding step 3. is that actually enough to decide to fix it?",
|
| 16 |
+
"should_trigger": true
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"query": "honestly, what's the evidence behind shipping a mobile app this half? strong enough to pull the trigger or not?",
|
| 20 |
+
"should_trigger": true
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"query": "before i tell eng to start, can you judge whether the dark-mode request has enough signal to justify it",
|
| 24 |
+
"should_trigger": true
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"query": "i keep going back and forth on the API rate-limit feature. do we have the right to make this call yet, and what gaps should i close first?",
|
| 28 |
+
"should_trigger": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"query": "gut check: is team-permissions a defensible build given what we actually know, or do we need more data before committing?",
|
| 32 |
+
"should_trigger": true
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"query": "we think churned accounts wanted Slack alerts. is that conviction earned by the evidence, or wishful thinking? want a yes/no and the holes",
|
| 36 |
+
"should_trigger": true
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"query": "my PM swears the saved-views feature is a slam dunk. can you sanity-check whether the evidence actually backs committing to it?",
|
| 40 |
+
"should_trigger": true
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"query": "rank these 8 feature ideas by what's most worth doing, we have analytics + support data",
|
| 44 |
+
"should_trigger": false
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"query": "which of our three enterprise bets has the strongest case? line them up and score them so we know where to spend",
|
| 48 |
+
"should_trigger": false
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"query": "poke holes in our Q3 roadmap before the leadership review on friday",
|
| 52 |
+
"should_trigger": false
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"query": "stress-test this PRD for the new onboarding flow before we commit to it next sprint",
|
| 56 |
+
"should_trigger": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"query": "review our north-star and activation metrics for the month and flag what moved",
|
| 60 |
+
"should_trigger": false
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"query": "how did retention and DAU trend last quarter vs target? give me the scorecard",
|
| 64 |
+
"should_trigger": false
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"query": "i have a pile of 30 user-interview transcripts in a folder, pull out the main themes and insights for me",
|
| 68 |
+
"should_trigger": false
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"query": "here are 200 raw survey responses, make sense of them and rank the findings by frequency",
|
| 72 |
+
"should_trigger": false
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"query": "pull the recurring complaints from zendesk, our g2 reviews, and the churn survey and grade how solid each signal is",
|
| 76 |
+
"should_trigger": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"query": "grade how crisp this problem statement is: 'onboarding is bad'",
|
| 80 |
+
"should_trigger": false
|
| 81 |
+
}
|
| 82 |
+
]
|
product-eval/evals/trigger/design-test.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"query": "decision-readiness says run a research sprint for SSO — design the cheapest test to close the gap",
|
| 4 |
+
"should_trigger": true
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"query": "how do we validate this billing bet before engineering starts building?",
|
| 8 |
+
"should_trigger": true
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"query": "what's the cheapest experiment that would de-risk the notifications idea?",
|
| 12 |
+
"should_trigger": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"query": "turn these readiness gaps into a concrete validation test with a pass fail threshold",
|
| 16 |
+
"should_trigger": true
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"query": "we need a smoke test for the enterprise audit logs bet before committing the quarter",
|
| 20 |
+
"should_trigger": true
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"query": "design a quick fake-door test to see if customers actually want scheduled csv exports",
|
| 24 |
+
"should_trigger": true
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"query": "the idea is promising but evidence is thin; tell me the fastest research sprint to run",
|
| 28 |
+
"should_trigger": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"query": "what would prove or disprove this onboarding hypothesis in two weeks?",
|
| 32 |
+
"should_trigger": true
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"query": "give me the riskiest assumption, method, sample, instrumentation, duration and pass fail bar",
|
| 36 |
+
"should_trigger": true
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"query": "de-risk this feature idea with a small experiment before we write a spec",
|
| 40 |
+
"should_trigger": true
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"query": "pull the recurring complaints from zendesk and g2 and grade how solid each signal is",
|
| 44 |
+
"should_trigger": false
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"query": "is SSO worth building before the enterprise push, do we have enough evidence?",
|
| 48 |
+
"should_trigger": false
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"query": "rank these 8 feature ideas by what's most worth doing",
|
| 52 |
+
"should_trigger": false
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"query": "write the opportunity brief for the approved billing decision",
|
| 56 |
+
"should_trigger": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"query": "turn the approved decision into a build spec for claude code",
|
| 60 |
+
"should_trigger": false
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"query": "pressure-test our Q3 roadmap before leadership review",
|
| 64 |
+
"should_trigger": false
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"query": "what product-data sources do I have connected?",
|
| 68 |
+
"should_trigger": false
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"query": "synthesize the evidence we pulled into problem themes",
|
| 72 |
+
"should_trigger": false
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"query": "make a scorecard from the ranked opportunities",
|
| 76 |
+
"should_trigger": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"query": "update our Now Next Later roadmap with the new SSO epic",
|
| 80 |
+
"should_trigger": false
|
| 81 |
+
}
|
| 82 |
+
]
|
product-eval/evals/trigger/discover-sources.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"query": "what data do I even have to make product decisions? scan my connectors and tell me the confidence ceiling",
|
| 4 |
+
"should_trigger": true
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"query": "scan my sources and tell me where product insights could realistically come from",
|
| 8 |
+
"should_trigger": true
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"query": "what can I connect for product decisions right now? show me whats callable and whats missing",
|
| 12 |
+
"should_trigger": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"query": "im starting fresh in this repo, before we frame anything map out where my product data actually lives",
|
| 16 |
+
"should_trigger": true
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"query": "do i have intercom, amplitude, and zendesk hooked up? give me an inventory of my product-data sources and how strong each can get",
|
| 20 |
+
"should_trigger": true
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"query": "whats the best decision confidence i can realistically hit given only the sources i have access to today?",
|
| 24 |
+
"should_trigger": true
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"query": "build me a source map of my product evidence and flag what i'd have to upload as a CSV since it cant be connected",
|
| 28 |
+
"should_trigger": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"query": "i just want the landscape of where signal could come from, not the actual data pulled yet",
|
| 32 |
+
"should_trigger": true
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"query": "refresh the source inventory in .product-eval/onboarding/sources.md, i think i wired up linear and pendo since we last looked",
|
| 36 |
+
"should_trigger": true
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"query": "new project, what's the ceiling on how confident any call could be with what i've got connected?",
|
| 40 |
+
"should_trigger": true
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"query": "pull the recurring complaints from zendesk, our g2 reviews, and the churn survey and grade how solid each signal is",
|
| 44 |
+
"should_trigger": false
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"query": "now that you know where my data lives, go ahead and pull everything from intercom and amplitude into the scope",
|
| 48 |
+
"should_trigger": false
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"query": "collect the last 90 days of support tickets and reviews and normalize them so we can analyze",
|
| 52 |
+
"should_trigger": false
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"query": "synthesize the evidence we just gathered into the main problem themes",
|
| 56 |
+
"should_trigger": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"query": "i have a folder of 30 user-interview transcripts, pull out the main themes and insights for me",
|
| 60 |
+
"should_trigger": false
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"query": "here are 200 raw survey responses we just got back, make sense of them and rank the findings",
|
| 64 |
+
"should_trigger": false
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"query": "review our north-star and activation metrics for the month and flag what moved",
|
| 68 |
+
"should_trigger": false
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"query": "put together our monthly product scorecard and call out the biggest trend changes",
|
| 72 |
+
"should_trigger": false
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"query": "give me a competitive brief on Linear vs Jira for our sales battlecard",
|
| 76 |
+
"should_trigger": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"query": "update our Now/Next/Later roadmap, move the billing rework to Next and add the SSO epic to Now",
|
| 80 |
+
"should_trigger": false
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"query": "is it worth building SSO before our enterprise push? do we even have enough evidence to call it?",
|
| 84 |
+
"should_trigger": false
|
| 85 |
+
}
|
| 86 |
+
]
|
product-eval/evals/trigger/drift-check.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{"query": "what changed since last month", "should_trigger": true},
|
| 3 |
+
{"query": "has this investigation drifted since we last looked at it", "should_trigger": true},
|
| 4 |
+
{"query": "compare the current state of the onboarding scope to the snapshot from last quarter and tell me what moved", "should_trigger": true},
|
| 5 |
+
{"query": "is the confidence trajectory on this bet actually improving, or are we just churning without new evidence coming in", "should_trigger": true},
|
| 6 |
+
{"query": "audit this scope before we re-decide — what's changed since the last decision was logged", "should_trigger": true},
|
| 7 |
+
{"query": "did our problem statement drift away from the evidence since the first version of the brief", "should_trigger": true},
|
| 8 |
+
{"query": "diff the billing investigation now versus the prior version — scores, evidence, and framing", "should_trigger": true},
|
| 9 |
+
{"query": "we snapshotted this scope a month ago — what evidence got added or retired, and how did Value and Confidence move", "should_trigger": true},
|
| 10 |
+
{"query": "are we accumulating real confidence on the activation problem over time, or has it just been flat churn", "should_trigger": true},
|
| 11 |
+
{"query": "show me what moved in this investigation since the last git ref", "should_trigger": true},
|
| 12 |
+
{"query": "has the narrative on the enterprise-churn bet been quietly reframed compared to the earlier brief", "should_trigger": true},
|
| 13 |
+
{"query": "set up a weekly digest of what moved across my investigations", "should_trigger": true},
|
| 14 |
+
{"query": "between the snapshot and now, which themes are new, which faded, and which got merged for this scope", "should_trigger": true},
|
| 15 |
+
{"query": "some of our evidence may have gone stale after the last release — compare against the prior snapshot and flag what got retired", "should_trigger": true},
|
| 16 |
+
|
| 17 |
+
{"query": "what's trending across the evidence we just gathered — which themes are getting worse month over month", "should_trigger": false},
|
| 18 |
+
{"query": "cluster the evidence in this scope into problem themes with confidence reasoning", "should_trigger": false},
|
| 19 |
+
{"query": "review our product metrics dashboard for the month and flag what moved on activation and retention", "should_trigger": false},
|
| 20 |
+
{"query": "our north-star metric dropped 8% this week, dig into what changed in the funnel", "should_trigger": false},
|
| 21 |
+
{"query": "rank these opportunities by value and confidence and tell me what to build next", "should_trigger": false},
|
| 22 |
+
{"query": "pull the latest zendesk tickets and g2 reviews into the scope", "should_trigger": false},
|
| 23 |
+
{"query": "do we have enough evidence to decide on the SSO bet yet", "should_trigger": false},
|
| 24 |
+
{"query": "let's brainstorm some new directions for our analytics product", "should_trigger": false},
|
| 25 |
+
{"query": "compare how our competitors solved onboarding versus how we did", "should_trigger": false}
|
| 26 |
+
]
|
product-eval/evals/trigger/gather-evidence.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"query": "pull the recurring complaints from zendesk, our g2 reviews, and the churn survey and grade how solid each signal is",
|
| 4 |
+
"should_trigger": true
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"query": "dig into the onboarding drop-off for me - go through intercom, amplitude, and our linear issues and tell me which findings actually hold up",
|
| 8 |
+
"should_trigger": true
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"query": "collect data on the billing complaints across our support tickets and app store reviews, last 90 days",
|
| 12 |
+
"should_trigger": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"query": "find signal for the slow-export problem - pull from wherever we have data and rate how strong each piece is",
|
| 16 |
+
"should_trigger": true
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"query": "i exported ~150 intercom convos to a csv plus a g2 dump, parse them and turn them into evidence items with strengths",
|
| 20 |
+
"should_trigger": true
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"query": "ok discover-sources is done, now actually go pull the tickets and analytics for the checkout friction area",
|
| 24 |
+
"should_trigger": true
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"query": "scrape the recent reddit + community threads about our competitor and our own churn survey, normalize it and dedupe the same users across sources",
|
| 28 |
+
"should_trigger": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"query": "we keep hearing notifications are noisy - go get me the actual receipts from pendo, the nps verbatims, and support, and tell me how much to trust each",
|
| 32 |
+
"should_trigger": true
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"query": "pull every lost-deal reason from the crm and the support tickets tagged 'sso' and weight them into evidence cards",
|
| 36 |
+
"should_trigger": true
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"query": "harvest signal on mobile crashes: error groups from datadog, app reviews, and the 40 support tickets, then strength-rate and resolve duplicate reporters",
|
| 40 |
+
"should_trigger": true
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"query": "synthesize the evidence we just pulled into themes",
|
| 44 |
+
"should_trigger": false
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"query": "what data do I even have to make product decisions? scan my connectors and tell me the confidence ceiling",
|
| 48 |
+
"should_trigger": false
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"query": "i have a pile of 30 user-interview transcripts in a folder, pull out the main themes and insights for me",
|
| 52 |
+
"should_trigger": false
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"query": "cluster this into the main problems - what patterns pop out of the signal we already collected?",
|
| 56 |
+
"should_trigger": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"query": "give me a competitive brief on Linear vs Jira for our sales battlecard",
|
| 60 |
+
"should_trigger": false
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"query": "do a teardown of Notion vs us - where are we losing on features and what do I put on the sales one-pager?",
|
| 64 |
+
"should_trigger": false
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"query": "review our north-star and activation metrics for the month and flag what moved",
|
| 68 |
+
"should_trigger": false
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"query": "which of our connected sources actually have usable product data, and how high can confidence get given what's available?",
|
| 72 |
+
"should_trigger": false
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"query": "is it worth building SSO before our enterprise push? do we even have the data to call it?",
|
| 76 |
+
"should_trigger": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"query": "new churn data came in - reshuffle our Now/Next/Later and tell me what slips to make room for the retention work",
|
| 80 |
+
"should_trigger": false
|
| 81 |
+
}
|
| 82 |
+
]
|
product-eval/evals/trigger/pressure-test.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{"query": "poke holes in our Q3 roadmap before the leadership review on friday", "should_trigger": true},
|
| 3 |
+
{"query": "stress-test this bet before we commit the whole quarter to it", "should_trigger": true},
|
| 4 |
+
{"query": "pressure-test the PRD for the new billing system, where's it weak", "should_trigger": true},
|
| 5 |
+
{"query": "red-team our go-to-market plan for the enterprise launch", "should_trigger": true},
|
| 6 |
+
{"query": "challenge the assumptions baked into this roadmap, i think we're kidding ourselves", "should_trigger": true},
|
| 7 |
+
{"query": "before we greenlight building SSO, tear the plan apart and find the holes", "should_trigger": true},
|
| 8 |
+
{"query": "we're about to commit to the mobile rewrite, what are the hidden assumptions and scope risks", "should_trigger": true},
|
| 9 |
+
{"query": "give this plan a hard critic review, find the weak grounding before we ship it", "should_trigger": true},
|
| 10 |
+
{"query": "what could go wrong with this roadmap? surface the soft spots before we present it", "should_trigger": true},
|
| 11 |
+
{"query": "play devil's advocate on our Q4 plan, what are we not seeing", "should_trigger": true},
|
| 12 |
+
|
| 13 |
+
{"query": "let's brainstorm some new directions for our analytics product, i want a sharp thinking partner", "should_trigger": false},
|
| 14 |
+
{"query": "help me come up with fresh feature ideas for our onboarding flow, just spitball with me", "should_trigger": false},
|
| 15 |
+
{"query": "i want to explore the problem space around developer retention and generate some options", "should_trigger": false},
|
| 16 |
+
{"query": "be my thinking partner, let's ideate on what we could build next in the observability space", "should_trigger": false},
|
| 17 |
+
{"query": "grade how crisp this problem statement is: 'onboarding is bad'", "should_trigger": false},
|
| 18 |
+
{"query": "is it worth building SSO before our enterprise push? do we even have the data to call it?", "should_trigger": false},
|
| 19 |
+
{"query": "update our Now/Next/Later roadmap, move the billing rework to Next and add the SSO epic to Now", "should_trigger": false},
|
| 20 |
+
{"query": "write a PRD for the new CSV export feature so engineering can pick it up", "should_trigger": false},
|
| 21 |
+
{"query": "review our north-star and activation metrics for the month and flag what moved", "should_trigger": false},
|
| 22 |
+
{"query": "write the weekly stakeholder update for leadership about the platform migration", "should_trigger": false}
|
| 23 |
+
]
|
product-eval/evals/trigger/prioritize-backlog.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{"query": "rank these 8 feature ideas by what's most worth doing, we have analytics and support data", "should_trigger": true},
|
| 3 |
+
{"query": "here's a list of 12 opportunities from our backlog, score them by value and confidence and tell me what to build", "should_trigger": true},
|
| 4 |
+
{"query": "prioritize my backlog for next quarter based on the evidence we've gathered", "should_trigger": true},
|
| 5 |
+
{"query": "i've got 15 problems competing for the same eng team, which ones are actually worth doing first", "should_trigger": true},
|
| 6 |
+
{"query": "score these opportunities and map each to a recommendation: build now, gather more, or drop", "should_trigger": true},
|
| 7 |
+
{"query": "we have evidence for some of these and basically nothing for others, rank them anyway and flag the low-confidence ones", "should_trigger": true},
|
| 8 |
+
{"query": "sequence these feature ideas by what's most worth doing given the data we have", "should_trigger": true},
|
| 9 |
+
{"query": "out of these 9 candidate bets, which should we tackle first, use value and confidence", "should_trigger": true},
|
| 10 |
+
{"query": "prioritize these: SSO, audit logs, SAML, bulk export, SCIM, rank by evidence-backed value", "should_trigger": true},
|
| 11 |
+
{"query": "what's the highest-leverage thing to build from this list of opportunities", "should_trigger": true},
|
| 12 |
+
|
| 13 |
+
{"query": "update our Now/Next/Later roadmap, move the billing rework to Next and add the SSO epic to Now", "should_trigger": false},
|
| 14 |
+
{"query": "reprioritize our roadmap, bump the mobile redesign up and push the API v2 work to later", "should_trigger": false},
|
| 15 |
+
{"query": "build me a Now / Next / Later roadmap view from scratch for the platform team", "should_trigger": false},
|
| 16 |
+
{"query": "the analytics dependency slipped two weeks, shift the roadmap timelines accordingly", "should_trigger": false},
|
| 17 |
+
{"query": "plan our next sprint, size the backlog against the team's capacity, we've got two people on PTO", "should_trigger": false},
|
| 18 |
+
{"query": "is it worth building SSO before our enterprise push? do we even have the data to call it?", "should_trigger": false},
|
| 19 |
+
{"query": "ok i've got ~200 intercom tickets exported and our amplitude funnel open, what should we actually build next quarter for onboarding", "should_trigger": false},
|
| 20 |
+
{"query": "review our north-star and activation metrics for the month and flag what moved", "should_trigger": false},
|
| 21 |
+
{"query": "write a PRD for the new CSV export feature so engineering can pick it up", "should_trigger": false},
|
| 22 |
+
{"query": "give me a competitive brief on Linear vs Jira for our sales battlecard", "should_trigger": false}
|
| 23 |
+
]
|
product-eval/evals/trigger/scorecard.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"query": "make a scorecard from the ranked opportunities in this product-eval scope",
|
| 4 |
+
"should_trigger": true
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"query": "turn the prioritization results into a visual dashboard i can share with leadership",
|
| 8 |
+
"should_trigger": true
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"query": "show me the ranked opportunities as an interactive html scorecard with value, confidence, verdicts and gaps",
|
| 12 |
+
"should_trigger": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"query": "after that backlog ranking, create the scorecard view with the value-confidence quadrant",
|
| 16 |
+
"should_trigger": true
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"query": "render a product decision dashboard from .product-eval/onboarding/scores.md and decisions-log.md",
|
| 20 |
+
"should_trigger": true
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"query": "give me a rich visual output for the readiness verdicts and opportunity ranking",
|
| 24 |
+
"should_trigger": true
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"query": "build a shareable html page of the opportunities, confidence bands, evidence weight, and open gaps",
|
| 28 |
+
"should_trigger": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"query": "make this prioritization easier to scan with cards, bands, and the top customer quotes",
|
| 32 |
+
"should_trigger": true
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"query": "open a scorecard for the current investigation so PMs can sort and act on the top bets",
|
| 36 |
+
"should_trigger": true
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"query": "can you generate the decision dashboard after running prioritize-backlog",
|
| 40 |
+
"should_trigger": true
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"query": "review our north-star and activation metrics for the month and flag what moved",
|
| 44 |
+
"should_trigger": false
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"query": "build me a scorecard of this quarter's product metrics with trends called out for the exec review",
|
| 48 |
+
"should_trigger": false
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"query": "rank these 8 feature ideas by what's most worth doing, we have analytics and support data",
|
| 52 |
+
"should_trigger": false
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"query": "is it worth building SSO before our enterprise push? do we have enough evidence to call it?",
|
| 56 |
+
"should_trigger": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"query": "write the decision memo for the billing rework with options and success criteria",
|
| 60 |
+
"should_trigger": false
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"query": "turn the approved decision into a spec i can hand straight to claude code",
|
| 64 |
+
"should_trigger": false
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"query": "poke holes in our Q3 roadmap before the leadership review on friday",
|
| 68 |
+
"should_trigger": false
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"query": "what data do I have connected for product decisions?",
|
| 72 |
+
"should_trigger": false
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"query": "pull the recurring complaints from zendesk and g2 and grade how solid each signal is",
|
| 76 |
+
"should_trigger": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"query": "draft the opportunity brief for the notifications problem",
|
| 80 |
+
"should_trigger": false
|
| 81 |
+
}
|
| 82 |
+
]
|
product-eval/evals/trigger/start.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"query": "start",
|
| 4 |
+
"should_trigger": true
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"query": "set up product-eval for my product",
|
| 8 |
+
"should_trigger": true
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"query": "help me decide what to build next, but first ask me what context and data you need",
|
| 12 |
+
"should_trigger": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"query": "help me prepare a decision report and set up the product context first",
|
| 16 |
+
"should_trigger": true
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"query": "hey just installed this, help me get going — where do i even start?",
|
| 20 |
+
"should_trigger": true
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"query": "what can this plugin actually do for me?",
|
| 24 |
+
"should_trigger": true
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"query": "i want to build something in the observability tooling space but don't know what — help me find the real problems worth solving",
|
| 28 |
+
"should_trigger": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"query": "should we build an AI changelog generator? honestly not sure, just point me in the right direction",
|
| 32 |
+
"should_trigger": true
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"query": "i'm a PM at a fintech trying to find our next big bet — how does this thing even work?",
|
| 36 |
+
"should_trigger": true
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"query": "help me figure out what to work on next, i don't even know which step to begin with",
|
| 40 |
+
"should_trigger": true
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"query": "explore the API-monitoring market for me and show me where the gaps are",
|
| 44 |
+
"should_trigger": true
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"query": "we want to figure out what to build next for our payments product — take it from the top",
|
| 48 |
+
"should_trigger": true
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"query": "give me the lay of the land here and kick off an investigation into the CI/CD space",
|
| 52 |
+
"should_trigger": true
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"query": "synthesize the evidence we just pulled into the main problem themes",
|
| 56 |
+
"should_trigger": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"query": "cluster the signal we already gathered into a handful of themes",
|
| 60 |
+
"should_trigger": false
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"query": "rank these 8 feature ideas by what's most worth building — we already have the analytics and support data",
|
| 64 |
+
"should_trigger": false
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"query": "poke holes in our Q3 roadmap before the leadership review on friday",
|
| 68 |
+
"should_trigger": false
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"query": "red-team this PRD and tell me where it falls apart before we commit",
|
| 72 |
+
"should_trigger": false
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"query": "what product data do i even have to work with? scan my connectors and tell me the confidence ceiling",
|
| 76 |
+
"should_trigger": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"query": "draft the opportunity brief for the notifications problem — both the narrative and the FAQ version",
|
| 80 |
+
"should_trigger": false
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"query": "let's brainstorm some fresh directions for our analytics product, i want a sharp thinking partner",
|
| 84 |
+
"should_trigger": false
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"query": "be my sounding board for a bit — i want to riff on new ideas for our developer tools",
|
| 88 |
+
"should_trigger": false
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"query": "i've got 30 user-interview transcripts in a folder, pull out the main themes and insights for me",
|
| 92 |
+
"should_trigger": false
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"query": "update our Now/Next/Later roadmap — move the billing rework to Next and add the SSO epic to Now",
|
| 96 |
+
"should_trigger": false
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"query": "reprioritize the roadmap, that dependency slipped so push the search revamp to Later",
|
| 100 |
+
"should_trigger": false
|
| 101 |
+
}
|
| 102 |
+
]
|
product-eval/evals/trigger/synthesize.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{"query": "synthesize the evidence we just pulled into themes", "should_trigger": true},
|
| 3 |
+
{"query": "ok we ran gather-evidence yesterday and pulled a bunch of tickets, reviews and analytics into the scope, now cluster all that into the main problem themes", "should_trigger": true},
|
| 4 |
+
{"query": "what are the recurring patterns across the evidence we collected for the onboarding scope, and how confident should we be in each theme", "should_trigger": true},
|
| 5 |
+
{"query": "group the weighted evidence items in .product-eval/onboarding/evidence into problem clusters for me", "should_trigger": true},
|
| 6 |
+
{"query": "we've got the signal gathered for this investigation, what's trending over time and what themes pop out", "should_trigger": true},
|
| 7 |
+
{"query": "turn the evidence we gathered into themes i can feed into prioritization", "should_trigger": true},
|
| 8 |
+
{"query": "now that the data's in for this scope, find the clusters and tell me where the gaps are", "should_trigger": true},
|
| 9 |
+
{"query": "what problem-themes emerge from all the evidence in this investigation, and which ones are getting worse month over month", "should_trigger": true},
|
| 10 |
+
{"query": "consolidate everything we collected on the billing pain into a few clear themes with confidence reasoning", "should_trigger": true},
|
| 11 |
+
{"query": "we pulled g2 reviews, intercom and amplitude into the scope last week, summarize the patterns into themes", "should_trigger": true},
|
| 12 |
+
{"query": "can you frame this up properly? right now all we've got is 'onboarding feels clunky' and i need it sharp enough that someone could actually build against it", "should_trigger": true},
|
| 13 |
+
{"query": "users keep dropping off somewhere in the signup flow. help me turn that into a real problem statement", "should_trigger": true},
|
| 14 |
+
{"query": "the eng lead handed me 'add SSO' as the ask, but that feels like a solution dressed up as a requirement. what's the real underlying problem here?", "should_trigger": true},
|
| 15 |
+
{"query": "everyone keeps saying 'make the dashboard better' and it's going nowhere because it's so broad. reshape it into an actual problem we could solve", "should_trigger": true},
|
| 16 |
+
{"query": "'enterprise customers churn' is one giant blob. split it into a few separate problems that are each small enough to build for", "should_trigger": true},
|
| 17 |
+
|
| 18 |
+
{"query": "i have a pile of 30 user-interview transcripts in a folder, pull out the main themes and insights for me", "should_trigger": false},
|
| 19 |
+
{"query": "just got back from 12 customer interviews, here are my raw notes, help me make sense of them and pull out themes", "should_trigger": false},
|
| 20 |
+
{"query": "we ran a survey and got 400 open-text responses in a csv, synthesize them into key insights ranked by frequency", "should_trigger": false},
|
| 21 |
+
{"query": "here's a dump of 200 support tickets exported from zendesk, what are the common themes and what should we prioritize", "should_trigger": false},
|
| 22 |
+
{"query": "pull the recurring complaints from zendesk, our g2 reviews, and the churn survey and grade how solid each signal is", "should_trigger": false},
|
| 23 |
+
{"query": "rank these 8 feature ideas by what's most worth doing, we have analytics and support data", "should_trigger": false},
|
| 24 |
+
{"query": "update our Now/Next/Later roadmap, move the billing rework to Next and add the SSO epic to Now", "should_trigger": false},
|
| 25 |
+
{"query": "review our north-star and activation metrics for the month and flag what moved", "should_trigger": false},
|
| 26 |
+
{"query": "let's brainstorm some new directions for our analytics product, i want a sharp thinking partner", "should_trigger": false},
|
| 27 |
+
{"query": "draft the opportunity brief for the notifications problem, both the narrative and the FAQ version", "should_trigger": false}
|
| 28 |
+
]
|
product-eval/evals/trigger/to-build-brief.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"query": "the SSO bet got approved, can you turn it into a spec i can hand straight to claude code?",
|
| 4 |
+
"should_trigger": true
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"query": "the notifications brief got approved yesterday — make it buildable, give me an agent-ready build spec",
|
| 8 |
+
"should_trigger": true
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"query": "convert our approved opportunity brief into a build spec with given/when/then acceptance criteria",
|
| 12 |
+
"should_trigger": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"query": "we signed off on the csv export bet — strip the prose and emit a structured spec claude code can just execute",
|
| 16 |
+
"should_trigger": true
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"query": "run the design mode on the approved onboarding decision so i can hand the screen-by-screen breakdown to figma",
|
| 20 |
+
"should_trigger": true
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"query": "we greenlit the billing rework, now produce the implementation spec for an AI builder with scope in/out and an MVP slice first",
|
| 24 |
+
"should_trigger": true
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"query": "take this approved brief and make a figma-ready spec: every screen, its empty/loading/error states, and the primary CTA per view",
|
| 28 |
+
"should_trigger": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"query": "decision's been signed off, just give me a literal testable build doc to drop into codex, no narrative",
|
| 32 |
+
"should_trigger": true
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"query": "hand this approved billing brief to claude code with the data model, edge cases, success metrics and instrumentation",
|
| 36 |
+
"should_trigger": true
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"query": "it passed readiness last week, can you turn it into something an agent can actually build from?",
|
| 40 |
+
"should_trigger": true
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"query": "the export feature got the go-ahead — break it into screens and states for our designer to mock in figma",
|
| 44 |
+
"should_trigger": true
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"query": "write a PRD for the new CSV export feature so engineering can pick it up",
|
| 48 |
+
"should_trigger": false
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"query": "draft a feature spec with goals, non-goals and acceptance criteria so the devs can start the export work",
|
| 52 |
+
"should_trigger": false
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"query": "draft the opportunity brief for the notifications problem, both the narrative and the FAQ version",
|
| 56 |
+
"should_trigger": false
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"query": "write up the human-readable brief for the SSO opportunity — problem, why now, impact, the ask",
|
| 60 |
+
"should_trigger": false
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"query": "write a decision memo for the SSO bet — options, falsifiable criteria, metrics, the ask and a deadline",
|
| 64 |
+
"should_trigger": false
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"query": "put together the memo so leadership can decide on billing rework: the options, what would prove us wrong, and the deadline",
|
| 68 |
+
"should_trigger": false
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"query": "is it worth building SSO before our enterprise push? do we even have the evidence to call it yet?",
|
| 72 |
+
"should_trigger": false
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"query": "poke holes in our Q3 roadmap and the export PRD before the leadership review on friday",
|
| 76 |
+
"should_trigger": false
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"query": "update our Now/Next/Later roadmap, move the billing rework to Next and add the SSO epic to Now",
|
| 80 |
+
"should_trigger": false
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"query": "implement this approved figma design as react code for the onboarding flow",
|
| 84 |
+
"should_trigger": false
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"query": "i have a pile of 30 user-interview transcripts in a folder, pull out the main themes and insights for me",
|
| 88 |
+
"should_trigger": false
|
| 89 |
+
}
|
| 90 |
+
]
|
product-eval/evals/trigger/write-brief.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{"query": "draft the opportunity brief for the notifications problem, both the narrative and the FAQ version", "should_trigger": true},
|
| 3 |
+
{"query": "write the opportunity brief for the onboarding pain now that it passed the readiness gate", "should_trigger": true},
|
| 4 |
+
{"query": "draft the narrative version of the brief: problem, why now, impact, the ask", "should_trigger": true},
|
| 5 |
+
{"query": "write the FAQ version of the brief for the billing opportunity", "should_trigger": true},
|
| 6 |
+
{"query": "put together the human decision doc for leadership on the SSO opportunity", "should_trigger": true},
|
| 7 |
+
{"query": "we decided to move forward, write up the brief that explains the problem and what we're asking for", "should_trigger": true},
|
| 8 |
+
{"query": "turn this investigation into an opportunity brief i can circulate to the exec team", "should_trigger": true},
|
| 9 |
+
{"query": "write the brief: problem statement, why-now, expected impact, and the ask", "should_trigger": true},
|
| 10 |
+
{"query": "draft both versions of the opportunity brief for the churn problem, report and FAQ", "should_trigger": true},
|
| 11 |
+
{"query": "i need the opportunity brief for the analytics problem written up as a narrative for the team", "should_trigger": true},
|
| 12 |
+
{"query": "write the decision memo for the SSO bet, options, success/failure criteria, metrics scorecard, and an explicit ask for friday", "should_trigger": true},
|
| 13 |
+
{"query": "draft a recommendation memo on whether to build the in-app notifications center, weigh at least 3 options including do-nothing and recommend one", "should_trigger": true},
|
| 14 |
+
{"query": "i need an options memo for the onboarding rework: choices, tradeoffs, and what i'm asking the exec team to decide by july 15", "should_trigger": true},
|
| 15 |
+
{"query": "write the doc that forces a build-vs-buy call on the analytics pipeline, with options, what we'd measure, and a recommendation", "should_trigger": true},
|
| 16 |
+
|
| 17 |
+
{"query": "write a PRD for the new CSV export feature so engineering can pick it up", "should_trigger": false},
|
| 18 |
+
{"query": "turn this feature idea into a spec with goals, non-goals, and acceptance criteria for the eng team", "should_trigger": false},
|
| 19 |
+
{"query": "scope the bulk-export feature into a PRD with success metrics and phased milestones", "should_trigger": false},
|
| 20 |
+
{"query": "write the engineering spec for the new webhooks system so the devs can start", "should_trigger": false},
|
| 21 |
+
{"query": "turn the approved decision into a spec i can hand straight to claude code", "should_trigger": false},
|
| 22 |
+
{"query": "write the weekly stakeholder update for leadership about the platform migration", "should_trigger": false},
|
| 23 |
+
{"query": "give me a competitive brief on Linear vs Jira for our sales battlecard", "should_trigger": false},
|
| 24 |
+
{"query": "ok i've got ~200 intercom tickets exported and our amplitude funnel open, what should we actually build next quarter for onboarding", "should_trigger": false},
|
| 25 |
+
{"query": "review our north-star and activation metrics for the month and flag what moved", "should_trigger": false}
|
| 26 |
+
]
|
product-eval/evals/triggering.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"purpose": "Routing / collision evals. Each query maps to the skill that SHOULD win. 'anthropic-pm:*' and 'none' mark cases that must NOT trigger one of our skills (near-misses against Anthropic's product-management plugin). To run the per-skill description optimizer (skill-creator run_loop.py), transform per skill: queries whose expected == <skill> are should_trigger:true, all others false.",
|
| 3 |
+
"skills": ["start","discover-sources","gather-evidence","synthesize","prioritize-backlog","decision-readiness","design-test","pressure-test","critique","write-brief","to-build-brief","scorecard","drift-check","calibrate"],
|
| 4 |
+
"cases": [
|
| 5 |
+
{"id": 1, "query": "ok i've got ~200 intercom tickets exported and our amplitude funnel open — what should we actually build next quarter for onboarding?", "expected": "start", "note": "setup, then evaluate job and chains"},
|
| 6 |
+
{"id": 2, "query": "is it worth building SSO before our enterprise push? do we even have the data to call it?", "expected": "decision-readiness"},
|
| 7 |
+
{"id": 3, "query": "rank these 8 feature ideas by what's most worth doing — we have analytics + support data", "expected": "prioritize-backlog"},
|
| 8 |
+
{"id": 4, "query": "synthesize the evidence we just pulled into themes", "expected": "synthesize"},
|
| 9 |
+
{"id": 5, "query": "i have a pile of 30 user-interview transcripts in a folder, pull out the main themes and insights for me", "expected": "anthropic-pm:synthesize-research", "note": "raw research outside our pipeline — must NOT trigger synthesize"},
|
| 10 |
+
{"id": 6, "query": "poke holes in our Q3 roadmap before the leadership review on friday", "expected": "pressure-test"},
|
| 11 |
+
{"id": 7, "query": "let's brainstorm some new directions for our analytics product, i want a sharp thinking partner", "expected": "anthropic-pm:product-brainstorming", "note": "generative — must NOT trigger pressure-test/critique"},
|
| 12 |
+
{"id": 8, "query": "update our Now/Next/Later roadmap — move the billing rework to Next and add the SSO epic to Now", "expected": "anthropic-pm:roadmap-update", "note": "roadmap edit — must NOT trigger prioritize-backlog"},
|
| 13 |
+
{"id": 9, "query": "write a PRD for the new CSV export feature so engineering can pick it up", "expected": "anthropic-pm:write-spec", "note": "engineering spec — must NOT trigger write-brief"},
|
| 14 |
+
{"id": 10, "query": "draft the opportunity brief for the notifications problem — both the narrative and the FAQ version", "expected": "write-brief"},
|
| 15 |
+
{"id": 11, "query": "grade how crisp this problem statement is: 'onboarding is bad'", "expected": "critique", "note": "crispness grader"},
|
| 16 |
+
{"id": 12, "query": "what data do I even have to make product decisions? scan my connectors and tell me the confidence ceiling", "expected": "discover-sources"},
|
| 17 |
+
{"id": 13, "query": "i want to build something in the observability tooling space but not sure what — find the real problems worth solving", "expected": "start", "note": "explore job"},
|
| 18 |
+
{"id": 14, "query": "turn the approved decision into a spec i can hand straight to claude code", "expected": "to-build-brief"},
|
| 19 |
+
{"id": 15, "query": "has our top opportunity drifted since last month? did confidence actually improve or are we spinning?", "expected": "drift-check"},
|
| 20 |
+
{"id": 16, "query": "the confidence numbers feel too generous — tune the thresholds against these 8 past launches we know the outcomes of", "expected": "calibrate"},
|
| 21 |
+
{"id": 17, "query": "give me a competitive brief on Linear vs Jira for our sales battlecard", "expected": "anthropic-pm:competitive-brief", "note": "must NOT trigger gather-evidence/pressure-test"},
|
| 22 |
+
{"id": 18, "query": "review our north-star and activation metrics for the month and flag what moved", "expected": "anthropic-pm:metrics-review", "note": "must NOT trigger drift-check"},
|
| 23 |
+
{"id": 19, "query": "write the weekly stakeholder update for leadership about the platform migration", "expected": "anthropic-pm:stakeholder-update", "note": "none of ours"},
|
| 24 |
+
{"id": 20, "query": "pull the recurring complaints from zendesk, our g2 reviews, and the churn survey and grade how solid each signal is", "expected": "gather-evidence"},
|
| 25 |
+
{"id": 21, "query": "decision-readiness says run a research sprint for SSO — design the cheapest test to close the gap", "expected": "design-test"},
|
| 26 |
+
{"id": 22, "query": "make a scorecard from the ranked opportunities in this product-eval scope", "expected": "scorecard"},
|
| 27 |
+
{"id": 23, "query": "write the decision memo for the SSO bet — options, metrics, falsifiable criteria, and the explicit ask", "expected": "write-brief"},
|
| 28 |
+
{"id": 24, "query": "what should we build next for activation if we have a csv of support tickets and some funnel data?", "expected": "start", "note": "Rank opportunities outcome with setup"},
|
| 29 |
+
{"id": 25, "query": "users keep dropping off somewhere in signup; turn that into a real problem statement", "expected": "synthesize", "note": "problem framing is now inside synthesize"},
|
| 30 |
+
{"id": 26, "query": "set up product-eval for my product", "expected": "start", "note": "first-run onboarding"},
|
| 31 |
+
{"id": 27, "query": "help me prepare a decision report and ask me what context you need first", "expected": "start", "note": "write outcome but missing source/audience setup"}
|
| 32 |
+
]
|
| 33 |
+
}
|
product-eval/examples/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Examples
|
| 2 |
+
|
| 3 |
+
## `activation-q3/`: a complete sample investigation
|
| 4 |
+
|
| 5 |
+
A synthetic, self-contained investigation scope for the fictional product "Pulse" (a B2B product-analytics workspace). It mirrors exactly what the plugin writes to `.product-eval/<scope>/` in a real project, and it serves two purposes:
|
| 6 |
+
|
| 7 |
+
1. **A `scorecard` reference output.** `activation-q3/scorecard.html` is the rendered decision scorecard for this scope: open it in a browser to see the KPI cards, the Value by Confidence quadrant, the four color-coded verdict cards (with verbatim quotes, top complaint, the ask, and "why it ranks here"), the glossary, and the honest footer.
|
| 8 |
+
2. **A conformance fixture.** Every file conforms to `DATA-CONTRACT.md`, and every number was computed from the shipped scoring defaults, so it is the fixture the validation preflight (and `scripts/validate_scope.py`) is tested against.
|
| 9 |
+
|
| 10 |
+
### What's inside
|
| 11 |
+
|
| 12 |
+
| File | Role |
|
| 13 |
+
|---|---|
|
| 14 |
+
| `context.md` | scope front-matter (product, north star, personas) |
|
| 15 |
+
| `evidence/E1.md` ... `E12.md` | 12 normalized, weighted evidence items (E12 is a flagged contradiction) |
|
| 16 |
+
| `identities.md` | resolved cross-system identities (same account across Zendesk + CRM + analytics; same email across Zendesk + CRM) |
|
| 17 |
+
| `themes.md` | 4 problem-framed themes with computed confidence |
|
| 18 |
+
| `scores.md` | Value/Confidence and a recommendation per theme |
|
| 19 |
+
| `decisions-log.md` | readiness verdicts (append-only) |
|
| 20 |
+
| `scorecard.html` | the rendered scorecard |
|
| 21 |
+
|
| 22 |
+
### The four opportunities (one of each verdict)
|
| 23 |
+
|
| 24 |
+
| Theme | Value | Confidence | Verdict |
|
| 25 |
+
|---|---|---|---|
|
| 26 |
+
| T1 New admins can't finish setup without CS help | 72 (High) | 89 (High) | **Decide now** |
|
| 27 |
+
| T2 Teams can't share saved views across the org | 70 (High) | 63 (Moderate) | **Run a research sprint** |
|
| 28 |
+
| T3 Alert noise pushes users to mute critical alerts | 60 (Moderate) | 24 (Low) | **Do not commit yet** |
|
| 29 |
+
| T4 Users want a dark-mode dashboard | 35 (Low) | 12 (Low) | **Deprioritize** |
|
| 30 |
+
|
| 31 |
+
T3 shows how a directly contradicting first-party signal (E12) drives confidence below the gate even when value is real.
|
| 32 |
+
|
| 33 |
+
### Verify it
|
| 34 |
+
|
| 35 |
+
```
|
| 36 |
+
python ../scripts/validate_scope.py activation-q3/ # -> OK (needs PyYAML)
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
All numbers are illustrative. No real customer data.
|
product-eval/examples/activation-q3/context.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
scope: activation-q3
|
| 3 |
+
job: evaluate
|
| 4 |
+
stage: evaluate
|
| 5 |
+
product: "Pulse, a B2B product-analytics workspace for SaaS teams"
|
| 6 |
+
north_star: "weekly activated workspaces"
|
| 7 |
+
personas: [admin, end_user, buyer]
|
| 8 |
+
updated: 2026-06-29
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
Synthetic example investigation shipped with the product-eval plugin. All numbers
|
| 12 |
+
are illustrative and were computed from the shipped scoring defaults so the files
|
| 13 |
+
can double as a validation fixture. No real customer data.
|
product-eval/examples/activation-q3/decisions-log.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Decisions log for activation-q3 (append-only)
|
| 2 |
+
|
| 3 |
+
- date: 2026-06-29
|
| 4 |
+
item: T1
|
| 5 |
+
event: readiness
|
| 6 |
+
verdict: "Decide now"
|
| 7 |
+
confidence: 89
|
| 8 |
+
confidence_band: high
|
| 9 |
+
evidence: [E1, E2, E3, E4]
|
| 10 |
+
open: ["which connector is worst", "trial-spam check on the 38%"]
|
| 11 |
+
contested: []
|
| 12 |
+
note: "Passed the sufficiency gate; first-party analytics + tickets + interviews + churn agree."
|
| 13 |
+
|
| 14 |
+
- date: 2026-06-29
|
| 15 |
+
item: T2
|
| 16 |
+
event: readiness
|
| 17 |
+
verdict: "Run a research sprint"
|
| 18 |
+
confidence: 63
|
| 19 |
+
confidence_band: moderate
|
| 20 |
+
evidence: [E5, E6, E7]
|
| 21 |
+
open: ["how many seats would share", "no first-party re-creation data"]
|
| 22 |
+
contested: []
|
| 23 |
+
note: "High value, but the cheapest validating test should run before committing (see design-test)."
|
| 24 |
+
|
| 25 |
+
- date: 2026-06-29
|
| 26 |
+
item: T3
|
| 27 |
+
event: readiness
|
| 28 |
+
verdict: "Do not commit yet"
|
| 29 |
+
confidence: 24
|
| 30 |
+
confidence_band: low
|
| 31 |
+
evidence: [E8, E9]
|
| 32 |
+
open: ["measure actual mute-rate"]
|
| 33 |
+
contested: [E12]
|
| 34 |
+
note: "Hypothesis contradicted by first-party analytics; do not act until measured."
|
product-eval/examples/activation-q3/evidence/E1.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E1
|
| 3 |
+
claim: "38% of new workspaces never finish setup, dropping at the data-source connection step (up from 24% last quarter)"
|
| 4 |
+
source_type: product_analytics
|
| 5 |
+
source_ref: "Amplitude > Activation funnel"
|
| 6 |
+
persona: [admin]
|
| 7 |
+
funnel_stage: activation
|
| 8 |
+
impact_type: activation
|
| 9 |
+
strength: 5
|
| 10 |
+
recency_days: 20
|
| 11 |
+
weight: 12
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: acct_acme
|
| 14 |
+
corroborated_by: [E2, E3]
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
Funnel: signup to first-connected-source. The cliff is the integrations step, not signup.
|
product-eval/examples/activation-q3/evidence/E10.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E10
|
| 3 |
+
claim: "6 scattered requests for a dark-mode dashboard over the past year"
|
| 4 |
+
source_type: feature_request
|
| 5 |
+
source_ref: "Productboard > misc (6 requests)"
|
| 6 |
+
persona: [end_user]
|
| 7 |
+
funnel_stage: engagement
|
| 8 |
+
impact_type: engagement
|
| 9 |
+
strength: 2
|
| 10 |
+
recency_days: 300
|
| 11 |
+
weight: 1
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: null
|
| 14 |
+
corroborated_by: []
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
Low frequency, spread thin over 12 months.
|
product-eval/examples/activation-q3/evidence/E11.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E11
|
| 3 |
+
claim: "Occasional app-store style reviews ask for dark mode"
|
| 4 |
+
source_type: app_review
|
| 5 |
+
source_ref: "Capterra (sparse)"
|
| 6 |
+
persona: [end_user]
|
| 7 |
+
funnel_stage: engagement
|
| 8 |
+
impact_type: engagement
|
| 9 |
+
strength: 2
|
| 10 |
+
recency_days: 200
|
| 11 |
+
weight: 1
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: null
|
| 14 |
+
corroborated_by: []
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
Aesthetic preference, no business-pain signal.
|
product-eval/examples/activation-q3/evidence/E12.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E12
|
| 3 |
+
claim: "Alert-channel engagement is flat quarter over quarter, not declining"
|
| 4 |
+
source_type: product_analytics
|
| 5 |
+
source_ref: "Amplitude > Alerts engagement"
|
| 6 |
+
persona: [end_user]
|
| 7 |
+
funnel_stage: engagement
|
| 8 |
+
impact_type: engagement
|
| 9 |
+
strength: 4
|
| 10 |
+
recency_days: 25
|
| 11 |
+
weight: 7
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: null
|
| 14 |
+
corroborated_by: []
|
| 15 |
+
stale: false
|
| 16 |
+
contradicts: [E8]
|
| 17 |
+
---
|
| 18 |
+
Direct first-party data that contradicts the "users are muting alerts" hypothesis (E8).
|
| 19 |
+
Kept and flagged: this is the unresolved material contradiction that drives T3's confidence penalty.
|
product-eval/examples/activation-q3/evidence/E2.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E2
|
| 3 |
+
claim: "Admins get stuck at the data-source connection step and open tickets to finish setup"
|
| 4 |
+
source_type: support_ticket
|
| 5 |
+
source_ref: "Zendesk > tag:onboarding (27 tickets / 6 weeks)"
|
| 6 |
+
persona: [admin]
|
| 7 |
+
funnel_stage: activation
|
| 8 |
+
impact_type: activation
|
| 9 |
+
strength: 4
|
| 10 |
+
recency_days: 30
|
| 11 |
+
weight: 7
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: acct_acme
|
| 14 |
+
corroborated_by: [E1, E3]
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
"I connected Postgres but nothing shows up, what am I missing?" Recurring across 27 tickets.
|
product-eval/examples/activation-q3/evidence/E3.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E3
|
| 3 |
+
claim: "In 4 onboarding calls, admins needed CS hand-holding to complete setup"
|
| 4 |
+
source_type: customer_interview
|
| 5 |
+
source_ref: "Onboarding calls (4 accounts)"
|
| 6 |
+
persona: [admin]
|
| 7 |
+
funnel_stage: activation
|
| 8 |
+
impact_type: activation
|
| 9 |
+
strength: 4
|
| 10 |
+
recency_days: 15
|
| 11 |
+
weight: 7
|
| 12 |
+
person_id: person_jordan
|
| 13 |
+
account_id: acct_acme
|
| 14 |
+
corroborated_by: [E1, E2]
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
"We almost gave up before your CS person walked us through the connectors."
|
product-eval/examples/activation-q3/evidence/E4.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E4
|
| 3 |
+
claim: "3 churned accounts named 'never got it set up' as the reason for leaving"
|
| 4 |
+
source_type: churn_survey
|
| 5 |
+
source_ref: "Churn survey Q2 (3 of 11 responses)"
|
| 6 |
+
persona: [admin, buyer]
|
| 7 |
+
funnel_stage: retention
|
| 8 |
+
impact_type: retention
|
| 9 |
+
strength: 4
|
| 10 |
+
recency_days: 120
|
| 11 |
+
weight: 5
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: null
|
| 14 |
+
corroborated_by: []
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
Setup friction reads through to retention, not just activation.
|
product-eval/examples/activation-q3/evidence/E5.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E5
|
| 3 |
+
claim: "19 feature requests asking for views/dashboards shared across the whole org"
|
| 4 |
+
source_type: feature_request
|
| 5 |
+
source_ref: "Productboard > top requests"
|
| 6 |
+
persona: [admin, end_user]
|
| 7 |
+
funnel_stage: expansion
|
| 8 |
+
impact_type: expansion
|
| 9 |
+
strength: 3
|
| 10 |
+
recency_days: 25
|
| 11 |
+
weight: 4
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: null
|
| 14 |
+
corroborated_by: [E6, E7]
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
Today views are per-user; teams rebuild the same view repeatedly.
|
product-eval/examples/activation-q3/evidence/E6.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E6
|
| 3 |
+
claim: "Two mid-market prospects asked about org-shared views during deals"
|
| 4 |
+
source_type: sales_call
|
| 5 |
+
source_ref: "Gong > deal notes (2 deals)"
|
| 6 |
+
persona: [buyer]
|
| 7 |
+
funnel_stage: expansion
|
| 8 |
+
impact_type: competitive
|
| 9 |
+
strength: 4
|
| 10 |
+
recency_days: 18
|
| 11 |
+
weight: 7
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: acct_northwind
|
| 14 |
+
corroborated_by: [E5]
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
Raised as a 'will our team adopt this' question, an expansion signal.
|
product-eval/examples/activation-q3/evidence/E7.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E7
|
| 3 |
+
claim: "A G2 review wants team-shared saved views"
|
| 4 |
+
source_type: app_review
|
| 5 |
+
source_ref: "G2 review (4-star)"
|
| 6 |
+
persona: [end_user]
|
| 7 |
+
funnel_stage: expansion
|
| 8 |
+
impact_type: competitive
|
| 9 |
+
strength: 3
|
| 10 |
+
recency_days: 140
|
| 11 |
+
weight: 3
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: null
|
| 14 |
+
corroborated_by: [E5]
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
"Love it solo, but my team can't see my views."
|
product-eval/examples/activation-q3/evidence/E8.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E8
|
| 3 |
+
claim: "CS suspects users mute alert channels because of noise; one large account muted everything"
|
| 4 |
+
source_type: internal_observation
|
| 5 |
+
source_ref: "CS Slack thread + 1 account"
|
| 6 |
+
persona: [end_user]
|
| 7 |
+
funnel_stage: retention
|
| 8 |
+
impact_type: retention
|
| 9 |
+
strength: 3
|
| 10 |
+
recency_days: 22
|
| 11 |
+
weight: 4
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: acct_acme
|
| 14 |
+
corroborated_by: []
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
Hypothesis, not measured. Flagged as contradicted by E-contra below.
|
product-eval/examples/activation-q3/evidence/E9.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
id: E9
|
| 3 |
+
claim: "A low-engagement community thread complains about alert spam"
|
| 4 |
+
source_type: community_post
|
| 5 |
+
source_ref: "Reddit r/devops (low engagement)"
|
| 6 |
+
persona: [end_user]
|
| 7 |
+
funnel_stage: engagement
|
| 8 |
+
impact_type: cost
|
| 9 |
+
strength: 2
|
| 10 |
+
recency_days: 150
|
| 11 |
+
weight: 1
|
| 12 |
+
person_id: null
|
| 13 |
+
account_id: null
|
| 14 |
+
corroborated_by: []
|
| 15 |
+
stale: false
|
| 16 |
+
---
|
| 17 |
+
Thin signal; included for completeness.
|
product-eval/examples/activation-q3/identities.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Resolved identities for activation-q3
|
| 2 |
+
# Shows the cross-system mapping: the same account/person stitched across
|
| 3 |
+
# Zendesk + CRM + analytics so multi-touchpoint signal collapses to one entity.
|
| 4 |
+
|
| 5 |
+
- entity: acct_acme
|
| 6 |
+
grain: account
|
| 7 |
+
matched_records: [zendesk:org_1183, hubspot:acct_55, amplitude:grp_acme]
|
| 8 |
+
method: email_domain # acme.io
|
| 9 |
+
match_confidence: high
|
| 10 |
+
# Appears in E1 (analytics), E2 (ticket), E3 (interview), E8 (observation):
|
| 11 |
+
# one account, four touchpoints, escalating -> a severity signal, not four voices.
|
| 12 |
+
|
| 13 |
+
- entity: person_jordan
|
| 14 |
+
grain: person
|
| 15 |
+
matched_records: [zendesk:user_991, hubspot:contact_77]
|
| 16 |
+
method: email # jordan@acme.io present verbatim in both systems
|
| 17 |
+
match_confidence: high
|
| 18 |
+
# The canonical case: same email in a Zendesk ticket AND the CRM -> one person,
|
| 19 |
+
# enriched with CRM context (admin at Acme, mid-market, renewal in 90 days).
|
| 20 |
+
|
| 21 |
+
- entity: acct_northwind
|
| 22 |
+
grain: account
|
| 23 |
+
matched_records: [gong:acct_nw, hubspot:acct_204]
|
| 24 |
+
method: email_domain # northwind.com
|
| 25 |
+
match_confidence: high
|
product-eval/examples/activation-q3/scorecard.html
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 6 |
+
<title>Decision Scorecard, activation-q3 (Pulse)</title>
|
| 7 |
+
<style>
|
| 8 |
+
:root{
|
| 9 |
+
--bg:#f7f8fa; --card:#ffffff; --ink:#15181d; --muted:#5b6471; --line:#e5e8ee;
|
| 10 |
+
--green:#16a34a; --green-bg:#e7f6ec; --amber:#c2780b; --amber-bg:#fdf3df;
|
| 11 |
+
--grey:#5b6471; --grey-bg:#eef0f4; --red:#dc2626; --red-bg:#fbe9e9;
|
| 12 |
+
--bar:#dfe3ea; --accent:#3b5bdb;
|
| 13 |
+
}
|
| 14 |
+
*{box-sizing:border-box}
|
| 15 |
+
body{margin:0;background:var(--bg);color:var(--ink);
|
| 16 |
+
font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}
|
| 17 |
+
.wrap{max-width:1040px;margin:0 auto;padding:28px 22px 60px}
|
| 18 |
+
header.top{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-end;gap:12px;margin-bottom:6px}
|
| 19 |
+
.brand{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);font-weight:700}
|
| 20 |
+
h1{font-size:24px;margin:4px 0 2px}
|
| 21 |
+
.sub{color:var(--muted);font-size:14px}
|
| 22 |
+
.summary{margin:14px 0 22px;padding:12px 16px;background:var(--card);border:1px solid var(--line);
|
| 23 |
+
border-radius:10px;font-size:14.5px}
|
| 24 |
+
.summary b{font-weight:650}
|
| 25 |
+
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-bottom:22px}
|
| 26 |
+
.kpi{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:14px 16px}
|
| 27 |
+
.kpi .n{font-size:26px;font-weight:700;line-height:1.1}
|
| 28 |
+
.kpi .l{font-size:12.5px;color:var(--muted);margin-top:3px}
|
| 29 |
+
.kpi .dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:6px;vertical-align:middle}
|
| 30 |
+
.panel{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:18px 20px;margin-bottom:22px}
|
| 31 |
+
.panel h2{font-size:16px;margin:0 0 4px}
|
| 32 |
+
.panel .hint{color:var(--muted);font-size:13px;margin:0 0 12px}
|
| 33 |
+
.quad-flex{display:flex;flex-wrap:wrap;gap:18px;align-items:center}
|
| 34 |
+
.legend{font-size:13px;min-width:190px}
|
| 35 |
+
.legend div{margin:6px 0;display:flex;align-items:center;gap:8px}
|
| 36 |
+
.sw{width:12px;height:12px;border-radius:3px;display:inline-block}
|
| 37 |
+
.toolbar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:14px}
|
| 38 |
+
.toolbar span{font-size:13px;color:var(--muted);margin-right:2px}
|
| 39 |
+
.toolbar button{font:inherit;font-size:13px;border:1px solid var(--line);background:var(--card);
|
| 40 |
+
color:var(--ink);border-radius:999px;padding:5px 12px;cursor:pointer}
|
| 41 |
+
.toolbar button.active{background:var(--ink);color:#fff;border-color:var(--ink)}
|
| 42 |
+
.card{background:var(--card);border:1px solid var(--line);border-left-width:5px;border-radius:10px;
|
| 43 |
+
padding:16px 18px;margin-bottom:14px}
|
| 44 |
+
.card .row1{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px;align-items:baseline}
|
| 45 |
+
.card h3{font-size:17px;margin:0}
|
| 46 |
+
.verdict{font-size:12.5px;font-weight:700;padding:3px 10px;border-radius:999px;white-space:nowrap}
|
| 47 |
+
.bands{display:flex;flex-wrap:wrap;gap:18px;margin:12px 0 6px}
|
| 48 |
+
.band{min-width:150px;flex:1}
|
| 49 |
+
.band .lab{font-size:12px;color:var(--muted);display:flex;justify-content:space-between}
|
| 50 |
+
.band .barwrap{height:8px;background:var(--bar);border-radius:6px;margin-top:4px;overflow:hidden}
|
| 51 |
+
.band .fill{height:100%;border-radius:6px}
|
| 52 |
+
.band .bandname{font-weight:650;font-size:13.5px}
|
| 53 |
+
.meta{display:flex;flex-wrap:wrap;gap:16px;font-size:13px;color:var(--muted);margin:8px 0 10px}
|
| 54 |
+
.meta b{color:var(--ink);font-weight:650}
|
| 55 |
+
blockquote{margin:10px 0;padding:8px 14px;border-left:3px solid var(--line);
|
| 56 |
+
background:#fafbfc;color:#2c313a;font-style:italic;border-radius:0 6px 6px 0;font-size:13.5px}
|
| 57 |
+
.pa{font-size:13.5px;margin:6px 0}
|
| 58 |
+
.pa .k{font-weight:650}
|
| 59 |
+
.why{font-size:13.5px;margin:10px 0 4px;padding:8px 12px;background:#f3f6ff;border-radius:7px}
|
| 60 |
+
.gaps{font-size:13px;color:var(--muted);margin-top:8px}
|
| 61 |
+
.gaps .k{font-weight:650;color:var(--ink)}
|
| 62 |
+
details.glossary{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:6px 20px;margin-bottom:22px}
|
| 63 |
+
details.glossary summary{cursor:pointer;font-weight:650;padding:12px 0;font-size:15px}
|
| 64 |
+
details.glossary dl{margin:0 0 12px}
|
| 65 |
+
details.glossary dt{font-weight:650;margin-top:10px;font-size:13.5px}
|
| 66 |
+
details.glossary dd{margin:2px 0 0;color:var(--muted);font-size:13.5px}
|
| 67 |
+
footer.honest{background:#10141b;color:#e7eaf0;border-radius:12px;padding:18px 20px;font-size:14px}
|
| 68 |
+
footer.honest b{color:#fff}
|
| 69 |
+
footer.honest .move{margin-top:8px;color:#aeb7c6}
|
| 70 |
+
.tag{font-size:11.5px;color:var(--muted)}
|
| 71 |
+
@media(max-width:560px){.bands{gap:10px}}
|
| 72 |
+
</style>
|
| 73 |
+
</head>
|
| 74 |
+
<body>
|
| 75 |
+
<div class="wrap">
|
| 76 |
+
<header class="top">
|
| 77 |
+
<div>
|
| 78 |
+
<div class="brand">product-eval / decision scorecard</div>
|
| 79 |
+
<h1>activation-q3</h1>
|
| 80 |
+
<div class="sub">Pulse, a B2B product-analytics workspace. North star: weekly activated workspaces. Generated 2026-06-29.</div>
|
| 81 |
+
</div>
|
| 82 |
+
</header>
|
| 83 |
+
|
| 84 |
+
<div class="summary" id="summary"></div>
|
| 85 |
+
|
| 86 |
+
<div class="kpis" id="kpis"></div>
|
| 87 |
+
|
| 88 |
+
<div class="panel">
|
| 89 |
+
<h2>Value × Confidence</h2>
|
| 90 |
+
<p class="hint">Each opportunity is plotted by how big it could be (Value, vertical) against how sure we are it is real (Confidence, horizontal). The gate lines sit at 70. The top-right box is where a bet is both worth it and proven enough to commit.</p>
|
| 91 |
+
<div class="quad-flex">
|
| 92 |
+
<svg viewBox="0 0 480 380" width="480" height="380" role="img" aria-label="Value by Confidence quadrant">
|
| 93 |
+
<!-- quadrant tints -->
|
| 94 |
+
<rect x="337" y="16" width="79" height="97" fill="var(--green-bg)"></rect>
|
| 95 |
+
<rect x="46" y="16" width="291" height="97" fill="#fcfcfd"></rect>
|
| 96 |
+
<!-- axes -->
|
| 97 |
+
<line x1="46" y1="16" x2="46" y2="340" stroke="var(--line)"></line>
|
| 98 |
+
<line x1="46" y1="340" x2="464" y2="340" stroke="var(--line)"></line>
|
| 99 |
+
<!-- gate lines at 70 -->
|
| 100 |
+
<line x1="337" y1="16" x2="337" y2="340" stroke="#c8ccd6" stroke-dasharray="4 4"></line>
|
| 101 |
+
<line x1="46" y1="113" x2="464" y2="113" stroke="#c8ccd6" stroke-dasharray="4 4"></line>
|
| 102 |
+
<text x="341" y="30" font-size="10" fill="#9aa1ad">conf gate 70</text>
|
| 103 |
+
<text x="50" y="110" font-size="10" fill="#9aa1ad">value 70</text>
|
| 104 |
+
<!-- axis labels -->
|
| 105 |
+
<text x="255" y="366" font-size="12" fill="#5b6471" text-anchor="middle">Confidence →</text>
|
| 106 |
+
<text x="14" y="180" font-size="12" fill="#5b6471" text-anchor="middle" transform="rotate(-90 14 180)">Value →</text>
|
| 107 |
+
<text x="46" y="356" font-size="10" fill="#9aa1ad" text-anchor="middle">0</text>
|
| 108 |
+
<text x="464" y="356" font-size="10" fill="#9aa1ad" text-anchor="middle">100</text>
|
| 109 |
+
<!-- points -->
|
| 110 |
+
<g>
|
| 111 |
+
<circle cx="416" cy="107" r="8" fill="var(--green)"></circle>
|
| 112 |
+
<text x="416" y="96" font-size="11" fill="#15181d" text-anchor="middle" font-weight="700">T1</text>
|
| 113 |
+
<circle cx="308" cy="113" r="8" fill="var(--amber)"></circle>
|
| 114 |
+
<text x="304" y="102" font-size="11" fill="#15181d" text-anchor="end" font-weight="700">T2</text>
|
| 115 |
+
<circle cx="146" cy="146" r="8" fill="var(--grey)"></circle>
|
| 116 |
+
<text x="146" y="135" font-size="11" fill="#15181d" text-anchor="middle" font-weight="700">T3</text>
|
| 117 |
+
<circle cx="96" cy="227" r="8" fill="var(--red)"></circle>
|
| 118 |
+
<text x="96" y="216" font-size="11" fill="#15181d" text-anchor="middle" font-weight="700">T4</text>
|
| 119 |
+
</g>
|
| 120 |
+
</svg>
|
| 121 |
+
<div class="legend">
|
| 122 |
+
<div><span class="sw" style="background:var(--green)"></span> Decide now</div>
|
| 123 |
+
<div><span class="sw" style="background:var(--amber)"></span> Run a research sprint</div>
|
| 124 |
+
<div><span class="sw" style="background:var(--grey)"></span> Do not commit yet</div>
|
| 125 |
+
<div><span class="sw" style="background:var(--red)"></span> Deprioritize</div>
|
| 126 |
+
</div>
|
| 127 |
+
</div>
|
| 128 |
+
</div>
|
| 129 |
+
|
| 130 |
+
<div class="toolbar">
|
| 131 |
+
<span>Sort by</span>
|
| 132 |
+
<button data-sort="tier" class="active">Recommendation</button>
|
| 133 |
+
<button data-sort="value">Value</button>
|
| 134 |
+
<button data-sort="confidence">Confidence</button>
|
| 135 |
+
<button data-sort="weight">Evidence weight</button>
|
| 136 |
+
</div>
|
| 137 |
+
|
| 138 |
+
<div id="cards"></div>
|
| 139 |
+
|
| 140 |
+
<details class="glossary">
|
| 141 |
+
<summary>How to read this</summary>
|
| 142 |
+
<dl>
|
| 143 |
+
<dt>Value (0 to 100)</dt>
|
| 144 |
+
<dd>If this problem is real, how big is it? Built from persona weight, funnel location, frequency, and competitive pressure (each 0 to 25). It is about potential impact, not certainty.</dd>
|
| 145 |
+
<dt>Confidence (0 to 100)</dt>
|
| 146 |
+
<dd>How sure are we the problem is real and worth acting on? Computed from total evidence weight, source-type diversity, and unresolved contradictions. Reported as a band (Low / Moderate / High); the number is for audit.</dd>
|
| 147 |
+
<dt>Evidence weight</dt>
|
| 148 |
+
<dd>Quality-weighted volume of evidence, deduplicated by account. Three strong first-party findings outweigh fifty vague mentions, so weight, not raw count, drives Confidence.</dd>
|
| 149 |
+
<dt>Accounts affected</dt>
|
| 150 |
+
<dd>Distinct accounts after identity resolution (one customer across Zendesk, CRM, and analytics counts once), so a single loud account is not mistaken for a widespread problem.</dd>
|
| 151 |
+
<dt>The recommendation tiers</dt>
|
| 152 |
+
<dd><b>Decide now</b>: worth building and well supported. <b>Run a research sprint</b>: high value but needs more proof, design the cheapest validating test. <b>Do not commit yet</b>: too unproven to act on. <b>Deprioritize</b>: prize too small to pursue.</dd>
|
| 153 |
+
</dl>
|
| 154 |
+
</details>
|
| 155 |
+
|
| 156 |
+
<footer class="honest" id="footer"></footer>
|
| 157 |
+
</div>
|
| 158 |
+
|
| 159 |
+
<script>
|
| 160 |
+
const CEILING = "Decide-now reachable: first-party analytics, support tickets, and CRM are connected.";
|
| 161 |
+
const DATA = [
|
| 162 |
+
{
|
| 163 |
+
id:"T1", tier:1, verdict:"Decide now", color:"green",
|
| 164 |
+
name:"New admins can't finish workspace setup without CS help",
|
| 165 |
+
value:72, valueBand:"High", confidence:89, confBand:"High",
|
| 166 |
+
weight:31, accounts:9, sources:4,
|
| 167 |
+
quote:"We almost gave up before your CS person walked us through the connectors.",
|
| 168 |
+
quoteSrc:"onboarding call, admin at Acme",
|
| 169 |
+
complaint:"38% of new workspaces never finish setup, dropping at the data-source connection step (up from 24% last quarter).",
|
| 170 |
+
ask:"Guided or auto-detected connector setup so an admin can finish without opening a ticket.",
|
| 171 |
+
why:"Ranks top-right: an activation cliff on the north-star path, corroborated across analytics, tickets, interviews, and churn. The score earns a commit.",
|
| 172 |
+
gaps:["Which connector is worst (Postgres vs Snowflake)?","Is the 38% inflated by trial spam?"]
|
| 173 |
+
},
|
| 174 |
+
{
|
| 175 |
+
id:"T2", tier:2, verdict:"Run a research sprint", color:"amber",
|
| 176 |
+
name:"Teams can't share saved views across the org",
|
| 177 |
+
value:70, valueBand:"High", confidence:63, confBand:"Moderate",
|
| 178 |
+
weight:14, accounts:6, sources:3,
|
| 179 |
+
quote:"Love it solo, but my team can't see my views.",
|
| 180 |
+
quoteSrc:"G2 review, end user",
|
| 181 |
+
complaint:"Views are per-user today, so teams rebuild the same view over and over; raised in two live deals.",
|
| 182 |
+
ask:"Org-shared saved views and dashboards a team can all see.",
|
| 183 |
+
why:"High value and competitors already solved it, but there is no first-party usage data on how often views get re-created. Validate before committing.",
|
| 184 |
+
gaps:["How many seats would actually share a view?","No first-party data on view re-creation."]
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
id:"T3", tier:3, verdict:"Do not commit yet", color:"grey",
|
| 188 |
+
name:"Alert noise pushes users to mute critical alerts",
|
| 189 |
+
value:60, valueBand:"Moderate", confidence:24, confBand:"Low",
|
| 190 |
+
weight:5, accounts:2, sources:2,
|
| 191 |
+
quote:"People just mute the whole channel, then miss the one that mattered.",
|
| 192 |
+
quoteSrc:"CS internal observation",
|
| 193 |
+
complaint:"Suspected that alert noise leads users to mute channels and miss critical alerts.",
|
| 194 |
+
ask:"Smarter alert grouping or quieter defaults so the signal survives.",
|
| 195 |
+
why:"Retention-relevant if true, but the core hypothesis is directly contradicted by first-party analytics (alert engagement is flat, not falling). Measure before acting.",
|
| 196 |
+
gaps:["No measured mute-rate.","Hypothesis (E8) directly contradicted by analytics (E12)."]
|
| 197 |
+
},
|
| 198 |
+
{
|
| 199 |
+
id:"T4", tier:4, verdict:"Deprioritize", color:"red",
|
| 200 |
+
name:"Users want a dark-mode dashboard",
|
| 201 |
+
value:35, valueBand:"Low", confidence:12, confBand:"Low",
|
| 202 |
+
weight:2, accounts:4, sources:2,
|
| 203 |
+
quote:"Would love a dark mode for late-night dashboards.",
|
| 204 |
+
quoteSrc:"Capterra review, end user",
|
| 205 |
+
complaint:"Scattered requests for a dark-mode theme, six over the past year.",
|
| 206 |
+
ask:"A dark-mode theme for the dashboard.",
|
| 207 |
+
why:"A secondary-persona, engagement-only preference with no competitive pressure. The prize is too small to pursue now, regardless of confidence.",
|
| 208 |
+
gaps:["No business-impact signal.","Low frequency, spread over 12 months."]
|
| 209 |
+
}
|
| 210 |
+
];
|
| 211 |
+
|
| 212 |
+
const C = {
|
| 213 |
+
green:{ink:"var(--green)",bg:"var(--green-bg)"},
|
| 214 |
+
amber:{ink:"var(--amber)",bg:"var(--amber-bg)"},
|
| 215 |
+
grey:{ink:"var(--grey)",bg:"var(--grey-bg)"},
|
| 216 |
+
red:{ink:"var(--red)",bg:"var(--red-bg)"}
|
| 217 |
+
};
|
| 218 |
+
|
| 219 |
+
function bandColor(band){return band==="High"?"var(--green)":band==="Moderate"?"var(--amber)":"var(--grey)";}
|
| 220 |
+
|
| 221 |
+
function renderSummary(){
|
| 222 |
+
const n=DATA.length;
|
| 223 |
+
const by=t=>DATA.filter(d=>d.verdict===t).length;
|
| 224 |
+
document.getElementById("summary").innerHTML =
|
| 225 |
+
`<b>${n} opportunities</b>: ${by("Decide now")} Decide now, `+
|
| 226 |
+
`${by("Run a research sprint")} Run a research sprint, `+
|
| 227 |
+
`${by("Do not commit yet")} Do not commit yet, ${by("Deprioritize")} Deprioritize. `+
|
| 228 |
+
`Confidence ceiling: ${CEILING}`;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
function renderKpis(){
|
| 232 |
+
const by=t=>DATA.filter(d=>d.verdict===t).length;
|
| 233 |
+
const cards=[
|
| 234 |
+
{n:DATA.length,l:"Opportunities",dot:null},
|
| 235 |
+
{n:by("Decide now"),l:"Decide now",dot:"var(--green)"},
|
| 236 |
+
{n:by("Run a research sprint"),l:"Research sprint",dot:"var(--amber)"},
|
| 237 |
+
{n:by("Do not commit yet"),l:"Do not commit yet",dot:"var(--grey)"},
|
| 238 |
+
{n:by("Deprioritize"),l:"Deprioritize",dot:"var(--red)"}
|
| 239 |
+
];
|
| 240 |
+
document.getElementById("kpis").innerHTML = cards.map(c=>
|
| 241 |
+
`<div class="kpi"><div class="n">${c.n}</div><div class="l">${c.dot?`<span class="dot" style="background:${c.dot}"></span>`:""}${c.l}</div></div>`
|
| 242 |
+
).join("");
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
function card(d){
|
| 246 |
+
const c=C[d.color];
|
| 247 |
+
return `<div class="card" style="border-left-color:${c.ink}">
|
| 248 |
+
<div class="row1">
|
| 249 |
+
<h3>${d.id}. ${d.name}</h3>
|
| 250 |
+
<span class="verdict" style="color:${c.ink};background:${c.bg}">${d.verdict}</span>
|
| 251 |
+
</div>
|
| 252 |
+
<div class="bands">
|
| 253 |
+
<div class="band">
|
| 254 |
+
<div class="lab"><span>Value</span><span class="bandname" style="color:${bandColor(d.valueBand)}">${d.valueBand}</span></div>
|
| 255 |
+
<div class="barwrap"><div class="fill" style="width:${d.value}%;background:${bandColor(d.valueBand)}"></div></div>
|
| 256 |
+
<div class="tag">audit: ${d.value}/100</div>
|
| 257 |
+
</div>
|
| 258 |
+
<div class="band">
|
| 259 |
+
<div class="lab"><span>Confidence</span><span class="bandname" style="color:${bandColor(d.confBand)}">${d.confBand}</span></div>
|
| 260 |
+
<div class="barwrap"><div class="fill" style="width:${d.confidence}%;background:${bandColor(d.confBand)}"></div></div>
|
| 261 |
+
<div class="tag">audit: ${d.confidence}/100</div>
|
| 262 |
+
</div>
|
| 263 |
+
</div>
|
| 264 |
+
<div class="meta">
|
| 265 |
+
<span><b>${d.weight}</b> evidence weight</span>
|
| 266 |
+
<span><b>${d.accounts}</b> accounts affected</span>
|
| 267 |
+
<span><b>${d.sources}</b> source types</span>
|
| 268 |
+
</div>
|
| 269 |
+
<blockquote>“${d.quote}” <span class="tag">(${d.quoteSrc})</span></blockquote>
|
| 270 |
+
<div class="pa"><span class="k">Top complaint:</span> ${d.complaint}</div>
|
| 271 |
+
<div class="pa"><span class="k">The ask:</span> ${d.ask}</div>
|
| 272 |
+
<div class="why"><b>Why it ranks here:</b> ${d.why}</div>
|
| 273 |
+
<div class="gaps"><span class="k">Open gaps:</span> ${d.gaps.join(" · ")}</div>
|
| 274 |
+
</div>`;
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
let sortKey="tier";
|
| 278 |
+
function renderCards(){
|
| 279 |
+
const arr=[...DATA].sort((a,b)=>{
|
| 280 |
+
if(sortKey==="tier") return a.tier-b.tier;
|
| 281 |
+
return b[sortKey]-a[sortKey];
|
| 282 |
+
});
|
| 283 |
+
document.getElementById("cards").innerHTML = arr.map(card).join("");
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
function renderFooter(){
|
| 287 |
+
const top=DATA.find(d=>d.tier===1)||DATA[0];
|
| 288 |
+
document.getElementById("footer").innerHTML =
|
| 289 |
+
`<b>Honest read.</b> Confidence ceiling: ${CEILING}<div class="move">`+
|
| 290 |
+
`Cheapest move to raise the top open item: instrument the connection step to break the 38% drop down by connector, which would convert T1's remaining gap into a measured fact and de-risk the build scope.</div>`;
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
document.querySelectorAll(".toolbar button").forEach(b=>{
|
| 294 |
+
b.addEventListener("click",()=>{
|
| 295 |
+
document.querySelectorAll(".toolbar button").forEach(x=>x.classList.remove("active"));
|
| 296 |
+
b.classList.add("active");
|
| 297 |
+
sortKey=b.dataset.sort;
|
| 298 |
+
renderCards();
|
| 299 |
+
});
|
| 300 |
+
});
|
| 301 |
+
|
| 302 |
+
renderSummary(); renderKpis(); renderCards(); renderFooter();
|
| 303 |
+
</script>
|
| 304 |
+
</body>
|
| 305 |
+
</html>
|
product-eval/examples/activation-q3/scores.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Scores for activation-q3 (exact 0-100 stored for audit; chat leads with bands)
|
| 2 |
+
|
| 3 |
+
- problem: T1
|
| 4 |
+
value: 72
|
| 5 |
+
value_inputs: {persona: 20, funnel: 22, frequency: 20, competitive: 10}
|
| 6 |
+
value_band: high
|
| 7 |
+
confidence: 89
|
| 8 |
+
confidence_band: high
|
| 9 |
+
recommendation: "Decide now"
|
| 10 |
+
rationale: "High-value activation cliff, corroborated across 4 first-party source types; the math supports committing."
|
| 11 |
+
override: null
|
| 12 |
+
|
| 13 |
+
- problem: T2
|
| 14 |
+
value: 70
|
| 15 |
+
value_inputs: {persona: 20, funnel: 15, frequency: 15, competitive: 20}
|
| 16 |
+
value_band: high
|
| 17 |
+
confidence: 63
|
| 18 |
+
confidence_band: moderate
|
| 19 |
+
recommendation: "Run a research sprint"
|
| 20 |
+
rationale: "High value and competitors solved it, but no first-party usage data; firm up proof before committing."
|
| 21 |
+
override: null
|
| 22 |
+
|
| 23 |
+
- problem: T3
|
| 24 |
+
value: 60
|
| 25 |
+
value_inputs: {persona: 15, funnel: 25, frequency: 10, competitive: 10}
|
| 26 |
+
value_band: moderate
|
| 27 |
+
confidence: 24
|
| 28 |
+
confidence_band: low
|
| 29 |
+
recommendation: "Do not commit yet"
|
| 30 |
+
rationale: "Retention-relevant if true, but the core hypothesis is directly contradicted by first-party analytics (E12)."
|
| 31 |
+
override: null
|
| 32 |
+
|
| 33 |
+
- problem: T4
|
| 34 |
+
value: 35
|
| 35 |
+
value_inputs: {persona: 10, funnel: 10, frequency: 10, competitive: 5}
|
| 36 |
+
value_band: low
|
| 37 |
+
confidence: 12
|
| 38 |
+
confidence_band: low
|
| 39 |
+
recommendation: "Deprioritize"
|
| 40 |
+
rationale: "Prize too small: secondary persona, engagement-only, no competitive pressure."
|
| 41 |
+
override: null
|
product-eval/examples/activation-q3/themes.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Problem-framed themes for activation-q3
|
| 2 |
+
|
| 3 |
+
- id: T1
|
| 4 |
+
name: "New admins can't finish workspace setup without CS help"
|
| 5 |
+
members: [E1, E2, E3, E4]
|
| 6 |
+
personas: [admin, buyer]
|
| 7 |
+
distinct_accounts: 9
|
| 8 |
+
total_weight: 31
|
| 9 |
+
source_types: [product_analytics, support_ticket, customer_interview, churn_survey]
|
| 10 |
+
trend: up
|
| 11 |
+
corroboration: cross-source
|
| 12 |
+
contradictions: []
|
| 13 |
+
confidence: 89 # base 89 (W=31) x 1.0 (4 source types) x 1.0 (no contradictions)
|
| 14 |
+
confidence_band: high
|
| 15 |
+
gaps: ["which connector is worst (Postgres vs Snowflake)?", "is the 38% inflated by trial spam?"]
|
| 16 |
+
|
| 17 |
+
- id: T2
|
| 18 |
+
name: "Teams can't share saved views across the org"
|
| 19 |
+
members: [E5, E6, E7]
|
| 20 |
+
personas: [admin, end_user, buyer]
|
| 21 |
+
distinct_accounts: 6
|
| 22 |
+
total_weight: 14
|
| 23 |
+
source_types: [feature_request, sales_call, app_review]
|
| 24 |
+
trend: emerging
|
| 25 |
+
corroboration: cross-source
|
| 26 |
+
contradictions: []
|
| 27 |
+
confidence: 63 # base 63 (W=14) x 1.0 (3 source types) x 1.0
|
| 28 |
+
confidence_band: moderate
|
| 29 |
+
gaps: ["how many seats would actually share?", "no first-party usage data on view re-creation"]
|
| 30 |
+
|
| 31 |
+
- id: T3
|
| 32 |
+
name: "Alert noise pushes users to mute critical alerts"
|
| 33 |
+
members: [E8, E9]
|
| 34 |
+
personas: [end_user]
|
| 35 |
+
distinct_accounts: 2
|
| 36 |
+
total_weight: 5
|
| 37 |
+
source_types: [internal_observation, community_post]
|
| 38 |
+
trend: flat
|
| 39 |
+
corroboration: single-source-ish
|
| 40 |
+
contradictions: [E12] # analytics show alert engagement flat -> 1 unresolved material contradiction
|
| 41 |
+
confidence: 24 # base 30 (W=5) x 0.9 (2 source types) x 0.9 (1 contradiction)
|
| 42 |
+
confidence_band: low
|
| 43 |
+
gaps: ["no measured mute-rate", "E8 hypothesis directly contradicted by E12"]
|
| 44 |
+
|
| 45 |
+
- id: T4
|
| 46 |
+
name: "Users want a dark-mode dashboard"
|
| 47 |
+
members: [E10, E11]
|
| 48 |
+
personas: [end_user]
|
| 49 |
+
distinct_accounts: 4
|
| 50 |
+
total_weight: 2
|
| 51 |
+
source_types: [feature_request, app_review]
|
| 52 |
+
trend: flat
|
| 53 |
+
corroboration: weak
|
| 54 |
+
contradictions: []
|
| 55 |
+
confidence: 12 # base 13 (W=2) x 0.9 (2 source types) x 1.0
|
| 56 |
+
confidence_band: low
|
| 57 |
+
gaps: ["no business-impact signal", "aesthetic preference, low frequency"]
|