@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.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +116 -387
- package/dist/agent-src/commands/analyze/inbox.md +36 -0
- package/dist/agent-src/rules/code-comment-discipline.md +6 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +6 -6
- package/dist/agent-src/scripts/guarded_baseline.ts +22 -7
- package/dist/agent-src/scripts/stubs_due.ts +118 -2
- package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -8
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli-delegate/cmd_conformance.js +38 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +4 -4
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +1438 -711
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +112 -17
- package/docs/guidelines/agent-infra/guarded-baseline.md +1 -1
- package/docs/guidelines/code-clarity.md +18 -0
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +6 -6
- package/src/agent-src/scripts/guarded_baseline.ts +22 -7
- package/src/agent-src/scripts/stubs_due.ts +118 -2
- package/src/agent-src/scripts/update_roadmap_progress.ts +8 -8
- package/src/config/estate-count-budget.json +20 -1
- package/src/config/gate-coverage.yml +150 -0
- package/src/config/gate-violation-baselines.json +8 -3
- package/src/config/preamble-payload-budget.json +19 -11
- package/src/config/rule-stub-ceilings.json +14 -7
- package/src/scripts/_dispatch.bash +0 -4
- package/src/scripts/_lib/activation_ladder.ts +47 -3
- package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
- package/src/scripts/_lib/adr_frontmatter.ts +26 -0
- package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
- package/src/scripts/_lib/carrier_status.ts +118 -0
- package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
- package/src/scripts/_lib/corpus_manifest.ts +726 -0
- package/src/scripts/_lib/delivery_arm_experiment.ts +18 -2
- package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
- package/src/scripts/_lib/evaluation_cascade.ts +452 -0
- package/src/scripts/_lib/evolution_roi.ts +562 -0
- package/src/scripts/_lib/harness_evolution_guards.ts +10 -0
- package/src/scripts/_lib/lexical_shortlist.ts +215 -0
- package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
- package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
- package/src/scripts/_lib/pathology_archive.ts +393 -0
- package/src/scripts/_lib/promotion_capability.ts +315 -0
- package/src/scripts/_lib/promotion_evidence.ts +414 -0
- package/src/scripts/_lib/promotion_review.ts +294 -0
- package/src/scripts/_lib/prompt_shape.ts +92 -0
- package/src/scripts/_lib/release_highlights.ts +70 -1
- package/src/scripts/_lib/release_material.ts +125 -2
- package/src/scripts/_lib/routing_corpus.ts +307 -0
- package/src/scripts/_lib/routing_index_input.ts +104 -0
- package/src/scripts/_lib/rule_injection.ts +22 -1
- package/src/scripts/_lib/semantic_noop.ts +167 -0
- package/src/scripts/activation_receipt.ts +258 -0
- package/src/scripts/ai_council/cross_exam.ts +128 -0
- package/src/scripts/ai_council/explain_route.ts +157 -0
- package/src/scripts/ai_council/information_gain.ts +293 -0
- package/src/scripts/ai_council/leakage_corpus.ts +385 -0
- package/src/scripts/ai_council/leakage_patterns.ts +453 -0
- package/src/scripts/ai_council/minority_retention.ts +171 -0
- package/src/scripts/ai_council/recouncil_savings.ts +299 -0
- package/src/scripts/ai_council/replay_route.ts +223 -0
- package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
- package/src/scripts/ai_council/routing_training_row.ts +197 -0
- package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
- package/src/scripts/check_adr_frontmatter.ts +4 -9
- package/src/scripts/check_estate_count.ts +205 -24
- package/src/scripts/check_release_highlights.ts +96 -13
- package/src/scripts/check_roadmap_trackable.ts +17 -2
- package/src/scripts/corpus_manifest.ts +235 -0
- package/src/scripts/evolution_lab.ts +181 -8
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +28 -6
- package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
- package/src/scripts/language_mirror_hook.ts +14 -2
- package/src/scripts/lint_carrier_integrity.ts +820 -0
- package/src/scripts/lint_code_comments.ts +643 -0
- package/src/scripts/lint_plan_risk_register.ts +39 -19
- package/src/scripts/lint_promotion_paths.ts +779 -0
- package/src/scripts/llm_propose.ts +256 -0
- package/src/scripts/measure_delivery_sets.ts +361 -0
- package/src/scripts/measure_routing_signal.ts +307 -0
- package/src/scripts/model_rule_injection.ts +19 -3
- package/src/scripts/probe_council_retention.ts +495 -0
- package/src/scripts/release.ts +21 -37
- package/src/scripts/release_drill.ts +143 -0
- package/src/scripts/release_env.ts +35 -0
- package/src/scripts/release_publication.ts +84 -0
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"artefact_count": 623,
|
|
4
4
|
"scanner_version": "de0a22b4ac4c"
|
|
5
5
|
},
|
|
6
|
-
"generated_at": "2026-
|
|
6
|
+
"generated_at": "2026-09-02",
|
|
7
7
|
"package": {
|
|
8
8
|
"description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) \u2014 every claim machine-checked, including the counts in these badges.",
|
|
9
9
|
"homepage": "https://event4u-app.github.io/agent-config",
|
|
10
10
|
"name": "@event4u/agent-config",
|
|
11
11
|
"repository": "https://github.com/event4u-app/agent-config",
|
|
12
|
-
"version": "14.
|
|
12
|
+
"version": "14.14.0"
|
|
13
13
|
},
|
|
14
14
|
"registries": [
|
|
15
15
|
{
|
package/dist/mcp/server.json
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
"transport": {
|
|
10
10
|
"type": "stdio"
|
|
11
11
|
},
|
|
12
|
-
"version": "14.
|
|
12
|
+
"version": "14.14.0"
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"repository": {
|
|
16
16
|
"source": "github",
|
|
17
17
|
"url": "https://github.com/event4u-app/agent-config"
|
|
18
18
|
},
|
|
19
|
-
"version": "14.
|
|
19
|
+
"version": "14.14.0"
|
|
20
20
|
}
|
package/dist/mcp/server.mjs
CHANGED
|
@@ -18969,6 +18969,11 @@ var init_dashboard_mode = __esm({
|
|
|
18969
18969
|
import * as fs23 from "node:fs";
|
|
18970
18970
|
import * as path22 from "node:path";
|
|
18971
18971
|
import { fileURLToPath as fileURLToPath17, pathToFileURL as pathToFileURL9 } from "node:url";
|
|
18972
|
+
function is_blocked_quickwin(design_validated, capability_gap, blocker_class2) {
|
|
18973
|
+
if (design_validated === null || design_validated === "") return false;
|
|
18974
|
+
if (capability_gap !== "none") return false;
|
|
18975
|
+
return QUICKWIN_BLOCKER_CLASSES.includes(blocker_class2 ?? "");
|
|
18976
|
+
}
|
|
18972
18977
|
function _isDir8(p) {
|
|
18973
18978
|
try {
|
|
18974
18979
|
return fs23.statSync(p).isDirectory();
|
|
@@ -19063,9 +19068,27 @@ function _parseIso(s) {
|
|
|
19063
19068
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
19064
19069
|
}
|
|
19065
19070
|
function scan(root, today) {
|
|
19066
|
-
return scan_dir(path22.join(root, STUB_DIR), today);
|
|
19071
|
+
return scan_dir(path22.join(root, STUB_DIR), today, release_dates(root));
|
|
19072
|
+
}
|
|
19073
|
+
function release_dates(root) {
|
|
19074
|
+
const out = [];
|
|
19075
|
+
for (const rel of CHANGELOG_ERAS) {
|
|
19076
|
+
let text;
|
|
19077
|
+
try {
|
|
19078
|
+
text = fs23.readFileSync(path22.join(root, rel), "utf8");
|
|
19079
|
+
} catch {
|
|
19080
|
+
continue;
|
|
19081
|
+
}
|
|
19082
|
+
for (const m of text.matchAll(RELEASE_HEADING)) {
|
|
19083
|
+
if (m[1] !== void 0) out.push(m[1]);
|
|
19084
|
+
}
|
|
19085
|
+
}
|
|
19086
|
+
return out;
|
|
19067
19087
|
}
|
|
19068
|
-
function
|
|
19088
|
+
function releases_since(opened, dates) {
|
|
19089
|
+
return dates.filter((d) => d > opened).length;
|
|
19090
|
+
}
|
|
19091
|
+
function scan_dir(base, today, releaseDates = []) {
|
|
19069
19092
|
if (!_isDir8(base)) return [];
|
|
19070
19093
|
const now = _parseIso(today);
|
|
19071
19094
|
const out = [];
|
|
@@ -19086,6 +19109,10 @@ function scan_dir(base, today) {
|
|
|
19086
19109
|
const review_by = _scalar(front, "review_by");
|
|
19087
19110
|
const reviewed_at = _scalar(front, "reviewed_at");
|
|
19088
19111
|
const probeVal = _scalar(front, "probe");
|
|
19112
|
+
const design_validated = _scalar(front, "design_validated");
|
|
19113
|
+
const capability_gap = _scalar(front, "capability_gap");
|
|
19114
|
+
const blocker_class2 = _scalar(front, "blocker_class");
|
|
19115
|
+
const blocker_opened = _scalar(front, "blocker_opened");
|
|
19089
19116
|
const shape = text.includes(TRANSFER_MARKER) ? "transfer" : "orgmode";
|
|
19090
19117
|
let overdue = false;
|
|
19091
19118
|
let days_overdue = null;
|
|
@@ -19105,7 +19132,13 @@ function scan_dir(base, today) {
|
|
|
19105
19132
|
has_probe_heading: /^#{1,4} *(Probe|Promotion)/m.test(text),
|
|
19106
19133
|
owner_decisions: count_owner_decisions(text),
|
|
19107
19134
|
overdue,
|
|
19108
|
-
days_overdue
|
|
19135
|
+
days_overdue,
|
|
19136
|
+
design_validated,
|
|
19137
|
+
capability_gap,
|
|
19138
|
+
blocker_class: blocker_class2,
|
|
19139
|
+
blocker_opened,
|
|
19140
|
+
releases_since_blocked: blocker_opened === null ? null : releases_since(blocker_opened, releaseDates),
|
|
19141
|
+
blocked_quickwin: is_blocked_quickwin(design_validated, capability_gap, blocker_class2)
|
|
19109
19142
|
});
|
|
19110
19143
|
}
|
|
19111
19144
|
return out;
|
|
@@ -19115,6 +19148,7 @@ function counts(records) {
|
|
|
19115
19148
|
overdue: records.filter((r) => r.overdue).length,
|
|
19116
19149
|
owner_decisions: records.reduce((s, r) => s + r.owner_decisions, 0),
|
|
19117
19150
|
missing_review_by: records.filter((r) => r.review_by === null).length,
|
|
19151
|
+
blocked_quickwin: records.filter((r) => r.blocked_quickwin).length,
|
|
19118
19152
|
total: records.length
|
|
19119
19153
|
};
|
|
19120
19154
|
}
|
|
@@ -19178,6 +19212,20 @@ function main9(argv = process.argv.slice(2)) {
|
|
|
19178
19212
|
process.stdout.write(":\n");
|
|
19179
19213
|
for (const r of withDecisions) {
|
|
19180
19214
|
process.stdout.write(` ${r.file} (${r.owner_decisions})
|
|
19215
|
+
`);
|
|
19216
|
+
}
|
|
19217
|
+
}
|
|
19218
|
+
const quickwins = records.filter((r) => r.blocked_quickwin);
|
|
19219
|
+
if (quickwins.length > 0) {
|
|
19220
|
+
process.stdout.write(
|
|
19221
|
+
`
|
|
19222
|
+
\u{1F513} ${quickwins.length} BLOCKED QUICK-WIN(S) \u2014 design validated, no capability gap,
|
|
19223
|
+
held by an estate or budget decision rather than a product one:
|
|
19224
|
+
`
|
|
19225
|
+
);
|
|
19226
|
+
for (const r of quickwins) {
|
|
19227
|
+
const since = r.releases_since_blocked === null ? "no `blocker_opened:`" : `${String(r.releases_since_blocked)} release(s) since ${r.blocker_opened}`;
|
|
19228
|
+
process.stdout.write(` ${r.file} (${r.blocker_class}, ${since})
|
|
19181
19229
|
`);
|
|
19182
19230
|
}
|
|
19183
19231
|
}
|
|
@@ -19227,7 +19275,7 @@ function headerFragment(stubsDir, today) {
|
|
|
19227
19275
|
}
|
|
19228
19276
|
return ` \xB7 **${overdue}** overdue stub${overdue !== 1 ? "s" : ""}, **${decisions}** owner decision${decisions !== 1 ? "s" : ""} \u2192 \`agent-config stubs:due\``;
|
|
19229
19277
|
}
|
|
19230
|
-
var STUB_DIR, CADENCE_DAYS, TRANSFER_MARKER, _HERE6;
|
|
19278
|
+
var STUB_DIR, CADENCE_DAYS, TRANSFER_MARKER, _HERE6, QUICKWIN_BLOCKER_CLASSES, CHANGELOG_ERAS, RELEASE_HEADING;
|
|
19231
19279
|
var init_stubs_due = __esm({
|
|
19232
19280
|
"src/agent-src/scripts/stubs_due.ts"() {
|
|
19233
19281
|
"use strict";
|
|
@@ -19235,6 +19283,9 @@ var init_stubs_due = __esm({
|
|
|
19235
19283
|
CADENCE_DAYS = { transfer: 30, orgmode: 120 };
|
|
19236
19284
|
TRANSFER_MARKER = "drain-run transfer";
|
|
19237
19285
|
_HERE6 = path22.resolve(fileURLToPath17(import.meta.url));
|
|
19286
|
+
QUICKWIN_BLOCKER_CLASSES = ["estate", "budget"];
|
|
19287
|
+
CHANGELOG_ERAS = ["CHANGELOG.md", "docs/archive/CHANGELOG-pre-14.12.0.md"];
|
|
19288
|
+
RELEASE_HEADING = /^## \[\d+\.\d+\.\d+\][^\n]*\((\d{4}-\d{2}-\d{2})\)\s*$/gm;
|
|
19238
19289
|
if (_isCliEntry9() || process.argv[1] === _HERE6) {
|
|
19239
19290
|
process.exitCode = main9();
|
|
19240
19291
|
}
|
|
@@ -19348,15 +19399,21 @@ function guardedBaselineStaleness(items, repo_root2) {
|
|
|
19348
19399
|
if (trigger === "") {
|
|
19349
19400
|
continue;
|
|
19350
19401
|
}
|
|
19351
|
-
|
|
19352
|
-
|
|
19353
|
-
|
|
19354
|
-
|
|
19402
|
+
const tokens = trigger.split(/[\s,]+/).filter((t) => t !== "");
|
|
19403
|
+
const paths = tokens.filter((t) => t.includes("/"));
|
|
19404
|
+
for (const token of paths) {
|
|
19405
|
+
if (fs24.existsSync(path23.join(repo_root2, token))) {
|
|
19355
19406
|
stale.push(
|
|
19356
19407
|
`line ${it.line} (${it.label}): recheck_when \`${token}\` now exists \u2014 re-verify against the real mechanism`
|
|
19357
19408
|
);
|
|
19358
19409
|
}
|
|
19359
19410
|
}
|
|
19411
|
+
if (paths.length > 0) {
|
|
19412
|
+
continue;
|
|
19413
|
+
}
|
|
19414
|
+
for (const token of tokens) {
|
|
19415
|
+
unverifiable.push(`line ${it.line} (${it.label}): recheck_when \`${token}\``);
|
|
19416
|
+
}
|
|
19360
19417
|
}
|
|
19361
19418
|
return { stale, unverifiable };
|
|
19362
19419
|
}
|
|
@@ -19435,8 +19492,8 @@ __export(update_roadmap_progress_exports, {
|
|
|
19435
19492
|
collect: () => collect,
|
|
19436
19493
|
collect_bundles: () => collect_bundles,
|
|
19437
19494
|
count_checkboxes: () => count_checkboxes,
|
|
19438
|
-
is_draft: () => is_draft,
|
|
19439
19495
|
is_roadmap_candidate: () => is_roadmap_candidate,
|
|
19496
|
+
is_unscheduled: () => is_unscheduled,
|
|
19440
19497
|
main: () => main10,
|
|
19441
19498
|
merge_gated_pending: () => merge_gated_pending,
|
|
19442
19499
|
parse_blockers: () => parse_blockers,
|
|
@@ -19492,8 +19549,8 @@ function _stripQuotes2(s) {
|
|
|
19492
19549
|
out = out.replace(/^'+/, "").replace(/'+$/, "");
|
|
19493
19550
|
return out;
|
|
19494
19551
|
}
|
|
19495
|
-
function
|
|
19496
|
-
return
|
|
19552
|
+
function is_unscheduled(fm) {
|
|
19553
|
+
return UNSCHEDULED_VALUES.has((fm["status"] ?? "").toLowerCase());
|
|
19497
19554
|
}
|
|
19498
19555
|
function is_roadmap_name(name) {
|
|
19499
19556
|
if (EXCLUDE_NAMES.has(name)) {
|
|
@@ -19785,7 +19842,7 @@ function collect(roadmap_root) {
|
|
|
19785
19842
|
continue;
|
|
19786
19843
|
}
|
|
19787
19844
|
const text = fs25.readFileSync(p, { encoding: "utf-8" });
|
|
19788
|
-
if (
|
|
19845
|
+
if (is_unscheduled(parse_frontmatter2(text))) {
|
|
19789
19846
|
continue;
|
|
19790
19847
|
}
|
|
19791
19848
|
const stats = parse_roadmap(p, roadmap_root);
|
|
@@ -19815,7 +19872,7 @@ function collect_parked(roadmap_root) {
|
|
|
19815
19872
|
} catch {
|
|
19816
19873
|
continue;
|
|
19817
19874
|
}
|
|
19818
|
-
if (
|
|
19875
|
+
if (is_unscheduled(parse_frontmatter2(text))) {
|
|
19819
19876
|
continue;
|
|
19820
19877
|
}
|
|
19821
19878
|
const cell = resume_cell(text);
|
|
@@ -20270,7 +20327,7 @@ function _isCliEntry10() {
|
|
|
20270
20327
|
return false;
|
|
20271
20328
|
}
|
|
20272
20329
|
}
|
|
20273
|
-
var _HERE7, _require3, CHECKBOX_RE, PHASE_RE, TITLE_RE, EXCLUDE_NAMES, EXCLUDE_PREFIXES, EXCLUDE_DIRS, FRONTMATTER_RE,
|
|
20330
|
+
var _HERE7, _require3, CHECKBOX_RE, PHASE_RE, TITLE_RE, EXCLUDE_NAMES, EXCLUDE_PREFIXES, EXCLUDE_DIRS, FRONTMATTER_RE, UNSCHEDULED_VALUES, MERGE_GATED_RE, PR_NUM_RE, PhaseStats, RoadmapStats, FENCED_CODE_RE, BLOCKERS_SECTION_RE, BLOCKER_HEADING_RE, NEXT_H2_RE, LEGACY_BLOCKED_UNTIL_RE, BLOCKER_FIELD_RE, RESUME_STATEMENT, RESUME_LOOSE, ArgparseExit, _PROG5;
|
|
20274
20331
|
var init_update_roadmap_progress = __esm({
|
|
20275
20332
|
"src/agent-src/scripts/update_roadmap_progress.ts"() {
|
|
20276
20333
|
"use strict";
|
|
@@ -20292,7 +20349,7 @@ var init_update_roadmap_progress = __esm({
|
|
|
20292
20349
|
EXCLUDE_PREFIXES = ["open-questions"];
|
|
20293
20350
|
EXCLUDE_DIRS = /* @__PURE__ */ new Set(["archive", "skipped", "stubs", "later"]);
|
|
20294
20351
|
FRONTMATTER_RE = /^---\n([\s\S]*?)\n---[ \t\n\r\f\v]*\n/;
|
|
20295
|
-
|
|
20352
|
+
UNSCHEDULED_VALUES = /* @__PURE__ */ new Set(["draft", "carrier"]);
|
|
20296
20353
|
MERGE_GATED_RE = /merge-gated/i;
|
|
20297
20354
|
PR_NUM_RE = /pr[ \t\n\r\f\v]*[=#:]?[ \t\n\r\f\v]*#?[ \t\n\r\f\v]*(\d+)/gi;
|
|
20298
20355
|
PhaseStats = class {
|
|
@@ -20432,6 +20489,7 @@ __export(archive_completed_roadmaps_exports, {
|
|
|
20432
20489
|
_git_mv: () => _git_mv,
|
|
20433
20490
|
_inbound_ref_rewrite: () => _inbound_ref_rewrite,
|
|
20434
20491
|
_is_frozen_record: () => _is_frozen_record,
|
|
20492
|
+
_relatesTo: () => _relatesTo,
|
|
20435
20493
|
_repo_root: () => _repo_root,
|
|
20436
20494
|
archive_completed: () => archive_completed,
|
|
20437
20495
|
deferralProblems: () => deferralProblems,
|
|
@@ -36552,11 +36610,48 @@ function humanAuthoredLead(text) {
|
|
|
36552
36610
|
}
|
|
36553
36611
|
return kept.join("\n");
|
|
36554
36612
|
}
|
|
36555
|
-
|
|
36613
|
+
function stripInjectedRegions(text) {
|
|
36614
|
+
const lines = text.split("\n");
|
|
36615
|
+
const kept = [];
|
|
36616
|
+
for (let i = 0; i < lines.length; i++) {
|
|
36617
|
+
const line = lines[i] ?? "";
|
|
36618
|
+
const open = REGION_OPEN.exec(line);
|
|
36619
|
+
if (open === null) {
|
|
36620
|
+
kept.push(line);
|
|
36621
|
+
continue;
|
|
36622
|
+
}
|
|
36623
|
+
const close = new RegExp(`^\\s*</${open[1] ?? ""}>\\s*$`);
|
|
36624
|
+
let end = -1;
|
|
36625
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
36626
|
+
if (close.test(lines[j] ?? "")) {
|
|
36627
|
+
end = j;
|
|
36628
|
+
break;
|
|
36629
|
+
}
|
|
36630
|
+
}
|
|
36631
|
+
if (end === -1) {
|
|
36632
|
+
kept.push(line);
|
|
36633
|
+
continue;
|
|
36634
|
+
}
|
|
36635
|
+
if (kept.length > 0 && REGION_NOTE.test(kept[kept.length - 1] ?? "")) {
|
|
36636
|
+
kept.pop();
|
|
36637
|
+
}
|
|
36638
|
+
i = end;
|
|
36639
|
+
while (i + 1 < lines.length && (lines[i + 1] ?? "").trim() !== "") {
|
|
36640
|
+
if (!REGION_NOTE.test(lines[i + 1] ?? "")) {
|
|
36641
|
+
break;
|
|
36642
|
+
}
|
|
36643
|
+
i++;
|
|
36644
|
+
}
|
|
36645
|
+
}
|
|
36646
|
+
return kept.join("\n");
|
|
36647
|
+
}
|
|
36648
|
+
var DOCUMENT_HEAD, REGION_OPEN, REGION_NOTE;
|
|
36556
36649
|
var init_prompt_shape = __esm({
|
|
36557
36650
|
"src/scripts/_lib/prompt_shape.ts"() {
|
|
36558
36651
|
"use strict";
|
|
36559
36652
|
DOCUMENT_HEAD = /^\s*(#{1,6}\s|-{3,}\s*$|={3,}\s*$|<[A-Za-z][\w-]*>\s*$)/;
|
|
36653
|
+
REGION_OPEN = /^\s*<([A-Za-z][\w-]*)>\s*$/;
|
|
36654
|
+
REGION_NOTE = /\b(content (above|below) is from|treat (it|this|that|the (content|text|above|following)) as data)\b/i;
|
|
36560
36655
|
}
|
|
36561
36656
|
});
|
|
36562
36657
|
|
|
@@ -36599,7 +36694,7 @@ function instructionText(prompt) {
|
|
|
36599
36694
|
return kept.join("\n");
|
|
36600
36695
|
}
|
|
36601
36696
|
function classify(prompt) {
|
|
36602
|
-
const text = instructionText(prompt);
|
|
36697
|
+
const text = instructionText(stripInjectedRegions(prompt));
|
|
36603
36698
|
const lead = humanAuthoredLead(text);
|
|
36604
36699
|
const leadVerdict = _score2(lead);
|
|
36605
36700
|
if (leadVerdict.language !== "und") {
|
|
@@ -34,6 +34,6 @@ Tooling, all of it in `guarded_baseline.ts` and enforced by both consumers:
|
|
|
34
34
|
| Reported **separately**: a `## 🛡️ Guarded baselines` dashboard section plus a per-step stderr line | `update_roadmap_progress` |
|
|
35
35
|
| **Rejected** — exit 1, on both `--check` and a plain regen — when `red_proof` is absent, when `category` is absent or illegal, when there is no evidence block, or when the annotation sits on anything but `- [ ]` | `update_roadmap_progress` |
|
|
36
36
|
| Treated as **incomplete**: archival refused and the reason named | `archive_completed_roadmaps` |
|
|
37
|
-
| Marked **stale** once a path-shaped `recheck_when` trigger resolves in the tree
|
|
37
|
+
| Marked **stale** once a path-shaped `recheck_when` trigger resolves in the tree. A trigger carrying **no** path token at all is reported as not machine-checkable rather than as not-stale; a trigger carrying at least one path token is decided by that path and is **not** reported, even when a companion symbol token sits beside it — a checked trigger that looks unchecked is the mirror of the failure the report exists to prevent (measured 2026-09-01: 3 of 4 reported lines were already decidable) | `guardedBaselineStaleness` |
|
|
38
38
|
|
|
39
39
|
Only verification against the real mechanism permits `[x]`. **A baseline that has not demonstrably gone RED is an ordinary open item** and must not carry the annotation at all — the sabotage-and-restore proof is the entry price, not a nice-to-have.
|
|
@@ -315,6 +315,24 @@ Behavioral baseline: `tests/code-comments/eval-fixtures.md`
|
|
|
315
315
|
`ccd-untouched-preservation`, `ccd-explicit-teaching-override`); the decidable
|
|
316
316
|
criteria are proven by `tests/scripts/code_comment_fixtures.test.ts`.
|
|
317
317
|
|
|
318
|
+
### Evidence belongs in the roadmap that asked for it
|
|
319
|
+
|
|
320
|
+
Measured 2026-09-02 in a consumer repository: **509 German comment lines** and
|
|
321
|
+
**21 report- or provenance-shaped comments** across **41 of 45** changed source
|
|
322
|
+
files, the worst a 101-line colour-analysis report inside a CSS file. The cause
|
|
323
|
+
was a roadmap requiring proof for every checked step: the run read that as
|
|
324
|
+
*evidence should be documented* and wrote the measurements into the source too,
|
|
325
|
+
where the roadmap already carried them.
|
|
326
|
+
|
|
327
|
+
The provenance of a value is not a WHY, and a roadmap cannot license a comment
|
|
328
|
+
the rule forbids.
|
|
329
|
+
|
|
330
|
+
Two enforcers carry this because neither rule could fire on a write:
|
|
331
|
+
`code-comment-discipline` matches prompt keywords, and `language-and-tone`'s
|
|
332
|
+
English-comment clause named a `.md`-only validator. `lint_code_comments`
|
|
333
|
+
refuses on the diff; the `comment-discipline` concern reports on the text as
|
|
334
|
+
written. Neither replaces the discipline.
|
|
335
|
+
|
|
318
336
|
## See also
|
|
319
337
|
|
|
320
338
|
- Language-specific anchors that link to this guideline:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@event4u/agent-config",
|
|
3
3
|
"mcpName": "io.github.event4u-app/agent-config",
|
|
4
|
-
"version": "14.
|
|
4
|
+
"version": "14.14.0",
|
|
5
5
|
"description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) — every claim machine-checked, including the counts in these badges.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"private": false,
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
* `urp.collect()` completion criterion, and exit code 0. snake_case kept.
|
|
13
13
|
*
|
|
14
14
|
* A roadmap that has reached `count_open == 0` and `count_deferred == 0` is
|
|
15
|
-
* **complete**. This sweep moves it to `agents/roadmaps/archive/`, rewrites
|
|
16
|
-
* inbound references (`agents/roadmaps/<x>.md` → `agents/roadmaps/archive/<x>.md`)
|
|
15
|
+
* **complete**. This sweep moves it to `agents/roadmaps/archive/`, rewrites code-comment-allow provenance-comment -- the sweep's own operand
|
|
16
|
+
* inbound references (`agents/roadmaps/<x>.md` → `agents/roadmaps/archive/<x>.md`) code-comment-allow provenance-comment -- the rewrite this sweep performs
|
|
17
17
|
* across tracked files so links never break, and regenerates the dashboard.
|
|
18
18
|
*
|
|
19
19
|
* It replaces the old **merge-gate** (keep one item open + a manual post-merge
|
|
@@ -136,7 +136,7 @@ function _branch_touched_paths(root: string, base: string): Set<string> | null {
|
|
|
136
136
|
*
|
|
137
137
|
* Two classes, and the second is why this predicate exists at all:
|
|
138
138
|
*
|
|
139
|
-
* - `agents/evidence/**` — a committed record of what was true, or of what a
|
|
139
|
+
* - `agents/evidence/**` — a committed record of what was true, or of what a code-comment-allow provenance-comment -- the predicate's operand set
|
|
140
140
|
* reviewer was shown, at one point in time. Retroactively editing it makes it
|
|
141
141
|
* claim something that did not happen, which is the failure
|
|
142
142
|
* `evaluator-independence` exists to prevent ("the prompt ships with the
|
|
@@ -146,7 +146,7 @@ function _branch_touched_paths(root: string, base: string): Set<string> | null {
|
|
|
146
146
|
* AND makes `git apply` target a path the diff never created.
|
|
147
147
|
*
|
|
148
148
|
* Measured 2026-08-11: archiving one roadmap rewrote four frozen artifacts
|
|
149
|
-
* under `agents/evidence/reviews/`, including the `diff.patch` headers of a
|
|
149
|
+
* under `agents/evidence/reviews/`, including the `diff.patch` headers of a code-comment-allow provenance-comment -- names what the predicate protects
|
|
150
150
|
* recorded review input. Nothing caught it — the sweep reported it as
|
|
151
151
|
* "4 ref(s) migrated", which reads like success.
|
|
152
152
|
*/
|
|
@@ -346,7 +346,7 @@ function _escapeRe(v: string): string {
|
|
|
346
346
|
* bare `- <name>` item inside the `relates:` block, which is a declaration the
|
|
347
347
|
* author made deliberately. A mention anywhere else in the file does not count.
|
|
348
348
|
*/
|
|
349
|
-
function _relatesTo(text: string, slug: string): boolean {
|
|
349
|
+
export function _relatesTo(text: string, slug: string): boolean {
|
|
350
350
|
const lines = text.split('\n');
|
|
351
351
|
const start = lines.findIndex((l) => /^relates:/.test(l));
|
|
352
352
|
if (start === -1) return false;
|
|
@@ -654,7 +654,7 @@ function _regen_dashboard(root: string, dry_run: boolean): void {
|
|
|
654
654
|
/**
|
|
655
655
|
* Rebuild the archive index after a move, when the builder is present.
|
|
656
656
|
*
|
|
657
|
-
* The sweep is the one operation that changes what `agents/roadmaps/archive/`
|
|
657
|
+
* The sweep is the one operation that changes what `agents/roadmaps/archive/` code-comment-allow provenance-comment -- the directory this function writes
|
|
658
658
|
* contains, so it is the one operation that can leave the generated index
|
|
659
659
|
* stale — and the drift gate on that index runs in the same PR the sweep runs
|
|
660
660
|
* in. Regenerating here keeps the two from disagreeing by construction rather
|
|
@@ -226,9 +226,18 @@ export function guardedBaselineProblems(items: readonly GuardedBaselineItem[]):
|
|
|
226
226
|
*
|
|
227
227
|
* HONEST SCOPE. Only a PATH trigger is machine-checkable: a token containing `/`
|
|
228
228
|
* is resolved against the repo root and stale iff it exists. A bare symbol name
|
|
229
|
-
* cannot be decided from a path, so
|
|
230
|
-
* silently reading as "not stale" — an
|
|
231
|
-
* the failure this whole state exists
|
|
229
|
+
* cannot be decided from a path, so a record carrying ONLY symbol tokens is
|
|
230
|
+
* returned as `unverifiable` rather than silently reading as "not stale" — an
|
|
231
|
+
* unchecked trigger that looks checked is the failure this whole state exists
|
|
232
|
+
* to avoid.
|
|
233
|
+
*
|
|
234
|
+
* A record whose trigger carries AT LEAST ONE path token is decided by that
|
|
235
|
+
* path and is NOT reported as unverifiable, even when a companion symbol token
|
|
236
|
+
* sits beside it. Reporting it would be the mirror of the failure above: a
|
|
237
|
+
* checked trigger that looks unchecked. Measured 2026-09-01 — three of the four
|
|
238
|
+
* lines the dashboard printed as "not machine-checkable" carried a path token
|
|
239
|
+
* and were therefore already decidable, which is noise that trains a reader to
|
|
240
|
+
* skip the section where the one genuinely undecidable trigger also lives.
|
|
232
241
|
*/
|
|
233
242
|
export function guardedBaselineStaleness(
|
|
234
243
|
items: readonly GuardedBaselineItem[],
|
|
@@ -241,16 +250,22 @@ export function guardedBaselineStaleness(
|
|
|
241
250
|
if (trigger === '') {
|
|
242
251
|
continue;
|
|
243
252
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
253
|
+
const tokens = trigger.split(/[\s,]+/).filter((t) => t !== '');
|
|
254
|
+
const paths = tokens.filter((t) => t.includes('/'));
|
|
255
|
+
for (const token of paths) {
|
|
256
|
+
if (fs.existsSync(path.join(repo_root, token))) {
|
|
248
257
|
stale.push(
|
|
249
258
|
`line ${it.line} (${it.label}): recheck_when \`${token}\` now exists — ` +
|
|
250
259
|
're-verify against the real mechanism',
|
|
251
260
|
);
|
|
252
261
|
}
|
|
253
262
|
}
|
|
263
|
+
if (paths.length > 0) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
for (const token of tokens) {
|
|
267
|
+
unverifiable.push(`line ${it.line} (${it.label}): recheck_when \`${token}\``);
|
|
268
|
+
}
|
|
254
269
|
}
|
|
255
270
|
return { stale, unverifiable };
|
|
256
271
|
}
|
|
@@ -66,6 +66,48 @@ export interface StubRecord {
|
|
|
66
66
|
owner_decisions: number;
|
|
67
67
|
overdue: boolean;
|
|
68
68
|
days_overdue: number | null;
|
|
69
|
+
/** Frontmatter `design_validated:` — a citation, or null when absent. */
|
|
70
|
+
design_validated: string | null;
|
|
71
|
+
/** Frontmatter `capability_gap:` — `none` means the stub declares no gap. */
|
|
72
|
+
capability_gap: string | null;
|
|
73
|
+
/** Frontmatter `blocker_class:` — `estate` | `budget` | `product`. */
|
|
74
|
+
blocker_class: string | null;
|
|
75
|
+
/** Frontmatter `blocker_opened:` — ISO date the hold began, or null. */
|
|
76
|
+
blocker_opened: string | null;
|
|
77
|
+
/** Releases published since `blocker_opened`, or null when it is absent. */
|
|
78
|
+
releases_since_blocked: number | null;
|
|
79
|
+
/** All three membership conditions hold. See {@link BLOCKED_QUICKWIN_FIELDS}. */
|
|
80
|
+
blocked_quickwin: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The three frontmatter keys that decide fourth-bucket membership.
|
|
85
|
+
*
|
|
86
|
+
* Read as SCALARS, never as substrings of the body. A substring match over
|
|
87
|
+
* prose is what put a validated fix and a waiting preference into one bucket
|
|
88
|
+
* in the first place; doing it with three substrings instead of one would be
|
|
89
|
+
* worse, not better. A stub missing any of the three is not a member and falls
|
|
90
|
+
* through to the OWNER bucket exactly as before — absence is never a member.
|
|
91
|
+
*/
|
|
92
|
+
export const BLOCKED_QUICKWIN_FIELDS = ['design_validated', 'capability_gap', 'blocker_class'] as const;
|
|
93
|
+
|
|
94
|
+
/** Blocker classes that make a stub a BLOCKED QUICK-WIN rather than a product wait. */
|
|
95
|
+
export const QUICKWIN_BLOCKER_CLASSES = ['estate', 'budget'] as const;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* All three conditions, read from frontmatter only.
|
|
99
|
+
*
|
|
100
|
+
* A recorded design validation, an explicit `capability_gap: none`, and an open
|
|
101
|
+
* blocker that is an estate or budget decision rather than a product one.
|
|
102
|
+
*/
|
|
103
|
+
export function is_blocked_quickwin(
|
|
104
|
+
design_validated: string | null,
|
|
105
|
+
capability_gap: string | null,
|
|
106
|
+
blocker_class: string | null,
|
|
107
|
+
): boolean {
|
|
108
|
+
if (design_validated === null || design_validated === '') return false;
|
|
109
|
+
if (capability_gap !== 'none') return false;
|
|
110
|
+
return (QUICKWIN_BLOCKER_CLASSES as readonly string[]).includes(blocker_class ?? '');
|
|
69
111
|
}
|
|
70
112
|
|
|
71
113
|
function _isDir(p: string): boolean {
|
|
@@ -188,7 +230,48 @@ function _parseIso(s: string): Date | null {
|
|
|
188
230
|
|
|
189
231
|
/** Read every stub and classify it. `today` is injectable so tests are stable. */
|
|
190
232
|
export function scan(root: string, today: string): StubRecord[] {
|
|
191
|
-
return scan_dir(path.join(root, STUB_DIR), today);
|
|
233
|
+
return scan_dir(path.join(root, STUB_DIR), today, release_dates(root));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Changelog files that carry released sections, newest era first.
|
|
238
|
+
*
|
|
239
|
+
* BOTH are read, and that is the whole point of the pair. The era split moved
|
|
240
|
+
* older releases into the archive, so a count taken over the current file alone
|
|
241
|
+
* silently reports zero for anything before the split — measured: 14.11.0 lives
|
|
242
|
+
* only in the archive, and grepping `CHANGELOG.md` for it returns nothing.
|
|
243
|
+
*/
|
|
244
|
+
export const CHANGELOG_ERAS = ['CHANGELOG.md', 'docs/archive/CHANGELOG-pre-14.12.0.md'] as const;
|
|
245
|
+
|
|
246
|
+
/** `## [x.y.z](…) (YYYY-MM-DD)` — a released section heading with its date. */
|
|
247
|
+
const RELEASE_HEADING = /^## \[\d+\.\d+\.\d+\][^\n]*\((\d{4}-\d{2}-\d{2})\)\s*$/gm;
|
|
248
|
+
|
|
249
|
+
/** Every released section's date across both eras, unsorted. */
|
|
250
|
+
export function release_dates(root: string): string[] {
|
|
251
|
+
const out: string[] = [];
|
|
252
|
+
for (const rel of CHANGELOG_ERAS) {
|
|
253
|
+
let text: string;
|
|
254
|
+
try {
|
|
255
|
+
text = fs.readFileSync(path.join(root, rel), 'utf8');
|
|
256
|
+
} catch {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
for (const m of text.matchAll(RELEASE_HEADING)) {
|
|
260
|
+
if (m[1] !== undefined) out.push(m[1]);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return out;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Releases published strictly AFTER the day the hold began.
|
|
268
|
+
*
|
|
269
|
+
* Strictly after, because a release cut on the same day cannot have carried a
|
|
270
|
+
* fix the hold was blocking — counting it would inflate the figure the
|
|
271
|
+
* council's falsifier is read against.
|
|
272
|
+
*/
|
|
273
|
+
export function releases_since(opened: string, dates: readonly string[]): number {
|
|
274
|
+
return dates.filter((d) => d > opened).length;
|
|
192
275
|
}
|
|
193
276
|
|
|
194
277
|
/**
|
|
@@ -198,7 +281,11 @@ export function scan(root: string, today: string): StubRecord[] {
|
|
|
198
281
|
* immediately re-join — a fragile round trip past exactly the directory both
|
|
199
282
|
* callers care about.
|
|
200
283
|
*/
|
|
201
|
-
export function scan_dir(
|
|
284
|
+
export function scan_dir(
|
|
285
|
+
base: string,
|
|
286
|
+
today: string,
|
|
287
|
+
releaseDates: readonly string[] = [],
|
|
288
|
+
): StubRecord[] {
|
|
202
289
|
if (!_isDir(base)) return [];
|
|
203
290
|
const now = _parseIso(today);
|
|
204
291
|
const out: StubRecord[] = [];
|
|
@@ -222,6 +309,10 @@ export function scan_dir(base: string, today: string): StubRecord[] {
|
|
|
222
309
|
const review_by = _scalar(front, 'review_by');
|
|
223
310
|
const reviewed_at = _scalar(front, 'reviewed_at');
|
|
224
311
|
const probeVal = _scalar(front, 'probe');
|
|
312
|
+
const design_validated = _scalar(front, 'design_validated');
|
|
313
|
+
const capability_gap = _scalar(front, 'capability_gap');
|
|
314
|
+
const blocker_class = _scalar(front, 'blocker_class');
|
|
315
|
+
const blocker_opened = _scalar(front, 'blocker_opened');
|
|
225
316
|
const shape: StubShape = text.includes(TRANSFER_MARKER) ? 'transfer' : 'orgmode';
|
|
226
317
|
let overdue = false;
|
|
227
318
|
let days_overdue: number | null = null;
|
|
@@ -242,6 +333,13 @@ export function scan_dir(base: string, today: string): StubRecord[] {
|
|
|
242
333
|
owner_decisions: count_owner_decisions(text),
|
|
243
334
|
overdue,
|
|
244
335
|
days_overdue,
|
|
336
|
+
design_validated,
|
|
337
|
+
capability_gap,
|
|
338
|
+
blocker_class,
|
|
339
|
+
blocker_opened,
|
|
340
|
+
releases_since_blocked:
|
|
341
|
+
blocker_opened === null ? null : releases_since(blocker_opened, releaseDates),
|
|
342
|
+
blocked_quickwin: is_blocked_quickwin(design_validated, capability_gap, blocker_class),
|
|
245
343
|
});
|
|
246
344
|
}
|
|
247
345
|
return out;
|
|
@@ -251,6 +349,8 @@ export interface Counts {
|
|
|
251
349
|
overdue: number;
|
|
252
350
|
owner_decisions: number;
|
|
253
351
|
missing_review_by: number;
|
|
352
|
+
/** ADDITIVE 2026-09-01. Existing keys are unchanged in name, type and meaning. */
|
|
353
|
+
blocked_quickwin: number;
|
|
254
354
|
total: number;
|
|
255
355
|
}
|
|
256
356
|
|
|
@@ -259,6 +359,7 @@ export function counts(records: StubRecord[]): Counts {
|
|
|
259
359
|
overdue: records.filter((r) => r.overdue).length,
|
|
260
360
|
owner_decisions: records.reduce((s, r) => s + r.owner_decisions, 0),
|
|
261
361
|
missing_review_by: records.filter((r) => r.review_by === null).length,
|
|
362
|
+
blocked_quickwin: records.filter((r) => r.blocked_quickwin).length,
|
|
262
363
|
total: records.length,
|
|
263
364
|
};
|
|
264
365
|
}
|
|
@@ -328,6 +429,21 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
|
328
429
|
}
|
|
329
430
|
}
|
|
330
431
|
|
|
432
|
+
const quickwins = records.filter((r) => r.blocked_quickwin);
|
|
433
|
+
if (quickwins.length > 0) {
|
|
434
|
+
process.stdout.write(
|
|
435
|
+
`\n 🔓 ${quickwins.length} BLOCKED QUICK-WIN(S) — design validated, no capability gap,\n` +
|
|
436
|
+
' held by an estate or budget decision rather than a product one:\n',
|
|
437
|
+
);
|
|
438
|
+
for (const r of quickwins) {
|
|
439
|
+
const since =
|
|
440
|
+
r.releases_since_blocked === null
|
|
441
|
+
? 'no `blocker_opened:`'
|
|
442
|
+
: `${String(r.releases_since_blocked)} release(s) since ${r.blocker_opened}`;
|
|
443
|
+
process.stdout.write(` ${r.file} (${r.blocker_class}, ${since})\n`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
331
447
|
const noProbe = records.filter((r) => !r.probe_none && !r.has_probe_heading);
|
|
332
448
|
if (noProbe.length > 0) {
|
|
333
449
|
process.stdout.write(
|