@geonosis/doctor 1.3.0 → 2.0.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.
@@ -3,7 +3,7 @@ import {
3
3
  formatDoctor,
4
4
  formatJson,
5
5
  runDoctor
6
- } from "./chunk-7BRGHYQR.js";
6
+ } from "./chunk-SMCRXSH5.js";
7
7
 
8
8
  // src/doctor-cli.ts
9
9
  import { resolve } from "path";
@@ -21,27 +21,59 @@ var ABOUT = {
21
21
  drift: `The gates that were set up and are no longer running: a CI job switched off by a
22
22
  condition that can never be true, a test file under a workspace with no test script, a
23
23
  script handing bun/node/tsx a file that is not on disk, a workspace bin nothing links,
24
- an integration directory the registry never names, a geonosis bin a git hook calls
25
- through pnpm/npx/bunx and therefore cannot start, a law over the ceiling its own
24
+ an integration directory the registry never names, a package lint script narrower
25
+ than the hook beside it, an allowBuilds entry naming one platform of a split package,
26
+ an observability package nothing composes, a law over the ceiling its own
26
27
  geonosis.json declared, nothing enabling the plugin in either scope, and a
27
28
  geonosis.json block no manifest declares a package for (or the reverse).`,
29
+ envelope: `The arithmetic under every other line: for each .geonosis/envelopes/<tool>.json a gate
30
+ wrote, considered === read + refused + excused. Four denominator bugs landed in one
31
+ day and every one of them was GREEN \u2014 a migrations run that reported on three of four
32
+ files, a plan check that printed "PASS \u2014 0 plan(s)" over a directory of twenty-one, a
33
+ parity run over a tree the second config ignored. Each published a numerator and no
34
+ denominator. Reads the files and imports nothing of the tools that wrote them; no
35
+ envelopes at all is a SKIP with the sentence.`,
28
36
  exercised: `Every rule a config enables, against the corpus the loaded plugin ships. A rule at
29
- "error" that can never fire is indistinguishable from a clean tree.`,
37
+ "error" that can never fire is indistinguishable from a clean tree. The line says what
38
+ its number is evidence ABOUT \u2014 the corpus and the probes, never this tree \u2014 and a rule
39
+ that PRESUMES an engine no manifest here declares is a WARN of its own: enabled where
40
+ the engine is absent it has no possible finding, which is the same green.`,
41
+ group: `The packages that are published on ONE version, asked of every workspace: one copy
42
+ repo-wide, and one number per workspace. A consumer carried @geonosis/visual-diff at
43
+ 1.1.0 and 1.4.0 in one tree while every other line read green, because they are all
44
+ scoped to the plugin a config names. Membership ships with the kit; a repo declares
45
+ its OWN held-together sets under doctor.groups in geonosis.json. Asked of the
46
+ resolver, never of find, and UNJUDGED when the tree installs none of the group.
47
+ It also reads what the ROOT declares: the door (@geonosis/cli, or the geonosis
48
+ metapackage) plus the bins the root's own scripts call by name, and nothing the door
49
+ already owns.`,
30
50
  loaded: `The plugin oxlint would LOAD from each config's directory, against the version that
31
51
  config's workspace DECLARES. oxlint resolves a jsPlugins specifier from the CONFIG
32
52
  FILE's directory, so a nested copy left behind by a per-workspace install runs while
33
53
  every manifest and the lockfile say otherwise \u2014 one consumer measured a whole bug
34
54
  report against 0.3.0 on a repo pinned to 0.4.0. Every copy is found by RESOLUTION,
35
- never by find: on pnpm the store keeps every version ever installed.`,
55
+ never by find: on pnpm the store keeps every version ever installed. It also reads
56
+ every committed git hook: a geonosis bin called through pnpm/npx/bunx cannot START,
57
+ because a hook's PATH carries no version-manager shim.`,
36
58
  observability: `The exporter named by the "observability" block in geonosis.json: is a sink
37
59
  configured, is its endpoint reachable (a HEAD with a short timeout), and did an event
38
60
  arrive inside maxAgeSeconds \u2014 read from the lastEventFile the sink writes, never from
39
61
  this tool importing the library it is checking. A deploy job reported success having
40
62
  deployed nothing and a /health answered ok over a dead database on the same
41
63
  afternoon; both left a green build and a silent project.`,
64
+ rails: `The egress an unattended run is bounded by, read back out of the settings that
65
+ actually LOAD rather than out of the file this repo rendered \u2014 D-038 one file over.
66
+ Claude Code merges sandbox.network.allowedDomains across the managed, user, project
67
+ and local scopes, and two measured things make a perfect render load as nothing: a
68
+ settings file that fails validation is SILENTLY ignored under -p, and a managed
69
+ allowManagedDomainsOnly makes every other scope's allow list ignored. deniedEgress in
70
+ .geonosis/rails-run.json is a GATE AT ZERO (D-025): one denied attempt fails, and it
71
+ is never a counter to hold flat.`,
42
72
  runner: `Workspaces whose test script's exit code is the only verdict. A pool exited 0 over
43
73
  suites it had just reported as failing, for weeks, in a consumer. A script with no
44
- test file under it is a SKIP \u2014 there is no result for an exit code to be wrong about.`
74
+ test file under it is a SKIP \u2014 there is no result for an exit code to be wrong about.
75
+ And whether anything here ever runs geonosis-ratchet --prove: a counter that has
76
+ never been seen reading its own planted finding reads exactly like a clean tree.`
45
77
  };
46
78
  var USAGE = `geonosis-doctor [--root <dir>] [--only <check,\u2026>] [--json] [--strict] [--baseline-against [<ref>]] [--oxlint <path>]
47
79
 
@@ -108,11 +140,16 @@ var parseDoctorArgs = (argv, cwd) => {
108
140
  };
109
141
  };
