@event4u/agent-config 14.13.0 → 14.14.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 (101) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +116 -387
  5. package/dist/agent-src/commands/analyze/inbox.md +36 -0
  6. package/dist/agent-src/rules/code-comment-discipline.md +6 -0
  7. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +6 -6
  8. package/dist/agent-src/scripts/guarded_baseline.ts +22 -7
  9. package/dist/agent-src/scripts/stubs_due.ts +118 -2
  10. package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -8
  11. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  12. package/dist/cli-delegate/cmd_conformance.js +38 -1
  13. package/dist/discovery/deprecation-report.md +1 -1
  14. package/dist/discovery/discovery-manifest.json +4 -4
  15. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  16. package/dist/discovery/discovery-manifest.summary.md +1 -1
  17. package/dist/discovery/dormancy-report.md +1 -1
  18. package/dist/discovery/orphan-report.md +1 -1
  19. package/dist/discovery/packs.json +2 -2
  20. package/dist/discovery/trust-report.md +1 -1
  21. package/dist/discovery/workspaces.json +2 -2
  22. package/dist/hooks/dispatch.js +1438 -711
  23. package/dist/mcp/registry-manifest.json +2 -2
  24. package/dist/mcp/server.json +2 -2
  25. package/dist/mcp/server.mjs +112 -17
  26. package/docs/guidelines/agent-infra/guarded-baseline.md +1 -1
  27. package/docs/guidelines/code-clarity.md +18 -0
  28. package/package.json +1 -1
  29. package/src/agent-src/scripts/archive_completed_roadmaps.ts +6 -6
  30. package/src/agent-src/scripts/guarded_baseline.ts +22 -7
  31. package/src/agent-src/scripts/stubs_due.ts +118 -2
  32. package/src/agent-src/scripts/update_roadmap_progress.ts +8 -8
  33. package/src/config/estate-count-budget.json +20 -1
  34. package/src/config/gate-coverage.yml +150 -0
  35. package/src/config/gate-violation-baselines.json +8 -3
  36. package/src/config/preamble-payload-budget.json +19 -11
  37. package/src/config/rule-stub-ceilings.json +14 -7
  38. package/src/scripts/_dispatch.bash +0 -4
  39. package/src/scripts/_lib/activation_ladder.ts +47 -3
  40. package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
  41. package/src/scripts/_lib/adr_frontmatter.ts +26 -0
  42. package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
  43. package/src/scripts/_lib/carrier_status.ts +118 -0
  44. package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
  45. package/src/scripts/_lib/corpus_manifest.ts +726 -0
  46. package/src/scripts/_lib/delivery_arm_experiment.ts +18 -2
  47. package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
  48. package/src/scripts/_lib/evaluation_cascade.ts +452 -0
  49. package/src/scripts/_lib/evolution_roi.ts +562 -0
  50. package/src/scripts/_lib/harness_evolution_guards.ts +10 -0
  51. package/src/scripts/_lib/lexical_shortlist.ts +215 -0
  52. package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
  53. package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
  54. package/src/scripts/_lib/pathology_archive.ts +393 -0
  55. package/src/scripts/_lib/promotion_capability.ts +315 -0
  56. package/src/scripts/_lib/promotion_evidence.ts +414 -0
  57. package/src/scripts/_lib/promotion_review.ts +294 -0
  58. package/src/scripts/_lib/prompt_shape.ts +92 -0
  59. package/src/scripts/_lib/release_highlights.ts +70 -1
  60. package/src/scripts/_lib/release_material.ts +125 -2
  61. package/src/scripts/_lib/routing_corpus.ts +307 -0
  62. package/src/scripts/_lib/routing_index_input.ts +104 -0
  63. package/src/scripts/_lib/rule_injection.ts +22 -1
  64. package/src/scripts/_lib/semantic_noop.ts +167 -0
  65. package/src/scripts/activation_receipt.ts +258 -0
  66. package/src/scripts/ai_council/cross_exam.ts +128 -0
  67. package/src/scripts/ai_council/explain_route.ts +157 -0
  68. package/src/scripts/ai_council/information_gain.ts +293 -0
  69. package/src/scripts/ai_council/leakage_corpus.ts +385 -0
  70. package/src/scripts/ai_council/leakage_patterns.ts +453 -0
  71. package/src/scripts/ai_council/minority_retention.ts +171 -0
  72. package/src/scripts/ai_council/recouncil_savings.ts +299 -0
  73. package/src/scripts/ai_council/replay_route.ts +223 -0
  74. package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
  75. package/src/scripts/ai_council/routing_training_row.ts +197 -0
  76. package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
  77. package/src/scripts/check_adr_frontmatter.ts +4 -9
  78. package/src/scripts/check_estate_count.ts +205 -24
  79. package/src/scripts/check_release_highlights.ts +96 -13
  80. package/src/scripts/check_roadmap_trackable.ts +17 -2
  81. package/src/scripts/corpus_manifest.ts +235 -0
  82. package/src/scripts/evolution_lab.ts +181 -8
  83. package/src/scripts/hook_manifest.json +1 -1
  84. package/src/scripts/hook_manifest.yaml +28 -6
  85. package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
  86. package/src/scripts/hooks/concern_registry.ts +2 -0
  87. package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
  88. package/src/scripts/language_mirror_hook.ts +14 -2
  89. package/src/scripts/lint_carrier_integrity.ts +820 -0
  90. package/src/scripts/lint_code_comments.ts +643 -0
  91. package/src/scripts/lint_plan_risk_register.ts +39 -19
  92. package/src/scripts/lint_promotion_paths.ts +779 -0
  93. package/src/scripts/llm_propose.ts +256 -0
  94. package/src/scripts/measure_delivery_sets.ts +361 -0
  95. package/src/scripts/measure_routing_signal.ts +307 -0
  96. package/src/scripts/model_rule_injection.ts +19 -3
  97. package/src/scripts/probe_council_retention.ts +495 -0
  98. package/src/scripts/release.ts +21 -37
  99. package/src/scripts/release_drill.ts +143 -0
  100. package/src/scripts/release_env.ts +35 -0
  101. package/src/scripts/release_publication.ts +84 -0
