@sun-asterisk/sungen 3.3.0-alpha.2 → 3.3.0-alpha.3

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 (85) hide show
  1. package/dist/cli/commands/contract.d.ts +3 -0
  2. package/dist/cli/commands/contract.d.ts.map +1 -1
  3. package/dist/cli/commands/contract.js +34 -4
  4. package/dist/cli/commands/contract.js.map +1 -1
  5. package/dist/contract/accept-opaque-steps.d.ts +3 -0
  6. package/dist/contract/accept-opaque-steps.d.ts.map +1 -0
  7. package/dist/contract/accept-opaque-steps.js +114 -0
  8. package/dist/contract/accept-opaque-steps.js.map +1 -0
  9. package/dist/contract/approve-contract.d.ts +8 -1
  10. package/dist/contract/approve-contract.d.ts.map +1 -1
  11. package/dist/contract/approve-contract.js +6 -0
  12. package/dist/contract/approve-contract.js.map +1 -1
  13. package/dist/contract/build-contract-verdict.js +2 -2
  14. package/dist/contract/build-contract-verdict.js.map +1 -1
  15. package/dist/contract/build-trace-conformance.d.ts +5 -1
  16. package/dist/contract/build-trace-conformance.d.ts.map +1 -1
  17. package/dist/contract/build-trace-conformance.js +9 -4
  18. package/dist/contract/build-trace-conformance.js.map +1 -1
  19. package/dist/contract/classify-contract-change.d.ts +3 -2
  20. package/dist/contract/classify-contract-change.d.ts.map +1 -1
  21. package/dist/contract/classify-contract-change.js.map +1 -1
  22. package/dist/contract/classify-trace-conformance.d.ts +18 -3
  23. package/dist/contract/classify-trace-conformance.d.ts.map +1 -1
  24. package/dist/contract/classify-trace-conformance.js +64 -17
  25. package/dist/contract/classify-trace-conformance.js.map +1 -1
  26. package/dist/contract/contract-schema.d.ts +21 -0
  27. package/dist/contract/contract-schema.d.ts.map +1 -1
  28. package/dist/contract/contract-schema.js +25 -3
  29. package/dist/contract/contract-schema.js.map +1 -1
  30. package/dist/contract/contracts-lock-file.d.ts.map +1 -1
  31. package/dist/contract/contracts-lock-file.js +1 -0
  32. package/dist/contract/contracts-lock-file.js.map +1 -1
  33. package/dist/contract/project-contract-blockers.d.ts.map +1 -1
  34. package/dist/contract/project-contract-blockers.js +4 -2
  35. package/dist/contract/project-contract-blockers.js.map +1 -1
  36. package/dist/contract/record-contract-approval.d.ts +16 -1
  37. package/dist/contract/record-contract-approval.d.ts.map +1 -1
  38. package/dist/contract/record-contract-approval.js +29 -1
  39. package/dist/contract/record-contract-approval.js.map +1 -1
  40. package/dist/contract/render-free-gherkin.d.ts +2 -0
  41. package/dist/contract/render-free-gherkin.d.ts.map +1 -1
  42. package/dist/contract/render-free-gherkin.js +6 -0
  43. package/dist/contract/render-free-gherkin.js.map +1 -1
  44. package/dist/contract/trace/collect-trace-evidence.d.ts +8 -3
  45. package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -1
  46. package/dist/contract/trace/collect-trace-evidence.js +65 -34
  47. package/dist/contract/trace/collect-trace-evidence.js.map +1 -1
  48. package/dist/contract/trace/read-file-once.d.ts +20 -0
  49. package/dist/contract/trace/read-file-once.d.ts.map +1 -0
  50. package/dist/contract/trace/read-file-once.js +135 -0
  51. package/dist/contract/trace/read-file-once.js.map +1 -0
  52. package/dist/contract/trace/select-final-attempt.d.ts +2 -2
  53. package/dist/contract/trace/select-final-attempt.d.ts.map +1 -1
  54. package/dist/contract/trace/select-final-attempt.js +3 -3
  55. package/dist/contract/trace/select-final-attempt.js.map +1 -1
  56. package/dist/contract/trace/trace-file-reader.d.ts +7 -1
  57. package/dist/contract/trace/trace-file-reader.d.ts.map +1 -1
  58. package/dist/contract/trace/trace-file-reader.js +17 -41
  59. package/dist/contract/trace/trace-file-reader.js.map +1 -1
  60. package/dist/contract/trace/trace-run-record.d.ts +2 -2
  61. package/dist/contract/trace/trace-run-record.d.ts.map +1 -1
  62. package/dist/contract/trace/trace-run-record.js +3 -3
  63. package/dist/contract/trace/trace-run-record.js.map +1 -1
  64. package/dist/contract/verify-approval-decisions.d.ts.map +1 -1
  65. package/dist/contract/verify-approval-decisions.js +9 -4
  66. package/dist/contract/verify-approval-decisions.js.map +1 -1
  67. package/package.json +3 -3
  68. package/src/cli/commands/contract.ts +35 -4
  69. package/src/contract/accept-opaque-steps.ts +114 -0
  70. package/src/contract/approve-contract.ts +10 -3
  71. package/src/contract/build-contract-verdict.ts +2 -2
  72. package/src/contract/build-trace-conformance.ts +8 -3
  73. package/src/contract/classify-contract-change.ts +3 -3
  74. package/src/contract/classify-trace-conformance.ts +76 -22
  75. package/src/contract/contract-schema.ts +31 -2
  76. package/src/contract/contracts-lock-file.ts +1 -0
  77. package/src/contract/project-contract-blockers.ts +4 -2
  78. package/src/contract/record-contract-approval.ts +41 -1
  79. package/src/contract/render-free-gherkin.ts +5 -0
  80. package/src/contract/trace/collect-trace-evidence.ts +66 -29
  81. package/src/contract/trace/read-file-once.ts +95 -0
  82. package/src/contract/trace/select-final-attempt.ts +3 -3
  83. package/src/contract/trace/trace-file-reader.ts +17 -6
  84. package/src/contract/trace/trace-run-record.ts +3 -3
  85. package/src/contract/verify-approval-decisions.ts +9 -5
