@geonosis/oxlint-plugin-biological-architecture 2.6.1 → 2.8.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # @geonosis/oxlint-plugin-biological-architecture
2
2
 
3
+ ## 2.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e880a6c: The tiers have no dead ends a consumer can reach (#1, #2). Three shapes from one migration had no
8
+ legal expression, because two rules together forbade every place the file could live:
9
+
10
+ - **`tissue-no-data-props`** accepts layout configuration: a `number` or `boolean` prop the tissue
11
+ gives a literal default (`initialCount = 10`, `wrap = false`). A stateless adapter between two
12
+ cells is a tissue, and now it can be one. A string, a default that is not a literal of the prop's
13
+ type, and a primitive with no default are still data.
14
+ - **`no-hook-in-component-disguise`** accepts the client-boundary beacon: a file whose directive
15
+ prologue says `'use client'`, whose component calls a hook and returns only `null`. Its parent — a
16
+ Server Component, or a tissue under `tissue-no-hooks` — cannot call the hook, so there was no
17
+ real component to move it into. A `'use client'` component that returns its `children`, or calls
18
+ no hook, is still reported. The no-hook message now tells a layout about metadata
19
+ (`passthroughLayout`) and tells any other component nothing of the kind.
20
+ - **`no-invalid-feature-folders`** takes `roots` (default: none). Directly under each declared
21
+ directory, a folder that is not a tier is a finding per file, so an unmigrated pile
22
+ (`src/components/organisms/`) is debt the ratchet counts and moving a file into it grows the
23
+ count, instead of silently clearing every tier rule.
24
+
25
+ `cell-must-not-compose-cell` keeps no exception; its fix now names the stateful host: two cells
26
+ side by side, coordinating through the store, arranged by a tissue.
27
+
28
+ ## 2.7.0
29
+
30
+ ### Minor Changes
31
+
32
+ - 08c9653: The kit knows no document kind. `document-sagas-are-generic` and `documents-share-one-table` are
33
+ gone from the plugin and from the `backend-workflows` preset, with their corpus and fixtures: both
34
+ took a list of one consumer's document kinds (`perKindPrefixes`, `perKindTables`) and enforced a
35
+ vocabulary the kit has no business holding — a document entity is whatever extends `Document`, and
36
+ the registry a consumer builds is the only enumeration there is. Their intent is held by types
37
+ now: a consumer's per-entity maps are folds over the registry, and a per-entity saga has nowhere to
38
+ be written once `documentWorkflows` mints them. Their ids stay for one release: oxlint refuses a
39
+ config that names a rule its plugin does not export, so a config naming either still parses, the
40
+ id reports nothing and says once that it is retired, and `geonosis doctor` WARNs naming it where
41
+ it would have failed. Migration: remove the block before the next major, when the ids go; the
42
+ doctor's floor table no longer lists them.
43
+
44
+ ### Patch Changes
45
+
46
+ - c8c5d51: `documentWorkflows(entity, { effects, ports })` at `@geonosis/document/workflows` — T3, the org
47
+ workflows over the engine, one body per Document: `create`, `save`, `setStatus`, `remove`, `send`
48
+ (durable), `convert`, `duplicate`, `share`, each named for the entity. A host decides
49
+ `effects.announce(fact)` — the product's events off a `DocumentFact` — and answers three ports,
50
+ `door`, `link` and `mail` (`Result<void, MailUndelivered>` from `better-result`); `beforeCreate`,
51
+ `conversion`, the mail words, `counter`, `actor`, `guard`, `now` and `seed` default, and a
52
+ counter-numbered entity or a template on a host that declares neither is refused by name. The
53
+ factory makes the two steps that reach the outside world, so the durable-body law holds on every
54
+ host. A third entry, like `./store`, so the core stays off every floor and browser-safe. The
55
+ Standard Schema builders the surface wrote for itself move to the core (`objectOf`, `enumOf`,
56
+ `optional`, `nullable`, `arrayOf`, `merge`, the scalars, `validate`) and `SchemaAdapter` is the
57
+ adapter's name (`SurfaceSchemaAdapter` stays as an alias). `@geonosis/workflows` and
58
+ `better-result` join the package's dependencies. The plugin's `document-sagas-are-generic` and
59
+ `documents-share-one-table` no longer carry `floor: pending`: the store shipped at 0.4 and the
60
+ workflows ship here. `documentIdentifiers` spells every identifier as a literal type off the name it was given (`CamelOf`, `DocumentIdentifiers`), so a consumer indexes a typed router map by the camel name without a cast. `documentEntities(map).keyed(pick)` answers one value per entity under its name, total by construction.
61
+
3
62
  ## 2.6.1