@@ -833,6 +833,28 @@ concerns:
833
833
  args: []
834
834
  fail_closed: false
835
835
  severity: blocking
836
+ # Comment-discipline advisory — the write-time half of
837
+ # `lint_code_comments`. Scans the TEXT JUST WRITTEN (Write ->
838
+ # tool_input.content, Edit -> tool_input.new_string), never the file on
839
+ # disk, so it is forward-only by construction: a pre-existing comment the
840
+ # edit did not touch cannot fire it and there is no baseline to keep. Three
841
+ # classes: `de-comment` (a non-English comment line), `report-comment` (a
842
+ # comment shaped like an analysis report — markdown table, box rule, `§`
843
+ # head, revisit-if) and `provenance-comment` (a roadmap or reference path
844
+ # explaining where the code came from). Reports `{decision:"warn", reason,
845
+ # additional_context}` at exit 2, the same verified delivery as
846
+ # `delegation-nudge`; never blocks, because the classifier is a line
847
+ # heuristic and the deterministic refusal belongs in the gate where a human
848
+ # reads the whole file. NOT once-per-session, unlike edit-shape: the
849
+ # measured failure was 41 files each carrying the defect, and a nudge that
850
+ # speaks once while forty more land is that incident. fail_closed: false.
851
+ comment-discipline:
852
+ script: src/scripts/hooks/comment_discipline_hook.ts
853
+ args: []
854
+ fail_closed: false
855
+ severity: advisory
856
+ tools: [Write, Edit]
857
+ needs_payload_bodies: [input]
836
858
  # road-to-token-economy-cache Phase 5.1/5.2 — edit-shape advisory. Fires
837
859
  # when a Write replaced an existing, git-tracked file of >= 50 lines while
838
860
  # the effective diff (`git diff HEAD --numstat` added+deleted vs current
