docs(changelog): fix round 4.5a
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5476a36782
commit
e351e7c29d
2 changed files with 159 additions and 0 deletions
71
CHANGELOG.md
71
CHANGELOG.md
|
|
@ -29,6 +29,76 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||
the description of the page and the "revises freehand" loop left the three commands. The call
|
||||
to `scripts/annotate.mjs`, the not-a-gate line and the printed links stay. The printed report now
|
||||
says a Question is answered and Fix and Change notes revise the file.
|
||||
- **`/trekendsession` is operator-only, and the planning and research spawn sites follow the profile.** The model can no longer start `/trekendsession` (`disable-model-invocation: true`). With `--project`, where the resolver runs, `/trekplan` and `/trekresearch` pass the resolved model at their spawn sites, so the `economy` profile gives Sonnet helpers unless the brief's phase signal for that phase names a model; without a resolved model the agent's own `model:` applies (opus for Claude Code's built-in agents), and `/trekexecute`'s step helper and controller stay on opus.
|
||||
|
||||
### Fixed
|
||||
|
||||
Fix round 4.5a (decisions 57, 67 and 68): the round's 30 findings, where a Voyage control could be bypassed or was too lax, or where the text gave a guarantee no code held. Each is fixed, and each has a test that fails on the code before it, except DJ, whose sentences already stood and whose pins fail when they are deleted (`tests/fix-round-4-5a-red.sh` proves every other id red at the round's start point, and DJ under its two mutations).
|
||||
|
||||
**Execute**
|
||||
|
||||
- **The merge lock refuses a review of an older commit** (R6). `lib/review/verdict-gate.mjs` takes `--repo <dir>`: an ALLOW or WARN review then opens only when its `scope_sha_end` is HEAD, or an ancestor of HEAD whose later commits (side branches included) change nothing but the review lessons and the `CLAUDE.md` pointer; anything else, a failed git call included, exits 2 with a reason that starts `review-stale` (the new `lib/review/reviewed-commit.mjs`). `/trekexecute` Phase 7.2 and the main-merge lock run the gate with `--repo .`, so the merge stays closed with the decline reason `review-stale`, also on `--resume`.
|
||||
- **`/trekexecute` runs the brief check it promised** (finding #33). With `--project` and a `brief.md`, Phase 1 runs the brief validator and the phase-model resolver (`lib/profiles/resolver.mjs --resolve-phase-model`) as `/trekplan` does, uses the effort it returns, and halts only on `BRIEF_V51_MISSING_SIGNALS`. Low effort runs the plan as one session, step after step; high effort changes nothing, and the text that set `gates_mode` from the effort and its `gates_mode_flag_override` record are gone.
|
||||
- **`/trekexecute` names and reads `--profile` and `--gates`** (finding #30). The argument hint, the usage block and Phase 1 carry both flags, Phase 1 strips `--profile <name>` before it reads the plan path, and the text says the profile changes no model here: the step helper and the controller stay on opus.
|
||||
- **The completion gate says which of its checks are commands and which are the executor's judgement** (finding #28). It no longer calls the counter check and the audit deterministic, and its two dead line references are gone.
|
||||
- **The final report says whether the app was seen with Claude Code's `run`** (decision 67). A ``**Seen with `run`:**`` line after End to end and a `run_seen` key in the summary JSON; the verdict is still the `End-to-end:` command.
|
||||
- **The park step no longer leaves an earlier attempt's files in the tree with exit 0** (6.5.0 Known issue: the park step). `lib/util/park-attempt-files.mjs` takes a file registered with `git add --intent-to-add` out of the index and parks it, strips colour codes from the diff and blocks on a non-empty diff with no readable header, reads the paths from the repository's top level whatever directory it runs in, and exits 2 when one of its git calls fails (a non-zero `git cat-file -e` reads as "not in HEAD"), before any file is moved. "Back to planning" saves the upward diff with `--no-color` and `core.quotepath=off`.
|
||||
|
||||
**Gates**
|
||||
|
||||
- **`--gates closed` turns gating on, and a bare `--gates` no longer swallows the next flag** (finding #1). The shim (`lib/util/autonomy-gate.mjs`) reads bare, `true` and `closed` as on and `false` and `open` as off, takes any other value as a usage error (exit 1), and leaves a following `--flag` in place. Before, only `true` was on.
|
||||
- **`--gates` means one thing in every command** (finding #1). `/trekbrief`, `/trekresearch`, `/trekplan` and `/trekexecute` share one rule and run the shim once to map the value. `/trekexecute` maps the value, and no phase of it pauses on it; its one stop is the merge into main. The executor strictness table (`adaptive`, `closed`, `open`) left README and `docs/`, and `/trekbrief` no longer promises pauses in the executor.
|
||||
|
||||
**Brief**
|
||||
|
||||
- **A brief with no research topics ends with its next steps** (finding #47). `/trekbrief` prints the manual path (`/trekplan --project`, then `/trekexecute --project`) and stops instead of entering the auto-only Phase 6, which now runs only after the operator opted into auto mode and Phase 4h approved the intent.
|
||||
|
||||
**Plan**
|
||||
|
||||
- **"execute" in `/trekplan` no longer builds the plan in the planning session** (finding #52). It prints the `/trekexecute` line and stops, so the approval check, the test lock, the step helpers and the review run; "team" and leaving plan mode do the same.
|
||||
- **The planning and research spawn sites take the resolved model** (findings #48 and #12). `/trekplan` passes `phase_signal_result.model` at its agent spawns, with the agent's own `model:` as the fallback and opus for the built-in Explore deep-dives; `/trekresearch`'s Phase 5 follow-ups do the same, with opus as the fallback.
|
||||
- **No turn budget is promised** (finding #57). The sentences that scaled `maxTurns` by codebase size left `/trekplan`, `/trekresearch` and the planning reference document; nothing set such a budget.
|
||||
|
||||
**Research**
|
||||
|
||||
- **The contrarian gets a conclusion to attack** (finding #113). `/trekresearch` launches `contrarian-researcher` as a second wave after every other agent of wave 1 returns, local ones included, with wave 1's leading answer, the claims for it and the alternatives it dismissed, taken from external findings only and with local parts removed; with `--engine deep-research` it runs after the engine returns.
|
||||
|
||||
**Review**
|
||||
|
||||
- **Core code outside the old deep-review patterns is now deep-reviewed** (6.5.0 Known issue: trial-5 finding 9). `/trekreview` triage makes deep review the default for every changed file it does not skip or mark summary-only, `CLAUDE.md`, `AGENTS.md` and `.claude/rules/**` included; summary-only is for `docs/**`, root Markdown other than those two, and `tests/fixtures/**`. The review orchestrator, README, the review template and the workflow's fallback say the same.
|
||||
- **A line past the end of the file no longer refutes a finding** (6.5.0 Known issue: the coordinator's line numbers). The coordinator's Accuracy rule refutes only a citation that escapes the repo root or a negative line; a line past the end of the file goes to `unverified` with the new reason `accuracy:line-out-of-range`: the citation is wrong, the claim is unchecked.
|
||||
- **Deleting the Declined to Judge copy-through now fails a test** (6.5.0 Known issue: the Declined to Judge copy-through). The sentences in `/trekreview` Phase 6 and in the coordinator's Input and body section 9 that carry each reviewer's Declined to Judge lines into `review.md` are pinned, and the round's red script deletes those sentences and sees the pins fail.
|
||||
- **Which row a finding joins no longer depends on the order the reviewers' payloads are read** (6.5.0 Known issue: the row order). Inside one file, line and rule key, `dedupByTriplet` groups the findings in two passes, title first and the untitled ones last, each in a fixed order, and a full tie picks its survivor in that order too; the coordinator's Pass 1 text and the workflow's copy follow the same rule. The rows and their `#k` ids still stand in input order.
|
||||
- **On the `--workflow` path, the severity floor and the put-back match each finding to its own row** (6.5.0 Known issue: the workflow floor and put-back). A returned finding is matched to the row with its triplet and title; with no title match, to the only row on its triplet, else to the strictest one there, never a lower one, and `engine` is read from that row only. Each engine row no returned finding carries is put back at its own severity, one copy per row.
|
||||
|
||||
**Continue**
|
||||
|
||||
- **`/trekcontinue` runs the arg parser instead of naming a JavaScript function** (finding #66). Phase 0 runs `lib/parsers/arg-parser.mjs --command trekcontinue -- $ARGUMENTS` and reads its JSON; the review orchestrator's parser line also passes its arguments after `--`.
|
||||
- **`/trekcontinue` finds the master prompt file at the repo root, and the consistency check reads the state file** (finding #102). The master file is looked for at `git rev-parse --show-toplevel`, not an undefined plugin root. The consistency call passes `--state-file` when the project's session state exists, and the validator now takes that value as the flag's own instead of a third path, and is valid only when both prompt files are valid.
|
||||
|
||||
**Endsession**
|
||||
|
||||
- **`/trekendsession` parses its arguments with the arg parser** (finding #15). A slug or label that holds `-h` is no help request: help comes only on `--help` or a first argument that is exactly `-h`, and Phase 2 reads the brief path and the label from the parser's positionals.
|
||||
- **Only the operator starts `/trekendsession`** (finding #67). Its frontmatter sets `disable-model-invocation: true`, and CLAUDE.md names it as the one command that does.
|
||||
|
||||
**Agents**
|
||||
|
||||
- **A reviewer drops a finding only with a trace** (finding #111). code-correctness-reviewer and brief-conformance-reviewer emit an off-tier finding at the catalogue's severity and drop it only when they can say why it is wrong, as one Declined to Judge line with that reason; `voyage:reviewing-adversarially` says the same, and a rule key outside the catalogue is described as routed to `unverified`, as the coordinator contract does.
|
||||
- **research-scout has the Tavily tools its "Try Tavily first" needs** (finding #24). Its tools now hold `mcp__tavily__tavily_search` and `mcp__tavily__tavily_research`, in docs-researcher's order.
|
||||
- **code-correctness-reviewer no longer cites a "MANDATORY OVERRIDE rule above" that is not there** (finding #23). The sentence states the rule itself.
|
||||
|
||||
**Docs**
|
||||
|
||||
- **Nothing sends a reader to run the planning reference document** (findings #2 and #26). `/trekexecute`, `/trekbrief`, brief-reviewer, session-decomposer, `docs/HANDOVER-CONTRACTS.md` and `docs/architecture.md` name `/trekplan` where they named `planning-orchestrator`.
|
||||
- **The three reference documents hold read-only tools** (finding #26). planning-orchestrator, research-orchestrator and review-orchestrator list only `Read`, `Glob` and `Grep`.
|
||||
|
||||
**Stats**
|
||||
|
||||
- **No command promises a stats key its record does not write** (finding #46). The "Stats records emit `profile` …" sentences left `/trekbrief`, `/trekplan`, `/trekexecute`, `/trekreview` and `/trekcontinue`; `/trekresearch` keeps only `engine`, which its record writes; `docs/profiles.md`, `docs/operations.md` and README no longer say a profile reaches the stats records.
|
||||
|
||||
### Known issues
|
||||
|
||||
- **A plan's `profile:` field has no writer.** README, `docs/`, `/trekexecute` and `/trekcontinue` say a plan carries or passes on a profile, but no command writes `profile:` to a plan; the plan validator's `MANIFEST_PROFILE_DRIFT` check reads it, and `resolveTrekcontinueProfile` has no caller outside its tests. Left whole for a later hardening part, which chooses between writing the field and taking the promises out.
|
||||
|
||||
### Doors
|
||||
|
||||
|
|
@ -36,6 +106,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||
- two-way: the coupling to Claude Code's `run` and the built-in owner list (R2) — a revert removes the three sentences and makes `owner=run` an unknown owner again; the criteria runner and `End-to-end:` are unchanged.
|
||||
- two-way: skill annotating and its pointers in three commands (order B) — revert the commit; the
|
||||
script, the page, the stored notes and the approval checks are unchanged.
|
||||
- two-way: fix round 4.5a (decisions 57, 67, 68) — a revert restores the old texts and checks
|
||||
|
||||
## v6.5.0 — 2026-10-18 — Three skills for brief, criteria and review, English labels, and three trial-5 fixes
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { tmpdir } from 'node:os';
|
|||
import { dirname, join, resolve, sep } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { findSection } from '../../lib/parsers/plan-schema.mjs';
|
||||
import { readFrontmatterFields } from '../../lib/skills/skill-frontmatter.mjs';
|
||||
import { childEnv } from '../helpers/child-env.mjs';
|
||||
|
|
@ -1483,3 +1484,90 @@ test('red script: the id list is the round\'s 30 ids, in the brief\'s order', ()
|
|||
assert.ok(m, `the IDS= line is not one single-quoted list: ${lines[0]}`);
|
||||
assert.deepEqual(m[1].trim().split(/\s+/), RED_IDS);
|
||||
});
|
||||
|
||||
// --- CHANGELOG: what the round fixed ----------------------------------------
|
||||
// Untagged: the CHANGELOG text is the round's report, not one id's fix. The
|
||||
// round's section is found by its title, as tests/helpers/changelog-section.mjs
|
||||
// finds the 6.4.0 delivery's: `## Unreleased — <title>` before the release,
|
||||
// `## vX.Y.Z — <date> — <title>` after it, exactly once, up to the next `## `
|
||||
// heading. The released 6.5.0 section must stay byte-equal: its sha256 (the
|
||||
// heading line through the line before the next `## ` heading, joined with
|
||||
// `\n`) was computed once from `git show ab6b32c:CHANGELOG.md` with this
|
||||
// slice; the test reads no git history.
|
||||
|
||||
const CHANGELOG = 'CHANGELOG.md';
|
||||
const ROUND_TITLE = "The annotating skill, the run coupling and P10's model-free part";
|
||||
const ROUND_HEADING = new RegExp(`^## (?:Unreleased|v\\d+\\.\\d+\\.\\d+ — \\d{4}-\\d{2}-\\d{2}) — ${ROUND_TITLE.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`);
|
||||
const V650_SHA256 = '1df8fd0fe7730204740ca509c8fceb6f9d331859b98ce5c1f8e62b9551ce3274';
|
||||
|
||||
/** The CHANGELOG lines from the one heading `isHeading` accepts to the line before the next `## ` heading. */
|
||||
function changelogPart(isHeading, what) {
|
||||
const lines = read(CHANGELOG).split('\n');
|
||||
const at = [];
|
||||
lines.forEach((l, i) => { if (isHeading(l.replace(/\s+$/, ''))) at.push(i); });
|
||||
assert.equal(at.length, 1, `${CHANGELOG} has the ${what} section exactly once (found ${at.length})`);
|
||||
let end = lines.length;
|
||||
for (let i = at[0] + 1; i < lines.length; i++) if (/^## /.test(lines[i])) { end = i; break; }
|
||||
return lines.slice(at[0], end).join('\n');
|
||||
}
|
||||
|
||||
const roundPart = () => changelogPart((l) => ROUND_HEADING.test(l), `"${ROUND_TITLE}"`);
|
||||
|
||||
/** The `### ` subsection headings of the round's section, in order. */
|
||||
const roundSubsections = () => roundPart().split('\n').filter((l) => /^### /.test(l)).map((l) => l.replace(/\s+$/, ''));
|
||||
|
||||
/** The bullets of one `### ` subsection of the round's section, each flattened to one line. */
|
||||
function roundBullets(heading) {
|
||||
const lines = section(roundPart(), heading).split('\n').slice(1);
|
||||
const out = [];
|
||||
for (const l of lines) {
|
||||
if (/^- /.test(l)) out.push(l);
|
||||
else if (out.length && l.trim() !== '') out[out.length - 1] += ` ${l}`;
|
||||
}
|
||||
return out.map(flat);
|
||||
}
|
||||
|
||||
const FIXED_KNOWN_ISSUES = [
|
||||
['trial-5 finding 9 (core code never deep-reviewed)', /trial-5 finding 9/],
|
||||
['the park step', /park step/],
|
||||
['the workflow floor and put-back', /`--workflow`.*floor.*put-back|`--workflow`.*put-back.*floor/],
|
||||
['the row order (which row a finding joins)', /which row a finding joins/i],
|
||||
['the coordinator\'s line numbers (a line past the end refuted)', /line (?:number )?past the end of the file.*(?:refuted|refutes)/],
|
||||
['the Declined to Judge copy-through', /Declined to Judge.*`review\.md`/],
|
||||
];
|
||||
|
||||
test('CHANGELOG: the round\'s section has ### Fixed between ### Changed and ### Doors, and ### Known issues after ### Fixed', () => {
|
||||
const subs = roundSubsections();
|
||||
for (const h of ['### Changed', '### Fixed', '### Known issues', '### Doors']) {
|
||||
assert.equal(subs.filter((s) => s === h).length, 1, `the round's section must have "${h}" once; it has ${JSON.stringify(subs)}`);
|
||||
}
|
||||
const at = (h) => subs.indexOf(h);
|
||||
assert.ok(at('### Changed') < at('### Fixed') && at('### Fixed') < at('### Doors'),
|
||||
`### Fixed must stand between ### Changed and ### Doors: ${JSON.stringify(subs)}`);
|
||||
assert.ok(at('### Fixed') < at('### Known issues'), `### Known issues must come after ### Fixed: ${JSON.stringify(subs)}`);
|
||||
});
|
||||
|
||||
test('CHANGELOG: ### Fixed names each of the six 6.5.0 Known issues the round fixed, each as a 6.5.0 Known issue', () => {
|
||||
const bullets = roundBullets('### Fixed');
|
||||
const known = bullets.filter((b) => /6\.5\.0 Known issue/.test(b));
|
||||
const missing = FIXED_KNOWN_ISSUES.filter(([, re]) => !known.some((b) => re.test(b))).map(([name]) => name);
|
||||
assert.deepEqual(missing, [], `### Fixed names no entry marked "6.5.0 Known issue" for: ${missing.join('; ')}`);
|
||||
});
|
||||
|
||||
test('CHANGELOG: ### Known issues names that a plan\'s profile: field has no writer, and names /trekexecute and /trekcontinue', () => {
|
||||
const hits = roundBullets('### Known issues').filter((b) => b.includes("**A plan's `profile:` field has no writer.**"));
|
||||
assert.equal(hits.length, 1, `expected one Known issues line on the plan's profile: field; found ${hits.length}`);
|
||||
assert.ok(hits[0].includes('`/trekexecute` and `/trekcontinue`'), `the line does not name \`/trekexecute\` and \`/trekcontinue\`: ${hits[0]}`);
|
||||
});
|
||||
|
||||
test('CHANGELOG: ### Doors has the two-way line for fix round 4.5a', () => {
|
||||
const hits = roundBullets('### Doors').filter((b) => b.startsWith('- two-way: fix round 4.5a'));
|
||||
assert.deepEqual(hits, ['- two-way: fix round 4.5a (decisions 57, 67, 68) — a revert restores the old texts and checks'],
|
||||
'the Doors part has no single two-way line for fix round 4.5a');
|
||||
});
|
||||
|
||||
test('CHANGELOG: the released v6.5.0 section is byte-equal to its text at ab6b32c (sha256)', () => {
|
||||
const part = changelogPart((l) => l.startsWith('## v6.5.0 — '), 'v6.5.0');
|
||||
assert.equal(createHash('sha256').update(part, 'utf8').digest('hex'), V650_SHA256,
|
||||
'the released v6.5.0 section changed; edit only the round\'s section');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue