Commit graph

40 commits

Author SHA1 Message Date
4d5c927c5d
refactor(simplify): drop a dead branch and repeated fixtures from the round-2 remediation
/simplify over bcf3adb..HEAD. Pass 3's last else could never run (RULE_KEYS is checked first); entryPaths tracks an open entry the way testFirstFileEntries does; wrapLine drops normalisations its callers already made. Tests: one payload builder, one BLOCKER fixture, one unreleasedBody helper, one 1.9-block loop, one plan-unreadable loop, and make_repo in the e2e script. No behaviour change; suite 2515 (2513/0/2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:43:24 +02:00
25856f2e9c
fix(review): the workflow review fails closed when its coordinator returns nothing
Review finding edf2ec56; every reviewer that did not run is named in allow_blocked_by.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:20:28 +02:00
05f6b67be9
fix(review): the workflow review ranks by tier and puts back every engine finding
Operator decision 23 (13.10); review findings ab1b5d9f and bc7f4e23 (workflow side).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:32:59 +02:00
ed6699da58
refactor(simplify): one source per rule, shared test helpers, a faster isolation test [skip-docs]
/simplify over a97efb6..HEAD (the plan_version 1.9 / trial-4 delivery).

- coordinator-contract: engine names come from engine-findings ENGINES;
  one markedMajorCodeReview predicate under both lowering checks;
  isEngineFinding everywhere; the unreachable branch (c) of
  illegalBriefLowering folded into (e).
- armB workflow: RULE_KEYS = Object.keys(RULE_TIERS); the engine map is a
  literal pinned equal to ENGINES by the workflow test.
- plan-schema: usesFilesGrammar() is the one 1.9 check (validator, sweep,
  testFirstFiles, stepTestsOnlyFromFields); opensEntry built on opensChunk.
- plan-validator: one issue builder for the Files and Test first grammar.
- plan-scope-sweep: the 1.9 and the 6.2.0 reader are one if/else.
- artifact-commit: TRAILER_RE/trailerProblem no longer exported (no
  importer); the order comment says the CLI finds the repo root first.
- tests: the lock drivers in session-id-isolation (d) run side by side per
  mode (~100 s -> ~30 s); a shared artifact-repo helper; severityRank and
  extractFindingsBlock reused; childEnv(env) without a spread; one copy of
  the PLAN_VERSION_CURRENT check.

Plan readers: validator errors/warnings, plannedPaths, fieldPaths,
testFirstFiles and stepTestsOnlyFromFields compared byte for byte against
HEAD over 510 plans / 1692 steps plus 210 synthetic 1.7-1.9 cases: same.
Suite 2384 (2382/0/2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:06:47 +02:00
305ac9284f
fix(review): the payload decides the engine, and a tie keeps the reviewer finding
An engine's brief-conflict mark could lower a reviewer agent's MAJOR: ingest kept an engine field a reviewer wrote on its own finding, and on a severity tie the survivor depended on payload order (engine first gave ALLOW, reviewer first WARN). ingest now takes engine from the payload source; Pass 1 and the workflow dedup keep the reviewer-agent finding on a tie. Prose (coordinator Pass 1, Handover 6) follows. Decision 13, operator 12.10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:50:56 +02:00
8cc6ba0181
fix(review): the workflow review floors an illegally lowered brief-conflict finding
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:16:07 +02:00
d8527976ef
fix(tests): the suite no longer hands the session id to the lock CLI
npm test now preloads tests/helpers/no-session-id.mjs, which deletes CLAUDE_CODE_SESSION_ID before any test file loads, and the 18 files that spread process.env into a child use childEnv() instead (23 sites). A live session's stop guard is no longer pointed at a temp-repo lock (S133).

engines stays >=18: --import exists from Node 18.18/20.6, and the quoted test glob already needs Node 21 (criteria-runner NODE_GLOB_MAJOR), so the real floor does not move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:09:14 +02:00
a1e0e50451
fix: round 9 of the release review of 6.3.0, for 6.3.1
Round 9 (0f400d3..a10018f, WARN: 0 BLOCKER, 12 MAJOR): seven findings and
three brief notes, by operator choice. Each finding began with a test that
failed on a10018f on its assertion; suite 2230 (2228/0/2).

- A check refused for its comment (a quote, $, backtick or backslash) keeps
  its command and its reason, and every reader refuses it out loud: a nested
  ## Verification bullet stays a criterion (PLAN_VERIFICATION_NOT_RUNNABLE)
  and a brief SC warns (BRIEF_SC_NOT_RUNNABLE). It was folded into a
  sub-point or read as prose, a regression from a10018f. Readers that took a
  command as runnable (the end-to-end lists) skip a refused one.
- The verdict gate reads the last fenced block's info string and body from
  one reading, and exits 2 unless the info string is exactly json: a last
  block opened as ```json {x} held a BLOCKER the gate passed with exit 0
  (also in 6.3.0). A last block never closed is exit 2 too.
- One fence reader (findings-schema fencedBlocks) for the gate and every
  trailing-json reader: a fence closes only on a run at least as long as its
  opener, as in Markdown, so a four-backtick example of a json block is one
  block; CRLF and an indented fence read alike in the gate and the readers.
- Files: a description runs on past a comma and onto the next line until a
  new entry starts (a list item on a new line, or a backticked path), and a
  plain path followed by a colon starts its description. Measured over all
  939 Files: fields in the .md files under the marketplace and the test repo
  (560 of them in the 48 plan.md files outside worktrees): 0 read
  differently, tests-only changed in 0.
- The test lock compares --cmd by its words, so other blanks between the
  same words are the step's command.
- release-check decides "two files" on real paths: one review.md reached
  through a symlinked --repo is one file.
- Brief notes: red proof's stopped control run has its own test (green at
  once, red with the branch deleted); the two tests that assumed jest is not
  installed run with a PATH that finds only git (red on a10018f with a jest
  on PATH, green now); the Files: reader's doc states the measured counts
  (520 fields in 48 plan files at rounds 7-8, not "182 plans"; 560 now).

Not in this round (operator 2026-10-11): a144e9ce, 1dc2e785, dc3a467e,
2fa88853, 26873fa5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:49:01 +02:00
a10018f9d3
fix: round 8 of the release review of 6.3.0, for 6.3.1
Round 8 (0f400d3..29b4ac9, BLOCK: 1 BLOCKER, 12 MAJOR, 1 MINOR). Each fix
began with a test that failed on 29b4ac9 (13 tests, all red there); suite
2221 (2219/0/2).

- BLOCKER: a backticked check whose trailing comment holds a quote, $,
  backtick or backslash is refused, not dropped. The comment was never
  screened, while the executor hands the Verify span as written to red
  proof, the test lock and the done line inside --cmd "...", where a $(...)
  runs and a quote ends the argument. trekplan's text and the reviewer's
  NOT RUN table say so.
- A span that is only a comment is not-a-command, not a placeholder. The
  dropComment text says the allowlist still refuses a word with a # in it.
- The criteria runner, comparison-gate and end-state-gate use isMain: they
  did nothing and exited 0 under a symlinked path. The test now refuses any
  process.argv[1] comparison outside lib/util/is-main.mjs.
- Files: in a field with backticked paths, a plain word counts only before
  the entry's description (a dash, or a colon after the path); a name with
  no slash only first in its entry or after and/or/+/&. "mocks
  fs.readFileSync", "runs on Node.js 22.x" or "no change to package.json"
  no longer make a tests-only step look like it builds something.
  Lowercase makefile, rakefile and justfile are build files. Measured on the
  520 Files: fields in 48 plans of the marketplace and the test repo:
  3 fields read differently (two notes no longer read as files, one
  duplicate name dropped), tests-only changed in 0.
- The test lock compares --cmd without its trailing comment, and the test
  lock and the done line read a stop with stoppedBy, the one reading.
  red-proof drops its second reading, spawnError.
- release-check reads a relative --review in --repo or, when only that one
  exists, from the current directory as 6.3.0 did; two different files are
  exit 2, never guessed. The runbook says so.
- One trailing-json reader: a closing fence may be longer than three
  backticks, in the block reader and the verdict gate alike, and the review
  validator and the synthesis digest use it, so three backticks inside a
  JSON string no longer hide a BLOCKER from the remediation-step check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:43:56 +02:00
29b4ac91b3
fix: round 7 of the release review of 6.3.0, for 6.3.1
Round 7 (516dffa..45aa9e1, WARN: 12 MAJOR, 0 BLOCKER) and the fence defect
found while writing its review.md. Each fix began with a test that failed on
0f400d3 (v6.3.0); suite 2208 (2206/0/2), 14 tests more.

- Tests-only (operator 2026-10-11): the plan's Files: alone decides, and the
  text says so (red-proof, trekexecute Sub-step B, step-implementer,
  HANDOVER-CONTRACTS). red-proof no longer reads the step's diff, so a change
  already in the tree when the step began no longer counts against it, and a
  plan placed outside .claude/ reads the same. The round-6 test that had the
  diff overrule the plan is rewritten to the new rule.
- The Files: reader keeps a plain file beside a backticked path
  (", Dockerfile", "the CLI entry src/cli.mjs", "and Makefile"). Measured on
  the 520 Files: fields in 182 plans: no field reads differently.
- Red proof reports a command its timeout killed as killed after the timeout,
  not "could not start"; the release check tells a timeout from output past
  its buffer and from another signal. One reading of a stop
  (criteria-runner stoppedBy) for red proof, the criteria runner and the
  release check.
- A trailing `# comment` is dropped in a backticked check too, and in a
  command passed as written, so the words screened are the words run.
- The release check reads a relative --review in --repo.
- The 15-minute timeout is defined once (criteria-runner.mjs).
- The findings check reads each cited file once per validation.
- One isMain helper (lib/util/is-main.mjs) for every CLI: the 31 copies of
  the realpath guard and the 20 modules still on the file:// guard, which
  exited 0 having done nothing under a symlink or a path with a space.
- The Bash guard writes its no-one-to-ask refusal once, on a direct condition.
- The findings check ends a ```json block only at a fence on its own line, so
  three backticks inside a JSON string no longer end it (also in 6.2.0).
- Brief-conformance notes: a test for test-lock green on exit 127 (it
  passed at once; it fails when 127 is read as could-not-run); the prose now
  names the git revision `@~1` as the one leading-@ exception.

Not changed: the example plan's steps 1-2 keep their tests-only warning
(operator decision 2026-10-09; the r5 test records it). Brief note 4 (a
Regression: whose runner is not installed goes to the fix rounds) is a
routing question for the operator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:11:57 +02:00
45aa9e107a
fix: round 6 of the release review of 6.3.0
Round 6 (v6.2.0..c3641ff, WARN: 11 MAJOR, 3 MINOR; 0 BLOCKER). The round-5
fixes hold (code-correctness-reviewer); three of the new MAJOR were side
effects of running checks with no shell. Each fixed behind a test that
failed first on c3641ff.

- git checks stay in the repo too: no path that climbs out with .., starts
  at / or reads <rev>:../x, and no --no-index (both reviewers).
- A trailing `# comment` on a shell-fence line is dropped: with no shell,
  its words made an honest check NOT RUN, among them the first check of the
  shipped example plan.
- A glob reaches `node --test` only on Node 21 and later, which expands it
  itself; on an older Node it is refused with that reason (engines >=18).
- With no shell, exit 126/127 is the test program's own: red proof reads it
  as a red (the control run still tells an environment fault apart), the
  done line and the test lock as a failure.
- A runner that could not start (not installed) is NOT RUN in the criteria
  runner and not-run (exit 2) in regression-check, as red-proof and
  done-line already said; never a red suite.
- Tests-only: a backticked `Makefile` alone in its entry is a path, and red
  proof confirms the plan's tests-only reading against the step's own diff
  (the altitude finding: the diff is a fact, the Files: prose is not).
- release-check stops a suite that never ends (15 minutes) and reads it as
  not measured (exit 2).
- The two lines this release added to pre-bash-executor.mjs are ASCII.
- MINOR: git and the other runners share one plain-word pattern.

Not in this round: MINOR f00a2eb8 (shared norm/ticked-path and isMain
helpers) and MINOR on plan-review-dedup's repeated tokenizing.

Suite 2194 (2192/0/2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:07:47 +02:00
c3641ffa42
fix: round 5 of the release review of 6.3.0, the structural fix
Round 5 (v6.2.0..d37e538, WARN: 11 MAJOR, 2 MINOR). The patching did not
converge (the same two places every round), so the operator chose a
structural fix on 2026-10-11. Each change behind a test that failed first.

- A check runs with no shell. criteria-runner's runCommand starts the runner
  with the very words the screen checked (spawnSync(words[0], words.slice(1)),
  without NODE_TEST_CONTEXT); Phase 7 criteria, Regression: (its exec copy is
  gone, MINOR 0e98d5c7), proof of red, the done line and the test lock all
  run through it. No quote, glob, tilde or variable can rewrite a checked
  word any more. The screen stays and says why: a word that means something
  else in a shell (quote, backslash, $, brace, leading ~) is refused; a glob
  reaches only node --test, which expands its own patterns (sh read
  `tests/.?/` as `tests/../`); no path climbs out with .. or starts at /;
  a word starting with @ is refused (pytest reads @file as more arguments).
- The K6 plan-file sweep has v6.2.0's own Files: reader again (516dffa):
  backticked paths, and plain words only in a field without them. The
  shared reader from round 3 planned directories a description named and
  dropped paths v6.2.0 planned. fieldPaths stays for the tests-only check,
  with a path test on spans (`parse()`, `p.parse()` are no paths), plain
  descriptions ignored when the field has backticked paths, dotfiles,
  backslash paths and glued spans read.
- Skill frontmatter reads a value as YAML does: trailing space is nothing,
  and a comment ends a plain value, a flow list or a block indicator
  (`model: opus # pinned`). A comment that cuts a plain description, or is
  the whole value, is still a hazard.
- release-check reads the diff with --no-renames: a test moved into an
  allowed place after the review shows as removed.
- The example plan's step 2 heading no longer says "must FAIL initially";
  steps 1-2 keep the tests-only warning (operator 2026-10-09, 73262b6).

Open: MINOR c1fef1ad (one shared isMain helper) is not in this round.
Measured: 0 of 463 Files: fields with backticked paths (520 fields in 182
plans across the marketplace repos) carry another path-like word.

Suite 2185 (2183/0/2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:38:42 +02:00
ab6dcd838e
fix: round 4 of the release review of 6.3.0
Round 4 (v6.2.0..41ea8fc, WARN: 9 MAJOR, 3 MINOR); the nine MAJOR fixed,
each behind a test that failed first (operator 2026-10-10). Three were
regressions from round 3's shared Files: reader.

- fieldPaths keeps a backticked path with punctuation after it and one
  inside a note, a directory (docs/) and a glob (src/*.mjs) in plain text,
  and app/(auth)/x.ts whole; a bare word counts only alone and capitalised
  (Makefile), so "format" or "v6.3.0" in a description is no path. The K6
  sweep plans what v6.2.0 planned for `a.mjs`: and `b.mjs`.
- skill frontmatter: a quoted value may carry a YAML comment after it.
- criteria runner: no word with a leading ~ (sh expands it), and nothing
  after `make test` (another target would run).
- release-check: scope_sha_end must be a commit sha (a ref name passed
  coverage whatever was reviewed), and README lines changed after the review
  may differ only in the badge's version. The round-3 leading-zero example
  is 7 characters now, the shortest sha accepted.

The three MINOR (one word screen for git, the exec copy in regression-check,
a shared isMain helper) are not in this round.

Suite 2175 (2173/0/2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 23:48:52 +02:00
0e612c88ac
fix: round 3 of the release review of 6.3.0
Round 3 (v6.2.0..96cb977, BLOCK: 1 BLOCKER, 8 MAJOR, 2 MINOR), each fixed
behind a test that failed first.

- Every allowlisted runner, not only git, takes plain words and a short list
  of options that only read: an option that writes a file or loads code
  (--test-reporter-destination, --outputFile, --junitxml, --basetemp,
  --import, --config, -p, -o, -exec, a reporter path) is on no list; after
  `npm test --` only paths follow; `make test` takes no VAR=value. A built-in
  node test reporter (tap, spec, dot, junit, lcov) stays allowed.
- /trekexecute: a restore the guard refuses (destructive git, in the mode
  that shows no prompts) or the operator declines is never recorded as
  reverted: simplify = "revert-refused" and the run stops before review; a
  refused step revert is reported with its paths.
- stepTestsOnly: a fixture document under tests/ is a test file, "e.g." is
  not a path, ./ is dropped; the plan-file sweep reads Files: with the same
  reader (fieldPaths); the validator hands its parsed fields over.
- plan-validator --steps-from asks for Verify: on a 1.8 plan too.
- skill frontmatter: a value starting with # is a hazard; a quote after an
  escaped backslash closes the value. Routing reads kind tags with hasOwn.
- release-check reads scope_sha_end as written (an all-digit sha keeps its
  leading zero), and Voyage's own artifacts under .claude/projects/ and
  .claude/voyage/ committed after the review do not count as unreviewed.

Suite 2170 (2168/0/2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 23:25:24 +02:00
ed87cc668d
fix: round 2 of the release review of 6.3.0
Round 2 (v6.2.0..0d044f6, BLOCK: 2 BLOCKER, 11 MAJOR, 1 MINOR), each fixed
behind a test that failed first.

- The git runner checks only words /bin/sh passes through unchanged (no
  quote, backslash, $, glob or brace) and refuses --output and its
  abbreviations: round 1's --output refusal was bypassed by quoting.
- fieldPaths: backticked paths are kept as written, parentheses and all; in
  plain text every path-like word counts, and a parenthesised note does not.
- plan-validator --steps-from reads the plan's ## Verification for an
  appended End-to-end step, and warns instead of failing under --soft.
- regression-check prints progress_status, the value progress.json takes;
  /trekexecute copies it.
- release-check: a plugin in a subdirectory is checked in its own directory,
  the suite is not run when a cheaper check already makes the answer exit 2,
  and a bad argument or a crash is exit 2.
- Skill routing looks a skill up among skills only, and builds the corpus
  vectors once.
- /trekexecute Phase 7.2 says plainly that remediation steps in the review
  template's own form stop with a re-plan; making them runnable is a later
  order (operator 2026-10-10).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 22:43:38 +02:00
bef9c5b3ac
fix: the findings of the release review of 6.3.0
The review of v6.2.0..f669b87 (BLOCK: 1 BLOCKER, 12 MAJOR, 1 MINOR), each
fixed behind a test that failed first, or, for the two missing tests, a test
shown to fail on a stub of the branch it covers.

- Review steps appended by /trekexecute Phase 7.2 are held to the step rules
  on any plan version: plan-validator --steps-from <N> (on a plan below 1.8 a
  template review step validated and was executed).
- The guard refuses where no one can be asked also when its rules will not
  load; the wave merge path names that refusal instead of MERGE_REFUSED.
  Tests for the classifier-error refusal and post-approval-log's own check.
- release-check: the version files may change only in their version after
  the review (JSON compared without it), README diff lines are read inside
  hunks only, an unreadable diff is exit 2, and npm test runs without
  NODE_TEST_CONTEXT.
- What counts as a step of only tests: a note in parentheses is not a path,
  and a data file under specs/ is not a test. End-to-end: rides on the last
  step that builds behaviour (validator hint, trekplan, template).
- A removed line is cited as <rev>:<path>:<line> (findings-schema hint,
  trekreview re-ask).
- skill-lint counts a trailing newline as no line; regression-check takes
  commandEnv from lib/util/command-env.mjs; CLAUDE.md names four mode-read
  exemptions.
- /security-review, older than v6.2.0: the criteria runner refuses git
  --output, which writes a file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 22:12:12 +02:00
4807f6c458
feat(release): a drilled release and rollback runbook, and a release check
P13 (wave 2, order 8). docs/release-runbook.md has three parts: before the
release, the release, and the rollback. The rollback was drilled first, in a
sandbox with local bare repos as the remotes: a release 6.2.0 -> 6.2.1, then
path A (git revert, catalog ref back to v6.2.0) and path B (a forward patch
6.2.2 that carries the revert), with the catalog's check-versions green after
each. Nothing reached a real remote; the real catalog was byte-identical
before and after.

Measured: release-plugin.mjs refuses a ref backwards while plugin.json still
says the newer version, and accepts it once the release commit is reverted.

scripts/release-check.mjs decides before a release: clean tree, npm test
green at HEAD, review verdict not BLOCK (K7) and covering HEAD, and a door
type per delivery (### Doors in the CHANGELOG section). 0 ready, 1 not
ready, 2 could not run (never green). A ready run prints the K2 command that
logs the operator's yes.

tests/lib/release-prose-pins.test.mjs holds every command in the rollback
part to the commands the drill ran (tests/fixtures/release-drill/).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:32:36 +02:00
40f6ae1177
fix(review): close the gate's fail-open paths an independent review found
An adversarial read of d88245c reproduced 15 problems; all fixed here, each
with a test that fails on the old code.

- verdict-gate: a greener verdict must be backed by the LAST fence being a
  `json` block of the right shape, with no BLOCKER in the JSON (any case),
  in `## Findings (BLOCKER)`, or a differing finding-id list; two verdict
  lines and more than one file argument are exit 2. ({}, null, lowercase
  "blocker", a trailing ```jsonc and a later json fence all gave exit 0.)
- engine-findings: a transcribed "narrower" key can no longer lower an
  engine tier; absolute paths under --repo-root match the scope; "12" lines
  parse; an empty scope is an error; out-of-scope engine findings are
  unverified (`engine:out-of-scope`) and forbid ALLOW.
- recurrence: the catch-all engine keys and keys normalised from unknown
  ones are never proposed; the same unfixed finding in two iterations is not
  a recurrence; proposals are validated before they are offered; \r/U+2028
  and damaged markers are refused; writes go through a symlinked CLAUDE.md.
  Prose points --repo at the session directory, not the git toplevel.
- Workflow substrate: engines are counted from what arrived, and the
  verdict's floor is recomputed from the coordinator's findings; now tested
  by running the script with stubbed Workflow globals. Two literal NUL bytes
  written as \u0000 (git saw the file as binary).
- Trimming keeps Pass 1's "Also flagged by" provenance; `## Declined to
  Judge` and remediation steps are required from review_version 1.1 only
  (N-1); the zero-diff review now carries the JSON block the gate needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:03:16 +02:00
ee4d748639
test(yardstick): use counts an order only when a Voyage record names its id (red)
measureUse({ queue, runs, cutoff, countingSince }): runs come from
orderRuns(stats) - trekbrief-stats.jsonl only. YES = a trekbrief record names
the order's id under one slug that names no other order; declared NO = a
new-work order carrying <!-- arbeidsform: ordre --> on its own line; no
record or a disputed record = NOT MEASURED, never a no (PM 04.10, point 1).
countingSince null -> NOT COUNTABLE, every order not measured; the window
starts at the latest of cutoff, MARKER_SINCE and the counting start.
facts.ordersNamedByARecord is the known-positive diagnostic (SC8).

Existing use tests get countingSince = MARKER_SINCE (their window unchanged)
and records instead of slugs; their denominators now read YES + declared NO.
Replaced: "a new-work order without a slug leaves the numerator NOT
MEASURED" - the slug join it guarded is gone. New exports are read through a
namespace import, so the trust/interrupts/mutants tests still run.

Red: 24 of 43 fail (every use test, the two measureAll tests, the symlink
CLI test); 19 pass, none of them new.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 19:52:22 +02:00
66cbf228c7
test(yardstick): a new-work order without a slug leaves the use numerator not measured (red)
Measured 2026-10-03: the two new-work orders on the real queue carry no `slug:`
(0 of 690 orders do), so "0 of 2" was forced by the missing join key, not by
work going around Voyage. An absence without a possible match is "not
measured", never 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 18:20:32 +02:00
e2186bf64f
test(yardstick): use counts new work from the loesningsvalg marker, from 2026-09-28 (red)
The use number read `work-class` from the order frontmatter; 0 of 690 orders
carry it, so the denominator was always empty. PM rule 02.10: the order
marker `<!-- loesningsvalg: plan|prove -->` is new work, `ikke-nytt` is not,
counted from 2026-09-28 (enforced by pre-order-loesningsvalg.sh since then).
Unmarked orders and orders before the start are "not measured", never a no.

Red against today's code: MARKER_SINCE is not exported, and with it stubbed in
a scratch copy all five new use tests fail on behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 18:19:20 +02:00
e9a4abc34f
feat(measure): the comparison gate counts the 14 areas against five frameworks and the tidy denominator, and it is RED [skip-docs]
The lifted target (operator, 2026-09-27; PM order 44111111): Voyage + the
operator's way of working level with or ahead of related frameworks in all
14 areas, and every Voyage part a documented Claude Code primitive covers
removed or with a measured reason to stay.

scripts/comparison-gate.mjs reads both denominators from their source, never
from the table: the areas from the first column of the PM report's table,
the parts from git ls-files (one part per eval case). It fells the table on
missing evidence, never on a verdict: a cited file must exist inside its
root and hold the cited lines, a pinned clone must sit at its pin, a web
citation needs a verbatim quote, an absence needs zero hits and a
known-positive control. Green also requires an independent reader. The
table itself is local-only (docs/comparison.local.json).

Measured today on 7439dac: RED, 0 evidence problems; 2 of 14 areas against
all five references (Superpowers 11, Pocock 14, agent-skills 11, Cherny 10,
playbook 2); tidy 5 of 64 covered parts resolved.

23 tests in tests/scripts/comparison-gate.test.mjs; six mutants felled (no
evidence check, no line check, no reader check, denominator from the table,
no tidy completeness, no pin check). Suite 1278 -> 1301 (1299/0/2).

[skip-docs]: an operator measurement instrument like scripts/yardstick.mjs,
whose table is local-only - no user-facing behaviour changes, so README and
CLAUDE.md have nothing true to say about it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 20:31:14 +02:00
d0dee914be
docs: remove dead references to a retired repository (green)
The annotation surface's provenance is now described as the pattern it
follows (pencil toggle, intent buttons, popover form, structured export)
rather than by naming a repository that no longer exists. Touches the
plugin/package descriptions, README, docs/architecture.md, the v5.0.3
CHANGELOG entry, and two comments in scripts/annotate.mjs and its test.

Retired-reference check: 12 hits in 7 files -> 0 (content and path names).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 12:28:05 +02:00
1779411b49
feat(measure): the yardstick prints Voyage's three numbers with denominators from the source, and it is RED
One command, `node scripts/yardstick.mjs`, prints use, trust and
interrupts. Each row gives countable YES/NO, the value, the denominator and
the source it was read from. A fourth row asks whether the end-state gate can
be fooled by a mutant that keeps the module's signature. Exit is non-zero
while any number is not countable, the mutant is not felled, or the verdict
over the first five deliveries is not judged. Nothing counts a delivery yet,
so today it is RED for the right reasons:

  use         NO   no order in the queue carries work-class
  trust       YES  current ALLOW streak 0 of 37 (BLOCK 14, WARN 12, ALLOW 11,
                   last 2026-09-05 BLOCK, ordered by ts, read as JSON)
  interrupts  NO   0 user_input records of ~141k lines in 5 files, 0 emitter
                   call sites outside lib/stats/ and tests/
  mutants     0 of 1 signature-preserving mutants felled: on M9 (every export
              returns {status:'PASSED'}, every named test only checks typeof)
              the gate closes both D-03 and D-04

It only measures. The gate, the emitter and the order writer are untouched.
The mutant row is meant to stay red until the gate learns to fell M9.

Choices, and why:
- Use counts over the order queue (pending, archive/ and claimed/), because
  an order is the unit of work. The denominator is orders dated on or after a
  cutoff (default 2026-09-21) that carry `work-class: new`. They count as
  having gone through Voyage when a Voyage run in the stats has the order's
  `slug:`. Both fields are the contract the order writer must meet. No order
  carries them today, so the number is NOT COUNTABLE, not 0 %.
- Mailboxes whose names start with a dot are mailboxes too. A shell `*`
  glob skips them, which is why a hand count of `coord/*/orders` comes out
  lower. The row names them so a re-measure can reconcile.
- M9 must be LIVE before its row can count. Its typeof tests have to pass on
  the M9 tree, checked by a runner independent of the gate, so a broken
  fixture can never read as "felled".

Also: tests/fixtures/red-first/02243c6-always-allow-shim.mjs, the shim that
makes the red-first claim of 02243c6 reproducible (6 of 55). The recipe is in
its header.

Red first: the new test file failed to load before scripts/yardstick.mjs
existed, and a dot-mailbox test was red before the census learned about
dot-mailboxes. Suite 1161 -> 1183 (1181/0/2), also green on a clean tree
exported from the index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-22 21:50:06 +02:00
3b3f06dd45
docs(tests): tracked comments name the measurement, not the coordination
`origin` is a public mirror. Comments in tracked test files named the internal
review mechanism by its role rather than the measurement they came from; the
same class as the frozen file's overclaim fixed in 83d82f1. Replaced with what
they actually are: a re-measurement on a named commit, with the date.

The one remaining occurrence is the assertion that FORBIDS those phrases in
tests/fixtures/end-state-frozen.json - a guard has to spell out what it guards.

Suite 1161 (1159/0/2). Comment-only change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 03:01:09 +02:00
83d82f121d
fix(end-state): a behaviour probe must FELL a stub, not just name a test
The cosmetic close came back one level up. The probe reads the test file from
the same tree it measures, so a four-line file holding two EMPTY tests with the
two named names closed D-03 and D-04 on a tree where `lib/verification/` did
not exist at all - "defects 0 of 7, registry intact" (measured 2026-09-18).
First a two-line stub exporting the right symbols; then an empty test with the
right name. A name is always forgeable.

So the named test is now run twice. Once on the tree, as before - and once in a
sandbox where the module the condition declares in `stubs` is replaced by a
stub exporting the same names, all inert. If the test still passes there, it
binds the name and not the behaviour, and the condition THROWS: NOT FELLABLE,
counted open. A condition that declares no `stubs`, or names a module that is
not there, cannot fire either.

The sandbox is a symlink overlay: every entry of the tree is symlinked, and
only the test file and the stubbed module are materialised for real - Node
resolves an ESM import through the realpath, so a symlinked test file would
import the original module and never see the mutant. Nothing is ever written
inside the measured tree, and the only directory removed is the one this code
made under the system temp dir (pinned by a test).

M7 is now a permanent mutant beside M6, in two forms: the checkpoint's own
reproduction (unfixed tree + empty named tests) and the harder one (the real
module present, so the stub can be built and the empty test passes against it).
Both report `defects 2 of 7`. A positive control pins that D-03/D-04 still
CLOSE on the real tree, so "not closed" everywhere cannot read as a working
probe.

The frozen denominator moves a third time, deliberately, and its `why` no
longer claims authority it does not have: the second and third amendments were
maintenance decisions by the maintainer, not operator decisions, and the
tracked file now says exactly that.

Measured after:
  real tree      node scripts/end-state-gate.mjs -> defects 0 of 7, intact, exit 1
  M6 (stub)      8d1669e + current gate/registry/frozen + lib/cosmetic/stub.mjs -> 2 of 7
  M7 (empty)     8d1669e + current gate/registry/frozen + 3-line
                 tests/lib/criteria-runner.test.mjs with the two named tests -> 2 of 7
Red first: 4 of the new tests failed before the change. Suite 1154 (1152/0/2).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 02:56:22 +02:00
a7af76e5ff
fix(end-state): the D-03/D-04 probes RUN a named test instead of grepping for a symbol
Measured 2026-09-18 (PM checkpoint on 6cafb4c, mutant M6): a two-line file

  export function runPlanVerification() { return { ok: true }; }
  export function formatCriteriaEvidence() { return ''; }

dropped into an otherwise UNFIXED tree closed both D-03 and D-04, and the gate
reported "defects 0 of 7, registry integrity: intact". The same checkpoint felled
5 of 5 mutants with the SUITE and 0 of 5 with the GATE. Both probes called
themselves `behaviour` while asking a grep whether an export name was present -
a phrase probe pointed at code.

A check condition may now name a test instead of a pattern:

  { "test": "tests/lib/criteria-runner.test.mjs", "name": "<exact test name>",
    "expect": "fails" }

The gate spawns the test runner on that one test and reads its TAP line.
`expect: "fails"` holds - the defect stays open - while the test does not pass.
A missing file, a name that matches nothing, a runner that will not start: all
throw, which counts as NOT FELLABLE and therefore open. A check that cannot fire
is never "fixed".

The child's `NODE_TEST_*` env is stripped. The gate usually runs UNDER the test
runner, and an inherited `NODE_TEST_CONTEXT` makes the grandchild report over
the parent's IPC channel instead of stdout - the TAP line would never arrive and
the probe would silently stop felling anything.

M6 is now a permanent mutant in the gate's own test, so the cosmetic close
cannot come back. Verified end to end against a real stub tree:

  git archive 8d1669e | tar -x -C $TMP
  cp scripts/end-state-gate.mjs scripts/end-state-registry.json $TMP/scripts/
  cp tests/fixtures/end-state-frozen.json $TMP/tests/fixtures/; cp STATE.md $TMP/
  printf 'export function runPlanVerification…' > $TMP/lib/cosmetic/stub.mjs
  node scripts/end-state-gate.mjs --root $TMP
  -> defects 2 of 7, both NOT FELLABLE, exit 1

The gate also now states the limit out loud, as its own line above the table:
a behaviour probe proves the capability WORKS; that Phase 7 and Phase 4.5 CALL
it is pinned by TEXT in doc-consistency, not proven deterministically - real
proof is a headless plugin-eval run against a fixture plan (week 40).

FROZEN DENOMINATOR AMENDED, second time in one day, by the work order that
carries this change: D-03 and D-04 signatures moved because their checks
changed on purpose. tests/fixtures/end-state-frozen.json and the FROZEN literal
in tests/scripts/end-state-gate.test.mjs are updated together, both dated, both
saying why. No entry was removed.

Gate after this change: defects 0 of 7, registry integrity intact, exit 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 02:08:40 +02:00
6cafb4c04c
fix(end-state): D-03 and D-04 measure behaviour, and the frozen denominator moves with them
The operator decided on 2026-09-18 that the two checks must stop measuring a
phrase and start measuring behaviour. The reason is the gate's own caveat: a
phrase probe closes on rewording, so "Phase 7 no longer says 'Skip for
trekplans'" and "the rubric no longer says 'exists and passes'" could both have
been satisfied by an edit that changed no behaviour at all. Both entries now
point at code a test exercises:

  D-03  lib/**/*.mjs exports runPlanVerification
  D-04  lib/**/*.mjs exports formatCriteriaEvidence

Verified open against the pre-fix tree (8d1669e) and closed against this one —
a check that cannot be seen to fire is not evidence.

What the probes can and cannot prove is now stated by the gate itself rather
than left to the reader. `PROBE_NOTES` carries one note per kind, the detail
line prints a note for every kind PRESENT in the row (and none for a kind no
entry declares), and the open/closed tags name the kind instead of labelling
`phrase` alone and leaving every other kind unlabelled. A behaviour probe
proves the capability exists; it does not prove a prose phase calls it — the
wiring is pinned by tests/lib/doc-consistency.test.mjs, and the gate says so.

THE DENOMINATOR MOVED ON PURPOSE. `tests/fixtures/end-state-frozen.json` and
the `FROZEN` literal in `tests/scripts/end-state-gate.test.mjs` carry new
signatures for D-03 and D-04, amended together and dated in both places. That
is the freeze mechanism working, not a bypass: the integrity check went
VIOLATED the moment the checks changed and stayed red until the amendment was
written down. The list may change — only as a decision said out loud. Nothing
else about the denominator moved: seven defect ids, three experiment ids, and
the agents/decisions/freeze configuration are unchanged, and no entry was
removed.

Gate after: defects 0 of 7, registry intact, still RED and exit 1 on the other
four rows — which is correct.

Suite: 1120 (1118/0/2), up 3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 01:36:44 +02:00
09feb415b3 fix(end-state): the gate can no longer be turned green by editing its own ledger
An independent adversarial review of the end-state gate reproduced a GREEN result, exit 0,
with the gate's 18 tests passing. Only the registry and the STATE markers were edited; every
other file stayed byte-identical. The judged party owned the denominator, and nothing
guarded it. This change closes that finding and three more, and reopens a defect the gate
had closed too early.

Registry integrity (the blocker):
- tests/fixtures/end-state-frozen.json freezes the denominator. It holds the 7 defect ids
  and 3 experiment ids, each with a sha256 signature of its check (canonical JSON, key
  order irrelevant), plus the exact agents / decisions / freeze configuration.
- The rule: an entry may close; it may never disappear or have its check changed. New
  entries are allowed. spawnSites may never include agents/.
- The test file pins the manifest literally, with a comment that the denominator was
  frozen on 2026-09-17 and that changing it is a decision. The gate verifies the registry
  against the manifest on every run.
- A violation makes the gate red and names what moved. A missing manifest makes integrity
  n/a, which is also red.

Dormant means "never spawned", not "never mentioned":
- An agent counts as spawned only when a command names it in a spawn instruction: a row of
  a table headed `Agent`, a line that starts with Launch/Spawn, or a **name** block followed
  by a Prompt: line.
- Prose, negations, HTML comments and fenced code never count. Block quotes cannot match
  either, because every form is anchored at the start of the line.
- Re-measured under this definition: still 1 of 20 (synthesis-agent). Per agent, every other
  spawnable agent has a spawn instruction in at least one command.

A fifth tally, feat-after-freeze:
- It counts commits after the `end-state-freeze` tag whose subject matches
  ^feat(\(|!|:).
- The row is n/a, and therefore red, when there is no tag yet, the root is not a git work
  tree, or the root is not the top of its work tree. It is never 0.

Honest output:
- Every registry entry now declares its probe kind (phrase or byte).
- Open phrase probes are labelled as such, and closed ids are listed. The output states that
  a closed phrase probe is evidence, not proof of behaviour. D-03 and D-04 stay open and
  labelled; how they are fixed is still to be decided.
- The decisions row now says it counts ticks, not verified decisions.

D-07 reopened:
- Its check now also covers README.md and commands/trekresearch.md, where the "orchestrator
  runs on opus" claim still lives. README even ships a sed recipe for `model: opus` lines no
  command has.
- Defects are 3 of 7 until the separate docs fix lands.

Three surviving review mutants were killed with tests:
- an empty glob over an existing dir is silent;
- the header counts n/a rows as zero;
- a dormant-row error reads as 0.

Measured on a clean export of the index:
- Mutation harness, adapted from the review's: review code mutants 18 of 18 killed. Four of
  them were re-targeted at the equivalent new code. M02 survived until a test with an
  intact registry plus a missing freeze tag was added.
- New-logic mutants: 12 of 12 killed. One equivalent mutant (block-quote stripping) was
  removed together with the dead clause it targeted.
- Registry attacks: 7 of 7 killed.
- The review's combined green attack (registry + STATE only) is now RED, exit 1:
  "defects: D-03 is frozen but missing from the registry".
- Gate tests 38/38. Suite 1059 -> 1079 (1077/0/2).
- Gate: RED, defects 3 of 7, experiments 3 of 3, dormant 1 of 20; decisions and
  feat-after-freeze are n/a in a clean export.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 16:57:57 +02:00
553c288925 feat(end-state): a gate that counts the distance to "Voyage is finished" - red
Voyage now has a destination that can fail: finish the phase-2 pipeline, close the open
experiments, freeze. This adds the gate that measures the distance to it. Nothing is
fixed or removed here; every defect and every removal is its own change.

scripts/end-state-gate.mjs counts four tallies; finished = all four at 0.
  defects         listed in scripts/end-state-registry.json, each with a runnable check
  experiments     listed in the registry, each with a runnable check
  dormant-agents  spawnable agents no commands/*.md references (structural, word-bounded;
                  files carrying the reference-document marker are excluded)
  decisions       open operator decisions in the local STATE.md, by a fixed marker
Exit 0 green, 1 red, 2 usage/registry error. `--json` for machines.

Fail-closed by construction: an entry with no check, or whose check cannot run (missing
file, empty glob, missing section), is NOT FELLABLE and counts as open; a missing STATE.md,
a missing section, or an unmarked list item in it makes the decisions tally n/a, which
keeps the gate red. The decisions row is therefore n/a in any clean clone.

Result today (clean export of the index): RED, 0 of 4 tallies at 0 -
defects 7 of 7, experiments 3 of 3, dormant agents 1 of 20, decisions n/a.
With the local STATE present: decisions 11 of 12.

Verified in both directions: 18 fixture tests pin each tally at 0 and above 0. Each of the
10 registry checks was measured open on this tree and closed after a simulated fix on a
throwaway copy (10 of 10). That run caught a too-broad D-03 check - Phase 4's legitimate
entry-condition skip also matched - which is now scoped to the Phase 7 section.
Suite 1041 -> 1059 (1057/0/2), also run on the clean export.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 15:27:21 +02:00
f19474acc6 fix(storm-measure): check BOTH halves of the activation SC, not just the count delta
The SC asks two things of an effort: high run: that it discovered at least
one dimension AND that the dimension list in the output brief is a TRUE
SUPERSET of the interview-derived ones. activationCheck computed
dimensions - dimensions_baseline >= 1 and returned ok on that alone. A
count delta says nothing about membership: a run that dropped two
interview dimensions and appended three discovered ones is +1 and passed
the check while violating the second half outright. Supersetness was
asserted only by Phase 4.5's prose contract that discovery appends -
nothing read it.

The stats record cannot carry the dimension names that would show it
directly: names are free prose, and lib/exporters/field-allowlist.mjs
denies prose by omission (question, project_dir, brief_path are already
excluded for that reason). So the run attests membership with
dimensions_baseline_preserved, a boolean set in a new Phase 4.5 step 5,
and the gate refuses to call activation OK without it. An ABSENT
attestation fails rather than falling back to the old count-only rule -
otherwise legacy rows would keep passing on the defect.

Producer side wired end to end: the record format, the measurement-fields
prose (five fields -> six), the exporter allowlist, the jsonl-schemas
fixture row, and the --activation-check comment in
docs/storm-measurement.md.

Review finding d2786604458207a5a73478cdcb6a54bbdb92141d (MINOR).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LuGhWAbWyRFBFeemfhxoVv
2026-08-12 23:01:59 +02:00
5ba7c64ace fix(storm-measure): exclude an unreadable empty_turns, and stop printing BOTH for an OR rule
Two defects in the adoption gate, both in the direction that flatters
adoption.

1. A non-numeric empty_turns counted as an eligible run.
   Number('many') is NaN, and the test was `Number.isFinite(empty) &&
   empty > 0`, so NaN fell through to the eligible branch. Measured
   before: 0 -> eligible, 2 -> excluded, undefined -> eligible, null ->
   eligible, 'many' -> ELIGIBLE, NaN -> ELIGIBLE. The exclusion is one of
   the two properties docs/storm-measurement.md names as carrying this
   gate's honesty, and the run whose bookkeeping broke is the run whose
   numbers deserve the least trust. Now excluded. Absent and null stay
   eligible via `?? 0` - a field never written is a genuine zero on a run
   where the loop never armed.

2. The printed threshold line said "adopt >= 30.0% on BOTH - decline <
   15.0% on BOTH" while decideVerdict evaluates OR on both sides. S82
   restored the pre-registered OR rule in the logic (c37bf50d) and left
   this line describing the stricter AND gate, one line above the verdict
   that OR produced. The summary is the only form of the rule most readers
   ever see, so it now states EITHER on both sides and that adopt wins
   ties. Found while fixing (1); not a review finding.

A test pins the printed line against the string "on BOTH" so the two
cannot drift apart again silently.

Review finding 24a76c21ffc694cd782cd449212c9502d31aeda6 (MINOR).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LuGhWAbWyRFBFeemfhxoVv
2026-08-12 22:59:08 +02:00
4c4457f6e9 fix(storm-measure): restore the pre-registered OR decision rule
The brief pre-registers "median forbedring >= 30 % pa (a) eller (b) ->
adopt. < 15 % -> decline." decideVerdict() required BOTH metrics to clear
the adopt bar and BOTH to fall under the decline bar, a rule introduced at
execution time (plan Step 11 restated the brief's wording unchanged).

The divergence is behavioural, not cosmetic: sources +90% / dimensions +10%
is adopt under the brief and was inconclusive in code; sources +2% /
dimensions +20% is decline under the brief and was inconclusive in code.

Adopt is evaluated before decline, so the OR bars do not conflict where they
overlap. docs/storm-measurement.md §2 and the test pins follow the same rule.

The stricter AND rule may well be the better decision procedure — but
changing it after the fact is exactly what pre-registration exists to
prevent. Review finding c37bf50d.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011vPSXe88qp5aqWUqbDNWoF
2026-08-12 22:15:07 +02:00
b194630842 feat(scripts): add STORM measurement harness with pre-registered thresholds 2026-08-12 20:25:27 +02:00
6b30483304 feat(voyage): S12 — NW3 synthesis-agent built + measured → declined per measurement [skip-docs]
NW3 (CC-26 §6 PoC): delegate trekplan Phase 7 synthesis to a synthesis-agent,
adopt only if Δ main-context ≥30% with no quality loss. Operator chose the
deterministic-proof path (live ≥3-run bake-off was env-blocked: no API key;
installed plugin is a cache copy so a new agent is invisible to `claude -p`).

Decisive structural finding: trekplan Phase 5 runs the swarm FOREGROUND, so its
outputs are already resident in main before Phase 7. Delegating only Phase 7
evicts nothing → Δ_faithful = 0% (BASE-independent). The ≥30% saving needs an
out-of-scope Phase-5 redesign (swarm-writes-to-disk / nested orchestrator).
VERDICT: DECLINED per measurement.

- agents/synthesis-agent.md — dormant, schema-conformant deliverable (NOT wired)
- lib/plan/synthesis-digest-schema.mjs — digest output contract (+ tests)
- scripts/synthesis-measure.mjs — deterministic Δ-accounting core (+ tests)
- tests/fixtures/synthesis/ — 7 exploration outputs + representative digest
- docs/T1-synthesis-poc-results.md — measurement + verdict (reproducible)
- CLAUDE.md — agent table row (doc-consistency: 24 agents)

Tests 670 → 695 (693 pass / 2 skip / 0 fail). `claude plugin validate` clean
(only the pre-existing root-CLAUDE.md warning). commands/trekplan.md untouched.

[skip-docs] rationale: no user-facing feature ships (NW3 declined; agent dormant
and unwired). The substantive doc is docs/T1-synthesis-poc-results.md; the
README/CHANGELOG roll-up for NW1–NW3 is the S13 coordinated release per
docs/W1-narrow-wins-plan.md §S13.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-18 17:58:39 +02:00
951b4abafa chore(voyage): release v5.0.3 — annotation UX matches the claude-code-100x reference
The operator pointed at ~/repos/claude-code-100x/claude-code-100x/build-site.js
as the annotation reference from the start. v4.2/v4.3 built a bespoke
playground instead. v5.0.0 deleted it. v5.0.1 pointed at /playground
document-critique (Claude-leads, wrong direction). v5.0.2 was operator-led
but too thin (line-click + freeform note, no intent). v5.0.3 finally
matches the reference.

scripts/annotate.mjs rewritten:
  - Markdown rendered as proper article HTML (h1/p/li/ul/table/blockquote/pre)
    instead of line-numbered raw lines.
  - Pencil-toggle annotation mode in the topbar, default ON.
  - Select text OR click any element → form popover at cursor.
  - Three intent buttons: Fiks (red) / Endre (orange) / Spørsmål (blue).
  - Comment textarea. Save (Cmd+Enter), Cancel (Esc).
  - Section context auto-detected from nearest h1/h2.
  - Sidebar panel: annotations grouped by section, intent badges,
    snippet quotes, delete buttons, click-to-scroll with flash highlight.
  - Copy Prompt: structured markdown export with intent labels.
  - localStorage persistence keyed on absolute artifact path
    (voyage-annotate:v2: prefix to avoid colliding with v5.0.2 state).

Tests: 12 (up from 10), all passing. npm test: 518 / 516 pass / 0 fail / 2 skipped.

Reference: ~/repos/claude-code-100x/claude-code-100x/build-site.js
lines 1431–2255 (annotation UI section).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 15:08:20 +02:00
a9e3a40f4a chore(voyage): release v5.0.2 — operator-driven annotation HTML (scripts/annotate.mjs)
v5.0.0 added a read-only HTML render. v5.0.1 deleted that and pointed at
/playground document-critique, which pre-generates Claude's suggestions
and asks the operator to approve/reject them. The operator asked for the
opposite — a surface where THEY drive every annotation. v5.0.2 lands it.

scripts/annotate.mjs (~430 lines, zero deps) takes any artifact .md and
writes a self-contained HTML next to it. The HTML renders the document
with line numbers, lets the operator click any line to add their own
note (inline textarea, save with Cmd+Enter or button), keeps a sidebar
of all notes (editable + deletable + persisted in localStorage per
artifact path), and exposes Copy Prompt to gather every note into one
structured prompt. Operator copies, pastes back, Claude revises the .md.

The three producing commands now run annotate.mjs at their last step and
print the file:// link with explicit "Click any line to add YOUR OWN note"
instructions. The v5.0.1 /playground document-critique line is gone.

npm test green: 516 tests, 514 pass, 0 fail, 2 skipped.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 14:04:28 +02:00
17039731a6 chore(voyage): release v5.0.1 — drop standalone HTML render; print literal /playground document-critique invocation
The v5.0.0 stop-gap had /trekbrief, /trekplan, and /trekreview each render
a read-only {artifact}.html (via scripts/render-artifact.mjs) AND print a
vague "run the /playground plugin" instruction. In practice the read-only
HTML was redundant with what /playground produces and the instruction
wasn't copy-paste-ready — the operator had to guess the right invocation.

v5.0.1 deletes scripts/render-artifact.mjs + its test + npm run render,
and makes each producing command end with a single boxed, literal,
copy-paste-ready line:

    /playground build a document-critique playground for {artifact_path}

One paste from the operator launches the official playground skill's
document-critique template, which builds an interactive HTML — artifact
on the left, per-line Approve/Reject/Comment cards on the right, Copy
Prompt button at the bottom. Mark suggestions, click Copy Prompt, paste
back, Claude revises the .md. Doc-consistency test pins the literal
invocation so the prose cannot soften back into vagueness.

npm test green: 503 tests, 501 pass, 0 fail, 2 skipped.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 13:24:32 +02:00
3683ae0070 chore(voyage): release v5.0.0 — remove bespoke playground + /trekrevise + Handover 8; render produced artifacts to HTML + link, annotate via /playground
The v4.2/v4.3 bespoke playground SPA (~388 KB), the /trekrevise command,
Handover 8 (annotation → revision), the supporting lib/ modules
(anchor-parser, annotation-digest, markdown-write, revision-guard), the
Playwright e2e suite, and the @playwright/test / @axe-core/playwright
devDeps are removed. A browser walkthrough found the playground borderline
unusable, and it duplicated the official /playground plugin's
document-critique / diff-review templates.

In their place: scripts/render-artifact.mjs — a small, zero-dependency
renderer that turns a brief/plan/review .md into a self-contained,
design-system-styled, zero-network .html (frontmatter folded into a
<details> block). /trekbrief, /trekplan, and /trekreview call it on their
last step and print the file:// link; to annotate, run /playground
(document-critique) on the .md and paste the generated prompt back.

Resolves the v4.3.1-deferred findings as moot (their target files are
deleted). npm test green: 509 tests, 507 pass, 0 fail, 2 skipped.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 14:05:07 +02:00
588ea38268 feat(voyage): vendor markdown-it/highlight.js + playground render-pipeline + scripts/render-artifact.mjs CLI — v4.2 Step 8 [skip-docs]
Vendored libs (locked headless via scripts/vendor-playground-libs.mjs;
plan-critic B3 — never use highlightjs.org website builder):
  - playground/lib/markdown-it.min.js           — markdown-it@14.1.0 UMD bundle
  - playground/lib/markdown-it-front-matter.min.js — markdown-it-front-matter@0.2.4 IIFE-wrapped
  - playground/lib/highlight.min.js             — highlight.js@11.11.1 (5-lang bundle:
                                                   yaml/json/javascript/bash/markdown/diff)
  - playground/lib/VENDOR-MANIFEST.json         — pin record + audit trail

scripts/vendor-playground-libs.mjs implements the reproducible
CommonJS-to-IIFE wrapping. Re-vendoring requires only:
  node scripts/vendor-playground-libs.mjs

Render pipeline in playground/voyage-playground.html (~330 LoC total):
  - inline <script src=lib/...> for the three vendored bundles
  - markdown-it init with html: true (preserves voyage:anchor comments)
  - front-matter plugin with pre-render-then-wrap pattern (research/03)
  - paste-import-row textarea + Render/Sample/Clear buttons
  - voyage-viewport region with role + aria-live for A11Y
  - localStorage key pattern: voyage_ann_<project>__<slug> (risk-assessor H7)
  - inline sample plan (mirrors annotation-plan.md fixture)

scripts/render-artifact.mjs CLI (~200 LoC) — brief SC1 + SC11:
  - reads input.md, runs same vendored pipeline server-side
  - inlines DS CSS + (URL-stripped) highlight.js into output
  - zero http://https:// URLs in output (verified by test)
  - deterministic: two invocations -> byte-identical sha256
  - default output: <input>.html next to input

Test coverage:
  - tests/scripts/render-artifact.test.mjs — 5 cases (SC1/SC11)
  - tests/playground/voyage-playground.test.mjs — +5 cases (Step 8 extension)

Verify: node --test tests/playground/voyage-playground.test.mjs
       tests/scripts/render-artifact.test.mjs -> 18 pass / 0 fail.
Full npm test: 587 pass / 0 fail / 2 skipped (Docker).

Refs plan.md Step 8 + plan-critic B3 + scope-guardian B1.
2026-05-09 15:20:17 +02:00