clearotron 0.2.4 → 0.3.0-beta.1

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 (235) hide show
  1. package/.env.example +13 -2
  2. package/CONTRIBUTING.md +1 -1
  3. package/INSTALL.md +62 -38
  4. package/bin/brandowner.mjs +18 -169
  5. package/bin/clearotron.mjs +3 -1
  6. package/bin/connect.mjs +28 -19
  7. package/bin/disconnect.mjs +3 -3
  8. package/bin/example.mjs +7 -7
  9. package/bin/framework-preflight.mjs +49 -0
  10. package/bin/grant.mjs +151 -93
  11. package/bin/onboard.mjs +220 -138
  12. package/bin/start.mjs +146 -137
  13. package/bin/stop.mjs +2 -2
  14. package/bin/update.mjs +1 -1
  15. package/build-info.json +2 -2
  16. package/docs/CLIENT-MCP.md +2 -2
  17. package/docs/E2E.md +12 -2
  18. package/docs/ONBOARDING.md +1 -1
  19. package/docs/PORTAL.md +14 -13
  20. package/docs/SECURITY.md +23 -24
  21. package/docs/architecture/04-configuration-reference.md +12 -5
  22. package/docs/architecture/05-config-governance.md +7 -7
  23. package/docs/architecture/07-quality-and-audit.md +1 -1
  24. package/docs/architecture/08-development-guide.md +5 -0
  25. package/docs/configuration.md +118 -0
  26. package/docs/decisions/0004-documentation-structure.md +2 -2
  27. package/docs/decisions/0006-what-the-public-repository-carries.md +2 -2
  28. package/driver/CHANGELOG.md +70 -0
  29. package/driver/ask-ledger.mjs +2 -2
  30. package/driver/cancel.mjs +27 -0
  31. package/driver/case-law-sources.mjs +3 -3
  32. package/driver/company-bundle.mjs +261 -0
  33. package/driver/compare.mjs +1 -1
  34. package/driver/compose-read.mjs +2 -2
  35. package/driver/config-inventory.mjs +2 -2
  36. package/driver/contract-audit.mjs +1 -1
  37. package/driver/contract-e3-backlog.mjs +1 -1
  38. package/driver/contract-vocabulary.mjs +1 -1
  39. package/driver/declination-call.mjs +1 -1
  40. package/driver/deliver-trigger.sh +3 -3
  41. package/driver/dev-portal.mjs +3 -1
  42. package/driver/digest-queue.mjs +1 -1
  43. package/driver/disposition-tool.mjs +1 -1
  44. package/driver/doc-constants.mjs +1 -1
  45. package/driver/drain-posture.mjs +2 -2
  46. package/driver/drainer-identity.mjs +1 -1
  47. package/driver/driver.config.mjs +44 -9
  48. package/driver/effective-scope.mjs +30 -1
  49. package/driver/effort-model.mjs +6 -6
  50. package/driver/engine/CONTRACT.md +2 -2
  51. package/driver/engine/anthropic-agent.mjs +11 -11
  52. package/driver/engine/jx-turn.mjs +1 -1
  53. package/driver/engine/mcp/gather-config.mjs +29 -4
  54. package/driver/engine/mcp/recording-server.mjs +73 -1
  55. package/driver/engine/openai-agent.mjs +1 -1
  56. package/driver/engine/probe.mjs +28 -4
  57. package/driver/enqueue-schema.mjs +23 -3
  58. package/driver/findings-model.mjs +2 -2
  59. package/driver/flag-snapshot.mjs +2 -2
  60. package/driver/floor-duty.mjs +2 -2
  61. package/driver/frame-diff-model.mjs +1 -1
  62. package/driver/framework-preflight.mjs +143 -0
  63. package/driver/gateway.mjs +9 -1
  64. package/driver/hit-list.mjs +1 -1
  65. package/driver/jx-lanes.mjs +1 -1
  66. package/driver/jx.mjs +1 -1
  67. package/driver/knockout-assess-record.mjs +1 -1
  68. package/driver/knockout-review-record.mjs +435 -0
  69. package/driver/order-probe.mjs +1 -1
  70. package/driver/outbox-backoff.mjs +2 -2
  71. package/driver/owner-use-check.mjs +2 -2
  72. package/driver/package.json +1 -1
  73. package/driver/pipeline-knockout.mjs +105 -8
  74. package/driver/pipeline.mjs +81 -30
  75. package/driver/plain-register.mjs +77 -3
  76. package/driver/portal-access.mjs +141 -74
  77. package/driver/portal-config-view.mjs +59 -70
  78. package/driver/portal-report.mjs +4 -4
  79. package/driver/portal-service.mjs +348 -141
  80. package/driver/portal-upstream.mjs +105 -17
  81. package/driver/predelivery-lint.mjs +43 -18
  82. package/driver/product-rows.mjs +1 -1
  83. package/driver/products.mjs +1 -1
  84. package/driver/profile-page.html +30 -5
  85. package/driver/profile-service.mjs +197 -26
  86. package/driver/profiles.mjs +48 -1
  87. package/driver/publish/index.mjs +31 -13
  88. package/driver/publish/knockout.mjs +9 -5
  89. package/driver/publish/office-record-links.mjs +189 -0
  90. package/driver/publish/parse.mjs +3 -3
  91. package/driver/publish/publish-inputs.mjs +26 -0
  92. package/driver/publish/render-knockout.mjs +42 -42
  93. package/driver/publish/render.mjs +29 -4
  94. package/driver/publish/report-data.mjs +2 -2
  95. package/driver/publish/seed-pool.mjs +1 -1
  96. package/driver/publish/templates/report.css +8 -8
  97. package/driver/publish/xlsx.mjs +49 -7
  98. package/driver/queue-watch-verdict.mjs +2 -2
  99. package/driver/recipe-service.mjs +1 -1
  100. package/driver/record-carry.mjs +1 -1
  101. package/driver/reference-score.mjs +1 -1
  102. package/driver/reference-strip-signatures.mjs +1 -1
  103. package/driver/register-availability.mjs +4 -3
  104. package/driver/register-count.mjs +3 -3
  105. package/driver/register-records.mjs +1 -1
  106. package/driver/repair-composers.mjs +1 -1
  107. package/driver/repairs.mjs +3 -3
  108. package/driver/replay-archive.mjs +1 -1
  109. package/driver/report-card-record.mjs +1 -1
  110. package/driver/result-noun-fields.mjs +5 -0
  111. package/driver/roster-verdict.mjs +48 -5
  112. package/driver/run-activity.mjs +1 -1
  113. package/driver/run-requirements.mjs +18 -5
  114. package/driver/runner.mjs +24 -15
  115. package/driver/search-policy.mjs +8 -8
  116. package/driver/senior-rights.mjs +1 -1
  117. package/driver/skills/prelim-search/delivery-contract.md +1 -1
  118. package/driver/skills/prelim-search/risk-framework-triage.md +10 -7
  119. package/driver/stages-knockout.mjs +72 -6
  120. package/driver/stages.mjs +10 -10
  121. package/driver/suite-census.json +238 -70
  122. package/driver/synthesis-record.mjs +2 -2
  123. package/driver/systemd/clearotron-client-mcp.service +3 -3
  124. package/driver/systemd/clearotron-deploy.service +2 -2
  125. package/driver/systemd/clearotron-mcp-face.service +1 -1
  126. package/driver/systemd/clearotron-portal.service +3 -3
  127. package/driver/systemd/clearotron-worker.service +5 -5
  128. package/driver/systemd/install-census.mjs +1 -1
  129. package/driver/systemd/render-units.mjs +9 -9
  130. package/driver/terminal-clamp.mjs +1 -1
  131. package/driver/trigger-cap.mjs +18 -2
  132. package/driver/unit-inventory.mjs +8 -8
  133. package/driver/usage-ledger.mjs +5 -3
  134. package/driver/verify-knockout.mjs +7 -7
  135. package/driver/verify.mjs +5 -5
  136. package/driver/whatif-memo-run.mjs +1 -1
  137. package/driver/whatif-queue.mjs +3 -3
  138. package/driver/whatif-worker.mjs +2 -2
  139. package/examples/README.md +1 -1
  140. package/examples/grants.example.json +25 -24
  141. package/mcp-server/CHANGELOG.md +10 -0
  142. package/mcp-server/http-server.mjs +3 -3
  143. package/mcp-server/key-socket.mjs +1 -1
  144. package/mcp-server/lib/audit-view.mjs +3 -3
  145. package/mcp-server/lib/brief.mjs +3 -3
  146. package/mcp-server/lib/driver.mjs +1 -1
  147. package/mcp-server/lib/events.mjs +1 -1
  148. package/mcp-server/lib/http-handler.mjs +2 -2
  149. package/mcp-server/lib/instructions.mjs +2 -2
  150. package/mcp-server/lib/knockout.mjs +1 -1
  151. package/mcp-server/lib/ops.mjs +6 -3
  152. package/mcp-server/lib/options.mjs +15 -4
  153. package/mcp-server/lib/plan.mjs +7 -6
  154. package/mcp-server/lib/runs.mjs +10 -0
  155. package/mcp-server/lib/whatif.mjs +5 -5
  156. package/mcp-server/package.json +1 -1
  157. package/mcp-server/packs/README.md +1 -1
  158. package/mcp-server/remote/client-mcp-apikey.service +1 -1
  159. package/mcp-server/remote/client-mcp.service +2 -2
  160. package/mcp-server/remote/trademark-artifacts-http.service +1 -1
  161. package/mcp-server/server.mjs +38 -24
  162. package/package.json +2 -2
  163. package/portal-ui/dist/assets/{index-KFAHMgdT.js → index-CWTHP0sH.js} +3471 -1901
  164. package/portal-ui/dist/assets/{index-1ziUJX1E.css → index-KpytsmNH.css} +79 -26
  165. package/portal-ui/dist/index.html +2 -2
  166. package/portal-ui/package.json +1 -1
  167. package/providers/_shared/lane-probe.mjs +9 -3
  168. package/providers/jx-subclass/lookup.mjs +1 -1
  169. package/providers/oauth-mcp-bridge/CHANGELOG.md +4 -0
  170. package/providers/oauth-mcp-bridge/package.json +1 -1
  171. package/providers/oauth-mcp-bridge/systemd/courtlistener-mcp.service +1 -1
  172. package/scripts/citation-drift-report.mjs +1 -1
  173. package/scripts/citation-line-check.mjs +2 -2
  174. package/scripts/drive-env-check.mjs +1 -1
  175. package/scripts/e2e.mjs +5 -5
  176. package/scripts/env-audit.mjs +13 -1
  177. package/scripts/headless-page.mjs +5 -5
  178. package/scripts/live-surface-check.mjs +26 -2
  179. package/scripts/mint-names-in-force.mjs +19 -5
  180. package/scripts/mint-reference-strip-backlog.mjs +1 -1
  181. package/scripts/mint-suite-census.mjs +37 -10
  182. package/scripts/pack-publishable.mjs +1 -1
  183. package/scripts/preinstall-node-check.mjs +1 -1
  184. package/scripts/release-await-cut.mjs +3 -3
  185. package/scripts/release-cut-decision.mjs +1 -1
  186. package/scripts/release-dist-tag.mjs +1 -1
  187. package/scripts/release-install-check.mjs +1 -1
  188. package/scripts/release-notes-lint.mjs +1 -1
  189. package/scripts/release-publish-guard.mjs +1 -1
  190. package/scripts/release-version-pr-checks.mjs +2 -2
  191. package/scripts/release-version.mjs +61 -5
  192. package/scripts/render-brand-banner.mjs +1 -1
  193. package/scripts/render-check.mjs +2 -2
  194. package/scripts/repo-writes.mjs +1 -1
  195. package/scripts/report-frame-check.mjs +1 -1
  196. package/scripts/report-screenshot.mjs +2 -2
  197. package/scripts/retire-bare-refs.mjs +1 -1
  198. package/scripts/revisit-render-check.mjs +1 -1
  199. package/scripts/score.mjs +1 -1
  200. package/scripts/strip-titles-and-attributions.mjs +389 -0
  201. package/scripts/strip-tracker-citations.mjs +122 -5
  202. package/scripts/test-run.mjs +4 -4
  203. package/scripts/third-party-notices.mjs +1 -1
  204. package/scripts/verify-publishable.mjs +1 -1
  205. package/shared/access-audience.mjs +2 -2
  206. package/shared/anon-overlay.mjs +1 -1
  207. package/shared/brand.mjs +15 -1
  208. package/shared/bundle-freshness.mjs +1 -1
  209. package/shared/bundle-rebuild.mjs +1 -1
  210. package/shared/checkout-move.mjs +2 -2
  211. package/shared/client-door.mjs +8 -8
  212. package/shared/connect-clients.mjs +7 -7
  213. package/shared/connector-signin-probe.mjs +1 -1
  214. package/shared/env-aliases.mjs +1 -1
  215. package/shared/env-local.mjs +5 -5
  216. package/shared/grants-edit.mjs +76 -0
  217. package/shared/install-auth.mjs +1 -1
  218. package/shared/listen.mjs +3 -3
  219. package/shared/mcp-challenge.mjs +1 -1
  220. package/shared/names-in-force.mjs +2 -1
  221. package/shared/onboarding-store.mjs +19 -2
  222. package/shared/reference-guard-classes.mjs +44 -2
  223. package/shared/register-selection.mjs +1 -1
  224. package/shared/scope.mjs +223 -56
  225. package/shared/secret-file.mjs +1 -1
  226. package/shared/server-units.mjs +1 -1
  227. package/shared/staff-domain.mjs +45 -78
  228. package/shared/summary-blocks.mjs +2 -2
  229. package/shared/systemd-failure.mjs +3 -3
  230. package/shared/tracked-files.mjs +1 -1
  231. package/shared/trigger-lane.mjs +1 -1
  232. package/shared/tty-style.mjs +1 -1
  233. package/shared/usage-block.mjs +1 -1
  234. package/shared/vacuous-pass.mjs +1 -1
  235. package/shared/verb-shim.mjs +1 -1
