@popovych.co/witness 0.24.0 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { Lexer, isCollection, isMap, isScalar, parseDocument } from 'yaml';
2
- import { LEGACY_COMMENTS } from './legacy-comments.js';
2
+ import { RELEASED_COMMENTS } from './released-comments.js';
3
3
  import { CHANGE_CLASSES, FIRST_LINE, GROUP_HEADINGS, SCHEMA_COMMENT, SETTINGS, getIn, inlineValue, } from './settings.js';
4
4
  import { sectionsOf } from './migration.js';
5
5
  const EMPTY = { top: [], above: new Map(), end: [] };
@@ -73,6 +73,9 @@ const CURRENT_COMMENTS = new Set([
73
73
  FIRST_LINE.slice(1).trim(),
74
74
  ...Object.values(GROUP_HEADINGS).map((h) => h.slice(1).trim()),
75
75
  ]);
76
+ // What a released witness wrote and this one no longer does: derived from the one record, so a
77
+ // reworded comment's old text can never be left out of it.
78
+ const LEGACY_COMMENTS = new Set([...RELEASED_COMMENTS].filter((t) => !CURRENT_COMMENTS.has(t)));
76
79
  // Where a human line can be printed: every setting and section, and a per-class reviewer line.
77
80
  const PRINTABLE = new Set([
78
81
  ...SETTINGS.map((s) => s.path),
@@ -150,7 +153,7 @@ export function readComments(text) {
150
153
  const comment = token.trimEnd();
151
154
  const body = comment.slice(1).trim();
152
155
  const ownLine = src.slice(lineStarts[line], at).trim() === '';
153
- if (LEGACY_COMMENTS.has(body) || CURRENT_COMMENTS.has(body)) {
156
+ if (RELEASED_COMMENTS.has(body) || CURRENT_COMMENTS.has(body)) {
154
157
  // A line of its own vanishes; one on a setting's line, or the first line, is replaced.
155
158
  if (ownLine && line !== 0 && LEGACY_COMMENTS.has(body))
156
159
  legacy++;
package/dist/install.js CHANGED
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url';
4
4
  import { version } from './cli.js';
5
5
  import { tryGit } from './gitio.js';
6
6
  import { ok, refuse, v } from './refusal.js';
7
+ import { SETTINGS } from './settings.js';
7
8
  import { NPX_LATEST, compareTriple, pinIn } from './version.js';
8
9
  // dist/install.js and src/install.ts both sit one level under the package root, so the
9
10
  // same '..' works built and under vitest — the pattern model.ts:14 already uses. This is
@@ -258,7 +259,8 @@ export function recordHarness(configText, name) {
258
259
  return { text: configText, changed: false, declared: found[1] };
259
260
  const suffix = configText.endsWith('\n') ? '' : '\n';
260
261
  return {
261
- text: `${configText}${suffix}harness: ${name} # the judge — which harness runs this repo's gate reviewers; declared wins\n`,
262
+ // The setting's own comment, as a fresh init writes it: one source of witness's comment text.
263
+ text: `${configText}${suffix}harness: ${name} # ${SETTINGS.find((s) => s.path === 'harness').comment}\n`,
262
264
  changed: true,
263
265
  };
264
266
  }
@@ -0,0 +1,79 @@
1
+ // Row 193 §4.5. Every comment text a released witness wrote into witness.config.yaml — the one
2
+ // record of which comments are witness's. A comment line whose trimmed text is one of these is
3
+ // witness's wherever it sits: `migrate` writes the current text on a setting's line and drops an
4
+ // old one on a line of its own, since what it described now exists for real. An edited copy no
5
+ // longer matches, so it is the human's. Append-only: rewording a comment in `src/settings.ts`
6
+ // adds its new text here and leaves the old one, which is what keeps every file an older witness
7
+ // wrote readable (tests/config-file.test.ts fails on a written text missing from the record).
8
+ // What this witness no longer writes is derived (config-file.ts), never a second list to keep.
9
+ export const RELEASED_COMMENTS = new Set([
10
+ // ── Before 0.21.0: each version of `init`'s template (git log -p --follow -- src/verbs/init.ts,
11
+ // the specflow era included; a continuation line is its own entry) and both of
12
+ // `recordHarness`'s texts (src/install.ts).
13
+ 'any gate block may pin its own model (wins over the global pin), e.g.',
14
+ 'conventions: [docs/code/architecture.md] # → injected into code-reviewer at implement + ship (cache-keyed)',
15
+ 'declared beats the ambient session (init --agent writes it once)',
16
+ 'decompose: { reviewers: [slicing-critic], model: claude-opus-4-8 }',
17
+ 'docs: # repo docs registry — enumerated keys, unknown keys refused',
18
+ "harness: pi # the judge — which harness runs this repo's gate reviewers;",
19
+ 'or: runner: full-suite + report: junit:**/reports/junit.xml',
20
+ 'paths: { specs: docs/specs, plans: docs/plans } # optional canon roots (defaults: specs, plans); git mv existing docs when changing',
21
+ 'per change class; a plain list = all classes',
22
+ 'reviewer model pin — exact id, aliases refused',
23
+ 'reviewerTimeoutMs: 600000 # ms per reviewer invocation (machine auth/extension knobs live in .witness/config.local.yaml)',
24
+ 'specflow.config.yaml — the whole surface',
25
+ 'witness.config.yaml — the whole surface',
26
+ "the judge — which harness runs this repo's gate reviewers; declared wins",
27
+ 'detection wins; this is the fallback',
28
+ // The end-of-line comments of the template's commented-out settings, which the template meant
29
+ // the human to uncomment (final review I3).
30
+ 'optional canon roots (defaults: specs, plans); git mv existing docs when changing',
31
+ 'repo docs registry — enumerated keys, unknown keys refused',
32
+ '→ injected into code-reviewer at implement + ship (cache-keyed)',
33
+ "the judge — which harness runs this repo's gate reviewers;",
34
+ 'ms per reviewer invocation (machine auth/extension knobs live in .witness/config.local.yaml)',
35
+ // ── Since 0.21.0 the template is `src/settings.ts`: every setting's comment, the per-class
36
+ // `for a …` lines, the schema line, the first line and the group headings, in every release.
37
+ // Collected from the published tarballs 0.21.0, 0.21.1, 0.22.0, 0.23.0 and 0.24.0.
38
+ "% of the context window at which a session hands over to a fresh one · 1–100",
39
+ "code docs handed to code-reviewer at implement and ship · file list, [] = none",
40
+ "design docs handed to design-critic and design-reviewer · file list, [] = none",
41
+ "extra globs never scanned for criteria tags · [] = none",
42
+ "folder for approved designs, repo-relative · git mv the docs when you change it",
43
+ "folder for plans, repo-relative · git mv the docs when you change it",
44
+ "folder for specs, repo-relative · git mv the docs when you change it",
45
+ "for a chore",
46
+ "for a feature",
47
+ "for a fix",
48
+ "format version · witness migrate raises it; never edit by hand",
49
+ "gate rounds one target may run across budget resets, then it is parked · ≥ 1",
50
+ "how a spec's criteria run · a command with {id}, or full-suite",
51
+ "how ship merges its own PR under autonomy · merge | squash | rebase",
52
+ "let test runs in two worktrees overlap · true | false",
53
+ "model for the arbiter that settles stops and checks recaps under autonomy · exact id, no aliases",
54
+ "model for the arbiter that settles stops under autonomy · exact id, no aliases",
55
+ "model for this gate's reviewers AND for the agent that writes the code",
56
+ "model for this gate's reviewers · exact id, [provider/]id[:thinking], no aliases",
57
+ "model for this gate's reviewers · exact id, no aliases",
58
+ "model for this gate's reviewers · runs only on specs marked ui",
59
+ "ms green CI must hold still before an autonomous merge · 0–1800000",
60
+ "ms of session time one target may take in one run (16 h), then it is parked · ≥ 1",
61
+ "ms one reviewer, or the arbiter, may run before it is stopped (10 min) · ≥ 1",
62
+ "ms one spawned session may run before it is stopped (1 h) · ≥ 1",
63
+ "on = the CLI settles its own stops and merges green PRs · on | off · counts once committed",
64
+ "reviewers this gate runs · one list, or one list per class",
65
+ "reviewers this gate runs · one list, or one list per class (feature, fix, chore)",
66
+ "sessions drive runs at once, one per target · ≥ 1",
67
+ "sessions one target may take in one run, then it is parked · ≥ 1",
68
+ "steps an implement session takes when its context fill can't be read · ≥ 1",
69
+ "the branch witness ships into",
70
+ "the judge: the agent CLI that runs this repo's gate reviewers and arbiter · claude-code | pi",
71
+ "the junit report witness reads · junit:<glob>, or none · full-suite needs one",
72
+ "the lint command ship runs",
73
+ "the suite command ship runs · full-suite criteria run it too",
74
+ "upstream resets one target may take, then it is parked · ≥ 1",
75
+ "witness.config.yaml — every setting witness reads. Change a value in place; `witness migrate` keeps the file current.",
76
+ "── Behavior: how witness works here ─────────────────────────────────────────",
77
+ "── Setup: what this repo is ─────────────────────────────────────────────────",
78
+ "── Tuning: witness drive ────────────────────────────────────────────────────",
79
+ ]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@popovych.co/witness",
3
- "version": "0.24.0",
3
+ "version": "0.24.1",
4
4
  "description": "Evidence-gated spec-driven development pipeline for AI coding agents: brainstorm to PR in six stages, where specs are state, plans are motion, and no transition passes without evidence. Drives from Claude Code or Pi.",
5
5
  "keywords": [
6
6
  "spec-driven-development",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "witness",
3
3
  "description": "Spec-driven development with evidence gates: brainstorm → PR through six stages and five gates. Skills author, the pinned witness CLI writes state and witnesses evidence; gates stop where judgment is owed.",
4
- "version": "0.24.0",
4
+ "version": "0.24.1",
5
5
  "author": {
6
6
  "name": "Kostiantyn Popovych"
7
7
  },
@@ -12,7 +12,7 @@ Any other words in `$ARGUMENTS` are the human's ask: run `$WITNESS ask "<those w
12
12
  Resolve the CLI once:
13
13
 
14
14
  ```bash
15
- WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.0}"
15
+ WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.1}"
16
16
  ```
17
17
 
18
18
  If the repo has no `witness.config.yaml`, run `$WITNESS init` first (one bootstrap commit), then proceed. If init or any verb refuses on a dirty tree, the human commits or cleans it — **never `git commit` yourself, anywhere, at any stage**: the CLI makes its own state commits, and the ship phase makes the sole code commit.
@@ -3,4 +3,4 @@
3
3
  # context). Silent everywhere that isn't a witness repo; failures swallowed:
4
4
  # session start must never hang or die on this.
5
5
  [ -f witness.config.yaml ] || exit 0
6
- ${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.0} 2>/dev/null || true
6
+ ${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.1} 2>/dev/null || true
@@ -16,7 +16,7 @@ recap, keeps a local draft, writes no document. See NOTICE.md. -->
16
16
  Resolve the CLI once per session:
17
17
 
18
18
  ```bash
19
- WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.0}"
19
+ WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.1}"
20
20
  ```
21
21
 
22
22
  - **Render the CLI's decision output verbatim and in full — every line, unmodified.** Never print a command set you remember; never recompose, reformat, summarise or reorder what the CLI emitted. Which decisions are live, how they rank, and what each costs are the CLI's answers, and they change with the round, the bound, the repair grant and the content sha — a remembered set is wrong in more states than it is right.
@@ -10,7 +10,7 @@ description: Slice a witness effort's confirmed recap into vertical spec slices,
10
10
  Resolve the CLI once per session:
11
11
 
12
12
  ```bash
13
- WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.0}"
13
+ WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.1}"
14
14
  ```
15
15
 
16
16
  - **Render the CLI's decision output verbatim and in full — every line, unmodified.** Never print a command set you remember; never recompose, reformat, summarise or reorder what the CLI emitted. Which decisions are live, how they rank, and what each costs are the CLI's answers, and they change with the round, the bound, the repair grant and the content sha — a remembered set is wrong in more states than it is right.
@@ -16,7 +16,7 @@ No text copied verbatim; the design-critic lens is new material. -->
16
16
  Resolve the CLI once per session:
17
17
 
18
18
  ```bash
19
- WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.0}"
19
+ WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.1}"
20
20
  ```
21
21
 
22
22
  - **Render the CLI's decision output verbatim and in full — every line, unmodified.** Never print a command set you remember; never recompose, reformat, summarise or reorder what the CLI emitted. Which decisions are live, how they rank, and what each costs are the CLI's answers, and they change with the round, the bound, the repair grant and the content sha — a remembered set is wrong in more states than it is right.
@@ -15,7 +15,7 @@ tests carry the parent spec's tag in their NAME. See NOTICE.md. -->
15
15
  Resolve the CLI once per session:
16
16
 
17
17
  ```bash
18
- WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.0}"
18
+ WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.1}"
19
19
  ```
20
20
 
21
21
  - **Render the CLI's decision output verbatim and in full — every line, unmodified.** Never print a command set you remember; never recompose, reformat, summarise or reorder what the CLI emitted. Which decisions are live, how they rank, and what each costs are the CLI's answers, and they change with the round, the bound, the repair grant and the content sha — a remembered set is wrong in more states than it is right.
@@ -15,7 +15,7 @@ parent's criteria. See NOTICE.md. -->
15
15
  Resolve the CLI once per session:
16
16
 
17
17
  ```bash
18
- WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.0}"
18
+ WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.1}"
19
19
  ```
20
20
 
21
21
  - **Render the CLI's decision output verbatim and in full — every line, unmodified.** Never print a command set you remember; never recompose, reformat, summarise or reorder what the CLI emitted. Which decisions are live, how they rank, and what each costs are the CLI's answers, and they change with the round, the bound, the repair grant and the content sha — a remembered set is wrong in more states than it is right.
@@ -15,7 +15,7 @@ model can. See NOTICE.md. -->
15
15
  Resolve the CLI once per session:
16
16
 
17
17
  ```bash
18
- WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.0}"
18
+ WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.24.1}"
19
19
  ```
20
20
 
21
21
  - **Render the CLI's decision output verbatim and in full — every line, unmodified.** Never print a command set you remember; never recompose, reformat, summarise or reorder what the CLI emitted. Which decisions are live, how they rank, and what each costs are the CLI's answers, and they change with the round, the bound, the repair grant and the content sha — a remembered set is wrong in more states than it is right.
@@ -1,30 +0,0 @@
1
- // Row 193 §4.5. Every comment text a released witness wrote into witness.config.yaml: each
2
- // version of `init`'s template (git log -p --follow -- src/verbs/init.ts, the specflow era
3
- // included; a continuation line is its own entry) and both of `recordHarness`'s texts
4
- // (src/install.ts). A comment line whose trimmed text is one of these is witness's, wherever it
5
- // sits: `migrate` replaces it on a setting's line and drops it on a line of its own, since what
6
- // it described now exists for real. An edited copy no longer matches, so it is the human's.
7
- export const LEGACY_COMMENTS = new Set([
8
- 'any gate block may pin its own model (wins over the global pin), e.g.',
9
- 'conventions: [docs/code/architecture.md] # → injected into code-reviewer at implement + ship (cache-keyed)',
10
- 'declared beats the ambient session (init --agent writes it once)',
11
- 'decompose: { reviewers: [slicing-critic], model: claude-opus-4-8 }',
12
- 'docs: # repo docs registry — enumerated keys, unknown keys refused',
13
- "harness: pi # the judge — which harness runs this repo's gate reviewers;",
14
- 'or: runner: full-suite + report: junit:**/reports/junit.xml',
15
- 'paths: { specs: docs/specs, plans: docs/plans } # optional canon roots (defaults: specs, plans); git mv existing docs when changing',
16
- 'per change class; a plain list = all classes',
17
- 'reviewer model pin — exact id, aliases refused',
18
- 'reviewerTimeoutMs: 600000 # ms per reviewer invocation (machine auth/extension knobs live in .witness/config.local.yaml)',
19
- 'specflow.config.yaml — the whole surface',
20
- 'witness.config.yaml — the whole surface',
21
- "the judge — which harness runs this repo's gate reviewers; declared wins",
22
- 'detection wins; this is the fallback',
23
- // The end-of-line comments of the template's commented-out settings, which the template meant
24
- // the human to uncomment (final review I3).
25
- 'optional canon roots (defaults: specs, plans); git mv existing docs when changing',
26
- 'repo docs registry — enumerated keys, unknown keys refused',
27
- '→ injected into code-reviewer at implement + ship (cache-keyed)',
28
- "the judge — which harness runs this repo's gate reviewers;",
29
- 'ms per reviewer invocation (machine auth/extension knobs live in .witness/config.local.yaml)',
30
- ]);