ai-design-context 0.4.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 (288) hide show
  1. package/AGENTS.md +156 -0
  2. package/CHANGELOG.md +71 -0
  3. package/CODE_OF_CONDUCT.md +29 -0
  4. package/CONTRIBUTING.md +128 -0
  5. package/LICENSE +21 -0
  6. package/README.md +283 -0
  7. package/RELEASE_NOTES_v0.1.0.md +45 -0
  8. package/RELEASE_NOTES_v0.3.0.md +47 -0
  9. package/RELEASE_NOTES_v0.4.0.md +29 -0
  10. package/RELEASE_READINESS.md +107 -0
  11. package/ROADMAP.md +60 -0
  12. package/SECURITY.md +40 -0
  13. package/assets/logo.svg +9 -0
  14. package/benchmarks/README.md +19 -0
  15. package/benchmarks/chat.md +37 -0
  16. package/benchmarks/mobile-home-screen.md +38 -0
  17. package/benchmarks/notes-app.md +37 -0
  18. package/benchmarks/settings.md +37 -0
  19. package/benchmarks/shopping-list.md +37 -0
  20. package/benchmarks/todo-app.md +144 -0
  21. package/checklists/DESIGN_QA.md +102 -0
  22. package/checklists/GENERATED_INDEX.md +7 -0
  23. package/docs/AGENT_CONTEXT.md +111 -0
  24. package/docs/BENCHMARK.md +170 -0
  25. package/docs/DESIGNLINT_READINESS.md +110 -0
  26. package/docs/DESIGN_SYSTEM.md +23 -0
  27. package/docs/EVALUATION_RUBRIC.md +154 -0
  28. package/docs/GITHUB_SETUP.md +28 -0
  29. package/docs/GLOSSARY.md +45 -0
  30. package/docs/INDEX.md +109 -0
  31. package/docs/KNOWLEDGE_ENGINE.md +594 -0
  32. package/docs/MOBILE_FIRST.md +18 -0
  33. package/docs/NPM_RELEASE.md +43 -0
  34. package/docs/PATTERN_SPEC.md +113 -0
  35. package/docs/PHILOSOPHY.md +25 -0
  36. package/docs/PRODUCT_THINKING.md +26 -0
  37. package/docs/STYLE_GUIDE.md +49 -0
  38. package/docs/TRACEABILITY.md +45 -0
  39. package/evidence/README.md +64 -0
  40. package/evidence/TEMPLATE.md +46 -0
  41. package/evidence/chat/.gitkeep +1 -0
  42. package/evidence/mobile-home/.gitkeep +1 -0
  43. package/evidence/notes/.gitkeep +1 -0
  44. package/evidence/settings/.gitkeep +1 -0
  45. package/evidence/shopping/.gitkeep +1 -0
  46. package/evidence/todo/.gitkeep +1 -0
  47. package/evidence/todo/2026-06-25-codex-gpt-5/EVALUATION.md +66 -0
  48. package/evidence/todo/2026-06-25-codex-gpt-5/README.md +40 -0
  49. package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/generated-output.md +163 -0
  50. package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/metadata.json +38 -0
  51. package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/notes.md +20 -0
  52. package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/prompt.md +16 -0
  53. package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/scores.md +18 -0
  54. package/evidence/todo/2026-06-25-codex-gpt-5/baseline/generated-output.md +98 -0
  55. package/evidence/todo/2026-06-25-codex-gpt-5/baseline/metadata.json +19 -0
  56. package/evidence/todo/2026-06-25-codex-gpt-5/baseline/notes.md +19 -0
  57. package/evidence/todo/2026-06-25-codex-gpt-5/baseline/prompt.md +9 -0
  58. package/evidence/todo/2026-06-25-codex-gpt-5/baseline/scores.md +18 -0
  59. package/evidence/todo/2026-09-28-codex-paired-todo/EVALUATION.md +70 -0
  60. package/evidence/todo/2026-09-28-codex-paired-todo/README.md +52 -0
  61. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/GENERATION_NOTES.md +133 -0
  62. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/app.js +289 -0
  63. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/context/context-preserving-preview.json +443 -0
  64. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/context/daily-home-surface.json +373 -0
  65. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/context/quick-capture.json +301 -0
  66. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/context/sources-read.txt +36 -0
  67. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/generated-output.md +11 -0
  68. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/index.html +64 -0
  69. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/launch-prompt.md +1 -0
  70. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/metadata.json +55 -0
  71. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/notes.md +15 -0
  72. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/parent-status-message.md +1 -0
  73. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/prompt.md +49 -0
  74. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/runtime-checks.json +776 -0
  75. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/scores.md +20 -0
  76. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-completed.png +0 -0
  77. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-default.png +0 -0
  78. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-detail-reduced-motion.png +0 -0
  79. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-detail.png +0 -0
  80. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-empty.png +0 -0
  81. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-keyboard-focus.png +0 -0
  82. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-save-error.png +0 -0
  83. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-saved.png +0 -0
  84. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-saving.png +0 -0
  85. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-validation.png +0 -0
  86. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-completed.png +0 -0
  87. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-default.png +0 -0
  88. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-detail-reduced-motion.png +0 -0
  89. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-detail.png +0 -0
  90. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-empty.png +0 -0
  91. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-keyboard-focus.png +0 -0
  92. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-save-error.png +0 -0
  93. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-saved.png +0 -0
  94. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-saving.png +0 -0
  95. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-validation.png +0 -0
  96. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/source-hashes.json +5 -0
  97. package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/styles.css +122 -0
  98. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/GENERATION_NOTES.md +86 -0
  99. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/app.js +303 -0
  100. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/generated-output.md +11 -0
  101. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/index.html +71 -0
  102. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/launch-prompt.md +1 -0
  103. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/metadata.json +55 -0
  104. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/notes.md +15 -0
  105. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/parent-status-message.md +1 -0
  106. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/prompt.md +49 -0
  107. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/runtime-checks.json +772 -0
  108. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/scores.md +20 -0
  109. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-completed.png +0 -0
  110. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-default.png +0 -0
  111. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-detail-reduced-motion.png +0 -0
  112. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-detail.png +0 -0
  113. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-empty.png +0 -0
  114. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-keyboard-focus.png +0 -0
  115. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-save-error.png +0 -0
  116. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-saved.png +0 -0
  117. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-saving.png +0 -0
  118. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-validation.png +0 -0
  119. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-completed.png +0 -0
  120. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-default.png +0 -0
  121. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-detail-reduced-motion.png +0 -0
  122. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-detail.png +0 -0
  123. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-empty.png +0 -0
  124. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-keyboard-focus.png +0 -0
  125. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-save-error.png +0 -0
  126. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-saved.png +0 -0
  127. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-saving.png +0 -0
  128. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-validation.png +0 -0
  129. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/source-hashes.json +5 -0
  130. package/evidence/todo/2026-09-28-codex-paired-todo/baseline/styles.css +9 -0
  131. package/evidence/todo/2026-09-28-codex-paired-todo/capture-ai-design-rules.js +60 -0
  132. package/evidence/todo/2026-09-28-codex-paired-todo/capture-baseline.js +60 -0
  133. package/evidence/todo/2026-09-28-codex-paired-todo/common/brief.md +35 -0
  134. package/evidence/todo/2026-09-28-codex-paired-todo/common/knowledge-files.json +127 -0
  135. package/evidence/todo/2026-09-28-codex-paired-todo/common/knowledge.patch +890 -0
  136. package/evidence/todo/2026-09-28-codex-paired-todo/common/review-context.json +550 -0
  137. package/evidence/todo/2026-09-28-codex-paired-todo/common/seed.json +86 -0
  138. package/evidence/todo/2026-09-28-codex-paired-todo/common/setup.json +47 -0
  139. package/evidence/todo/2026-09-28-codex-paired-todo/common/technical-envelope.md +11 -0
  140. package/evidence/todo/2026-09-28-codex-paired-todo/layout-metrics.json +133 -0
  141. package/evidence/todo/2026-09-28-codex-paired-todo/layout-probe.js +15 -0
  142. package/examples/GENERATED_INDEX.md +8 -0
  143. package/examples/INDEX.md +16 -0
  144. package/examples/README.md +15 -0
  145. package/examples/consequential-action-confirmation-reference.md +83 -0
  146. package/examples/todo-app-benchmark.md +117 -0
  147. package/examples/todo-reference/README.md +29 -0
  148. package/examples/todo-reference/app.js +154 -0
  149. package/examples/todo-reference/favicon.svg +4 -0
  150. package/examples/todo-reference/index.html +67 -0
  151. package/examples/todo-reference/review-evidence/2026-07-15/desktop-default.png +0 -0
  152. package/examples/todo-reference/review-evidence/2026-07-15/desktop-detail.png +0 -0
  153. package/examples/todo-reference/review-evidence/2026-07-15/mobile-detail.png +0 -0
  154. package/examples/todo-reference/review-evidence/2026-07-15/mobile-error.png +0 -0
  155. package/examples/todo-reference/styles.css +241 -0
  156. package/graph/GENERATED_GRAPH.md +71 -0
  157. package/observations/README.md +23 -0
  158. package/observations/accessibility/reduced-interaction-motion.md +49 -0
  159. package/observations/accessibility/textual-error-recovery.md +50 -0
  160. package/observations/accessibility/visible-keyboard-focus.md +49 -0
  161. package/observations/ai/agent-consequential-action-controls.md +56 -0
  162. package/observations/ai/agent-work-visibility-and-intervention.md +51 -0
  163. package/observations/ai/figma-agent-context-and-skills.md +52 -0
  164. package/observations/finance/high-risk-wallet-recovery-flows.md +55 -0
  165. package/observations/finance/market-interface-adaptive-trading-surfaces.md +55 -0
  166. package/observations/interaction/chrome-scoped-view-transitions.md +52 -0
  167. package/observations/interaction/figma-motion-as-system-capability.md +53 -0
  168. package/observations/mobile/mobile-bottom-sheet-choice-contracts.md +55 -0
  169. package/observations/performance/reserved-loading-space.md +51 -0
  170. package/observations/product-repos/pinned-ai-design-rules-integration.md +49 -0
  171. package/observations/visual/apple-liquid-glass-functional-layer.md +52 -0
  172. package/observations/visual/chrome-content-first-adaptive-ui.md +51 -0
  173. package/observations/visual/material-3-expressive-system.md +52 -0
  174. package/package.json +65 -0
  175. package/patterns/GENERATED_INDEX.md +13 -0
  176. package/patterns/INDEX.md +41 -0
  177. package/patterns/README.md +5 -0
  178. package/patterns/consequential-action-confirmation.md +127 -0
  179. package/patterns/context-preserving-preview.md +145 -0
  180. package/patterns/daily-home-surface.md +134 -0
  181. package/patterns/mobile-primary-action.md +110 -0
  182. package/patterns/object-status-list.md +114 -0
  183. package/patterns/progressive-detail.md +113 -0
  184. package/patterns/quick-capture.md +132 -0
  185. package/prompts/CONSEQUENTIAL_ACTION_REVIEW.md +100 -0
  186. package/prompts/DESIGN_EVIDENCE_REVIEW.md +49 -0
  187. package/prompts/GENERATED_INDEX.md +11 -0
  188. package/prompts/INDEX.md +24 -0
  189. package/prompts/PROTOTYPE_REVIEW.md +189 -0
  190. package/prompts/QUICK_CAPTURE_STATE_REVIEW.md +74 -0
  191. package/prompts/TODO_APP_BENCHMARK.md +88 -0
  192. package/registry/objects.json +568 -0
  193. package/registry/relationships.json +972 -0
  194. package/research/GENERATED_INDEX.md +18 -0
  195. package/research/INDEX.md +40 -0
  196. package/research/accessibility/keyboard-focus-and-interaction-motion.md +62 -0
  197. package/research/accessibility/textual-error-recovery.md +57 -0
  198. package/research/performance/reserved-loading-space.md +56 -0
  199. package/research/products/apple-reminders.md +59 -0
  200. package/research/products/arc.md +61 -0
  201. package/research/products/linear.md +62 -0
  202. package/research/products/telegram.md +61 -0
  203. package/research/products/things-3.md +60 -0
  204. package/research/ux/contextual-agentic-interface.md +68 -0
  205. package/research/ux/high-risk-operational-flows.md +89 -0
  206. package/research/ux/motion-as-state-continuity.md +71 -0
  207. package/research/visual/expressive-system-ui-2026.md +75 -0
  208. package/reviews/GENERATED_INDEX.md +9 -0
  209. package/reviews/README.md +25 -0
  210. package/reviews/consequential-action-confirmation-review.md +92 -0
  211. package/reviews/todo-app-benchmark-reference-review.md +86 -0
  212. package/reviews/todo-reference-fixture-review.md +77 -0
  213. package/rules/GENERATED_INDEX.md +23 -0
  214. package/rules/INDEX.md +37 -0
  215. package/rules/accessibility/A11Y-001.md +58 -0
  216. package/rules/accessibility/A11Y-002.md +55 -0
  217. package/rules/accessibility/A11Y-003.md +54 -0
  218. package/rules/accessibility/A11Y-004.md +54 -0
  219. package/rules/ia/IA-001.md +60 -0
  220. package/rules/ia/IA-002.md +61 -0
  221. package/rules/performance/PERF-001.md +55 -0
  222. package/rules/product/PRD-001.md +61 -0
  223. package/rules/product/PRD-002.md +61 -0
  224. package/rules/ux/UX-001.md +58 -0
  225. package/rules/ux/UX-002.md +61 -0
  226. package/rules/ux/UX-003.md +60 -0
  227. package/rules/ux/UX-004.md +61 -0
  228. package/rules/ux/UX-005.md +62 -0
  229. package/rules/ux/UX-006.md +69 -0
  230. package/rules/visual/VIS-001.md +59 -0
  231. package/rules/visual/VIS-002.md +59 -0
  232. package/schema/checklist.schema.json +21 -0
  233. package/schema/common.schema.json +178 -0
  234. package/schema/observation.schema.json +21 -0
  235. package/schema/pattern.schema.json +21 -0
  236. package/schema/prompt.schema.json +21 -0
  237. package/schema/reference-project.schema.json +21 -0
  238. package/schema/research.schema.json +21 -0
  239. package/schema/review.schema.json +21 -0
  240. package/schema/rule.schema.json +21 -0
  241. package/skills/README.md +48 -0
  242. package/skills/accessibility-reviewer/SKILL.md +101 -0
  243. package/skills/agent-context/SKILL.md +34 -0
  244. package/skills/agent-context/agents/openai.yaml +4 -0
  245. package/skills/design-evidence-researcher/SKILL.md +47 -0
  246. package/skills/design-evidence-researcher/agents/openai.yaml +4 -0
  247. package/skills/design-reviewer/SKILL.md +113 -0
  248. package/skills/design-system-architect/SKILL.md +101 -0
  249. package/skills/information-architect/SKILL.md +97 -0
  250. package/skills/interaction-designer/SKILL.md +104 -0
  251. package/skills/knowledge-graph-architect/SKILL.md +96 -0
  252. package/skills/mobile-ux-expert/SKILL.md +105 -0
  253. package/skills/motion-designer/SKILL.md +100 -0
  254. package/skills/performance-reviewer/SKILL.md +97 -0
  255. package/skills/product-designer/SKILL.md +104 -0
  256. package/skills/prompt-architect/SKILL.md +105 -0
  257. package/skills/reference-driven-design/SKILL.md +119 -0
  258. package/skills/ux-reviewer/SKILL.md +99 -0
  259. package/skills/visual-designer/SKILL.md +107 -0
  260. package/starter-kit/AGENTS.md +37 -0
  261. package/starter-kit/BOOTSTRAP.md +13 -0
  262. package/starter-kit/INSTALL_WITH_AGENT.md +133 -0
  263. package/starter-kit/PROJECT_INTEGRATION.md +60 -0
  264. package/starter-kit/README.md +41 -0
  265. package/starter-kit/benchmarks/BENCHMARK_CHECKLIST.md +10 -0
  266. package/starter-kit/docs/DESIGN_DECISIONS.md +22 -0
  267. package/starter-kit/docs/INFORMATION_ARCHITECTURE.md +25 -0
  268. package/starter-kit/docs/PERSONAS.md +14 -0
  269. package/starter-kit/docs/PRD.md +32 -0
  270. package/starter-kit/docs/USER_FLOWS.md +19 -0
  271. package/starter-kit/reviews/DESIGN_REVIEW.md +49 -0
  272. package/starter-kit/templates/FEATURE_TEMPLATE.md +36 -0
  273. package/starter-kit/templates/TASK_TEMPLATE.md +22 -0
  274. package/templates/CHECKLIST_TEMPLATE.md +43 -0
  275. package/templates/OBSERVATION_TEMPLATE.md +41 -0
  276. package/templates/PATTERN_TEMPLATE.md +100 -0
  277. package/templates/PROMPT_TEMPLATE.md +46 -0
  278. package/templates/PROTOTYPE_REVIEW.md +50 -0
  279. package/templates/REFERENCE_PROJECT_TEMPLATE.md +49 -0
  280. package/templates/REVIEW_TEMPLATE.md +55 -0
  281. package/templates/RULE_TEMPLATE.md +57 -0
  282. package/tools/cli.mjs +46 -0
  283. package/tools/context.mjs +342 -0
  284. package/tools/designlint.mjs +77 -0
  285. package/tools/generate-indexes.mjs +621 -0
  286. package/tools/init.mjs +99 -0
  287. package/tools/validate-benchmark-evidence.mjs +248 -0
  288. package/tools/validate-knowledge.mjs +481 -0
