# Owner Gate Review

> Use when a design, refactor or review document needs a per-decision ruling from one human reviewer and the answers must come back attached to the decision they belong to. Triggers: pasting a long document into chat and getting a wall of prose back, an answer that can't be matched to its question, a reviewer hand-editing answer slots in markdown, or a set of decisions that must each be approved, changed, rejected or deferred before work is scoped.

- Skill: `arasz/owner-gate-review-2` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add arasz/owner-gate-review-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/arasz/owner-gate-review-2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- License: MIT
- Author: Arasz (https://skillmd.com/u/arasz)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/arasz/owner-gate-review-2

---


# Owner gate review

Generate a **review form** — one card per decision, a verdict control and a notes box — that
emits structured markdown. The reviewer clicks and types; the agent gets back a file where every
answer is bound to its decision by construction, not by paragraph order.

**Why this exists.** Prose feedback loses the mapping from answer to question. Answer slots
hand-edited into markdown are better but still lose content: a line-shaped slot hid multi-line
answers, and a reader parsing only the marker line reported six points unanswered when every one
had a written answer beneath it. A form cannot lose the mapping — the DOM enforces it.

## Two variants, one interface

| Variant | Reviewer does | Agent gets it back by |
|---|---|---|
| **Local file** (`file://…/<slug>-review.html`) — **prefer this** | opens the file, answers, clicks **Save feedback** | watching for the result file on disk; no copy-paste |
| **Artifact** (published to claude.ai) | answers, clicks **Copy feedback**, pastes into chat | reading the pasted block |

Same template, same markdown output. Use the Artifact only when the reviewer is not on a machine
you can watch — an artifact page has no filesystem and cannot write next to itself.

## Agent-side protocol

1. **Write the form** from `references/form-template.html` to `<docs>/work/<date>-<slug>-review.html`
   — the dated-work-record directory of the canonical tree, where the docs root comes from
   `.ai-badger/config.json`'s `docs.root` and defaults to `docs/`. A project that keeps work
   records somewhere else uses that instead. Fill the `DECISIONS` array and all per-review
   `CONFIG` fields: `title`, `subtitle`, `source`, `outName`, `expectedDir`, and a unique
   `storageKey` such as `refinement:<slug>:v1`.

   **If `work/` does not exist, create it and give it a README before writing the form** — run
   `scaffold-documentation` if the project has it. Do not fall back to a scratch directory. This
   step named `docs/designs/` until 2026-08-01, a directory the canonical tree does not have; in a
   repo that did not have it either, two real review gates landed in `.tmp/` instead — gitignored,
   hidden, and unreachable by the ripgrep every agent's search is built on. A form nobody can
   grep is a review that did not happen.
2. **Pre-create nothing that could read as a real answer.** Do not write a stub result file, do
   not seed `localStorage`, do not fill any verdict "as an example". A pre-created result file
   makes the watch fire instantly and gets ingested as a review that never happened.
3. **Start the watch** (below) before telling the reviewer the form is ready.
4. **Tell the reviewer to press Clear first** if they have used a review form before — see the
   shared-origin hazard below. The Clear button exists for exactly this.
5. **Ingest** when the file appears: **read the file**, do not trust the notification's timing.
   Check the trailing `<!-- end refinement feedback -->` marker; without it the file was caught
   mid-write — re-read.
6. **Read every note in full.** A note may be a counter-question. That is a legitimate answer and
   means the decision stays open. Verdict alone is never the whole answer.
7. **Reconcile the `## Not answered` list explicitly.** Silence is not consent. Ask again or
   record the item as still open — never resolve it yourself.

### The watch

```bash
OUT="/abs/path/docs/work/2026-01-15-import-pipeline-feedback.md"
for i in $(seq 1 720); do [ -f "$OUT" ] && break; sleep 5; done   # capped: 720 × 5s = 1h
[ -f "$OUT" ] && echo "feedback landed at $OUT" || echo "timed out, no feedback"
```

Run it with `run_in_background: true`. The cap is mandatory: a watch with no stopping condition
is a loop nobody can answer "what ends this?" for, and it outlives the session that started it.
The example uses POSIX shell syntax and is intended for macOS/Linux; on another platform, use an
equivalent finite watcher and preserve the same one-hour cap.

**Caveats.** It fires on file *creation*: a reviewer who saves twice produces one notification,
not two, so the notification tells you a review exists, never that it is the final one — re-read
the file at ingest and re-read again if the reviewer says they changed something. If the reviewer
fell back to `a[download]`, the file is in the browser's download directory, not `$OUT`; the form
tells them so, but also check `~/Downloads/<OUT_NAME>` before declaring a timeout.

## What the save chain guarantees

The template's save chain is **remembered directory → one-time directory grant → `a[download]` →
clipboard → always-visible textarea**, and the UI names which link it used and where the file
went. Four consequences bind the protocol above:

- **The folder is granted once, not per save** — persisted as a `FileSystemDirectoryHandle` in
  IndexedDB under `<storageKey>:dir`. Point the one dialog at the folder holding the HTML.
- **Only Chromium has a picker.** Firefox and WebKit fall through to `a[download]`, so never tell
  a reviewer the file "will be" at `expectedDir` — read back what the UI reports.
- **An `AbortError` means the reviewer cancelled.** The chain stops there.
- **The storage key must be unique per review.** Every `file://` page shares one origin, which is
  why step 4 exists.

The measurements these rest on — three engines, two passes, and the four things still unverified —
are in `references/browser-capabilities.md`. Read it before changing the chain or blaming it.

## Writing decision cards

A card the reviewer cannot decide from without opening the source document has failed.

Each card carries exactly three things:

1. **Claim** — one line, present tense, stating what will be true if approved.
   "`X-Source-System` is the discriminator", not "Discriminator options".
2. **Detail** — the minimum needed to rule on it: the specific numbers, the names, the mechanism.
   Two short paragraphs at most.
3. **Why this matters** — the consequence of getting it wrong, or the thing that changed. This is
   what turns a shrug into a verdict.

Group cards under headings when the kinds differ (corrections / design / open items). Give every
card a short stable id (`D1`, `C2`, `O4`) — it is the join key in the result file.

## Gotchas

No environment-specific gotchas known.

## Red flags — STOP

- A result file that exists before the reviewer has opened the form
- Reading only the verdict and skipping the note
- Treating an item under `## Not answered` as agreement
- A storage key that isn't unique to this review
- A card whose detail is "see §4 of the design doc"
- An uncapped watch loop
- Claiming the save worked because the code path exists — the UI reports the outcome; believe the
  reported outcome, and if the reviewer says nothing, check the file

## Verification Checklist

- [ ] `CONFIG.storageKey` is unique to this review and does not retain the template example
- [ ] `CONFIG.outName` and `CONFIG.expectedDir` match the watch path
- [ ] No result file was pre-created and the watch has a finite stopping condition
- [ ] The saved result ends with `<!-- end refinement feedback -->`
- [ ] Every answered decision's verdict and complete note were read before reconciliation

## Files

- `references/form-template.html` — the generator template, parameterised by `DECISIONS`; read
  it **when writing the form**.
- `references/result-template.md` — the exact markdown shape the form emits, so the parser knows
  what to expect; read it **when reconciling a saved result**.