@@ -1,39 +1,7 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.readTraceBuffer = readTraceBuffer;
4
+ exports.traceFromRead = traceFromRead;
37
5
  exports.readTraceFile = readTraceFile;
38
6
  /**
39
7
  * One Playwright trace.zip → its parsed parts, after the zip limits and the format-version gate
@@ -49,7 +17,7 @@ exports.readTraceFile = readTraceFile;
49
17
  * a part without one is refused. Every JSONL line must parse — a line that does not is never skipped.
50
18
  */
51
19
  const crypto_1 = require("crypto");
52
- const fs = __importStar(require("fs"));
20
+ const read_file_once_1 = require("./read-file-once");
53
21
  const trace_zip_reader_1 = require("./trace-zip-reader");
54
22
  const trace_zip_limits_1 = require("./trace-zip-limits");
55
23
  const CALL_ID = /^[\w@.:-]{1,128}$/;
@@ -149,13 +117,21 @@ function readTraceBuffer(buf, label, limits = (0, trace_zip_limits_1.traceZipLim
149
117
  },
150
118
  };
151
119
  }
152
- /** Read a trace from disk: a regular file, size-checked BEFORE it is read into memory. */
120
+ /**
121
+ * A trace opened once (read-file-once.ts) → parsed: the size was checked on the descriptor BEFORE it
122
+ * was read into memory. `missing` / `outside` are the caller's to report; here they throw.
123
+ */
124
+ function traceFromRead(read, label, limits = (0, trace_zip_limits_1.traceZipLimits)()) {
125
+ switch (read.status) {
126
+ case 'read': return readTraceBuffer(read.bytes, read.real, limits);
127
+ case 'too-large': throw new trace_zip_limits_1.TraceRejected('zip.too-large', `${read.size} B > ${limits.maxZipBytes}`);
128
+ case 'not-a-file': throw new trace_zip_limits_1.TraceRejected('zip.malformed', `${label} is not a regular file`);
129
+ case 'missing': throw new trace_zip_limits_1.TraceRejected('zip.malformed', `${label} does not exist`);
130
+ default: throw new trace_zip_limits_1.TraceRejected('zip.malformed', `${label} was not read: ${read.why}`);
131
+ }
132
+ }
133
+ /** Read a trace from a trusted path (a fixture, a test): a regular file, opened once. */
153
134
  function readTraceFile(file, limits = (0, trace_zip_limits_1.traceZipLimits)()) {
154
- const st = fs.statSync(file);
155
- if (!st.isFile())
156
- throw new trace_zip_limits_1.TraceRejected('zip.malformed', `${file} is not a regular file`);
157
- if (st.size > limits.maxZipBytes)
158
- throw new trace_zip_limits_1.TraceRejected('zip.too-large', `${st.size} B > ${limits.maxZipBytes}`);
159
- return readTraceBuffer(fs.readFileSync(file), file, limits);
135
+ return traceFromRead((0, read_file_once_1.readFileOnce)(file, limits.maxZipBytes), file, limits);
160
136
  }
161
137
  //# sourceMappingURL=trace-file-reader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"trace-file-reader.js","sourceRoot":"","sources":["../../../src/contract/trace/trace-file-reader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trace-file-reader.js","sourceRoot":"","sources":["../../../src/contract/trace/trace-file-reader.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,6 @@ export declare const FREE_RUN_DIR = "test-results-free";
25
25
  /** Where run records are read, in this order: the free run's dir, then Playwright's default (older configs). */
26
26
  export declare const RUN_RECORD_DIRS: readonly string[];
27
27
  export declare function findRunRecords(projectRoot: string): string[];
28
- /** Read and check one record; throws an Error naming what is wrong. */
29
- export declare function readRunRecord(file: string): RunRecord;
28
+ /** Read and check one record (`text`: its bytes, already read once by the caller); throws an Error naming what is wrong. */
29
+ export declare function readRunRecord(file: string, text?: string): RunRecord;
30
30
  //# sourceMappingURL=trace-run-record.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"trace-run-record.d.ts","sourceRoot":"","sources":["../../../src/contract/trace/trace-run-record.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAC3E,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACvE;AACD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAOD,uHAAuH;AACvH,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAChD,gHAAgH;AAChH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAAmC,CAAC;AAEjF,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAO5D;AAgBD,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAgBrD"}
