@event4u/agent-config 14.22.0 → 15.0.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 (557) 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 +333 -356
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/agent-handoff.md +8 -7
  7. package/dist/agent-src/commands/agents/init.md +1 -1
  8. package/dist/agent-src/commands/agents/user/accept.md +4 -4
  9. package/dist/agent-src/commands/agents/user/delete.md +2 -2
  10. package/dist/agent-src/commands/agents/user/init.md +3 -3
  11. package/dist/agent-src/commands/agents/user/review.md +3 -3
  12. package/dist/agent-src/commands/agents/user/show.md +3 -3
  13. package/dist/agent-src/commands/agents/user/update.md +2 -2
  14. package/dist/agent-src/commands/agents/user.md +6 -6
  15. package/dist/agent-src/commands/analytics/prune.md +1 -1
  16. package/dist/agent-src/commands/analytics/show.md +2 -2
  17. package/dist/agent-src/commands/analyze/decision.md +2 -2
  18. package/dist/agent-src/commands/analyze/inbox.md +5 -5
  19. package/dist/agent-src/commands/analyze/incident.md +3 -3
  20. package/dist/agent-src/commands/analyze/near-miss.md +3 -3
  21. package/dist/agent-src/commands/analyze/postmortem.md +4 -4
  22. package/dist/agent-src/commands/analyze/premortem.md +2 -2
  23. package/dist/agent-src/commands/analyze.md +2 -2
  24. package/dist/agent-src/commands/bug/fix.md +1 -1
  25. package/dist/agent-src/commands/bug/investigate.md +2 -2
  26. package/dist/agent-src/commands/cost/profile.md +3 -3
  27. package/dist/agent-src/commands/design.md +1 -1
  28. package/dist/agent-src/commands/feature/explore.md +1 -1
  29. package/dist/agent-src/commands/feature/plan.md +2 -2
  30. package/dist/agent-src/commands/feature/roadmap.md +2 -2
  31. package/dist/agent-src/commands/ghostwriter/fetch.md +4 -4
  32. package/dist/agent-src/commands/ghostwriter/list.md +1 -1
  33. package/dist/agent-src/commands/ghostwriter/show.md +1 -1
  34. package/dist/agent-src/commands/ghostwriter/write.md +9 -9
  35. package/dist/agent-src/commands/humanize.md +6 -6
  36. package/dist/agent-src/commands/jira-ticket.md +1 -1
  37. package/dist/agent-src/commands/judge/solo.md +1 -1
  38. package/dist/agent-src/commands/judge.md +1 -1
  39. package/dist/agent-src/commands/knowledge/cross-repo.md +1 -1
  40. package/dist/agent-src/commands/knowledge/forget.md +1 -1
  41. package/dist/agent-src/commands/knowledge/ingest.md +2 -2
  42. package/dist/agent-src/commands/knowledge/list.md +1 -1
  43. package/dist/agent-src/commands/memory/add.md +3 -3
  44. package/dist/agent-src/commands/memory/load.md +4 -4
  45. package/dist/agent-src/commands/memory/mine-session.md +1 -1
  46. package/dist/agent-src/commands/memory/promote.md +4 -4
  47. package/dist/agent-src/commands/memory/propose.md +2 -2
  48. package/dist/agent-src/commands/mode.md +5 -5
  49. package/dist/agent-src/commands/post-as/ghostwriter.md +3 -3
  50. package/dist/agent-src/commands/post-as/me.md +7 -7
  51. package/dist/agent-src/commands/pr/create.md +1 -1
  52. package/dist/agent-src/commands/pr/merge.md +48 -39
  53. package/dist/agent-src/commands/profile/activate.md +1 -1
  54. package/dist/agent-src/commands/profile/show.md +1 -1
  55. package/dist/agent-src/commands/research/deep.md +2 -2
  56. package/dist/agent-src/commands/research/report.md +2 -2
  57. package/dist/agent-src/commands/review/changes.md +1 -1
  58. package/dist/agent-src/commands/review/routing.md +1 -1
  59. package/dist/agent-src/commands/roadmap/create.md +1 -1
  60. package/dist/agent-src/commands/roadmap/materialize.md +2 -2
  61. package/dist/agent-src/commands/roadmap/next.md +9 -1
  62. package/dist/agent-src/commands/roadmap/process-full.md +2 -2
  63. package/dist/agent-src/commands/security-audit-config.md +3 -3
  64. package/dist/agent-src/commands/skill/preview.md +1 -1
  65. package/dist/agent-src/commands/skills/discover.md +1 -1
  66. package/dist/agent-src/commands/sync/agent-settings.md +2 -2
  67. package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
  68. package/dist/agent-src/commands/tests/create.md +1 -1
  69. package/dist/agent-src/commands/tests/e2e-heal.md +1 -1
  70. package/dist/agent-src/commands/tests/e2e-plan.md +1 -1
  71. package/dist/agent-src/contexts/authority/kernel-rule-edits.md +6 -6
  72. package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -2
  73. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +2 -2
  74. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +88 -1
  75. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +1 -1
  76. package/dist/agent-src/contexts/contracts/frugality-charter.md +1 -1
  77. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +1 -1
  78. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
  79. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +13 -1
  80. package/dist/agent-src/contexts/execution/cheap-question-mechanics.md +1 -1
  81. package/dist/agent-src/contexts/execution/contract-decision-sheet.md +3 -3
  82. package/dist/agent-src/contexts/execution/mandated-lines.md +1 -1
  83. package/dist/agent-src/contexts/execution/non-interactive-contract.md +1 -1
  84. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -1
  85. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +5 -5
  86. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +1 -1
  87. package/dist/agent-src/contexts/execution/subagent-modes-detail.md +1 -1
  88. package/dist/agent-src/contexts/execution/subagent-routing.md +2 -2
  89. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +1 -1
  90. package/dist/agent-src/contexts/execution/user-memory-channels.md +3 -3
  91. package/dist/agent-src/contexts/execution/verification-mechanics.md +1 -1
  92. package/dist/agent-src/contexts/judges/persona-voice-rubric.md +2 -2
  93. package/dist/agent-src/guidelines/abstraction-thresholds.md +88 -0
  94. package/dist/agent-src/guidelines/agent-infra/5w2h-analysis.md +260 -0
  95. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +99 -0
  96. package/dist/agent-src/guidelines/agent-infra/agent-interaction-and-decision-quality.md +325 -0
  97. package/dist/agent-src/guidelines/agent-infra/api-cost-levers.md +177 -0
  98. package/dist/agent-src/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +222 -0
  99. package/dist/agent-src/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
  100. package/dist/agent-src/guidelines/agent-infra/asking-and-brevity-examples.md +198 -0
  101. package/dist/agent-src/guidelines/agent-infra/break-glass-usage.md +113 -0
  102. package/dist/agent-src/guidelines/agent-infra/carve-out-predicates.md +17 -0
  103. package/dist/agent-src/guidelines/agent-infra/comparison-matrix.md +179 -0
  104. package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +165 -0
  105. package/dist/agent-src/guidelines/agent-infra/corpus-grounding-authoring.md +91 -0
  106. package/dist/agent-src/guidelines/agent-infra/critical-thinking.md +156 -0
  107. package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +109 -0
  108. package/dist/agent-src/guidelines/agent-infra/developer-judgment.md +82 -0
  109. package/dist/agent-src/guidelines/agent-infra/direct-answers-demos.md +142 -0
  110. package/dist/agent-src/guidelines/agent-infra/domain-adoption-gates.md +112 -0
  111. package/dist/agent-src/guidelines/agent-infra/domain-eval-anti-pattern.md +53 -0
  112. package/dist/agent-src/guidelines/agent-infra/domain-pack-architecture.md +56 -0
  113. package/dist/agent-src/guidelines/agent-infra/downstream-changes-mechanics.md +91 -0
  114. package/dist/agent-src/guidelines/agent-infra/emphasis-budget.md +45 -0
  115. package/dist/agent-src/guidelines/agent-infra/engineering-memory-data-format.md +210 -0
  116. package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
  117. package/dist/agent-src/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  118. package/dist/agent-src/guidelines/agent-infra/failure-signatures.md +70 -0
  119. package/dist/agent-src/guidelines/agent-infra/false-green.md +233 -0
  120. package/dist/agent-src/guidelines/agent-infra/first-principles.md +192 -0
  121. package/dist/agent-src/guidelines/agent-infra/framework-neutrality-patterns.md +66 -0
  122. package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +169 -0
  123. package/dist/agent-src/guidelines/agent-infra/gate-authoring.md +177 -0
  124. package/dist/agent-src/guidelines/agent-infra/guarded-baseline.md +39 -0
  125. package/dist/agent-src/guidelines/agent-infra/installed-tools-manifest.md +142 -0
  126. package/dist/agent-src/guidelines/agent-infra/inversion-thinking.md +388 -0
  127. package/dist/agent-src/guidelines/agent-infra/ios-simulator-guide.md +378 -0
  128. package/dist/agent-src/guidelines/agent-infra/language-and-tone-examples.md +141 -0
  129. package/dist/agent-src/guidelines/agent-infra/layered-settings.md +317 -0
  130. package/dist/agent-src/guidelines/agent-infra/linked-projects-onboarding-gate.md +80 -0
  131. package/dist/agent-src/guidelines/agent-infra/mcp-request-signing.md +197 -0
  132. package/dist/agent-src/guidelines/agent-infra/memory-access.md +149 -0
  133. package/dist/agent-src/guidelines/agent-infra/mental-models.md +314 -0
  134. package/dist/agent-src/guidelines/agent-infra/minimal-safe-diff-mechanics.md +241 -0
  135. package/dist/agent-src/guidelines/agent-infra/missing-tool-handling.md +66 -0
  136. package/dist/agent-src/guidelines/agent-infra/model-recommendation.md +101 -0
  137. package/dist/agent-src/guidelines/agent-infra/naming.md +69 -0
  138. package/dist/agent-src/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
  139. package/dist/agent-src/guidelines/agent-infra/output-patterns.md +117 -0
  140. package/dist/agent-src/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
  141. package/dist/agent-src/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  142. package/dist/agent-src/guidelines/agent-infra/review-routing-data-format.md +143 -0
  143. package/dist/agent-src/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
  144. package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +274 -0
  145. package/dist/agent-src/guidelines/agent-infra/role-contracts.md +209 -0
  146. package/dist/agent-src/guidelines/agent-infra/role-mode-router.md +89 -0
  147. package/dist/agent-src/guidelines/agent-infra/rule-body-migration-inventory.md +241 -0
  148. package/dist/agent-src/guidelines/agent-infra/rule-type-governance.md +73 -0
  149. package/dist/agent-src/guidelines/agent-infra/runtime-layer.md +89 -0
  150. package/dist/agent-src/guidelines/agent-infra/scqa-framework.md +526 -0
  151. package/dist/agent-src/guidelines/agent-infra/security-lint-containment.md +121 -0
  152. package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +134 -0
  153. package/dist/agent-src/guidelines/agent-infra/simplicity-and-goal-demos.md +211 -0
  154. package/dist/agent-src/guidelines/agent-infra/six-hats.md +353 -0
  155. package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +229 -0
  156. package/dist/agent-src/guidelines/agent-infra/skill-quality-checklist.md +157 -0
  157. package/dist/agent-src/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  158. package/dist/agent-src/guidelines/agent-infra/symptom-driven-harvest-loop.md +104 -0
  159. package/dist/agent-src/guidelines/agent-infra/systems-thinking.md +220 -0
  160. package/dist/agent-src/guidelines/agent-infra/tool-description-as-policy.md +35 -0
  161. package/dist/agent-src/guidelines/agent-infra/tool-integration.md +73 -0
  162. package/dist/agent-src/guidelines/agent-infra/traceability-field-mechanics.md +50 -0
  163. package/dist/agent-src/guidelines/agent-infra/untrusted-input-spotlighting.md +166 -0
  164. package/dist/agent-src/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
  165. package/dist/agent-src/guidelines/augment-portability-patterns.md +70 -0
  166. package/dist/agent-src/guidelines/code-clarity.md +350 -0
  167. package/dist/agent-src/guidelines/component-oriented-and-oop-development.md +189 -0
  168. package/dist/agent-src/guidelines/cross-role-handoff.md +127 -0
  169. package/dist/agent-src/guidelines/design-antipatterns-triggers.json +18 -0
  170. package/dist/agent-src/guidelines/design-antipatterns.md +327 -0
  171. package/dist/agent-src/guidelines/design-asset-discipline.md +38 -0
  172. package/dist/agent-src/guidelines/design-canon.md +63 -0
  173. package/dist/agent-src/guidelines/design-fidelity-mechanics.md +293 -0
  174. package/dist/agent-src/guidelines/design-fidelity-routing.md +78 -0
  175. package/dist/agent-src/guidelines/design-handover-extraction.md +117 -0
  176. package/dist/agent-src/guidelines/design-modes.md +143 -0
  177. package/dist/agent-src/guidelines/design-reconciliation.md +172 -0
  178. package/dist/agent-src/guidelines/docs/readme-size-and-splitting.md +209 -0
  179. package/dist/agent-src/guidelines/e2e/playwright.md +363 -0
  180. package/dist/agent-src/guidelines/gtm-handoff.md +114 -0
  181. package/dist/agent-src/guidelines/monorepo-antipatterns.md +141 -0
  182. package/dist/agent-src/guidelines/php/api-design.md +115 -0
  183. package/dist/agent-src/guidelines/php/artisan-commands.md +81 -0
  184. package/dist/agent-src/guidelines/php/blade-ui.md +78 -0
  185. package/dist/agent-src/guidelines/php/controllers.md +90 -0
  186. package/dist/agent-src/guidelines/php/database.md +194 -0
  187. package/dist/agent-src/guidelines/php/eloquent.md +208 -0
  188. package/dist/agent-src/guidelines/php/flux.md +80 -0
  189. package/dist/agent-src/guidelines/php/general.md +207 -0
  190. package/dist/agent-src/guidelines/php/git.md +164 -0
  191. package/dist/agent-src/guidelines/php/jobs.md +111 -0
  192. package/dist/agent-src/guidelines/php/livewire.md +71 -0
  193. package/dist/agent-src/guidelines/php/logging.md +79 -0
  194. package/dist/agent-src/guidelines/php/naming.md +89 -0
  195. package/dist/agent-src/guidelines/php/patterns/dependency-injection.md +57 -0
  196. package/dist/agent-src/guidelines/php/patterns/dtos.md +199 -0
  197. package/dist/agent-src/guidelines/php/patterns/events.md +67 -0
  198. package/dist/agent-src/guidelines/php/patterns/factory.md +53 -0
  199. package/dist/agent-src/guidelines/php/patterns/pipelines.md +66 -0
  200. package/dist/agent-src/guidelines/php/patterns/policies.md +66 -0
  201. package/dist/agent-src/guidelines/php/patterns/repositories.md +122 -0
  202. package/dist/agent-src/guidelines/php/patterns/service-layer.md +64 -0
  203. package/dist/agent-src/guidelines/php/patterns/strategy.md +247 -0
  204. package/dist/agent-src/guidelines/php/patterns.md +28 -0
  205. package/dist/agent-src/guidelines/php/performance.md +92 -0
  206. package/dist/agent-src/guidelines/php/php-coding-patterns.md +80 -0
  207. package/dist/agent-src/guidelines/php/resources.md +100 -0
  208. package/dist/agent-src/guidelines/php/security.md +110 -0
  209. package/dist/agent-src/guidelines/php/sql.md +97 -0
  210. package/dist/agent-src/guidelines/php/validations.md +119 -0
  211. package/dist/agent-src/guidelines/php/websocket.md +100 -0
  212. package/dist/agent-src/guidelines/prompt-templates.md +189 -0
  213. package/dist/agent-src/guidelines/redundancy-taxonomy.md +208 -0
  214. package/dist/agent-src/guidelines/wing4-handoff.md +127 -0
  215. package/dist/agent-src/personas/README.md +1 -1
  216. package/dist/agent-src/personas/_template-specialist/persona.md +1 -1
  217. package/dist/agent-src/personas/product-owner.md +1 -1
  218. package/dist/agent-src/rules/active-remediation.md +1 -1
  219. package/dist/agent-src/rules/architecture.md +2 -2
  220. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  221. package/dist/agent-src/rules/ask-when-uncertain.md +2 -2
  222. package/dist/agent-src/rules/brand-source-of-truth.md +9 -7
  223. package/dist/agent-src/rules/code-comment-discipline.md +2 -2
  224. package/dist/agent-src/rules/code-provenance.md +1 -1
  225. package/dist/agent-src/rules/content-quoting-floor.md +1 -1
  226. package/dist/agent-src/rules/context-hygiene.md +5 -5
  227. package/dist/agent-src/rules/cross-source-consistency.md +1 -1
  228. package/dist/agent-src/rules/design-fidelity.md +36 -46
  229. package/dist/agent-src/rules/direct-answers.md +2 -2
  230. package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
  231. package/dist/agent-src/rules/evaluator-independence.md +1 -1
  232. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
  233. package/dist/agent-src/rules/icon-consistency.md +5 -1
  234. package/dist/agent-src/rules/improve-before-implement.md +1 -1
  235. package/dist/agent-src/rules/language-and-tone.md +3 -3
  236. package/dist/agent-src/rules/minimal-safe-diff.md +1 -1
  237. package/dist/agent-src/rules/notes-first-reasoning.md +36 -25
  238. package/dist/agent-src/rules/recurring-criticism.md +1 -1
  239. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  240. package/dist/agent-src/rules/role-mode-adherence.md +2 -2
  241. package/dist/agent-src/rules/security-sensitive-stop.md +1 -1
  242. package/dist/agent-src/rules/size-enforcement.md +1 -1
  243. package/dist/agent-src/rules/source-confidentiality.md +2 -2
  244. package/dist/agent-src/rules/think-before-action.md +1 -1
  245. package/dist/agent-src/rules/token-efficiency.md +7 -5
  246. package/dist/agent-src/rules/ui-audit-gate.md +3 -2
  247. package/dist/agent-src/rules/untrusted-input-defense.md +3 -3
  248. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +106 -4
  249. package/dist/agent-src/skills/activation-design/SKILL.md +2 -2
  250. package/dist/agent-src/skills/adr-create/SKILL.md +5 -5
  251. package/dist/agent-src/skills/ai-council/SKILL.md +1 -1
  252. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +1 -1
  253. package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
  254. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
  255. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +24 -3
  256. package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
  257. package/dist/agent-src/skills/build-buy-partner/SKILL.md +1 -1
  258. package/dist/agent-src/skills/churn-prevention/SKILL.md +2 -2
  259. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -1
  260. package/dist/agent-src/skills/code-refactoring/SKILL.md +3 -3
  261. package/dist/agent-src/skills/code-review/SKILL.md +3 -3
  262. package/dist/agent-src/skills/command-writing/SKILL.md +3 -3
  263. package/dist/agent-src/skills/comp-banding/SKILL.md +1 -1
  264. package/dist/agent-src/skills/competitive-moat-analysis/SKILL.md +1 -1
  265. package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
  266. package/dist/agent-src/skills/complexity-first-planning/SKILL.md +1 -1
  267. package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
  268. package/dist/agent-src/skills/content-funnel-design/SKILL.md +2 -2
  269. package/dist/agent-src/skills/contracts-cognition/SKILL.md +1 -1
  270. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +2 -2
  271. package/dist/agent-src/skills/corpus-grounding/SKILL.md +2 -2
  272. package/dist/agent-src/skills/customer-research/SKILL.md +2 -2
  273. package/dist/agent-src/skills/dashboard-design/SKILL.md +1 -1
  274. package/dist/agent-src/skills/data-handling-judgment/SKILL.md +1 -1
  275. package/dist/agent-src/skills/deal-qualification-meddic/SKILL.md +2 -2
  276. package/dist/agent-src/skills/decision-record/SKILL.md +3 -3
  277. package/dist/agent-src/skills/decision-review/SKILL.md +8 -8
  278. package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +22 -22
  279. package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
  280. package/dist/agent-src/skills/design-intelligence/references/context-and-registers.md +2 -2
  281. package/dist/agent-src/skills/design-review/SKILL.md +4 -4
  282. package/dist/agent-src/skills/design-system-capture/references/design-system-json.md +20 -1
  283. package/dist/agent-src/skills/design-tokens/SKILL.md +17 -2
  284. package/dist/agent-src/skills/design-variations/SKILL.md +2 -2
  285. package/dist/agent-src/skills/developer-like-execution/SKILL.md +2 -2
  286. package/dist/agent-src/skills/discovery-interview/SKILL.md +2 -2
  287. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +3 -3
  288. package/dist/agent-src/skills/editorial-calendar/SKILL.md +2 -2
  289. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +44 -1
  290. package/dist/agent-src/skills/existing-ui-audit/references/anti-slop-cross-reference.md +2 -2
  291. package/dist/agent-src/skills/expansion-playbook/SKILL.md +2 -2
  292. package/dist/agent-src/skills/experiment-loop/SKILL.md +1 -1
  293. package/dist/agent-src/skills/experiment-loop/references/protocol.md +1 -1
  294. package/dist/agent-src/skills/fe-design/SKILL.md +3 -3
  295. package/dist/agent-src/skills/fe-design/references/design-patterns.md +1 -1
  296. package/dist/agent-src/skills/fe-design/references/design-read-and-memory.md +3 -3
  297. package/dist/agent-src/skills/fe-design/references/source-led-port.md +1 -1
  298. package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
  299. package/dist/agent-src/skills/flux/SKILL.md +1 -1
  300. package/dist/agent-src/skills/forecast-accuracy/SKILL.md +2 -2
  301. package/dist/agent-src/skills/forecasting/SKILL.md +2 -2
  302. package/dist/agent-src/skills/fundraising-narrative/SKILL.md +2 -2
  303. package/dist/agent-src/skills/funnel-analysis/SKILL.md +2 -2
  304. package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +9 -0
  305. package/dist/agent-src/skills/gtm-launch/SKILL.md +2 -2
  306. package/dist/agent-src/skills/hiring-loop-design/SKILL.md +1 -1
  307. package/dist/agent-src/skills/html-deck/SKILL.md +5 -5
  308. package/dist/agent-src/skills/humanizer/SKILL.md +1 -1
  309. package/dist/agent-src/skills/humanizer/data/patterns.md +1 -1
  310. package/dist/agent-src/skills/iconography/SKILL.md +3 -3
  311. package/dist/agent-src/skills/judge-synthesis/SKILL.md +1 -1
  312. package/dist/agent-src/skills/laravel-api-endpoint/SKILL.md +2 -2
  313. package/dist/agent-src/skills/launch-readiness/SKILL.md +3 -3
  314. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +6 -6
  315. package/dist/agent-src/skills/livewire/SKILL.md +1 -1
  316. package/dist/agent-src/skills/market-entry-analysis/SKILL.md +1 -1
  317. package/dist/agent-src/skills/mcp-builder/SKILL.md +1 -1
  318. package/dist/agent-src/skills/memory-consolidation/SKILL.md +3 -3
  319. package/dist/agent-src/skills/messaging-architecture/SKILL.md +2 -2
  320. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  321. package/dist/agent-src/skills/onboarding-design/SKILL.md +2 -2
  322. package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
  323. package/dist/agent-src/skills/one-on-one-cadence/SKILL.md +1 -1
  324. package/dist/agent-src/skills/org-design/SKILL.md +1 -1
  325. package/dist/agent-src/skills/overbuild-review-lens/SKILL.md +3 -3
  326. package/dist/agent-src/skills/override-management/SKILL.md +1 -1
  327. package/dist/agent-src/skills/perf-feedback-craft/SKILL.md +1 -1
  328. package/dist/agent-src/skills/persona-writing/SKILL.md +1 -1
  329. package/dist/agent-src/skills/php-coder/SKILL.md +1 -1
  330. package/dist/agent-src/skills/pipeline-strategy/SKILL.md +2 -2
  331. package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -3
  332. package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
  333. package/dist/agent-src/skills/positioning-strategy/SKILL.md +2 -2
  334. package/dist/agent-src/skills/privacy-review/SKILL.md +1 -1
  335. package/dist/agent-src/skills/prompt-optimizer/SKILL.md +3 -3
  336. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  337. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -2
  338. package/dist/agent-src/skills/receiving-code-review/SKILL.md +1 -1
  339. package/dist/agent-src/skills/refine-ticket/SKILL.md +2 -2
  340. package/dist/agent-src/skills/release-comms/SKILL.md +2 -2
  341. package/dist/agent-src/skills/retention-loops/SKILL.md +2 -2
  342. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  343. package/dist/agent-src/skills/roadmap-management/SKILL.md +1 -1
  344. package/dist/agent-src/skills/roadmap-management/references/archival.md +1 -1
  345. package/dist/agent-src/skills/roadmap-writing/SKILL.md +5 -5
  346. package/dist/agent-src/skills/rule-writing/SKILL.md +6 -6
  347. package/dist/agent-src/skills/runway-cognition/SKILL.md +2 -2
  348. package/dist/agent-src/skills/scenario-modeling/SKILL.md +2 -2
  349. package/dist/agent-src/skills/skill-writing/SKILL.md +2 -2
  350. package/dist/agent-src/skills/skill-writing/references/procedure.md +1 -1
  351. package/dist/agent-src/skills/skill-writing/references/section-patterns.md +3 -3
  352. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +1 -1
  353. package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +3 -3
  354. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
  355. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +1 -1
  356. package/dist/agent-src/skills/systematic-debugging/SKILL.md +2 -2
  357. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +60 -4
  358. package/dist/agent-src/skills/throughput-vs-morale-tradeoff/SKILL.md +1 -1
  359. package/dist/agent-src/skills/token-optimizer/SKILL.md +1 -1
  360. package/dist/agent-src/skills/typography-system/SKILL.md +2 -2
  361. package/dist/agent-src/skills/ui-component-architect/SKILL.md +28 -8
  362. package/dist/agent-src/skills/unit-economics-modeling/SKILL.md +2 -2
  363. package/dist/agent-src/skills/upstream-contribute/SKILL.md +1 -1
  364. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +2 -2
  365. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
  366. package/dist/agent-src/skills/vision-articulation/SKILL.md +1 -1
  367. package/dist/agent-src/skills/voc-extract/SKILL.md +2 -2
  368. package/dist/agent-src/skills/voice-and-tone-design/SKILL.md +2 -2
  369. package/dist/agent-src/skills/wireframe/SKILL.md +1 -1
  370. package/dist/agent-src/skills/workspace-link/SKILL.md +1 -1
  371. package/dist/agent-src/templates/agent-settings.md +6 -6
  372. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  373. package/dist/agent-src/templates/contexts/knowledge-pages.md +2 -3
  374. package/dist/agent-src/templates/copilot-instructions.md +1 -1
  375. package/dist/agent-src/templates/roadmaps.md +1 -1
  376. package/dist/agent-src/templates/scripts/README.md +2 -2
  377. package/dist/agent-src/user-types/_template/user-type.md +1 -1
  378. package/dist/cli/registry.js +1 -1
  379. package/dist/cli-delegate/archive_completed_roadmaps.js +52 -4
  380. package/dist/cli-delegate/check_update_banner.js +12 -1
  381. package/dist/cli-delegate/{chunk-TGIPZBCW.js → chunk-2KKXJW25.js} +22 -8
  382. package/dist/cli-delegate/{chunk-NLP54U3J.js → chunk-2XY7ILBT.js} +13 -1
  383. package/dist/cli-delegate/{chunk-4FS4WRXP.js → chunk-3FKR64R5.js} +34 -6
  384. package/dist/cli-delegate/{chunk-J3RFNKG4.js → chunk-55ACLDUE.js} +2 -2
  385. package/dist/cli-delegate/{chunk-PKOBQADP.js → chunk-57PN4GYJ.js} +1 -1
  386. package/dist/cli-delegate/{chunk-BIXEDQPZ.js → chunk-AK6HODNQ.js} +4 -4
  387. package/dist/cli-delegate/{chunk-2FTMENJL.js → chunk-GYC3VRYN.js} +1 -1
  388. package/dist/cli-delegate/{chunk-LWTYTX6F.js → chunk-HZ52BRGG.js} +24 -18
  389. package/dist/cli-delegate/{chunk-6RJA2F5A.js → chunk-IVBPRCQO.js} +1 -1
  390. package/dist/cli-delegate/{chunk-I6RHFQEG.js → chunk-YUM5KURG.js} +17 -1
  391. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  392. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  393. package/dist/cli-delegate/cmd_conformance.js +3 -3
  394. package/dist/cli-delegate/cmd_doctor.js +3 -3
  395. package/dist/cli-delegate/cmd_explain.js +2 -2
  396. package/dist/cli-delegate/cmd_export.js +4 -4
  397. package/dist/cli-delegate/cmd_handoff.js +24 -16
  398. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  399. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  400. package/dist/cli-delegate/cmd_migrate.js +2 -2
  401. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  402. package/dist/cli-delegate/cmd_prune.js +4 -4
  403. package/dist/cli-delegate/cmd_route_audit.js +3 -3
  404. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  405. package/dist/cli-delegate/cmd_session_recycle.js +4 -14
  406. package/dist/cli-delegate/cmd_settings_get.js +15 -9
  407. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  408. package/dist/cli-delegate/cmd_settings_set.js +41 -11
  409. package/dist/cli-delegate/cmd_sync.js +4 -4
  410. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  411. package/dist/cli-delegate/cmd_update.js +1 -1
  412. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  413. package/dist/cli-delegate/cmd_validate.js +4 -4
  414. package/dist/cli-delegate/cmd_versions.js +1 -1
  415. package/dist/discovery/deprecation-report.md +1 -1
  416. package/dist/discovery/discovery-manifest.json +27 -80
  417. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  418. package/dist/discovery/discovery-manifest.summary.md +3 -3
  419. package/dist/discovery/dormancy-report.md +1 -1
  420. package/dist/discovery/orphan-report.md +1 -1
  421. package/dist/discovery/packs.json +5 -7
  422. package/dist/discovery/trust-report.md +2 -2
  423. package/dist/discovery/workspaces.json +4 -6
  424. package/dist/hooks/dispatch.js +9249 -8981
  425. package/dist/install/install.mjs +47 -8
  426. package/dist/mcp/registry-manifest.json +3 -3
  427. package/dist/mcp/server.json +2 -2
  428. package/dist/mcp/server.mjs +5496 -2400
  429. package/dist/router.json +1 -1
  430. package/dist/scripts/_lib/agent_settings.js +73 -0
  431. package/dist/scripts/_lib/agent_src.js +20 -0
  432. package/dist/scripts/_lib/guidelines_lane.js +158 -0
  433. package/dist/scripts/_lib/lean_projection_mode.js +108 -0
  434. package/dist/scripts/_lib/router_match.js +243 -0
  435. package/dist/scripts/_lib/rule_injection.js +216 -0
  436. package/dist/scripts/condense.js +22 -25
  437. package/dist/scripts/project_thin_rules.js +139 -19
  438. package/dist/server/io/yamlIO.js +125 -17
  439. package/dist/server/schemas/settings.js +32 -5
  440. package/dist/shared/settingsSurface.js +6 -1
  441. package/docs/MIGRATION.md +56 -0
  442. package/docs/contracts/settings-classes.md +48 -7
  443. package/docs/guidelines/abstraction-thresholds.md +35 -0
  444. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +3 -3
  445. package/docs/guidelines/agent-infra/false-green.md +2 -2
  446. package/docs/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
  447. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  448. package/docs/guidelines/agent-infra/skill-quality-checklist.md +1 -1
  449. package/docs/guidelines/design-fidelity-mechanics.md +4 -0
  450. package/docs/guidelines/design-fidelity-routing.md +78 -0
  451. package/docs/guidelines/design-reconciliation.md +172 -0
  452. package/docs/guidelines/gtm-handoff.md +2 -2
  453. package/docs/guidelines/wing4-handoff.md +2 -2
  454. package/llms.txt +1 -1
  455. package/package.json +7 -3
  456. package/src/agent-src/scripts/archive_completed_roadmaps.ts +106 -4
  457. package/src/config/agent-settings.template.yml +94 -1
  458. package/src/config/ci-local-parity.yml +34 -0
  459. package/src/config/continuity-surface.json +8 -29
  460. package/src/config/evaluator-budgets.json +4 -4
  461. package/src/config/gate-coverage.yml +31 -8
  462. package/src/config/gate-reachability-exemptions.json +1 -0
  463. package/src/config/gate-violation-baselines.json +3 -3
  464. package/src/config/hook-token-budget.json +8 -7
  465. package/src/config/host-injection-effect.json +2 -2
  466. package/src/config/pack-size-budget.json +55 -4
  467. package/src/config/packed-binary-manifest.json +1 -1
  468. package/src/config/platform-anchor.json +47 -0
  469. package/src/config/preamble-payload-budget.json +2 -3
  470. package/src/config/publish-surface.json +4 -2
  471. package/src/config/ratification-policy.json +7 -0
  472. package/src/config/routing-coverage-seed.json +9 -2
  473. package/src/config/rule-stub-ceilings.json +16 -9
  474. package/src/scripts/_cli/cmd_session_recycle.ts +2 -25
  475. package/src/scripts/_cli/cmd_settings_get.ts +22 -7
  476. package/src/scripts/_cli/handoff_sessions.ts +14 -44
  477. package/src/scripts/_lib/agent_settings.ts +85 -0
  478. package/src/scripts/_lib/agent_src.ts +21 -0
  479. package/src/scripts/_lib/artifact_maturity.ts +242 -0
  480. package/src/scripts/_lib/conformance_report.ts +403 -0
  481. package/src/scripts/_lib/continuity_slot.ts +295 -0
  482. package/src/scripts/_lib/continuity_writer.ts +312 -0
  483. package/src/scripts/_lib/design_system_import.ts +20 -0
  484. package/src/scripts/_lib/design_tolerance.ts +281 -0
  485. package/src/scripts/_lib/guidelines_lane.ts +164 -0
  486. package/src/scripts/_lib/hook_settings.ts +85 -0
  487. package/src/scripts/_lib/lean_projection_mode.ts +127 -0
  488. package/src/scripts/_lib/obligation_frequency.ts +2 -3
  489. package/src/scripts/_lib/packed_binary_predicate.ts +37 -0
  490. package/src/scripts/_lib/platform_anchor.ts +1053 -0
  491. package/src/scripts/_lib/ratification_artifact.ts +278 -0
  492. package/src/scripts/_lib/recycle_envelope_paths.ts +109 -21
  493. package/src/scripts/_lib/regression_neighbourhood.ts +159 -22
  494. package/src/scripts/_lib/security_lint.ts +23 -2
  495. package/src/scripts/_lib/self_repair.ts +21 -0
  496. package/src/scripts/_lib/session_eol.ts +44 -0
  497. package/src/scripts/_lib/session_index_trust.ts +387 -0
  498. package/src/scripts/_lib/standing_bound_ratchet.ts +220 -0
  499. package/src/scripts/_lib/tolerance_shadow.ts +177 -0
  500. package/src/scripts/_lib/vendored_grammar_upstream.ts +280 -0
  501. package/src/scripts/ai_council/redact_low_impact_entry.ts +8 -0
  502. package/src/scripts/audit_mcp_tools.ts +69 -25
  503. package/src/scripts/autonomy_friction_traffic.ts +379 -0
  504. package/src/scripts/build_mcp_catalog.ts +24 -1
  505. package/src/scripts/check_host_tree_parity.ts +291 -0
  506. package/src/scripts/check_kernel_edit_ratified.ts +462 -0
  507. package/src/scripts/check_loss_class_declared.ts +793 -46
  508. package/src/scripts/check_platform_anchor.ts +390 -0
  509. package/src/scripts/check_preamble_payload_budget.ts +424 -7
  510. package/src/scripts/check_projected_rule_routes.ts +395 -0
  511. package/src/scripts/check_rule_projection_integrity.ts +102 -2
  512. package/src/scripts/ci_settle.ts +205 -5
  513. package/src/scripts/code_graph/build.ts +79 -0
  514. package/src/scripts/code_graph/cli.ts +264 -7
  515. package/src/scripts/code_graph/detect.ts +38 -0
  516. package/src/scripts/code_graph/query.ts +25 -2
  517. package/src/scripts/code_graph/sqlite_store.ts +16 -1
  518. package/src/scripts/code_graph/types.ts +52 -3
  519. package/src/scripts/code_graph/validate.ts +3 -1
  520. package/src/scripts/code_graph/verbs.ts +590 -0
  521. package/src/scripts/condense.ts +22 -26
  522. package/src/scripts/generate_host_cost_table.ts +354 -0
  523. package/src/scripts/handoff_context_hook.ts +39 -1
  524. package/src/scripts/hook_manifest.json +1 -1
  525. package/src/scripts/hook_manifest.yaml +59 -28
  526. package/src/scripts/hooks/block_speaking_inbox_dir.ts +182 -16
  527. package/src/scripts/hooks/category_a.ts +1 -1
  528. package/src/scripts/hooks/chain_nudge_hook.ts +311 -25
  529. package/src/scripts/hooks/code_graph_context_hook.ts +7 -18
  530. package/src/scripts/hooks/push_settle_hook.ts +3 -2
  531. package/src/scripts/hooks/rule_inject_hook.ts +107 -20
  532. package/src/scripts/hooks/session_eol_hook.ts +177 -145
  533. package/src/scripts/hooks/source_first_gate_hook.ts +12 -0
  534. package/src/scripts/hooks/ui_route_nudge_hook.ts +52 -15
  535. package/src/scripts/hot_context_hook.ts +103 -408
  536. package/src/scripts/lint_evidence_artifacts.ts +1 -0
  537. package/src/scripts/lint_knowledge_scale.ts +0 -26
  538. package/src/scripts/lint_roadmap_blockers.ts +164 -1
  539. package/src/scripts/mcp_server/consumer_tool_catalog.json +152 -2
  540. package/src/scripts/mcp_server/graph_tools.ts +294 -0
  541. package/src/scripts/mcp_server/path_util.ts +31 -0
  542. package/src/scripts/mcp_server/tool_catalog_source.ts +7 -1
  543. package/src/scripts/mcp_server/tools.ts +3 -13
  544. package/src/scripts/memory_lookup.ts +9 -9
  545. package/src/scripts/model_rule_injection.ts +61 -4
  546. package/src/scripts/project_thin_rules.ts +149 -16
  547. package/src/scripts/report_standing_payload_by_host.ts +650 -0
  548. package/src/scripts/schemas/agent-settings.schema.json +7 -1
  549. package/src/scripts/session_memory_index.ts +86 -8
  550. package/src/scripts/sync_agent_settings.ts +270 -10
  551. package/src/server/io/yamlIO.ts +127 -17
  552. package/src/server/schemas/settings.ts +45 -6
  553. package/src/shared/settingsSurface.ts +13 -2
  554. package/src/templates/compact-instructions.md +8 -3
  555. package/src/vendor/grammars/README.md +27 -2
  556. package/dist/agent-src/commands/chat-history/import.md +0 -170
  557. package/dist/agent-src/commands/chat-history.md +0 -63
