@event4u/agent-config 9.30.0 → 9.31.0

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 (62) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +31 -314
  3. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  4. package/dist/cli-delegate/{chunk-IYTGIG2Y.js → chunk-2WCLVDWC.js} +1 -1
  5. package/dist/cli-delegate/{chunk-66OVWGB5.js → chunk-AG47LAGQ.js} +1 -1
  6. package/dist/cli-delegate/{chunk-MP3JT3IU.js → chunk-DS6BLDMG.js} +1 -1
  7. package/dist/cli-delegate/{chunk-O3CO5BFB.js → chunk-EJITJBJX.js} +12 -1
  8. package/dist/cli-delegate/{chunk-EQY4FLJB.js → chunk-ITIQSGOQ.js} +3 -3
  9. package/dist/cli-delegate/{chunk-LCFJIQ4J.js → chunk-JEJABGKB.js} +110 -6
  10. package/dist/cli-delegate/{chunk-BTJNRUX3.js → chunk-QEEB4LHO.js} +1 -1
  11. package/dist/cli-delegate/{chunk-DDUNNFYX.js → chunk-UVKNIJH2.js} +2 -2
  12. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  13. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  14. package/dist/cli-delegate/cmd_conformance.js +98 -36
  15. package/dist/cli-delegate/cmd_doctor.js +3 -3
  16. package/dist/cli-delegate/cmd_explain.js +2 -2
  17. package/dist/cli-delegate/cmd_export.js +4 -4
  18. package/dist/cli-delegate/cmd_handoff.js +2 -2
  19. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  20. package/dist/cli-delegate/cmd_migrate.js +2 -2
  21. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  22. package/dist/cli-delegate/cmd_prune.js +4 -4
  23. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  24. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  25. package/dist/cli-delegate/cmd_session_recycle.js +2 -2
  26. package/dist/cli-delegate/cmd_settings_get.js +2 -55
  27. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  28. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  29. package/dist/cli-delegate/cmd_sync.js +4 -4
  30. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  31. package/dist/cli-delegate/cmd_update.js +1 -1
  32. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  33. package/dist/cli-delegate/cmd_validate.js +4 -4
  34. package/dist/cli-delegate/cmd_versions.js +1 -1
  35. package/dist/discovery/deprecation-report.md +1 -1
  36. package/dist/discovery/discovery-manifest.json +1 -1
  37. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  38. package/dist/discovery/discovery-manifest.summary.md +1 -1
  39. package/dist/discovery/orphan-report.md +1 -1
  40. package/dist/discovery/packs.json +1 -1
  41. package/dist/discovery/trust-report.md +1 -1
  42. package/dist/discovery/workspaces.json +1 -1
  43. package/dist/hooks/dispatch.js +347 -174
  44. package/dist/install/install.mjs +121 -16
  45. package/dist/mcp/registry-manifest.json +1 -1
  46. package/dist/mcp/server.json +2 -2
  47. package/dist/mcp/server.mjs +310 -138
  48. package/dist/scripts/_lib/agent_settings.js +111 -2
  49. package/dist/scripts/_lib/agent_settings.js.map +1 -1
  50. package/dist/server/schemas/settings.js +2 -2
  51. package/dist/server/schemas/settings.js.map +1 -1
  52. package/package.json +1 -1
  53. package/src/config/pack-size-budget.json +3 -2
  54. package/src/scripts/_cli/explain_last/inputs.ts +13 -0
  55. package/src/scripts/_lib/agent_settings.ts +119 -2
  56. package/src/scripts/_lib/carrier_divergence.ts +47 -0
  57. package/src/scripts/hooks/turn_end_gate_hook.ts +296 -88
  58. package/src/scripts/language_mirror_hook.ts +69 -16
  59. package/src/scripts/measure_turn_end_gate.ts +129 -51
  60. package/src/scripts/report_carrier_divergence.ts +72 -24
  61. package/src/scripts/report_conformance_funnel.ts +11 -4
  62. package/src/server/schemas/settings.ts +2 -2
@@ -4,11 +4,67 @@ import {
4
4
  write_target
5
5
  } from "./chunk-NDJLNC6Q.js";
6
6
 
