1. plan-review-dedup skips only a null or undefined finding; any other entry that is not an object (a string, a number, an array) goes on as before E, a finding with no valid severity that the plan gate counts as a blocker (it was dropped, so a string blocker recorded PASS). 2. plan-gate --record: a previous finding that rule A carried as counted and whose id is backed this round leaves the counted set, the counts, the verdict and the stop rule's summary (it was counted and listed in known_outside at once: BLOCK, not-fewer, and --accept-open refused). 3. A known_outside entry keeps rule_keys; extractVerdict accepts it (a list of strings), and the bare gate re-checks with the same keys the recorder used, so a merged finding whose security key is only in rule_keys is a WARN, not a STOP. 4. plan-critic, scope-guardian and /trekplan Phase 9's round-2 sentences say the Critic Verdict also lists known_outside and each is marked by id in previous. Code already accepts such a mark (dedup passes it; countRound ignores ids it does not carry; --record removes the entry on true); pinned in diff mode and full count. 5. The approval prose names ## Threat Model where it named only ## Intent + ## Goal: skills/annotating/SKILL.md (description, step 4, guard list), docs/command-modes.md, Handover 1's intent_approved_hash row, README (approval, Approve row, intent approval gate) and CLAUDE.md's /trekbrief row. 6. threat-model.mjs gains usableInRepo (a brief path relative to the repo top level) and repoRelativeBrief; --record stores brief_path relative to the top level, never absolute, and both gates read it from there, so the gate run from a subdirectory reads the same brief. reviewThreatModel uses usableInRepo. Handover 4 and the gate header say so. 7. review-finalize's outside pass puts an entry back only when no finding carries its row yet (engine-compare rowOf): an engine finding listed in known_outside while its payload is saved went back twice. 8. A test runs scripts/release-check.mjs on a review whose known_outside entry the brief does not back: exit 2 (control: backed passes the review check). Existing tests changed: plan-gate-threat-model's entry-keys assertion now expects rule_keys (item 3), and its planted non-security entry drops the security key from rule_keys too, since the gate reads rule_keys (item 3). Part 2 fix round of the E plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
98 lines
7.1 KiB
Markdown
98 lines
7.1 KiB
Markdown
---
|
|
name: annotating
|
|
description: "The operator's own annotation loop for a Voyage brief, plan or review (a research document too, when asked): build the page with scripts/annotate.mjs so the person writes every note, take the pasted Copy Prompt back, and revise note by note. Fix and Change edit only the text the note points at; a Question is answered and changes nothing unless the person says so; nothing the notes did not ask for is edited. A note on ## Intent or ## Goal (or ## Threat Model) of an approved brief makes the approval stale, and a changed plan needs a new approval, said before the edit. The page is built again on the revised file. Use when someone wants to comment on, annotate or mark up a brief, plan, review or research document in the browser, or pastes back the notes from that page (Fix, Change, Question)."
|
|
---
|
|
|
|
# Annotating
|
|
|
|
## Overview
|
|
|
|
The annotation page lets the person read a Voyage artifact in the browser, click a line and write
|
|
their own note, then copy every note back as one prompt. The loop is theirs: Claude builds the page,
|
|
and later does what the notes say, no more. Two things go wrong without this skill. A Question gets
|
|
answered and then written into the text as if it were a change. And the revision spreads: the same
|
|
"fix" applied to parts no note named, a section rewritten to match, a new criterion added. Every such
|
|
edit is a decision the person did not make, and on an approved brief or plan it also throws away an
|
|
approval.
|
|
|
|
## When to use
|
|
|
|
- A `/trek*` command has just written a brief, plan or review and builds the page.
|
|
- Someone says "let me comment on the plan", "I want to mark up the brief", "annotate this".
|
|
- Someone asks to annotate a research document under `research/`. `/trekresearch` does not build
|
|
the page itself; build it on request.
|
|
- The person pastes a prompt that starts "Please revise the voyage artifact at" and lists notes as
|
|
`[Fix]`, `[Change]` or `[Question]`.
|
|
- Not for: someone who asks for Claude's own review of the artifact. That is a review
|
|
(`voyage:reviewing-adversarially`, `/trekreview`), not annotation.
|
|
|
|
## Process
|
|
|
|
1. **Build the page.** Run the script on the file and keep its stdout, the absolute path of the
|
|
page:
|
|
|
|
```bash
|
|
ANNOT_HTML=$(node ${CLAUDE_PLUGIN_ROOT}/scripts/annotate.mjs "<path to the .md>" 2>&1)
|
|
```
|
|
|
|
Print `file://<path>` and the line `open file://<path>`. If the script exits non-zero, say so in
|
|
one line and go on: the page is a convenience, never a gate.
|
|
2. **The person writes the notes. Claude writes none.** Next to the link, say only how the page works:
|
|
click a line (or select a phrase first), pick Fix, Change or Question, write the note, and press
|
|
"Copy Prompt" when done; the notes stay in the browser if the tab is closed. No list of "points I
|
|
would look at", no summary of weaknesses, no suggested notes. Those would steer the notes the
|
|
person writes. If they want Claude's view as well, they ask for a review.
|
|
3. **Read the pasted notes.** Each note has a number, a type, the section, the quoted text it is
|
|
anchored to, and the comment. Work from the quote and the comment, one note at a time.
|
|
4. **Before any edit, check what the edit costs.**
|
|
- A brief with `intent_approved_hash` in its frontmatter, and a Fix or Change in `## Intent` or
|
|
`## Goal` (or `## Threat Model`, when the brief has one): say in one line, before the edit, that the edit makes the approval stale, that
|
|
`/trekplan` halts until the new text is approved, and how to approve it
|
|
(`/trekbrief --approve <project dir>`). Then edit.
|
|
- A plan the person approved: any edit gives it a new sha256, the approval log no longer covers it,
|
|
and `/trekexecute` refuses it until the plan is approved again. Say that before the edit.
|
|
- Never stamp, log or commit an approval in this loop. Only the person's explicit answer approves.
|
|
5. **Fix and Change: edit the text the note points at, and only that.** The quote marks the place.
|
|
If the comment cannot be done without touching other text (a summary that now disagrees, the same
|
|
gap in another step, a new criterion the change seems to need), do not edit that text. List it in
|
|
the reply as a question with a recommended answer. A validator error that was already there before
|
|
the notes is reported, not fixed in passing.
|
|
6. **Question: answer it in the reply. The text stays as it was.** No new row under alternatives, no
|
|
new rule, no rewording to "make the answer visible". End the answer with one line offering to write
|
|
it in if the person wants that. Only their yes turns a Question into a change.
|
|
7. **Build the page again** on the revised file, and print the new link, so the person reads the
|
|
revised text where they wrote the notes. The page keeps notes per file path, so last round's notes
|
|
still show in its sidebar: tell the person that "Clear all" empties it before the next round.
|
|
8. **Reply note by note:** for each number, "edited" (with the new wording) or "answered" (with the
|
|
answer); then the approval consequence from step 4, the open questions from step 5, and the link.
|
|
|
|
## Red flags
|
|
|
|
| Thought | What it means |
|
|
|---|---|
|
|
| "I'll add a few points of my own next to the link, to help" | The notes are the person's. Your points steer theirs. Offer a review instead. |
|
|
| "The Question shows a gap, so I'll fix the gap too" | Answer it. The gap is theirs to turn into a Change. |
|
|
| "I'll record the answer under alternatives, so it isn't lost" | That is an edit nobody asked for, and on an approved plan it costs the approval. |
|
|
| "The same fix applies to steps 2 to 4 as well" | Then ask. The note named one step. |
|
|
| "The summary no longer matches the new intent, I'll update it" | Ask, with a recommended answer. The person approves the words. |
|
|
| "The brief fails the validator anyway, I'll fix the frontmatter while I'm here" | Report it. A fix in passing is still a change the person did not ask for. |
|
|
| "I'll mention the approval is stale at the end" | Say it before the edit. It is the price of the edit. |
|
|
| "I'll re-stamp it so planning can go on" | Only the person's explicit approval stamps. |
|
|
|
|
## Enforced by
|
|
|
|
- `tests/lib/doc-consistency.test.mjs` and `tests/lib/skills-annotating-prose-pins.test.mjs` (in
|
|
`npm test`): the script `scripts/annotate.mjs` exists, the three producing commands call it, print
|
|
the `file://` link and the `open` line, and name this skill. Deterministic, but only at test time.
|
|
- `lib/validators/intent-approval.mjs` (inside `/trekplan`): an edit to `## Intent` or `## Goal` (or `## Threat Model`)
|
|
after approval makes the approval stale, and planning halts until the new text is approved.
|
|
- `lib/util/approval-log.mjs` (inside `/trekexecute`, K2): a plan whose current sha256 the approval
|
|
log does not cover is refused. Both checks hold whether or not the edit's cost was said.
|
|
- prose only: that the person writes every note and Claude none, that a Question changes nothing,
|
|
that only what the notes ask for is edited, that the cost of the edit is said before it, and that
|
|
the page is built again.
|
|
|
|
## Credits
|
|
|
|
Voyage's own content: the page (`scripts/annotate.mjs`), the loop and its rules come from Voyage's
|
|
pipeline and from the red baseline run for this skill. Nothing here is borrowed.
|