@@ -1145,7 +1167,7 @@ platforms:
1145
1167
  session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush]
1146
1168
  stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
1147
1169
  pre_tool_use: [block-no-verify, block-unauthorized-git, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard]
1148
- post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
1170
+ post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
1149
1171
 
1150
1172
  claude:
1151
1173
  session_start: [chat-history, hot-context, handoff-context, session-canary, council-availability, telemetry-disclosure, first-run-gate, onboarding-gate, verify-before-complete, minimal-safe-diff, profile-staleness, wrapper-freshness, surface-probe, session-register, journal-record]
@@ -1153,7 +1175,7 @@ platforms:
1153
1175
  stop: [chat-history, hot-context, verify-before-complete, team-review-gate, end-review-nudge, turn-end-gate, self-repair, session-register, session-eol, interruption-ledger, roadmap-progress, design-pass-stop, suggestion-capture, journal-record, run-continuation]
1154
1176
  user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, delegation-nudge, skill-route, git-authorization, session-canary, self-repair, session-register, rule-inject, suggestion-capture, journal-record]
1155
1177
  pre_tool_use: [block-no-verify, block-unauthorized-git, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, rule-inject]
1156
- post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, language-mirror, design-pass, journal-record]
1178
+ post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, language-mirror, design-pass, journal-record]
1157
1179
  # `language-mirror` — round-5 § 6.1. `pre_compact` sets a pin-lost marker;
1158
1180
  # the `post_tool_use` entry above re-emits the pin exactly once while that
1159
1181
  # marker is set, then clears it. One extra injection per compaction EVENT —
@@ -1207,7 +1229,7 @@ platforms:
1207
1229
  stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
1208
1230
  user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, git-authorization, session-canary, self-repair, session-register]
1209
1231
  pre_tool_use: [block-no-verify, block-unauthorized-git, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate]
1210
- post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
1232
+ post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
1211
1233
  # subagent-ledger IS bound here, unlike the two nudges above, and the
1212
1234
  # difference is the delivery channel rather than the platform: the nudges
1213
1235
  # depend on stdout reaching the model, which this trampoline discards by
@@ -1230,7 +1252,7 @@ platforms:
1230
1252
  session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush]
1231
1253
  stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
1232
1254
  user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, git-authorization, session-canary, self-repair, session-register]
1233
- post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
1255
+ post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
1234
1256
 
1235
1257
  # Phase 7.6 — Cline. Hooks live under `.clinerules/hooks/<HookName>`
1236
1258
  # (project, no file extension, must be executable per Cline docs) or
@@ -1245,7 +1267,7 @@ platforms:
1245
1267
  session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush]
1246
1268
  stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
1247
1269
  user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, git-authorization, session-canary, self-repair, session-register]
1248
- post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
1270
+ post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
1249
1271
 
1250
1272
  # Phase 7.7 — Windsurf (Cascade). Hooks live at `.windsurf/hooks.json`
1251
1273
  # (project) or `~/.codeium/windsurf/hooks.json` (user). Cascade has
@@ -1281,7 +1303,7 @@ platforms:
1281
1303
  session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush]
1282
1304
  stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
1283
1305
  user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, git-authorization, session-canary, self-repair, session-register]
1284
- post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
1306
+ post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
1285
1307
 
1286
1308
  # Phase 7.9 — Copilot has no hook surface. Concerns route through
