@event4u/agent-config 14.18.0 → 14.20.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 (210) 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 +120 -129
  5. package/README.md +71 -149
  6. package/dist/agent-src/README.md +1 -1
  7. package/dist/agent-src/commands/agent-handoff.md +44 -43
  8. package/dist/agent-src/commands/review/changes.md +19 -19
  9. package/dist/agent-src/commands/review.md +2 -2
  10. package/dist/agent-src/contexts/execution/host-capability-manifest.md +37 -4
  11. package/dist/agent-src/rules/autonomous-execution.md +1 -1
  12. package/dist/agent-src/rules/git-history-discipline.md +2 -2
  13. package/dist/agent-src/rules/guidelines.md +1 -1
  14. package/dist/agent-src/rules/session-canary.md +2 -2
  15. package/dist/agent-src/rules/token-efficiency.md +1 -1
  16. package/dist/agent-src/rules/untrusted-input-defense.md +0 -2
  17. package/dist/agent-src/skills/adversarial-review/SKILL.md +0 -8
  18. package/dist/agent-src/skills/canvas-design/SKILL.md +1 -1
  19. package/dist/agent-src/skills/design-intelligence/SKILL.md +1 -1
  20. package/dist/agent-src/skills/design-intelligence/data/app-interface.csv +1 -1
  21. package/dist/agent-src/skills/design-intelligence/data/motion.csv +17 -17
  22. package/dist/agent-src/skills/design-intelligence/data/ux-guidelines.csv +2 -2
  23. package/dist/agent-src/skills/design-intelligence/references/context-and-registers.md +17 -0
  24. package/dist/agent-src/skills/design-intelligence/references/design-rules-checklist.md +4 -4
  25. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  26. package/dist/agent-src/skills/design-variations/SKILL.md +1 -1
  27. package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +1 -1
  28. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +1 -1
  29. package/dist/agent-src/skills/fe-design/SKILL.md +32 -5
  30. package/dist/agent-src/skills/fe-design/references/craft-floor.md +7 -0
  31. package/dist/agent-src/skills/fe-design/references/design-patterns.md +47 -2
  32. package/dist/agent-src/skills/laravel-scheduling/SKILL.md +3 -1
  33. package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
  34. package/dist/agent-src/skills/project-analyzer/SKILL.md +0 -6
  35. package/dist/agent-src/skills/react-native-setup/SKILL.md +3 -3
  36. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  37. package/dist/agent-src/skills/sequential-thinking/SKILL.md +18 -8
  38. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +28 -6
  39. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  40. package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -3
  41. package/dist/agent-src/skills/ui-apply-generic/SKILL.md +1 -1
  42. package/dist/agent-src/skills/ui-component-architect/SKILL.md +1 -1
  43. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +17 -2
  44. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  45. package/dist/agent-src/templates/roadmaps.md +14 -1
  46. package/dist/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
  47. package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
  48. package/dist/agent-src/templates/scripts/telemetry_report.ts +22 -2
  49. package/dist/cli/commands/recordTriggerEval.js +2 -2
  50. package/dist/cli/main.js +1 -1
  51. package/dist/cli/mcp/dispatch.js +10 -0
  52. package/dist/cli/mcp/stdio.js +33 -2
  53. package/dist/cli/mcp/telemetry.js +227 -0
  54. package/dist/cli-delegate/{chunk-AKJGUQNO.js → chunk-C6IPZRDA.js} +484 -353
  55. package/dist/cli-delegate/{chunk-CYH5SP6M.js → chunk-I6RHFQEG.js} +151 -16
  56. package/dist/cli-delegate/{chunk-7RXIKF62.js → chunk-NUMQHLS5.js} +304 -136
  57. package/dist/cli-delegate/{chunk-PMEKGDED.js → chunk-PI2GU3DP.js} +163 -1
  58. package/dist/cli-delegate/{chunk-7PRE6ZV2.js → chunk-YS6XTLEK.js} +199 -4
  59. package/dist/cli-delegate/chunk-ZVBOHSVF.js +1109 -0
  60. package/dist/cli-delegate/cmd_adr_effective.js +318 -81
  61. package/dist/cli-delegate/cmd_conformance.js +489 -121
  62. package/dist/cli-delegate/cmd_doctor.js +2 -2
  63. package/dist/cli-delegate/cmd_export.js +2 -2
  64. package/dist/cli-delegate/cmd_handoff.js +42 -12
  65. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  66. package/dist/cli-delegate/cmd_prune.js +2 -2
  67. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  68. package/dist/cli-delegate/cmd_session_recycle.js +59 -902
  69. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  70. package/dist/cli-delegate/cmd_sync.js +2 -2
  71. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  72. package/dist/cli-delegate/cmd_validate.js +2 -2
  73. package/dist/discovery/deprecation-report.md +1 -1
  74. package/dist/discovery/discovery-manifest.json +34 -33
  75. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  76. package/dist/discovery/discovery-manifest.summary.md +1 -1
  77. package/dist/discovery/dormancy-report.md +1 -1
  78. package/dist/discovery/orphan-report.md +1 -1
  79. package/dist/discovery/packs.json +2 -2
  80. package/dist/discovery/trust-report.md +1 -1
  81. package/dist/discovery/workspaces.json +2 -2
  82. package/dist/hooks/dispatch.js +4455 -3025
  83. package/dist/install/install.mjs +975 -689
  84. package/dist/mcp/registry-manifest.json +2 -2
  85. package/dist/mcp/server.json +2 -2
  86. package/dist/mcp/server.mjs +2087 -1134
  87. package/dist/scripts/_lib/model_tier.js +1 -1
  88. package/dist/scripts/mcp_server/telemetry.js +148 -0
  89. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +1 -1
  90. package/docs/guidelines/agent-infra/naming.md +1 -1
  91. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  92. package/docs/guidelines/agent-infra/security-lint-containment.md +46 -6
  93. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +4 -4
  94. package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +1 -1
  95. package/docs/guidelines/design-antipatterns.md +87 -64
  96. package/docs/guidelines/redundancy-taxonomy.md +28 -0
  97. package/package.json +1 -1
  98. package/src/agent-src/README.md +1 -1
  99. package/src/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
  100. package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
  101. package/src/agent-src/templates/scripts/telemetry_report.ts +22 -2
  102. package/src/config/assurance-capability-registry.json +9 -0
  103. package/src/config/ci-local-parity.yml +6 -0
  104. package/src/config/gate-coverage.yml +225 -0
  105. package/src/config/gate-violation-baselines.json +18 -6
  106. package/src/config/release-gate-locality.yml +12 -0
  107. package/src/scripts/_cli/cmd_doctor.ts +2 -2
  108. package/src/scripts/_cli/cmd_handoff.ts +1 -1
  109. package/src/scripts/_cli/cmd_session_recycle.ts +51 -3
  110. package/src/scripts/_cli/cmd_update.ts +1 -1
  111. package/src/scripts/_cli/cmd_versions.ts +1 -1
  112. package/src/scripts/_lib/adr_frontmatter.ts +44 -0
  113. package/src/scripts/_lib/audit_field_provenance.ts +44 -3
  114. package/src/scripts/_lib/consequence_objects.ts +152 -0
  115. package/src/scripts/_lib/exec_evidence.ts +7 -0
  116. package/src/scripts/_lib/global_deploy_inventory.ts +2 -2
  117. package/src/scripts/_lib/host_capability.ts +38 -0
  118. package/src/scripts/_lib/host_permission_checks.ts +251 -0
  119. package/src/scripts/_lib/install_reach_checks.ts +33 -1
  120. package/src/scripts/_lib/mcp_bridge.ts +222 -10
  121. package/src/scripts/_lib/mcp_consent_residual.ts +173 -0
  122. package/src/scripts/_lib/model_tier.ts +1 -1
  123. package/src/scripts/_lib/obligation_frequency.ts +2 -2
  124. package/src/scripts/_lib/orchestration_record.ts +23 -1
  125. package/src/scripts/_lib/recycle_envelope_paths.ts +190 -0
  126. package/src/scripts/_lib/release_highlights.ts +93 -0
  127. package/src/scripts/_lib/release_material.ts +64 -1
  128. package/src/scripts/_lib/release_position.ts +96 -0
  129. package/src/scripts/_lib/review_skipped_record.ts +17 -1
  130. package/src/scripts/_lib/runtime_journal.ts +26 -3
  131. package/src/scripts/_lib/runtime_wiring_checks.ts +12 -1
  132. package/src/scripts/_lib/security_lint.ts +179 -7
  133. package/src/scripts/_lib/self_repair.ts +141 -6
  134. package/src/scripts/_lib/self_repair_store.ts +273 -7
  135. package/src/scripts/_lib/session_register.ts +11 -6
  136. package/src/scripts/_lib/sqlite_schema.ts +22 -0
  137. package/src/scripts/_lib/subagent_capsule.ts +155 -3
  138. package/src/scripts/_lib/surface.ts +86 -0
  139. package/src/scripts/_lib/ui_authority.ts +116 -0
  140. package/src/scripts/adr/regenerate_index.ts +54 -1
  141. package/src/scripts/adr_cite_check.ts +71 -15
  142. package/src/scripts/ai_council/clients.ts +1 -1
  143. package/src/scripts/autonomy_friction_corpus.ts +229 -0
  144. package/src/scripts/build_proof.ts +15 -2
  145. package/src/scripts/build_rule_trigger_matrix.ts +5 -0
  146. package/src/scripts/check_beta_review_markers.ts +141 -17
  147. package/src/scripts/check_enforcement_coverage.ts +1 -1
  148. package/src/scripts/check_enforcement_denominator.ts +121 -11
  149. package/src/scripts/check_finding_dispositions.ts +66 -9
  150. package/src/scripts/check_gate_coverage.ts +96 -0
  151. package/src/scripts/check_mcp_doc_drift.ts +217 -0
  152. package/src/scripts/check_pack_size.ts +321 -3
  153. package/src/scripts/check_release_highlights.ts +74 -1
  154. package/src/scripts/check_skill_activation_claim.ts +179 -0
  155. package/src/scripts/check_trigger_evals.ts +1 -1
  156. package/src/scripts/conformance_scan.ts +44 -3
  157. package/src/scripts/explain_run.ts +1 -1
  158. package/src/scripts/generate_capability_matrix.ts +1 -1
  159. package/src/scripts/git_authorization_hook.ts +75 -1
  160. package/src/scripts/handoff_context_hook.ts +54 -7
  161. package/src/scripts/hook_manifest.json +1 -1
  162. package/src/scripts/hook_manifest.yaml +14 -11
  163. package/src/scripts/hooks/augment-dispatcher.sh +1 -1
  164. package/src/scripts/hooks/category_a.ts +291 -0
  165. package/src/scripts/hooks/cline-dispatcher.sh +1 -1
  166. package/src/scripts/hooks/cursor-dispatcher.sh +11 -5
  167. package/src/scripts/hooks/dispatch_hook.ts +17 -22
  168. package/src/scripts/hooks/git_command_classifier.ts +156 -1
  169. package/src/scripts/hooks/host_lowering.ts +215 -0
  170. package/src/scripts/hooks/host_lowering.yaml +185 -0
  171. package/src/scripts/hooks/host_semantics.ts +105 -37
  172. package/src/scripts/hooks/journal_record_hook.ts +10 -0
  173. package/src/scripts/hooks/permission_gate.ts +117 -0
  174. package/src/scripts/hooks/session_eol_hook.ts +18 -7
  175. package/src/scripts/hooks_status.ts +12 -10
  176. package/src/scripts/install.ts +57 -86
  177. package/src/scripts/install_anthropic_key.sh +2 -2
  178. package/src/scripts/lint_agent_security.ts +316 -25
  179. package/src/scripts/lint_confusables.ts +42 -6
  180. package/src/scripts/lint_design_antipattern_parity.ts +80 -0
  181. package/src/scripts/lint_evidence_artifacts.ts +45 -1
  182. package/src/scripts/lint_handoffs.ts +0 -132
  183. package/src/scripts/lint_hidden_unicode.ts +49 -7
  184. package/src/scripts/lint_hook_manifest.ts +87 -3
  185. package/src/scripts/lint_instruction_smuggling.ts +42 -6
  186. package/src/scripts/lint_mcp_config_security.ts +42 -6
  187. package/src/scripts/lint_motion_authority_drift.ts +731 -0
  188. package/src/scripts/lint_readme_size.ts +158 -12
  189. package/src/scripts/lint_reasoning_fixtures.ts +216 -0
  190. package/src/scripts/lint_roadmap_later_disposition.ts +217 -27
  191. package/src/scripts/lint_skill_frontmatter_safety.ts +43 -7
  192. package/src/scripts/lint_skill_trigger_contradiction.ts +161 -0
  193. package/src/scripts/mcp_server/resources.ts +41 -0
  194. package/src/scripts/mcp_server/telemetry.ts +19 -4
  195. package/src/scripts/measure_sibling_naming.ts +150 -0
  196. package/src/scripts/orchestration_record.ts +12 -1
  197. package/src/scripts/redact_hook_capture.ts +1 -1
  198. package/src/scripts/release.ts +24 -24
  199. package/src/scripts/release_publication.ts +6 -2
  200. package/src/scripts/report_skill_activation.ts +319 -7
  201. package/src/scripts/schemas/review-findings.schema.json +5 -0
  202. package/src/scripts/schemas/skill.schema.json +2 -2
  203. package/src/scripts/self_repair_cli.ts +31 -1
  204. package/src/scripts/session_canary_hook.ts +1 -1
  205. package/src/scripts/session_register_hook.ts +4 -3
  206. package/src/scripts/skill_scout.ts +69 -0
  207. package/src/scripts/trigger_eval_grandfather.json +5 -1
  208. package/src/scripts/validate_agent_settings.ts +1 -1
  209. package/dist/cli-delegate/chunk-2GNWGMAL.js +0 -172
  210. package/dist/cli-delegate/chunk-LPPWO5CE.js +0 -161