110
142
  var CONFIG_SHAPE = `geonosis-doctor reads geonosis.json, geonosis.ratchet.json, .oxlintrc.json,
111
- pnpm-workspace.yaml and .claude/settings.json
143
+ pnpm-workspace.yaml, .claude/settings.json and this repo's committed git hooks
112
144
 
113
145
  geonosis.json \u2192 "law"
114
146
  file string? the law file to measure (default "CLAUDE.md")
115
147
  maxLines number? the ceiling. Undeclared means UNJUDGED, never a default it fires on
148
+ geonosis.json \u2192 "doctor"
149
+ corpus string? the reach corpus this repo ships for its own rule options
150
+ groups object[]? { name, packages } sets of this repo's OWN packages that must resolve
151
+ to one version; declared and empty is a refusal. The kit's own fixed
152
+ group is checked when this is absent
116
153
  geonosis.json \u2192 "observability"
117
154
  sink string where this repo sends its errors
118
155
  endpoint string the URL that must be reachable
@@ -133,8 +170,22 @@ geonosis.ratchet.json
133
170
  pnpm-workspace.yaml
134
171
  publicHoistPattern string[] the packages this repo claims are linked at the root, read as
135
172
  text; a "*" is the only wildcard and it spans "/"
136
- .claude/settings.json
137
- enabledPlugins object what installs the kit's plugin in THIS repo`;
173
+ lefthook.yml, .lefthook.yml, .husky/*, .githooks/*
174
+ every line, as text a geonosis bin run through pnpm/npx/bunx cannot START from a hook
175
+ geonosis.json \u2192 "rails.egress"
176
+ allow string[] the hosts an unattended run may reach. The rails line reads each one
177
+ back out of the settings that actually LOAD, never out of the file
178
+ this repo rendered
179
+ deny string[] the hosts it may never reach
180
+ .claude/settings.json, .claude/settings.local.json, ~/.claude/settings.json,
181
+ /Library/Application Support/ClaudeCode/managed-settings.json (/etc/claude-code on Linux)
182
+ enabledPlugins object what installs the kit's plugin in THIS repo
183
+ sandbox.network.allowedDomains string[] merged across every scope above; a managed
184
+ allowManagedDomainsOnly makes every other scope's list ignored
185
+ sandbox.network.deniedDomains string[] what this repo renders its deny list into
186
+ .geonosis/rails-run.json
187
+ deniedEgress object[] what a run reached for and was refused. A GATE AT ZERO (D-025): one
188
+ entry fails, and it is never a counter to hold flat`;
138
189
  var main = async () => {
139
190
  const argv = process.argv.slice(2);
140
191
  if (argv.includes("--help") || argv.includes("-h")) {
package/dist/index.d.ts CHANGED
@@ -5,11 +5,13 @@ type Overrides = {
5
5
 
6
6
  /**
7
7
  * The questions a bump is not finished until something has asked, in the order a run asks them.
8
- * The first four are ways enforcement has reported green while measuring nothing; `drift` asks
9
- * whether the gate is still there at all; `observability` and `deployed` ask the same question one
10
- * layer out — whether what was reported is what happened.
8
+ * The first five are ways enforcement has reported green while measuring nothing; `envelope` asks
9
+ * the arithmetic underneath all of them — whether a gate read as many things as it was handed;
10
+ * `drift` asks whether the gate is still there at all; `observability` and `deployed` ask the same
11
+ * question one layer out — whether what was reported is what happened; `rails` asks it of the
12
+ * settings an unattended run is bounded by, where a rendered file is not a loaded setting.
11
13
  */