1287
1309
  # rule-only fallback; the dispatcher silently no-ops on --platform copilot.
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Comment-discipline advisory — `post_tool_use` concern.
4
+ *
5
+ * The write-time half of `lint_code_comments`. The gate answers "may this
6
+ * land"; this answers "was it written that way in the first place", which is
7
+ * the question the maintainer actually asked after a run produced 509 German
8
+ * comment lines across 41 of 45 changed source files without anything
9
+ * objecting once.
10
+ *
11
+ * `code-comment-discipline` is `type: auto` with PROMPT keywords (`comment`,
12
+ * `refactor`, `implement`, …). A run that writes forty-five files while the
13
+ * user says "build the todo module" matches none of them, so the rule never
14
+ * loads — the activation gap `fix-what-you-see` names for itself, in the one
15
+ * place where the agent is producing the artefact the rule governs. A
16
+ * post-write concern fires on the TOOL EVENT and therefore does not depend on
17
+ * what the prompt happened to say.
18
+ *
19
+ * `Write` carries the new content in `tool_input.content`; `Edit` carries the
20
+ * replacement in `tool_input.new_string`. Scanning that text rather than the
21
+ * file on disk makes the concern forward-only by construction: a pre-existing
22
+ * comment the edit did not touch cannot fire it, so there is no baseline to
23
+ * maintain and no legacy tree to clean before turning it on.
24
+ *
25
+ * Same shape as `edit_shape_hook.ts` and `delegation_nudge_hook.ts`:
26
+ * `host_semantics.emitFor`'s `severity === "warn"` branch returns exit 0 with
27
+ * the text in `hookSpecificOutput.additionalContext`, unconditionally, so the
28
+ * byte handed to the host is always 0. Advisory is the right severity here
29
+ * and not a hedge — the classifier is a line heuristic, and a heuristic that
30
+ * can refuse a write would turn one false positive into a blocked session.
31
+ * The deterministic refusal lives in the gate, where a human can read the
32
+ * whole file before answering.
33
+ *
34
+ * `edit-shape` fires once per session because its advice is a habit
35
+ * correction that lands the first time. This one is per-write on purpose: the
36
+ * measured failure is forty-one files each carrying the defect, and a nudge
37
+ * that speaks once and then watches forty more land is the shape that
38
+ * produced the incident. The cost is bounded by naming at most
39
+ * `MAX_REPORTED` findings and no more than one line per write.
40
+ *
41
+ * ROBUSTNESS: malformed payload → exit 0 silently. This concern never blocks.
42
+ */
43
+ import * as fs from 'node:fs';
44
+ import * as path from 'node:path';
45
+ import { fileURLToPath, pathToFileURL } from 'node:url';
46
+
47
+ import { isScannable, scanText, type CommentFinding } from '../lint_code_comments.js';
48
+ import { unwrap, type JsonObject, type JsonValue } from './envelope.js';
49
+ import { readHookStdin } from './hook_stdin.js';
50
+
51
+ const EXIT_ALLOW = 0;
52
+ const EXIT_WARN = 2;
53
+
54
+ /** Findings named in the advisory line. The rest are counted, never listed. */
55
+ export const MAX_REPORTED = 3;
56
+
57
+ function str(v: JsonValue | undefined): string {
58
+ return typeof v === 'string' ? v : '';
59
+ }
60
+ function isObject(v: unknown): v is JsonObject {
61
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
62
+ }
63
+
64
+ /** The written text, per tool. Empty string when the payload carries none. */
65
+ export function writtenText(toolName: string, toolInput: JsonObject): string {
66
+ if (toolName === 'Write') return str(toolInput['content'] as JsonValue | undefined);
67
+ if (toolName === 'Edit') {
68
+ return str(toolInput['new_string'] as JsonValue | undefined)
69
+ || str(toolInput['newString'] as JsonValue | undefined);
70
+ }
71
+ return '';
72
+ }
73
+
74
+ /** One advisory line, naming what fired and where. */
75
+ export function buildAdvisoryLine(file: string, findings: readonly CommentFinding[]): string {
76
+ const counts = new Map<string, number>();
77
+ for (const f of findings) counts.set(f.cls, (counts.get(f.cls) ?? 0) + 1);
78
+ const summary = [...counts].map(([c, n]) => `${c} ×${n}`).join(' · ');
79
+ const named = findings.slice(0, MAX_REPORTED)
80
+ .map((f) => `line ${f.line} (${f.signal})`)
81
+ .join(', ');
82
+ const more = findings.length > MAX_REPORTED ? `, +${findings.length - MAX_REPORTED} more` : '';
83
+ return (
84
+ `comment-discipline: the text just written to ${file} carries ${summary} — ${named}${more}. `
85
+ + 'A comment states a WHY or a constraint the code cannot show, in English; evidence for a '
86
+ + 'roadmap step belongs in that roadmap, not in a second copy in the source. Rewrite or '
87
+ + 'delete those lines now, before the next write — `lint_code_comments` refuses them at the gate.'
88
+ );
89
+ }
90
+
91
+ export function main(): number {
92
+ try {
93
+ const [envelope, payload] = unwrap(readHookStdin(), 'claude');
94
+
95
+ const event = str(envelope['event'] as JsonValue | undefined);
96
+ if (event !== '' && event !== 'post_tool_use') return EXIT_ALLOW;
97
+
98
+ const toolName = str(
99
+ (payload['tool_name'] ?? payload['toolName'] ?? payload['tool']) as JsonValue | undefined,
100
+ );
101
+ if (toolName !== 'Write' && toolName !== 'Edit') return EXIT_ALLOW;
102
+
103
+ const ti = payload['tool_input'] ?? payload['toolInput'] ?? payload['input'];
104
+ if (!isObject(ti)) return EXIT_ALLOW;
105
+
106
+ const filePath = str((ti['file_path'] ?? ti['path'] ?? ti['filePath']) as JsonValue | undefined);
107
+ if (!filePath || !isScannable(filePath)) return EXIT_ALLOW;
108
+
109
+ const text = writtenText(toolName, ti);
110
+ if (!text) return EXIT_ALLOW;
111
+
112
+ const workspaceRoot = str(envelope['workspace_root'] as JsonValue | undefined).trim() || process.cwd();
113
+ const abs = path.isAbsolute(filePath) ? filePath : path.resolve(workspaceRoot, filePath);
114
+ const rel = path.relative(workspaceRoot, abs);
115
+ const shown = rel.startsWith('..') ? path.basename(abs) : rel;
116
+
117
+ const findings = scanText(shown, text);
118
+ if (findings.length === 0) return EXIT_ALLOW;
119
+
120
+ process.stdout.write(
121
+ `${JSON.stringify({
122
+ decision: 'warn',
123
+ reason: `comment-discipline: ${findings.length} comment finding(s) in the text written to ${shown}`,
124
+ additional_context: buildAdvisoryLine(shown, findings),
125
+ })}\n`,
126
+ );
127
+ return EXIT_WARN;
128
+ } catch {
129
+ return EXIT_ALLOW;
130
+ }
131
+ }
132
+
133
+ declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
134
+ function _isCliEntry(): boolean {
135
+ if (typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__) return false;
136
+ if (process.argv[1] === undefined) return false;
137
+ const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
138
+ if (import.meta.url === argvUrl) return true;
139
+ try {
140
+ return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
141
+ } catch {
142
+ return false;
143
+ }
144
+ }
145
+
146
+ if (_isCliEntry()) process.exit(main());
@@ -69,6 +69,7 @@ import { main as ruleInjectMain } from './rule_inject_hook.js';
69
69
  import { main as endReviewNudgeMain } from './end_review_nudge_hook.js';