@@ -11,7 +11,7 @@
11
11
  * - the repo generator (`condense.py generate_claude_skills`), which
12
12
  * builds the package's own `.claude/skills/` tree, and
13
13
  * - the consumer install finalizer
14
- * (`install.py finalize_claude_model_tiers`), which rewrites the
14
+ * (the installer's `finalize_claude_model_tiers`), which rewrites the
15
15
  * installed `.claude/skills/` tree so Claude Code performs the
16
16
  * per-turn model switch on a consumer with `model.auto_switch: auto`.
17
17
  *
@@ -0,0 +1,148 @@
1
+ // MCP telemetry sink — Phase 1 J4 instrumentation.
2
+ //
3
+ // Per `agents/roadmaps/archive/road-to-mcp-full-coverage.md` §Phase 1 J4 +
4
+ // `docs/contracts/mcp-tool-stub-envelope.md`, both transports log every
5
+ // `tools/call` with `{tool_name, client_id_hash, ts, transport,
6
+ // outcome}`. The stdio-lite surface (`src/cli/mcp/`) appends a sixth,
7
+ // optional `host` field; callers that do not know their client omit it and
8
+ // their records stay byte-identical to the frozen five-field envelope. Payload bodies are never logged; the client identifier is
9
+ // hashed at the server boundary so the queryable store never sees raw
10
+ // identity.
11
+ //
12
+ // Outcomes:
13
+ //
14
+ // - `implemented` — real handler ran (no envelope returned).
15
+ // - `stub` — catalog entry missing this transport; `not_implemented`
16
+ // envelope returned.
17
+ // - `latent_demand` — caller asked for a tool not in the catalog.
18
+ //
19
+ // The sink writes JSONL to `agents/runtime/mcp-telemetry/calls.jsonl` under the
20
+ // consumer root. Failure to write must not break the wire surface: the
21
+ // `record_call` helper swallows OSError + ValueError and emits a single
22
+ // warning to stderr.
23
+ //
24
+ // TS port of the retired Python telemetry.py (ADR-200). Preserves the full public surface:
25
+ // - Outcome type, TELEMETRY_REL_DIR, TELEMETRY_FILENAME, hash_client_id,
26
+ // build_record, record_call.
27
+ import * as crypto from 'node:crypto';
28
+ import * as fs from 'node:fs';
29
+ import * as os from 'node:os';
30
+ import * as path from 'node:path';
31
+ // Stable file location relative to consumer_root. Phase 2 K1 routes
32
+ // this into a queryable store; Phase 1 only needs the file to exist.
33
+ export const TELEMETRY_REL_DIR = 'agents/runtime/mcp-telemetry';
34
+ export const TELEMETRY_FILENAME = 'calls.jsonl';
35
+ // Truncation length for the client_id hash. 12 hex chars = 48 bits of
36
+ // entropy — enough to distinguish hundreds of consumers without
37
+ // becoming a re-identification vector.
38
+ const _HASH_LEN = 12;
39
+ /**
40
+ * Identity components that together pin a consumer install.
41
+ *
42
+ * USER + machine hostname + repo path is a stable triple that survives
43
+ * sessions without leaking PII into the log. The hash never reverses.
44
+ */
45
+ function _client_id_seed() {
46
+ const user = process.env.USER || process.env.USERNAME || 'unknown';
47
+ let host = process.env.HOSTNAME;
48
+ if (!host) {
49
+ // Mirrors Python `os.uname().nodename` (POSIX) — Node exposes
50
+ // `os.hostname()`. Guarded so an empty value falls through to "unknown".
51
+ try {
52
+ host = os.hostname();
53
+ }
54
+ catch {
55
+ host = undefined;
56
+ }
57
+ }
58
+ host = host || 'unknown';
59
+ const cwd = _resolvePath(process.cwd());
60
+ return `${user}|${host}|${cwd}`;
61
+ }
62
+ /** SHA-256(seed) truncated to 12 hex chars. Boundary-only call. */
63
+ export function hash_client_id(seed) {
64
+ const raw = seed !== undefined ? seed : _client_id_seed();
65
+ const digest = crypto.createHash('sha256').update(Buffer.from(raw, 'utf-8')).digest('hex');
66
+ return digest.slice(0, _HASH_LEN);
67
+ }
68
+ /**
69
+ * Resolve a path like Python `Path(...).resolve()` — absolutize + realpath
70
+ * the existing prefix, tolerating a non-existent tail (Python resolve does
71
+ * not require the path to exist; `fs.realpathSync` does, so fall back to a
72
+ * plain absolute path on ENOENT).
73
+ */
74
+ function _resolvePath(p) {
75
+ try {
76
+ return fs.realpathSync(p);
77
+ }
78
+ catch {
79
+ return path.resolve(p);
80
+ }
81
+ }
82
+ /** Pick the JSONL location. Defaults to CWD when no override given. */
83
+ function _resolve_log_path(consumer_root) {
84
+ const root = _resolvePath(consumer_root ?? process.cwd());
85
+ return path.join(root, TELEMETRY_REL_DIR, TELEMETRY_FILENAME);
86
+ }
87
+ /** ISO-8601 UTC timestamp, seconds precision. */
88
+ function _now_iso() {
89
+ // Mirrors Python `time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())`.
90
+ return new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
91
+ }
92
+ /**
93
+ * Pure helper — assemble the record without touching the filesystem.
94
+ *
95
+ * Field insertion order matches the Python dict literal so the
96
+ * compact-JSON serialization is byte-identical.
97
+ */
98
+ export function build_record(options) {
99
+ const { tool_name, outcome, transport, client_id_hash_value, ts, host } = options;
100
+ const record = {
101
+ tool_name,
102
+ client_id_hash: client_id_hash_value || hash_client_id(),
103
+ ts: ts || _now_iso(),
104
+ transport,
105
+ outcome,
106
+ };
107
+ // `host` is APPENDED, and only when a caller supplies one, so a record
108
+ // written by a caller that does not know its client stays byte-identical
109
+ // to the five-field envelope the stub contract froze. It is a closed
110
+ // vocabulary resolved at the boundary (see `src/cli/mcp/telemetry.ts`),
111
+ // never a free-form string: a record type that cannot hold arbitrary text
112
+ // has no scrubber to fail.
113
+ if (typeof host === 'string' && host !== '') {
114
+ record.host = host;
115
+ }
116
+ return record;
117
+ }
118
+ /**
119
+ * Append one JSONL record. Returns the record or null on failure.
120
+ *
121
+ * Failures are swallowed: telemetry must never break the wire surface.
122
+ * A single `mcp-server: warn: telemetry` line is emitted to stderr
123
+ * so silent-failure windows show up in the boot log and the J6
124
+ * healthcheck can detect them.
125
+ */
126
+ export function record_call(options) {
127
+ const { tool_name, outcome, transport, consumer_root, client_id_hash_value, host } = options;
128
+ const record = build_record({
129
+ tool_name,
130
+ outcome,
131
+ transport,
132
+ client_id_hash_value,
133
+ host,
134
+ });
135
+ const target = _resolve_log_path(consumer_root ?? undefined);
136
+ try {
137
+ fs.mkdirSync(path.dirname(target), { recursive: true });
138
+ // json.dumps(record, separators=(",", ":")) — compact, no spaces.
139
+ fs.appendFileSync(target, JSON.stringify(record) + '\n', { encoding: 'utf-8' });
140
+ }
141
+ catch (exc) {
142
+ const message = exc instanceof Error ? exc.message : String(exc);
143
+ process.stderr.write(`mcp-server: warn: telemetry write failed: ${message}\n`);
144
+ return null;
145
+ }
146
+ return record;
147
+ }
148
+ //# sourceMappingURL=telemetry.js.map
@@ -51,7 +51,7 @@ drew.** It said `pre_tool_use` "exists on three hosts" and that the guard has
51
51
  tree. **Downward:** the manifest's own `native_event_aliases` table already maps
52
52
  `preToolUse` (cursor), `PreToolUse` (cline) and `BeforeTool` (gemini) onto
53
53
  `pre_tool_use`, so there the guard is **unbound, not unbindable**; only windsurf
54
- and copilot carry no pre-tool surface at all. **Upward, and worse:**
54
+ and copilot carry no pre-tool alias row at all. **Upward, and worse:**
55
55
  `host_semantics.ts` certifies **claude alone**, and the augment and cowork
56
56
  trampolines discard dispatcher output and `exit 0` unconditionally — so on two
57
57
  of the three "enforcing" hosts this guard runs and is then ignored. Nor may the
@@ -34,7 +34,7 @@ source: package
34
34
  |---|---|---|
35
35
  | `{concern}` | Behavioral constraint | `scope-control`, `ask-when-uncertain` |
36
36
  | `{domain}-{concern}` | Domain-specific rule | `php-coding`, `e2e-testing` |
37
- | `{action}-{target}` | Trigger-based auto rule | `capture-learnings`, `downstream-changes` |
37
+ | `{action}-{target}` | Trigger-based auto rule | `invite-challenge`, `downstream-changes` |
38
38
 
39
39
  ### Commands
40
40
 
@@ -19,7 +19,7 @@ _Origin: migrated from `.agent-src.uncondensed/rules/roadmap-progress-sync.md` p
19
19
  > stale dashboard even if local hooks were bypassed.
20
20
  >
21
21
  > Hook is primary; the prose below is the specification the hook
22
- > implements and the fallback when the platform has no hook surface.
22
+ > implements and the fallback where no hook is bound on the platform.
23
23
 
24
24
  ## Iron Law — dashboard sync
25
25
 
@@ -45,18 +45,51 @@ are *expected* to contain illustrative patterns. Only a full-weight (1.0×)
45
45
  **HIGH** finding in a real artifact fails the build. (`is_example_path()` in the
46
46
  shared lib defines the path set.)
47
47
 
48
- ### 3. Per-file pragma
48
+ ### 3. Bound pragma
49
49
 
50
- A single check can be suppressed for one file with an auditable, reasoned
51
- marker placed anywhere in the file:
50
+ A single check can be suppressed for **specific evidence** in one file with an
51
+ auditable, reasoned, content-bound marker placed anywhere in the file:
52
52
 
53
53
  ```
54
- <!-- security-lint: allow instruction-smuggling "teaching example: quotes a prompt-injection string" -->
54
+ <!-- security-lint: allow instruction-smuggling "teaching example: quotes a prompt-injection string" sha256:<hex> -->
55
55
  ```
56
56
 
57
57
  - The `<check>` token is the linter's check id (`hidden-unicode`,
58
- `instruction-smuggling`, `mcp-config-security`, `dangerous-frontmatter`).
58
+ `mixed-script-confusable`, `instruction-smuggling`, `mcp-config-security`,
59
+ `dangerous-frontmatter`).
59
60
  - The `"<reason>"` is **mandatory** — an empty reason does not parse.
