@homeflare/alchemy 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +3 -3
  2. package/dist/caddy/admin-guard.d.ts +1 -1
  3. package/dist/caddy/index.js.map +2 -2
  4. package/dist/cloudflare/client.d.ts +1 -1
  5. package/dist/cloudflare/index.js.map +2 -2
  6. package/dist/cloudflare/lock-rules.d.ts +1 -1
  7. package/dist/forgejo/branch-protection-form.d.ts +1 -1
  8. package/dist/forgejo/branch-protection.d.ts +1 -1
  9. package/dist/forgejo/index.js.map +10 -10
  10. package/dist/forgejo/org-actions-secrets.d.ts +1 -1
  11. package/dist/forgejo/org-label.d.ts +1 -1
  12. package/dist/forgejo/org-team.d.ts +1 -1
  13. package/dist/forgejo/repo-webhook.d.ts +1 -1
  14. package/dist/forgejo/repository.d.ts +2 -2
  15. package/dist/forgejo/repository.d.ts.map +1 -1
  16. package/dist/forgejo/resource.d.ts +2 -2
  17. package/dist/forgejo/team-member.d.ts +1 -1
  18. package/dist/openbao/auth-role.d.ts +1 -1
  19. package/dist/openbao/bao-http.d.ts +4 -4
  20. package/dist/openbao/cloudflare-permission-groups.d.ts +1 -1
  21. package/dist/openbao/cloudflare-role-form.d.ts +2 -2
  22. package/dist/openbao/cloudflare-role-form.d.ts.map +1 -1
  23. package/dist/openbao/cloudflare-roles-expand.d.ts +1 -1
  24. package/dist/openbao/digest.d.ts +1 -1
  25. package/dist/openbao/forgejo-bootstrap-parse.d.ts +2 -2
  26. package/dist/openbao/forgejo-bootstrap-parse.d.ts.map +1 -1
  27. package/dist/openbao/forgejo-bootstrap.d.ts +1 -1
  28. package/dist/openbao/index.js.map +14 -14
  29. package/dist/openbao/mount.d.ts +1 -1
  30. package/dist/openbao/pki-role.d.ts +1 -1
  31. package/dist/openbao/policy.d.ts +2 -2
  32. package/dist/openbao/proxmox-role-form.d.ts +2 -2
  33. package/dist/openbao/proxmox-role-form.d.ts.map +1 -1
  34. package/dist/openbao/proxmox-role.d.ts +10 -10
  35. package/dist/openbao/ssh-role.d.ts +3 -3
  36. package/dist/proxmox/acl.d.ts +2 -2
  37. package/dist/proxmox/acl.d.ts.map +1 -1
  38. package/dist/proxmox/api-token-form.d.ts +2 -2
  39. package/dist/proxmox/api-token.d.ts +11 -11
  40. package/dist/proxmox/ceph-daemon-form.d.ts +3 -3
  41. package/dist/proxmox/ceph-daemon.d.ts +19 -19
  42. package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
  43. package/dist/proxmox/ceph-flag.d.ts +5 -5
  44. package/dist/proxmox/ceph-fs-wire.d.ts +5 -5
  45. package/dist/proxmox/ceph-fs.d.ts +16 -16
  46. package/dist/proxmox/ceph-osd-tree.d.ts +16 -16
  47. package/dist/proxmox/ceph-osd.d.ts +5 -5
  48. package/dist/proxmox/ceph-pool-form.d.ts +13 -13
  49. package/dist/proxmox/ceph-pool-form.d.ts.map +1 -1
  50. package/dist/proxmox/ceph-pool.d.ts +3 -3
  51. package/dist/proxmox/client.d.ts +2 -2
  52. package/dist/proxmox/credentials.d.ts +8 -8
  53. package/dist/proxmox/credentials.d.ts.map +1 -1
  54. package/dist/proxmox/firewall-alias-form.d.ts +1 -1
  55. package/dist/proxmox/firewall-alias.d.ts +1 -1
  56. package/dist/proxmox/generated/pbs.d.ts +1 -1
  57. package/dist/proxmox/generated/pve.d.ts +1 -1
  58. package/dist/proxmox/group.d.ts +8 -8
  59. package/dist/proxmox/ha-resource.d.ts +3 -2
  60. package/dist/proxmox/ha-resource.d.ts.map +1 -1
  61. package/dist/proxmox/ha-rule-form.d.ts +5 -5
  62. package/dist/proxmox/ha-rule.d.ts +3 -3
  63. package/dist/proxmox/index.d.ts +6 -0
  64. package/dist/proxmox/index.d.ts.map +1 -1
  65. package/dist/proxmox/index.js +356 -142
  66. package/dist/proxmox/index.js.map +59 -56
  67. package/dist/proxmox/lease-cache.d.ts +4 -4
  68. package/dist/proxmox/lxc-harness.d.ts +1 -1
  69. package/dist/proxmox/lxc-props.d.ts +2 -2
  70. package/dist/proxmox/lxc.d.ts +3 -3
  71. package/dist/proxmox/members.d.ts +3 -3
  72. package/dist/proxmox/network-apply-read.d.ts +5 -5
  73. package/dist/proxmox/network-apply.d.ts +9 -9
  74. package/dist/proxmox/node-network-form.d.ts +6 -6
  75. package/dist/proxmox/node-network.d.ts +17 -17
  76. package/dist/proxmox/node-network.d.ts.map +1 -1
  77. package/dist/proxmox/notification-target.d.ts +3 -2
  78. package/dist/proxmox/notification-target.d.ts.map +1 -1
  79. package/dist/proxmox/pbs-datastore-guard.d.ts +1 -1
  80. package/dist/proxmox/pbs-datastore.d.ts +10 -10
  81. package/dist/proxmox/pbs-prune-job.d.ts +2 -2
  82. package/dist/proxmox/pbs-sync-job.d.ts +4 -4
  83. package/dist/proxmox/pbs-verify-job.d.ts +1 -1
  84. package/dist/proxmox/pool.d.ts +4 -4
  85. package/dist/proxmox/provision-baseline.d.ts +74 -0
  86. package/dist/proxmox/provision-baseline.d.ts.map +1 -0
  87. package/dist/proxmox/provision-bootstrap.d.ts +33 -0
  88. package/dist/proxmox/provision-bootstrap.d.ts.map +1 -0
  89. package/dist/proxmox/provision-cli-fake.d.ts +38 -0
  90. package/dist/proxmox/provision-cli-fake.d.ts.map +1 -0
  91. package/dist/proxmox/provision-declare.d.ts +25 -0
  92. package/dist/proxmox/provision-declare.d.ts.map +1 -0
  93. package/dist/proxmox/replication-job.d.ts +9 -8
  94. package/dist/proxmox/replication-job.d.ts.map +1 -1
  95. package/dist/proxmox/resource.d.ts +2 -2
  96. package/dist/proxmox/resource.d.ts.map +1 -1
  97. package/dist/proxmox/sdn-apply-read.d.ts +7 -7
  98. package/dist/proxmox/sdn-apply.d.ts +1 -1
  99. package/dist/proxmox/sdn-subnet-form.d.ts +1 -1
  100. package/dist/proxmox/sdn-subnet.d.ts +5 -5
  101. package/dist/proxmox/sdn-vnet.d.ts +5 -6
  102. package/dist/proxmox/sdn-vnet.d.ts.map +1 -1
  103. package/dist/proxmox/storage.d.ts +4 -3
  104. package/dist/proxmox/storage.d.ts.map +1 -1
  105. package/dist/proxmox/user.d.ts +3 -2
  106. package/dist/proxmox/user.d.ts.map +1 -1
  107. package/dist/proxmox/values.d.ts +1 -1
  108. package/dist/proxmox/zfs-pool-write.d.ts +1 -1
  109. package/dist/proxmox/zfs-pool.d.ts +5 -5
  110. package/dist/talos/credentials.d.ts +1 -1
  111. package/dist/talos/credentials.d.ts.map +1 -1
  112. package/dist/talos/index.js.map +1 -1
  113. package/docs/adopt-verify.md +21 -5
  114. package/docs/adopted-deploys.md +1 -1
  115. package/docs/ownership.md +26 -1
  116. package/docs/provision-baseline.md +106 -0
  117. package/docs/proxmox-lxc-adopt.md +2 -2
  118. package/docs/proxmox-lxc.md +5 -4
  119. package/docs/proxmox.md +6 -0
  120. package/package.json +1 -1
  121. package/src/caddy/admin-guard.ts +1 -1
  122. package/src/caddy/local-admin.ts +1 -1
  123. package/src/cloudflare/client.ts +1 -1
  124. package/src/cloudflare/lock-rules.ts +1 -1
  125. package/src/forgejo/branch-protection-form.ts +1 -1
  126. package/src/forgejo/branch-protection.ts +1 -1
  127. package/src/forgejo/client.ts +1 -1
  128. package/src/forgejo/org-actions-secrets.ts +1 -1
  129. package/src/forgejo/org-label.ts +1 -1
  130. package/src/forgejo/org-team.ts +1 -1
  131. package/src/forgejo/repo-webhook.ts +1 -1
  132. package/src/forgejo/repository.ts +2 -2
  133. package/src/forgejo/resource.ts +2 -2
  134. package/src/forgejo/team-member.ts +1 -1
  135. package/src/openbao/README.md +4 -4
  136. package/src/openbao/auth-role.ts +1 -1
  137. package/src/openbao/bao-http.test.ts +2 -2
  138. package/src/openbao/bao-http.ts +6 -6
  139. package/src/openbao/bao-status.test.ts +1 -1
  140. package/src/openbao/bao-status.ts +1 -1
  141. package/src/openbao/cloudflare-group-scope.test.ts +1 -1
  142. package/src/openbao/cloudflare-permission-groups.test.ts +1 -1
  143. package/src/openbao/cloudflare-permission-groups.ts +3 -3
  144. package/src/openbao/cloudflare-policy.ts +1 -1
  145. package/src/openbao/cloudflare-role-form.ts +2 -2
  146. package/src/openbao/cloudflare-roles-expand.ts +1 -1
  147. package/src/openbao/digest.ts +1 -1
  148. package/src/openbao/forgejo-bootstrap-parse.test.ts +3 -3
  149. package/src/openbao/forgejo-bootstrap-parse.ts +2 -2
  150. package/src/openbao/forgejo-bootstrap.ts +4 -4
  151. package/src/openbao/kubernetes-role-form.test.ts +5 -5
  152. package/src/openbao/mount.ts +1 -1
  153. package/src/openbao/pki-role.ts +1 -1
  154. package/src/openbao/policy-wire.test.ts +3 -3
  155. package/src/openbao/policy.ts +2 -2
  156. package/src/openbao/proxmox-role-form.ts +5 -5
  157. package/src/openbao/proxmox-role.ts +11 -11
  158. package/src/openbao/ssh-role.ts +3 -3
  159. package/src/proxmox/acl.ts +4 -4
  160. package/src/proxmox/adopt-noop.test.ts +6 -6
  161. package/src/proxmox/api-token-form.ts +4 -4
  162. package/src/proxmox/api-token.ts +13 -13
  163. package/src/proxmox/ceph-daemon-form.ts +3 -3
  164. package/src/proxmox/ceph-daemon.ts +20 -20
  165. package/src/proxmox/ceph-flag.ts +7 -7
  166. package/src/proxmox/ceph-fs-wire.ts +7 -7
  167. package/src/proxmox/ceph-fs.ts +18 -18
  168. package/src/proxmox/ceph-osd-tree.ts +16 -16
  169. package/src/proxmox/ceph-osd.ts +6 -6
  170. package/src/proxmox/ceph-pool-adopt.test.ts +14 -14
  171. package/src/proxmox/ceph-pool-form.ts +13 -13
  172. package/src/proxmox/ceph-pool.ts +6 -6
  173. package/src/proxmox/client.test.ts +3 -3
  174. package/src/proxmox/client.ts +3 -3
  175. package/src/proxmox/credentials.test.ts +6 -8
  176. package/src/proxmox/credentials.ts +8 -8
  177. package/src/proxmox/firewall-alias-form.ts +1 -1
  178. package/src/proxmox/firewall-alias.ts +1 -1
  179. package/src/proxmox/generated/pbs.ts +1 -1
  180. package/src/proxmox/generated/pve.ts +1 -1
  181. package/src/proxmox/group.ts +10 -10
  182. package/src/proxmox/ha-resource.ts +3 -2
  183. package/src/proxmox/ha-rule-form.ts +5 -5
  184. package/src/proxmox/ha-rule.ts +3 -3
  185. package/src/proxmox/index.test.ts +7 -0
  186. package/src/proxmox/index.ts +14 -0
  187. package/src/proxmox/lease-cache.test.ts +19 -19
  188. package/src/proxmox/lease-cache.ts +4 -4
  189. package/src/proxmox/lxc-adopt.test.ts +3 -3
  190. package/src/proxmox/lxc-create-form.ts +1 -1
  191. package/src/proxmox/lxc-guards.test.ts +4 -4
  192. package/src/proxmox/lxc-harness.ts +3 -3
  193. package/src/proxmox/lxc-judge.test.ts +5 -5
  194. package/src/proxmox/lxc-lifecycle.ts +1 -1
  195. package/src/proxmox/lxc-props.ts +2 -2
  196. package/src/proxmox/lxc-read.test.ts +3 -3
  197. package/src/proxmox/lxc-strict-adopt.test.ts +1 -1
  198. package/src/proxmox/lxc-volume.test.ts +9 -9
  199. package/src/proxmox/lxc-volume.ts +1 -1
  200. package/src/proxmox/lxc-wire.ts +1 -1
  201. package/src/proxmox/lxc.ts +3 -3
  202. package/src/proxmox/members.test.ts +1 -1
  203. package/src/proxmox/members.ts +3 -3
  204. package/src/proxmox/metric-server-otel.ts +2 -2
  205. package/src/proxmox/network-apply-read.ts +10 -10
  206. package/src/proxmox/network-apply.ts +10 -10
  207. package/src/proxmox/node-network-form.ts +7 -7
  208. package/src/proxmox/node-network.ts +18 -18
  209. package/src/proxmox/notification-target.ts +3 -2
  210. package/src/proxmox/pbs-datastore-guard.ts +1 -1
  211. package/src/proxmox/pbs-datastore.ts +10 -10
  212. package/src/proxmox/pbs-prune-job.ts +2 -2
  213. package/src/proxmox/pbs-sync-job.ts +4 -4
  214. package/src/proxmox/pbs-verify-job.ts +1 -1
  215. package/src/proxmox/pool.test.ts +2 -2
  216. package/src/proxmox/pool.ts +4 -4
  217. package/src/proxmox/provision-baseline.test.ts +87 -0
  218. package/src/proxmox/provision-baseline.ts +162 -0
  219. package/src/proxmox/provision-bootstrap.test.ts +132 -0
  220. package/src/proxmox/provision-bootstrap.ts +135 -0
  221. package/src/proxmox/provision-cli-fake.ts +217 -0
  222. package/src/proxmox/provision-declare.test.ts +111 -0
  223. package/src/proxmox/provision-declare.ts +103 -0
  224. package/src/proxmox/replication-job.ts +9 -8
  225. package/src/proxmox/resource.ts +3 -3
  226. package/src/proxmox/sdn-apply-read.test.ts +16 -16
  227. package/src/proxmox/sdn-apply-read.ts +7 -7
  228. package/src/proxmox/sdn-apply.ts +3 -3
  229. package/src/proxmox/sdn-subnet-form.ts +1 -1
  230. package/src/proxmox/sdn-subnet.ts +5 -5
  231. package/src/proxmox/sdn-vnet.ts +5 -6
  232. package/src/proxmox/storage.ts +4 -3
  233. package/src/proxmox/user.ts +3 -2
  234. package/src/proxmox/values.test.ts +2 -2
  235. package/src/proxmox/values.ts +1 -1
  236. package/src/proxmox/zfs-pool-write.ts +1 -1
  237. package/src/proxmox/zfs-pool.ts +6 -6
  238. package/src/talos/credentials.ts +3 -3
  239. package/src/talos/values.test.ts +9 -9
  240. package/src/verify/cli.test.ts +1 -1