12
- declare const CHECKS: readonly ["loaded", "exercised", "baseline", "runner", "drift", "observability", "deployed"];
14
+ declare const CHECKS: readonly ["loaded", "group", "exercised", "baseline", "runner", "envelope", "drift", "observability", "deployed", "rails"];
13
15
  type CheckName = (typeof CHECKS)[number];
14
16
  /**
15
17
  * `SKIP` is a first-class answer and is printed like any other: a check whose line is missing reads
@@ -136,6 +138,14 @@ declare const readRatchet: (root: string) => RatchetConfig | undefined;
136
138
 
137
139
  declare const runDoctor: ({ baseline, only, oxlint, root, strict, }: DoctorOptions) => Promise<DoctorReport>;
138
140
 
141
+ /** The file `create-geonosis --domains` writes, held against the scaffold's own name by a test. */
142
+ declare const COMPOSITION_ROOT = "src/platform.ts";
143
+ /**
144
+ * The floors, as data a consumer's tree can read — the same reason `FIXED_GROUP` ships as a list: a
145
+ * consumer has none of the kit's workspace globs to glob. `tooling/group-membership.test.ts` holds
146
+ * it against the workspace, so a foundation or a domain added tomorrow cannot arrive unasked.
147
+ */
148
+ declare const FLOOR_PACKAGES: readonly string[];
139
149
  /** Which kit package reads which block of `geonosis.json`. */
140
150
  declare const READERS: Record<string, string>;
