plan.md
c11 Plan — Conversation Profiles
Context
Mark asked to (1) pull down the latest Mark Peterson call and the latest AMZ call and treat them as team meetings — speakers who offer a perspective on the customer, not the customer's own voice, though that perspective is still worth capturing; (2) create cycle c11 with a plan to explore and build an extraction engine where the kind of insight, inputs, and expected outputs follow from the nature of the conversation, so the pipeline stops being overconfident (ex blunder: a team member's or advisor's opinion counted as customer validation); (3) extract product direction, todos, outstanding decisions, tabled ideas from working sessions like the Aug 31 Mark Peterson call; (4) review the design repo's founding docs and start formalizing Raw conversations → Insights → Design Brief → wireframe → q-nuxt-layer component build → Refinement → Install on production app.
Two steering notes from Mark: be explicit about the nature of the meeting (better focus, enforceable expectations, mismatch becomes a signal), and keep it simple — small concessions only where they yield the truest analysis.
What I verified (read-only)
- Mark Peterson's latest call is already in the corpus.
38075ead-…"Mark | Qpoint Dashboard + Reporting" (2026-08-31), extracted, indexed, stampedciso-advisoryvia the person override indata/known-entities.json. Avoma has no newer Mark Peterson call. - The AMZ call is new. Avoma uuid
6fe4a00b-85a1-40b6-8b1b-c17d3706bc08, "AMZ | Qpoint New Feature Discussion + Fleet Overview Story", 2026-09-02, 91 min, transcript ready. Every attendee is Qpoint. Fetch withnpm run fetch -- --uuid 6fe4a00b-…(does not advance the sync window). 13 other new calls exist (Cam syncs, Tyler 1:1s, recruiting screens, Uncork monthly) — out of scope. - The blunder is already in the data. Both Mark Peterson calls: interest 5/5,
use-case-evidencevalidates/reaction-based. The Aug 20 AMZ + Sam Curry call: 21 observations, 12 attributed to Qpoint speakers (AMZ 7, Tyler 5) despite prompt guideline 1. Prose rules alone are not reliably followed. - No profile reaches extraction.
buildExtractionPrompt({transcript, avomaMetadata, notesBlocks})(pipeline/prompt.ts:64); one uniform prompt, static part cached (cut at## Transcript).sourceTypeis resolved after extraction (pipeline/build-index.ts:25resolveSourceType: person override → company record →'prospect').SOURCE_TYPEShasinternalbut nothing assigns it; an all-Qpoint meeting resolves toprospect. - Triage is a boolean.
data/call-classifications.jsonexternal: true|false;false= never extracted, never indexed (extract.ts:245,batch.ts:25,build-index.ts:85). - No perspective concept exists;
Observation.speakeris a free string. Only hint:speculativedescribed as "hypothetical or secondhand" (schemas/vocabularies.ts:182). - Weighting is prose only.
goals.md: "validated only with usage-based evidence from more than one company" — never enforced inpipeline/analyze.ts; Map B (trimCallForCompany, L134) even dropsevidenceKind/direction. - Working-session output is thin. For 38075ead: 7 product-feedback observations, 3 Avoma action items (
parseActionItems,pipeline/avoma-notes.ts:84),decisionMaking: null. Avoma notes carry "Key Takeaways" / "Product Development Roadmap" / "Primary product focus decided…" blocks, injected only as free text. Decisions, tabled ideas, todos are not first-class. - c8 already set the principle (
cycles/c8.agent-pivot/plan.md:73): "Source type says who's talking; evidence kind says what the evidence is." Open c8 items: "Mark M advisory tag decision pending", "callType tuning watch". c11 is free; c10 is complete-but-unarchived.
Design (lean)
A. Declare the nature of the meeting at triage — two fields, both existing vocabularies.data/call-classifications.json entry becomes { subject, date, sourceType, callType, classifiedAt } (sourceType: null = skip; replaces external). Triage shows a derived default for each and Enter accepts:
sourceTypedefault:known-entities.jsonperson override →companies.json→ all attendees Qpoint ⇒internal→prospect.callTypedefault: from subject/agenda keywords (review/scoping/roadmap ⇒roadmap-planning; demo ⇒demo; elsediscovery), else ask. The model still reportsclassification.observedCallType; build-index prints a warning when it disagrees with the declaration. Nothing else — no intent field, no toggles.
B. Expectations are a small table in code, not a UI. CONVERSATION_PROFILES in schemas/vocabularies.ts, keyed by sourceType, with a callType override for session records:
counterparty:external|none(internal: company is null, no positioning/decisionMaking/funnel)evidenceCeiling:usage-based(build-partner, prospect) |reaction-based(ciso-advisory, industry-peer, analyst) |speculative(investor, internal)ratesInterest: false forinternal; advisory/investor interest is labelled "conviction" in the sitesessionRecord: true whencallType ∈ {working-session, roadmap-planning, build-feedback, advisor-input}guidance: 2–3 sentences of profile-specific extraction focus Rendered into the static (cached) prompt as one table; the per-call profile line ("This is aciso-advisory×roadmap-planningconversation; ceiling reaction-based; emit session record") goes at the top of the dynamic part. Static prefix stays byte-identical.
C. One new observation field: perspective = first-hand (speaker's own org/experience/need) | relayed (speaker reporting what others want or would do) | internal (Qpoint speaker). This is the concession that fixes the blunder: the AMZ + Curry call stays prospect, AMZ's lines become internal, Curry's first-hand, "CISOs will never…" becomes relayed.
D. Two deterministic rules in schemas/validation.ts (warn to console, then fix):
speakermatches a Qpoint attendee or roster ⇒perspective: internal(the code enforcement guideline 1 never had).use-case-evidenceabove the profile'sevidenceCeiling, or withperspective ≠ first-handandevidenceKind: usage-based⇒ downgradeevidenceKindto the ceiling /speculative. Never touchesdirection.
E. One pure function in pipeline/analyze.ts. computeValidation(evidence) → { status: validated | partial | unvalidated, reasons[] } from the goals.md rule: ≥2 distinct companies with validates + usage-based + first-hand from a non-internal source. Written next to the existing tallies (L190); the prompt is told the status; the model narrates, it does not decide. Map B stops dropping evidence qualifiers.
F. Session record = three lists, emitted when the profile says so, on CallData.session:
decisions[]: { text, status: made | open | tabled, owner?, speaker, verbatim? }
todos[]: { text, owner?, source: transcript | avoma-notes } // merged with parseActionItems()
ideas[]: { text, status: parked | adopted, speaker, perspective, relatedUseCaseId? }
Avoma "Key Takeaways"/"Roadmap"/"Action Item" blocks are candidates the model must confirm against the transcript. Cross-call rollup (open decisions, todos by owner, parked ideas) is computed in site/composables/useCallData.ts from all-calls.json — no new pipeline file, no new page: a "Direction" section on the dashboard and a session tab on the call detail page.
G. resolveSourceType precedence: declared classification → person override → company record → all-Qpoint ⇒ internal → prospect. README amended: the label still corrects via npm run index; the extraction behaviour needs a re-extract.
H. No stopgap. Extracting the AMZ call under today's prompt yields either nothing (guideline 1 followed) or leaked team opinion as prospect signal (Aug 20). Fetch now; extract as the T1 pilot.
Threads (ordered)
- T1 — Profile + perspective + session record; pilot on the two calls.
schemas/vocabularies.ts:PERSPECTIVES,CONVERSATION_PROFILES,renderConversationProfiles().schemas/call.ts:Observation.perspective,Classification.observedCallType?,Classification.interestLevel?,CallData.profile { sourceType, callType },CallData.session?.pipeline/prompts/extract-call.md: perspective in schema + guideline; rewrite guideline 1 (capture Qpoint speakers, taginternal; tag secondhandrelayed);{{CONVERSATION_PROFILES}}; session-record section.pipeline/prompt.ts:buildExtractionPrompt({…, profile}); profile line in dynamic part.pipeline/extract.ts: triage (L67-107) asks sourceType + callType with derived defaults; single-file path reads the classification (or--source/--type); stampprofile; printcache_read_input_tokens.pipeline/batch.ts: filtersourceType !== null; pass profile.schemas/validation.ts: perspective vocab + rules D1/D2 (uses attendees + roster frompipeline/known-entities.ts).pipeline/build-index.ts: precedence G; observedCallType warning; index gainsperspectiveCounts,sessionCounts.- Baseline first (scratch run, recorded in
cycles/c11.<name>/CYCLE.md): Qpoint-speaker leakage per call;validatesitems by sourceType; gate result on today's data (expected 0 validated). - Pilot:
npm run fetch -- --uuid 6fe4a00b-…; triageinternal×working-session; extract; re-extract 38075ead asciso-advisory×roadmap-planning;npm run index; review both session records with Mark.
- T2 — Gate + site.
analyze.ts(EvidenceItem.perspective,computeValidation,perspectiveBalance, Map B fix);prompts/analyze-use-case.mdtold the computed status. Site: perspective pill (site/utils/format.ts,pages/calls/[id].vuenext to the Qpoint badge at L81); perspective + sourceType inFilterBar.vue; internal/advisory excluded from prospect KPIs (useCallData.ts:354/413); use-case cards show gate status + reasons; Direction section + session tab. - T3 — Re-extract corpus (5 files) + docs.
--force, index, analyze. UpdateREADME.md"How to Interpret",CLAUDE.md,.claude/skills/extract/SKILL.md,goals.md. Close c8's "Mark M tag" item (staysciso-advisory; his calls are declared by callType). - T4 — Design-machine hand-off (lean). Survey result per stage — 1 Raw conversations: documented (market-analyst
CLAUDE.md§ Data Flow). 2 Insights: a queryable corpus, not a durable artifact; consumers hand-copy quotes into their own cycle docs (design c77/c78/c81; c81 had to inline Cam's directive because the repo wasn't reachable). 3 Design brief: bob-wirebrief-writertemplate is de-facto canon but its "Before Starting" never reads market-analyst; design hand-writes briefs in three shapes; no brief has a required source field. 4 Wireframe: fully documented (bob-wire). 5 Layer component build: mockups + extraction documented, the "graduation" trigger is undefined (used in c67/c77/c79, defined only in abandoned c44). 6 Refinement: practice is rich (/iterate, c84 iteration prompt/plan pairs, c67 checkpoint gate) but undefined as a stage; design'spage-registry.tshas no status field. 7 Production install: layer release is airtight (q-nuxt-layer/CLAUDE.md§ Releasing,design/.claude/skills/release-layer), but surfaces ship to qcontrol/qdash, which is in no Sister Projects list and not inbuildCycles.ts; nothing links shipped UI back to the originating insight, sofeedback.json'sshipped/validated-in-usestatuses never advance. The one real end-to-end run is bob-wirec21.inventory, sourced by hand from the Aug 31 Mark Peterson call. c11 does the three smallest things that make the front half explicit, without reversing c12's peer-to-peer ruling:- Brief = the Insights artifact.
market-analyst/briefs/gets a template with a required## Sourceblock (call ids, observation/session item refs, sourceType + perspective + evidenceKind visible) and abriefs/INDEX.md;cam-dashboard-directives.mdis retrofitted as the first entry. A/briefskill drafts one from/analyzeoutput (the analyze skill stays read-only). - Pipeline map, one page.
design/brand/pipeline.md(or a § indesign_philosophy.md"How We Work"): the 7 stages as a table — artifact, owner repo, location, status field — with the c21 run as the worked example. A map, not an orchestrator. - Bilateral pointers.
bob-wire/.claude/agents/brief-writer.md"Before Starting" reads../market-analyst/briefs/INDEX.md; market-analystCLAUDE.mdSister Projects names the brief as the hand-off artifact. Deferred to a design-repo cycle (noted in c11's Outcome as follow-ups): graduation rule incomponent_philosophy.md, refinement/ruling record + status field onpage-registry.ts,## Shipsection convention, qcontrol in Sister Projects /buildCycles.ts, back-link from shipped work to brief ids.
- Brief = the Insights artifact.
Decisions confirmed by Mark (2026-09-03)
- AMZ call: fetch now; extract only as the T1 pilot (no stopgap under the current prompt).
- Mark Peterson stays
ciso-advisory— he acts as a product advisor under his own firm's identity. The declared callType + perspective tagging is what keeps his conviction from reading as customer validation. - Pipeline map lives in
design/brand, with clear references from this repo's docs. Where appropriate, this repo'sCLAUDE.md/skills direct agents to read the relevant instructions in../design. Operating model to state in the map: design is the driver; appendage projects (market-analyst, bob-wire, q-nuxt-layer) run as sub-agents with clear goals and narrowed scope. market-analyst's scope in that model: turn conversations into perspective-tagged insights and briefs; nothing downstream. - Archive c10 in the same commit that creates c11.
Execution order
npm run fetch -- --uuid 6fe4a00b-85a1-40b6-8b1b-c17d3706bc08→ raw transcript + sidecars only. No extraction yet.cycle-manager: createcycles/c11.conversation-profiles/(initial-prompt.md, CYCLE.md, plan.md), add to CYCLES.md, archive c10 to HISTORY.md. Commitc11: create cycle (conversation profiles) + close c10.- T1 implementation + pilot on the two calls; review session records with Mark; commit.
- T2 → T3 → T4 as separate commits, Key Changes dated in CYCLE.md as they land.
Cycle records (via cycle-manager agent)
cycles/c11.conversation-profiles/initial-prompt.md— Mark's ask verbatim (all messages), canonical closing line.cycles/c11.conversation-profiles/CYCLE.md— Why / Objective / Scope (T1–T4; out of scope: the 13 other Avoma calls, OAuth, design-repo stages 5–7) / Key Changes (dated) / Outcome.cycles/c11.conversation-profiles/plan.md— this design.cycles/CYCLES.md— add c11 (flat bullet format); remove c10.cycles/HISTORY.md— c10 entry in the c9 format.- Docs touched in T3/T4:
README.md"How to Interpret" (declared profile, perspective, validation gate),CLAUDE.md(Sister Projects: design as driver, link to../design/brand/pipeline.md; brief as hand-off artifact),.claude/skills/extract/SKILL.md(two-field triage),goals.md(points at the enforced rule).
Risks
relayedvsfirst-handis judgment; onlyinternalis deterministic. The gate treats anything notfirst-handas non-validating, so errors bias toward under-confidence.- Declared vs registry sourceType can disagree — fixed precedence + index warning.
interestLeveloptional:build-index.ts:178defaults to 0 and would drag averages; site skips undefined.- Every use case will read
unvalidated— that is the honest state; the card explains what would validate it (nextTest). validation.tsmust stay in sync with the new fields (structured-output grammar ceiling inoutput-schema.ts:1-14does not apply to prompt-driven extraction).
Verification
npx tsc --noEmitclean (root + site).- AMZ 2026-09-02:
sourceType: internal, every observationperspective: internal, no interest/funnel,sessionpresent,internalpill in dashboard. - Mark Peterson 08-31:
ciso-advisory, secondhand CISO claimsrelayed+ downgraded, session record lists the visibility-before-governance decision, spec/prototype todos (Mark P / Tyler / Rob), parked ideas (gamified rollout checklist, auto-docs from recordings). - AMZ + Curry 08-20 re-extracted: AMZ/Tyler
internal, Curryfirst-hand. data/analysis/use-cases/*.jsoncarryvalidation.status+reasons; overview validated = 0 with reasons naming the missing usage-based / second-company evidence.- Extract log shows
cache_read_input_tokens> 0 on the second call of a run under two different profiles. npm run dev: Direction section and session tab render.