@@ -6,7 +6,7 @@
6
6
  * in OpenBao, not Alchemy state.
7
7
  *
8
8
  * ★ `defaultRemovalPolicy: 'retain'` — disabling a mount destroys every secret under it.
9
- * Opt in with `.pipe(RemovalPolicy.destroy())`; see resource.ts in house/proxmox.
9
+ * Opt in with `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.
10
10
  *
11
11
  * ★ REPLACE SEMANTICS (audited 2026-09-21, see src/openbao/REPLACE.md):
12
12
  * · `type` changed → plans `replace`, and the APPLY FAILS, destroying nothing: the new
@@ -36,7 +36,7 @@
36
36
  * never a policy one — but neither is a measurement.
37
37
  *
38
38
  * ★ `defaultRemovalPolicy: 'retain'` — see the delete comment below. Opt in with
39
- * `.pipe(RemovalPolicy.destroy())`; see resource.ts in house/proxmox.
39
+ * `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.
40
40
  */
41
41
  import { Resource } from 'alchemy';
42
42
  import * as Provider from 'alchemy/Provider';
@@ -15,8 +15,8 @@ import type * as HttpClient from 'effect/unstable/http/HttpClient';
15
15
  * ⛔ THERE IS NO `Bao.Secret`, AND THERE MUST NEVER BE ONE. Alchemy persists attributes to
16
16
  * its state store and does NOT encrypt them: StateEncoding.ts unwraps `Redacted` to
