@intentius/tsad-conformance 1.4.0 → 1.6.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 (130) hide show
  1. package/dist/adapter.d.ts +53 -1
  2. package/dist/adapter.d.ts.map +1 -1
  3. package/dist/fixture.d.ts +28 -1
  4. package/dist/fixture.d.ts.map +1 -1
  5. package/dist/fixture.js +27 -2
  6. package/dist/fixture.js.map +1 -1
  7. package/dist/host.d.ts +13 -0
  8. package/dist/host.d.ts.map +1 -1
  9. package/dist/host.js +33 -0
  10. package/dist/host.js.map +1 -1
  11. package/dist/runner.d.ts +28 -2
  12. package/dist/runner.d.ts.map +1 -1
  13. package/dist/runner.js +129 -3
  14. package/dist/runner.js.map +1 -1
  15. package/fixtures/F-Call/a-host-factory-is-invoked/expect.json +45 -0
  16. package/fixtures/F-Call/a-host-factory-is-invoked/project/app.ts +4 -0
  17. package/fixtures/F-Call/a-host-factory-is-invoked/project/nested.ts +3 -0
  18. package/fixtures/F-Call/a-host-factory-is-invoked/project/plain.ts +3 -0
  19. package/fixtures/F-Declarator/a-const-alias-of-a-call-resolves-at-the-declarator/expect.json +50 -0
  20. package/fixtures/F-Declarator/a-const-alias-of-a-call-resolves-at-the-declarator/project/app.ts +13 -0
  21. package/fixtures/F-Declarator/a-const-alias-of-a-call-resolves-at-the-declarator/project/nested.ts +5 -0
  22. package/fixtures/F-Declarator/a-const-alias-of-a-call-resolves-at-the-declarator/project/store.ts +3 -0
  23. package/fixtures/F-Div-Step/step-reads-the-resolved-composite/expect.json +48 -0
  24. package/fixtures/F-Div-Step/step-reads-the-resolved-composite/project/app.ts +4 -0
  25. package/fixtures/F-Div-Step/step-reads-the-resolved-composite/project/pipeline.ts +3 -0
  26. package/fixtures/F-Host-Closed-vs-Open/package-call-is-closed/expect.json +18 -5
  27. package/fixtures/F-Host-Composite/a-registered-composite-is-interpreted/expect.json +47 -0
  28. package/fixtures/F-Host-Composite/a-registered-composite-is-interpreted/project/app.ts +4 -0
  29. package/fixtures/F-Host-Composite/a-registered-composite-is-interpreted/project/store.ts +6 -0
  30. package/fixtures/F-IsolatedRefusal/a-project-factory-is-refused-not-invoked/expect.json +18 -0
  31. package/fixtures/F-IsolatedRefusal/a-project-factory-is-refused-not-invoked/project/app.ts +3 -0
  32. package/fixtures/F-IsolatedRefusal/a-project-factory-is-refused-not-invoked/project/shapes.ts +5 -0
  33. package/fixtures/F-Obs-Counters/a-build-reports-its-counts/expect.json +43 -0
  34. package/fixtures/F-Obs-Counters/a-build-reports-its-counts/project/app.ts +5 -0
  35. package/fixtures/F-Obs-Counters/a-build-reports-its-counts/project/shapes.ts +3 -0
  36. package/fixtures/F-Rule-Equivalence/same-source-same-findings/expect.json +21 -0
  37. package/fixtures/F-Rule-Equivalence/same-source-same-findings/project/buckets.ts +8 -0
  38. package/fixtures/F-Rule-Equivalence/same-source-same-findings/project/helpers.ts +3 -0
  39. package/fixtures/F-Rule-Input/a-rule-sees-the-folded-namespace/expect.json +21 -0
  40. package/fixtures/F-Rule-Input/a-rule-sees-the-folded-namespace/project/buckets.ts +4 -0
  41. package/fixtures/F-Rule-Phase/a-post-rule-reads-the-artifact/expect.json +21 -0
  42. package/fixtures/F-Rule-Phase/a-post-rule-reads-the-artifact/project/pairs.ts +3 -0
  43. package/fixtures/F-Rule-Pure/findings-are-a-function-of-the-input/expect.json +21 -0
  44. package/fixtures/F-Rule-Pure/findings-are-a-function-of-the-input/project/buckets.ts +4 -0
  45. package/fixtures/F-Rule-Pure/findings-are-a-function-of-the-input/project/clock.ts +1 -0
  46. package/fixtures/F-Rule-Supply/the-host-names-the-rule/expect.json +21 -0
  47. package/fixtures/F-Rule-Supply/the-host-names-the-rule/project/app.ts +4 -0
  48. package/fixtures/F-Val-Domain/every-case-is-a-value/expect.json +49 -0
  49. package/fixtures/F-Val-Domain/every-case-is-a-value/project/app.ts +6 -0
  50. package/fixtures/F-Val-Envelope/envelopes-are-the-output-in-data-host/expect.json +41 -0
  51. package/fixtures/F-Val-Envelope/envelopes-are-the-output-in-data-host/project/app.ts +5 -0
  52. package/fixtures/F-Val-Source/a-form-per-case-in-data-host/expect.json +74 -0
  53. package/fixtures/F-Val-Source/a-form-per-case-in-data-host/project/app.ts +8 -0
  54. package/fixtures/F-Val-Source/a-form-per-case-in-full/expect.json +35 -0
  55. package/fixtures/F-Val-Source/a-form-per-case-in-full/project/app.ts +7 -0
  56. package/fixtures/F-Val-Symbol-Scope/a-symbol-only-inside-an-intrinsic/expect.json +32 -0
  57. package/fixtures/F-Val-Symbol-Scope/a-symbol-only-inside-an-intrinsic/project/interior.ts +3 -0
  58. package/fixtures/F-Val-Symbol-Scope/a-symbol-only-inside-an-intrinsic/project/top.ts +1 -0
  59. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/expect.json +34 -0
  60. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/project/array.ts +1 -0
  61. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/project/class.ts +1 -0
  62. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/project/default-function.ts +3 -0
  63. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/project/let.ts +1 -0
  64. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/project/ok.ts +1 -0
  65. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/project/rest.ts +1 -0
  66. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/project/star.ts +1 -0
  67. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/project/uninitialized.ts +1 -0
  68. package/fixtures/S-Disqualify/each-arm-disqualifies-the-file/project/var.ts +1 -0
  69. package/fixtures/S-ExportDestructure/plain-elements/expect.json +16 -0
  70. package/fixtures/S-ExportDestructure/plain-elements/project/app.ts +3 -0
  71. package/fixtures/S-ExportNamed/local-names-with-an-alias/expect.json +19 -0
  72. package/fixtures/S-ExportNamed/local-names-with-an-alias/project/app.ts +4 -0
  73. package/fixtures/S-ExportResource/new-with-props/expect.json +26 -0
  74. package/fixtures/S-ExportResource/new-with-props/project/app.ts +3 -0
  75. package/fixtures/S-ExportSingle/an-expression-initializer/expect.json +21 -0
  76. package/fixtures/S-ExportSingle/an-expression-initializer/input.ts +1 -0
  77. package/fixtures/S-ExportTypeOnly/type-exports-are-invisible/expect.json +19 -0
  78. package/fixtures/S-ExportTypeOnly/type-exports-are-invisible/project/app.ts +12 -0
  79. package/fixtures/S-FactoryBody/consts-then-a-final-return/expect.json +38 -0
  80. package/fixtures/S-FactoryBody/consts-then-a-final-return/project/bad-shapes.ts +7 -0
  81. package/fixtures/S-FactoryBody/consts-then-a-final-return/project/empty.ts +3 -0
  82. package/fixtures/S-FactoryBody/consts-then-a-final-return/project/good-shapes.ts +7 -0
  83. package/fixtures/S-FactoryBody/consts-then-a-final-return/project/good.ts +3 -0
  84. package/fixtures/S-FactoryBody/consts-then-a-final-return/project/no-return.ts +3 -0
  85. package/fixtures/S-FactoryParams/one-plainly-bound-parameter/expect.json +38 -0
  86. package/fixtures/S-FactoryParams/one-plainly-bound-parameter/project/bad-shapes.ts +4 -0
  87. package/fixtures/S-FactoryParams/one-plainly-bound-parameter/project/good-shapes.ts +3 -0
  88. package/fixtures/S-FactoryParams/one-plainly-bound-parameter/project/named.ts +3 -0
  89. package/fixtures/S-FactoryParams/one-plainly-bound-parameter/project/rest.ts +3 -0
  90. package/fixtures/S-FactoryParams/one-plainly-bound-parameter/project/two.ts +3 -0
  91. package/fixtures/S-Module/non-exported-statements-are-invisible/expect.json +17 -0
  92. package/fixtures/S-Module/non-exported-statements-are-invisible/project/app.ts +13 -0
  93. package/fixtures/S-Prop/a-computed-key-rejects/expect.json +10 -0
  94. package/fixtures/S-Prop/a-computed-key-rejects/input.ts +3 -0
  95. package/fixtures/S-Prop/literal-keys/expect.json +15 -0
  96. package/fixtures/S-Prop/literal-keys/input.ts +1 -0
  97. package/fixtures/S-ReExport/named-from-a-sibling/expect.json +18 -0
  98. package/fixtures/S-ReExport/named-from-a-sibling/project/app.ts +1 -0
  99. package/fixtures/S-ReExport/named-from-a-sibling/project/config.ts +2 -0
  100. package/fixtures/S-Shorthand/a-shorthand-property-resolves-as-an-identifier/expect.json +14 -0
  101. package/fixtures/S-Shorthand/a-shorthand-property-resolves-as-an-identifier/input.ts +4 -0
  102. package/fixtures/S-TopConst/an-unexported-const-is-a-binding/expect.json +16 -0
  103. package/fixtures/S-TopConst/an-unexported-const-is-a-binding/project/binding.ts +3 -0
  104. package/fixtures/S-TopConst/an-unexported-const-is-a-binding/project/invisible.ts +3 -0
  105. package/fixtures/UNCOVERED.md +1 -28
  106. package/fixtures/roundtrip/a-resource-and-its-attribute/expect.json +8 -0
  107. package/fixtures/roundtrip/a-resource-and-its-attribute/value.json +29 -0
  108. package/fixtures/roundtrip/a-resource-by-args/expect.json +8 -0
  109. package/fixtures/roundtrip/a-resource-by-args/value.json +14 -0
  110. package/fixtures/roundtrip/intrinsics-and-a-symbol/expect.json +8 -0
  111. package/fixtures/roundtrip/intrinsics-and-a-symbol/value.json +36 -0
  112. package/fixtures/roundtrip/scalars-and-containers/expect.json +8 -0
  113. package/fixtures/roundtrip/scalars-and-containers/value.json +28 -0
  114. package/package.json +1 -1
  115. package/spec/VERSION +1 -1
  116. package/spec/hosts.md +6 -2
  117. package/spec/judgments.md +27 -10
  118. package/spec/rules.md +7 -4
  119. package/spec/values.md +47 -2
  120. package/src/adapter.ts +53 -0
  121. package/src/adapters/chant.ts +361 -10
  122. package/src/adapters/rust.ts +77 -0
  123. package/src/chant-agreement.test.ts +68 -23
  124. package/src/corpus.test.ts +12 -0
  125. package/src/corpus.ts +76 -34
  126. package/src/fixture.ts +42 -3
  127. package/src/host.ts +50 -0
  128. package/src/runner.test.ts +6 -2
  129. package/src/runner.ts +107 -5
  130. package/src/rust-agreement.test.ts +37 -0