61
+ - Each `sha256:<hex>` **binds the suppression to one accepted match**. Repeat the
62
+ token once per accepted match; a file with three accepted matches carries three
63
+ hashes. Anything the check finds that is not in that set is still reported.
64
+ - The fingerprint covers the **check id**, the artifact's **source identity**, and
65
+ the **normalized text of the matched line** — ASCII whitespace runs collapse so
66
+ a reflow does not break the binding, and nothing else is stripped, because the
67
+ zero-width characters this suite hunts are exactly what a wider normalizer
68
+ would erase. It is deliberately NOT the line number (an unrelated insert above
69
+ would break every pragma in the file) and NOT the whole file (every unrelated
70
+ edit would re-fire it, which is how blanket suppressions get written).
71
+ A `dist/agent-src/` path folds to its `src/` original first: the projection is
72
+ byte-exact by contract, so an artifact and its copy are one identity.
73
+ - **A pair pinned equal by a parity test carries ONE HASH PER IDENTITY.** The
74
+ fold above covers `dist/agent-src/` and nothing else, so where a second
75
+ hand-maintained copy exists and a test asserts the two are byte-identical —
76
+ `src/subagents/<stem>.md` and `docs/wedge/<stem>/<stem>.md`, pinned by
77
+ `tests/scripts/subagent_distribution.test.ts` — one hash cannot satisfy both:
78
+ giving each file its own makes the lines differ and reds the parity test,
79
+ which is exactly how this was found. Put BOTH hashes in BOTH files. That is
80
+ what the repeatable token is for, and it is why the grammar has one. A purely
81
+ GENERATED third copy (`.claude/agents/<stem>.md`) needs no hash of its own:
82
+ nothing scans it and nobody edits it, so binding it would be a fingerprint
83
+ for an identity no finding can arise at.
84
+ - Compute one with the linter itself, never by hand — a hash typed from memory
85
+ is a suppression nobody audited.
86
+
87
+ **The unbound form still parses**, suppresses the whole file as it always did,
88
+ and reports itself as a `legacy-pragma` LOW finding. That is a migration signal,
89
+ not a mode to choose: a key lookup with no content binding accepts whatever the
90
+ matched text is later changed to say, which is the defect the hash exists to
91
+ close. There are zero unbound pragmas in the tree.
92
+
60
93
  - Pragmas are **counted and capped**: crossing **20** across the repo means the
