@geonosis/oxlint-plugin-biological-architecture 2.2.0 → 2.3.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 (35) hide show
  1. package/RULES.md +37 -18
  2. package/corpus/.oxlintrc.json +48 -10
  3. package/corpus/affordances/bad-dead-control.tsx +6 -0
  4. package/corpus/affordances/good-live-control.tsx +12 -0
  5. package/corpus/api/store/history/find-orders.ts +8 -0
  6. package/corpus/api/store/history/route.ts +7 -0
  7. package/corpus/api/store/track/find-tracked-order.ts +12 -0
  8. package/corpus/api/store/track/route.ts +10 -0
  9. package/corpus/dates/bad-string-order.ts +7 -0
  10. package/corpus/dates/good-time-order.ts +7 -0
  11. package/corpus/engine/good-durable-read-through-step-proxy.ts +13 -0
  12. package/corpus/failure/good-refresh.ts +17 -0
  13. package/corpus/failure/logged.ts +6 -0
  14. package/corpus/failure/refresh.ts +4 -0
  15. package/corpus/failure/reload.ts +6 -0
  16. package/corpus/manifest.json +6 -0
  17. package/corpus/medusa/queries/bad-unordered-page.ts +20 -0
  18. package/corpus/medusa/queries/good-ordered-page.ts +23 -0
  19. package/corpus/messaging/providers/email-gmail.ts +2 -0
  20. package/corpus/messaging/providers/sms-twilio.ts +2 -0
  21. package/corpus/messaging/providers/whatsapp-360dialog.ts +2 -0
  22. package/corpus/messaging/registry.ts +5 -0
  23. package/corpus/packages/pricing/package.json +5 -0
  24. package/corpus/packages/pricing/src/index.ts +2 -0
  25. package/corpus/packages/utils/package.json +5 -0
  26. package/corpus/packages/utils/src/index.ts +4 -0
  27. package/corpus/suites/__tests__/awaits.ts +17 -0
  28. package/corpus/suites/__tests__/settles.ts +14 -0
  29. package/dist/{chunk-LTDP2733.js → chunk-KV7JRNAP.js} +7 -2
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.js +812 -61
  32. package/dist/presets.d.ts +3 -0
  33. package/dist/presets.js +1 -1
  34. package/package.json +2 -2
  35. /package/corpus/api/store/orders/{scoped.route.ts → scoped/route.ts} +0 -0
package/RULES.md CHANGED
@@ -9,11 +9,13 @@ 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-two the kit wrote for itself — `layer-walls`,
13
- `emit-declares-attempts`, `cell-no-cross-feature-organelles`, the `backend-medusa` ten of 1.0.0,
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
14
  `no-unregistered-plugin-dir` + `router-schema-parity`, the `themekit` two,
15
15
  `no-mock-db-in-integration`, `todo-names-its-plan`, `boundary-time-is-primitive`,
16
- `durable-body-reads-through-steps` and `subpath-over-barrel` — **76**.
16
+ `durable-body-reads-through-steps`, `subpath-over-barrel` and the six of the W67 batch — **82**.
17
+ Every one of the twenty-eight is marked **written here** in the inventory, and the table below is
18
+ held against that column rather than kept by hand.
17
19
 
18
20
  | | count |
19
21
  |---|---|
