@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.
- package/README.md +6 -6
- package/VERSION +1 -1
- package/catalog/backend/list_routes_paginate.json +2 -2
- package/catalog/backend/safe_methods_are_read_only.json +1 -1
- package/catalog/backend/schemas_exclude_sensitive_fields.json +1 -1
- package/catalog/frontend/escape-hatch.json +1 -1
- package/catalog/frontend/generated-client-only.json +2 -2
- package/catalog/frontend/layout-contract.json +3 -3
- package/catalog/frontend/no-cross-module-imports.json +1 -1
- package/catalog/frontend/no-deep-imports.json +2 -2
- package/catalog/frontend/no-dom-html-injection.json +2 -2
- package/catalog/frontend/no-eval.json +1 -1
- package/catalog/frontend/no-inline-styling.json +2 -2
- package/catalog/frontend/no-style-imports.json +1 -1
- package/catalog/frontend/no-unsafe-href.json +1 -1
- package/catalog/frontend/no-unsafe-target-blank.json +1 -1
- package/catalog/frontend/router-links.json +2 -2
- package/catalog/frontend/token-styled-elements.json +2 -2
- package/corpus/frontend/generated-client-only/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/generated-client-only/compliant-02/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/generated-client-only/compliant-04/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/layout-contract/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/layout-contract/violation-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/no-cross-module-imports/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/no-deep-imports/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/no-deep-imports/violation-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/no-dom-html-injection/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/no-eval/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/no-inline-styling/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/no-style-imports/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/router-links/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- package/corpus/frontend/token-styled-elements/compliant-01/src/modules/widgets/Widget.tsx +1 -1
- 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 `@
|
|
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
|
-
`@
|
|
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 `@
|
|
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
|
-
(`@
|
|
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` + `@
|
|
392
|
-
`terp.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.
|
|
1
|
+
0.16.0
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"kind": "black-box",
|
|
15
|
-
"tool": "@
|
|
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 @
|
|
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
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"enforcement": [
|
|
8
8
|
{
|
|
9
9
|
"kind": "build-time",
|
|
10
|
-
"tool": "@
|
|
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 @
|
|
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": "@
|
|
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": "@
|
|
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 @
|
|
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,12 +7,12 @@
|
|
|
7
7
|
"enforcement": [
|
|
8
8
|
{
|
|
9
9
|
"kind": "build-time",
|
|
10
|
-
"tool": "@
|
|
10
|
+
"tool": "@terpjs/eslint-boundaries",
|
|
11
11
|
"ref": "BOUNDARY_SPEC.internalImportPatterns",
|
|
12
12
|
"reported_as": "no-restricted-imports"
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
|
-
"reference": "@
|
|
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": "@
|
|
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 @
|
|
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,12 +7,12 @@
|
|
|
7
7
|
"enforcement": [
|
|
8
8
|
{
|
|
9
9
|
"kind": "build-time",
|
|
10
|
-
"tool": "@
|
|
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 @
|
|
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,12 +7,12 @@
|
|
|
7
7
|
"enforcement": [
|
|
8
8
|
{
|
|
9
9
|
"kind": "build-time",
|
|
10
|
-
"tool": "@
|
|
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 @
|
|
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": "@
|
|
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 @
|
|
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,2 +1,2 @@
|
|
|
1
|
-
import Button from "@
|
|
1
|
+
import Button from "@terpjs/react-core/src/Button";
|
|
2
2
|
export const Widget = () => <Button>x</Button>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@terpjs/spec",
|
|
3
|
-
"version": "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",
|