7
+ // src/shared/settingsCarveOut.ts
8
+ var SETTINGS_CARVE_OUT = [
9
+ {
10
+ key: "projection.mode",
11
+ reader: "src/scripts/install.ts:3409 _resolve_scoped_projection",
12
+ absentResolvesTo: "legacy-all",
13
+ reason: "The template fallback applies only when NO global settings file exists. Once a file exists, an absent key means legacy-all by documented contract, so an existing install is never silently narrowed on upgrade."
14
+ },
15
+ {
16
+ key: "projection.rule_workspaces",
17
+ reader: "src/install/rule_scope.ts:96 ruleScopeFromSettings",
18
+ absentResolvesTo: "null \u2014 LEGACY_ALL, i.e. every rule ships including maintainer-only ones",
19
+ reason: "Same upgrade contract as projection.mode, and the failure is louder: an absent list widens the projection instead of narrowing it."
20
+ },
21
+ {
22
+ key: "discipline_profile",
23
+ reader: "work_engine/_lib/agent_settings.ts:1263",
24
+ absentResolvesTo: "essential, unconditionally",
25
+ reason: "The template ships `auto`, which resolves to `off` on any measured-null model, any non-Claude host, and any host exposing no model id. Absent skips that resolution entirely and loads the essential tier everywhere."
26
+ },
27
+ {
28
+ key: "chat_history.frequency",
29
+ reader: "src/scripts/chat_history.ts:1140",
30
+ absentResolvesTo: "per_phase",
31
+ reason: "Canonical substitution is `per_turn`. Absent gives coarser capture than the shipped default \u2014 an audit-thinning change, which the class contract's own test 8 (what can the attacker HIDE) names as the severe direction."
32
+ },
33
+ {
34
+ key: "profile.id",
35
+ reader: "src/scripts/config/profiles.ts:221 resolve_profile",
36
+ absentResolvesTo: "the id `developer`, but a DEGRADED profile \u2014 packs: [], personas: [], hints: []",
37
+ reason: "Exactly the projection.mode shape: the template default is honoured only when no settings file exists. With a file present the id resolves but its profile body does not load, so the install silently loses every pack and persona."
38
+ },
39
+ {
40
+ key: "quality.local_auto_run",
41
+ reader: "src/scripts/lint_roadmap_ci_steps.ts:106",
42
+ absentResolvesTo: "true \u2014 which DISABLES the CI-step gate",
43
+ reason: "Inverted polarity, and the most dangerous row in the set: the template ships `false`, which ARMS the gate. Omitting the key would disarm a quality gate for every fresh install while the reference page says it is on."
44
+ },
45
+ {
46
+ key: "onboarding.onboarded",
47
+ reader: "src/scripts/onboarding_gate_hook.ts:99",
48
+ absentResolvesTo: "gate skipped, as if onboarding had already completed",
49
+ reason: "Absent behaves like `onboarded: true`, not like the template default `false`. Omitting it would skip the onboarding gate on precisely the fresh installs the gate exists for."
50
+ },
51
+ {
52
+ key: "chat_history.enabled",
53
+ reader: "src/scripts/chat_history.ts:1025 _read_chat_history_enabled",
54
+ absentResolvesTo: "false",
55
+ reason: "The reader falls back to false while the template ships true. This one is privacy-shaped: fixing the reader would start recording history for every install whose file lacks the key. Writing it explicitly keeps the decision visible in the file the user can read."
56
+ }
57
+ ];
58
+ function carveOutKeys() {
59
+ return SETTINGS_CARVE_OUT.map((c) => c.key);
60
+ }
61
+
7
62
  // src/scripts/_lib/agent_settings.ts
8
63
  import { createRequire } from "node:module";
9
64
  import * as fs from "node:fs";
10
65
  import * as os from "node:os";
11
66
  import * as path from "node:path";
67
+ import { fileURLToPath } from "node:url";
12
68
  var _require = createRequire(import.meta.url);
