Claude_Opus_4.8_Review Studio review.md
Active Working and Red Team/DOC23 Working/DOC23 Red Teaming/Claude_Opus_4.8_Review Studio review.md
# Review Studio (DOC23 Addenda B) — Red-Team Review
**Reviewer:** Claude Opus 4.8
**Target:** `DOC23 Add B Review Studo D1.md` (Rev 2)
**Operative context read in full:** Common Contracts V1.1.1; Feedback Delivery V1.0.1; Outcome Evaluator+Revisor V3.3.1 (§0.4.7, §5.1.1, §5.7, §6.7–§6.11, §10.5, §11.1, §11.21, §14, §16.5–§16.6); DOC20 R4.3 (§6.6, §6.10, §6.16) + DOC20 Addendum B "MS Word Viewer" R3 + R4.3 Delta; Adjudication Card STAGED (A‑01, A‑16/A‑17, G‑02/G‑04, L1.1/L1.3).
**Date:** 2026‑05‑31
---
## Overall assessment
This is a strong, disciplined unit. The boundary work in §1.2 (Review Studio = one artifact, in place; Revisor = the task graph) is exactly right and is the spine that keeps the two from colliding. The "two meanings of revise" disambiguation (§5.4) and the three‑layer action model are genuinely good — they fix the single most confusing thing about review gates. Grounding density is high and mostly accurate, and the unit correctly refuses to build a second orchestrator (Tier 3 reserved, §11.1).
But the unit has **two load‑bearing problems that are not yet closed, and both live exactly where Will is most worried (Document Review / in‑place editing):**
1. **The in‑place assist edit path is not reconciled with the A‑16 `revision_in` single‑mutation chokepoint.** As written, §6.3 mutates the artifact through the DOC20 `DocumentReviewRequest` → `revised_artifact` path, which is *not* the `revision_in` port that the card (A‑16, CRITICAL) makes the *sole* sanctioned mutation path. This is the one finding I would block ratification on until resolved. → **C1.**
2. **The docx editing/versioning model the unit relies on does not exist as cited.** §5.1 names "Word (mammoth.js)" as the review/edit surface and §8.1 versions edits as `v{N}`. But in operative DOC20, **docx is a read‑only mammoth.js preview** (`editable:false`, `supports_tracked_changes:false`, `supports_inline_comments:false`, DOC20 R4.3 §6.16.5A line 4033). The real docx editor is **OnlyOffice with copy‑on‑write `_E{N}.docx` + mandatory tracked changes** (DOC20 Addendum B R3), an unreconciled second engine whose file‑copy version model collides with `v{N}`. For the principal legal artifact type (.docx expert reports/briefs), the review surface the unit assumes is not the surface that is actually specced. → **C2.**
Everything else is substantive‑or‑below and fixable in place. The good news for Will's specific item‑4 concern: the *Tiptap‑native* review surface (Notes / markdown / code) is genuinely built to the depth Review Studio needs — comments, threading, tracked changes, anchor remapping, immutable versioning, Send‑to‑Agent. The gap is almost entirely about **docx/pdf** and about **which mutation path** the assist uses.
I have typed every finding and cited sections. Paste‑ready TS is inline. The value‑tiered summary is at the end.
---
## 1. New ideas to make it better
**BETTER_IDEA 1 — Adopt a per‑gate `allowed_decisions` interrupt policy (steal from LangGraph `HumanInTheLoopMiddleware`).**
Today `IntrinsicReviewGatePolicy` (§4.2) only toggles *which* gate points fire (`enabled_points`). Production HITL frameworks pair the interrupt point with a per‑point *decision allow‑list* — e.g. `{write_file: all decisions; execute_sql: [approve, reject] (no edit); read_data: auto}` (LangChain HITL docs). This is a clean primitive for ELNOR: some review points should allow the full action set (approve / send_for_revision / reject / edit / advise), some should be approve‑or‑reject only (e.g. an irreversible‑send pre‑gate), some auto‑pass. Extend the policy:
```ts
type ReviewDecisionKind = "approve" | "send_for_revision" | "reject" | "edit" | "advise"
interface IntrinsicGatePointPolicy {
point: IntrinsicGatePoint // §4.2
enabled: boolean
allowed_decisions: ReviewDecisionKind[] // gate-point-scoped allow-list
default_assist_target: "producing_agent" | "task_agent" | "none"
expiry: ReviewGateExpiryPolicy // BETTER_IDEA 4
}
```
Trace: extends `IntrinsicReviewGatePolicy` (§4.2). Lint `review_studio.decision_outside_allowed_set`.
**BETTER_IDEA 2 — "Review Playbooks": promote run‑scoped criteria to a saved, reusable criteria set.**
Every serious legal redline tool (Spellbook, CoCounsel) ships **Playbooks** — a saved set of standards run against any document, producing a pass/fail/needs‑attention checklist. Review Studio already mints run‑scoped Criteria from directives (§3.5); the missing 10% is letting the user *save and re‑apply* a criteria set. This maps cleanly onto the existing `saved_criteria` authority basis (FD §3.2) and saved Task Blueprints (Core R0.6.4). It would make the "forces clearer goals" property (§11.1 Tier 2) durable instead of per‑run. Net‑new surface is small; the substrate (Criterion, EvaluationOutcomeDefinition, Blueprint) already exists. Flag the *promotion* (run → matter/firm scope) through the existing `DirectInstructionCandidate` scope‑rule machinery (§14.7.1) so a saved review checklist can't silently leak across matters.
**BETTER_IDEA 3 — `restore_known_good_state` as a first‑class terminal action.**
The card's `RevisionReviewPacket.reviewer_action` (G‑02) already has `restore_known_good_state`, pairing with G‑04 (restore) and `RevisionOperationKind.rollback_apply` (§0.4.7). Review Studio's terminal set is only approve / send_for_revision / reject (§5.4, §7.1). A human reviewing a bad co‑authored revision needs a one‑click "revert to v{N‑k}" that fires the cascade via `rollback_apply`. This is the single most valuable missing terminal control. → folded into S6.
**BETTER_IDEA 4 — Gate expiry / resume‑idempotency contract.**
Adding a human interrupt introduces *unbounded latency* and forces *idempotent resume* (LangGraph's well‑documented constraint: the interrupted node re‑executes from the top on resume). A `step.review_studio` that pauses a long run can sit for days. Specify an expiry policy and an idempotent‑resume rule so the loop does not re‑dispatch already‑completed revision steps when the human finally answers. → folded into S8.
**BETTER_IDEA 5 — Diff‑first review for co‑authored edits (steal from agentic IDEs).**
Cursor/Copilot agent mode's strongest affordance is the **inline per‑hunk accept/reject diff** — the human reviews the *change*, not the whole doc, and stays in muscle memory. Review Studio renders findings well, but after an in‑place assist revision (§6.5) it just "loads the new version into the viewer." It should instead present the `before→candidate semantic diff + finding_to_change_map` (already a derived field in the card's `RevisionReviewPacket`, G‑02) with per‑change accept/reject. This is the same primitive as DOC20 tracked‑change accept/reject (§6.10.4/§6.10.5) — wire it. → folded into S6.
**BETTER_IDEA 6 — "Why this finding" provenance hovercard.**
Each finding already carries `authority_basis` (9‑value, FD §3.2), `assurance_basis`, `confidence`, and `evidence_refs` (§5.7). Surface them as a hovercard so the human disposing a finding sees *why* the evaluator raised it and *how much to trust it* before accept/reject. GC AI's "Exact Quote" (character‑level citation) is the bar here. Zero new contract — pure render of existing fields.
---
## 2. How others do it (research)
**Agentic IDEs (Cursor, GitHub Copilot agent mode, Google Antigravity).** The dominant pattern is **inline per‑hunk accept/reject diffs** — "developers see diffs in real time, accept or reject changes inline, and stay in their existing muscle memory" (Dailybot, *The agent landscape*, 2026). Cursor 3 (Apr 2026) and Google Antigravity add **parallel agents with artifact‑based transparency** (a sidebar of agent runs you can inspect/approve). Take‑aways for Review Studio: (a) review the *change*, not the whole artifact (BETTER_IDEA 5); (b) a **plan/sidebar view** for multi‑step work (your `plan_in` port, §4.1, is the right instinct); (c) the lesson from Copilot's late, weak agent mode is that *the review/diff surface is the product* — a strong evaluator with a weak review surface loses. Sources: sitepoint.com "Claude Code vs Cursor vs Copilot 2026"; dailybot.com agent‑landscape; devtoolpicks.com "Cursor 3 review".
**Legal redline tools (Spellbook, Thomson Reuters CoCounsel, Harvey, GC AI).** Remarkably convergent, and it validates this unit's core design:
- **Suggestions are never auto‑applied.** "Lawyers review, then accept, edit, or reject each suggestion. AI‑generated revisions are not automatically applied. The lawyer controls every modification. This approach preserves the editorial chain for compliance and defensibility" (Spellbook, *Using AI to Review Contracts*, 2026). This is precisely your A‑16 chokepoint + per‑finding disposition model.
- **Accepted edits render as tracked changes under the lawyer's name** (Spellbook; CoCounsel: "Accepted suggestions show as tracked changes under the lawyer's name"). This is exactly the DOC20 Addendum B R3 copy‑on‑write + `w:author` model — *steal the attribution semantics* into `LifecycleActorEnvelope` and `human_resolved` provenance.
- **Playbooks**: "Apply a Playbook to automatically run your firm's negotiation standards against any contract … rules (clause validation against preferred and fallback positions) and questions (data extraction) to produce a structured checklist of what passed, failed, and needs attention" (Spellbook, *Best Legal AI Agent*, 2026). → BETTER_IDEA 2.
- **Three dispositions: accept / modify / reject**, with a "filter to only negotiation points" view (Spellbook). → your per‑finding action model + a UI finding‑filter (item 7).
- For litigation‑scale review, **Relativity aiR for Review** is the separate "bulk / issue‑coding / privilege" market — explicitly *not* a single‑artifact in‑place tool. Good confirmation that Review Studio is correctly scoped to single‑artifact review and should not try to absorb bulk review.
Sources: spellbook.com (`/learn/using-ai-to-review-contracts`, `/learn/best-legal-ai-agent`, `/learn/contract-redline-software-features`); gc.ai/blog/legal-ai-tools; buildmvpfast.com legal‑AI 2026.
**Human‑in‑the‑loop orchestration (LangGraph / LangChain HITL).** The canonical primitive is **`interrupt()` → checkpoint → `Command(resume=…)` / `update_state()`**: pause the graph mid‑node, persist a state snapshot keyed by `thread_id`, present to the human, and resume from the checkpoint. Three decision shapes are standard: **approve‑as‑is, reject‑and‑alt‑route, and edit‑the‑proposed‑action‑before‑executing** (TURION.AI; LangChain HITL docs add a fourth, "respond"). Two hard constraints the docs stress: (1) **the interrupted node re‑executes from the top on resume → pre‑interrupt logic must be idempotent**; (2) **interrupts add unbounded latency.** Their worked legal example is almost your exact use case: "A lawyer reviews each proposed clause in a web UI, edits the text via `update_state()`, and marks it approved. The agent then formats the final document with the reviewed text" (abstractalgorithms.dev). Take‑aways: your intrinsic gate (§4.2) *is* `interrupt()`; adopt a per‑point `allowed_decisions` map (BETTER_IDEA 1); specify resume‑idempotency + gate expiry (S8). Sources: langchain.com "interrupt" announcement; docs.langchain.com human‑in‑the‑loop; abstractalgorithms.dev; towardsdatascience.com "LangGraph 201".
---
## 3. Bugs / breaks / missing wiring / phantom features / missing contracts
### CRITICAL
**C1 — ARCHITECT_STOP — The in‑place assist mutation path bypasses the A‑16 `revision_in` chokepoint.**
§6.3/§6.5 perform the in‑place edit by sending a DOC20 `DocumentReviewRequest` to the assist agent and consuming a `DocumentReviewResultEvent` with disposition `revised_artifact` (DOC20 §6.16.8). That is the **DOC20 Send‑to‑Agent mutation path**. The adjudication card A‑16 (CRITICAL, confirmed — card lines 269, 322, 1793) holds that the **`revision_in` port (or a `revision_compatible=true` port + capability) is the *sole* sanctioned artifact‑mutation path**; anything else fires `validation.repair_routed_to_non_revision_port` (card line 330). GS‑01 (card line 529) states the rule explicitly, and line 1793 says outright that "the `revision_in` chokepoint (A‑16) is the single mutation path that the Review Studio human‑assist also relies on." The unit *asserts* reliance (§1.2 cross‑ref) but the *mechanism* (§6.3) routes through Send‑to‑Agent, not `revision_in`.
This is the contradiction to resolve before ratification. Two clean resolutions, pick one:
- **(a) Capability‑gated `revision_compatible` port.** Declare the assist‑edit output port `revision_compatible = true` and gate the mutation behind a `LifecycleWriteCapability` (§9.3) + EC `PolicyDecision`. This is the GS‑01 escape hatch and keeps "single mutation path" true (one *kind* of sanctioned port). Preferred — it also makes §6.3 honest about being a write.
- **(b) 1‑step revision through `revision_in`.** Route the assist edit as a degenerate single‑step `RevisionPlan` through `revision_in`. Cleanest for the cascade, but it contradicts §1.2's "no RevisionPlan / not a graph redo," so it muddies the boundary you worked hard to draw.
Add lint: `review_studio.in_place_assist_mutated_outside_revision_contract` (a Review Studio‑scoped instance of `validation.repair_routed_to_non_revision_port`). Required fixture: GS‑RS‑11 "in‑place assist edit routes through a `revision_compatible` port + LifecycleWriteCapability + PolicyDecision; a bare Send‑to‑Agent mutation is rejected." Also note the card's `requires_verification_when` already includes `"in_place_mutation"` (card line 643) — the assist edit must trip that verification.
**C2 — BUG (CRITICAL) — The docx review/edit/version model cited in §5.1/§8.1 does not match operative DOC20.**
Three sub‑facts, all verified against source:
- §5.1 says the surface "reuses the Word (mammoth.js) … renderer … tracked changes (§6.10) … Convert‑to‑Note." But DOC20 R4.3 `RENDERER_CAPABILITIES.docx` (§6.16.5A, line 4033) is `{ supports_tracked_changes:false, supports_inline_comments:false, supports_page_anchors:false, supports_line_anchors:false, editable:false }` — **mammoth.js is a read‑only HTML preview.** mammoth.js *cannot* do tracked changes, inline comments, anchors, or in‑place editing. Those are properties of the **`tiptap`** renderer (`editable:true, supports_tracked_changes:true, supports_inline_comments:true`).
- The actual docx editor is **OnlyOffice** (DOC20 Addendum B "MS Word Viewer" R3), under a **HARD copy‑on‑write rule**: agent edits never touch the original; they produce `{name}_E{N}.docx` with **mandatory tracked changes** via `enforceEditPolicy()` (R3 §6.1–§6.7). "No agent code may call `fs.writeFile()` on a document path directly" (R3 §6.7).
- §8.1's version model is `v{N}` in `artifacts_current.json` (the DOC20 artifact‑version model, §6.16.10). The OnlyOffice path produces `_E{N}.docx` *files*, not artifact versions. These are two different version spines and are **not reconciled.**
Consequence for item 4: for a .docx, the review surface cannot host anchored finding‑comments or per‑finding click‑to‑highlight (renderer caps say so), the in‑place edit is OnlyOffice copy‑on‑write (not `v{N}`), and the assist mutation must additionally route through `enforceEditPolicy()` — which §6.3 doesn't mention. See §4 below for the full effort breakdown. This needs an explicit architect decision (which is the docx review/edit engine: OnlyOffice‑in‑review‑mode, or Convert‑to‑Note→Tiptap?), so it is at minimum a hard GAP and arguably an ARCHITECT_STOP for the docx path.
### SUBSTANTIVE
**S1 — GAP — The §8.2 revalidation fix has no runner at a standalone placeable gate.**
§8.2 adds `human_authored_version_created` to the §11.21 trigger set "so the cascade fires identically." But §11.21 is explicitly a **Loop Controller** protocol ("The Loop Controller revalidates automatically"), and §11.21.1 only re‑evaluates outcomes that **declare** a dependency via `OutcomeDependencySpec`. Meanwhile §4.2 designs the intrinsic gate to have **no Loop Controller** ("avoids the R3.1 §6.2 re‑activation wart"). So when a `step.review_studio` is dropped into an arbitrary graph that has *no* evaluate‑revise loop and *no* declared `OutcomeDependencySpec` on the artifact (the common placeable‑module case), a human edit emits the receipt but nothing runs the cascade and no findings refresh. Specify: (i) the placeable gate, on a human/co‑authored edit, must *register* the artifact's outcomes (or create a minimal `OutcomeDependencySpec`) so a cascade has a target; or (ii) if no outcome depends on the artifact, the edit is simply version‑forward with no revalidation (state this explicitly and lint it). Lint `review_studio.human_edit_receipt_without_cascade_consumer`.
**S2 — GAP (verify‑before‑reporting) — §0.4.7 already defines `human_gate_decision`; §8.2's new value isn't reconciled with it.**
`RevisionOperationKind` (§0.4.7) is `… | "candidate_version_created" | "candidate_version_accepted" | … | "human_gate_decision" | "rollback_apply" | …`. §8.2 proposes adding `human_authored_version_created` and considers only the "reuse `candidate_version_accepted`" alternative — it never mentions the adjacent existing `human_gate_decision`. The new value is probably still justified (decision vs content‑mutation are distinct), but the doc must (a) cite §0.4.7's existing `human_gate_decision`, (b) state the boundary (`human_gate_decision` = the approve/reject/route *decision* receipt; `human_authored_version_created` = the artifact *mutation* receipt), and (c) confirm `human_gate_decision` is correctly *absent* from the §11.21 trigger set (a decision doesn't mutate) while the new value is *added*. OBL‑RS‑09 stays, with this reconciliation noted.
**S3 — GAP — §5.7 already defines `human_verified`/`user_approved`/`rejected_by_user`; §8.3's `human_resolved` isn't reconciled and the §5.7.2 invariant isn't added.**
`FindingState` (§5.7) already has a rich human cluster: `human_verified` (human confirmed the finding is *correct*), `user_approved`, `rejected_by_user`, plus `superseded_by_revision` and Revisor‑`resolved` (§5.7.2: requires a `RevisionExecutionReceipt` in `addressed_findings`). §8.3's `human_resolved` (human edited; defect gone) is **genuinely not covered** by any of these, so adopting it is right — and the card's L1.3 already accepts it ("`human_resolved` per … Review Studio Sec. 8.3", card line 134). Two fixes: (a) cite the card's L1.3 acceptance instead of presenting it as a fresh decision; (b) **add the matching §5.7.2 invariant** — e.g. "a finding with `state == human_resolved` has a corresponding `human_authored_version_created` receipt (§8.2), and a `TaintClearanceRecord` (§15.12) if its `taint_class` was originally untrusted" — mirroring the existing invariant for `user_approved`/`human_verified`. Without the invariant, `human_resolved` is unprovable.
**S4 — BUG — §3.5 mistypes `InterpretedOutcomeFeedback.proposed_durable_candidate`.**
§3.5 prints the "existing" field as `proposed_durable_candidate?: DirectInstructionCandidate`. The operative type (§14.3.1) is `proposed_durable_candidate?: DurableKnowledgeCandidate` (§14.5). `DirectInstructionCandidate` is a *separate* downstream artifact produced under §14.7 (durable *instruction*, not a *pattern*). The teaching path therefore has two outputs (`DurableKnowledgeCandidate` for patterns, `DirectInstructionCandidate` for instructions); §3.5 and §7.2 conflate them. Fix: in the §3.5 extension keep the real field name+type (`proposed_durable_candidate?: DurableKnowledgeCandidate`), and in §7.2 say teaching feedback routes to *either* a `DurableKnowledgeCandidate` (§14.5) *or* a `DirectInstructionCandidate` (§14.7) depending on `authority_class` (§14.6: `future_pattern_signal` → pattern; `durable_instruction_candidate` → instruction).
**S5 — GAP — Disposition‑verb fidelity is lost in the §7.2 decomposition.**
§7.2 maps each `FindingDisposition` → a `HumanOutcomeFeedbackEvent` (§14.2). But §14.2's schema is `{ … feedback_text: string; finding_id?; outcome_id?; artifact_ref?; user_classification?{…}; ui_source }` — there is **no structured field for the disposition verb** (`accept | reject | reject_with_modification`). As written, the structured per‑finding verb the human chose gets flattened into free text and the Feedback Interpreter must re‑parse it. Specify the **two‑path decomposition** explicitly:
- *Disposition verb* → a **gated finding‑state transition** (via `LifecycleWriteCapability` §9.3 + PolicyDecision): `accept` → `human_verified`/`user_approved`; `reject` → `rejected_by_user`; `reject_with_modification` → stays `active` + emits the corrective `RevisionRequest`. Reconcile each against §5.7.1's transition list (which does *not* currently name `accept`/`reject_with_modification` as transitions — add them).
- *Comment / modification text* → a `HumanOutcomeFeedbackEvent` (§14.2) → Feedback Interpreter (§14.3) → `RevisionRequest` (§14.4).
- Also emit the matching signal (§14.8.1 `finding_marked_wrong`/`finding_marked_correct`) so the Evaluator learning loop sees the verb.
Lint: `review_studio.finding_disposition_not_mapped_to_state_transition`.
**S6 — GAP / BETTER_IDEA — Reconcile the terminal decision with the existing `RevisionReviewPacket.reviewer_action`, and add a revision‑review surface.**
The card's G‑02 (line 463) already defines `RevisionReviewPacket` with `reviewer_action: accept | reject | fork | request_changes | restore_known_good_state | no_user_review_required`, carrying a derived **before→candidate semantic diff + `finding_to_change_map` + preservation/revalidation results** — i.e. the exact context a human needs to review a *completed* revision. Review Studio's terminal set is only `approve | send_for_revision | reject` (§5.4/§7.1) and has no port to ingest a completed revision for review. Three actions:
- Add **`restore_known_good_state`** (rollback to a prior `v{N}`, firing `RevisionOperationKind.rollback_apply` §0.4.7; pairs G‑04) and decide whether **`fork`** (`TaskRunFork`, already a ladder rung §6.1) and **`request_changes`** are distinct from `send_for_revision`.
- Add a **`revision_review_packet_in` (Input, optional)** port to `step.review_studio` (§4.1) that consumes a `RevisionReviewPacket`; the `post_revision_exec` intrinsic gate (§4.2) renders its diff + `finding_to_change_map` with per‑change accept/reject (BETTER_IDEA 5). Today `post_revision_exec` is enumerated but has no surface contract.
- Reconcile `ReviewRoutingDecision` (§7.1) as a *superset/explicit‑map* of `reviewer_action` so there aren't two human‑review action vocabularies in DOC23.
**S7 — GAP — No concurrency control on in‑place edits.**
§6.5 explicitly supports an **iterating** loop (discuss / revise / edit / review / repeat) and §6.3 has the assist agent editing while the human may also edit. That is concurrent mutation of one artifact with no specified guard. The substrate exists: `ArtifactMutationPrecondition` validates against snapshot content hashes (CC §3.5, V3.1 §7.13), and the card already mandates it (line 933: "snapshot‑hash precondition on every in‑place workspace write; on mismatch, abort and re‑evaluate rather than overwrite; add explicit lock semantics"). Require: every in‑place edit (human, co‑authored, or successive assist round) carries an `ArtifactMutationPrecondition` against the version it started from; on hash mismatch, abort and re‑surface rather than overwrite. Lint `review_studio.in_place_edit_without_mutation_precondition`. Fixture GS‑RS‑12 "second assist round on a stale version is rejected by precondition."
**S8 — GAP — Resume idempotency + gate expiry for paused checkpoints.**
(Research, item 2.) A paused gate introduces unbounded latency and, on resume, the surrounding loop logic re‑runs. Specify: (a) **resume idempotency** — when the human finally answers, the evaluate‑revise loop must not re‑dispatch already‑completed revision steps (key on `RevisionOperationReceipt`/`attempt_seq`); (b) a **`ReviewGateExpiryPolicy`** with a TTL + on‑expiry action (`hold | auto_reject | escalate_to_task_agent | notify_only`). This connects to the already‑open ADQ‑306 ("review‑queue auto‑archive TTL") — flag the dependency so the two don't define conflicting TTLs.
```ts
interface ReviewGateExpiryPolicy {
ttl_hours: number | null // null => never expires
on_expiry: "hold" | "auto_reject" | "escalate_to_task_agent" | "notify_only" // default "hold"
schema_version: 1
}
```
Trace: new, but `default_if_no_response` discipline and review‑queue TTL are precedented (Flatten plan §11.4 ADQ pattern; ADQ‑306). Mark `OPEN_FOR_ARCHITECT_REVIEW` on the default.
**S9 — GAP — Three anchor vocabularies are not reconciled.**
Findings use `TargetScopeRef` (A‑01 / Review Studio §2); the operative `EvaluationResultEnvelope.target_scope_ref` is typed `ArtifactScopeRef` (CC §7, with `scope_kind` document/section/paragraph/citation_block/claim/page_range/line_range/field + `TextAnchor | StructuredAnchor`); DOC20 comments use `CommentAnchor` (`TextAnchor | PageAnchor | LineAnchor | UnanchoredAnchor`). §3.6 maps `TargetScopeRef` → `CommentAnchor` but never states the relationship between `TargetScopeRef` and `ArtifactScopeRef`. Define the canonical mapping (ideally: `TargetScopeRef ≡ ArtifactScopeRef`, with a total function `ArtifactScopeRef → CommentAnchor` whose `field`/`citation_block`/`claim` kinds fall back to `UnanchoredAnchor` where the renderer can't host them). Lint `review_studio.target_scope_ref_unmappable_to_comment_anchor`.
**S10 — GAP — Findings can only be *anchored* on Tiptap; the surface contract doesn't degrade per renderer.**
Per `RENDERER_CAPABILITIES` (DOC20 §6.16.5A): inline comments are supported **only on `tiptap`**; page anchors **only on `pdf`**; line anchors on `markdown`/`code`; **docx supports none**. So §5.1's "findings load into the Comments panel as anchored finding‑comments" and §3.6's click‑finding→highlight are only fully true for Notes (tiptap). §5.2's surface‑adaptation table addresses *which panels show*, not *whether anchors are possible*. Specify the degradation: for renderers without inline‑comment support, findings render in the **General/unanchored** group (`UnanchoredAnchor`), and per‑finding click‑to‑highlight is hidden via `RendererCapabilities`. For docx specifically, anchored review requires either Convert‑to‑Note (Tiptap, gains anchoring, loses native docx fidelity) or the OnlyOffice bridge (C2). This is the heart of the item‑4 answer.
**S11 — GAP — `shifted` / `approximate` anchor states are unhandled.**
§3.6 maps only `orphaned ↔ superseded_by_revision`. DOC20 §6.6.8A defines four anchor states: `active | shifted | approximate | orphaned`. A **`shifted`** finding anchor (fuzzy‑match 0.7–0.99 after an edit) is *still valid* — the targeted defect may persist at the remapped location — so treating a post‑edit shift as `superseded_by_revision` would silently drop a live finding. Specify: on a human/co‑authored edit, run the existing anchor remap (§6.6.7A); `active`/`shifted`/`approximate` → finding stays live at the remapped anchor and is re‑evaluated; only `orphaned` → `superseded_by_revision`. Lint `review_studio.finding_superseded_on_nonorphan_anchor`.
**S12 — GAP — Routing *all* general directives to run‑scoped Criteria over‑gates soft guidance.**
§3.5 turns every `GeneralDirective` into a run‑scoped `Criterion` the Evaluator re‑checks every round (a *pass‑bar* item). A soft preference ("use a more formal register") then becomes a hard re‑checked criterion that can block `pass`. The system already has the right home for soft guidance: **`RunGuidanceItem`** (FD §4) with `guidance_kind: style_rule | do_not_use | …`, lifecycled, defeasible, rendered as *guidance* (consumers skip `contested`; card line 297 fixes its store to `TaskBlueprint.persistent_guidance[]`). Split the directive intake by `authority_class` (§14.6): `current_run_instruction` (controlling) → run‑scoped Criterion; `current_run_preference` (advisory) → `RunGuidanceItem`. This also removes the need to invent `RunScopedCriterion` (M1).
**S13 — GAP — Reconcile `HumanReviewResult` with the reserved `human_review` ProducerKind and the human‑review feedback bundle.**
CC §2.1 reserves a `human_review` `ProducerKind` (populating `qualitative_slice` + `assurance_slice`), and FD §1.2/§2.3 explicitly contemplates a **human‑review `EvaluationFeedbackBundle`** ("Human review records may include a manual bundle"). Review Studio decomposes only to `HumanOutcomeFeedbackEvent`s (§7.2) and never emits an `EvaluationResultEnvelope`/`EvaluationFeedbackBundle`. Decide explicitly: does a Review Studio decision *also* emit a `human_review` envelope+bundle? Doing so would (a) finally implement the reserved producer kind, (b) make human review a first‑class evaluation in audit/UI chain reconstruction (CC §3.7 chain semantics), and (c) feed learning correlation symmetrically with machine evaluators. If you decline, say so and state why human review stays "events‑only." Either way it should be a stated decision, not an omission. → OBL‑RS‑11.
### MINOR
- **M1 — GAP — `RunScopedCriterion` is an undefined type name** (§3.5 extension). CC §6 defines `Criterion`; there is no `RunScopedCriterion`. Either define it as `Criterion` + a run‑scope facet or rename. (S12 likely dissolves the need for it.)
- **M2 — BUG (minor) — `human_label` is an `authority_basis` value, not `assurance_basis`.** §3.5 says the human‑authored finding's "`assurance_basis` includes `human_label`," but `human_label` lives in `EvaluationAuthorityBasis` (FD §3.2; card L1.3 line 116 keeps the two bases distinct). Set `authority_basis ∋ human_label`; set `assurance_basis` from the `AssuranceBasis` enum.
- **M3 — SUGGESTION — Cite the real source for "Gate‑4" / "rely with limitations" (§2.1).** Those labels are not in V3.3.1 §6.7.3 (which is the *loop breaker* → §6.8 escalation). "Gate‑4 / human" is the card's `FeedbackResponsibilityMatrix` framing ("ambiguous/contested → human (Gate‑4)", card line 599). Cite that; keep §6.7.3→§6.8 for the escalation mechanic.
- **M4 — GAP — `post_revision_plan` overlaps the existing plan‑review `human_gate`.** §6.10 already surfaces low‑confidence plans for human review via `PlanAssurancePolicy.required_modes ∋ human_gate`. Reconcile so `post_revision_plan` (§4.2) and the §6.10 `human_gate` are one gate, not two.
- **M5 — CONFIRMED + note — OBL‑RS‑04 (Attachment `parent_type` extension) is correct.** §7.18 was split (R2) into `AttachmentBlobSchema` + `AttachmentRefSchema`; the `comment | finding | review_result` extension lands on `AttachmentRefSchema.parent_type` (current values `chat_message | note | task | room_message | forum_post`). `created_by` already accepts `agent_id`, which is what co‑authored attribution needs — good.
- **M6 — GAP (cross‑doc seam) — Two finding‑state enums coexist.** V3.3.1 §5.7 `FindingState` (12‑value) vs FD §3.1 `EvaluationFindingLifecycleState` (7‑value: `proposed|accepted|user_approved|tool_verified|contested|superseded|expired`). Review Studio rides §5.7, but its materialized findings also flow into FD bundles (§3.5). State which enum governs a finding that exists in both surfaces (this is a DOC23‑family seam, not strictly Review Studio's bug, but Review Studio is the junction that exposes it).
### CONFIRMED (not problems — verified sound)
- **The Tier‑1 decomposition is real and buildable.** `HumanOutcomeFeedbackEvent` (§14.2) → Feedback Interpreter (§14.3) → `RevisionRequest` (§14.4) → Revisor, with `authority_class` (§14.6 `current_run_instruction` vs `current_run_preference`) and the `no‑current‑plan`/`completed‑plan` routing rules (§14.4) — all present as cited. (§7.2 is accurate modulo S4/S5.)
- **The signal layer Review Studio rides is real.** `finding_marked_wrong`, `finding_marked_correct`, `revision_instruction_useful`, `evaluator_plan_user_edited` (§14.8.1/§14.8.2) and consumers (§14.8.4: DOC72, DOC8/BDSM Phase 2, DOC24, EC) — confirmed. §11.2's "signal layer wired, reasoner reserved" is correct.
- **OBL‑RS‑10 is correctly identified.** §14.2 `ui_source` is `evaluation_result_card | revision_result_card | plan_review | hard_call_response | teach_from_feedback_card | direct_chat` — `review_studio_card | document_viewer | email_reply` are absent and must be added.
- **The finding model is shared, not forked.** Card L1.3 (lines 108, 571, 1793) confirms `EvaluationFinding` event/record/view is the same model as Review Studio §2 — but see S‑note below on the `governance` vs `actor` field divergence.
- **The Tiptap review surface is built to the needed depth.** Comments (§6.6.2), threading (§6.6.3), anchor visualization + remap (§6.6.7/§6.6.7A), tracked changes (§6.10), immutable versioning with `artifact_id` root + `version_id` children (§6.16.10), Send‑to‑Agent + `DocumentReviewRequest`/`DocumentReviewResultEvent` (§6.16.8) — all present.
**S‑note (Substantive) — `LifecycleActorEnvelope` vs `GovernanceEnvelope` on the shared record.** The card's shared L1.3 `EvaluationFindingRecord` carries `governance: GovernanceEnvelope`; Review Studio §2's record carries `actor: LifecycleActorEnvelope` (and §9.1 says `LifecycleActorEnvelope` *extends* `GovernanceEnvelope`). Since the model is declared shared (not forked), the field name+type must be identical in both docs. Recommend: the record field is `actor: LifecycleActorEnvelope` where `LifecycleActorEnvelope extends GovernanceEnvelope` (so it satisfies the governance mixin *and* adds `author_kind`/`author_ref`/`on_behalf_of_ref`), and the card's L1.3 is updated to match. Otherwise the "shared schema" claim is false at the field level.
---
## 4. End‑to‑end human‑gate walkthrough (with the Document‑Review / in‑place‑editing reality)
**Trace (a Tiptap‑native artifact — the path that works today):**
1. Evaluator runs → emits `EvaluationResultEnvelope` (CC §3) + `EvaluationFeedbackBundle` (FD §2) with findings (§5.7). Intrinsic gate `post_evaluation` fires (§4.2). ✓
2. Gate opens the DOC20 viewer in review mode (§5.1); findings load as `finding`‑kind comments anchored via `TargetScopeRef`→`CommentAnchor` (§3.6). ✓ on tiptap; ✗ anchoring on docx (S10/C2).
3. Human disposes findings (accept/reject/modify, §5.3) → `FindingDisposition[]` (§3.2). **Verb→state‑transition path is underspecified (S5).**
4. Human optionally collaborates: Discuss (advise) / Revise with Agent / Edit (§5.4 Layer 2). The in‑place assist (§6.3) edits the artifact. **Mutation must route through `revision_in`/`revision_compatible` (C1), not bare Send‑to‑Agent.**
5. Edit → new version + `human_authored_version_created` receipt (§8.2) → cascade (§11.21). **Needs a runner at standalone gates (S1).**
6. Human takes the terminal decision (approve / send_for_revision / reject, §5.4 Layer 3) → routing (§7.1) → ports (§7.3). **Missing `restore_known_good_state`/`fork` (S6).**
7. `send_for_revision` decomposes into the §14 pipeline (§7.2). ✓ modulo S4/S5.
The walkthrough **does** work end‑to‑end for a **Note (Tiptap)** artifact once S1/S5 are closed. It does **not** yet work for a **.docx** artifact, which is the part Will is right to worry about.
### (a) What is already built / worked out (verified)
- **Tiptap‑native review & editing:** anchored comments + threading (§6.6.2/§6.6.3), four‑state anchor remap (§6.6.7A/§6.6.8A), tracked changes with per‑change and Accept‑All/Reject‑All → new version (§6.10.4/§6.10.5), Convert‑to‑Note fork (§6.16.9), immutable `artifact_id`+`version_id` versioning (§6.16.10), Send‑to‑Agent request/response (`DocumentReviewRequest`/`DocumentReviewResultEvent`, §6.16.8), `RendererCapabilities` gating (§6.16.5A). This is real and adequate.
- **docx full editing exists — but in a different engine:** OnlyOffice with copy‑on‑write `_E{N}.docx`, mandatory tracked changes, `enforceEditPolicy()`, multi‑account OneDrive/Word‑Online resolution, agent‑edit notifications (DOC20 Addendum B R3, complete to front‑end‑build depth). The *attribution* model there (tracked changes under an author name) is exactly what `LifecycleActorEnvelope` + `human_resolved` want.
- **pdf:** PDF.js view‑only, page anchors, no annotation (Addendum B R3 §1.3; `RENDERER_CAPABILITIES.pdf`).
### (b) How hard to get Document Review / in‑place editing "back to where it's supposed to be" — the specific gaps and the effort
The honest framing: it's not that editing is *missing* — it's that **two docx editing engines exist and were never reconciled**, and Review Studio cited the wrong one. The work is reconciliation + bridging, not greenfield.
| Gap | What's needed | Effort |
|---|---|---|
| **G‑A: Pick the docx review/edit engine** | Architect decision: docx review surface = OnlyOffice‑in‑review‑mode, **or** Convert‑to‑Note→Tiptap‑then‑review, **or** mammoth preview + comments‑only (no in‑place). This is the gating decision; everything below depends on it. | **Decision (ARCHITECT_STOP for docx).** Low effort to decide, high blast radius. |
| **G‑B: Reconcile version spines** | Map OnlyOffice `_E{N}.docx` ⇆ artifact `v{N}` (`artifacts_current.json`). Likely: ingest each OnlyOffice save as a new artifact `version_id` so `reviewed_artifact_version_ref` (§8.1) is well‑defined for docx. | **Medium.** Schema + ingest wiring; the artifact‑version model already exists. |
| **G‑C: Anchored findings on docx** | mammoth docx supports no anchors (line 4033). Either (i) Convert‑to‑Note to gain Tiptap anchoring, or (ii) bridge OnlyOffice native comments ⇆ `CommentAnchor` (OnlyOffice comments are `.docx`‑internal/copy‑on‑write — a non‑trivial bridge), or (iii) accept unanchored findings on docx (S10). | **Medium–High** for a true OnlyOffice⇆CommentAnchor bridge; **Low** if you accept Convert‑to‑Note or unanchored. |
| **G‑D: Route the assist edit through the mutation contract** | §6.3's in‑place assist on a docx must go through `enforceEditPolicy()` (copy‑on‑write, tracked changes) **and** the A‑16 `revision_in`/`revision_compatible` contract (C1). Today it mentions neither. | **Medium.** Mostly contract + wiring; both substrates exist. |
| **G‑E: pdf review** | No annotation today; page‑anchored findings are renderable (PageAnchor) but pdf is `editable:false`. In‑place pdf edit is out of scope unless PSPDFKit (flagged "future" in R3 §1.3). | **Low** (page‑anchored, read‑only findings) / **High** (true pdf editing — defer). |
Net: for **Notes/markdown/code**, Review Studio is ~"close to where it's supposed to be" after S1/S5. For **docx**, the path back is **G‑A (decide) → G‑B/G‑D (reconcile, medium) → G‑C (bridge or accept‑unanchored)**. I'd estimate the docx reconciliation is the single largest chunk of real work in the whole unit, and it's currently hidden behind the inaccurate "mammoth.js" citation.
**Controls the human needs that aren't currently in the unit:**
- **Restore / revert to a prior version** (`restore_known_good_state`, S6) — the most important missing control.
- **Per‑change accept/reject on a co‑authored revision** (diff‑first review, BETTER_IDEA 5 / S6) — today the result just "loads into the viewer."
- **A finding filter** (by severity / state / un‑disposed) — Spellbook's "concentrate on negotiation points" (item 7).
- **A "why this finding" provenance peek** (BETTER_IDEA 6).
- **A visible "this is a copy — original untouched" affordance** for docx (the copy‑on‑write `_E{N}.docx` reality must be surfaced, or the human will not know which file they're editing).
---
## 5. Downstream context injection after a human review
**Substantive answer.** The receiving module must not be blind to (i) *what the human changed* and (ii) *what the human decided / instructed and why*. ELNOR already owns the right boundary for this — and §7.2 currently underspecifies it by hand‑waving "CIL/DOC15 auto‑frames provenance."
The correct mechanism, in the operative ownership model (FD §8): **DOC23 carries the changes/decisions as durable objects; DOC15/CIL assembles the final prompt; DOC24 selects/summarizes/permissions scoped context.** FD §8.3 is explicit that you must *not* say "DOC24 injects the human's edits"; you say DOC24 *selects* feedback‑derived material and DOC15/CIL *renders* it. Concretely, three carriers:
1. **The reviewed version, by reference (not re‑sent).** `reviewed_artifact_version_ref` (§8.1) is the new `version_id`; downstream reads the current version. The `human_authored_version_created` receipt (§8.2) + cascade make the new version the live one. (Fix S1 so this actually fires at standalone gates.)
2. **The decisions/directives as lifecycled objects** — *this is the part §7.2 must make concrete*:
- Controlling directives → run‑scoped Criteria (the Evaluator re‑checks them; S12 splits these from soft guidance).
- Advisory directives → **`RunGuidanceItem`** (FD §4), `guidance_kind` typed, lifecycled, **rendered into downstream prompts by CIL/DOC15 filtered to `active`/`user_approved`/`tool_verified`** (FD §4.4, §10.3 DOC15 insert) and selected as scoped context by DOC24 when the module had no wired feedback (FD §8.2, §10.3 DOC24 insert). This is the existing, owned path — Review Studio should name it instead of "auto‑frames."
- Per‑finding dispositions → finding‑state transitions (S5) that the next Evaluator sees.
3. **A consumption receipt to close the loop.** Every downstream module that consumes the human's directives/guidance must emit a `FeedbackConsumptionReceipt` (FD §9) — `consumption_mode` ∈ `used_as_instruction | used_as_context | conflicted_with_newer_guidance | …`, linking `produced_artifact_refs`. Silent non‑consumption fires `validation.feedback_consumed_without_receipt` (FD §9.4). This is how you *prove* the downstream module wasn't blind.
**What to add to the unit:** a short "downstream context" subsection that (a) maps Review Studio outputs onto `RunGuidanceItem`/Criterion/finding‑transition, (b) states the FD §8 ownership phrasing verbatim (DOC23 wires, DOC15 assembles, DOC24 scopes), (c) requires `FeedbackConsumptionReceipt` from the receiving module, and (d) names a small **"human‑review context capsule"** that the next module receives: `{ reviewed_version_ref, decision, controlling_criteria[], advisory_guidance[], disposed_findings_summary, edit_provenance }`. The capsule is *derived* (a projection, §9.2) — not a new truth store. Lint `review_studio.downstream_handoff_without_guidance_or_capsule`.
This is also where the **matter/privilege firewall** must hold: the capsule and any `RunGuidanceItem` carry `GovernanceEnvelope.matter_ref` (card L1.1 / D‑24) and are AccessTier‑filtered under default‑deny (§16.5/§16.6) — a human's privileged comment must not leak cross‑matter (FD §5.3; card line 379).
---
## 6. Straight from review into the Revisor
**Possible? Yes. Feasible? Yes — it's mostly already contracted. Worthwhile? Yes, with two guardrails.**
This is Tier 1 (§11.1) and it is real: a review's dispositions/directives already become `HumanOutcomeFeedbackEvent`s (§14.2) → Feedback Interpreter (§14.3) → `RevisionRequest` (§14.4) → Revisor, and the Revisor already reaches multiple modules via `RepairTarget` routing and Task‑Agent escalation (§6.9). The card even names the responsibility map — `FeedbackResponsibilityMatrix`: "repair instruction → Revisor (via `revision_in`, A‑16); strategic/scope change → Task Agent; ambiguous/contested → human (Gate‑4)" (card line 599), with lint `feedback.without_responsible_owner`. So "review → Revisor" is not new machinery; it's wiring that largely exists.
**What it takes (the real work):**
- **Fix S5** (disposition‑verb fidelity) so the Revisor receives structured intent, not re‑parsed free text.
- **Honor C1** (the resulting Revisor mutation goes through `revision_in` — which is *exactly* where you want it; the Revisor *is* the sanctioned mutation path, so "straight into the Revisor" is actually the A‑16‑clean route).
- **Decide the auto‑vs‑confirm gate.** Going straight in should respect the user's `RevisorConfig.autonomous_mode_policy` (§6.6) and `PlanAssurancePolicy` (§6.10) — low‑confidence or high‑stakes plans still surface for human review rather than auto‑applying.
**Risks:** (a) over‑gating — sending every soft preference into a full Revisor cycle (mitigated by S12's guidance/criterion split); (b) loop cost — repeated review→Revisor→review cycles bounded by `max_revisions` (§3.2.3) and the §6.7.3 loop breaker; (c) the Tier‑2 "evaluator‑bridge" (§11.1) is the *better* multi‑module path because it routes intent through an Evaluator (materialization §3.5) and gets the multi‑module Revisor job + Task‑Agent escalation for free — recommend defaulting multi‑module intent to Tier 2, reserving "straight into Revisor" for single‑artifact corrective intent.
**Benefit:** for the common case (human marks 3 findings reject‑with‑modification on one artifact and wants them fixed now), straight‑into‑Revisor is the fastest correct path and is A‑16‑clean. Worth wiring as the default for single‑artifact corrective dispositions.
---
## 7. UI advice (mockup‑ready)
Layout — review mode over the DOC20 viewer (§5.1), three regions:
- **Center: the artifact** (renderer per `RendererCapabilities`). For docx, a persistent chip: **"Reviewing copy `_E{N}.docx` — original untouched"** (surfaces the copy‑on‑write reality, C2/G‑A). Active‑finding highlight reuses §6.6.7 (author color at 18% bg).
- **Right panel, tabbed `[Findings (n)] [Comments] [Assist]`** (extends DOC20's `[Comments][Send to Agent]`, §6.16.6/§6.16.8):
- **Findings tab:** list of `finding`‑kind items, each a card with severity chip, state badge (`active|human_resolved|superseded|rejected_by_user|…`, §5.7 + §8.3), an `authority_basis`/`confidence` provenance peek (BETTER_IDEA 6), and the three actions **Accept / Reject / Reject‑with‑modification** (+ comment box). Click‑to‑highlight where the renderer supports anchors (S10); otherwise the card sits in **"General (unanchored)"**. A **filter bar**: `All · Blocking · Un‑disposed · Mine` (Spellbook "concentrate on negotiation points"). Anchor‑state affordances per §6.6.8A: `shifted` ⚠ "may have shifted" with original quote; `orphaned` ❌ + **Re‑anchor** (S11).
- **Assist tab:** agent picker (producer pre‑selected; candidate list = task agents + Task Agent + forum, §6.2), **interaction‑mode toggle `Discuss | Revise with Agent`** (advise hides mutation actions; lint `review_studio.advise_mode_mutated_artifact`), `context_scope` + `result_format` (surfaced from §6.16.8), and a chat thread (ModuleActivationChat, adopted §6.4). Assist results return *into* the surface (§6.5): a `revised_artifact` loads a **diff view with per‑change accept/reject** (BETTER_IDEA 5 / S6), not a blind new version.
- **Footer action bar (Layer 3 terminal, §5.4):** context‑aware primary — **"Approve"** (review‑only) / **"Accept revision & continue"** (after an in‑place revision); **"Send for revision ▾"** (target picker: next step · Revisor · module · Task Agent · forum); **"Reject ▾"** (`pause | redirect | abort`). Add **"Restore version ▾"** (S6/BETTER_IDEA 3 — the missing control). A `fork` action lives here too if S6 adopts it.
States every surface needs (your own discipline + DOC20): **loading** (findings streaming), **empty** ("No findings — review or approve"), **degraded** (renderer can't anchor → "Findings shown as general comments for this file type"), **error** (assist failed → `error_out`, notification‑delivery only), **paused/expired** (gate TTL, S8: "This review has been waiting N days — [Resume] [Escalate]"). Plan‑review layout for `plan_in` (§5.2) and the new revision‑review layout for `revision_review_packet_in` (S6).
Show/hide rule: drive *every* action's visibility off `RendererCapabilities` + the gate's `allowed_decisions` (BETTER_IDEA 1) — never render an action the surface can't honor (DOC20 §6.16.5A "hidden, not disabled").
---
## Value‑tiered summary
### Critical (block ratification until resolved)
- **C1 [ARCHITECT_STOP]** In‑place assist mutates via DOC20 Send‑to‑Agent, bypassing the A‑16 `revision_in` single‑mutation chokepoint. Route through `revision_in` or a `revision_compatible=true` port + `LifecycleWriteCapability` + PolicyDecision. (§6.3/§6.5; card A‑16/GS‑01)
- **C2 [BUG/ARCHITECT_STOP for docx]** Cited docx review/edit surface ("Word (mammoth.js)", `v{N}`) doesn't exist as described; docx is read‑only mammoth preview, real editor is OnlyOffice copy‑on‑write `_E{N}.docx`, version spines unreconciled. (§5.1/§8.1; DOC20 §6.16.5A line 4033; Addendum B R3)
### Substantive (fix in this revision)
- **S1** §8.2 cascade has no runner at standalone placeable gates (Loop Controller absent, §4.2; declared‑deps‑only, §11.21.1).
- **S4** §3.5 mistypes `proposed_durable_candidate` as `DirectInstructionCandidate`; it's `DurableKnowledgeCandidate` (§14.3.1/§14.5).
- **S5** Disposition‑verb fidelity lost; specify the verb→finding‑state‑transition + comment→`HumanOutcomeFeedbackEvent` two‑path decomposition (§7.2; §14.2; §5.7.1).
- **S6** Reconcile terminal decision with `RevisionReviewPacket.reviewer_action` (add `restore_known_good_state`/`fork`/`request_changes`); add `revision_review_packet_in` + diff‑first review (card G‑02/G‑04; §0.4.7 `rollback_apply`).
- **S7** No concurrency control on iterating in‑place edits; require `ArtifactMutationPrecondition` + locks (CC §3.5; card line 933).
- **S9** Reconcile `TargetScopeRef` ↔ `ArtifactScopeRef` ↔ `CommentAnchor` (§3.6; CC §7; DOC20 §6.6.2).
- **S10** Findings anchorable only on Tiptap; specify per‑renderer degradation (DOC20 §6.16.5A).
- **S11** Handle `shifted`/`approximate` anchor states, not just `orphaned`→superseded (DOC20 §6.6.8A).
- **S12** Don't route all general directives to pass‑bar Criteria; split advisory → `RunGuidanceItem` (FD §4; §14.6).
- **S13** Decide whether human review emits a `human_review` envelope+bundle (CC §2.1; FD §1.2/§2.3) or stays events‑only.
- **S‑note** Align the shared finding‑record field: `actor: LifecycleActorEnvelope` (extends `GovernanceEnvelope`) in both Review Studio §2 and card L1.3.
- **S2** Reconcile new `human_authored_version_created` with existing `human_gate_decision` (§0.4.7).
- **S3** `human_resolved`: cite card L1.3 acceptance + add the §5.7.2 invariant.
- **S8** Add resume‑idempotency rule + `ReviewGateExpiryPolicy` (ties to ADQ‑306).
### Minor (cleanup)
- **M1** Define/rename `RunScopedCriterion` (likely dissolved by S12).
- **M2** `human_label` → `authority_basis`, not `assurance_basis` (§3.5; FD §3.2).
- **M3** Cite real source for "Gate‑4"/"rely with limitations" (card FeedbackResponsibilityMatrix; §6.7.3→§6.8 for the mechanic).
- **M4** Reconcile `post_revision_plan` with the existing plan‑review `human_gate` (§6.10).
- **M5** Confirm OBL‑RS‑04 lands on `AttachmentRefSchema.parent_type` (§7.18 R2 split).
- **M6** Note which finding‑state enum governs (§5.7 vs FD §3.1).
### Considered and declined
- **Building a dedicated review→orchestrator engine now (Tier 3).** Correctly reserved (§11.1); the building blocks (`TaskRunFork` §6.1, `graph_patch_proposal` §6.9, Task‑Agent graph‑design) exist, so deferral is cheap and right. Do not build it in this unit.
- **A separate human‑review request schema.** Correctly avoided — `HumanReviewResult extends DocumentReviewRequest` (§3.2) is the right reuse (modulo S13's envelope/bundle question, which is a *different* axis).
- **Absorbing bulk/issue‑coding review.** Out of scope (that's the Relativity‑aiR market, item 2). Keep Review Studio single‑artifact.
- **A fourth terminal "advise/revise" button.** Correctly rejected (§5.4) — advise is a session mode, not a terminal; the genuinely new controls are the Layer‑2 affordances. Agree.
---
*Reviewer: Claude Opus 4.8. Findings typed BUG/GAP/SUGGESTION/BETTER_IDEA/CONFIRMED/ARCHITECT_STOP; sections cited; proposed contracts traced to cited sections or flagged OPEN_FOR_ARCHITECT_REVIEW. No phantom features introduced.*