@mnstry/atelier 0.2.0-alpha.13 → 0.2.0-alpha.15

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 (253) hide show
  1. package/CHANGELOG.md +283 -0
  2. package/README.md +102 -52
  3. package/SECURITY.md +1 -1
  4. package/TRADEMARKS.md +2 -2
  5. package/contracts/atelier-extension-manifest.v1.schema.json +412 -0
  6. package/contracts/atelier-graph-view.v1.schema.json +1085 -0
  7. package/contracts/public-api-baseline.json +298 -19
  8. package/docs/README.md +90 -0
  9. package/docs/blocks/capability-stewardship.md +1 -1
  10. package/docs/blocks/claims.md +2 -2
  11. package/docs/blocks/conformance-admission.md +1 -1
  12. package/docs/blocks/learning-harnesses.md +1 -1
  13. package/docs/{atelier-sync.md → guides/atelier-sync.md} +20 -14
  14. package/docs/{capability-stewardship.md → guides/capability-stewardship.md} +2 -4
  15. package/docs/guides/co-authoring.md +113 -0
  16. package/docs/{distributions.md → guides/distributions.md} +13 -8
  17. package/docs/guides/extensions.md +189 -0
  18. package/docs/guides/graph-refresh.md +152 -0
  19. package/docs/guides/graph-workspace.md +64 -0
  20. package/docs/{ingestion.md → guides/ingestion.md} +16 -15
  21. package/docs/{inquiry-harnesses.md → guides/inquiry-harnesses.md} +2 -3
  22. package/docs/{knowledge-workspace.md → guides/knowledge-workspace.md} +2 -2
  23. package/docs/{learning-harnesses.md → guides/learning-harnesses.md} +2 -3
  24. package/docs/{learning.md → guides/learning.md} +12 -5
  25. package/docs/{obsidian.md → guides/obsidian.md} +370 -23
  26. package/docs/guides/ontology-guide.md +111 -0
  27. package/docs/{personal-workspace.md → guides/personal-workspace.md} +17 -5
  28. package/docs/{research-starter.md → guides/research-starter.md} +1 -1
  29. package/docs/{tenant-readiness.md → guides/tenant-readiness.md} +39 -0
  30. package/docs/{upgrade.md → guides/upgrade.md} +197 -11
  31. package/docs/knowledge-health/assessment/capabilities.md +6 -15
  32. package/docs/knowledge-health/facilitator.md +15 -4
  33. package/docs/knowledge-health/{devday/participant-response.md → participant-response.md} +4 -2
  34. package/docs/knowledge-health/quickstart.md +97 -75
  35. package/docs/knowledge-health/readme.md +13 -5
  36. package/docs/maintainers/describing-the-atelier.md +173 -0
  37. package/docs/{release-engineering.md → maintainers/release-engineering.md} +5 -4
  38. package/docs/{announcements.md → reference/announcements.md} +1 -1
  39. package/docs/{architecture.md → reference/architecture.md} +31 -5
  40. package/docs/{atelier-runtime.md → reference/atelier-runtime.md} +1 -1
  41. package/docs/{connected-composition.md → reference/connected-composition.md} +7 -10
  42. package/docs/{coordination.md → reference/coordination.md} +1 -1
  43. package/docs/{decisions.md → reference/decisions.md} +3 -3
  44. package/docs/{design.md → reference/design.md} +1 -1
  45. package/docs/reference/edge-policy.md +151 -0
  46. package/docs/reference/graph-view-structured.md +119 -0
  47. package/docs/reference/graph-view.md +139 -0
  48. package/docs/reference/graph-workspace.md +37 -0
  49. package/docs/{intake-and-guides.md → reference/intake-and-guides.md} +3 -4
  50. package/docs/{knowledge-graph.md → reference/knowledge-graph.md} +120 -6
  51. package/docs/{local-services.md → reference/local-services.md} +43 -4
  52. package/docs/{obsidian-contract.md → reference/obsidian-contract.md} +29 -4
  53. package/docs/{obsidian-plugin.md → reference/obsidian-plugin.md} +218 -68
  54. package/docs/{practical-judgment.md → reference/phronesis.md} +12 -3
  55. package/docs/reference/portability.md +92 -0
  56. package/docs/{portable-presentation.md → reference/portable-presentation.md} +2 -2
  57. package/docs/{presentation-consumer-boundaries.md → reference/presentation-consumer-boundaries.md} +5 -0
  58. package/docs/{project-options.md → reference/project-options.md} +17 -0
  59. package/docs/{repo-boundary-guard.md → reference/repo-boundary-guard.md} +50 -4
  60. package/docs/{review-portability.md → reference/review-portability.md} +4 -0
  61. package/docs/{semantic-operation.md → reference/semantic-operation.md} +4 -3
  62. package/docs/{template-profile.md → reference/template-profile.md} +1 -1
  63. package/docs/{trackables.md → reference/trackables.md} +2 -2
  64. package/docs/start/independent-start.md +89 -0
  65. package/docs/{install.md → start/install.md} +9 -9
  66. package/docs/{knowledge-setup.md → start/knowledge-setup.md} +5 -5
  67. package/docs/{research-starter-quickstart.md → start/research-starter-quickstart.md} +6 -6
  68. package/fixtures/atelier-architecture/catalog/invalid/document.json +2 -2
  69. package/fixtures/atelier-architecture/catalog/valid/document.json +2 -2
  70. package/fixtures/graph-view/synthetic-authorized-input.v1.json +437 -0
  71. package/fixtures/graph-view/synthetic-view.v1.json +1 -0
  72. package/fixtures/knowledge-health/workshop/README.md +1 -1
  73. package/fixtures/templates/local-library.v1.json +3 -1
  74. package/package.json +22 -8
  75. package/plugins/obsidian/main.js +57 -8
  76. package/plugins/obsidian/manifest.json +1 -1
  77. package/skills/claude/atelier-guided-upgrade/SKILL.md +1 -1
  78. package/skills/claude/atelier-knowledge-setup/SKILL.md +2 -2
  79. package/skills/claude/atelier-local-service/SKILL.md +1 -1
  80. package/skills/claude/atelier-practical-judgment/SKILL.md +7 -2
  81. package/skills/claude/atelier-skill-steward/SKILL.md +1 -1
  82. package/skills/claude/mnstry-readiness/SKILL.md +2 -2
  83. package/skills/codex/atelier-guided-upgrade/SKILL.md +1 -1
  84. package/skills/codex/atelier-knowledge-setup/SKILL.md +2 -2
  85. package/skills/codex/atelier-local-service/SKILL.md +1 -1
  86. package/skills/codex/atelier-practical-judgment/SKILL.md +7 -2
  87. package/skills/codex/atelier-skill-steward/SKILL.md +1 -1
  88. package/skills/codex/mnstry-readiness/SKILL.md +2 -2
  89. package/src/architecture/catalog.mjs +2 -2
  90. package/src/attestation/sign.mjs +1 -1
  91. package/src/boundary/content-rules.mjs +534 -68
  92. package/src/boundary/policy.mjs +187 -60
  93. package/src/cli/run.mjs +26 -9
  94. package/src/commands/distribution.mjs +1 -1
  95. package/src/commands/extension.mjs +27 -0
  96. package/src/commands/ingest.mjs +1 -1
  97. package/src/commands/learn.mjs +1 -1
  98. package/src/commands/obsidian.mjs +49 -21
  99. package/src/commands/review.mjs +3 -0
  100. package/src/edge-policy/contract.mjs +69 -0
  101. package/src/edge-policy/policy.mjs +142 -0
  102. package/src/edge-policy/source-citation-adapter.mjs +43 -0
  103. package/src/extension-packs/loader.mjs +4 -3
  104. package/src/extensions/admission.mjs +83 -0
  105. package/src/extensions/client.d.mts +23 -0
  106. package/src/extensions/client.mjs +99 -0
  107. package/src/extensions/contracts.d.mts +29 -0
  108. package/src/extensions/contracts.mjs +163 -0
  109. package/src/extensions/convex.d.mts +24 -0
  110. package/src/extensions/convex.mjs +189 -0
  111. package/src/extensions/delegation.mjs +54 -0
  112. package/src/extensions/drizzle.d.mts +11 -0
  113. package/src/extensions/drizzle.mjs +33 -0
  114. package/src/extensions/postgres.d.mts +7 -0
  115. package/src/extensions/postgres.mjs +66 -0
  116. package/src/extensions/prisma.d.mts +13 -0
  117. package/src/extensions/prisma.mjs +63 -0
  118. package/src/extensions/project.mjs +432 -0
  119. package/src/extensions/scaffold-convex.mjs +130 -0
  120. package/src/extensions/scaffold-sql.mjs +144 -0
  121. package/src/extensions/server.d.mts +20 -0
  122. package/src/extensions/server.mjs +102 -0
  123. package/src/extensions/sql-scope.mjs +22 -0
  124. package/src/graph/graph.mjs +13 -5
  125. package/src/graph/knowledge-graph.mjs +20 -2
  126. package/src/graph/repo-contribution.mjs +405 -0
  127. package/src/graph/repo-contribution.types.mjs +32 -0
  128. package/src/graph-access/edge-decision-adapter.mjs +41 -0
  129. package/src/graph-access/edge-record-adapter.mjs +73 -0
  130. package/src/graph-access/index.mjs +253 -0
  131. package/src/graph-access/multi-contribution-record-adapter.mjs +101 -0
  132. package/src/graph-access/multi-record-projection-adapter.mjs +74 -0
  133. package/src/graph-access/source-adapter.mjs +81 -0
  134. package/src/graph-refresh/compare.mjs +110 -0
  135. package/src/graph-refresh/controller.mjs +324 -0
  136. package/src/graph-refresh/index.mjs +3 -0
  137. package/src/graph-refresh/local.mjs +78 -0
  138. package/src/graph-view/babylon/babylon-scene-port.mjs +64 -0
  139. package/src/graph-view/babylon/index.mjs +2 -0
  140. package/src/graph-view/babylon/navigator.mjs +312 -0
  141. package/src/graph-view/babylon/provenance.mjs +36 -0
  142. package/src/graph-view/babylon/scene-controller.mjs +131 -0
  143. package/src/graph-view/babylon/semantic-picking.mjs +35 -0
  144. package/src/graph-view/babylon/web-host.mjs +188 -0
  145. package/src/graph-view/cli.mjs +3 -0
  146. package/src/graph-view/command.mjs +34 -0
  147. package/src/graph-view/contracts.mjs +79 -0
  148. package/src/graph-view/errors.mjs +5 -0
  149. package/src/graph-view/index.mjs +4 -0
  150. package/src/graph-view/intents.mjs +30 -0
  151. package/src/graph-view/query.mjs +213 -0
  152. package/src/graph-view/refs.mjs +2 -0
  153. package/src/graph-view/structured/browser.mjs +262 -0
  154. package/src/graph-view/structured/styles.mjs +8 -0
  155. package/src/graph-workspace/authoring.mjs +185 -0
  156. package/src/graph-workspace/browser/constellation.mjs +369 -0
  157. package/src/graph-workspace/browser/dom.mjs +23 -0
  158. package/src/graph-workspace/browser/index.mjs +6 -0
  159. package/src/graph-workspace/browser/review.mjs +55 -0
  160. package/src/graph-workspace/browser/styles.mjs +11 -0
  161. package/src/graph-workspace/browser/workbench.mjs +351 -0
  162. package/src/graph-workspace/browser/workspace.mjs +431 -0
  163. package/src/graph-workspace/disclosure.mjs +39 -0
  164. package/src/graph-workspace/geometry.mjs +78 -0
  165. package/src/graph-workspace/index.mjs +11 -0
  166. package/src/graph-workspace/labels.mjs +50 -0
  167. package/src/graph-workspace/model.mjs +109 -0
  168. package/src/graph-workspace/recipes.mjs +88 -0
  169. package/src/graph-workspace/scale.mjs +95 -0
  170. package/src/graph-workspace/theme.mjs +156 -0
  171. package/src/ingestion/optional/graphify/graphify_supplier.py +5 -0
  172. package/src/ingestion/optional/graphify/native-closure-pins.json +275 -0
  173. package/src/ingestion/optional/graphify/native-pins.json +306 -0
  174. package/src/knowledge/ontology-guide.mjs +152 -0
  175. package/src/knowledge-health/proof/installed-check.mjs +2 -2
  176. package/src/knowledge-health/rule-identity.mjs +14 -9
  177. package/src/knowledge-health/workshop.mjs +22 -2
  178. package/src/personal-workspace/index.mjs +1 -1
  179. package/src/personal-workspace/selection.mjs +34 -3
  180. package/src/project/config.mjs +1 -1
  181. package/src/project/path-match.mjs +2 -1
  182. package/src/project/providers/github.mjs +24 -0
  183. package/src/project/repo-identity.mjs +3 -22
  184. package/src/projection/obsidian/contracts.mjs +1 -1
  185. package/src/projection/obsidian/materialize/path-registry.mjs +1 -1
  186. package/src/projection/obsidian/materialize/prepare-view.mjs +88 -6
  187. package/src/projection/obsidian/materialize/redaction.mjs +1 -1
  188. package/src/projection/obsidian/personal-workspace.mjs +84 -5
  189. package/src/projection/obsidian/plugin-bridge/channel.mjs +1 -1
  190. package/src/projection/obsidian/proposals/adapter.mjs +46 -23
  191. package/src/projection/obsidian/proposals/observation.mjs +40 -2
  192. package/src/projection/obsidian/publication/publisher.mjs +96 -8
  193. package/src/projection/project.mjs +21 -16
  194. package/src/readiness/readiness.mjs +20 -11
  195. package/src/readiness-protocols/bundled-pack.mjs +14 -766
  196. package/src/readiness-protocols/bundled-selection.mjs +32 -0
  197. package/src/readiness-protocols/evidence.mjs +2 -1
  198. package/src/readiness-protocols/packs/mnstry.mjs +766 -0
  199. package/src/readiness-protocols/runtime.mjs +43 -6
  200. package/src/runtime/obsidian/engine.mjs +387 -76
  201. package/src/runtime/obsidian/lifecycle.mjs +20 -15
  202. package/src/runtime/obsidian/login-item.mjs +6 -3
  203. package/src/runtime/obsidian/machine-settings.mjs +52 -8
  204. package/src/runtime/obsidian/observation.mjs +36 -4
  205. package/src/runtime/obsidian/opening.mjs +4 -3
  206. package/src/runtime/obsidian/personal-selection.mjs +187 -0
  207. package/src/runtime/obsidian/pipeline.mjs +115 -6
  208. package/src/runtime/obsidian/private-lock.mjs +50 -6
  209. package/src/runtime/obsidian/selection-continuity.mjs +124 -0
  210. package/src/runtime/obsidian/service-main.mjs +68 -16
  211. package/src/runtime/obsidian/service.mjs +80 -6
  212. package/src/runtime/obsidian/unheld-evidence.mjs +1 -1
  213. package/src/runtime/obsidian/view-permission.mjs +335 -0
  214. package/src/ui/control-system.mjs +201 -0
  215. package/src/ui/html-primitives.mjs +3 -0
  216. package/src/upgrade/closure-diagnostics.mjs +135 -0
  217. package/src/upgrade/closure.mjs +649 -0
  218. package/src/upgrade/upgrade.mjs +42 -11
  219. package/templates/distribution-workspace/README.md +2 -2
  220. package/templates/external-project-workspace/atelier.project.json +3 -0
  221. package/templates/external-project-workspace/pack-lifecycle.json +3 -1
  222. package/templates/knowledge-workspace/README.md +2 -2
  223. package/docs/integration-and-review-plan.md +0 -409
  224. package/docs/integration-contract-decisions.md +0 -44
  225. package/docs/knowledge-health/devday/facilitator.md +0 -16
  226. package/docs/knowledge-health/devday/public-default.md +0 -107
  227. package/docs/knowledge-health/devday/quickstart.md +0 -18
  228. package/docs/knowledge-health/devday/support.md +0 -22
  229. package/docs/knowledge-health/exercise.md +0 -17
  230. package/docs/knowledge-health/support.md +0 -34
  231. package/docs/presentation-review-disposition.md +0 -47
  232. package/docs/progressive-ingestion-acceptance.md +0 -89
  233. package/docs/progressive-ingestion.md +0 -235
  234. /package/docs/{exact-upgrades.md → guides/exact-upgrades.md} +0 -0
  235. /package/docs/{guided-upgrades.md → guides/guided-upgrades.md} +0 -0
  236. /package/docs/{local-review.md → guides/local-review.md} +0 -0
  237. /package/docs/{skill-steward.md → guides/skill-steward.md} +0 -0
  238. /package/docs/{template-upgrades.md → guides/template-upgrades.md} +0 -0
  239. /package/docs/{assurance-controls.md → maintainers/assurance-controls.md} +0 -0
  240. /package/docs/{attestation.md → reference/attestation.md} +0 -0
  241. /package/docs/{coauthor-session.md → reference/coauthor-session.md} +0 -0
  242. /package/docs/{continuity.md → reference/continuity.md} +0 -0
  243. /package/docs/{contract-stability.md → reference/contract-stability.md} +0 -0
  244. /package/docs/{decision-practices.md → reference/decision-practices.md} +0 -0
  245. /package/docs/{evidence-navigation.md → reference/evidence-navigation.md} +0 -0
  246. /package/docs/{extension-pack-lifecycle.md → reference/extension-pack-lifecycle.md} +0 -0
  247. /package/docs/{interaction-and-reflection.md → reference/interaction-and-reflection.md} +0 -0
  248. /package/docs/{local-state.md → reference/local-state.md} +0 -0
  249. /package/docs/{ontology.md → reference/ontology.md} +0 -0
  250. /package/docs/{optional-ingestion.md → reference/optional-ingestion.md} +0 -0
  251. /package/docs/{project-command-inventory.md → reference/project-command-inventory.md} +0 -0
  252. /package/docs/{semantic-ingestion.md → reference/semantic-ingestion.md} +0 -0
  253. /package/docs/{vault-service.md → reference/vault-service.md} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,288 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0-alpha.15