17
17
  * plaintext under a marker key, and nothing under alchemy/src/State encrypts. This
18
- * estate's state store is the `alchemy` Postgres database, which pg-backup.sh dumps
19
- * nightly (it enumerates EVERY non-template database), copies to CT100, and PBS backs up
18
+ * estate's state store is the `alchemy` Postgres database, which a nightly job dumps
19
+ * (it enumerates EVERY non-template database), copies to a backup guest, and PBS backs up
20
20
  * from there. A KV value here would exist in four places, none of them OpenBao.
21
21
  *
22
22
  * So this declares the SHAPE AROUND secrets. Every attribute it stores is a name, a
@@ -1,5 +1,5 @@
1
1
  export interface BaoProxmoxRoleProps {
2
- /** Mount path of the proxmox secrets engine, e.g. `proxmox-tb4`. A trailing slash is fine. */
2
+ /** Mount path of the proxmox secrets engine, e.g. `proxmox-c1`. A trailing slash is fine. */
3
3
  mount: string;
4
4
  /**
5
5
  * Role name, as `<mount>/roles/<name>` takes it.
@@ -61,7 +61,7 @@ export interface BaoProxmoxRoleAttributes {
61
61
  /** SHA-256 of the managed fields — safe to persist; see policy.ts. */
62
62
  digest: string;
63
63
  }
64
- /** `proxmox-tb4/roles/read` — read, write and delete all address the role here. */
64
+ /** `proxmox-c1/roles/read` — read, write and delete all address the role here. */
65
65
  export declare const rolePath: (mount: string, name: string) => string;
66
66
  export declare const attributesOf: (props: Pick<BaoProxmoxRoleProps, 'mount' | 'name'>, live: Record<string, unknown>) => BaoProxmoxRoleAttributes;
67
67
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"proxmox-role-form.d.ts","sourceRoot":"","sources":["../../src/openbao/proxmox-role-form.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,mBAAmB;IAClC,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;;OASG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAmBD,mFAAmF;AACnF,eAAO,MAAM,QAAQ,UAAW,MAAM,QAAQ,MAAM,WAAwC,CAAC;AAE7F,eAAO,MAAM,YAAY,UAChB,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,MAAM,CAAC,QAC5C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,wBAYF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,UACb,mBAAmB,KACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAWzE,CAAC;AAaF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,WACjB,MAAM,YACJ,MAAM,uBACK,MAAM,GAAG,SAAS,KACtC,MAAM,GAAG,SAIyF,CAAC;AAEtG,gGAAgG;AAChG,eAAO,MAAM,OAAO,eAAgB,wBAAwB,SAAS,mBAAmB,YAG9C,CAAC"}
1
+ {"version":3,"file":"proxmox-role-form.d.ts","sourceRoot":"","sources":["../../src/openbao/proxmox-role-form.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,mBAAmB;IAClC,6FAA6F;IAC7F,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;;OASG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAmBD,kFAAkF;AAClF,eAAO,MAAM,QAAQ,UAAW,MAAM,QAAQ,MAAM,WAAwC,CAAC;AAE7F,eAAO,MAAM,YAAY,UAChB,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,MAAM,CAAC,QAC5C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,wBAYF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,UACb,mBAAmB,KACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAWzE,CAAC;AAaF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,WACjB,MAAM,YACJ,MAAM,uBACK,MAAM,GAAG,SAAS,KACtC,MAAM,GAAG,SAIyF,CAAC;AAEtG,gGAAgG;AAChG,eAAO,MAAM,OAAO,eAAgB,wBAAwB,SAAS,mBAAmB,YAG9C,CAAC"}
@@ -3,20 +3,20 @@
3
3
  * mint user, plus the lease ceilings that consumer's tokens get. METADATA ONLY.
4
4
  *
5
5
  * ★ WHY THIS FAMILY MATTERS MORE THAN IT LOOKS. Declaring these roles is how the estate
6
- * replaces HAND-MADE PERMANENT PVE TOKENS with short-lived minted ones. On TB4, SEVEN tokens
7
- * carry expire=0 and privsep=0 — root@pam!proxbox-sync, mcp@pve!executor,
8
- * monitoring@pve!exporter, sablier@pve!sablier, tofu@pve!ro, tofu@pve!apply and
9
- * vaultmint@pve!engine. Six of those are one Bao.ProxmoxRole plus a scoped PVE user away from
6
+ * replaces HAND-MADE PERMANENT PVE TOKENS with short-lived minted ones. On C1, SEVEN tokens
7
+ * carry expire=0 and privsep=0 — root@pam!inventory-sync, agent@pve!executor,
8
+ * metrics@pve!exporter, app@pve!app, iac@pve!ro, iac@pve!apply and
9
+ * mint@pve!engine. Six of those are one Bao.ProxmoxRole plus a scoped PVE user away from
10
10
  * being a 5-minute lease instead of a forever key.
11
11
  *
12
- * The seventh cannot be. vaultmint@pve!engine is the credential the ENGINE ITSELF
12
+ * The seventh cannot be. mint@pve!engine is the credential the ENGINE ITSELF
13
13
  * authenticates with in order to mint anything at all: the thing that issues short-lived
14
14
  * tokens needs a standing one, and no role can resolve that chicken-and-egg. It stays
15
15
  * permanent, which makes it the single most valuable token on the cluster and the one whose
16
16
  * rotation must be a deliberate, hand-run procedure rather than a plan.
17
17
  *
18
- * MEASURED here: `bao read proxmox-tb4/config` returns parent_token_id
19
- * `vaultmint@pve!engine`, parent_secret_set true, parent_secret_tail `…eb01` — the engine's
18
+ * MEASURED here: `bao read proxmox-c1/config` returns parent_token_id
19
+ * `mint@pve!engine`, parent_secret_set true, parent_secret_tail `…eb01` — the engine's
20
20
  * own key, present and, by the schema's own "Write-only: never returned by a read", not
21
21
  * retrievable. The seven-token inventory was handed to this change and NOT re-counted against
22
22
  * the PVE API in this session.
@@ -27,13 +27,13 @@
27
27
  *
28
28
  * ⛔ ISSUANCE IS NOT THIS RESOURCE, AND MUST NEVER BECOME ONE. `<mount>/creds/<name>` returns a
29
29
  * LIVE PVE TOKEN. Alchemy persists attributes unencrypted (StateEncoding.ts tags Redacted
30
- * values rather than encrypting them) into the `alchemy` Postgres, which pg-backup.sh dumps
31
- * nightly to CT100, from where PBS backs it up. A minted token declared as a resource would
30
+ * values rather than encrypting them) into the `alchemy` Postgres, which a nightly job dumps
31
+ * to a backup guest, from where PBS backs it up. A minted token declared as a resource would
32
32
  * outlive its own lease in at least four places, none of them OpenBao. This resource declares
33
33
  * the DOOR; walking through it is a runtime call, not a plan.
34
34
  *
35
35
  * ★ `defaultRemovalPolicy: 'retain'` — deleting a role breaks every consumer that mints from
36
- * it. Opt in with `.pipe(RemovalPolicy.destroy())`; see resource.ts in house/proxmox.
36
+ * it. Opt in with `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.
37
37
  */
38
38
  import { Resource } from 'alchemy';
39
39
  import * as Provider from 'alchemy/Provider';
@@ -4,8 +4,8 @@
4
4
  * ⛔ THE SIGNING KEY IS OUT OF SCOPE AND MUST STAY OUT. `ssh/config/ca` holds (or generates)
5
5
  * the CA private key and `ssh/sign/<role>` issues certificates. Neither is declarable
6
6
  * here, for the reason policy.ts spells out: Alchemy persists attributes to its state
7
- * store WITHOUT encrypting them, that store is the `alchemy` Postgres, and pg-backup.sh
8
- * dumps it nightly to CT100. A CA key there would outlive the vault that guards it. This
7
+ * store WITHOUT encrypting them, that store is the `alchemy` Postgres, and a nightly job
8
+ * dumps it to a backup guest. A CA key there would outlive the vault that guards it. This
9
9
  * resource declares the SHAPE a signature must satisfy — principals, extensions, TTLs.
10
10
  *
11
11
  * ⛔ THE ROLE WRITE IS A FULL REPLACE, NOT A PATCH. OpenBao rebuilds the role entry from the
@@ -29,7 +29,7 @@
29
29
  *
30
30
  * ★ `defaultRemovalPolicy: 'retain'`. Deleting this role locks every operator out of the
31
31
  * estate — the memory note "operator SSH is homeflare-bot@<host>" is this CA. Opt in with
32
- * `.pipe(RemovalPolicy.destroy())`; see resource.ts in house/proxmox.
32
+ * `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.
33
33
  */
34
34
  import { Resource } from 'alchemy';
35
35
  import * as Provider from 'alchemy/Provider';
@@ -36,14 +36,14 @@ import { type PveRequirements, type WithTarget } from './resource.ts';
36
36
  export type AclSubjectType = 'user' | 'group' | 'token';