61
94
  linter is mis-scoped. Stop adding pragmas; redesign or narrow the check
62
95
  (escalate per `autonomous-execution` — the allowlist-growth antipattern).
@@ -72,7 +105,14 @@ marker placed anywhere in the file:
72
105
 
73
106
  `security-example` fence → confidence weight → pragma. A HIGH finding survives
74
107
  to fail the build only when it is full-weight (not in an example path), not
75
- inside a `security-example` fence, and not covered by a matching pragma.
108
+ inside a `security-example` fence, and not covered by a pragma whose fingerprint
109
+ set contains that match.
110
+
111
+ One consumer deliberately departs from the weighting rung: `skill_scout`'s
112
+ `security_licence` gate refuses a quarantined candidate on **any** HIGH finding,
113
+ whatever its weight. Path-based confidence is a false-positive containment device
114
+ for a corpus whose provenance is known; a third-party candidate has none, and a
115
+ directory named `examples/` in it is the submitter's word for it.
76
116
 
77
117
  ## See also
78
118
 
@@ -4,10 +4,10 @@ Five-stage flow that turns real project experience into reviewed
4
4
  rule / skill / command / guideline changes. No autonomous self-edits;
5
5
  every upstream change ships via a human-reviewed PR.
6
6
 
7
- Referenced by `road-to-curated-self-improvement.md`. Consumed by the
8
- existing skills `capture-learnings`, `learning-to-rule-or-skill`,
9
- `skill-improvement-pipeline`, and `upstream-contribute` — each becomes
10
- a stage, not a standalone invocation.
7
+ Referenced by `road-to-curated-self-improvement.md`. Consumed by the live
8
+ artifacts — the `skill-improvement-trigger` rule and the existing skills
9
+ `learning-to-rule-or-skill`, `skill-improvement-pipeline`, and
10
+ `upstream-contribute` — each becomes a stage, not a standalone invocation.
11
11
 
12
12
  ## The five stages
13
13
 
@@ -1,4 +1,4 @@
1
- <!-- security-lint: allow instruction-smuggling "defense guideline: quotes role-takeover phrases (ignore previous instructions, you are now, <IMPORTANT>) to teach refusal" -->
1
+ <!-- security-lint: allow instruction-smuggling "defense guideline: quotes role-takeover phrases (ignore previous instructions, you are now, <IMPORTANT>) to teach refusal" sha256:d84759534e0fd3ebc5a66533b4a9f52364ef5286eaf3674a611c9c2adf89b969 sha256:f08c68182232149c7ecd881e88ca81dc98a9313c06ba6d010b065f9feef2c149 sha256:4f5936bb0a57de8ff3ce590fb12607cdcb046a31262b5e4d40377c6e6184f494 -->
2
2
 
3
3
  # untrusted-input spotlighting + least-agency mapping
4
4
 
@@ -68,105 +68,128 @@ generation ships a visibly different default aesthetic. It is a *when-does-it-
68
68
  rotate* note, not a new pattern — never add a tell here that lacks a catalog
69
69
  entry in the sections below.
70
70
 
71
+ ### The three census columns — class, remediation, verification
72
+
73
+ `Class` says what KIND of rule an entry is; **status** (§ Detector status) says
74
+ how its enforcement is wired. The two axes are independent, and a reader who
75
+ conflates them draws the wrong conclusion in both directions: a `floor` may be
76
+ `judgment-only` because nothing can detect it yet, and a `style-preference` may
77
+ be `backed` because it happens to be trivially greppable. Detectability is not
78
+ authority.
79
+
80
+ - **Class** — one of `floor` (an objective threshold, accessibility or
81
+ correctness) · `invariant` (a structural rule that must hold) ·
82
+ `craft-presumption` (a default a competent designer usually follows,
83
+ overridable on evidence) · `style-preference` (taste) ·
84
+ `reference-constraint` (bound to a supplied reference, brand, or `DESIGN.md`).
85
+ The two soft classes lose to a supplied reference artifact, a coherent
86
+ incumbent, and a project `DESIGN.md` — asserted on the resolver in
87
+ `src/scripts/_lib/ui_authority.ts` rather than stated here as prose.
88
+ - **Remediation** — the order to try, worst-first: `delete` before `reduce`
89
+ before `retune`, with `replace` where the pattern has a direct substitute.
90
+ - **Verification** — how a fix is checked: `static` (readable from the source)
91
+ · `render` (needs the rendered surface) · `feel` (perceptual, per the `feel`
92
+ evidence type in `docs/contracts/evidence-artifact-types.md`) · `judgment`.
93
+
71
94
  ### Consistency Locks & layout caps (taste-dials roadmap)
72
95
 
73
96
  Within-project invariants + repetition caps. Override = declare the value in
74
97
  `DESIGN.md` (`## Consistency Locks` / a brutalist or uniform-grid style note).
75
98
 
76
- | # | Pattern | Why it reads as AI-generated | Override condition |
77
- |---|---|---|---|
78
- | V8 | Shape Lock — ≥ 4 distinct corner-radius scales in one surface | A fragmented radius system reads as no shape decision | Declare the radius scale in `DESIGN.md`; a genuine multi-tier scale documents each tier |
79
- | C6 | Colour Lock — ≥ 3 distinct saturated accent hue families | No single accent identity; reads as default-palette sprawl | Brand genuinely uses a multi-accent system, declared in `DESIGN.md` / `brand-to-tokens` |
80
- | C7 | Theme inversion — a light island mid-dark surface (or vice versa) not driven by the theme system | Mid-surface inversion breaks the theme rhythm | Intentional inverted callout with a documented reason — **judgment-only**, design-review calls it (deterministic detection is unreliable) |
81
- | L9 | Section monotony — ≥ 8 sections, < 4 distinct layout families | Uniform section rhythm collapses scannability | Deliberately uniform grid (e.g. a gallery), declared as such |
82
- | L10 | Zigzag — > 2 consecutive image-left/text-right two-column sections | The alternating-zigzag landing-page tell | A genuinely sequenced walkthrough where alternation aids comprehension |
99
+ | # | Pattern | Why it reads as AI-generated | Override condition | Class | Remediation | Verification |
100
+ |---|---|---|---|---|---|---|
101
+ | V8 | Shape Lock — ≥ 4 distinct corner-radius scales in one surface | A fragmented radius system reads as no shape decision | Declare the radius scale in `DESIGN.md`; a genuine multi-tier scale documents each tier | invariant | reduce → retune | static |
102
+ | C6 | Colour Lock — ≥ 3 distinct saturated accent hue families | No single accent identity; reads as default-palette sprawl | Brand genuinely uses a multi-accent system, declared in `DESIGN.md` / `brand-to-tokens` | invariant | reduce → retune | static |
103
+ | C7 | Theme inversion — a light island mid-dark surface (or vice versa) not driven by the theme system | Mid-surface inversion breaks the theme rhythm | Intentional inverted callout with a documented reason — **judgment-only**, design-review calls it (deterministic detection is unreliable) | craft-presumption | delete → retune | judgment |
104
+ | L9 | Section monotony — ≥ 8 sections, < 4 distinct layout families | Uniform section rhythm collapses scannability | Deliberately uniform grid (e.g. a gallery), declared as such | craft-presumption | retune | render |
105
+ | L10 | Zigzag — > 2 consecutive image-left/text-right two-column sections | The alternating-zigzag landing-page tell | A genuinely sequenced walkthrough where alternation aids comprehension | craft-presumption | delete → retune | static |
83
106
 
