learningfoundry 0.79.1__tar.gz → 0.79.2__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 (120) hide show
  1. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/CHANGELOG.md +16 -0
  2. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/PKG-INFO +1 -1
  3. learningfoundry-0.79.2/docs/specs/nbfoundry/README.md +100 -0
  4. learningfoundry-0.79.2/docs/specs/pyve/README.md +1213 -0
  5. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/pyproject.toml +1 -1
  6. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/__init__.py +1 -1
  7. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/package.json +4 -4
  8. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/pnpm-lock.yaml +49 -77
  9. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/db/database.test.ts +39 -0
  10. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/db/database.ts +34 -1
  11. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/vite.config.ts +19 -7
  12. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/.gitignore +0 -0
  13. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/LICENSE +0 -0
  14. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/README.md +0 -0
  15. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/docs/specs/quizazz/README.md +0 -0
  16. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/__main__.py +0 -0
  17. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/asset_resolver.py +0 -0
  18. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/cli.py +0 -0
  19. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/config.py +0 -0
  20. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/directives.py +0 -0
  21. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/exceptions.py +0 -0
  22. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/generator.py +0 -0
  23. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/integrations/__init__.py +0 -0
  24. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/integrations/d3foundry_stub.py +0 -0
  25. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/integrations/nbfoundry_stub.py +0 -0
  26. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/integrations/protocols.py +0 -0
  27. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/integrations/quizazz.py +0 -0
  28. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/logging_config.py +0 -0
  29. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/parser.py +0 -0
  30. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/pipeline.py +0 -0
  31. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/py.typed +0 -0
  32. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/resolver.py +0 -0
  33. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/schema_extensions.py +0 -0
  34. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/schema_v1.py +0 -0
  35. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/README.md +0 -0
  36. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/finish.spec.ts +0 -0
  37. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/fixtures/curriculum.json +0 -0
  38. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/global-teardown.ts +0 -0
  39. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/lifecycle.spec.ts +0 -0
  40. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/navigation.spec.ts +0 -0
  41. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/progress.spec.ts +0 -0
  42. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/reset.spec.ts +0 -0
  43. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/text-block-bottom.spec.ts +0 -0
  44. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/e2e/video.spec.ts +0 -0
  45. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/playwright.config.ts +0 -0
  46. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/pnpm-workspace.yaml +0 -0
  47. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/app.css +0 -0
  48. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/app.html +0 -0
  49. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/AssessmentBlock.svelte +0 -0
  50. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/AssessmentBlock.test.ts +0 -0
  51. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/ContentBlock.svelte +0 -0
  52. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/ExerciseBlock.svelte +0 -0
  53. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/LessonList.svelte +0 -0
  54. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/LessonList.test.ts +0 -0
  55. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/LessonView.svelte +0 -0
  56. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/LessonView.test.ts +0 -0
  57. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/LockedLessonPlaceholder.svelte +0 -0
  58. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/ModuleList.svelte +0 -0
  59. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/ModuleList.test.ts +0 -0
  60. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/Navigation.svelte +0 -0
  61. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/PlaceholderBlock.svelte +0 -0
  62. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/ProgressBar.svelte +0 -0
  63. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/ProgressDashboard.svelte +0 -0
  64. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/ProgressDashboard.test.ts +0 -0
  65. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/RecordingPausedBanner.svelte +0 -0
  66. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/RecordingPausedBanner.test.ts +0 -0
  67. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/ResetCourseButton.svelte +0 -0
  68. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/ResetCourseButton.test.ts +0 -0
  69. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/TextBlock.observer.test.ts +0 -0
  70. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/TextBlock.svelte +0 -0
  71. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/TextBlock.test.ts +0 -0
  72. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/VideoBlock.svelte +0 -0
  73. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/VideoBlock.test.ts +0 -0
  74. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/VisualizationBlock.svelte +0 -0
  75. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/lesson-view.helpers.ts +0 -0
  76. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/module-list.helpers.ts +0 -0
  77. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/module-list.test.ts +0 -0
  78. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/mount.test.ts +0 -0
  79. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/navigation.helpers.ts +0 -0
  80. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/navigation.test.ts +0 -0
  81. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/components/progress-dashboard.helpers.ts +0 -0
  82. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/db/index.ts +0 -0
  83. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/db/progress.test.ts +0 -0
  84. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/db/progress.ts +0 -0
  85. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/db/user-id.test.ts +0 -0
  86. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/db/user-id.ts +0 -0
  87. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/stores/curriculum.test.ts +0 -0
  88. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/stores/curriculum.ts +0 -0
  89. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/stores/db-init.test.ts +0 -0
  90. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/stores/db-init.ts +0 -0
  91. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/stores/progress.test.ts +0 -0
  92. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/stores/progress.ts +0 -0
  93. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/types/index.ts +0 -0
  94. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/assessment-passed.test.ts +0 -0
  95. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/assessment-passed.ts +0 -0
  96. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/duration.test.ts +0 -0
  97. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/duration.ts +0 -0
  98. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/locking.test.ts +0 -0
  99. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/locking.ts +0 -0
  100. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/markdown-directives.ts +0 -0
  101. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/markdown.test.ts +0 -0
  102. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/markdown.ts +0 -0
  103. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/progress.test.ts +0 -0
  104. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/progress.ts +0 -0
  105. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/lib/utils/viewport-completion.ts +0 -0
  106. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/+layout.svelte +0 -0
  107. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/+layout.ts +0 -0
  108. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/+page.svelte +0 -0
  109. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/[module]/[lesson]/+page.svelte +0 -0
  110. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/[module]/[lesson]/page.test.ts +0 -0
  111. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/[module]/assessment/[id]/+page.svelte +0 -0
  112. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/[module]/assessment/[id]/page.test.ts +0 -0
  113. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/layout.helpers.ts +0 -0
  114. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/layout.scroll.test.ts +0 -0
  115. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/layout.scroll.ts +0 -0
  116. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/src/routes/layout.test.ts +0 -0
  117. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/static/.gitkeep +0 -0
  118. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/svelte.config.js +0 -0
  119. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/test-results/.last-run.json +0 -0
  120. {learningfoundry-0.79.1 → learningfoundry-0.79.2}/src/learningfoundry/sveltekit_template/tsconfig.json +0 -0
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.79.2] - 2026-06-02
11
+
12
+ Fix sql.js browser-ESM init failure in the SvelteKit template's dev-server preview path. Module and lesson routes were returning 500 in `learningfoundry preview` because `(await import('sql.js')).default` was `undefined` in the browser. Diagnosed in `docs/specs/bug-sql-js-browser-esm-spec.md`; fixed via Story J.y.
13
+
14
+ ### Fixed
15
+
16
+ - **`vite.config.ts` — `optimizeDeps.exclude` scoped to test mode only.** The exclude was added by Story J.w as a belt-and-braces safety net (J.w's actual fix was the `vi.mock('@pointmatic/quizazz', …)`), but in dev/prod mode it disables Vite's CJS→ESM dep pre-bundling for `sql.js`. Without that pre-bundling layer, the dev-server browser receives `sql.js@1.13+`'s raw UMD `dist/sql-wasm-browser.js`, whose CJS/AMD export branches don't run in pure browser ESM — so `.default` is `undefined` and `initSqlJsFn(...)` throws `TypeError: initSqlJsFn is not a function`. The exclude is now gated on `process.env.VITEST` so vitest 4.x still skips the dep-optimizer (preserving the J.w WASM-magic-header fix) while dev/prod regain CJS-interop.
17
+ - **`src/lib/db/database.ts` — typed `CjsEsmInteropError` backstop.** The dynamic `import('sql.js')` site now reads `.default` defensively and throws a named `CjsEsmInteropError` instead of an opaque `TypeError` when the initializer is missing. So the *next* sql.js drift surfaces a self-describing error in the dev-server console rather than the previous unactionable shape.
18
+
19
+ ### Verified
20
+
21
+ - `pnpm exec vitest run` → 278 passed (was 277; +1 new contract test for the CJS/ESM interop guard).
22
+ - `pnpm exec svelte-check` → 0 errors, 0 warnings.
23
+ - `pnpm exec vite build` → succeeds (confirms the gated `optimizeDeps.exclude` doesn't break prod build; the J.w comment's "covers both prod build" framing was incorrect).
24
+ - Manual: dev-server `/{moduleId}/{lessonId}` route renders without 500 in the d802-deep-learning consumer (verification scheduled with the consumer team — captured as a `[ ]` follow-up).
25
+
10
26
  ## [0.79.1] - 2026-05-22
11
27
 
12
28
  Fix five pre-existing `svelte-check` and `vitest` failures uncovered after the J.v post-assessment work landed (Story J.w). All five are type-only or test-only — no runtime behaviour changes.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: learningfoundry
3
- Version: 0.79.1
3
+ Version: 0.79.2
4
4
  Summary: A curriculum engine that turns a YAML curriculum definition into a deployable SvelteKit learning application.
5
5
  Project-URL: Homepage, https://github.com/pointmatic/learningfoundry
6
6
  Project-URL: Repository, https://github.com/pointmatic/learningfoundry
@@ -0,0 +1,100 @@
1
+ # nbfoundry
2
+
3
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
4
+
5
+ Marimo-based notebook framework for ML/DS work. One notebook source compiles into two
6
+ artifacts: a standalone runnable application and an `ExerciseBlock`-compatible artifact
7
+ that drops into a learningfoundry curriculum.
8
+
9
+ For the why, see [`docs/specs/concept.md`](docs/specs/concept.md). For the what, see
10
+ [`docs/specs/features.md`](docs/specs/features.md). For the how, see
11
+ [`docs/specs/tech-spec.md`](docs/specs/tech-spec.md).
12
+
13
+ ## Installation
14
+
15
+ `nbfoundry` targets Python 3.12.13 with the pinned Pyve + micromamba environment defined
16
+ in [`src/nbfoundry/templates/environment.yml`](src/nbfoundry/templates/environment.yml).
17
+ That one shared file ships as package data, gets copied into every scaffolded project by
18
+ `nbfoundry init`, and is the same spec the standalone artifact emitter falls back to.
19
+
20
+ ### Apple Silicon quickstart
21
+
22
+ The pinned stack defaults to Apple Silicon with Metal/MPS acceleration across PyTorch,
23
+ TensorFlow (via `tensorflow-metal`), and the bundled Keras 3 namespace from TF 2.16+.
24
+ It also ships the wider cross-project stack (HuggingFace `transformers` / `datasets` /
25
+ `peft`, Optuna, the plotly/seaborn/pyarrow utility set, dev tooling, and the
26
+ Pointmatic-internal `ml-datarefinery` package).
27
+
28
+ To verify the stack on a clean Apple Silicon machine, copy the shared env file and
29
+ `scripts/metal_smoke.py` into a fresh directory and let pyve build a micromamba-backed
30
+ env from the spec:
31
+
32
+ ```bash
33
+ mkdir nbfoundry-test && cd nbfoundry-test
34
+ mkdir scripts
35
+ cp <path-to-nbfoundry-root>/src/nbfoundry/templates/environment.yml .
36
+ cp <path-to-nbfoundry-root>/scripts/metal_smoke.py scripts/
37
+ pyve init --backend micromamba
38
+ pyve run python scripts/metal_smoke.py
39
+ ```
40
+
41
+ `pyve init --backend micromamba` reads the local `environment.yml` and provisions the
42
+ runtime env from it. The smoke script exercises PyTorch / TensorFlow / Keras against the
43
+ MPS device and then imports every other package added in Phase F (HuggingFace, Optuna,
44
+ plotly, seaborn, etc.) to assert basic availability — it doesn't import `nbfoundry`
45
+ itself, so no `pip install -e .` step is required for the verify.
46
+
47
+ Successful output ends with `all frameworks ran on MPS ✓`. If any framework or import
48
+ fails, the script reports which one and why (no MPS device, plugin not installed,
49
+ package missing from the env, etc.).
50
+
51
+ #### Cross-platform users (CUDA / CPU-only)
52
+
53
+ The shared `environment.yml` ships comment-delimited swap blocks for the framework
54
+ sections:
55
+
56
+ - **PyTorch CUDA:** drop the `pytorch` conda-forge line and add to the `pip:` block
57
+ `--extra-index-url https://download.pytorch.org/whl/cu126` + `torch` (or `.../cu128`
58
+ for CUDA 12.8).
59
+ - **TensorFlow CPU-only or Linux+CUDA:** replace the `tensorflow-macos` /
60
+ `tensorflow-metal` pip lines with `tensorflow>=2.16` (CPU-only) or
61
+ `tensorflow[and-cuda]>=2.16` (Linux + CUDA).
62
+
63
+ Both swap blocks are documented inline in the env file at the framework section.
64
+
65
+ ### Development setup (Pyve two-env)
66
+
67
+ ```bash
68
+ pyve init
69
+ pyve run pip install -e .
70
+ pyve testenv init
71
+ pyve testenv install -r requirements-dev.txt
72
+ ```
73
+
74
+ ## Usage
75
+
76
+ The CLI surface (`nbfoundry init`, `compile`, `compile-exercise`, `validate`) lands
77
+ across Phase D. See [`docs/specs/stories.md`](docs/specs/stories.md) for the
78
+ implementation roadmap.
79
+
80
+ ## Releasing to PyPI
81
+
82
+ Releases ship through [`.github/workflows/publish.yml`](.github/workflows/publish.yml),
83
+ which is triggered by pushing a `v*` tag. The workflow builds an sdist + wheel with
84
+ `hatch build` and publishes via PyPI [trusted publishing](https://docs.pypi.org/trusted-publishers/)
85
+ (OIDC, no long-lived API tokens).
86
+
87
+ One-time PyPI setup: register `nbfoundry` on PyPI and add a pending trusted publisher
88
+ under the project's *Publishing* settings — owner `pointmatic`, repository `nbfoundry`,
89
+ workflow `publish.yml`, environment `pypi`.
90
+
91
+ Per-release procedure:
92
+
93
+ 1. Land the version-bump story on `main` (package version in `src/nbfoundry/_version.py`
94
+ and a matching `CHANGELOG.md` entry).
95
+ 2. Tag the commit with the matching `v<version>` (e.g. `git tag v0.29.0 && git push origin v0.29.0`).
96
+ 3. The workflow verifies the tag matches `hatch version`, builds the distributions, and
97
+ publishes to PyPI under the `pypi` GitHub environment.
98
+
99
+ The workflow refuses to publish if the tag and `hatch version` disagree, so the only way
100
+ to ship a release is to tag the same commit that owns the version bump.