← Market Analyst · c12

product-input-plan.md

c12 thread: product-input — plan

Written 2026-10-20 from a read of the agent-facing context (CLAUDE.md, goals.md, pipeline/prompts/*, .claude/skills/{analyze,brief}, briefs/TEMPLATE.md), the profile and standing code (schemas/{vocabularies,validation,problem-standing}.ts, pipeline/prompt.ts), and the Oct 12/14/19 product-session extractions. Prompt: product-input-prompt.md. Status: plan; nothing built.

The project is now used mostly as input to product work: weekly product sessions with an advisor, rulings handed to design as decision briefs. This thread makes five changes so that use is first-class. Four fix context that still reads market-first (A, B, C, E). The fifth adds a decisions ledger (D) so the project can answer "what have we decided, and what replaced what."

1. What the read found

The straddle works at the spine. The single observation stream with perspective on every item, use case → micro problem decomposition, and the two code-computed honesty rules (validation-gate.ts, problem-standing.ts) serve both lenses. goals.md puts the design lens first. Problems are consumed downstream: problem:<id> appears in design c105, c114, c116 and c118, and the Oct 19 decision brief became design c118 the same day.

Where market framing still steers agents:

  1. Role lines and ordering. extract-call.md opens "You are an analyst". All three analyze-*.md prompts open "You are a market analyst". The extraction schema puts urgency, positioning and decisionMaking before session and candidateProblems, and candidate problems are guideline 19 of 20. analyze-overview asks for six market sections before problemSpace. The /analyze skill is titled "Market Analyst Agent" and says "always connect back to the use-case-honing objective", which contradicts goals.md.
  2. Product sessions are run through sales fields. Oct 12/14/19 are declared ciso-advisory × roadmap-planning. Each got interest 4 ("conviction") and an urgency score whose summary explains there is no deal. Mark Peterson's design opinions were tagged as positioning resonance, and a design preference ("I love it a lot better that there's both") became a value echo. Profiles can turn off interest (ratesInterest), but only the internal profile turns off positioning and decision-making, and nothing turns off urgency.
  3. The advisor rule doesn't fit a co-designer. c12 confirmed that an advisor's first-hand experience counts as their own organization (Moto), labelled. Moto is one of the two organizations behind all 5 recurring problems. Today the October sessions move no standing: recomputing without them leaves every problem where it is, because Moto's support comes from Aug 20/31 and Sep 3. But the October sessions are already adding Moto first-hand items to findings-resolution-workflow (3 sessions) and safe-to-enforce (2). The rule counts a co-designer's preferences about the design as their organization having the problem. This fix is preventive.
  4. Rulings are a per-call sidecar. 44 session.decisions exist across the corpus, each inside its own call, with no supersession, no surface and no current state. The data holds both Oct 14 "V1 needs … policy groups mapped to teams" and Oct 19 "policy groups stop being a managed object" as made, and both Oct 14 "defer frameworks" and Oct 19 "frameworks are the entry point". The decision brief sorted this by hand (§4 "Workshopped and superseded"). Nothing in the repo answers "what have we decided about policies?".
  5. Template drift. briefs/TEMPLATE.md and /brief list kinds problem / story / position; INDEX.md already uses decision. The template's Consumers line still says "feedback.json items advanced", and that file was retired in c12.

Out of scope here, noted for later: a product-state context alongside _qpoint-context.md (that file describes Qpoint as pitched, not what is built or in design); design-native observation types (mock critique, naming / mental model, which is Q9); closing the shipped → validated-in-use loop (no problem has shipped yet); tracing engineering repos in consumers.ts; the ~19 fetched-but-untriaged meetings in data/raw/; reviewing the 25 candidates.

2. The changes

A. Role lines and agent framing (wording only)

  • pipeline/prompts/extract-call.md line 1 → "You are extracting structured insights from a conversation for Qpoint's problem space: the problems users have, the decisions the team makes, and how the market receives it." Move session and candidateProblems above urgency / positioning / decisionMaking in the schema block. Moving keys in the prompt's example is safe: the output is parsed as JSON and validated by key, not by position.
  • analyze-use-case.md, analyze-company.md: "You are a market analyst" → "You are an analyst". These two stages are market-lens by design and keep their content.
  • analyze-overview.md: "synthesizing the overall state of Qpoint's market evidence" → "…of Qpoint's problem space and market evidence". Move problemSpace to the top of the task list. The output schema order in schemas/output-schema.ts follows. The site reads by key, so nothing breaks.
  • .claude/skills/analyze/SKILL.md: title "Market Analyst Agent" → "Analysis Agent". "Think through the use-case lens" → "Think through both lenses (design first)". "always connect back to the use-case-honing objective" → "always connect back to the lenses in goals.md".

B. Turn off market blocks where they don't apply

Today only profile.counterparty === 'none' drops positioning and decision-making. Add a call-type rule beside the existing SESSION_RECORD_CALL_TYPES:

  • schemas/vocabularies.ts: MARKET_BLOCK_OMIT maps a call type to the blocks it omits:
    • design-session (new, see C): interestLevel, funnelStage, urgency, positioning, decisionMaking. Next steps move to session.todos, which already exist.
    • document: the same set. This codifies what prompt.ts says in prose today.
    • working-session, roadmap-planning, build-feedback: positioning only. A build partner's rollout timeline and approvers still matter, so urgency and decision-making stay.
  • pipeline/prompt.ts renderDeclaredProfile: one line listing the omitted blocks, replacing the counterparty-only clause.
  • schemas/validation.ts: rule 4 generalises from "internal profile" to "the profile or call type omits it". Fix messages follow the existing pattern ("positioning dropped (call type design-session)").
  • Site: these fields are already optional (internal calls lack them). Dashboard averages for interest and urgency simply exclude these calls. Check the call page renders cleanly with them absent.

C. A design-session call type, and what it means for standing

  • CALL_TYPES gains design-session: "A product design session where the team, possibly with an advisor or partner as co-designer, works out what the product should do. Yields decisions, ideas and problem tags, not market signals." Add it to SESSION_RECORD_CALL_TYPES.
  • CONVERSATION_PROFILES guidance for ciso-advisory gains one sentence: in a design-session, the advisor's opinions about the design are ideas or decisions, not pain points. Their own organization's experience is still first-hand.
  • Standing rule (schemas/problem-standing.ts): items that extraction tagged from a design-session call are counted and shown as design input (a new count beside relayed and internal) and do not move standing. Curated refs (human-pinned in problems.json) from those calls still count, because a person checked them. Reasons gain "N design-session item(s): design input, not evidence". build-index.ts passes call type into StandingEvidence. The site's client-side recompute in useCallData.ts (problemRollup) mirrors the rule, the same pairing c12 used for the advisor rule.
  • Re-triage: Oct 12, 14 and 19 → ciso-advisory × design-session in data/call-classifications.json, keeping their shown artifacts. Re-extract all three, which CLAUDE.md requires after a profile change. Expected effect: no standing change (§1.3). There are no curated refs from October, so nothing needs re-pinning.

D. Decisions ledger

A curated registry of product rulings made in conversations, the same pattern as problems.json: extraction proposes, a person promotes, the index computes, the site reads.

D1. Shape: data/decisions.json (human-curated)

{
  "id": "policy-one-per-concern",               // kebab, stable, cited as decision:<id>
  "statement": "One policy per area of concern; the policy holds its own definition, severity, mode, exceptions and knobs.",
  "status": "ruled",                            // DECISION_STATUSES (below)
  "date": "2026-10-19",                         // when it took this status
  "area": "policy-model",                       // free kebab grouping, for the ledger view
  "problemIds": ["safe-to-enforce"],
  "surfaces": ["policy-enforcement", "controls"],
  "supersedes": ["policy-groups-mapped-to-teams"],
  "source": [{ "callId": "154b2679-…", "decision": 2, "verbatim": "…", "at": "1:26" }],
  "owner": "Mark Parson",
  "notes": "Later statements win; the recap at 1:26–1:32 is the ruling.",
  "statusHistory": [{ "status": "direction", "date": "2026-10-14", "by": "Oct 14 session" }, { "status": "ruled", "date": "2026-10-19", "by": "Oct 19 recap" }]
}
  • DECISION_STATUSES in vocabularies.ts: ruled (agreed, in force), direction (leaning, not final: the brief's "direction" items), open (raised, explicitly undecided), tabled (deliberately deferred), superseded (replaced by a later entry), rejected (workshopped and dropped: the brief's "do not revive" list). rejected keeps a dropped idea from being revived from an old transcript.
  • supersedes is written by hand. The index computes supersededBy, and it warns when an entry is superseded but its status still says ruled / direction.
  • Source refs carry verbatim as well as the index. This is the c12 re-extraction lesson: indices change, verbatims don't.
  • Types in schemas/call.ts (Decision, DecisionRegistry), runtime checks in validation.ts.

D2. Extraction proposes, linked to the ledger

  • session.decisions[] gains optional decisionId + decisionDirection (reaffirms / revises / reverses), validated against the ledger exactly as problemId is validated against problems (unknown ids dropped with a fix message).
  • prompt.ts renders a Named Decisions section (id, status, one-line statement; superseded and rejected entries included and marked) into the cached static part beside {{PROBLEMS}}. Guideline 21: tag a session decision when it restates, revises or reverses a named one. Never invent an id. A ruling that matches no named decision stays untagged and becomes a promotion candidate.
  • This makes supersession something the pipeline notices: a revises / reverses tag on a new call surfaces as "this may supersede X" for a person to confirm.

D3. Index and consumers

  • build-index.ts → data/decisions-index.json: per decision, resolved source text, supersededBy, inForce (ruled or direction and not superseded), later revisits from extraction tags (call, date, direction), consumers. Plus a list of untagged made session decisions across the corpus: the promotion queue.
  • pipeline/consumers.ts scans decision:<id> as well as problem:<id> and briefs.

D4. Seed (the T0-style hand pass, after C's re-extraction so indices are stable)

  • Review all session decisions across the corpus: 44 today; the count changes with C's re-extraction. Use briefs/policy-model-and-publishing.md as the spine for policy, findings and publishing. Expect roughly 20–30 entries, including superseded and rejected ones, because the brief's §4 becomes rejected / superseded rows.
  • Draft in decisions-draft.md for Mark's review, then write data/decisions.json. This mirrors problems-draft.md → problems.json.
  • Retro-cite: the decision brief's §1 items (A1… D…) gain decision:<id> tokens.

D5. Site

  • New /decisions page, third in the nav (Dashboard · Problems · Decisions · Calls · …):
    • In force, grouped by area, then each entry's statement, status pill, date, source session link, problem and surface chips, and a collapsed "replaced" chain.
    • Open / tabled.
    • Superseded and rejected, collapsed by default.
    • Not in the ledger yet: untagged made session decisions with copy-JSON promotion, the same idiom as candidates on /problems.
  • /problems/[id] gains a Decisions card. The call page's Session Record shows a ledger chip on tagged decisions. The dashboard Direction block links "Ledger →".
  • useCallData.ts loads decisions.json + decisions-index.json.

D6. Docs and skills

  • goals.md design lens gains key questions: "What is in force for each surface? What has been superseded or rejected, so it is not revived?"
  • /analyze loads the ledger. /brief writes decision briefs that cite decision:<id> and list superseded or rejected ids in place of the free-text §4.
  • CLAUDE.md: the ledger in the tree, data flow and conventions ("data/decisions.json is human-curated").

Boundary with design. Design records what a ruling changes in the design: c118 is writing dated decisions into c114's CYCLE.md. The ledger records what was decided in conversation, when, by whom, and what it replaced. To keep one source of truth per fact, design cites decision:<id> rather than restating the ruling. That needs a small addition to design's brand/pipeline.md hand-off rule 4, made as its own commit in design and only with Mark's OK (Q5).

E. Brief template and skill drift

  • briefs/TEMPLATE.md: Kind line gains decision. The Source block gains a Decisions: line (decision:<id>, status). Consumers: "feedback.json items advanced" → "problems / decisions advanced".
  • .claude/skills/brief/SKILL.md: a "Decisions are briefs too" paragraph covering the decision kind, its sections, and citing the ledger.

3. Build order

  1. A + E (wording; no data change). Commit.
  2. B + C code: vocabularies, prompt, validation, standing, build-index, site recompute. npm run index shows no standing change on the existing corpus. Commit.
  3. D1 + D2 schema: ledger types, vocab, validation, prompt section (renders empty until seeded), guideline 21. Commit.
  4. Re-triage and re-extract Oct 12/14/19 as design-session (sequential, env -u ANTHROPIC_API_KEY). Check: no interest, urgency, positioning or decision-making on the three; session records intact; standing unchanged. Commit.
  5. D4 seed: decisions-draft.md → Mark reviews → data/decisions.json. Commit.
  6. D3 index + consumers. Commit.
  7. D5 site. Typecheck, build and preview on :3100 (not while the dev server runs). Commit.
  8. D6 docs and skills; retro-cite the decision brief. Commit. Update c12 CYCLE.md Key Changes.

Steps 2–4 are ordered so the seed is pinned against the final extractions. Seeding before the re-extract would repeat the c12 index-invalidation problem.

4. Verification

  • npm run index: standing identical to before (5 recurring / 10 observed); reasons show design-input counts on findings-resolution-workflow and safe-to-enforce.
  • The three October extractions validate with no interest, urgency, positioning or decision-making, and with their session records and problem tags intact.
  • /decisions "In force → policy-model" reads the same as the decision brief §1. Oct 14 "policy groups mapped to teams" and "defer frameworks" appear under superseded, each pointing to its Oct 19 replacement.
  • npm run consumers reports decision tokens once design cites them, and c118 still resolves against its four problems.
  • nuxi typecheck clean apart from the pre-existing Segments errors. All routes return 200.
  • A test extraction of a later product session (the Oct 21 Wednesday session, if fetched) tags at least one decision reaffirms or revises against the ledger.

5. Decisions for Mark

#QuestionRecommendation
Q1Which calls become design-session?Oct 12, 14, 19. Leave Aug 31 and Sep 3 as advisor roadmap calls: they are Mark Peterson scoping from Moto's experience, and they hold most of Moto's first-hand problem evidence.
Q2Do any design-session items move standing?Curated (human-pinned) refs only; extraction tags count as design input.
Q3Which blocks does each call type omit (B)?As in §2B: everything market-shaped for design-session and document; positioning only for working-session, roadmap-planning and build-feedback.
Q4Ledger statusesruled / direction / open / tabled / superseded / rejected.
Q5Ask design to cite decision:<id> (pipeline.md rule 4, a design commit)?Yes, after the seed exists.
Q6Seed scopeReview all session decisions; promote what is still relevant. Superseded and rejected rows are worth keeping.

Qpoint Brand Style Guide