DOC23 Add B Review Studio D1.md
Active Working and Red Team/DOC23 Working/DOC23 Non Operative Proposals/DOC23 Add B Review Studio D1.md
ELNOR REPO READER TEXT MIRROR
Original path: Active Working and Red Team/DOC23 Working/DOC23 Non Operative Proposals/DOC23 Add B Review Studio D1.md
Source repo: /Users/OpenClaw1/Elnor/Elnor Specs
Git branch: main
Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331
Generated: 2026-06-09T01:23:58.539Z
---
````
# DOC23 Addenda B — Review Studio (Human Review & Agent-Assisted Revision)
**Type:** Design spec unit (draft, pending architect review + multi-LLM red-team).
**Target home:** `Current Specs/DOC23/DOC23 Addenda B/` (new module). Liftable into the consolidated adjudication card as a section; the card otherwise carries a one-line pointer.
**Module type id:** `step.review_studio`
**Status of dependencies:** A-01 finding model (event/record/view + `EvaluationAuthorityBasis`) is summarized in §2 at the level Review Studio relies on; its full adjudication remains a card Layer-1 item. The Gemini math/C-cluster audit is unrelated and remains a card row.
**Grounding rule (no phantom features):** every contract below traces to a cited section in DOC23 R3.1, Outcome Evaluator-Revisor V3.3.1, DOC20 R4.3, or DOC23 Addenda B Core R0.7.1 — or is explicitly flagged `OPEN_FOR_ARCHITECT_REVIEW`. Citations are inline. Appendix B is the consolidated operative-vs-net-new log.
---
## 0. Scope and non-goals
### 0.1 In scope
- The `step.review_studio` module (placeable form) and the intrinsic evaluate-revise gate (policy-toggled form).
- The complete human-review **input model** (`HumanReviewResult`, defined as a superset of DOC20's `DocumentReviewRequest`).
- **Materialization** of human comments into lifecycle-tracked objects (findings / run-scoped criteria) so they resurface across re-evaluation.
- The **agent-collaboration** layer: session continuity to the producing agent + the agent-selection ladder + agent-assisted in-place revision.
- The **output/routing** model and how it decomposes into the existing Feedback Interpreter pipeline (V3.3.1 §14).
- **Versioning / provenance / revalidation** wiring for human and co-authored edits.
- The **exposure** primitives: `LifecycleActorEnvelope`, the per-owner read contract, the gated (reserved) write capability.
### 0.2 Non-goals (explicit `slice.negative_space`)
- **NOT** redoing the automated Revisor's graph orchestration (V3.3.1 §6–§11). Review Studio does not plan or dispatch across the task graph (§1.2).
- **NOT** rewriting DOC20 UI mechanics beyond the review surface. DOC20-owned changes are collected, clearly labeled and liftable, in Appendix A. UI here is specified to **mockup-ready** depth (contracts tight, UI light).
- **NOT** building the Human-Review→Orchestrator engine or the review-gate learning-reasoner. Both are reserved (§11).
- This unit does **not** touch the memory-spec flatten. DOC23 is outside the flatten scope (Flatten plan §1.2); findings/comments/revisions remain DOC23/DOC20-owned task-system truth, not memory-system truth.
---
## 1. The module, and the boundary against the automated Revisor
### 1.1 One paragraph
Review Studio is a task-graph checkpoint where the human (a) reviews an output, (b) optionally **collaborates with the agent that produced it** — its working session resumed — to revise the artifact **in place** or get advice, and (c) **routes** the (possibly revised) version onward. It is the interactive, collaborative form of the current `step.user_review_gate` (DOC23 R3.1 §3.2.3): same "pause the run, human decides" spine, but with the DOC20 Document Viewer as the review surface and an agent-assist channel attached.
### 1.2 Boundary vs the automated Revisor (load-bearing — prevents two orchestrators)
| | Automated Revisor (V3.3.1 §6–§11) | Review Studio (this unit) |
|---|---|---|
| Driver | Agent-automated | Human-driven, agent-assisted |
| Operates on | The **task graph** (re-runs modules, escalates to Task Agent §6.9, forks) | **One artifact, in place** |
| Trigger | Findings / outcomes (revalidation cascade) | Human at a checkpoint |
| Output | Repaired graph state + new artifact version | Revised artifact version + a routing decision |
| Orchestration | Yes (RevisionPlan, RevisionDispatcher §11.1) | **No** — it co-edits one output, then hands off |
They **compose**: Review Studio's revised version can be routed into the automated loop, and the automated loop's output can land at a Review Studio checkpoint. The agent-assist inside Review Studio is a **scoped single-artifact edit** the human directs (the producing agent makes the changes), producing a new co-authored version — it is explicitly *not* a graph redo. This boundary is the reason the two do not collide.
### 1.3 Relationship to the other checkpoints
Review Studio is the **human-driven** checkpoint; it does not replace the other DOC23 review constructs:
- `step.agent_review_gate` (R3.1 §3.2.4) remains the **agent-reviews-agent** checkpoint.
- `step.panel` (R3.1 §3.2.5), a pointer to a DOC12 room, is the **forum** rung of the assist ladder (§6.1), used for multi-agent collaborative review.
- The `human_review_gate` experiment-winner **routing disposition** (Addenda A R227) opens a Review Studio surface when an experiment routes to human review.
---
## 2. Foundational dependency — the finding model (A-01), as relied on here
Review Studio renders Evaluator findings as anchored comments and lets the human dispose them; it also creates human-authored findings. It therefore depends on the A-01 finding model. The elements relied on (full definition and adjudication: card Layer 1):
```ts
// Immutable audit record of a finding as first observed in a given evaluation round.
interface EvaluationFindingEvent {
finding_event_id: string
outcome_id: string
target_artifact_ref: string
target_version_ref: string // findings are version-pinned (V3.3.1 §5.7)
target_scope_ref: TargetScopeRef | null // the anchor; maps to a DOC20 CommentAnchor (§3.6)
detected_at: string
severity: FindingSeverity // IMPORTANCE, never a halt (§2.1)
assurance_basis: AssuranceBasis[] // how much trust the finding carries
authority_basis: EvaluationAuthorityBasis[] // who/what authorizes it (9-value FD enum)
body: string
schema_version: 1
}
// Mutable lifecycle row keyed to the event; carries current state.
interface EvaluationFindingRecord {
finding_id: string
origin_event_id: string
state: FindingState // V3.3.1 §5.7 / §0.4.4
target_version_ref: string
actor: LifecycleActorEnvelope // §9.1 — who created/last-changed it
superseded_by_finding_id: string | null
resolved_by_receipt_ref: string | null // only Revisor receipts mark `resolved` (§5.7.2)
schema_version: 1
}
// Read-only projection the UI renders (the "copy"). No new truth store.
interface FeedbackFindingView {
finding_id: string
display_state: FindingState
anchor: TargetScopeRef | null
severity: FindingSeverity
body: string
history: FindingStateTransition[] // per-round snapshots → cross-round drift view
schema_version: 1
}
```
### 2.1 Severity is importance, not a halt (propagated decision)
`FindingSeverity` drives revision priority and human-review surfacing. It **never halts** the run. Only mechanical/system errors halt execution (`StepExecutionFailureKind`, DOC23 R3.1). An output is not auto-"passed" while serious findings are unresolved; it stays in the revision loop, and if unresolvable the termination logic (V3.3.1 §6.7.3) **escalates** (Gate-4 human review or "rely with limitations") rather than halting. Irreversible external actions (filing, sending) remain gated by an action permission — that is an action gate, not a finding block.
---
## 3. Input model — everything the user can submit at a Review Studio checkpoint
### 3.1 Complete input taxonomy (grounded in the current modules)
From the DOC23 gate (R3.1 §3.2.3 / §6.5.4) and the DOC20 review surface (§6.6.2, §6.10.4, §6.16.8):
1. **Decision** — Approve / Reject / Revise (incl. email APPROVE/REJECT/REVISE). [DOC23 §3.2.3]
2. **Rejection reason** (free text). [DOC23 §6.5.4]
3. **General instruction** (free text). [DOC23 textarea; DOC20 Send-to-Agent `instruction`]
4. **Attachments** (FileRef[]). [DOC23 revision payload; DOC20 §7.18]
5. **Anchored in-line comment** — `CommentAnchor` (text/page/line) + body + threaded replies. [DOC20 §6.6.2/§6.6.3]
6. **General / unanchored comment** — `UnanchoredAnchor`. [DOC20 §6.6.2]
7. **Comment status change** — open/resolved/deleted. [DOC20 §6.6.2]
8. **Per-tracked-change accept/reject** (+ Accept/Reject All). [DOC20 §6.10.4/§6.10.5]
9. **Direct document edit** → new version. [DOC20 §6.16.9/§6.16.11]
10. **Per-finding disposition** — Accept / Reject / Reject-with-modification + comment (this unit, built on DOC20 comment affordances + A-01).
11. **Send-to-Agent controls** — `context_scope`, `output_mode` (respond_in_chat | send_with_instructions), `result_format` (revise_artifact | convert_to_note | respond_in_comments), `agent_id`, `chat_id`. [DOC20 §6.16.8]
### 3.2 `HumanReviewResult` — defined as a superset of DOC20 `DocumentReviewRequest`
DOC20 already owns the human-review→agent request/response contract (`DocumentReviewRequest` / `DocumentReviewResultEvent`, §6.16.8). Review Studio does **not** create a parallel request schema; it **extends** that contract with the evaluate-loop layer. (Owner-boundary note → OP-A, §12.)
```ts
// Reuses DOC20 DocumentReviewRequest fields (agent_id, chat_id, context_scope,
// selected_comment_ids, comments[], instruction, output_mode, result_format)
// and adds the evaluate-loop fields below.
interface HumanReviewResult extends DocumentReviewRequest {
review_id: string
task_id: string
run_id: string
gate_id: string // placeable module id OR intrinsic gate id (§4)
// --- interaction axis (ADD #1; closes the advise-vs-revise gap) ---
interaction_mode: "revise" | "advise" // advise = no document mutation; answer in chat/comments
// --- top-level decision (only meaningful for interaction_mode = "revise") ---
decision: "approve" | "send_for_revision" | "reject" // terminal; see §5.4 action model
rejection_reason: string | null // + honors DOC23 on_reject_action (pause|redirect|abort)
redirect_target_ref: string | null // when on_reject_action = redirect (R3.1 §3.2.3)
// --- structured dispositions ---
finding_dispositions: FindingDisposition[] // per-finding accept/reject/modify + comment + anchor
general_directives: GeneralDirective[] // unanchored comments/instructions → run-scoped criteria
tracked_change_dispositions: TrackedChangeDisposition[] | null // ADD #5 (signal of which Revisor edits were rejected)
// --- artifact + provenance ---
reviewed_artifact_version_ref: string // NEW version if edited, else the reviewed version
artifact_edited_by_human: boolean
edit_provenance: "none" | "human_direct" | "human_directed_agent" // co-authored when agent assisted (§6.3)
// --- routing + follow-up ---
routing: ReviewRoutingDecision // §7
requested_followup: FollowupIntent[] | null // multi-step intent captured as data (reserved engine, §11)
// --- attachments (ADD #6) ---
attachments: AttachmentRef[] // review-global; per-disposition attachments live on the disposition
actor: LifecycleActorEnvelope // §9.1
ui_source: ReviewUiSource // ADD #8
created_at: string
schema_version: 1
}
type ReviewUiSource = // extends DOC20/V3.3.1 ui_source enums
| "review_studio_card" | "document_viewer" | "email_reply" | "api"
interface FindingDisposition {
finding_id: string | null // null => a NEW anchored comment that becomes a finding (§3.5)
anchor: TargetScopeRef | null // DOC20 CommentAnchor (§3.6)
disposition: "accept" | "reject" | "reject_with_modification"
comment: string | null // the modification / rationale
authority_class: HumanFeedbackAuthorityClass // V3.3.1 §14.6 (controlling vs advisory)
research_request: ResearchNeedRef | null // optional (Grok §5.9 import)
attachments: AttachmentRef[] | null
}
interface GeneralDirective {
directive_id: string
text: string
scope: "this_artifact_goal" | "this_outcome" | "this_run"
authority_class: HumanFeedbackAuthorityClass
attachments: AttachmentRef[] | null
}
interface TrackedChangeDisposition { // DOC20 §6.10.5 produces tracked_change_accept/reject
change_id: string
decision: "accept" | "reject"
}
```
### 3.3 `requested_result_format` (ADD #2)
The DOC20 `result_format` field (`revise_artifact` | `convert_to_note` | `respond_in_comments`) sets the downstream output contract. It is carried on `HumanReviewResult` (inherited from `DocumentReviewRequest`) and is authoritative for what the assisting agent returns. `respond_in_comments` / `respond_in_chat` imply `interaction_mode = "advise"`.
### 3.4 `context_scope` and agent/chat targeting (ADD #3, #4)
`context_scope` (`full` | `comments_only` | `selected_comments`) and `agent_id` / `chat_id` are inherited from `DocumentReviewRequest`. `agent_id` lets the human **re-target** which agent handles the assist — this is the user-facing override of the routing in §6. Default resolution is the producing agent's session (§6.2).
**Channel limits:** the email-reply channel (R3.1 §3.2.3) carries only the coarse decision (APPROVE/REJECT/REVISE) plus free-text revision and attachments; anchored per-finding dispositions and in-place edits require the Document Viewer surface (§5).
### 3.5 Materialization — the mechanism that makes comments persist across re-evaluation
The Feedback Interpreter (V3.3.1 §14.3) is a one-shot intake service; resurfacing comes from the **finding/outcome lifecycle**, not from the Interpreter. Review Studio therefore materializes inputs into lifecycle objects at intake:
- **Anchored comment / per-finding modification → a human-authored `EvaluationFindingEvent`** (`assurance_basis` includes `human_label`; `target_version_ref` pinned; `target_scope_ref` = the anchor). It then rides `findings_to_address` (V3.3.1 §7.1), the Revision Compiler routes it to a module (§6.4), and the finding lifecycle resurfaces it every re-evaluation until `resolved` / `superseded_by_revision` / `unrecoverable` (§5.7). Finding creation by a human actor is authorized via §9.1 (`author_kind = "human"`).
- **General directive → a run-scoped `Criterion`** on the run's `EvaluationOutcomeDefinition` (V3.3.1 §5.1.1), minted by the Outcome Compiler from the directive text. The Evaluator then re-checks it on every re-evaluation, version-independently, until satisfied; a failing criterion yields a finding (outcome-level, `target_criterion_id = null`) that routes like any other.
Extend `InterpretedOutcomeFeedback` (V3.3.1 §14.3.1) output accordingly:
```ts
interface InterpretedOutcomeFeedback {
// existing:
proposed_revision_request?: RevisionRequest // V3.3.1 §14.4 (current run)
proposed_durable_candidate?: DirectInstructionCandidate // V3.3.1 §14.7 (teaching)
// ADD:
proposed_findings?: EvaluationFindingEvent[] // span corrections (anchored)
proposed_run_criteria?: RunScopedCriterion[] // goal corrections (general)
}
```
#### 3.5.1 Governance guardrails on run-scoped criteria
- Human-authored, **scoped to this run only** — never raises the pass bar for any other run.
- **Inspector-visible** with provenance ("added from your review comment").
- Outcome-set mutation in the revision path is already contemplated (`added_outcome_id`, V3.3.1 §11 status model), so this is not a foreign construct.
### 3.6 Comment ↔ finding reconciliation (ADD #7)
- A finding's `target_scope_ref` maps onto a DOC20 `CommentAnchor` (text/page/line/unanchored). Click-finding→highlight is the existing click-comment→highlight behavior (DOC20 §6.6.7).
- Map comment-status ↔ finding-state: DOC20 `orphaned` ↔ A-01 `superseded_by_revision`; `resolved` ↔ the finding's resolved/dismissed state. The conversational thread (DOC20 §6.6.3, event-sourced) stays DOC20-owned; dispositions carry `thread_root_id` so the exchange is linked, not duplicated.
---
## 4. The hybrid gate — placeable module + intrinsic loop gate
### 4.1 Placeable module `step.review_studio`
A drop-in checkpoint for arbitrary points in a graph. Superset of `step.user_review_gate` (R3.1 §3.2.3).
```
Config (adds to user_review_gate config):
review_instructions: string
surface: "review_studio" // opens the DOC20 Document Viewer in review mode (§5)
load_findings: boolean // load Evaluator findings as anchored finding-comments
allow_agent_assist: boolean // enable the collaboration channel (§6); default true
default_assist_target: "producing_agent" | "task_agent" | "none" // default producing_agent (§6.2)
interaction_modes_allowed: ("revise" | "advise")[] // default both
on_reject_action: "pause" | "redirect" | "abort" // R3.1 §3.2.3
redirect_target / max_redirects / max_revisions // R3.1 §3.2.3
revision_delivery: "wired_target" | "to_revisor" | "to_producing_module" | "auto_previous" | "smart"
Ports:
data_in (Input) — content to review
findings_in (Input, optional) — A-01 finding views; presence => load as finding-comments
plan_in (Input, optional) — a Revisor RevisionPlan; presence => plan-review layout
approved_out (Output) — fires with the (possibly revised) version on Approve / proceed
rejected_out (Output) — fires with rejection_reason + payload
revision_out (Output) — fires with the full HumanReviewResult (decomposed downstream, §7)
feedback_out (Output, optional) — teaching feedback (HumanOutcomeFeedbackEvent) only
signal_out (Output) — "decision made" (fires regardless)
error_out (Output) — notification-delivery failure only
```
Typed `findings_in` / `plan_in` make the graph self-documenting and let the surface adapt (§5.2).
### 4.2 Intrinsic gate (no wiring, no Loop Controller)
The evaluate-revise loop raises a Review Studio gate automatically at its natural points, toggled by per-task/outcome policy — same Review Card, no module wiring, and **no Loop Controller** (avoids the R3.1 §6.2 re-activation wart, since the loop owns re-activation):
```ts
type IntrinsicGatePoint =
| "post_evaluation" // after Evaluator, BEFORE Revisor plans (findings review)
| "post_revision_plan" // review the Revisor's plan before execution
| "post_revision_exec" // review a produced revision
| "pre_final_acceptance" // final-pass review before reliance
interface IntrinsicReviewGatePolicy {
enabled_points: IntrinsicGatePoint[]
// defaults: post_evaluation/plan/exec OFF; pre_final_acceptance ON (Gate-4)
default_assist_target: "producing_agent" | "task_agent" | "none"
schema_version: 1
}
```
Timing correction: findings review is **after the Evaluator / before the Revisor**, not "when the task finishes."
---
## 5. The review surface (review mode over the DOC20 Document Viewer)
### 5.1 Reuse, don't rebuild
The gate opens the **DOC20 Document Viewer** (§6.16) in a `doc` tab in "review mode" rather than rendering a minimal Review Card body. This reuses the Word (mammoth.js), PDF (PDF.js), Markdown/code renderers, the tabbed right panel `[Comments][Send to Agent]` (§6.16.6/§6.16.8), anchored comments (§6.6.2), tracked changes (§6.10), and Convert-to-Note editing (§6.16.9). Findings load into the Comments panel as a **`finding` comment kind**, anchored via `target_scope_ref` → `CommentAnchor`. The legacy Review Card (R3.1 §13.9) remains the lightweight fallback for text-only review.
### 5.2 Surface adapts to inputs (per the typed ports, §4.1)
| Inputs present | Surface |
|---|---|
| `data_in` only | Document preview; Comments panel empty/closed |
| `data_in` + `findings_in` | Findings as anchored finding-comments; per-finding actions (§5.3) |
| `findings_in`, no doc focus | Finding list / chat-style review |
| `plan_in` | Plan-review layout: plan steps as side-panel items with approve / drop / modify |
`RendererCapabilities` (DOC20) hides actions a renderer cannot support (e.g., inline editing on a preview-only DOCX). UI depth here is **mockup-ready**; pixel/interaction detail and all new DOC20 surfaces are in Appendix A.
### 5.3 Per-finding actions
Accept / Reject / Reject-with-modification, each with an optional comment box (Word-comment ergonomics). Maps to `FindingDisposition` (§3.2). Reject-with-modification supplies the corrective instruction that the assist agent or Revisor consumes.
### 5.4 Action model — three layers, and what "Revise" means
Actions at the surface fall into three distinct layers; conflating them is what made "Revise" ambiguous.
**Layer 1 — Per-finding / per-comment actions** (Comments panel): Accept / Reject / Reject-with-modification + comment (§5.3). These dispose individual items; they do not end the checkpoint.
**Layer 2 — In-Studio collaboration** (chat / assist / edit), which loops and does **not** end the checkpoint:
- **Discuss** — advise mode (`interaction_mode = "advise"`): ask the assist agent, no document mutation.
- **Revise with Agent** — the agent edits the artifact in place (`AssistRevisionRequest`, §6.3) -> new version, addressing your comments/instructions **here, now**.
- **Edit** — you edit directly -> new version (§8.1).
**Layer 3 — Terminal decision** (ends the checkpoint, fires a port + routing, §7.1): **Approve / Proceed**, **Send for Revision**, **Reject**.
**The two meanings of "revise":** the terminal **Send for Revision** routes the artifact **plus your dispositions/directives** to a revision *target* (Revisor / producing module / wired target / next step) to be addressed *elsewhere* — the original `revision_out` semantics, with your comments/instructions as the payload. Layer-2 **Revise with Agent** addresses the same comments/instructions *in place*. Both "address comments and instructions"; the difference is **where**.
**After an in-place revision** no new terminal button is needed — Approve/Proceed, Send for Revision, Reject still cover "what next." Refinements: the **Approve** label is context-aware ("Approve" for review-only; "Accept revision & continue" after an in-place revision); **Send for Revision** carries a target picker (next step · Revisor · specific module · Task Agent · forum). The genuinely new controls are the Layer-2 affordances (Discuss / Revise with Agent / Edit) — what was missing, not a fourth terminal button.
---
## 6. Agent collaboration — session continuity and the agent-selection ladder
### 6.1 The ladder (all rungs map to operative primitives)
| Rung | Mechanism | Citation |
|---|---|---|
| Producing agent, **same session** (default) | Module session continuation via `TaskModuleSessionRef` + `session_persist` | Core R0.7.1 §3170/§3449/§10363; Reprompt §7.1 → Addenda A §A9 |
| Producing agent, **new scoped thread** | Module follow-up session (`followup_session_id`) | Core R0.7.1 §261/§9397 |
| **Another module's** agent | Select by `module_ref` → its session | Core R0.7.1 §10363 |
| **Task Agent** | Task Agent contextual side-panel chat (task/run/module/artifact scope, attachments) | Core R0.7.1 §260/§9604 |
| **Forum** | DOC12 room (Plan Review Forum / role-scoped critique) | V3.3.1 §14.9 |
| **Branch the run** | `TaskRunFork` | Core R0.7.1 §8622 |
### 6.2 Default target resolution
The default assist target is the **producing agent, session resumed**, resolved from the artifact's provenance: the module/run that produced `reviewed_artifact_version_ref` → its `TaskModuleSessionRef`. The picker's candidate list = "agents involved in this task" (derivable from the run graph) + Task Agent + forum, with the producer pre-selected. `agent_id` on `HumanReviewResult` (§3.4) is the explicit override. If the producing module is not an agent (a deterministic module) or has no resumable session, the default falls back to the Task Agent — or to `none` (review-only) when `allow_agent_assist = false`.
### 6.3 Agent-assisted in-place revision (the scoped op)
When the human asks the assist agent to make a change, the agent — its session resumed so it knows how the output was produced — edits **this artifact only** as directed, producing a new version with `edit_provenance = "human_directed_agent"` and a co-authored `LifecycleActorEnvelope` (`author_kind = "module"`, with the directing human recorded). This is **not** the automated Revisor's graph plan (§1.2); it is a single-artifact edit. The resulting version triggers the same revalidation cascade as a human edit (§8.2).
```ts
interface AssistRevisionRequest { // thin wrapper over DOC20 DocumentReviewRequest
review_id: string
assist_target: AssistTargetRef // resolved per §6.1/§6.2
session_ref: TaskModuleSessionRef | FollowupSessionRef | null // null => fresh session
directive: string // the in-place change requested
scope_ref: TargetScopeRef | null // optional span
result_format: "revise_artifact" | "convert_to_note" | "respond_in_comments"
schema_version: 1
}
```
### 6.4 Operative vs net-new here
Operative: session continuation/follow-up, Task Agent chat, fork, forum, and the `DocumentReviewRequest` request/response. Net-new: (a) defaulting the assist target to the producing agent's session; (b) the in-place assist op as a scoped single-artifact edit distinct from the Revisor; (c) the checkpoint chat UI — which the reprompt/chat/continuation addendum already proposes (ModuleActivationChat: inspect/advise/branch), so it slots in rather than starting cold. The architect has elected to **adopt** the ModuleActivationChat surface, so the checkpoint chat UI is in scope here; its detailed spec lands when that addendum is folded in (OBL-RS-08).
### 6.5 Assist result handling and iteration
An assist action returns a DOC20 `DocumentReviewResultEvent` (disposition `revised_artifact` | `chat_response` | `note_created` | `comments_replied`, §6.16.8) **back to the review surface**, not straight onward:
- `revised_artifact` / `note_created` -> a new version loaded into the viewer for the human to review.
- `comments_replied` -> threaded replies appear under the relevant finding-comments.
- `chat_response` -> answer in the chat (advise mode).
The Studio session can **iterate** — discuss / revise / edit, review the result, repeat — bounded by `max_revisions` (R3.1 §3.2.3). Only when satisfied does the human take the Layer-3 terminal decision (§5.4). Each assist round is attributed via the `LifecycleActorEnvelope` (§9.1) and, when it mutates the artifact, emits a `human_authored_version_created` receipt that triggers revalidation (§8.2).
---
## 7. Output and routing
### 7.1 The routing decision
After review (and any in-place revision), the human routes the (possibly revised) version:
```ts
type ReviewRoutingDecision = // the terminal decision (one of three; see §5.4)
| { kind: "approve" } // proceed with the current/revised version -> approved_out -> next step
| { kind: "send_for_revision"; target_ref: string; via: RoutingVia } // route artifact + dispositions/directives to be addressed
| { kind: "reject" } // honors on_reject_action (pause|redirect|abort)
// NOTE: "advise" is NOT a terminal routing -- it is a session mode (interaction_mode, §3.2);
// an advise-only session still terminates with approve / send_for_revision / reject.
type RoutingVia =
| "wired_target" | "to_revisor" | "to_producing_module" | "next_step" | "task_agent" | "forum"
```
### 7.2 Decomposition into the existing Feedback Interpreter pipeline
This is the **Tier-1 Human-Review -> Revisor path** (§11.1): in scope and buildable now (mostly wiring), and it already reaches multiple modules via the Revisor's `RepairTarget` routing and Task Agent escalation.
`revision_out` carries the whole `HumanReviewResult`, but routing **decomposes** it into the existing V3.3.1 §14 pipeline rather than inventing new routing:
- Each `FindingDisposition` and `GeneralDirective` → a `HumanOutcomeFeedbackEvent` (§14.2; targets optional, so un-pinned is supported) with the appropriate `authority_class` (§14.6: `current_run_instruction` = controlling vs `current_run_preference` = advisory).
- The Feedback Interpreter (§14.3) parses these into a `proposed_revision_request` → Revisor (current run) and/or the materialized `proposed_findings` / `proposed_run_criteria` (§3.5). Routing of the request to the Revisor — including the no-current-plan and completed-plan cases — is the existing §14.4 rule.
- **Teaching** feedback (improve the module, not this revision) → `feedback_out` only, as a `HumanOutcomeFeedbackEvent` with a durable authority class → `DirectInstructionCandidate` (§14.7). Kept separate from the revision path.
- A human-edited or co-authored **version** is referenced forward (not re-sent); CIL/DOC15 auto-frames provenance to the next module ("continuation of task X, human-reviewed at a gate; here is the version + directives; revise"). Directives self-describe via their anchors.
### 7.3 Port behavior recap
`approved_out` (proceed, with the revised version) · `rejected_out` (reason + payload, honoring `on_reject_action`) · `revision_out` (full `HumanReviewResult`, decomposed per §7.2) · `feedback_out` (teaching only) · `signal_out` · `error_out`. The intrinsic gate (§4.2) uses the same outputs internally without external wiring.
---
## 8. Versioning, provenance, and the revalidation trigger
### 8.1 Editing is version-creating and method-agnostic
Any human edit (in-app tiptap/Convert-to-Note, DOC20 §6.16.9; or external native app) and any agent-assisted in-place edit (§6.3) produces a **new artifact version** with human / co-authored provenance; the prior version is preserved (DOC20 versions artifacts: `v{N}`, `artifacts_current.json` + events). The reference is sent forward. External-app editing builds on DOC20's "Open External" action: on external save, ingest as a new version. The editing **contract** is method-agnostic — however edited, the result is a new version referenced forward.
### 8.2 GAP/fix — a human (or co-authored) edit must trigger the revalidation cascade
The revalidation cascade (V3.3.1 §11.21) and the dirty-flip (§10.5) are triggered by **revision-step** mutations only: `RevisionOperationReceipt` with `operation_kind in { candidate_version_accepted, direct_fix_applied, rollback_apply }` (`RevisionOperationKind`, §0.4.7). A human-authored version is **not** a revision step and emits none of these — so as specced, a human edit would not refresh findings, and the Revisor could plan against a stale version.
**Fix (preferred — honest provenance):** add a `RevisionOperationKind` value `human_authored_version_created` and include it in the §11.21 trigger set. The review-gate edit path emits a `RevisionOperationReceipt` of that kind. The cascade then fires identically: dependent outcomes (declared via `OutcomeDependencySpec.declared_dependencies`, §11.21.1) → `dirty` → Evaluator re-runs against the human's version → findings whose target section no longer exists → `superseded_by_revision` (§5.7.1) → Revisor plans against the current version.
**Zero-schema alternative (noted, not preferred):** model the human edit as a `CandidateArtifactVersion` that is immediately accepted, reusing `candidate_version_accepted`. It fires the cascade with no enum change but mislabels provenance ("candidate" = produced by revision, §0.4.5); rejected because this unit values truthful history.
### 8.3 `human_resolved` provenance (adopted)
A finding a human resolves by editing (not deleting) does not acquire the `resolved` state — §5.7.2 reserves `resolved` for findings carried in a Revisor `RevisionExecutionReceipt.addressed_findings`, which a human edit does not produce. **Decision: adopt a distinct `human_resolved` provenance** so a human-fixed finding is attributed truthfully rather than silently superseded:
- Add `human_resolved` to `FindingState` (or as a resolution-provenance facet on the resolved transition), set when re-evaluation against a human/co-authored version finds the targeted defect gone and a `human_authored_version_created` receipt (§8.2) is the cause.
- Distinct from `superseded_by_revision` (the section changed/disappeared) and from Revisor-`resolved` (a `RevisionExecutionReceipt` addressed it). Carries the `LifecycleActorEnvelope` (§9.1) so authorship is explicit.
---
## 9. Exposure — multi-actor envelope, read contract, gated write
### 9.1 `LifecycleActorEnvelope` (the multi-actor primitive)
Generalizes the existing per-object authorship (`comment.author`, `attachment.created_by`, tracked-change attribution) so a finding/comment/criterion/transition created by a human, an evaluator, the Revisor, a module, or the Task Agent is structurally identical, differing only in actor + authority. It is an extension of the converged `GovernanceEnvelope` Layer-1 mixin (card Layer 1).
```ts
interface LifecycleActorEnvelope {
author_kind: "human" | "evaluator" | "revisor" | "module" | "task_agent"
author_ref: string // UserRef | ModuleRef | AgentRef
on_behalf_of_ref: string | null // co-authored: directing human for author_kind="module"
authority_class: HumanFeedbackAuthorityClass | ModuleAuthorityClass // V3.3.1 §14.6, extended
basis: AssuranceBasis // human_label | model:<id> | evaluator | ...
taint_class: TaintClass // rides the object; consumers treat content as data
policy_decision_ref: string // every WRITE is an EC PolicyDecision, not the actor's call
schema_version: 1
}
```
### 9.2 Per-owner READ contract (build now; first consumer is Review Studio itself)
Expose the lifecycle as a **derived projection published by each owning subsystem** — DOC23 publishes finding/outcome/revision reads; DOC20 publishes comment/anchor reads — via the patterns already in use (cross-module query API, V3.3.1 §4.9.2; signal pub/sub, §14.8.4; derived read-models "derived, not invented," §11.1.1).
```ts
interface LifecycleReadQuery { // pull; modeled on V3.3.1 §4.9.2 (read-only, no cross-mutation)
by: "artifact" | "outcome" | "task" | "run"
ref: string
include: ("findings" | "comments" | "revisions" | "history")[]
schema_version: 1
}
// returns the existing view types (FeedbackFindingView, DOC20 comment views,
// RevisionExecutionRecord/Summary), privilege/AccessTier-filtered (§16.6) under default-deny (§16.5).
interface LifecycleEventSubscription { // push; over §14.8 signals + finding-state transitions
events: ("finding_created" | "finding_resolved" | "finding_superseded"
| "revision_applied" | "directive_raised" | "directive_satisfied")[]
scope_ref: string
schema_version: 1
}
```
Read guardrails: projection only, never an authoritative store (§11.1.1); privilege/AccessTier filtering (§16.6); `taint_class` rides the view; reads never mutate the owner.
### 9.3 Gated WRITE capability (declared; behaviors reserved)
A typed capability so future modules can interact in the same manner, gated behind `LifecycleActorEnvelope` + an EC `PolicyDecision`. "Can module M create/resolve finding F?" is a policy decision, not M's call (preserves one-compiled-evaluator). Per-module write **behaviors are reserved** (§11) — only the contract + authority gate land now.
```ts
interface LifecycleWriteCapability {
op: "create_finding" | "transition_finding" | "add_comment" | "add_run_criterion"
actor: LifecycleActorEnvelope // author_kind != "human" requires capability declaration
target_ref: string
payload_ref: string
requires_policy_decision: true
schema_version: 1
}
```
---
## 10. Lints and fixtures
### 10.1 New lints
```
review_studio.finding_disposition_without_anchor_or_id
review_studio.general_directive_not_materialized_to_finding_or_criterion
review_studio.run_criterion_scope_wider_than_run
review_studio.human_edit_without_revalidation_trigger // §8.2
review_studio.advise_mode_mutated_artifact // interaction_mode=advise must not change the doc
review_studio.result_format_unhonored_by_assist_output
review_studio.intrinsic_gate_used_loop_controller // intrinsic gate must not require one (§4.2)
review_studio.advise_treated_as_terminal_routing // advise is a session mode, not a terminal (§5.4)
review_studio.terminal_decision_not_approve_send_or_reject // Layer-3 must be one of three (§5.4)
lifecycle.read_projection_treated_as_truth_store // §9.2
lifecycle.read_without_privilege_filter // §16.6
lifecycle.write_without_policy_decision // §9.3
lifecycle.actor_envelope_missing
review_result.duplicates_document_review_request_schema // must extend, not fork (§3.2)
```
### 10.2 Golden fixtures (executable assertions; gate level in brackets)
```
GS-RS-01 per-finding disposition -> human-authored finding -> Revisor routes to module [slice]
GS-RS-02 general directive -> run-scoped criterion -> persists across re-eval until satisfied [cross_slice]
GS-RS-03 human deletes section with a finding -> human_authored_version_created -> cascade ->
finding superseded_by_revision -> Revisor plans against current version [cross_slice]
GS-RS-04 advise mode: agent answers in comments/chat, artifact unchanged [slice]
GS-RS-05 agent-assisted in-place edit -> new co-authored version -> route "proceed" [cross_slice]
GS-RS-06 default assist target resolves to producing agent's session; override via agent_id [slice]
GS-RS-07 intrinsic post_evaluation gate raised with no module wiring and no Loop Controller [slice]
GS-RS-08 teaching feedback -> feedback_out -> DirectInstructionCandidate (not the revision path) [slice]
GS-RS-09 read query returns privilege-filtered views; cross-matter read denied by default [final_switchover]
GS-RS-10 assist result returns to surface; session iterates within max_revisions before terminal decision [cross_slice]
```
---
## 11. Reserved sections (contract reserved, behaviors deferred)
### 11.1 Revision pathways: in scope, the evaluator-bridge, and the reserved orchestrator
Three tiers, deliberately separated so we do not build a second orchestrator (§1.2):
- **Tier 1 — Human-Review -> Revisor (IN SCOPE, buildable now).** A review's dispositions/directives drive the Revisor to revise the artifact / repair via the existing loop. Already contracted (HumanOutcomeFeedbackEvent -> Feedback Interpreter -> RevisionRequest -> Revisor, V3.3.1 §14); Review Studio wires into it (§7.2). **Not reserved** — mostly wiring. The Revisor already reaches **multiple modules** on its own via `RepairTarget` routing (§6.4) and Task Agent escalation (§6.9), so Tier 1 already covers much of the multi-module need.
- **Tier 2 — The evaluator-bridge (recommended multi-module path; a pattern, not new machinery).** Route the human's intent **through an Evaluator**: the comments/directives become an Evaluator's findings/criteria (the materialization in §3.5 is exactly this), and the existing Revisor consumes them and does its normal multi-module job, escalating to the Task Agent where needed. Yields human-driven multi-module revision by reusing Evaluator -> Revisor -> Task-Agent, with **no new orchestrator**. It also "forces clearer goals," since intent must be expressed as checkable findings/criteria.
- **Tier 3 — Human-Review -> Orchestrator engine (RESERVED).** A dedicated engine where human review directly drives runtime multi-module orchestration, bypassing the Evaluator/Revisor. **Reserved**, because it would be a second orchestrator overlapping the Revisor's (the §1.2 boundary). Architect's framing: this is essentially the existing "ask ELNOR for a task -> Task Agent designs it -> it is revised" flow, surfaced with a different level of explanation and made re-runnable mid-task. Its building blocks already exist — `TaskRunFork` (Core R0.7.1 §8622), `graph_patch_proposal` (the Revisor->Task Agent escalation output, V3.3.1 §6.9), and the Task Agent's graph-design/revision role — so assembling it later is expected to be cheap, which is why it is deferred rather than built now. Build Tier 1 + use the Tier 2 bridge in the interim; `requested_followup: FollowupIntent[]` (§3.2) captures multi-step intent as data meanwhile.
### 11.2 Self-learning from review gates
The reasoning side (learning standing preferences/quality models from review-gate activity) is **reserved**, gated on DOC8/the memory flatten. The **signal layer is already wired**: V3.3.1 §14.8 emits `finding_marked_wrong`, `revision_instruction_useful`, `evaluator_plan_user_edited`, etc., to DOC72/BDSM consumers (§14.8.4). This unit emits those signals from Review Studio actions (including per-tracked-change rejections, §3.2) but does not build the learning reasoner.
---
## 12. OP-A obligations (interim pre-flatten tracker rows)
Recorded in the interim cross-doc tracker (not canonical OP-A, reconciled at flatten completion). None of these are flatten-blocking.
```
OBL-RS-01 §G UI rows -> DOC20 migration
OBL-RS-02 Review Studio review-surface UI (Appendix A) -> DOC20
OBL-RS-03 Reconcile HumanReviewResult ⊇ DocumentReviewRequest (request shape is DOC20-owned, §3.2)
OBL-RS-04 AttachmentSchema.parent_type extension: add comment / finding / review_result (DOC20 §7.18)
OBL-RS-05 plan_review room kind dependency -> DOC12 (B-15; OBL-DOC12-FORUM-01)
OBL-RS-06 NoVerdictReason full consolidation -> when next in Addenda A
OBL-RS-07 Unified cross-module lifecycle substrate ownership (DOC23<->DOC20) — ordinary owner-boundary
decision + OP-A row; NOT a flatten/DOC80 gate, NOT a blocker
OBL-RS-08 Fold the ADOPTED ModuleActivationChat surface (reprompt/chat/continuation addendum) into DOC20/DOC23 -> the §6.4/§6.5 checkpoint chat UI
OBL-RS-09 RevisionOperationKind += human_authored_version_created; add to §11.21 trigger set (V3.3.1 owner)
OBL-RS-10 ui_source += review_studio_card / document_viewer / email_reply (DOC20 + V3.3.1 §14.2)
```
---
## Appendix A — DOC20 additions / obligations (liftable, mockup-ready)
Clearly-labeled DOC20-owned work, liftable to DOC20 when next revised. Specified to mockup-ready depth.
- **Review mode for the Document Viewer** (§6.16): a `doc` tab opened by the gate, with findings loaded into the Comments panel as a **`finding` comment kind** (extends `NoteCommentStatus`/comment-kind set). Click-finding->highlight reuses §6.6.7.
- **Per-finding actions** in the Comments panel: Accept / Reject / Reject-with-modification + comment (Word-comment ergonomics).
- **Interaction-mode toggle** (revise | advise) on the review surface; advise hides mutation actions.
- **Result-format selector** — already present (§6.16.8 `result_format`); surface it in review mode and bind to the assist output contract.
- **Context-scope control** — already present (§6.16.8 `context_scope`).
- **Assist-target picker** — producing-agent default; candidate list = "agents involved in this task" (from the run graph) + Task Agent + forum; maps `agent_id`/`chat_id` (§6.2). Chat surface = ModuleActivationChat (proposal, OBL-RS-08).
- **Attachment `parent_type` extension** to cover `comment` / `finding` / `review_result` (§7.18; OBL-RS-04).
- **Comment-status <-> finding-state reconciliation**: `orphaned` <-> `superseded_by_revision`; carry `thread_root_id` on dispositions so threads link, not duplicate (§3.6).
- **`ui_source` values** for review surfaces (OBL-RS-10).
- **Plan-review layout**: Revisor plan steps as side-panel items with approve / drop / modify (consumes `plan_in`).
---
## Appendix B — Verification log (operative vs net-new)
**Operative (reused, cited):**
- `step.user_review_gate` spine, Review Card, email-reply actions, ports, `on_reject_action`, `max_revisions`, `revision_delivery`, Loop Controller Pattern B — DOC23 R3.1 §3.2.3 / §6.5.4 / §3.3.4 / §6.2 / §13.9.
- Document Viewer, anchored comments + threading, tracked changes, Convert-to-Note, Send-to-Agent + `DocumentReviewRequest`/`DocumentReviewResultEvent`, comment event-store, attachments — DOC20 R4.3 §6.6.2 / §6.6.3 / §6.10 / §6.16.6 / §6.16.8 / §6.16.9 / §6.16.11 / §7.16–§7.18.
- Finding lifecycle + `superseded_by_revision`, revalidation cascade + declared-dependency closure, `RevisionOperationKind`, `HumanOutcomeFeedbackEvent` (un-pinned supported), Feedback Interpreter + routing, authority classes, `DirectInstructionCandidate`, signals + consumers, Plan Review Forum, `RevisionRequest`, `TypedRevisionInstruction`, repair strategy/target taxonomies, Task Agent escalation, Outcome Compiler/Criterion, export/governance + default-deny + matter governance, derived-read-model "derived, not invented" — V3.3.1 §5.7 / §11.21 / §3.1.7 / §0.4.7 / §14.2 / §14.3 / §14.4 / §14.6 / §14.7 / §14.8 / §14.9 / §7.1 / §7.6 / §6.3 / §6.4 / §6.9 / §5.1.1 / §16.3 / §16.5 / §16.6 / §11.1 / §4.9.2.
- Module session continuation, module follow-up, Task Agent side-panel chat, `TaskRunFork`, `TaskModuleSessionRef` — Addenda B Core R0.7.1 §3170 / §3449 / §261 / §9397 / §10363 / §8622; Reprompt §7.1 -> Addenda A §A9.
**Net-new this unit (and its trace):**
- `interaction_mode` revise|advise — closes a gap vs DOC20 `output_mode` respond_in_chat / `result_format` respond_in_comments (§3.1/§3.3).
- `HumanReviewResult` as a superset of `DocumentReviewRequest` (§3.2) — reconciliation OBL-RS-03.
- Materialization of comments -> human-authored findings / run-scoped criteria; `InterpretedOutcomeFeedback` output extension (§3.5) — built on §5.1.1 + §5.7 + §14.3.
- Hybrid placeable + intrinsic gate (§4) — extends §3.2.3; intrinsic timing after Evaluator/before Revisor.
- `human_authored_version_created` revalidation trigger (§8.2) — OBL-RS-09.
- `LifecycleActorEnvelope`, `LifecycleReadQuery`/`LifecycleEventSubscription`, gated `LifecycleWriteCapability` (§9) — extend GovernanceEnvelope + §4.9.2/§11.1/§16.
**`OPEN_FOR_ARCHITECT_REVIEW`:** none outstanding. Resolved this revision: ModuleActivationChat — **adopted** (§6.4); `human_resolved` provenance — **adopted** (§8.3); Tier-1 Human-Review->Revisor — **in scope** (§7.2/§11.1). The Tier-3 orchestrator (§11.1) is **reserved by decision** (not an open question), to revisit after the other pieces land.
---
## Revision log
**Rev 2 (this pass)** — folded in architect decisions + audit findings:
- Adopted the ModuleActivationChat checkpoint chat UI (§6.4, OBL-RS-08).
- Adopted a distinct `human_resolved` provenance (§8.3).
- Confirmed Tier-1 Human-Review->Revisor as in scope; named the Tier-2 evaluator-bridge; reserved the Tier-3 orchestrator with building-block framing (§7.2, §11.1).
- Added the three-layer action model and disambiguated "Revise"; refined the `decision` enum to approve/send_for_revision/reject and removed `advise_only` as a routing kind (§5.4, §7.1).
- Added assist-result handling + iteration (§6.5), no-producing-agent fallback (§6.2), relationship to agent_review_gate / panel / the human_review_gate disposition (§1.3), email-channel limits (§3.4), two action-model lints, and GS-RS-10.
*End of design unit. Draft pending architect review and multi-LLM red-team.*
````