Skip to content

Commit f06e414

Browse files
docs(spec): idea-intake bridge schema (#5783)
Defines the interface that turns a freeform renter idea into a structured, claimable task-graph, so a person renting a loop doesn't hand-translate intent into a well-formed issue. Specifies the idea submission schema, deterministic translation rules (idea -> constituent issues with per-issue testable acceptance criteria and dependsOn ordering), and a scoring rubric that reuses the existing feasibility gate: each issue is reduced to the FeasibilityGateInput discriminants buildFeasibilityVerdict already consumes, with graph disposition = least-favorable go/raise/avoid across issues (no second decision surface). Includes two end-to-end worked examples (single-issue and a dependency chain). Written spec only, no code; concrete enough for the freeform feasibility scoring in #5671 to implement against. Closes #4779
1 parent 4b6b5c6 commit f06e414

1 file changed

Lines changed: 152 additions & 0 deletions

File tree

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# Idea-intake bridge schema
2+
3+
Product spec for **#4779**. Defines the interface that turns a freeform human idea into something the loop
4+
mechanics can execute against, so a person renting a loop does not have to hand-translate their intent into a
5+
well-formed, claimable issue. It is the input contract the feasibility scoring adapted in **#5671** reads, and
6+
the upstream boundary for the Rent-a-Loop execution path.
7+
8+
This is a written spec only — no code is implemented here. It defines (1) the **idea submission schema**, (2) the
9+
**translation rules** from an idea to a structured, claimable task-graph, (3) the **scoring rubric** the execution
10+
loop evaluates its own output against, and (4) two worked examples traced end-to-end.
11+
12+
## Design constraints (why the shape below)
13+
14+
- **Reuse the existing feasibility gate, don't reinvent it.** `packages/loopover-engine/src/feasibility.ts`
15+
already reduces a candidate to a `go` / `raise` / `avoid` verdict over three discriminants
16+
(`claimStatus`, `duplicateClusterRisk`, `issueStatus`) with `avoid > raise > go` precedence. The idea bridge
17+
must produce, per constituent issue, exactly those discriminants so the adapted freeform scoring (#5671) can
18+
call the same `buildFeasibilityVerdict` without a parallel decision path.
19+
- **Emit the shape the loop already runs on.** Each constituent issue must translate into the fields the coding
20+
loop already consumes — a title, a body, `labels`, `linkedIssues`, and an acceptance-criteria artifact — so the
21+
bridge output drops straight into the existing claim → analyze → execute flow.
22+
- **Freeform in, structured out, human-auditable at the seam.** The idea is natural language; the task-graph is
23+
strict. The translation is the only fuzzy step, so it is explicit, bounded, and always reviewable before any
24+
loop claims work.
25+
26+
## 1. Idea submission schema
27+
28+
An `IdeaSubmission` is the raw input a renter provides.
29+
30+
| Field | Type | Required | Notes |
31+
|---|---|---|---|
32+
| `id` | string | yes | Stable idea identifier (bridge-assigned). |
33+
| `title` | string | yes | One-line intent. Bounded (≤ 120 chars). |
34+
| `body` | string | yes | Freeform description of the desired outcome. Bounded + public-safe (no secrets). |
35+
| `targetRepo` | string | yes | `owner/name` the loop will act on. Must be an installed, registered repo. |
36+
| `constraints` | string[] | no | Renter-stated musts/must-nots (e.g. "no new dependencies", "keep the public API stable"). |
37+
| `acceptanceHints` | string[] | no | Renter's own success signals, folded into per-issue acceptance criteria. |
38+
| `priority` | `"normal" \| "high"` | no | Advisory only. Never maps to `gittensor:priority` (that label is maintainer-propagated, never renter-set). |
39+
40+
Rules:
41+
- `title`/`body`/each `constraints[]` entry are length-bounded and stripped of anything non-public-safe at intake,
42+
mirroring the manifest text-slot handling in `focus-manifest.ts`.
43+
- `targetRepo` that is not installed+registered is rejected at intake, not scored — an uninstallable repo can
44+
never produce a `go`.
45+
46+
## 2. Translation rules — idea → task-graph
47+
48+
The bridge deterministically expands one `IdeaSubmission` into a `TaskGraph`.
49+
50+
```
51+
TaskGraph {
52+
ideaId: string
53+
issues: ConstituentIssue[] // ≥ 1, topologically ordered by dependsOn
54+
rubric: ScoringRubric // see §3
55+
}
56+
57+
ConstituentIssue {
58+
key: string // stable within the graph, e.g. "issue-1"
59+
title: string // becomes the issue/PR title
60+
body: string // becomes the issue/PR body
61+
labels: string[] // gittensor:bug | gittensor:feature (type), never gittensor:priority
62+
dependsOn: string[] // keys of issues that must land first
63+
acceptanceCriteria: AcceptanceCriterion[] // ≥ 1
64+
feasibility: FeasibilityGateInput // the discriminants §3 scores — { claimStatus, duplicateClusterRisk, issueStatus, found }
65+
}
66+
67+
AcceptanceCriterion {
68+
id: string
69+
statement: string // testable, behavior-level ("uploads retry on 5xx"), not implementation-level
70+
kind: "behavior" | "artifact" | "constraint"
71+
}
72+
```
73+
74+
Translation rules:
75+
1. **Decompose by independently-shippable outcome.** Each `ConstituentIssue` is a unit that can be claimed,
76+
executed, and merged on its own. A multi-step idea becomes several issues linked by `dependsOn`; a simple idea
77+
becomes exactly one.
78+
2. **Every issue carries testable acceptance criteria.** Criteria are behavior-level and implementation-agnostic —
79+
they describe *what* is true when done, never *how*. Renter `acceptanceHints` and `constraints` fold in as
80+
`artifact`/`constraint` criteria.
81+
3. **Type labels are inferred, priority is never.** An issue gets `gittensor:bug` or `gittensor:feature` from its
82+
outcome; `gittensor:priority` is never emitted by the bridge (it is maintainer-propagated only).
83+
4. **Each issue is pre-scored for feasibility** by populating `feasibility` (§3), so the loop can gate before
84+
claiming rather than after wasting an attempt.
85+
5. **Ordering respects `dependsOn`.** An issue whose dependency has not landed is held (`raise`), never claimed
86+
ahead of its prerequisite.
87+
88+
## 3. Scoring rubric
89+
90+
The rubric is the existing feasibility gate applied per constituent issue. The freeform-scoring work in #5671
91+
maps idea/issue text onto the three discriminants; this spec fixes what those discriminants mean for an idea so
92+
the mapping is stable:
93+
94+
| Discriminant | Idea-bridge meaning | Verdict effect (per `feasibility.ts`) |
95+
|---|---|---|
96+
| `issueStatus = ready` | criteria are testable, scope is a single shippable outcome, no blocking prerequisite open | eligible for `go` |
97+
| `issueStatus = needs_proof` / `hold` | outcome under-specified, or a `dependsOn` prerequisite not yet landed | `raise` (`issue_quality_uncertain`) |
98+
| `issueStatus = invalid` / `do_not_use` | not implementable as stated, or violates a hard constraint/guarded surface | `avoid` |
99+
| `duplicateClusterRisk = high` | outcome duplicates an existing open issue/PR cluster | `avoid` (`duplicate_cluster_high`) |
100+
| `duplicateClusterRisk = medium` | overlaps an existing effort but not identical | `raise` |
101+
| `claimStatus = claimed` | an equivalent issue is already claimed by another loop | `raise` (`claim_status_claimed`) |
102+
| `claimStatus = solved` | the outcome already exists on the default branch | `avoid` (`claim_status_solved`) |
103+
| `found = false` | the bridge could not resolve a concrete target for this issue | `raise` (`target_not_found`) |
104+
105+
The graph-level disposition is the **least-favorable** verdict across its issues (`avoid` if any issue avoids,
106+
else `raise` if any raises, else `go`) — a renter should not be told "go" while any constituent is unshippable.
107+
Precedence (`avoid > raise > go`) is inherited unchanged from `buildFeasibilityVerdict`, so the bridge adds no
108+
second decision surface.
109+
110+
## 4. Worked examples
111+
112+
### Example A — simple idea (single issue)
113+
114+
**Idea:** `{ title: "Retry flaky uploads", body: "Our upload client gives up on the first 5xx; it should retry a
115+
few times before failing.", targetRepo: "acme/widgets", constraints: ["no new dependencies"] }`
116+
117+
**Task-graph:**
118+
- `issue-1` — title *"Uploads should retry on 5xx"*, labels `[gittensor:bug]`, `dependsOn: []`
119+
- AC1 (behavior): a 5xx upload response triggers a bounded retry before surfacing an error
120+
- AC2 (behavior): a non-5xx (e.g. 4xx) failure is **not** retried
121+
- AC3 (constraint): no new runtime dependency is added
122+
- `feasibility`: `{ claimStatus: "unclaimed", duplicateClusterRisk: "none", issueStatus: "ready", found: true }`
123+
- **rubric →** `buildFeasibilityVerdict(issue-1.feasibility)` = **`go`**. Graph verdict = `go`. One claimable issue
124+
drops straight into the loop.
125+
126+
### Example B — multi-step idea (dependency chain)
127+
128+
**Idea:** `{ title: "Add API key auth to the public endpoints", body: "Let callers authenticate the read API with
129+
an API key instead of leaving it open.", targetRepo: "acme/widgets", acceptanceHints: ["existing callers keep
130+
working during rollout"] }`
131+
132+
**Task-graph (ordered by `dependsOn`):**
133+
- `issue-1`*"Introduce API-key store + validation helper"*, labels `[gittensor:feature]`, `dependsOn: []`
134+
- AC1 (behavior): a valid key validates; an unknown/expired key is rejected
135+
- AC2 (artifact): keys are stored hashed, never in plaintext
136+
- `feasibility`: `{ claimStatus: "unclaimed", duplicateClusterRisk: "none", issueStatus: "ready", found: true }``go`
137+
- `issue-2`*"Gate the read endpoints behind key validation"*, labels `[gittensor:feature]`, `dependsOn: ["issue-1"]`
138+
- AC1 (behavior): a request with a valid key succeeds; without one is rejected
139+
- AC2 (constraint, from `acceptanceHints`): a documented grace/rollout path keeps existing callers working
140+
- `feasibility`: `{ claimStatus: "unclaimed", duplicateClusterRisk: "none", issueStatus: "hold", found: true }`
141+
`hold` because `issue-1` has not landed → **`raise`** (`issue_quality_uncertain`)
142+
- **rubric →** graph verdict = least-favorable = **`raise`**: `issue-1` is claimable now (`go`), `issue-2` is
143+
correctly held until its prerequisite lands, then re-scores to `go`.
144+
145+
## Acceptance-criteria checklist (per #4779)
146+
147+
- [x] Input schema for an idea submission — §1.
148+
- [x] Translation rules idea → structured, claimable task-graph (constituent issues, per-issue acceptance
149+
criteria, scoring rubric) — §2, §3.
150+
- [x] At least two fully worked examples (one simple, one multi-step) traced end-to-end — §4.
151+
- [x] Concrete enough for the freeform feasibility scoring (#5671) to implement against — the rubric maps idea
152+
text onto the exact `FeasibilityGateInput` discriminants `buildFeasibilityVerdict` already consumes.

0 commit comments

Comments
 (0)