@@ -0,0 +1,3 @@
1
+ const base = 21;
2
+
3
+ export const x = base * 2;
@@ -0,0 +1,3 @@
1
+ const { q } = { q: 1 };
2
+
3
+ export const y = q;
@@ -2,36 +2,9 @@
2
2
 
3
3
  Deliberate, and this list may only shrink (#8). Each entry names the rule and why it is still uncovered. Remove an entry when its fixture lands; the gate fails if an entry is stale.
4
4
 
5
- 107 of 138 rules have fixtures. Most of the rules below are uncovered because the corpus is still growing (#24); where a rule needs something the reference implementation does not have, the entry says so.
5
+ 135 of 139 rules have fixtures. Every rule below needs something the reference implementation does not have, or something no adapter can observe; the entry says which.
6
6
 
7
- - `F-Rule-Input` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
8
- - `F-Rule-Phase` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
9
- - `F-Rule-Pure` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
10
- - `F-Rule-Finding` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
11
- - `F-Rule-Equivalence` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
12
- - `F-Rule-Supply` — the harness has no rule hook and no findings-as-data fixture kind yet (#101)
13
- - `F-Div-Step` — needs `{__compositeStep}`, which has no fate in the reference implementation (no composite factory form)
14
- - `F-Eval-Interior` — an unresolved chain inside an intrinsic call folds to a symbol only with a registry in scope, and an expression fixture names no host
15
- - `F-Host-Composite` — needs the composite registration form `Composite(fn, "N")`, which the reference implementation does not have
16
7
  - `F-Host-Generality` — says what a host may vary and what it may not; no verdict exercises it
17
- - `F-IsolatedRefusal` — needs isolation mode, which the reference implementation does not have
18
8
  - `F-NoOwnExecution` — measured by chant's `test/leftness` profile; an adapter reports verdicts and cannot observe execution
19
9
  - `F-NotProject` — a file inside the host's own module tree; the reference's project is a map with no outside
20
- - `F-Obs-Counters` — the conformance adapter exposes no counters
21
10
  - `F-Obs-Provenance` — an optional capability, reported rather than asserted
22
- - `F-Val-Domain` — no fixture yet; corpus is #24's
23
- - `F-Val-Envelope` — no fixture yet; corpus is #24's
24
- - `F-Val-Symbol-Scope` — no fixture yet; corpus is #24's
25
- - `S-Disqualify` — no fixture yet; corpus is #24's
26
- - `S-ExportDestructure` — no fixture yet; corpus is #24's
27
- - `S-ExportNamed` — no fixture yet; corpus is #24's
28
- - `S-ExportResource` — no fixture yet; corpus is #24's
29
- - `S-ExportSingle` — no fixture yet; corpus is #24's
30
- - `S-ExportTypeOnly` — no fixture yet; corpus is #24's
31
- - `S-FactoryBody` — needs the composite factory form, which the reference implementation does not have
32
- - `S-FactoryParams` — needs the composite factory form, which the reference implementation does not have
33
- - `S-Module` — no fixture yet; corpus is #24's
34
- - `S-Prop` — no fixture yet; corpus is #24's
35
- - `S-ReExport` — no fixture yet; corpus is #24's
36
- - `S-Shorthand` — no fixture yet; corpus is #24's
37
- - `S-TopConst` — no fixture yet; corpus is #24's
@@ -0,0 +1,8 @@
1
+ {
2
+ "rules": [
3
+ "F-Val-Source"
4
+ ],
5
+ "roundtrip": true,
6
+ "host": "shapes",
7
+ "note": "A resource with props and attributes, and attribute references to it at the top and nested. The generator names the same-file binding; F-Eval-Member step 1 folds the read back to the reference."
8
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "logs": {
3
+ "__resource": "Bucket",
4
+ "props": {
5
+ "name": "logs",
6
+ "tags": [
7
+ "a",
8
+ "b"
9
+ ]
10
+ },
11
+ "attributes": {
12
+ "region": "eu"
13
+ }
14
+ },
15
+ "arn": {
16
+ "__attrRef": {
17
+ "entity": "logs",
18
+ "attribute": "arn"
19
+ }
20
+ },
21
+ "site": {
22
+ "origin": {
23
+ "__attrRef": {
24
+ "entity": "logs",
25
+ "attribute": "website"
26
+ }
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "rules": [
3
+ "F-Val-Source"
4
+ ],
5
+ "roundtrip": true,
6
+ "host": "shapes",
7
+ "note": "A resource whose constructor arguments are not (props) or (props, attributes): args is authoritative and the generator spreads it; props is the first object-literal argument, reported for readers and never re-passed (F-Val-Arity)."
8
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "pair": {
3
+ "__resource": "Pair",
4
+ "props": {
5
+ "right": true
6
+ },
7
+ "args": [
8
+ "left",
9
+ {
10
+ "right": true
11
+ }
12
+ ]
13
+ }
14
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "rules": [
3
+ "F-Val-Source"
4
+ ],
5
+ "roundtrip": true,
6
+ "host": "shapes",
7
+ "note": "Both intrinsic forms with a symbol, an attribute reference and a span that needs escaping inside them. A symbol has a form only inside an interior, which is where the generator puts it."
8
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "logs": {
3
+ "__resource": "Bucket",
4
+ "props": {
5
+ "name": "logs"
6
+ }
7
+ },
8
+ "tagged": {
9
+ "__intrinsic": "join",
10
+ "strings": [
11
+ "arn:",
12
+ ":",
13
+ "/`${x}`"
14
+ ],
15
+ "values": [
16
+ {
17
+ "__symbol": "Region.Name"
18
+ },
19
+ {
20
+ "__attrRef": {
21
+ "entity": "logs",
22
+ "attribute": "arn"
23
+ }
24
+ }
25
+ ]
26
+ },
27
+ "called": {
28
+ "__intrinsic": "ref",
29
+ "args": [
30
+ "logs",
31
+ {
32
+ "__symbol": "Stack.Id"
33
+ }
34
+ ]
35
+ }
36
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "rules": [
3
+ "F-Val-Source"
4
+ ],
5
+ "roundtrip": true,
6
+ "host": "shapes",
7
+ "note": "Every scalar, arrays and objects of them, a key that is not an identifier. The generator writes literals; the fold reads them back."
8
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "scalars": {
3
+ "s": "text",
4
+ "n": 1.5,
5
+ "big": 1e+21,
6
+ "b": false,
7
+ "z": null,
8
+ "u": "$undefined"
9
+ },
10
+ "list": [
11
+ 1,
12
+ "two",
13
+ [
14
+ 3,
15
+ [
16
+ 4
17
+ ]
18
+ ],
19
+ {
20
+ "five": 5
21
+ }
22
+ ],
23
+ "keys": {
24
+ "plain": 1,
25
+ "with-dash": 2,
26
+ "3": "three"
27
+ }
28
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/tsad-conformance",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "The conformance suite of the typescript-as-data specification: fixture loader, runner, and the named hosts. An implementation supplies an adapter and gets a report.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/spec/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4
1
+ 1.6
package/spec/hosts.md CHANGED
@@ -90,8 +90,12 @@ helpers and `propagate` mutates in place; `createResource()`/
90
90
 
91
91
  A call into a **package** folds only through a closed allowlist, a
92
92
  registered intrinsic or helper, checked by name *and* by the provenance of
93
- the binding (R3.3, F-Div-Provenance). A call into a **project file** folds
94
- whenever the callee's body is itself in the subset (R6.5), with no allowlist.
93
+ the binding (R3.3, F-Div-Provenance), or at a declarator by invocation
94
+ (F-Call), reached directly or through a const alias (F-Declarator), where
95
+ since `1.6` the result is a value whatever it is. A call nested inside an
96
+ expression never folds through a package. A call into a **project file**
97
+ folds whenever the callee's body is itself in the subset (R6.5), with no
98
+ allowlist.
95
99
 
96
100
  The asymmetry is the trust boundary (R2.1, #36). Package code is already
97
101
  loaded and executed by the build before discovery begins; admitting a call
package/spec/judgments.md CHANGED
@@ -63,6 +63,7 @@ another language embeds, or a JavaScript tool that folds and never runs. It is
63
63
  | `F-Val-Fate` | altered: revival is serialization. An envelope is the output; `{__resource}`, `{__intrinsic}` and `{__attrRef}` reach the artifact as data for the host's serializer to map. No constructor and no function is invoked |
64
64
  | `F-Eval-CallHelper`, `F-Eval-CallEager`, `F-Host-Admission`, `F-Host-NoSubstitution` | absent: there is nothing to invoke. A registered helper or eager name is an ordinary unresolved identifier |
65
65
  | `F-Eval-Tagged`, `F-Eval-CallIntrinsic` | apply; the envelope stays an envelope |
66
+ | `F-Val-Source` | applies, and the round trip is `fold(generate(v)) = v` literally: no fate runs, so the fold of a form is the envelope itself. The helper and composite-step cases are absent with their rules |
66
67
  | `F-Call`, `F-Host-Composite` | interpretation only (step 4). A factory that is not interpretable is an error, never invoked |
67
68
  | `S-LocalFunction`, `S-CallLocal` | apply in full: a same-file or project-imported function is called by interpretation, which needs no runtime |
68
69
  | `S-ExportDefault` | applies: a default export is the declarator named `default`. In `full` it is permitted, not required, and chant does not yet admit it |
@@ -331,11 +332,23 @@ F-IsolatedRefusal like any other.
331
332
  here; a second construction would put two entities where running puts one
332
333
  (F-Count). Under `isolated`, a `T` from a project file is
333
334
  F-IsolatedRefusal.
334
- - *single* `export const x = e`: if `e` is a call, F-Call; if a member or
335
- element access on a call's result, F-Call then index (base must be an
336
- indexable object); otherwise J1 on `e`, revived.
337
- - *destructure* `export const { a, b: c } = e`: `e` must resolve to a
338
- composite instance or an indexable object; each element indexes it.
335
+ - *single* `export const x = e`: if `e` is a call, its direct arguments are
336
+ resolved first. An argument that is itself a package call resolves by
337
+ F-Call, as does a member read on such a call or a const alias of either;
338
+ every other argument is J1's (`1.6`, #110, `L2.18`). Then the call is
339
+ F-Call for an unregistered callee, or J1's registered form for a helper or
340
+ an intrinsic. If `e` is a member or element access on a
341
+ call's result, F-Call then index (base must be an indexable object); when
342
+ `e` is an identifier bound by a top-level `const`,
343
+ through any chain of such aliases (`L7.7`), to a call or to a member access
344
+ on one, the same again, with the call resolved once per file (F-Count);
345
+ otherwise J1 on `e`, revived. The alias case was added in `1.6` (#110),
346
+ since chant had followed it for a composite and for any package export
347
+ alike (`L2.18`); a call reached any other way, nested inside an expression,
348
+ stays J1's rejection.
349
+ - *destructure* `export const { a, b: c } = e`: `e`, through the same
350
+ aliases, must resolve to a composite instance or an indexable object; each
351
+ element indexes it.
339
352
  - *named-export* `export { a, b as c }`: each local name resolves through
340
353
  `locals` then `externals`, by F-Eval-Ident and not by re-folding the
341
354
  initializer, so a name bound to a same-file `new` reads F-Prebuild's
@@ -361,10 +374,14 @@ F-IsolatedRefusal like any other.
361
374
  6. Otherwise the module is imported (once per build) and `c` **invoked** with
362
375
  the resolved arguments; `factoryInvocations += 1`, and
363
376
  `projectFactoryInvocations += 1` if the specifier is a project file.
364
- Arguments that are live objects pass through unchanged; a `{__attrRef}`
365
- among them stays symbolic (R1.2, L6.9).
366
- 7. The result must be a `CompositeInstance` or a `Declarable`; otherwise
367
- `run`.
377
+ An argument is resolved as F-Declarator says, a direct package call by
378
+ this rule in turn and the rest by J1; a call nested deeper inside an
379
+ argument is J1's rejection. Arguments that are live objects pass
380
+ through unchanged; a `{__attrRef}` among them stays symbolic (R1.2, `L6.9`).
381
+ 7. The result is a value, live or plain, and is what the declarator binds
382
+ (`1.6`, #110); a destructured declarator needs an indexable object
383
+ (F-Declarator). Before `1.6` the text required an entity or a composite
384
+ instance here, which chant never implemented (`L8.19`).
368
385
 
369
386
  **F-Count.** Within `f`, a composite call reached by several member accesses
370
387
  or destructured names is resolved once (`ResolveCtx.memo`); a same-file
@@ -879,7 +896,7 @@ position and calls through a bare identifier. A body that references one of
879
896
  its module's own module-level resources declines (L7.6), that resource is a
880
897
  singleton the run path shares, and interpretation would not, and
881
898
  `constResolvesToResource` follows alias chains so it cannot be smuggled in
882
- (L7.7). The defining module is never imported; members are built by the
899
+ (`L7.7`). The defining module is never imported; members are built by the
883
900
  lexicon's constructors from the folded props.
884
901
 
885
902
  **F-Eval-CallEager, F-Eval-CallMethod** *(was R7.3. Evaluate eagerly)*
package/spec/rules.md CHANGED
@@ -96,7 +96,10 @@ refuses to load one into its own process while the sandbox is armed and
96
96
  runs it in the child instead (chant#1131), which is the isolation mode's
97
97
  boundary drawn once more around rules.
98
98
 
99
- **Fixtures.** No `F-Rule-*` rule has a fixture yet: the harness has no hook
100
- that runs a rule and no fixture kind whose expectation is a finding. That
101
- work is #101; until it lands the family is listed in `fixtures/UNCOVERED.md`
102
- with that reason.
99
+ The fixtures for this family carry the finding as data and not the rule,
100
+ since a rule is host code (#101): the `shapes` host names two rules by id and
101
+ phase, a fixture's `findings` says what they report, and an implementation
102
+ that carries no rule of that id says so and is skipped visibly. The runner
103
+ asks for each phase twice and holds the two runs to the same answer, which
104
+ is F-Rule-Pure tested before anything else, and `compareAdapters` holds two
105
+ implementations to the same findings, which is F-Rule-Equivalence.
package/spec/values.md CHANGED
@@ -132,6 +132,32 @@ arguments (`foldIntrinsicValue`). Anywhere else an unresolved chain is a
132
132
  located rejection (F-Reference, J2). A `__symbol` therefore never appears at
133
133
  the top of a folded tree.
134
134
 
135
+ ## F-Val-Source (every value has a source form)
136
+
137
+ For every value `v` of F-Val-Domain there is source in the subset
138
+ (grammar.md) whose fold, in the profile named, is `v`. The table names one
139
+ such form per case, which is the form a generator should prefer and not the
140
+ only one the subset admits; the rule was added in `1.5` (#80).
141
+
142
+ | Case | A source form that folds to it | In |
143
+ |---|---|---|
144
+ | scalar | the literal: `"s"`, `1.5`, `true`, `null`, `undefined` (F-Eval-Literal, F-Eval-Undefined) | both |
145
+ | array, object | the literal, with each member's source form as its element or value; a key that is not an identifier is a string key (S-Prop) | both |
146
+ | attribute reference `{__attrRef: {entity, attribute}}` | `entity.attribute`, where `entity` is a same-file `const` bound to a `new` (F-Eval-Member step 1, F-Prebuild) | both |
147
+ | intrinsic, tag form `{__intrinsic, strings, values}` | the tagged template `name\`s₀${v₀}s₁…\`` for a registered tag (F-Eval-Tagged) | both |
148
+ | intrinsic, call form `{__intrinsic, args}` | `name(args…)` for an intrinsic registered with `foldsAsCall` (F-Eval-CallIntrinsic) | both |
149
+ | helper call `{__helper, args}` | `name(args…)` for a registered helper (F-Eval-CallHelper). J1 yields the envelope and revival invokes the helper, so the envelope is never the output | `full` |
150
+ | resource `{__resource, props, attributes?, args?}` | `new C(props)`, `new C(props, attributes)`, or `new C(…args)` when `args` is present (F-Eval-New, F-Val-Arity) | both |
151
+ | composite step `{__compositeStep, args}` | the interpretable factory form (F-Host-Composite) | `full` |
152
+ | symbol `{__symbol}` | the unresolved chain, written inside an intrinsic's interior (F-Eval-Interior, F-Val-Symbol-Scope) | both |
153
+
154
+ Nothing else is a value, so nothing else needs a form, and the fold of a
155
+ form in `full` is the value after F-Val-Fate, so a resource's form folds to a
156
+ live instance there and to the envelope in `data-host`; the round trip
157
+ (README.md, "the generator obligation") is stated per profile for that
158
+ reason. A live instance has no source form of its own: its form is the
159
+ envelope's.
160
+
135
161
  ---
136
162
 
137
163
  ## Rationale
@@ -144,8 +170,9 @@ The spec must define what a fold produces. Every other requirement quantifies
144
170
  over it, and it is currently defined only by a TypeScript union
145
171
  (`FoldedValue`, `fold.ts:116`; L4.1).
146
172
 
147
- Nine cases. Six are ordinary JSON, string, number, boolean, null, undefined,
148
- arrays and plain objects. The rest carry envelopes:
173
+ There are nine cases, and six of them are ordinary JSON, the scalars with
174
+ `undefined` beside them, plus arrays and plain objects. The rest carry
175
+ envelopes:
149
176
 
150
177
  | Case | Envelope key | Denotes | Fate (R1.2) |
151
178
  |---|---|---|---|
@@ -157,6 +184,24 @@ arrays and plain objects. The rest carry envelopes:
157
184
  | `FoldedCompositeStepCall` | `__compositeStep` | `<Identifier>(...).step`, member fixed | revived |
158
185
  | `SymbolicValue` | `__symbol` | source text preserved inside an intrinsic interior | revived |
159
186
 
187
+ **F-Val-Source.** The round trip, `fold(generate(v)) = v`, is what makes
188
+ the choice of language a matter of correctness. A generator decides what
189
+ each value is: this string is a literal and that one is a reference to
190
+ another resource's attribute, while a repetition across forty resources is
191
+ one `const`. Each decision needs a form the subset can express and the fold
192
+ reverses, and the rule is the completeness half of that property, written
193
+ as a table rather than a sentence so that a generator author can read off a
194
+ form per case. The two open questions on #80 are settled here as follows.
195
+ The table names one form per case and requires only that one exists, so
196
+ generators stay comparable without being constrained to agree; and the
197
+ property is stated per profile, because in `full` the fold of a resource's
198
+ form is a live instance and not the envelope. chant's three generators, `chant import` from a template,
199
+ `--from` live import and carve-out from Terraform, emit through one
200
+ pipeline (`L12.1`) whose forms are the table's; its Kubernetes round-trip
201
+ suite compares resource count and kinds after re-serialization and not
202
+ bytes (`L12.4`), so the byte-level measurement the paper wants is still to be
203
+ taken.
204
+
160
205
  **F-Val-Envelope** *(was R1.1. Symbolic is not unevaluated)*
161
206
 
162
207
  An `__attrRef` is not a thunk. It is the envelope `AttrRef.prototype.toJSON()`
package/src/adapter.ts CHANGED
@@ -22,8 +22,42 @@ export interface ProjectResult {
22
22
  tentative?: Record<string, "fold" | "run">;
23
23
  /** For a file J3 tainted, the file whose taint reached it. */
24
24
  taintedBy?: Record<string, string>;
25
+ /** F-Obs-Counters, per build. Omitted by an implementation whose public entry exposes none. */
26
+ counters?: ExecutionCounters;
25
27
  }
26
28
 
29
+ /**
30
+ * F-Obs-Counters: in-process factory or constructor invocations while folding;
31
+ * of those, how many resolved to project-owned code; and how many factory
32
+ * bodies were interpreted instead. Three non-negative integers; the names
33
+ * follow the reference and only the shape is normative.
34
+ */
35
+ export interface ExecutionCounters { factoryInvocations: number; projectFactoryInvocations: number; factoryInterpretations: number }
36
+
37
+ /** F-Rule-Finding's closed severity set. */
38
+ export type Severity = "error" | "warning" | "info";
39
+ /** F-Rule-Phase: named by the input the rule reads, the folded namespace or the artifact. */
40
+ export type RulePhase = "pre" | "post";
41
+ /**
42
+ * A finding, as data (F-Rule-Finding). `rule`, `severity` and `subject` are
43
+ * compared; `message` is not (F-Obs-Messages); `at` only when the fixture
44
+ * gives one and the implementation reports one (F-Obs-Provenance is
45
+ * optional). `file` names the file whose namespace holds the subject for a
46
+ * pre-synthesis finding; a post-synthesis finding concerns the artifact and
47
+ * carries none.
48
+ */
49
+ export interface Finding {
50
+ rule: string;
51
+ severity: Severity;
52
+ subject: string;
53
+ message: string;
54
+ file?: string;
55
+ at?: { line: number; column: number };
56
+ }
57
+
58
+ /** J2's ι (F-IsolatedRefusal): under `isolated`, no project code is invoked or imported on the fold path. */
59
+ export type IsolationMode = "open" | "isolated";
60
+
27
61
  export interface ConformanceAdapter {
28
62
  readonly name: string;
29
63
  /**
@@ -48,5 +82,24 @@ export interface ConformanceAdapter {
48
82
  foldProject?(
49
83
  files: Map<string, string>,
50
84
  host?: ConformanceHost,
85
+ mode?: IsolationMode,
51
86
  ): ProjectResult | "unavailable" | Promise<ProjectResult | "unavailable">;
87
+ /**
88
+ * The findings of the host's rules of one phase over the build (#101).
89
+ * A rule is host code, so the harness carries only its identifier and its
90
+ * findings; an implementation that cannot run a rule the host names
91
+ * reports "unavailable" and the fixture is skipped visibly.
92
+ */
93
+ rules?(
94
+ files: Map<string, string>,
95
+ host: ConformanceHost,
96
+ phase: RulePhase,
97
+ ): Finding[] | "unavailable" | Promise<Finding[] | "unavailable">;
98
+ /**
99
+ * The round trip's generator (#80): source in the subset, as one module,
100
+ * whose fold is `namespace` (export name to value, envelopes included).
101
+ * "unavailable" for an implementation with no generator, or for a value it
102
+ * has no form for; F-Val-Source says a form exists for every value.
103
+ */
104
+ generate?(namespace: Record<string, unknown>, host?: ConformanceHost): string | "unavailable";
52
105
  }