@@ -1,40 +1,28 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-only
2
2
  // Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
3
- // staff-domain.mjs — what a staff-domain rule ADMITS, decided before one is written.
3
+ // staff-domain.mjs — the sign-in addresses setup and `clearotron start` refuse, and why.
4
4
  //
5
- // `PORTAL_STAFF_DOMAINS` is a list of email domains, and every address at a listed domain that gets
6
- // past this instance's sign-in door is staff: it sees every brand owner on the instance
7
- // (driver/portal-access.mjs). That is a rule about a set of people, not about one person.
5
+ // This module used to decide what a staff-domain rule would admit, because the install built one from
6
+ // everything after the `@` of the address it was given. That rule is deleted: a person is admitted by
7
+ // their own entry in the grants file (shared/scope.mjs `resolvePerson`), and nothing about the part of an
8
+ // address after its `@` admits anyone. The person who installs is the first person, with access to
9
+ // everything (bin/start.mjs `installerGrants`).
8
10
  //
9
- // The install used to build that rule by taking everything after the last `@` of the one address it
10
- // was given. On a laptop that address is `<account>@localhost` and the rule admits the one identity
11
- // that can sign in, which is why it was safe and why nobody looked at it again. Given a real address
12
- // the same line turns a person into their whole employer, or into every customer of a webmail
13
- // provider, with nothing said to the operator and nothing to undo. A stranger's install granted a
14
- // documentation domain that way, read its own settings page back, and reported it as a back door.
11
+ // Two refusals about the ADDRESS ITSELF outlive the rule, and this module owns the second:
15
12
  //