@@ -0,0 +1,890 @@
1
+ diff --git a/CHANGELOG.md b/CHANGELOG.md
2
+ index 2e97f56..59642ca 100644
3
+ --- a/CHANGELOG.md
4
+ +++ b/CHANGELOG.md
5
+ @@ -1,5 +1,18 @@
6
+ # Changelog
7
+
8
+ +## Unreleased — Focused Context And Applied Patterns
9
+ +
10
+ +- Rank task context by exact identifiers and focused titles before incidental mentions, with whole-word matching and support for simple English task phrasing.
11
+ +- Resolve all transitive required and upstream knowledge dependencies while limiting optional graph expansion; include an explanation for every selected object.
12
+ +- Select platform context from eligible rules and patterns before ranking, and preserve JSON object fields with additive selection reasons.
13
+ +- Apply `VIS-001` and `VIS-002` in Daily Home Surface and `UX-004` in Context-Preserving Preview, with concrete hierarchy, focus, interruption, and fallback contracts.
14
+ +- Add regression coverage for realistic queries, dependency completeness, cycles, platform selection, and missing targets.
15
+ +- Define the next paired rendered Todo run, with identical generation conditions, mobile/desktop state captures, interaction checks, and evaluation limits.
16
+ +
17
+ +### Evidence Boundary
18
+ +
19
+ +The updated patterns remain `draft` / `seed`. Retrieval behavior is covered by automated tests, but the rendered Todo comparison is a protocol pending execution. No visual-quality gain or independent evaluation is claimed.
20
+ +
21
+ ## v0.3.0 — Expressive Systems And Agent Context
22
+
23
+ - Added primary-source observations for expressive platform materials, adaptive web UI, systematic motion, and observable agentic workflows.
24
+ diff --git a/docs/AGENT_CONTEXT.md b/docs/AGENT_CONTEXT.md
25
+ index 06a3d31..865952e 100644
26
+ --- a/docs/AGENT_CONTEXT.md
27
+ +++ b/docs/AGENT_CONTEXT.md
28
+ @@ -7,6 +7,7 @@
29
+ ```bash
30
+ # Design or implement a feature.
31
+ npm run context -- --task quick-capture --platform mobile --intent implement
32
+ +npm run context -- --task "build a shopping list" --intent implement
33
+
34
+ # Review an implementation, benchmark artifact, or reference fixture.
35
+ npm run context -- --review examples/todo-reference --intent qa
36
+ @@ -29,7 +30,56 @@ Markdown is the human default. `--format json` emits only this stable shape on s
37
+ }
38
+ ```
39
+
40
+ -Task and review modes search stable registry fields and object Markdown. Object mode matches an exact ID, alias, slug, or registry path. From its anchors the resolver follows typed relationships to include directly applicable rules, upstream research, patterns, prompts, checklists, reference projects, and reviews. Platform matching is additive: it can include mobile-relevant rules or patterns, but does not replace the task's graph context.
41
+ +Every entry in `anchors` and `objects` retains `id`, `alias`, `title`, `type`, `status`, `maturity`, and `path`, and now adds a `reason` object. Consumers should allow additive fields. For example:
42
+ +
43
+ +```json
44
+ +{
45
+ + "id": "RULE-00002",
46
+ + "alias": "PRD-002",
47
+ + "title": "Low-Friction Capture Before Organization",
48
+ + "type": "rule",
49
+ + "status": "draft",
50
+ + "maturity": "seed",
51
+ + "path": "rules/product/PRD-002.md",
52
+ + "reason": { "kind": "dependency", "source": "PAT-00002", "relationship": "requires" }
53
+ +}
54
+ +```
55
+ +
56
+ +## Matching And Scope
57
+ +
58
+ +Task and review modes search stable registry fields and object Markdown. An exact ID, alias, slug, or registry path wins first. Otherwise, whole Unicode words must match; titles rank above slugs, aliases, categories, and incidental body mentions. Shorter focused titles break otherwise equal title matches. One highest-ranked anchor is selected, with stable ID ordering as the final tie-breaker.
59
+ +
60
+ +The small English filler set (`a`, `an`, `the`, `please`, `build`, `create`, `implement`, `make`, `for`, `me`) is ignored in non-exact queries. Thus `build a shopping list` and `shopping list` resolve alike. Unknown subject terms are not dropped. This is lexical retrieval, not translation or semantic search: use a known slug or ID when a paraphrase or another language has no matching words. A query containing only fillers fails instead of selecting arbitrary knowledge.
61
+ +
62
+ +Object mode matches only an exact ID, alias, slug, or registry path and does not apply filler handling.
63
+ +
64
+ +From the anchor the resolver includes:
65
+ +
66
+ +- Direct `related_to` neighbors for research, rules, and patterns, without recursively following optional neighbors.
67
+ +- Rules derived from a research anchor through `derived_from` or `inspired_by`.
68
+ +- Direct review prompts and checklists for anchors and those derived rules; reviews that `validate` a reference-project anchor.
69
+ +- All transitive registered `requires`, `derived_from`, `inspired_by`, and `implements` dependencies of every selected object; `validates` targets of selected reviews and reference projects.
70
+ +
71
+ +Dependencies are followed to completion even across cycles. A missing registered dependency is an error. The resolver does not walk backward from every shared rule into every consuming pattern or generation prompt. Broad review checklists remain available as gates, but their optional `related_to` links do not automatically select the whole graph. Follow those links explicitly when broadening a review. Non-registry observation sources remain in the research files and must be read there.
72
+ +
73
+ +Platform matching is additive. It selects at most one matching rule or pattern from eligible types **before** ranking, then includes its dependencies and direct context under the same rules. A platform with no match adds nothing. Platform matching does not replace the task anchor or prove applicability.
74
+ +
75
+ +There is no hard object-count cap: completeness of required dependencies takes priority over a fixed limit. Large mandatory graphs may still produce large bundles.
76
+ +
77
+ +## Selection Reasons
78
+ +
79
+ +Markdown explains the selection beside each object. JSON records the first deterministic inclusion reason:
80
+ +
81
+ +| `reason.kind` | Meaning | Additional fields |
82
+ +| --- | --- | --- |
83
+ +| `match` | Exact match or highest-ranked lexical match | `field`, `terms` matched in that field |
84
+ +| `platform` | Added by the platform query | `value`, `field`, `terms` |
85
+ +| `dependency` | Outgoing mandatory or validation edge from a selected object | `source`, `relationship` |
86
+ +| `related` | Direct optional neighbor of a seed object | `source`, `relationship` |
87
+ +| `derived_rule` | Rule points back to selected research | `source` (research), `relationship` |
88
+ +| `review` | Review gate points back to the selected object | `source` (reviewed object), `relationship` |
89
+ +
90
+ +For `derived_rule` and `review`, the stored graph edge points from the returned object to `reason.source`. For `dependency` and `related`, it points from `reason.source` to the returned object. A reason explains inclusion; it is not a confidence score or a claim of validation.
91
+
92
+ `--intent implement` gives an implementation-first use order. `--intent qa` gives an evidence-and-checklist-first use order. Task mode defaults to `implement`; review mode defaults to `qa`.
93
+
94
+ @@ -42,3 +92,4 @@ An unmatched query returns a non-zero exit code; with `--format json` the error
95
+ 3. Treat `draft` and `seed` objects as guidance with explicit limits, not as validated truth.
96
+ 4. Use listed checklists and reviews as quality gates.
97
+ 5. If no context matches, capture an observation or research need; do not invent a rule to fill the gap.
98
+ +6. Use `reason` to distinguish task matches, required knowledge, and review gates. Apply only guidance relevant to the current task.
99
+ diff --git a/docs/BENCHMARK.md b/docs/BENCHMARK.md
100
+ index f3baa88..4324bef 100644
101
+ --- a/docs/BENCHMARK.md
102
+ +++ b/docs/BENCHMARK.md
103
+ @@ -118,3 +118,51 @@ Benchmark results should guide rule, pattern, prompt, and skill evolution. They
104
+ Store future results in `evidence/`.
105
+
106
+ Do not add synthetic scores. Do not invent studies. Do not compare against private internal systems.
107
+ +
108
+ +## Next Rendered Run: Todo
109
+ +
110
+ +Use `benchmarks/todo-app.md` for the first paired rendered run of the next release. It exercises the updated Daily Home Surface (`PAT-001`, `VIS-002`) and Context-Preserving Preview (`PAT-005`, `UX-004`) alongside existing capture, accessibility, and recovery guidance. This is a run protocol, not a completed experiment or evidence of improvement.
111
+ +
112
+ +### Freeze The Setup
113
+ +
114
+ +Before either generation starts, record one shared setup in the run notes:
115
+ +
116
+ +- The scenario file, its hash, the knowledge revision, and any uncommitted knowledge patch used by the rules run.
117
+ +- The exact common brief: the Product Brief, Expected User, Expected Platform, Constraints, and Core User Tasks sections from `benchmarks/todo-app.md`, unchanged and identical in both prompts.
118
+ +- One model/provider/version, generation surface, exposed sampling settings, tool set, and time budget. Record unexposed settings as unexposed; do not invent values.
119
+ +- The implementation target: static HTML, CSS, and JavaScript served locally, with no build dependencies or external assets. Use the same target for both runs.
120
+ +- The same deterministic task data, browser/version, viewport sizes, and storage-reset procedure for both evaluations.
121
+ +
122
+ +Give both runs the same technical requirement to document how the evaluator can reproduce empty, loading, failed-save, and successful-save states. Local test hooks are acceptable; do not expose test controls as product features. Let each run design its interface from the same brief.
123
+ +
124
+ +Use two fresh generation sessions with no shared conversation or output access. Give the baseline only the common brief and shared technical setup. Give the rules session those same inputs plus the pinned knowledge source and instructions to retrieve context for `daily-home-surface`, `quick-capture`, and `context-preserving-preview`, with `--platform mobile`, before implementation. Save the exact returned context and actual prompts. Both sessions must have equivalent tool access; document any isolation limitations.
125
+ +
126
+ +Do not use the existing runnable Todo fixture as either generated result. Do not manually improve one output before scoring. A failure to build, render, or reproduce a required state is a recorded result.
127
+ +
128
+ +### Capture The Same Tasks
129
+ +
130
+ +Evaluate both outputs at **390 × 844** and **1440 × 900** CSS pixels, at the same browser zoom and device scale. Reset storage and use the same task data before each sequence. Save these local artifacts inside each run type's `screenshots/` directory:
131
+ +
132
+ +| Artifact suffix | Action and observable evidence |
133
+ +| --- | --- |
134
+ +| `default.png` | Open the populated daily surface; inspect current work and the primary action. |
135
+ +| `empty.png` | Reset to no tasks; inspect the starting action. |
136
+ +| `saving.png` | Submit a task under controlled delay; inspect input retention and layout stability. |
137
+ +| `save-error.png` | Cause a failed save; inspect error text, retained input, and retry. |
138
+ +| `saved.png` | Retry successfully; inspect feedback and duplicate prevention. |
139
+ +| `completed.png` | Mark a task complete; inspect state clarity and remaining work. |
140
+ +| `detail.png` | Open task details after scrolling; inspect the relation to the source list. |
141
+ +| `keyboard-focus.png` | Reach a core action by keyboard; inspect visible focus and accessible naming. |
142
+ +| `detail-reduced-motion.png` | Repeat detail opening with reduced motion; inspect equivalent information and controls. |
143
+ +
144
+ +Prefix each filename with `mobile-` or `desktop-`. Record the exact reproduction steps with each capture. If a state cannot be reached, record it as missing; do not create a substitute screenshot that pretends to show the state.
145
+ +
146
+ +Screenshots do not prove timing, focus restoration, or interruption behavior. Record interaction results separately: close the preview and verify source position/focus; close or change selection during opening and check for stale content; repeat with reduced motion; verify retry and task completion. Performance observations remain qualitative unless measurements are actually collected.
147
+ +
148
+ +### Score And Publish Evidence
149
+ +
150
+ +Use the same evaluator and `docs/EVALUATION_RUBRIC.md` for both outputs. Score visible behavior, include a note and artifact reference for each category, and report all category differences as well as the averages. If possible, score anonymous A/B outputs before revealing their conditions. Disclose whether evaluation was blinded and whether the evaluator participated in generation; a parent agent reviewing its own team's output is not independent evaluation.
151
+ +
152
+ +Store completed runs using `evidence/TEMPLATE.md`, including raw source, prompts, settings, screenshots, state coverage, evaluator identity, and limitations. Run `npm run benchmark:validate`. The validator currently checks artifact presence, metadata consistency, and image signatures; it does not enforce this state matrix or judge visual quality. The evaluator must check those manually.
153
+ +
154
+ +Do not create scored evidence entries or change rule maturity while preparation is incomplete. One completed pair remains a small-sample result; it cannot establish universal improvement or isolate the effect of context retrieval from pattern changes. Repeated pairs or a separate previous-version comparison are needed for those stronger claims.
155
+ diff --git a/graph/GENERATED_GRAPH.md b/graph/GENERATED_GRAPH.md
156
+ index 6fa760e..eeaa66c 100644
157
+ --- a/graph/GENERATED_GRAPH.md
158
+ +++ b/graph/GENERATED_GRAPH.md
159
+ @@ -22,7 +22,7 @@ This file is generated from registry metadata. Do not edit manually.
160
+ | derived_from | 32 |
161
+ | implements | 12 |
162
+ | related_to | 65 |
163
+ -| requires | 61 |
164
+ +| requires | 64 |
165
+ | validates | 18 |
166
+
167
+ ## Orphan Objects
168
+ @@ -56,11 +56,11 @@ None
169
+ - PROMPT-TODO-BENCHMARK / PROMPT-00003 Todo App Benchmark Prompt: 18
170
+ - REF-TODO-BENCHMARK / REF-00001 Todo App Benchmark Reference Project: 16
171
+ - PAT-002 / PAT-00002 Quick Capture: 15
172
+ +- PAT-005 / PAT-00005 Context-Preserving Preview: 13
173
+ - PAT-006 / PAT-00006 Object Status List: 13
174
+ - UX-003 / RULE-00007 Preserve Context During Inspection: 13
175
+ -- PAT-005 / PAT-00005 Context-Preserving Preview: 12
176
+ +- PAT-001 / PAT-00001 Daily Home Surface: 12
177
+ - A11Y-001 / RULE-00009 44x44 Touch Targets: 12
178
+ -- PAT-007 / PAT-00007 Consequential Action Confirmation: 11
179
+
180
+ ## Patterns Without Required Rules
181
+
182
+ @@ -68,5 +68,4 @@ None
183
+
184
+ ## Rules Not Used By Any Pattern
185
+
186
+ -- VIS-002 / RULE-00014 Keep Expression Subordinate To Content
187
+ -- UX-004 / RULE-00015 Use Motion To Explain State Continuity
188
+ +None
189
+ diff --git a/patterns/GENERATED_INDEX.md b/patterns/GENERATED_INDEX.md
190
+ index 327df50..0f287fa 100644
191
+ --- a/patterns/GENERATED_INDEX.md
192
+ +++ b/patterns/GENERATED_INDEX.md
193
+ @@ -4,10 +4,10 @@ This file is generated from registry metadata. Do not edit manually.
194
+
195
+ | ID | Alias | Title | Category | Status | Maturity | File Path | Required Rules | Related Research |
196
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- |
197
+ -| PAT-00001 | PAT-001 | Daily Home Surface | product | draft | seed | patterns/daily-home-surface.md | PRD-001 / RULE-00001 Daily Actions First<br>IA-001 / RULE-00003 One Stable Home Surface<br>UX-002 / RULE-00006 Progressively Disclose Power<br>A11Y-001 / RULE-00009 44x44 Touch Targets | THINGS-3 / RESEARCH-00002 Things 3<br>TELEGRAM / RESEARCH-00001 Telegram<br>APPLE-REMINDERS / RESEARCH-00003 Apple Reminders |
198
+ +| PAT-00001 | PAT-001 | Daily Home Surface | product | draft | seed | patterns/daily-home-surface.md | PRD-001 / RULE-00001 Daily Actions First<br>IA-001 / RULE-00003 One Stable Home Surface<br>UX-002 / RULE-00006 Progressively Disclose Power<br>A11Y-001 / RULE-00009 44x44 Touch Targets<br>VIS-001 / RULE-00008 Semantic Tokens Only<br>VIS-002 / RULE-00014 Keep Expression Subordinate To Content | THINGS-3 / RESEARCH-00002 Things 3<br>TELEGRAM / RESEARCH-00001 Telegram<br>APPLE-REMINDERS / RESEARCH-00003 Apple Reminders<br>LINEAR / RESEARCH-00004 Linear<br>EXPRESSIVE-SYSTEM-UI-2026 / RESEARCH-00009 Expressive System UI In 2026 |
199
+ | PAT-00002 | PAT-002 | Quick Capture | workflow | draft | seed | patterns/quick-capture.md | PRD-002 / RULE-00002 Low-Friction Capture Before Organization<br>UX-001 / RULE-00005 Thumb-Zone Primary Actions<br>UX-002 / RULE-00006 Progressively Disclose Power<br>A11Y-001 / RULE-00009 44x44 Touch Targets<br>A11Y-002 / RULE-00010 Textual Input Error Recovery<br>PERF-001 / RULE-00011 Reserve Layout Space For Asynchronous Content<br>A11Y-003 / RULE-00012 Visible Keyboard Focus | APPLE-REMINDERS / RESEARCH-00003 Apple Reminders<br>THINGS-3 / RESEARCH-00002 Things 3<br>TELEGRAM / RESEARCH-00001 Telegram<br>TEXTUAL-ERROR-RECOVERY / RESEARCH-00006 Textual Error Recovery<br>RESERVED-LOADING-SPACE / RESEARCH-00007 Reserved Loading Space<br>KEYBOARD-FOCUS-AND-MOTION / RESEARCH-00008 Keyboard Focus And Interaction Motion |
200
+ | PAT-00003 | PAT-003 | Mobile Primary Action | mobile | draft | seed | patterns/mobile-primary-action.md | UX-001 / RULE-00005 Thumb-Zone Primary Actions<br>PRD-001 / RULE-00001 Daily Actions First<br>A11Y-001 / RULE-00009 44x44 Touch Targets | THINGS-3 / RESEARCH-00002 Things 3<br>TELEGRAM / RESEARCH-00001 Telegram<br>APPLE-REMINDERS / RESEARCH-00003 Apple Reminders |
201
+ | PAT-00004 | PAT-004 | Progressive Detail | ux | draft | seed | patterns/progressive-detail.md | UX-002 / RULE-00006 Progressively Disclose Power<br>PRD-002 / RULE-00002 Low-Friction Capture Before Organization<br>VIS-001 / RULE-00008 Semantic Tokens Only<br>A11Y-001 / RULE-00009 44x44 Touch Targets | APPLE-REMINDERS / RESEARCH-00003 Apple Reminders<br>THINGS-3 / RESEARCH-00002 Things 3<br>TELEGRAM / RESEARCH-00001 Telegram<br>LINEAR / RESEARCH-00004 Linear |
202
+ -| PAT-00005 | PAT-005 | Context-Preserving Preview | ux | draft | seed | patterns/context-preserving-preview.md | UX-003 / RULE-00007 Preserve Context During Inspection<br>IA-002 / RULE-00004 Define The Object Model Before Screens<br>IA-001 / RULE-00003 One Stable Home Surface<br>A11Y-001 / RULE-00009 44x44 Touch Targets<br>A11Y-004 / RULE-00013 Reduce Non-Essential Interaction Motion | TELEGRAM / RESEARCH-00001 Telegram<br>THINGS-3 / RESEARCH-00002 Things 3<br>APPLE-REMINDERS / RESEARCH-00003 Apple Reminders<br>LINEAR / RESEARCH-00004 Linear<br>ARC / RESEARCH-00005 Arc<br>KEYBOARD-FOCUS-AND-MOTION / RESEARCH-00008 Keyboard Focus And Interaction Motion |
203
+ +| PAT-00005 | PAT-005 | Context-Preserving Preview | ux | draft | seed | patterns/context-preserving-preview.md | UX-003 / RULE-00007 Preserve Context During Inspection<br>IA-002 / RULE-00004 Define The Object Model Before Screens<br>IA-001 / RULE-00003 One Stable Home Surface<br>A11Y-001 / RULE-00009 44x44 Touch Targets<br>A11Y-004 / RULE-00013 Reduce Non-Essential Interaction Motion<br>UX-004 / RULE-00015 Use Motion To Explain State Continuity | TELEGRAM / RESEARCH-00001 Telegram<br>THINGS-3 / RESEARCH-00002 Things 3<br>APPLE-REMINDERS / RESEARCH-00003 Apple Reminders<br>LINEAR / RESEARCH-00004 Linear<br>ARC / RESEARCH-00005 Arc<br>KEYBOARD-FOCUS-AND-MOTION / RESEARCH-00008 Keyboard Focus And Interaction Motion<br>MOTION-AS-STATE-CONTINUITY / RESEARCH-00010 Motion As State Continuity |
204
+ | PAT-00006 | PAT-006 | Object Status List | ia | draft | seed | patterns/object-status-list.md | IA-002 / RULE-00004 Define The Object Model Before Screens<br>UX-003 / RULE-00007 Preserve Context During Inspection<br>VIS-001 / RULE-00008 Semantic Tokens Only<br>A11Y-001 / RULE-00009 44x44 Touch Targets | LINEAR / RESEARCH-00004 Linear<br>TELEGRAM / RESEARCH-00001 Telegram<br>ARC / RESEARCH-00005 Arc<br>THINGS-3 / RESEARCH-00002 Things 3<br>APPLE-REMINDERS / RESEARCH-00003 Apple Reminders |
205
+ | PAT-00007 | PAT-007 | Consequential Action Confirmation | ux | active | validated | patterns/consequential-action-confirmation.md | UX-006 / RULE-00017 Confirm Consequential Actions With Preserved Context<br>UX-003 / RULE-00007 Preserve Context During Inspection<br>A11Y-002 / RULE-00010 Textual Input Error Recovery<br>UX-005 / RULE-00016 Expose Agent Work And Intervention | ARC / RESEARCH-00005 Arc<br>LINEAR / RESEARCH-00004 Linear<br>TELEGRAM / RESEARCH-00001 Telegram<br>TEXTUAL-ERROR-RECOVERY / RESEARCH-00006 Textual Error Recovery<br>CONTEXTUAL-AGENTIC-INTERFACE / RESEARCH-00011 Contextual And Observable Agentic Interfaces<br>HIGH-RISK-OPERATIONAL-FLOWS / RESEARCH-00012 High-Risk Operational Flows |
206
+ diff --git a/patterns/context-preserving-preview.md b/patterns/context-preserving-preview.md
207
+ index 06ef6cb..5ab2fb3 100644
208
+ --- a/patterns/context-preserving-preview.md
209
+ +++ b/patterns/context-preserving-preview.md
210
+ @@ -5,7 +5,7 @@ slug: context-preserving-preview
211
+ title: Context-Preserving Preview
212
+ object_type: pattern
213
+ status: draft
214
+ -version: 0.1.0
215
+ +version: 0.2.0
216
+ category: ux
217
+ tags:
218
+ - ux
219
+ @@ -23,6 +23,8 @@ relationships:
220
+ target: RULE-00009
221
+ - type: requires
222
+ target: RULE-00013
223
+ + - type: requires
224
+ + target: RULE-00015
225
+ - type: related_to
226
+ target: PAT-00006
227
+ ---
228
+ @@ -58,6 +60,7 @@ Lists, workspaces, conversations, and browsers where users inspect multiple item
229
+ - `UX-003` Preserve Context During Inspection
230
+ - `IA-002` Define The Object Model Before Screens
231
+ - `IA-001` One Stable Home Surface
232
+ +- `UX-004` Use Motion To Explain State Continuity
233
+
234
+ ## Accessibility Rules
235
+
236
+ @@ -68,6 +71,16 @@ Lists, workspaces, conversations, and browsers where users inspect multiple item
237
+
238
+ If opening or closing preview uses non-essential motion, respect a reduced-motion preference or provide an equivalent way to disable it. The reduced-motion state may switch directly to the same sheet, panel, or preview state; it must not remove the preview or its return path.
239
+
240
+ +Use motion only to explain the selected item's relationship to its preview (`UX-004`). Reuse the product's named timing and easing roles; do not introduce a fixed duration or require a particular animation API. Define the following behavior before implementing the transition:
241
+ +
242
+ +| State or transition | Required outcome |
243
+ +| --- | --- |
244
+ +| Closed to open | Keep the selected item, filters, and scroll position; show which item the preview belongs to. Define the focus destination for the chosen panel or dialog behavior. |
245
+ +| Loading or error | Keep the source usable and show feedback in the preview. Feedback must remain understandable without movement. |
246
+ +| Close | Restore the source context. If focus moved into the preview, return it to the invoking control or a logical surviving control if that item was removed. |
247
+ +| Interrupted opening or item switch | The latest selection determines the visible item. A delayed transition must not reopen a closed preview or move focus to an old item. |
248
+ +| Reduced motion or unsupported animation | Reach the same selected item, information, controls, and focus outcome without non-essential movement. |
249
+ +
250
+ ## Mobile Behavior
251
+
252
+ Use a sheet, drawer, or temporary detail view that preserves return state. Avoid resetting filters or scroll on close.
253
+ @@ -95,12 +108,14 @@ Show preview-level error and keep the source list usable.
254
+ - `IA-001` One Stable Home Surface
255
+ - `A11Y-001` 44x44 Touch Targets
256
+ - `A11Y-004` Reduce Non-Essential Interaction Motion
257
+ +- `UX-004` Use Motion To Explain State Continuity
258
+
259
+ ## Related Research
260
+
261
+ - `research/products/arc.md`
262
+ - `research/products/linear.md`
263
+ - `research/products/telegram.md`
264
+ +- `research/ux/motion-as-state-continuity.md`
265
+
266
+ ## Related Patterns
267
+
268
+ @@ -114,6 +129,8 @@ Show preview-level error and keep the source list usable.
269
+ - A consumer task app opens task detail from Today without losing the Today list.
270
+ - An issue tracker opens issue detail beside the filtered issue list.
271
+
272
+ +For a task preview, a brief local transition can connect the selected row to its details. With reduced motion, open those same details immediately. Animating every list row or waiting for a closing animation before accepting the next selection would add motion without preserving useful context.
273
+ +
274
+ ## Agent Checklist
275
+
276
+ - Does opening detail preserve source context?
277
+ @@ -121,3 +138,8 @@ Show preview-level error and keep the source list usable.
278
+ - Is the return path obvious?
279
+ - Does preview stay smaller than a full workspace?
280
+ - When motion exists, can reduced motion reach the same preview and return state?
281
+ +- Are the start state, end state, focus destination, interruption behavior, and fallback recorded?
282
+ +- Can a user close or switch items during opening without stale content or focus taking over?
283
+ +- Is loading and error feedback still clear with animation disabled?
284
+ +
285
+ +The motion guidance remains `draft` / `seed`; this revision does not establish rendered or independent validation.
286
+ diff --git a/patterns/daily-home-surface.md b/patterns/daily-home-surface.md
287
+ index 31c7e39..054386a 100644
288
+ --- a/patterns/daily-home-surface.md
289
+ +++ b/patterns/daily-home-surface.md
290
+ @@ -5,7 +5,7 @@ slug: daily-home-surface
291
+ title: Daily Home Surface
292
+ object_type: pattern
293
+ status: draft
294
+ -version: 0.1.0
295
+ +version: 0.2.0
296
+ category: product
297
+ tags:
298
+ - product
299
+ @@ -21,6 +21,10 @@ relationships:
300
+ target: RULE-00006
301
+ - type: requires
302
+ target: RULE-00009
303
+ + - type: requires
304
+ + target: RULE-00008
305
+ + - type: requires
306
+ + target: RULE-00014
307
+ - type: related_to
308
+ target: PAT-00002
309
+ - type: related_to
310
+ @@ -67,10 +71,14 @@ Consumer products with recurring workflows, such as family tasks, reminders, rou
311
+
312
+ Show the current work and primary daily action in the first 390px-wide viewport. Keep navigation secondary and reachable.
313
+
314
+ +Keep current-work labels readable beside the primary action. Use the same semantic content, action, and supporting-surface roles as desktop; reducing width must not give every row or navigation control the same emphasis as the main action (`VIS-001`, `VIS-002`).
315
+ +
316
+ ## Desktop Behavior
317
+
318
+ Use the extra width for supporting context, not competing entry points. Keep the same home concept as mobile.
319
+
320
+ +Identify the content layer (current work), functional layer (navigation and controls), focal emphasis (the repeated daily action), and quiet supporting surfaces. Reuse existing typography, spacing, and color roles. Strong material, shape, or color treatments must clarify that hierarchy; removing decorative effects must leave content order and the primary action understandable (`VIS-001`, `VIS-002`).
321
+ +
322
+ ## Empty State
323
+
324
+ Explain what belongs here and provide the primary create or start action.
325
+ @@ -89,12 +97,15 @@ Preserve the home surface and show a recovery action without replacing the whole
326
+ - `IA-001` One Stable Home Surface
327
+ - `UX-002` Progressively Disclose Power
328
+ - `A11Y-001` 44x44 Touch Targets
329
+ +- `VIS-001` Semantic Tokens Only
330
+ +- `VIS-002` Keep Expression Subordinate To Content
331
+
332
+ ## Related Research
333
+
334
+ - `research/products/things-3.md`
335
+ - `research/products/telegram.md`
336
+ - `research/products/apple-reminders.md`
337
+ +- `research/visual/expressive-system-ui-2026.md`
338
+
339
+ ## Related Patterns
340
+
341
+ @@ -108,9 +119,16 @@ Preserve the home surface and show a recovery action without replacing the whole
342
+ - A consumer task app opens to Today, showing current tasks and the main add action.
343
+ - A reminders app opens to the user's current list instead of settings or analytics.
344
+
345
+ +For a household shopping list, the current items form the content layer, list switching belongs to the functional layer, and Add item is the focal action. Bought items remain readable but quieter. Giving every item, navigation control, and background the same strong accent would obscure this hierarchy. This is an application of `VIS-002`, not a required brand style or a new component system.
346
+ +
347
+ ## Agent Checklist
348
+
349
+ - Is there one recognizable home surface?
350
+ - Is the repeated daily action visible without scrolling?
351
+ - Can users return after exploring secondary modes?
352
+ - Are advanced controls quieter than current work?
353
+ +- Can the content, functional layer, focal emphasis, and supporting surfaces be identified on both mobile and desktop?
354
+ +- Does the hierarchy remain clear without transparency, shadows, or decorative motion?
355
+ +- Do repeated visual decisions reuse the project's semantic roles?
356
+ +
357
+ +The visual guidance remains `draft` / `seed`; this revision adds an application contract, not rendered benchmark validation.
358
+ diff --git a/registry/objects.json b/registry/objects.json
359
+ index ad06c2e..c1eaf10 100644
360
+ --- a/registry/objects.json
361
+ +++ b/registry/objects.json
362
+ @@ -223,7 +223,7 @@
363
+ "title": "Daily Home Surface",
364
+ "object_type": "pattern",
365
+ "status": "draft",
366
+ - "version": "0.1.0",
367
+ + "version": "0.2.0",
368
+ "category": "product",
369
+ "maturity": "seed",
370
+ "path": "patterns/daily-home-surface.md"
371
+ @@ -271,7 +271,7 @@
372
+ "title": "Context-Preserving Preview",
373
+ "object_type": "pattern",
374
+ "status": "draft",
375
+ - "version": "0.1.0",
376
+ + "version": "0.2.0",
377
+ "category": "ux",
378
+ "maturity": "seed",
379
+ "path": "patterns/context-preserving-preview.md"
380
+ diff --git a/registry/relationships.json b/registry/relationships.json
381
+ index f562e4d..d658ba2 100644
382
+ --- a/registry/relationships.json
383
+ +++ b/registry/relationships.json
384
+ @@ -952,6 +952,21 @@
385
+ "type": "validates",
386
+ "source": "REVIEW-00003",
387
+ "target": "PROMPT-00006"
388
+ + },
389
+ + {
390
+ + "type": "requires",
391
+ + "source": "PAT-00001",
392
+ + "target": "RULE-00008"
393
+ + },
394
+ + {
395
+ + "type": "requires",
396
+ + "source": "PAT-00001",
397
+ + "target": "RULE-00014"
398
+ + },
399
+ + {
400
+ + "type": "requires",
401
+ + "source": "PAT-00005",
402
+ + "target": "RULE-00015"
403
+ }
404
+ ]
405
+ }
406
+ diff --git a/rules/GENERATED_INDEX.md b/rules/GENERATED_INDEX.md
407
+ index ab0e91e..f2440e4 100644
408
+ --- a/rules/GENERATED_INDEX.md
409
+ +++ b/rules/GENERATED_INDEX.md
410
+ @@ -11,13 +11,13 @@ This file is generated from registry metadata. Do not edit manually.
411
+ | RULE-00005 | UX-001 | Thumb-Zone Primary Actions | ux | draft | seed | rules/ux/UX-001.md | PAT-002 / PAT-00002 Quick Capture<br>PAT-003 / PAT-00003 Mobile Primary Action | derived_from: THINGS-3 / RESEARCH-00002 Things 3<br>derived_from: APPLE-REMINDERS / RESEARCH-00003 Apple Reminders<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist |
412
+ | RULE-00006 | UX-002 | Progressively Disclose Power | ux | draft | seed | rules/ux/UX-002.md | PAT-001 / PAT-00001 Daily Home Surface<br>PAT-002 / PAT-00002 Quick Capture<br>PAT-004 / PAT-00004 Progressive Detail | derived_from: THINGS-3 / RESEARCH-00002 Things 3<br>derived_from: APPLE-REMINDERS / RESEARCH-00003 Apple Reminders<br>derived_from: TELEGRAM / RESEARCH-00001 Telegram<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist |
413
+ | RULE-00007 | UX-003 | Preserve Context During Inspection | ux | draft | seed | rules/ux/UX-003.md | PAT-005 / PAT-00005 Context-Preserving Preview<br>PAT-006 / PAT-00006 Object Status List<br>PAT-007 / PAT-00007 Consequential Action Confirmation | derived_from: ARC / RESEARCH-00005 Arc<br>derived_from: LINEAR / RESEARCH-00004 Linear<br>derived_from: TELEGRAM / RESEARCH-00001 Telegram<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: UX-004 / RULE-00015 Use Motion To Explain State Continuity<br>related_to: UX-005 / RULE-00016 Expose Agent Work And Intervention<br>related_to: UX-006 / RULE-00017 Confirm Consequential Actions With Preserved Context |
414
+ -| RULE-00008 | VIS-001 | Semantic Tokens Only | visual | draft | seed | rules/visual/VIS-001.md | PAT-004 / PAT-00004 Progressive Detail<br>PAT-006 / PAT-00006 Object Status List | derived_from: LINEAR / RESEARCH-00004 Linear<br>derived_from: THINGS-3 / RESEARCH-00002 Things 3<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: VIS-002 / RULE-00014 Keep Expression Subordinate To Content |
415
+ +| RULE-00008 | VIS-001 | Semantic Tokens Only | visual | draft | seed | rules/visual/VIS-001.md | PAT-004 / PAT-00004 Progressive Detail<br>PAT-006 / PAT-00006 Object Status List<br>PAT-001 / PAT-00001 Daily Home Surface | derived_from: LINEAR / RESEARCH-00004 Linear<br>derived_from: THINGS-3 / RESEARCH-00002 Things 3<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: VIS-002 / RULE-00014 Keep Expression Subordinate To Content |
416
+ | RULE-00009 | A11Y-001 | 44x44 Touch Targets | accessibility | draft | seed | rules/accessibility/A11Y-001.md | PAT-001 / PAT-00001 Daily Home Surface<br>PAT-002 / PAT-00002 Quick Capture<br>PAT-003 / PAT-00003 Mobile Primary Action<br>PAT-004 / PAT-00004 Progressive Detail<br>PAT-005 / PAT-00005 Context-Preserving Preview<br>PAT-006 / PAT-00006 Object Status List | derived_from: APPLE-REMINDERS / RESEARCH-00003 Apple Reminders<br>derived_from: THINGS-3 / RESEARCH-00002 Things 3<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist |
417
+ | RULE-00010 | A11Y-002 | Textual Input Error Recovery | accessibility | draft | seed | rules/accessibility/A11Y-002.md | PAT-002 / PAT-00002 Quick Capture<br>PAT-007 / PAT-00007 Consequential Action Confirmation | derived_from: TEXTUAL-ERROR-RECOVERY / RESEARCH-00006 Textual Error Recovery<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt<br>related_to: UX-006 / RULE-00017 Confirm Consequential Actions With Preserved Context |
418
+ | RULE-00011 | PERF-001 | Reserve Layout Space For Asynchronous Content | performance | draft | seed | rules/performance/PERF-001.md | PAT-002 / PAT-00002 Quick Capture | derived_from: RESERVED-LOADING-SPACE / RESEARCH-00007 Reserved Loading Space<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt |
419
+ | RULE-00012 | A11Y-003 | Visible Keyboard Focus | accessibility | draft | seed | rules/accessibility/A11Y-003.md | PAT-002 / PAT-00002 Quick Capture | derived_from: KEYBOARD-FOCUS-AND-MOTION / RESEARCH-00008 Keyboard Focus And Interaction Motion<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt |
420
+ | RULE-00013 | A11Y-004 | Reduce Non-Essential Interaction Motion | accessibility | draft | seed | rules/accessibility/A11Y-004.md | PAT-005 / PAT-00005 Context-Preserving Preview | derived_from: KEYBOARD-FOCUS-AND-MOTION / RESEARCH-00008 Keyboard Focus And Interaction Motion<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: UX-004 / RULE-00015 Use Motion To Explain State Continuity<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt |
421
+ -| RULE-00014 | VIS-002 | Keep Expression Subordinate To Content | visual | draft | seed | rules/visual/VIS-002.md | None | derived_from: EXPRESSIVE-SYSTEM-UI-2026 / RESEARCH-00009 Expressive System UI In 2026<br>related_to: VIS-001 / RULE-00008 Semantic Tokens Only<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt |
422
+ -| RULE-00015 | UX-004 | Use Motion To Explain State Continuity | ux | draft | seed | rules/ux/UX-004.md | None | derived_from: MOTION-AS-STATE-CONTINUITY / RESEARCH-00010 Motion As State Continuity<br>related_to: UX-003 / RULE-00007 Preserve Context During Inspection<br>related_to: A11Y-004 / RULE-00013 Reduce Non-Essential Interaction Motion<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt |
423
+ +| RULE-00014 | VIS-002 | Keep Expression Subordinate To Content | visual | draft | seed | rules/visual/VIS-002.md | PAT-001 / PAT-00001 Daily Home Surface | derived_from: EXPRESSIVE-SYSTEM-UI-2026 / RESEARCH-00009 Expressive System UI In 2026<br>related_to: VIS-001 / RULE-00008 Semantic Tokens Only<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt |
424
+ +| RULE-00015 | UX-004 | Use Motion To Explain State Continuity | ux | draft | seed | rules/ux/UX-004.md | PAT-005 / PAT-00005 Context-Preserving Preview | derived_from: MOTION-AS-STATE-CONTINUITY / RESEARCH-00010 Motion As State Continuity<br>related_to: UX-003 / RULE-00007 Preserve Context During Inspection<br>related_to: A11Y-004 / RULE-00013 Reduce Non-Essential Interaction Motion<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt |
425
+ | RULE-00016 | UX-005 | Expose Agent Work And Intervention | ux | draft | seed | rules/ux/UX-005.md | PAT-007 / PAT-00007 Consequential Action Confirmation | derived_from: CONTEXTUAL-AGENTIC-INTERFACE / RESEARCH-00011 Contextual And Observable Agentic Interfaces<br>related_to: IA-002 / RULE-00004 Define The Object Model Before Screens<br>related_to: UX-003 / RULE-00007 Preserve Context During Inspection<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt<br>related_to: UX-006 / RULE-00017 Confirm Consequential Actions With Preserved Context<br>related_to: PROMPT-CONSEQUENTIAL-ACTION-REVIEW / PROMPT-00006 Consequential Action Review Prompt |
426
+ | RULE-00017 | UX-006 | Confirm Consequential Actions With Preserved Context | ux | active | validated | rules/ux/UX-006.md | PAT-007 / PAT-00007 Consequential Action Confirmation | derived_from: HIGH-RISK-OPERATIONAL-FLOWS / RESEARCH-00012 High-Risk Operational Flows<br>related_to: UX-003 / RULE-00007 Preserve Context During Inspection<br>related_to: A11Y-002 / RULE-00010 Textual Input Error Recovery<br>related_to: UX-005 / RULE-00016 Expose Agent Work And Intervention<br>related_to: CHECK-DESIGN-QA / CHECK-00001 Design QA Checklist<br>related_to: PROMPT-PROTOTYPE-REVIEW / PROMPT-00002 Prototype Review Prompt<br>validates: REF-CONSEQUENTIAL-ACTION-CONFIRMATION / REF-00002 Consequential Action Confirmation Reference Project<br>validates: REVIEW-CONSEQUENTIAL-ACTION-CONFIRMATION / REVIEW-00003 Consequential Action Confirmation Validation Review |
427
+ diff --git a/skills/agent-context/SKILL.md b/skills/agent-context/SKILL.md
428
+ index d825a48..3d7bb38 100644
429
+ --- a/skills/agent-context/SKILL.md
430
+ +++ b/skills/agent-context/SKILL.md
431
+ @@ -22,9 +22,11 @@ Run this skill before a user-facing implementation or review when the applicable
432
+ 4. Apply only the returned rules and patterns that fit the task.
433
+ 5. Preserve every returned evidence boundary; `draft` and `seed` do not justify broad product claims.
434
+ 6. If the resolver returns no match, create an observation or research need rather than inventing a rule.
435
+ +7. Inspect each object's selection reason. Required dependencies are complete, while optional links in broad review gates must be followed explicitly when the review needs them.
436
+
437
+ ## Boundaries
438
+
439
+ - The CLI is read-only and does not replace `npm run check`.
440
+ - `--platform` adds relevant context; it does not prove that a pattern applies.
441
+ - Use `--format json` for another agent or script; errors are machine-readable on stderr.
442
+ +- Task matching is lexical. Simple English task wrappers are supported; arbitrary paraphrases and translation are not. Prefer an exact known slug or ID when available.
443
+ diff --git a/tools/context.mjs b/tools/context.mjs
444
+ index 8adc592..db4815e 100644
445
+ --- a/tools/context.mjs
446
+ +++ b/tools/context.mjs
447
+ @@ -85,118 +85,145 @@ function normalize(value) {
448
+ function tokenise(value) {
449
+ return normalize(value)
450
+ .split(/\s+/u)
451
+ - .filter((token) => token.length > 1);
452
+ + .filter(Boolean);
453
+ }
454
+
455
+ -function objectText(object) {
456
+ - const filePath = path.join(root, object.path);
457
+ - const content = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
458
+ - return normalize([object.id, object.alias, object.slug, object.title, object.category, object.path, content].join('\n'));
459
+ +const taskFillers = new Set(['a', 'an', 'the', 'please', 'build', 'create', 'implement', 'make', 'for', 'me']);
460
+ +const dependencyTypes = new Set(['requires', 'derived_from', 'inspired_by', 'implements']);
461
+ +
462
+ +function searchIndex(objects) {
463
+ + return objects.map((object) => {
464
+ + const filePath = path.join(root, object.path);
465
+ + const content = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
466
+ + return {
467
+ + object,
468
+ + terms: new Set(tokenise([object.id, object.alias, object.slug, object.title, object.category, object.path, content].join('\n'))),
469
+ + fields: [
470
+ + ['title', object.title, 100],
471
+ + ['slug', object.slug, 90],
472
+ + ['alias', object.alias, 80],
473
+ + ['category', object.category, 20],
474
+ + ],
475
+ + };
476
+ + });
477
+ }
478
+
479
+ -function findAnchors(objects, query) {
480
+ +function findAnchors(index, query) {
481
+ const normalizedQuery = normalize(query);
482
+ - const tokens = tokenise(query);
483
+ + const exact = findExactObject(index.map(({ object }) => object), query);
484
+ + if (exact.length > 0) return exact;
485
+ + const tokens = [...new Set(tokenise(query).filter((token) => !taskFillers.has(token)))];
486
+ if (!normalizedQuery || tokens.length === 0) return [];
487
+
488
+ - const scored = objects
489
+ - .map((object) => {
490
+ - const text = objectText(object);
491
+ - const exactFields = [object.id, object.alias, object.slug, object.path].map(normalize);
492
+ - const allTokensMatch = tokens.length > 0 && tokens.every((token) => text.includes(token));
493
+ - if (!text.includes(normalizedQuery) && !allTokensMatch) return null;
494
+ -
495
+ - const score =
496
+ - (exactFields.includes(normalizedQuery) ? 100 : 0) +
497
+ - (text.includes(normalizedQuery) ? 20 : 0) +
498
+ - tokens.filter((token) => text.includes(token)).length;
499
+ - return { object, score };
500
+ + const scored = index
501
+ + .map(({ object, terms, fields }) => {
502
+ + if (!tokens.every((token) => terms.has(token))) return null;
503
+ + let score = 0;
504
+ + let field = 'content';
505
+ + let matchedTerms = tokens;
506
+ + for (const [name, value, weight] of fields) {
507
+ + const fieldTerms = new Set(tokenise(value));
508
+ + const matched = tokens.filter((token) => fieldTerms.has(token)).length;
509
+ + const fieldScore = matched === 0 ? 0 : weight * matched / tokens.length + matched / fieldTerms.size;
510
+ + if (fieldScore > score) {
511
+ + score = fieldScore;
512
+ + field = name;
513
+ + matchedTerms = tokens.filter((token) => fieldTerms.has(token));
514
+ + }
515
+ + }
516
+ + return { object, score, reason: { kind: 'match', field, terms: matchedTerms } };
517
+ })
518
+ .filter(Boolean)
519
+ .sort((left, right) => right.score - left.score || left.object.id.localeCompare(right.object.id));
520
+
521
+ - return scored.slice(0, 1).map(({ object }) => object);
522
+ + return scored.slice(0, 1);
523
+ }
524
+
525
+ function findExactObject(objects, query) {
526
+ const normalizedQuery = normalize(query);
527
+ if (!normalizedQuery) return [];
528
+
529
+ - const object = objects.find((candidate) =>
530
+ - [candidate.id, candidate.alias, candidate.slug, candidate.path]
531
+ - .map(normalize)
532
+ - .includes(normalizedQuery),
533
+ - );
534
+ -
535
+ - return object ? [object] : [];
536
+ + for (const object of objects) {
537
+ + const field = ['id', 'alias', 'slug', 'path'].find((name) => normalize(object[name]) === normalizedQuery);
538
+ + if (field) return [{ object, reason: { kind: 'match', field, terms: tokenise(query) } }];
539
+ + }
540
+ + return [];
541
+ }
542
+
543
+ -function relatedContext(anchors, objectsById, relationships, platform) {
544
+ - const selected = new Map(anchors.map((object) => [object.id, object]));
545
+ - const add = (id) => {
546
+ +function relatedContext(anchors, objectsById, relationships, platform, index) {
547
+ + const selected = new Map();
548
+ + const queue = [];
549
+ + const outgoing = new Map();
550
+ + const incoming = new Map();
551
+ + for (const edge of [...relationships].sort((a, b) =>
552
+ + a.source.localeCompare(b.source) || a.type.localeCompare(b.type) || a.target.localeCompare(b.target))) {
553
+ + if (!outgoing.has(edge.source)) outgoing.set(edge.source, []);
554
+ + if (!incoming.has(edge.target)) incoming.set(edge.target, []);
555
+ + outgoing.get(edge.source).push(edge);
556
+ + incoming.get(edge.target).push(edge);
557
+ + }
558
+ + const add = (id, reason) => {
559
+ const object = objectsById.get(id);
560
+ - if (object) selected.set(id, object);
561
+ + if (!object) throw new Error(`Context relationship target is not registered: ${id}`);
562
+ + if (selected.has(id)) return;
563
+ + selected.set(id, { object, reason });
564
+ + queue.push(object);
565
+ };
566
+ - const outgoing = (id) => relationships.filter((relationship) => relationship.source === id);
567
+ - const incoming = (id) => relationships.filter((relationship) => relationship.target === id);
568
+ -
569
+ - for (const anchor of anchors) {
570
+ - for (const relationship of outgoing(anchor.id)) add(relationship.target);
571
+ + const seeds = [...anchors];
572
+ + if (platform) {
573
+ + const matches = findAnchors(
574
+ + index.filter(({ object }) => ['rule', 'pattern'].includes(object.object_type)), platform,
575
+ + );
576
+ + seeds.push(...matches.map(({ object, reason }) => ({ object, reason: { ...reason, kind: 'platform', value: platform } })));
577
+ + }
578
+ + for (const { object, reason } of seeds) add(object.id, reason);
579
+
580
+ - if (anchor.object_type === 'rule') {
581
+ - for (const relationship of incoming(anchor.id)) {
582
+ - if (['pattern', 'prompt', 'checklist'].includes(objectsById.get(relationship.source)?.object_type)) add(relationship.source);
583
+ + // Only seed objects select optional neighbors; dependencies cannot pull in every consumer.
584
+ + const reviewTargets = new Set(seeds.map(({ object }) => object.id));
585
+ + for (const { object } of seeds) {
586
+ + for (const edge of outgoing.get(object.id) ?? []) {
587
+ + if (edge.type === 'related_to' && ['research', 'rule', 'pattern'].includes(object.object_type)) {
588
+ + add(edge.target, { kind: 'related', source: edge.source, relationship: edge.type });
589
+ }
590
+ }
591
+ - if (anchor.object_type === 'research') {
592
+ - for (const relationship of incoming(anchor.id)) {
593
+ - if (objectsById.get(relationship.source)?.object_type === 'rule') add(relationship.source);
594
+ + for (const edge of incoming.get(object.id) ?? []) {
595
+ + const source = objectsById.get(edge.source);
596
+ + if (object.object_type === 'research' && source?.object_type === 'rule' && ['derived_from', 'inspired_by'].includes(edge.type)) {
597
+ + add(source.id, { kind: 'derived_rule', source: object.id, relationship: edge.type });
598
+ + reviewTargets.add(source.id);
599
+ }
600
+ - }
601
+ - if (anchor.object_type === 'pattern') {
602
+ - for (const relationship of incoming(anchor.id)) {
603
+ - if (['prompt', 'reference_project'].includes(objectsById.get(relationship.source)?.object_type)) add(relationship.source);
604
+ + if (object.object_type === 'reference_project' && source?.object_type === 'review' && edge.type === 'validates') {
605
+ + add(source.id, { kind: 'review', source: object.id, relationship: edge.type });
606
+ }
607
+ }
608
+ - if (anchor.object_type === 'reference_project') {
609
+ - for (const relationship of incoming(anchor.id)) {
610
+ - if (objectsById.get(relationship.source)?.object_type === 'review') add(relationship.source);
611
+ + }
612
+ + for (const id of reviewTargets) {
613
+ + for (const edge of incoming.get(id) ?? []) {
614
+ + const source = objectsById.get(edge.source);
615
+ + if (['requires', 'related_to'].includes(edge.type) &&
616
+ + (source?.object_type === 'checklist' || (source?.object_type === 'prompt' && source.category === 'review'))) {
617
+ + add(source.id, { kind: 'review', source: id, relationship: edge.type });
618
+ }
619
+ }
620
+ }
621
+
622
+ - for (const object of [...selected.values()]) {
623
+ - if (object.object_type === 'rule') {
624
+ - for (const relationship of outgoing(object.id)) {
625
+ - if (objectsById.get(relationship.target)?.object_type === 'research') add(relationship.target);
626
+ - }
627
+ - for (const relationship of incoming(object.id)) {
628
+ - if (['pattern', 'prompt', 'checklist'].includes(objectsById.get(relationship.source)?.object_type)) add(relationship.source);
629
+ + // A growing queue computes the dependency closure and terminates even when the graph has cycles.
630
+ + for (let cursor = 0; cursor < queue.length; cursor += 1) {
631
+ + const object = queue[cursor];
632
+ + for (const edge of outgoing.get(object.id) ?? []) {
633
+ + if (dependencyTypes.has(edge.type) ||
634
+ + (edge.type === 'validates' && ['reference_project', 'review'].includes(object.object_type))) {
635
+ + add(edge.target, { kind: 'dependency', source: edge.source, relationship: edge.type });
636
+ }
637
+ }
638
+ - if (object.object_type === 'pattern') {
639
+ - for (const relationship of outgoing(object.id)) {
640
+ - if (objectsById.get(relationship.target)?.object_type === 'rule') add(relationship.target);
641
+ - }
642
+ - }
643
+ - if (object.object_type === 'review') {
644
+ - for (const relationship of outgoing(object.id)) add(relationship.target);
645
+ - }
646
+ - }
647
+ -
648
+ - if (platform) {
649
+ - const platformMatches = findAnchors([...objectsById.values()], platform).filter((object) =>
650
+ - ['rule', 'pattern'].includes(object.object_type),
651
+ - );
652
+ - for (const object of platformMatches.slice(0, 2)) add(object.id);
653
+ }
654
+
655
+ return [...selected.values()].sort(
656
+ - (left, right) => objectOrder.indexOf(left.object_type) - objectOrder.indexOf(right.object_type) || left.id.localeCompare(right.id),
657
+ + (left, right) => objectOrder.indexOf(left.object.object_type) - objectOrder.indexOf(right.object.object_type) || left.object.id.localeCompare(right.object.id),
658
+ );
659
+ }
660
+
661
+ -function serializeObject(object) {
662
+ +function serializeObject({ object, reason }) {
663
+ return {
664
+ id: object.id,
665
+ alias: object.alias,
666
+ @@ -205,9 +232,17 @@ function serializeObject(object) {
667
+ status: object.status,
668
+ maturity: object.maturity,
669
+ path: object.path,
670
+ + reason,
671
+ };
672
+ }
673
+
674
+ +function explainReason(reason) {
675
+ + if (reason.kind === 'match') return `matched ${reason.field}: ${reason.terms.join(', ')}`;
676
+ + if (reason.kind === 'platform') return `platform ${reason.value}, matched ${reason.field}`;
677
+ + if (['review', 'derived_rule'].includes(reason.kind)) return `${reason.kind === 'review' ? 'review gate' : 'derived rule'} for ${reason.source} (${reason.relationship})`;
678
+ + return `${reason.source} ${reason.relationship} this object`;
679
+ +}
680
+ +
681
+ function asMarkdown(result) {
682
+ const lines = [
683
+ '# Agent Context',
684
+ @@ -229,7 +264,7 @@ function asMarkdown(result) {
685
+ lines.push(
686
+ ...objects.map(
687
+ (object) =>
688
+ - `- \`${object.id}\` / \`${object.alias}\` — ${object.title} (${object.status}, ${object.maturity}) · \`${object.path}\``,
689
+ + `- \`${object.id}\` / \`${object.alias}\` — ${object.title} (${object.status}, ${object.maturity}) · \`${object.path}\` — ${explainReason(object.reason)}`,
690
+ ),
691
+ );
692
+ }
693
+ @@ -268,16 +303,17 @@ function main() {
694
+ fs.readFileSync(path.join(root, 'registry/relationships.json'), 'utf8'),
695
+ );
696
+ const objectsById = new Map(registry.objects.map((object) => [object.id, object]));
697
+ + const index = searchIndex(registry.objects);
698
+ const query = options[options.mode];
699
+ const anchors = options.mode === 'object'
700
+ ? findExactObject(registry.objects, query)
701
+ - : findAnchors(registry.objects, query);
702
+ + : findAnchors(index, query);
703
+ if (anchors.length === 0) throw new Error(`No graph object matches "${query}"`);
704
+
705
+ const result = {
706
+ query: { mode: options.mode, value: query, platform: options.platform ?? null, intent: options.intent },
707
+ anchors: anchors.map(serializeObject),
708
+ - objects: relatedContext(anchors, objectsById, relationshipRegistry.relationships, options.platform).map(serializeObject),
709
+ + objects: relatedContext(anchors, objectsById, relationshipRegistry.relationships, options.platform, index).map(serializeObject),
710
+ };
711
+ console.log(options.format === 'json' ? JSON.stringify(result, null, 2) : asMarkdown(result));
712
+ } catch (error) {
713
+ diff --git a/tools/context.test.mjs b/tools/context.test.mjs
714
+ index 2650ecd..69c5d63 100644
715
+ --- a/tools/context.test.mjs
716
+ +++ b/tools/context.test.mjs
717
+ @@ -1,5 +1,7 @@
718
+ import assert from 'node:assert/strict';
719
+ +import fs from 'node:fs';
720
+ import { spawnSync } from 'node:child_process';
721
+ +import os from 'node:os';
722
+ import path from 'node:path';
723
+ import test from 'node:test';
724
+ import { fileURLToPath } from 'node:url';
725
+ @@ -7,10 +9,29 @@ import { fileURLToPath } from 'node:url';
726
+ const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
727
+
728
+ function runContext(...args) {
729
+ - return spawnSync(process.execPath, ['tools/context.mjs', ...args], {
730
+ - cwd: projectRoot,
731
+ + return runContextAt(projectRoot, ...args);
732
+ +}
733
+ +
734
+ +function runContextAt(cwd, ...args) {
735
+ + return spawnSync(process.execPath, [path.join(projectRoot, 'tools/context.mjs'), ...args], {
736
+ + cwd,
737
+ encoding: 'utf8',
738
+ + timeout: 10000,
739
+ + });
740
+ +}
741
+ +
742
+ +function fixture(t, definitions, relationships = []) {
743
+ + const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'design-context-'));
744
+ + t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
745
+ + fs.mkdirSync(path.join(directory, 'registry'));
746
+ + const objects = definitions.map(({ content = '', ...definition }) => {
747
+ + const object = { status: 'draft', maturity: 'seed', category: 'ux', slug: definition.title.toLowerCase().replaceAll(' ', '-'), ...definition, path: `${definition.id}.md` };
748
+ + fs.writeFileSync(path.join(directory, object.path), content);
749
+ + return object;
750
+ });
751
+ + fs.writeFileSync(path.join(directory, 'registry/objects.json'), JSON.stringify({ objects }));
752
+ + fs.writeFileSync(path.join(directory, 'registry/relationships.json'), JSON.stringify({ relationships }));
753
+ + return directory;
754
+ }
755
+
756
+ test('resolves a task into patterns, rules, and upstream research', () => {
757
+ @@ -70,3 +91,133 @@ test('object mode resolves only exact stable fields', () => {
758
+ assert.equal(fuzzy.status, 1);
759
+ assert.deepEqual(JSON.parse(fuzzy.stderr), { error: 'No graph object matches "pattern"' });
760
+ });
761
+ +
762
+ +test('resolves ordinary task phrasing without dropping unknown subject terms', () => {
763
+ + const direct = runContext('--task', 'shopping list', '--format', 'json');
764
+ + assert.equal(direct.status, 0, direct.stderr);
765
+ + const expected = JSON.parse(direct.stdout);
766
+ + assert.ok(expected.objects.some((object) => object.id === 'PAT-00002'), 'shopping lists include quick capture');
767
+ + for (const query of ['shopping list', 'build a shopping list', 'please create the shopping list for me']) {
768
+ + const result = runContext('--task', query, '--format', 'json');
769
+ + assert.equal(result.status, 0, result.stderr);
770
+ + const context = JSON.parse(result.stdout);
771
+ + assert.deepEqual(context.anchors, expected.anchors);
772
+ + assert.deepEqual(context.objects, expected.objects);
773
+ + }
774
+ + for (const query of ['please build', 'shopping qzxvzz-notfound']) {
775
+ + const result = runContext('--task', query, '--format', 'json');
776
+ + assert.equal(result.status, 1);
777
+ + assert.match(JSON.parse(result.stderr).error, /No graph object matches/);
778
+ + }
779
+ +});
780
+ +
781
+ +test('ranks a focused motion title above incidental checklist mentions', () => {
782
+ + const result = runContext('--task', 'motion', '--format', 'json');
783
+ + assert.equal(result.status, 0, result.stderr);
784
+ + const context = JSON.parse(result.stdout);
785
+ + assert.equal(context.anchors[0].id, 'RESEARCH-00010');
786
+ + assert.equal(context.anchors[0].reason.field, 'title');
787
+ + assert.ok(context.objects.some((object) => object.id === 'RULE-00015'));
788
+ + assert.ok(context.objects.some((object) => object.id === 'CHECK-00001'));
789
+ + assert.ok(context.objects.length <= 10, 'motion context must stay focused');
790
+ +});
791
+ +
792
+ +test('quick capture excludes unrelated consumers and explains every selection', () => {
793
+ + const result = runContext('--task', 'quick-capture', '--format', 'json');
794
+ + assert.equal(result.status, 0, result.stderr);
795
+ + const context = JSON.parse(result.stdout);
796
+ + const ids = new Set(context.objects.map((object) => object.id));
797
+ + assert.ok(ids.has('PROMPT-00004'), 'include the directly applicable review');
798
+ + assert.ok(!ids.has('PROMPT-00003'), 'do not pull in the entire Todo benchmark');
799
+ + assert.ok(!ids.has('PAT-00007'), 'shared rules do not imply consequential actions');
800
+ + assert.ok(context.objects.length <= 20);
801
+ + for (const object of context.objects) {
802
+ + assert.ok(object.reason.kind);
803
+ + if (object.reason.source) assert.ok(ids.has(object.reason.source));
804
+ + }
805
+ + const markdown = runContext('--task', 'quick-capture');
806
+ + assert.equal(markdown.status, 0, markdown.stderr);
807
+ + assert.match(markdown.stdout, /matched slug: quick, capture/);
808
+ + assert.match(markdown.stdout, /PAT-00002 requires this object/);
809
+ +});
810
+ +
811
+ +test('every registered anchor includes all transitive dependencies', () => {
812
+ + const { objects } = JSON.parse(fs.readFileSync(path.join(projectRoot, 'registry/objects.json'), 'utf8'));
813
+ + const { relationships } = JSON.parse(fs.readFileSync(path.join(projectRoot, 'registry/relationships.json'), 'utf8'));
814
+ + for (const anchor of objects) {
815
+ + const result = runContext('--object', anchor.id, '--platform', 'mobile', '--format', 'json');
816
+ + assert.equal(result.status, 0, result.stderr);
817
+ + const context = JSON.parse(result.stdout);
818
+ + const ids = new Set(context.objects.map((object) => object.id));
819
+ + for (const edge of relationships) {
820
+ + if (ids.has(edge.source) && ['requires', 'derived_from', 'inspired_by', 'implements', 'validates'].includes(edge.type)) {
821
+ + assert.ok(ids.has(edge.target), `${anchor.id}: missing ${edge.source} ${edge.type} ${edge.target}`);
822
+ + }
823
+ + }
824
+ + }
825
+ +});
826
+ +
827
+ +test('dependency cycles terminate and optional relations do not expand recursively', (t) => {
828
+ + const directory = fixture(t, [
829
+ + { id: 'PAT-00001', object_type: 'pattern', title: 'Capture' },
830
+ + { id: 'RULE-00001', object_type: 'rule', title: 'Input' },
831
+ + { id: 'RESEARCH-00001', object_type: 'research', title: 'Evidence' },
832
+ + { id: 'PAT-00002', object_type: 'pattern', title: 'Unrelated' },
833
+ + ], [
834
+ + { source: 'PAT-00001', type: 'requires', target: 'RULE-00001' },
835
+ + { source: 'RULE-00001', type: 'derived_from', target: 'RESEARCH-00001' },
836
+ + { source: 'RESEARCH-00001', type: 'requires', target: 'PAT-00001' },
837
+ + { source: 'RULE-00001', type: 'related_to', target: 'PAT-00002' },
838
+ + { source: 'PAT-00002', type: 'requires', target: 'RULE-00001' },
839
+ + ]);
840
+ + const result = runContextAt(directory, '--object', 'PAT-00001', '--format', 'json');
841
+ + assert.equal(result.status, 0, result.stderr);
842
+ + const ids = JSON.parse(result.stdout).objects.map((object) => object.id);
843
+ + assert.deepEqual(new Set(ids), new Set(['PAT-00001', 'RULE-00001', 'RESEARCH-00001']));
844
+ + assert.equal(ids.length, 3);
845
+ +});
846
+ +
847
+ +test('platform selection filters eligible types before ranking and includes their dependencies', (t) => {
848
+ + const directory = fixture(t, [
849
+ + { id: 'RESEARCH-00001', object_type: 'research', title: 'Mobile' },
850
+ + { id: 'PAT-00001', object_type: 'pattern', title: 'Capture' },
851
+ + { id: 'PAT-00002', object_type: 'pattern', title: 'Mobile Action' },
852
+ + { id: 'RULE-00001', object_type: 'rule', title: 'Touch Targets' },
853
+ + { id: 'RESEARCH-00002', object_type: 'research', title: 'Touch Evidence' },
854
+ + ], [
855
+ + { source: 'PAT-00002', type: 'requires', target: 'RULE-00001' },
856
+ + { source: 'RULE-00001', type: 'derived_from', target: 'RESEARCH-00002' },
857
+ + ]);
858
+ + const result = runContextAt(directory, '--object', 'PAT-00001', '--platform', 'mobile', '--format', 'json');
859
+ + assert.equal(result.status, 0, result.stderr);
860
+ + const context = JSON.parse(result.stdout);
861
+ + assert.equal(context.anchors[0].id, 'PAT-00001');
862
+ + assert.equal(context.objects.find((object) => object.id === 'PAT-00002').reason.kind, 'platform');
863
+ + assert.ok(context.objects.some((object) => object.id === 'RESEARCH-00002'));
864
+ + assert.ok(!context.objects.some((object) => object.id === 'RESEARCH-00001'));
865
+ +});
866
+ +
867
+ +test('matches whole Unicode words and prefers an exact identifier over a title', (t) => {
868
+ + const directory = fixture(t, [
869
+ + { id: 'PAT-00001', alias: 'SPECIAL', object_type: 'pattern', title: 'Capture', content: 'Start capturing' },
870
+ + { id: 'PAT-00002', object_type: 'pattern', title: 'Special' },
871
+ + { id: 'PAT-00003', object_type: 'pattern', title: 'Быстрый ввод' },
872
+ + ]);
873
+ + const exact = runContextAt(directory, '--task', 'SPECIAL', '--format', 'json');
874
+ + assert.equal(exact.status, 0, exact.stderr);
875
+ + assert.equal(JSON.parse(exact.stdout).anchors[0].id, 'PAT-00001');
876
+ + const unicode = runContextAt(directory, '--task', 'БЫСТРЫЙ ввод', '--format', 'json');
877
+ + assert.equal(unicode.status, 0, unicode.stderr);
878
+ + assert.equal(JSON.parse(unicode.stdout).anchors[0].id, 'PAT-00003');
879
+ + const partial = runContextAt(directory, '--task', 'art', '--format', 'json');
880
+ + assert.equal(partial.status, 1, 'art must not match Start');
881
+ +});
882
+ +
883
+ +test('reports a missing required target instead of returning incomplete context', (t) => {
884
+ + const directory = fixture(t, [{ id: 'PAT-00001', object_type: 'pattern', title: 'Capture' }], [
885
+ + { source: 'PAT-00001', type: 'requires', target: 'RULE-99999' },
886
+ + ]);
887
+ + const result = runContextAt(directory, '--object', 'PAT-00001', '--format', 'json');
888
+ + assert.equal(result.status, 1);
889
+ + assert.deepEqual(JSON.parse(result.stderr), { error: 'Context relationship target is not registered: RULE-99999' });
890
+ +});