Repository navigation
Owner decisions as one-click actions in the Issues and PR panes #46
Copy link
Copy link
Open
Description
Owner request, 2026-10-15, from the ePC-SAFT orchestrator thread. Related: #43 and #44 (Issues pane), and the issue-upkeep approval flow behind propose_issue_change.
Problem
Repository orchestrators regularly reach decisions only the owner can make:
- adopt a change whose evidence is mixed;
- close an issue on the agent's recommendation;
- confirm an allowance the lead set while the owner was away.
Today those decisions live in chat or in issue comments, and there are four ways the owner can lose them:
- The question tool (
AskUserQuestion/request_user_input) shows buttons, but when the owner is away it auto-answers "choose the recommended option". That answer is not an owner decision, so the decision is lost or has to be asked again. - GitHub's PR Approve button can't be used: agents open PRs under the owner's account, and GitHub doesn't let authors approve their own PRs.
- Checkboxes in an issue body change the body, and the T3 issue inbox doesn't track body edits, so the agent never hears the answer.
- Issue-upkeep approval mode makes every agent issue edit wait for approval. It applies to routine status updates too, which is too noisy, and it doesn't cover merges.
Wanted
- A decision request an agent can post on an issue or PR. It carries a short question, two to four options, the agent's recommendation and its evidence link, and what happens after each choice.
- A Decisions view, or a filter in the Issues and PR panes, listing every open decision request across projects, with the option buttons inline. One click records the owner's choice.
- The choice is durable and owner-authored. It can't come from away-mode or agent answers, and it is recorded on GitHub as a comment or label for history.
- The requesting orchestrator is woken with the choice, through the issue inbox or a task notification, and acts on it.
- Optional: a badge on the thread and project when decisions are waiting, and a hover card on the decision row showing the evidence summary (see Issues pane as a modular extension of upstream's pull request pane: gather ideas, borrow its patterns #44's hover-card ideas).
Example
Waiting at the time of writing on tannerpolley/ePC-SAFT:
- Support Ubuntu .deb desktop builds pingdotgg/t3code#543: adopt CppAD tape optimization, which is 29–47 % faster with rounding-driven near-critical corpus changes. The lead recommends adopting.
- fix: preserve cursor behavior in plan question mode pingdotgg/t3code#529: close the issue (recommended).
- Confirm the lead-set line allowances and the Tighten chat layout, composer spacing, and sidebar handling pingdotgg/t3code#505 equivalence rule.
Interim workaround
Until this exists, the agent can tag such issues decision-needed and act on a decision:approve or decision:decline label, or a one-word comment. The inbox does track label changes and comments.
Reactions are currently unavailable
Activity
tannerpolley commentedon Oct 20, 2026
Orchestrator review (2026-10-20): still relevant; it starts with a design for the owner's approval.
Nothing in the code implements decision requests yet. The question tool's away-mode problem is unchanged; that setting is now called Ask mode (#59).
Stage 1, when this issue's queue notice arrives (owner decision 2026-10-20): its worker posts a short design here, covering:
The owner approves the design, then the same issue gets built. Until then, the interim
decision-needed/decision:approvelabels keep working through the inbox.tannerpolley commentedon Oct 20, 2026
T3 Code status: Done
Issue: #46 Owner decisions as one-click actions in the Issues and PR panes
Thread: thread:delegated-task:command%3Amcp%3A667e5306-5428-4b55-a9f6-4ae3fcb3609b%3Adelegate-task%3Apr72-fix-1
Model: gpt-6.1-sol
Branch: issue-46-owner-decisions-as-one-click-actions-in-4
Updated: 2026-10-21T00:35:33.730Z
tannerpolley commentedon Oct 20, 2026
T3 Code closeout: done
Issue: #46 Owner decisions as one-click actions in the Issues and PR panes
Thread: thread:delegated-task:command%3Amcp%3A667e5306-5428-4b55-a9f6-4ae3fcb3609b%3Adelegate-task%3Aissue-46-design-1
Model: gpt-6.1-sol
Branch: issue-46-owner-decisions-as-one-click-actions-in
Completed: 2026-10-20T23:59:11.156Z
Recommendation
Use a small server-side decision record, mirrored to GitHub comments. GitHub preserves the history; the server proves which choice came through T3’s owner interface and reliably wakes the requester.
This design follows #46 and its comments. No product code changed, servers started, live userdata accessed, or GitHub writes made.
1. Request and storage
Each immutable request contains:
A fork migration adds one authoritative table holding that request, its GitHub comment reference, state, owner choice, authenticated owner identity, timestamps, and pending publication/delivery steps. States distinguish publishing, awaiting choice, answered, withdrawn, and failed publication.
GitHub-only storage cannot establish owner authorship because agents share the owner’s login. This constraint already appears in IssueInboxRules.ts; durable records and delivery receipts have precedents in migration 015 and migration 006.
2. Agent tools
Add three MCP tools:
request_owner_decision: publish a request; retries return the same request.list_owner_decisions: list requests and their current state within the caller’s permitted scope.withdraw_owner_decision: withdraw the caller’s unanswered request, with a reason.There is no agent tool for choosing. Changing options requires withdrawal and a new request.
Reuse caller identity and GitHub posting helpers from IssueInboxMcpTools.ts, without making arbitrary
t3_issue_postcomments into trusted requests.propose_issue_changeremains the owner of exact issue mutations. A decision can link its preview, but answering does not approve that separate proposal or bypass its gates. Do not reuse its automatic approval policy for owner decisions. See IssueChangeService.ts.3. Owner interface
Add a Decisions filter with a count in the shared IssueBrowser.tsx, covering both the Issues page and thread-side Issues pane.
Rows show the full question, target, requesting project/thread, recommendation, evidence link, and inline option buttons. Each option exposes its consequence before selection; the recommendation is marked but never preselected. Clicking records the choice, disables competing buttons, and shows publication status.
The all-project view collects records from connected environments, with project/repository filters and visible offline warnings. Writes return to the environment owning the record.
A fork-owned component also appears above issue detail content, beside existing change cards. Later, reuse it in the PR list filter, thread PR pane, and PR detail panel. Reuse PullRequestListRow.tsx and PullRequestDetailLayout.tsx, following #44. Thread/project count badges and evidence hover cards are optional later additions.
4. Durable owner choices
Publish a readable request comment plus a versioned structured marker:
<!-- t3-decision-request:v1 id=D42 -->The comment includes the complete question, options, consequences, recommendation, evidence, and requester.
A choice appends another readable comment: “Owner chose Adopt for D42,” with the consequence, timestamp, and request link, plus:
<!-- t3-decision-choice:v1 id=D42 option=adopt -->The server accepts choices only through an authenticated owner-client command, using the user/scopes checks demonstrated in ForkWsRpc.ts. Choice and publication work commit together; concurrent clicks accept one choice. Retries reconcile comment markers before reposting.
These records never become runtime questions. Today DontAskModeWorker.ts selects the first option and accepts ordinary approvals when Ask mode is off; it cannot touch decisions.
This enforces T3’s user/agent credential boundary. GitHub markers alone—and unrestricted access to owner credentials—cannot prove a physical human acted.
5. Wake-up
Reuse the inbox’s durable queued-message delivery pattern, with a stable command identifier. After the choice comment is confirmed, send:
Delivery retries after restart. An unavailable requester leaves visible undelivered work; repository handoff resolves the destination.
Do not depend on ordinary polling: IssueInboxWatcher.ts excludes PR comments, while IssueInbox.ts digests tagged activity. Keep decision responses separate from issue admission in IssueQueueCommands.ts.
6. Labels and batches
Keep the manual workaround. Managed requests use
decision-needed; remove it only when no managed requests remain. Legacydecision:approve/decision:declinelabels remain inbox signals, never verified owner receipts.Estimated files, including focused tests:
Follow fork.md and #24: small hooks, fork-owned modules. Web and desktop apply; mobile is outside this fork’s scope.
7. Owner decisions before implementation
No tests or UI verification were run for this read-only design. The identity guarantee needs explicit agreement before implementation.
tannerpolley commentedon Oct 21, 2026
Stage 1 design (2026-10-20). Waiting for owner approval; nothing is built. Read-only research by GPT-6.1 Sol (high) against
main.Recommendation
A small server-side decision record, mirrored to GitHub comments. GitHub keeps the history. The server proves the choice came through T3's owner interface, and wakes the thread that asked.
GitHub alone can't prove the owner chose: agents post under the owner's login (see
apps/server/src/issues/IssueInboxRules.ts).1. Request and storage
Each request is immutable. It holds:
A fork migration adds one table for the request, its GitHub comment, its state, the owner's choice and identity, timestamps, and the publish and delivery steps. The states are publishing, awaiting choice, answered, withdrawn and publication failed. The same pattern is used in migrations 015 (issue inbox) and 006 (issue changes).
2. Agent tools
request_owner_decision: publishes a request. A retry returns the same request.list_owner_decisions: lists requests within the caller's scope.withdraw_owner_decision: withdraws the caller's unanswered request, with a reason.There is no agent tool for choosing. To change the options, withdraw the request and post a new one.
propose_issue_changekeeps owning exact issue edits: a decision may link one, but answering a decision doesn't approve it.3. Owner interface
IssueBrowser.tsx, covering both the Issues page and the thread's Issues pane.PullRequestListRow.tsxandPullRequestDetailLayout.tsx(see Issues pane as a modular extension of upstream's pull request pane: gather ideas, borrow its patterns #44).4. Durable, owner-authored choices
<!-- t3-decision-request:v1 id=D42 -->.<!-- t3-decision-choice:v1 id=D42 option=adopt -->.ForkWsRpc.ts). Concurrent clicks accept one choice.DontAskModeWorker.ts), can't answer them.5. Wake-up
The inbox's durable delivery sends the requester a message, for example "Owner decision D42 on owner/repo#123: Adopt. Next: … Evidence: … Owner record: …". It's retried after a restart. It doesn't rely on inbox polling, which skips PR comments, and it stays separate from issue admission.
6. Labels and batches
decision-needed, which is removed when none remain.decision:approveanddecision:declinestay inbox signals, never verified choices.Questions for the owner (recommendation in bold)
tannerpolley commentedon Oct 21, 2026
Approval status (2026-10-20): the question to approve this design was answered while the owner was away (Don't ask mode). Per this issue's own rule, an away-mode answer isn't an owner decision, so it doesn't count as approval.
Batch A is being built as designed, with the recommended answers to all five questions, so the worker slot isn't idle. It won't merge until the owner approves the design in person.
tannerpolley commentedon Oct 21, 2026
T3 Code closeout: done
Issue: #46 Owner decisions as one-click actions in the Issues and PR panes
Thread: thread:delegated-task:command%3Amcp%3A667e5306-5428-4b55-a9f6-4ae3fcb3609b%3Adelegate-task%3Aissue-46-batch-a-1
Model: gpt-6.1-sol
Branch: issue-46-owner-decisions-as-one-click-actions-in-2
Completed: 2026-10-21T00:20:57.337Z
Batch A is implemented and pushed. The worktree is clean.
issue-46-owner-decisions-as-one-click-actions-in020_OwnerDecisions, adding the authoritative decision table and pending-work indexes.request_owner_decision,list_owner_decisions, andwithdraw_owner_decision, with presentation labels. There is no agent tool for choosing.issues.decisions.list,issues.decisions.choose, andissues.decisions.subscribe.publishing,awaiting_choice,answered,withdrawn, andpublication_failed.The choice RPC takes identity and scopes from the authenticated client session. The service requires a user actor and
orchestration:operate; the client usescreateEnvironmentRpcCommandand its permission atom. A transactional compare-and-set accepts one winning choice and commits its publication and delivery work together.GitHub publication reconciles request and choice markers before reposting. Confirmed choices notify the requester through a system
message.dispatchusing a stable command ID andqueue_after_active. Failed delivery remains visible and retries after restart. Decisions never enter runtime-question storage, so Ask mode cannot answer them.The shared Issues browser has the Decisions filter and count, project/repository filtering, cross-environment gathering, and offline warnings. Issue details show decision cards with consequences visible before selection. Writes target the environment owning each record. The user documentation includes the identity limit.
Validation passed:
Full changed-file lint still fails on existing errors in
IssueBrowser.tsxandIssueDetailPanel.tsx. I reproduced those errors on their pre-change versions; the evidence is in the baseline lint log.No PR was opened. The branch is ready for orchestrator review and PR creation; merge still requires the owner’s in-person design approval. Browser verification was not run. Batch B, optional badges, and mobile remain outside this delivery.
tannerpolley commentedon Oct 21, 2026
T3 Code closeout: done
Issue: #46 Owner decisions as one-click actions in the Issues and PR panes
Thread: thread:delegated-task:command%3Amcp%3A667e5306-5428-4b55-a9f6-4ae3fcb3609b%3Adelegate-task%3Apr72-review-1
Model: gpt-6.1-sol
Branch: issue-46-owner-decisions-as-one-click-actions-in-3
Completed: 2026-10-21T00:25:52.273Z
Found three P2 defects in draft PR #72 at
dff447f58f:Decision delivery ignores repository handoff. OwnerDecisions.ts:465
If root A requests a decision, hands ownership to B, and the owner then answers, delivery still targets A. It never follows
retiredToThreadIdor resolves the current repository owner. An unarchived A receives the message and the record is marked delivered; an archived A leaves it retrying indefinitely. B never receives the decision. Resolve and durably record the delivery destination through the handoff chain while preserving duplicate-delivery protection.Reconciliation accepts altered or forged comments as the published owner record. OwnerDecisions.ts:365
Reconciliation checks only whether a comment contains the marker. For example, a choice comment is posted, its response is lost, and its readable text is edited while its marker remains. The retry accepts that altered comment, marks publication complete, and wakes the requester with its URL—even if the text contradicts the recorded choice or consequence. A preexisting comment quoting the marker produces the same result. Validate the expected audit content before accepting a matching comment; surface a mismatch instead of confirming publication.
One environment can remove another environment’s
decision-neededlabel. OwnerDecisions.ts:431Two connected environments can each publish a request on the same GitHub issue. When the final local request in environment B is answered or withdrawn, B counts only its own database rows and deletes the shared label, although environment A still has an unanswered request. A has already cleared
pending_label, so it does not restore the label. Label removal needs to account for outstanding managed requests from other environments.The requested checks passed: 97 server tests across eight files, all 25 client permission tests, and server/web/contracts type checks.
Read-only review completed; the checkout remains clean. Browser verification was excluded as requested. These defects and the owner’s in-person design approval remain open gates.
tannerpolley commentedon Oct 21, 2026
T3 Code closeout: done
Issue: #46 Owner decisions as one-click actions in the Issues and PR panes
Thread: thread:delegated-task:command%3Amcp%3A667e5306-5428-4b55-a9f6-4ae3fcb3609b%3Adelegate-task%3Apr72-fix-1
Model: gpt-6.1-sol
Branch: issue-46-owner-decisions-as-one-click-actions-in-4
Completed: 2026-10-21T00:35:33.182Z
Committed and pushed afdb99c698 to
issue-46-owner-decisions-as-one-click-actions-infor draft PR #72. The requested co-author trailer is present, and the worktree is clean.retiredToThreadIdchains or the repository owner lookup, then persistsdeliveryThreadIdbefore dispatch. Retries retain that destination and the original command ID. The restart test verifies one persisted message despite a lost delivery receipt. Deleted or archived requesters without a successor now enter visibledelivery_failed, stopping delivery retries. Migration021_OwnerDecisionDeliveryadds the stored destination.publication_mismatch, with a reason. I chose terminal failure: publication and delivery work are cleared, so it cannot loop through retries or replacement posts.decision-needed, the service checks GitHub comments for unresolved requests from any environment. Altered withdrawal comments cannot close a request.Validation completed:
prefer-effect-fnerrors inIssueInbox.ts, reproduced on the original file. Evidence: current lint log, baseline lint log.The label check reads at most 100 comments; if more pages exist, it conservatively retains the label. Browser verification and repo-wide checks were not run. #46 remains open.
tannerpolley commentedon Oct 21, 2026
Migration numbering for the batch A draft (PR #72): #80 takes fork migration 020 (
020_MarkedIssueInbox) because it merges first. Before #72 lands, renumber its020_OwnerDecisionsand021_OwnerDecisionDeliveryto 021 and 022, in the files and inForkMigrations.tsand its test. The fork migrator skips any id below the highest one already applied, so a lower number would never run on an upgraded database.