84
107
  ---
85
108
 
86
109
  ## Visual
87
110
 
88
- | # | Pattern | Why it reads as AI-generated | Override condition |
89
- |---|---|---|---|
90
- | V1 | A colored accent border above 1px — the side stripe (`border-left` / `border-right`), a fully colored border on all four sides, or a gradient `border-image` | The single most recognizable AI-UI signature; every scaffold-default card uses it. Widened 2026-09-03: the side stripe was the 2024 form, the four-sided colored or gradient card border is the current one, and the entry as written reached only the first | Brand token explicitly defines the accent border; document the decision in the design brief. A 1px neutral border, a `border-color`-only focus treatment, and `transparent` / `currentColor` at any width are not accents and do not flag |
91
- | V2 | Glassmorphism as decoration (`backdrop-blur` + `bg-white/10`) with no functional depth hierarchy | Model defaults to it for "premium feel"; result looks like 2021 Material You clip-art | Element genuinely sits above a complex, blurred background layer; use sparingly and only for top-level floating surfaces |
92
- | V3 | Ghost card: `border: 1px solid` + box-shadow ≥ 16px spread together | The combination creates visual noise — the ghost card signals no confident decision about depth | Choose either border OR shadow to indicate depth; never both on the same surface |
93
- | V4 | Over-rounded small cards or badges: `border-radius` > 16px on elements < 200px wide | Excessive rounding on small surfaces looks toy-ish; standard cap is 12–16px | Pill shape (`border-radius: 9999px`) is intentional on single-line tags/chips only |
94
- | V5 | Hand-drawn or illustrated SVG icons mixed with crisp icon-system icons | Visual register collision; instantly reads as "generated asset" | Intentional illustrative section (hero illustration, empty-state art); isolate from the icon system |
95
- | V6 | Repeating diagonal stripes as a background texture | A cliché background default; reads as generated CSS art | Brand explicitly uses pattern backgrounds (e.g., a textile brand); document the stripe definition |
96
- | V7 | Nested cards: a card inside a card inside a card | Depth hierarchy collapses; user cannot parse elevation intent | A truly three-level hierarchy (e.g., project → board → card); ensure each level has distinct visual weight |
97
- | V9 | Noise or grain texture laid over a gradient as a "premium" surface default | The visual sibling of V6's diagonal stripes — a generated-CSS-art texture reached for to make a flat gradient look considered, applied because it is available rather than because the surface needed a texture | The texture is part of a documented brand surface treatment (a print-inspired or analog-photographic identity) with the grain opacity defined as a token, not chosen per surface |
111
+ | # | Pattern | Why it reads as AI-generated | Override condition | Class | Remediation | Verification |
112
+ |---|---|---|---|---|---|---|
113
+ | V1 | A colored accent border above 1px — the side stripe (`border-left` / `border-right`), a fully colored border on all four sides, or a gradient `border-image` | The single most recognizable AI-UI signature; every scaffold-default card uses it. Widened 2026-09-03: the side stripe was the 2024 form, the four-sided colored or gradient card border is the current one, and the entry as written reached only the first | Brand token explicitly defines the accent border; document the decision in the design brief. A 1px neutral border, a `border-color`-only focus treatment, and `transparent` / `currentColor` at any width are not accents and do not flag | craft-presumption | delete → retune | static |
114
+ | V2 | Glassmorphism as decoration (`backdrop-blur` + `bg-white/10`) with no functional depth hierarchy | Model defaults to it for "premium feel"; result looks like 2021 Material You clip-art | Element genuinely sits above a complex, blurred background layer; use sparingly and only for top-level floating surfaces | craft-presumption | delete → reduce | static |
115
+ | V3 | Ghost card: `border: 1px solid` + box-shadow ≥ 16px spread together | The combination creates visual noise — the ghost card signals no confident decision about depth | Choose either border OR shadow to indicate depth; never both on the same surface | invariant | delete → reduce | static |
116
+ | V4 | Over-rounded small cards or badges: `border-radius` > 16px on elements < 200px wide | Excessive rounding on small surfaces looks toy-ish; standard cap is 12–16px | Pill shape (`border-radius: 9999px`) is intentional on single-line tags/chips only | craft-presumption | retune | static |
117
+ | V5 | Hand-drawn or illustrated SVG icons mixed with crisp icon-system icons | Visual register collision; instantly reads as "generated asset" | Intentional illustrative section (hero illustration, empty-state art); isolate from the icon system | invariant | replace | render |
118
+ | V6 | Repeating diagonal stripes as a background texture | A cliché background default; reads as generated CSS art | Brand explicitly uses pattern backgrounds (e.g., a textile brand); document the stripe definition | style-preference | delete | static |
119
+ | V7 | Nested cards: a card inside a card inside a card | Depth hierarchy collapses; user cannot parse elevation intent | A truly three-level hierarchy (e.g., project → board → card); ensure each level has distinct visual weight | invariant | delete → reduce | render |
120
+ | V9 | Noise or grain texture laid over a gradient as a "premium" surface default | The visual sibling of V6's diagonal stripes — a generated-CSS-art texture reached for to make a flat gradient look considered, applied because it is available rather than because the surface needed a texture | The texture is part of a documented brand surface treatment (a print-inspired or analog-photographic identity) with the grain opacity defined as a token, not chosen per surface | style-preference | delete | render |
98
121
 
99
122
  ---
100
123
 
101
124
  ## Typography
102
125
 
