@terpjs/spec 0.15.0 → 0.16.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.
Files changed (33) hide show
  1. package/README.md +6 -6
  2. package/VERSION +1 -1
  3. package/catalog/backend/list_routes_paginate.json +2 -2
  4. package/catalog/backend/safe_methods_are_read_only.json +1 -1
  5. package/catalog/backend/schemas_exclude_sensitive_fields.json +1 -1
  6. package/catalog/frontend/escape-hatch.json +1 -1
  7. package/catalog/frontend/generated-client-only.json +2 -2
  8. package/catalog/frontend/layout-contract.json +3 -3
  9. package/catalog/frontend/no-cross-module-imports.json +1 -1
  10. package/catalog/frontend/no-deep-imports.json +2 -2
  11. package/catalog/frontend/no-dom-html-injection.json +2 -2
  12. package/catalog/frontend/no-eval.json +1 -1
  13. package/catalog/frontend/no-inline-styling.json +2 -2
  14. package/catalog/frontend/no-style-imports.json +1 -1
  15. package/catalog/frontend/no-unsafe-href.json +1 -1
  16. package/catalog/frontend/no-unsafe-target-blank.json +1 -1
  17. package/catalog/frontend/router-links.json +2 -2
  18. package/catalog/frontend/token-styled-elements.json +2 -2
  19. package/corpus/frontend/generated-client-only/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  20. package/corpus/frontend/generated-client-only/compliant-02/src/modules/widgets/Widget.tsx +1 -1
  21. package/corpus/frontend/generated-client-only/compliant-04/src/modules/widgets/Widget.tsx +1 -1
  22. package/corpus/frontend/layout-contract/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  23. package/corpus/frontend/layout-contract/violation-01/src/modules/widgets/Widget.tsx +1 -1
  24. package/corpus/frontend/no-cross-module-imports/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  25. package/corpus/frontend/no-deep-imports/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  26. package/corpus/frontend/no-deep-imports/violation-01/src/modules/widgets/Widget.tsx +1 -1
  27. package/corpus/frontend/no-dom-html-injection/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  28. package/corpus/frontend/no-eval/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  29. package/corpus/frontend/no-inline-styling/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  30. package/corpus/frontend/no-style-imports/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  31. package/corpus/frontend/router-links/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  32. package/corpus/frontend/token-styled-elements/compliant-01/src/modules/widgets/Widget.tsx +1 -1
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -138,7 +138,7 @@ The standalone suite enforces the split
138
138
  | `title` | One-line statement of the invariant. |
139
139
  | `intent` | Why the rule exists — the drift or threat it prevents. |
140
140
  | `layer` | Cheapest faithful verification for a *new* stack: see below. |
141
- | `enforcement` | How the reference implementation enforces it (first entry: the `build-time` check). A `runtime` entry names the fail-closed runtime control pairing with it (the two-layer discipline a Level 3 stack must reproduce for the rules that require it); a `black-box` entry names the `@terp/conformance` probe title. For frontend rules, `reported_as` is the ESLint rule id violations surface as — several catalog rules share one core rule id, so the adapter publishes a `catalogRuleId()` mapping and findings are attributed through it. |
141
+ | `enforcement` | How the reference implementation enforces it (first entry: the `build-time` check). A `runtime` entry names the fail-closed runtime control pairing with it (the two-layer discipline a Level 3 stack must reproduce for the rules that require it); a `black-box` entry names the `@terpjs/conformance` probe title. For frontend rules, `reported_as` is the ESLint rule id violations surface as — several catalog rules share one core rule id, so the adapter publishes a `catalogRuleId()` mapping and findings are attributed through it. |
142
142
  | `runtime` | **Mandatory.** The rule's runtime-applicability classification (`required` / `not-applicable` / `deferred`) plus a `rationale` (mandatory for exemptions) and, for `deferred`, a `tracking` reference naming where the deferral is tracked — see “Runtime applicability” below. |
143
143
  | `restricted_surface` | Frontend prohibition rules only: the `restricted-surface.json` keys the rule realises — the structural citation the spec suite resolves (every key must be claimed by some rule; a prose mention in `intent` must agree with the field). |
144
144
  | `opt_out` | The *reference realisation* of the abstract escape-hatch contract (see below). |
@@ -159,7 +159,7 @@ The standalone suite enforces the split
159
159
 
160
160
  The classification is a judgment about *porting cost*, not a limit on the
