aboutsummaryrefslogtreecommitdiff
path: root/.ai/workflows/spec-response.org
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-23 12:59:31 -0500
committerCraig Jennings <c@cjennings.net>2026-05-23 12:59:31 -0500
commit7f2aea1e022c93f3eb463e5222bdb0d8ae6288b9 (patch)
treecbbd70275d9384d102d1825e441a114b0e84ca36 /.ai/workflows/spec-response.org
parent2d34e9ac3a9cec1f625df75f08890ee85836afa3 (diff)
downloadrulesets-7f2aea1e022c93f3eb463e5222bdb0d8ae6288b9.tar.gz
rulesets-7f2aea1e022c93f3eb463e5222bdb0d8ae6288b9.zip
feat(workflows): add spec-review and spec-response workflow pair
These two workflows form a reviewer side and an author side for taking a design spec to implementation-ready. spec-review judges a spec against a readiness gate, reads the code before critiquing, evaluates across dimensions, assigns a rubric (Ready / Ready-with-caveats / Not-ready / Needs-research), and writes a <spec>-review.org file when it isn't ready. spec-response consumes that file: it decides accept / modify / reject for every recommendation, weaves the accepts into the spec body, records the modifies and rejects with reasons in a "Review dispositions" section, and reconciles tensions when coupled specs get reviewed together. The review file is the contract between them. Both were validated by a real run on 2026-05-23 before landing here. I then reviewed them against established practice and tightened five things. The readiness gate now covers security/privacy and observability, since a spec shouldn't pass with those undefined. Phase 1 is a fast triage and Phase 3 is the authoritative gate after the code read. Finding severity maps to blocking power. A rejection goes back to the reviewer instead of standing as a unilateral call. And the response loop has an explicit termination condition. I added both to INDEX.org under a new "Specs and design" section with trigger phrases, cross-linked as a pair, and kept the canonical and mirror copies identical.
Diffstat (limited to '.ai/workflows/spec-response.org')
-rw-r--r--.ai/workflows/spec-response.org138
1 files changed, 138 insertions, 0 deletions
diff --git a/.ai/workflows/spec-response.org b/.ai/workflows/spec-response.org
new file mode 100644
index 0000000..2986d0d
--- /dev/null
+++ b/.ai/workflows/spec-response.org
@@ -0,0 +1,138 @@
+#+TITLE: Spec-Response Workflow
+#+AUTHOR: Craig Jennings
+#+DATE: 2026-05-23
+#+STARTUP: showall
+
+* Overview
+
+The spec-response workflow processes external reviews of a design spec and folds them into the spec until it is implementation-ready. A reviewer (human or another agent) leaves a review file next to the spec — typically produced by its counterpart, the *spec-review* workflow, which writes =<spec-basename>-review.org= and assigns a readiness rubric. Claude works through every recommendation, deciding accept / modify / reject for each, updates the spec for the accepted ones, documents the modified and rejected ones with reasons, then deletes the review file. Repeat for each spec under review.
+
+The output is a spec a reader could implement from, plus a durable record — inside the spec — of why any recommendation was changed or declined, so the reviewer can find the reasoning later without re-litigating.
+
+This workflow was first run on 2026-05-23 against the linear-emacs =issue-query-spec.org= and =issue-representation-spec.org= reviews, and written up from that run.
+
+* Problem We're Solving
+
+A review is only useful if every point in it gets a decision. Without a defined process:
+
+- *Recommendations get dropped silently.* A skim picks up the obvious ones and loses the rest; the reviewer can't tell whether a missing change was rejected or forgotten.
+- *Rejections leave no trace.* When a recommendation is declined for a good reason, that reason lives only in chat and evaporates. The next reviewer re-raises it.
+- *Reviews get rubber-stamped.* Accepting everything uncritically is as bad as ignoring it — the point of the review is judgment, including the judgment to say no.
+- *Cross-spec conflicts go unreconciled.* When two related specs are reviewed and the reviews pull in opposite directions, nobody resolves the tension and it surfaces during implementation.
+- *The spec never converges.* Without an explicit "implementation-ready" bar, review cycles drift.
+
+*Impact:* slow convergence, lost rationale, re-litigated decisions, and specs that look reviewed but aren't decided.
+
+* Exit Criteria
+
+A spec's review is fully processed when:
+
+1. *Every recommendation has an explicit disposition* — accepted, modified, or rejected. None dropped.
+2. *Accepted recommendations are woven into the spec body* — the spec reads as if they were always there, not appended as a changelog.
+3. *Modified and rejected recommendations are documented in a bottom section* (e.g. "Review dispositions") with a one-paragraph reason each, so the reviewer can find the reasoning.
+4. *Pre-agreed decisions are baked in as decisions*, moved out of "open questions."
+5. *Cross-spec tensions are reconciled in writing* when related specs were reviewed together.
+6. *The review file is deleted* once 1-5 hold.
+7. *Tracking is updated* — the spec's VERIFY/task body notes "review incorporated" and whether it's implementation-ready.
+
+The whole run is done when no =*-review.org= files remain and each spec is judged implementation-ready (or its remaining blockers are named).
+
+*Measurable validation:* a reader scanning the review against the revised spec can find, for every review point, either the change in the body or its disposition at the bottom. Nothing is unaccounted for.
+
+* When to Use This Workflow
+
+Trigger when:
+
+- A reviewer drops a review file alongside a spec — convention: same basename with a =-review.org= suffix (=foo.org= → =foo-review.org=).
+- Craig says "respond to the review" / "let's run the spec-response workflow" / "process the spec reviews."
+- Any time a spec needs to absorb structured external feedback and converge to implementation-ready.
+
+Not for: drafting a spec from scratch (that's a design conversation), or informal inline comments (handle those conversationally / via the cj-comment flow).
+
+* Approach: How We Work Together
+
+** Phase 0: Orient
+
+1. List the review files (=ls docs/*-review.org= or wherever they live). Process them one at a time in whatever order; the user may name an order.
+2. Re-read the *current* spec, not your memory of it — it may have changed since you wrote it (the user or a linter may have edited it, and pre-agreed decisions may already be encoded in the tracking file).
+3. Note any *pre-agreed decisions* the reviewer or user has already settled — in the review's own "Agreed decisions" section, or in the spec's tracking task. These are settled inputs. Don't reopen them; bake them in.
+
+** Phase 1: Read the whole review before touching the spec
+
+Read the entire review first. Recommendations interact — an early "medium" finding may be subsumed by a "high" one, or two findings may point at the same edit. Decide dispositions with the whole picture in view, not finding-by-finding as you scroll.
+
+** Phase 2: Decide a disposition for every recommendation
+
+For each recommendation, choose one:
+
+- *Accept* — the recommendation is right as written. Plan the edit.
+- *Modify* — the recommendation is right in spirit but wrong in detail or scope. Adjust it, and record what you changed and why.
+- *Reject* — the recommendation doesn't fit. Record why.
+
+*Engage critically.* Rubber-stamping is a failure mode. On a strong review most points are accepts, but actively look for the genuine modify/reject cases — they are where your judgment earns its place. Examples from the first run:
+
+- *Modify:* the review proposed an automatic cache-TTL defcustom. Accepted the goal (fresh data) but deferred TTL to vNext because for a single-user tool an explicit force-refresh + clear-cache command covers it without invalidation complexity.
+- *Reject:* the review floated a separate =default-issue-filter= defcustom. Rejected as redundant — a fixed default command plus a default-view preference already covered it.
+- *Modify (scope):* "split representation from network into modules" — adopted the logical boundaries but kept a single file, because the package is a single-file MELPA target and a file split is a larger restructuring.
+
+*Honor pre-agreed decisions.* If the reviewer marked a decision "agreed" (or the user pre-encoded it), treat it as accepted and settled — move it from the spec's open questions into a decisions section.
+
+** Phase 3: Reconcile cross-spec tensions
+
+When related specs were reviewed together, two reviews can recommend opposite things. Don't pick one and silently drop the other — find the framing in which both hold. Example from the first run: one review said "switching views *replaces* the active file"; the other said "refresh by *merge*, not wholesale rewrite." Reconciliation: switching *source* replaces; refreshing the *same source* merges by stable ID with a per-item conflict check. Write the reconciliation into the spec.
+
+** Phase 4: Update the spec
+
+1. *Weave accepted recommendations into the body.* The spec should read naturally — a new "Selector semantics" section, a revised phase plan, an added test-strategy section — not a list of "review said X so I did Y." The body reflects the decisions; it doesn't narrate them.
+2. *Add a bottom "Review dispositions" section* listing only the *modified* and *rejected* recommendations, each with a short reason. Close it with a one-line "everything else accepted as written" so the reader knows the omissions from this section are accepts, not gaps.
+3. *Move settled questions out of "Open decisions"* into an "Agreed decisions" (or equivalent) section. Open decisions should contain only what genuinely still blocks.
+4. *Raise the spec to implementation-ready:* consolidate decisions up front, add any implementation prerequisites the review surfaced (e.g. a schema-verification checklist), a consolidated test strategy, and a phased plan ordered so dependencies (like an output model everything depends on) come early.
+5. *Update the status line* to note "review incorporated (<reviewer>, <date>)."
+
+** Phase 5: Close out and iterate
+
+1. *Delete the review file* — only after every recommendation has a disposition. Its deletion is the signal the review is fully processed.
+2. *Update tracking* — the spec's VERIFY/task body gets a line noting review incorporated, what changed at a high level, which recommendations were modified (pointing at Review dispositions), and whether it's now implementation-ready pending final go.
+3. *Update the session log* (state changed this turn).
+4. *Move to the next review file.* Repeat Phases 1-5 until none remain.
+5. *Report* what was accepted-wholesale, what was modified/rejected and why, any cross-spec reconciliations, and the implementation-ready verdict per spec.
+
+* Principles to Follow
+
+** Every recommendation gets a decision
+Accept, modify, or reject — but never silently drop. The reviewer must be able to account for every point.
+
+** Document the no's, not the yes's
+Accepted recommendations live in the spec body (the change *is* the record). Modified and rejected ones need an explicit written reason at the bottom, because the change is invisible and the reasoning would otherwise be lost. The asymmetry is deliberate.
+
+** Critique, don't rubber-stamp
+A review you accept entirely without finding a single thing to push on probably wasn't read critically. Your judgment — including a well-reasoned no — is the value you add.
+
+** Pre-agreed decisions are settled inputs
+Don't re-open what the reviewer or user already agreed. Bake it in and move on.
+
+** Reconcile, don't choose-and-drop
+When reviews conflict, find the framing where both are right. Silently honoring one and ignoring the other reintroduces the conflict at implementation time.
+
+** A reject goes back to the reviewer, not just into the file
+Recording a reasoned reject is the floor, not the close. Communicate the rejection and its reason to the reviewer — a reject is a two-party event, not a unilateral call. If the reviewer disagrees, that's a discussion: weigh the counter, and if you still can't agree, escalate to whoever owns the decision rather than letting the author's "no" stand by default. "I'm not doing that" with no reason the reviewer can engage is the failure mode. (For a tight solo author-reviewer loop this is lightweight; for a team it's the difference between a review and a rubber-stamp-in-reverse.)
+
+** The spec reads forward, the dispositions read backward
+The body is written for the implementer (no review archaeology). The dispositions section is written for the reviewer (the reasoning trail). Keep the two audiences separate.
+
+** Re-read before editing
+The spec may have changed since you last saw it. Edit the current file, reconcile against the latest tracking state.
+
+** Converge to implementation-ready
+The bar is "a reader could implement from this." Decisions consolidated, prerequisites named, tests strategized, phases ordered by dependency. The loop terminates when the spec-review rubric reaches =Ready= (or =Ready with caveats= the author accepts) and every blocking, high-priority finding has a disposition — not when you run out of energy. Iterate toward that bar, not in circles.
+
+* Living Document
+
+Update this workflow as we learn what works. Capture new disposition patterns, better reconciliation examples, and refinements to the implementation-ready bar.
+
+** Updates and Learnings
+
+*** 2026-05-23: First run — two coupled specs, one reviewer
+*Learning:* The reviews were high quality and mostly accepts, which made the genuine modify/reject cases the high-value work — and the cross-spec reconciliation (replace-on-switch vs merge-on-refresh) was the single most useful synthesis, something neither review could do alone. The "Review dispositions" section closing with "everything else accepted as written" proved important: without it, a reader can't tell whether an unlisted recommendation was accepted or missed.
+
+*Open question for next run:* whether to keep dispositions inside each spec (current approach) or in a shared response doc when many specs are reviewed at once. Inside-the-spec kept the reasoning next to the affected text, which read well for two specs.