103
- | # | Pattern | Why it reads as AI-generated | Override condition |
104
- |---|---|---|---|
105
- | T1 | Flat type hierarchy: body and headings use the same optical weight and nearly the same size | Type hierarchy is invisible; user cannot scan the page | Deliberately minimal aesthetic where all text is body-weight; must be an explicit brand decision |
106
- | T2 | Oversized italic serif as the primary hero headline | The "AI startup landing page" template; seen on ~60% of AI-generated marketing pages | Brand adopts editorial-magazine aesthetic with a documented italic serif rationale |
107
- | T3 | Icon tile (small rounded-square container) above heading | The universal AI feature-card template; reads as scaffold | Listed features genuinely benefit from visual-icon-then-title affordance AND the icons are custom, not library defaults |
108
- | T4 | Eyebrow / ALL-CAPS label above every section heading | Overuse collapses the emphasis; maximum is 1 eyebrow per 3 sections (countable: grep tracking classes) | Used for genuine section-type differentiation with meaningful vocabulary (not just "FEATURES", "PRICING") |
109
- | T5 | Repeated section kickers ("Our mission", "What we offer", "Why choose us") | Filler vocabulary; every AI-generated page has the same three section titles | Every kicker is substantive and uses brand-specific vocabulary, not generic marketing speak |
110
- | T6 | Crushed letter-spacing on display text (`letter-spacing` < −0.04em) | Below −0.04em glyphs collide optically; reads as "designer-ish effect" with no grounding | Intentional tight display treatment with a documented minimum floor; verify at the actual render size |
111
- | T7 | Overused fonts without a stated reason: Inter, Roboto, DM Sans, Geist, Space Grotesk, Instrument Serif | These are the default AI-coding-tool font picks; every generated UI uses one of them | **Register-scoped.** In the **brand** register: the brand has explicitly adopted one of these AND there is a documented reason. In the **product** register: a single reliable family is the sanctioned strategy ([`design-modes`](design-modes.md) § The two registers), so one of these is legitimate on a **stated** product-register choice — the register itself is the reason, and it must be stated (DESIGN.md, the surface brief, or `design-slop-disable`). Neither register admits an *undeclared* pick. |
112
- | T8 | Single typeface for everything | Missed typographic contrast opportunity; in the **brand** register an unexamined single family reads as "I did not think about fonts" | **Register-scoped like T7.** Intentional mono-typeface aesthetic (e.g., terminal-inspired), stated in the brief — *or* the **product** register, where one reliable family is the sanctioned strategy ([`design-modes`](design-modes.md) § The two registers) and contrast is carried by weight and scale rather than by a second family. |
113
- | T9 | All-caps body paragraphs or field labels | Reduces legibility below WCAG AA for sustained reading; reads as flair over function | Short UI labels (e.g., button text in a brutalist layout); never for body paragraphs |
114
- | T10 | Wide letter-spacing on body text (`letter-spacing` > 0.05em) | Reduces readability for sustained reading; reserved for display use | Display text (headlines, pull quotes) where intentional tracking is a brand element |
126
+ | # | Pattern | Why it reads as AI-generated | Override condition | Class | Remediation | Verification |
127
+ |---|---|---|---|---|---|---|
128
+ | T1 | Flat type hierarchy: body and headings use the same optical weight and nearly the same size | Type hierarchy is invisible; user cannot scan the page | Deliberately minimal aesthetic where all text is body-weight; must be an explicit brand decision | craft-presumption | retune | render |
129
+ | T2 | Oversized italic serif as the primary hero headline | The "AI startup landing page" template; seen on ~60% of AI-generated marketing pages | Brand adopts editorial-magazine aesthetic with a documented italic serif rationale | style-preference | replace | render |
130
+ | T3 | Icon tile (small rounded-square container) above heading | The universal AI feature-card template; reads as scaffold | Listed features genuinely benefit from visual-icon-then-title affordance AND the icons are custom, not library defaults | style-preference | delete | static |
131
+ | T4 | Eyebrow / ALL-CAPS label above every section heading | Overuse collapses the emphasis; maximum is 1 eyebrow per 3 sections (countable: grep tracking classes) | Used for genuine section-type differentiation with meaningful vocabulary (not just "FEATURES", "PRICING") | craft-presumption | delete → reduce | static |
132
+ | T5 | Repeated section kickers ("Our mission", "What we offer", "Why choose us") | Filler vocabulary; every AI-generated page has the same three section titles | Every kicker is substantive and uses brand-specific vocabulary, not generic marketing speak | craft-presumption | replace | judgment |
133
+ | T6 | Crushed letter-spacing on display text (`letter-spacing` < −0.04em) | Below −0.04em glyphs collide optically; reads as "designer-ish effect" with no grounding | Intentional tight display treatment with a documented minimum floor; verify at the actual render size | floor | retune | static |
134
+ | T7 | Overused fonts without a stated reason: Inter, Roboto, DM Sans, Geist, Space Grotesk, Instrument Serif | These are the default AI-coding-tool font picks; every generated UI uses one of them | **Register-scoped.** In the **brand** register: the brand has explicitly adopted one of these AND there is a documented reason. In the **product** register: a single reliable family is the sanctioned strategy ([`design-modes`](design-modes.md) § The two registers), so one of these is legitimate on a **stated** product-register choice — the register itself is the reason, and it must be stated (DESIGN.md, the surface brief, or `design-slop-disable`). Neither register admits an *undeclared* pick. | reference-constraint | replace | judgment |
135
+ | T8 | Single typeface for everything | Missed typographic contrast opportunity; in the **brand** register an unexamined single family reads as "I did not think about fonts" | **Register-scoped like T7.** Intentional mono-typeface aesthetic (e.g., terminal-inspired), stated in the brief — *or* the **product** register, where one reliable family is the sanctioned strategy ([`design-modes`](design-modes.md) § The two registers) and contrast is carried by weight and scale rather than by a second family. | reference-constraint | retune | judgment |
136
+ | T9 | All-caps body paragraphs or field labels | Reduces legibility below WCAG AA for sustained reading; reads as flair over function | Short UI labels (e.g., button text in a brutalist layout); never for body paragraphs | floor | delete → retune | static |
137
+ | T10 | Wide letter-spacing on body text (`letter-spacing` > 0.05em) | Reduces readability for sustained reading; reserved for display use | Display text (headlines, pull quotes) where intentional tracking is a brand element | craft-presumption | retune | static |
115
138
 
116
139
  ---
117
140
 
118
141
  ## Color
119
142
 
120
- | # | Pattern | Why it reads as AI-generated | Override condition |
121
- |---|---|---|---|
122
- | C1 | Purple/violet + cyan-on-dark palette as the primary scheme | The most recognizable AI-UI color combination in 2024–2026; instantly signals "generated" | Brand color system genuinely defines a violet primary; must come from `brand-to-tokens`, not from model defaults |
123
- | C2 | Gradient text via `background-clip: text` as a primary accent | Overused to the point of invisibility; also has rendering edge cases on some platforms | Headline treatment in a brand that explicitly uses gradient identity (e.g., a product whose logo is a gradient) |
124
- | C3 | Glowing colored accents on dark mode (bright neon `box-shadow` or `text-shadow`) | Looks like a 2020 gaming UI; reads as an AI attempt at "moody" | Brand explicitly defines neon accents with a documented usage rule (e.g., error or alert states in a security product) |
125
- | C4 | Gray text on colored background without WCAG AA check | Muted gray chosen for "elegance" often fails 4.5:1 contrast; the failure is invisible until audited | Any use — always verify the contrast ratio; if it fails, either darken the text or lighten/darken the background |
126
- | C5 | Cream/sand body background (OKLCH L 0.84–0.97, C < 0.06) with brass/clay/oxblood accents | The 2025 "premium-consumer" AI palette; every generated "sophisticated" product uses this exact combination | Brand has an explicit warm-neutral design language documented in `brand-to-tokens`; the palette is first-party, not a default reach |
143
+ | # | Pattern | Why it reads as AI-generated | Override condition | Class | Remediation | Verification |
144
+ |---|---|---|---|---|---|---|
145
+ | C1 | Purple/violet + cyan-on-dark palette as the primary scheme | The most recognizable AI-UI color combination in 2024–2026; instantly signals "generated" | Brand color system genuinely defines a violet primary; must come from `brand-to-tokens`, not from model defaults | style-preference | replace | static |
146
+ | C2 | Gradient text via `background-clip: text` as a primary accent | Overused to the point of invisibility; also has rendering edge cases on some platforms | Headline treatment in a brand that explicitly uses gradient identity (e.g., a product whose logo is a gradient) | style-preference | delete | static |
147
+ | C3 | Glowing colored accents on dark mode (bright neon `box-shadow` or `text-shadow`) | Looks like a 2020 gaming UI; reads as an AI attempt at "moody" | Brand explicitly defines neon accents with a documented usage rule (e.g., error or alert states in a security product) | style-preference | delete → reduce | static |
148
+ | C4 | Gray text on colored background without WCAG AA check | Muted gray chosen for "elegance" often fails 4.5:1 contrast; the failure is invisible until audited | Any use — always verify the contrast ratio; if it fails, either darken the text or lighten/darken the background | floor | retune | static |
149
+ | C5 | Cream/sand body background (OKLCH L 0.84–0.97, C < 0.06) with brass/clay/oxblood accents | The 2025 "premium-consumer" AI palette; every generated "sophisticated" product uses this exact combination | Brand has an explicit warm-neutral design language documented in `brand-to-tokens`; the palette is first-party, not a default reach | style-preference | replace | static |
127
150
 
128
151
  ---
129
152
 
130
153
  ## Layout
131
154
 