161
161
  reference implementation — today every rule is enforced by `terp.arch` or
162
- `@terp/eslint-boundaries` regardless of layer.
162
+ `@terpjs/eslint-boundaries` regardless of layer.
163
163
 
164
164
  ### Runtime applicability (the two-layer discipline, per rule)
165
165
 
@@ -222,7 +222,7 @@ consumers acting on findings without re-reading the catalog), and a
222
222
  can be tracked across line-shifting edits). Attribution is always to the
223
223
  stack-neutral catalog id — the reference ESLint adapter, whose core rule ids
224
224
  are shared between several catalog rules, publishes this mapping as
225
- `catalogRuleId()` in `@terp/eslint-boundaries`.
225
+ `catalogRuleId()` in `@terpjs/eslint-boundaries`.
226
226
 
227
227
  ## Check-report format
228
228
 
@@ -380,7 +380,7 @@ rule can ship with its gap explicit and reviewed.
380
380
  ## Conformance levels
381
381
 
382
382
  - **Level 1 — black-box:** the app passes the runnable conformance suite
383
- (`@terp/conformance`) for the capabilities it claims, including the
383
+ (`@terpjs/conformance`) for the capabilities it claims, including the
384
384
  `standard:` probes the `black-box` catalog entries name.
385
385
  - **Level 2 — static rule pack:** additionally, a checker validated against
386
386
  this corpus enforces the `static-portable` rules for the app's language(s),
@@ -388,8 +388,8 @@ rule can ship with its gap explicit and reviewed.
388
388
  - **Level 3 — full harness:** additionally, the `static-bespoke` rules, the
389
389
  paired `runtime` controls of every rule whose `runtime.applicability` is
390
390
  `required`, and the governed escape-hatch budget ratchet are enforced (today:
391
- the `terp.arch` + `@terp/eslint-boundaries` reference harness on top of
392
- `terp.core` / `@terp/react-core`).
391
+ the `terp.arch` + `@terpjs/eslint-boundaries` reference harness on top of
392
+ `terp.core` / `@terpjs/react-core`).
393
393
 
394
394
  ## Growing the spec
395
395
 
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.15.0
1
+ 0.16.0
@@ -12,7 +12,7 @@
12
12
  },
13
13
  {
14
14
  "kind": "black-box",
15
- "tool": "@terp/conformance",
15
+ "tool": "@terpjs/conformance",
16
16
  "ref": "standard: list routes return a capped Page envelope"
17
17
  },
18
18
  {
@@ -25,7 +25,7 @@
25
25
  "opt_out": "# arch-allow-list-routes-paginate: <reason>",
26
26
  "runtime": {
27
27
  "applicability": "required",
28
- "rationale": "At boot, the route scan on the composition seam (the same seam as _validate_router_response_models) walks every composed route \u2014 decorator, imperative add_api_route, and nested included routers alike \u2014 and raises a BootError naming this rule and the route when a route declares a bare list[...] / Sequence[...] response_model instead of Page[T]. PaginationDep's fail-closed skip/limit caps and the @terp/conformance Page-envelope probe remain in place on top of this in-app refusal."
28
+ "rationale": "At boot, the route scan on the composition seam (the same seam as _validate_router_response_models) walks every composed route \u2014 decorator, imperative add_api_route, and nested included routers alike \u2014 and raises a BootError naming this rule and the route when a route declares a bare list[...] / Sequence[...] response_model instead of Page[T]. PaginationDep's fail-closed skip/limit caps and the @terpjs/conformance Page-envelope probe remain in place on top of this in-app refusal."
29
29
  },
30
30
  "guide_topic": "service",
31
31
  "corpus": true
@@ -17,7 +17,7 @@
17
17
  },
18
18
  {
19
19
  "kind": "black-box",
20
- "tool": "@terp/conformance",
20
+ "tool": "@terpjs/conformance",
21
21
  "ref": "standard: safe methods observably mutate nothing"
22
22
  }
23
23
  ],
@@ -12,7 +12,7 @@
12
12
  },
13
13
  {
14
14
  "kind": "black-box",
15
- "tool": "@terp/conformance",
15
+ "tool": "@terpjs/conformance",
16
16
  "ref": "standard: responses never expose credential-shaped fields"
17
17
  },
18
18
  {
@@ -7,7 +7,7 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "terp/escape-hatch",
12
12
  "reported_as": "terp/escape-hatch"
13
13
  }