4
63
 
5
64
  ## 2.6.0
package/README.md CHANGED
@@ -136,8 +136,6 @@ months. Carry these across, or turn the rule off:
136
136
  | `no-brand-names` | `{ brands, allowedSubstrings }` | refuses the run |
137
137
  | `organelle-dependency` | `{ sharedFeatures }` | only `shared` crosses a feature boundary |
138
138
  | `cell-no-cross-feature-organelles` | `{ sharedFeatures }` | only `shared` crosses a feature boundary |
139
- | `documents-share-one-table` | `{ perKindTables }` | refuses the run |
140
- | `document-sagas-are-generic` | `{ perKindPrefixes }` | refuses the run |
141
139
  | `step-opens-its-own-cell` | `{ engine, within, wrapper }` | refuses the run |
142
140
  | `no-raw-html-atoms` | the positional element→atom map | refuses the run |
143
141
  | `layer-walls` | `{ layers: [{ name, paths, mayImport }], externals? }` | refuses the run |
package/RULES.md CHANGED
@@ -9,11 +9,14 @@ Read from the two source trees on 2026-08-29:
9
9
  One plugin name, two rule sets, no shared code. **33 rules had the same filename in both trees; only
10
10
  3 of those 33 were byte-identical.** A fix in one never reached the other.
11
11
 
12
- The union here is **54 rules**, plus twenty-eight the kit wrote for itself `layer-walls`,
13
- `emit-declares-attempts`, `cell-no-cross-feature-organelles`, the `backend-medusa` ten,
14
- `no-unregistered-plugin-dir` + `router-schema-parity`, the `themekit` two,
15
- `no-mock-db-in-integration`, `todo-names-its-plan`, `boundary-time-is-primitive`,
16
- `durable-body-reads-through-steps`, `subpath-over-barrel` and the six of the W67 batch — **82**.
12
+ The union here is **52 rules** 54 when it was cut, less `document-sagas-are-generic` and
13
+ `documents-share-one-table`, retired in 2.7.0 because both enforced one consumer's document kinds —
14
+ plus twenty-eight the kit wrote for itself: `layer-walls`, `emit-declares-attempts`,
15
+ `cell-no-cross-feature-organelles`, the `backend-medusa` ten, `no-unregistered-plugin-dir` +
16
+ `router-schema-parity`, the `themekit` two, `no-mock-db-in-integration`, `todo-names-its-plan`,
17
+ `boundary-time-is-primitive`, `durable-body-reads-through-steps`, `subpath-over-barrel` and the six
18
+ of the W67 batch — **80**. The two retired ids still resolve for one release, as no-ops that say
19
+ they are retired, so a config naming them parses; they go at the next major.
17
20
  Every one of the twenty-eight is marked **written here** in the inventory, and the table below is
18
21
  held against that column rather than kept by hand.
19
22
 
@@ -22,10 +25,10 @@ held against that column rather than kept by hand.
22
25
  | in both trees, byte-identical | 3 |
23
26
  | in both trees, **diverged** | 30 |
24
27
  | dielime only | 3 |
25
- | during.day only | 18 |
26
- | **union** | **54** |
28
+ | during.day only | 16 |
29
+ | **union** | **52** |
27
30
  | written here | 28 |
28
- | **total** | **82** |
31
+ | **total** | **80** |
29
32
 
30
33
  ## How divergence was resolved
31
34
 
@@ -513,26 +516,6 @@ Closing it also fixed a hole in the barrel rule's own pattern, which required a
513
516
  therefore no-op'd on the cwd-relative `cells/index.ts` oxlint reports for a package whose own root
514
517
  holds `cells/`.
515
518
 
516
- ### `documents-share-one-table` — matches `pgTable` as well as `sqliteTable`
517
-
518
- during.day's fork matched `literalNamedBy(node, 'sqliteTable')` and nothing else, and every tenant
519
- table on that tree has been `pgTable` since its plan 037. Its own probe: a well-formed per-kind
520
- table
521
-
522
- ```ts
523
- export const invoices = pgTable('invoices', { id: text('id').primaryKey(), orgId: orgIdColumn() })
524
- ```
525
-
526
- under `packages/db/src/schema/tenant/` produced **zero** findings from this rule; only the malformed
527
- variant was caught, by `tenant-tables-carry-org-id`, and by accident. The fork's rule had been dead
528
- since the tenant plane moved to Postgres.
529
-
530
- The kit matching both constructors is therefore a fix, not a widening for its own sake. It stands
531
- because the rule is about the second storage a base entity retired — which is true whatever the
532
- dialect — and because `dialect-through-the-seam` already says the dialect is a seam fact rather than
533
- a thing a document kind gets to have an opinion about. Both branches are exercised through the real
534
- binary in `src/rules/__fixtures__/packages/db/src/schema/tenant/`, so neither can go quiet again.
535
-
536
519
  ### `no-raw-html-atoms` — the tier it was always documented for (0.3.0)