1
+ {"version":3,"file":"trace-run-record.d.ts","sourceRoot":"","sources":["../../../src/contract/trace/trace-run-record.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAC3E,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACvE;AACD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAOD,uHAAuH;AACvH,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAChD,gHAAgH;AAChH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAAmC,CAAC;AAEjF,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAO5D;AAgBD,4HAA4H;AAC5H,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAgBpE"}
@@ -87,11 +87,11 @@ function attemptOf(raw, i) {
87
87
  throw new Error(`${at}: trace must be null or {sha256}`);
88
88
  return { testId, file, title, retry: retry, status, startTime, duration, trace: trace };
89
89
  }
90
- /** Read and check one record; throws an Error naming what is wrong. */
91
- function readRunRecord(file) {
90
+ /** Read and check one record (`text`: its bytes, already read once by the caller); throws an Error naming what is wrong. */
91
+ function readRunRecord(file, text) {
92
92
  let raw;
93
93
  try {
94
- raw = JSON.parse(fs.readFileSync(file, 'utf8'));
94
+ raw = JSON.parse(text ?? fs.readFileSync(file, 'utf8'));
95
95
  }
96
96
  catch (e) {
97
97
  throw new Error(`not readable JSON (${e.message.split('\n')[0]})`);
@@ -1 +1 @@
1
- {"version":3,"file":"trace-run-record.js","sourceRoot":"","sources":["../../../src/contract/trace/trace-run-record.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trace-run-record.js","sourceRoot":"","sources":["../../../src/contract/trace/trace-run-record.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"verify-approval-decisions.d.ts","sourceRoot":"","sources":["../../src/contract/verify-approval-decisions.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,YAAY,EAA0C,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,YAAY,EAA8B,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AA6B3D,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,YAAY,GAC7G,gBAAgB,EAAE,CAWpB"}
1
+ {"version":3,"file":"verify-approval-decisions.d.ts","sourceRoot":"","sources":["../../src/contract/verify-approval-decisions.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,YAAY,EAA0C,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EAAE,YAAY,EAA8B,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AA+B3D,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,YAAY,GAC7G,gBAAgB,EAAE,CAWpB"}
@@ -38,9 +38,10 @@ exports.unverifiedApprovals = unverifiedApprovals;
38
38
  * Every approved lock entry must be vouched for by its decision (DOS-13.2, DOS-14.4, review M1):
39
39
  * `qa/<kind>/<unit>/decisions/<decisionId>.yaml`, COMMITTED in git HEAD (outside git: on disk),
40
40
  * intact (schema, id = content, entry_hash = entry), of kind `contract-approval`, whose payload lists
41
- * this scenario at this hash, and whose `valid_from` is the entry's `approvedAt`. A lock line copied
42
- * from elsewhere, re-pointed at another decision, or backdated fails here — `unverified`, reported
43
- * under contract.lock-uncommitted (hard).
41
+ * this scenario at this hash — with exactly the opaque steps the entry says QA accepted (#923) — and
42
+ * whose `valid_from` is the entry's `approvedAt`. A lock line copied from elsewhere, re-pointed at
43
+ * another decision, backdated, or given an acceptance nobody recorded fails here — `unverified`,
44
+ * reported under contract.lock-uncommitted (hard).
44
45
  *
45
46
  * Only entries that are otherwise identical to HEAD are checked: an entry already added, changed or
46
47
  * tampered is a hard finding on its own.
@@ -50,6 +51,7 @@ const decision_identity_1 = require("../decisions/decision-identity");
50
51
  const decision_schema_1 = require("../decisions/decision-schema");
51
52
  const safe_yaml_parse_1 = require("../utils/safe-yaml-parse");
52
53
  const contract_git_1 = require("./contract-git");
54
+ const contract_hash_1 = require("./contract-hash");
53
55
  const contract_schema_1 = require("./contract-schema");
54
56
  function loadDecision(projectRoot, unitDir, id, snap) {
55
57
  const file = path.join(unitDir, 'decisions', `${id}.yaml`);
@@ -80,8 +82,11 @@ function mismatch(scenario, lockEntry, d) {
80
82
  if (d.kind !== 'contract-approval')
81
83
  return `decision ${d.id} is a ${d.kind}, not a contract-approval`;
82
84
  const listed = Array.isArray(d.payload?.scenarios) ? d.payload.scenarios : [];
83
- if (!listed.some((s) => s && s.id === scenario && s.hash === lockEntry.hash))
85
+ const item = listed.find((s) => s && s.id === scenario && s.hash === lockEntry.hash);
86
+ if (!item)
84
87
  return `decision ${d.id} does not approve ${scenario} at hash ${lockEntry.hash}`;
88
+ if (!(0, contract_hash_1.sameJson)(item.acceptedOpaque ?? [], lockEntry.acceptedOpaque ?? []))
89
+ return `decision ${d.id} does not accept the opaque step(s) the lock entry of ${scenario} lists (acceptedOpaque)`;
85
90
  if (Date.parse(lockEntry.approvedAt) !== Date.parse(d.valid_from))
86
91
  return `approvedAt ${lockEntry.approvedAt} is not decision ${d.id}'s valid_from ${d.valid_from}`;
87
92
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"verify-approval-decisions.js","sourceRoot":"","sources":["../../src/contract/verify-approval-decisions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verify-approval-decisions.js","sourceRoot":"","sources":["../../src/contract/verify-approval-decisions.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sungen",
3
- "version": "3.3.0-alpha.2",
3
+ "version": "3.3.0-alpha.3",
4
4
  "description": "Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -40,8 +40,8 @@
40
40
  "@babel/types": "^7.28.5",
41
41
  "@cucumber/gherkin": "^37.0.0",
42
42
  "@cucumber/messages": "^31.0.0",
43
- "@sungen/driver-data-factory": "3.3.0-alpha.2",
44
- "@sungen/driver-ui": "3.3.0-alpha.2",
43
+ "@sungen/driver-data-factory": "3.3.0-alpha.3",
44
+ "@sungen/driver-ui": "3.3.0-alpha.3",
45
45
  "chalk": "^5.6.2",
46
46
  "commander": "^14.0.2",
47
47
  "dotenv": "^17.2.3",
@@ -4,6 +4,9 @@
4
4
  * approve --screen <u> [--scenario <id>] [--reason <text>]
5
5
  * a human types a confirmation on a TTY; writes contracts.lock.yaml + a contract-approval
6
6
  * decision. No TTY → refused with the exact command (exit 1).
7
+ * approve --screen <u> --scenario <id> --accept-opaque [--reason <text>]
8
+ * the same human act for the reviewed opaque trace steps of one approved free / impl:code
9
+ * scenario (#923): bound to each step as it reads now (accept-opaque-steps.ts).
7
10
  * check --screen <u> [--trace] [--json]
8
11
  * rebuilds the verdict from .feature + lock + git HEAD + recorded traces (never from a report),
9
12
  * writes .sungen/reports/<slug>-contract.json as output (secret-scanned first). Exit 2 on a hard
@@ -17,6 +20,7 @@ import * as fs from 'fs';
17
20
  import * as path from 'path';
18
21
  import { approveContract } from '../../contract/approve-contract';
19
22
  import { buildContractVerdict, ContractVerdict } from '../../contract/build-contract-verdict';
23
+ import { LOW_IDENTITY_FINDING } from '../../contract/classify-trace-conformance';
20
24
  import { contractReportPath, writeContractReport } from '../../contract/contract-report-file';
21
25
  import { HARD_CLASSES, REVIEW_CLASSES } from '../../contract/contract-schema';
22
26
  import { processIO } from '../../decisions/human-confirmation';
@@ -33,7 +37,13 @@ const MARK: Record<string, string> = {
33
37
  const CHECK_TRACE_BUDGET_MS = 120_000;
34
38
  const UNPROVEN_HINT = " → free / impl:code tests need their own config (outputDir 'test-results-free', trace: 'on', the sungen run-record reporter), then a fresh run (see `sungen contract derive`).";
35
39
 
36
- function printVerdict(v: ContractVerdict, reportFile: string): void {
40
+ /** The command that recompiles a unit's spec — `sungen generate --screen|--flow|--api <unit>`. */
41
+ function generateCommand(unit: { name: string; dir: string }): string {
42
+ const kind = path.relative(path.join(process.cwd(), 'qa'), unit.dir).split(path.sep)[0];
43
+ return `sungen generate --${kind === 'flows' ? 'flow' : kind === 'api' ? 'api' : 'screen'} ${unit.name}`;
44
+ }
45
+
46
+ function printVerdict(v: ContractVerdict, reportFile: string, generate: string): void {
37
47
  const L = console.log;
38
48
  const head = v.verdict === 'pass' ? '✓ PASS' : v.verdict === 'review'
39
49
  ? '⚖ REVIEW — changed, not weaker. Exit 0 here, but review blocks `sungen delivery` until QA re-approves' : '✗ FAIL';
@@ -64,7 +74,19 @@ function printVerdict(v: ContractVerdict, reportFile: string): void {
64
74
  : onlyUnproven ? " → Re-run the free / impl:code tests with trace: 'on', then check again."
65
75
  : ' → Restore the approved checks in the .feature — or, if the change is intended, QA approves it on a terminal:');
66
76
  }
67
- if (v.verdict !== 'pass' && !v.uncommitted.length && !onlyUnproven) L(` sungen contract approve --screen ${v.unit}`);
77
+ // An opaque step is not cleared by re-approving (#923): QA reviews it, then accepts it as it reads now.
78
+ const acceptable = blocking.filter((s) => s.class === 'opaque' && s.trace?.opaque?.some((o) => !o.accepted)
79
+ && !s.findings.some((f) => f.detail.startsWith(LOW_IDENTITY_FINDING)));
80
+ if (v.verdict !== 'pass' && !v.uncommitted.length && !onlyUnproven && acceptable.length < blocking.length) L(` sungen contract approve --screen ${v.unit}`);
81
+ for (const s of acceptable) {
82
+ L(` → ${s.id}: QA reviews each opaque step above (verbatim, file:line); to accept them as they read now, on a terminal:`);
83
+ L(` sungen contract approve --screen ${v.unit} --scenario ${s.id} --accept-opaque`);
84
+ }
85
+ // A weakened compiled scenario also leaves its spec out of step (#943): name the command that fixes the drift.
86
+ // (A free / impl:code scenario carries a trace summary; its test is hand-written, never regenerated.)
87
+ if (v.verdict === 'fail' && !v.uncommitted.length && v.scenarios.some((s) => !s.trace && HARD_CLASSES.has(s.class))) {
88
+ L(` → After fixing the scenario, run \`${generate}\`: until the compiled spec is regenerated, \`sungen script-check\` reports drift.`);
89
+ }
68
90
  L(` Report: ${path.relative(process.cwd(), reportFile)}`);
69
91
  L('');
70
92
  }
@@ -85,11 +107,20 @@ export function registerContractCommand(program: Command): void {
85
107
  .option('-s, --screen <name>', 'Screen / flow / api unit name')
86
108
  .option('--scenario <id>', 'Approve one scenario only (its ID, e.g. VP-LOGIN-001)')
87
109
  .option('--reason <text>', 'Why (recorded in the contract-approval decision)')
110
+ .option('--accept-opaque', 'With --scenario: accept the reviewed opaque trace step(s) of one approved free / impl:code scenario')
88
111
  .action(async (options) => {
89
112
  try {
90
113
  const unit = unitOrThrow(options.screen);
91
- const r = await approveContract({ projectRoot: process.cwd(), unit: unit.name, scenario: options.scenario, reason: options.reason, io: processIO() });
114
+ const r = await approveContract({
115
+ projectRoot: process.cwd(), unit: unit.name, scenario: options.scenario, reason: options.reason, acceptOpaque: options.acceptOpaque === true, io: processIO(),
116
+ });
92
117
  if (r.status === 'nothing-to-approve') { console.log(`\n= Nothing to approve: every chosen scenario of ${unit.name} already matches its approved lock entry.\n`); return; }
118
+ if (r.status === 'nothing-to-accept') { console.log(`\n= Nothing to accept: every opaque step of ${options.scenario} is already accepted as it reads now.\n`); return; }
119
+ if (r.status === 'accepted') {
120
+ console.log(`\n✓ Accepted ${r.accepted?.length ?? 0} opaque step(s) of ${options.scenario} → ${path.relative(process.cwd(), r.lockPath)} (decision ${r.decisionId})`);
121
+ console.log(' Commit the lock and the decision through review, then re-run the free test with its trace: a trace older than the lock proves nothing.\n');
122
+ return;
123
+ }
93
124
  console.log(`\n✓ Approved ${r.approved.length} scenario(s)${r.removed.length ? `, removed ${r.removed.length}` : ''} → ${path.relative(process.cwd(), r.lockPath)} (decision ${r.decisionId})`);
94
125
  console.log(' Commit the lock and the decision through review: until they are in git HEAD, `sungen contract check` reports contract.lock-uncommitted.\n');
95
126
  } catch (error) {
@@ -116,7 +147,7 @@ export function registerContractCommand(program: Command): void {
116
147
  if (hits.length) throw new Error(`Refused to write the contract report — likely secret(s): ${hits.map((h) => `${h.where} ${h.reason}`).join('; ')}`);
117
148
  const file = writeContractReport(process.cwd(), verdict);
118
149
  if (options.json) console.log(JSON.stringify(verdict, null, 2));
119
- else printVerdict(verdict, file);
150
+ else printVerdict(verdict, file, generateCommand(unit));
120
151
  process.exit(verdict.exitCode);
121
152
  } catch (error) {
122
153
  // Unreadable = not run (DOS-14.0): an earlier report must not outlive the inputs it judged.
@@ -0,0 +1,114 @@
1
+ /**
2
+ * `sungen contract approve --screen <u> --scenario <id> --accept-opaque` — a QA accepts the reviewed
3
+ * opaque steps of ONE approved free / impl:code scenario (#923). An opaque step (a check on a JS value,
4
+ * an API request, an evaluate) is never compared by code, so without this an approved test that has one
5
+ * stays in review for good: re-approving changes nothing and contract.opaque-step allows no override.
6
+ * In order, like `approve` (approve-contract.ts), so a human never confirms something then refused:
7
+ *
8
+ * 1. the scenario must be approved AS IT READS NOW — its lock entry human-approved, intact, at the
9
+ * current hash, and vouched for by its decision — else: approve it first
10
+ * 2. its verdict is rebuilt (buildContractVerdict, as `contract check`): the opaque steps must be the
11
+ * ONLY thing holding it; anything else (changed, unproven, inconclusive, a `low` identity…) refuses
12
+ * with its own fix. Every opaque step already accepted → nothing to accept, no prompt
13
+ * 3. each opaque step is shown verbatim with its file:line; on a TTY the human types the scenario id
14
+ * and a one-time code — without one: refused with the exact command (an agent never runs this)
15
+ * 4. everything is read AGAIN: if the trace, the feature or the lock moved meanwhile → refused
16
+ * 5. a contract-approval decision records the scenario at its hash WITH the accepted steps (step + sha)
17
+ * and the lock entry points at it (record-contract-approval.ts)
18
+ *
19
+ * The acceptance is bound to each step's sha (opaqueStepSha): a change to an accepted step, or a new
20
+ * approval of the scenario, brings it back to review.
21
+ *
22
+ * Trust boundary: the TTY confirmation guards this command, not the files. A lock entry AND a matching
23
+ * decision forged together and committed through review are trusted like any approval — git review
24
+ * is that boundary, here as for `approve`.
25
+ */
26
+ import { gitUserName } from '../decisions/decision-source';
27
+ import { formatCommand, requireTypedConfirmation } from '../decisions/human-confirmation';
28
+ import type { ApproveInput, ApproveResult } from './approve-contract';
29
+ import { buildContractVerdict } from './build-contract-verdict';
30
+ import { LOW_IDENTITY_FINDING } from './classify-trace-conformance';
31
+ import { canonicalJson } from './contract-hash';
32
+ import { ContractScenario, isHumanApproved, OpaqueStep } from './contract-schema';
33
+ import { resolveContractUnit } from './contract-units';
34
+ import { lockPathFor, ReadLock, readLockFile } from './contracts-lock-file';
35
+ import { loadContractScenarios } from './normalize-feature-steps';
36
+ import { recordOpaqueAcceptance } from './record-contract-approval';
37
+ import { unverifiedApprovals } from './verify-approval-decisions';
38
+
39
+ /** Accepting reads the traces with `contract check`'s generous deadline, never the guard's ~3 s. */
40
+ const ACCEPT_TRACE_BUDGET_MS = 120_000;
41
+ /** Findings that never hold a scenario back may stand beside the opaque steps. */
42
+ const HARMLESS = new Set(['strengthened', 'nondeterministic']);
43
+
44
+ interface Plan { unitDir: string; unit: string; scenario: ContractScenario; lock: ReadLock; decisionId: string; opaque: OpaqueStep[]; fingerprint: string }
45
+
46
+ const isLow = (detail: string): boolean => detail.startsWith(LOW_IDENTITY_FINDING);
47
+
48
+ function plan(i: ApproveInput, id: string): Plan {
49
+ const unit = resolveContractUnit(i.projectRoot, i.unit);
50
+ const lock = readLockFile(lockPathFor(unit.dir));
51
+ const matches = loadContractScenarios(unit.dir, unit.name).filter((s) => s.id === id);
52
+ if (!matches.length) throw new Error(`--scenario ${id} names no scenario of ${i.unit}`);
53
+ if (matches.length > 1) throw new Error(`Refused: scenario id ${id} is used by ${matches.length} scenarios — an acceptance must name exactly one. Give each its own ID.`);
54
+ const sc = matches[0];
55
+ if (sc.implementation === 'compiled') throw new Error(`Refused: ${id} is compiled — only a free / impl:code test has trace steps to accept.`);
56
+ const entry = lock?.scenarios[id];
57
+ if (!lock || !isHumanApproved(entry) || lock.tampered.includes(id) || entry.hash !== sc.hash) {
58
+ throw new Error(`Refused: ${id} is not approved as it reads now — approve it first (\`sungen contract approve --screen ${i.unit} --scenario ${id}\`), re-run it with a trace, then accept its opaque steps.`);
59
+ }
60
+ // The entry an acceptance re-points must be QA's own: its decision (on disk) vouches for it as it is.
61
+ const [unvouched] = unverifiedApprovals(i.projectRoot, unit.dir, { schema: lock.schema, scenarios: { [id]: entry } }, new Set(), { root: i.projectRoot, timeoutMs: 0, blobs: null });
62
+ if (unvouched) throw new Error(`Refused: the lock entry of ${id} is not vouched for by its decision (${unvouched.detail}) — restore the lock from git, or approve the scenario again.`);
63
+
64
+ const v = buildContractVerdict(i.projectRoot, unit, { traceBudgetMs: ACCEPT_TRACE_BUDGET_MS });
65
+ const bad = v.uncommitted.find((u) => u.id === id && (u.change === 'tampered' || u.change === 'unverified'));
66
+ if (bad) throw new Error(`Refused: the lock entry of ${id} is ${bad.change} (${bad.detail}) — restore it from git before accepting anything.`);
67
+ const r = v.scenarios.find((s) => s.id === id);
68
+ const blocking = (r?.findings ?? []).filter((f) => !HARMLESS.has(f.class) && !(f.class === 'opaque' && !isLow(f.detail)));
69
+ if (blocking.length) {
70
+ const fix = blocking.some((f) => isLow(f.detail))
71
+ ? `run \`sungen contract check --screen ${i.unit} --trace\` (a real browser resolves the identity) first`
72
+ : `settle that first — \`sungen contract check --screen ${i.unit}\` names the fix`;
73
+ throw new Error(`Refused: accepting clears only opaque steps, and ${id} is also held by: ${blocking.map((f) => `${f.class}${f.step ? ` (step ${f.step})` : ''} — ${f.detail}`).join('; ')}. ${fix[0].toUpperCase()}${fix.slice(1)}.`);
74
+ }
75
+ const opaque = r?.trace?.opaque ?? [];
76
+ if (!opaque.length) throw new Error(`Refused: the trace of ${id} has no opaque step — nothing to accept (${r?.class ?? 'not judged'}).`);
77
+ return { unitDir: unit.dir, unit: unit.name, scenario: sc, lock, decisionId: entry.decisionId, opaque, fingerprint: canonicalJson({ lock, hash: sc.hash, opaque }) };
78
+ }
79
+
80
+ const describe = (o: OpaqueStep): string =>
81
+ `${o.accepted ? '=' : '◐'} step ${o.step} opaque ${o.kind === 'assert' ? 'check' : 'step'} "${o.verbatim}"${o.where ? ` at ${o.where}` : ''}`
82
+ + `${o.replaces ? ` — replaces approved ${o.replaces}` : ''}${o.accepted ? ' (accepted before)' : ''}`;
83
+
84
+ export async function acceptOpaqueSteps(i: ApproveInput): Promise<ApproveResult> {
85
+ const id = i.scenario;
86
+ if (!id) throw new Error('--accept-opaque needs --scenario <id>: an acceptance names the one scenario whose opaque steps QA reviewed');
87
+ const before = plan(i, id);
88
+ const lockPath = lockPathFor(before.unitDir);
89
+ if (before.opaque.every((o) => o.accepted)) return { status: 'nothing-to-accept', lockPath, approved: [], removed: [] };
90
+
91
+ const pending = before.opaque.filter((o) => !o.accepted);
92
+ await requireTypedConfirmation({
93
+ what: `accept ${pending.length} reviewed opaque step(s) of ${id} (${i.unit}) — steps sungen cannot compare, so they are never checked by code`,
94
+ phrase: id,
95
+ command: formatCommand(['sungen', 'contract', 'approve', '--screen', i.unit, '--scenario', id, '--accept-opaque', ...(i.reason ? ['--reason', i.reason] : [])]),
96
+ summary: [
97
+ ...before.opaque.map(describe),
98
+ `bound to each step as it reads now: a change to it, or a new approval of ${id}, brings it back to review`,
99
+ `${id} stays approved at hash ${before.scenario.hash}; its lock entry moves from decision ${before.decisionId} to the new one`,
100
+ `recorded by: ${gitUserName(i.projectRoot)}`,
101
+ ],
102
+ io: i.io,
103
+ });
104
+
105
+ const after = plan(i, id);
106
+ if (after.fingerprint !== before.fingerprint) {
107
+ throw new Error('Refused: the trace, the feature or the lock changed while you were confirming — nothing was written. Run the command again and review the new summary.');
108
+ }
109
+ const { decisionId } = recordOpaqueAcceptance({
110
+ projectRoot: i.projectRoot, unitDir: after.unitDir, unit: after.unit, scenario: after.scenario, reason: i.reason, lock: after.lock,
111
+ accepted: after.opaque.map((o) => ({ step: o.step, sha: o.sha })),
112
+ });
113
+ return { status: 'accepted', lockPath, decisionId, approved: [id], removed: [], accepted: after.opaque };
114
+ }
@@ -11,25 +11,31 @@
11
11
  * 5. read everything AGAIN: if the feature or the lock moved while the human was reading, what
12
12
  * they confirmed is not what would be written — refuse (L5)
13
13
  * 6. record the decision and the lock (record-contract-approval.ts)
14
+ *
15
+ * `--accept-opaque` (with `--scenario`) is the other human act of this command: accepting the reviewed
16
+ * opaque trace steps of one approved free / impl:code scenario — accept-opaque-steps.ts (#923).
14
17
  */
15
18
  import { ConfirmationIO, formatCommand, requireTypedConfirmation } from '../decisions/human-confirmation';
16
19
  import { gitUserName } from '../decisions/decision-source';
17
20
  import { classifyScenario } from './classify-contract-change';
18
21
  import { canonicalJson } from './contract-hash';
19
- import { ContractScenario, isHumanApproved } from './contract-schema';
22
+ import { acceptOpaqueSteps } from './accept-opaque-steps';
23
+ import { ContractScenario, isHumanApproved, OpaqueStep } from './contract-schema';
20
24
  import { resolveContractUnit } from './contract-units';
21
25
  import { lockPathFor, ReadLock, readLockFile } from './contracts-lock-file';
22
26
  import { dropProposedTags } from './free-feature-blocks';
23
27
  import { contractFeatureFiles, loadContractScenarios } from './normalize-feature-steps';
24
28
  import { ApprovalWrite, checkApprovalSecrets, recordContractApproval } from './record-contract-approval';
25
29
 
26
- export interface ApproveInput { projectRoot: string; unit: string; scenario?: string; reason?: string; io: ConfirmationIO }
30
+ export interface ApproveInput { projectRoot: string; unit: string; scenario?: string; reason?: string; io: ConfirmationIO; acceptOpaque?: boolean }
27
31
  export interface ApproveResult {
28
- status: 'approved' | 'nothing-to-approve';
32
+ status: 'approved' | 'nothing-to-approve' | 'accepted' | 'nothing-to-accept';
29
33
  lockPath: string;
30
34
  decisionId?: string;
31
35
  approved: string[];
32
36
  removed: string[];
37
+ /** `--accept-opaque`: the scenario's opaque steps, all accepted by the new decision. */
38
+ accepted?: OpaqueStep[];
33
39
  }
34
40
 
35
41
  interface Plan { write: ApprovalWrite; lock: ReadLock | null; fingerprint: string }
@@ -62,6 +68,7 @@ function describe(sc: ContractScenario, lock: ReadLock | null): string {
62
68
  }
63
69
 
64
70
  export async function approveContract(i: ApproveInput): Promise<ApproveResult> {
71
+ if (i.acceptOpaque) return acceptOpaqueSteps(i);
65
72
  const before = plan(i);
66
73
  const { approve, removed } = before.write;
67
74
  const lockPath = lockPathFor(before.write.unitDir);
@@ -9,7 +9,7 @@
9
9
  * (added · changed · removed vs HEAD, tampered, unverified), or an APPROVED free /
10
10
  * impl:code scenario with no admissible trace (unproven, also past the deadline) exit 2
11
11
  * review any hash-changed (changed, not weaker — QA re-approves), opaque (a check no code
12
- * can compare, or a target identity that is only `low`), or inconclusive (an
12
+ * can compare and QA has not accepted, or a target identity that is only `low`), or inconclusive (an
13
13
  * approved free scenario's final attempt did not pass); blocks delivery exit 0
14
14
  * pass only match / strengthened / proposed / nondeterministic exit 0
15
15
  *
@@ -64,7 +64,7 @@ function withTrace(results: ScenarioResult[], outcomes: Map<string, TraceOutcome
64
64
  const o = outcomes.get(r.id);
65
65
  if (!o) return r;
66
66
  const cls = severityOf(o.class) > severityOf(r.class) ? o.class : r.class;
67
- return { ...r, class: cls, findings: [...r.findings, ...o.findings], trace: { hashes: o.hashes, runs: o.runs } };
67
+ return { ...r, class: cls, findings: [...r.findings, ...o.findings], trace: { hashes: o.hashes, runs: o.runs, ...(o.opaque.length ? { opaque: o.opaque } : {}) } };
68
68
  });
69
69
  }
70
70
 
@@ -38,11 +38,16 @@ const sha = (s: string | Buffer): string => createHash('sha256').update(s).diges
38
38
  const why = (e: unknown): string => (e instanceof Error ? e.message : String(e)).split('\n')[0].slice(0, 300);
39
39
 
40
40
  export const MOBILE_NOT_SUPPORTED = 'trace conformance is web-only: free / impl:code scenarios of a mobile project are not supported yet (not judged)';
41
- /** The guard path's deadline for the trace part of one unit's verdict (override: SUNGEN_TRACE_VERDICT_BUDGET_MS). */
41
+ /** The Claude Code guard's deadline for the trace part of one unit's verdict (its hook has ~5 s in all). */
42
+ export const GUARD_TRACE_BUDGET_MS = 3_000;
43
+ /** The default deadline (`next`, the guard) — override: SUNGEN_TRACE_VERDICT_BUDGET_MS. */
42
44
  export function defaultTraceBudgetMs(env: Record<string, string | undefined> = process.env): number {
43
45
  const v = Number(env.SUNGEN_TRACE_VERDICT_BUDGET_MS);
44
- return Number.isFinite(v) && v > 0 ? v : 3_000;
46
+ return Number.isFinite(v) && v > 0 ? v : GUARD_TRACE_BUDGET_MS;
45
47
  }
48
+ /** Inside the guard path the override may only SHORTEN the deadline (#926): the hook cannot wait longer. */
49
+ export const guardTraceBudgetMs = (env: Record<string, string | undefined> = process.env): number =>
50
+ Math.min(defaultTraceBudgetMs(env), GUARD_TRACE_BUDGET_MS);
46
51
 
47
52
  export function traceConformanceForUnit(
48
53
  projectRoot: string, unit: { name: string; dir: string }, current: ContractScenario[], lock: ContractLock | null,
@@ -61,7 +66,7 @@ export function traceConformanceForUnit(
61
66
  let setupError = '';
62
67
  try {
63
68
  const notBefore = Math.max(mtimeMs(lockPathFor(unit.dir)), ...contractFeatureFiles(unit.dir, unit.name).map(mtimeMs));
64
- evidence = collectScenarioEvidence(projectRoot, new Set(traced.map((s) => s.id)), notBefore, deadline);
69
+ evidence = collectScenarioEvidence(projectRoot, new Set(traced.map((s) => s.id)), notBefore, deadline, new Map(traced.map((s) => [s.id, s.source.name])));
65
70
  index = loadTestDataIndex(unit.dir, unit.name);
66
71
  } catch (e) { setupError = `trace conformance could not run: ${why(e)}`; }
67
72
  const { cache, problem } = readIdentityCache(projectRoot);
@@ -14,12 +14,12 @@
14
14
  * still `hash-changed`: equal hashes are the only road to `match`.
15
15
  */
16
16
  import { sameJson } from './contract-hash';
17
- import { ContractScenario, ContractStep, FindingClass, LadderClass, LockEntry, RULE_OF, ScenarioClass, TraceClass } from './contract-schema';
17
+ import { ContractScenario, ContractStep, FindingClass, LadderClass, LockEntry, OpaqueStep, RULE_OF, ScenarioClass, TraceClass } from './contract-schema';
18
18
  import { compareAsserts } from './oracle-strength';
19
19
 
20
20
  export interface ContractFinding { class: FindingClass; rule?: string; detail: string; step?: number }
21
- /** What a free / impl:code scenario's traces fingerprinted to (DOS-14.6) — output only. */
22
- export interface TraceSummary { hashes: string[]; runs: string[] }
21
+ /** What a free / impl:code scenario's traces fingerprinted to (DOS-14.6), and their opaque steps (#923) — output only. */
22
+ export interface TraceSummary { hashes: string[]; runs: string[]; opaque?: OpaqueStep[] }
23
23
  export interface ScenarioResult { id: string; class: ScenarioClass; findings: ContractFinding[]; file?: string; trace?: TraceSummary }
24
24
 
25
25
  const SEVERITY: Record<ScenarioClass, number> = {