codemble 0.6.3__tar.gz → 0.7.0__tar.gz

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 (259) hide show
  1. {codemble-0.6.3 → codemble-0.7.0}/.gitignore +1 -0
  2. {codemble-0.6.3 → codemble-0.7.0}/CHANGELOG.md +122 -0
  3. {codemble-0.6.3 → codemble-0.7.0}/CLAUDE.md +70 -4
  4. {codemble-0.6.3 → codemble-0.7.0}/PKG-INFO +31 -14
  5. {codemble-0.6.3 → codemble-0.7.0}/README.md +30 -13
  6. {codemble-0.6.3 → codemble-0.7.0}/codemble/__init__.py +1 -1
  7. {codemble-0.6.3 → codemble-0.7.0}/codemble/checks/service.py +14 -8
  8. {codemble-0.6.3 → codemble-0.7.0}/codemble/lens/python.py +6 -1
  9. {codemble-0.6.3 → codemble-0.7.0}/codemble/progress/store.py +44 -7
  10. {codemble-0.6.3 → codemble-0.7.0}/codemble/server/project_selection.py +16 -1
  11. codemble-0.6.3/codemble/web_dist/assets/index-CnZFAhwF.js → codemble-0.7.0/codemble/web_dist/assets/index-CMsEPFpK.js +1 -1
  12. codemble-0.7.0/codemble/web_dist/assets/index-CU2GP4jq.css +1 -0
  13. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/index.html +2 -2
  14. codemble-0.7.0/docs/releases/v0.6.4.md +89 -0
  15. codemble-0.7.0/docs/releases/v0.7.0.md +64 -0
  16. {codemble-0.6.3 → codemble-0.7.0}/docs-site/package.json +1 -1
  17. codemble-0.7.0/docs-site/public/shots/easy-mode.png +0 -0
  18. codemble-0.7.0/docs-site/public/shots/galaxy-lit.png +0 -0
  19. codemble-0.7.0/docs-site/public/shots/galaxy.png +0 -0
  20. codemble-0.7.0/docs-site/public/shots/map-architecture.png +0 -0
  21. codemble-0.7.0/docs-site/public/shots/map-workflow.png +0 -0
  22. codemble-0.7.0/docs-site/public/shots/study-panel.png +0 -0
  23. codemble-0.7.0/docs-site/public/shots/system.png +0 -0
  24. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/checks-and-lighting.md +13 -6
  25. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/quickstart.md +15 -0
  26. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/study-panel.md +16 -7
  27. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/the-galaxy.md +53 -17
  28. {codemble-0.6.3 → codemble-0.7.0}/pyproject.toml +1 -1
  29. {codemble-0.6.3 → codemble-0.7.0}/tests/test_checks.py +29 -0
  30. {codemble-0.6.3 → codemble-0.7.0}/tests/test_progress.py +55 -0
  31. {codemble-0.6.3 → codemble-0.7.0}/tests/test_project_selection.py +34 -0
  32. {codemble-0.6.3 → codemble-0.7.0}/web/package-lock.json +2 -2
  33. {codemble-0.6.3 → codemble-0.7.0}/web/package.json +2 -2
  34. codemble-0.7.0/web/scripts/check_galaxy_effects.mjs +89 -0
  35. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/check_graph_data.mjs +126 -2
  36. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/check_learner_projection.mjs +103 -1
  37. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/check_learner_session.mjs +2 -2
  38. codemble-0.7.0/web/scripts/check_map_viewport.mjs +84 -0
  39. {codemble-0.6.3 → codemble-0.7.0}/web/src/App.jsx +342 -71
  40. {codemble-0.6.3 → codemble-0.7.0}/web/src/GalaxyCanvas.jsx +25 -2
  41. {codemble-0.6.3 → codemble-0.7.0}/web/src/MapView.jsx +139 -12
  42. {codemble-0.6.3 → codemble-0.7.0}/web/src/StudyPanel.jsx +53 -5
  43. {codemble-0.6.3 → codemble-0.7.0}/web/src/galaxyEffects.js +8 -4
  44. {codemble-0.6.3 → codemble-0.7.0}/web/src/graphData.js +110 -8
  45. {codemble-0.6.3 → codemble-0.7.0}/web/src/learnerProjection.js +55 -9
  46. {codemble-0.6.3 → codemble-0.7.0}/web/src/learnerSession.js +14 -0
  47. codemble-0.7.0/web/src/mapViewport.js +86 -0
  48. {codemble-0.6.3 → codemble-0.7.0}/web/src/styles.css +205 -33
  49. {codemble-0.6.3 → codemble-0.7.0}/web/src/tokens.css +27 -0
  50. codemble-0.6.3/codemble/web_dist/assets/index-CDRcoar-.css +0 -1
  51. codemble-0.6.3/docs-site/public/shots/easy-mode.png +0 -0
  52. codemble-0.6.3/docs-site/public/shots/galaxy-lit.png +0 -0
  53. codemble-0.6.3/docs-site/public/shots/galaxy.png +0 -0
  54. codemble-0.6.3/docs-site/public/shots/map-architecture.png +0 -0
  55. codemble-0.6.3/docs-site/public/shots/map-workflow.png +0 -0
  56. codemble-0.6.3/docs-site/public/shots/study-panel.png +0 -0
  57. codemble-0.6.3/docs-site/public/shots/system.png +0 -0
  58. codemble-0.6.3/web/scripts/check_map_viewport.mjs +0 -38
  59. codemble-0.6.3/web/src/mapViewport.js +0 -45
  60. {codemble-0.6.3 → codemble-0.7.0}/.env.example +0 -0
  61. {codemble-0.6.3 → codemble-0.7.0}/.gitattributes +0 -0
  62. {codemble-0.6.3 → codemble-0.7.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  63. {codemble-0.6.3 → codemble-0.7.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  64. {codemble-0.6.3 → codemble-0.7.0}/.github/ISSUE_TEMPLATE/early_tester.yml +0 -0
  65. {codemble-0.6.3 → codemble-0.7.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  66. {codemble-0.6.3 → codemble-0.7.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  67. {codemble-0.6.3 → codemble-0.7.0}/.github/dependabot.yml +0 -0
  68. {codemble-0.6.3 → codemble-0.7.0}/.github/workflows/ci.yml +0 -0
  69. {codemble-0.6.3 → codemble-0.7.0}/.github/workflows/pages.yml +0 -0
  70. {codemble-0.6.3 → codemble-0.7.0}/.github/workflows/publish-pypi.yml +0 -0
  71. {codemble-0.6.3 → codemble-0.7.0}/AGENTS.md +0 -0
  72. {codemble-0.6.3 → codemble-0.7.0}/CODE_OF_CONDUCT.md +0 -0
  73. {codemble-0.6.3 → codemble-0.7.0}/CONTEXT.md +0 -0
  74. {codemble-0.6.3 → codemble-0.7.0}/CONTRIBUTING.md +0 -0
  75. {codemble-0.6.3 → codemble-0.7.0}/LICENSE +0 -0
  76. {codemble-0.6.3 → codemble-0.7.0}/NOTICE +0 -0
  77. {codemble-0.6.3 → codemble-0.7.0}/SECURITY.md +0 -0
  78. {codemble-0.6.3 → codemble-0.7.0}/TESTING.md +0 -0
  79. {codemble-0.6.3 → codemble-0.7.0}/assets/demo.gif +0 -0
  80. {codemble-0.6.3 → codemble-0.7.0}/codemble/adapters/__init__.py +0 -0
  81. {codemble-0.6.3 → codemble-0.7.0}/codemble/adapters/base.py +0 -0
  82. {codemble-0.6.3 → codemble-0.7.0}/codemble/adapters/discovery.py +0 -0
  83. {codemble-0.6.3 → codemble-0.7.0}/codemble/adapters/parse_progress.py +0 -0
  84. {codemble-0.6.3 → codemble-0.7.0}/codemble/adapters/project.py +0 -0
  85. {codemble-0.6.3 → codemble-0.7.0}/codemble/adapters/python_ast.py +0 -0
  86. {codemble-0.6.3 → codemble-0.7.0}/codemble/adapters/typescript_tree_sitter.py +0 -0
  87. {codemble-0.6.3 → codemble-0.7.0}/codemble/checks/__init__.py +0 -0
  88. {codemble-0.6.3 → codemble-0.7.0}/codemble/cli.py +0 -0
  89. {codemble-0.6.3 → codemble-0.7.0}/codemble/graph/__init__.py +0 -0
  90. {codemble-0.6.3 → codemble-0.7.0}/codemble/graph/finalize.py +0 -0
  91. {codemble-0.6.3 → codemble-0.7.0}/codemble/graph/layout.py +0 -0
  92. {codemble-0.6.3 → codemble-0.7.0}/codemble/graph/mapview.py +0 -0
  93. {codemble-0.6.3 → codemble-0.7.0}/codemble/lens/__init__.py +0 -0
  94. {codemble-0.6.3 → codemble-0.7.0}/codemble/lens/javascript_typescript.py +0 -0
  95. {codemble-0.6.3 → codemble-0.7.0}/codemble/llm/__init__.py +0 -0
  96. {codemble-0.6.3 → codemble-0.7.0}/codemble/llm/local_status.py +0 -0
  97. {codemble-0.6.3 → codemble-0.7.0}/codemble/llm/providers.py +0 -0
  98. {codemble-0.6.3 → codemble-0.7.0}/codemble/llm/structural.py +0 -0
  99. {codemble-0.6.3 → codemble-0.7.0}/codemble/llm/study.py +0 -0
  100. {codemble-0.6.3 → codemble-0.7.0}/codemble/paths.py +0 -0
  101. {codemble-0.6.3 → codemble-0.7.0}/codemble/progress/__init__.py +0 -0
  102. {codemble-0.6.3 → codemble-0.7.0}/codemble/server/__init__.py +0 -0
  103. {codemble-0.6.3 → codemble-0.7.0}/codemble/server/app.py +0 -0
  104. {codemble-0.6.3 → codemble-0.7.0}/codemble/server/parse_job.py +0 -0
  105. {codemble-0.6.3 → codemble-0.7.0}/codemble/server/project_activation.py +0 -0
  106. {codemble-0.6.3 → codemble-0.7.0}/codemble/server/runtime.py +0 -0
  107. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  108. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  109. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  110. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  111. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/shippori-mincho-latin-500-normal-C-QwvIb3.woff +0 -0
  112. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/shippori-mincho-latin-500-normal-XI1O8euf.woff2 +0 -0
  113. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/shippori-mincho-latin-700-normal-CkoCYOiI.woff +0 -0
  114. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/shippori-mincho-latin-700-normal-DHcmzUO5.woff2 +0 -0
  115. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/zen-kaku-gothic-new-latin-400-normal-BEdayliK.woff2 +0 -0
  116. {codemble-0.6.3 → codemble-0.7.0}/codemble/web_dist/assets/zen-kaku-gothic-new-latin-400-normal-CPSmNJAU.woff +0 -0
  117. {codemble-0.6.3 → codemble-0.7.0}/docs/adr/README.md +0 -0
  118. {codemble-0.6.3 → codemble-0.7.0}/docs/plans/2026-07-19-audience-modes-and-local-narration-design.md +0 -0
  119. {codemble-0.6.3 → codemble-0.7.0}/docs/plans/2026-07-19-audience-modes-backend-plan.md +0 -0
  120. {codemble-0.6.3 → codemble-0.7.0}/docs/plans/2026-07-19-audience-modes-frontend-plan.md +0 -0
  121. {codemble-0.6.3 → codemble-0.7.0}/docs/plans/2026-07-19-install-ux-folder-picker-design.md +0 -0
  122. {codemble-0.6.3 → codemble-0.7.0}/docs/plans/2026-07-19-install-ux-folder-picker-plan.md +0 -0
  123. {codemble-0.6.3 → codemble-0.7.0}/docs/plans/2026-07-20-oss-inspired-map-and-constellations.md +0 -0
  124. {codemble-0.6.3 → codemble-0.7.0}/docs/plans/README.md +0 -0
  125. {codemble-0.6.3 → codemble-0.7.0}/docs/plans/phase-1.md +0 -0
  126. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/checklist.md +0 -0
  127. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.1.0.md +0 -0
  128. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.2.0.md +0 -0
  129. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.4.0.md +0 -0
  130. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.5.0.md +0 -0
  131. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.5.1.md +0 -0
  132. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.5.2.md +0 -0
  133. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.5.3.md +0 -0
  134. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.6.1.md +0 -0
  135. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.6.2.md +0 -0
  136. {codemble-0.6.3 → codemble-0.7.0}/docs/releases/v0.6.3.md +0 -0
  137. {codemble-0.6.3 → codemble-0.7.0}/docs/research/2026-07-20-opensource-graph-architecture-inspiration.md +0 -0
  138. {codemble-0.6.3 → codemble-0.7.0}/docs/research/README.md +0 -0
  139. {codemble-0.6.3 → codemble-0.7.0}/docs/superpowers/plans/2026-07-19-galaxy-ux-phase-a.md +0 -0
  140. {codemble-0.6.3 → codemble-0.7.0}/docs/superpowers/plans/2026-07-19-galaxy-ux-phase-b.md +0 -0
  141. {codemble-0.6.3 → codemble-0.7.0}/docs/superpowers/plans/2026-07-19-galaxy-ux-phase-c.md +0 -0
  142. {codemble-0.6.3 → codemble-0.7.0}/docs/superpowers/plans/2026-07-19-galaxy-ux-shared-contract.md +0 -0
  143. {codemble-0.6.3 → codemble-0.7.0}/docs/superpowers/specs/2026-07-19-galaxy-ux-overhaul-design.md +0 -0
  144. {codemble-0.6.3 → codemble-0.7.0}/docs/superpowers/specs/2026-07-21-navigation-design-clarity-design.md +0 -0
  145. {codemble-0.6.3 → codemble-0.7.0}/docs-site/.gitignore +0 -0
  146. {codemble-0.6.3 → codemble-0.7.0}/docs-site/astro.config.mjs +0 -0
  147. {codemble-0.6.3 → codemble-0.7.0}/docs-site/design.md +0 -0
  148. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/favicon-16.png +0 -0
  149. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/favicon-32.png +0 -0
  150. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/icon-180.png +0 -0
  151. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/icon-192.png +0 -0
  152. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/icon-512.png +0 -0
  153. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/icon.svg +0 -0
  154. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/icons/asterism.svg +0 -0
  155. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/icons/install.svg +0 -0
  156. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/mark-animated.svg +0 -0
  157. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/mark.svg +0 -0
  158. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/plates/hero-chart.svg +0 -0
  159. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/plates/hero-field.svg +0 -0
  160. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/plates/hero-gold.svg +0 -0
  161. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/plates/kasumi-rule.svg +0 -0
  162. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/plates/plate-galaxy.svg +0 -0
  163. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/plates/plate-study.svg +0 -0
  164. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/plates/plate-system.svg +0 -0
  165. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/brand/plates/seal.svg +0 -0
  166. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/favicon.svg +0 -0
  167. {codemble-0.6.3 → codemble-0.7.0}/docs-site/public/shots/loading.png +0 -0
  168. {codemble-0.6.3 → codemble-0.7.0}/docs-site/scripts/build-plates.mjs +0 -0
  169. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/assets/codemble-mark-dark.svg +0 -0
  170. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/assets/codemble-mark-light.svg +0 -0
  171. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/components/Search.astro +0 -0
  172. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/components/Tatebanko.astro +0 -0
  173. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/architecture.md +0 -0
  174. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/build-from-source.md +0 -0
  175. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/contributing.md +0 -0
  176. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/correctness.md +0 -0
  177. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/early-testing.md +0 -0
  178. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/installation.md +0 -0
  179. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/introduction.md +0 -0
  180. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m1-parser.md +0 -0
  181. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m10-polyglot-release.md +0 -0
  182. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m12-galaxy-look.md +0 -0
  183. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m13-scale.md +0 -0
  184. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m2-galaxy.md +0 -0
  185. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m3-study.md +0 -0
  186. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m4-lens.md +0 -0
  187. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m5-checks.md +0 -0
  188. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m6-release.md +0 -0
  189. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m8-typescript.md +0 -0
  190. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/progress/m9-typescript-lens.md +0 -0
  191. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/roadmap.md +0 -0
  192. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content/docs/star-chart.md +0 -0
  193. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/content.config.ts +0 -0
  194. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/pages/index.astro +0 -0
  195. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/styles/custom.css +0 -0
  196. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/styles/landing.css +0 -0
  197. {codemble-0.6.3 → codemble-0.7.0}/docs-site/src/styles/tokens.css +0 -0
  198. {codemble-0.6.3 → codemble-0.7.0}/scripts/dev.sh +0 -0
  199. {codemble-0.6.3 → codemble-0.7.0}/scripts/record_demo.sh +0 -0
  200. {codemble-0.6.3 → codemble-0.7.0}/tests/conftest.py +0 -0
  201. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/check_suites.json +0 -0
  202. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/concepts_sample.py +0 -0
  203. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/impact/alpha.py +0 -0
  204. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/impact/beta.py +0 -0
  205. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/impact/gamma.py +0 -0
  206. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/impact/helpers.py +0 -0
  207. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/impact/noisy.py +0 -0
  208. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/polyglot/python_worker.py +0 -0
  209. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/polyglot/src/broken.ts +0 -0
  210. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/polyglot/src/legacy.js +0 -0
  211. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/polyglot/src/local.js +0 -0
  212. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/polyglot/src/main.ts +0 -0
  213. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/polyglot/src/reexport.ts +0 -0
  214. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/polyglot/src/util.ts +0 -0
  215. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/polyglot/src/widget.tsx +0 -0
  216. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/repeated_calls.py +0 -0
  217. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/.gitignore +0 -0
  218. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/ambiguous.py +0 -0
  219. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/api.py +0 -0
  220. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/app.py +0 -0
  221. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/broken.py +0 -0
  222. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/cli.py +0 -0
  223. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/pkg/__init__.py +0 -0
  224. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/pkg/helpers.py +0 -0
  225. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/pkg/service.py +0 -0
  226. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/pkg/util.py +0 -0
  227. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/runner/__main__.py +0 -0
  228. {codemble-0.6.3 → codemble-0.7.0}/tests/fixtures/sampleproj/shared.py +0 -0
  229. {codemble-0.6.3 → codemble-0.7.0}/tests/test_dependency_compatibility.py +0 -0
  230. {codemble-0.6.3 → codemble-0.7.0}/tests/test_graph_finalization.py +0 -0
  231. {codemble-0.6.3 → codemble-0.7.0}/tests/test_mapview.py +0 -0
  232. {codemble-0.6.3 → codemble-0.7.0}/tests/test_parse_job.py +0 -0
  233. {codemble-0.6.3 → codemble-0.7.0}/tests/test_parse_progress.py +0 -0
  234. {codemble-0.6.3 → codemble-0.7.0}/tests/test_project_activation.py +0 -0
  235. {codemble-0.6.3 → codemble-0.7.0}/tests/test_project_parser.py +0 -0
  236. {codemble-0.6.3 → codemble-0.7.0}/tests/test_providers.py +0 -0
  237. {codemble-0.6.3 → codemble-0.7.0}/tests/test_python_ast.py +0 -0
  238. {codemble-0.6.3 → codemble-0.7.0}/tests/test_server.py +0 -0
  239. {codemble-0.6.3 → codemble-0.7.0}/tests/test_smoke.py +0 -0
  240. {codemble-0.6.3 → codemble-0.7.0}/tests/test_structural.py +0 -0
  241. {codemble-0.6.3 → codemble-0.7.0}/tests/test_study.py +0 -0
  242. {codemble-0.6.3 → codemble-0.7.0}/tests/test_typescript_tree_sitter.py +0 -0
  243. {codemble-0.6.3 → codemble-0.7.0}/web/README.md +0 -0
  244. {codemble-0.6.3 → codemble-0.7.0}/web/index.html +0 -0
  245. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/benchmark_learner_projection.mjs +0 -0
  246. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/check_focus_handoffs.mjs +0 -0
  247. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/check_mode_gate_portal.mjs +0 -0
  248. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/check_name_atlas.mjs +0 -0
  249. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/check_orbit_pointer_guard.mjs +0 -0
  250. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/check_project_mapping.mjs +0 -0
  251. {codemble-0.6.3 → codemble-0.7.0}/web/scripts/record_demo.mjs +0 -0
  252. {codemble-0.6.3 → codemble-0.7.0}/web/src/GuidanceLayer.jsx +0 -0
  253. {codemble-0.6.3 → codemble-0.7.0}/web/src/ModeControl.jsx +0 -0
  254. {codemble-0.6.3 → codemble-0.7.0}/web/src/galaxyMaterials.js +0 -0
  255. {codemble-0.6.3 → codemble-0.7.0}/web/src/main.jsx +0 -0
  256. {codemble-0.6.3 → codemble-0.7.0}/web/src/nameAtlas.js +0 -0
  257. {codemble-0.6.3 → codemble-0.7.0}/web/src/orbitPointerGuard.js +0 -0
  258. {codemble-0.6.3 → codemble-0.7.0}/web/src/projectMapping.js +0 -0
  259. {codemble-0.6.3 → codemble-0.7.0}/web/vite.config.js +0 -0
@@ -35,3 +35,4 @@ graphify-out/
35
35
  # Subagent-driven-development scratch coordination (not product truth)
36
36
  .superpowers/
37
37
  .remember
38
+ .playwright-mcp/
@@ -5,6 +5,128 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) · Versioning:
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.7.0] - 2026-07-22
9
+
10
+ ### Added
11
+ - **Constellations you can tell apart.** Every parser-proven import community
12
+ now wears one of eight traditional Japanese colour families (seiji, fuji,
13
+ koke, asagi, toki, umenezumi, wakatake, kikyō), assigned deterministically
14
+ from the community id — same code, same sky, same colours. Galaxy stars keep
15
+ centrality as lightness inside the family hue, planets inherit their
16
+ system's family, and Architecture boxes tint toward it. Every hue is
17
+ lightness-capped beneath the unlit ceiling and the amber band is excluded
18
+ from the wheel, so a lit star stays the brightest object in the sky and
19
+ nothing unproven can read as understood. The Key gains a colour-family row.
20
+ - **A counted shelf for unreachable modules.** On the Architecture map, modules
21
+ with no import route from Home fold away behind their exact count with a
22
+ **Show them** control (auto-folded above eight). On this repository that
23
+ turns a 1:3.2-tall drawing dominated by 80 test fixtures into a readable
24
+ connected core — with nothing hidden from the count and every module still
25
+ one click away.
26
+ - **Class rings.** A structure the parser knows is a class wears a thin ring in
27
+ the system view — parser fact, not decoration.
28
+
29
+ ### Fixed
30
+ - **Connections are visible.** Routes on both layers used to borrow the border
31
+ hairline at ~1.6:1 contrast — and the galaxy multiplied it to 32% opacity —
32
+ so the relationships the app teaches were its least visible marks. Both
33
+ layers now draw a dedicated route ink (4.0:1), arrowheads included, and a
34
+ *possible* relationship stays deliberately the more visible claim, dashed on
35
+ the map as before.
36
+ - **The map's language stripe actually renders.** It set its colour through an
37
+ SVG presentation attribute, where `var()` is invalid, and silently fell back
38
+ to the box navy — the Key advertised Python/JS/TS colours the map never
39
+ drew. The stripe now paints through a style property.
40
+ - **The nebula dawn no longer corrupts the lit system's name plate.** The
41
+ animation snapshotted one scale axis and restored all three from it, so the
42
+ celebration squashed the plate into a blurry square until a level change
43
+ rebuilt it. It now restores the full vector — the one bold moment ends
44
+ crisp.
45
+ - **Escape steps back from anywhere on the Map.** The handler listened only
46
+ inside the stage, and the most common Easy path leaves focus on the page
47
+ body, so the documented recovery silently did nothing; the study exit also
48
+ said "Back to system" on the Diagram. Escape is now a window-level handler
49
+ (with dialog and typing guards) and the exit says "Back to the module".
50
+ - **A resize cannot strand you in empty space.** Restored map viewports are
51
+ replayed only while they still show your focus; shrinking a desktop window
52
+ to phone width used to keep the desktop scroll and show empty layer bands.
53
+ Both the restore path and live resizes now re-centre on the parser-backed
54
+ target.
55
+ - **Fit lands on something readable.** On tall drawings a true fit reached 7% —
56
+ a thumbnail with no names — so Fit now fits the width and lets the height
57
+ scroll when the whole shape would be unreadable, and keeps whole-shape fit
58
+ otherwise. The open Key also no longer covers the zoom controls, and the
59
+ region panel's actions no longer clip at desktop heights.
60
+ - **Easy mode speaks its own register end to end.** "parser rank 0" became
61
+ "candidate 1", the checks header reads "Quiz · answers come from your code,
62
+ not AI", the lit celebration explains what the source hash means instead of
63
+ naming it, study metadata reads "What it is / Length / Evidence", and the
64
+ chrome attributes fixture errors to their shared directory ("2 could not be
65
+ read · all under tests/"). Expert keeps every precise term.
66
+ - **Guidance stops sending beginners into tests first.** The nearest-unlit
67
+ ranking now charges test-scoped paths a bounded +1.5-hop penalty — a real
68
+ source module one hop farther wins the tie, an all-tests project is still
69
+ guided, and the displayed hop count stays the real one. On this repository
70
+ the second stop changed from `tests.test_python_ast` to
71
+ `codemble.adapters.project`.
72
+ - **The study panel's connection diagram names its dots.** Six anonymous dots
73
+ used to decorate the labelled list below; each now carries its structure's
74
+ own (tail-truncated) name.
75
+
76
+ ## [0.6.4] - 2026-07-21
77
+
78
+ ### Fixed
79
+ - **A missed check no longer hands back its own answer.** Getting a question
80
+ wrong printed the parser answer and its evidence, and the same question then
81
+ accepted that answer — so a region could light without understanding. A miss
82
+ now returns neither the answer nor the citations (an importer check's
83
+ evidence *is* its answer); both appear once the learner has proven it.
84
+ - **The Map can show you the code it is asking about.** Easy mode lands on the
85
+ Map, which offered checks but no way to read a module. Region focus now
86
+ carries **Read the source** beside **Prove understanding**, and Easy guidance
87
+ recommends reading before proving instead of sending the learner to another
88
+ layer. Escape steps back a level on the Map, as it always has in the Galaxy.
89
+ - **The checks panel is usable from the keyboard.** Opening it hands focus to
90
+ the panel instead of leaving it on the trigger behind ~114 tab stops, and
91
+ submitting keeps focus on the result rather than dropping it to the document.
92
+ - **Enter opens the structure the arrow keys selected.** At study level the
93
+ canvas announced a sibling while the panel kept showing the old one; Enter
94
+ was a no-op despite the view's own instructions.
95
+ - **Guidance is docked, and waits its turn.** The hint chip took its own strip
96
+ above the footer instead of floating over captions, name plates and its own
97
+ button, and it no longer appears during the audience, Home and coach steps —
98
+ where it used to recommend a target "because no import route reaches it from
99
+ Home" while no Home existed.
100
+ - **Compact Map controls no longer stack.** At 375 px the Key button covered
101
+ 40% of the "What runs first" tab and the zoom pill covered the top row of
102
+ boxes. Measured at 320 and 375: zero overlapping interactive rectangles.
103
+ - **The study panel stops contradicting itself.** Easy mode showed "Used by 0"
104
+ above a summary saying five other parts use the file; the call-edge stat is
105
+ now "Called by", leaving "use" to imports.
106
+ - **The audience question is asked once per learner, not once per project.**
107
+ A new project inherits the last answer; the header toggle still overrides any
108
+ single project.
109
+ - **Home calibration is navigable on real projects.** It is now a modal sized
110
+ to the window rather than a card capped to a short stage, states how many
111
+ candidates exist, groups them by their real top-level scope (so test fixtures
112
+ no longer sit unmarked beside your entrypoint), and keeps "Explore without
113
+ Home" on screen instead of thousands of pixels below the fold.
114
+ - **The star chart is reachable from anywhere and closes with Escape.** It kept
115
+ its header slot at every level instead of surrendering it to the level-return
116
+ button, and every exit now names the layer it returns to.
117
+ - **Galaxy plates are named by path tail**, the rule the Map's boxes already
118
+ use, so two different `__init__.py` modules no longer wear identical names.
119
+ - **Find opens on Home and the most-used modules** instead of a screen of
120
+ identical `__init__.py` rows.
121
+ - **Easy guidance prefers a substantive module** when several sit the same
122
+ number of import hops from Home, instead of the alphabetically-first
123
+ four-line package init.
124
+ - **The exception-handling lens note is true of `raise`,** not only of
125
+ `try`/`except`, since the parser files all three under one concept.
126
+ - **Counts of one read as one** ("1 structure", not "1 structures").
127
+ - **The picker opens beside your last project** rather than at your home
128
+ directory every time.
129
+
8
130
  ## [0.6.3] - 2026-07-21
9
131
 
10
132
  ### Fixed
@@ -167,9 +167,57 @@ Polish, then the coordinated launch (Show HN / X; lit-galaxy GIF as hero).
167
167
 
168
168
  ## Current State **[AGENT-MAINTAINED]**
169
169
 
170
- **Current milestone: Phase 1 tester evidence** · Last updated: 2026-07-21 ·
171
- Session note: v0.6.3 closes the four follow-up findings from the 2026-07-21
172
- user-flow audit. Easy guidance is now level-aware and never offers an enabled
170
+ **Current milestone: Phase 1 tester evidence** · Last updated: 2026-07-22 ·
171
+ Session note: v0.7.0 implements all fourteen findings of a fresh evidence-based
172
+ user-flow audit of the served v0.6.4 build (run as a first-run Easy learner on
173
+ this repository at 1280/375/320, with before/after screenshots) plus the
174
+ approved D1 design direction: parser-proven import communities now wear eight
175
+ deterministic traditional Japanese colour families (galaxy stars, planets, and
176
+ Architecture-box tints), lightness-capped beneath the unlit ceiling with the
177
+ amber band excluded so understanding stays the brightest claim in the sky.
178
+ Routes on both layers moved from the 1.6:1 border hairline to a dedicated
179
+ 4.0:1 route ink (possible relationships stay dashed and deliberately more
180
+ visible); the Architecture map folds modules with no route from Home into a
181
+ counted shelf behind a Show-them control; Fit fits width when whole-shape fit
182
+ would be unreadable; and Easy guidance charges test-scoped paths a bounded
183
+ +1.5-hop penalty so a learner's own code outranks its test suite at equal
184
+ distance. Mechanical fixes: the nebula dawn restores sprite scale as a vector
185
+ (it squashed the lit system's name plate square), the map's language stripe
186
+ paints via a style property (an SVG fill attribute cannot resolve var() and
187
+ silently rendered navy), Escape on the Map is a window-level handler that
188
+ works with focus on body, stale map viewports re-centre on the focus point on
189
+ restore and on live resizes, the open Key stacks below the zoom controls, the
190
+ region panel's actions no longer clip, study connection dots carry names, and
191
+ the Easy register replaces parser vocabulary end to end ("candidate 1",
192
+ "Quiz · answers come from your code, not AI", "What it is / Length /
193
+ Evidence", fixture errors attributed "all under tests/"). Parser, graph,
194
+ checks, progress, provider, and HTTP contracts are byte-unchanged; the suite
195
+ grew a nebula-dawn scale-restore check plus community-colour, viewport, and
196
+ guidance-penalty contract assertions (241 pytest, ruff clean, 12 frontend
197
+ checks, rebuilt web_dist). Full planet realism explicitly remains a Phase 3
198
+ decision under the game-art Non-Goal. The milestone does not advance: issue
199
+ #13 still requires human tester evidence. Previously: v0.6.4 closes all twenty findings of a fresh end-to-end user-flow
200
+ audit run against the served build on three real projects (Codemble, Golavo,
201
+ FolioOrb) at 1280/375/320 px with a keyboard pass. The headline fix is a
202
+ Correctness Contract one: a missed check printed the parser answer and its
203
+ evidence and then accepted that answer, so a region could light without
204
+ understanding; a miss now returns neither, and both appear only after the
205
+ learner proves it. The Easy default layer gained the reading path it never had
206
+ (**Read the source** on the Map, guidance that says read-before-prove, Escape
207
+ stepping back a level), the checks panel became keyboard-usable (focus handoff
208
+ on open, focus preserved across submits), Enter now opens the arrow-selected
209
+ structure at study level, and the guidance chip is docked into its own strip
210
+ and hidden until the first-run decisions finish. Home calibration is now a
211
+ viewport-sized modal that states its candidate count, groups candidates by
212
+ their real scope, and keeps its escape hatch on screen; the audience question
213
+ is asked once per learner instead of once per project; the star chart is
214
+ reachable from every level and closes with Escape; exits name the layer they
215
+ return to; galaxy plates and the module index use path tails; Find opens on
216
+ Home and the busiest modules; and compact Map controls no longer share touch
217
+ targets (zero overlapping interactive rectangles at 320 and 375). Parser,
218
+ graph, checks, progress, and provider contracts are unchanged except for the
219
+ deliberate withholding of answers on a failed submission. Previously, v0.6.3
220
+ closed the four follow-up findings from the earlier user-flow audit. Easy guidance is now level-aware and never offers an enabled
173
221
  no-op; compact Maps open at readable 100% around Home and preserve zoom/pan
174
222
  through data refreshes; Switch project confirms on the first compact-Menu click
175
223
  without leaking disclosure state across project or breakpoint changes; and Home
@@ -551,6 +599,15 @@ shows lower repeated-commit work without changing derived values.
551
599
  | 2026-07-21 | Easy guidance actions are derived from level, region, and layer, then executed by `LearnerSession`; the chip renders no button when the next step is already on screen | React must not guess a structure or own navigation truth, and an enabled action that commits the same state is a false promise. The nearest unlit region remains graph-derived; only the honest route to it changes with the learner's current context |
552
600
  | 2026-07-21 | Map zoom/pan is renderer-local state keyed by tab and Home, preserved through transient data remounts but cleared with the project lifecycle; compact Maps start at 100% centred on the parser-backed target | Auto-fitting made 56 px boxes as little as 8–18 px tall and re-ran after check-driven map refreshes. Fit is still a valid explicit overview, while session state stays reserved for graph and learning truth |
553
601
  | 2026-07-21 | Responsive disclosures and global surfaces own explicit focus handoffs; compact Menu closes on project exit and when crossing to the desktop rail | DOM focus and disclosure visibility are view concerns, but leaving focus on removed or hidden controls makes a successful navigation indistinguishable from a dead action to a keyboard or screen-reader user |
602
+ | 2026-07-21 | A wrong check submission returns no answer, no answer labels and no evidence; all three are returned only once the learner answers correctly | The response printed the parser answer on every miss and the same question then accepted it, so a region could light on an answer the app itself had just displayed — illumination stopped meaning understanding, the same failure class as the 2026-07-19 "every check needs a wrong option" fix. Evidence is withheld with the answer because an importer check cites exactly the files that *are* its answer |
603
+ | 2026-07-21 | The 2D Map gets a reading path: region focus offers **Read the source** beside the checks, Easy guidance recommends reading before proving, and Escape steps back a level there as it does in the Galaxy | Easy mode lands on the Map, where the only action was a quiz about code the layer could not show. The study panel is layer-neutral (`/api/node/:id/study`), so the Map only needed to select the module node the parser already produced — no new truth, and the audience that most needs to read first stops being sent to another layer to do it |
604
+ | 2026-07-21 | The audience answer is stored per learner as well as per project (`learner.json` beside progress); a fresh bind seeds from it and skips the gate, while the header toggle still overrides one project | The gate asks who the *learner* is, but the answer lived only under the project key, so every new project re-asked an expert whether they were new to coding. The file carries no `schema_version`, which is what keeps recents from reading it as a project |
605
+ | 2026-07-21 | Home calibration is a native modal sized to the viewport, grouped by the candidates' real top-level scope, with the candidate count stated and "Explore without Home" outside the scrolling list | It is the second step of the same required sequence as the audience gate and deserves the same shape. As a card capped to a share of the stage it showed one candidate of eleven with the escape hatch thousands of pixels below the fold, and a flat list put `tests/fixtures/...` beside the learner's entrypoint with nothing to tell them apart. Scope and rank are parser facts already in the payload; the leading group always opens so a project whose best candidate is rank 1 is never met by an all-collapsed list |
606
+ | 2026-07-21 | Galaxy name plates use the same path-tail rule as map schema 3's `short_label`; the shared module index and the command palette use it too, and the palette's unfiltered order is Home → lit → centrality | Basenames collide hard in a Python project — every package carries an `__init__.py` — so identical plates named different modules, which is precisely the wrong a learner cannot detect, and the palette opened on a screen of indistinguishable rows |
607
+ | 2026-07-22 | **Hue means import community.** Each parser-proven community takes one of eight traditional Japanese colour tokens (`--cm-com-0..7`) by `community id mod 8`; stars, planets and Architecture boxes all read the same arithmetic in `graphData.communityShade`. This amends the M2 encoding row: colour was "language", which is now the nebula/stripe channel only | Approved by UD. The sky had one hue for 109 systems, so nothing could be tracked without reading every plate — and the graph had proven communities since schema 5 that nothing rendered. Guardrails that keep the Correctness Contract intact: every token is lightness-tuned to `--cm-ink-2`'s luminance (0.389) so a lit star at 0.598 always wins, the kohaku band (~40°) is excluded so no community can read as "understood", a missing community id falls back to the old neutral ramp rather than borrowing a hue, and the mapping is pure arithmetic on graph truth so the same code always yields the same sky |
608
+ | 2026-07-22 | Routes get their own ink (`--cm-route`, 4.0:1) on both layers, and it sits deliberately BELOW `--cm-route-possible` (6.4:1) | Edges borrowed `--cm-hairline`, the ink of box borders and panel rules, measuring 1.57:1 on the canvas ground — the relationships the product exists to teach were its least visible marks, which is the literal complaint that opened the audit. Ordering the two inks this way keeps the 2026-07-19 rule that an unproven claim must be the more visible one |
609
+ | 2026-07-22 | Architecture-map modules with no import route from Home fold into a counted shelf behind an explicit control (auto-folded above 8), and Fit fits WIDTH when a whole-shape fit would land below 35% | On this repository 80 of 109 boxes are test fixtures and scripts, making the drawing 1:3.2 tall so the connected core fit at an unreadable 7%. Folding is view state, never truth: the note carries the exact count, **Show them** draws every one, and both surfaces still reach every module. Distinct from progressive reveal, which stays galaxy-only |
610
+ | 2026-07-22 | Easy guidance charges test-scoped paths a bounded +1.5-hop penalty; the displayed hop count stays the real one | A CLI's nearest neighbour is usually its own test suite, so pure hop-distance sent a brand-new learner from Home straight into `tests/`. The penalty is bounded so a non-test module one hop farther wins while a distant one does not, and an all-tests project is still guided. Both inputs stay parser truth (the BFS count and the recorded file path); only the ranking key is biased, never the reported fact |
554
611
 
555
612
  ## Non-Goals — do NOT build (point here when asked)
556
613
 
@@ -563,7 +620,11 @@ shows lower repeated-commit work without changing derived values.
563
620
  - ❌ Accounts, cloud hosting, multi-user; share link waits for Phase 3
564
621
  - ❌ Extra quest types before Phase 3
565
622
  - ❌ GitHub-URL ingestion in v1
566
- - ❌ Elaborate game art before the loop teaches well
623
+ - ❌ Elaborate game art before the loop teaches well — **still holds**: the
624
+ 2026-07-22 visual pass shipped only encodings that carry parser facts
625
+ (community hue, class rings). Procedural planet surfaces, atmospheres and
626
+ rotation ("almost real planets, like a game") remain OUT until Phase 1
627
+ tester evidence lands, and would need their own Decision Log entry
567
628
 
568
629
  ## Gotchas
569
630
 
@@ -591,6 +652,11 @@ shows lower repeated-commit work without changing derived values.
591
652
  - **Canvas colours must be plain values, never `color-mix()`** — WebGL receives
592
653
  a custom property's authored text, so a computed token renders black. Add new
593
654
  canvas tokens through `readPalette`, which resolves them.
655
+ - **`var()` never works in an SVG presentation attribute** — `fill="var(--x)"`
656
+ is invalid and falls back to the cascade *silently*, which is how the map's
657
+ language stripe rendered box-navy for a release while the legend advertised
658
+ three colours. Use `style={{ fill: … }}` (a CSS property) for any
659
+ token-driven SVG paint.
594
660
 
595
661
  ## Edge cases & limits
596
662
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codemble
3
- Version: 0.6.3
3
+ Version: 0.7.0
4
4
  Summary: A learning game that turns the code AI wrote for you into a galaxy you light up by understanding it.
5
5
  Project-URL: Homepage, https://udhawan97.github.io/Codemble/
6
6
  Project-URL: Repository, https://github.com/udhawan97/Codemble
@@ -66,7 +66,7 @@ Description-Content-Type: text/markdown
66
66
  </p>
67
67
 
68
68
  <p align="center">
69
- <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/galaxy.png" alt="Codemble at galaxy level: eighty dim star systems parsed from real source, with a legend, language focus buttons, and a notice that two files are unchartable because their parser reported a syntax error" width="960">
69
+ <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/galaxy.png" alt="Codemble at galaxy level: 109 star systems parsed from real source, 23 charted and named by file path, constellations wearing their import-community colour families in traditional Japanese hues around an amber lit Home, with language focus buttons, a Key disclosure, and a notice that two files could not be read all under tests/" width="960">
70
70
  </p>
71
71
 
72
72
  <p align="center"><sub>
@@ -148,7 +148,7 @@ of your own code becomes a sky you understand.
148
148
  ## What it looks like
149
149
 
150
150
  <p align="center">
151
- <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/system.png" alt="A single star system, codemble.server.app, showing its functions and classes in orbits with call edges and a keyboard focus reticle" width="900">
151
+ <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/system.png" alt="A single star system, codemble.server.app, its functions and classes as planets in the system's own colour family, in call-depth orbits with the call edges between them" width="900">
152
152
  </p>
153
153
 
154
154
  <p align="center"><sub>
@@ -156,7 +156,7 @@ of your own code becomes a sky you understand.
156
156
  </sub></p>
157
157
 
158
158
  <p align="center">
159
- <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/study-panel.png" alt="The study panel for create_app, showing kind, span, 36 callers, a structural summary marked no model needed, guidance for configuring a provider or a local Ollama, and a parser connections diagram with an inbound call citing a real file and line" width="900">
159
+ <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/study-panel.png" alt="The study panel for create_app, showing kind, span, 53 callers, parser-proven resolution, and a structural summary marked no model needed" width="900">
160
160
  </p>
161
161
 
162
162
  <p align="center"><sub>
@@ -188,9 +188,17 @@ computed in the graph layer and served as data.
188
188
  | **Map · Workflow** | The call tree from your entrypoint, depth by depth | Seeing what runs first |
189
189
 
190
190
  The Map is plain SVG, so it still works on a machine that cannot draw WebGL.
191
- On a compact screen it opens at readable 100% around Home or the selected
192
- target; **Fit** is an explicit whole-diagram overview. Zoom and pan survive Map
193
- refreshes and layer switches instead of snapping back after a passed check.
191
+ Click a box and it offers both halves of a step **Read the source** opens that
192
+ module's real source, lens notes and relationships without leaving the layer,
193
+ and **Prove understanding** starts its checks. Escape steps back a level, as in
194
+ the Galaxy. On a compact screen the Map opens at readable 100% around Home or
195
+ the selected target; **Fit** is an explicit whole-diagram overview. Zoom and pan
196
+ survive Map refreshes and layer switches instead of snapping back after a passed
197
+ check.
198
+
199
+ In Easy mode these surfaces carry plainer labels — the layer is **Diagram** and
200
+ the tabs are **How it fits together** and **What runs first**. Same views, same
201
+ evidence; only the wording follows the audience.
194
202
 
195
203
  ## Open a structure, read what the parser knows first
196
204
 
@@ -207,10 +215,14 @@ Sections other than the narration never involve a model at all.
207
215
  A header toggle changes how Codemble talks to you and how much it puts on
208
216
  screen: plain language, larger type, the Map by default, and a hint chip naming
209
217
  the nearest unlit region to Home — counted in import hops over the graph, not
210
- chosen by a model. The hint opens that system, switches from Map to Galaxy when
211
- its internal structures are the next step, then becomes an instruction rather
212
- than an enabled no-op. It never changes graph truth, coordinates, progress, or
213
- how a check is scored.
218
+ chosen by a model, and broken by parser-proven structure count when several sit
219
+ the same distance away. The hint opens that system, offers to read its source,
220
+ then becomes an instruction rather than an enabled no-op. It waits until the
221
+ first-run choices are done before it appears at all, and it never changes graph
222
+ truth, coordinates, progress, or how a check is scored.
223
+
224
+ Codemble asks which audience you are **once** — the question is about you, not
225
+ about the project — and each project still keeps its own mode.
214
226
 
215
227
  You can also switch project or change Home without leaving the app.
216
228
 
@@ -224,6 +236,7 @@ You can also switch project or change Home without leaving the app.
224
236
  | A route or edge | An import or call; approximate calls are labeled **possible** |
225
237
  | Size | Lines of code |
226
238
  | Brightness and glow | How many **distinct** structures call it |
239
+ | Colour family | Import community — modules that import each other share one of eight traditional Japanese hues |
227
240
  | Nebula tint | Language, at galaxy level |
228
241
  | Orbit ring | Call depth — the inner ring runs first |
229
242
  | Drifting particles | A call the parser proved; a possible call stays still |
@@ -231,9 +244,13 @@ You can also switch project or change Home without leaving the app.
231
244
 
232
245
  Understanding owns the top of the brightness range: the unlit ramp stops below
233
246
  the amber a lit star uses, so a busy module you have not proven can never
234
- outshine one you have. Pass a region's checks and that system plays a short
235
- amber "nebula dawn" after the light is already saved, so the animation marks
236
- a fact rather than delivering one.
247
+ outshine one you have every community hue is lightness-capped beneath it, and
248
+ the amber band is excluded from the community wheel entirely. Pass a region's
249
+ checks and that system plays a short amber "nebula dawn" — after the light is
250
+ already saved, so the animation marks a fact rather than delivering one. On the
251
+ flat Map, modules with no import route from Home fold into a counted shelf
252
+ (**Show them** draws every one), so test scaffolding never buries the connected
253
+ core it cannot reach.
237
254
 
238
255
  Python-only, JavaScript-only, TypeScript-only, and mixed projects share the same
239
256
  graph contract. Language focus changes only what you are looking at; it never
@@ -34,7 +34,7 @@
34
34
  </p>
35
35
 
36
36
  <p align="center">
37
- <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/galaxy.png" alt="Codemble at galaxy level: eighty dim star systems parsed from real source, with a legend, language focus buttons, and a notice that two files are unchartable because their parser reported a syntax error" width="960">
37
+ <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/galaxy.png" alt="Codemble at galaxy level: 109 star systems parsed from real source, 23 charted and named by file path, constellations wearing their import-community colour families in traditional Japanese hues around an amber lit Home, with language focus buttons, a Key disclosure, and a notice that two files could not be read all under tests/" width="960">
38
38
  </p>
39
39
 
40
40
  <p align="center"><sub>
@@ -116,7 +116,7 @@ of your own code becomes a sky you understand.
116
116
  ## What it looks like
117
117
 
118
118
  <p align="center">
119
- <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/system.png" alt="A single star system, codemble.server.app, showing its functions and classes in orbits with call edges and a keyboard focus reticle" width="900">
119
+ <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/system.png" alt="A single star system, codemble.server.app, its functions and classes as planets in the system's own colour family, in call-depth orbits with the call edges between them" width="900">
120
120
  </p>
121
121
 
122
122
  <p align="center"><sub>
@@ -124,7 +124,7 @@ of your own code becomes a sky you understand.
124
124
  </sub></p>
125
125
 
126
126
  <p align="center">
127
- <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/study-panel.png" alt="The study panel for create_app, showing kind, span, 36 callers, a structural summary marked no model needed, guidance for configuring a provider or a local Ollama, and a parser connections diagram with an inbound call citing a real file and line" width="900">
127
+ <img src="https://github.com/udhawan97/Codemble/raw/main/docs-site/public/shots/study-panel.png" alt="The study panel for create_app, showing kind, span, 53 callers, parser-proven resolution, and a structural summary marked no model needed" width="900">
128
128
  </p>
129
129
 
130
130
  <p align="center"><sub>
@@ -156,9 +156,17 @@ computed in the graph layer and served as data.
156
156
  | **Map · Workflow** | The call tree from your entrypoint, depth by depth | Seeing what runs first |
157
157
 
158
158
  The Map is plain SVG, so it still works on a machine that cannot draw WebGL.
159
- On a compact screen it opens at readable 100% around Home or the selected
160
- target; **Fit** is an explicit whole-diagram overview. Zoom and pan survive Map
161
- refreshes and layer switches instead of snapping back after a passed check.
159
+ Click a box and it offers both halves of a step **Read the source** opens that
160
+ module's real source, lens notes and relationships without leaving the layer,
161
+ and **Prove understanding** starts its checks. Escape steps back a level, as in
162
+ the Galaxy. On a compact screen the Map opens at readable 100% around Home or
163
+ the selected target; **Fit** is an explicit whole-diagram overview. Zoom and pan
164
+ survive Map refreshes and layer switches instead of snapping back after a passed
165
+ check.
166
+
167
+ In Easy mode these surfaces carry plainer labels — the layer is **Diagram** and
168
+ the tabs are **How it fits together** and **What runs first**. Same views, same
169
+ evidence; only the wording follows the audience.
162
170
 
163
171
  ## Open a structure, read what the parser knows first
164
172
 
@@ -175,10 +183,14 @@ Sections other than the narration never involve a model at all.
175
183
  A header toggle changes how Codemble talks to you and how much it puts on
176
184
  screen: plain language, larger type, the Map by default, and a hint chip naming
177
185
  the nearest unlit region to Home — counted in import hops over the graph, not
178
- chosen by a model. The hint opens that system, switches from Map to Galaxy when
179
- its internal structures are the next step, then becomes an instruction rather
180
- than an enabled no-op. It never changes graph truth, coordinates, progress, or
181
- how a check is scored.
186
+ chosen by a model, and broken by parser-proven structure count when several sit
187
+ the same distance away. The hint opens that system, offers to read its source,
188
+ then becomes an instruction rather than an enabled no-op. It waits until the
189
+ first-run choices are done before it appears at all, and it never changes graph
190
+ truth, coordinates, progress, or how a check is scored.
191
+
192
+ Codemble asks which audience you are **once** — the question is about you, not
193
+ about the project — and each project still keeps its own mode.
182
194
 
183
195
  You can also switch project or change Home without leaving the app.
184
196
 
@@ -192,6 +204,7 @@ You can also switch project or change Home without leaving the app.
192
204
  | A route or edge | An import or call; approximate calls are labeled **possible** |
193
205
  | Size | Lines of code |
194
206
  | Brightness and glow | How many **distinct** structures call it |
207
+ | Colour family | Import community — modules that import each other share one of eight traditional Japanese hues |
195
208
  | Nebula tint | Language, at galaxy level |
196
209
  | Orbit ring | Call depth — the inner ring runs first |
197
210
  | Drifting particles | A call the parser proved; a possible call stays still |
@@ -199,9 +212,13 @@ You can also switch project or change Home without leaving the app.
199
212
 
200
213
  Understanding owns the top of the brightness range: the unlit ramp stops below
201
214
  the amber a lit star uses, so a busy module you have not proven can never
202
- outshine one you have. Pass a region's checks and that system plays a short
203
- amber "nebula dawn" after the light is already saved, so the animation marks
204
- a fact rather than delivering one.
215
+ outshine one you have every community hue is lightness-capped beneath it, and
216
+ the amber band is excluded from the community wheel entirely. Pass a region's
217
+ checks and that system plays a short amber "nebula dawn" — after the light is
218
+ already saved, so the animation marks a fact rather than delivering one. On the
219
+ flat Map, modules with no import route from Home fold into a counted shelf
220
+ (**Show them** draws every one), so test scaffolding never buries the connected
221
+ core it cannot reach.
205
222
 
206
223
  Python-only, JavaScript-only, TypeScript-only, and mixed projects share the same
207
224
  graph contract. Language focus changes only what you are looking at; it never
@@ -1,4 +1,4 @@
1
1
  """Codemble — a learning game that turns the code AI wrote for you into a galaxy
2
2
  you light up by understanding it. See CLAUDE.md for the agent brief and roadmap."""
3
3
 
4
- __version__ = "0.6.3"
4
+ __version__ = "0.7.0"
@@ -124,22 +124,28 @@ class CheckService:
124
124
  if complete:
125
125
  self._progress.mark_understood(region_id)
126
126
 
127
- answer_labels = [
128
- option.label for option in check.options if option.id in check.answer_ids
129
- ]
130
- return {
127
+ result: dict[str, object] = {
131
128
  "correct": correct,
132
129
  "check_id": check.id,
133
- "answer_ids": list(check.answer_ids),
134
- "answer_labels": answer_labels,
135
- "evidence": list(check.evidence),
136
130
  "message": (
137
131
  "Correct. That answer is fixed by the parser graph."
138
132
  if correct
139
- else "Not yet. Re-read the graph relationship and try again."
133
+ else "Not yet. Re-read the relationship in your own code and try again."
140
134
  ),
141
135
  "region_understood": complete,
142
136
  }
137
+ if not correct:
138
+ # A miss returns no answer and no citations. An importer check
139
+ # cites the very files that are its answer, so handing either back
140
+ # let the next submission replay what the screen had just shown --
141
+ # and a region lit that way proves nothing.
142
+ return result
143
+ result["answer_ids"] = list(check.answer_ids)
144
+ result["answer_labels"] = [
145
+ option.label for option in check.options if option.id in check.answer_ids
146
+ ]
147
+ result["evidence"] = list(check.evidence)
148
+ return result
143
149
 
144
150
  def _region_checks(self, region_id: str) -> tuple[Check, ...]:
145
151
  if region_id not in self._checks:
@@ -47,10 +47,15 @@ _PYTHON_NOTES = {
47
47
  "expert": "Python calls this specially named method through a language protocol such as length, comparison, or display.",
48
48
  },
49
49
  ),
50
+ # One concept id covers `try`, `try*` and `raise` (python_ast visits all
51
+ # three), so the copy has to be true of a line that *signals* a problem as
52
+ # well as one that catches it. The old easy note taught catching only, and
53
+ # anchored to `raise SystemExit(main())` it claimed roughly the opposite of
54
+ # what that line does.
50
55
  "exception-handling": (
51
56
  "Exception handling",
52
57
  {
53
- "easy": "This plans for something going wrong, so the program can react instead of crashing.",
58
+ "easy": "This treats failure as part of the plan: code like this either raises a problem for whoever called it, or catches one so the program can react instead of crashing.",
54
59
  "expert": "This construct makes failure part of explicit control flow by catching, grouping, or raising an exception.",
55
60
  },
56
61
  ),
@@ -12,6 +12,11 @@ from codemble.adapters.base import Graph
12
12
  from codemble.paths import data_dir
13
13
 
14
14
  _SCHEMA_VERSION = 1
15
+ _MODES = frozenset({"easy", "expert"})
16
+ # The audience answer is about the learner, not the project, so it is also kept
17
+ # once per data directory. Project payloads still win, which is what keeps the
18
+ # header toggle a genuine per-project override.
19
+ _LEARNER_FILE = "learner.json"
15
20
 
16
21
 
17
22
  class UnknownRegionError(KeyError):
@@ -26,6 +31,7 @@ class ProgressStore:
26
31
  self._root = root or data_dir() / "progress"
27
32
  project_key = hashlib.sha256(graph.project_root.encode()).hexdigest()[:20]
28
33
  self.path = self._root / f"{project_key}.json"
34
+ self._learner_path = self._root / _LEARNER_FILE
29
35
  self._signatures = _region_signatures(graph)
30
36
 
31
37
  def understood_regions(self) -> frozenset[str]:
@@ -72,24 +78,55 @@ class ProgressStore:
72
78
  def mode(self) -> str:
73
79
  """Return the learner's audience mode; this never affects progress."""
74
80
 
75
- payload = self._read()
76
- value = payload.get("mode")
77
- return value if value in {"easy", "expert"} else "easy"
81
+ value = self._read().get("mode")
82
+ if value in _MODES:
83
+ return value
84
+ return self._learner_mode() or "easy"
78
85
 
79
86
  def mode_chosen(self) -> bool:
80
- """Return whether the learner has explicitly chosen an audience mode."""
87
+ """Return whether this learner has answered the audience question.
81
88
 
82
- payload = self._read()
83
- return payload.get("mode") in {"easy", "expert"}
89
+ Per project first, then the learner-level answer. The gate asks who
90
+ the *learner* is, so re-asking it on every project would be asking a
91
+ question they have already answered; the header toggle still overrides
92
+ any single project.
93
+ """
94
+
95
+ return self._read().get("mode") in _MODES or self._learner_mode() is not None
84
96
 
85
97
  def set_mode(self, mode: str) -> None:
86
98
  """Persist the audience mode beside progress without touching signatures."""
87
99
 
88
- if mode not in {"easy", "expert"}:
100
+ if mode not in _MODES:
89
101
  raise ValueError("Mode must be 'easy' or 'expert'.")
90
102
  payload = self._read()
91
103
  payload["mode"] = mode
92
104
  self._write(payload)
105
+ self._write_learner_mode(mode)
106
+
107
+ def _learner_mode(self) -> str | None:
108
+ """Read the last audience answered on any project in this data dir."""
109
+
110
+ try:
111
+ payload = json.loads(self._learner_path.read_text(encoding="utf-8"))
112
+ except (OSError, json.JSONDecodeError, UnicodeDecodeError):
113
+ return None
114
+ if not isinstance(payload, dict):
115
+ return None
116
+ value = payload.get("mode")
117
+ return value if value in _MODES else None
118
+
119
+ def _write_learner_mode(self, mode: str) -> None:
120
+ self._root.mkdir(parents=True, exist_ok=True)
121
+ temporary = self._learner_path.with_suffix(f".{os.getpid()}.tmp")
122
+ try:
123
+ temporary.write_text(
124
+ json.dumps({"mode": mode}, indent=2, sort_keys=True) + "\n",
125
+ encoding="utf-8",
126
+ )
127
+ temporary.replace(self._learner_path)
128
+ finally:
129
+ temporary.unlink(missing_ok=True)
93
130
 
94
131
  def selected_entrypoint(self) -> str | None:
95
132
  """Return the learner's persisted Home choice, if one was stored.
@@ -69,7 +69,7 @@ class ProjectSelector:
69
69
  def browse(self, path: str | Path | None = None) -> FolderListing:
70
70
  """List non-hidden child directories for one allowed folder."""
71
71
 
72
- resolved = self.resolve(path if path is not None else self._root)
72
+ resolved = self.resolve(path if path is not None else self._default_start())
73
73
  if not resolved.is_dir():
74
74
  raise ProjectFolderMissing("That folder does not exist.")
75
75
  try:
@@ -97,6 +97,21 @@ class ProjectSelector:
97
97
  if self._is_inside_root(Path(str(entry["project_root"])).resolve())
98
98
  )
99
99
 
100
+ def _default_start(self) -> Path:
101
+ """Open browsing beside the newest remembered project, else at the root.
102
+
103
+ Projects tend to live as siblings, so starting at the browse root made
104
+ every switch re-walk the same folders. Derived from recents rather than
105
+ stored, so it cannot drift, and it stays inside the same jail because
106
+ ``recents`` already filtered by it.
107
+ """
108
+
109
+ for entry in self.recents():
110
+ parent = Path(str(entry["project_root"])).parent
111
+ if self._is_inside_root(parent) and parent.is_dir():
112
+ return parent
113
+ return self._root
114
+
100
115
  def _require_inside_root(self, path: Path) -> None:
101
116
  if not self._is_inside_root(path):
102
117
  raise ProjectFolderForbidden(