37
37
  export interface AclProps extends WithTarget {
38
38
  /**
39
- * The PVE object path the grant is ON — `/`, `/pool/house`, `/vms/101`, `/storage/local-zfs`.
39
+ * The PVE object path the grant is ON — `/`, `/pool/lab`, `/vms/101`, `/storage/local-zfs`.
40
40
  * ⚠️ NOT THE API PATH: `spec.path` below is the endpoint (`access/acl`). PVE's API overloads the
41
41
  * word, so this file does too rather than renaming a field the cluster calls `path`.
42
42
  */
43
43
  path: string;
44
44
  /** Which kind of subject `ugid` names. Identity: changing it is a different grant. */
45
45
  type: AclSubjectType;
46
- /** `tim@pve`, `admins`, `hf-provision@pve!hf-provision-…`. Identity. */
46
+ /** `alice@pve`, `admins`, `hf-provision@pve!hf-provision-…`. Identity. */
47
47
  ugid: string;
48
48
  /** The role bound here, e.g. `PVEAuditor`. ⚠️ It must exist — PVE refuses an unknown roleid. */
49
49
  roleid: string;
@@ -1 +1 @@
1
- {"version":3,"file":"acl.d.ts","sourceRoot":"","sources":["../../src/proxmox/acl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAiB,MAAM,eAAe,CAAC;AAErF,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAExD,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,IAAI,EAAE,cAAc,CAAC;IACrB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,MAAM,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAAsC,CAAC;AAmH9D,eAAO,MAAM,kBAAkB,gIAqE5B,CAAC"}
1
+ {"version":3,"file":"acl.d.ts","sourceRoot":"","sources":["../../src/proxmox/acl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAiB,MAAM,eAAe,CAAC;AAErF,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAExD,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,IAAI,EAAE,cAAc,CAAC;IACrB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,MAAM,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAAsC,CAAC;AAmH9D,eAAO,MAAM,kBAAkB,gIAqE5B,CAAC"}
@@ -12,7 +12,7 @@ import type { ApiTokenAttributes, ApiTokenProps } from './api-token.ts';
12
12
  *
13
13
  * ⛔ THE WRITE SEMANTICS BELOW ARE READ FROM THE CLUSTER'S OWN PERL RATHER THAN INFERRED FROM THE
14
14
  * API SCHEMA — `/usr/share/perl5/PVE/API2/User.pm`, subs `generate_token` and
15
- * `update_token_info`, read over SSH on n2 on 2026-09-13. The two disagree in exactly the place
15
+ * `update_token_info`, read over SSH on node-b on 2026-09-13. The two disagree in exactly the place
16
16
  * that costs a forever-diff: the schema gives `expire` the default "same as user", and the code
17
17
  * never implements it. api-token.ts records what that means.
18
18
  */
@@ -24,7 +24,7 @@ import type { PveSpec } from './resource.ts';
24
24
  * `ugid`, so reporting it as an attribute is what lets a privilege-separated token be granted
25
25
  * anything at all without somebody retyping the join by hand.
26
26
  *
27
- * ⚠️ DERIVED, NOT READ. MEASURED: `GET /access/users/monitoring@pve/token/exporter` answers
27
+ * ⚠️ DERIVED, NOT READ. MEASURED: `GET /access/users/metrics@pve/token/exporter` answers
28
28
  * `{"expire":0,"privsep":0}` and echoes back neither half of its own identity. So this is built
29
29
  * from props, cannot disagree with the path the read used, and is therefore true by
30
30
  * construction — which is why it is reported and never compared.
@@ -2,11 +2,11 @@
2
2
  * `Proxmox.ApiToken` — a PVE API token: the thing a service actually authenticates as.
3
3
  *
4
4
  * ⛔ THE SECRET EXISTS FOR ONE HTTP RESPONSE AND THEN NOWHERE. MEASURED from the cluster's own
5
- * schema (`/usr/share/pve-docs/api-viewer/apidoc.js` on n2, 2026-09-13): POST returns
5
+ * schema (`/usr/share/pve-docs/api-viewer/apidoc.js` on node-b, 2026-09-13): POST returns
6
6
  * `["full-tokenid","info","value"]`; PUT returns `["comment","expire","full-tokenid","privsep",
7
7
  * "value"]` with `value` present ONLY when `regenerate` was set; GET returns
8
8
  * `["comment","expire","privsep"]` and never the secret. A live token agrees —
9
- * `GET /access/users/monitoring@pve/token/exporter` answers `{"expire":0,"privsep":0}`. PVE says
9
+ * `GET /access/users/metrics@pve/token/exporter` answers `{"expire":0,"privsep":0}`. PVE says
10
10
  * it plainly on the POST: the value "needs to be stored as it cannot be retrieved afterwards".
11
11
  *
12
12
  * ⛔ SO A TOKEN THIS RESOURCE CREATES IS UNUSABLE, AND SAYING SO IS THE POINT OF THIS BLOCK. The
@@ -19,7 +19,7 @@
19
19
  * ★ SO POINT THIS FAMILY AT TOKENS THAT ALREADY EXIST. `comment`, `expire` and `privsep` are the
20
20
  * whole of a token's policy, and declaring them is real work: it is how `expire` stops being
21
21
  * whatever somebody typed in 2024. Mint NEW tokens where the secret can be caught — OpenBao's
22
- * `proxmox-tb4` mount, or a human at `pveum user token add`.
22
+ * `proxmox-c1` mount, or a human at `pveum user token add`.
23
23
  * ⚠️ THE CREATE PATH IS LEFT REACHABLE RATHER THAN STUBBED. A create that silently did nothing
24
24
  * would be the same lie as the stubbed delete resource.ts's ★ refuses; the honest arrangement
25
25
  * is a create that works and a header that says what it produces.
@@ -31,8 +31,8 @@
31
31
  * that owns the lease, or to a human who is watching.
32
32
  *
33
33
  * ⚠️ THERE IS A SECOND WRITER TO THESE OBJECTS AND IT IS THE ONE THIS PROVIDER RUNS ON. OpenBao's
34
- * `proxmox-tb4` engine mints PVE tokens under `hf-read@pve` and `hf-provision@pve` — read from
35
- * `house/platform/secrets/vault/plugin-proxmox/proxmox/`: `privsep=0` (client.go), `expire` set
34
+ * `proxmox-c1` engine mints PVE tokens under `hf-read@pve` and `hf-provision@pve` — read from
35
+ * `<estate>/platform/secrets/vault/plugin-proxmox/proxmox/`: `privsep=0` (client.go), `expire` set
36
36
  * to the lease deadline, and an id the plugin CHOOSES,
37
37
  * `hf-<role>-<actor>-<entity6>-<stamp>-<nonce>` (tokenname.go). Revocation and WAL rollback look
38
38
  * up that one exact id (wal.go); neither sweeps a prefix. So the two systems cannot collide on
@@ -59,7 +59,7 @@ import * as Provider from 'alchemy/Provider';
59
59
  import { type PveRequirements, type WithTarget } from './resource.ts';
60
60
  export interface ApiTokenProps extends WithTarget {
61
61
  /**
62
- * The account that owns the token, realm-qualified: `tofu@pve`, `root@pam`. Identity.
62
+ * The account that owns the token, realm-qualified: `iac@pve`, `root@pam`. Identity.
63
63
  *
64
64
  * ⚠️ THE ACCOUNT MUST ALREADY EXIST. Every method here runs `check_user_exist` first, so a
65
65
  * token named under a missing user fails the READ (folded to "absent") and then fails the
@@ -117,7 +117,7 @@ export interface ApiTokenProps extends WithTarget {
117
117
  * — `$privsep = $privsep ? 1 : 0` (AccessControl.pm:1622), so there is no unset state to
118
118
  * preserve. Were this optional, adopting a live token without mentioning `privsep` would plan
119
119
  * an update to 1 and STRIP a working credential of every privilege it has, silently: PVE
120
- * returns 401/403 to the service, nothing errors here, and `tofu@pve!apply` simply stops
120
+ * returns 401/403 to the service, nothing errors here, and `iac@pve!apply` simply stops
121
121
  * working. Required, so adopting a token is a sentence that states what it is.
122
122
  * ⚠️ AND `false` IS NOT A SHRUG. It is a token with its owner's whole privilege set; under a
123
123
  * provisioning account that is the account's full authority with a separate secret.
@@ -139,9 +139,9 @@ export interface ProxmoxApiToken extends Resource<'Proxmox.ApiToken', ApiTokenPr
139
139
  * ★ `retain` BY DEFAULT, AND THIS IS THE PLAINEST CASE FOR IT IN THE PACKAGE. A token's contents
140
140
  * are one irreplaceable secret: delete it and the value is gone, a replacement is a DIFFERENT
141
141
  * value, and every holder loses access the instant `cfs_write_file` returns — with no error
142
- * raised anywhere near them. The live cluster's tokens are `monitoring@pve!exporter` (the PVE
143
- * exporter feeding VictoriaMetrics), `mcp@pve!executor`, `tofu@pve!apply`, `tofu@pve!ro`,
144
- * `sablier@pve!sablier` and `vaultmint@pve!engine` — the last being the parent credential the
142
+ * raised anywhere near them. The live cluster's tokens are `metrics@pve!exporter` (the PVE
143
+ * exporter feeding VictoriaMetrics), `agent@pve!executor`, `iac@pve!apply`, `iac@pve!ro`,
144
+ * `app@pve!app` and `mint@pve!engine` — the last being the parent credential the
145
145
  * OpenBao mount itself authenticates with, so orphaning that one would stop every plan in this
146
146
  * package, this resource included. `delete` is FULLY IMPLEMENTED (DELETE is a real method on
147
147
  * this path, measured) and runs the moment a caller opts in with `.pipe(RemovalPolicy.destroy())`.
@@ -150,7 +150,7 @@ export interface ProxmoxApiToken extends Resource<'Proxmox.ApiToken', ApiTokenPr
150
150
  export declare const ProxmoxApiToken: import("alchemy").ResourceClass<ProxmoxApiToken>;
151
151
  /**
152
152
  * ⛔ `list` IS EMPTY, AND FOR THIS FAMILY THAT MATTERS MORE THAN THE GENERIC ARGUMENT IN
153
- * resource.ts. A token index handed to Alchemy would offer up `vaultmint@pve!engine` and every
153
+ * resource.ts. A token index handed to Alchemy would offer up `mint@pve!engine` and every
154
154
  * live OpenBao lease for adoption — and adoption is what makes a later plan willing to delete.
155
155
  * The mount's leases in particular appear and vanish on their own; anything that adopted one
156
156
  * would report drift against a credential that was never its to hold.
@@ -9,7 +9,7 @@
9
9
  * here decides a diff; `findRow` picks a row out of an answer its caller already fetched.
10
10
  *
11
11
  * ⛔ THE TWO PATHS ARE DIFFERENT AND THAT IS THE WHOLE REASON THIS FILE HAS TWO OF THEM. MEASURED
12
- * on n2, 2026-09-13: there is no GET on the id path — `pvesh get /nodes/n2/ceph/mon/n2` answers
12
+ * on node-b, 2026-09-13: there is no GET on the id path — `pvesh get /nodes/node-b/ceph/mon/node-b` answers
13
13
  * "No 'get' handler defined" — while POST and DELETE are registered ONLY there. So the read uses
14
14
  * `collectionPath` and the two writes use `daemonPath`, and swapping either one is a silent
15
15
  * 501: a create that never lands, or a destroy that reports failure while the daemon runs on.
@@ -38,8 +38,8 @@ import type { CephDaemonProps } from './ceph-daemon.ts';
38
38
  export declare const daemonId: (props: CephDaemonProps) => string;
39
39
  /**
40
40
  * The read path. ⚠️ `{node}` HERE IS ONLY THE NODE BEING ASKED, not a filter. MEASURED:
41
- * `GET /nodes/n2/ceph/mon` returns n2, n3 AND n4, and `GET /nodes/n3/ceph/mon` returns the same
42
- * three IN A DIFFERENT ORDER — [n4,n2,n3] from n2 against [n3,n2,n4] from n3. A caller that took
41
+ * `GET /nodes/node-b/ceph/mon` returns node-b, node-c AND node-d, and `GET /nodes/node-c/ceph/mon` returns the same
42
+ * three IN A DIFFERENT ORDER — [node-d,node-b,node-c] from node-b against [node-c,node-b,node-d] from node-c. A caller that took
43
43
  * row zero, or assumed the list was this node's daemons, would be wrong on both counts.
44
44
  */
45
45
  export declare const collectionPath: (props: CephDaemonProps) => string;
@@ -2,7 +2,7 @@
2
2
  * `Proxmox.CephDaemon` — a Ceph monitor, manager or metadata server on one node.
3
3
  *
4
4
  * ★ ONE RESOURCE FOR THREE KINDS, AND THE SCHEMAS WERE CHECKED BEFORE THAT WAS DECIDED. Parsed
5
- * from `/usr/share/pve-docs/api-viewer/apidoc.js` on n2, 2026-09-13: mon, mgr and mds each
5
+ * from `/usr/share/pve-docs/api-viewer/apidoc.js` on node-b, 2026-09-13: mon, mgr and mds each
6
6
  * expose GET on the collection and POST + DELETE on the id below it, each returns
7
7
  * name/host/state/addr/ceph_version*, and the only divergence is the create parameter
8
8
  * (`mon-address` / none / `hotstandby`) and the read-only extras (mon: quorum, rank; mds: rank,
@@ -10,11 +10,11 @@
10
10
  * times over and let them drift — the argument resource.ts already makes for the factory itself.
11
11
  *
12
12
  * ⛔ THE ONLY GET IS THE COLLECTION'S, AND IT ANSWERS FOR THE WHOLE CLUSTER. MEASURED:
13
- * `GET /nodes/n2/ceph/mon` returns n2, n3 AND n4, and `GET /nodes/n3/ceph/mon` returns the same
14
- * three IN A DIFFERENT ORDER — [n4,n2,n3] from n2, [n3,n2,n4] from n3 — so a row is found by
13
+ * `GET /nodes/node-b/ceph/mon` returns node-b, node-c AND node-d, and `GET /nodes/node-c/ceph/mon` returns the same
14
+ * three IN A DIFFERENT ORDER — [node-d,node-b,node-c] from node-b, [node-c,node-b,node-d] from node-c — so a row is found by
15
15
  * `name` and NEVER by position, and the `{node}` in the path is only the node being ASKED.
16
- * MEASURED too: there is no GET on the id path at all; `pvesh get /nodes/n2/ceph/mon/n2` answers
17
- * "No 'get' handler defined for '/nodes/n2/ceph/mon/n2'", and mgr and mds answer the same.
16
+ * MEASURED too: there is no GET on the id path at all; `pvesh get /nodes/node-b/ceph/mon/node-b` answers
17
+ * "No 'get' handler defined for '/nodes/node-b/ceph/mon/node-b'", and mgr and mds answer the same.
18
18
  * That is why `path()` below is the COLLECTION, and that in turn is why `delete` is the one
19
19
  * handler this file writes by hand: `pveOperations.destroy` sends its DELETE to `spec.path`,
20
20
  * which here would be the collection — a 501 reported as a failed destroy, with the daemon still
@@ -27,11 +27,11 @@
27
27
  * strips its section from ceph.conf. THREE MONS TOLERATE ONE LOSS; TWO TOLERATE NONE. Removing
28
28
  * two in one deploy — or removing the mon on the node whose API is serving the call — loses
29
29
  * quorum, and a cluster without mon quorum BLOCKS every RBD and CephFS I/O rather than erroring
30
- * it, so on this cluster every guest on `cephtb4` hangs.
30
+ * it, so on this cluster every guest on `rbd-c1` hangs.
31
31
  * `mds`: destroying a STANDBY is a non-event; destroying the ACTIVE one fails CephFS over,
32
- * and with no standby left `cephfs-tb4` goes unavailable. `mgr`: no guest I/O depends on it, but
32
+ * and with no standby left `cephfs-c1` goes unavailable. `mgr`: no guest I/O depends on it, but
33
33
  * the last one takes the PG autoscaler, the dashboard and PVE's own Ceph status with it.
34
- * Live on 2026-09-13: mon, mgr AND mds on each of n2, n3, n4.
34
+ * Live on 2026-09-13: mon, mgr AND mds on each of node-b, node-c, node-d.
35
35
  *
36
36
  * ★ AND THE ONLY WAY TO REACH THAT DESTROY IS TO DELETE THE DECLARATION. `matches` is deliberately
37
37
  * total (see its ⛔), so this resource CANNOT plan a `replace` — which is the one action that
@@ -41,7 +41,7 @@
41
41
  * `Sys.Audit`/`Datastore.Audit` on `/`, and PVEAuditor holds both (MEASURED:
42
42
  * `GET /access/roles/PVEAuditor`), so the mount's `read` role can see this family — unlike
43
43
  * `Proxmox.Storage`, which 403s under that lease. POST and DELETE both check `Sys.Modify` on
44
- * `/`, and MEASURED on this cluster `LXCProvisioner` already holds it, so the provision lane
44
+ * `/`, and MEASURED on this cluster the provision role already held it (it is in `PROVISION_PRIVILEGES`), so the provision lane
45
45
  * needs no widening for once. ⚠️ `Sys.Modify` on the ROOT path is broad — it also buys
46
46
  * datacenter options and every other cluster-wide config write — so it is worth knowing that
47
47
  * this credential already has it rather than discovering it the next time something is scoped.
@@ -80,9 +80,9 @@ export interface CephDaemonProps extends WithTarget {
80
80
  name?: string;
81
81
  /**
82
82
  * mon only. Overrides the autodetected monitor IP; must sit in Ceph's public network — on this
83
- * cluster that is 10.20.11.0/24, carried by `vmbr1.11`.
83
+ * cluster that is 198.51.100.0/24, carried by `vmbr1.42`.
84
84
  * ⛔ CREATE-ONLY AND NEVER COMPARED. PVE takes a bare ip-list on write and hands back `addr` as
85
- * `10.20.11.12:6789/0` — an address, a port and a nonce. The two are not the same string and
85
+ * `198.51.100.12:6789/0` — an address, a port and a nonce. The two are not the same string and
86
86
  * never will be, so diffing them would report a mismatch on every plan; with no PUT on this
87
87
  * family that mismatch becomes a REPLACE, and a replace of a mon is the quorum loss in the
88
88
  * header. Left out of `matches` on purpose.
@@ -92,7 +92,7 @@ export interface CephDaemonProps extends WithTarget {
92
92
  * mds only. Makes this standby replay the active MDS's journal for a faster failover.
93
93
  * ⛔ CREATE-ONLY AND NEVER COMPARED, AND THE FIELD THAT LOOKS LIKE ITS READBACK IS NOT ONE.
94
94
  * `standby_replay` in the list is the daemon's CURRENT state, not its configuration: MEASURED
95
- * 2026-09-13, all three mds report `standby_replay: false`, n3 included — and n3 is the ACTIVE
95
+ * 2026-09-13, all three mds report `standby_replay: false`, node-c included — and node-c is the ACTIVE
96
96
  * mds, which is not a standby at all and so can never report true however it was created.
97
97
  * Comparing `hotstandby` to it would plan a replace against whichever mds Ceph happens to have
98
98
  * elected, i.e. against a value no declaration controls.
@@ -121,22 +121,22 @@ export interface CephDaemonAttributes {
121
121
  host: string;
122
122
  /**
123
123
  * mon `running`/`stopped`/`unknown`, mgr `active`/`standby`, mds `up:active`/`up:standby`/…
124
- * ⛔ CEPH ELECTS THIS AND REWRITES IT WITHOUT ANYONE DECLARING ANYTHING. MEASURED: mgr n2 is
125
- * `active` while n3 and n4 are `standby`; mds n3 is `up:active` while n2 and n4 are
124
+ * ⛔ CEPH ELECTS THIS AND REWRITES IT WITHOUT ANYONE DECLARING ANYTHING. MEASURED: mgr node-b is
125
+ * `active` while node-c and node-d are `standby`; mds node-c is `up:active` while node-b and node-d are
126
126
  * `up:standby`. Restart a daemon and the roles move. It is reported so a plan can show what is
127
127
  * live and kept out of `matches` so that an election is never a diff.
128
128
  * ⚠️ IT ALSO MEANS THIS RESOURCE DOES NOT MANAGE WHETHER THE DAEMON IS RUNNING. A configured but
129
129
  * stopped daemon is still a row in the list, so it reads as present and plans `noop`.
130
130
  */
131
131
  state: string;
132
- /** Ceph-formatted, e.g. `10.20.11.12:6789/0`. Reported; see `mon-address` for why never compared. */
132
+ /** Ceph-formatted, e.g. `198.51.100.12:6789/0`. Reported; see `mon-address` for why never compared. */
133
133
  addr: string;
134
134
  /** `ceph_version_short`, e.g. `20.2.2`. Reported: a straggler after an upgrade is worth seeing. */
135
135
  version: string;
136
136
  /**
137
137
  * mon rank in the monmap, mds rank in the filesystem, `-1` when the daemon has neither.
138
- * ⛔ CEPH ASSIGNS IT AND NOTHING DECLARES IT. MEASURED: the mons are ranked n4=0, n3=1, n2=2 —
139
- * monmap order, not declaration order — and the mds ranks are 0 for the active n3 and -1 for
138
+ * ⛔ CEPH ASSIGNS IT AND NOTHING DECLARES IT. MEASURED: the mons are ranked node-d=0, node-c=1, node-b=2 —
139
+ * monmap order, not declaration order — and the mds ranks are 0 for the active node-c and -1 for
140
140
  * the two standbys. Rank moves when a daemon is added, removed or restarted.
141
141
  */
142
142
  rank: number;
@@ -145,8 +145,8 @@ export interface CephDaemonAttributes {
145
145
  /** mds only, and NOT the readback of `hotstandby` — see the ⛔ on that prop. */
146
146
  standbyReplay: boolean;
147
147
  /**
148
- * mds only: the CephFS this daemon currently serves — `cephfs-tb4` here.
149
- * ⛔ PRESENT ONLY ON THE ACTIVE MDS. MEASURED: n3 carries `fs_name`, n2 and n4 have no such key
148
+ * mds only: the CephFS this daemon currently serves — `cephfs-c1` here.
149
+ * ⛔ PRESENT ONLY ON THE ACTIVE MDS. MEASURED: node-c carries `fs_name`, node-b and node-d have no such key
150
150
  * at all. So it is empty for two of three identical declarations, and comparing it would
151
151
  * report work on exactly the daemons that are healthy standbys.
152
152
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ceph-daemon.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AAGnF;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEnD,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,IAAI,EAAE,cAAc,CAAC;IACrB;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,qGAAqG;IACrG,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,MAAM,EAAE,OAAO,CAAC;IAChB,+EAA+E;IAC/E,aAAa,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAkB,SAAQ,QAAQ,CACjD,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,oDAE5B,CAAC;AA+CH,eAAO,MAAM,yBAAyB,uIAoBnC,CAAC"}
1
+ {"version":3,"file":"ceph-daemon.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AAGnF;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEnD,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,IAAI,EAAE,cAAc,CAAC;IACrB;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,uGAAuG;IACvG,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,MAAM,EAAE,OAAO,CAAC;IAChB,+EAA+E;IAC/E,aAAa,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAkB,SAAQ,QAAQ,CACjD,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,oDAE5B,CAAC;AA+CH,eAAO,MAAM,yBAAyB,uIAoBnC,CAAC"}
@@ -2,7 +2,7 @@
2
2
  * `Proxmox.CephFlag` — one cluster-wide Ceph OSD flag, declared: `noout`, `pause`, `norebalance`.
3
3
  *
4
4
  * ★ ONE RESOURCE PER FLAG, NOT ONE CARRYING ALL ELEVEN, AND THE CLUSTER'S OWN API DECIDED IT.
5
- * MEASURED on TB4 2026-09-13 (pve-manager 9.2.11, ceph tentacle 20.2.2) by reading
5
+ * MEASURED on C1 2026-09-13 (pve-manager 9.2.11, ceph tentacle 20.2.2) by reading
6
6
  * `/usr/share/perl5/PVE/API2/Cluster/Ceph.pm` and the published schema in
7
7
  * `/usr/share/pve-docs/api-viewer/apidoc.js`:
8
8
  * · `PUT /cluster/ceph/flags` ends in `fork_worker('cephsetflags', ...)` and returns a STRING
@@ -30,7 +30,7 @@
30
30
  * defaulting to false would make `CephFlag('noout', { flag: 'noout', target })` mean "clear
31
31
  * it" — the dangerous direction, chosen by OMISSION. Here the dangerous sentence has to be
32
32
  * typed out by a person. Do not add a default, and do not declare a flag merely to document
33
- * that it is off: MEASURED 2026-09-13, all eleven flags on TB4 read 0, so eleven
33
+ * that it is off: MEASURED 2026-09-13, all eleven flags on C1 read 0, so eleven
34
34
  * `value: false` lines would plan green forever and do nothing except take the brake off
35
35
  * whenever somebody happens to apply them.
36
36
  *
@@ -58,8 +58,8 @@
58
58
  * and plans `noop` straight past it. It cannot express a half-pause, so never use it to prove
59
59
  * one is gone; `ceph osd dump | head -1` can.
60
60
  * ⛔ `pause` AND `noup` ARE ALSO THE TWO THAT TAKE THE CLUSTER DOWN FROM A TYPO. `pause: true`
61
- * stops all reads and writes, so every guest on `cephtb4` — the cluster's only rbd pool,
62
- * MEASURED 2026-09-13 — freezes on its root disk, and so does `cephfs-tb4`. `noup: true`
61
+ * stops all reads and writes, so every guest on `rbd-c1` — the cluster's only rbd pool,
62
+ * MEASURED 2026-09-13 — freezes on its root disk, and so does `cephfs-c1`. `noup: true`
63
63
  * stops a rebooted OSD from ever rejoining. Neither is undone by deleting the line.
64
64
  *
65
65
  * ⚠️ PRIVILEGES, AND THE WRITE ONE IS A BIG ASK. Both GETs check `Sys.Audit` on `/`; both PUTs
@@ -80,7 +80,7 @@ import { type PveRequirements, type WithTarget } from './resource.ts';
80
80
  *
81
81
  * ⚠️ THE ENUM IS CLOSED AND A TYPO IS A 400, WHICH IS WHY THIS IS A UNION AND NOT `string`. Both
82
82
  * the GET and the PUT declare `additionalProperties => 0` over exactly this list.
83
- * ⚠️ CEPH HAS FLAGS PVE DOES NOT MODEL, and four of them are always on. MEASURED on TB4:
83
+ * ⚠️ CEPH HAS FLAGS PVE DOES NOT MODEL, and four of them are always on. MEASURED on C1:
84
84
  * `ceph osd dump` reports `flags sortbitwise,recovery_deletes,purged_snapdirs,pglog_hardlimit`.
85
85
  * PVE reads that same string and answers only about its own eleven, so the others can neither
86
86
  * leak in here nor be set from here — `noautoscale` and `nosnaptrim` included.
@@ -16,7 +16,7 @@
16
16
  *
17
17
  * ⛔ POST AND DELETE ANSWER WITH A UPID, NOT A RESULT — THE WRITE IS ASYNCHRONOUS AND A FAILED ONE
18
18
  * IS STILL HTTP 200. Read from the cluster's own source, /usr/share/perl5/PVE/API2/Ceph/FS.pm on
19
- * n2: `createfs` and `destroyfs` both end `return $rpcenv->fork_worker(...)`. Two different lies
19
+ * node-b: `createfs` and `destroyfs` both end `return $rpcenv->fork_worker(...)`. Two different lies
20
20
  * come out of trusting that status code. A read-back straight after the POST reports "still
21
21
  * absent" about a filesystem that is being built as it says so — which is precisely the message
22
22
  * `pveOperations.reconcile` would print, pointing at the wrong cause. And a worker that dies
@@ -26,7 +26,7 @@
26
26
  * has not been observed; only the `fork_worker` that guarantees it is there.
27
27
  *
28
28
  * ⛔ A DELETE BODY IS SILENTLY DISCARDED BY PVE, SO `remove-pools` GOES IN THE QUERY STRING.
29
- * MEASURED in /usr/share/perl5/PVE/APIServer/AnyEvent.pm on n2: line 928 reads the request
29
+ * MEASURED in /usr/share/perl5/PVE/APIServer/AnyEvent.pm on node-b: line 928 reads the request
30
30
  * content into params only `if ($method eq 'PUT' || $method eq 'POST')`, and line 1653 sends
31
31
  * every other method down a branch that parses `$request->url->query()` and nothing else. So
32
32
  * `pve(target, role, 'DELETE', path, form)` would send a body PVE never looks at: the flags would
@@ -41,7 +41,7 @@
41
41
  * ⛔ THE POLLER IS NEVER THE TASK'S OWNER, WHICH COSTS A PRIVILEGE, AND THIS ONE IS MEASURED
42
42
  * RATHER THAN FEARED. client.ts mints a fresh credential per call and the mount vends a NEW
43
43
  * token id each time, so the token reading the status is never the token recorded in the UPID —
44
- * and PVE compares them exactly. /usr/share/perl5/PVE/API2/Tasks.pm on n2, `$check_task_user`:
44
+ * and PVE compares them exactly. /usr/share/perl5/PVE/API2/Tasks.pm on node-b, `$check_task_user`:
45
45
  * `return $user eq $fulltoken || $user eq $task->{user};`, above it the comment "token only sees
46
46
  * token tasks, user sees user + token tasks". Token B of the same user matches neither branch.
47
47
  * So the fallback is the schema's other clause for `GET /nodes/{node}/tasks/{upid}/status`: "The
@@ -75,8 +75,8 @@ export declare const createForm: (props: CephFsProps) => Record<string, string>;
75
75
  *
76
76
  * ⚠️ A CREATE NEEDS A RUNNING *AND* A STANDBY MDS, and refuses BEFORE it forks -- "no running
77
77
  * Metadata Server (MDS) found!" / "no standby Metadata Server (MDS) found!" are synchronous, so
78
- * they surface as a failed POST rather than as a silent worker. TB4 has three (MEASURED: n3
79
- * `up:active` for cephfs-tb4, n2 and n4 `up:standby`), so this is a note for a smaller cluster.
78
+ * they surface as a failed POST rather than as a silent worker. C1 has three (MEASURED: node-c
79
+ * `up:active` for cephfs-c1, node-b and node-d `up:standby`), so this is a note for a smaller cluster.
80
80
  * ⚠️ BOTH WRITES CHECK `Sys.Modify` ON `/` -- the root, with the breadth metric-server.ts warns
81
81
  * about: granting it buys datacenter options and every other cluster-wide config write too.
82
82
  */
@@ -2,7 +2,7 @@
2
2
  * `Proxmox.CephFs` — a CephFS on the cluster's own Ceph. The filesystem a `cephfs` storage mounts.
3
3
  *
4
4
  * ⛔ A REPLACE OF THIS RESOURCE DESTROYS A LIVE FILESYSTEM, AND THERE IS NO PUT TO SAVE YOU FROM
5
- * IT. MEASURED from the published schema on n2, 2026-09-13: `/nodes/{node}/ceph/fs/{name}` has
5
+ * IT. MEASURED from the published schema on node-b, 2026-09-13: `/nodes/{node}/ceph/fs/{name}` has
6
6
  * exactly two methods, POST and DELETE. A CephFS cannot be edited in place, so `updateForm` is
7
7
  * left undefined and anything the factory can see as changed becomes a REPLACE — and Alchemy's
8
8
  * replace is create-then-delete, where the delete is `destroyfs`: the entry leaves the MDS map,
@@ -12,9 +12,9 @@
12
12
  * one it is a live filesystem destroyed on every deploy, forever, because a background daemon
13
13
  * moved a number nobody declared.
14
14
  *
15
- * ⛔ THERE IS NO SINGLE-OBJECT READ, WHICH INVERTS `path` AND `collection`. MEASURED on n2:
16
- * pvesh get /nodes/n2/ceph/fs/cephfs-tb4
17
- * -> No 'get' handler defined for '/nodes/n2/ceph/fs/cephfs-tb4'
15
+ * ⛔ THERE IS NO SINGLE-OBJECT READ, WHICH INVERTS `path` AND `collection`. MEASURED on node-b:
16
+ * pvesh get /nodes/node-b/ceph/fs/cephfs-c1
17
+ * -> No 'get' handler defined for '/nodes/node-b/ceph/fs/cephfs-c1'
18
18
  * `GET /nodes/{node}/ceph/fs` is a directory index and is the only read there is, so `path()`
19
19
  * below returns the INDEX and `attributes` picks this filesystem out of the array client-side —
20
20
  * the shape acl.ts uses for the one flat `GET /access/acl`. The POST goes to the `{name}` path,
@@ -28,9 +28,9 @@
28
28
  *
29
29
  * ⛔ CREATING A CephFS CREATES TWO CEPH POOLS, AND A `Proxmox.CephPool` MUST NOT ALSO DECLARE THEM.
30
30
  * `createfs` builds `<name>_data` and `<name>_metadata` itself and refuses outright if either
31
- * exists ("ceph pools '…_data' and/or '…_metadata' already exist"). MEASURED on TB4: the live
32
- * `cephfs-tb4` owns `cephfs-tb4_data` (id 6) and `cephfs-tb4_metadata` (id 7), both of which
33
- * `GET /nodes/n2/ceph/pool` lists like any other pool — and `/nodes/{node}/ceph/pool/{name}` DOES
31
+ * exists ("ceph pools '…_data' and/or '…_metadata' already exist"). MEASURED on C1: the live
32
+ * `cephfs-c1` owns `cephfs-c1_data` (id 6) and `cephfs-c1_metadata` (id 7), both of which
33
+ * `GET /nodes/node-b/ceph/pool` lists like any other pool — and `/nodes/{node}/ceph/pool/{name}` DOES
34
34
  * have GET, PUT and DELETE, so a pool resource would be a clean `pveHandlers` fit and would
35
35
  * adopt them without noticing. Declaring both is double management of one object: whichever
36
36
  * reconciles first wins, and the loser either fails its create or PUTs `size`/`pg_num` onto pools
@@ -38,16 +38,16 @@
38
38
  *
39
39
  * ⚠️ `add-storage` IS A SECOND SIDE EFFECT AND IT LANDS IN storage.cfg. Set, `createfs` also calls
40
40
  * `PVE::API2::Storage::Config->create` with type `cephfs`, content `backup,iso,vztmpl` and
41
- * `fs-name <name>`. MEASURED: /etc/pve/storage.cfg on n2 holds exactly that — `cephfs:
42
- * cephfs-tb4` / `content backup,vztmpl,iso` / `fs-name cephfs-tb4`. So a `Proxmox.Storage`
43
- * declaring `cephfs-tb4` would be managing an entry this resource created. Declare ONE of them:
41
+ * `fs-name <name>`. MEASURED: /etc/pve/storage.cfg on node-b holds exactly that — `cephfs:
42
+ * cephfs-c1` / `content backup,vztmpl,iso` / `fs-name cephfs-c1`. So a `Proxmox.Storage`
43
+ * declaring `cephfs-c1` would be managing an entry this resource created. Declare ONE of them:
44
44
  * either `add-storage` here and no storage resource, or `add-storage` off and a
45
45
  * `Proxmox.Storage` that reads this resource's `name` attribute — which also gets the ordering
46
46
  * right for free, because Alchemy orders by data flow.
47
47
  *
48
48
  * ⚠️ `node` IS A ROUTE, NOT IDENTITY, AND MUST NEVER BE DIFFED. A CephFS is cluster-wide; the node
49
- * in the path only says which node PVE proxies the call to. MEASURED: `GET /nodes/n2/ceph/fs`,
50
- * `…/n3/…` and `…/n4/…` returned the byte-identical array. So changing `node` plans `noop`, and
49
+ * in the path only says which node PVE proxies the call to. MEASURED: `GET /nodes/node-b/ceph/fs`,
50
+ * `…/node-c/…` and `…/node-d/…` returned the byte-identical array. So changing `node` plans `noop`, and
51
51
  * two resources naming the same `name` on different nodes are the SAME filesystem — the vmid
52
52
  * hazard from lxc.ts, with a filesystem on the end of it instead of a container.
53
53
  *
@@ -72,11 +72,11 @@ export interface CephFsProps extends WithTarget {
72
72
  * this is under 32. PVE's default is 128.
73
73
  *
74
74
  * ⛔ CREATE-TIME ONLY, UNREADABLE, AND OWNED BY THE AUTOSCALER FROM THE SECOND IT LANDS. It is
75
- * never compared — see the ⛔ on `matches` — and this is not caution, it is measured. TB4's
76
- * `cephfs-tb4` was created with the default 128 (the arithmetic proves it: `cephfs-tb4_metadata`
77
- * sits at 32, which is 128/4), and `cephfs-tb4_data` reads pg_num 32 TODAY. The autoscaler moved
75
+ * never compared — see the ⛔ on `matches` — and this is not caution, it is measured. C1's
76
+ * `cephfs-c1` was created with the default 128 (the arithmetic proves it: `cephfs-c1_metadata`
77
+ * sits at 32, which is 128/4), and `cephfs-c1_data` reads pg_num 32 TODAY. The autoscaler moved
78
78
  * it by a factor of four, and it is not finished: `pg_autoscale_mode` is `on` for every pool on
79
- * this cluster and `cephfs-tb4_metadata` already reports `pg_num_final: 16` against its live 32.
79
+ * this cluster and `cephfs-c1_metadata` already reports `pg_num_final: 16` against its live 32.
80
80
  */
81
81
  pg_num?: number;
82
82
  /**
@@ -11,13 +11,13 @@
11
11
  * `CephOsdProps` is a cycle on paper only: it is erased before anything runs.
12
12
  *
13
13
  * ⛔ `GET /nodes/{node}/ceph/osd` ANSWERS A TREE, NOT A LIST, AND IT IS THE WHOLE CLUSTER'S TREE.
14
- * MEASURED 2026-09-13: asked of n2 it answers `{"flags":…,"root":{"children":[…]}}` whose
15
- * leaves include osd.0 and osd.5 on n4; asked of n3 it answers the identical six leaves. The
14
+ * MEASURED 2026-09-13: asked of node-b it answers `{"flags":…,"root":{"children":[…]}}` whose
15
+ * leaves include osd.0 and osd.5 on node-d; asked of node-c it answers the identical six leaves. The
16
16
  * `{node}` in the path chooses WHO ANSWERS, not what is listed. A provider that read it as "the
17
- * OSDs on this node" would find osd.0 through n2 and then report it as living there.
17
+ * OSDs on this node" would find osd.0 through node-b and then report it as living there.
18
18
  *
19
19
  * ⛔ AND THE SINGLE-OBJECT PATH CANNOT BE USED INSTEAD — THIS WALK EXISTS BECAUSE IT LIES.
20
- * MEASURED: `GET /nodes/n2/ceph/osd/99`, an id with no OSD behind it, answers HTTP 200 with
20
+ * MEASURED: `GET /nodes/node-b/ceph/osd/99`, an id with no OSD behind it, answers HTTP 200 with
21
21
  * `[{"name":"metadata"},{"name":"lv-info"}]` — byte for byte what `…/osd/2` answers for a real
22
22
  * one. It is a directory index (its schema says `permissions: {"user":"all"}`), not a read of
23
23
  * the OSD. Point `PveSpec.path` at it and every declared OSD is "present": `diff` reports
@@ -25,18 +25,18 @@
25
25
  * stops this package recording objects that do not exist — passes on an OSD that was never
26
26
  * built. The only endpoint that can tell present from absent is the tree.
27
27
  *
28
- * ★ MEASURED ON TB4 ON 2026-09-13, `GET /nodes/n2/ceph/osd`. Six leaves, all `up` and `in`, Ceph
28
+ * ★ MEASURED ON C1 ON 2026-09-13, `GET /nodes/node-b/ceph/osd`. Six leaves, all `up` and `in`, Ceph
29
29
  * 20.2.2 tentacle:
30
30
  *
31
- * id name host device_class crush_weight reweight pgs status
32
- * 0 osd.0 n4 ssd 1.86299133300781 1 99 up
33
- * 5 osd.5 n4 ssd 1.86299133300781 1 94 up
34
- * 1 osd.1 n3 ssd 1.86299133300781 1 96 up
35
- * 4 osd.4 n3 ssd 1.81939697265625 1 97 up
36
- * 2 osd.2 n2 ssd 1.81939697265625 1 88 up
37
- * 3 osd.3 n2 ssd 1.81939697265625 1 105 up
31
+ * id name host device_class crush_weight reweight pgs status
32
+ * 0 osd.0 node-d ssd 1.86299133300781 1 99 up
33
+ * 5 osd.5 node-d ssd 1.86299133300781 1 94 up
34
+ * 1 osd.1 node-c ssd 1.86299133300781 1 96 up
35
+ * 4 osd.4 node-c ssd 1.81939697265625 1 97 up
36
+ * 2 osd.2 node-b ssd 1.81939697265625 1 88 up
37
+ * 3 osd.3 node-b ssd 1.81939697265625 1 105 up
38
38
  *
39
- * `{ node: 'n2', osdid: 2, host: 'n2', device_class: 'ssd' }` plans `noop` against that row.
39
+ * `{ node: 'node-b', osdid: 2, host: 'node-b', device_class: 'ssd' }` plans `noop` against that row.
40
40
  * That is the acceptance test this file was written to pass.
41
41
  *
42
42
  * ⚠️ EVERY OTHER COLUMN IS REPORTED AND NEVER COMPARED, FOR FOUR DIFFERENT REASONS. `pgs` is the
@@ -63,8 +63,8 @@ type CrushNode = Record<string, unknown>;
63
63
  /**
64
64
  * Every OSD leaf under the tree root, at any depth.
65
65
  *
66
- * ⚠️ RECURSIVE BECAUSE THE TREE IS NOT THREE LEVELS DEEP BY LAW. TB4 measures as
67
- * root(`default`) -> host(n2|n3|n4) -> osd, but CRUSH admits datacenter, rack and chassis
66
+ * ⚠️ RECURSIVE BECAUSE THE TREE IS NOT THREE LEVELS DEEP BY LAW. C1 measures as
67
+ * root(`default`) -> host(node-b|node-c|node-d) -> osd, but CRUSH admits datacenter, rack and chassis
68
68
  * buckets between them, and an OSD created outside a host bucket hangs off the root. Reaching
69
69
  * in as `root.children[].children[]` would read this cluster correctly and answer "absent" —
70
70
  * i.e. "the replica is gone" — on the first cluster that has a rack in it.
@@ -128,7 +128,7 @@ export interface CephOsdAttributes {
128
128
  * ⚠️ THE TELEMETRY IS DELIBERATELY DROPPED, NOT FORGOTTEN. The leaf also carries `bytes_used`,
129
129
  * `percent_used`, `apply_latency_ms` and `commit_latency_ms`. MEASURED, AND THE MEASUREMENT SAYS
130
130
  * THE OPPOSITE OF WHAT YOU WOULD EXPECT: across two reads minutes apart, all four were identical
131
- * on every OSD, and both latencies read 0 — TB4 was idle, so nothing was caught in the act. That
131
+ * on every OSD, and both latencies read 0 — C1 was idle, so nothing was caught in the act. That
132
132
  * these move is therefore REASONED, from what they count, not observed. Alchemy persists
133
133
  * attributes; on a cluster doing work, keeping them would rewrite all six resources' state on
134
134
  * every deploy and record a number that is stale by the time anybody reads it. What is kept is