537
520
 
538
521
  Its own description said levels 2-6 and it fired at every level, `atoms/` included, where a raw
@@ -567,13 +550,9 @@ rule the option refusal exists to stop, one option along.
567
550
  | `organelle-dependency` | `sharedFeatures` | `['shared']` — during.day's `charts`/`document` are config, not law |
568
551
  | `mutating-step-declares-retry` | `retryKey` | `maxRetries` — Medusa's key. `@geonosis/workflows` spells the same budget `retry: { limit, backoff }` (`create-step.ts`), and with the key compiled in a correctly budgeted step on that engine was a finding for ever |
569
552
  | `mutating-step-declares-retry` | `retryLimitKey` | `limit` — the key that holds the NUMBER when the budget is an object. #191: reading only the bare form let `retry: { limit: 0 }` pass, which is the same silence as `maxRetries: 0` |
570
- | `documents-share-one-table` | `perKindTables` | **refuses the run** |
571
553
  | `worker-handles-are-scoped` | `within` + `wrapper` | **refuses the run** — `withCells` and `/apps/api/src/` were compiled in, so the rule served one repo's layout and one repo's vocabulary and a scope opener called anything else read as unscoped for ever |
572
554
  | `subpath-over-barrel` | `packages` (`{ name, subpaths: { <subpath>: string[] } }[]`) | **refuses the run** — which of a repo's own packages expose subpaths, and which names live under each, is a map only that package's owner has |
573
555
  | `durable-body-reads-through-steps` | `ports` | **refuses the run** — what a body reaches the outside world through is the repo's vocabulary; `durableKey` / `durableValue` (default `durable: true`) say how a workflow declares itself durable |
574
- | `document-sagas-are-generic` | `perKindPrefixes` | **refuses the run** |
575
- | `document-sagas-are-generic` | `within` | **refuses the run** — `/packages/workflows/src/` was compiled in, so the same per-kind saga one directory over was silent and no other layout could enable the rule at all |
576
- | `document-sagas-are-generic` | `factories` | `['saga', 'createWorkflow']` — the callee was `saga` alone, so a per-entity `createWorkflow('invoice.create', …)` produced no finding (026-W2, measured). A name assembled from the entity is a template literal the rule cannot read: that is the mint the rule sends people to, not a gap in it |
577
556
  | `unique-query-step-name` | `queryStepCalls` | **refuses the run** — the two names it shipped with are Medusa framework calls with no counterpart, so on the org engine the rule had zero reach while reading as enforced (026-W2, measured through the binary). There is no second spelling to inherit: `@geonosis/workflows` has no query-step primitive, and a repeated step name there is DEFINED rather than lost — `reserve`, `reserve#2` in call order (`engine.ts:124`) |
578
557
  | `no-raw-html-atoms` | (positional) element→atom map | **refuses the run** |
579
558
  | `no-raw-html-atoms` | `scope` (second positional, `{ scope: ["cells", …] }`) | every file except the atom tier |
@@ -710,8 +689,6 @@ has, and one a kit that guessed at it would keep stale on somebody else's behalf
710
689
  | `compound-no-stores` | frontend | — | `directionRule` | yes | yes | diverged |
711
690
  | `constants-in-constants-file` | backend-workflows | — | `paths` | — | yes | during only |
712
691
  | `dialect-through-the-seam` | backend-workflows | — | `onImportSource` + `mergeVisitors` + `paths` | — | yes | during only |
