@particle-academy/fancy-conformance 0.21.0 → 0.21.1

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.21.0
1
+ 0.21.1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/fancy-conformance",
3
- "version": "0.21.0",
3
+ "version": "0.21.1",
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 \u2014 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",
@@ -60,8 +60,16 @@
60
60
  },
61
61
  "initialInputs": {},
62
62
  "runIdentity": {
63
- "derivation": "\"lab\" + sha256(canonical json of input.schema)[0:8]",
64
- "note": "Supplied, not optional. The connector derives its idempotency key from this, and some connectors refuse to write without one — a runner that omits it exercises a different path."
63
+ "derivation": "\"lab\" + sha256(canonicalJson(input.schema))[0:8]",
64
+ "canonicalJson": [
65
+ "Object keys sorted lexicographically by UTF-16 code unit, at every depth. Array order is preserved.",
66
+ "No insignificant whitespace: separators are exactly `,` and `:`.",
67
+ "UTF-8 output. Escape only what JSON requires — PHP must pass JSON_UNESCAPED_SLASHES and JSON_UNESCAPED_UNICODE, because its default escapes `/` and every non-ASCII character and neither matches the other three runtimes.",
68
+ "Numbers as written in this file. No reformatting of integers to floats or vice versa."
69
+ ],
70
+ "note": "Supplied, not optional. The connector derives its idempotency key from this, and some connectors refuse to write without one — a runner that omits it exercises a different path.",
71
+ "why-spelled-out": "The word `canonical` alone is not a specification, and leaving it at that is worse than either concrete choice: every runtime believes its own encoder is canonical, and PHP's `json_encode` escapes slashes and unicode by default while Node's does neither. Two runners would then derive different identities from the same graph, send different idempotency keys, and — because the faker seeds from the key — produce different ids, failing a determinism check for a reason that has nothing to do with the connector.",
72
+ "pending": "The resulting key is NOT yet pinned as a literal here. It should be: for a fixed fixture graph the identity is a constant, and a constant cannot be disagreed about the way a derivation can. Awaiting the value from the first runner to implement this canonical form, after which the literal becomes authoritative and the derivation stays as provenance."
65
73
  }
66
74
  },
67
75
  "expected": {
@@ -37,7 +37,7 @@
37
37
 
38
38
  "IMPORT IS STRICT HERE, and graph-runs is lenient. That difference is deliberate and worth stating rather than inheriting: a document one engine accepts and another refuses is not one document. It is also live — `fancy-flow-php`'s `FancyFlowManager::toGraph()` forces `lenient: true` on every `run()` caller while the TypeScript and Python twins default strict, so the same versionless graph runs in Laravel and is refused by the editor meant to edit it. Ungating the version check is queued on the PHP side; until it lands, a PHP runner for this suite must call the strict import path explicitly rather than going through `run()`.",
39
39
 
40
- "A RUN IDENTITY MUST BE SUPPLIED. The connector derives an idempotency key from it, and some connectors refuse to write without one — so a runner that omits it is not exercising the same code path. Derive it from the graph so every runner sends the same key; the reference derivation is `\"lab\" + sha256(canonical json)[0:8]`. That was originally kept short to dodge a defect in `fancy-connector-core` — `Idempotency::fit()` clamped only at the 255-character catalogue ceiling and never at the provider's own declared `idempotencyMaxLength`, so Discord (25) refused a legitimate 29-character key. Fixed in fancy-connector-core 0.4.0; the short derivation is kept here because a stable short key is good practice, not because it is still required.",
40
+ "A RUN IDENTITY MUST BE SUPPLIED. The connector derives an idempotency key from it, and some connectors refuse to write without one — so a runner that omits it is not exercising the same code path. Derive it from the graph so every runner sends the same key; the reference derivation is `\"lab\" + sha256(canonicalJson(input.schema))[0:8]`, and `canonicalJson` is DEFINED on the case under `input.runIdentity.canonicalJson` — sorted keys, no whitespace, unescaped slashes and unicode. Not defined here as well, so there is one definition rather than two that can drift. That was originally kept short to dodge a defect in `fancy-connector-core` — `Idempotency::fit()` clamped only at the 255-character catalogue ceiling and never at the provider's own declared `idempotencyMaxLength`, so Discord (25) refused a legitimate 29-character key. Fixed in fancy-connector-core 0.4.0; the short derivation is kept here because a stable short key is good practice, not because it is still required.",
41
41
 
42
42
  "THIS SUITE ASSERTS NAMED PATHS, NOT THE WHOLE OUTPUTS OBJECT, and that is weaker than graph-runs in one specific way: an extra key a runtime publishes at `out` will not fail a case. It is done this way because `out.data.id` is drawn from the faker's seeded sequence and cannot be authored, so a whole-object equality would have to pin a value nobody wrote down. Read the green tick as \"every named field agrees\", not \"the outputs are identical\". The softer whole-object claim is recorded in the case's own notes where it has been measured.",
43
43