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,289 @@
1
+ 'use strict';
2
+ const SEED = [
3
+ {
4
+ "id": "t01",
5
+ "title": "Book dentist appointment",
6
+ "notes": "Ask about a morning appointment.",
7
+ "dueDate": "2026-09-28",
8
+ "completed": false
9
+ },
10
+ {
11
+ "id": "t02",
12
+ "title": "Pick up parcel",
13
+ "notes": "",
14
+ "dueDate": "2026-09-28",
15
+ "completed": false
16
+ },
17
+ {
18
+ "id": "t03",
19
+ "title": "Reply to Maya",
20
+ "notes": "",
21
+ "dueDate": "2026-09-28",
22
+ "completed": false
23
+ },
24
+ {
25
+ "id": "t04",
26
+ "title": "Pay electricity bill",
27
+ "notes": "",
28
+ "dueDate": "2026-09-28",
29
+ "completed": false
30
+ },
31
+ {
32
+ "id": "t05",
33
+ "title": "Fix bicycle light",
34
+ "notes": "",
35
+ "dueDate": "2026-09-28",
36
+ "completed": false
37
+ },
38
+ {
39
+ "id": "t06",
40
+ "title": "Water the plants",
41
+ "notes": "",
42
+ "dueDate": "2026-09-28",
43
+ "completed": false
44
+ },
45
+ {
46
+ "id": "t07",
47
+ "title": "Read chapter twelve",
48
+ "notes": "",
49
+ "dueDate": "2026-09-28",
50
+ "completed": false
51
+ },
52
+ {
53
+ "id": "t08",
54
+ "title": "Plan weekend walk",
55
+ "notes": "",
56
+ "dueDate": "2026-09-28",
57
+ "completed": false
58
+ },
59
+ {
60
+ "id": "t09",
61
+ "title": "Return library book",
62
+ "notes": "",
63
+ "dueDate": "2026-09-28",
64
+ "completed": false
65
+ },
66
+ {
67
+ "id": "t10",
68
+ "title": "Take out recycling",
69
+ "notes": "",
70
+ "dueDate": "2026-09-28",
71
+ "completed": false
72
+ },
73
+ {
74
+ "id": "t11",
75
+ "title": "Order coffee beans",
76
+ "notes": "",
77
+ "dueDate": "2026-09-28",
78
+ "completed": false
79
+ },
80
+ {
81
+ "id": "t12",
82
+ "title": "Stretch for ten minutes",
83
+ "notes": "",
84
+ "dueDate": "2026-09-28",
85
+ "completed": true
86
+ }
87
+ ];
88
+ const TODAY = '2026-09-28';
89
+ const STORE = 'daylight-adr-benchmark-v1';
90
+ const $ = id => document.getElementById(id);
91
+ const clone = value => JSON.parse(JSON.stringify(value));
92
+ let tasks = clone(SEED), view = 'today', loading = true, showCompleted = true;
93
+ let delay = 500, failNext = false, pending = null, epoch = 0, sequence = 0;
94
+ let selected = null, opener = null, sourceScroll = 0, failedOperation = null;
95
+ let drafts = {}, status = 'idle';
96
+ try {
97
+ const stored = JSON.parse(localStorage.getItem(STORE));
98
+ if (Array.isArray(stored) && stored.every(t => typeof t.id === 'string' && typeof t.title === 'string' && typeof t.notes === 'string' && typeof t.dueDate === 'string' && typeof t.completed === 'boolean')) tasks = stored;
99
+ } catch (_) { /* The app remains usable; a failed write gets explicit recovery. */ }
100
+
101
+ function message(text, kind = 'idle', retry = false) {
102
+ status = kind;
103
+ $('feedback-text').textContent = text;
104
+ $('feedback').className = 'feedback ' + kind;
105
+ $('retry').hidden = !retry;
106
+ }
107
+ function detailMessage(text, kind = '') {
108
+ $('detail-feedback').textContent = text;
109
+ $('detail-feedback').className = 'detail-feedback ' + kind;
110
+ }
111
+ function visibleTasks() { return tasks.filter(t => view === 'all' || t.dueDate === TODAY || (t.dueDate && t.dueDate < TODAY && !t.completed)); }
112
+ function dateLabel(date) {
113
+ if (!date) return 'No date';
114
+ if (date === TODAY) return 'Today';
115
+ return new Date(date + 'T12:00:00').toLocaleDateString('en-US', {month:'short', day:'numeric'});
116
+ }
117
+ function taskRow(task) {
118
+ const row = document.createElement('li');
119
+ row.className = 'task-row' + (task.completed ? ' is-completed' : '');
120
+ row.dataset.taskId = task.id;
121
+ if (pending?.id === task.id) row.setAttribute('aria-busy', 'true');
122
+ const check = document.createElement('button');
123
+ check.className = 'check';
124
+ check.setAttribute('role', 'checkbox');
125
+ check.setAttribute('aria-checked', String(task.completed));
126
+ check.setAttribute('aria-label', `${task.completed ? 'Mark incomplete' : 'Complete'}: ${task.title}`);
127
+ check.disabled = Boolean(pending);
128
+ const circle = document.createElement('span');
129
+ circle.className = 'check-circle'; circle.setAttribute('aria-hidden', 'true'); circle.textContent = task.completed ? '✓' : '';
130
+ check.append(circle);
131
+ check.addEventListener('click', () => save({kind:'complete', id:task.id, completed:!task.completed, title:task.title}));
132
+ const open = document.createElement('button');
133
+ open.className = 'task-open'; open.dataset.openId = task.id;
134
+ open.setAttribute('aria-label', `Details: ${task.title}`);
135
+ const text = document.createElement('span'); text.className = 'task-text';
136
+ const title = document.createElement('span'); title.className = 'task-title'; title.textContent = task.title;
137
+ text.append(title);
138
+ if (task.notes || view === 'all' || (task.dueDate && task.dueDate < TODAY)) {
139
+ const meta = document.createElement('span'); meta.className = 'task-meta';
140
+ meta.textContent = [task.dueDate && task.dueDate < TODAY && !task.completed ? 'Overdue · ' + dateLabel(task.dueDate) : view === 'all' ? dateLabel(task.dueDate) : '', task.notes ? 'Has notes' : ''].filter(Boolean).join(' · ');
141
+ text.append(meta);
142
+ }
143
+ const arrow = document.createElement('span'); arrow.className = 'row-arrow'; arrow.textContent = '›'; arrow.setAttribute('aria-hidden','true');
144
+ open.append(text,arrow); open.addEventListener('click', () => openDetail(task.id, open));
145
+ row.append(check,open); return row;
146
+ }
147
+ function render() {
148
+ const list = visibleTasks(); const active = list.filter(t => !t.completed); const done = list.filter(t => t.completed);
149
+ $('today-count').textContent = tasks.filter(t => !t.completed && t.dueDate && t.dueDate <= TODAY).length;
150
+ $('all-count').textContent = tasks.filter(t => !t.completed).length;
151
+ document.querySelectorAll('[data-view]').forEach(button => {
152
+ const activeView = button.dataset.view === view;
153
+ button.classList.toggle('active', activeView);
154
+ if (activeView) button.setAttribute('aria-current','page'); else button.removeAttribute('aria-current');
155
+ });
156
+ $('view-title').replaceChildren(document.createTextNode(view === 'today' ? 'Today' : 'All tasks'));
157
+ if (view === 'today') { const sun=document.createElement('span'); sun.className='sun'; sun.textContent='☀'; sun.setAttribute('aria-hidden','true'); $('view-title').append(sun); }
158
+ $('summary').textContent = loading ? 'Getting your day ready…' : active.length ? `${active.length} ${active.length === 1 ? 'task' : 'tasks'} to do. One thing at a time.` : done.length ? 'A good day, one small step at a time.' : 'A fresh start. Make room for what matters.';
159
+ $('remaining-count').textContent = loading ? '' : active.length;
160
+ $('task-region').setAttribute('aria-busy',String(loading));
161
+ $('task-list').replaceChildren(); $('completed-list').replaceChildren();
162
+ if (loading) {
163
+ for (let i=0;i<Math.max(1,active.length);i++) { const li=document.createElement('li'); li.className='task-row'; li.setAttribute('aria-hidden','true'); const line=document.createElement('span'); line.className='skeleton'; li.append(line); $('task-list').append(li); }
164
+ } else { active.forEach(task => $('task-list').append(taskRow(task))); done.forEach(task => $('completed-list').append(taskRow(task))); }
165
+ $('empty').hidden = loading || active.length > 0;
166
+ $('empty-title').textContent = done.length ? 'All clear for now' : view === 'today' && tasks.length ? 'Nothing planned for today' : 'A little room to begin';
167
+ $('empty-copy').textContent = done.length ? 'You’ve taken care of your list. Enjoy a little breathing room.' : 'Add a task below. One small thing is a good start.';
168
+ $('completed-section').hidden = loading || done.length === 0;
169
+ $('completed-count').textContent = done.length;
170
+ $('completed-toggle').setAttribute('aria-expanded',String(showCompleted));
171
+ $('completed-chevron').textContent = showCompleted ? '⌄' : '›';
172
+ $('completed-list').hidden = !showCompleted;
173
+ $('add-task').disabled = Boolean(pending) || loading;
174
+ $('task-title').readOnly = Boolean(pending) || loading;
175
+ $('add-task').textContent = pending?.kind === 'add' ? 'Saving…' : failedOperation?.kind === 'add' ? 'Retry' : 'Add';
176
+ $('save-detail').disabled = Boolean(pending);
177
+ for (const id of ['detail-title','detail-notes','detail-date']) $(id).readOnly = Boolean(pending?.kind === 'edit' && pending.id === selected);
178
+ }
179
+ function save(operation) {
180
+ if (pending || loading) return;
181
+ const token = epoch; const shouldFail = failNext; failNext = false;
182
+ pending = clone(operation); failedOperation = null;
183
+ message('Saving…', 'saving');
184
+ if (operation.kind === 'edit' && selected === operation.id) detailMessage('Saving your changes…');
185
+ render();
186
+ setTimeout(() => {
187
+ if (token !== epoch) return;
188
+ let updated = clone(tasks);
189
+ if (operation.kind === 'add') updated.unshift(operation.task);
190
+ if (operation.kind === 'complete') updated = updated.map(t => t.id === operation.id ? {...t, completed:operation.completed} : t);
191
+ if (operation.kind === 'edit') updated = updated.map(t => t.id === operation.id ? {...t,...operation.fields} : t);
192
+ try {
193
+ if (shouldFail) throw new Error('simulated');
194
+ localStorage.setItem(STORE,JSON.stringify(updated));
195
+ tasks = updated; pending = null; failedOperation = null;
196
+ if (operation.kind === 'add') {
197
+ $('task-title').value = ''; $('task-title').removeAttribute('aria-invalid');
198
+ message('Task added to Today.', 'success');
199
+ } else if (operation.kind === 'complete') {
200
+ message(operation.completed ? 'Task completed. You can uncheck it below.' : 'Task marked incomplete.', 'success');
201
+ } else {
202
+ delete drafts[operation.id];
203
+ message('Changes saved.', 'success');
204
+ if (selected === operation.id) detailMessage('Changes saved.', 'success');
205
+ }
206
+ render();
207
+ if (operation.kind === 'add' && !$('detail').open) $('task-title').focus({preventScroll:true});
208
+ if (operation.kind === 'complete' && !$('detail').open) {
209
+ const target = [...document.querySelectorAll('[data-task-id]')].find(el => el.dataset.taskId === operation.id);
210
+ const focusTarget = operation.completed && !showCompleted ? $('completed-toggle') : target?.querySelector('.check');
211
+ (focusTarget || $('task-title')).focus({preventScroll:true});
212
+ }
213
+ } catch (_) {
214
+ pending = null; failedOperation = operation;
215
+ message(operation.kind === 'add' ? 'Task wasn’t saved. Your title is kept. Try again.' : 'Changes weren’t saved. Try again.', 'error', operation.kind !== 'add');
216
+ if (operation.kind === 'edit' && selected === operation.id) detailMessage('Changes weren’t saved. Your edits are kept. Choose Save changes to retry.','error');
217
+ render();
218
+ }
219
+ }, delay);
220
+ }
221
+ $('capture').addEventListener('submit', event => {
222
+ event.preventDefault(); if (pending || loading) return;
223
+ const title = $('task-title').value.trim();
224
+ if (!title) { message('Task title: enter something you need to do.','error'); $('task-title').setAttribute('aria-invalid','true'); $('task-title').focus(); return; }
225
+ $('task-title').removeAttribute('aria-invalid');
226
+ save({kind:'add',task:{id:`new-${Date.now()}-${++sequence}`,title,notes:'',dueDate:TODAY,completed:false}});
227
+ });
228
+ $('task-title').addEventListener('input', () => {
229
+ $('task-title').removeAttribute('aria-invalid');
230
+ if (failedOperation?.kind === 'add') { failedOperation = null; $('add-task').textContent='Add'; }
231
+ });
232
+ $('retry').addEventListener('click',() => { if (failedOperation) save(failedOperation); });
233
+ $('empty-add').addEventListener('click',() => $('task-title').focus({preventScroll:true}));
234
+ $('completed-toggle').addEventListener('click',() => { showCompleted = !showCompleted; render(); $('completed-toggle').focus({preventScroll:true}); });
235
+ document.querySelectorAll('[data-view]').forEach(button => button.addEventListener('click',() => {view = button.dataset.view; render(); window.scrollTo(0,0);}));
236
+ function openDetail(id, source) {
237
+ const task = tasks.find(t => t.id === id); if (!task) return;
238
+ selected = id; opener = source; sourceScroll = window.scrollY;
239
+ const values = drafts[id] || task;
240
+ $('detail-title').value = values.title; $('detail-notes').value = values.notes; $('detail-date').value = values.dueDate;
241
+ $('detail-title').removeAttribute('aria-invalid');
242
+ detailMessage(drafts[id] ? 'Your unsaved edits are here.' : task.completed ? 'Completed. You can still update the details.' : 'Make a little space for the details.');
243
+ $('detail').showModal(); document.body.style.overflow='hidden';
244
+ $('close-detail').focus({preventScroll:true}); render();
245
+ }
246
+ function preserveDraft() {
247
+ if (!selected) return;
248
+ const task=tasks.find(t => t.id === selected);
249
+ const values={title:$('detail-title').value, notes:$('detail-notes').value, dueDate:$('detail-date').value};
250
+ if (task && (values.title!==task.title || values.notes!==task.notes || values.dueDate!==task.dueDate)) drafts[selected]=values;
251
+ else delete drafts[selected];
252
+ }
253
+ function closeDetail() {
254
+ preserveDraft(); const returnId=selected;
255
+ $('detail').close(); document.body.style.overflow=''; selected=null;
256
+ window.scrollTo(0,sourceScroll);
257
+ const target = opener?.isConnected ? opener : [...document.querySelectorAll('[data-open-id]')].find(el => el.dataset.openId===returnId);
258
+ (target || $('task-title')).focus({preventScroll:true});
259
+ }
260
+ $('close-detail').addEventListener('click',closeDetail); $('detail-cancel').addEventListener('click',closeDetail);
261
+ $('detail').addEventListener('cancel', event => {event.preventDefault(); closeDetail();});
262
+ $('detail').addEventListener('click', event => { if(event.target === $('detail')) {const r=$('detail').getBoundingClientRect(); if(event.clientX<r.left || event.clientX>r.right || event.clientY<r.top || event.clientY>r.bottom) closeDetail();} });
263
+ $('detail-form').addEventListener('input',preserveDraft);
264
+ $('detail-form').addEventListener('submit', event => {
265
+ event.preventDefault(); if(pending) return;
266
+ const title=$('detail-title').value.trim();
267
+ if(!title) {detailMessage('Task title: enter a name before saving.','error'); $('detail-title').setAttribute('aria-invalid','true'); $('detail-title').focus(); return;}
268
+ $('detail-title').removeAttribute('aria-invalid');
269
+ preserveDraft();
270
+ save({kind:'edit',id:selected,fields:{title,notes:$('detail-notes').value,dueDate:$('detail-date').value}});
271
+ });
272
+ window.__benchmark = {
273
+ reset(mode) {
274
+ if (!['seed','empty'].includes(mode)) throw new Error('Use seed or empty');
275
+ epoch++; pending=null; failedOperation=null; failNext=false; delay=500; sequence=0;
276
+ tasks=mode==='seed'?clone(SEED):[]; loading=false; view='today'; showCompleted=true; drafts={};
277
+ if($('detail').open) $('detail').close(); selected=null; opener=null; document.body.style.overflow='';
278
+ $('task-title').value=''; $('task-title').removeAttribute('aria-invalid');
279
+ try {localStorage.setItem(STORE,JSON.stringify(tasks));} catch (_) {}
280
+ message('Tasks stay on this device.'); render(); window.scrollTo(0,0);
281
+ return this.getState();
282
+ },
283
+ setSaveDelay(milliseconds) { delay=Math.max(0,Number(milliseconds)||0); },
284
+ failNextSave() { failNext=true; },
285
+ getState() { return clone({tasks,view,loading,selected,status,pending,failedOperation,saveDelay:delay,failNextSave:failNext,captureDraft:$('task-title').value,detailDrafts:drafts,showCompleted}); }
286
+ };
287
+ render();
288
+ const initialEpoch=epoch;
289
+ setTimeout(() => { if(initialEpoch===epoch) {loading=false;render();} },350);