@@ -7,12 +7,12 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "BOUNDARY_SPEC.restrictedGlobals",
12
12
  "reported_as": "no-restricted-globals"
13
13
  }
14
14
  ],
15
- "reference": "useTerpClient() + unwrap from @terp/react-core for request/response; useRealtimeChannel() from @terp/react-core for typed SSE/WebSocket subscriptions (one-use ticket minted through the generated client).",
15
+ "reference": "useTerpClient() + unwrap from @terpjs/react-core for request/response; useRealtimeChannel() from @terpjs/react-core for typed SSE/WebSocket subscriptions (one-use ticket minted through the generated client).",
16
16
  "opt_out": "// terp-allow-generated-client-only: <reason>",
17
17
  "runtime": {
18
18
  "applicability": "not-applicable",
@@ -7,18 +7,18 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "terp/layout-contract",
12
12
  "reported_as": "terp/layout-contract"
13
13
  },
14
14
  {
15
15
  "kind": "runtime",
16
- "tool": "@terp/react-core",
16
+ "tool": "@terpjs/react-core",
17
17
  "ref": "verifySlotChildren"
18
18
  }
19
19
  ],
20
20
  "opt_out": "// terp-allow-layout-contract: <reason>",
21
- "reference": "frontend/layout-contract.json + the layoutContract bootstrap option (ADR 0079); verifySlotChildren in @terp/react-core is the runtime DOM check.",
21
+ "reference": "frontend/layout-contract.json + the layoutContract bootstrap option (ADR 0079); verifySlotChildren in @terpjs/react-core is the runtime DOM check.",
22
22
  "runtime": {
23
23
  "applicability": "required"
24
24
  },
@@ -7,7 +7,7 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "terp/no-cross-module-imports",
12
12
  "reported_as": "terp/no-cross-module-imports"
13
13
  }
@@ -7,12 +7,12 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "BOUNDARY_SPEC.internalImportPatterns",
12
12
  "reported_as": "no-restricted-imports"
13
13
  }
14
14
  ],
15
- "reference": "@terp/*/src/* and @terp/*/dist/* imports are refused; import from the @terp/* package root.",
15
+ "reference": "@terpjs/*/src/* and @terpjs/*/dist/* imports are refused; import from the @terpjs/* package root.",
16
16
  "opt_out": "// terp-allow-no-deep-imports: <reason>",
17
17
  "runtime": {
18
18
  "applicability": "not-applicable",
@@ -7,12 +7,12 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "terp/no-dom-html-injection",
12
12
  "reported_as": "terp/no-dom-html-injection"
13
13
  }
14
14
  ],
15
- "reference": "The Markdown component from @terp/react-core for rich text.",
15
+ "reference": "The Markdown component from @terpjs/react-core for rich text.",
16
16
  "opt_out": "// terp-allow-no-dom-html-injection: <reason>",
17
17
  "runtime": {
18
18
  "applicability": "not-applicable",
@@ -7,7 +7,7 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "terp/no-eval",
12
12
  "reported_as": "terp/no-eval"
13
13
  }
@@ -7,12 +7,12 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "BOUNDARY_SPEC.restrictedAttributes",
12
12
  "reported_as": "no-restricted-syntax"
13
13
  }
14
14
  ],
15
- "reference": "Layout via Stack, DetailList and the page archetypes from @terp/react-core; theming via the app's token source.",
15
+ "reference": "Layout via Stack, DetailList and the page archetypes from @terpjs/react-core; theming via the app's token source.",
16
16
  "opt_out": "// terp-allow-no-inline-styling: <reason>",
17
17
  "runtime": {
18
18
  "applicability": "not-applicable",
@@ -7,7 +7,7 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "BOUNDARY_SPEC.styleImportPatterns",
12
12
  "reported_as": "no-restricted-imports"
13
13
  }
@@ -7,7 +7,7 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "terp/no-unsafe-href",
12
12
  "reported_as": "terp/no-unsafe-href"
13
13
  }
@@ -7,7 +7,7 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "terp/no-unsafe-target-blank",
12
12
  "reported_as": "terp/no-unsafe-target-blank"
13
13
  }
@@ -7,12 +7,12 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "BOUNDARY_SPEC.restrictInAppAnchors",
12
12
  "reported_as": "no-restricted-syntax"
13
13
  }
14
14
  ],