132
- | # | Pattern | Why it reads as AI-generated | Override condition |
133
- |---|---|---|---|
134
- | L1 | Hero metric template: giant number, small label, 3–4 stats in a row, gradient | The default SaaS dashboard hero; appears on ~70% of AI-generated dashboard screens | Data storytelling genuinely requires a primary metric with supporting context; must vary the arrangement |
135
- | L2 | Three identical feature cards in a grid with the same visual weight | The scaffold-default; no visual rhythm, no hierarchy among features | Product genuinely has three equally weighted features; must still vary padding, or use a different composition |
136
- | L3 | Monotonous spacing: one spacing value (usually 24px) used for everything | Spacing is rhythm; uniform spacing collapses the hierarchy of proximity | Intentional grid where every element has equal weight; must document the grid definition |
137
- | L4 | Numbered section markers (01 / 02 / 03) as a primary section-order device | Universal AI-generated marketing page tell; seen on virtually every generated landing page | A genuinely numbered process or sequenced guide where the step number carries meaning beyond decoration |
138
- | L5 | Line length > 80ch in body copy without column constraint | Reduces readability; WCAG recommends 45–75 characters; beyond 80 the eye struggles to track | Data-dense dashboards where column width is driven by tabular data, not narrative text |
139
- | L6 | `position: absolute` dropdown inside `overflow: hidden` container | Dropdown clips; a common AI-generated layout bug | Refactor: use `<dialog>`, the Popover API, or `position: fixed` / portal to escape the stacking context |
140
- | L7 | Content that overflows its container | Text truncation or reflow failures at non-default viewport widths; reads as untested | Never acceptable in production output; test at 320px, 768px, 1280px minimally |
141
- | L8 | Z-index values of 99, 999, 9999 without a semantic z-index scale | Magic numbers; the first time two elements compete, the scale breaks | Establish a named semantic z-index scale (`--z-modal: 400`, `--z-toast: 500`, etc.) and use it |
155
+ | # | Pattern | Why it reads as AI-generated | Override condition | Class | Remediation | Verification |
156
+ |---|---|---|---|---|---|---|
157
+ | L1 | Hero metric template: giant number, small label, 3–4 stats in a row, gradient | The default SaaS dashboard hero; appears on ~70% of AI-generated dashboard screens | Data storytelling genuinely requires a primary metric with supporting context; must vary the arrangement | craft-presumption | retune | render |
158
+ | L2 | Three identical feature cards in a grid with the same visual weight | The scaffold-default; no visual rhythm, no hierarchy among features | Product genuinely has three equally weighted features; must still vary padding, or use a different composition | craft-presumption | retune | render |
159
+ | L3 | Monotonous spacing: one spacing value (usually 24px) used for everything | Spacing is rhythm; uniform spacing collapses the hierarchy of proximity | Intentional grid where every element has equal weight; must document the grid definition | craft-presumption | retune | static |
160
+ | L4 | Numbered section markers (01 / 02 / 03) as a primary section-order device | Universal AI-generated marketing page tell; seen on virtually every generated landing page | A genuinely numbered process or sequenced guide where the step number carries meaning beyond decoration | style-preference | delete | static |
161
+ | L5 | Line length > 80ch in body copy without column constraint | Reduces readability; WCAG recommends 45–75 characters; beyond 80 the eye struggles to track | Data-dense dashboards where column width is driven by tabular data, not narrative text | floor | retune | render |
162
+ | L6 | `position: absolute` dropdown inside `overflow: hidden` container | Dropdown clips; a common AI-generated layout bug | Refactor: use `<dialog>`, the Popover API, or `position: fixed` / portal to escape the stacking context | invariant | replace | render |
163
+ | L7 | Content that overflows its container | Text truncation or reflow failures at non-default viewport widths; reads as untested | Never acceptable in production output; test at 320px, 768px, 1280px minimally | invariant | retune | render |
164
+ | L8 | Z-index values of 99, 999, 9999 without a semantic z-index scale | Magic numbers; the first time two elements compete, the scale breaks | Establish a named semantic z-index scale (`--z-modal: 400`, `--z-toast: 500`, etc.) and use it | invariant | replace | static |
142
165
 
143
166
  ---
144
167
 
145
168
  ## Motion
146
169
 
147
- | # | Pattern | Why it reads as AI-generated | Override condition |
148
- |---|---|---|---|
149
- | M1 | Bounce or elastic easing curves on UI elements | Bounce draws attention to the animation itself; UI motion should serve the action, not perform | Intentional playful affordance (game UI, onboarding celebration state); must be brief and non-repeating |
150
- | M2 | Animating layout properties (width, height, top, left, padding) | Triggers browser layout recalculation; janky on mid-range devices; always solvable with `transform` | Never — use `transform: scaleX()` for width-like effects, `transform: translateY()` for position |
151
- | M3 | Animating `<img>` element on hover (scale, filter, transform) | Triggers composite + image decode; often causes content shift | Animate the card's background, border, or shadow instead; leave the image static |
152
- | M4 | `transition: all` shorthand | Animates every property including layout, color, opacity simultaneously; unpredictable and expensive | Enumerate only the properties that should animate: `transition: transform 200ms ease-out, opacity 200ms` |
153
- | M5 | Missing `@media (prefers-reduced-motion: reduce)` alternative for any animation | Accessibility violation; vestibular disorders make animated UI unusable | Never acceptable; always add a `prefers-reduced-motion` variant — gentler animation (reduced distance/opacity) is preferred over `display: none` |
154
- | M6 | Every section fading and rising into view on scroll | The most recognisable interaction tell of the current generation; a reveal applied per section carries no information — the reader has already scrolled to the content, so the animation delays what they asked for | The reveal carries meaning: a stepped narrative where each beat must land before the next, or a long-form article using position to signal progress. A reveal on *every* section is a default, not a decision |
155
- | M7 | A radial highlight tracking the pointer across a dark hero | A `mousemove` handler feeding a radial gradient; it draws the eye to the cursor, which is the one thing on the page the user already knows the position of | The spotlight is the interaction — a genuine reveal mechanic, a canvas inspection tool, an accessibility magnifier. Ambience is not a purpose |
156
- | M8 | An interactive control that reduces its own opacity on hover | Reads as the element retreating from the pointer rather than responding to it, and a fade is the one hover treatment that *reduces* legibility at the moment the user is committing to the target — see the six interaction states in [`design-review`](../../src/skills/design-review/SKILL.md) | The fade communicates a real state change (an item being dismissed, a layer being peeled back). Hover must stay legible; brightness, background or border carry hover without spending contrast |
170
+ | # | Pattern | Why it reads as AI-generated | Override condition | Class | Remediation | Verification |
171
+ |---|---|---|---|---|---|---|
172
+ | M1 | Bounce or elastic easing curves on UI elements | Bounce draws attention to the animation itself; UI motion should serve the action, not perform | Intentional playful affordance (game UI, onboarding celebration state); must be brief and non-repeating | invariant | replace | feel |
173
+ | M2 | Animating layout properties (width, height, top, left, padding) | Triggers browser layout recalculation; janky on mid-range devices; always solvable with `transform` | Never — use `transform: scaleX()` for width-like effects, `transform: translateY()` for position | floor | replace | static |
174
+ | M3 | Animating `<img>` element on hover (scale, filter, transform) | Triggers composite + image decode; often causes content shift | Animate the card's background, border, or shadow instead; leave the image static | invariant | replace | render |
175
+ | M4 | `transition: all` shorthand | Animates every property including layout, color, opacity simultaneously; unpredictable and expensive | Enumerate only the properties that should animate: `transition: transform 200ms ease-out, opacity 200ms` | invariant | replace | static |
176
+ | M5 | Missing `@media (prefers-reduced-motion: reduce)` alternative for any animation | Accessibility violation; vestibular disorders make animated UI unusable | Never acceptable; always add a `prefers-reduced-motion` variant — gentler animation (reduced distance/opacity) is preferred over `display: none` | floor | delete → retune | static |
177
+ | M6 | Every section fading and rising into view on scroll | The most recognisable interaction tell of the current generation; a reveal applied per section carries no information — the reader has already scrolled to the content, so the animation delays what they asked for | The reveal carries meaning: a stepped narrative where each beat must land before the next, or a long-form article using position to signal progress. A reveal on *every* section is a default, not a decision | craft-presumption | delete → reduce | feel |
178
+ | M7 | A radial highlight tracking the pointer across a dark hero | A `mousemove` handler feeding a radial gradient; it draws the eye to the cursor, which is the one thing on the page the user already knows the position of | The spotlight is the interaction — a genuine reveal mechanic, a canvas inspection tool, an accessibility magnifier. Ambience is not a purpose | style-preference | delete | feel |
179
+ | M8 | An interactive control that reduces its own opacity on hover | Reads as the element retreating from the pointer rather than responding to it, and a fade is the one hover treatment that *reduces* legibility at the moment the user is committing to the target — see the six interaction states in [`design-review`](../../src/skills/design-review/SKILL.md) | The fade communicates a real state change (an item being dismissed, a layer being peeled back). Hover must stay legible; brightness, background or border carry hover without spending contrast | craft-presumption | retune | feel |
157
180
 