141
151
  /**
@@ -163,6 +173,27 @@ declare const checkDrift: ({ readers, root, userSettings, workspaces, }: {
163
173
  workspaces: Workspace[];
164
174
  }) => Finding[];
165
175
 
176
+ /**
177
+ * The one line that catches a denominator bug: for every envelope a tool wrote,
178
+ * `considered === read + refused + excused`.
179
+ *
180
+ * Four of them landed in one day, all green — a migrations run that reported on three of four
181
+ * files, a plan check that printed `PASS — 0 plan(s)` over a directory of twenty-one, a parity run
182
+ * over a tree the second config had ignored, a validator that walked a list it had already
183
+ * filtered. Every one published a numerator and no denominator, so nothing could be wrong.
184
+ *
185
+ * This READS the files and imports nothing of the tools that wrote them — the same discipline
186
+ * `deployed` and `observability` follow. A check that needed the package it checks cannot run in
187
+ * the tree where that package is missing, which is the first case it exists to find; and this one
188
+ * has to work over a consumer's `.geonosis/` with no kit installed at all. The arithmetic is
189
+ * duplicated here on purpose: it is one comparison over three numbers, and it is the check.
190
+ */
191
+ declare const ENVELOPES_DIR = ".geonosis/envelopes";
192
+ declare const NO_ENVELOPES = "no .geonosis/envelopes/*.json \u2014 the tools write one per run, so an absent envelope is a run nobody has made here yet, and it is not a balanced one";
193
+ declare const checkEnvelopes: ({ root }: {
194
+ root: string;
195
+ }) => Finding[];
196
+
166
197
  /**
167
198
  * The rules of one plugin a config actually turns on. A rule NAMED in a config is not a rule
168
199
  * enabled by it — `"off"` is how a config records a rule it decided against, and counting those as
@@ -187,6 +218,51 @@ declare const checkExercised: ({ config, corpus, entry, oxlint, repoCorpus, root
187
218
  root: string;
188
219
  }) => Promise<Finding>;
189
220
 
221
+ /**
222
+ * The packages that version as ONE number — the kit's method floor, as data a consumer's tree can
223
+ * read.
224
+ *
225
+ * It ships here rather than being derived where it is decided: a consumer has no
226
+ * `.changeset/config.json` and no workspace globs of the kit to glob, so the only form of this fact
227
+ * that survives an install is a list inside a published package. `tooling/group-membership.test.ts`
228
+ * holds it against the workspace and against every other door that names the group, so the list
229
+ * cannot drift from the floors it describes.
230
+ *
231
+ * Foundations and domains are absent on purpose (D-053): a floor package moves on a line of its
232
+ * own, and asking it to match this number would be the cadence coupling the floors exist to end.
233
+ */
234
+ declare const FIXED_GROUP: readonly string[];
235
+ /** A set of packages a repo declares must move together. The kit's own is the default. */
236
+ type HeldTogether = {
237
+ name: string;
238
+ packages: readonly string[];
239
+ };
240
+ declare const KIT_GROUP: HeldTogether;
241
+ /**
242
+ * The groups a repo declares for its OWN packages, under `doctor.groups` in `geonosis.json`. Law 6:
243
+ * the kit's group is the default and a repo that declares nothing gets it; a repo that declares the
244
+ * key and puts nothing in it is REFUSED, because "two copies are a bug" is a claim someone made and
245
+ * an empty list cannot hold it.
246
+ */
247
+ declare const declaredGroupsOf: (root: string) => HeldTogether[] | undefined;
248
+ /**
249
+ * #158 — the group question nothing asked.
250
+ *
251
+ * during.day carried `@geonosis/visual-diff` at 1.1.0 and 1.4.0 in one tree and every doctor line
252
+ * was green: `loaded` is scoped to the plugin a config names, so a second kit package at a second
253
+ * version is outside every question it asks. This is the consumer-side mirror of
254
+ * `geonosis-release published --group`.
255
+ *
256
+ * Asked of the RESOLVER from each workspace directory, never of `find` over `node_modules` — on
257
+ * pnpm the store keeps every version ever installed, so a count of directories answers nonsense on
258
+ * a correct tree.
259
+ */
260
+ declare const checkGroup: ({ groups, root, workspaces, }: {
261
+ groups?: readonly HeldTogether[];
262
+ root: string;
263
+ workspaces: Workspace[];
264
+ }) => Finding[];
265
+
190
266
  /** The scope this tool asks about. A config's other plugins are somebody else's release to check. */
191
267
  declare const SCOPE = "@geonosis/";
192
268
  /**
@@ -286,9 +362,10 @@ declare const relativeToRoot: (root: string, path: string) => string;
286
362
  * a WARN that names the wrong runner's sin is a line a reader learns to skip, and the lines it
287
363
  * teaches them to skip are the true ones next to it.
288
364
  */
