@geonosis/lint-parity 2.3.0 → 2.4.2

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,406 @@
1
+ # @geonosis/lint-parity
2
+
3
+ ## 2.4.2
4
+
5
+ ## 2.4.1
6
+
7
+ ## 2.4.0
8
+
9
+ ## 2.3.1
10
+
11
+ ## 2.3.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 3dac9a7: **A rule a config turns off is out of the corpus's scope (#16).** `rulesNamedBy` took every key and
16
+ ignored severity, so three rules read as "fire nowhere" under a consumer's config where the doctor,
17
+ which reads severity, said one. A rule is in scope when some layer — base block or `overrides` entry
18
+ — leaves it running; a rule every layer sets to `"off"` (or `0`) is excluded, counted in the report
19
+ and named. `rulesTurnedOffBy` is the new door for the excluded list.
20
+ - 3dac9a7: **One `--since`, and a report a machine can read (#97).** `--since` names a plan number, a day and
21
+ a git ref in three commands, and all three took any string: `plan check --since garbage` exempted
22
+ nothing and printed the verdict it would have printed with no flag, `stats --since notadate` put
23
+ every recorded day outside the window and printed `0 turns` as a pass rate. One reader now declares
24
+ which kind each means and refuses an unreadable value by name. `geonosis-ratchet`,
25
+ `geonosis-verify-arch` and `geonosis-lint-parity` take `--json`: the same report, on stdout,
26
+ whatever the verdict — `--json` with an explicit `--format` is refused rather than resolved.
27
+
28
+ ### Patch Changes
29
+
30
+ - 3dac9a7: **A config oxlint would not parse is refused by name, never read as zero (#310).** Measured on
31
+ oxlint 1.80: a config naming a rule the loaded plugin does not export, or passing options to a rule
32
+ whose `schema` is `[]`, prints `Failed to parse oxlint configuration file`, exits 1 and lints
33
+ nothing — and zero findings against zero findings is a parity run that passes. The refusal is now
34
+ its own sentence, quoting what oxlint refused and naming the recipe: config A is the base commit's
35
+ corpus config against the base BUILD, never HEAD's config against an older one.
36
+ - 3dac9a7: **One documented spelling (#90).** Every README of a package the metapackage fronts now names
37
+ `geonosis <tool>` — the door that pins the whole toolchain at one version — beside the bare bin, and
38
+ a `tooling/` test holds it. `#230`'s stamp test lands with it: every flag `docs/orchestration.md`'s
39
+ adoption loop names has to carry the version it first ships in, because the loop once told a
40
+ consumer to run a flag the published version did not have.
41
+
42
+ ## 2.2.0
43
+
44
+ ### Patch Changes
45
+
46
+ - d15a654: **An envelope writer refuses a root it has been told is not its (#241).** A suite ran one over the
47
+ SHARED repo root mid-run: parallel suites made the comparison racy, and the file it left behind is
48
+ one the next run reads as real. Every one of the seven writer copies now refuses to write when
49
+ `GEONOSIS_ENVELOPES_FORBIDDEN_ROOT` names the root it was pointed at, saying so and pointing at a
50
+ scratch root instead. The kit's own vitest config sets it to the repo root, so a test that writes an
51
+ envelope there names itself — which is how the offender that filed this row was found again.
52
+
53
+ ## 2.1.0
54
+
55
+ ## 2.0.0
56
+
57
+ ## 1.4.0
58
+
59
+ ### Minor Changes
60
+
61
+ - c712f3d: **A parity run now says which files both configs actually opened.** `filesLintedBy` asks oxlint itself, through `--debug=files`, and `fileCensus` splits the tree three ways; `geonosis-lint-parity` writes `.geonosis/envelopes/lint-parity.json` where `read` is the files BOTH configs read — the only population a findings diff means anything over — and a file one side ignores is `excused`, named with the side that ignored it. "B reported everything A did" over a tree B half-ignored has been the shape of an adoption proof that proved nothing. The census argv deliberately mirrors the lint argv, because oxlint's ignore resolution is sensitive to it: a config named through a symlinked prefix applies none of its own `ignorePatterns`.
62
+
63
+ ## 1.3.0
64
+
65
+ ### Patch Changes
66
+
67
+ - 0a7673c: **`geonosis-lint-parity --print-config-shape` (#75).** It reads no configuration file: the two
68
+ `.oxlintrc.json` files it compares are named with `--a` and `--b`, and it reads them as oxlint does.
69
+ - 228566f: **The doctor reads the options oxlint RESOLVES, not the base object beside them (#102).** A
70
+ config's `rules` block is only its first layer. An `overrides[]` entry naming a rule again replaces
71
+ its options for the files its globs claim — and dielime declares two of its three Medusa provider
72
+ registries exactly there, because that is where oxlint reads them. The rule resolved it correctly.
73
+ `drift` read `rules` alone and reported two working fulfillment carriers as directories the base
74
+ registry "never names": one config, two answers, from the tool whose whole subject is gates that
75
+ disagree with what they claim to measure.
76
+
77
+ Every reader that consumes a rule's configuration now takes base + matching overrides, resolved the
78
+ way oxlint resolves them — **measured** against oxlint 1.80, not assumed: an override REPLACES the
79
+ base's options for its files rather than merging into them, and the last of several matching
80
+ overrides wins outright.
81
+
82
+ - `drift`'s plugin-directory check asks each directory which layer governs it and checks it against
83
+ THAT layer's registry and manifests, so a repo with several registries gets a line per registry.
84
+ - `exercised` counts a rule an overrides entry enables — it read "no rule of this plugin is enabled
85
+ here" before, a SKIP from the check whose thesis is that an invisible check reads as a passing one
86
+ — and builds a probe from every configuration the repo gives a rule, not only the first.
87
+ - `@geonosis/lint-parity`'s `rulesNamedBy` reads overrides too: a rule configured only there fired
88
+ in the reach run and had no row in the report about which rules reach anything.
89
+
90
+ A layer's options are only half of what it resolves; the other half is which FILES it governs. A
91
+ probe built from an override's options and written where the RULE looks is a probe for a
92
+ configuration that will not run on it — during.day scopes `no-raw-html-atoms` to its compound and
93
+ cell folders, and the probe lands nowhere near them. When no layer enabling a rule claims where its
94
+ probe lands, the question was not ASKED: UNJUDGED, naming the globs, never a FAIL against a repo
95
+ enforcing the rule on every file it means to.
96
+
97
+ Measured read-only. dielime: `2 directory(ies) it never names` becomes five OK lines, one per
98
+ registry, and nothing else in the run moves. during.day: the rules it enables only in `overrides[]`
99
+ were invisible to this check and are now counted — two configs move from silence to UNJUDGED, which
100
+ is what "we could not tell" has always meant here, and neither passes.
101
+
102
+ ## 1.2.0
103
+
104
+ ## 1.1.0
105
+
106
+ ## 1.0.1
107
+
108
+ ### Patch Changes
109
+
110
+ - 1c2ee0b: **Every package ships its declarations and says where they are.** `@geonosis/visual-diff` and
111
+ `@geonosis/verify` emitted no `.d.ts` at all (TS7016 in a consumer: the comparator every visual test
112
+ calls became `any` at the one seam that decides whether a screenshot regressed), and no package
113
+ declared `types` — the nineteen that worked did so through the sibling-file fallback, which ends the
114
+ day `exports` gains a condition. Every export now carries a `types` condition beside `default`, every
115
+ manifest a `types` field, and `tooling/types.test.ts` holds all twenty-one to it after the build.
116
+
117
+ `geonosis-verify-arch` prints a check once when its label is its id ("direction, orphan", not
118
+ "direction direction").
119
+
120
+ ## 1.0.0
121
+
122
+ ### Major Changes
123
+
124
+ - c575f44: Five counters, `tolerance`, and a baseline rewrite that only ever goes down.
125
+
126
+ - `disabledCiJobs` — lines of `if: false` across the workflow files (`dir`). A job switched off to
127
+ get a release through is debt exactly like a lint error: invisible, because the pipeline goes
128
+ green. A condition that merely mentions `false` is not one, and a repo with no workflows
129
+ directory reads 0 rather than refusing; a workflow that is there and cannot be read refuses.
130
+ - `bundleBytes` — one integer out of whatever the repo's sizing command printed (`command`,
131
+ `match`), separators and all. With `match` it takes the group that pattern names and refuses when
132
+ it matches nothing, rather than falling back to any integer and reporting the wrong number as
133
+ confidently as the right one.
134
+ - `fastTierMs` — `finishedAt − startedAt` from the gate report `geonosis-verify` wrote (`report`,
135
+ `tier`). It refuses a report of another tier: the full tier takes minutes, and timing it against
136
+ the fast tier's baseline would report a regression of the wrong thing.
137
+ - `testsWithoutRunner` — workspaces holding tests with no `test` script. Unmeasured and passing are
138
+ indistinguishable from outside, so the count of unmeasured things has to be a number of its own.
139
+ - `packagesWithoutTypecheck` — workspaces with no `typecheck` script (`script`).
140
+
141
+ `tolerance` is new on the verdict: the fraction of the baseline a number may drift UP before the
142
+ ratchet calls it growth. Bytes and milliseconds move on a dependency patch nobody chose, and a gate
143
+ that fails on +40 bytes is a gate that gets switched off. It forgives noise upward only — a shrink
144
+ of any size still lowers the baseline — and a `tolerance` that is not a non-negative number stops
145
+ the run naming the entry, because one that silently became `NaN` reads exactly like a counter that
146
+ can never grow.
147
+
148
+ **Fix:** a baseline rewrite now lowers only the numbers that SHRANK. Writing every measured key back
149
+ was a harmless no-op while `held` implied `now === baseline`. Tolerance breaks that implication, and
150
+ the blanket rewrite would have laundered growth-within-tolerance into the new floor on the first
151
+ unrelated win — a baseline going up on a pass.
152
+
153
+ `examples/dielime.ratchet.json` is dielime's Phase 3 config: 36 keys, one `testFailures` entry per
154
+ workspace. It keeps `--format=unix` and `expectFormat` on the two oxlint counters, which dielime's
155
+ own config drops — the summary cross-check can tell a misparse from a clean run only when the run
156
+ printed a summary, and a warnings-only run in an unreadable shape prints one that says nothing
157
+ about errors. Pinning the format is what closes that window.
158
+ - c418f91: The `geonosis` Claude Code plugin — the method as enforcement rather than advice.
159
+
160
+ `plugin/` ships five hooks, Node ≥ 22, zero dependencies, every tool resolved from the CONSUMER's
161
+ `node_modules/.bin` so a repo that has not adopted a tool is never blocked on a tool it lacks:
162
+
163
+ - **SessionStart** runs `geonosis-doctor` if it is installed and prints a one-line digest of
164
+ `.oxlintrc.json` — which plugins are loaded, how many architecture rules are at `error`. It never
165
+ fails a session.
166
+ - **PreToolUse / Bash** refuses `prettier` (law 4) and `--no-verify` (law 7), and hands a
167
+ `git commit` to `geonosis-ledger` — the message its `-m` flags compose, and whether the staged
168
+ diff delivers anything but comments. The detectors are the ledger's, never reimplemented here; a
169
+ repo without it gets a note and no opinion.
170
+ - **PreToolUse / Edit|Write|MultiEdit** refuses a write that ADDS `eslint-disable`,
171
+ `oxlint-disable`, `@ts-ignore` or `@ts-expect-error` (law 3), any write to `gate-baseline.json` or
172
+ under `.geonosis/` (D-007 — the scored agent never writes the scoreboard), and a lint config that
173
+ sets a rule to `"warn"`, `"off"`, `0` or `1` (law 2). It reads what the call would ADD, never what
174
+ it removes, so the edit that DELETES a suppression is not refused by the guard against them.
175
+ - **PostToolUse / Edit|Write** runs oxfmt on the file just written. It never blocks.
176
+ - **Stop** runs `geonosis-verify fast` and will not let the turn end on a red one, capped at five
177
+ blocks per session — an agent retrying the same broken thing five times has a problem it will not
178
+ solve on the sixth, so the sixth prints the report and lets go.
179
+
180
+ `.claude-plugin/marketplace.json` offers it from `./plugin`. `pnpm generate:skill` now writes the
181
+ plugin's copy of the mechanical skill, the engineer agent with the machine-specific path taken out,
182
+ and `plugin.json` carrying the kit's own version; staleness tests fail when any of the four drift.
183
+ - 5f09ddc: Every hook is driven end to end, as Claude Code drives it.
184
+
185
+ Each script is SPAWNED with real stdin JSON over a throwaway repo carrying a `geonosis.json`, a
186
+ `gate-baseline.json`, an `.oxlintrc.json` and a `node_modules/.bin` linked to the BUILT
187
+ `geonosis-verify` and `geonosis-ratchet`. A hook tested by calling its policy function proves the
188
+ policy; only a spawn proves the exit code, the JSON on stdout and the tool resolution — which is
189
+ the whole of what Claude Code actually reads.
190
+
191
+ The Stop hook is exercised against a real fast tier that really goes red: a law file one line over
192
+ its baseline, so the ratchet grows and the hook blocks with exit 2, the failing step and its tail on
193
+ stderr. Then the sixth block prints the report and exits 0; a green run clears the session's count;
194
+ `stop_hook_active` short-circuits; and a repo with a BACKLOG that did not regress is not blocked at
195
+ all — which is the whole adoption argument, tested rather than asserted.
196
+
197
+ The suite was falsified before it was trusted: making Stop exit 0 instead of 2, dropping the
198
+ delivery check, and raising the cap to 50 each turned exactly the tests that should have gone red,
199
+ red.
200
+ - 89c6769: The ratchet's own layers are walled, and the walls have a door that is proved open.
201
+
202
+ The three ratchet layers named FILE paths only, so `packages/ratchet/src/index.ts` — the published
203
+ entry — sat in no layer and could import anything, the CLI included, with lint green. It is
204
+ `ratchet-api` now, and the formatter it shares with the CLI has moved into a `ratchet-report` layer
205
+ of its own rather than being counted as part of the CLI it is not.
206
+
207
+ The dogfood suite gains a second kind of plant. A wall that refused everything would be as useless
208
+ as one that refused nothing, so each layer's permitted import — `verify` reaching the lock through
209
+ `@geonosis/ratchet` — is planted and asserted to stay CLEAN. Without that, the next engineer widens
210
+ `mayImport` to get their work through and the wall goes with it.
211
+ - b2d915f: **Fix:** a counter's command no longer loses what it wrote to stderr.
212
+
213
+ `<command> 2>&1` binds the redirect to the LAST command of the string. `echo boom >&2; echo fine`
214
+ therefore merged nothing, and on a ZERO exit `execSync` hands back stdout alone — so a tool that
215
+ prints its findings to stderr and exits 0 read as a tool that found nothing. That is the exact shape
216
+ of a gate that has quietly stopped gating, and it is the one direction in which this kind of bug is
217
+ dangerous: the number comes back lower than the truth and the baseline banks it.
218
+
219
+ On a NON-ZERO exit the line survived, because the failure path concatenates both captured buffers —
220
+ but concatenation put every stderr line after every stdout line, moving each diagnostic away from
221
+ the line it was about, which is what the evidence tail on a regression is for.
222
+
223
+ The command now runs in a subshell, so the shell itself merges the streams in the order they were
224
+ written. Measured before and after: `echo boom >&2` on a zero exit read `""` and now reads `boom`;
225
+ `echo one; echo two >&2; echo three; exit 4` read `one three two` and now reads `one two three`.
226
+ - 48bce0c: **Fix:** only a counter that measures a quantity accepts a `tolerance`.
227
+
228
+ Any counter took one. `{"counter":"lawLineCount","tolerance":0.5}` over a two-line law with a
229
+ baseline of 2 printed `ratchet PASS` at three lines — a 50 % growth, waved through. The same edit is
230
+ `"tolerance": 100` on `oxlintErrors`: the gate switched off from the config file, with the run still
231
+ reporting green. That is law 2 — never downgrade a rule — wearing a friendlier name, and it was the
232
+ easiest edit in the repo to get past a reviewer.
233
+
234
+ `Counter` gains `tolerates?: true`, declared only by `bundleBytes` and `fastTierMs`. Whether a
235
+ number is a measured quantity or a count of findings is the counter's to know, not the config's.
236
+ Anything else now stops the run, naming the entry:
237
+
238
+ ```
239
+ geonosis-ratchet: "oxlintErrors" does not accept a tolerance — only a counter that measures a
240
+ quantity declares one
241
+ ```
242
+
243
+ The plugin's write guard gains its first **ask**. A write to `geonosis.ratchet.json` that introduces
244
+ or raises a `"tolerance"` is neither refused nor allowed: it goes in front of the human as
245
+ `permissionDecision: "ask"`. Widening a band is legitimate and is not the agent's call — a band
246
+ somebody chose and a band somebody's agent chose are not the same thing. A tolerance carried through
247
+ an edit unchanged is not a change and says nothing.
248
+ - 461233c: Docs for the two new things: `docs/plugin.md` and `packages/verify/README.md`.
249
+
250
+ `docs/plugin.md` covers installing the plugin from a local path and from the remote once it is
251
+ pushed, what each of the five hooks does and the reason it does it that way, the five-block cap,
252
+ which files the runner owns and why the agent may not write them, what to put in `geonosis.json`,
253
+ and — the section every README skips — what the plugin CANNOT do. A `fast` tier of `["true"]` passes
254
+ for ever; only `geonosis-ratchet --prove` shows a counter can go red.
255
+
256
+ `packages/verify/README.md` is the runner's own: `--prove` first, the config with no default tier,
257
+ the three exit codes and why a report that could not be written is exit 2, the report shape with the
258
+ `<tier>/<n>` id rule, and `--exclusive`.
259
+
260
+ `docs/README.md` indexes both. The ratchet README gains rows for the five new counters, a section on
261
+ `tolerance` and the shrank-only rewrite it forces, and the landmine that cost an afternoon: a
262
+ loader or shim named RELATIVELY in a counter's command resolves to nothing under `--prove`, whose
263
+ probes run in a scratch directory. Write it `$PWD/…` and it works in both.
264
+ - e48501b: `@geonosis/verify` — one gate runner, with a report a hook can read.
265
+
266
+ `geonosis-verify <tier>` runs the shell steps a repo declared under `verify` in `geonosis.json`,
267
+ serially, stopping at the first red, and writes `.geonosis/gate-report.json`:
268
+ `{ tier, startedAt, finishedAt, ok, steps: [{ id, command, ok, exitCode, ms, tail, skipped? }] }`.
269
+ A step whose text is another tier's name is that tier, inlined in place; the inlined steps keep the
270
+ tier that declared them, so `fast/2` is the same command whether the operator ran `fast` or ran the
271
+ `full` tier that inlines it.
272
+
273
+ There is no default tier and there never will be one: no config, no `verify` object, or an unknown
274
+ tier is refused by name with exit 2, and so is a green run whose report could not be written — a
275
+ gate that cannot record has not passed. A failed step is exit 1.
276
+
277
+ `--exclusive` takes the ratchet's machine-wide lock through `@geonosis/ratchet`'s published entry
278
+ (`--exclusive-timeout <seconds>` bounds the wait), so a verify and a ratchet on one laptop serialise
279
+ against each other rather than each against itself. `--prove` plants a tier with one passing step
280
+ and one that exits 3, runs the real binary over it in a temp directory, and checks the failure
281
+ reached the report — a runner that reports green is worth nothing until it has been watched going
282
+ red on purpose.
283
+
284
+ The kit walls the new package with its own `layer-walls` rule: `verify` may import `ratchet-api`
285
+ and nothing behind it, planted against in the dogfood suite like the other walls.
286
+
287
+ ## 0.6.0
288
+
289
+ ### Minor Changes
290
+
291
+ - e446760: **New package `@geonosis/doctor` (bin `geonosis-doctor`).** Four questions a version bump is not
292
+ finished until something has asked. Each one is a way enforcement has reported green while measuring
293
+ nothing, in a real repo, for weeks.
294
+
295
+ - **`loaded` — declared ≠ loaded.** oxlint resolves a `jsPlugins` specifier from the CONFIG FILE's
296
+ directory, so a nested `apps/<ws>/node_modules/@scope/plugin` left behind by a per-workspace
297
+ install runs while every manifest and the lockfile say a different version. One consumer measured
298
+ a whole bug report against 0.3.0 on a repo pinned to 0.4.0. For every config in the tree naming a
299
+ `@geonosis/*` plugin, this resolves it from that config's own directory, imports it, reads
300
+ `meta.version`, and compares it to the version the nearest manifest declares — then lists every
301
+ copy **resolution** reaches, one question per workspace. Never a `find`: on pnpm the store keeps
302
+ every version ever installed, so counting directories answers 7 on a correct tree. A declared
303
+ range it cannot read is a FAIL, not a pass.
304
+ - **`exercised` — enabled ≠ exercised.** Every rule a config enables, run against the corpus the
305
+ loaded plugin ships, under that config's own options — because the options are usually where the
306
+ reach went. Reuses `@geonosis/lint-parity`'s `corpusOf`; a plugin shipping no corpus is a SKIP.
307
+ - **`baseline` — a number that may only shrink, against another ref.** A ratchet lowers its own
308
+ baseline when a number shrinks, so nothing inside one checkout can see a branch raise one back up.
309
+ `--baseline-against [ref]` compares `gate-baseline.json` at HEAD with the same file at a ref. It
310
+ is OFF unless asked for by name: it is the only check that runs git, and this tool gets pointed at
311
+ repos other people are working in.
312
+ - **`runner` — an exit code is not a verdict.** Workspaces whose `test` script runs vitest or
313
+ `bun test` without asking for a JSON report, and which no `testFailures` counter in report mode
314
+ covers. `@cloudflare/vitest-pool-workers` exited 0 over suites it had just reported as failing.
315
+
316
+ `--strict` promotes every WARN to a FAIL; `--json` prints the whole report for CI. Exits 1 on any
317
+ FAIL, 2 when the run could not be made at all.
318
+
319
+ The package depends on `@geonosis/lint-parity` and on **nothing from the rule plugin** — it asks
320
+ which plugin a config loads, and a copy in its own dependency tree would be one more copy for the
321
+ question to be wrong about. A `layer-walls` layer named `doctor` in the kit's own config holds that
322
+ wall, planted against in `dogfood.test.ts`.
323
+
324
+ **`@geonosis/lint-parity` exports `resolveOxlint(from)`** — the consumer's own oxlint, walking up
325
+ from a directory. It was already the answer the CLI needed; it is now the answer every tool that
326
+ spawns oxlint shares, rather than each keeping its own.
327
+
328
+ **Measured, and worth knowing before writing anything that reads oxlint's output:** on oxlint 1.80 a
329
+ JS plugin rule that throws from `create()` is reported ONCE PER FILE, and `--format=unix` renders
330
+ each of those as `:0:0: [Warning]` — no path, no rule id, no sentence. The reason survives only in
331
+ the default formatter. `geonosis-doctor` therefore asks a second time, over one trivial file, in the
332
+ format that answers. No rule changed in this release.
333
+
334
+ ## 0.5.0
335
+
336
+ ### Minor Changes
337
+
338
+ - **New rule `cell-no-cross-feature-organelles` (preset `frontend`).** `organelle-dependency` is scoped
339
+ to `organelles/` and `no-cross-feature-stores` only judges stores, so a CELL importing another
340
+ feature's ORGANELLE passed both while both stayed green. Option `sharedFeatures`, default
341
+ `['shared']` — the same option and the same default as `organelle-dependency`'s, because the two
342
+ rules draw one boundary from two sides. Measured on a consumer: three findings in two files.
343
+
344
+ **The corpus carries both spellings of every direction rule.** A direction rule judges where an
345
+ import lands, so `@/features/billing/x` and `../../billing/x` are one breach; the corpus previously
346
+ carried whichever spelling each rule's author happened to write. Fifteen fixtures added. No rule
347
+ changed.
348
+
349
+ **`geonosis-lint-parity --corpus --expect-changed <rule,…>`.** A changelog line that names a rule is
350
+ a claim; this makes it data the corpus judges, and exits 1 on a claim the corpus is silent about or a
351
+ change nobody claimed. Mandatory for any release whose notes name a rule.
352
+
353
+ **`testFailures` reads the runner's JSON report** with `report: "vitest-json"`, refusing when the
354
+ report is absent, unparsable, missing `numFailedTests`, or says `success: false` while naming none.
355
+ `Counter.probe` takes a list, so `--prove` proves each reading mode by name.
356
+
357
+ **`geonosis-ratchet --prove` proves the lock**, by running two children of the CLI over a slow
358
+ `--hold` and requiring the second to start after the first finished.
359
+
360
+ `@geonosis/ratchet`'s source is layered — `core/`, `counters/`, `report.ts`, `cli.ts` — with no
361
+ change to what `@geonosis/ratchet` exports or to a single line the CLI prints.
362
+
363
+ ## 0.4.0
364
+
365
+ Version only — the three `@geonosis/*` packages move as one fixed group, and nothing in this package
366
+ changed in 0.4.0. The release is the plugin's rule core and `@geonosis/ratchet`'s heavy lock.
367
+
368
+ ## 0.3.0
369
+
370
+ ## 0.2.1
371
+
372
+ Version only — the three `@geonosis/*` packages move as one fixed group, and nothing in this
373
+ package changed in 0.2.1. The release is `@geonosis/ratchet`'s: `--prove`, `--exclusive`, and
374
+ `typecheckErrors` refusing on an unbuilt workspace.
375
+
376
+ ## 0.2.0
377
+
378
+ ### Minor Changes
379
+
380
+ - Loose coupling, first slice — and a posture change that will break a config on purpose.
381
+
382
+ **`@geonosis/lint-parity` is a new package.** Findings parity, rule reach, the corpus-manifest
383
+ contract and the `geonosis-lint-parity` bin now live on their own. The tool knows no rule name and
384
+ no plugin: two oxlint configs and a tree are the whole input, and a corpus arrives as a directory
385
+ whose own `manifest.json` says which rules it speaks for. A parity tool welded to one rule plugin
386
+ can only ever check that plugin.
387
+
388
+ **BREAKING (plugin): the `geonosis-lint-parity` bin and the `./parity` export are gone.** Install
389
+ `@geonosis/lint-parity` and pass `--corpus node_modules/@geonosis/oxlint-plugin-biological-architecture/corpus`
390
+ — the plugin still ships the corpus, which is the part that is genuinely its own. `--corpus` now
391
+ requires its directory.
392
+
393
+ **BREAKING (plugin): a rule enabled without the options it needs refuses the run.** `no-brand-names`,
394
+ `no-raw-html-atoms`, `documents-share-one-table`, `document-sagas-are-generic`,
395
+ `step-opens-its-own-cell` and `layer-walls` throw from `create()` naming the missing option, instead
396
+ of returning an empty visitor. A consumer that enabled one bare will fail lint until it configures
397
+ the rule or turns it off — which is the point: one consumer ran `no-raw-html-atoms` at "error" for
398
+ months with no element→atom map, over 136 raw elements, and the gate was green. An enabled rule that
399
+ cannot fire is indistinguishable from compliance. A rule nobody enabled still does nothing.
400
+
401
+ **New rule `layer-walls`, new preset `tooling`.** A repo declares its own layers as data —
402
+ `{ name, paths, mayImport }` — and the rule enforces the direction between them: relative sources
403
+ resolved against the importing file first, `import()`, `require()` and both re-export forms visited,
404
+ externals not walls unless asked. The kit enables it on itself.
405
+
406
+ The plugin also ships type declarations now, for all three entries.
@@ -17,11 +17,25 @@ const newest = (dir) =>
17
17
  }, 0)
18
18
  : 0
19
19
  const src = join(here, '..', 'src')
20
- if (existsSync(src) && newest(src) > newest(join(here, '..', 'dist'))) {
21
- process.stderr.write(
22
- 'geonosis-lint-parity: dist is older than srcrun pnpm build before trusting this bin.\n',
23
- )
24
- process.exit(2)
20
+ const dist = join(here, '..', 'dist')
21
+ // `newest` answers 0 for a directory that is NOT THERE and for one that is merely old, so the
22
+ // two conditions were one comparison and one sentence and the staleness sentence was printed
23
+ // over trees that had never been built at all, blocking a turn in a fresh git worktree, which
24
+ // has no dist because dist is not committed (#357). Only the second is evidence of a mistake.
25
+ if (existsSync(src)) {
26
+ const built = newest(dist)
27
+ if (built === 0) {
28
+ process.stderr.write(
29
+ 'geonosis-lint-parity: this tree has never been built — run pnpm build. No dist here at all, which is what a fresh clone or a linked git worktree starts with; nothing is stale.\n',
30
+ )
31
+ process.exit(2)
32
+ }
33
+ if (newest(src) > built) {
34
+ process.stderr.write(
35
+ 'geonosis-lint-parity: dist is older than src — run pnpm build before trusting this bin.\n',
36
+ )
37
+ process.exit(2)
38
+ }
25
39
  }
26
40
 
27
41
  await import('../dist/parity-cli.js')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geonosis/lint-parity",
3
- "version": "2.3.0",
3
+ "version": "2.4.2",
4
4
  "types": "./dist/index.d.ts",
5
5
  "description": "Findings parity and rule reach over any two oxlint configs — the diff a fork is deleted on.",
6
6
  "keywords": [
@@ -31,6 +31,7 @@
31
31
  }
32
32
  },
33
33
  "files": [
34
+ "CHANGELOG.md",
34
35
  "bin",
35
36
  "dist"
36
37
  ],
@@ -44,7 +45,7 @@
44
45
  "access": "public"
45
46
  },
46
47
  "devDependencies": {
47
- "@geonosis/ratchet": "2.3.0"
48
+ "@geonosis/ratchet": "2.4.2"
48
49
  },
49
50
  "scripts": {
50
51
  "build": "tsup",