16
- // So the derivation is classified before it is used, and there are three answers:
13
+ // not a single email address refused where it is typed (bin/onboard.mjs `askSignIn`, bin/start.mjs),
14
+ // because the portal refuses a multi-`@` identity outright.
15
+ // a public or reserved domain refused here. The address becomes the first person, with access to
16
+ // everything, and a personal mailbox at a webmail provider is not an
17
+ // address an organisation controls. A domain reserved for documentation
18
+ // receives no real mail, so an address there is a placeholder somebody
19
+ // typed — which is how an outside install came to be set up in the name of
20
+ // nobody.
17
21
  //
18
- // "narrow" the domain cannot name a second person on this machine — `localhost`, or any bare
19
- // hostname with no dot. Deriving a rule from it is what it always was: safe, silent.
20
- // "public" a webmail or shared provider. Never a staff rule: it would admit strangers, and no
21
- // deployment can want it. Refused outright, and the refusal names the domain.
22
- // "reserved" a domain reserved for documentation and testing (RFC 2606). Nobody's real mail lives
23
- // there, so a rule built from one is always an address somebody typed as a placeholder.
24
- // Refused for the same reason, with a different sentence, because the remedy differs.
25
- // "wide" an ordinary routable domain. It may well be the right rule — it is how a firm admits
26
- // its own lawyers — but it admits people the operator has not met, so it is stated in
27
- // the words the settings page will use and confirmed before it is written. It is never
28
- // derived silently from one address.
29
- //
30
- // FAIL-CLOSED, in the direction of a smaller grant. A domain wrongly classified `public` refuses, and
31
- // the operator sets `PORTAL_STAFF_DOMAINS` themselves in one line — an explicit decision, recorded
32
- // where the settings page can name it. A domain wrongly classified `wide` asks a question. Neither
33
- // outcome grants anything, which is why the lists below are allowed to be short and stay short: the
34
- // `wide` branch is what actually protects an operator, and the lists only decide whether the product
35
- // asks a question or refuses to ask one.
22
+ // The lists stay short on purpose. An unlisted provider is accepted, and since the domain rule went an
23
+ // accepted address admits that one address and nobody else, so a miss admits no stranger.
36
24
 