15
- "reference": "Link from @terp/react-core (router-integrated, role-aware).",
15
+ "reference": "Link from @terpjs/react-core (router-integrated, role-aware).",
16
16
  "opt_out": "// terp-allow-router-links: <reason>",
17
17
  "runtime": {
18
18
  "applicability": "not-applicable",
@@ -7,12 +7,12 @@
7
7
  "enforcement": [
8
8
  {
9
9
  "kind": "build-time",
10
- "tool": "@terp/eslint-boundaries",
10
+ "tool": "@terpjs/eslint-boundaries",
11
11
  "ref": "BOUNDARY_SPEC.restrictedElements",
12
12
  "reported_as": "no-restricted-syntax"
13
13
  }
14
14
  ],
15
- "reference": "Button, Input, Select, Textarea, DataView, ConfirmDialog and Stack as=\"form\" from @terp/react-core (BOUNDARY_SPEC.restrictedElements maps each element to its replacement).",
15
+ "reference": "Button, Input, Select, Textarea, DataView, ConfirmDialog and Stack as=\"form\" from @terpjs/react-core (BOUNDARY_SPEC.restrictedElements maps each element to its replacement).",
16
16
  "opt_out": "// terp-allow-token-styled-elements: <reason>",
17
17
  "runtime": {
18
18
  "applicability": "not-applicable",
@@ -1,4 +1,4 @@
1
- import { useTerpClient } from "@terp/react-core";
1
+ import { useTerpClient } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  const client = useTerpClient();
4
4
  void client;
@@ -1,4 +1,4 @@
1
- import { useTerpClient } from "@terp/react-core";
1
+ import { useTerpClient } from "@terpjs/react-core";
2
2
 
3
3
  const repository = {
4
4
  fetch(id: string): string {
@@ -1,4 +1,4 @@
1
- import { useRealtimeChannel } from "@terp/react-core";
1
+ import { useRealtimeChannel } from "@terpjs/react-core";
2
2
 
3
3
  type Notice = { sequence: number; text: string };
4
4
 
@@ -1,4 +1,4 @@
1
- import { HubCard, HubPage } from "@terp/react-core";
1
+ import { HubCard, HubPage } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return (
4
4
  <HubPage title="Notes">
@@ -1,4 +1,4 @@
1
- import { DetailList, HubPage } from "@terp/react-core";
1
+ import { DetailList, HubPage } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return (
4
4
  <HubPage title="Notes">
@@ -1,4 +1,4 @@
1
- import { Button } from "@terp/react-core";
1
+ import { Button } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return <Button>ok</Button>;
4
4
  }
@@ -1,4 +1,4 @@
1
- import { Button } from "@terp/react-core";
1
+ import { Button } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return <Button>ok</Button>;
4
4
  }
@@ -1,2 +1,2 @@
1
- import Button from "@terp/react-core/src/Button";
1
+ import Button from "@terpjs/react-core/src/Button";
2
2
  export const Widget = () => <Button>x</Button>;
@@ -1,4 +1,4 @@
1
- import { Button } from "@terp/react-core";
1
+ import { Button } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return <Button>ok</Button>;
4
4
  }
@@ -1,4 +1,4 @@
1
- import { Button } from "@terp/react-core";
1
+ import { Button } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return <Button>ok</Button>;
4
4
  }
@@ -1,4 +1,4 @@
1
- import { Button } from "@terp/react-core";
1
+ import { Button } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return <Button>ok</Button>;
4
4
  }
@@ -1,4 +1,4 @@
1
- import { Button } from "@terp/react-core";
1
+ import { Button } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return <Button>ok</Button>;
4
4
  }
@@ -1,4 +1,4 @@
1
- import { Link } from "@terp/react-core";
1
+ import { Link } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return <Link to="/notes">notes</Link>;
4
4
  }
@@ -1,4 +1,4 @@
1
- import { Button } from "@terp/react-core";
1
+ import { Button } from "@terpjs/react-core";
2
2
  export function Widget() {
3
3
  return <Button>ok</Button>;
4
4
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@terpjs/spec",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "The Terp Standard — stack-neutral rule catalog, violation corpus, finding format, and refused-surface declaration (ADRs 0080/0081; packaged per ADR 0082, published per ADR 0086). Data only: consumers resolve the spec root via require.resolve('@terpjs/spec/package.json').",
5
5
  "files": [
6
6
  "VERSION",