harness-everything 0.46.3 → 0.47.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.
Files changed (51) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +32 -1
  4. package/benchmarks/results/live-host/claude-341-outline-dispatch-2026-10-28/README.md +33 -8
  5. package/benchmarks/results/live-host/claude-341-outline-dispatch-2026-10-28/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md +128 -0
  6. package/benchmarks/results/live-host/claude-341-outline-dispatch-2026-10-28/sanitize-outline-capture.js +105 -0
  7. package/ci/mechanism-379-self-evolve-workspace.test.js +151 -0
  8. package/ci/mechanism-383-doc-glob-line-terminators.test.js +131 -0
  9. package/ci/mechanism-e1-derived-regenerate.test.js +333 -0
  10. package/ci/mechanism-outline-sanitizer.test.js +79 -0
  11. package/ci/mechanism-prb-outline-review.test.js +278 -31
  12. package/docs/doc-workflow-reconciliation.md +12 -8
  13. package/docs/document-lifecycle.md +1 -1
  14. package/docs/platform-capabilities.md +5 -1
  15. package/harness-everything/SKILL.md +1 -1
  16. package/harness-everything/scripts/doc-check.js +107 -9
  17. package/harness-everything/scripts/doc-lifecycle.js +51 -3
  18. package/harness-everything/scripts/doc-obligations.js +2 -2
  19. package/hooks/scripts/lib/doc-reconciliation-core.js +2 -2
  20. package/hooks/scripts/lib/doc-reconciliation-events.js +22 -0
  21. package/hooks/scripts/lib/doc-reconciliation-outline-capture.sanitized.jsonl +24 -0
  22. package/hooks/scripts/lib/doc-reconciliation-pilot.js +3 -1
  23. package/hooks/scripts/lib/doc-reconciliation-provider.js +168 -15
  24. package/hooks/scripts/lib/doc-reconciliation-qualification.json +20 -0
  25. package/opencode-plugin/plugin.json +1 -1
  26. package/package.json +1 -1
  27. package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
  28. package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-core.js +2 -2
  29. package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-events.js +22 -0
  30. package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-outline-capture.sanitized.jsonl +24 -0
  31. package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-pilot.js +3 -1
  32. package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-provider.js +168 -15
  33. package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-qualification.json +20 -0
  34. package/plugins/harness-everything/plugin.json +1 -1
  35. package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
  36. package/plugins/harness-everything/skills/harness-everything/scripts/doc-check.js +107 -9
  37. package/plugins/harness-everything/skills/harness-everything/scripts/doc-lifecycle.js +51 -3
  38. package/plugins/harness-everything/skills/harness-everything/scripts/doc-obligations.js +2 -2
  39. package/plugins/harness-everything/skills/self-evolve/SKILL.md +1 -1
  40. package/plugins/harness-everything/skills/self-evolve/references/memory-resolution.md +11 -0
  41. package/plugins/harness-everything/skills/self-evolve/scripts/lesson-candidate.js +9 -12
  42. package/plugins/harness-everything/skills/self-evolve/scripts/persist-memory.js +1 -14
  43. package/plugins/harness-everything/skills/self-evolve/scripts/register-dynamic-skill.js +5 -9
  44. package/plugins/harness-everything/skills/self-evolve/scripts/workspace-helper.js +98 -0
  45. package/sbom.cdx.json +7 -7
  46. package/self-evolve/SKILL.md +1 -1
  47. package/self-evolve/references/memory-resolution.md +11 -0
  48. package/self-evolve/scripts/lesson-candidate.js +9 -12
  49. package/self-evolve/scripts/persist-memory.js +1 -14
  50. package/self-evolve/scripts/register-dynamic-skill.js +5 -9
  51. package/self-evolve/scripts/workspace-helper.js +98 -0
@@ -8,13 +8,14 @@ const fs = require('fs');
8
8
  const path = require('path');
9
9
  const crypto = require('crypto');
10
10
  const { execFileSync, spawnSync } = require('child_process');
11
- const { collectDocs } = require('./doc-lifecycle');
11
+ const { isDeepStrictEqual } = require('node:util');
12
+ const { collectDocs, buildIndexSnapshot } = require('./doc-lifecycle');
12
13
 
13
14
  // Logical command IDs (A3 section 3): stdout that repeats an ID is not trusted as credit by itself.
14
15
  const CHECK_ID = 'harness.doc-check.check.v1';
15
16
  const COMPARE_ID = 'harness.doc-check.compare-derived.v1';
16
- const USAGE = 'usage: doc-check.js check --workspace <dir> --config <json-file, relative to --workspace> --changed-path <path> [--changed-path <path> ...] [--base <git-rev>] [--conflict-assessment]';
17
- const VALUE_FLAGS = ['--workspace', '--config', '--changed-path', '--base'];
17
+ const USAGE = 'usage: doc-check.js check --workspace <dir> --config <json-file, relative to --workspace> --changed-path <path> [--changed-path <path> ...] [--base <git-rev>] [--derived-view <path>] [--conflict-assessment]';
18
+ const VALUE_FLAGS = ['--workspace', '--config', '--changed-path', '--base', '--derived-view'];
18
19
  const CONFLICT_SCHEMA = 'harness.doc-check.conflict-assessment.v1';
19
20
  const EXTERNAL = /^(?:https?:|mailto:)/i;
20
21
  const SCHEME = /^[a-z][a-z0-9+.-]*:/i;
@@ -91,10 +92,11 @@ function parseArgs(argv) {
91
92
  if (!VALUE_FLAGS.includes(flag) || rest[index + 1] === undefined) throw new Error(`${USAGE}\nunknown or incomplete argument: ${flag}`);
92
93
  const value = rest[++index];
93
94
  if (value.startsWith('--')) throw new Error(`${USAGE}\n${flag} requires a value, not a flag: ${value}`);
94
- if (flag === '--changed-path') options.changedPaths.push(value);
95
+ if (flag === '--changed-path') options.changedPaths.push(value);
95
96
  else {
96
- if (options[flag.slice(2)] !== undefined) throw new Error(`${USAGE}\nrepeated argument: ${flag}`);
97
- options[flag.slice(2)] = value;
97
+ const key = flag === '--derived-view' ? 'derivedView' : flag.slice(2);
98
+ if (options[key] !== undefined) throw new Error(`${USAGE}\nrepeated argument: ${flag}`);
99
+ options[key] = value;
98
100
  }
99
101
  }
100
102
  if (!options.workspace || !options.config) throw new Error(`${USAGE}\n--workspace and --config are required`);
@@ -241,7 +243,7 @@ function parseCompareArgs(argv) {
241
243
 
242
244
  // Escape regex metacharacters, then translate `**`, `*` and `?`. Used only to detect a declared glob.
243
245
  function globToRegExp(pattern) {
244
- const body = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*\*/g, '\u0000').replace(/\*/g, '[^/]*').replace(/\?/g, '[^/]').replace(/\u0000/g, '.*');
246
+ const body = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*\*/g, '\u0000').replace(/\*/g, '[^/]*').replace(/\?/g, '[^/]').replace(/\u0000/g, '[\\s\\S]*');
245
247
  return new RegExp(`^${body}$`);
246
248
  }
247
249
 
@@ -310,7 +312,7 @@ function compareDerived(argv) {
310
312
  }
311
313
 
312
314
  const GLOB_CHARS = /[*?[\]{}]/;
313
- const VIEW_REASON = 'derived view not verified: run its authorized generator, then compare-derived';
315
+ const VIEW_REASON = 'derived view not verified: request check --derived-view to regenerate and compare it';
314
316
 
315
317
  // Near-miss comparison only (separators, leading ./, trailing /, case); never used to accept a view.