70
70
  import { main as turnEndGateMain } from './turn_end_gate_hook.js';
71
71
  import { main as editShapeMain } from './edit_shape_hook.js';
72
+ import { main as commentDisciplineMain } from './comment_discipline_hook.js';
72
73
  import { main as rereadGuardMain } from './reread_guard_hook.js';
73
74
  import { main as sessionEolMain } from './session_eol_hook.js';
74
75
  import { main as subagentLedgerMain } from './subagent_ledger_hook.js';
@@ -129,6 +130,7 @@ export const CONCERN_REGISTRY: Readonly<Record<string, ConcernMain>> = {
129
130
  'src/scripts/hooks/end_review_nudge_hook.ts': endReviewNudgeMain as ConcernMain,
130
131
  'src/scripts/hooks/turn_end_gate_hook.ts': turnEndGateMain as ConcernMain,
131
132
  'src/scripts/hooks/edit_shape_hook.ts': editShapeMain as ConcernMain,
133
+ 'src/scripts/hooks/comment_discipline_hook.ts': commentDisciplineMain as ConcernMain,
132
134
  'src/scripts/hooks/reread_guard_hook.ts': rereadGuardMain as ConcernMain,
133
135
  'src/scripts/hooks/session_eol_hook.ts': sessionEolMain as ConcernMain,
134
136
  'src/scripts/hooks/subagent_ledger_hook.ts': subagentLedgerMain as ConcernMain,
@@ -579,12 +579,20 @@ export function readLanguagePin(workspaceRoot: string, session_id: string): Verd
579
579
  * WHAT IS ACTUALLY CLASSIFIED, stated accurately because R2 finding 9 caught
580
580
  * this file claiming otherwise in three places. `visibleProse` strips code,
581
581
  * quotes, tables, URLs and paths from the whole reply — but `classify` then
582
- * applies `instructionText` (which drops output-shaped lines and their
582
+ * applies `stripInjectedRegions` (which removes balanced host wrapper regions
583
+ * such as `<launch-selected-element>`, plus the host's advisory sentence beside
584
+ * them), then `instructionText` (which drops output-shaped lines and their
583
585
  * followers) and `humanAuthoredLead`, and RETURNS ON THE LEAD ALONE when the
584
586
  * lead is determined. So in the common case the verdict comes from the reply's
585
587
  * opening chunk, not from all of it, and indented prose is discarded before
586
588
  * scoring.
587
589
  *
590
+ * The region strip reaches this path too, and its effect here is small by
591
+ * construction: `visibleProse` has already removed fenced code, so a balanced
592
+ * bare-tag pair surviving into the scorer is prose the reply wrote around a tag
593
+ * rather than markup. Named rather than omitted, because enumerating the
594
+ * scoring surface accurately is this comment's entire job.
595
+ *
588
596
  * That is deliberately left as-is rather than swapped for a full-text scorer:
589
597
  * sharing one classifier with `language_mirror_hook` is what stops the pin and
590
598
  * the detector disagreeing about what language a turn is in, and changing the
@@ -83,7 +83,11 @@ import {
83
83
  session_state_file,
84
84
  } from "./hooks/state_io.js";
85
85
  import { readHookStdin } from "./hooks/hook_stdin.js";
86
- import { humanAuthoredLead, isSyntheticPrompt } from "./_lib/prompt_shape.js";
86
+ import {
87
+ humanAuthoredLead,
88
+ isSyntheticPrompt,
89
+ stripInjectedRegions,
90
+ } from "./_lib/prompt_shape.js";
87
91
 
88
92
  const EXIT_ALLOW = 0;
89
93
  // Severity is taken from the EXIT CODE, not from the `decision` field in the
@@ -296,9 +300,17 @@ export function instructionText(prompt: string): string {
296
300
  * an English instruction over a German paste resolves to English by the same
297
301
  * step. The fallback is what keeps it conservative: a prompt with no document
298
302
  * marker classifies exactly as it did before.
303
+ *
304
+ * `stripInjectedRegions` runs FIRST, and the order is load-bearing rather than
305
+ * tidy. A host wrapper the user never typed — `<launch-selected-element>` — is
306
+ * a bare tag line, which `humanAuthoredLead` read as the END of the human lead;
307
+ * prepended, as the host prepends it, that returned an empty lead and handed the
308
+ * verdict to ~4 KB of injected markup. Stripping before `instructionText` also
309
+ * keeps the block's indented lines from arming that filter's paste state, which
310
+ * was deleting the user's own sentence outright.
299
311
  */
300
312
  export function classify(prompt: string): Classification {
301
- const text = instructionText(prompt);
313
+ const text = instructionText(stripInjectedRegions(prompt));
302
314
  const lead = humanAuthoredLead(text);
303
315
  const leadVerdict = _score(lead);
304
316
  if (leadVerdict.language !== "und") {