@particle-academy/fancy-conformance 0.27.0 → 0.29.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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.27.0
1
+ 0.29.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/fancy-conformance",
3
- "version": "0.27.0",
3
+ "version": "0.29.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",
@@ -238,7 +238,8 @@
238
238
  "config": {
239
239
  "level": "info",
240
240
  "message": "regular {{ $json.name }}"
241
- }
241
+ },
242
+ "outputs": []
242
243
  },
243
244
  {
244
245
  "id": "o",
@@ -293,13 +294,10 @@
293
294
  "lg": {
294
295
  "logged": "regular Bo",
295
296
  "level": "info"
296
- },
297
- "o": {
298
- "logged": "regular Bo",
299
- "level": "info"
300
297
  }
301
298
  }
302
- }
299
+ },
300
+ "notes": "THE GOLDEN CHANGED IN 0.28.0 AND THE DOCUMENT CHANGED IN 0.29.0 — read both, because the second change is what makes the row answerable at all. `lg` is a `log` node and edge e3 leaves it for `o`. Every runtime used to refuse an empty output declaration and publish `out` instead, so the chain ran straight through a node that publishes nothing, and `o` ran. Under the owner's strict-but-loud ruling the declaration is honoured: `lg` terminates, `o` never runs, and the run raises the undelivered-edge warning naming e3 rather than truncating in silence. 0.29.0 adds an explicit `\"outputs\": []` TO THE `lg` NODE, and that is not cosmetic. Without it the row asked whether the runner holds a kind CATALOGUE — `log`'s empty list lives on the kind — and this suite's contract deliberately leaves that to the runtime: PHP's runner always has one and Rust's graph-runs harness deliberately has none, so the identical document gave two answers for a reason that had nothing to do with the rule under test. Declaring the ports on the NODE removes the ambiguity instead of picking a side: every runtime reads them from the document. The kind-level half of the same rule is pinned by each runtime's own suite, where the catalogue is not in question."
303
301
  },
304
302
  {
305
303
  "id": "0004-switch-case",
@@ -160,10 +160,7 @@
160
160
  "result": { "ok": true }
161
161
  },
162
162
  "expected": [],
163
- "skip": {
164
- "node": "DIVERGENCE, not an exemption: @particle-academy/fancy-flow collapses an explicitly-empty outputs to ['out'] because its fallback tests `declared?.length` and [] is falsy, so the three states (undeclared / explicitly none / declared) become two. Measured on 0.74.1. PHP, Python and Rust all publish nothing. Tracked as an issue on fancy-flow; this row starts passing there the day it is fixed."
165
- },
166
- "notes": "THREE STATES, NOT TWO. `null` falls back to `out` (row 0302); `[]` means a terminal node that genuinely publishes nothing. Collapsing them is how a terminal node starts publishing — and downstream of that, an edge nobody drew starts delivering. Kept as a skipped row rather than deleted so every runner prints the disagreement: a table that omits the one case its implementations disagree on is a table that agrees by saying less."
163
+ "notes": "THREE STATES, NOT TWO. `null` falls back to `out` (row 0302); `[]` means a node that genuinely publishes nothing. Collapsing them is how a terminal node starts publishing — and downstream of that, an edge nobody drew starts delivering. THIS ROW WAS SKIPPED FOR NODE IN 0.27.0 and is unskipped in 0.28.0: it recorded a real divergence (that engine collapsed `[]` to `out` while PHP, Python and Rust published nothing), the owner ruled strict-but-loud, and all four now agree. The skip was the right way to carry a disagreement — visible in every runner's summary — and removing it is what settling the disagreement looks like."
167
164
  }
168
165
  ]
169
166
  }