13
69
  var Logger = class {
14
70
  name = "scripts._lib.agent_settings";
@@ -117,7 +173,45 @@ var MERGEABLE_KEYS = [
117
173
  "knowledge.global_sharing.freshness.hypothesis_after_days",
118
174
  "knowledge.global_sharing.freshness.stale_after_days"
119
175
  ];
120
- var _DEFAULTS = {};
176
+ var TEMPLATE_RELATIVE = path.join("src", "config", "agent-settings.template.yml");
177
+ var _PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
178
+ function default_template_path() {
179
+ return path.join(_PACKAGE_ROOT, TEMPLATE_RELATIVE);
180
+ }
181
+ function _is_placeholder(value) {
182
+ return typeof value === "string" && /^__[A-Z0-9_]+__$/.test(value);
183
+ }
184
+ function _prune_template(tree, excluded, prefix = "") {
185
+ const out = {};
186
+ for (const [key, value] of Object.entries(tree)) {
187
+ const dotted = prefix === "" ? key : `${prefix}.${key}`;
188
+ if (excluded.has(dotted) || _is_placeholder(value)) {
189
+ continue;
190
+ }
191
+ if (_is_plain_dict(value)) {
192
+ const child = _prune_template(value, excluded, dotted);
193
+ if (Object.keys(child).length > 0) {
194
+ out[key] = child;
195
+ }
196
+ continue;
197
+ }
198
+ out[key] = value;
199
+ }
200
+ return out;
201
+ }
202
+ var _template_defaults_cache = null;
203
+ function template_defaults(template_path) {
204
+ const use_cache = template_path === void 0;
205
+ if (use_cache && _template_defaults_cache !== null) {
206
+ return _deepcopy(_template_defaults_cache);
207
+ }
208
+ const parsed = _read_yaml(template_path ?? default_template_path()) ?? {};
209
+ const pruned = _prune_template(parsed, new Set(carveOutKeys()));
210
+ if (use_cache) {
211
+ _template_defaults_cache = pruned;
212
+ }
213
+ return _deepcopy(pruned);
214
+ }
121
215
  var ANCHOR_AGENT_SETTINGS = "agent-settings";
122
216
  var ANCHOR_AGENTS_DIR = "agents-dir";
123
217
  var ANCHOR_GIT = "git";
@@ -386,6 +480,7 @@ function load_agent_settings(options = {}) {
386
480
  const user_global_path = options.user_global_path ?? null;
387
481
  const verbose = options.verbose ?? false;
388
482
  const cwd = options.cwd ?? null;
483
+ const template_path = options.template_path ?? null;
389
484
  const user_global_raw = {};
390
485
  for (const p of user_global_path ? [user_global_path] : user_global_settings_paths()) {
391
486
  _deep_merge(user_global_raw, _read_yaml(p) ?? {});
@@ -398,7 +493,7 @@ function load_agent_settings(options = {}) {
398
493
  );
399
494
  }
400
495
  const cascade = _resolve_cascade_paths(cwd, project_path);
401
- const merged = _deep_copy_defaults(_DEFAULTS);
496
+ const merged = template_defaults(template_path ?? void 0);
402
497
  _deep_merge(merged, user_global_filtered);
403
498
  for (const p of cascade) {
404
499
  const layer = _read_yaml(p) ?? {};
@@ -555,16 +650,25 @@ function _deep_merge(dst, src) {
555
650
  }
556
651
  }
557
652
  }
558
- function _deep_copy_defaults(src) {
559
- const out = {};
560
- _deep_merge(out, src);
561
- return out;
653
+ function _deepcopy(value) {
654
+ if (Array.isArray(value)) {
655
+ return value.map((v) => _deepcopy(v));
656
+ }
657
+ if (_is_plain_dict(value)) {
658
+ const out = {};
659
+ for (const [k, v] of Object.entries(value)) {
660
+ out[k] = _deepcopy(v);
661
+ }
662
+ return out;
663
+ }
664
+ return value;
562
665
  }
563
666
  function _is_plain_dict(value) {
564
667
  return typeof value === "object" && value !== null && !Array.isArray(value);
565
668
  }
566
669
 
567
670
  export {
671
+ SETTINGS_CARVE_OUT,
568
672
  logger,
569
673
  DEFAULT_PROJECT_FILE,
570
674
  LOCAL_PROJECT_FILE,
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-MMJL4TIX.js";
5
5
  import {
6
6
  load_agent_settings
7
- } from "./chunk-LCFJIQ4J.js";
7
+ } from "./chunk-JEJABGKB.js";
8
8
 
9
9
  // src/scripts/chat_history.ts
10
10
  import { createHash } from "node:crypto";
@@ -4549,10 +4549,10 @@ var settingsSchema = external_exports.object({
4549
4549
  "Stop-slot turn-end gate (road-to-conformance-round5 Phase 3). Default off, and it is the only concern that can REFUSE a turn-end rather than a tool call \u2014 so it soaks behind an explicit opt-in before it binds. Round 5 measured the reason: both blocking carriers reached zero violations, neither advisory carrier did, and 19 wrong-language replies survived a pin that had fired 26-35 seconds earlier. A refused turn continues in the SAME turn and is never refused twice."
4550
4550
  ),
4551
4551
  promissory: external_exports.boolean().default(true).describe(
4552
- "Detector A of the turn-end gate: refuse a turn whose closing paragraph promises work not yet performed while asking the user nothing (20 measured occurrences). Inert while hooks.turn_end_gate.enabled is false."
4552
+ "Detector A of the turn-end gate: refuse a turn whose closing paragraph promises work not yet performed while asking the user nothing (20 measured occurrences). No fire rate is quoted here on purpose: the measured rate moved twice while the instrument itself was being corrected, so a number in a shipped description would be a moving target. Re-derive it with `measure-turn-end-gate --store <transcript dir>` against your own corpus before arming the gate. Inert while hooks.turn_end_gate.enabled is false."
4553
4553
  ),
4554
4554
  language: external_exports.boolean().default(true).describe(
4555
- "Detector B of the turn-end gate: refuse a turn whose user-visible prose is not in the pinned language, with fenced code, inline code, quoted tool output, tables, URLs, paths and identifiers excluded first (19 measured occurrences). Fires 18.0% of turns on the measured corpus, which is why the master switch is off by default. Inert while hooks.turn_end_gate.enabled is false."
4555
+ "Detector B of the turn-end gate: refuse a turn whose reply is not in the pinned language (19 measured occurrences). Fenced code, inline code, quoted tool output, tables, URLs and paths are stripped first, and the remainder is then scored LEAD-FIRST by the same classifier that sets the pin \u2014 so the verdict usually comes from the reply opening, not from all of it. Sharing that classifier is deliberate: it stops the pin and the detector disagreeing about a turn. Accepted opt-in spellings for the switches below include YAML true/false and yes/no/on/off. Inert while hooks.turn_end_gate.enabled is false."
4556
4556
  )
4557
4557
  }).default({})
4558
4558
  }),
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  ProjectRootError,
9
9
  resolve_project_root