713
- | `document-sagas-are-generic` | backend-workflows | `perKindPrefixes` | `paths` + `options` + `literal-call` | — | yes | during only |
714
- | `documents-share-one-table` | backend-workflows | `perKindTables` | `paths` + `options` + `literal-call` | — | yes | during only |
715
692
  | `durable-body-reads-through-steps` | backend-workflows | `ports` | `nodes` + `objects` + `steps` + `options` | — | — | **written here** (#167, design-026 §8) |
716
693
  | `effect-hook-naming` | frontend | — | `paths` | yes | yes | diverged |
717
694
  | `emit-declares-attempts` | backend-medusa | — | `options` | — | — | **written here** |
@@ -867,8 +844,6 @@ option not named here is one no rule reads.
867
844
  | `compound-no-stores` | — |
868
845
  | `constants-in-constants-file` | — |
869
846
  | `dialect-through-the-seam` | — |
870
- | `document-sagas-are-generic` | `factories`, `perKindPrefixes`, `within` |
871
- | `documents-share-one-table` | `perKindTables` |
872
847
  | `durable-body-reads-through-steps` | `durableKey`, `durableValue`, `ports`, `stepFactories`, `stepProxies`, `workflowFactories` |
873
848
  | `effect-hook-naming` | — |
874
849
  | `emit-declares-attempts` | `budgetHelpers`, `emitters` |
@@ -892,7 +867,7 @@ option not named here is one no rule reads.
892
867
  | `no-index-count-as-exact` | `estimateFields`, `labelKey` |
893
868
  | `no-inert-hidden-jsx` | — |
894
869
  | `no-inline-data-in-jsx` | — |
895
- | `no-invalid-feature-folders` | |
870
+ | `no-invalid-feature-folders` | `roots` |
896
871
  | `no-loader-side-effect-in-index-file` | `directories`, `resourceFactories` |
897
872
  | `no-logic-in-component-files` | — |
898
873
  | `no-mock-db-in-integration` | `dbModules`, `integrationDirs`, `mockNames` |
@@ -951,8 +926,6 @@ itself, and the doctor says so on the `exercised` line.
951
926
 
952
927
  | Rule | Floor | Shipped |
953
928
  |---|---|---|
954
- | `document-sagas-are-generic` | `document` | PENDING |
955
- | `documents-share-one-table` | `document` | PENDING |
956
929
  | `step-opens-its-own-cell` | `workflows` | yes |
957
930
 
958
931
  <!-- END GENERATED FLOORS -->
@@ -37,24 +37,6 @@
37
37
  "biological-architecture/compound-no-stores": "error",
38
38
  "biological-architecture/constants-in-constants-file": "error",
39
39
  "biological-architecture/dialect-through-the-seam": "error",
40
- "biological-architecture/document-sagas-are-generic": [
41
- "error",
42
- {
43
- "perKindPrefixes": [
44
- "invoice"
45
- ],
46
- "within": "(?:__fixtures__|corpus)/domains/[^/]+/workflows/"
47
- }
48
- ],
49
- "biological-architecture/documents-share-one-table": [
50
- "error",
51
- {
52
- "perKindTables": [
53
- "invoices",
54
- "quotes"
55
- ]
56
- }
57
- ],
58
40
  "biological-architecture/durable-body-reads-through-steps": [
59
41
  "error",
60
42
  {
@@ -12,8 +12,6 @@
12
12
  "biological-architecture/compound-no-stores",
13
13
  "biological-architecture/constants-in-constants-file",
14
14
  "biological-architecture/dialect-through-the-seam",
15
- "biological-architecture/document-sagas-are-generic",
16
- "biological-architecture/documents-share-one-table",
17
15
  "biological-architecture/durable-body-reads-through-steps",
18
16
  "biological-architecture/effect-hook-naming",
19
17
  "biological-architecture/emit-declares-attempts",
@@ -42,8 +42,6 @@ var BACKEND_WORKFLOWS = [
42
42
  "boundary-time-is-primitive",
43
43
  "constants-in-constants-file",
44
44
  "dialect-through-the-seam",
45
- "document-sagas-are-generic",
46
- "documents-share-one-table",
47
45
  "durable-body-reads-through-steps",
48
46
  "mutating-step-declares-retry",
49
47
  "no-date-string-compare",
package/dist/index.d.ts CHANGED
@@ -36,6 +36,16 @@ type ProbeTree = {
36
36
  };
37
37
  type ProbeFn = (options: readonly unknown[]) => Probe | ProbeTree;
38
38
 
39
+ type RetiredRule = Rule & {
40
+ meta: Rule['meta'] & {
41
+ retired: {
42
+ reason: string;
43
+ since: string;
44
+ };
45
+ };
46
+ };
47
+ declare const RETIRED_RULES: Record<'document-sagas-are-generic' | 'documents-share-one-table', RetiredRule>;
48
+
39
49
  type Rule = {
40
50
  create: (context: never) => Record<string, unknown>;
41
51
  fixShape: string;
@@ -123,4 +133,4 @@ declare const plugin: {
123
133
  rules: Record<string, Rule>;
124
134
  };
125
135
 
126
- export { Preset, type Rule, type RuleName, plugin as default, rules };
136
+ export { Preset, RETIRED_RULES, type Rule, type RuleName, plugin as default, rules };