@@ -24,7 +24,9 @@
24
24
  "PER-PORT PAYLOADS ARE READ BY KEY PRESENCE, NEVER BY TRUTHINESS (rows 0103, 0202). A payload that is present and null is a payload. `values[port] ?? value` and `$ports[$port] ?? $result` cannot tell 'no key' from 'null', and all four runtimes shipped exactly that confusion in `branch` — every downstream node received the `{branch, value}` WRAPPER, two fields no kind declares, while the fields it does declare were absent. No parity table caught it because the four agreed on being wrong; these rows exist so the next one cannot hide the same way.",
25
25
  "AN EMPTY `__ports` LIGHTS NOTHING, DELIBERATELY (row 0104). It is the honest answer for a router that matched no rule, and it is the same answer an explicitly empty `outputs` gives in three of the four runtimes. Lighting every port instead would wake every lane precisely when the node decided none applied.",
26
26
  "A MALFORMED `__ports` FALLS THROUGH to the every-declared-port rule rather than lighting nothing (row 0106). `__ports` that is a string, a number or null is not a subset instruction, and treating an unreadable one as 'no ports' would turn a typo into a silently truncated run — the failure mode this whole table is written against.",
27
- "ROW 0303 IS THE DIVERGENCE, AND IT IS RECORDED RATHER THAN REMOVED. `declaredOutputs: []` means 'this node explicitly has no output ports'. PHP, Python and Rust honour it and publish nothing; `@particle-academy/fancy-flow` collapses it to `[\"out\"]`, because its fallback tests `declared?.length` and an empty array is falsy so the three-state distinction (undeclared / explicitly none / declared) becomes two-state there. Measured on fancy-flow 0.74.1, not inferred. It is skipped for node with that reason so every runner PRINTS it, which is the only way a known disagreement stays visible; deleting the row would make the table agree by saying less. Tracked as an issue on fancy-flow.",
27
+ "ROW 0303 WAS THE DIVERGENCE, AND IT IS NOW SETTLED. `declaredOutputs: []` means 'this node explicitly has no output ports'. PHP, Python and Rust honoured it and published nothing; `@particle-academy/fancy-flow` collapsed it to `[\"out\"]` because its fallback tested `declared?.length` and an empty array is falsy, so the three states became two. Measured on fancy-flow 0.74.1, carried as a `skip` for node in 0.27.0 so every runner printed the disagreement, and resolved in 0.28.0 by the owner's ruling: STRICT, BUT A TERMINAL NODE MUST BE LOUD. All four now publish nothing, and the skip is gone. Carrying a disagreement as a visible skip, then removing it when it is decided, is what this mechanism is for.",
28
+ "THE SAME RULE APPLIES TO A PORT SET INHERITED FROM THE KIND, and it is pinned by `flow/graph-runs` row 0003 rather than here, because it needs a registered kind and these rows deliberately name one no runtime ships. Every runtime used to REFUSE an empty declaration coming from a kind — a terminal `log` / `output` kind declares one — and published `out` instead, on the stated grounds that honouring it would silently cut every chain through such a node. That reasoning held only while the cut was silent. It no longer is, so the refusal is gone in all four and 0003's golden changed with it: a `log` node now terminates, and the node after it does not run.",
29
+ "STRICT IS ONLY HALF THE RULING; THE OTHER HALF IS NOT OPTIONAL. An edge leaving a node that published nothing must raise the undelivered-edge warning (`flow/run-diagnostics`). Both gates that shape a port set have to honour the empty declaration — the one that decides what a node PUBLISHES, and the one behind the warning that decides what is DELIVERABLE. A runtime that fixes only the first truncates chains while its own diagnostic still reports the edge as fine, which is strictly worse than the lenient behaviour it replaced.",
28
30
  "Nothing here asserts that a lit port must be a DECLARED one. All four runtimes publish whatever `__port` / `__ports` / `branch` names, declared or not, and an edge from a port that does not exist simply matches nothing. That is deliberate slack for hosts whose ports are config-driven, and pinning it either way belongs in its own row once someone decides it — not smuggled in through a row about something else."
29
31
  ]
30
32
  }