recordMaintainerFeedback(problem, tool_area, trigger, suggested_direction?)
│ (called by the retro-analyst, or by a dev/reviewer during /flow:run)
▼
src/tools/record-maintainer-feedback.ts
│ • validates the item against schemas/maintainer-feedback.ts
│ • writes one JSON file → .flow/maintainer-inbox/-.json ← durable, full detail
│ • this is the PRIMARY side-effect; the URL is a "bonus for live sessions"
▼
… time passes; you ask to review the inbox …
▼
reviewMaintainerInbox(targetRepoRoot) [src/tools/review-maintainer-inbox.ts]
│ 1. reads every .flow/maintainer-inbox/*.json
│ 2. resolveGhRepoIdentity() ──────────────► runs gh repo view --json owner,name ★ THE BUG
│ └─ returns { owner, repo } of the CURRENT repo's gh origin → folio
│ └─ returns null if gh unavailable → items listed WITHOUT a link (fail-soft)
│ 3. for each item: buildFeedbackIssueUrl({ owner, repo, item }) [build-feedback-issue-url.ts]
│ • composeFeedbackIssueTitle → "[tool-feedback] : <problem…120>"
│ • composeFeedbackIssueBody → Problem / Tool area / Suggested direction / Trigger
│ • base = https://github.com///issues/new
│ • ?title=encodeURIComponent(...)&body=encodeURIComponent(...)
│ • AC3 guard: if URL > 8192 bytes → binary-search-truncate body + "(shortened)" note
│ 4. renderFeedbackLinkBlock(url, title, body)
│ → 3 forms: Open in GitHub · bare url · gh issue create --title … --body …
▼
returns { items:[{ …, issueUrl }], _message: "" }
Where the logic needs updating — resolveGhRepoIdentity (line 243)
This is the bug you intuited. The URL builder (buildFeedbackIssueUrl) is correct and generic — it takes whatever { owner, repo } it's handed. The problem is upstream, in how reviewMaintainerInbox resolves that owner/repo:
// build-feedback-issue-url.ts:257
const stdout = impl("gh repo view --json owner,name", …) // ← the CURRENT working repo
resolveGhRepoIdentity runs gh repo view against the cwd — which is the target project (claude-transcribe → origin folio). So every maintainer-feedback link is hard-wired to the project's repo, never the Flow plugin's repo. But a maintainer finding is, by definition, a bug in Flow — it should always file against jackmcintyre/flow, regardless of which project surfaced it.
The design comment even admits the assumption (line 27): "Owner/repo resolution is the CALLER'S responsibility (via gh repo view)" — and the caller (review-maintainer-inbox.ts) just calls resolveGhRepoIdentity() with no override. There's no seam to say "this issue belongs to the plugin, not the project."
The fix (in Flow, your repo): reviewMaintainerInbox should target the plugin's own repo for maintainer feedback, not the target project's. Options, cheapest first:
- (a) Hard-code the Flow repo identity (jackmcintyre/flow, or read it from the plugin's own package.json/marketplace.json) for maintainer-inbox links — since every maintainer finding is a Flow bug by construction. Cleanest.
- (b) Add an issueRepo override param to buildFeedbackIssueUrl's caller, defaulting to the plugin repo for the maintainer-feedback path while leaving other gh-issue paths on the project repo.
- (c) Stamp the resolved plugin repo at recordMaintainerFeedback time (when the plugin's own location is known) and store it in the inbox JSON, so review-time just reads it.
(a) or (c) are the right call — a maintainer finding's destination is knowable at record time and is invariant: it's always Flow.
recordMaintainerFeedback(problem, tool_area, trigger, suggested_direction?)
│ (called by the retro-analyst, or by a dev/reviewer during /flow:run)
▼
src/tools/record-maintainer-feedback.ts
│ • validates the item against schemas/maintainer-feedback.ts
│ • writes one JSON file → .flow/maintainer-inbox/-.json ← durable, full detail
│ • this is the PRIMARY side-effect; the URL is a "bonus for live sessions"
▼
… time passes; you ask to review the inbox …
▼
reviewMaintainerInbox(targetRepoRoot) [src/tools/review-maintainer-inbox.ts]
│ 1. reads every .flow/maintainer-inbox/*.json
│ 2. resolveGhRepoIdentity() ──────────────► runs
gh repo view --json owner,name★ THE BUG│ └─ returns { owner, repo } of the CURRENT repo's gh origin → folio
│ └─ returns null if gh unavailable → items listed WITHOUT a link (fail-soft)
│ 3. for each item: buildFeedbackIssueUrl({ owner, repo, item }) [build-feedback-issue-url.ts]
│ • composeFeedbackIssueTitle → "[tool-feedback] : <problem…120>"
│ • composeFeedbackIssueBody → Problem / Tool area / Suggested direction / Trigger
│ • base = https://github.com///issues/new
│ • ?title=encodeURIComponent(...)&body=encodeURIComponent(...)
│ • AC3 guard: if URL > 8192 bytes → binary-search-truncate body + "(shortened)" note
│ 4. renderFeedbackLinkBlock(url, title, body)
│ → 3 forms: Open in GitHub · bare url ·
gh issue create --title … --body …▼
returns { items:[{ …, issueUrl }], _message: "" }
Where the logic needs updating — resolveGhRepoIdentity (line 243)
This is the bug you intuited. The URL builder (buildFeedbackIssueUrl) is correct and generic — it takes whatever { owner, repo } it's handed. The problem is upstream, in how reviewMaintainerInbox resolves that owner/repo:
// build-feedback-issue-url.ts:257
const stdout = impl("gh repo view --json owner,name", …) // ← the CURRENT working repo
resolveGhRepoIdentity runs gh repo view against the cwd — which is the target project (claude-transcribe → origin folio). So every maintainer-feedback link is hard-wired to the project's repo, never the Flow plugin's repo. But a maintainer finding is, by definition, a bug in Flow — it should always file against jackmcintyre/flow, regardless of which project surfaced it.
The design comment even admits the assumption (line 27): "Owner/repo resolution is the CALLER'S responsibility (via gh repo view)" — and the caller (review-maintainer-inbox.ts) just calls resolveGhRepoIdentity() with no override. There's no seam to say "this issue belongs to the plugin, not the project."
The fix (in Flow, your repo): reviewMaintainerInbox should target the plugin's own repo for maintainer feedback, not the target project's. Options, cheapest first:
(a) or (c) are the right call — a maintainer finding's destination is knowable at record time and is invariant: it's always Flow.