@particle-academy/fancy-conformance 0.22.1 → 0.23.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 +2 -0
- package/VERSION +1 -1
- package/package.json +1 -1
- package/suites/shared/expr/cases.json +69 -0
- package/suites/shared/expr/manifest.json +6 -2
package/README.md
CHANGED
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.23.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@particle-academy/fancy-conformance",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Shared cross-language conformance fixtures for the Fancy suite. One contract, N implementations, and a single table that every implementation asserts in its own CI — so 'parity' is a test result rather than a claim. Ships the fixture data itself, so a Rust, Go or Python runner can consume it without a JavaScript toolchain.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -181,6 +181,75 @@
|
|
|
181
181
|
"fn": "truthy",
|
|
182
182
|
"input": { "value": "no thanks" },
|
|
183
183
|
"expected": true
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"id": "0021-several-references-interpolate-each",
|
|
187
|
+
"title": "A template that starts with `{{` and ends with `}}` but holds two references interpolates both",
|
|
188
|
+
"since": "0.23.0",
|
|
189
|
+
"tags": ["evaluate", "regression"],
|
|
190
|
+
"fn": "evaluateExpression",
|
|
191
|
+
"input": {
|
|
192
|
+
"template": "{{ in.text }} --- {{ user.transcript }}",
|
|
193
|
+
"context": { "in": { "text": "SUMMARY" }, "user": { "transcript": "TRANSCRIPT" } }
|
|
194
|
+
},
|
|
195
|
+
"expected": "SUMMARY --- TRANSCRIPT",
|
|
196
|
+
"notes": "fancy-flow-php#16. Every runtime used to read this as ONE whole expression whose path was `in.text }} --- {{ user.transcript`, because the whole-string test only asked whether the trimmed template starts with `{{` and ends with `}}`. That path never resolves, so the template returned null and a document node wrote nothing, with both references individually valid. It was documented as a deliberate corner in all four runtimes, so no row here could see it. Golden from fancy-flow-php 0.52.2; 0.52.1 returns null."
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"id": "0022-several-references-across-newlines",
|
|
200
|
+
"title": "A multi-line template with a reference on its first and last line interpolates, trailing newline kept",
|
|
201
|
+
"since": "0.23.0",
|
|
202
|
+
"tags": ["evaluate", "regression"],
|
|
203
|
+
"fn": "evaluateExpression",
|
|
204
|
+
"input": {
|
|
205
|
+
"template": "{{ in.text }}\n\n---\n\n## Original\n\n{{ user.transcript }}\n",
|
|
206
|
+
"context": { "in": { "text": "SUMMARY" }, "user": { "transcript": "TRANSCRIPT" } }
|
|
207
|
+
},
|
|
208
|
+
"expected": "SUMMARY\n\n---\n\n## Original\n\nTRANSCRIPT\n",
|
|
209
|
+
"notes": "The production shape from #16: a prompt or document template whose first and last lines are references. Two things are pinned. The whole-string test runs on the TRIMMED template, so a trailing newline does not protect it from the old corner; and the interpolation runs on the UNTRIMMED template, so the newline survives. A port that interpolated the trimmed string would drop it."
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"id": "0023-adjacent-references-are-two-references",
|
|
213
|
+
"title": "`{{ a }}{{ b }}` is two references, interpolated as text",
|
|
214
|
+
"since": "0.23.0",
|
|
215
|
+
"tags": ["evaluate", "regression", "stringify"],
|
|
216
|
+
"fn": "evaluateExpression",
|
|
217
|
+
"input": { "template": "{{ a }}{{ b }}", "context": { "a": 1, "b": 2 } },
|
|
218
|
+
"expected": "12",
|
|
219
|
+
"notes": "The corner the runtimes' own docs used to name as deliberate: one path, `a }}{{ b`, that resolved to null. The golden is the STRING \"12\" — two numbers interpolated as text, not added and not typed."
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"id": "0024-padded-single-expression-keeps-type",
|
|
223
|
+
"title": "Exactly one expression, with surrounding whitespace, still returns the typed value",
|
|
224
|
+
"since": "0.23.0",
|
|
225
|
+
"tags": ["evaluate", "types"],
|
|
226
|
+
"fn": "evaluateExpression",
|
|
227
|
+
"input": { "template": " {{ a }} ", "context": { "a": 1, "b": 2 } },
|
|
228
|
+
"expected": 1,
|
|
229
|
+
"notes": "The other side of 0021-0023. The fix narrows the whole-string branch; it must not remove it. A port that 'fixed' #16 by always interpolating passes 0021-0023 and fails this row and 0001."
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"id": "0025-one-unresolved-reference-of-several-interpolates-empty",
|
|
233
|
+
"title": "When one of several references does not resolve, the others still interpolate",
|
|
234
|
+
"since": "0.23.0",
|
|
235
|
+
"tags": ["evaluate", "regression"],
|
|
236
|
+
"fn": "evaluateExpression",
|
|
237
|
+
"input": {
|
|
238
|
+
"template": "{{ in.text }} / {{ in.nope }}",
|
|
239
|
+
"context": { "in": { "text": "SUMMARY" } }
|
|
240
|
+
},
|
|
241
|
+
"expected": "SUMMARY / ",
|
|
242
|
+
"notes": "The unresolved-path policy applies PER REFERENCE, not to the template. This table models only the default policy (an unresolved reference interpolates to empty); the contract takes no policy argument and fancy-flow-rs has none. Under Keep the golden is \"SUMMARY / {{ in.nope }}\" and under Throw evaluation throws; those are pinned in each runtime's own suite (fancy-flow-php TemplateWithSeveralReferencesTest and its TypeScript and Python ports). Before #16 this returned null."
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"id": "0026-an-inner-opening-brace-is-not-one-expression",
|
|
246
|
+
"title": "A template whose inner text holds `{{` is not a single expression either",
|
|
247
|
+
"since": "0.23.0",
|
|
248
|
+
"tags": ["evaluate", "regression"],
|
|
249
|
+
"fn": "evaluateExpression",
|
|
250
|
+
"input": { "template": "{{ a {{ b }}", "context": { "a": 1, "b": 2 } },
|
|
251
|
+
"expected": "",
|
|
252
|
+
"notes": "The rule has TWO conditions: the inner text may contain neither `}}` nor `{{`. 0021-0023 all contain `}}`, so a port that checked only that half would pass them and still read this template as one path. It fails here instead: the whole-string branch returns null, and the golden is the empty STRING. The template is malformed, and the value is simply what the scan does with it (the first `{{` pairs with the first `}}`, giving the path `a {{ b`, which does not resolve). This row pins the rule, not that reading."
|
|
184
253
|
}
|
|
185
254
|
]
|
|
186
255
|
}
|
|
@@ -10,13 +10,17 @@
|
|
|
10
10
|
"summary": "Resolve a dot-path template against an executor's inputs, and decide branch truthiness. Deliberately NOT a general expression language: dot-paths only, no arithmetic, comparisons or calls.",
|
|
11
11
|
"implementations": [
|
|
12
12
|
{ "language": "php", "package": "particle-academy/fancy-flow-php", "symbol": "FancyFlow\\Nodes\\Support\\Expr" },
|
|
13
|
-
{ "language": "node", "package": "@particle-academy/fancy-flow", "symbol": "evaluateExpression / truthy" }
|
|
13
|
+
{ "language": "node", "package": "@particle-academy/fancy-flow", "symbol": "evaluateExpression / truthy" },
|
|
14
|
+
{ "language": "python", "package": "fancy-flow", "symbol": "fancy_flow.nodes.support.expr.evaluate / truthy" },
|
|
15
|
+
{ "language": "rust", "package": "fancy-flow", "symbol": "fancy_flow::nodes::support::expr::evaluate / truthy" }
|
|
14
16
|
]
|
|
15
17
|
},
|
|
16
18
|
"notes": [
|
|
17
19
|
"This suite exists because of what conformance could NOT catch. `Expr` shipped in PHP with no TypeScript twin at all, and a fixture table compares two implementations — it is structurally unable to report a MISSING one. The gap surfaced only when someone asked for editor autocomplete over a grammar and the grammar turned out to live on one side.",
|
|
18
20
|
"`truthy` is where the two languages disagree by default, so those rows carry the weight. `\"0\"`, `\"false\"` and `[]` are all truthy in JavaScript and falsy here; a branch node reading a form value or a JSON body hits every one of them. An implementation that forwards to native truthiness fails cases 0013-0015 and nothing else, which is exactly the signal wanted.",
|
|
19
21
|
"Case 0008 pins that a missing path interpolates to an empty string rather than the text \"null\" — the difference between a quietly-blank message and one that ships the word null to a customer.",
|
|
20
|
-
"fancy-flow's own `runFlow` does not call this. The PHP runtime resolves expressions inside its executors; the JS runtime hands config to the host's executor verbatim, and every host that uses `{{ }}` today already resolves it itself. Turning it on inside `runFlow` would interpolate a second time over values those hosts had already substituted. The TS side is therefore an opt-in export, and this suite pins its SEMANTICS, not where it is called from."
|
|
22
|
+
"fancy-flow's own `runFlow` does not call this. The PHP runtime resolves expressions inside its executors; the JS runtime hands config to the host's executor verbatim, and every host that uses `{{ }}` today already resolves it itself. Turning it on inside `runFlow` would interpolate a second time over values those hosts had already substituted. The TS side is therefore an opt-in export, and this suite pins its SEMANTICS, not where it is called from.",
|
|
23
|
+
"A WHOLE-STRING EXPRESSION IS EXACTLY ONE `{{ }}` (0021-0026, since 0.23.0). Until fancy-flow-php 0.52.2 every runtime asked only whether the trimmed template starts with `{{` and ends with `}}`, so `{{ in.text }} --- {{ user.transcript }}` became one path that never resolves and the template returned null (fancy-flow-php#16, hit in production). All four runtimes documented it as a deliberate corner and reproduced it faithfully, and a table compares runtimes with each other: agreement on a bug reads as parity. The rule now is that the inner text may contain neither `}}` nor `{{`; anything else interpolates each reference. A runtime still carrying the corner fails 0021, 0022, 0023, 0025 and 0026 and nothing else; one that checks only `}}` fails 0026 alone; one that drops the typed branch altogether fails 0001, 0007 and 0024. `tests/discrimination-shared-expr.test.ts` asserts those exact sets.",
|
|
24
|
+
"THIS TABLE MODELS ONLY THE DEFAULT UNRESOLVED-PATH POLICY. The contract takes no policy argument, and fancy-flow-rs has no policy at all. PHP, TypeScript and Python also offer Keep (the `{{ }}` text stays) and Throw; each pins those in its own suite, including for 0025's partly unresolved template."
|
|
21
25
|
]
|
|
22
26
|
}
|