10
- } from "./chunk-LCFJIQ4J.js";
10
+ } from "./chunk-JEJABGKB.js";
11
11
  import "./chunk-NDJLNC6Q.js";
12
12
  import "./chunk-J55WI3RR.js";
13
13
 
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
2
  import {
3
3
  resolve_project_root
4
- } from "./chunk-LCFJIQ4J.js";
4
+ } from "./chunk-JEJABGKB.js";
5
5
  import "./chunk-NDJLNC6Q.js";
6
6
  import "./chunk-J55WI3RR.js";
7
7
 
@@ -14,11 +14,13 @@ import {
14
14
  _run_checks,
15
15
  _run_checks_no_manifest,
16
16
  _scan_foreign
17
- } from "./chunk-IYTGIG2Y.js";
17
+ } from "./chunk-2WCLVDWC.js";
18
18
  import "./chunk-FTAISGDQ.js";
19
19
  import {
20
- atomic_write_json
21
- } from "./chunk-O3CO5BFB.js";
20
+ atomic_write_json,
21
+ atomic_write_text,
22
+ is_replay_mode
23
+ } from "./chunk-EJITJBJX.js";
22
24
  import "./chunk-LVRYBKTI.js";
23
25
  import "./chunk-736JCWLM.js";
24
26
  import {
@@ -28,7 +30,7 @@ import {
28
30
  } from "./chunk-63WSP6YZ.js";
29
31
  import "./chunk-GRRPEPRN.js";
30
32
  import "./chunk-NXFWFAYV.js";
31
- import "./chunk-LCFJIQ4J.js";
33
+ import "./chunk-JEJABGKB.js";
32
34
  import "./chunk-NDJLNC6Q.js";
33
35
  import {
34
36
  detectToolPresence
@@ -140,6 +142,16 @@ function comparePair(a, b) {
140
142
  }
141
143
  return "body-diff";
142
144
  }
145
+ function stripFrontmatter(text) {
146
+ if (!text.startsWith("---")) return text;
147
+ const end = text.indexOf("\n---", 3);
148
+ if (end === -1) return text;
149
+ const afterFence = text.indexOf("\n", end + 1);
150
+ return afterFence === -1 ? "" : text.slice(afterFence + 1);
151
+ }
152
+ function proseEqual(a, b) {
153
+ return stripFrontmatter(a).trim() === stripFrontmatter(b).trim();
154
+ }
143
155
  function censusRuleDir(dir) {
144
156
  let files = 0;
145
157
  let chars = 0;
@@ -223,7 +235,11 @@ function humanAuthoredLead(text) {
223
235
  var EXIT_ALLOW = 0;
224
236
  var EXIT_WARN = 2;
225
237
  var STATE_FILE = path2.join("agents", "state", "language-mirror.json");
226
- var PIN_LOST_MARKER = path2.join("agents", "state", "language-mirror.pin-lost");
238
+ var PIN_LOST_DIR = path2.join("agents", "state", "language-mirror.pin-lost");
239
+ function pinLostMarker(session_id) {
240
+ const safe = (session_id || "unknown-session").replace(/[^A-Za-z0-9._-]/g, "_");
241
+ return path2.join(PIN_LOST_DIR, `${safe}.marker`);
242
+ }
227
243
  function _isObject2(v) {
228
244
  return typeof v === "object" && v !== null && !Array.isArray(v);
229
245
  }
@@ -362,35 +378,49 @@ function _extractPrompt(payload) {
362
378
  }
363
379
  return "";
364
380
  }
365
- function _setPinLost(consumer_root) {
381
+ function _sessionId(envelope) {
382
+ const v = envelope["session_id"];
383
+ return typeof v === "string" && v.trim() !== "" ? v : "unknown-session";
384
+ }
385
+ function _migrateLegacyMarker(consumer_root) {
386
+ const legacy = path2.join(consumer_root, PIN_LOST_DIR);
366
387
  try {
367
- const target = path2.join(consumer_root, PIN_LOST_MARKER);
368
- fs2.mkdirSync(path2.dirname(target), { recursive: true });
369
- fs2.writeFileSync(target, (/* @__PURE__ */ new Date()).toISOString());
388
+ if (fs2.statSync(legacy).isFile()) {
389
+ fs2.rmSync(legacy, { force: true });
390
+ }
370
391
  } catch {
371
392
  }
372
393
  }
373
- function _pinLost(consumer_root) {
394
+ function _setPinLost(consumer_root, session_id) {
395
+ if (is_replay_mode()) return;
396
+ _migrateLegacyMarker(consumer_root);
374
397
  try {
375
- return fs2.existsSync(path2.join(consumer_root, PIN_LOST_MARKER));
398
+ atomic_write_text(path2.join(consumer_root, pinLostMarker(session_id)), (/* @__PURE__ */ new Date()).toISOString());
399
+ } catch {
400
+ }
401
+ }
402
+ function _pinLost(consumer_root, session_id) {
403
+ try {
404
+ return fs2.existsSync(path2.join(consumer_root, pinLostMarker(session_id)));
376
405
  } catch {
377
406
  return false;
378
407
  }
379
408
  }
380
- function _clearPinLost(consumer_root) {
409
+ function _clearPinLost(consumer_root, session_id) {
410
+ if (is_replay_mode()) return;
381
411
  try {
382
- fs2.rmSync(path2.join(consumer_root, PIN_LOST_MARKER), { force: true });
412
+ fs2.rmSync(path2.join(consumer_root, pinLostMarker(session_id)), { force: true });
383
413
  } catch {
384
414
  }
385
415
  }
386
- function _reEmitAfterCompaction(consumer_root) {
387
- if (!_pinLost(consumer_root)) {
416
+ function _reEmitAfterCompaction(consumer_root, session_id) {
417
+ if (!_pinLost(consumer_root, session_id)) {
388
418
  return EXIT_ALLOW;
389
419
  }
390
420
  const previous = _loadState(path2.join(consumer_root, STATE_FILE));
391
421
  const language = previous.language;
392
422
  const source = previous.source === "system-locale" ? "system-locale" : "prompt";
393
- _clearPinLost(consumer_root);
423
+ _clearPinLost(consumer_root, session_id);
394
424
  if (language !== "de" && language !== "en") {
395
425
  return EXIT_ALLOW;
396
426
  }
@@ -419,11 +449,11 @@ function run(stdin_text, options) {
419
449
  const payload = _isObject2(envelope["payload"]) ? envelope["payload"] : envelope;
420
450
  const event = typeof envelope["event"] === "string" ? envelope["event"] : "";
421
451
  if (event === "pre_compact") {
422
- _setPinLost(options.consumer_root);
452
+ _setPinLost(options.consumer_root, _sessionId(envelope));
423
453
  return EXIT_ALLOW;
424
454
  }
425
455
  if (event === "post_tool_use") {
426
- return _reEmitAfterCompaction(options.consumer_root);
456
+ return _reEmitAfterCompaction(options.consumer_root, _sessionId(envelope));
427
457
  }
428
458
  const prompt = _extractPrompt(payload);
429
459
  if (!prompt) {
@@ -1959,6 +1989,7 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
1959
1989
  shared: 0,
1960
1990
  identical: [],
1961
1991
  provenanceOnly: [],
1992
+ frontmatterOnly: [],
1962
1993
  bodyDiff: [],
1963
1994
  projectOnly: [],
1964
1995
  globalOnly: [],
@@ -1983,11 +2014,12 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
1983
2014
  }
1984
2015
  out.shared += 1;
1985
2016
  let verdict;
2017
+ let proseSame;
1986
2018
  try {
1987
- verdict = comparePair(
1988
- fs8.readFileSync(path8.join(projectDir, rule)),
1989
- fs8.readFileSync(path8.join(globalDir, rule))
1990
- );
2019
+ const projectCopy = fs8.readFileSync(path8.join(projectDir, rule));
2020
+ const globalCopy = fs8.readFileSync(path8.join(globalDir, rule));
2021
+ verdict = comparePair(projectCopy, globalCopy);
2022
+ proseSame = proseEqual(projectCopy.toString("utf-8"), globalCopy.toString("utf-8"));
1991
2023
  } catch {
1992
2024
  out.shared -= 1;
1993
2025
  out.unreadable.push(rule);
@@ -1995,6 +2027,7 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
1995
2027
  }
1996
2028
  if (verdict === "identical") out.identical.push(rule);
1997
2029
  else if (verdict === "provenance-only") out.provenanceOnly.push(rule);
2030
+ else if (proseSame) out.frontmatterOnly.push(rule);
1998
2031
  else out.bodyDiff.push(rule);
1999
2032
  }
2000
2033
  return out;
@@ -2023,7 +2056,8 @@ function render2(d) {
2023
2056
  lines.push(` shared rule names ${d.shared}`);
2024
2057
  lines.push(` byte-identical ${d.identical.length}`);
2025
2058
  lines.push(` differ ONLY in the install stamp ${d.provenanceOnly.length}`);
2026
- lines.push(` differ in BODY ${d.bodyDiff.length}`);
2059
+ lines.push(` differ ONLY in frontmatter ${d.frontmatterOnly.length}`);
2060
+ lines.push(` differ in PROSE ${d.bodyDiff.length}`);
2027
2061
  if (d.unreadable.length > 0) {
2028
2062
  lines.push(` unreadable on one side ${d.unreadable.length} (${d.unreadable.join(", ")})`);
2029
2063
  lines.push(" Not counted as shared and NOT a body difference \u2014 a dangling entry is");
@@ -2033,15 +2067,32 @@ function render2(d) {
2033
2067
  lines.push(` present at global scope only ${d.globalOnly.length}`);
2034
2068
  lines.push("");
2035
2069
  if (d.bodyDiff.length > 0) {
2036
- lines.push(" BODY DIVERGENCE \u2014 the two carriers deliver different text for these rules.");
2037
- lines.push(" Both copies reach the model, with no precedence marker between them, so a");
2038
- lines.push(" claim one copy retracts can be re-asserted by the other. PRECEDENCE: the");
2039
- lines.push(" project projection is generated from src/ at this commit and wins; the");
2040
- lines.push(" global install is a release snapshot. Close it by reinstalling the global");
2041
- lines.push(" copy, or by reading the project copy as authoritative.");
2070
+ lines.push(" PROSE DIVERGENCE \u2014 the two carriers deliver different governed text for");
2071
+ lines.push(" these rules. Both copies reach the model, and the host resolves NOTHING:");
2072
+ lines.push(" rules without a `paths` key load at launch with the same priority as");
2073
+ lines.push(" CLAUDE.md, with no precedence marker between the layers, so a claim one");
2074
+ lines.push(" copy retracts can be re-asserted by the other and which text binds is");
2075
+ lines.push(" UNDEFINED. Cited, not inferred \u2014 agents/evidence/analysis/");
2076
+ lines.push(" claude-code-rules-dir-contract.md (host 2.1.226, the host's own docs plus");
2077
+ lines.push(" a first-party observation). The project copy is the NEWER text, which is a");
2078
+ lines.push(" fact about recency and NOT a host precedence rule: close the divergence by");
2079
+ lines.push(" reinstalling the global copy, or decide which text binds \u2014 do not assume");
2080
+ lines.push(" the newer one already won.");
2042
2081
  for (const r of d.bodyDiff) lines.push(` - ${r}`);
2043
2082
  lines.push("");
2044
2083
  }
2084
+ if (d.frontmatterOnly.length > 0) {
2085
+ lines.push(` ${String(d.frontmatterOnly.length)} pair(s) differ ONLY in the frontmatter block \u2014 prose byte-identical.`);
2086
+ lines.push(" Not a governed-text difference and nothing to act on: the host delivers the");
2087
+ lines.push(" prose without that block, and none of the keys in it is one this host reads");
2088
+ lines.push(" (claude-code-rules-dir-contract.md: it reads `paths`, and agent-config's own");
2089
+ lines.push(" vocabulary is not read at all). Two writers, two frontmatter policies \u2014");
2090
+ lines.push(" `generate-tools` emits `paths` where a rule is path-scoped and nothing");
2091
+ lines.push(" otherwise; `install.ts` writes the full vocabulary plus its ownership stamp.");
2092
+ lines.push(" Reported as a count on purpose: naming every pair would bury the class");
2093
+ lines.push(" above, which is the one a reader must act on.");
2094
+ lines.push("");
2095
+ }
2045
2096
  if (d.provenanceOnly.length > 0) {
2046
2097
  lines.push(` ${String(d.provenanceOnly.length)} pair(s) differ only by the installer's package:/source_path: stamp.`);
2047
2098
  lines.push(" Not a content difference and NOT a defect: install.ts stamps every installed");
@@ -2077,9 +2128,14 @@ function render2(d) {
2077
2128
  }
2078
2129
  if (d.bodyDiff.length === 0) {
2079
2130
  lines.push("");
2080
- lines.push(" No body divergence. The condition is transient \u2014 it returns whenever the");
2081
- lines.push(" checkout moves ahead of the installed release \u2014 so this is a reading of");
2082
- lines.push(" right now, not a property of the repo. Re-run it, do not cite it.");
2131
+ lines.push(" No prose divergence \u2014 no rule's governed text differs between the carriers.");
2132
+ lines.push(" The condition is transient \u2014 it returns whenever the checkout moves ahead of");
2133
+ lines.push(" the installed release \u2014 so this is a reading of right now, not a property of");
2134
+ lines.push(" the repo. Re-run it, do not cite it. That holds doubly here: the reading also");
2135
+ lines.push(" depends on WHICH GENERATION of the emitter produced the project tree (a");
2136
+ lines.push(" frontmatter-carrying symlink tree and a frontmatter-less real-file tree");
2137
+ lines.push(" classify the same commit differently), so a number from another checkout is");
2138
+ lines.push(" not comparable to this one.");
2083
2139
  }
2084
2140
  return lines.join("\n");
2085
2141
  }
@@ -2680,12 +2736,18 @@ function render5(r) {
2680
2736
  lines.push(" substituted with dist/, which would answer a different question.");
2681
2737
  } else {
2682
2738
  lines.push(
2683
- ` Divergence: ${d.shared} shared \xB7 ${d.bodyDiff.length} body-diff \xB7 ${d.provenanceOnly.length} provenance-only \xB7 ${d.projectOnly.length} project-only \xB7 ${d.globalOnly.length} global-only` + (d.manualOnlyGlobal.length > 0 ? ` (${d.manualOnlyGlobal.length} by design, ADR-004 manual)` : "")
2739
+ ` Divergence: ${d.shared} shared \xB7 ${d.bodyDiff.length} prose-diff \xB7 ${d.frontmatterOnly.length} frontmatter-only \xB7 ${d.provenanceOnly.length} provenance-only \xB7 ${d.projectOnly.length} project-only \xB7 ${d.globalOnly.length} global-only` + (d.manualOnlyGlobal.length > 0 ? ` (${d.manualOnlyGlobal.length} by design, ADR-004 manual)` : "")
2684
2740
  );
2685
2741
  if (d.bodyDiff.length > 0) {
2686
- lines.push(` BODY DIVERGENCE \u2014 both copies reach the model: ${d.bodyDiff.join(", ")}`);
2687
- lines.push(" Precedence: the project projection is generated from src/ at this commit");
2688
- lines.push(" and wins; the global install is a release snapshot.");
2742
+ lines.push(` PROSE DIVERGENCE \u2014 both copies reach the model: ${d.bodyDiff.join(", ")}`);
2743
+ lines.push(" The host resolves nothing: both layers load at launch at the same");
2744
+ lines.push(" priority with no precedence marker, so which text binds is UNDEFINED");
2745
+ lines.push(" (claude-code-rules-dir-contract.md). The project copy is merely the");
2746
+ lines.push(" newer one \u2014 recency, not precedence.");
2747
+ }
2748
+ if (d.frontmatterOnly.length > 0) {
2749
+ lines.push(` ${String(d.frontmatterOnly.length)} pair(s) differ only in frontmatter \u2014 prose byte-identical, nothing`);
2750
+ lines.push(" to act on; the host delivers the prose without that block.");
2689
2751
  }
2690
2752
  if (d.unreadable.length > 0) {
2691
2753
  lines.push(` Unreadable on one side (${d.unreadable.length}) \u2014 a broken install, not a disagreement.`);
@@ -66,15 +66,15 @@ import {
66
66
  _wizard_state_path,
67
67
  main,
68
68
  shutilWhich
69
- } from "./chunk-IYTGIG2Y.js";
69
+ } from "./chunk-2WCLVDWC.js";
70
70
  import "./chunk-FTAISGDQ.js";
71
- import "./chunk-O3CO5BFB.js";
71
+ import "./chunk-EJITJBJX.js";
72
72
  import "./chunk-LVRYBKTI.js";
73
73
  import "./chunk-736JCWLM.js";
74
74
  import "./chunk-63WSP6YZ.js";
75
75
  import "./chunk-GRRPEPRN.js";
76
76
  import "./chunk-NXFWFAYV.js";
77
- import "./chunk-LCFJIQ4J.js";
77
+ import "./chunk-JEJABGKB.js";
78
78
  import "./chunk-NDJLNC6Q.js";
79
79
  import "./chunk-OY53J6II.js";
80
80
  import "./chunk-MCJYCQPF.js";
@@ -8,7 +8,7 @@ import {
8
8
  ProfileError,
9
9
  artefact_roots,
10
10
  resolve_profile
11
- } from "./chunk-66OVWGB5.js";
11
+ } from "./chunk-AG47LAGQ.js";
12
12
  import {
13
13
  StateLoadError,
14
14
  load_state
@@ -19,7 +19,7 @@ import {
19
19
  load_agent_settings,
20
20
  logger,
21
21
  resolve_project_root
22
- } from "./chunk-LCFJIQ4J.js";
22
+ } from "./chunk-JEJABGKB.js";
23
23
  import "./chunk-NDJLNC6Q.js";
24
24
  import {
25
25
  __export
@@ -9,14 +9,14 @@ import {
9
9
  KIRO_MARKER,
10
10
  ROOCODE_MARKER,
11
11
  ZED_MARKER
12
- } from "./chunk-EQY4FLJB.js";
13
- import "./chunk-DDUNNFYX.js";
14
- import "./chunk-MP3JT3IU.js";
12
+ } from "./chunk-ITIQSGOQ.js";
13
+ import "./chunk-UVKNIJH2.js";
14
+ import "./chunk-DS6BLDMG.js";
15
15
  import "./chunk-BKO2AZ7Z.js";
16
16
  import "./chunk-63WSP6YZ.js";
17
17
  import "./chunk-GRRPEPRN.js";
18
18
  import "./chunk-NXFWFAYV.js";
19
- import "./chunk-LCFJIQ4J.js";
19
+ import "./chunk-JEJABGKB.js";
20
20
  import "./chunk-NDJLNC6Q.js";
21
21
  import "./chunk-523HCFYO.js";
22
22
  import "./chunk-OY53J6II.js";
@@ -4,7 +4,7 @@ import {
4
4
  derive_session_tag,
5
5
  list_sessions,
6
6
  read_entries
7
- } from "./chunk-BTJNRUX3.js";
7
+ } from "./chunk-QEEB4LHO.js";
8
8
  import {
9
9
  RECYCLE_CONSUMED_REL,
10
10
  RECYCLE_ENVELOPE_REL,
@@ -19,7 +19,7 @@ import {
19
19
  _RAW_KEY_PREFIXES,
20
20
  hardenedSpawnEnv
21
21
  } from "./chunk-LVRYBKTI.js";
22
- import "./chunk-LCFJIQ4J.js";
22
+ import "./chunk-JEJABGKB.js";
23
23
  import "./chunk-NDJLNC6Q.js";
24
24
  import "./chunk-OY53J6II.js";
25
25
  import "./chunk-J55WI3RR.js";
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
2
  import {
3
3
  resolve_project_root
4
- } from "./chunk-LCFJIQ4J.js";
4
+ } from "./chunk-JEJABGKB.js";
5
5
  import "./chunk-NDJLNC6Q.js";
6
6
  import "./chunk-J55WI3RR.js";
7
7
 
@@ -1,8 +1,8 @@
1
1
  import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
2
  import {
3
3
  main
4
- } from "./chunk-MP3JT3IU.js";
5
- import "./chunk-LCFJIQ4J.js";
4
+ } from "./chunk-DS6BLDMG.js";
5
+ import "./chunk-JEJABGKB.js";
6
6
  import "./chunk-NDJLNC6Q.js";
7
7
  import "./chunk-MCJYCQPF.js";
8
8
  import "./chunk-J55WI3RR.js";
@@ -4,12 +4,12 @@ import {
4
4
  SOURCE_MISSING,
5
5
  profile_file,
6
6
  resolve_profile
7
- } from "./chunk-66OVWGB5.js";
7
+ } from "./chunk-AG47LAGQ.js";
8
8
  import {
9
9
  DEFAULT_PROJECT_FILE,
10
10
  load_agent_settings,
11
11
  resolve_project_root
12
- } from "./chunk-LCFJIQ4J.js";
12
+ } from "./chunk-JEJABGKB.js";
13
13
  import "./chunk-NDJLNC6Q.js";
14
14
  import "./chunk-J55WI3RR.js";
15
15
 
@@ -1,9 +1,9 @@
1
1
  import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
2
  import {
3
3
  PROJECT_BRIDGE_MARKERS
4
- } from "./chunk-EQY4FLJB.js";
5
- import "./chunk-DDUNNFYX.js";
6
- import "./chunk-MP3JT3IU.js";
4
+ } from "./chunk-ITIQSGOQ.js";
5
+ import "./chunk-UVKNIJH2.js";
6
+ import "./chunk-DS6BLDMG.js";
7
7
  import "./chunk-BKO2AZ7Z.js";
8
8
  import {
9
9
  manifest_path,
@@ -13,7 +13,7 @@ import "./chunk-GRRPEPRN.js";
13
13
  import "./chunk-NXFWFAYV.js";
14
14
  import {
15
15
  resolve_project_root
16
- } from "./chunk-LCFJIQ4J.js";
16
+ } from "./chunk-JEJABGKB.js";
17
17
  import "./chunk-NDJLNC6Q.js";
18
18
  import "./chunk-523HCFYO.js";
19
19
  import "./chunk-OY53J6II.js";
@@ -2,7 +2,7 @@
2
2
  import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
3
3
  import {
4
4
  read_entries
5
- } from "./chunk-BTJNRUX3.js";
5
+ } from "./chunk-QEEB4LHO.js";
6
6
  import "./chunk-3EWYC3YK.js";
7
7
  import "./chunk-MMJL4TIX.js";
8
8
  import {
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-LF2KKJ4Q.js";
11
11
  import {
12
12
  load_agent_settings
13
- } from "./chunk-LCFJIQ4J.js";
13
+ } from "./chunk-JEJABGKB.js";
14
14
  import "./chunk-NDJLNC6Q.js";
15
15
  import "./chunk-OY53J6II.js";
16
16
  import {
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-LF2KKJ4Q.js";
7
7
  import {
8
8
  load_agent_settings
9
- } from "./chunk-LCFJIQ4J.js";
9
+ } from "./chunk-JEJABGKB.js";
10
10
  import "./chunk-NDJLNC6Q.js";
11
11
  import {
12
12
  resolvePackageRoot
@@ -7,10 +7,10 @@ import {
7
7
  } from "./chunk-RVGBH4XK.js";
8
8
  import {
9
9
  atomic_write_json
10
- } from "./chunk-O3CO5BFB.js";
10
+ } from "./chunk-EJITJBJX.js";
11
11
  import {
12
12
  resolve_project_root
13
- } from "./chunk-LCFJIQ4J.js";
13
+ } from "./chunk-JEJABGKB.js";
14
14
  import "./chunk-NDJLNC6Q.js";
15
15
  import "./chunk-J55WI3RR.js";
16
16