289
- declare const checkRunner: ({ ratchet, workspaces, }: {
365
+ declare const checkRunner: ({ ratchet, root, workspaces, }: {
290
366
  ratchet?: RatchetConfig;
367
+ root: string;
291
368
  workspaces: Workspace[];
292
369
  }) => Finding[];
293
370
 
294
- export { CHECKS, CONFIG_FILE, type CheckName, DEPLOYED_FILE, type DiscoveredConfig, DoctorError, type DoctorOptions, type DoctorReport, type Finding, GEONOSIS_FILE, type LastEventRecord, MANIFEST_FILE, type Manifest, NOT_WRITTEN, type ObservabilityConfig, RATCHET_FILE, READERS, type RatchetConfig, SCOPE, type Verdict, type Workspace, checkBaseline, checkDeployed, checkDrift, checkExercised, checkLoaded, checkObservability, checkRunner, corpusOfPlugin, declaredFor, defaultRef, discoverConfigs, discoverWorkspaces, enabledRulesOf, formatDoctor, formatJson, packageDirOf, pluginVersionOf, readConfig, readRatchet, relativePath, relativeToRoot, repoCorpusOf, resolveFrom, runDoctor, satisfies };
371
+ export { CHECKS, COMPOSITION_ROOT, CONFIG_FILE, type CheckName, DEPLOYED_FILE, type DiscoveredConfig, DoctorError, type DoctorOptions, type DoctorReport, ENVELOPES_DIR, FIXED_GROUP, FLOOR_PACKAGES, type Finding, GEONOSIS_FILE, type HeldTogether, KIT_GROUP, type LastEventRecord, MANIFEST_FILE, type Manifest, NOT_WRITTEN, NO_ENVELOPES, type ObservabilityConfig, RATCHET_FILE, READERS, type RatchetConfig, SCOPE, type Verdict, type Workspace, checkBaseline, checkDeployed, checkDrift, checkEnvelopes, checkExercised, checkGroup, checkLoaded, checkObservability, checkRunner, corpusOfPlugin, declaredFor, declaredGroupsOf, defaultRef, discoverConfigs, discoverWorkspaces, enabledRulesOf, formatDoctor, formatJson, packageDirOf, pluginVersionOf, readConfig, readRatchet, relativePath, relativeToRoot, repoCorpusOf, resolveFrom, runDoctor, satisfies };
package/dist/index.js CHANGED
@@ -1,23 +1,32 @@
1
1
  import {
2
2
  CHECKS,
3
+ COMPOSITION_ROOT,
3
4
  CONFIG_FILE,
4
5
  DEPLOYED_FILE,
5
6
  DoctorError,
7
+ ENVELOPES_DIR,
8
+ FIXED_GROUP,
9
+ FLOOR_PACKAGES,
6
10
  GEONOSIS_FILE,
11
+ KIT_GROUP,
7
12
  MANIFEST_FILE,
8
13
  NOT_WRITTEN,
14
+ NO_ENVELOPES,
9
15
  RATCHET_FILE,
10
16
  READERS,
11
17
  SCOPE,
12
18
  checkBaseline,
13
19
  checkDeployed,
14
20
  checkDrift,
21
+ checkEnvelopes,
15
22
  checkExercised,
23
+ checkGroup,
16
24
  checkLoaded,
17
25
  checkObservability,
18
26
  checkRunner,
19
27
  corpusOfPlugin,
20
28
  declaredFor,
29
+ declaredGroupsOf,
21
30
  defaultRef,
22
31
  discoverConfigs,
23
32
  discoverWorkspaces,
@@ -34,27 +43,36 @@ import {
34
43
  resolveFrom,
35
44
  runDoctor,
36
45
  satisfies
37
- } from "./chunk-7BRGHYQR.js";
46
+ } from "./chunk-SMCRXSH5.js";
38
47
  export {
39
48
  CHECKS,
49
+ COMPOSITION_ROOT,
40
50
  CONFIG_FILE,
41
51
  DEPLOYED_FILE,
42
52
  DoctorError,
53
+ ENVELOPES_DIR,
54
+ FIXED_GROUP,
55
+ FLOOR_PACKAGES,
43
56
  GEONOSIS_FILE,
57
+ KIT_GROUP,
44
58
  MANIFEST_FILE,
45
59
  NOT_WRITTEN,
60
+ NO_ENVELOPES,
46
61
  RATCHET_FILE,
47
62
  READERS,
48
63
  SCOPE,
49
64
  checkBaseline,
50
65
  checkDeployed,
51
66
  checkDrift,
67
+ checkEnvelopes,
52
68
  checkExercised,
69
+ checkGroup,
53
70
  checkLoaded,
54
71
  checkObservability,
55
72
  checkRunner,
56
73
  corpusOfPlugin,
57
74
  declaredFor,
75
+ declaredGroupsOf,
58
76
  defaultRef,
59
77
  discoverConfigs,
60
78
  discoverWorkspaces,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geonosis/doctor",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "types": "./dist/index.d.ts",
5
5
  "description": "The adoption doctor — declared ≠ loaded, enabled ≠ exercised, a baseline that grew, a runner whose exit code is the only verdict.",
6
6
  "keywords": [
@@ -35,7 +35,7 @@
35
35
  "dist"
36
36
  ],
37
37
  "dependencies": {
38
- "@geonosis/lint-parity": "1.3.0"
38
+ "@geonosis/lint-parity": "2.0.0"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "oxlint": ">=1.77"