research: integrations outcome + rich wizard cards + coordinator template
Adds a fifth outcome kind ('integrations') tuned for the "audit repo,
survey papers, propose a menu of concrete integrations" use case.
Every INT-XX item is self-contained (what, how, where, prereqs, effort,
risk, testing, rollback, acceptance) so a downstream loop can execute
one per iteration.
Backend:
- Migration 0041 drops + re-adds the outcome_kind CHECK constraint
with 'integrations' allowed. Existing rows unaffected.
- VALID_OUTCOMES gains 'integrations'.
- New deliverable_template(kind) returns the canonical section shape
for each outcome — spec, prod_plan, roadmap, paper, integrations all
get first-class treatment (prior: all shared a bare label).
- build_coordinator_task injects an ARTIFACT SHAPE block from the
template into the coordinator prompt, so the final synthesis
actually matches the promise the wizard made.
Frontend:
- OutcomeKind gains 'integrations'.
- ResearchWizard OUTCOMES list carries a `sections` array per kind.
- Selected card renders an "ARTIFACT WILL CONTAIN" preview so users
pick by seeing what they'll get, not by reading a one-line hint.
- Integrations card gets the fullest preview (executive summary +
INT-XX card shape) since it's the most structured deliverable.
Follow-ups queued (next commit): loop wizard "Import from research
artifact" bridge + one-INT-per-iteration mode.
This commit is contained in:
@@ -28,7 +28,91 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use crate::{ApiError, AppState, Authed};
|
use crate::{ApiError, AppState, Authed};
|
||||||
|
|
||||||
const VALID_OUTCOMES: &[&str] = &["spec", "prod_plan", "roadmap", "paper"];
|
const VALID_OUTCOMES: &[&str] = &["spec", "prod_plan", "roadmap", "paper", "integrations"];
|
||||||
|
|
||||||
|
/// The canonical deliverable shape for an outcome kind, injected into the
|
||||||
|
/// coordinator prompt so runs actually produce the promised structure —
|
||||||
|
/// prior to this the kind was a bare label with no template. The block
|
||||||
|
/// lands under an "ARTIFACT SHAPE" header in the coordinator task.
|
||||||
|
fn deliverable_template(kind: &str) -> &'static str {
|
||||||
|
match kind {
|
||||||
|
"spec" => {
|
||||||
|
"\
|
||||||
|
Deliver a technical specification with exactly these sections in order:\n\
|
||||||
|
## Problem\n\
|
||||||
|
## Goals + non-goals\n\
|
||||||
|
## Interfaces (types, function signatures, protocols)\n\
|
||||||
|
## Data model\n\
|
||||||
|
## Alternatives considered (with rejection rationale)\n\
|
||||||
|
## Acceptance criteria (measurable)\n"
|
||||||
|
}
|
||||||
|
"prod_plan" => {
|
||||||
|
"\
|
||||||
|
Deliver a prioritized execution plan with exactly these sections in order:\n\
|
||||||
|
## Objective\n\
|
||||||
|
## Success metrics\n\
|
||||||
|
## Workstreams (P0 → P1 → P2, each with owner + estimate)\n\
|
||||||
|
## Milestones (dated where possible)\n\
|
||||||
|
## Risks + dependencies\n\
|
||||||
|
## Definition of done\n"
|
||||||
|
}
|
||||||
|
"roadmap" => {
|
||||||
|
"\
|
||||||
|
Deliver a horizon roadmap with exactly these sections in order:\n\
|
||||||
|
## Vision\n\
|
||||||
|
## Now (0-6 weeks) — bulleted, dated\n\
|
||||||
|
## Next (6-16 weeks) — themes + expected outputs\n\
|
||||||
|
## Later (16+ weeks) — bets + open questions\n\
|
||||||
|
## Cross-cutting concerns\n"
|
||||||
|
}
|
||||||
|
"paper" => {
|
||||||
|
"\
|
||||||
|
Deliver a short scientific-style paper with exactly these sections in order:\n\
|
||||||
|
## Abstract (150-200 words)\n\
|
||||||
|
## Background + related work (with citations)\n\
|
||||||
|
## Method\n\
|
||||||
|
## Findings\n\
|
||||||
|
## Discussion + limitations\n\
|
||||||
|
## References\n"
|
||||||
|
}
|
||||||
|
"integrations" => {
|
||||||
|
"\
|
||||||
|
Deliver a prioritized MENU of concrete integrations we can implement in the \
|
||||||
|
BOUND REPO, each grounded in one or more published papers AND in real files/\
|
||||||
|
modules of this repo. Every integration is self-contained so a downstream \
|
||||||
|
coding loop can execute exactly one item per iteration.\n\
|
||||||
|
\n\
|
||||||
|
Required top matter:\n\
|
||||||
|
# Integration Plan · <repo slug>\n\
|
||||||
|
## Executive summary\n\
|
||||||
|
· Focus areas: <perf | stability | security | provenance — one or more>\n\
|
||||||
|
· Papers surveyed: <n>\n\
|
||||||
|
· Recommended integrations: <n> (P0: <n>, P1: <n>, P2: <n>)\n\
|
||||||
|
\n\
|
||||||
|
Then ## Integrations, and for EACH candidate emit an item with this exact \
|
||||||
|
shape and stable id (INT-01, INT-02, ...) so a loop can address items by id:\n\
|
||||||
|
\n\
|
||||||
|
### INT-<NN> · <Name> · P0|P1|P2 · <focus area>\n\
|
||||||
|
**What it is**: 1-3 sentence description of the technique.\n\
|
||||||
|
**Source(s)**: paper title · authors · year · arXiv/DOI (one line per paper).\n\
|
||||||
|
**How we would accomplish it**: numbered concrete steps — reference the \
|
||||||
|
paper's algorithm/section AND the repo's actual file paths.\n\
|
||||||
|
**Where in the architecture**: bulleted list of files/modules touched; \
|
||||||
|
mark NEW modules explicitly.\n\
|
||||||
|
**Prerequisites**: other INT-ids that must land first (or 'none').\n\
|
||||||
|
**Effort**: S / M / L with a one-line breakdown.\n\
|
||||||
|
**Risk**: low / med / high + one specific concern.\n\
|
||||||
|
**Testing**: existing suites to exercise + new tests to add.\n\
|
||||||
|
**Rollback**: feature flag name or revert plan.\n\
|
||||||
|
**Acceptance criteria**: bulleted, measurable, tied to the focus area.\n\
|
||||||
|
\n\
|
||||||
|
Ordering rules: sort by priority (P0 first), and within a priority sort so \
|
||||||
|
prerequisites come before dependents. Cite every claim with either a paper \
|
||||||
|
reference or a repo file path — never fabricate paths or citations.\n"
|
||||||
|
}
|
||||||
|
_ => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_outcome(kind: &str) -> Result<(), ApiError> {
|
fn check_outcome(kind: &str) -> Result<(), ApiError> {
|
||||||
if VALID_OUTCOMES.contains(&kind) {
|
if VALID_OUTCOMES.contains(&kind) {
|
||||||
@@ -124,12 +208,19 @@ fn build_coordinator_task(
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
let template = deliverable_template(outcome);
|
||||||
|
let shape_block = if template.is_empty() {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
format!("ARTIFACT SHAPE (the final synthesis MUST match this):\n{template}\n")
|
||||||
|
};
|
||||||
let framing = format!(
|
let framing = format!(
|
||||||
"RESEARCH TOPIC: {title}\n\
|
"RESEARCH TOPIC: {title}\n\
|
||||||
OUTCOME KIND: {outcome} (spec / prod_plan / roadmap / paper)\n\n\
|
OUTCOME KIND: {outcome} (spec / prod_plan / roadmap / paper / integrations)\n\n\
|
||||||
DESCRIPTION:\n{description}\n\n\
|
DESCRIPTION:\n{description}\n\n\
|
||||||
{repo_block}\
|
{repo_block}\
|
||||||
{repo_guidance}\
|
{repo_guidance}\
|
||||||
|
{shape_block}\
|
||||||
TEAM:\n{roster}\n\n"
|
TEAM:\n{roster}\n\n"
|
||||||
);
|
);
|
||||||
let body = match topo {
|
let body = match topo {
|
||||||
|
|||||||
@@ -45,18 +45,54 @@ const TOPOLOGIES: { kind: TopologyKind; label: string; hint: string }[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const OUTCOMES: { kind: OutcomeKind; label: string; hint: string }[] = [
|
const OUTCOMES: {
|
||||||
{ kind: "spec", label: "Spec", hint: "A structured technical specification." },
|
kind: OutcomeKind;
|
||||||
|
label: string;
|
||||||
|
hint: string;
|
||||||
|
/** Optional: what the artifact will contain. Shown as a preview on the
|
||||||
|
* wizard card so users pick by seeing what they'll get. */
|
||||||
|
sections?: string[];
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
kind: "spec",
|
||||||
|
label: "Spec",
|
||||||
|
hint: "Technical spec: problem, interfaces, data model, acceptance criteria.",
|
||||||
|
sections: ["Problem", "Goals + non-goals", "Interfaces", "Data model", "Alternatives", "Acceptance criteria"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
kind: "prod_plan",
|
kind: "prod_plan",
|
||||||
label: "Prod plan",
|
label: "Prod plan",
|
||||||
hint: "A prioritized product/execution plan.",
|
hint: "Prioritized execution plan with P0/P1/P2 workstreams and milestones.",
|
||||||
|
sections: ["Objective", "Success metrics", "Workstreams", "Milestones", "Risks", "Definition of done"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "roadmap",
|
||||||
|
label: "Roadmap",
|
||||||
|
hint: "Horizon roadmap — Now / Next / Later with cross-cutting concerns.",
|
||||||
|
sections: ["Vision", "Now (0-6w)", "Next (6-16w)", "Later (16w+)", "Cross-cutting"],
|
||||||
},
|
},
|
||||||
{ kind: "roadmap", label: "Roadmap", hint: "A phased horizon roadmap." },
|
|
||||||
{
|
{
|
||||||
kind: "paper",
|
kind: "paper",
|
||||||
label: "Paper",
|
label: "Paper",
|
||||||
hint: "A short scientific-style paper with methods + findings.",
|
hint: "Short scientific paper with methods, findings, related work.",
|
||||||
|
sections: ["Abstract", "Background", "Method", "Findings", "Discussion", "References"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "integrations",
|
||||||
|
label: "Integration plan",
|
||||||
|
hint:
|
||||||
|
"Audit the bound repo + survey papers → prioritized menu of concrete " +
|
||||||
|
"INT-XX items (what · how · where in architecture · effort · risk · " +
|
||||||
|
"acceptance). Loops can consume one item per iteration.",
|
||||||
|
sections: [
|
||||||
|
"Executive summary",
|
||||||
|
"INT-XX cards (P0/P1/P2)",
|
||||||
|
"· What it is + source paper(s)",
|
||||||
|
"· How to accomplish",
|
||||||
|
"· Where in the architecture (file paths)",
|
||||||
|
"· Prereqs, effort, risk, testing, rollback",
|
||||||
|
"· Acceptance criteria",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -317,9 +353,48 @@ export function ResearchWizard({
|
|||||||
onChange={() => setOutcome(o.kind)}
|
onChange={() => setOutcome(o.kind)}
|
||||||
style={{ marginTop: 2 }}
|
style={{ marginTop: 2 }}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div style={{ flex: 1, minWidth: 0 }}>
|
||||||
<div style={{ fontWeight: 600, color: "#f3f3f5" }}>{o.label}</div>
|
<div style={{ fontWeight: 600, color: "#f3f3f5" }}>{o.label}</div>
|
||||||
<div style={{ fontFamily: mono, fontSize: 11, color: "#8a8a92" }}>{o.hint}</div>
|
<div style={{ fontFamily: mono, fontSize: 11, color: "#8a8a92", lineHeight: 1.4 }}>
|
||||||
|
{o.hint}
|
||||||
|
</div>
|
||||||
|
{o.sections && outcome === o.kind ? (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginTop: 8,
|
||||||
|
padding: "8px 10px",
|
||||||
|
borderRadius: 6,
|
||||||
|
background: "rgba(255,255,255,.02)",
|
||||||
|
border: "1px solid rgba(255,255,255,.06)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontFamily: mono,
|
||||||
|
fontSize: 9,
|
||||||
|
letterSpacing: ".1em",
|
||||||
|
color: "#5a5a62",
|
||||||
|
marginBottom: 4,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
ARTIFACT WILL CONTAIN
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
style={{
|
||||||
|
margin: 0,
|
||||||
|
paddingLeft: 16,
|
||||||
|
fontFamily: mono,
|
||||||
|
fontSize: 10.5,
|
||||||
|
color: "#c3c3c8",
|
||||||
|
lineHeight: 1.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{o.sections.map((s) => (
|
||||||
|
<li key={s}>{s}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Research API client. Uses relative fetch(): the Next.js server proxies
|
// Research API client. Uses relative fetch(): the Next.js server proxies
|
||||||
// to the Rust backend with the auth cookie.
|
// to the Rust backend with the auth cookie.
|
||||||
|
|
||||||
export type OutcomeKind = "spec" | "prod_plan" | "roadmap" | "paper";
|
export type OutcomeKind = "spec" | "prod_plan" | "roadmap" | "paper" | "integrations";
|
||||||
export type TopicStatus =
|
export type TopicStatus =
|
||||||
| "standby"
|
| "standby"
|
||||||
| "processing"
|
| "processing"
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
-- Extends research_topics.outcome_kind to include 'integrations' — a new
|
||||||
|
-- deliverable shape for "audit this repo, survey the literature, produce
|
||||||
|
-- a prioritized menu of concrete integrations we can implement" runs.
|
||||||
|
-- The artifact is a list of INT-XX items, each self-contained (what,
|
||||||
|
-- how, where in the architecture, prereqs, effort, risk, acceptance
|
||||||
|
-- criteria) so a downstream loop can consume them one-per-iteration.
|
||||||
|
--
|
||||||
|
-- The existing check constraint is dropped and re-added with the new
|
||||||
|
-- value; existing rows aren't affected. Postgres requires the drop
|
||||||
|
-- because you can't ALTER a constraint's expression in place.
|
||||||
|
ALTER TABLE research_topics
|
||||||
|
DROP CONSTRAINT research_topics_outcome_kind_check;
|
||||||
|
|
||||||
|
ALTER TABLE research_topics
|
||||||
|
ADD CONSTRAINT research_topics_outcome_kind_check
|
||||||
|
CHECK (outcome_kind IN ('spec', 'prod_plan', 'roadmap', 'paper', 'integrations'));
|
||||||
Reference in New Issue
Block a user