37
- /** Last-@ semantics, matching driver/portal-access.mjs and shared/scope.mjs `isFirmDomain`. */
25
+ /** Last-@ semantics, matching shared/scope.mjs `resolvePerson`. */
38
26
  export function domainOfEmail(email) {
39
27
  const e = String(email ?? "").trim().toLowerCase();
40
28
  const at = e.lastIndexOf("@");
@@ -44,10 +32,9 @@ export function domainOfEmail(email) {
44
32
  /**
45
33
  * Webmail and shared mailbox providers, exactly.
46
34
  *
47
- * Not a census of the internet, and deliberately not growing into one: an unlisted provider still
48
- * lands in `wide`, where it is stated and confirmed rather than written silently. What this list buys
49
- * is that the commonest addresses a person types — their own personal mail — are refused with a
50
- * sentence about why, instead of being offered as a rule somebody might say yes to.
35
+ * Not a census of the internet, and deliberately not growing into one: an unlisted provider is accepted.
36
+ * What this list buys is that the commonest addresses a person types — their own personal mail — are
37
+ * sent back with a sentence about why.
51
38
  */
52
39
  export const PUBLIC_EMAIL_DOMAINS = Object.freeze(new Set([
53
40
  "gmail.com", "googlemail.com", "icloud.com", "me.com", "mac.com",
@@ -81,10 +68,10 @@ export const PUBLIC_EMAIL_FAMILIES = Object.freeze(new Set([
81
68
  *
82
69
  * `example.com`, `example.net`, `example.org` and everything under them, plus the whole of the
83
70
  * `.example`, `.invalid`, `.test` and `.localhost` top-level names. Real mail is never delivered to
84
- * any of them, so an address at one is a placeholder somebody typed — which is exactly what happened.
71
+ * any of them, so an address at one is a placeholder somebody typed.
85
72
  *
86
- * `localhost` ITSELF IS NOT HERE. A bare `localhost` is the local-account default and is classified
87
- * `narrow` below; only `something.localhost` reaches this test.
73
+ * `localhost` ITSELF IS NOT HERE. A bare `localhost` is the local-account default, `<account>@localhost`,
74
+ * and every first install takes it; only `something.localhost` reaches this test.
88
75
  */
89
76
  function isReservedDomain(domain) {
90
77
  if (/^example\.(com|net|org)$/.test(domain)) return true;
@@ -93,62 +80,42 @@ function isReservedDomain(domain) {
93
80
  return domain.includes(".") && ["example", "invalid", "test", "localhost"].includes(tld);
94
81
  }
95
82
 
96
- /** A domain that cannot name a second person on this machine: `localhost`, or any dotless hostname. */
97
- function isNarrowDomain(domain) {
98
- return domain === "localhost" || domain === "localhost.localdomain" || !domain.includes(".");
99
- }
100
-
101
83
  /**
102
- * What a staff rule built from this domain would admit.
84
+ * Whether an address at this domain may be the one that signs in.
103
85
  *
104
- * @param {string} domain a bare domain, already lowercased — `domainOfEmail` produces one.
105
- * @returns {"narrow"|"public"|"reserved"|"wide"|""} "" only when there is no domain to classify.
86
+ * @param {string} domain a bare domain — `domainOfEmail` produces one.
87
+ * @returns {"public"|"reserved"|"accepted"|""} "" only when there is no domain to classify.
106
88
  */
107
- export function classifyStaffDomain(domain) {
89
+ export function classifyAddressDomain(domain) {
108
90
  const d = String(domain ?? "").trim().toLowerCase();
109
91
  if (!d) return "";
110
- if (isNarrowDomain(d)) return "narrow";
111
92
  if (isReservedDomain(d)) return "reserved";
112
93
  if (PUBLIC_EMAIL_DOMAINS.has(d)) return "public";
113
- if (PUBLIC_EMAIL_FAMILIES.has(d.slice(0, d.indexOf(".")))) return "public";
114
- return "wide";
94
+ if (d.includes(".") && PUBLIC_EMAIL_FAMILIES.has(d.slice(0, d.indexOf(".")))) return "public";
95
+ return "accepted";
115
96
  }
116
97
 
117
98
  /**
118
- * The rule in the words the settings page uses, so the operator recognises what they agreed to.
99
+ * Why this address cannot be the one that signs in, or null when it can.
119
100
  *
120
- * ONE COMPOSER FOR BOTH SURFACES. The People & access screen renders "Anyone at <domain>" under a
121
- * heading that calls it a config rule rather than a person, and describes staff as capable of seeing
122
- * every brand owner. A consent prompt phrased any other way asks about one thing and shows another.
101
+ * NAMES THE SETTING, because the reader's next act is to change it: the address is `PORTAL_LOCAL_USER`
102
+ * whether it arrived from setup's question, from `--user` or from the environment file.
123
103
  */
124
- export function staffGrantSentence(domain, { staffLabel = "Staff" } = {}) {
125
- return `Anyone at ${domain} — a rule, not a person. ${staffLabel}: capable to see every brand owner `
126
- + "on this instance.";
127
- }
128
-
129
- /**
130
- * Why this domain cannot become a staff rule, and what to do instead.
131
- *
132
- * Returns null for a domain that CAN — `narrow` and `wide` are not refusals, and `wide` is answered by
133
- * the confirmation the caller runs, not by this function.
134
- */
135
- export function staffDomainRefusal(domain, { variable = "PORTAL_STAFF_DOMAINS" } = {}) {
136
- const d = String(domain ?? "").trim().toLowerCase();
137
- const verdict = classifyStaffDomain(d);
104
+ export function addressRefusal(email) {
105
+ const d = domainOfEmail(email);
106
+ const verdict = classifyAddressDomain(d);
138
107
  if (verdict === "public") {
139
- return `${d} is a public email provider, so a staff rule built from it would admit anyone with an `
140
- + `address there — not your colleagues. Refusing to write one.\n`
141
- + ` Use an address at a domain your organisation controls, or set ${variable} yourself to the `
142
- + "domain you mean.\n"
143
- + " If this machine is only yours, the local-account form takes no rule at all: leave the "
144
- + "address as <account>@localhost.";
108
+ return `${d} is a public email provider. The address that signs in here becomes the first person on `
109
+ + "this install, with access to everything, and a personal mailbox is not an address your "
110
+ + "organisation controls. Refusing it.\n"
111
+ + " Use an address at your organisation's own domain as PORTAL_LOCAL_USER, or, if this machine is "
112
+ + "only yours, the local-account form <account>@localhost.";
145
113
  }
146
114
  if (verdict === "reserved") {
147
- return `${d} is reserved for documentation and receives no real mail (RFC 2606), so it is an `
148
- + "address somebody typed as a placeholder rather than one that signs in. Refusing to build a "
149
- + "staff rule from it.\n"
150
- + " Use the address you actually sign in with, or the local-account form <account>@localhost "
151
- + "if this machine is only yours.";
115
+ return `${d} is reserved for documentation and receives no real mail (RFC 2606), so this is an `
116
+ + "address somebody typed as a placeholder rather than one that signs in. Refusing it.\n"
117
+ + " Set PORTAL_LOCAL_USER to the address you actually sign in with, or to the local-account form "
118
+ + "<account>@localhost if this machine is only yours.";
152
119
  }
153
120
  return null;
154
121
  }
@@ -2,8 +2,8 @@
2
2
  // Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
3
3
  // THE SUMMARY'S BLOCK GRAMMAR — one definition, because it has four readers.
4
4
  //
5
- // Owner ruling 2026-08-31 (tracker issues 1934 and 2056): "keep the length, add the structure, so long
6
- // as length is consistent more or less." The assess seat now writes sub-headers and bullets inside the
5
+ // Decided 2026-08-31: keep the length and add the structure, so long as length stays
6
+ // broadly consistent. The assess seat now writes sub-headers and bullets inside the
7
7
  // summary it emits, and FOUR surfaces read that string back:
8
8
  //
9
9
  // driver/publish/render-knockout.mjs the per-mark report and the grouped HTML
@@ -5,7 +5,7 @@
5
5
  //
6
6
  // ── ONE DEFINITION, BECAUSE THE SECOND CALLER HAD NONE ───────────────────────────────────────────────
7
7
  //
8
- // `connect` learned this the expensive way (tracker issue 121): its `systemctl` calls ran with
8
+ // `connect` learned this the expensive way: its `systemctl` calls ran with
9
9
  // `stdio: "ignore"`, so systemd's own explanation was thrown away before anyone could read it and the
10
10
  // whole output was `connect: Command failed: systemctl --user daemon-reload`; and the session-bus remedy
11
11
  // was appended to EVERY failure, so a unit that would not start for a bound port or a bad ExecStart was
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // `start --background` never learned it. Its `enable --now` loop ran uncaught, so the same refusal
16
16
  // arrived as a raw Node stack trace — `at genericNodeError (node:internal/errors:983:15)`, a status
17
- // code, and no statement of what had happened to the install (tracker issue 203). That is the failure
17
+ // code, and no statement of what had happened to the install. That is the failure
18
18
  // `shared/listen.mjs` was written to end one layer down, and its rule is the rule here: an unrecognised
19
19
  // failure still gets a sentence and still exits non-zero; what it must not do is arrive as a stack trace
20
20
  // with no statement of consequence.
@@ -31,7 +31,7 @@ import { existsSync } from "node:fs";
31
31
  /**
32
32
  * Does this failure say the SESSION BUS is missing, rather than anything about the unit?
33
33
  *
34
- * ONE AUTHORITY, because more than one reader asks it (tracker issue 130, criterion 3). The failure text
34
+ * ONE AUTHORITY, because more than one reader asks it (criterion 3). The failure text
35
35
  * below offers the bus remedy on a yes, and connect's health reader refuses to translate a yes into "the
36
36
  * door is not open" — that mistranslation is the defect, and a second copy of this test is how the two
37
37
  * would come to disagree about which failures are bus failures.
@@ -117,7 +117,7 @@ export function grepTrackedFiles(guard, { root, args }) {
117
117
  /**
118
118
  * The tracked corpus WITH ITS INDEX MODES, or null when this tree has no checkout to read it from.
119
119
  *
120
- * WHY THIS IS HERE RATHER THAN LEFT TO ITS ONE CALLER (tracker issue 235). The executable-bits guard
120
+ * WHY THIS IS HERE RATHER THAN LEFT TO ITS ONE CALLER. The executable-bits guard
121
121
  * needs `ls-files -s`, which carries the mode, and `trackedFiles` above deliberately returns paths
122
122
  * only. So that guard called the helper for its skip contract and then spawned git a SECOND time,
123
123
  * raw, for the modes — correct, because the raw call sits behind the helper's null check, but
@@ -135,7 +135,7 @@ export function triggerLaneVerdict({ url = null, hasToken = false, verbs = null,
135
135
  message: `the trigger lane answers at ${raw}${probe.status ? ` (${probe.status})` : ""}${challengeNote(challenge)}` };
136
136
  }
137
137
  const why = probe.error ? probe.error : `it answered ${probe.status}`;
138
- // ── A DOOR THAT IS NOT LISTENING YET IS NOT A DOOR THAT IS DOWN (tracker issue 222) ───────────────
138
+ // ── A DOOR THAT IS NOT LISTENING YET IS NOT A DOOR THAT IS DOWN ───────────────────────────────────
139
139
  //
140
140
  // On a simultaneous restart of the unit set the portal binds before the engine door does — the units
141
141
  // carry no ordering between them — and this branch logged an OUTAGE in the present indicative, with a
@@ -2,7 +2,7 @@
2
2
  // Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
3
3
  // tty-style.mjs — weight where the meaning is, and NOTHING when the reader is not a terminal.
4
4
  //
5
- // ── why this exists (owner ruling 2026-08-31) ────────────────────────────────────
5
+ // ── why this exists (ruling 2026-08-31) ────────────────────────────────────
6
6
  //
7
7
  // "new terminals can do things like bold and colours etc — good formatting impresses people because it's
8
8
  // made clear to them someone put the time in." That is a product argument, not a decorative one: setup
@@ -2,7 +2,7 @@
2
2
  // Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
3
3
  // ── The synopsis a verb prints for --help, read out of its own header ─────────────────────────────
4
4
  //
5
- // tracker issues 1861 and 1882. Four verbs printed their LICENCE HEADER as the first line of `--help`:
5
+ // Four verbs printed their LICENCE HEADER as the first line of `--help`:
6
6
  //
7
7
  // $ npx clearotron doctor --help
8
8
  // SPDX-License-Identifier: AGPL-3.0-only
@@ -29,7 +29,7 @@
29
29
  //
30
30
  // The GATED (env-conditional) member named in is NOT here: measured on the same tree, the
31
31
  // dominant `if (process.env.X …)` idiom is save/restore teardown, which guards no assertion and cannot
32
- // pass vacuously. Ruled out as measured-harmless (owner ruling 2026-08-20) rather than left unbuilt.
32
+ // pass vacuously. Ruled out as measured-harmless (ruling 2026-08-20) rather than left unbuilt.
33
33
 
34
34
  /**
35
35
  * THE REMEDY, at the site. Wrap the set a loop walks:
@@ -7,7 +7,7 @@
7
7
  // directory, and got `npm error could not determine executable to run`. Not our error, naming no
8
8
  // product, suggesting no fix. `npx` resolves a local package by walking UP from the current directory
9
9
  // to find node_modules, so every command this product prints worked only where the reader happened to
10
- // be standing. Owner ruling, 2026-08-26: put the verb on PATH.
10
+ // be standing. Ruling, 2026-08-26: put the verb on PATH.
11
11
  //
12
12
  // WHY A PER-USER SHIM AND NOT `npm link`. `npm link` writes to npm's global prefix, which on a default
13
13
  // install is `/usr` and refuses without root (recorded, which is why that issue