316
318
  function normalizeView(value) {
@@ -366,6 +368,97 @@ function derivedCoverage(config, { workspace, configRelative, configChanged, aff
366
368
  return entries;
367
369
  }
368
370
 
371
+ function digest(bytes) { return crypto.createHash('sha256').update(bytes).digest('hex'); }
372
+
373
+ function derivedRegenerate(workspace, options, config, configBytes) {
374
+ const view = options.derivedView;
375
+ const unavailable = reason => ({ state: 'unavailable', checkedPaths: [view], reason });
376
+ if (typeof view !== 'string' || !view || path.isAbsolute(view) || view.includes('\\')
377
+ || view.split('/').some(part => !part || part === '.' || part === '..') || GLOB_CHARS.test(view)) {
378
+ return { state: 'unsupported', checkedPaths: [], reason: 'view must be a literal workspace-relative path' };
379
+ }
380
+ const configRelative = workspaceRelative(workspace, options.config);
381
+ if (!configRelative || path.isAbsolute(options.config) || options.config.includes('\\')
382
+ || !/^[A-Za-z0-9._/-]+$/.test(options.config)
383
+ || options.config.split('/').some(part => !part || part === '.' || part === '..')) {
384
+ return { state: 'unsupported', checkedPaths: [view], reason: 'config must be a canonical workspace-relative path' };
385
+ }
386
+ const selected = (Array.isArray(config.derived) ? config.derived : []).filter(item => item && item.path === view);
387
+ if (selected.length !== 1) return { state: 'unsupported', checkedPaths: [view], reason: 'view must name exactly one declared derived path' };
388
+ const governedPatterns = [
389
+ ...(Array.isArray(config.governed) ? config.governed.map(item => item && item.path) : []),
390
+ ...(Array.isArray(config.legacy) ? config.legacy : [])
391
+ ].filter(item => typeof item === 'string');
392
+ if (governedPatterns.some(pattern => globToRegExp(pattern).test(view))) {
393
+ return { state: 'unsupported', checkedPaths: [view], reason: 'a derived view cannot be governed by its own index' };
394
+ }
395
+ const expectedGenerator = `node harness-everything/scripts/doc-lifecycle.js index --workspace . --config ${options.config} --all`;
396
+ if (selected[0].generator !== expectedGenerator) {
397
+ return { state: 'unsupported', checkedPaths: [view], reason: 'configured generator is not the supported lifecycle index operation' };
398
+ }
399
+
400
+ const target = path.resolve(workspace, view);
401
+ const generatorPath = path.resolve(__dirname, 'doc-lifecycle.js');
402
+ const rootReal = fs.realpathSync(workspace);
403
+ const targetBytes = () => {
404
+ const stat = fs.lstatSync(target);
405
+ if (!stat.isFile()) throw new Error('view is not a regular file');
406
+ const real = fs.realpathSync(target);
407
+ const relative = path.relative(rootReal, real);
408
+ if (!relative || relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
409
+ throw new Error('view resolves outside the workspace');
410
+ }
411
+ return readRegularFile(target);
412
+ };
413
+
414
+ try {
415
+ const configPath = path.resolve(workspace, options.config);
416
+ const configReal = fs.realpathSync(configPath);
417
+ const configPathRelative = path.relative(rootReal, configReal);
418
+ if (!configPathRelative || configPathRelative === '..' || configPathRelative.startsWith(`..${path.sep}`)
419
+ || !fs.lstatSync(configPath).isFile()) return { state: 'unsupported', checkedPaths: [view], reason: 'config is not a workspace-contained regular file' };
420
+ const beforeTarget = targetBytes();
421
+ const generatorDigest = digest(fs.readFileSync(generatorPath, 'utf8').replace(/\r\n/g, '\n'));
422
+ const first = buildIndexSnapshot(workspace, configPath, config, configBytes);
423
+ const currentConfigBytes = fs.readFileSync(configPath);
424
+ const currentConfig = JSON.parse(currentConfigBytes.toString('utf8'));
425
+ const second = buildIndexSnapshot(workspace, configPath, currentConfig, currentConfigBytes);
426
+ const afterTarget = targetBytes();
427
+ const currentGeneratorDigest = digest(fs.readFileSync(generatorPath, 'utf8').replace(/\r\n/g, '\n'));
428
+ const outputDigest = digest(first.bytes);
429
+ const targetDigest = digest(beforeTarget);
430
+ const stable = digest(configBytes) === digest(currentConfigBytes)
431
+ && first.corpus.complete === true && second.corpus.complete === true
432
+ && first.configInventory.complete === true && second.configInventory.complete === true
433
+ && isDeepStrictEqual(first.corpus.paths, second.corpus.paths)
434
+ && isDeepStrictEqual(first.corpus.digests, second.corpus.digests)
435
+ && isDeepStrictEqual(first.configInventory.sources, second.configInventory.sources)
436
+ && isDeepStrictEqual(first.configSources, second.configSources)
437
+ && Buffer.compare(first.bytes, second.bytes) === 0
438
+ && generatorDigest === currentGeneratorDigest
439
+ && digest(afterTarget) === targetDigest;
440
+ const equal = Buffer.compare(first.bytes, beforeTarget) === 0;
441
+ const comparisonState = stable ? (equal ? 'equal' : 'stale') : 'unavailable';
442
+ const binding = {
443
+ view,
444
+ sourceCorpus: { complete: first.corpus.complete === true, paths: first.corpus.paths, digests: first.corpus.digests },
445
+ config: { path: configRelative, digest: digest(configBytes), sources: first.configInventory.sources },
446
+ generator: { path: fs.realpathSync(generatorPath), digest: generatorDigest },
447
+ generation: { state: 'pass', outputDigest },
448
+ comparison: { state: comparisonState, targetDigest },
449
+ };
450
+ return {
451
+ state: stable && equal ? 'pass' : stable ? 'stale' : 'unavailable',
452
+ checkedPaths: [view],
453
+ ...(stable ? {} : { reason: 'source, config, generator, or target changed during the check' }),
454
+ ...(!stable && !first.corpus.complete ? { reason: 'source corpus is incomplete' } : {}),
455
+ binding,
456
+ };
457
+ } catch (error) {
458
+ return unavailable(error.message || 'generation or comparison unavailable');
459
+ }
460
+ }
461
+
369
462
  function check(options) {
370
463
  const workspace = path.resolve(options.workspace);
371
464
  const configPath = path.resolve(workspace, options.config);
@@ -422,7 +515,7 @@ function check(options) {
422
515
  // SHOULD reminders only: they never change the exit code and are never diagnostics.
423
516
  const changed = new Set(options.changedPaths.map(value => path.relative(workspace, path.resolve(workspace, value)).split(path.sep).join('/')));
424
517
  // F3 applicability (conservative): a governed or legacy source, an unknown or deleted path, a derived output or the config
425
- // itself marks every declared view unverified. check still never runs a generator.
518
+ // itself marks every declared view unverified until the explicit derived-view mode is selected.
426
519
  const configRelative = path.relative(workspace, configPath).split(path.sep).join('/');
427
520
  const declaredViews = [...new Set((Array.isArray(config.derived) ? config.derived : []).map(entry => entry.path))];
428
521
  const affectsViews = [...changed].some(item => {
@@ -465,6 +558,11 @@ function check(options) {
465
558
  },
466
559
  }
467
560
  };
561
+ if (options.derivedView) {
562
+ const derived = derivedRegenerate(workspace, options, config, configBytes);
563
+ result.capabilities['derived-regenerate'] = derived;
564
+ if (derived.state === 'pass') result.coverage.unsupported = result.coverage.unsupported.filter(item => item.path !== options.derivedView || item.state !== 'unverified');
565
+ }
468
566
  if (options.conflictAssessment) {
469
567
  const scopePaths = [...new Set(options.changedPaths.map(value => workspaceRelative(workspace, value)).filter(Boolean))].sort();
470
568
  const corpus = analysis.corpus;
@@ -202,10 +202,10 @@ function globToRegExp(glob) {
202
202
  const char = source[index];
203
203
  if (char === '*' && source[index + 1] === '*') {
204
204
  if (source[index + 2] === '/') {
205
- pattern += '(?:.*/)?';
205
+ pattern += '(?:[\\s\\S]*/)?';
206
206
  index += 2;
207
207
  } else {
208
- pattern += '.*';
208
+ pattern += '[\\s\\S]*';
209
209
  index++;
210
210
  }
211
211
  } else if (char === '*') {
@@ -1839,6 +1839,24 @@ function readWorkspaceConfigSources(root, explicitConfigPath, fallbackConfig) {
1839
1839
  return sources.length ? sources : [fallbackConfig];
1840
1840
  }
1841
1841
 
1842
+ function configSourceInventory(root, explicitConfigPath) {
1843
+ const sources = [];
1844
+ let complete = true;
1845
+ for (const relativePath of [...configPathsForWorkspace(root, explicitConfigPath)].sort(compareText)) {
1846
+ const file = path.join(root, ...relativePath.split('/'));
1847
+ try {
1848
+ const stat = fs.lstatSync(file);
1849
+ if (!stat.isFile()) { sources.push({ path: relativePath, presence: 'unsupported' }); complete = false; continue; }
1850
+ const bytes = fs.readFileSync(file);
1851
+ sources.push({ path: relativePath, presence: 'present', digest: crypto.createHash('sha256').update(bytes).digest('hex') });
1852
+ } catch (error) {
1853
+ if (error.code === 'ENOENT' || error.code === 'ENOTDIR') sources.push({ path: relativePath, presence: 'missing' });
1854
+ else { sources.push({ path: relativePath, presence: 'unreadable' }); complete = false; }
1855
+ }
1856
+ }
1857
+ return { complete, sources };
1858
+ }
1859
+
1842
1860
  function readGitBaseInventory(root, baseRef, config, explicitConfigPath = null) {
1843
1861
  if (!root || typeof baseRef !== 'string' || !baseRef.trim()) return { available: false, inventory: [], files: [] };
1844
1862
  try {
@@ -2602,6 +2620,27 @@ function buildIndex(docs, config, options = {}) {
2602
2620
  return `${lines.join('\n').replace(/\n+$/, '')}\n`;
2603
2621
  }
2604
2622
 
2623
+ function buildIndexSnapshot(workspace, configPath, config, configBytes, options = {}) {
2624
+ const root = path.resolve(workspace);
2625
+ const corpus = { complete: false, skipped: [], paths: [], digests: {} };
2626
+ const docs = collectDocs(root, config, corpus);
2627
+ const relativeConfig = path.relative(root, configPath);
2628
+ corpus.config = relativeConfig && relativeConfig !== '..' && !relativeConfig.startsWith(`..${path.sep}`)
2629
+ ? { path: relativeConfig.split(path.sep).join('/'), digest: crypto.createHash('sha256').update(configBytes).digest('hex') }
2630
+ : null;
2631
+ const configSources = readWorkspaceConfigSources(root, configPath, config);
2632
+ const configInventory = configSourceInventory(root, configPath);
2633
+ const mode = { all: true, workspace: root, base: options.base, configPath, configSources };
2634
+ const analysis = analyzeDocs(docs, config, mode);
2635
+ const bytes = Buffer.from(buildIndex(docs, config, {
2636
+ ...mode,
2637
+ diagnostics: analysis.diagnostics,
2638
+ _graph: analysis._graph,
2639
+ _retirementEligibleSources: analysis._retirementEligibleSources
2640
+ }), 'utf8');
2641
+ return { bytes, corpus, configSources, configInventory };
2642
+ }
2643
+
2605
2644
  function parseCli(argv) {
2606
2645
  const [command, ...rest] = argv;
2607
2646
  const options = { command, changedProvided: false, changedPaths: [], proposedUntracked: [], all: false };
@@ -2709,6 +2748,15 @@ function main(argv = process.argv.slice(2)) {
2709
2748
  process.stderr.write(`${error.message}\n`);
2710
2749
  return 2;
2711
2750
  }
2751
+ if (options.command === 'index' && options.all) {
2752
+ try {
2753
+ process.stdout.write(buildIndexSnapshot(workspacePath, configPath, config, configBytes, options).bytes);
2754
+ return 0;
2755
+ } catch (error) {
2756
+ process.stderr.write(`index generation failed: ${error.message}\n`);
2757
+ return 2;
2758
+ }
2759
+ }
2712
2760
  const corpus = options.all ? { complete: false, skipped: [], paths: [], digests: {} } : null;
2713
2761
  const docs = collectDocs(workspacePath, config, corpus);
2714
2762
  if (corpus) {
@@ -2737,6 +2785,6 @@ function main(argv = process.argv.slice(2)) {
2737
2785
  return analysis.diagnostics.some(item => item.severity === 'error') ? 1 : 0;
2738
2786
  }
2739
2787
 
2740
- module.exports = { readGitBaseInventory, scanWorkspaceFiles, parseFrontmatter, parseRequirementBlocks, collectDocs, documentCorpusPaths, analyzeDocs, resolveRef, lintDocs, buildIndex, diffRevisions, buildGitDocumentInventory };
2788
+ module.exports = { readGitBaseInventory, scanWorkspaceFiles, parseFrontmatter, parseRequirementBlocks, collectDocs, documentCorpusPaths, analyzeDocs, resolveRef, lintDocs, buildIndex, buildIndexSnapshot, configSourceInventory, diffRevisions, buildGitDocumentInventory };
2741
2789
 
2742
2790
  if (require.main === module) process.exitCode = main();
@@ -70,10 +70,10 @@ function globToRegExp(glob) {
70
70
  const char = source[index];
71
71
  if (char === '*' && source[index + 1] === '*') {
72
72
  if (source[index + 2] === '/') {
73
- pattern += '(?:.*/)?';
73
+ pattern += '(?:[\\s\\S]*/)?';
74
74
  index += 2;
75
75
  } else {
76
- pattern += '.*';
76
+ pattern += '[\\s\\S]*';
77
77
  index++;
78
78
  }
79
79
  } else if (char === '*') {
@@ -50,8 +50,8 @@ function globToRegExp(glob) {
50
50
  for (let index = 0; index < source.length; index++) {
51
51
  const char = source[index];
52
52
  if (char === '*' && source[index + 1] === '*') {
53
- if (source[index + 2] === '/') { pattern += '(?:.*/)?'; index += 2; }
54
- else { pattern += '.*'; index += 1; }
53
+ if (source[index + 2] === '/') { pattern += '(?:[\\s\\S]*/)?'; index += 2; }
54
+ else { pattern += '[\\s\\S]*'; index += 1; }
55
55
  } else if (char === '*') pattern += '[^/]*';
56
56
  else pattern += char.replace(/[|\\{}()[\]^$+?.]/g, '\\$&');
57
57
  }
@@ -226,6 +226,28 @@ function acceptDocEvents(input = {}, dependencies = {}) {
226
226
  if (!configSource || configSource.presence !== 'present'
227
227
  || U.sha(U.bytes(configSource.bytes)) !== binding?.config?.digest) reject('config-capture-mismatch');
228
228
  }
229
+ if (event?.capability === 'derived-regenerate') {
230
+ const binding = event.derivedBinding;
231
+ const corpus = binding?.sourceCorpus;
232
+ const expectedPaths = U.runtimeModule('doc-lifecycle.js').documentCorpusPaths(
233
+ snapshot.candidate.records, snapshot.config.resolution.config
234
+ );
235
+ if (!U.record(binding) || binding.view !== paths[0] || !U.record(corpus) || corpus.complete !== true
236
+ || !Array.isArray(corpus.paths) || U.stable(corpus.paths) !== U.stable(expectedPaths)
237
+ || !U.record(corpus.digests) || U.stable(Object.keys(corpus.digests).sort()) !== U.stable(expectedPaths)
238
+ || !expectedPaths.every(p => artifacts[p] && corpus.digests[p] === artifacts[p].digest)) reject('corpus-mismatch');
239
+ if (binding?.baselineDigest !== snapshot.identity.baselineDigest
240
+ || binding?.candidateDigest !== snapshot.identity.candidateDigest
241
+ || binding?.configIdentityDigest !== snapshot.identity.configDigest) reject('snapshot-changed');
242
+ const configSource = snapshot.config.capture.sources.find(source => source.path === binding?.config?.path);
243
+ if (!configSource || configSource.presence !== 'present'
244
+ || U.sha(U.bytes(configSource.bytes)) !== binding?.config?.digest) reject('config-capture-mismatch');
245
+ const generated = binding?.generation?.outputDigest;
246
+ const target = binding?.comparison?.targetDigest;
247
+ if (binding?.generation?.state !== 'pass' || binding?.comparison?.state !== 'equal'
248
+ || !U.text(generated) || generated !== target || !artifacts[binding.view]
249
+ || artifacts[binding.view].digest !== target) reject('derived-binding-mismatch');
250
+ }
229
251
  if (event?.kind === 'review') {
230
252
  if (event.verdict !== 'approve' || !U.text(event.summary)) reject('event-invalid');
231
253
  const principals = context?.principals;
@@ -0,0 +1,24 @@
1
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","effort":{"level":"medium"},"tool_name":"Bash","tool_input":{"command":"cat /sanitized/run8/stage1.txt"},"tool_use_id":"<tool-use-1>","event":"PreToolUse"}
2
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","effort":{"level":"medium"},"tool_name":"Bash","tool_input":{"command":"cat /sanitized/run8/stage1.txt"},"tool_response":{"stdout":"STAGE1 READY\nOutline file: /sanitized/run8/project/docs/adr/VERI-001.md\nInventory file: /sanitized/run8/state/workspaces/project-c3344fec53f4/state/sessions/<session-1>/doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md\nReviewer must end its reply with exactly these four lines:\nReview verdict: approve\nReviewed artifact: docs/adr/VERI-001.md sha256:7e03847cc8ceae735bfb76d85f4fcdf09ea0cd6e84299405ee44733e4917b6b8\nReviewed artifact: doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md sha256:2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6\nSummary: Approved inventory row 16 for docs/adr/VERI-001.md in domain VERI.","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"tool_use_id":"<tool-use-1>","duration_ms":415,"event":"PostToolUse"}
3
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","effort":{"level":"medium"},"tool_name":"Agent","tool_input":{"description":"Review outline","prompt":"STAGE1 READY\nOutline file: /sanitized/run8/project/docs/adr/VERI-001.md\nInventory file: /sanitized/run8/state/workspaces/project-c3344fec53f4/state/sessions/<session-1>/doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md\nReviewer must end its reply with exactly these four lines:\nReview verdict: approve\nReviewed artifact: docs/adr/VERI-001.md sha256:7e03847cc8ceae735bfb76d85f4fcdf09ea0cd6e84299405ee44733e4917b6b8\nReviewed artifact: doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md sha256:2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6\nSummary: Approved inventory row 16 for docs/adr/VERI-001.md in domain VERI.\n\nReview the outline against the inventory row","subagent_type":"outline-reviewer","run_in_background":false},"tool_use_id":"<tool-use-2>","event":"PreToolUse"}
4
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","agent_id":"<agent-1>","agent_type":"outline-reviewer","event":"SubagentStart"}
5
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-1>","agent_type":"outline-reviewer","effort":{"level":"medium"},"tool_name":"Read","tool_input":{"file_path":"/sanitized/run8/project/docs/adr/VERI-001.md"},"tool_use_id":"<tool-use-3>","event":"PreToolUse"}
6
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-1>","agent_type":"outline-reviewer","effort":{"level":"medium"},"tool_name":"Read","tool_input":{"file_path":"/sanitized/run8/project/docs/adr/VERI-001.md"},"tool_response":{"type":"text","file":{"filePath":"/sanitized/run8/project/docs/adr/VERI-001.md","content":"---\nid: VERI-001\nstatus: proposed\n---\n\nInventory row: 16\nTarget: docs/adr/VERI-001.md\nDomain: VERI\n\n## Outline\n- Context: verification is recorded as observed, timed evidence (verify-gate).\n- Decision: TBD\n","numLines":13,"startLine":1,"totalLines":13}},"tool_use_id":"<tool-use-3>","duration_ms":2,"event":"PostToolUse"}
7
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-1>","agent_type":"outline-reviewer","effort":{"level":"medium"},"tool_name":"Read","tool_input":{"file_path":"/sanitized/run8/state/workspaces/project-c3344fec53f4/state/sessions/<session-1>/doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md"},"tool_use_id":"<tool-use-4>","event":"PreToolUse"}
8
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-1>","agent_type":"outline-reviewer","effort":{"level":"medium"},"tool_name":"Read","tool_input":{"file_path":"/sanitized/run8/state/workspaces/project-c3344fec53f4/state/sessions/<session-1>/doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md"},"tool_response":{"type":"text","file":{"filePath":"/sanitized/run8/state/workspaces/project-c3344fec53f4/state/sessions/<session-1>/doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md","content":"# Report INV — existing-mechanism inventory for retroactive ADRs\n\nrun id `e1-inv-1` · packet rev 1 · input SHA `0ef0541c6cae550e8269ba712e03797e0e987dfb` (verified: `git rev-parse HEAD` — **executed**).\nFacts only, no decisions. Issue states: **executed** via read-only `gh issue view N --json state` (57 numbers queried 2026-10-27). File/test/issue-number mapping: **source-traced** (grep of `ci/`, `docs/*.md`, `git log --oneline --all --grep`, code citations). ADR shape: **source-traced** (code citations, no execution). Status flags: my classification of those facts.\n\n## 1. ADR shape — the exact minimum file this repo's checker accepts\n\nChecker: `harness-everything/scripts/doc-lifecycle.js` (run via `doc-check.js`; config from `project-docs-resolver.js`). `describes:` is **not** recognized by `doc-lifecycle.js` (absent — grep, **source-traced**).\n\n| Rule | Value | Citation |\n| --- | --- | --- |\n| ID regex | `/^([A-Z][A-Z0-9]{1,9})-(\\d{3,})$/` — domain 2–10 uppercase alnum chars, number ≥ 3 digits | doc-lifecycle.js:20 |\n| ID required | `missing-id` when `id` absent/empty | doc-lifecycle.js:1075–1076 |\n| ID malformed | `invalid-id` when regex fails | doc-lifecycle.js:1077 |\n| Domain declared | `unknown-domain` unless domain ∈ `config.domains` (set from config, doc-lifecycle.js:1035; never hardcoded) | doc-lifecycle.js:1078 |\n| Status required | `missing-status` / `invalid-status` vs `ROLE_STATUSES.adr` | doc-lifecycle.js:1070–1073 |\n| ADR status vocabulary | exactly `proposed` / `accepted` / `rejected` / `superseded` | doc-lifecycle.js:14 |\n| Frontmatter `role` | optional; if present must equal path role (`role-mismatch`) | doc-lifecycle.js:1063–1064 |\n| Frontmatter fields recognized | `id`, `role`, `status`, `aliases`, `supersedes`, `conflicts_with` (+ PRD-only fields); leading `---` YAML subset, no tabs | doc-lifecycle.js:119–147, 1082–1092, 1210–1221, 1315–1321 |\n| `aliases[]` | strings matching ID pattern; no `legacy:` prefix, not self (`invalid-alias`); collisions → `alias-collision` | doc-lifecycle.js:1082–1092, 1159+ |\n| `supersedes` | list of resolvable refs; effective edge requires target `status: superseded`; self/cycle → `supersede-cycle` | doc-lifecycle.js:1210–1221, 1259–1268 |\n| `conflicts_with` | refs must resolve or stay `recorded-conflict` until an effective `supersedes` | doc-lifecycle.js:1315–1321 |\n| Location | **config-driven, not hardcoded**: file must match a `governed` glob entry carrying `role: \"adr\"` (collection doc-lifecycle.js:295–300; `roleAtPath` 2147–2152; no `docs/adr` hardcode in the checker). Resolver infers `docs/adr`/`docs/decisions` only when *generating* config | project-docs-resolver.js:578,599 |\n| Ratchet | schema checks apply to governed files named in `changedPaths`; full mode only with `--all` | docs/document-lifecycle.md:132 |\n\nMinimum accepted new ADR (given a config that declares the domain and an ADR glob):\n\n```markdown\n---\nid: ROUTE-001\nstatus: accepted\n---\n\n# ROUTE-001 — <title>\n\n## Decision\n<text>\n```\n\nThat is the whole required shape: `id` + `status` (+ declared domain). `Decision`-section presence matters only for D6.5 normative-trigger classification, not lint. Pending/edge extras: optional `role`, `aliases`, `supersedes` (with target `superseded`), `conflicts_with`.\n\n## 2. Mechanism inventory\n\nPath abbreviations: **H/** `hooks/scripts/`, **R/** `harness-everything/scripts/`, **C/** `ci/`. States: `M`=merged PR, `C`=closed, `O`=open. All issue states **executed**; attributions **source-traced**.\n\n| # | Mechanism | Decision it embodies | Implementing file(s) | Tests (grep C/) | Issues (state) | Flag |\n| --- | --- | --- | --- | --- | --- | --- |\n| 01 | Kernel routing | Route before execute: tier/strategy/invariants before mutation | R/kernel-router.js, R/tier-router.js, R/router-contract.js, R/routing-keywords.json | C/invariant-routing, C/router-workflow-plan, C/router-phase2-safety, C/prompt-contract-regressions, C/skill-routing-check | #142 (M), #217 (C) | CONSISTENT |\n| 02 | Step-scoped binding resolution | Disclose only active-step knowledge; unknown stays visible | R/kernel-router.js, H/lib/binding-resolver.js, R/kernel-router-core.js | C/mechanism-2ar-binding-resolution, C/invariant-routing | #297 (C) | CONSISTENT |\n| 03 | Workflow lifecycle evidence | Objective evidence before completion; explicit dispositions | H/workflow-stop-gate.js, H/workflow-disposition.js, H/lib/workflow-obligations.js, H/lib/fable-contracts.js | C/mechanism-2an, C/mechanism-2ah, C/mechanism-2as, C/mechanism-2az, C/workflow-execution-contract | #143 (M), #242 (C) | CONSISTENT |\n| 04 | Worktree/Fable isolation | Isolate broad mutation before it starts | H/lib/workflow-isolation.js, R/kernel-router.js | C/mechanism-2af, C/mechanism-2ai, C/mechanism-34-worktree-submodule-reachability | #150,#152,#154,#156,#158 (all M) | CONSISTENT |\n| 05 | Harness Status protocol | One user-visible status block for non-trivial work (semantic, no lock) | skill text (routing docs); no dedicated runtime file | C/reference-check only (no mechanism test) | NO-ISSUE found | NO-TEST |\n| 06 | Action gate | Explicit approval for destructive/external side effects (hard block) | H/action-gate.js, H/action-gate-rules.json, H/codex-action-gate-pre.js, H/codex-action-gate-post.js, H/codex-permission-request.js | C/action-gate, C/mechanism-2ad, C/mechanism-2aa, C/mechanism-2au, C/action-gate-platform-doc | #144 (M); live approval matrix #100 (C) | CONSISTENT |\n| 07 | Rule-of-3 / zoom-out | Stop after 3 same-signature failures; hard boundary | H/rule-of-3.js, H/rule-of-3-tracker.js, H/reset-circuit-breaker.js | C/mechanism-2a-rule-of-3, C/self-evolve-loop | #201 (C) | CONSISTENT |\n| 08 | Stop gate | No completion without observed successful verification | H/stop-gate.js | C/mechanism-2f-stop-gate | #190 (C) | CONSISTENT |\n| 09 | Advisory guard trio | Warn about broad searches, blind overwrites, context pressure (fail-open) | H/boundary-guard.js, H/depth-guard.js, H/context-compact.js | C/mechanism-2b (boundary only); depth/context **no test** | #190 (C) | NO-TEST (2 of 3) |\n| 10 | State persistence / WAL | Persist tool outcomes, mutations, verification milestones | H/state-persist.js, H/lib/harness-state.js | C/mechanism-2c, C/mechanism-2ah, C/telemetry | #160 (M), #147 (M) | CONSISTENT |\n| 11 | Subagent scope guard + contract test | Snapshot/diff around subagent bursts; inter-agent contract testing | H/subagent-scope-guard.js, H/contract-test.js | C/mechanism-2e, C/workflow-plan-consumers, C/workflow-plan-consumers-edge | NO-ISSUE found | NO-ISSUE |\n| 12 | Memory capability token | One-time workflow-bound capability for memory writes | R/kernel-router.js (`issueMemoryCapability`) | **no function-level test** (adjacent: C/phase4-ensemble-memory) | #145 (M) | NO-TEST |\n| 13 | Ensemble policy | MAY-level multi-agent composition under high uncertainty | R/ensemble-policy.js | C/phase4-ensemble-memory | NO-ISSUE found | NO-ISSUE |\n| 14 | Bootstrap / self-repo guard / self-heal | Session bootstrap, env detection, environment repair | R/bootstrap.js, R/self-heal.js, R/runtime-paths.js | C/mechanism-2m-self-repo-guard, C/mechanism-2an-environment-detection-readonly | NO-ISSUE found | NO-ISSUE |\n| 15 | Contract-integrity audit | Prove artifact↔spec traceability | contract-integrity/scripts/audit.js | C/contract-integrity.test | #84 (C), #58 (C) | CONSISTENT |\n| 16 | Verify gate | Treat verification as observed, timed evidence | R/verify-gate.js | C/mechanism-35-verification-contract, C/mechanism-36-verify-timeout | #242 (C) | CONSISTENT |\n| 17 | verify:all aggregate gate | One CI-ordered gate list with PASS/FAIL/UNCHECKED report | scripts/verify-all.js | C/mechanism-38-verify-all (self-regression subset) | NO-ISSUE found | CONSISTENT (see Open Q1) |\n| 18 | Paired behavioral / benchmark evidence | No \"improved\" claim without paired baseline-vs-treatment evidence | behavioral-evals/run.js, benchmarks/run.js, C/ab-test-harness.js | C/mechanism-2j, C/mechanism-32, C/mechanism-335, C/mechanism-2v | #71 (**O**), #130 (M), #242 (C) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 19 | Doc config resolution (D5) | Committed host-neutral config wholly overrides host manifests; AGENTS.md never config | R/project-docs-resolver.js, R/doc-check.js | C/mechanism-2aw, C/reference-check | #325 (**O**) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 20 | ADR/REQ identity + supersession + index (D6.1–D6.4) | Domain-scoped IDs, aliases, legacy refs, generated index | R/doc-lifecycle.js | C/mechanism-2ax, C/reference-check | #325 (**O**) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 21 | PRD revision contract (D6.9) | Effective PRD = frozen revision chain with approval record | R/doc-lifecycle.js | C/mechanism-2ay | #325 (**O**) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 22 | `doc-change` step type | Explicit doc-edit step type, no implicit TDD binding | H/lib/step-types.json, H/lib/workflow-obligations.js | C/mechanism-2az-step-type-registry | #326 (C), #328 (M) | CONSISTENT |\n| 23 | Doc obligations + evidence producer (3a) | Fail-closed doc MUSTs with trusted-producer identity binding | R/doc-obligations.js, R/doc-evidence.js, R/doc-evidence-capture.js | C/mechanism-325-3a-doc-obligations, C/mechanism-325-3a-doc-evidence, C/mechanism-335-baseline-evidence | #334 (M), #335 (C, fixed by #342 — executed state for #342 not queried, result merged) | CONSISTENT |\n| 24 | Reconciliation pilot S1/F4 | Default-OFF opt-in gate; limited credit for `doc-lint`/`link-check` only | H/lib/doc-reconciliation-*.js, H/codex-user-prompt.js (switch) | C/mechanism-325-3b-preparation, C/mechanism-325-3b-s1-review, C/mechanism-341-opencode-lane | #341 (**O**), #350 (**O**), #358 (M), #375 (M: E1 zero qualifying cycles) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 25 | Shared doc craft + derived views (F2/F3) | Regenerate-equals for authorized generators; shared references | R/doc-obligations.js, harness-everything/references/documentation/_shared/ | C/mechanism-325-f3-derived-views, C/reference-check | #356 (M), #357 (M) | CONSISTENT |\n| 26 | #320 obligation abstraction (bounded consumer) | Doc workflow reconciliation consumes workflow abstractions; broad promotion gated | H/lib/doc-reconciliation-core.js + R/doc-obligations.js | same as #24 tests | #320 (**O**) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 27 | System One observation capture | Local, content-private turn observation; fail-open, silent | H/observation-hook.js, hooks/scripts/lib/telemetry.js | C/mechanism-34-observations, C/mechanism-2am-observations-session-import | #233 (**O**) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 28 | System One engine (tier-4 experimental) | Learned intent routing + resident/eval pipeline | scripts/system-one-*.js/py, R/system-one/ (install) | C/mechanism-system-one-*.test.js suite; ci.yml Windows S1 lanes | #233 (**O**) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 29 | S1 intent/suggestion/noise gates | Weak-intent gating with Laya teacher; `rule_v2` noise gate | docs-system-one-* scripts (corpus/evaluate/label) | C/mechanism-system-one-evaluation, C/system-one-*.py | #255 (**O**), #265 (**O**), #297 (C) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 30 | Skill telemetry | Privacy-safe skill load start/close telemetry window | H/telemetry-adapter.js, H/lib/telemetry.js, telemetry/scripts/ | C/telemetry.test | #147 (M), #37 (C), #122 top-level blocker (**O**) | CONSISTENT |\n| 31 | OpenCode plugin | Project-scope `.js` loading + edit/verify state on OpenCode 1.18.31 (macOS, retained evidence only) | opencode-plugin/ | C/mechanism-2n, C/mechanism-30-loadability, C/mechanism-31-hardlock-evidence, C/mechanism-2p, C/mechanism-39, C/mechanism-341-opencode-lane | #128 (M), #129 (M), #82 (**O**) | **ISSUE-OPEN-BUT-SHIPPED** (live claim bounded) |\n| 32 | Codex plugin hooks compat | Codex hook adapters/package-level parity with Claude hooks | H/lib/platforms/codex.js, scripts/codex-hooks-compat.js | C/mechanism-2al, C/mechanism-2au, C/mechanism-2ao | #110 (**O**), #122 (**O**), #135 (C), #98 (M), #109 (C) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 33 | Platform adapter matrix | Per-host capability/evidence claims centralized and claimed as tested contract | H/lib/platforms/ (claude/codex/cursor/copilot/continue/hermes), docs/platform-capabilities.md | C/mechanism-2w-platform-compatibility, C/mechanism-2t-platform-skill-targets, C/mechanism-2g-platform-ignore | #82 (**O**), #123 (M), #127 (C), #135 (C) | **ISSUE-OPEN-BUT-SHIPPED** |\n| 34 | Plugin packaging (Claude + OpenAI + submission) | Generated distribution manifests are facts, byte-consistent copies | scripts/stage-claude-plugin.js, scripts/validate-claude-plugin.js, scripts/sync-openai-plugin.js, scripts/build-openai-submission.js, .claude-plugin/ | C/mechanism-2z, C/openai-plugin-package, C/openai-plugin-submission, C/openai-plugin-runtime, C/mechanism-packaging-bytecode | #123 (M), #128 (M), #129 (M) | CONSISTENT |\n| 35 | Release automation | semantic-release owns SemVer; nested versions synced; skip-CI version bumps | scripts/sync-release-version.js, .github/workflows/release.yml, scripts/generate-sbom.js | C/mechanism-2x (×2), C/mechanism-2y, C/mechanism-2ap-sbom, C/mechanism-2u-issue-44, C/semantic-release-analyzer | #20 (C) | CONSISTENT |\n| 36 | Manifest sync across hosts | All distribution manifests generated from canonical skills | scripts/plugin-sync.js (.sh/.ps1), scripts/repository-contract.js | C/mechanism-2ao, C/mechanism-2ab, C/repository-contract.test | #123 (M) | CONSISTENT |\n| 37 | Installer | Interactive/non-interactive install, verify, uninstall, shared store | scripts/installer.js, bin/cli.js | C/installer-roundtrip, C/mechanism-2h, C/mechanism-2i (×2), C/mechanism-2p-installer-links, C/mechanism-2q, C/mechanism-2r | NO-ISSUE found | NO-ISSUE |\n| 38 | Skill routing evals / collision gate | Every routed skill has a trigger eval; descriptions must not collide | evals/<skill>/eval.yaml, C/description-collision.js, C/skill-routing-check.js | (these files are the gates) | NO-ISSUE found | CONSISTENT (see Open Q1) |\n| 39 | Commit discipline | Conventional commits enforced locally via husky+commitlint | commitlint.config.js, .husky/ | C/mechanism-33-issues-205-207, C/mechanism-2x-release-commit-message | #205 (C), #207 (C) | CONSISTENT |\n\nCounts: 39 rows · CONSISTENT 21 · ISSUE-OPEN-BUT-SHIPPED 11 · NO-ISSUE 5 · NO-TEST 2 (02 rows flagged NO-TEST cover 3 sub-mechanisms).\n\n## 3. Area grouping + candidate domain prefixes\n\nFormats follow `^[A-Z][A-Z0-9]{1,9}$` (checked against doc-lifecycle.js:20 ADR_ID domain form). No domains are declared today (`.agents/harness-everything/project-docs.json` governs two `reference` files only, no `domains` key) — so every candidate is new, and adopting any requires editing `project-docs.json`, which under #325 D6.8 is the project's own declared list (Harness never hard-codes it).\n\n| Area | Rows | Candidate prefix | Why |\n| --- | --- | --- | --- |\n| Routing & workflow contract | 01–05 | `ROUTE` | Kernel routing / topology / bindings are one decision family |\n| Enforcement & safety boundaries | 06–15 | `ENFC` | Approval, breaker, stop evidence, persistence — the hook-path contract |\n| Verification & evidence | 16–18, 15 | `VERI` | Shared \"objective evidence before claiming done\" decision |\n| Document lifecycle (#325) | 19–26 | `DOCS` | Already contract-scoped to #325; natural domain |\n| System One (experimental) | 27–29 | `SONE` | Clearly-labeled tier-4 experimental family |\n| Platform, packaging, release | 30–39 | `DIST` | Distribution/platform claims and tooling |\n\nZero-commit numbers (#71, #84, #109, #110, #122, #127, #135, #217, #350 — doc-referenced only in this clone) are kept **with state flags** rather than dropped, so a future ADR citing them shows they lack commit-message anchors in this SHA's history.\n\n**Single-domain alternative:** one prefix `HARN` for every retroactive ADR (Harness-wide decisions), splitting later via `supersedes`/aliases once areas stabilize. Cheaper to ship (one `domains` entry, no per-area risk of overlap collisions); loses the ability to grep decisions by area from the ID alone.\n\n## 4. Mismatch list (non-CONSISTENT rows) — the \"功能與 issues 狀態\" findings\n\n1. **depth-guard.js, context-compact.js — NO-TEST.** Shipped on the hook path (`hooks/hooks.json:99–115`) under closed issue #190, but their basenames appear nowhere in `ci/` outside `archive/`. Candidate: ISSUE-CLOSED-BUT-MISSING *test coverage*, not mechanism.\n2. **memory capability token (kernel-router.js#issueMemoryCapability) — NO-TEST** despite merged #145. Function itself untested; only adjacent ensemble-memory policy tests exist.\n3. **Harness Status protocol (row 05) — NO-TEST.** Mandated in AGENTS.md #11 and docs/routing.md; no mechanism test exists (it is semantic, not enforced — #11 itself says \"Not a hard lock\").\n4. **#71 OPEN vs shipped policy.** architecture.md and the validation boundary require paired behavioral evidence for lifecycle-effectiveness claims — the requirement is live and unmet while the machinery (rows 18, 24) ships around it: the classic \"shipped, gate pending\" split. #375 (merged) reports E1 with zero qualifying cycles.\n5. **#341/#350 OPEN vs shipped default-OFF pilot.** S1 + F4 shipped as opt-in (`HARNESS_DOC_RECONCILIATION_PILOT=1`) with fail-closed withholding; expansion explicitly not approved (E1 gate). Consistent-with-docs but issue-open → flagged.\n6. **#82/#110/#122 OPEN: live-host verification umbrella.** platform-capabilities claims are held to mechanism-package evidence; live-host firing is still open for Codex (#110, #122 mount/attribution blocker) and the #82 compatibility program. All OpenCode/Codex live rows inherit this.\n7. **#233/#255/#265 OPEN vs shipped System One.** Experimental engine, gates and Windows CI lanes are live in `ci.yml` while their governing experiment issues are open — intentional (labeled experimental) but must be reflected, not hidden, in the ADR set.\n8. **#325 OPEN vs merged doc-lifecycle slices.** The owner-decision umbrella (#325) stays open by design; all shipped phases (#327/#334/#356/#357/#358, …) flag ISSUE-OPEN-BUT-SHIPPED. Not a defect — a structural fact for the retroactive ADRs' status choices.\n9. **#201 as Rule-of-3 anchor (row 07) is the only issue found** — \"advisory re-trip contract (#201)\" from this clone's log. Earlier origin of the mechanism may be unreferenced; treating #201 as governing is an inference (label: source-traced, weak).\n\n## 5. Open questions\n\n1. **Q1 — CI routing-gate coverage (inconclusive):** `package.json` exposes `test:routing:skills`/`test:routing:invariants` and `scripts/verify-all.js` runs them, but `.github/workflows/ci.yml` jobs do not invoke them by name (consistency job runs `test:consistency`, `test:references`, `test:release`, `test:collision`, `test:plugin:openai`, `test:plugin:submission`, `test:platform:compatibility`, `test:portability`; self-regression job runs `npm test` + `test:mutations`). Whether `npm test` self-regression reaches the routing tests was not traced end to end — rows 01 and 38 keep CONSISTENT subject to Q1.\n2. **Q2 — ADR scope boundary:** does \"已經存在的機制\" (existing mechanisms) cover semantic/instruction-only contracts (rows 05, plus skill-text obligations), or only runtime code with hooks/tests? Recommendation-shaped, not a fact: mechanism code first.\n3. **Q3 — domain assignment ownership:** adopting `ROUTE/ENFC/…` (or `HARN`) requires a `project-docs.json` `domains` edit + ADR glob + `project-overrides-host` warning reconciliation under D5; owner decides under #325.\n4. **Q4 — #342 executed state:** #335's own state was queried (closed, executed) but the first fix PR #342's state was not queried in the batch (its merge is source-traced from docs only).\n5. **Q5 — alias stability:** issues with zero commit-message matches in this clone (71, 84, 109, 110, 122, 127, 135, 217, 350) may exist in other branches/clone histories; anchor-richness is lower than for #233/#325.\n\n<!-- harness-label {\"judgement\":\"facts-only inventory report per packet; no repo writes\",\"risk\":\"none\"} -->\nSTATUS: DONE\n","numLines":129,"startLine":1,"totalLines":129}},"tool_use_id":"<tool-use-4>","duration_ms":1,"event":"PostToolUse"}
9
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-1>","agent_type":"outline-reviewer","effort":{"level":"medium"},"stop_hook_active":false,"agent_transcript_path":"/sanitized/run8/agent-transcripts/transcript-1.jsonl","last_assistant_message":"The outline passes all four checks against the inventory.\n\n- **Inventory row:** The outline cites \"Inventory row: 16\". Row 16 in the inventory is \"Verify gate\", \"Treat verification as observed, timed evidence\", implemented in `R/verify-gate.js`. The outline's context line matches it.\n- **Target path:** `docs/adr/VERI-001.md` is the file reviewed. Its frontmatter `id: VERI-001` fits the checker's ID pattern, and `status: proposed` is an allowed ADR status.\n- **Domain:** The outline says \"Domain: VERI\". Section 3 of the inventory assigns rows 16–18 and 15 to the candidate prefix `VERI`.\n- **Decision:** The line reads \"Decision: TBD\", so there is no substantive Decision yet.\n\nI did not compute the SHA-256 hashes. The two `Reviewed artifact` lines below use the values you gave me unchanged.\n\nFiles reviewed:\n- `/sanitized/run8/project/docs/adr/VERI-001.md`\n- `/sanitized/run8/state/workspaces/project-c3344fec53f4/state/sessions/<session-1>/doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md`\n\nReview verdict: approve\nReviewed artifact: docs/adr/VERI-001.md sha256:7e03847cc8ceae735bfb76d85f4fcdf09ea0cd6e84299405ee44733e4917b6b8\nReviewed artifact: doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md sha256:2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6\nSummary: Approved inventory row 16 for docs/adr/VERI-001.md in domain VERI.","background_tasks":[],"session_crons":[],"event":"SubagentStop"}
10
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","effort":{"level":"medium"},"tool_name":"Agent","tool_input":{"description":"Review outline","prompt":"STAGE1 READY\nOutline file: /sanitized/run8/project/docs/adr/VERI-001.md\nInventory file: /sanitized/run8/state/workspaces/project-c3344fec53f4/state/sessions/<session-1>/doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md\nReviewer must end its reply with exactly these four lines:\nReview verdict: approve\nReviewed artifact: docs/adr/VERI-001.md sha256:7e03847cc8ceae735bfb76d85f4fcdf09ea0cd6e84299405ee44733e4917b6b8\nReviewed artifact: doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md sha256:2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6\nSummary: Approved inventory row 16 for docs/adr/VERI-001.md in domain VERI.\n\nReview the outline against the inventory row","subagent_type":"outline-reviewer","run_in_background":false},"tool_response":{"status":"completed","prompt":"STAGE1 READY\nOutline file: /sanitized/run8/project/docs/adr/VERI-001.md\nInventory file: /sanitized/run8/state/workspaces/project-c3344fec53f4/state/sessions/<session-1>/doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md\nReviewer must end its reply with exactly these four lines:\nReview verdict: approve\nReviewed artifact: docs/adr/VERI-001.md sha256:7e03847cc8ceae735bfb76d85f4fcdf09ea0cd6e84299405ee44733e4917b6b8\nReviewed artifact: doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md sha256:2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6\nSummary: Approved inventory row 16 for docs/adr/VERI-001.md in domain VERI.\n\nReview the outline against the inventory row","agentId":"<agent-1>","agentType":"outline-reviewer","toolsUsed":["Read"],"harnessNoteCount":1,"harnessTailCount":0,"harnessSectionHash":"510238c68f070d12","content":[{"type":"text","text":"<tools-used-before-summary>Read</tools-used-before-summary>\n"},{"type":"text","text":"The outline passes all four checks against the inventory.\n\n- **Inventory row:** The outline cites \"Inventory row: 16\". Row 16 in the inventory is \"Verify gate\", \"Treat verification as observed, timed evidence\", implemented in `R/verify-gate.js`. The outline's context line matches it.\n- **Target path:** `docs/adr/VERI-001.md` is the file reviewed. Its frontmatter `id: VERI-001` fits the checker's ID pattern, and `status: proposed` is an allowed ADR status.\n- **Domain:** The outline says \"Domain: VERI\". Section 3 of the inventory assigns rows 16–18 and 15 to the candidate prefix `VERI`.\n- **Decision:** The line reads \"Decision: TBD\", so there is no substantive Decision yet.\n\nI did not compute the SHA-256 hashes. The two `Reviewed artifact` lines below use the values you gave me unchanged.\n\nFiles reviewed:\n- `/sanitized/run8/project/docs/adr/VERI-001.md`\n- `/sanitized/run8/state/workspaces/project-c3344fec53f4/state/sessions/<session-1>/doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md`\n\nReview verdict: approve\nReviewed artifact: docs/adr/VERI-001.md sha256:7e03847cc8ceae735bfb76d85f4fcdf09ea0cd6e84299405ee44733e4917b6b8\nReviewed artifact: doc-reconciliation/outline-confirmation/inventory/2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6.md sha256:2741bd4514d2cd68f57d93a2b3ce94cbe597ca62d30e26f0ca58e882df5b03c6\nSummary: Approved inventory row 16 for docs/adr/VERI-001.md in domain VERI."}],"resolvedModel":"claude-sonnet-5-5","totalDurationMs":12002,"totalTokens":14638,"totalToolUseCount":2,"usage":{"output_tokens_details":{"thinking_tokens":85},"input_tokens":2,"cache_creation_input_tokens":10723,"cache_read_input_tokens":2956,"output_tokens":957,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":10723},"inference_geo":"global","iterations":[{"input_tokens":2,"output_tokens":957,"cache_read_input_tokens":2956,"cache_creation_input_tokens":10723,"cache_creation":{"ephemeral_5m_input_tokens":10723,"ephemeral_1h_input_tokens":0},"type":"message"}],"speed":"standard","fallback_credit":null},"toolStats":{"readCount":2,"searchCount":0,"bashCount":0,"editFileCount":0,"linesAdded":0,"linesRemoved":0,"otherToolCount":0},"canContinueAgent":true},"tool_use_id":"<tool-use-2>","duration_ms":12003,"event":"PostToolUse"}
11
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","effort":{"level":"medium"},"tool_name":"Bash","tool_input":{"command":"cat /sanitized/run8/stage2.txt"},"tool_use_id":"<tool-use-5>","event":"PreToolUse"}
12
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","effort":{"level":"medium"},"tool_name":"Bash","tool_input":{"command":"cat /sanitized/run8/stage2.txt"},"tool_response":{"stdout":"STAGE2 READY\nWorker prompt (first line verbatim):\nHARNESS_OUTLINE_DISPATCH_V1 taskId=task-veri16+verify attemptId=attempt-1 token=sanitized-dispatch-token-1 workerRoot=/sanitized/run8/project","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"tool_use_id":"<tool-use-5>","duration_ms":12,"event":"PostToolUse"}
13
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","effort":{"level":"medium"},"tool_name":"Agent","tool_input":{"description":"Draft ADR","prompt":"HARNESS_OUTLINE_DISPATCH_V1 taskId=task-veri16+verify attemptId=attempt-1 token=sanitized-dispatch-token-1 workerRoot=/sanitized/run8/project\nDraft the ADR as instructed.","subagent_type":"outline-drafter","run_in_background":false},"tool_use_id":"<tool-use-6>","event":"PreToolUse"}
14
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","agent_id":"<agent-2>","agent_type":"outline-drafter","event":"SubagentStart"}
15
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-2>","agent_type":"outline-drafter","effort":{"level":"medium"},"tool_name":"Read","tool_input":{"file_path":"/sanitized/run8/project/docs/adr/VERI-001.md"},"tool_use_id":"<tool-use-7>","event":"PreToolUse"}
16
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-2>","agent_type":"outline-drafter","effort":{"level":"medium"},"tool_name":"Read","tool_input":{"file_path":"/sanitized/run8/project/docs/adr/VERI-001.md"},"tool_response":{"type":"text","file":{"filePath":"/sanitized/run8/project/docs/adr/VERI-001.md","content":"---\nid: VERI-001\nstatus: proposed\n---\n\nInventory row: 16\nTarget: docs/adr/VERI-001.md\nDomain: VERI\n\n## Outline\n- Context: verification is recorded as observed, timed evidence (verify-gate).\n- Decision: TBD\n","numLines":13,"startLine":1,"totalLines":13}},"tool_use_id":"<tool-use-7>","duration_ms":1,"event":"PostToolUse"}
17
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-2>","agent_type":"outline-drafter","effort":{"level":"medium"},"tool_name":"Write","tool_input":{"file_path":"/sanitized/run8/project/docs/adr/VERI-001.md","content":"---\nid: VERI-001\nstatus: proposed\n---\n\nInventory row: 16\nTarget: docs/adr/VERI-001.md\nDomain: VERI\n\n## Context\nWithout a shared standard, claims that work is verified can rest on anything from a test run to a quick read of the code.\n\n## Decision\nVerification is accepted only as observed, timed command evidence, meaning a command that was actually run with its output and duration recorded. Claims made from reading code are not verification.\n"},"tool_use_id":"<tool-use-8>","event":"PreToolUse"}
18
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-2>","agent_type":"outline-drafter","effort":{"level":"medium"},"tool_name":"Write","tool_input":{"file_path":"/sanitized/run8/project/docs/adr/VERI-001.md","content":"---\nid: VERI-001\nstatus: proposed\n---\n\nInventory row: 16\nTarget: docs/adr/VERI-001.md\nDomain: VERI\n\n## Context\nWithout a shared standard, claims that work is verified can rest on anything from a test run to a quick read of the code.\n\n## Decision\nVerification is accepted only as observed, timed command evidence, meaning a command that was actually run with its output and duration recorded. Claims made from reading code are not verification.\n"},"tool_response":{"type":"update","filePath":"/sanitized/run8/project/docs/adr/VERI-001.md","content":"---\nid: VERI-001\nstatus: proposed\n---\n\nInventory row: 16\nTarget: docs/adr/VERI-001.md\nDomain: VERI\n\n## Context\nWithout a shared standard, claims that work is verified can rest on anything from a test run to a quick read of the code.\n\n## Decision\nVerification is accepted only as observed, timed command evidence, meaning a command that was actually run with its output and duration recorded. Claims made from reading code are not verification.\n","structuredPatch":[{"oldStart":7,"oldLines":6,"newStart":7,"newLines":8,"lines":[" Target: docs/adr/VERI-001.md"," Domain: VERI"," ","-## Outline","-- Context: verification is recorded as observed, timed evidence (verify-gate).","-- Decision: TBD","+## Context","+Without a shared standard, claims that work is verified can rest on anything from a test run to a quick read of the code.","+","+## Decision","+Verification is accepted only as observed, timed command evidence, meaning a command that was actually run with its output and duration recorded. Claims made from reading code are not verification."]}],"originalFile":"---\nid: VERI-001\nstatus: proposed\n---\n\nInventory row: 16\nTarget: docs/adr/VERI-001.md\nDomain: VERI\n\n## Outline\n- Context: verification is recorded as observed, timed evidence (verify-gate).\n- Decision: TBD\n","userModified":false},"tool_use_id":"<tool-use-8>","duration_ms":2,"event":"PostToolUse"}
19
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-2>","agent_type":"outline-drafter","effort":{"level":"medium"},"tool_name":"Bash","tool_input":{"command":"git add docs/adr/VERI-001.md"},"tool_use_id":"<tool-use-9>","event":"PreToolUse"}
20
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-2>","agent_type":"outline-drafter","effort":{"level":"medium"},"tool_name":"Bash","tool_input":{"command":"git add docs/adr/VERI-001.md"},"tool_response":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"tool_use_id":"<tool-use-9>","duration_ms":15,"event":"PostToolUse"}
21
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-2>","agent_type":"outline-drafter","effort":{"level":"medium"},"tool_name":"Bash","tool_input":{"command":"git commit -q -m \"D: draft VERI-001\""},"tool_use_id":"<tool-use-10>","event":"PreToolUse"}
22
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-2>","agent_type":"outline-drafter","effort":{"level":"medium"},"tool_name":"Bash","tool_input":{"command":"git commit -q -m \"D: draft VERI-001\""},"tool_response":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"tool_use_id":"<tool-use-10>","duration_ms":23,"event":"PostToolUse"}
23
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","agent_id":"<agent-2>","agent_type":"outline-drafter","effort":{"level":"medium"},"stop_hook_active":false,"agent_transcript_path":"/sanitized/run8/agent-transcripts/transcript-2.jsonl","last_assistant_message":"worker done.","background_tasks":[],"session_crons":[],"event":"SubagentStop"}
24
+ {"session_id":"<session-1>","cwd":"/sanitized/run8/project","prompt_id":"<prompt-1>","permission_mode":"default","effort":{"level":"medium"},"tool_name":"Agent","tool_input":{"description":"Draft ADR","prompt":"HARNESS_OUTLINE_DISPATCH_V1 taskId=task-veri16+verify attemptId=attempt-1 token=sanitized-dispatch-token-1 workerRoot=/sanitized/run8/project\nDraft the ADR as instructed.","subagent_type":"outline-drafter","run_in_background":false},"tool_response":{"status":"completed","prompt":"HARNESS_OUTLINE_DISPATCH_V1 taskId=task-veri16+verify attemptId=attempt-1 token=sanitized-dispatch-token-1 workerRoot=/sanitized/run8/project\nDraft the ADR as instructed.","agentId":"<agent-2>","agentType":"outline-drafter","toolsUsed":["Bash","Read","Write"],"harnessNoteCount":1,"harnessTailCount":0,"harnessSectionHash":"f724eae3efefe206","content":[{"type":"text","text":"<tools-used-before-summary>Write</tools-used-before-summary>\n"},{"type":"text","text":"worker done."}],"resolvedModel":"claude-sonnet-5-5","totalDurationMs":16376,"totalTokens":6343,"totalToolUseCount":4,"usage":{"output_tokens_details":{"thinking_tokens":0},"input_tokens":2,"cache_creation_input_tokens":79,"cache_read_input_tokens":6256,"output_tokens":6,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":79},"inference_geo":"global","iterations":[{"input_tokens":2,"output_tokens":6,"cache_read_input_tokens":6256,"cache_creation_input_tokens":79,"cache_creation":{"ephemeral_5m_input_tokens":79,"ephemeral_1h_input_tokens":0},"type":"message"}],"speed":"standard","fallback_credit":null},"toolStats":{"readCount":1,"searchCount":0,"bashCount":2,"editFileCount":1,"linesAdded":15,"linesRemoved":0,"otherToolCount":0},"canContinueAgent":true},"tool_use_id":"<tool-use-6>","duration_ms":16376,"event":"PostToolUse"}
@@ -346,7 +346,7 @@ function captureReferences(context) {
346
346
  const taskId = context.workflow.docReconciliationTask?.taskId;
347
347
  const outlineReviews = outlineReviewCaptureRefs(context.sessionDir, taskId);
348
348
  const reviews = captures.filter(item => item && typeof item.ref === 'string' && item.event === 'SubagentStop'
349
- && !outlineReviews.has(item.ref));
349
+ && ['approve', 'reject'].includes(item.reviewVerdict) && !outlineReviews.has(item.ref));
350
350
  const references = [];
351
351
  for (const [index, capability] of ['doc-lint', 'link-check'].entries()) {
352
352
  const ordered = index ? candidates.slice(1).concat(candidates.slice(0, 1)) : candidates;
@@ -355,6 +355,8 @@ function captureReferences(context) {
355
355
  const provider = require('./doc-reconciliation-provider');
356
356
  references.push(...candidates.filter(item => provider.resolveDocCheckInvocation(item.command, item.cwd).conflictAssessment === true)
357
357
  .map(item => `${item.ref}#conflict-check`));
358
+ references.push(...candidates.filter(item => provider.resolveDocCheckInvocation(item.command, item.cwd).derivedView)
359
+ .map(item => `${item.ref}#derived-regenerate`));
358
360
  references.push(...outlineDispatchReferences(captures, taskId, context.sessionDir));
359
361
  // The adapter accepts one event per capability; rotating candidate order lets separate valid runs fill each capability.
360
362
  return [...references, ...reviews.map(item => `${item.ref}#quality-review`)];