Skip to content

feat(engine): represent idea targetRepo as an existing-vs-provision union - #7710

Merged
JSONbored merged 1 commit into
JSONbored:mainfrom
davion-knight:feat-idea-target-union
Jul 21, 2026
Merged

feat(engine): represent idea targetRepo as an existing-vs-provision union#7710
JSONbored merged 1 commit into
JSONbored:mainfrom
davion-knight:feat-idea-target-union

Conversation

@davion-knight

Copy link
Copy Markdown
Contributor

Problem

IdeaSubmission.targetRepo (packages/loopover-engine/src/idea-intake.ts) is a plain string, assuming a repo already exists (BYOR only). With auto-provisioned repos (#7589) confirmed direction, this pure IO-free bridge module needs to represent both cases so downstream consumers know which path a submission takes.

Change

export type IdeaTarget =
  | { kind: "existing"; repo: string }
  | { kind: "provision" };

IdeaSubmission.targetRepo is retyped to IdeaTarget.

Backward-compatible input (no wire-contract break). Validation still accepts a bare "owner/name" string as the existing-repo form (same regex/error codes) and resolves it to { kind: "existing", repo }; a { kind: "provision" } object requests a not-yet-created repo. The zod request schemas are deliberately unchanged — an existing BYOR caller POSTing the historical bare string keeps working.

No consumer file touched. buildClaimPlan now accepts IdeaTarget | string and resolves it to a repo string internally ("" for a not-yet-provisioned target). Every caller threading a submission's targetRepo into it (the /v1/loop/plan-idea-claims route, the remote MCP server, the MCP CLI bin) compiles unchangedClaimStep/ClaimPlan.targetRepo stays a plain string. The whole diff is the engine module + its test.

Verification

  • packages/loopover-engine/src/idea-intake.ts: 100% — 90/90 statements, 98/98 branches (both validation forms incl. provision + malformed + object-without-provision-kind rejection, and all three buildClaimPlan argument shapes: bare string, existing target, provision target).
  • Root npm run typecheck exits 0; @loopover/engine build exits 0; the mcp bin is untouched so check-build-drift stays clean.
  • Affected suites pass: idea-intake-bridge, routes-intake-idea, routes-plan-idea-claims, mcp-cli-plan-idea-claims-tool. Bare-string input still validates, so the intake tests need no changes.

Closes #7635

@davion-knight
davion-knight requested a review from JSONbored as a code owner July 21, 2026 10:13
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.55%. Comparing base (3a9450b) to head (7994ebf).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7710      +/-   ##
==========================================
- Coverage   88.56%   88.55%   -0.01%     
==========================================
  Files         725      725              
  Lines       76266    76271       +5     
  Branches    22705    22707       +2     
==========================================
+ Hits        67544    67545       +1     
  Misses       7680     7680              
- Partials     1042     1046       +4     
Flag Coverage Δ
shard-1 52.84% <57.14%> (-0.01%) ⬇️
shard-2 51.91% <28.57%> (-0.05%) ⬇️
shard-3 48.47% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/loopover-engine/src/idea-intake.ts 100.00% <100.00%> (ø)
packages/loopover-mcp/bin/loopover-mcp.js 0.00% <ø> (ø)

... and 1 file with indirect coverage changes

…nion

IdeaSubmission.targetRepo was a plain string, assuming a repo already exists
(BYOR only). With auto-provisioned repos (JSONbored#7589) confirmed direction, this
pure IO-free bridge module needs to represent both cases so downstream
consumers know which path a submission takes.

Introduce IdeaTarget = { kind: "existing"; repo: string } | { kind: "provision" }
and retype targetRepo to it. Validation stays backward-compatible: a bare
"owner/name" string is the existing-repo wire form (format-checked as before),
a { kind: "provision" } object requests a not-yet-created repo. Same error
codes (target_repo_required / target_repo_malformed), and the zod request
schemas are unchanged so an existing BYOR caller POSTing the bare string keeps
working.

buildClaimPlan now accepts IdeaTarget | string and resolves it to a repo
string internally ("" for a not-yet-provisioned target), so every caller
threading a submission's targetRepo compiles unchanged -- no consumer file
touched, ClaimStep/ClaimPlan.targetRepo stays a plain string.

Closes JSONbored#7635
@davion-knight
davion-knight force-pushed the feat-idea-target-union branch from 745357e to 7994ebf Compare July 21, 2026 10:23
@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 21, 2026
@loopover-orb

loopover-orb Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-21 10:36:33 UTC

4 files · 1 AI reviewer · no blockers · readiness 98/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This retypes IdeaSubmission.targetRepo from a bare string to a discriminated IdeaTarget union (existing vs provision), while preserving backward-compatible wire input (bare 'owner/name' string still validates and resolves to {kind:'existing'}) and keeping buildClaimPlan/ClaimStep/ClaimPlan.targetRepo as plain strings so no downstream consumer needs changes. The validation and resolution logic in idea-intake.ts is correctly traced: resolvedTarget is only set on success paths and errors are pushed otherwise, and buildClaimPlan's target-to-string resolution correctly handles all three input shapes (string, existing, provision). Tests cover both validation branches (string/object) and all three buildClaimPlan argument shapes, matching the stated 100% coverage claim.

Nits — 4 non-blocking
  • idea-intake.ts:104 uses an inline object-shape check `(input.targetRepo as Record<string, unknown>).kind === "provision"` rather than a small type guard — fine here but slightly harder to extend if a third IdeaTarget variant is added later.
  • packages/loopover-engine/src/index.ts is now ~627 lines per the external size-smell note; not something this diff needs to fix, but worth flagging for a future split of the barrel export file.
  • The malformed-object rejection test only covers `{}` and `{kind:'existing'}` — consider also asserting `{kind:'provision', repo:'x'}` (extra property) still resolves cleanly, to lock in that resolvedTarget ignores extraneous fields.
  • If a third target kind is anticipated (e.g. Epic: dual-path repo provisioning — BYOR + APR #7589's auto-provisioning may need repo-name hints), consider whether `{kind:'provision'}` should eventually carry an optional preferred name — but only if that's in scope for a future issue, not this one.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #7635
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 146 registered-repo PR(s), 91 merged, 4 issue(s).
Contributor context ✅ Confirmed Gittensor contributor davion-knight; Gittensor profile; 146 PR(s), 4 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Addressed
The diff adds the exact IdeaTarget discriminated union and retypes IdeaSubmission.targetRepo as required, updates validateIdeaSubmission to resolve either a bare string or a provision object into the union, and updates the test file to cover both variants without regressing coverage.

Review context
  • Author: davion-knight
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, Rust
  • Official Gittensor activity: 146 PR(s), 4 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@JSONbored
JSONbored merged commit d7042ef into JSONbored:main Jul 21, 2026
12 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 21, 2026
12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add existing-vs-provision target discriminated union to IdeaSubmission.targetRepo

3 participants