You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We have two question types that are both approval flows:
Type
Attachments
Decisions
approval
not rendered
approved / rejected / abstained
documentReview
rendered with review checkboxes
approved / changes_requested / comment_only
Both ask a human to make an approval decision. The only real difference is whether the reviewer needs to look at an attached document. That is not a reason to have two types — it is a reason to make attachments optional on one type.
Having two types forces the outpost to know upfront whether a document will be attached. It also confuses outpost authors: "which one do I use?"
Decision set analysis
Before proposing the merge, it is worth clarifying what each decision value means for the agent:
Decision
Agent behavior
Status
approved
proceed
keep
rejected
stop, fix
keep
changes_requested
stop, fix
same as rejected — merge into rejected
comment_only
proceed (same as approved + comment)
no separate behavior — drop
abstained
undefined — agent stuck
no defined outcome — drop
Simplified: two outcomes, two buttons.
Decision
Agent behavior
Comment
approved
proceed
optional
rejected
stop + fix
required
Proposal
Single approval type. Attachments optional. Two decisions: approved / rejected.
Type shape
Field
Rule
type
"approval"
attachmentList
optional. If present — UI renders attachment list with "I reviewed this" checkboxes before decision buttons. If absent — decision buttons only.
deliverableSummary
optional. Describes document content when attachments present.
reviewLinks
optional on both cases.
Answer shape
"answer": {
"approvalDecision": "approved | rejected",
"comment": "optional on approved; required on rejected",
"reviewedAttachmentIds": ["..."] // present when attachmentList non-empty; reviewer must confirm at least one
}
Answer: approved or rejected + comment, plus reviewedAttachmentIds.
What changes
Validator (QuestionTemplateValidator.cs)
Drop documentReview from QuestionTypes.AllowedTypes
Allow attachmentList on approval
Update ApprovalDecisions.ApprovalAllowed to [ "approved", "rejected" ]
Drop DocumentReviewAllowed
comment required when approvalDecision = "rejected"
Web form (Respond.cshtml)
Merge case QuestionTypes.DocumentReview into case QuestionTypes.Approval
Within approval case: branch on Model.Template.Attachments is { Count: > 0 } to render attachment list + review checkboxes
Decision buttons: Approve + Reject only (drop Abstain, changes_requested, comment_only)
Outpost UI (actions.js) + dual-surface push-back
PR #417 implements dual-surface push-back for approval type: reviewer clicks Approve / Reject / Abstain in the Outpost Decisions tab, outpost POSTs back to mothership /api/responses with answeredVia: "outpost".
PR [PR-11/#29] Dual-surface approval (P2) #417 must render the attachment list + review checkboxes when question.attachmentList is non-empty (currently only the mothership web form does this)
Send-LocalApprovalResponse payload shape stays the same — just fewer valid approvalDecision values
Dual-surface push-back stays scoped to approval per issue #29. The merged type covers both doc and no-doc cases within that scope.
Other types: singleChoice, freeText, priorityRanking
Escalation decisions — future versions may add decision values that trigger escalation (e.g. escalated, needs_more_info) to signal the agent to ask a different person or wait. Not in scope now (YAGNI — no escalation mechanism exists yet). Add when role routing (Project team and roles (v4 phase 14) #98) lands.
[PR-13/#29] Merge
approvalanddocumentReviewinto oneapprovaltypeParent
#29
Problem
We have two question types that are both approval flows:
approvaldocumentReviewBoth ask a human to make an approval decision. The only real difference is whether the reviewer needs to look at an attached document. That is not a reason to have two types — it is a reason to make attachments optional on one type.
Having two types forces the outpost to know upfront whether a document will be attached. It also confuses outpost authors: "which one do I use?"
Decision set analysis
Before proposing the merge, it is worth clarifying what each decision value means for the agent:
approvedrejectedchanges_requestedrejected— merge intorejectedcomment_onlyabstainedSimplified: two outcomes, two buttons.
approvedrejectedProposal
Single
approvaltype. Attachments optional. Two decisions:approved/rejected.Type shape
type"approval"attachmentListdeliverableSummaryreviewLinksAnswer shape
Examples
Approval without document:
{ "type": "approval", "title": "Approve architecture v2 - monolith split", "description": "Move auth, billing, notifications into services.", "options": [] }Answer:
approvedorrejected+ comment.Approval with document:
{ "type": "approval", "title": "Review PRD draft - billing service", "deliverableSummary": "Billing service - invoice API, async events, Postgres datastore.", "options": [], "attachmentList": [ { "id": "...", "name": "prd-billing-service.pdf", "contentType": "application/pdf", "sizeBytes": 184500 } ] }Answer:
approvedorrejected+ comment, plusreviewedAttachmentIds.What changes
Validator (
QuestionTemplateValidator.cs)documentReviewfromQuestionTypes.AllowedTypesattachmentListonapprovalApprovalDecisions.ApprovalAllowedto[ "approved", "rejected" ]DocumentReviewAllowedcommentrequired whenapprovalDecision = "rejected"Web form (
Respond.cshtml)case QuestionTypes.DocumentReviewintocase QuestionTypes.Approvalapprovalcase: branch onModel.Template.Attachments is { Count: > 0 }to render attachment list + review checkboxesOutpost UI (
actions.js) + dual-surface push-backPR #417 implements dual-surface push-back for
approvaltype: reviewer clicks Approve / Reject / Abstain in the Outpost Decisions tab, outpost POSTs back to mothership/api/responseswithansweredVia: "outpost".This merge is compatible with PR #417:
approvalstays — no rename neededapproved/rejectedonly)question.attachmentListis non-empty (currently only the mothership web form does this)Send-LocalApprovalResponsepayload shape stays the same — just fewer validapprovalDecisionvaluesDual-surface push-back stays scoped to
approvalper issue #29. The merged type covers both doc and no-doc cases within that scope.Out of scope
singleChoice,freeText,priorityRankingescalated,needs_more_info) to signal the agent to ask a different person or wait. Not in scope now (YAGNI — no escalation mechanism exists yet). Add when role routing (Project team and roles (v4 phase 14) #98) lands.