@@ -22,13 +24,8 @@ The union here is **54 rules**, plus twenty-two the kit wrote for itself — `la
22
24
  | dielime only | 3 |
23
25
  | during.day only | 18 |
24
26
  | **union** | **54** |
25
- | written here (`layer-walls`, `emit-declares-attempts`, `cell-no-cross-feature-organelles`) | 3 |
26
- | written here, `backend-medusa` (1.0.0) | 7 |
27
- | written here, the integration seam (1.0.0) | 2 |
28
- | **total** | **66** |
29
- | written here, `backend-medusa` (1.0.0) | 10 |
30
- | **total** | **67** |
31
- | written here, `themekit` (1.0.0) | 2 |
27
+ | written here | 28 |
28
+ | **total** | **82** |
32
29
 
33
30
  ## How divergence was resolved
34
31
 
@@ -88,6 +85,16 @@ decided the boundary or counts what accumulated on the far side — a consumer's
88
85
  took on seven unchartered exports, one of them a write, lint-free, in eleven commits. A list of
89
86
  module names is a number a reader can hold: a repo has one door, or it has three and knows it.
90
87
 
88
+ Every other rule that grants by path now takes the same enumeration beside its pattern (#139).
89
+ `time-through-the-door`'s `exempt`, `font-roles-only`'s `allow` and `tokens-only-colors`' `allow` —
90
+ measured from the option table, and the only three path GRANTS the plugin has; `within`, `paths`,
91
+ `roots` and `routers` are scopes — each accept `exemptModules`, a list of modules named in full,
92
+ matched by path or by the tail a repo writes them as and never as a pattern. The patterns still
93
+ work. What changed is that they are counted: each of those rules declares `meta.grants`
94
+ (`{ paths, modules }`), and `geonosis-doctor`'s `exercised` line WARNs with the number of files the
95
+ pattern exempts in THIS tree beside the number the enumeration names — so a grant nobody decided
96
+ stops being a grant nobody can see.
97
+
91
98
  ### An enabled rule that cannot fire **refuses the run** (0.2.0)
92
99
 
93
100
  This replaces the "does nothing until configured" posture below, and it is the one breaking change
@@ -710,20 +717,23 @@ has, and one a kit that guessed at it would keep stale on somebody else's behalf
710
717
  | `emit-declares-attempts` | backend-medusa | — | `options` | — | — | **written here** |
711
718
  | `font-roles-only` | themekit | `roles` | `paths` + `options` + `styling` | — | — | **written here** (U2) |
712
719
  | `layer-walls` | tooling | `layers` | `onImportSource` + `imports` + `paths` + `options` | — | — | **written here** |
720
+ | `list-take-without-order` | backend-medusa | — | `nodes` + `options` | — | — | **written here** (#21) |
713
721
  | `max-comment-density` | comment-ceiling | — | `paths` | — | yes | during only |
714
722
  | `molecule-atoms-only` | frontend | — | `directionRule` | yes | yes | diverged |
715
723
  | `molecule-must-compose` | frontend | — | — | yes | yes | diverged |
716
724
  | `mutating-step-declares-retry` | backend-medusa + backend-workflows | — | `nodes` + `objects` + `steps` + `options` | — | — | **written here** (dielime scan R5.2) |
717
725
  | `named-when-block` | backend-medusa | — | `nodes` + `options` | — | — | **written here** (dielime scan R5.5) |
718
726
  | `next-route-segment-is-thin-delegate` | frontend | — | `paths` | yes | yes | diverged |
719
- | `no-unregistered-plugin-dir` | integrations | `roots` | `options` + `paths` | — | — | **written here** (Midday's 8 dead dirs) |
727
+ | `no-unregistered-plugin-dir` | integrations | `roots` | `options` + `paths` | — | — | **written here** (Midday's 8 dead dirs; flat seam #36) |
720
728
  | `no-mock-db-in-integration` | testbed | `integrationDirs` | `options` + `paths` | — | — | **written here** (Midday's 35 mocked router suites) |
721
729
  | `router-schema-parity` | backend-trpc | `routers` | `options` + `paths` | — | — | **written here** (during.day's mirror) |
722
730
  | `no-brand-names` | frontend | `brands` | `paths` + `options` | yes | — | dielime only |
723
731
  | `no-card-shaped-div` | frontend | — | — | yes | yes | diverged |
724
732
  | `no-cross-feature-stores` | frontend | — | `directionRule` | yes | yes | diverged |
725
733
  | `no-d1-transaction` | backend-d1 | — | `paths` | — | yes | during only |
734
+ | `no-date-string-compare` | backend-workflows | — | `nodes` + `options` | — | — | **written here** (#20) |
726
735
  | `no-duplicate-jsx-patterns` | frontend | — | `paths` | yes | yes | diverged |
736
+ | `no-generic-utility-package` | tooling | — | `paths` + `options` | — | — | **written here** (#171) |
727
737
  | `no-hook-in-component-disguise` | frontend | — | `paths` | yes | yes | diverged |
728
738
  | `no-index-count-as-exact` | backend-medusa | — | `nodes` + `objects` + `options` | — | — | **written here** (Medusa source) |
729
739
  | `no-inert-hidden-jsx` | frontend | — | `paths` | yes | yes | diverged |
@@ -738,6 +748,8 @@ has, and one a kit that guessed at it would keep stale on somebody else's behalf
738
748
  | `no-react-namespace` | frontend | — | — | yes | yes | **identical** |
739
749
  | `no-renamed-html-props` | frontend | — | — | yes | yes | **identical** |
740
750
  | `no-render-prop-reader` | frontend | — | `paths` | yes | yes | diverged |
751
+ | `no-swallowed-catch` | failure-paths | — | `nodes` + `paths` + `options` | — | — | **written here** (#3) |
752
+ | `no-runtime-dead-affordance` | frontend | — | `options` | — | — | **written here** (#5) |
741
753
  | `no-trivial-wrapper-component` | frontend | — | `paths` | yes | yes | diverged |
742
754
  | `no-ts-in-bio-folders` | frontend | — | `paths` | yes | yes | diverged |
743
755
  | `no-type-definitions-in-components` | frontend | — | `paths` | yes | yes | diverged |
@@ -752,11 +764,12 @@ has, and one a kit that guessed at it would keep stale on somebody else's behalf
752
764
  | `ssot-no-process-env` | backend-workflows | — | `paths` | — | yes | during only |
753
765
  | `step-declares-compensation-or-none` | backend-medusa + backend-workflows | — | `nodes` + `objects` + `steps` + `options` | — | — | **written here** (Medusa source) |
754
766
  | `step-opens-its-own-cell` | backend-workflows-cf | `within` | `nodes` + `objects` + `paths` + `options` | — | yes | during only, re-targeted |
755
- | `store-route-scopes-tenant-data` | backend-medusa + tenant-scoping | — | `paths` | yes | — | dielime only |
767
+ | `store-route-scopes-tenant-data` | backend-medusa + tenant-scoping | — | `nodes` + `imports` + `paths` + `options` | yes | — | dielime only, de-hardcoded |
756
768
  | `subpath-over-barrel` | package-subpaths | `packages` | `nodes` + `options` | — | — | **written here** (#180, during.day asked) |
757
769
  | `subscriber-declares-id` | backend-medusa | — | `objects` + `paths` + `options` | — | — | **written here** (dielime scan R5.4) |
758
770
  | `tables-declare-their-plane` | backend-workflows + tenant-scoping | — | `paths` + `literal-call` | — | yes | during only |
759
771
  | `tenant-tables-carry-org-id` | tenant-scoping | — | `paths` + `literal-call` | — | yes | during only |
772
+ | `test-no-clock-polling-for-promise-flips` | testbed | — | `nodes` + `paths` + `options` | — | — | **written here** (#4) |
760
773
  | `tokens-only-colors` | themekit | `tokenPrefix` | `paths` + `options` + `styling` + `colors` | — | — | **written here** (U2) |
761
774
  | `time-through-the-door` | backend-workflows | `door` | `paths` + `options` | — | yes | during only, de-hardcoded |
762
775
  | `tissue-must-compose` | frontend | — | `paths` | yes | yes | diverged |
@@ -856,11 +869,12 @@ option not named here is one no rule reads.
856
869
  | `dialect-through-the-seam` | — |
857
870
  | `document-sagas-are-generic` | `factories`, `perKindPrefixes`, `within` |
858
871
  | `documents-share-one-table` | `perKindTables` |
859
- | `durable-body-reads-through-steps` | `durableKey`, `durableValue`, `ports`, `stepFactories`, `workflowFactories` |
872
+ | `durable-body-reads-through-steps` | `durableKey`, `durableValue`, `ports`, `stepFactories`, `stepProxies`, `workflowFactories` |
860
873
  | `effect-hook-naming` | — |
861
874
  | `emit-declares-attempts` | `budgetHelpers`, `emitters` |
862
- | `font-roles-only` | `allow`, `prefix`, `roles` |
875
+ | `font-roles-only` | `allow`, `exemptModules`, `prefix`, `roles` |
863
876
  | `layer-walls` | `externals`, `layers`, `typeOnly` |
877
+ | `list-take-without-order` | `callees`, `orderKeys` |
864
878
  | `max-comment-density` | — |
865
879
  | `molecule-atoms-only` | — |
866
880
  | `molecule-must-compose` | — |
@@ -871,7 +885,9 @@ option not named here is one no rule reads.
871
885
  | `no-card-shaped-div` | — |
872
886
  | `no-cross-feature-stores` | — |
873
887
  | `no-d1-transaction` | — |
888
+ | `no-date-string-compare` | `fieldPattern` |
874
889
  | `no-duplicate-jsx-patterns` | — |
890
+ | `no-generic-utility-package` | `entries`, `names` |
875
891
  | `no-hook-in-component-disguise` | — |
876
892
  | `no-index-count-as-exact` | `estimateFields`, `labelKey` |
877
893
  | `no-inert-hidden-jsx` | — |
@@ -886,6 +902,8 @@ option not named here is one no rule reads.
886
902
  | `no-react-namespace` | — |
887
903
  | `no-renamed-html-props` | — |
888
904
  | `no-render-prop-reader` | — |
905
+ | `no-runtime-dead-affordance` | (a positional list) |
906
+ | `no-swallowed-catch` | `paths` |
889
907
  | `no-trivial-wrapper-component` | — |
890
908
  | `no-ts-in-bio-folders` | — |
891
909
  | `no-type-definitions-in-components` | — |
@@ -899,23 +917,24 @@ option not named here is one no rule reads.
899
917
  | `route-no-inline-mutation` | `inlineMutationOk`, `mutationPrefixes`, `paths` |
900
918
  | `router-schema-parity` | `ignore`, `mounts`, `routers`, `schemas`, `suffix` |
901
919
  | `service-name-not-reserved` | `moduleFactories`, `reserved` |
902
- | `ssot-no-inline-facts` | |
920
+ | `ssot-no-inline-facts` | `declarationCallees` |
903
921
  | `ssot-no-process-env` | — |
904
922
  | `step-declares-compensation-or-none` | `stepFactories` |
905
923
  | `step-opens-its-own-cell` | `engine`, `hosts`, `scopeKey`, `within`, `wrapper` |
906
- | `store-route-scopes-tenant-data` | |
924
+ | `store-route-scopes-tenant-data` | `entities`, `evidenceCalls`, `routes`, `scopingCalls` |
907
925
  | `subpath-over-barrel` | `packages` |
908
926
  | `subscriber-declares-id` | `paths` |
909
927
  | `tables-declare-their-plane` | — |
910
928
  | `tenant-tables-carry-org-id` | — |
911
- | `time-through-the-door` | `door`, `exempt`, `libraries` |
929
+ | `test-no-clock-polling-for-promise-flips` | `pollers`, `testGlobs` |
930
+ | `time-through-the-door` | `door`, `exempt`, `exemptModules`, `libraries` |
912
931
  | `tissue-must-compose` | — |
913
932
  | `tissue-no-data-props` | — |
914
933
  | `tissue-no-hooks` | — |
915
934
  | `tissue-no-organelles` | — |
916
935
  | `tissue-no-stores` | — |
917
936
  | `todo-names-its-plan` | `id`, `markers` |
918
- | `tokens-only-colors` | `allow`, `tokenPrefix` |
937
+ | `tokens-only-colors` | `allow`, `exemptModules`, `tokenPrefix` |
919
938
  | `unique-query-step-name` | `queryStepCalls`, `workflowFactories` |
920
939
  | `worker-handles-are-scoped` | `within`, `wrapper` |
921
940
  | `zustand-v5-best-practices` | — |
@@ -60,7 +60,11 @@
60
60
  {
61
61
  "ports": [
62
62
  "store",
63
- "billing"
63
+ "billing",
64
+ "q"
65
+ ],
66
+ "stepProxies": [
67
+ "q"
64
68
  ]
65
69
  }
66
70
  ],
@@ -106,6 +110,7 @@
106
110
  ]
107
111
  }
108
112
  ],
113
+ "biological-architecture/list-take-without-order": "error",
109
114
  "biological-architecture/max-comment-density": "error",
110
115
  "biological-architecture/molecule-atoms-only": "error",
111
116
  "biological-architecture/molecule-must-compose": "error",
@@ -126,7 +131,9 @@
126
131
  "biological-architecture/no-card-shaped-div": "error",
127
132
  "biological-architecture/no-cross-feature-stores": "error",
128
133
  "biological-architecture/no-d1-transaction": "error",
134
+ "biological-architecture/no-date-string-compare": "error",
129
135
  "biological-architecture/no-duplicate-jsx-patterns": "error",
136
+ "biological-architecture/no-generic-utility-package": "error",
130
137
  "biological-architecture/no-hook-in-component-disguise": "error",
131
138
  "biological-architecture/no-index-count-as-exact": "error",
132
139
  "biological-architecture/no-inert-hidden-jsx": "error",
@@ -149,6 +156,14 @@
149
156
  }
150
157
  ],
151
158
  "biological-architecture/no-orm-outside-db": "error",
159
+ "biological-architecture/no-swallowed-catch": [
160
+ "error",
161
+ {
162
+ "paths": [
163
+ "(?:__fixtures__|corpus)/failure/"
164
+ ]
165
+ }
166
+ ],
152
167
  "biological-architecture/no-raw-html-atoms": [
153
168
  "error",
154
169
  [
@@ -161,6 +176,16 @@
161
176
  ],
162
177
  "biological-architecture/no-raw-sql-outside-allowed": "error",
163
178
  "biological-architecture/no-react-namespace": "error",
179
+ "biological-architecture/no-runtime-dead-affordance": [
180
+ "error",
181
+ [
182
+ {
183
+ "element": "button",
184
+ "atom": "Button",
185
+ "importPath": "@kit/ui/atoms/button"
186
+ }
187
+ ]
188
+ ],
164
189
  "biological-architecture/no-renamed-html-props": "error",
165
190
  "biological-architecture/no-render-prop-reader": "error",
166
191
  "biological-architecture/no-trivial-wrapper-component": "error",
@@ -170,11 +195,16 @@
170
195
  "error",
171
196
  {
172
197
  "roots": [
173
- "integrations/providers"
198
+ "integrations/providers",
199
+ {
200
+ "path": "messaging/providers",
201
+ "files": true
202
+ }
174
203
  ],
175
204
  "registry": [
176
205
  "integrations/registry.ts",
177
- "integrations/registry.fulfillment.ts"
206
+ "integrations/registry.fulfillment.ts",
207
+ "messaging/registry.ts"
178
208
  ],
179
209
  "manifests": [
180
210
  "index.ts"
@@ -235,7 +265,14 @@
235
265
  "wrapper": "(?:__fixtures__|corpus)/workflows/step\\.ts$"
236
266
  }
237
267
  ],
238
- "biological-architecture/store-route-scopes-tenant-data": "error",
268
+ "biological-architecture/store-route-scopes-tenant-data": [
269
+ "error",
270
+ {
271
+ "evidenceCalls": [
272
+ "assertTrackingEvidence"
273
+ ]
274
+ }
275
+ ],
239
276
  "biological-architecture/subpath-over-barrel": [
240
277
  "error",
241
278
  {
@@ -260,12 +297,13 @@
260
297
  "biological-architecture/subscriber-declares-id": "error",
261
298
  "biological-architecture/tables-declare-their-plane": "error",
262
299
  "biological-architecture/tenant-tables-carry-org-id": "error",
300
+ "biological-architecture/test-no-clock-polling-for-promise-flips": "error",
263
301
  "biological-architecture/time-through-the-door": [
264
302
  "error",
265
303
  {
266
304
  "door": "(?:__fixtures__|corpus)/time/door\\.ts$",
267
- "exempt": [
268
- "(?:__fixtures__|corpus)/time/generated/"
305
+ "exemptModules": [
306
+ "time/generated/from-openapi.ts"
269
307
  ]
270
308
  }
271
309
  ],
@@ -310,8 +348,8 @@
310
348
  "body",
311
349
  "display"
312
350
  ],
313
- "allow": [
314
- "__fixtures__/tokens/theme/"
351
+ "exemptModules": [
352
+ "tokens/theme/palette.tsx"
315
353
  ]
316
354
  }
317
355
  ],
@@ -322,8 +360,8 @@
322
360
  "--mc-",
323
361
  "--theme-"
324
362
  ],
325
- "allow": [
326
- "__fixtures__/tokens/theme/"
363
+ "exemptModules": [
364
+ "tokens/theme/palette.tsx"
327
365
  ]
328
366
  }
329
367
  ]
@@ -0,0 +1,6 @@
1
+ // BREACH: it renders, it looks pressable, and pressing it does nothing.
2
+ import { Button } from '@kit/ui/atoms/button'
3
+
4
+ export const DielineDownload = (): JSX.Element => (
5
+ <Button type="button">Download the dieline</Button>
6
+ )
@@ -0,0 +1,12 @@
1
+ // ACCEPTED: one carries a handler, one hands the press to the child, one is the form's submit.
2
+ import { Button } from '@kit/ui/atoms/button'
3
+
4
+ export const Downloads = ({ download }: { download: () => void }): JSX.Element => (
5
+ <form>
6
+ <Button onClick={download}>Download</Button>
7
+ <Button asChild>
8
+ <a href="/dieline.pdf">Open</a>
9
+ </Button>
10
+ <Button type="submit">Save</Button>
11
+ </form>
12
+ )
@@ -0,0 +1,8 @@
1
+ // BREACH, one file sideways: the read the route delegates, narrowed to nobody.
2
+ export const findOrders = async (query: {
3
+ graph: (c: unknown) => Promise<{ data: unknown[] }>
4
+ }): Promise<unknown[]> => {
5
+ const { data } = await query.graph({ entity: 'order', fields: ['id'] })
6
+
7
+ return data
8
+ }
@@ -0,0 +1,7 @@
1
+ // BREACH: the route itself names no entity — the read is in the module beside it.
2
+ import { findOrders } from './find-orders'
3
+
4
+ export async function GET(req: unknown, res: { json: (b: unknown) => void }): Promise<void> {
5
+ const query = { graph: async (_c: unknown) => ({ data: [] as unknown[] }) }
6
+ res.json({ orders: await findOrders(query) })
7
+ }
@@ -0,0 +1,12 @@
1
+ // ACCEPTED: a public route scoped by caller-supplied evidence — a reference and an email.
2
+ export const findTrackedOrder = async (
3
+ query: { graph: (c: unknown) => Promise<{ data: unknown[] }> },
4
+ input: { email: string; reference: string },
5
+ ): Promise<unknown> => {
6
+ assertTrackingEvidence(input)
7
+ const { data } = await query.graph({ entity: 'order', fields: ['id'] })
8
+
9
+ return data[0]
10
+ }
11
+
12
+ declare function assertTrackingEvidence(input: { email: string; reference: string }): void
@@ -0,0 +1,10 @@
1
+ // ACCEPTED: the evidence check the config names stands in for a session.
2
+ import { findTrackedOrder } from './find-tracked-order'
3
+
4
+ export async function GET(
5
+ req: { body: { email: string; reference: string } },
6
+ res: { json: (b: unknown) => void },
7
+ ): Promise<void> {
8
+ const query = { graph: async (_c: unknown) => ({ data: [] as unknown[] }) }
9
+ res.json({ order: await findTrackedOrder(query, req.body) })
10
+ }
@@ -0,0 +1,7 @@
1
+ // BREACH: "newest first" becomes "starts with F" — the sort is stable, plausible and wrong.
2
+ type Load = { created_at: Date; id: string; updatedAt: Date }
3
+
4
+ export const newestFirst = (loads: Load[]): Load[] =>
5
+ [...loads].sort((a, b) => String(b.created_at).localeCompare(String(a.created_at)))
6
+
7
+ export const changedSince = (load: Load, cut: string): boolean => `${load.updatedAt}` > cut
@@ -0,0 +1,7 @@
1
+ // ACCEPTED: one orders by the time, the other by the ISO string the API returned.
2
+ type Load = { created_at: Date; id: string; shipped_at: string }
3
+
4
+ export const newestFirst = (loads: Load[]): Load[] =>
5
+ [...loads].sort((a, b) => b.created_at.getTime() - a.created_at.getTime())
6
+
7
+ export const shippedSince = (load: Load, cut: string): boolean => load.shipped_at > cut
@@ -0,0 +1,13 @@
1
+ import { createWorkflow } from '@corpus/workflows'
2
+
3
+ // ACCEPTED: `q` is the engine's step proxy, so every call through it is a step — journalled under
4
+ // its own name and answered from the record on a replay.
5
+ export const settle = createWorkflow(
6
+ 'invoice.settle',
7
+ async (id: string, ctx: { q: { getInvoice: (id: string) => Promise<{ status: string }> } }) => {
8
+ const doc = await ctx.q.getInvoice(id)
9
+
10
+ return doc.status
11
+ },
12
+ { durable: true },
13
+ )
@@ -0,0 +1,17 @@
1
+ // ACCEPTED: the failure is written where the caller reads it, and the other one is rethrown.
2
+ export const refresh = (
3
+ load: () => Promise<void>,
4
+ setError: (message: string) => void,
5
+ ): void => {
6
+ load().catch((error: Error) => {
7
+ setError(error.message)
8
+ })
9
+ }
10
+
11
+ export const reload = async (load: () => Promise<void>): Promise<void> => {
12
+ try {
13
+ await load()
14
+ } catch (error) {
15
+ throw error
16
+ }
17
+ }
@@ -0,0 +1,6 @@
1
+ // BREACH: a log is not a state the caller can read — downstream, this refresh succeeded.
2
+ export const refresh = (load: () => Promise<void>): void => {
3
+ load().catch((error: Error) => {
4
+ console.error('refresh failed', error)
5
+ })
6
+ }
@@ -0,0 +1,4 @@
1
+ // BREACH: the refresh that failed reads as a refresh that succeeded.
2
+ export const refresh = (load: () => Promise<void>): void => {
3
+ load().catch(() => {})
4
+ }
@@ -0,0 +1,6 @@
1
+ // BREACH: an empty catch block, and a handler whose only answer is a log.
2
+ export const reload = async (load: () => Promise<void>): Promise<void> => {
3
+ try {
4
+ await load()
5
+ } catch {}
6
+ }
@@ -19,6 +19,7 @@
19
19
  "biological-architecture/emit-declares-attempts",
20
20
  "biological-architecture/font-roles-only",
21
21
  "biological-architecture/layer-walls",
22
+ "biological-architecture/list-take-without-order",
22
23
  "biological-architecture/max-comment-density",
23
24
  "biological-architecture/molecule-atoms-only",
24
25
  "biological-architecture/molecule-must-compose",
@@ -29,7 +30,9 @@
29
30
  "biological-architecture/no-card-shaped-div",
30
31
  "biological-architecture/no-cross-feature-stores",
31
32
  "biological-architecture/no-d1-transaction",
33
+ "biological-architecture/no-date-string-compare",
32
34
  "biological-architecture/no-duplicate-jsx-patterns",
35
+ "biological-architecture/no-generic-utility-package",
33
36
  "biological-architecture/no-hook-in-component-disguise",
34
37
  "biological-architecture/no-index-count-as-exact",
35
38
  "biological-architecture/no-inert-hidden-jsx",
@@ -44,6 +47,8 @@
44
47
  "biological-architecture/no-react-namespace",
45
48
  "biological-architecture/no-renamed-html-props",
46
49
  "biological-architecture/no-render-prop-reader",
50
+ "biological-architecture/no-runtime-dead-affordance",
51
+ "biological-architecture/no-swallowed-catch",
47
52
  "biological-architecture/no-trivial-wrapper-component",
48
53
  "biological-architecture/no-ts-in-bio-folders",
49
54
  "biological-architecture/no-type-definitions-in-components",
@@ -66,6 +71,7 @@
66
71
  "biological-architecture/subscriber-declares-id",
67
72
  "biological-architecture/tables-declare-their-plane",
68
73
  "biological-architecture/tenant-tables-carry-org-id",
74
+ "biological-architecture/test-no-clock-polling-for-promise-flips",
69
75
  "biological-architecture/time-through-the-door",
70
76
  "biological-architecture/tissue-must-compose",
71
77
  "biological-architecture/tissue-no-data-props",
@@ -0,0 +1,20 @@
1
+ // BREACH: the stage before this one wrote the plan, and this page never sees it.
2
+ declare const query: { graph: (config: unknown) => Promise<{ data: unknown[] }> }
3
+ declare function listPlannedOrders(filters: unknown, config: unknown): Promise<unknown[]>
4
+
5
+ export const latestPlan = async (orderId: string): Promise<unknown> => {
6
+ const { data } = await query.graph({
7
+ entity: 'planned_order',
8
+ fields: ['id'],
9
+ filters: { order_id: orderId },
10
+ pagination: { take: 1 },
11
+ })
12
+
13
+ return data[0]
14
+ }
15
+
16
+ export const firstOpen = async (orderId: string): Promise<unknown> => {
17
+ const rows = await listPlannedOrders({ order_id: orderId }, { take: 1 })
18
+
19
+ return rows[0]
20
+ }
@@ -0,0 +1,23 @@
1
+ // ACCEPTED: the page names the column it is a page of, so the first row is the first row.
2
+ declare const query: { graph: (config: unknown) => Promise<{ data: unknown[] }> }
3
+ declare function listPlannedOrders(filters: unknown, config: unknown): Promise<unknown[]>
4
+
5
+ export const latestPlan = async (orderId: string): Promise<unknown> => {
6
+ const { data } = await query.graph({
7
+ entity: 'planned_order',
8
+ fields: ['id'],
9
+ filters: { order_id: orderId },
10
+ pagination: { order: { created_at: 'DESC' }, take: 1 },
11
+ })
12
+
13
+ return data[0]
14
+ }
15
+
16
+ export const firstOpen = async (orderId: string): Promise<unknown> => {
17
+ const rows = await listPlannedOrders(
18
+ { order_id: orderId },
19
+ { order: { created_at: 'ASC' }, take: 1 },
20
+ )
21
+
22
+ return rows[0]
23
+ }
@@ -0,0 +1,2 @@
1
+ // ACCEPTED: the registry names this file.
2
+ export default { channel: 'email' }
@@ -0,0 +1,2 @@
1
+ // ACCEPTED: the registry names this file too.
2
+ export default { channel: 'sms' }
@@ -0,0 +1,2 @@
1
+ // BREACH: a provider file nothing reaches — it reads as a channel and behaves as dead weight.
2
+ export default { channel: 'whatsapp' }
@@ -0,0 +1,5 @@
1
+ // The flat seam's registry: providers are FILES here, one per channel.
2
+ export const providers = {
3
+ email: './providers/email-gmail',
4
+ sms: './providers/sms-twilio',
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@corpus/pricing",
3
+ "version": "0.0.0",
4
+ "private": true
5
+ }
@@ -0,0 +1,2 @@
1
+ // ACCEPTED: named for what it does, so a wrong import is obviously wrong.
2
+ export const priceOf = (cents: number, quantity: number): number => cents * quantity
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@corpus/utils",
3
+ "version": "0.0.0",
4
+ "private": true
5
+ }
@@ -0,0 +1,4 @@
1
+ // BREACH: named for nothing, so nothing can be refused entry and everything arrived.
2
+ export const formatMoney = (cents: number): string => `${(cents / 100).toFixed(2)}`
3
+ export const SUPPORT_EMAIL = 'support@corpus.example'
4
+ export const slugify = (value: string): string => value.toLowerCase().replaceAll(' ', '-')
@@ -0,0 +1,17 @@
1
+ // ACCEPTED: the promise is awaited where it was created, and the assertion runs once after it.
2
+ declare function waitFor(check: () => void): Promise<void>
3
+ declare function expect(value: unknown): { toBe: (other: unknown) => void }
4
+
5
+ export const savesTheCart = async (
6
+ save: () => Promise<void>,
7
+ subject: { done: boolean },
8
+ ): Promise<void> => {
9
+ await save()
10
+ expect(subject.done).toBe(true)
11
+ }
12
+
13
+ export const rendersTheRow = async (subject: { done: boolean }): Promise<void> => {
14
+ await waitFor(() => {
15
+ expect(subject.done).toBe(true)
16
+ })
17
+ }
@@ -0,0 +1,14 @@
1
+ // BREACH: the test holds the promise and polls the clock for the flip it decides.
2
+ declare function waitFor(check: () => void): Promise<void>
3
+ declare function expect(value: unknown): { toBe: (other: unknown) => void }
4
+
5
+ export const savesTheCart = async (
6
+ save: () => Promise<void>,
7
+ subject: { done: boolean },
8
+ ): Promise<void> => {
9
+ const settled = save()
10
+ await waitFor(() => {
11
+ expect(subject.done).toBe(true)
12
+ })
13
+ await settled
14
+ }
@@ -25,6 +25,7 @@ var FRONTEND = [
25
25
  "no-react-namespace",
26
26
  "no-renamed-html-props",
27
27
  "no-render-prop-reader",
28
+ "no-runtime-dead-affordance",
28
29
  "no-trivial-wrapper-component",
29
30
  "no-ts-in-bio-folders",
30
31
  "no-type-definitions-in-components",
@@ -45,6 +46,7 @@ var BACKEND_WORKFLOWS = [
45
46
  "documents-share-one-table",
46
47
  "durable-body-reads-through-steps",
47
48
  "mutating-step-declares-retry",
49
+ "no-date-string-compare",
48
50
  "no-orm-outside-db",
49
51
  "no-raw-sql-outside-allowed",
50
52
  "no-void-port",
@@ -71,6 +73,7 @@ var announceRename = (from) => {
71
73
  };
72
74
  var BACKEND_MEDUSA = [
73
75
  "emit-declares-attempts",
76
+ "list-take-without-order",
74
77
  "mutating-step-declares-retry",
75
78
  "named-when-block",
76
79
  "no-index-count-as-exact",
@@ -83,6 +86,7 @@ var BACKEND_MEDUSA = [
83
86
  "subscriber-declares-id",
84
87
  "unique-query-step-name"
85
88
  ];
89
+ var FAILURE_PATHS = ["no-swallowed-catch"];
86
90
  var INTEGRATIONS = ["no-unregistered-plugin-dir"];
87
91
  var BACKEND_TRPC = ["router-schema-parity"];
88
92
  var TENANT_SCOPING = [
@@ -91,9 +95,9 @@ var TENANT_SCOPING = [
91
95
  "tables-declare-their-plane",
92
96
  "tenant-tables-carry-org-id"
93
97
  ];
94
- var TOOLING = ["layer-walls", "todo-names-its-plan"];
98
+ var TOOLING = ["layer-walls", "no-generic-utility-package", "todo-names-its-plan"];
95
99
  var THEMEKIT = ["font-roles-only", "tokens-only-colors"];
96
- var TESTBED = ["no-mock-db-in-integration"];
100
+ var TESTBED = ["no-mock-db-in-integration", "test-no-clock-polling-for-promise-flips"];
97
101
  var PACKAGE_SUBPATHS = ["subpath-over-barrel"];
98
102
  var RULE_PREFIX = "biological-architecture";
99
103
  var asRules = (names) => Object.fromEntries(names.map((name) => [`${RULE_PREFIX}/${name}`, "error"]));
@@ -123,6 +127,7 @@ var PRESETS = {
123
127
  "backend-workflows": { rules: asRules(BACKEND_WORKFLOWS) },
124
128
  "backend-workflows-cf": { rules: asRules(BACKEND_WORKFLOWS_CF) },
125
129
  "comment-ceiling": COMMENT_CEILING,
130
+ "failure-paths": { rules: asRules(FAILURE_PATHS) },
126
131
  frontend: { rules: asRules(FRONTEND) },
127
132
  integrations: { rules: asRules(INTEGRATIONS) },
128
133
  "package-subpaths": { rules: asRules(PACKAGE_SUBPATHS) },