158
181
  ---
159
182
 
160
183
  ## Copy
161
184
 
162
- | # | Pattern | Why it reads as AI-generated | Override condition |
163
- |---|---|---|---|
164
- | CP1 | Em-dash (`—`) overuse | The #1 syntactic LLM signature; appears in AI copy at 3–5× the frequency of human editorial copy; maximum 2 per 500 words | Specific editorial voice that uses em-dashes deliberately; count them before shipping |
165
- | CP2 | Marketing buzzwords: streamline, empower, supercharge, world-class, enterprise-grade, seamlessly, robust, leverage | These words carry no information; an AI-slop test: replace each with nothing — the sentence still communicates the same thing | No override; if a word can be deleted without loss, delete it |
166
- | CP3 | Aphoristic manufactured contrast ("We don't do X. We do Y." / "Not just A, but B.") | A generated sentence rhythm that sounds like brand writing but carries no specificity | Aphoristic copy is legitimate when the contrast reveals a genuine product distinction; test by asking whether the Y side says something concrete |
167
- | CP4 | "Theater" framing — copy that announces what the product does without saying how or why | "The platform for modern teams." communicates nothing; it is content-shaped noise | Every tagline must pass the "so what" test: can a skeptic follow it with "but how?" and get a concrete answer? |
168
- | CP5 | Emoji-decoration in UI markup — 🚀/✅/🎉 prepending headings, buttons, list items, or CTAs (`🚀 Get Started`) | Performative-enthusiasm coating; the default-startup-template tell. No emoji is better than decorative emoji | Brand/`DESIGN.md` declares a systematic emoji strategy, or the emoji is functional (status indicator, category marker tied to real meaning) |
169
- | CP6 | Stock render subject named instead of the product's own subject matter — "floating abstract shapes", "gradient mesh", "glowing orb", "particle field", "futuristic HUD" | These name the default thing a render becomes when nobody decided what it is about; same delete-test as CP2, applied to art direction — swap the phrase for what the product actually shows and the brief says more | The subject IS abstract by decision (a generative-art surface, a data-driven field whose data is named), and the brief says which decision and why |
185
+ | # | Pattern | Why it reads as AI-generated | Override condition | Class | Remediation | Verification |
186
+ |---|---|---|---|---|---|---|
187
+ | CP1 | Em-dash (`—`) overuse | The #1 syntactic LLM signature; appears in AI copy at 3–5× the frequency of human editorial copy; maximum 2 per 500 words | Specific editorial voice that uses em-dashes deliberately; count them before shipping | craft-presumption | delete → reduce | static |
188
+ | CP2 | Marketing buzzwords: streamline, empower, supercharge, world-class, enterprise-grade, seamlessly, robust, leverage | These words carry no information; an AI-slop test: replace each with nothing — the sentence still communicates the same thing | No override; if a word can be deleted without loss, delete it | craft-presumption | delete | static |
189
+ | CP3 | Aphoristic manufactured contrast ("We don't do X. We do Y." / "Not just A, but B.") | A generated sentence rhythm that sounds like brand writing but carries no specificity | Aphoristic copy is legitimate when the contrast reveals a genuine product distinction; test by asking whether the Y side says something concrete | style-preference | delete → replace | judgment |
190
+ | CP4 | "Theater" framing — copy that announces what the product does without saying how or why | "The platform for modern teams." communicates nothing; it is content-shaped noise | Every tagline must pass the "so what" test: can a skeptic follow it with "but how?" and get a concrete answer? | craft-presumption | replace | judgment |
191
+ | CP5 | Emoji-decoration in UI markup — 🚀/✅/🎉 prepending headings, buttons, list items, or CTAs (`🚀 Get Started`) | Performative-enthusiasm coating; the default-startup-template tell. No emoji is better than decorative emoji | Brand/`DESIGN.md` declares a systematic emoji strategy, or the emoji is functional (status indicator, category marker tied to real meaning) | craft-presumption | delete | static |
192
+ | CP6 | Stock render subject named instead of the product's own subject matter — "floating abstract shapes", "gradient mesh", "glowing orb", "particle field", "futuristic HUD" | These name the default thing a render becomes when nobody decided what it is about; same delete-test as CP2, applied to art direction — swap the phrase for what the product actually shows and the brief says more | The subject IS abstract by decision (a generative-art surface, a data-driven field whose data is named), and the brief says which decision and why | craft-presumption | replace | judgment |
170
193
 
171
194
  ---
172
195
 
@@ -86,6 +86,34 @@ translation frequently denote different mechanisms — here `route`, `dispatch`,
86
86
  five ways — so a sweep over them destroys information the echo classes exist to
87
87
  protect.
88
88
 
89
+ ## The avoid-list — one term, one concept
90
+
91
+ A homonym collision is only half-diagnosed when it is classified. The other
92
+ half is the **decision**: which concept keeps the word, and what every other
93
+ sense is called instead. This list carries the decided ones. A word is added
94
+ here when the same term has been observed denoting more than one shipped
95
+ mechanism; it is removed only when the collision is gone from the tree, never
96
+ because the entry became inconvenient.
97
+
98
+ Read the columns as a rename instruction for **prose you write from now on**.
99
+ The identifier layer is decided separately and per cluster, exactly as the
100
+ prose/identifier split above requires — a term may be `canonicalize-term` in
101
+ prose and `keep-distinct` in identifiers, and both verdicts are recorded.
102
+
103
+ | Term | Concept that keeps the word | Other senses, and what to call them | Identifier verdict |
104
+ |---|---|---|---|
105
+ | `envelope` | The **transport wrapper** around a payload — `OutcomeEnvelope` (a run's terminal outcome, `src/scripts/_lib/outcome_envelope.ts`) and the `CHECKPOINT` envelope a worker capsule rides in. | The **session continuity record** is a **capsule**. The word is not chosen for readability — it is the shipped discriminator (`CAPSULE_SCHEMA_VERSION`, `CAPSULE_VARIANTS = ['worker','main_session']`, `src/scripts/_lib/subagent_capsule.ts`), so the surviving term is read off what ships rather than off what reads best. | `keep-distinct` for now. `MainSessionRecycleEnvelope` and `RECYCLE_ENVELOPE_*` keep their names until a rename is costed on its own; the prose rule binds immediately and the symbols are a separate blast radius. |
106
+ | `handoff` | The **session-to-session continuity handover** a developer invokes — the `handoff` verb and the `/agent-handoff` command. | The lint over senior-tier skills' `## Related Skills` edges is a **cross-wing skill link**, never "a handoff". | `keep-distinct`, recorded reason: `lint_handoffs.ts` mirrors a ported CLI contract (ADR-200) whose name is an external surface. Its module docstring already says "cross-wing", which is the disambiguation the prose rule now requires everywhere else. |
107
+
108
+ **Why a list and not a linter.** `lint_canonical_terms` decides *spelling*
109
+ pairs, where one side is mechanically wrong. A homonym is not mechanically
110
+ wrong anywhere — every occurrence is a legitimate word for a legitimate
111
+ concept, and only the reader's inability to tell them apart is the defect. A
112
+ gate that flagged `envelope` would flag the entry that is supposed to survive.
113
+ So this list is enforced at review, by citation, and its cost of being ignored
114
+ is the cost the taxonomy already names: the model telling you it has not
115
+ decided.
116
+
89
117
  ## Why any of this is worth a gate at all
90
118
 
91
119
  Generated code trends toward duplication rather than reuse: measured
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.18.0",
4
+ "version": "14.20.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,
@@ -17,7 +17,7 @@ it as `.augment/` (local projection).
17
17
  ├── contexts/ # Background context documents for the agent
18
18
  ├── guidelines/ # Coding guidelines by language (reference material)
19
19
  ├── rules/ # Always-active behavior rules (auto-loaded every conversation)
20
- ├── skills/ # On-demand expertise (matched by topic)
20
+ ├── skills/ # On-demand expertise (named or trigger-matched)
21
21
  └── templates/ # File templates for roadmaps, features, skills, etc.
22
22
  ```
23
23