@event4u/agent-config 10.2.0 → 10.3.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +110 -276
- package/dist/agent-src/commands/analyze/reference-repo.md +62 -0
- package/dist/agent-src/commands/roadmap/create.md +4 -1
- package/dist/agent-src/personas/advisors/first-principles.md +6 -0
- package/dist/agent-src/rules/active-remediation.md +53 -2
- package/dist/agent-src/rules/code-provenance.md +66 -4
- package/dist/agent-src/rules/content-quoting-floor.md +6 -0
- package/dist/agent-src/rules/design-fidelity.md +49 -3
- package/dist/agent-src/skills/design-review/references/verification-automation.md +23 -1
- package/dist/agent-src/skills/fe-design/SKILL.md +27 -3
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +30 -0
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +11 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +8 -8
- package/dist/agent-src/skills/skill-writing/SKILL.md +4 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/persona.md +26 -0
- package/dist/agent-src/templates/roadmaps.md +27 -7
- package/dist/agent-src/templates/skill.md +35 -1
- package/dist/cli/commands/commands.candidates.test.js +257 -0
- package/dist/cli/commands/commands.candidates.test.js.map +1 -0
- package/dist/cli/commands/commands.js +199 -0
- package/dist/cli/commands/commands.js.map +1 -1
- package/dist/cli/main.js +1 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-E4RUZKXB.js → chunk-FV34EGEX.js} +1 -1
- package/dist/cli-delegate/cmd_conformance.js +1 -1
- package/dist/cli-delegate/cmd_doctor.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +13 -13
- 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 +116 -24
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1 -1
- package/dist/router.json +1 -1
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +54 -0
- package/docs/guidelines/design-antipatterns.md +79 -10
- package/docs/guidelines/design-fidelity-mechanics.md +120 -2
- package/package.json +1 -1
- package/src/config/gate-coverage.yml +42 -8
- package/src/config/gate-violation-baselines.json +6 -0
- package/src/config/review-prompt-binding-baseline.json +19 -0
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/scripts/_dispatch.bash +1 -0
- package/src/scripts/ai_council/clients.ts +15 -1
- package/src/scripts/check_ci_local_parity.ts +60 -6
- package/src/scripts/check_review_prompt_binding.ts +553 -0
- package/src/scripts/check_suppression_hygiene.ts +19 -3
- package/src/scripts/design_slop_rules.test.ts +37 -6
- package/src/scripts/design_slop_rules.ts +150 -22
- package/src/scripts/dispatch_r2_reviewer.ts +15 -1
- package/src/scripts/hooks/ui_route_nudge_hook.ts +55 -2
- package/src/scripts/lint_design_antipattern_parity.ts +201 -0
- package/src/scripts/lint_harvest_provenance.ts +483 -0
- package/src/scripts/lint_skill_router_head.ts +254 -0
- package/src/scripts/report_consultation_rate.ts +126 -1
- package/src/scripts/run_skill_evals.ts +10 -5
- package/src/scripts/schemas/persona.schema.json +8 -0
- package/src/scripts/schemas/provenance-harvest.schema.json +39 -0
- package/src/scripts/sweep_dead_scan_roots.ts +51 -0
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": "10.
|
|
4
|
+
"version": "10.3.0",
|
|
5
5
|
"description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) — every claim machine-checked, including \"zero runtime daemon\".",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"private": false,
|
|
@@ -40,16 +40,29 @@
|
|
|
40
40
|
# visible, or it repeats the sin it exists to catch.
|
|
41
41
|
# canary optional mutation recipe (Phase 7) — see CANARY below
|
|
42
42
|
#
|
|
43
|
-
# COVERAGE — THE HONEST DENOMINATOR (re-measured 2026-08-
|
|
43
|
+
# COVERAGE — THE HONEST DENOMINATOR (re-measured 2026-08-13)
|
|
44
44
|
# ----------------------------------------------------------
|
|
45
|
-
#
|
|
45
|
+
# 257 `lint_*` / `check_*` / `audit_*` scripts live under `src/scripts/`
|
|
46
46
|
# (the count is computed, not asserted — `check_gate_coverage.count_gate_scripts`).
|
|
47
|
-
# **
|
|
48
|
-
# CI-identical argv, and all
|
|
49
|
-
# complete with respect to its own contract, and covers ~
|
|
50
|
-
# (The 2026-08-05 reading said "32 … and all 31 are listed"
|
|
51
|
-
#
|
|
52
|
-
#
|
|
47
|
+
# **35 of them emit the machine-readable `scanned: <N>` line under their
|
|
48
|
+
# CI-identical argv, and all 35 are listed below.** The manifest is therefore
|
|
49
|
+
# complete with respect to its own contract, and covers ~14 % of the population.
|
|
50
|
+
# (The 2026-08-05 reading said "32 … and all 31 are listed"; the 2026-08-10
|
|
51
|
+
# reading said "33 … and all 33" while 34 entries were listed. Both halves are
|
|
52
|
+
# RECOUNTED here: 257 is what `count_gate_scripts()` returns on the tree that
|
|
53
|
+
# carries this change, and 35 is the entries counted directly. It read 255 while
|
|
54
|
+
# this change was being written and 257 after `main` merged in two further gate
|
|
55
|
+
# scripts — re-measured at the merge rather than left at the earlier reading,
|
|
56
|
+
# which is the same discipline the note below records failing.)
|
|
57
|
+
#
|
|
58
|
+
# A 2026-08-13 revision of this paragraph first wrote 256, derived as "255 before
|
|
59
|
+
# this change plus the one it adds" — inside the sentence claiming to have
|
|
60
|
+
# recounted. It was wrong twice over: 255 was already the reading WITH the new
|
|
61
|
+
# script present, and arithmetic on the previous prose is the exact move this
|
|
62
|
+
# paragraph forbids. Recorded rather than quietly corrected, because a
|
|
63
|
+
# denominator that goes stale by being adjusted is the failure documented here
|
|
64
|
+
# twice before, and the third instance is the one that shows the note is not
|
|
65
|
+
# enough on its own.
|
|
53
66
|
#
|
|
54
67
|
# Two revisions of this header have now gone stale the same way. It claimed
|
|
55
68
|
# "8 of 211", then "22 of 223" while 26 entries were listed. Both halves drift
|
|
@@ -677,6 +690,27 @@ gates:
|
|
|
677
690
|
a gate scanning nothing — it plants the removal-permitting class with no
|
|
678
691
|
evidence and the gate reds.
|
|
679
692
|
|
|
693
|
+
- id: check_review_prompt_binding
|
|
694
|
+
argv: []
|
|
695
|
+
min_scanned: 15
|
|
696
|
+
corpus: "agents/evidence/reviews/<slug>.review-input/prompt.md paired with a prompt_hash in <slug>.findings.md (19 at baseline)"
|
|
697
|
+
status: enforced
|
|
698
|
+
canary:
|
|
699
|
+
class: unbound-review-prompt
|
|
700
|
+
path: agents/evidence/reviews/zcs-closure.review-input/prompt.md
|
|
701
|
+
content: |
|
|
702
|
+
Planted canary: a reviewer prompt whose sha256 cannot equal the
|
|
703
|
+
prompt_hash recorded in zcs-closure.findings.md.
|
|
704
|
+
note: >
|
|
705
|
+
The plant needs a slug that already carries a `prompt_hash` but no committed
|
|
706
|
+
package — a brand-new `zz-canary` slug is skipped, not caught, because an
|
|
707
|
+
artefact without a package is deliberately out of scope. `zcs-closure` is a
|
|
708
|
+
closed round, so it will not gain a real package and the plant cannot
|
|
709
|
+
collide with one. The two planted failures the roadmap asked for (a one-byte
|
|
710
|
+
prompt edit, a pre-loaded verdict) are pinned in
|
|
711
|
+
tests/scripts/check_review_prompt_binding.test.ts, which is where the
|
|
712
|
+
two-file plants this single-file recipe cannot express are exercised.
|
|
713
|
+
|
|
680
714
|
- id: check_corpus_staleness
|
|
681
715
|
argv: ["--quiet", "--today", "2026-08-06"]
|
|
682
716
|
min_scanned: 5
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "Violation ratchet for gates whose dead scan root was repaired. A repair REVEALS pre-existing debt; it does not create it. Each entry records the count revealed at repair time — the gate fails only when its count RISES. Lowering a count is a normal commit; raising one is a defect. Entries expire: a baseline that has not dropped within 56 days of `landed` (or of `reaffirmed.date`) fails its gate, because a number that never moves is suppression with extra steps. Mechanism + rationale: src/scripts/_lib/gate_baseline.ts. Decision: AI council 2026-08-02, roadmap road-to-gates-that-can-fail blocker `dead-gate-finding-triage`.",
|
|
3
3
|
"gates": {
|
|
4
|
+
"ci-parity:local-only": {
|
|
5
|
+
"count": 167,
|
|
6
|
+
"landed": "2026-08-13",
|
|
7
|
+
"note": "Gates that `task ci` runs and no workflow does — the direction this manifest's own header calls the one that let real defects merge (16 stale index rows reached the trunk behind a local-only check-index). Revealed, not created, by repairing the checker's extraction: check_ci_local_parity built its CI-side set by regexing RAW workflow text for `task <name>` and expanding each closure, comments included. Several workflow comments contain the literal string `task ci` while stating that no workflow invokes it, so `ci` was read as an invocation and its full 247-gate closure entered the 'runs in CI' set. The count was therefore 0 BY CONSTRUCTION, and the prose documenting the gap was what suppressed it. Measured at the repair: CI-side 273 → 106, undeclared_local_only 0 → 167 of 247 local gates (68%). Baselined rather than hard-failed because 167 findings nobody can clear in the change that reveals them is the gate-that-lands-as-N-instant-blockers failure this repository has refused before; shrink-only keeps the property that matters, namely that a NEW gate registered in `task ci` with no workflow reds immediately. Lowering happens by wiring gates into workflows or declaring them under `local_only:` with a reason. Note the punchline, because it bounds the risk of this entry: check_ci_local_parity ITSELF runs in no workflow, so it is its own finding and this ratchet has no remote reach either — clearing the backlog is what gives it teeth.",
|
|
8
|
+
"falsifier": "./scripts-run src/scripts/check_ci_local_parity"
|
|
9
|
+
},
|
|
4
10
|
"check_no_new_legacy_path:hardcoded-scan-roots": {
|
|
5
11
|
"count": 48,
|
|
6
12
|
"landed": "2026-08-09",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema_note": "Consumed by src/scripts/check_review_prompt_binding.ts. An entry EXEMPTS one committed review prompt from the sha256(prompt.md) == prompt_hash check. Both hashes are pinned on purpose: if either moves, the entry stops matching and the gate reds, so a later repair and a further corruption are equally visible. A pre-loaded verdict is NEVER suppressed by the hash exemption alone — it needs its own `steered_ack` block on the entry, which pins the exact matched phrase, so growth of the shared steering predicate cannot turn committed prompts into permanent unfixable blocks and cannot be waved through silently either.",
|
|
3
|
+
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"slug": "zcs-close-2026-08-09",
|
|
6
|
+
"declared": "48eae5ad829b375c4667fcd72ecc482cbd62ae90788134ca46a81eacce267d49",
|
|
7
|
+
"actual": "f83ee959abb7f8c333bc89f117d3dee93f0e7b2a816c4593471aeda9b18c302d",
|
|
8
|
+
"reason": "Explained and closed at the cause: the archival sweep rewrote a roadmap path INSIDE this committed reviewer prompt while migrating inbound references. The cause was fixed on 2026-08-11 by _FROZEN_RECORD_PREFIXES in the sweep. Not repaired because repair is not available here: the recorded hash was produced by the ORIGINAL prompt text, so rewriting the hash to match the corrupted text would fabricate a binding that never existed, and restoring the text from history would erase the only evidence that the sweep reached inside a committed round at all. An earlier revision of this entry cited section 2.7 as forbidding the edit; that citation was wrong and is corrected here, because section 2.7 says the rename is an archival step and never an edit ban on a live artefact.",
|
|
9
|
+
"falsifier": "npx tsx src/scripts/check_review_prompt_binding.ts --json # the recorded actual hash stops matching the committed prompt.md, i.e. the record moved after all"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"slug": "feat-parallel-session-collision-hardening",
|
|
13
|
+
"declared": "d996e8e86a6e21a7cad66963f70219e59fe8cb96bca0bd1adceeea7ad2565c4b",
|
|
14
|
+
"actual": "dae1f14e90be94e71415e520b08222ea819488188d670de280d874803de1035c",
|
|
15
|
+
"reason": "Current and UNEXPLAINED, and it is the empirical justification for this gate. The prompt.md has a single commit dated 2026-08-12, after the sweep fix, so the sweep did not cause it; the declared hash never matched the committed text. CRLF/LF and trailing-newline variants were all tried and none reproduces the declared hash. Not repaired because no repair is knowable: with the cause unidentified, neither side can be established as the correct one, and editing either to make them agree would assert a binding nobody has evidence for. Recording it keeps the discrepancy visible until someone can explain it.",
|
|
16
|
+
"falsifier": "npx tsx src/scripts/check_review_prompt_binding.ts --json # a cause is found and the entry is replaced by the repair, or the recorded actual hash stops matching"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -80,6 +80,7 @@ TS-shell native (run via the installed `agent-config` binary):
|
|
|
80
80
|
Names the degraded case (settings file without a
|
|
81
81
|
profile.id → zero packs) that nothing else reports.
|
|
82
82
|
commands [ls|explain] List/explain the command surface from the discovery manifest
|
|
83
|
+
(ls --candidates: surface-reduction report, report-only)
|
|
83
84
|
mcp-server Turnkey read-only stdio MCP server (no repo clone; ADR-085)
|
|
84
85
|
doctor-shell Probe the TS-shell environment
|
|
85
86
|
rtk:detect rtk (Rust Token Killer) presence + identity readout (--json)
|
|
@@ -949,7 +949,21 @@ export const CLI_CALLS_FILENAME = 'cli-calls.json';
|
|
|
949
949
|
// Default subprocess timeout (seconds) for a single CLI call. Long enough for
|
|
950
950
|
// the largest frontier models to think; short enough to surface a hung
|
|
951
951
|
// subprocess without freezing the council run.
|
|
952
|
-
|
|
952
|
+
//
|
|
953
|
+
// Raised 120 → 300 (2026-08-13) to match the API transport, which has carried
|
|
954
|
+
// `--max-time 290` / `timeout: 300_000` since the 2026-06-24 repair of the same
|
|
955
|
+
// symptom. That repair landed in `_curlJsonPost` only, so when a member resolves
|
|
956
|
+
// to `cli · subscription` the old cap was still live — and a deep design run
|
|
957
|
+
// reproduced it exactly: both members returned `error: timeout` at
|
|
958
|
+
// `latency_ms: 122921` with `timeout_seconds: 120`, and the run reported
|
|
959
|
+
// `0/2 present — INCONCLUSIVE`.
|
|
960
|
+
//
|
|
961
|
+
// This is not a comfort setting. A council that cannot finish a deep prompt is
|
|
962
|
+
// a council the agent cannot use, and every question it would have answered
|
|
963
|
+
// falls back to interrupting the user — the routing that
|
|
964
|
+
// `decision_resolution` classes `medium_impact → council` depends on this
|
|
965
|
+
// call completing.
|
|
966
|
+
export const DEFAULT_CLI_TIMEOUT_SECONDS = 300.0;
|
|
953
967
|
|
|
954
968
|
/** Return the canonical write target for the daily-quota counter. */
|
|
955
969
|
function _cliCallsStatePath(): string {
|
|
@@ -30,6 +30,8 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
30
30
|
|
|
31
31
|
import { parse as parseYaml } from 'yaml';
|
|
32
32
|
|
|
33
|
+
import { checkRatchet } from './_lib/gate_baseline.js';
|
|
34
|
+
|
|
33
35
|
const _FILE = fileURLToPath(import.meta.url);
|
|
34
36
|
export const REPO = path.resolve(path.dirname(_FILE), '..', '..');
|
|
35
37
|
const MANIFEST = path.join(REPO, 'src', 'config', 'ci-local-parity.yml');
|
|
@@ -202,13 +204,49 @@ export function local_closure(roots: readonly string[], tasks: Map<string, TaskD
|
|
|
202
204
|
return gates;
|
|
203
205
|
}
|
|
204
206
|
|
|
207
|
+
/**
|
|
208
|
+
* Drop YAML comments before anything is extracted from a workflow.
|
|
209
|
+
*
|
|
210
|
+
* WHY, and it is the defect this checker was blind to for its whole life. The CI
|
|
211
|
+
* side is built by regexing workflow TEXT for `task <name>` and expanding each
|
|
212
|
+
* name's closure. Several workflow comments contain the literal string
|
|
213
|
+
* `task ci` — while stating that **no workflow invokes it**:
|
|
214
|
+
*
|
|
215
|
+
* # invokes `task ci`, so a gate registered only there never runs remotely.
|
|
216
|
+
* # …NO workflow invokes `task ci`, `ci-strict`, or …
|
|
217
|
+
*
|
|
218
|
+
* Read as an invocation, `ci` expanded to its full closure and put all 247
|
|
219
|
+
* `task ci` gates into the "runs in CI" set. `undeclared_local_only` was
|
|
220
|
+
* therefore **0 by construction** — the one direction this manifest's own header
|
|
221
|
+
* calls the one that let real defects merge could not be reported at all, and the
|
|
222
|
+
* prose documenting the gap was what suppressed it.
|
|
223
|
+
*
|
|
224
|
+
* Measured at the repair: CI-side 273 → 106, `undeclared_local_only` 0 → 167 of
|
|
225
|
+
* 247 local gates. A checker whose extraction invents coverage is worse than
|
|
226
|
+
* none, which this file already says about a different extraction bug ten lines
|
|
227
|
+
* up — the same lesson, learned twice.
|
|
228
|
+
*
|
|
229
|
+
* Deliberately crude: a `#` inside a quoted YAML scalar is treated as a comment
|
|
230
|
+
* start. That direction is safe here — it can only make the checker see LESS
|
|
231
|
+
* wiring, i.e. over-report drift, never invent coverage. A YAML parse would be
|
|
232
|
+
* exact, but every workflow would have to be structurally valid for the checker
|
|
233
|
+
* to run at all, and a parity checker that cannot run on a malformed workflow is
|
|
234
|
+
* a parity checker that goes quiet exactly when someone is editing CI.
|
|
235
|
+
*/
|
|
236
|
+
export function strip_yaml_comments(text: string): string {
|
|
237
|
+
return text
|
|
238
|
+
.split('\n')
|
|
239
|
+
.map((l) => l.replace(/(^|\s)#.*$/, '$1'))
|
|
240
|
+
.join('\n');
|
|
241
|
+
}
|
|
242
|
+
|
|
205
243
|
function _read_all(dir: string): string {
|
|
206
244
|
if (!fs.existsSync(dir)) return '';
|
|
207
245
|
return fs
|
|
208
246
|
.readdirSync(dir)
|
|
209
247
|
.filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'))
|
|
210
248
|
.sort()
|
|
211
|
-
.map((f) => fs.readFileSync(path.join(dir, f), 'utf-8'))
|
|
249
|
+
.map((f) => strip_yaml_comments(fs.readFileSync(path.join(dir, f), 'utf-8')))
|
|
212
250
|
.join('\n');
|
|
213
251
|
}
|
|
214
252
|
|
|
@@ -332,17 +370,33 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
|
332
370
|
' Undeclared, it means a contributor discovers this failure only after pushing.\n',
|
|
333
371
|
);
|
|
334
372
|
}
|
|
335
|
-
|
|
373
|
+
// Ratcheted, not listed one by one.
|
|
374
|
+
//
|
|
375
|
+
// Repairing the comment-blindness above took this count from 0 to 167 in one
|
|
376
|
+
// step — pre-existing debt the checker could not see, not new breakage. A hard
|
|
377
|
+
// fail on 167 findings nobody can clear in the change that reveals them is the
|
|
378
|
+
// gate that lands as N instant blockers, which this repository has recorded as
|
|
379
|
+
// a failure mode and refused before. A shrink-only count keeps the property
|
|
380
|
+
// that matters: the number may not RISE, so a gate added to `task ci` with no
|
|
381
|
+
// workflow reds immediately, which is the regression this direction exists to
|
|
382
|
+
// catch. Listing all 167 every run would bury that signal in its own noise.
|
|
383
|
+
const parity = checkRatchet({
|
|
384
|
+
gate: 'ci-parity:local-only',
|
|
385
|
+
actual: r.undeclared_local_only.length,
|
|
386
|
+
repoRoot: REPO,
|
|
387
|
+
});
|
|
388
|
+
if (!parity.ok) {
|
|
336
389
|
failed = true;
|
|
337
|
-
process.stdout.write(
|
|
338
|
-
`❌ ${String(r.undeclared_local_only.length)} gate(s) run locally but in no workflow:\n`,
|
|
339
|
-
);
|
|
390
|
+
process.stdout.write(`❌ ${parity.message}\n`);
|
|
340
391
|
for (const g of r.undeclared_local_only) process.stdout.write(` - ${g}\n`);
|
|
341
392
|
process.stdout.write(
|
|
342
393
|
'\n Prefer adding it to a workflow — this is the direction that let real defects\n' +
|
|
343
394
|
' merge (16 stale index rows reached main behind a local-only check-index).\n' +
|
|
344
|
-
' If remote enforcement is genuinely not wanted, declare it under `local_only:`.\n'
|
|
395
|
+
' If remote enforcement is genuinely not wanted, declare it under `local_only:`.\n' +
|
|
396
|
+
' Raising the baseline is a defect, not a fix.\n',
|
|
345
397
|
);
|
|
398
|
+
} else {
|
|
399
|
+
process.stdout.write(`ℹ️ ${parity.message}\n`);
|
|
346
400
|
}
|
|
347
401
|
if (r.stale_declarations.length > 0) {
|
|
348
402
|
failed = true;
|