@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
@@ -30,7 +30,7 @@ sources, concepts, relations, and questions before operational use.
30
30
 
31
31
  An existing enrolled project needs a valid `knowledge-plan.json` beside its
32
32
  project configuration. Use the schema and guide in
33
- [knowledge setup](knowledge-setup.md). Rebuild the projection when its source
33
+ [knowledge setup](../start/knowledge-setup.md). Rebuild the projection when its source
34
34
  changes. The knowledge panels read the current enrolled graph on request; the
35
35
  ordinary projection remains the last explicitly built projection.
36
36
 
@@ -216,7 +216,7 @@ Start takes `requestId` (a fresh UUID, retained for exact retry), `flow`
216
216
  and `author`. Read/recover take only `sessionId`. Event takes `sessionId` and
217
217
  an `event` with a unique `id`, current `expectedRevision`, and reducer `type`.
218
218
  An `answer` or `propose` also carries `text`. All other event behavior follows
219
- [coauthor sessions](coauthor-session.md). Clients cannot submit receipts or
219
+ [coauthor sessions](../reference/coauthor-session.md). Clients cannot submit receipts or
220
220
  failure events. Stale versions never silently overwrite an intervening answer.
221
221
 
222
222
  Ask one useful question at a time. Record the person's exact answer. For
@@ -1,8 +1,7 @@
1
1
  # Knowledge development and the learning cycle
2
2
 
3
- Status: implemented locally for the next release. Published alpha.7 does not
4
- contain these commands. Use `node bin/atelier.mjs harness help` in this source
5
- checkout, or `atelier harness help` from a package built from this candidate.
3
+ Status: shipped since 0.2.0-alpha.13. Run `atelier harness help` for the
4
+ commands.
6
5
 
7
6
  Knowledge Harness helps people establish, develop, use and revise what they know.
8
7
  Ingestion is one capability within that larger purpose. Sources can also originate
@@ -5,6 +5,11 @@ decisions, and supplies explicitly activated lessons to a named harness. It is
5
5
  an experimental local source capability. It requires consumer integration and
6
6
  does not establish availability in a published package or installed desktop.
7
7
 
8
+ Here, `capture` means recording the observation explicitly supplied by a caller
9
+ or on stdin. It does not monitor an editor, microphone, conversation or desktop.
10
+ The [independent local start](../start/independent-start.md) needs no desktop or MNSTRY
11
+ account; integrated capture is a separate host capability.
12
+
8
13
  A person defines the task and scope, an agent can propose a lesson, and the
9
14
  person reviews its wording and consequences. Evidence can be represented before
10
15
  acceptance. Only accepted, activated content is eligible for task context.
@@ -202,11 +207,13 @@ Campaigns may stay in their own workspaces; selected references do not change
202
207
  their writer ownership. Private evidence projections stay outside committed
203
208
  canonical graphs unless an owner explicitly authors an appropriate source.
204
209
 
205
- A desktop or other host owns integrated capture, authenticating its caller,
206
- background jobs, provider access, budgets, review controls and actual harness
207
- integration. Private feedback, preferences, methods and authored skills remain
208
- in their owning workspace. A commercial host should consume these contracts
209
- without making basic local learning or export depend on an account.
210
+ A consuming host owns integrated capture, authenticating its caller, background
211
+ jobs, provider access, budgets, review controls and actual harness integration.
212
+ MNSTRY's desktop utility is a separate proprietary consumer of this public
213
+ foundation. Other hosts can use the same portable APIs and optional public
214
+ startup, editor and native-presentation bindings. Private feedback, preferences,
215
+ methods and authored skills remain in their owning workspace. Basic local
216
+ learning and export require no MNSTRY account or service.
210
217
 
211
218
  Run `node --test test/learning-*.test.mjs` on the supported Node version for
212
219
  the local acceptance cases. They cover terminal capture through withdrawal
@@ -4,7 +4,7 @@ This document describes the selection binding, the apply policy setup, the
4
4
  conflict-state view and the acceptance receipt validator under
5
5
  `src/projection/obsidian/selection-ui/`. It states what each one does on this
6
6
  machine and what it does not. The contract itself is in
7
- [obsidian-contract.md](obsidian-contract.md).
7
+ [obsidian-contract.md](../reference/obsidian-contract.md).
8
8
 
9
9
  Nothing in this module starts the app, runs `obsidian-cli`, publishes a vault
10
10
  or writes a source file. The test suite installs a spawn guard that throws if
@@ -273,7 +273,7 @@ path. The package root (`@mnstry/atelier`) exports nothing of the projection.
273
273
  Names ending `ForOracleTests` are mutation controls for the test suite, not a
274
274
  supported API. The whole surface is alpha and may change between prereleases.
275
275
  What the tarball must and must not carry, and the package proof, are in
