stylegallery 0.1.0 → 0.1.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.
Files changed (230) hide show
  1. package/AGENTS.md +4 -1
  2. package/DOMAINS.md +2 -6
  3. package/GOVERNANCE.md +10 -9
  4. package/README.md +23 -127
  5. package/consumer-reference/agent-native/v2/admission-policy.json +646 -0
  6. package/consumer-reference/agent-native/v2/material-registry.json +1 -0
  7. package/consumer-reference/agent-native/v2/schema/admission-policy.schema.json +50 -0
  8. package/consumer-reference/agent-native/v2/schema/material-manifest.schema.json +17 -0
  9. package/consumer-reference/agent-native/v2/schema/material-record.schema.json +20 -0
  10. package/consumer-reference/contract.md +1 -1
  11. package/consumer-reference/index.md +5 -3
  12. package/layout/index.md +124 -0
  13. package/log.md +51 -0
  14. package/package.json +181 -22
  15. package/scripts/agent-native/v2/experimental-extension-registry.mjs +143 -0
  16. package/scripts/agent-native/v2/extensions/a2a-projection.mjs +264 -0
  17. package/scripts/agent-native/v2/extensions/agui-projection.mjs +191 -0
  18. package/scripts/agent-native/v2/material-admission.mjs +295 -0
  19. package/scripts/agent-native/v2/material-cli-adapter.mjs +134 -0
  20. package/scripts/agent-native/v2/material-context.mjs +251 -0
  21. package/scripts/agent-native/v2/material-identity.mjs +71 -0
  22. package/scripts/agent-native/v2/material-mcp-adapter.mjs +253 -0
  23. package/scripts/agent-native/v2/material-operation-registry.mjs +123 -0
  24. package/scripts/agent-native/v2/material-queries.mjs +398 -0
  25. package/scripts/agent-native/v2/material-registry.mjs +319 -0
  26. package/scripts/sg-material-mcp.mjs +98 -0
  27. package/scripts/sg-material.mjs +27 -0
  28. package/consumer-reference/adapters/style-dictionary.config.mjs +0 -36
  29. package/consumer-reference/baselines/calibration.json +0 -260
  30. package/consumer-reference/baselines/manifest.json +0 -21
  31. package/consumer-reference/fixtures/consumer-conformance/e2e-fixture.mjs +0 -282
  32. package/consumer-reference/fixtures/consumer-conformance/manifest.json +0 -102
  33. package/consumer-reference/fixtures/consumer-conformance/runtime-proof.mjs +0 -32
  34. package/consumer-reference/fixtures/consumer-conformance/valid-migration-result.json +0 -18
  35. package/consumer-reference/fixtures/consumer-conformance/valid-migration.json +0 -142
  36. package/consumer-reference/fixtures/invalid-stable-ended-support.json +0 -19
  37. package/consumer-reference/fixtures/promotion/invalid-blocking-evidence.json +0 -26
  38. package/consumer-reference/fixtures/promotion/invalid-count-only.json +0 -29
  39. package/consumer-reference/fixtures/promotion/invalid-missing-owner-migration.json +0 -25
  40. package/consumer-reference/fixtures/promotion/invalid-normative-bypass-no-regression.json +0 -25
  41. package/consumer-reference/fixtures/promotion/invalid-related-counted-independent.json +0 -45
  42. package/consumer-reference/fixtures/promotion/invalid-stable-ended-support.json +0 -26
  43. package/consumer-reference/fixtures/promotion/manifest.json +0 -15
  44. package/consumer-reference/fixtures/promotion/valid-deferred-example.json +0 -67
  45. package/consumer-reference/fixtures/promotion/valid-normative-bypass.json +0 -67
  46. package/consumer-reference/fixtures/token-portability/invalid-cycle.json +0 -7
  47. package/consumer-reference/fixtures/token-portability/invalid-dangling-alias.json +0 -6
  48. package/consumer-reference/fixtures/token-portability/invalid-extends.json +0 -4
  49. package/consumer-reference/fixtures/token-portability/invalid-json-pointer.json +0 -7
  50. package/consumer-reference/fixtures/token-portability/invalid-resolver.json +0 -9
  51. package/consumer-reference/fixtures/token-portability/invalid-type-mismatch.json +0 -10
  52. package/consumer-reference/fixtures/token-portability/invalid-unknown-reserved.json +0 -6
  53. package/consumer-reference/fixtures/token-portability/invalid-untested-type.json +0 -6
  54. package/consumer-reference/fixtures/token-portability/valid-border.json +0 -14
  55. package/consumer-reference/fixtures/token-portability/valid-reference.json +0 -32
  56. package/consumer-reference/fixtures/token-portability/valid-whole-alias.json +0 -7
  57. package/consumer-reference/fixtures/valid-deprecated.json +0 -21
  58. package/consumer-reference/fixtures/valid-experimental.json +0 -19
  59. package/consumer-reference/generated/manifest.json +0 -40
  60. package/consumer-reference/generated/tokens.css +0 -12
  61. package/consumer-reference/policies/shared-experimental.json +0 -37
  62. package/consumer-reference/schema/ax-evidence.schema.json +0 -30
  63. package/consumer-reference/schema/baseline-manifest.schema.json +0 -55
  64. package/consumer-reference/schema/calibration-record.schema.json +0 -190
  65. package/consumer-reference/schema/capture-session.schema.json +0 -161
  66. package/consumer-reference/schema/component-state.schema.json +0 -150
  67. package/consumer-reference/schema/consumer-conformance-record.schema.json +0 -365
  68. package/consumer-reference/schema/dom-evidence.schema.json +0 -38
  69. package/consumer-reference/schema/evidence-record.schema.json +0 -81
  70. package/consumer-reference/schema/fixture-manifest.schema.json +0 -32
  71. package/consumer-reference/schema/item.schema.json +0 -188
  72. package/consumer-reference/schema/page-evidence-manifest.schema.json +0 -216
  73. package/consumer-reference/schema/page-evidence-session.schema.json +0 -119
  74. package/consumer-reference/schema/portable-tokens.schema.json +0 -104
  75. package/consumer-reference/schema/promotion-rfc.schema.json +0 -219
  76. package/consumer-reference/schema/runtime-evidence-manifest.schema.json +0 -33
  77. package/consumer-reference/schema/visual-evidence.schema.json +0 -31
  78. package/design-engineering/consumer-migration-readiness.md +0 -124
  79. package/design-engineering/interface-craft.md +0 -107
  80. package/design-engineering/reference-profiles/external-adaptation/index.md +0 -12
  81. package/design-engineering/reference-profiles/governed-local/editorial/components/button.component.json +0 -125
  82. package/design-engineering/reference-profiles/governed-local/editorial/evidence/button.evidence.json +0 -3504
  83. package/design-engineering/reference-profiles/governed-local/editorial/fixtures/button.fixture.json +0 -65
  84. package/design-engineering/reference-profiles/governed-local/editorial/generated/evidence-coverage.md +0 -23
  85. package/design-engineering/reference-profiles/governed-local/editorial/generated/keyboard-matrix.md +0 -19
  86. package/design-engineering/reference-profiles/governed-local/editorial/generated/state-matrix.md +0 -21
  87. package/design-engineering/reference-profiles/governed-local/editorial/local-foundations.json +0 -12
  88. package/design-engineering/reference-profiles/governed-local/editorial/states/button.states.json +0 -195
  89. package/design-engineering/reference-profiles/governed-local/editorial/tokens.dtcg.json +0 -17
  90. package/design-engineering/reference-profiles/governed-local/terminal/components/button.component.json +0 -125
  91. package/design-engineering/reference-profiles/governed-local/terminal/evidence/button.evidence.json +0 -3504
  92. package/design-engineering/reference-profiles/governed-local/terminal/fixtures/button.fixture.json +0 -65
  93. package/design-engineering/reference-profiles/governed-local/terminal/generated/evidence-coverage.md +0 -23
  94. package/design-engineering/reference-profiles/governed-local/terminal/generated/keyboard-matrix.md +0 -19
  95. package/design-engineering/reference-profiles/governed-local/terminal/generated/state-matrix.md +0 -21
  96. package/design-engineering/reference-profiles/governed-local/terminal/local-foundations.json +0 -12
  97. package/design-engineering/reference-profiles/governed-local/terminal/profile.json +0 -43
  98. package/design-engineering/reference-profiles/governed-local/terminal/states/button.states.json +0 -195
  99. package/design-engineering/reference-profiles/governed-local/terminal/tokens.dtcg.json +0 -17
  100. package/game-ui/classification.md +0 -82
  101. package/game-ui/reference-record.md +0 -62
  102. package/game-ui/screen-hierarchy.md +0 -107
  103. package/game-ui/unity/architecture.md +0 -166
  104. package/game-ui/unity/cli-loop.md +0 -84
  105. package/game-ui/unity/data/unity-technologies-public-repositories.json +0 -26654
  106. package/game-ui/unity/org-wiki.md +0 -146
  107. package/game-ui/unity/repository-map.md +0 -102
  108. package/game-ui/unity/ui-systems.md +0 -85
  109. package/motion/practice-reference.md +0 -145
  110. package/motion/review-workflow.md +0 -86
  111. package/motion/vocabulary.md +0 -82
  112. package/platform-guides/apple-interaction.md +0 -89
  113. package/scripts/agent-native/events.mjs +0 -113
  114. package/scripts/agent-native/immutable-store.mjs +0 -102
  115. package/scripts/artifact-metadata.mjs +0 -20
  116. package/scripts/audit-evidence-freshness.mjs +0 -308
  117. package/scripts/baseline-contract.mjs +0 -189
  118. package/scripts/baseline-schema-parity.mjs +0 -40
  119. package/scripts/build-reference-artifacts.mjs +0 -127
  120. package/scripts/calibration-raw-contract.mjs +0 -172
  121. package/scripts/capture-session-contract.mjs +0 -187
  122. package/scripts/component-state-artifact-fixture.mjs +0 -44
  123. package/scripts/component-state-contract.mjs +0 -99
  124. package/scripts/component-state-semantics.mjs +0 -128
  125. package/scripts/component-state-workflow-contract.mjs +0 -67
  126. package/scripts/component-state-workflow-negative-cases.mjs +0 -64
  127. package/scripts/consumer-conformance-contract.mjs +0 -198
  128. package/scripts/consumer-evidence-governance-contract.mjs +0 -210
  129. package/scripts/consumer-reference-case-runner.mjs +0 -93
  130. package/scripts/consumer-reference-schema.mjs +0 -155
  131. package/scripts/create-component-state-session.mjs +0 -100
  132. package/scripts/create-page-evidence-session.mjs +0 -139
  133. package/scripts/domain-document-boundaries.mjs +0 -40
  134. package/scripts/domain-validation-checks.mjs +0 -141
  135. package/scripts/evidence-artifact-contract.mjs +0 -191
  136. package/scripts/finalize-component-state-evidence.mjs +0 -165
  137. package/scripts/finalize-page-evidence.mjs +0 -197
  138. package/scripts/generate-consumer-reference-evidence.mjs +0 -154
  139. package/scripts/generate-patterns.mjs +0 -218
  140. package/scripts/governance-matrix-contract.mjs +0 -73
  141. package/scripts/governance-matrix-negative-cases.mjs +0 -114
  142. package/scripts/governance-policy-contract.mjs +0 -49
  143. package/scripts/governance-test-fixture.mjs +0 -321
  144. package/scripts/governance-workflow-negative-cases.mjs +0 -241
  145. package/scripts/governed-profile-registry.mjs +0 -125
  146. package/scripts/json-schema-formats.mjs +0 -31
  147. package/scripts/markdown-structure.mjs +0 -45
  148. package/scripts/page-artifact-metadata.mjs +0 -124
  149. package/scripts/page-evidence-contract.mjs +0 -297
  150. package/scripts/page-evidence-fixture.mjs +0 -271
  151. package/scripts/pattern-data.mjs +0 -325
  152. package/scripts/profile-record-contract.mjs +0 -140
  153. package/scripts/promotion-attestation-contract.mjs +0 -91
  154. package/scripts/promotion-boundary-test-contract.mjs +0 -92
  155. package/scripts/promotion-fixture-inventory.mjs +0 -109
  156. package/scripts/promotion-governance-contract.mjs +0 -28
  157. package/scripts/reference-artifact-path-contract.mjs +0 -28
  158. package/scripts/reference-profile-contract.mjs +0 -114
  159. package/scripts/reference-token-contract.mjs +0 -156
  160. package/scripts/run-consumer-page-evidence-ci.mjs +0 -170
  161. package/scripts/summarize-sentinel-calibration.mjs +0 -98
  162. package/scripts/test-agent-adapter-conformance.mjs +0 -250
  163. package/scripts/test-agent-conformance-receipt.mjs +0 -106
  164. package/scripts/test-agent-events.mjs +0 -81
  165. package/scripts/test-agent-execution-effects.mjs +0 -114
  166. package/scripts/test-agent-execution-fixtures.mjs +0 -140
  167. package/scripts/test-agent-execution-kernel.mjs +0 -39
  168. package/scripts/test-agent-execution-learning.mjs +0 -130
  169. package/scripts/test-agent-execution-lifecycle.mjs +0 -143
  170. package/scripts/test-agent-execution-safety.mjs +0 -158
  171. package/scripts/test-agent-execution-views.mjs +0 -117
  172. package/scripts/test-agent-identity-integrity-cases.mjs +0 -160
  173. package/scripts/test-agent-knowledge-kernel.mjs +0 -183
  174. package/scripts/test-agent-learning.mjs +0 -246
  175. package/scripts/test-agent-mcp.mjs +0 -246
  176. package/scripts/test-agent-native-schemas.mjs +0 -215
  177. package/scripts/test-agent-projections.mjs +0 -249
  178. package/scripts/test-agent-registry-mcp-integrity.mjs +0 -215
  179. package/scripts/test-agent-registry-mutations.mjs +0 -110
  180. package/scripts/test-audit-evidence-freshness.mjs +0 -177
  181. package/scripts/test-component-state-sentinel.mjs +0 -35
  182. package/scripts/test-component-state-source-contract.mjs +0 -83
  183. package/scripts/test-consumer-conformance-sentinel.mjs +0 -165
  184. package/scripts/test-consumer-reference-sentinel.mjs +0 -31
  185. package/scripts/test-generate-consumer-reference-evidence.mjs +0 -124
  186. package/scripts/test-json-cli-output.mjs +0 -151
  187. package/scripts/test-json-schema-formats.mjs +0 -40
  188. package/scripts/test-reference-adapters.mjs +0 -199
  189. package/scripts/test-renderer-purity.mjs +0 -34
  190. package/scripts/test-sg-cli.mjs +0 -129
  191. package/scripts/test-summarize-sentinel-calibration.mjs +0 -226
  192. package/scripts/test-validate-baseline-manifest.mjs +0 -234
  193. package/scripts/test-validate-component-state-artifacts.mjs +0 -243
  194. package/scripts/test-validate-component-state.mjs +0 -106
  195. package/scripts/test-validate-consumer-conformance.mjs +0 -427
  196. package/scripts/test-validate-consumer-reference-cli.mjs +0 -69
  197. package/scripts/test-validate-consumer-reference.mjs +0 -263
  198. package/scripts/test-validate-domains.mjs +0 -357
  199. package/scripts/test-validate-governance.mjs +0 -292
  200. package/scripts/test-validate-ia.mjs +0 -262
  201. package/scripts/test-validate-okf.mjs +0 -73
  202. package/scripts/test-validate-page-evidence.mjs +0 -302
  203. package/scripts/test-validate-patterns.mjs +0 -157
  204. package/scripts/test-validate-promotion-rfc.mjs +0 -250
  205. package/scripts/test-validate-reference-profiles.mjs +0 -170
  206. package/scripts/test-validate-unity-org-wiki.mjs +0 -57
  207. package/scripts/test-validate-unity-source-contracts.mjs +0 -67
  208. package/scripts/test-validate-vocabulary.mjs +0 -174
  209. package/scripts/test-validate-webpage-workflow.mjs +0 -293
  210. package/scripts/validate-baseline-manifest.mjs +0 -44
  211. package/scripts/validate-catalog.mjs +0 -65
  212. package/scripts/validate-component-state.mjs +0 -141
  213. package/scripts/validate-consumer-conformance.mjs +0 -477
  214. package/scripts/validate-consumer-reference.mjs +0 -288
  215. package/scripts/validate-domains.mjs +0 -237
  216. package/scripts/validate-governance.mjs +0 -248
  217. package/scripts/validate-ia.mjs +0 -136
  218. package/scripts/validate-links.mjs +0 -66
  219. package/scripts/validate-okf.mjs +0 -104
  220. package/scripts/validate-page-evidence.mjs +0 -191
  221. package/scripts/validate-patterns.mjs +0 -246
  222. package/scripts/validate-promotion-rfc.mjs +0 -224
  223. package/scripts/validate-reference-artifacts.mjs +0 -125
  224. package/scripts/validate-renderer-purity.mjs +0 -56
  225. package/scripts/validate-unity-org-wiki.mjs +0 -146
  226. package/scripts/validate-unity-source-contracts.mjs +0 -107
  227. package/scripts/validate-vocabulary.mjs +0 -115
  228. package/scripts/validate-webpage-workflow.mjs +0 -254
  229. package/scripts/visual-expectation-contract.mjs +0 -20
  230. package/scripts/workflow-action-contract.mjs +0 -163