@@ -0,0 +1,242 @@
1
+ /**
2
+ * `spec.maturity` — the artefact-maturity axis as a resolved field with
3
+ * provenance, not as a prose table two surfaces each keep a copy of.
4
+ *
5
+ * The axis itself is already decided. `design-fidelity.md` § Two axes states
6
+ * it: maturity is a property of the ARTEFACT, mandate is a property of the
7
+ * INSTRUCTION, and reproducing a wireframe's placeholder greys 1:1 honours the
8
+ * wrong half of the artefact. `design-fidelity-mechanics § Artefact maturity`
9
+ * carries the low-versus-finished table. What was missing is a value anything
10
+ * can read: the table was prose, so every consumer re-derived it by eye and two
11
+ * consumers could disagree without either being wrong about the text.
12
+ *
13
+ * **Two-valued on purpose, and not the same axis as `ReferenceMaturity`.**
14
+ * `ui_authority.ts` carries a five-valued `ReferenceMaturity`
15
+ * (`wireframe` | `prototype` | `finished-comp` | `runnable-artifact` |
16
+ * `production-incumbent`) answering *what kind of thing is this*. This answers
17
+ * the narrower question the rule actually branches on: *does its pixel detail
18
+ * carry decisions*. `mapReferenceMaturity` below is the one place the two are
19
+ * related, so a future edit to either enum has exactly one seam to update
20
+ * rather than a scattering of `=== 'wireframe'` comparisons.
21
+ *
22
+ * **The resolution ladder, and why `finished` is the default.** A user signal
23
+ * beats everything, then the artefact's own declaration, then inference from
24
+ * its content, then the default. The default is `finished` because the rule
25
+ * says so in as many words — *"When the artefact does not declare its maturity,
26
+ * it is treated as finished: the 1:1 floor is stricter, and guessing low
27
+ * fidelity would authorise the redesign this rule prevents."* Defaulting the
28
+ * other way would make silence a licence.
29
+ */
30
+
31
+ /** Does the artefact's pixel detail carry decisions, or placeholders? */
32
+ export type ArtifactMaturity = 'low' | 'finished';
33
+
34
+ /** Which rung of the ladder produced the verdict. */
35
+ export type MaturitySource = 'user' | 'declaration' | 'inference' | 'default';
36
+
37
+ export interface MaturityVerdict {
38
+ maturity: ArtifactMaturity;
39
+ source: MaturitySource;
40
+ /**
41
+ * The concrete thing that decided it, quotable back to the user. Never a
42
+ * restatement of the verdict — "the artefact declares itself a wireframe"
43
+ * is a signal, "it is low fidelity" is not.
44
+ */
45
+ signal: string;
46
+ }
47
+
48
+ /** Everything the resolver may look at. Every field is optional by design. */
49
+ export interface MaturityInput {
50
+ /** What the user said this run. Beats every other rung. */
51
+ userSignal?: ArtifactMaturity | null;
52
+ /** A `spec.maturity` the artefact carries about itself. */
53
+ declared?: string | null;
54
+ /** The artefact's filename, if it has one. */
55
+ filename?: string | null;
56
+ /** The artefact's own body — markup, CSS, or a token file's text. */
57
+ body?: string | null;
58
+ /** A five-valued `ReferenceMaturity` already resolved elsewhere. */
59
+ referenceMaturity?: string | null;
60
+ }
61
+
62
+ /**
63
+ * The one seam between the five-valued `ReferenceMaturity` and this axis.
64
+ * Returns `null` for a value that does not decide the question.
65
+ */
66
+ export function mapReferenceMaturity(value: string | null | undefined): ArtifactMaturity | null {
67
+ switch (value) {
68
+ case 'wireframe':
69
+ return 'low';
70
+ case 'finished-comp':
71
+ case 'runnable-artifact':
72
+ case 'production-incumbent':
73
+ return 'finished';
74
+ // `prototype` is deliberately unmapped: the word covers both a greybox
75
+ // click-through and a pixel-complete interactive build, so mapping it
76
+ // either way would decide by vocabulary rather than by evidence. It
77
+ // falls through to inference, which reads the artefact itself.
78
+ default:
79
+ return null;
80
+ }
81
+ }
82
+
83
+ /** Markers an artefact uses to declare itself low-fidelity. */
84
+ const LOW_DECLARATIONS = new Set(['low', 'low-fidelity', 'lofi', 'lo-fi', 'wireframe', 'sketch']);
85
+ /** Markers an artefact uses to declare itself finished. */
86
+ const FINISHED_DECLARATIONS = new Set([
87
+ 'finished',
88
+ 'final',
89
+ 'high',
90
+ 'high-fidelity',
91
+ 'hifi',
92
+ 'hi-fi',
93
+ 'comp',
94
+ 'production',
95
+ ]);
96
+
97
+ /** Content tells that the pixels are placeholders rather than decisions. */
98
+ const LOW_CONTENT_TELLS: ReadonlyArray<readonly [RegExp, string]> = [
99
+ [/lorem\s+ipsum/i, 'placeholder copy (lorem ipsum) in the body'],
100
+ [/\bwireframe\b/i, 'the body calls itself a wireframe'],
101
+ [/\bgreybox\b|\bgraybox\b/i, 'the body describes greybox placeholders'],
102
+ // NOT a bare `\bplaceholder\b`. That fired on
103
+ // `<input placeholder="you@example.com">` in the committed finished
104
+ // fixture — an ordinary HTML attribute, present in most real forms, and
105
+ // the single broadest false positive available on this axis. The tell is
106
+ // the artefact CALLING ITS OWN CONTENT placeholder, so the noun has to
107
+ // follow.
108
+ [
109
+ /placeholder\s+(?:copy|content|text|image|images|art|asset|assets|data)\b/i,
110
+ 'the body marks its own content as placeholder',
111
+ ],
112
+ ];
113
+
114
+ function normalizeDeclaration(value: string): string {
115
+ return value.trim().toLowerCase();
116
+ }
117
+
118
+ /**
119
+ * True when every colour the body states is greyscale — the canonical wireframe
120
+ * tell, and the one the rule names by hand ("reproducing a wireframe's
121
+ * placeholder grays"). Requires at least two colours so a one-off `#fff`
122
+ * in an otherwise colourless token file does not decide anything.
123
+ */
124
+ export function isGreyscaleOnly(body: string): boolean {
125
+ const hexes = body.match(/#[0-9a-fA-F]{3,8}\b/g) ?? [];
126
+ if (hexes.length < 2) return false;
127
+ return hexes.every((hex) => {
128
+ const raw = hex.slice(1);
129
+ const six =
130
+ raw.length === 3
131
+ ? raw
132
+ .split('')
133
+ .map((c) => c + c)
134
+ .join('')
135
+ : raw.slice(0, 6);
136
+ if (six.length < 6) return false;
137
+ const r = parseInt(six.slice(0, 2), 16);
138
+ const g = parseInt(six.slice(2, 4), 16);
139
+ const b = parseInt(six.slice(4, 6), 16);
140
+ return r === g && g === b;
141
+ });
142
+ }
143
+
144
+ /**
145
+ * Resolve the artefact's maturity, naming the signal that decided it.
146
+ *
147
+ * Never throws: an unreadable or absent artefact resolves `finished` by
148
+ * default, which is the conservative direction — see the header.
149
+ */
150
+ export function resolveArtifactMaturity(input: MaturityInput = {}): MaturityVerdict {
151
+ /** Set when rung 2 saw a declaration it could not read; reported, not obeyed. */
152
+ let unreadableDeclaration: string | null = null;
153
+ const withNote = (v: MaturityVerdict): MaturityVerdict =>
154
+ unreadableDeclaration === null
155
+ ? v
156
+ : {
157
+ ...v,
158
+ signal: `${v.signal} (the artifact also declares \`maturity: ${unreadableDeclaration}\`, which this resolver does not recognise)`,
159
+ };
160
+
161
+ // 1. The user. `design-fidelity` § Two axes: a user signal beats any
162
+ // inference, because the human can see what the heuristic cannot.
163
+ if (input.userSignal === 'low' || input.userSignal === 'finished') {
164
+ return {
165
+ maturity: input.userSignal,
166
+ source: 'user',
167
+ signal: `the user stated the artefact is ${input.userSignal} fidelity`,
168
+ };
169
+ }
170
+
171
+ // 2. The artefact's own declaration — the case the rule's Iron Law names.
172
+ if (typeof input.declared === 'string' && input.declared.trim() !== '') {
173
+ const declared = normalizeDeclaration(input.declared);
174
+ if (LOW_DECLARATIONS.has(declared)) {
175
+ return {
176
+ maturity: 'low',
177
+ source: 'declaration',
178
+ signal: `the artefact declares \`maturity: ${declared}\``,
179
+ };
180
+ }
181
+ if (FINISHED_DECLARATIONS.has(declared)) {
182
+ return {
183
+ maturity: 'finished',
184
+ source: 'declaration',
185
+ signal: `the artefact declares \`maturity: ${declared}\``,
186
+ };
187
+ }
188
+ // An unrecognised declaration is NOT silently treated as absent, and it
189
+ // does NOT short-circuit the ladder either. The first version returned
190
+ // here, so an artifact declaring `maturity: draft` while carrying a
191
+ // wireframe filename, a lorem-ipsum body AND a greyscale-only palette
192
+ // resolved `finished` — an unparseable string outranking three signals
193
+ // the resolver does recognise, which inverts the ladder this module's
194
+ // header describes. Blind-review finding. It is remembered instead:
195
+ // reported on whatever verdict the remaining rungs produce, so the
196
+ // reader sees both the unreadable declaration and the evidence.
197
+ unreadableDeclaration = declared;
198
+ }
199
+
200
+ // 3. A ReferenceMaturity already resolved upstream, where it decides.
201
+ const mapped = mapReferenceMaturity(input.referenceMaturity);
202
+ if (mapped !== null) {
203
+ return withNote({
204
+ maturity: mapped,
205
+ source: 'inference',
206
+ signal: `reference_maturity is \`${String(input.referenceMaturity)}\``,
207
+ });
208
+ }
209
+
210
+ // 4. The filename. Cheap, and the one signal present even when the body is
211
+ // not readable.
212
+ if (typeof input.filename === 'string' && /wireframe|wf-|lofi|lo-fi/i.test(input.filename)) {
213
+ return withNote({
214
+ maturity: 'low',
215
+ source: 'inference',
216
+ signal: `the filename \`${input.filename}\` names a wireframe`,
217
+ });
218
+ }
219
+
220
+ // 5. The body.
221
+ if (typeof input.body === 'string' && input.body !== '') {
222
+ for (const [pattern, why] of LOW_CONTENT_TELLS) {
223
+ if (pattern.test(input.body)) {
224
+ return withNote({ maturity: 'low', source: 'inference', signal: why });
225
+ }
226
+ }
227
+ if (isGreyscaleOnly(input.body)) {
228
+ return withNote({
229
+ maturity: 'low',
230
+ source: 'inference',
231
+ signal: 'every color in the body is greyscale',
232
+ });
233
+ }
234
+ }
235
+
236
+ // 6. Default — finished, deliberately. Silence is not a licence to redesign.
237
+ return withNote({
238
+ maturity: 'finished',
239
+ source: 'default',
240
+ signal: 'the artifact declares no maturity and shows no low-fidelity tell',
241
+ });
242
+ }
@@ -0,0 +1,403 @@
1
+ /**
2
+ * Per-dimension conformance of a port against the artifact it was ported from.
3
+ *
4
+ * WHY A DIMENSION REPORT AND NOT A SCORE. `internal/bench/ui` already scores a
5
+ * port on pixel / dom / tokens / interactions and produces one weighted number.
6
+ * A number answers "how close", which is the right question for a benchmark and
7
+ * the wrong one for a fidelity gate: a port can be pixel-identical and still
8
+ * have dropped a keyboard interaction, inlined every value the project has a
9
+ * token for, or lost a breakpoint. Averaged into a weighted score those
10
+ * disappear, because the axis that carries them is small and the axis that
11
+ * hides them is large.
12
+ *
13
+ * A GREEN PIXEL DIFF ALONE CANNOT PRODUCE A PASS, and that is enforced by
14
+ * construction rather than by policy: pixel similarity is not one of the
15
+ * dimensions below. It is evidence a human may read; it is never an input to
16
+ * `overall`.
17
+ *
18
+ * WHAT EACH ROW OWES. Every finding cites BOTH sides — what the artifact has
19
+ * and what the implementation has. A finding that names only the implementation
20
+ * is unactionable: the reader cannot tell whether the port dropped something or
21
+ * whether the artifact never had it.
22
+ *
23
+ * SCOPE, stated because the honest version is narrower than the obvious one.
24
+ * These are static checks over two documents' text. They catch the deviations
25
+ * that leave a textual trace — a value gone, a handler gone, a breakpoint gone.
26
+ * They do NOT catch a deviation that is only visible when rendered, and they do
27
+ * not claim to. Where a rendered comparison is available it belongs beside this
28
+ * report, not inside it.
29
+ */
30
+ import { type TokenCandidate, type ValueKind, type ValueRow, reconcileValue } from './design_tolerance.js';
31
+ import { recordToleranceShadow } from './tolerance_shadow.js';
32
+
33
+ export type Dimension = 'structure' | 'values' | 'behaviour' | 'responsive' | 'icons' | 'carrier';
34
+
35
+ export const DIMENSIONS: readonly Dimension[] = [
36
+ 'structure',
37
+ 'values',
38
+ 'behaviour',
39
+ 'responsive',
40
+ 'icons',
41
+ 'carrier',
42
+ ];
43
+
44
+ export interface Finding {
45
+ dimension: Dimension;
46
+ /** What the artifact carries. Never omitted — see the header. */
47
+ artifact: string;
48
+ /** What the implementation carries in its place. */
49
+ implementation: string;
50
+ detail: string;
51
+ }
52
+
53
+ export interface DimensionVerdict {
54
+ dimension: Dimension;
55
+ verdict: 'conforms' | 'deviates';
56
+ findings: Finding[];
57
+ }
58
+
59
+ export interface ConformanceReport {
60
+ dimensions: DimensionVerdict[];
61
+ /** Value rows with their distance, reported whether or not they deviate. */
62
+ values: ValueRow[];
63
+ overall: 'conforms' | 'deviates';
64
+ /** Dimensions that deviated, in `DIMENSIONS` order. */
65
+ deviating: Dimension[];
66
+ }
67
+
68
+ // ------------------------------------------------------------- extraction
69
+
70
+ const HEX_RE = /#[0-9a-fA-F]{3}\b|#[0-9a-fA-F]{6}\b/g;
71
+ const LENGTH_RE = /\b\d*\.?\d+(?:px|rem)\b/g;
72
+ const TAG_RE = /<([a-zA-Z][a-zA-Z0-9-]*)\b/g;
73
+ // EVERY width bound in a query, not the first. `@media (min-width: 48rem) and
74
+ // (max-width: 80rem)` has two, and capturing one left `80rem` counted as a
75
+ // VALUE — which reds two dimensions for one corruption and breaks the
76
+ // one-dimension property 4.1's verify clause rests on. Found by a blind review.
77
+ const MEDIA_QUERY_RE = /@media[^{]+/g;
78
+ const MEDIA_BOUND_RE = /\(\s*(?:min|max)-width\s*:\s*([^)]+)\)/g;
79
+ // Case-insensitive on the listener name: the first version required an
80
+ // all-lowercase quoted name, so `addEventListener('DOMContentLoaded', …)` and
81
+ // any camelCase custom event were invisible to the behavior dimension that
82
+ // exists to catch a dropped interaction. Blind-review finding.
83
+ const LISTENER_RE = /addEventListener\(\s*['"]([A-Za-z][A-Za-z0-9_:.-]*)['"]/g;
84
+
85
+ /**
86
+ * `on*` ATTRIBUTES, matched against a closed set rather than by shape.
87
+ *
88
+ * A word boundary does not separate `onclick` from `onboarding` — both begin
89
+ * with `on` and both are followed by `=`, so a shape rule reads the second as a
90
+ * hook named `boarding`. It is the inline-handler namespace that is closed, so
91
+ * the set is what discriminates. A custom event never appears as an attribute
92
+ * anyway; it appears in `addEventListener`, which the regex above reads openly.
93
+ */
94
+ const INLINE_EVENTS = new Set([
95
+ 'click', 'dblclick', 'mousedown', 'mouseup', 'mouseenter', 'mouseleave',
96
+ 'mousemove', 'mouseover', 'mouseout', 'keydown', 'keyup', 'keypress',
97
+ 'input', 'change', 'submit', 'reset', 'focus', 'blur', 'focusin',
98
+ 'focusout', 'scroll', 'wheel', 'load', 'error', 'resize', 'toggle',
99
+ 'select', 'drag', 'dragstart', 'dragend', 'dragover', 'drop', 'touchstart',
100
+ 'touchend', 'touchmove', 'pointerdown', 'pointerup', 'pointermove',
101
+ 'animationend', 'transitionend', 'contextmenu', 'copy', 'cut', 'paste',
102
+ 'invalid', 'play', 'pause', 'ended',
103
+ ]);
104
+ const ON_ATTR_RE = /(?:^|[\s"'`<])on([a-z]+)\s*=/g;
105
+ // Attribute-bounded and quote-agnostic. Unbounded, it false-positived on any
106
+ // attribute ENDING in `style` (`data-style=`, `hover-style=`); double-quote-only,
107
+ // it missed `style='…'` entirely. Blind-review finding.
108
+ const INLINE_STYLE_RE = /(?:^|[\s"'`<])style\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
109
+
110
+ /** Landmark and control tags — the structural skeleton, not every `<div>`. */
111
+ const STRUCTURAL_TAGS = new Set([
112
+ 'main',
113
+ 'header',
114
+ 'footer',
115
+ 'nav',
116
+ 'aside',
117
+ 'section',
118
+ 'article',
119
+ 'form',
120
+ 'table',
121
+ 'dialog',
122
+ 'button',
123
+ 'input',
124
+ 'select',
125
+ 'textarea',
126
+ 'a',
127
+ 'label',
128
+ 'svg',
129
+ ]);
130
+
131
+ function setMinus(a: Set<string>, b: Set<string>): Set<string> {
132
+ const out = new Set<string>();
133
+ for (const v of a) if (!b.has(v)) out.add(v);
134
+ return out;
135
+ }
136
+
137
+ function matchSet(text: string, re: RegExp, group = 0): Set<string> {
138
+ const out = new Set<string>();
139
+ for (const m of text.matchAll(re)) {
140
+ const v = m[group];
141
+ if (typeof v === 'string' && v !== '') out.add(v.toLowerCase().trim());
142
+ }
143
+ return out;
144
+ }
145
+
146
+ /** Counts per structural tag; a dropped control is a count change, not absence. */
147
+ export function structuralCounts(html: string): Map<string, number> {
148
+ const counts = new Map<string, number>();
149
+ for (const m of html.matchAll(TAG_RE)) {
150
+ const tag = (m[1] as string).toLowerCase();
151
+ if (!STRUCTURAL_TAGS.has(tag)) continue;
152
+ counts.set(tag, (counts.get(tag) ?? 0) + 1);
153
+ }
154
+ return counts;
155
+ }
156
+
157
+ /** Event names the document wires, from listeners and from `on*` attributes. */
158
+ export function behaviourHooks(html: string): Set<string> {
159
+ const out = new Set<string>();
160
+ for (const m of html.matchAll(LISTENER_RE)) {
161
+ out.add((m[1] as string).toLowerCase());
162
+ }
163
+ for (const m of html.matchAll(ON_ATTR_RE)) {
164
+ const name = (m[1] as string).toLowerCase();
165
+ if (INLINE_EVENTS.has(name)) out.add(name);
166
+ }
167
+ return out;
168
+ }
169
+
170
+ /** Breakpoints, normalised so `48rem` and `48 rem` are one value. */
171
+ export function breakpoints(html: string): Set<string> {
172
+ const out = new Set<string>();
173
+ for (const q of html.matchAll(MEDIA_QUERY_RE)) {
174
+ for (const b of (q[0] as string).matchAll(MEDIA_BOUND_RE)) {
175
+ const v = (b[1] as string).toLowerCase().trim();
176
+ if (v !== '') out.add(v);
177
+ }
178
+ }
179
+ return out;
180
+ }
181
+
182
+ /**
183
+ * Static declarations sitting in a `style=` attribute.
184
+ *
185
+ * The carrier axis: static presentation belongs in CSS or classes, and `style=`
186
+ * is for what only the runtime knows. A port that moves the artifact's inline
187
+ * styles into classes is CONFORMING as long as the resolved value is identical
188
+ * — which is why this counts declarations the IMPLEMENTATION added, never ones
189
+ * it removed.
190
+ */
191
+ export function inlineStaticDeclarations(html: string): string[] {
192
+ const out: string[] = [];
193
+ for (const m of html.matchAll(INLINE_STYLE_RE)) {
194
+ for (const decl of ((m[1] ?? m[2] ?? '') as string).split(';')) {
195
+ const trimmed = decl.trim();
196
+ if (trimmed === '') continue;
197
+ // A custom property or a `var()` is plausibly runtime-driven.
198
+ if (trimmed.startsWith('--') || trimmed.includes('var(')) continue;
199
+ out.push(trimmed.toLowerCase());
200
+ }
201
+ }
202
+ return out;
203
+ }
204
+
205
+ /** Inline `<svg>` occurrences — the icon carrier a port reproduces. */
206
+ export function inlineSvgCount(html: string): number {
207
+ return (html.match(/<svg\b/gi) ?? []).length;
208
+ }
209
+
210
+ // ------------------------------------------------------------------ report
211
+
212
+ function verdictFor(dimension: Dimension, findings: Finding[]): DimensionVerdict {
213
+ return { dimension, verdict: findings.length > 0 ? 'deviates' : 'conforms', findings };
214
+ }
215
+
216
+ export interface ReportInput {
217
+ artifact: string;
218
+ implementation: string;
219
+ /** Project tokens, so a value row can carry its distance. */
220
+ tokens?: readonly TokenCandidate[];
221
+ /**
222
+ * Repo root. When given, every measurable value row is appended to the
223
+ * shadow log as a `tolerance_shadow` record.
224
+ *
225
+ * OPT-IN, and that is the whole design: a report is also built by tests and
226
+ * by a reader inspecting a port, and a window that recorded those would be
227
+ * measuring its own test fixtures. The caller that wants the window says so.
228
+ */
229
+ shadowRoot?: string;
230
+ }
231
+
232
+ /**
233
+ * Build the report. Pure over two strings, so a test can corrupt exactly one
234
+ * dimension and assert that exactly one reds.
235
+ */
236
+ export function buildConformanceReport(input: ReportInput): ConformanceReport {
237
+ const { artifact, implementation } = input;
238
+ const tokens = input.tokens ?? [];
239
+
240
+ // --- structure
241
+ const structureFindings: Finding[] = [];
242
+ const aCounts = structuralCounts(artifact);
243
+ const iCounts = structuralCounts(implementation);
244
+ for (const tag of new Set([...aCounts.keys(), ...iCounts.keys()])) {
245
+ const a = aCounts.get(tag) ?? 0;
246
+ const i = iCounts.get(tag) ?? 0;
247
+ // `svg` is the icons dimension's subject; counting it here too would
248
+ // red two dimensions for one corruption and break the step's verify.
249
+ if (tag === 'svg' || a === i) continue;
250
+ structureFindings.push({
251
+ dimension: 'structure',
252
+ artifact: `${String(a)} × <${tag}>`,
253
+ implementation: `${String(i)} × <${tag}>`,
254
+ detail: `structural element count differs for <${tag}>`,
255
+ });
256
+ }
257
+
258
+ // --- values, and their distances
259
+ const aHex = matchSet(artifact, HEX_RE);
260
+ const iHex = matchSet(implementation, HEX_RE);
261
+ // A breakpoint's own length belongs to `responsive`, not to `values`.
262
+ // Without this both axes red on one corruption — measured: dropping
263
+ // `@media (min-width: 48rem)` also dropped `48rem` from the value set, so
264
+ // the responsive case reported `['values', 'responsive']` and the step's
265
+ // "and no other" clause could not hold. Same shape as the `svg` exclusion
266
+ // in the structure loop above.
267
+ const aLen = setMinus(matchSet(artifact, LENGTH_RE), breakpoints(artifact));
268
+ const iLen = setMinus(matchSet(implementation, LENGTH_RE), breakpoints(implementation));
269
+ const valueFindings: Finding[] = [];
270
+ const valueRows: ValueRow[] = [];
271
+ // Parallel to `valueRows`: a row does not carry its own kind, and the
272
+ // shadow record needs it to pick the right candidate-threshold spread.
273
+ const valueKinds: ValueKind[] = [];
274
+
275
+ for (const hex of aHex) {
276
+ // Reported on every value, present or missing — the distance is the
277
+ // point, not the verdict (`design_tolerance.ts` header).
278
+ valueRows.push(reconcileValue('color', hex, tokens));
279
+ valueKinds.push('color');
280
+ if (!iHex.has(hex)) {
281
+ valueFindings.push({
282
+ dimension: 'values',
283
+ artifact: hex,
284
+ implementation: iHex.size > 0 ? `absent (port uses ${[...iHex].join(', ')})` : 'absent',
285
+ detail: 'a colour the artifact states does not appear in the port',
286
+ });
287
+ }
288
+ }
289
+ for (const len of aLen) {
290
+ valueRows.push(reconcileValue('length', len, tokens));
291
+ valueKinds.push('length');
292
+ if (!iLen.has(len)) {
293
+ valueFindings.push({
294
+ dimension: 'values',
295
+ artifact: len,
296
+ implementation: 'absent',
297
+ detail: 'a length the artifact states does not appear in the port',
298
+ });
299
+ }
300
+ }
301
+
302
+ // --- behaviour
303
+ const aHooks = behaviourHooks(artifact);
304
+ const iHooks = behaviourHooks(implementation);
305
+ const behaviourFindings: Finding[] = [];
306
+ for (const hook of aHooks) {
307
+ if (iHooks.has(hook)) continue;
308
+ behaviourFindings.push({
309
+ dimension: 'behaviour',
310
+ artifact: `wires \`${hook}\``,
311
+ implementation: 'not wired',
312
+ detail: `an interaction the artifact wires is missing from the port`,
313
+ });
314
+ }
315
+
316
+ // --- responsive
317
+ const aBp = breakpoints(artifact);
318
+ const iBp = breakpoints(implementation);
319
+ const responsiveFindings: Finding[] = [];
320
+ for (const bp of aBp) {
321
+ if (iBp.has(bp)) continue;
322
+ responsiveFindings.push({
323
+ dimension: 'responsive',
324
+ artifact: `breakpoint ${bp}`,
325
+ implementation: iBp.size > 0 ? `only ${[...iBp].join(', ')}` : 'no breakpoints',
326
+ detail: 'a breakpoint the artifact declares is missing from the port',
327
+ });
328
+ }
329
+
330
+ // --- icons
331
+ const aSvg = inlineSvgCount(artifact);
332
+ const iSvg = inlineSvgCount(implementation);
333
+ const iconFindings: Finding[] = [];
334
+ if (aSvg !== iSvg) {
335
+ iconFindings.push({
336
+ dimension: 'icons',
337
+ artifact: `${String(aSvg)} inline <svg>`,
338
+ implementation: `${String(iSvg)} inline <svg>`,
339
+ detail: 'the port does not carry the artifact’s icon count',
340
+ });
341
+ }
342
+
343
+ // --- carrier
344
+ const aInline = new Set(inlineStaticDeclarations(artifact));
345
+ const carrierFindings: Finding[] = [];
346
+ for (const decl of inlineStaticDeclarations(implementation)) {
347
+ if (aInline.has(decl)) continue;
348
+ carrierFindings.push({
349
+ dimension: 'carrier',
350
+ artifact: 'not inline in the artifact',
351
+ implementation: `style="${decl}"`,
352
+ detail: 'a static declaration the port put inline; static presentation belongs in a class',
353
+ });
354
+ }
355
+
356
+ const dimensions: DimensionVerdict[] = [
357
+ verdictFor('structure', structureFindings),
358
+ verdictFor('values', valueFindings),
359
+ verdictFor('behaviour', behaviourFindings),
360
+ verdictFor('responsive', responsiveFindings),
361
+ verdictFor('icons', iconFindings),
362
+ verdictFor('carrier', carrierFindings),
363
+ ];
364
+ const deviating = dimensions.filter((d) => d.verdict === 'deviates').map((d) => d.dimension);
365
+
366
+ // The one place the shadow window is fed. Without this the records the
367
+ // flip criterion is meant to read never exist, and its reverse trigger is
368
+ // satisfied by construction — the defect a blind review caught on the
369
+ // branch that introduced the module.
370
+ if (input.shadowRoot !== undefined) {
371
+ recordToleranceShadow(
372
+ input.shadowRoot,
373
+ valueRows.map((row, i) => ({ kind: valueKinds[i] as ValueKind, row })),
374
+ );
375
+ }
376
+
377
+ return {
378
+ dimensions,
379
+ values: valueRows,
380
+ overall: deviating.length > 0 ? 'deviates' : 'conforms',
381
+ deviating,
382
+ };
383
+ }
384
+
385
+ /** One line per dimension, then the value rows with their distances. */
386
+ export function formatConformanceReport(report: ConformanceReport): string {
387
+ const lines: string[] = [];
388
+ for (const d of report.dimensions) {
389
+ const mark = d.verdict === 'conforms' ? '✅' : '❌';
390
+ lines.push(`${mark} ${d.dimension}: ${d.verdict} (${String(d.findings.length)} finding(s))`);
391
+ for (const f of d.findings) {
392
+ lines.push(` artifact: ${f.artifact} · port: ${f.implementation} — ${f.detail}`);
393
+ }
394
+ }
395
+ lines.push(
396
+ `\noverall: ${report.overall}` +
397
+ (report.deviating.length > 0 ? ` (${report.deviating.join(', ')})` : ''),
398
+ );
399
+ // Stated on every report, not only on a failing one: a reader who sees a
400
+ // pass has to know what it did NOT measure.
401
+ lines.push('pixel similarity is not a dimension here and cannot produce a pass on its own.');
402
+ return lines.join('\n');
403
+ }