4
+
5
+ - Patch the fast-uri dependency and override from 3.1.8 to 3.1.9, the patched 3.x release for GHSA-w74x-v6f9-j3xg, GHSA-xhq7-xmqj-769h, GHSA-wjr9-j795-jxcr and GHSA-333x-w4r6-6crp (3.1.8 is in each affected range; whether Atelier's use was exploitable is not established). Ajv's own `^3.0.1` range resolves to the same copy, so a bare consumer installs 3.1.9 only, and `npm audit` reports no runtime advisory.
6
+ - Add the graph workspace (`@mnstry/atelier/graph-workspace` and `/graph-workspace/browser`): one graph in three rooms, a constellation of every readable record on a night-sky canvas with folder zones and collision-free labels, a workbench of sparse cards beside a focused authoring sheet, and a review that shows before and proposed and leaves the decision to a person. Work recipes choose the room, lens and primary action, and compose across Atelier, coach and owner layers with per-field provenance; themes compose the same way and refuse unsafe values and low contrast. Scale helpers show the whole as zones beyond 12,000 records and open one zone at a time with every omission counted. Drafts live behind a storage port (this browser by default, and the interface says so). A shareable-content gate finds fingerprints of private graphs in shareable text. Renderer packages are injected by the host; Atelier adds no runtime dependency. See the [graph workspace guide](docs/guides/graph-workspace.md).
7
+ - Add renderer-neutral graph views (`atelier.graph-view@v1`), a reader-bound graph access port, repository-qualified Markdown source contributions, a source-bound edge eligibility policy and adapters that bind source contributions through edge policy to graph access. Hosts still own authentication, grants, revalidation and keys.
8
+ - Add a structured graph explorer with a provenance inspector, an optional Babylon graph-view consumer, source-bound ontology guidance drafts, and an authorized projection refresh lifecycle with scoped impact comparison.
9
+ - Refuse aliases of Git metadata, a root Git metadata entry that disappears before capture, and impossible UTF-16 or UTF-8 locator offsets in repository contributions, and resolve outgoing links from uppercase `.MD` sources. Knowledge Health pins the bytes of the knowledge-graph file, so its rule identity is regenerated for it: the `check` each assessment carries names a new `version` and `sourceTree`, and the rule it applies is unchanged.
10
+
11
+ - Accept a longer personal-selection history without a fresh confirmation only when it still holds the accepted record at its position. After a confirmed shortening, a divergent history at or above the earlier maximum refuses until it is confirmed again; ordinary appends and exact restoration are unchanged.
12
+
13
+ - Check the private-state location before a first use writes the workspace pointer, and check the persisted identity again before any further write. A refused location now leaves no pointer and no local state behind.
14
+
15
+ - Write no refusal bookkeeping for a private-state location refusal (a lock held or just taken is still released or withdrawn), and none unless the state root is still outside every root declared now, for a cached store as well as a newly located one. A configured locator that refuses leaves current roots unknown, so nothing is written. Retained selection-continuity writes, freshness writes and every engine phase that writes after a cooperative wait (vault-edit preservation, pending edits, automatic apply, preparation and publication) prove the location again against the roots declared now, as do engine-lock acquisition after its inspection, vault allocation after reading the app's list, and the publisher after each wait for the app, its list of vaults, its comparison of kept notes or its quiet period. Neither a location refusal nor a failure that leaves the location unproven (a wait for the app that gave up) writes a publication failure entry. A service started by a login item no longer falls back to the workspace the unit names when locating its workspace refuses, and prints a location refusal instead of logging or recording it there; a tick the engine refuses outright for the location of private state leaves the service's error record as it was. A refusal of the private state's own location found in one view (`managed-root-unproven`) stops the whole tick, so no later view goes on under roots that can no longer be trusted; a view whose own vault is in a bad place is still refused alone. These proofs are made at named points in the engine and the publisher, not at every write. Roots "declared now" are a personal home's manifest read again at each proof; an ordinary project's are those of the project as last loaded, until it is loaded again. The service process's own records, its plugin state and the built-in proposal store are not proven against the roots declared now; Known limits in the Obsidian guide lists them.
16
+
17
+ - Never let an unpersisted selection acceptance replace a newer durable one: a retained observation keeps its maximum and identities, but the checkpoint's accepted head wins once another writer has changed it.
18
+
19
+ - Refuse `obsidian uninstall` when the workspace location or identity cannot be established, instead of reporting that nothing was installed. No login-item or service action is taken.
20
+
21
+ - Create every workshop directory and file exclusively when initializing a new workshop, so a directory or file that arrives meanwhile refuses instead of being merged, and refuse before Git initialization if an unknown entry appears inside a directory the initialization created. Nothing is overwritten and nothing unknown is removed.
22
+
23
+ - Order journey runs by their validated creation instant, with run identity as the deterministic tie-break. Latest-per-protocol summaries and tenant packets share that rule; malformed times refuse rather than inherit hash-filename order. Clarify that a review-workspace decision concerns its run claims and source linkage alone does not establish logical support.
24
+
25
+ - Refuse a view as mixed-read when a previously observed source becomes a directory or changes during its pinned read, or a graph-declared sidecar disappears during the build. Other views can proceed; never-observed and unreadable sources retain their own errors.
26
+ - Cover the Astro presentation example in weekly dependency updates. Update Astro to 7.3.8 and refresh its locked sharp and HTTP cache-semantics dependencies to their patched releases.
27
+
28
+ - Event-loop benchmark results record the host logical CPU count and the one-, five- and fifteen-minute load averages at the start and end, including failed runs, so responsiveness evidence can be read with its host conditions.
29
+ - Keep all enrolled repository roots outside private service state when locating a personal workspace. Locating an existing home now requires its readable authored manifest, including an explicitly empty enrollment; the lower-level service API refuses a bare home instead of assuming no repository exclusions. Login-item removal and uninstall can retain their off choice before any generation is confirmed, and report the actual kept workspace pointer. Clarify which generation reads and assembly still run on the caller thread.
30
+
31
+ - Persist personal-selection continuity across service starts. A shortened history stays refused until its removed records return or a fresh confirmation accepts it; previously observed records cannot stand in for a new confirmation. A missing checkpoint with retained private ownership evidence refuses instead of becoming a first start.
32
+ - Initialize an undecided personal vault audience as owner only in machine settings. Explicit choices and clears keep their meaning; personal bindings permit `audience set me` and `audience clear`, and refuse custom audience lists. Initialization rereads under the same lock as setting writes so a concurrent clear stays empty.
33
+ - Keep blocking boundary diagnostics visible before warnings, report one aggregate evidence limit, and pin path quoting in Git evidence. Staged acquisition refuses missing or incomplete repository evidence and covers type changes without rename collapse. Conservative semantic assignment detection and runner-error handling preserve classified-document deletion review. Boundary checks flush complete JSON diagnostics through pipes before returning their refusal exit code.
34
+
35
+ - Allow projects to deselect the bundled MNSTRY readiness pack with tracked `ext["mnstry.atelier"].readiness.includeBundled: false`. Generic graph, project and readiness checks and selected custom protocols remain available; bundled journey, packet and readiness export commands refuse. Selection changes require an explicit lock write. Absent or `true` preserves the existing default, IDs and APIs.
36
+
37
+ - Name the practical-judgment responsibility Phronesis, with practical judgment as its plain-language description. Existing catalog identity, English lookup alias, judgment API and skill identities remain compatible. Keep Knowledge Stewardship distinct from the shared Knowledge Graph representation; move the current guide to `docs/reference/phronesis.md`.
38
+
39
+ - The boundary push check names its reason when a push's refs together exceed the evidence budget (`push-evidence-too-large`, with `limitBytes`, as when one ref's commits do), where before that refusal carried no reason. The text output of `atelier boundary check` and `atelier boundary push-check` lists a scan that could not finish (`content-scan-incomplete`, `semantic-field-scan-incomplete`, `repo-unscannable`) before the content findings and says how many findings past the first 50 it leaves out, so a long list no longer hides why a commit or push was refused. The guard documentation says the 1000-commit limit applies to each ref update and what to do with a single commit over the budget on its own.
40
+
41
+ - Add the optional native Convex backend adapter and TypeScript starter through the existing extension init/seal/validate/bundle workflow. HTTP admission and private native mutations reuse the delegation contract; indexed operation results commit with custom writes. Native provider qualification remains separate from reactive lifecycle and complete host/customer acceptance.
42
+
43
+ - Add native Drizzle DB-first/code-first and Prisma 7 project profiles, prepared scoped transactions and provider receipt recovery. Optional provider dependencies stay in the generated app; Root and supported-host acceptance remain separate gates.
44
+
45
+
46
+ - Organize current documentation into start, guides, reference and maintainer folders with one index. Remove superseded planning/review and event walkthrough files. Remove the retired Obsidian publication experiment, retaining its active isolated-app test fixture in the maintained harness with read-only inspection and refusal coverage. Required packed-document and inbound references follow the new paths.
47
+
48
+ - Repository cleanup groups vault test helpers under `test/support/vault/` and imports consumer-closure diagnostics directly from their existing source module. CLI help describes `mnstry-atelier` as a supported npm alias. The repository-local reconsideration tool now measures only the explicitly marked Maintained implementation decisions section of the architecture reference; definition revision four retains predicate v3 and all original measurement records.
49
+
50
+ - Add portable typed extension contracts, authenticated host clients, signed server admission and native Postgres transaction/receipt helpers under the existing package.
51
+ - Add `atelier extension init|validate|seal` for a customer-owned Postgres TypeScript project. Generation and sealing do not deploy or authorize an installation. Provider and supported-host qualification carry separate evidence.
52
+
53
+ ## 0.2.0-alpha.14
54
+
55
+ - The Obsidian maintenance service's log no longer gets a `status-project-loaded` line for every failure and recovery, or every slow load, of the plugin's status read while its loads come less than a minute apart and fail, or are slow, every other load or every third. Before, any load that answered ended a row of failures, and any load in time a row of slow loads. Now a row of failures ends only at a load that answers a minute or more after its last failure, with a line that names how many failures it held, and a row of slow loads only at a load in time a minute or more after the last slow one. Such a loader writes one row, less and less often. While a project is kept, it is loaded again every two and a half minutes, so there a row of failures ends at the next reload that answers. A loader that answers at least one reload between two failures still writes each failure and the load that ends its row, and one that fails at every reload and answers only at its retry keeps one row. Each slow load is still written there. A load at every request is now written too, when each load names the files it started over. That happens while a file that decides the views vouches for nothing, or while loads never agree, and before it showed only as a growing count. A load after which nothing is kept, though it named the files it started over, is written from the second in a row, on the same doubling row (`notKept`, with `vouched`); a load that named other files, as after a new confirmed selection, neither counts nor ends that row. `statusLoads` in the status document counts these loads as `notKept`, one at a start and one after each change on a healthy service.
56
+ - An Obsidian maintenance service started by a login item asks its project loader once (under `--personal-home`, its locator), and now hands its first answer on faithfully. A thenable that is no promise is adopted once as a native promise that settles as it does, so its `then` is called once in all. Before, it was called twice: once where the process let the answer go, and again at the service's own start. A promise whose `constructor` reads as this realm's `Promise` is let go without calling a `then` of its own, which may throw; any other, as a rule another realm's promise or a subclass's, is adopted as any other thenable is. A service started any other way that is handed a promise with a `then` of its own that throws now refuses it typed as well. Before, that start ended untyped. Anything thrown, `undefined` included, and a project whose `then` cannot be read, ends the start as a failure of the loader does. Before, `undefined` was taken as an answer of nothing: the start went on to resolve a workspace from it, and for a locator it was refused as `service-locator-invalid`. An unreadable `then` ended the process with an error the service never logged. The service also logs what was thrown when it has no prototype, or a `code` or `message` that cannot be read, where before that logging itself threw. A start ended by an error without a code is still a crash that the service manager restarts.
57
+ - A view the Obsidian maintenance service refuses for a file-system error is now named in its private log. The view's freshness names only the refusal's code, and such a tick is no failure, so nothing recorded the error before. Examples are `vault-location-unusable` for a vault folder that could not be allocated or placed, `mixed-read` for a configuration file that could not be read again during the tick or a source removed while it was read, and `staging-failed` for candidates that could not be staged. The service now writes a `view-refused` line for each such view whose refusal carries a file-system error's code, at most 64 a tick. The line names the view, the refusal's code and the error's code (`EACCES`, `EIO`, `ENOENT`, `ENOSPC`), and `cleanupCause` when a cleanup after it failed too. Only codes shaped as a file-system error's are written, never a message. A view the next tick names for the same reason is not written again, so a vault folder that stays unwritable, tried at every tick, is written once. The engine's tick report carries the same entries as `refusalCauses`, only when there are any.
58
+ - A failure while the publisher cleans up the candidates of a staging that did not complete no longer replaces what ended the staging. Before, a removal or a read that failed (`EBUSY`, `EPERM`, `EIO`, a volume gone) was thrown in place of the refusal or stop, and the tick failed without a typed reason. Now each candidate is cleaned up on its own, so one that cannot be removed leaves the others removed. What ended the staging is handed on unchanged: a caller's stop, a refusal such as `vault-root-moved`, or `staging-failed`. The code of the first such failure is added to a copy of its detail as `cleanupCause`. A candidate that could not be removed stays where it was, as before. That is in staging, or at its exchange path once the publication's journal is written, where the restart recovery of the next publication removes it.
59
+ - A selected source removed while the Obsidian maintenance service prepares or publishes a view, after the tick observed it and before the preparation, or the look again at the sources before the commit, read it, now refuses that view as `mixed-read`, as a source removed during the graph build does: no generation is committed for the view, the tick goes on to its other views, and the next tick reads everything again and publishes without the source. A generation already committed and prepared again is not reported current. Before, the tick failed without a typed reason: the view read `publisher-error`, the views after it were not prepared in that tick, and the service read degraded and recorded the error until the next tick. The rule is the build's: only a source the tick observed and that is gone when it is read (or its folder) is refused this way, and a file that cannot be read for another reason, or a path still there, still stops the tick. The engine primitive that decides it is now named `sourceRemovedSinceObserved`.
60
+ - A running Obsidian maintenance service whose loaded project is pinned to a selection record below the highest record any part of the service has read the selection history ending at loads the project again at its next tick, with no read of its own to trigger it. A confirmation read by another part of the service (the plugin's status read) and removed before the engine looked therefore refuses `selection-history-shortened` at that tick. Before, the engine went on publishing under its record until its next recheck, at the latest the next full reconciliation. Views that a change stops one after another have the history's end read once, not once a view, and it is read also when a file that decides the views could not be read.
61
+ - A source removed while the Obsidian maintenance service builds the canonical graph, after the build listed it and before it read it, now refuses the views of that tick as `mixed-read`, as a source changed during the build is: nothing is prepared from the build, and the next tick reads everything again and publishes without it. Before, the tick failed without a typed reason, and the service read degraded and recorded the error until the next tick. Only a source this tick observed, gone when the build reads it (or its folder), is refused this way. Anything else still stops the tick: a file that cannot be read for another reason, a path still there, one the walk over the sources listed and could not read, or one it never observed, so a path that can never be read fails every tick as before.
62
+ - AP-03 cleanup joins owned child handles even when the runtime status record is missing or malformed, and retains disposable roots when cleanup cannot be proven.
63
+ - The Obsidian maintenance service goes on answering health and status while a tick observes and routes pending edits. Observation gives the event loop a turn between two edits, and proposal routing gives it one before each repository and between two operations. Each edit and each operation is still handled in one stretch, and what is observed, recorded and proposed is unchanged. Before, a tick with a burst of edits held the listener for the whole observation. An observation asked for while another is under way now waits for it.
64
+ - The event-loop benchmark (`scripts/obsidian/benchmark-event-loop.mjs`) waits for the health request in flight at the end of the first tick, and of a transition, before it judges the window. A stretch at the end that holds the listener is then measured by that request's latency, under the same five-second rule as any other, instead of being read as a gap in the sampling; the 250 ms edge rule is about whether the sampling reached the edge, as it already was at the start of a tick. A request in flight at the end that is never answered now fails the run, where before it was left out. The rules a request is judged by are unchanged. The result's `health` and `transitionHealth` say whether such a request was waited for (`awaitedProbeInFlightAtEnd`; `false` also when it was answered at once). `--timeout-ms` may now be up to four hours, so a first publication of ten thousand notes in six views can be run; the window is judged without a limit on how many requests it holds.
65
+ - A running Obsidian maintenance service no longer follows a selection history back when it is cut short. It notes the highest record number at every read of the history's end, and a history that ends earlier refuses `selection-history-shortened`: nothing is loaded from it, a project already loaded is refused at its next recheck, the views say why and the vault keeps what it last published, until the removed records are back or the history is as long again. Before, the service loaded whatever record the history then ended with, so a history cut after a restore nobody confirmed published that restore. The number is kept in the process only: a service started after the cut, by the person or at login, after an upgrade or a failure, reads the history as it then stands and follows what it ends with, as each command run once does. Keeping it across a start is not part of this change.
66
+ - The Obsidian maintenance service goes on answering health and status while a published view is read back. The read-back after a commit gives the event loop a turn between notes, as preparation and publication do. It ran through before: for one view of 10,000 notes it held the listener for 1.9 s on a quiet host and 16.8 s on a loaded one, long enough for three health requests in a row to time out. Each note of the committed generation is still read once, and a view is reported current only after its read-back. `reconcileCooperatively` beside `reconcile` in `src/runtime/obsidian/observation.mjs` is the walk that waits.
67
+ - The event-loop benchmark (`scripts/obsidian/benchmark-event-loop.mjs`) has two more scenarios, which ask the service for one more tick after the first publication, with nothing changed, and judge that tick: by what it did, by how long it held the event loop, and by the health requests across it. `--scenario=next-tick` keeps the watcher a service runs with, so that tick is told of the notes the publication wrote, as the tick after a publication is; when the publication took five minutes or more it is also a full reconciliation, as it is in a service. `--scenario=full-reconciliation` makes it a full reconciliation whatever the publication took. The result records the tick, whether it was full, its longest event-loop delay, and what the watcher had reported before it. Until now no stage ran a tick that a watcher had told of anything, and the one full reconciliation a stage ran (in `observe-16`) was over the small corpus that stage is run with.
68
+ - The Obsidian maintenance service goes on answering health and status while a tick looks at the vault and at the sources. Before a view is prepared, the walk over every view's notes and the walk over the sources give the event loop a turn between files, as the read-back does. They ran through before: on one view of 10,000 notes the tick after a publication (told by the watcher of every note it wrote, and a full reconciliation as well after a long publication) held the listener for 5.5 s on a loaded host, and a health request timed out; at every full reconciliation, every five minutes, each walk reads every file. The pending edits are still read, compared and written in one stretch, after the walk over the vault. A file changed after its turn in a walk is seen by the next tick, by its stat hint or the watcher, or at the latest by the next full reconciliation. The tick reports two more phases to a caller that asks for them, `vault-observation` and `late-writer-recheck`. In the event-loop benchmark, a second-tick stage's ending is one tested function, and its delay test samples the stretch it means to leave out.
69
+ - A note removed from a vault is no longer lost when the tick that saw it fails without a typed reason (a source or a note it cannot read, a full disk while an edit is kept). The removal is a change once, and such a tick had recorded it without acting on it, so the view stayed `current` with the note gone, through every later full reconciliation. The tick after a failure without a typed reason now starts as the first tick of a process does: it loads the project again and looks at every view, and the view reads `vault-note-missing`. A source changed in such a tick, or a view added to the configuration in a tick whose project loader failed, is published by the next one for the same reason. The phase `late-writer-recheck` is reported when the look again at displaced files fails too.
70
+ - An Obsidian maintenance service whose engine lock could not be given back at the end of a tick (its released ticket could not be written: a full disk, an I/O error) goes on maintaining once the write succeeds. Before, every later tick found the service's own unreleased ticket and answered `busy`, which the service counts as a success: health read healthy, the views stayed `current`, and nothing was maintained until the service was started again. The tick whose release failed still fails; the lock stays held, and the next tick gives it back before it takes it again. A release of a private generation lock that throws now settles nothing, so calling it again tries again.
71
+ - A private generation lock whose acquisition fails after its ticket was put in place (the directory sync or the read-back of the ticket, or the listing that confirms it) removes that ticket again, while it still holds its own bytes, before the failure is reported; a removal that fails too is made at that process's next acquisition in the same directory. Before, the ticket stayed on disk unreleased and nobody held it to release it: every later acquisition by the same process found it held by that process, so an Obsidian maintenance service answered `busy` at every tick until it was started again, with health reading healthy. The engine lock, the start lock of `service start` and the proposal adapter's lock all take this path.
72
+ - The Obsidian maintenance service goes on answering health and status while a tick builds the canonical graph. The census (each Markdown source read, hashed and parsed, or reused from the graph file cache) gives the event loop a turn between sources; a first tick reads every source, and on a heavily loaded host the build for one view of 10,000 invented notes held the listener for 8 s in one stretch. The settings that select the views are checked at each wait, as during a preparation. `buildKnowledgeGraphSteps` and `buildCanonicalGraphSteps` are the builds as steps; `buildKnowledgeGraph` and `buildCanonicalGraph` run them through, unchanged for their callers. A project bound to a personal workspace is built by its own route in one stretch, as before, and the other sources (HTML files, the sidecars of PDF and Word documents) are read without a turn between them. Walking the directories, resolving links and assembling the graph still run through. `createProductionSeams()` has one more member, `buildGraphCooperatively`, which the engine uses for every project not bound to a personal workspace; a caller that replaces `buildGraph` and leaves `buildGraphCooperatively` as it ships builds every graph through its own `buildGraph`, as a replaced `prepareView` already prepares every view. Knowledge Health pins the bytes of the two graph files, so its rule identity is regenerated for them: the `check` each assessment carries names a new `version`, `sourceTree` and `graphBlob`, and the rule it applies is unchanged.
73
+ - Pages that still called shipped commands unreleased now say they shipped in 0.2.0-alpha.13: `atelier knowledge semantic`, `atelier ingest` (with the `./ingestion` export), `atelier inquiry`, `atelier harness` and `atelier capability`. Each was checked against the published 0.2.0-alpha.12 and 0.2.0-alpha.13 packages.
74
+ - A staged or pushed deletion of a tracked binary file no longer blocks the boundary check. A deleted path has nothing to read at the revision being scanned, yet the check tried to read it and reported `content-scan-incomplete` ("binary content could not be read within the 8388608-byte per-file limit"), which refused the commit or the push. A binary added or changed in the same change is still read and scanned, and only the extended header of the diff can say a path was deleted, so a content line cannot skip a file. A binary rename that git shows as a deletion and an addition is unblocked the same way.
75
+ - The optional Graphify supplier loads again. `graphify_supplier.py` reads `native-pins.json` and `native-closure-pins.json` beside it when it is imported, and neither file was in the package, so importing it (and the JSON bridge, query and composition receivers that import it) failed with a missing file in 0.2.0-alpha.13. Both pin files ship now, admitted by the release tarball audit, pinning Graphify 0.9.72 at upstream commit `1cd9a36c`: 30 operations and 67 closure modules. Of the 30, `extract-semantic` is pinned but cannot run, because its `graphify.llm` module is outside the admitted closure, so 29 are usable. `extract-structure` now refuses `parallel: true` with `NATIVE_WORKERS_UNATTESTED`: parallel extraction starts worker processes that import Graphify outside the pinned source loader, so only in-process extraction is admitted.
76
+ - `atelier upgrade closure` says what to do in two more cases and refuses one more flag. A refused linked `--npm-root` prints the directory's `realPath`, and the docs say why macOS `/tmp` and `$TMPDIR` are refused until it is given. A tarball URL with no readable host no longer suggests `--registry-host`, which cannot clear it. The `prefix-mismatch` message no longer claims npm would use another root, since the plan refuses any parent that declares workspaces. `--__proto__`, which the shared argument parser dropped, is refused as an unsupported flag. The upgrade guide now matches the code on an empty `--npm-root=` (`npm-root-required`), on `http` and `https` (counted separately in `registrySchemes`) and on when Atelier's own `package.json` is read.
77
+ - The practice-consumer reconsideration tool (`scripts/practice-consumer/reconsider.mjs measure`) can keep the full context of one measurement with `--capture NEWFILE`: the records and definition the evaluator was given, each evaluation's input and outcome as received, the citations that were not evaluated and why, and the decisions with no citation. It is written once, to a file that must not exist yet and must not be the measurements file under another name (checked by real path before measuring and by the file itself after writing), only when the measurement line can be appended, and before that line, so a refused capture appends nothing and the run removes the capture it wrote; only a run interrupted between writing the capture and appending its line can leave one standing. Without `--capture` nothing changes.
78
+ - The boundary content scan reads every changed file under its own name. Its diffs now pin their format (`--no-ext-diff --no-textconv --no-color --src-prefix=a/ --dst-prefix=b/ --no-relative --inter-hunk-context=0 --submodule=short --full-index`), so `diff.noprefix`, `diff.mnemonicPrefix`, changed prefixes, forced colour, an external diff or a textconv driver no longer leave a staged or pushed change unscanned, and fused hunks or submodule summaries do not stop clean work. Quoted paths (non-ASCII, quotes, tabs) and paths containing ` b/` are read correctly instead of being skipped or read as another file; a name holding a backslash is reported as it is, never inherits a sibling path's exception, and is in scope of every path-scoped rule. Changed binaries are read by object id, so a name shaped like an index stage (`0:name`) is read as itself. Added lines are taken from each hunk by its own line counts, so an added line that itself begins with `+`, such as a Markdown bullet, is scanned. Text that the repository's attributes declare binary (UTF-8 without a NUL byte in its first 8 KiB) was not scanned at all; it is now judged by its added lines like any other text, with renames and copies paired as in the main diff, and other content declared binary is scanned as a binary, as before. A changed file the scan cannot read from the diff is reported as `content-scan-incomplete` and blocks, where before it was skipped; a Git setting not pinned here can therefore stop a commit but cannot hide content.
79
+ - The boundary pre-commit check judges what is being committed. `git commit -a` and `git commit <paths>` hand the hook a temporary index, and a commit from a linked worktree its own index; the check dropped it with the rest of the Git environment, read the configured checkout's index and saw nothing staged. It now reads the index and work tree Git names, for the managed repository being committed, found by Git even from a hook chained into a subdirectory, and blocks when no single declared repository is being committed (`pre-commit-repo-unresolved`), as the push check does. Staged paths are listed NUL-separated, so a quoted name (non-ASCII, quotes) is matched against forbidden-path patterns, and a repository whose staged paths cannot be listed blocks. The semantic-field review reads the staged diff with the same pinned format and parser as the content scan, reads a document Git would call binary as text, blocks on a diff it cannot read, and takes only an added review marker as approval: a removed marker, or one in a file name, approves nothing; `atelier upgrade` applies the same marker rule. A forbidden-path pattern's `**` now also matches across a newline in a name.
80
+ - In the boundary content scan, a file that takes the name of a directory, or moves into a directory of its own name, in text that Git reports as binary, is judged as the main diff pairs it instead of blocking the commit. When such text is still unreadable the message says Git reports it as binary, which also covers text replacing binary content.
81
+ - The boundary push check judges the commits a push carries that the remote's tracking refs do not hold, each against its parent, binaries included, so a key added in one commit and removed in the next is no longer published unscanned; such a finding names its commit, and a key that reaches the pushed tip is reported once, listing the commits that carry it. A merge is judged only for what is new against all its parents, so a pull merge into the branch you push is not refused for what the remote already holds. The pre-push hook now passes the remote Git names (a configured remote, or a URL matched to one); reinstall hooks (`atelier boundary install-hooks`) so history held only by another remote is judged on its way to a new one. A push carrying more than 1000 such commits or more than the evidence budget is refused with `content-scan-incomplete`; push it in smaller parts. The content scan's diffs omit a deleted file's removed lines, which it never judges (the semantic-field review still reads them), so deleting a large file no longer exhausts the output limit. A new branch in a SHA-256 repository is diffed against that format's empty tree instead of failing.
82
+
83
+ - `atelier upgrade closure --npm-root ABSOLUTE_NPM_ROOT` plans a check of a staged
84
+ candidate's own dependency closure, and `planConsumerClosure` is exported from
85
+ `@mnstry/atelier/upgrade`. The plan reads the candidate's `package.json` and
86
+ `package-lock.json`, the installed manifest of every lockfile copy of the
87
+ selected package, `package.json` in each directory above the npm root (to
88
+ refuse a parent that declares workspaces) and, for the default package name,
89
+ Atelier's own `package.json`. It runs no npm command, uses no network, reads
90
+ no npm configuration and writes nothing. It reports the lockfile's sources,
91
+ registry hosts and schemes, and platform exclusions. It checks the selected
92
+ package's exact `overrides` against every installed copy, only after binding
93
+ each installed manifest to the name and version of its lockfile entry, and
94
+ lists selector, nested and non-exact overrides, and overrides for packages a
95
+ link provides, as unchecked. The npm root must be the directory's real path.
96
+ Refusals reuse `usage`, `consumer-closure-incomplete` and
97
+ `override-not-inherited`, each with one bounded reason. Every run prints one
98
+ JSON document, including a run whose arguments are refused. A completed plan
99
+ exits 3 with `"proof": "not-run"` and a refusal exits 2; the command never
100
+ exits 0 and does not prove an offline reinstall. The consumer-closure
101
+ classifiers moved to `src/upgrade/closure-diagnostics.mjs`, and
102
+ `scripts/consumer-closure-diagnostics.mjs` re-exports them. Two of them
103
+ changed: a project folder entry in a lockfile is never counted as an
104
+ installed copy, and a lockfile entry that is not an object is reported as
105
+ missing by `capturedClosure` instead of raising a `TypeError`.
106
+
107
+ - Add a tenant-neutral HTML control system at `@mnstry/atelier/ui`. The shared
108
+ geometry, variants, focus treatment, motion, action-group layouts, and safe
109
+ renderers are used by Atelier's generated project UI and are available to
110
+ downstream publication kits without importing publication semantics into
111
+ Atelier.
112
+ - The Obsidian service test suites reserve the loopback ports they choose, so
113
+ another test cannot take a port between its selection and its use.
114
+ - The Obsidian plugin (1.1.2) keeps the last authenticated status in view
115
+ through a transport interruption. After a connection refusal or timeout on
116
+ the same channel, the status window shows the last observed state, reason,
117
+ generation and check under "Last observed" labels. Those rows are historical
118
+ and never establish current freshness, service health or permission. The
119
+ history stays in memory and is cleared on a channel change, an
120
+ authentication refusal, an untrusted or malformed answer, a report for
121
+ another scope, or unload. A republish that names a different channel resets
122
+ the display to `connecting` without repeating an unchanged notice, and the
123
+ plugin opens no channel before startup admits it or after unload.
124
+ - The Obsidian maintenance service tells a plugin a view's stored freshness
125
+ and pending-edit count only while the project allows that view at the moment
126
+ of the request: its Obsidian settings are enabled and declare the view, and
127
+ its workspace pointer still names the workspace the service runs for.
128
+ Before, a view that was turned off or taken out of the settings was still
129
+ told what the service had stored, until the next tick and, for its
130
+ generations and counts, after it. The answer is now sealed as before with
131
+ `view` and `pendingEdits` null, so the plugin shows `Atelier: stale`, keeps
132
+ its session and asks again; anything that cannot be established (settings
133
+ that refuse, a project that does not load) is answered the same way. The
134
+ project is loaded again only when a file that decides it changed, compared
135
+ by content at every request. A loader that answers a promise is never
136
+ waited for: its view is told nothing until the load has answered.
137
+ - The real-app acceptance run of the small-fixture desktop procedure
138
+ (`scripts/obsidian/desktop-receipts.mjs`, maintainer tooling that is not
139
+ shipped) ends the processes it started, removes the temporary directories it
140
+ created, and bounds the receipt and console output it keeps. It signals only
141
+ a process it spawned or a recorded child of one, and removes a directory only
142
+ while the path still names the one it created; otherwise it keeps the
143
+ directories and names them.
144
+ - A project configuration file that is a link (one kept in a dotfiles
145
+ repository, say) no longer makes the Obsidian maintenance service load the
146
+ project, and run Git, at every status request a plugin makes. The service
147
+ compares what the loader reads through the link: the file it leads to and
148
+ that file's bytes, so a link pointed elsewhere is a change. A folder in a
149
+ file's place, or a link that leads nowhere or to a folder, still vouches for
150
+ nothing. The project the service keeps for those requests is taken only from
151
+ two loads in a row that agree over the same bytes, is loaded again every two
152
+ and a half minutes and never used past five. A loader that answers a promise
153
+ is given up after two and a half minutes, and a load that fails is asked for
154
+ again after two seconds, then four, up to thirty, unless a file changed.
155
+ - The Obsidian maintenance service refuses to start on a project loader that
156
+ answers a promise (or any other thenable), with
157
+ `service-loader-not-synchronous`, before it reads anything from it, listens
158
+ or records anything. Before, it handed the promise to its workspace
159
+ resolution, which then read the workspace pointer of the working directory
160
+ and protected no repository. For the status read of a plugin: a load whose
161
+ answer comes after its deadline is given up even when no request saw the
162
+ deadline pass; a link is resolved as the system resolves it, a `..` after a
163
+ link included, and a link to a folder above a configuration file pointed
164
+ elsewhere is a change; two loads agree when what the decision reads of the
165
+ project is the same, so a field that differs between loads (a time, a
166
+ binding under a symbol key) no longer stops a project from being kept; and
167
+ a load that fails, is given up or holds the event loop is logged with how
168
+ long it took.
169
+ - The Obsidian maintenance service stays responsive while it prepares and
170
+ publishes a view. The engine prepares each view cooperatively and the
171
+ publisher yields between complete units, so the loopback listener answers
172
+ health and status while notes are emitted, staged and published, instead of
173
+ being `busy` for the length of a large first publication. `open` and
174
+ `service stop` therefore reach a service in the middle of a publication:
175
+ `open` waits for a tick that starts after the one in flight, and `service
176
+ stop` ends the service after the tick in flight or its shutdown grace,
177
+ leaving a publication cut short to the publisher's restart recovery.
178
+ Walking the directories, resolving links and assembling the canonical
179
+ graph, capturing the source snapshot, the
180
+ publisher's restart recovery, validating a prepared view and planning its
181
+ units, the exchange probe, writing and syncing the journal before the
182
+ candidates move and the look again at displaced files after the units
183
+ still run without yielding. So did reading the sources into the canonical
184
+ graph, observing the source and vault files and the read-back after a
185
+ commit, until later changes made them wait between files (for the graph,
186
+ between Markdown sources, outside a personal workspace).
187
+ `prepareView` stays synchronous
188
+ and returns the same bytes. Across each wait of preparation and publication
189
+ the configuration files, the machine settings and the eligibility revision
190
+ are checked again, and after
191
+ a view is prepared and before its generation commits every selected source
192
+ is checked as observation checks it: by its stat hint, and by digest where
193
+ the hint moved. A change during the tick refuses the generation as
194
+ `mixed-read`; neither that tick nor a later restart recovery commits it,
195
+ and the next tick prepares the view again. A source that drifts under an
196
+ unchanged stat hint is still seen by the next full reconciliation, and a
197
+ note reused from the preparation cache is still not read. A cancelled
198
+ preparation leaves the preparation cache as it was, and publication keeps
199
+ its locks, journal and conditional writes.
200
+ - Started by a login item, the Obsidian maintenance service asks its project
201
+ loader once, and a loader that answers a promise there is refused and
202
+ recorded as at any other start, ending with 0. Before, the promise reached
203
+ the workspace resolution, and a refused one ended the process with an error
204
+ that the service manager answered by starting it again. The loads behind a
205
+ plugin's status requests are counted in the service's status document
206
+ (`statusLoads`), and the service log gets a `status-project-loaded` line
207
+ only for a load that failed or was given up (the first in a row, then when
208
+ the row is 2, 4, 8 and so on long), the first that answered after a failure,
209
+ and one that held the event loop for a second or more. A regular
210
+ configuration file the system resolves no path for (some Windows volumes)
211
+ is compared by its own path and bytes, instead of the project being loaded
212
+ at every request.
213
+ - A publication of the Obsidian maintenance service that is stopped or refused
214
+ on the way is recorded and cleaned up as what it was. A caller's stop after
215
+ the journal was opened (a setting that changed during the tick,
216
+ `mixed-read`, or a cancellation) is recorded in the journal's last entry
217
+ under that stop's own code instead of `publisher-error`; restart recovery
218
+ reads such a journal as before. A configuration file that cannot be read
219
+ again at a wait (no permission, an I/O error, no descriptor left) refuses
220
+ that view as `mixed-read` and has the next tick read everything again;
221
+ before, the raw error ended the tick, and the views after that one were not
222
+ prepared. A refusal raised while candidates are being staged (the vault's
223
+ folder replaced or gone) is still reported under its own code, now after
224
+ the candidates it staged are removed; before, those staged ahead of the
225
+ journal stayed in private staging, where restart recovery never looks. And
226
+ the service reads an explicit `prepareViewCooperatively: null` among its
227
+ engine seams as the engine does: there is no cooperative preparation, so a
228
+ replaced `prepareView` prepares the view.
229
+ - The desktop acceptance procedures (`scripts/obsidian/desktop-receipts.mjs`,
230
+ maintainer tooling that is not shipped) no longer signal the isolated app
231
+ by its process number outside the small-fixture run: quitting signals it
232
+ through the handle spawn returned and waits on that handle, a launch that
233
+ gives up signals the app's process group only while that handle still
234
+ holds the app, and a launch under the user's own HOME is refused before the
235
+ stale command-line socket there is removed. In the small-fixture run, a
236
+ process first recorded from a process table passes lineage on only from the
237
+ next read; a process the table shows, unrecorded, under a parent that
238
+ exited or changed during the read is remembered until it is seen gone, and
239
+ the directories are kept while it is there; and the app log copy's credit
240
+ is charged back when a directory is kept after all, with the excess over
241
+ the output bound's allowance reported.
242
+ - `atelier obsidian`, the Obsidian maintenance service and its login item take
243
+ `--personal-home DIR` instead of `--project`, and then follow the generation
244
+ last confirmed in that private home of a personal workspace. The head of the
245
+ selection history is read, that generation is loaded (composed in a worker
246
+ for the service), and the head is read again; a head that moved refuses
247
+ `personal-selection-changed`. Nothing confirmed publishes nothing, each with
248
+ its own code (`nothing-selected`, `stale-generation`,
249
+ `selection-history-corrupt`, `personal-home-unavailable`, or the module's own
250
+ code for a home that is gone), and nothing falls back to another project.
251
+ The service locates its workspace from the home alone through a new
252
+ `locateProject` option, so it starts whatever the selection; a service given
253
+ only a loader that answers a promise is still refused at start. The engine
254
+ observes the selection's record and the next one, so a confirmation or a
255
+ history cut short is loaded at the next tick, and reads the history again at
256
+ every full reconciliation. `status` reports the confirmed generation, and
257
+ nothing here confirms one. Who may see a bound vault is not decided: it stays
258
+ the machine's audience setting, none by default. `readPersonalSelectionHead`
259
+ is added to `@mnstry/atelier/personal-workspace`, and the selection history is
260
+ read without waiting on a record that is not a regular file. Without
261
+ `--personal-home` nothing changes.
262
+ - The desktop acceptance procedures (`scripts/obsidian/desktop-receipts.mjs`,
263
+ maintainer tooling that is not shipped) interrupt AP-03's service only
264
+ after a healthy status, and only through the handle of the service process
265
+ the run started; any other number is refused and the step fails. A launch
266
+ is refused unless the instance's HOME lies inside a layout root the run
267
+ made and is not the user's own home, however it is reached. In the
268
+ small-fixture run, cleanup reads the process table until a read records
269
+ nothing new before its first signal, and the run records how many
270
+ processes one command-line call becomes. The event-loop benchmark
271
+ (`scripts/obsidian/benchmark-event-loop.mjs`) signals its child's process
272
+ group only while it still holds the child.
273
+
274
+ - AP-03 reports a refused interruption without losing its failure evidence.
275
+ Separately, small-fixture cleanup remembers a child observed under a run-owned
276
+ process that exited or changed during the process-table read, then remembers
277
+ descendants of those children. It retains its temporary roots while those
278
+ remembered processes remain. It also reserves estimated time for SIGTERM
279
+ grace after reading the process tree.
280
+ - AP-03 test cleanup runs before temporary-workspace removal. It joins children
281
+ through retained handles even when the service record is missing or malformed
282
+ or graceful stop fails. Unheld launcher services use the existing forced-stop
283
+ fallback, which rechecks healthy runtime identity before signalling the PID.
284
+ A held child that does not exit within the cleanup bound fails the test.
285
+
3
286
  ## 0.2.0-alpha.13
4
287
 
5
288
  - Add the public Knowledge Health workshop on the existing local Knowledge