276
- [release-engineering.md](release-engineering.md#obsidian-package-contents).
276
+ [release-engineering.md](../maintainers/release-engineering.md#obsidian-package-contents).
277
277
 
278
278
  ## First vault: what to expect
279
279
 
@@ -538,9 +538,19 @@ earlier one, so two installations used on one workspace (a global and a
538
538
  project-local one, say) do not replace each other's service on every open:
539
539
  `open` answers `service-unavailable` / `service-other-release`, and `service
540
540
  start` answers that it runs, with `release: later`; run `atelier obsidian
541
- service stop`, then open again, or open with the later release. A service in a
542
- long tick is not stopped (`open` answers `busy`), and a listener that does not
543
- prove itself this workspace's service is never touched.
541
+ service stop`, then open again, or open with the later release. A service that
542
+ does not answer health in time, in a stretch of a tick that does not yield, is
543
+ not stopped (`open` answers `busy`), and a listener that does not prove itself
544
+ this workspace's service is never touched. While a view is being prepared and
545
+ published the service does answer: `open` asks it for a tick that starts after
546
+ the one in flight and waits for that tick, two minutes at most unless
547
+ `atelier obsidian open --wait-ms MS` sets another bound, before it reports the
548
+ view as it is (one that read `current` is reported `updating`, with the reason
549
+ `tick-still-running`, while that tick has not ended); and `service stop` is
550
+ accepted and ends the
551
+ service after the tick in flight or after its shutdown grace, whichever comes
552
+ first. A publication cut short that way is settled by the publisher's restart
553
+ recovery at the next one.
544
554
 
545
555
  The first time Obsidian opens a view's vault it asks "Do you trust the author
546
556
  of this vault?", because every vault Atelier publishes carries Atelier's own
@@ -554,7 +564,7 @@ its own storage and asks again the next time until the vault is trusted or
554
564
  restricted mode is switched on for good in its settings. Turning the plugin
555
565
  off in a vault, or uninstalling it there, is respected from then on;
556
566
  `atelier obsidian plugin on --scope ID` brings it back. What the plugin does
557
- and never does is in [obsidian-plugin.md](obsidian-plugin.md).
567
+ and never does is in [obsidian-plugin.md](../reference/obsidian-plugin.md).
558
568
 
559
569
  `open` and `status` answer with a freshness state, not a promise. `current`
560
570
  means the vault is the present generation, verified by read-back, and the app
@@ -679,7 +689,7 @@ exactly because the folder is listed.
679
689
  Obsidian does not have to be quit.
680
690
  - **Obsidian is not running.** The view is published on the path with no app,
681
691
  as before. `open` then adds the vault to the app's settings file (see
682
- [Obsidian's vault list](obsidian-contract.md#obsidians-vault-list) for
692
+ [Obsidian's vault list](../reference/obsidian-contract.md#obsidians-vault-list) for
683
693
  exactly when and how that one file is written, marked to reopen) and starts
684
694
  Obsidian plainly, with no link: an Obsidian started with a link opens only
685
695
  that vault and drops the reopen flag of every other one, so your other
@@ -815,7 +825,7 @@ names the folder meanwhile, a settings file with other bytes is already
815
825
  there, or an interrupted run left a replacement or a removal. `open` may then
816
826
  add and open the vault before it is complete, and the app publishes the rest.
817
827
  Anything that would replace or remove a file waits for the app. See "First publication into a vault no Obsidian lists" in
818
- [obsidian-contract.md](obsidian-contract.md). The plugin's entry written this
828
+ [obsidian-contract.md](../reference/obsidian-contract.md). The plugin's entry written this
819
829
  way counts as offered until the plugin says hello from the vault.
820
830
 
821
831
  The publisher still writes into a vault only when it can coordinate with every
@@ -862,8 +872,9 @@ generationId })` in `src/projection/obsidian/personal-workspace.mjs`. Both
862
872
  arguments are explicit; neither is discovered from the environment or the
863
873
  working directory. A loader uses `loadBoundProject` with the same arguments,
864
874
  or `loadBoundProjectOffThread`, which composes in a worker thread; the engine
865
- awaits its loader. No command or service binds one yet: that waits for the selection seam that
866
- keeps one projection configuration per person.
875
+ awaits its loader. The command, the service and the login item bind a personal
876
+ home through `--personal-home`, which follows the generation the person
877
+ confirmed there (see "A confirmed selection", below).
867
878
 
868
879
  - **One graph.** The binding is attached to the generation's resolved
869
880
  `atelier.project.json` under one symbol key. When a project carries it, the
@@ -960,9 +971,12 @@ keeps one projection configuration per person.
960
971
  (`personal-views-exceed-settings-limit`), within the Obsidian settings
961
972
  contract. The preferred view, when it names a saved one, is the default. No
962
973
  generation file is written. `view add` refuses `views-from-personal-overlay`;
963
- `audience set`, `audience clear` and `location set` refuse
964
- `personal-binding-decision-unavailable`. Each refuses before anything is
965
- resolved or written.
974
+ `audience set me` records owner-only visibility in the machine settings, and
975
+ `audience clear` withholds every audience. Custom audience lists refuse
976
+ `personal-binding-owner-only`; `location set` still refuses
977
+ `personal-binding-decision-unavailable`. Refused operations do not change
978
+ audience, view or location settings. Following a selection may still keep
979
+ machine-private continuity evidence before the setting operation refuses.
966
980
  - **Preferences and coverage.** `preferences` are returned read only. A theme
967
981
  is reported and never written: `appearance.json` stays the person's.
968
982
  `coverage` is passed through untouched. No Obsidian code reads it: it states
@@ -984,6 +998,173 @@ keeps one projection configuration per person.
984
998
  in memory. A project configuration that declares it itself is refused at
985
999
  every build (`personal-binding-lost`, naming the key).
986
1000
 
1001
+ ### A confirmed selection
1002
+
1003
+ `--personal-home DIR`, given instead of `--project` to `atelier obsidian`, to
1004
+ the service entry and in a login item's unit, binds the personal home DIR
1005
+ (`src/runtime/obsidian/personal-selection.mjs`). Without it, every argument,
1006
+ unit and loader is what it was.
1007
+
1008
+ - **What is loaded.** The generation the person last confirmed with
1009
+ `selectPersonalGeneration` (see [personal-workspace.md](personal-workspace.md)),
1010
+ and nothing else. The loader reads the head of the selection history from
1011
+ the history alone (`readPersonalSelectionHead`), loads the generation it
1012
+ names through the route above (in a worker for the service, in the
1013
+ command's thread for a command), then reads the head again. A head that
1014
+ moved meanwhile refuses `personal-selection-changed`. Nothing here confirms
1015
+ a selection or chooses one for the person.
1016
+ - **Nothing confirmed publishes nothing.** No record refuses
1017
+ `nothing-selected`; a confirmed generation whose inputs were edited and not
1018
+ confirmed again refuses `stale-generation`; a history whose hash chain does
1019
+ not hold refuses `selection-history-corrupt`; a history that ends at an
1020
+ earlier record than the running service has read refuses
1021
+ `selection-history-shortened`; a home whose history cannot be read refuses
1022
+ `personal-home-unavailable`, and a home that is gone or not
1023
+ private refuses with the module's own code (`root-missing`,
1024
+ `not-private-location`, `root-symlinked`). Every other refusal of the
1025
+ composition keeps its code. Nothing falls back to another generation or to
1026
+ the project without a binding. The vault keeps what it last published from
1027
+ a confirmed generation. `status`, `open` and `service start` load the
1028
+ selection and refuse with its code; the service's freshness shows every view
1029
+ `stale` with it, and its status document has it as the last tick's reason.
1030
+ The command and service read the same machine-private continuity state, so a
1031
+ restart or a separate command does not accept a shortened history. An invalid
1032
+ checkpoint refuses `invalid-selection-continuity`; a checkpoint that cannot be
1033
+ kept refuses `selection-continuity-unavailable`. No project is returned in either case.
1034
+ A confirmed selection is reported by `status` (`selection`: the generation
1035
+ and the number of its record).
1036
+ - **The service starts from an initialized home whatever the selection.** A bound
1037
+ project's folder is its private home. The home must contain its caller-authored
1038
+ `atelier.personal.json`, even when its enrollment is explicitly empty and no
1039
+ generation is confirmed. A bare directory or a missing/unreadable manifest
1040
+ refuses before startup; the locator cannot infer that no repositories were
1041
+ enrolled from missing evidence. This tightens the former lower-level API
1042
+ behavior that could start from a bare home. The locator reads the home and the
1043
+ current manifest's repository roots for exclusion, without composing or
1044
+ selecting a generation. A data root
1045
+ inside a declared repository is refused before private state is created or a
1046
+ login item is removed for a restart, including when nothing is confirmed.
1047
+ The service resolves its workspace from that at once and starts, and its
1048
+ engine awaits the loader at each tick. `atelier obsidian --personal-home`
1049
+ does this for a bound home. A
1050
+ program that runs the service itself (`runMaintenanceService` from
1051
+ `@mnstry/atelier/obsidian`) gives it the same through `locateProject`, a
1052
+ synchronous function that answers, without loading anything, a project whose
1053
+ `configDir` is the folder the workspace is resolved from. The workspace is
1054
+ then resolved from that answer alone: a data root named only in the loaded
1055
+ project's local overlay, and not in the answer, is not seen, so the service's
1056
+ state can lie under another data root than the loaded project's. Name the data
1057
+ root through the `dataRoot` option or the workspace pointer instead, which
1058
+ both see. Started by a login item, the service asks the home, not the loader,
1059
+ for its workspace and log. `service status` and `stop`, the ticks `open` asks
1060
+ for, `service unit --remove` and `uninstall` locate the service the same way.
1061
+ When no project loaded (a restart while nothing is confirmed), the engine
1062
+ locates the workspace too, so each view published before says why nothing is
1063
+ published now instead of keeping the previous run's `current`. A service given
1064
+ a loader that answers a promise and no locator is still refused at start with
1065
+ `service-loader-not-synchronous`, and so is one whose locator answers a
1066
+ promise; a located value that names no folder refuses
1067
+ `service-locator-invalid`. The workspace pointer is under the home, so a home
1068
+ that is gone when the service starts leaves it no workspace to find
1069
+ (`service-workspace-not-prepared`).
1070
+ - **Cleanup with nothing confirmed.** `service unit --remove` and `uninstall`
1071
+ locate the existing protected workspace without a generation, and remember
1072
+ the machine's login-item decision as `off` there. They do not change the
1073
+ audience or confirm anything. Uninstall reports the actual kept workspace
1074
+ pointer under the personal home, and leaves its bytes, private state,
1075
+ generations and selection history in place.
1076
+ - **Following the history.** A loaded project is pinned to the record it was
1077
+ loaded under, and the engine observes that record and the place of the next
1078
+ one as configuration. A confirmation is therefore loaded at the next tick. A
1079
+ history cut short is seen at the next tick too, and a running service does
1080
+ not follow it back. Selections are only ever appended, so a history that
1081
+ ends at an earlier record than the service has read it ending at was cut by
1082
+ something other than a confirmation, and following it back could publish
1083
+ what nobody confirmed after the records removed: cut after a restore nobody
1084
+ confirmed, it would publish that restore. The service notes the highest
1085
+ record number at every read of the history's end (a load's first read, its
1086
+ read once the generation is loaded, the recheck at a full reconciliation,
1087
+ and a read made when a tick stops a view as `mixed-read` because the tick's
1088
+ settings changed or could not be read, once for views stopped one after
1089
+ another), whether or not the
1090
+ record's generation could be used, and whichever part of the service read
1091
+ it. A history that ends earlier refuses `selection-history-shortened` at a
1092
+ load and at a recheck until a fresh confirmation accepts it; at
1093
+ the read made when a tick stops a view, the view says `mixed-read` at that
1094
+ tick and the code at the next. A project already loaded is loaded again at
1095
+ the next tick once any part of the service has read the history ending at a
1096
+ later record than the one the project was loaded under, so a confirmation
1097
+ read elsewhere in the service and removed before the engine looked refuses at
1098
+ that tick; otherwise a project already loaded is held to this at its next
1099
+ recheck, at the latest the next full reconciliation, and until then it
1100
+ publishes nothing new under another record, and a change at its sources
1101
+ brings the recheck forward. A record added and removed between two of those
1102
+ reads was never read, and does not count: while a load of its own is under
1103
+ way, the plugin's status read compares the files that decide its views and
1104
+ reads no history, so a record it sees then only as a changed file is not
1105
+ noted. The views say why (`open` and
1106
+ `status --json` name the ways out), and the vault keeps what it last
1107
+ published.
1108
+ - **What ends that refusal.** Put the removed records back, or explicitly confirm
1109
+ the currently eligible generation through `selectPersonalGeneration` again.
1110
+ That existing confirmation operation is the accepting act; no new command is
1111
+ needed. One fresh confirmation accepts a shorter history even when its record
1112
+ number remains below the highest ever observed. Its unique confirmation
1113
+ identity distinguishes it from a previously observed record restored to the
1114
+ same position. Replaying a previously observed prefix refuses, including after
1115
+ a shorter history was accepted. Composition still decides whether the chosen
1116
+ generation is eligible.
1117
+ - **Continuity across starts.** The highest observed number, accepted head and
1118
+ previously observed record digests live in
1119
+ `state/maintenance/selection-continuity.json` under the existing private
1120
+ workspace. Reads validate its closed schema, workspace and personal-home
1121
+ identities; changed writes are serialized through the existing private-state
1122
+ lock, owner-only and atomic. State is bounded at 1 MiB and 8,192 observed record
1123
+ identities; exhausting the identity budget refuses `selection-continuity-capacity`.
1124
+ First use initializes from the current valid history, including historical v1
1125
+ records without a confirmation identity. Retain this private state: deleting
1126
+ all of it removes the evidence that distinguishes prior observation from a first
1127
+ installation. Damaged existing state is never treated as a new installation.
1128
+ - **What the history is checked for besides.** At every full reconciliation the
1129
+ history is read again, so a record before the last that no longer links, or
1130
+ a confirmation that landed before the engine first looked at the record,
1131
+ refuses with its code within the reconciliation interval. A confirmation
1132
+ during a tick changes an observed file: the view being prepared or published
1133
+ refuses `mixed-read` at its next wait, before its generation commits (one
1134
+ already committed stays), so do the views after it, and the next tick
1135
+ publishes under the new record. While the last load was refused, every tick
1136
+ loads again: with nothing confirmed the manifest, history and private continuity
1137
+ state are read without composition, and with a
1138
+ confirmed generation that no longer holds, one composition runs in a worker
1139
+ per tick.
1140
+ - **A narrowing.** When the newly confirmed generation drops a source (a
1141
+ repository withdrawn, a view narrowed), each view follows the publisher's
1142
+ rule for notes that leave a view; this binding adds no rule. At the view's
1143
+ next publication a generated note of the dropped source leaves the vault and
1144
+ its bytes are moved to private recovery. A note the person edited, once the
1145
+ engine has queued the edit, holds the whole view at the generation it last
1146
+ published (`held-for-your-edit`, `publication-withheld-for-your-edit`): the
1147
+ note is neither removed nor overwritten. A note edited during the
1148
+ publication itself stays in the vault (`retained-edit`).
1149
+ - **Who may see.** The existing machine audience setting owns this decision.
1150
+ For a personal binding, an undecided empty audience initializes to `only-you`
1151
+ with notes without a classification shown, recorded with `defaults` provenance.
1152
+ Existing explicit `only-you` lists and unclassified choices retain their exact
1153
+ meaning. An explicit `audience clear` stays empty across ticks and restarts.
1154
+ A nonempty custom setting refuses `personal-binding-owner-only` until
1155
+ `audience set me` or `audience clear` is recorded. Nothing is written into a
1156
+ generation or the personal overlay.
1157
+ - **Reading the history on the service's event loop.** The head is one
1158
+ directory listing and one bounded read per record. A record that is not a
1159
+ regular file (a FIFO, a device) refuses `selection-history-corrupt` without
1160
+ being waited on. A home that becomes unreadable while the engine holds a
1161
+ project (its permissions changed, not removed) fails the tick when the
1162
+ engine observes its files, as an unreadable configuration file does: nothing
1163
+ is published, and the service reports the failed tick.
1164
+ After a worker composes a generation, the caller still reads generation
1165
+ files, resolves the generation's project configuration and assembles the
1166
+ bound project on its own thread. Composition itself remains in the worker.
1167
+
987
1168
  Measured once on 2,156 notes in three repositories, with 50 annotations and five
988
1169
  saved views (six views in all). The production contributions were loaded, as
989
1170
  the service loads them, so the proposal adapter was registered. The host's load
@@ -1011,16 +1192,133 @@ again. While an edit stays open and shared sources are quiet, the adapter
1011
1192
  builds nothing more; under continuous change it builds once per tick until a
1012
1193
  quiet tick.
1013
1194
 
1014
- **What remains before a service or `open` binds a personal workspace of this
1015
- size.** The first publication blocks the event loop far longer than the
1016
- service's five-second health probe: about ten minutes here. That is the
1195
+ **What a service binding needed.** The first publication blocked the event
1196
+ loop far longer than the service's five-second health probe: about ten minutes
1197
+ here. That is the
1017
1198
  publication path every project takes, not this route: an ordinary project of
1018
1199
  450 notes, measured the same way, blocked as long as a bound one. Preparing six
1019
1200
  views again blocked 4.5 s, under the probe. The proposal adapter's build of a
1020
1201
  newly observed edit, without the engine's file cache, blocked 2.0 s, at a
1021
- two-second target, as for an ordinary project. A service binding needs the
1022
- first publication to yield to the event loop (or run off it), or a corpus small
1023
- enough to stay within the probe.
1202
+ two-second target, as for an ordinary project. A service binding needed the
1203
+ first publication to yield to the event loop, which it now does (see "Since
1204
+ that measurement"), and a start that does not wait for its loader. The service
1205
+ resolves its workspace from the project its loader answers when it starts, and refuses a loader that answers a promise or any
1206
+ other thenable, such as `loadBoundProjectOffThread`, with
1207
+ `service-loader-not-synchronous`, before it reads anything from it, listens or
1208
+ records anything; a promise it was handed is let go, and its refusal, if it
1209
+ is refused, does not go unhandled. Started by a login item (`--startup`), the
1210
+ service asks its loader (or, under `--personal-home`, its locator) once for both
1211
+ the lookup of its workspace and its own start. One that answers a promise there
1212
+ is never handed to the workspace resolution: a promise whose `constructor`
1213
+ reads as this realm's `Promise` is let go without calling a `then` of its
1214
+ own, any other thenable (as a rule another realm's promise or a subclass's)
1215
+ is adopted once (its `then` is called once in all), the refusal is recorded
1216
+ in the workspace the unit names, when that exists, and the process ends with
1217
+ 0, so the service manager does not start it again at once. One that throws
1218
+ there, whatever it throws (`undefined` too, a value with no prototype, or one
1219
+ whose `code` cannot be read), or answers a project whose `then` cannot be
1220
+ read, ends the start as a failure of the loader does anywhere else: it is
1221
+ logged, and what carries no code is a crash.
1222
+ A service bound through `--personal-home` is given a locator as well, and starts
1223
+ from it (see "A confirmed selection"). The plugin's status read allows for such
1224
+ a loader without waiting for it (see "The channel" in
1225
+ [obsidian-plugin.md](../reference/obsidian-plugin.md)).
1226
+
1227
+ **Since that measurement.** The engine prepares each view cooperatively and
1228
+ the publisher yields between complete units, so the service answers health and
1229
+ status while notes are emitted, staged and published. The first-tick figures
1230
+ in the table are from before that change and have not been taken again on that
1231
+ corpus. Building the canonical graph gives the event loop a turn between the
1232
+ Markdown sources it reads, hashes and parses (the census): a first tick reads
1233
+ every source, and on a heavily loaded host the build of one view of 10,000
1234
+ invented notes held the listener for 8 s in one stretch. The other sources
1235
+ (HTML files and the sidecars of PDF and Word documents) are read without a turn
1236
+ between them, and a project bound to a personal workspace is built by its own
1237
+ route in one stretch. Walking the directories, resolving the links and
1238
+ assembling the graph still run through.
1239
+ So do capturing the source snapshot, the publisher's restart recovery,
1240
+ validating a prepared view and planning its units, the exchange probe, writing
1241
+ and syncing the journal before the candidates move, and the look again at
1242
+ displaced files after the units (`recheckDisplacedFiles`).
1243
+ The read-back after a commit waits between
1244
+ notes: on a loaded host it took 16.8 s for one view of 10,000 invented notes
1245
+ and held the listener for all of it, and now a request is answered between two
1246
+ notes. Nothing is checked at those waits, since the generation is committed. A
1247
+ note edited in the vault while the read-back is under way is read as edited
1248
+ when the walk has not reached it, and is seen by the next tick when it has, as
1249
+ an edit made just after a read-back is. A stop whose grace runs out while a
1250
+ read-back waits ends the process after the commit and before the view is
1251
+ recorded as current, as a crash there does: the next start's first tick reads
1252
+ the committed generation back. Before a view is prepared, a tick looks at
1253
+ every view's notes and then at the sources, and both walks wait between files.
1254
+ They matter after a publication, when the watcher has named the notes it
1255
+ wrote, and at every full reconciliation, when every note and every source is
1256
+ hashed: on one view of 10,000 invented notes on a loaded host such a tick held
1257
+ the listener for 5.5 s when the walks ran through. Nothing is checked at their
1258
+ waits and nothing is written. Within Atelier only the engine commits a
1259
+ manifest or writes the pending edits, under the lock the tick holds, so the
1260
+ pending edits are read, compared and written in one stretch after the walk
1261
+ over the vault, and the bytes an edit keeps are read there. A file changed
1262
+ after its turn in a walk is seen by the next tick, by its stat hint or the
1263
+ watcher (one that keeps its size and times and draws no event, at the latest
1264
+ by the next full reconciliation), as one changed just after a walk that ran
1265
+ through is; when the tick builds the graph, the look again at the sources
1266
+ after the build refuses such a change as `mixed-read`. A source this tick
1267
+ observed, removed before the build read it (or its folder), is refused the
1268
+ same way. So is a selected source removed before a view's preparation, or the
1269
+ look again before its commit, read it: that view is refused, and the tick goes
1270
+ on to its other views. Either way the next tick reads everything again; a path
1271
+ that can never be read still fails the tick. A note gone from a
1272
+ vault, a source that changed, or a configuration file that changed is a change
1273
+ once: a tick that sees it and then fails without a typed reason (a file it
1274
+ cannot read, a disk that is full, a project loader that fails) has recorded it
1275
+ without acting on it. The next tick therefore starts as the first tick of a
1276
+ process does: it loads the project again and looks at every view, so a view
1277
+ whose note is missing reads `vault-note-missing` instead of staying `current`,
1278
+ and a changed source or view is published.
1279
+ The comparison of kept notes with their candidates reads asynchronously,
1280
+ sixteen at a time, and does not hold the listener. Observing pending edits
1281
+ and routing proposals wait between two edits and between two operations, so
1282
+ a burst of edits does not hold the listener for its whole length. One edit,
1283
+ or one operation, is still one stretch. The first edit an observation looks
1284
+ at that the object store does not hold yet builds the canonical graph in its
1285
+ stretch, and the first operation routed builds it again while the lock of
1286
+ its repository is held. An edit whose published note
1287
+ is not retained has its whole view prepared again in its stretch: once for a
1288
+ view and generation in an observation when the preparation succeeds, and for
1289
+ every such edit when it fails. A stop whose grace runs out while proposals
1290
+ are routed can end the process between two operations of a repository with
1291
+ that repository's proposal lock still held, as a crash can. A service in one
1292
+ of those stretches does not answer until it ends, and is `busy` if that
1293
+ outlasts the probe. A request can
1294
+ hold the listener too: the plugin's status read loads the project on the event
1295
+ loop at its first requests after the service starts (until two loads agree),
1296
+ when a configuration file changed, every two and a half minutes, again two to
1297
+ thirty seconds after a load that failed, and at every request while one of
1298
+ those files vouches for nothing or while its loads never agree. For a project
1299
+ named by `--project` none of those loads is taken off the loop. For a bound
1300
+ personal home they compose in a worker, as the engine's loads do, and the read
1301
+ starts each one on the loop by reading the selection history. A load that holds the loop
1302
+ for a second or more is logged (`status-project-loaded`), and so is a load at
1303
+ every request that names the files it started over (see "What the service
1304
+ shows of these loads" in [obsidian-plugin.md](../reference/obsidian-plugin.md)).
1305
+
1306
+ What the waits cost. The waits of observation and routing are taken at
1307
+ every boundary between two edits or two operations and before each
1308
+ repository, whatever time was spent; while routing describes its operations
1309
+ a wait comes after about 8 ms of work or 32 units. Nothing is checked around
1310
+ any of them. In preparation and publication a wait
1311
+ comes after about 8 ms of work or 32 units,
1312
+ whichever is first, and around each one the engine checks that the tick's
1313
+ settings still hold: it reads and hashes every configuration file it observes
1314
+ (the project configuration, the repository access file, local overlays and,
1315
+ for a bound personal workspace, its inputs), reads and validates the machine
1316
+ settings, and asks the eligibility revision. Measured on six configuration
1317
+ files, that check took about 0.2 ms, twice per wait; a first publication of
1318
+ 200 invented notes waited 463 times, so roughly 0.2 s of a 64 s tick, on a
1319
+ host with a load average above 200 (indicative only). The selected sources
1320
+ cost one stat call each after the preparation and one before the commit; a
1321
+ note reused from the preparation cache is still not read.
1024
1322
 
1025
1323
  ## Known limits
1026
1324
 
@@ -1047,7 +1345,7 @@ test reported as a pass.
1047
1345
  is admitted although the protocol depends on the view's undocumented
1048
1346
  `lastSavedData` field, and the protocol cases have not been re-run on any
1049
1347
  later release. See the "App capability floor" row of
1050
- [obsidian-contract.md](obsidian-contract.md). An app that was not running
1348
+ [obsidian-contract.md](../reference/obsidian-contract.md). An app that was not running
1051
1349
  when an adapter was qualified had no version to check, and neither had an
1052
1350
  app that was not found. Such an answer is never reused, and the adapter
1053
1351
  built on it does not coordinate with any app it then finds running, and
@@ -1087,6 +1385,50 @@ test reported as a pass.
1087
1385
  first allocation or when a vault is made again. Every other check runs
1088
1386
  again at both, and a vault made again, or published into, through a link on
1089
1387
  the way is refused (`vault-allocation-moved`).
1388
+ - Private state after a wait: that the private state is outside every
1389
+ repository the workspace declares now is proven when a project loads, around
1390
+ each engine phase, inside the engine and selection locks, and after each wait
1391
+ the publisher makes for the app, its list of vaults, its comparison of kept
1392
+ notes or its quiet period. "Declares now" differs by binding. For a project
1393
+ bound to a personal home, each proof reads the home's manifest again, so a
1394
+ repository enrolled while a tick waits is seen at the next proof. For an
1395
+ ordinary project, each proof uses the repositories of the project as it was
1396
+ last loaded. A change to its configuration or overlay that declares a
1397
+ repository enclosing the data root is not seen until the project is loaded
1398
+ again, and the writes of the tick in flight (preserved edits, pending edits
1399
+ and freshness, say) can land under it meanwhile. The proof is not made again
1400
+ at every write, and it is not made at all for writes made outside the
1401
+ engine's phases and the publisher. Those are:
1402
+ - the built-in proposal store's writes for pending edits to shared notes
1403
+ (kept bytes, arbitration records and its queue) while it works through
1404
+ several of them;
1405
+ - everything the service process itself keeps: its log, service settings,
1406
+ runtime record (with its bearer), service-start lock, startup record,
1407
+ error record and login-item record, including those written after it waits
1408
+ for a free port, for its server to listen or for the service manager, and
1409
+ those a login item's start writes in the workspace the unit names when the
1410
+ project's loader fails;
1411
+ - the plugin channel's bearer and the plugin choices it records, including a
1412
+ first-use bearer minted while a view is prepared and the confirmation
1413
+ written when a plugin session opens;
1414
+ - lock cleanup when a proof fails: any private lock that is held, or whose
1415
+ ticket was just published, when its proof refuses is still released or
1416
+ withdrawn, so that ownership is never left behind. This covers the engine
1417
+ lock (a release record, or the withdrawal of a ticket published before
1418
+ the last check of its acquisition), the selection continuity lock and the
1419
+ publication locks, including a release retried at the next acquisition.
1420
+ Lock cleanup and removing staged candidates are the only changes the
1421
+ engine and the publisher make after one of their proofs refuses.
1422
+
1423
+ Each of these writers keeps its file inside the workspace's private state,
1424
+ but none checks the roots declared now. A manifest that comes to enclose the
1425
+ data root, or that cannot be read, while the service runs can therefore
1426
+ receive these writes. A refusal of the private state's own location
1427
+ (`managed-root-unproven`) stops the whole tick, whichever view it is found
1428
+ in: no later view is prepared, given a store or published, and no view is
1429
+ reported current after it. A view whose own vault is in a bad place is still
1430
+ refused alone. A single check of the declared
1431
+ roots at every private-state write is planned as a separate change.
1090
1432
  - Replacing a vault during a publication: the allocated folder is checked
1091
1433
  before the vault lock is taken and again once its folder is made, after the
1092
1434
  app is asked about the vault, before each note and before the generation is
@@ -1111,7 +1453,7 @@ test reported as a pass.
1111
1453
  `~/.config/obsidian`) on Linux. It is written only while the process table
1112
1454
  shows, positively, that no Obsidian runs, only when Obsidian created it
1113
1455
  before, and with a backup beside it; see
1114
- [Obsidian's vault list](obsidian-contract.md#obsidians-vault-list). A
1456
+ [Obsidian's vault list](../reference/obsidian-contract.md#obsidians-vault-list). A
1115
1457
  Flatpak or snap build keeps its list inside its sandbox and never reads that
1116
1458
  file. Which build is in use is read from which vault list was written last
1117
1459
  (every build rewrites its own when a vault window opens or closes), and only
@@ -1166,7 +1508,7 @@ test reported as a pass.
1166
1508
  - The command-line tool (`obsidian-cli`) is a client of the app and is not
1167
1509
  counted. An app packaged under another executable name, an app on
1168
1510
  another machine and an app that starts after a reading are not seen; see
1169
- "The path with no app" in [obsidian-contract.md](obsidian-contract.md).
1511
+ "The path with no app" in [obsidian-contract.md](../reference/obsidian-contract.md).
1170
1512
  - The app-free path is live: before 0.2.0-alpha.10 the probe always found
1171
1513
  Atelier's own service, so publication never took the path with no app.
1172
1514
  From 0.2.0-alpha.10 it does, whenever the process table shows, positively,
@@ -1196,7 +1538,7 @@ test reported as a pass.
1196
1538
  back and a deleted folder is not made again until the person turns it on
1197
1539
  in Obsidian's settings or runs
1198
1540
  `atelier obsidian plugin on --scope ID`. Plugin files are never removed from
1199
- a vault. See [obsidian-plugin.md](obsidian-plugin.md).
1541
+ a vault. See [obsidian-plugin.md](../reference/obsidian-plugin.md).
1200
1542
  - Login items: the tests run the launchd and systemd managers' own code
1201
1543
  against stand-ins that answer as launchctl and systemctl do, and never
1202
1544
  against a real session. What `launchctl print-disabled` says for an item
@@ -1227,3 +1569,8 @@ The test suite proves each oracle can fail:
1227
1569
  - `createMaintenanceEngineForOracleTests` with an
1228
1570
  `ENGINE_PRIMITIVES.isRetryDue` that never holds: a refused view waits for
1229
1571
  the full reconciliation, and the retry oracle fails.
1572
+ - `createMaintenanceEngineForOracleTests` with
1573
+ `ENGINE_PRIMITIVES.rechecksEveryViewAfterFailure` false: a note removed, a
1574
+ source changed or a view added in a tick that then fails without a typed
1575
+ reason is lost, the view stays `current` with the note gone or the old
1576
+ content, the new view is never published, and the oracle fails.