@@ -1,427 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from "node:fs";
4
- import os from "node:os";
5
- import path from "node:path";
6
- import { execFileSync, spawnSync } from "node:child_process";
7
- import { fileURLToPath } from "node:url";
8
- import {
9
- endToEndCaseNames,
10
- runEndToEndCase,
11
- } from "../consumer-reference/fixtures/consumer-conformance/e2e-fixture.mjs";
12
- import { MIGRATION_DIMENSIONS, validateConsumerConformanceSemantics } from "./consumer-conformance-contract.mjs";
13
- import { canonicalSourceManifest } from "./page-evidence-contract.mjs";
14
- import { parseStrictJson } from "./strict-json.mjs";
15
-
16
- const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
17
- const fixtureRoot = path.join(repositoryRoot, "consumer-reference", "fixtures", "consumer-conformance");
18
- const validator = path.join(repositoryRoot, "scripts", "validate-consumer-conformance.mjs");
19
- const contractCases = Object.freeze([
20
- ["omitted-dimension", "migration_dimension_required"],
21
- ["applicable-without-scenario", "migration_dimension_scenario_required"],
22
- ["source-regex-runtime-proof", "runtime_evidence_method_invalid"],
23
- ["orphan-adoption-scenario", "adoption_scenario_unknown"],
24
- ["malformed-local-target", "adoption_consumer_target_invalid"],
25
- ["unpinned-stylegallery-revision", "adoption_stylegallery_revision_unpinned"],
26
- ["unknown-stylegallery-revision", "adoption_stylegallery_revision_unknown"],
27
- ["missing-stylegallery-path", "adoption_stylegallery_path_missing"],
28
- ["missing-stylegallery-anchor", "adoption_stylegallery_anchor_missing"],
29
- ["debt-without-lifecycle", "adoption_debt_incomplete"],
30
- ]);
31
- const runtimeCases = Object.freeze([
32
- ["missing-source", "consumer_source_missing"],
33
- ["symlink-source", "consumer_source_symlink"],
34
- ["checkout-symlink", "runtime_command_checkout_symlink"],
35
- ["missing-result-artifact", "runtime_result_artifact_missing"],
36
- ["symlink-result-artifact", "runtime_result_artifact_symlink"],
37
- ["invalid-result-artifact-json", "runtime_result_artifact_json_invalid"],
38
- ["fabricated-result-artifact", "runtime_result_artifact_mismatch"],
39
- ["fabricated-repository", "consumer_repository_mismatch"],
40
- ["fabricated-revision", "consumer_revision_unknown"],
41
- ["fabricated-source-digest", "runtime_source_digest_mismatch"],
42
- ["nonzero-command", "runtime_command_failed"],
43
- ["forged-noop-result", "runtime_command_result_missing"],
44
- ["github-repository-spoof", "consumer_repository_mismatch", { GITHUB_REPOSITORY: "example/spoof" }],
45
- ]);
46
- const documentedLifecycleCase = "documented-page-evidence-lifecycle";
47
-
48
- function parseArguments(argv) {
49
- const options = { caseName: undefined, json: false };
50
- for (let index = 2; index < argv.length; index += 1) {
51
- const argument = argv[index];
52
- if (argument === "--json") options.json = true;
53
- else if (argument === "--case") {
54
- const value = argv[index + 1];
55
- if (!value || value.startsWith("--")) throw new Error("--case requires a case name");
56
- options.caseName = value;
57
- index += 1;
58
- } else throw new Error(`unsupported argument ${argument}`);
59
- }
60
- return options;
61
- }
62
-
63
- function sameSet(actual, expected) {
64
- return actual.length === expected.length && new Set(actual).size === expected.length && expected.every((entry) => actual.includes(entry));
65
- }
66
-
67
- function readJson(file) {
68
- return parseStrictJson(fs.readFileSync(file, "utf8"));
69
- }
70
-
71
- function validateInventory(manifest) {
72
- const expectedKeys = ["id", "invalid_cases", "schema_record", "schema_version", "valid_records"];
73
- const encodedCases = Array.isArray(manifest.invalid_cases)
74
- ? manifest.invalid_cases.map((entry) => Object.keys(entry).length === 2 ? `${entry.name}:${entry.expected_code}` : "")
75
- : [];
76
- const expectedEncoded = [...contractCases, ...runtimeCases].map(([name, code]) => `${name}:${code}`);
77
- const entries = fs.readdirSync(fixtureRoot, { withFileTypes: true });
78
- const closedFiles = entries.every((entry) => entry.isFile())
79
- && sameSet(entries.map((entry) => entry.name), ["e2e-fixture.mjs", "manifest.json", "runtime-proof.mjs", "valid-migration-result.json", "valid-migration.json"]);
80
- return Object.keys(manifest).length === expectedKeys.length
81
- && sameSet(Object.keys(manifest), expectedKeys)
82
- && manifest.id === "consumer-conformance-fixture-inventory"
83
- && manifest.schema_version === "1.0"
84
- && manifest.schema_record === "consumer-reference/schema/consumer-conformance-record.schema.json"
85
- && Array.isArray(manifest.valid_records)
86
- && sameSet(manifest.valid_records, ["valid-migration.json"])
87
- && sameSet(encodedCases, expectedEncoded)
88
- && closedFiles;
89
- }
90
-
91
- function git(root, ...args) {
92
- return execFileSync("git", ["-c", `safe.directory=${root}`, ...args], { cwd: root, encoding: "utf8" }).trim();
93
- }
94
-
95
- function writeFile(root, reference, content) {
96
- const file = path.join(root, reference);
97
- fs.mkdirSync(path.dirname(file), { recursive: true });
98
- fs.writeFileSync(file, content);
99
- }
100
-
101
- function runtimeResult(value, overrides = {}) {
102
- const scenario = value.scenarios[0];
103
- return {
104
- argv: scenario.argv,
105
- evidence_method: scenario.evidence_method,
106
- exit_code: scenario.exit_code,
107
- record_kind: "consumer_migration_scenario_result",
108
- recorded_at: "2026-07-21T00:00:00Z",
109
- repository: value.consumer.repository,
110
- revision: value.consumer.revision,
111
- run_id: scenario.run_id,
112
- scenario_id: scenario.id,
113
- schema_version: "1.0",
114
- session_id: scenario.session_id,
115
- source_digest: scenario.source_digest,
116
- status: "passed",
117
- ...overrides,
118
- };
119
- }
120
-
121
- function initializeRuntimeFixture(source) {
122
- const root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "stylegallery-consumer-runtime-")));
123
- execFileSync("git", ["init", "-b", "main"], { cwd: root, stdio: "ignore" });
124
- git(root, "config", "user.email", "fixture@example.com");
125
- git(root, "config", "user.name", "StyleGallery fixture");
126
- git(root, "remote", "add", "origin", "https://github.com/example/consumer-web.git");
127
- writeFile(root, "src/app.js", "export const app = true;\n");
128
- writeFile(root, "src/styles.css", ".app { display: block; }\n");
129
- writeFile(root, "tests/migration.mjs", `import fs from "node:fs";\nimport path from "node:path";\nimport { spawnSync } from "node:child_process";\nif (process.argv.includes("--lock-worktree")) { const locked = spawnSync("git", ["worktree", "lock", "."]); if (locked.status !== 0) process.exit(18); }\nconst reference = process.env.STYLEGALLERY_RESULT_ARTIFACT;\nconst context = JSON.parse(process.env.STYLEGALLERY_RUNTIME_CONTEXT);\nconst file = path.resolve(process.cwd(), reference);\nfs.mkdirSync(path.dirname(file), { recursive: true });\nif (process.argv.includes("--oversized-result")) { const descriptor = fs.openSync(file, "wx"); fs.ftruncateSync(descriptor, 67108865); fs.closeSync(descriptor); process.exit(0); }\nfs.writeFileSync(file, JSON.stringify({ ...context, record_kind: "consumer_migration_scenario_result", recorded_at: "2026-07-21T00:00:00Z", schema_version: "1.0", status: "passed" }, null, 2) + "\\n", { flag: "wx" });\n`);
130
- writeFile(root, "tests/failing.mjs", "process.exit(17);\n");
131
- writeFile(root, "tests/hanging.mjs", "setInterval(() => {}, 1000);\n");
132
- writeFile(root, "tests/noop.mjs", "// Intentionally produces no result artifact.\n");
133
- git(root, "add", "src/app.js", "src/styles.css", "tests/migration.mjs", "tests/failing.mjs", "tests/hanging.mjs", "tests/noop.mjs");
134
- git(root, "commit", "-m", "fixture sources");
135
- const cleanRevision = git(root, "rev-parse", "HEAD");
136
- fs.symlinkSync("app.js", path.join(root, "src/linked.js"));
137
- git(root, "add", "src/linked.js");
138
- git(root, "commit", "-m", "fixture symlink source");
139
- const symlinkRevision = git(root, "rev-parse", "HEAD");
140
- git(root, "reset", "--hard", cleanRevision);
141
-
142
- const value = structuredClone(source);
143
- value.consumer = {
144
- relevant_sources: ["src/app.js", "src/styles.css", "tests/migration.mjs"],
145
- repository: "example/consumer-web",
146
- revision: git(root, "rev-parse", "HEAD"),
147
- };
148
- const styleGalleryRevision = git(repositoryRoot, "rev-parse", "HEAD");
149
- for (const mapping of value.adoption_mappings) mapping.stylegallery.revision = styleGalleryRevision;
150
- const sourceFailures = [];
151
- const manifest = canonicalSourceManifest(root, value.consumer.relevant_sources, sourceFailures);
152
- if (!manifest || sourceFailures.length > 0) throw new Error(`runtime fixture source manifest failed: ${JSON.stringify(sourceFailures)}`);
153
- value.scenarios[0] = {
154
- ...value.scenarios[0],
155
- argv: ["node", "tests/migration.mjs"],
156
- evidence_method: "integration",
157
- result_artifact: "evidence/results/migration-round-trip.json",
158
- source_digest: manifest.sha256,
159
- };
160
- writeFile(root, value.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(value), null, 2)}\n`);
161
- writeFile(root, "evidence/results/fabricated.json", `${JSON.stringify(runtimeResult(value, { scenario_id: "fabricated-scenario" }), null, 2)}\n`);
162
- const failing = structuredClone(value);
163
- failing.scenarios[0].argv = ["node", "tests/failing.mjs"];
164
- failing.scenarios[0].result_artifact = "evidence/results/nonzero-command.json";
165
- writeFile(root, failing.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(failing), null, 2)}\n`);
166
- const noop = structuredClone(value);
167
- noop.scenarios[0].argv = ["node", "tests/noop.mjs"];
168
- noop.scenarios[0].result_artifact = "evidence/results/forged-noop-result.json";
169
- writeFile(root, noop.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(noop), null, 2)}\n`);
170
- writeFile(root, "evidence/results/invalid.json", "{not json}\n");
171
- fs.symlinkSync("migration-round-trip.json", path.join(root, "evidence/results/redirect.json"));
172
- return { root, symlinkRevision, value };
173
- }
174
-
175
- function mutatedRuntimeRecord(name, source, fixture) {
176
- const value = structuredClone(source);
177
- if (name === "missing-source") value.consumer.relevant_sources[0] = "src/missing.js";
178
- else if (name === "symlink-source") {
179
- value.consumer.relevant_sources[0] = "src/linked.js";
180
- value.consumer.revision = fixture.symlinkRevision;
181
- }
182
- else if (name === "checkout-symlink") value.consumer.revision = fixture.symlinkRevision;
183
- else if (name === "missing-result-artifact") value.scenarios[0].result_artifact = "evidence/results/missing.json";
184
- else if (name === "symlink-result-artifact") value.scenarios[0].result_artifact = "evidence/results/redirect.json";
185
- else if (name === "invalid-result-artifact-json") value.scenarios[0].result_artifact = "evidence/results/invalid.json";
186
- else if (name === "fabricated-result-artifact") value.scenarios[0].result_artifact = "evidence/results/fabricated.json";
187
- else if (name === "fabricated-repository") value.consumer.repository = "fabricated/consumer";
188
- else if (name === "fabricated-revision") value.consumer.revision = "0".repeat(40);
189
- else if (name === "fabricated-source-digest") value.scenarios[0].source_digest = "0".repeat(64);
190
- else if (name === "nonzero-command") {
191
- value.scenarios[0].argv = ["node", "tests/failing.mjs"];
192
- value.scenarios[0].result_artifact = "evidence/results/nonzero-command.json";
193
- }
194
- else if (name === "forged-noop-result") {
195
- value.scenarios[0].argv = ["node", "tests/noop.mjs"];
196
- value.scenarios[0].result_artifact = "evidence/results/forged-noop-result.json";
197
- }
198
- else if (name === "github-repository-spoof") value.consumer.repository = "example/spoof";
199
- else throw new Error(`unknown runtime fixture case ${name}`);
200
- return value;
201
- }
202
-
203
- function documentedLifecycleIsExecutable() {
204
- const document = fs.readFileSync(path.join(repositoryRoot, "design-engineering", "consumer-migration-readiness.md"), "utf8");
205
- const start = document.indexOf("## Verification Contract");
206
- const end = document.indexOf("## Source, License, And Attribution");
207
- const verification = document.slice(start, end);
208
- return [
209
- "create-page-evidence-session.mjs",
210
- "finalize-page-evidence.mjs",
211
- "validate-consumer-conformance.mjs",
212
- "--root <consumer-root>",
213
- "--record <record.json>",
214
- "--artifact-root <artifact-root>",
215
- "--runner-result <runner-result.json>",
216
- "--review-by <RFC3339-date-time>",
217
- ].every((fragment) => verification.includes(fragment));
218
- }
219
-
220
- function mutatedRecord(name, source) {
221
- const value = structuredClone(source);
222
- if (name === "omitted-dimension") delete value.migration_dimensions.exact_time_boundary;
223
- else if (name === "applicable-without-scenario") value.migration_dimensions.route_parity = { scenario_ids: [], status: "applicable" };
224
- else if (name === "source-regex-runtime-proof") value.scenarios[0].evidence_method = "source_regex";
225
- else if (name === "orphan-adoption-scenario") value.adoption_mappings[0].scenario_ids = ["missing-scenario"];
226
- else if (name === "malformed-local-target") value.adoption_mappings[0].consumer_target = { identity: "app shell", kind: "selector" };
227
- else if (name === "unpinned-stylegallery-revision") value.adoption_mappings[0].stylegallery.revision = "abc123";
228
- else if (name === "unknown-stylegallery-revision") value.adoption_mappings[0].stylegallery.revision = "0".repeat(40);
229
- else if (name === "missing-stylegallery-path") value.adoption_mappings[0].stylegallery.path = "recipes/missing.md";
230
- else if (name === "missing-stylegallery-anchor") value.adoption_mappings[0].stylegallery.anchor = "#missing-anchor";
231
- else if (name === "debt-without-lifecycle") value.adoption_mappings[0].debt = [{ summary: "Replace the temporary spacing bridge." }];
232
- else throw new Error(`unknown fixture case ${name}`);
233
- return value;
234
- }
235
-
236
- function runValidator(root, record, env = {}) {
237
- const child = spawnSync(process.execPath, [validator, "--root", root, "--record", record, "--json"], {
238
- cwd: repositoryRoot,
239
- encoding: "utf8",
240
- env: { ...process.env, ...env },
241
- });
242
- let output;
243
- try {
244
- output = JSON.parse(child.stdout);
245
- } catch {
246
- output = { failures: [], parse_error: child.stderr || child.stdout };
247
- }
248
- return { output, status: child.status };
249
- }
250
-
251
- const options = parseArguments(process.argv);
252
- const tempRoot = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "stylegallery-consumer-conformance-")));
253
- const results = [];
254
- let runtimeFixture;
255
- try {
256
- const manifest = readJson(path.join(fixtureRoot, "manifest.json"));
257
- const inventoryOk = validateInventory(manifest) && fs.existsSync(path.join(repositoryRoot, manifest.schema_record));
258
- results.push({ actual: inventoryOk, expected: true, name: "closed-fixture-inventory", ok: inventoryOk });
259
- const valid = readJson(path.join(fixtureRoot, "valid-migration.json"));
260
- const selected = options.caseName ?? "all";
261
- for (const name of endToEndCaseNames) {
262
- if (selected === "all" || selected === name) results.push(runEndToEndCase(name, valid));
263
- }
264
- if (selected === "all" || selected === "valid-migration") {
265
- const codes = validateConsumerConformanceSemantics(valid, "valid-migration.json").map((entry) => entry.code);
266
- const checkedDimensions = Object.keys(valid.migration_dimensions ?? {}).length;
267
- const checkedMappings = valid.adoption_mappings?.length ?? 0;
268
- const ok = codes.length === 0 && checkedDimensions === MIGRATION_DIMENSIONS.length && checkedMappings === 1;
269
- results.push({ actual: { checkedDimensions, checkedMappings, codes }, expected: "valid static template, 13 dimensions, one mapping", name: "valid-migration", ok });
270
- }
271
- if (selected === "all" || selected === "stale-template-rebound") {
272
- const stale = structuredClone(valid);
273
- stale.adoption_mappings[0].stylegallery.revision = "0".repeat(40);
274
- const result = runEndToEndCase("end-to-end-consumer", stale);
275
- results.push({ ...result, expected: "dynamic record rebound to the current StyleGallery checkout", name: "stale-template-rebound" });
276
- }
277
- const contractTemplate = structuredClone(valid);
278
- const styleGalleryRevision = git(repositoryRoot, "rev-parse", "HEAD");
279
- for (const mapping of contractTemplate.adoption_mappings) mapping.stylegallery.revision = styleGalleryRevision;
280
- for (const [name, expectedCode] of contractCases) {
281
- if (selected !== "all" && selected !== name) continue;
282
- const record = path.join(tempRoot, `${name}.json`);
283
- fs.writeFileSync(record, `${JSON.stringify(mutatedRecord(name, contractTemplate), null, 2)}\n`);
284
- const child = runValidator(tempRoot, path.basename(record));
285
- const codes = child.output.failures?.map((entry) => entry.code) ?? [];
286
- const ok = child.status !== 0 && codes.includes(expectedCode);
287
- results.push({ actual: { codes, status: child.status }, expected: expectedCode, name, ok });
288
- }
289
- const runtimeTemplate = structuredClone(valid);
290
- runtimeTemplate.adoption_mappings[0].stylegallery.revision = "0".repeat(40);
291
- runtimeFixture = initializeRuntimeFixture(runtimeTemplate);
292
- if (selected === "all" || selected === "valid-runtime-proof") {
293
- const record = "records/valid-runtime-proof.json";
294
- writeFile(runtimeFixture.root, record, `${JSON.stringify(runtimeFixture.value, null, 2)}\n`);
295
- const child = runValidator(runtimeFixture.root, record);
296
- const ok = child.status === 0 && child.output.ok === true && child.output.checkedScenarios === 1;
297
- results.push({ actual: { codes: child.output.failures?.map((entry) => entry.code) ?? [], status: child.status }, expected: "runtime-bound record and exit:0", name: "valid-runtime-proof", ok });
298
- }
299
- for (const [name, expectedCode, env] of runtimeCases) {
300
- if (selected !== "all" && selected !== name) continue;
301
- const record = `records/${name}.json`;
302
- writeFile(runtimeFixture.root, record, `${JSON.stringify(mutatedRuntimeRecord(name, runtimeFixture.value, runtimeFixture), null, 2)}\n`);
303
- const child = runValidator(runtimeFixture.root, record, env);
304
- const codes = child.output.failures?.map((entry) => entry.code) ?? [];
305
- const ok = child.status !== 0 && codes.includes(expectedCode);
306
- results.push({ actual: { codes, status: child.status }, expected: expectedCode, name, ok });
307
- }
308
- if (selected === "all" || selected === "child-process-denied-cleanup") {
309
- const value = structuredClone(runtimeFixture.value);
310
- value.scenarios[0].argv = ["node", "tests/migration.mjs", "--lock-worktree"];
311
- value.scenarios[0].result_artifact = "evidence/results/locked-worktree-cleanup.json";
312
- writeFile(runtimeFixture.root, value.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(value), null, 2)}\n`);
313
- const record = "records/locked-worktree-cleanup.json";
314
- writeFile(runtimeFixture.root, record, `${JSON.stringify(value, null, 2)}\n`);
315
- const before = git(runtimeFixture.root, "worktree", "list", "--porcelain");
316
- const child = runValidator(runtimeFixture.root, record);
317
- const after = git(runtimeFixture.root, "worktree", "list", "--porcelain");
318
- const codes = child.output.failures?.map((entry) => entry.code) ?? [];
319
- const ok = child.status !== 0 && codes.includes("runtime_command_failed") && before === after;
320
- results.push({ actual: { codes, registeredWorktreesUnchanged: before === after, status: child.status }, expected: "child process denied and no registered temporary worktree", name: "child-process-denied-cleanup", ok });
321
- }
322
- if (selected === "all" || selected === "timed-out-command-cleanup") {
323
- const value = structuredClone(runtimeFixture.value);
324
- value.scenarios[0].argv = ["node", "tests/hanging.mjs"];
325
- value.scenarios[0].result_artifact = "evidence/results/timed-out-command.json";
326
- writeFile(runtimeFixture.root, value.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(value), null, 2)}\n`);
327
- const record = "records/timed-out-command.json";
328
- writeFile(runtimeFixture.root, record, `${JSON.stringify(value, null, 2)}\n`);
329
- const before = git(runtimeFixture.root, "worktree", "list", "--porcelain");
330
- const child = runValidator(runtimeFixture.root, record, { STYLEGALLERY_RUNTIME_TIMEOUT_MS: "100" });
331
- const after = git(runtimeFixture.root, "worktree", "list", "--porcelain");
332
- const codes = child.output.failures?.map((entry) => entry.code) ?? [];
333
- const ok = child.status !== 0 && codes.includes("runtime_command_failed") && before === after;
334
- results.push({ actual: { codes, registeredWorktreesUnchanged: before === after, status: child.status }, expected: "timeout and no registered temporary worktree", name: "timed-out-command-cleanup", ok });
335
- }
336
- if (selected === "all" || selected === "permission-override-denied") {
337
- const value = structuredClone(runtimeFixture.value);
338
- value.scenarios[0].argv = ["node", "--allow-child-process", "tests/migration.mjs"];
339
- value.scenarios[0].result_artifact = "evidence/results/permission-override.json";
340
- writeFile(runtimeFixture.root, value.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(value), null, 2)}\n`);
341
- const record = "records/permission-override.json";
342
- writeFile(runtimeFixture.root, record, `${JSON.stringify(value, null, 2)}\n`);
343
- const child = runValidator(runtimeFixture.root, record);
344
- const codes = child.output.failures?.map((entry) => entry.code) ?? [];
345
- const ok = child.status !== 0 && codes.includes("runtime_command_argv_unsafe") && child.output.checkedRuntimeCommands === 0;
346
- results.push({ actual: { checkedRuntimeCommands: child.output.checkedRuntimeCommands, codes, status: child.status }, expected: "permission override rejected before execution", name: "permission-override-denied", ok });
347
- }
348
- if (selected === "all" || selected === "permission-disable-denied") {
349
- const value = structuredClone(runtimeFixture.value);
350
- value.scenarios[0].argv = ["node", "--no-permission=false", "tests/migration.mjs"];
351
- value.scenarios[0].result_artifact = "evidence/results/permission-disable.json";
352
- writeFile(runtimeFixture.root, value.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(value), null, 2)}\n`);
353
- const record = "records/permission-disable.json";
354
- writeFile(runtimeFixture.root, record, `${JSON.stringify(value, null, 2)}\n`);
355
- const child = runValidator(runtimeFixture.root, record);
356
- const codes = child.output.failures?.map((entry) => entry.code) ?? [];
357
- const ok = child.status !== 0 && codes.includes("runtime_command_argv_unsafe") && child.output.checkedRuntimeCommands === 0;
358
- results.push({ actual: { checkedRuntimeCommands: child.output.checkedRuntimeCommands, codes, status: child.status }, expected: "permission disable rejected before execution", name: "permission-disable-denied", ok });
359
- }
360
- if (selected === "all" || selected === "permission-underscore-denied") {
361
- const value = structuredClone(runtimeFixture.value);
362
- value.scenarios[0].argv = ["node", "--allow_child_process", "tests/migration.mjs"];
363
- value.scenarios[0].result_artifact = "evidence/results/permission-underscore.json";
364
- writeFile(runtimeFixture.root, value.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(value), null, 2)}\n`);
365
- const record = "records/permission-underscore.json";
366
- writeFile(runtimeFixture.root, record, `${JSON.stringify(value, null, 2)}\n`);
367
- const child = runValidator(runtimeFixture.root, record);
368
- const codes = child.output.failures?.map((entry) => entry.code) ?? [];
369
- const ok = child.status !== 0 && codes.includes("runtime_command_argv_unsafe") && child.output.checkedRuntimeCommands === 0;
370
- results.push({ actual: { checkedRuntimeCommands: child.output.checkedRuntimeCommands, codes, status: child.status }, expected: "underscore permission override rejected before execution", name: "permission-underscore-denied", ok });
371
- }
372
- if (selected === "all" || selected === "permission-path-shaped-denied") {
373
- const value = structuredClone(runtimeFixture.value);
374
- value.scenarios[0].argv = ["node", "--allow-fs-read=/tmp/outside.mjs", "tests/migration.mjs"];
375
- value.scenarios[0].result_artifact = "evidence/results/permission-path-shaped.json";
376
- writeFile(runtimeFixture.root, value.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(value), null, 2)}\n`);
377
- const record = "records/permission-path-shaped.json";
378
- writeFile(runtimeFixture.root, record, `${JSON.stringify(value, null, 2)}\n`);
379
- const child = runValidator(runtimeFixture.root, record);
380
- const codes = child.output.failures?.map((entry) => entry.code) ?? [];
381
- const ok = child.status !== 0 && codes.includes("runtime_command_argv_unsafe") && child.output.checkedRuntimeCommands === 0;
382
- results.push({ actual: { checkedRuntimeCommands: child.output.checkedRuntimeCommands, codes, status: child.status }, expected: "path-shaped permission option rejected before execution", name: "permission-path-shaped-denied", ok });
383
- }
384
- if (selected === "all" || selected === "oversized-command-result") {
385
- const value = structuredClone(runtimeFixture.value);
386
- value.scenarios[0].argv = ["node", "tests/migration.mjs", "--oversized-result"];
387
- value.scenarios[0].result_artifact = "evidence/results/oversized-command-result.json";
388
- writeFile(runtimeFixture.root, value.scenarios[0].result_artifact, `${JSON.stringify(runtimeResult(value), null, 2)}\n`);
389
- const record = "records/oversized-command-result.json";
390
- writeFile(runtimeFixture.root, record, `${JSON.stringify(value, null, 2)}\n`);
391
- const child = runValidator(runtimeFixture.root, record);
392
- const codes = child.output.failures?.map((entry) => entry.code) ?? [];
393
- const ok = child.status !== 0 && codes.includes("runtime_command_result_missing") && child.output.checkedRuntimeCommands === 0;
394
- results.push({ actual: { checkedRuntimeCommands: child.output.checkedRuntimeCommands, codes, status: child.status }, expected: "oversized command result rejected before read", name: "oversized-command-result", ok });
395
- }
396
- if (selected === "all" || selected === documentedLifecycleCase) {
397
- const actual = documentedLifecycleIsExecutable();
398
- results.push({ actual, expected: true, name: documentedLifecycleCase, ok: actual });
399
- }
400
- const knownCase = selected === "all"
401
- || selected === "valid-migration"
402
- || selected === "valid-runtime-proof"
403
- || selected === "stale-template-rebound"
404
- || selected === documentedLifecycleCase
405
- || selected === "child-process-denied-cleanup"
406
- || selected === "timed-out-command-cleanup"
407
- || selected === "permission-override-denied"
408
- || selected === "permission-disable-denied"
409
- || selected === "permission-underscore-denied"
410
- || selected === "permission-path-shaped-denied"
411
- || selected === "oversized-command-result"
412
- || endToEndCaseNames.includes(selected)
413
- || contractCases.some(([name]) => name === selected)
414
- || runtimeCases.some(([name]) => name === selected);
415
- if (!knownCase) {
416
- results.push({ actual: selected, expected: "known case", name: "case-selection", ok: false });
417
- }
418
- } finally {
419
- fs.rmSync(tempRoot, { force: true, recursive: true });
420
- if (runtimeFixture) fs.rmSync(runtimeFixture.root, { force: true, recursive: true });
421
- }
422
-
423
- const result = { ok: results.every((entry) => entry.ok), results };
424
- if (options.json) console.log(JSON.stringify(result, null, 2));
425
- else if (result.ok) console.log(`ok: ${results.length} consumer conformance fixture cases`);
426
- else console.error(results.filter((entry) => !entry.ok).map((entry) => `${entry.name}: expected ${entry.expected}`).join("\n"));
427
- process.exitCode = result.ok ? 0 : 1;
@@ -1,69 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { spawnSync } from "node:child_process";
4
- import path from "node:path";
5
- import { fileURLToPath } from "node:url";
6
-
7
- const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
8
- const validator = path.join(repositoryRoot, "scripts", "validate-consumer-reference.mjs");
9
- const validItem = "consumer-reference/fixtures/valid-experimental.json";
10
- const errorCases = [
11
- { args: ["--item", "--json"], codes: ["argument_value_required"], name: "item_missing_value_before_json" },
12
- { args: ["--item", "--unknown", "--json"], codes: ["argument_value_required", "argument_unknown"], name: "item_missing_value_before_unknown" },
13
- { args: ["--profile", "--json"], codes: ["argument_value_required"], name: "profile_missing_value_before_json" },
14
- { args: ["--profile", "--unknown", "--json"], codes: ["argument_value_required", "argument_unknown"], name: "profile_missing_value_before_unknown" },
15
- { args: ["--json", "--item"], codes: ["argument_value_required"], name: "json_before_item_missing_value" },
16
- { args: ["--json", "--profile"], codes: ["argument_value_required"], name: "json_before_profile_missing_value" },
17
- ];
18
-
19
- function run(args) {
20
- return spawnSync(process.execPath, [validator, ...args], {
21
- cwd: repositoryRoot,
22
- encoding: "utf8",
23
- });
24
- }
25
-
26
- function runErrorCase(testCase) {
27
- const child = run(testCase.args);
28
- let report;
29
- try {
30
- report = JSON.parse(child.stdout);
31
- } catch (error) {
32
- return {
33
- actual: { stderr: child.stderr.trim(), status: child.status, stdout: child.stdout },
34
- expected: `${testCase.codes.join(",")} in parseable JSON with nonzero exit`,
35
- name: testCase.name,
36
- ok: false,
37
- reason: error instanceof Error ? error.message : String(error),
38
- };
39
- }
40
- const codes = Array.isArray(report.failures) ? report.failures.map((failure) => failure.code) : [];
41
- return {
42
- actual: { codes, ok: report.ok, status: child.status, stderr: child.stderr.trim() },
43
- expected: `${testCase.codes.join(",")} in parseable JSON with nonzero exit`,
44
- name: testCase.name,
45
- ok: child.status !== 0
46
- && child.stderr.length === 0
47
- && report.ok === false
48
- && codes.length === testCase.codes.length
49
- && testCase.codes.every((code) => codes.includes(code)),
50
- };
51
- }
52
-
53
- const results = errorCases.map(runErrorCase);
54
- const jsonLast = run(["--item", validItem, "--json"]);
55
- const jsonFirst = run(["--json", "--item", validItem]);
56
- results.push({
57
- actual: { firstStatus: jsonFirst.status, lastStatus: jsonLast.status, stderr: `${jsonFirst.stderr}${jsonLast.stderr}` },
58
- expected: "valid arguments produce byte-identical JSON regardless of --json position",
59
- name: "valid_json_option_order",
60
- ok: jsonFirst.status === 0
61
- && jsonLast.status === 0
62
- && jsonFirst.stderr.length === 0
63
- && jsonLast.stderr.length === 0
64
- && jsonFirst.stdout === jsonLast.stdout,
65
- });
66
-
67
- const report = { ok: results.every((result) => result.ok), results };
68
- process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
69
- process.exitCode = report.ok ? 0 : 1;