@sun-asterisk/sungen 3.2.34 → 3.3.0-alpha.2
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/dist/basis/anchor-grammar.d.ts +32 -0
- package/dist/basis/anchor-grammar.d.ts.map +1 -0
- package/dist/basis/anchor-grammar.js +82 -0
- package/dist/basis/anchor-grammar.js.map +1 -0
- package/dist/basis/anchor-hash.d.ts +6 -0
- package/dist/basis/anchor-hash.d.ts.map +1 -0
- package/dist/basis/anchor-hash.js +28 -0
- package/dist/basis/anchor-hash.js.map +1 -0
- package/dist/basis/bm51-tables.d.ts +20 -0
- package/dist/basis/bm51-tables.d.ts.map +1 -0
- package/dist/basis/bm51-tables.js +71 -0
- package/dist/basis/bm51-tables.js.map +1 -0
- package/dist/basis/extract-spec-anchors.d.ts +39 -0
- package/dist/basis/extract-spec-anchors.d.ts.map +1 -0
- package/dist/basis/extract-spec-anchors.js +81 -0
- package/dist/basis/extract-spec-anchors.js.map +1 -0
- package/dist/basis/migration-sentinel.d.ts +47 -0
- package/dist/basis/migration-sentinel.d.ts.map +1 -0
- package/dist/basis/migration-sentinel.js +219 -0
- package/dist/basis/migration-sentinel.js.map +1 -0
- package/dist/basis/spec-frontmatter.d.ts +18 -0
- package/dist/basis/spec-frontmatter.d.ts.map +1 -0
- package/dist/basis/spec-frontmatter.js +55 -0
- package/dist/basis/spec-frontmatter.js.map +1 -0
- package/dist/basis/spec-sections.d.ts +18 -0
- package/dist/basis/spec-sections.d.ts.map +1 -0
- package/dist/basis/spec-sections.js +27 -0
- package/dist/basis/spec-sections.js.map +1 -0
- package/dist/basis/test-basis-schema.d.ts +28 -0
- package/dist/basis/test-basis-schema.d.ts.map +1 -0
- package/dist/basis/test-basis-schema.js +141 -0
- package/dist/basis/test-basis-schema.js.map +1 -0
- package/dist/capabilities/discover.d.ts +4 -0
- package/dist/capabilities/discover.d.ts.map +1 -1
- package/dist/capabilities/discover.js +16 -2
- package/dist/capabilities/discover.js.map +1 -1
- package/dist/capabilities/registry.d.ts +15 -0
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +10 -5
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.d.ts.map +1 -1
- package/dist/cli/commands/capability.js +6 -2
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/contract-derive-command.d.ts +11 -0
- package/dist/cli/commands/contract-derive-command.d.ts.map +1 -0
- package/dist/cli/commands/contract-derive-command.js +99 -0
- package/dist/cli/commands/contract-derive-command.js.map +1 -0
- package/dist/cli/commands/contract.d.ts +17 -0
- package/dist/cli/commands/contract.d.ts.map +1 -0
- package/dist/cli/commands/contract.js +162 -0
- package/dist/cli/commands/contract.js.map +1 -0
- package/dist/cli/commands/defect.d.ts +7 -0
- package/dist/cli/commands/defect.d.ts.map +1 -0
- package/dist/cli/commands/defect.js +68 -0
- package/dist/cli/commands/defect.js.map +1 -0
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +96 -12
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +3 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/journey.d.ts.map +1 -1
- package/dist/cli/commands/journey.js +43 -15
- package/dist/cli/commands/journey.js.map +1 -1
- package/dist/cli/commands/next.d.ts +8 -0
- package/dist/cli/commands/next.d.ts.map +1 -1
- package/dist/cli/commands/next.js +68 -8
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/triage.d.ts +7 -0
- package/dist/cli/commands/triage.d.ts.map +1 -0
- package/dist/cli/commands/triage.js +98 -0
- package/dist/cli/commands/triage.js.map +1 -0
- package/dist/cli/commands/update.d.ts +11 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +31 -6
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.js +24 -33
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/project-sungen-invocation.d.ts +7 -0
- package/dist/cli/project-sungen-invocation.d.ts.map +1 -0
- package/dist/cli/project-sungen-invocation.js +76 -0
- package/dist/cli/project-sungen-invocation.js.map +1 -0
- package/dist/contract/approve-contract.d.ts +31 -0
- package/dist/contract/approve-contract.d.ts.map +1 -0
- package/dist/contract/approve-contract.js +87 -0
- package/dist/contract/approve-contract.js.map +1 -0
- package/dist/contract/assertion-matcher-vocabulary.d.ts +24 -0
- package/dist/contract/assertion-matcher-vocabulary.d.ts.map +1 -0
- package/dist/contract/assertion-matcher-vocabulary.js +100 -0
- package/dist/contract/assertion-matcher-vocabulary.js.map +1 -0
- package/dist/contract/build-contract-verdict.d.ts +32 -0
- package/dist/contract/build-contract-verdict.d.ts.map +1 -0
- package/dist/contract/build-contract-verdict.js +123 -0
- package/dist/contract/build-contract-verdict.js.map +1 -0
- package/dist/contract/build-trace-conformance.d.ts +18 -0
- package/dist/contract/build-trace-conformance.d.ts.map +1 -0
- package/dist/contract/build-trace-conformance.js +153 -0
- package/dist/contract/build-trace-conformance.js.map +1 -0
- package/dist/contract/classify-contract-change.d.ts +23 -0
- package/dist/contract/classify-contract-change.d.ts.map +1 -0
- package/dist/contract/classify-contract-change.js +98 -0
- package/dist/contract/classify-contract-change.js.map +1 -0
- package/dist/contract/classify-contract-unit.d.ts +18 -0
- package/dist/contract/classify-contract-unit.d.ts.map +1 -0
- package/dist/contract/classify-contract-unit.js +49 -0
- package/dist/contract/classify-contract-unit.js.map +1 -0
- package/dist/contract/classify-trace-conformance.d.ts +32 -0
- package/dist/contract/classify-trace-conformance.d.ts.map +1 -0
- package/dist/contract/classify-trace-conformance.js +117 -0
- package/dist/contract/classify-trace-conformance.js.map +1 -0
- package/dist/contract/contract-git.d.ts +24 -0
- package/dist/contract/contract-git.d.ts.map +1 -0
- package/dist/contract/contract-git.js +144 -0
- package/dist/contract/contract-git.js.map +1 -0
- package/dist/contract/contract-hash.d.ts +7 -0
- package/dist/contract/contract-hash.d.ts.map +1 -0
- package/dist/contract/contract-hash.js +38 -0
- package/dist/contract/contract-hash.js.map +1 -0
- package/dist/contract/contract-report-file.d.ts +4 -0
- package/dist/contract/contract-report-file.d.ts.map +1 -0
- package/dist/contract/contract-report-file.js +60 -0
- package/dist/contract/contract-report-file.js.map +1 -0
- package/dist/contract/contract-schema.d.ts +71 -0
- package/dist/contract/contract-schema.d.ts.map +1 -0
- package/dist/contract/contract-schema.js +102 -0
- package/dist/contract/contract-schema.js.map +1 -0
- package/dist/contract/contract-units.d.ts +12 -0
- package/dist/contract/contract-units.d.ts.map +1 -0
- package/dist/contract/contract-units.js +96 -0
- package/dist/contract/contract-units.js.map +1 -0
- package/dist/contract/contracts-lock-file.d.ts +24 -0
- package/dist/contract/contracts-lock-file.d.ts.map +1 -0
- package/dist/contract/contracts-lock-file.js +140 -0
- package/dist/contract/contracts-lock-file.js.map +1 -0
- package/dist/contract/data-normalize.d.ts +10 -0
- package/dist/contract/data-normalize.d.ts.map +1 -0
- package/dist/contract/data-normalize.js +110 -0
- package/dist/contract/data-normalize.js.map +1 -0
- package/dist/contract/derive-free-feature.d.ts +38 -0
- package/dist/contract/derive-free-feature.d.ts.map +1 -0
- package/dist/contract/derive-free-feature.js +154 -0
- package/dist/contract/derive-free-feature.js.map +1 -0
- package/dist/contract/field-semantic-redaction.d.ts +21 -0
- package/dist/contract/field-semantic-redaction.d.ts.map +1 -0
- package/dist/contract/field-semantic-redaction.js +118 -0
- package/dist/contract/field-semantic-redaction.js.map +1 -0
- package/dist/contract/free-feature-blocks.d.ts +10 -0
- package/dist/contract/free-feature-blocks.d.ts.map +1 -0
- package/dist/contract/free-feature-blocks.js +94 -0
- package/dist/contract/free-feature-blocks.js.map +1 -0
- package/dist/contract/lock-secret-guard.d.ts +22 -0
- package/dist/contract/lock-secret-guard.d.ts.map +1 -0
- package/dist/contract/lock-secret-guard.js +134 -0
- package/dist/contract/lock-secret-guard.js.map +1 -0
- package/dist/contract/lock-vs-git-head.d.ts +26 -0
- package/dist/contract/lock-vs-git-head.d.ts.map +1 -0
- package/dist/contract/lock-vs-git-head.js +28 -0
- package/dist/contract/lock-vs-git-head.js.map +1 -0
- package/dist/contract/normalize-contract-step.d.ts +21 -0
- package/dist/contract/normalize-contract-step.d.ts.map +1 -0
- package/dist/contract/normalize-contract-step.js +70 -0
- package/dist/contract/normalize-contract-step.js.map +1 -0
- package/dist/contract/normalize-feature-steps.d.ts +7 -0
- package/dist/contract/normalize-feature-steps.d.ts.map +1 -0
- package/dist/contract/normalize-feature-steps.js +127 -0
- package/dist/contract/normalize-feature-steps.js.map +1 -0
- package/dist/contract/oracle-strength.d.ts +12 -0
- package/dist/contract/oracle-strength.d.ts.map +1 -0
- package/dist/contract/oracle-strength.js +88 -0
- package/dist/contract/oracle-strength.js.map +1 -0
- package/dist/contract/project-contract-blockers.d.ts +10 -0
- package/dist/contract/project-contract-blockers.d.ts.map +1 -0
- package/dist/contract/project-contract-blockers.js +73 -0
- package/dist/contract/project-contract-blockers.js.map +1 -0
- package/dist/contract/record-contract-approval.d.ts +21 -0
- package/dist/contract/record-contract-approval.d.ts.map +1 -0
- package/dist/contract/record-contract-approval.js +98 -0
- package/dist/contract/record-contract-approval.js.map +1 -0
- package/dist/contract/render-free-gherkin.d.ts +40 -0
- package/dist/contract/render-free-gherkin.d.ts.map +1 -0
- package/dist/contract/render-free-gherkin.js +141 -0
- package/dist/contract/render-free-gherkin.js.map +1 -0
- package/dist/contract/render-trace-sentence.d.ts +20 -0
- package/dist/contract/render-trace-sentence.d.ts.map +1 -0
- package/dist/contract/render-trace-sentence.js +109 -0
- package/dist/contract/render-trace-sentence.js.map +1 -0
- package/dist/contract/render-trace-target.d.ts +14 -0
- package/dist/contract/render-trace-target.d.ts.map +1 -0
- package/dist/contract/render-trace-target.js +70 -0
- package/dist/contract/render-trace-target.js.map +1 -0
- package/dist/contract/resolve-unit-trace-identities.d.ts +8 -0
- package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -0
- package/dist/contract/resolve-unit-trace-identities.js +78 -0
- package/dist/contract/resolve-unit-trace-identities.js.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts +33 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.js +161 -0
- package/dist/contract/trace/collect-trace-evidence.js.map +1 -0
- package/dist/contract/trace/identity-cache.d.ts +19 -0
- package/dist/contract/trace/identity-cache.d.ts.map +1 -0
- package/dist/contract/trace/identity-cache.js +104 -0
- package/dist/contract/trace/identity-cache.js.map +1 -0
- package/dist/contract/trace/select-final-attempt.d.ts +27 -0
- package/dist/contract/trace/select-final-attempt.d.ts.map +1 -0
- package/dist/contract/trace/select-final-attempt.js +116 -0
- package/dist/contract/trace/select-final-attempt.js.map +1 -0
- package/dist/contract/trace/snapshot-html-renderer.d.ts +31 -0
- package/dist/contract/trace/snapshot-html-renderer.d.ts.map +1 -0
- package/dist/contract/trace/snapshot-html-renderer.js +172 -0
- package/dist/contract/trace/snapshot-html-renderer.js.map +1 -0
- package/dist/contract/trace/snapshot-resolver.d.ts +21 -0
- package/dist/contract/trace/snapshot-resolver.d.ts.map +1 -0
- package/dist/contract/trace/snapshot-resolver.js +65 -0
- package/dist/contract/trace/snapshot-resolver.js.map +1 -0
- package/dist/contract/trace/snapshot-store.d.ts +66 -0
- package/dist/contract/trace/snapshot-store.d.ts.map +1 -0
- package/dist/contract/trace/snapshot-store.js +173 -0
- package/dist/contract/trace/snapshot-store.js.map +1 -0
- package/dist/contract/trace/target-identity.d.ts +74 -0
- package/dist/contract/trace/target-identity.d.ts.map +1 -0
- package/dist/contract/trace/target-identity.js +68 -0
- package/dist/contract/trace/target-identity.js.map +1 -0
- package/dist/contract/trace/test-step-join.d.ts +65 -0
- package/dist/contract/trace/test-step-join.d.ts.map +1 -0
- package/dist/contract/trace/test-step-join.js +80 -0
- package/dist/contract/trace/test-step-join.js.map +1 -0
- package/dist/contract/trace/trace-binding.d.ts +21 -0
- package/dist/contract/trace/trace-binding.d.ts.map +1 -0
- package/dist/contract/trace/trace-binding.js +88 -0
- package/dist/contract/trace/trace-binding.js.map +1 -0
- package/dist/contract/trace/trace-file-reader.d.ts +41 -0
- package/dist/contract/trace/trace-file-reader.d.ts.map +1 -0
- package/dist/contract/trace/trace-file-reader.js +161 -0
- package/dist/contract/trace/trace-file-reader.js.map +1 -0
- package/dist/contract/trace/trace-fingerprint.d.ts +22 -0
- package/dist/contract/trace/trace-fingerprint.d.ts.map +1 -0
- package/dist/contract/trace/trace-fingerprint.js +96 -0
- package/dist/contract/trace/trace-fingerprint.js.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts +26 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.js +84 -0
- package/dist/contract/trace/trace-identity-resolution.js.map +1 -0
- package/dist/contract/trace/trace-run-record.d.ts +30 -0
- package/dist/contract/trace/trace-run-record.d.ts.map +1 -0
- package/dist/contract/trace/trace-run-record.js +121 -0
- package/dist/contract/trace/trace-run-record.js.map +1 -0
- package/dist/contract/trace/trace-steps.d.ts +19 -0
- package/dist/contract/trace/trace-steps.d.ts.map +1 -0
- package/dist/contract/trace/trace-steps.js +79 -0
- package/dist/contract/trace/trace-steps.js.map +1 -0
- package/dist/contract/trace/trace-zip-limits.d.ts +45 -0
- package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -0
- package/dist/contract/trace/trace-zip-limits.js +52 -0
- package/dist/contract/trace/trace-zip-limits.js.map +1 -0
- package/dist/contract/trace/trace-zip-reader.d.ts +10 -0
- package/dist/contract/trace/trace-zip-reader.d.ts.map +1 -0
- package/dist/contract/trace/trace-zip-reader.js +186 -0
- package/dist/contract/trace/trace-zip-reader.js.map +1 -0
- package/dist/contract/verify-approval-decisions.d.ts +5 -0
- package/dist/contract/verify-approval-decisions.d.ts.map +1 -0
- package/dist/contract/verify-approval-decisions.js +104 -0
- package/dist/contract/verify-approval-decisions.js.map +1 -0
- package/dist/decisions/append-decision.d.ts +12 -0
- package/dist/decisions/append-decision.d.ts.map +1 -0
- package/dist/decisions/append-decision.js +73 -0
- package/dist/decisions/append-decision.js.map +1 -0
- package/dist/decisions/confirmed-decision-commands.d.ts +41 -0
- package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -0
- package/dist/decisions/confirmed-decision-commands.js +190 -0
- package/dist/decisions/confirmed-decision-commands.js.map +1 -0
- package/dist/decisions/decision-file.d.ts +31 -0
- package/dist/decisions/decision-file.d.ts.map +1 -0
- package/dist/decisions/decision-file.js +139 -0
- package/dist/decisions/decision-file.js.map +1 -0
- package/dist/decisions/decision-identity.d.ts +12 -0
- package/dist/decisions/decision-identity.d.ts.map +1 -0
- package/dist/decisions/decision-identity.js +78 -0
- package/dist/decisions/decision-identity.js.map +1 -0
- package/dist/decisions/decision-integrity-check.d.ts +12 -0
- package/dist/decisions/decision-integrity-check.d.ts.map +1 -0
- package/dist/decisions/decision-integrity-check.js +102 -0
- package/dist/decisions/decision-integrity-check.js.map +1 -0
- package/dist/decisions/decision-schema.d.ts +42 -0
- package/dist/decisions/decision-schema.d.ts.map +1 -0
- package/dist/decisions/decision-schema.js +75 -0
- package/dist/decisions/decision-schema.js.map +1 -0
- package/dist/decisions/decision-source.d.ts +2 -0
- package/dist/decisions/decision-source.d.ts.map +1 -0
- package/dist/decisions/decision-source.js +18 -0
- package/dist/decisions/decision-source.js.map +1 -0
- package/dist/decisions/exclusive-file-create.d.ts +3 -0
- package/dist/decisions/exclusive-file-create.d.ts.map +1 -0
- package/dist/decisions/exclusive-file-create.js +84 -0
- package/dist/decisions/exclusive-file-create.js.map +1 -0
- package/dist/decisions/git-head-trust.d.ts +7 -0
- package/dist/decisions/git-head-trust.d.ts.map +1 -0
- package/dist/decisions/git-head-trust.js +76 -0
- package/dist/decisions/git-head-trust.js.map +1 -0
- package/dist/decisions/human-confirmation.d.ts +35 -0
- package/dist/decisions/human-confirmation.d.ts.map +1 -0
- package/dist/decisions/human-confirmation.js +161 -0
- package/dist/decisions/human-confirmation.js.map +1 -0
- package/dist/decisions/legacy-waiver-migration.d.ts +31 -0
- package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -0
- package/dist/decisions/legacy-waiver-migration.js +170 -0
- package/dist/decisions/legacy-waiver-migration.js.map +1 -0
- package/dist/decisions/read-decisions.d.ts +19 -0
- package/dist/decisions/read-decisions.d.ts.map +1 -0
- package/dist/decisions/read-decisions.js +90 -0
- package/dist/decisions/read-decisions.js.map +1 -0
- package/dist/decisions/viewpoint-baseline-adapter.d.ts +7 -0
- package/dist/decisions/viewpoint-baseline-adapter.d.ts.map +1 -0
- package/dist/decisions/viewpoint-baseline-adapter.js +109 -0
- package/dist/decisions/viewpoint-baseline-adapter.js.map +1 -0
- package/dist/decisions/waiver-decisions.d.ts +24 -0
- package/dist/decisions/waiver-decisions.d.ts.map +1 -0
- package/dist/decisions/waiver-decisions.js +46 -0
- package/dist/decisions/waiver-decisions.js.map +1 -0
- package/dist/exporters/csv-exporter.d.ts +4 -0
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +1 -1
- package/dist/exporters/csv-exporter.js.map +1 -1
- package/dist/exporters/feature-parser.d.ts +8 -0
- package/dist/exporters/feature-parser.d.ts.map +1 -1
- package/dist/exporters/feature-parser.js +12 -0
- package/dist/exporters/feature-parser.js.map +1 -1
- package/dist/exporters/matrix/build.d.ts +3 -0
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +59 -19
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/carry-manual-results.d.ts +19 -0
- package/dist/exporters/matrix/carry-manual-results.d.ts.map +1 -1
- package/dist/exporters/matrix/carry-manual-results.js +76 -6
- package/dist/exporters/matrix/carry-manual-results.js.map +1 -1
- package/dist/exporters/matrix/export.d.ts +8 -2
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +16 -3
- package/dist/exporters/matrix/export.js.map +1 -1
- package/dist/exporters/matrix/gates.d.ts +6 -1
- package/dist/exporters/matrix/gates.d.ts.map +1 -1
- package/dist/exporters/matrix/gates.js +57 -128
- package/dist/exporters/matrix/gates.js.map +1 -1
- package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
- package/dist/exporters/matrix/render-csv.js +4 -1
- package/dist/exporters/matrix/render-csv.js.map +1 -1
- package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts +13 -0
- package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-gate-overrides-sheet.js +44 -0
- package/dist/exporters/matrix/render-gate-overrides-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
- package/dist/exporters/matrix/render-xlsx.js +6 -0
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +9 -1
- package/dist/exporters/matrix/types.d.ts.map +1 -1
- package/dist/exporters/matrix/types.js.map +1 -1
- package/dist/exporters/matrix/xlsx-cells.js +1 -1
- package/dist/exporters/matrix/xlsx-cells.js.map +1 -1
- package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
- package/dist/exporters/playwright-report-parser.js +1 -0
- package/dist/exporters/playwright-report-parser.js.map +1 -1
- package/dist/exporters/scenario-merger.d.ts.map +1 -1
- package/dist/exporters/scenario-merger.js +2 -0
- package/dist/exporters/scenario-merger.js.map +1 -1
- package/dist/exporters/types.d.ts +5 -0
- package/dist/exporters/types.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +13 -0
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/graph/evaluate-graph.d.ts +23 -0
- package/dist/graph/evaluate-graph.d.ts.map +1 -0
- package/dist/graph/evaluate-graph.js +52 -0
- package/dist/graph/evaluate-graph.js.map +1 -0
- package/dist/graph/locate-finding.d.ts +20 -0
- package/dist/graph/locate-finding.d.ts.map +1 -0
- package/dist/graph/locate-finding.js +137 -0
- package/dist/graph/locate-finding.js.map +1 -0
- package/dist/graph/node-decl.d.ts +66 -0
- package/dist/graph/node-decl.d.ts.map +1 -0
- package/dist/graph/node-decl.js +8 -0
- package/dist/graph/node-decl.js.map +1 -0
- package/dist/graph/nodes/core-node-catalog.d.ts +7 -0
- package/dist/graph/nodes/core-node-catalog.d.ts.map +1 -0
- package/dist/graph/nodes/core-node-catalog.js +13 -0
- package/dist/graph/nodes/core-node-catalog.js.map +1 -0
- package/dist/graph/nodes/test-case-contract-nodes.d.ts +21 -0
- package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/test-case-contract-nodes.js +59 -0
- package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -0
- package/dist/graph/nodes/test-case-nodes.d.ts +26 -0
- package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/test-case-nodes.js +66 -0
- package/dist/graph/nodes/test-case-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-audit-nodes.d.ts +18 -0
- package/dist/graph/nodes/unit-audit-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/unit-audit-nodes.js +95 -0
- package/dist/graph/nodes/unit-audit-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-contract-node.d.ts +21 -0
- package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -0
- package/dist/graph/nodes/unit-contract-node.js +88 -0
- package/dist/graph/nodes/unit-contract-node.js.map +1 -0
- package/dist/graph/nodes/unit-design-nodes.d.ts +14 -0
- package/dist/graph/nodes/unit-design-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/unit-design-nodes.js +91 -0
- package/dist/graph/nodes/unit-design-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-execution-nodes.d.ts +16 -0
- package/dist/graph/nodes/unit-execution-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/unit-execution-nodes.js +79 -0
- package/dist/graph/nodes/unit-execution-nodes.js.map +1 -0
- package/dist/graph/test-case-identity.d.ts +13 -0
- package/dist/graph/test-case-identity.d.ts.map +1 -0
- package/dist/graph/test-case-identity.js +106 -0
- package/dist/graph/test-case-identity.js.map +1 -0
- package/dist/graph/test-case-results.d.ts +11 -0
- package/dist/graph/test-case-results.d.ts.map +1 -0
- package/dist/graph/test-case-results.js +137 -0
- package/dist/graph/test-case-results.js.map +1 -0
- package/dist/graph/test-case-satisfied.d.ts +25 -0
- package/dist/graph/test-case-satisfied.d.ts.map +1 -0
- package/dist/graph/test-case-satisfied.js +51 -0
- package/dist/graph/test-case-satisfied.js.map +1 -0
- package/dist/graph/test-case-state-shape.d.ts +67 -0
- package/dist/graph/test-case-state-shape.d.ts.map +1 -0
- package/dist/graph/test-case-state-shape.js +3 -0
- package/dist/graph/test-case-state-shape.js.map +1 -0
- package/dist/graph/test-case-states.d.ts +9 -0
- package/dist/graph/test-case-states.d.ts.map +1 -0
- package/dist/graph/test-case-states.js +116 -0
- package/dist/graph/test-case-states.js.map +1 -0
- package/dist/graph/unit-artifact-probes.d.ts +19 -0
- package/dist/graph/unit-artifact-probes.d.ts.map +1 -0
- package/dist/graph/unit-artifact-probes.js +133 -0
- package/dist/graph/unit-artifact-probes.js.map +1 -0
- package/dist/graph/unit-state-facts.d.ts +43 -0
- package/dist/graph/unit-state-facts.d.ts.map +1 -0
- package/dist/graph/unit-state-facts.js +87 -0
- package/dist/graph/unit-state-facts.js.map +1 -0
- package/dist/harness/audit.d.ts +11 -0
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +34 -9
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/catalog/gate-rules.yaml +647 -0
- package/dist/harness/counted-assertions.d.ts +2 -0
- package/dist/harness/counted-assertions.d.ts.map +1 -0
- package/dist/harness/counted-assertions.js +38 -0
- package/dist/harness/counted-assertions.js.map +1 -0
- package/dist/harness/defect-draft.d.ts +14 -0
- package/dist/harness/defect-draft.d.ts.map +1 -0
- package/dist/harness/defect-draft.js +143 -0
- package/dist/harness/defect-draft.js.map +1 -0
- package/dist/harness/defects.d.ts +24 -0
- package/dist/harness/defects.d.ts.map +1 -0
- package/dist/harness/defects.js +118 -0
- package/dist/harness/defects.js.map +1 -0
- package/dist/harness/gates/audit-gate-terms.d.ts +41 -0
- package/dist/harness/gates/audit-gate-terms.d.ts.map +1 -0
- package/dist/harness/gates/audit-gate-terms.js +72 -0
- package/dist/harness/gates/audit-gate-terms.js.map +1 -0
- package/dist/harness/gates/audit-gate-verdict.d.ts +31 -0
- package/dist/harness/gates/audit-gate-verdict.d.ts.map +1 -0
- package/dist/harness/gates/audit-gate-verdict.js +101 -0
- package/dist/harness/gates/audit-gate-verdict.js.map +1 -0
- package/dist/harness/gates/audit-input-hash.d.ts +4 -0
- package/dist/harness/gates/audit-input-hash.d.ts.map +1 -0
- package/dist/harness/gates/audit-input-hash.js +96 -0
- package/dist/harness/gates/audit-input-hash.js.map +1 -0
- package/dist/harness/gates/audit-report-verification.d.ts +41 -0
- package/dist/harness/gates/audit-report-verification.d.ts.map +1 -0
- package/dist/harness/gates/audit-report-verification.js +236 -0
- package/dist/harness/gates/audit-report-verification.js.map +1 -0
- package/dist/harness/gates/decisions-hash.d.ts +13 -0
- package/dist/harness/gates/decisions-hash.d.ts.map +1 -0
- package/dist/harness/gates/decisions-hash.js +72 -0
- package/dist/harness/gates/decisions-hash.js.map +1 -0
- package/dist/harness/gates/delivery-checklist.d.ts +21 -0
- package/dist/harness/gates/delivery-checklist.d.ts.map +1 -0
- package/dist/harness/gates/delivery-checklist.js +128 -0
- package/dist/harness/gates/delivery-checklist.js.map +1 -0
- package/dist/harness/gates/delivery-decision-gate.d.ts +33 -0
- package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -0
- package/dist/harness/gates/delivery-decision-gate.js +116 -0
- package/dist/harness/gates/delivery-decision-gate.js.map +1 -0
- package/dist/harness/gates/delivery-decision-step.d.ts +19 -0
- package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -0
- package/dist/harness/gates/delivery-decision-step.js +86 -0
- package/dist/harness/gates/delivery-decision-step.js.map +1 -0
- package/dist/harness/gates/gate-override-report.d.ts +59 -0
- package/dist/harness/gates/gate-override-report.d.ts.map +1 -0
- package/dist/harness/gates/gate-override-report.js +86 -0
- package/dist/harness/gates/gate-override-report.js.map +1 -0
- package/dist/harness/gates/gate-override-scope.d.ts +18 -0
- package/dist/harness/gates/gate-override-scope.d.ts.map +1 -0
- package/dist/harness/gates/gate-override-scope.js +98 -0
- package/dist/harness/gates/gate-override-scope.js.map +1 -0
- package/dist/harness/gates/gate-override-validation.d.ts +25 -0
- package/dist/harness/gates/gate-override-validation.d.ts.map +1 -0
- package/dist/harness/gates/gate-override-validation.js +81 -0
- package/dist/harness/gates/gate-override-validation.js.map +1 -0
- package/dist/harness/gates/gate-rule-catalog.d.ts +24 -0
- package/dist/harness/gates/gate-rule-catalog.d.ts.map +1 -0
- package/dist/harness/gates/gate-rule-catalog.js +112 -0
- package/dist/harness/gates/gate-rule-catalog.js.map +1 -0
- package/dist/harness/gates/gate-terms.d.ts +33 -0
- package/dist/harness/gates/gate-terms.d.ts.map +1 -0
- package/dist/harness/gates/gate-terms.js +41 -0
- package/dist/harness/gates/gate-terms.js.map +1 -0
- package/dist/harness/gates/in-run-decision-check.d.ts +21 -0
- package/dist/harness/gates/in-run-decision-check.d.ts.map +1 -0
- package/dist/harness/gates/in-run-decision-check.js +138 -0
- package/dist/harness/gates/in-run-decision-check.js.map +1 -0
- package/dist/harness/gates/journey-gate-inputs.d.ts +37 -0
- package/dist/harness/gates/journey-gate-inputs.d.ts.map +1 -0
- package/dist/harness/gates/journey-gate-inputs.js +81 -0
- package/dist/harness/gates/journey-gate-inputs.js.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts +6 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.js +116 -0
- package/dist/harness/gates/migrated-waiver-review.js.map +1 -0
- package/dist/harness/gates/resolve-rule.d.ts +59 -0
- package/dist/harness/gates/resolve-rule.d.ts.map +1 -0
- package/dist/harness/gates/resolve-rule.js +41 -0
- package/dist/harness/gates/resolve-rule.js.map +1 -0
- package/dist/harness/gates/unit-gate-overrides.d.ts +25 -0
- package/dist/harness/gates/unit-gate-overrides.d.ts.map +1 -0
- package/dist/harness/gates/unit-gate-overrides.js +122 -0
- package/dist/harness/gates/unit-gate-overrides.js.map +1 -0
- package/dist/harness/journey.d.ts +43 -1
- package/dist/harness/journey.d.ts.map +1 -1
- package/dist/harness/journey.js +207 -33
- package/dist/harness/journey.js.map +1 -1
- package/dist/harness/manifest.d.ts +12 -0
- package/dist/harness/manifest.d.ts.map +1 -1
- package/dist/harness/manifest.js +73 -45
- package/dist/harness/manifest.js.map +1 -1
- package/dist/harness/next-step.d.ts +37 -6
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +34 -174
- package/dist/harness/next-step.js.map +1 -1
- package/dist/harness/parse.d.ts +25 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +38 -13
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/provenance.d.ts +29 -0
- package/dist/harness/provenance.d.ts.map +1 -1
- package/dist/harness/provenance.js +109 -9
- package/dist/harness/provenance.js.map +1 -1
- package/dist/harness/script-check.d.ts.map +1 -1
- package/dist/harness/script-check.js +29 -6
- package/dist/harness/script-check.js.map +1 -1
- package/dist/harness/sensors.d.ts +14 -3
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +64 -44
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/triage-signals.d.ts +20 -0
- package/dist/harness/triage-signals.d.ts.map +1 -0
- package/dist/harness/triage-signals.js +30 -0
- package/dist/harness/triage-signals.js.map +1 -0
- package/dist/harness/triage-unit.d.ts +23 -0
- package/dist/harness/triage-unit.d.ts.map +1 -0
- package/dist/harness/triage-unit.js +142 -0
- package/dist/harness/triage-unit.js.map +1 -0
- package/dist/harness/triage.d.ts +28 -0
- package/dist/harness/triage.d.ts.map +1 -0
- package/dist/harness/triage.js +99 -0
- package/dist/harness/triage.js.map +1 -0
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +2 -1
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/hooks/bash-write-targets.d.ts +15 -0
- package/dist/hooks/bash-write-targets.d.ts.map +1 -0
- package/dist/hooks/bash-write-targets.js +173 -0
- package/dist/hooks/bash-write-targets.js.map +1 -0
- package/dist/hooks/claude-hook-entry.d.ts +11 -0
- package/dist/hooks/claude-hook-entry.d.ts.map +1 -0
- package/dist/hooks/claude-hook-entry.js +137 -0
- package/dist/hooks/claude-hook-entry.js.map +1 -0
- package/dist/hooks/claude-transcript-turn.d.ts +11 -0
- package/dist/hooks/claude-transcript-turn.d.ts.map +1 -0
- package/dist/hooks/claude-transcript-turn.js +143 -0
- package/dist/hooks/claude-transcript-turn.js.map +1 -0
- package/dist/hooks/guard-delivery-contract-rule.d.ts +10 -0
- package/dist/hooks/guard-delivery-contract-rule.d.ts.map +1 -0
- package/dist/hooks/guard-delivery-contract-rule.js +152 -0
- package/dist/hooks/guard-delivery-contract-rule.js.map +1 -0
- package/dist/hooks/guard-protected-paths.d.ts +9 -0
- package/dist/hooks/guard-protected-paths.d.ts.map +1 -0
- package/dist/hooks/guard-protected-paths.js +107 -0
- package/dist/hooks/guard-protected-paths.js.map +1 -0
- package/dist/hooks/guard-rules.d.ts +37 -0
- package/dist/hooks/guard-rules.d.ts.map +1 -0
- package/dist/hooks/guard-rules.js +61 -0
- package/dist/hooks/guard-rules.js.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts +15 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.js +21 -0
- package/dist/hooks/guard-tty-spoof-rule.js.map +1 -0
- package/dist/hooks/hand-back-core.d.ts +39 -0
- package/dist/hooks/hand-back-core.d.ts.map +1 -0
- package/dist/hooks/hand-back-core.js +122 -0
- package/dist/hooks/hand-back-core.js.map +1 -0
- package/dist/hooks/hook-cli-command.d.ts +9 -0
- package/dist/hooks/hook-cli-command.d.ts.map +1 -0
- package/dist/hooks/hook-cli-command.js +46 -0
- package/dist/hooks/hook-cli-command.js.map +1 -0
- package/dist/hooks/hook-registry.d.ts +10 -0
- package/dist/hooks/hook-registry.d.ts.map +1 -0
- package/dist/hooks/hook-registry.js +24 -0
- package/dist/hooks/hook-registry.js.map +1 -0
- package/dist/hooks/hook-result-contract.d.ts +50 -0
- package/dist/hooks/hook-result-contract.d.ts.map +1 -0
- package/dist/hooks/hook-result-contract.js +80 -0
- package/dist/hooks/hook-result-contract.js.map +1 -0
- package/dist/hooks/hook-toggles.d.ts +10 -0
- package/dist/hooks/hook-toggles.d.ts.map +1 -0
- package/dist/hooks/hook-toggles.js +107 -0
- package/dist/hooks/hook-toggles.js.map +1 -0
- package/dist/hooks/pre-tool-guard-hook.d.ts +10 -0
- package/dist/hooks/pre-tool-guard-hook.d.ts.map +1 -0
- package/dist/hooks/pre-tool-guard-hook.js +105 -0
- package/dist/hooks/pre-tool-guard-hook.js.map +1 -0
- package/dist/hooks/session-start-unit-state-hook.d.ts +13 -0
- package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -0
- package/dist/hooks/session-start-unit-state-hook.js +57 -0
- package/dist/hooks/session-start-unit-state-hook.js.map +1 -0
- package/dist/hooks/stop-next-step-hook.d.ts +16 -0
- package/dist/hooks/stop-next-step-hook.d.ts.map +1 -0
- package/dist/hooks/stop-next-step-hook.js +42 -0
- package/dist/hooks/stop-next-step-hook.js.map +1 -0
- package/dist/hooks/sungen-project-root.d.ts +19 -0
- package/dist/hooks/sungen-project-root.d.ts.map +1 -0
- package/dist/hooks/sungen-project-root.js +130 -0
- package/dist/hooks/sungen-project-root.js.map +1 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.d.ts +15 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.js +106 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.js.map +1 -0
- package/dist/orchestrator/ai-skills/commands.d.ts +5 -1
- package/dist/orchestrator/ai-skills/commands.d.ts.map +1 -1
- package/dist/orchestrator/ai-skills/commands.js +16 -6
- package/dist/orchestrator/ai-skills/commands.js.map +1 -1
- package/dist/orchestrator/ai-skills/golden-skills.test.js +29 -0
- package/dist/orchestrator/ai-skills/golden-skills.test.js.map +1 -1
- package/dist/orchestrator/assets-drift.d.ts +5 -0
- package/dist/orchestrator/assets-drift.d.ts.map +1 -1
- package/dist/orchestrator/assets-drift.js +12 -3
- package/dist/orchestrator/assets-drift.js.map +1 -1
- package/dist/orchestrator/claude-hooks-install.d.ts +27 -0
- package/dist/orchestrator/claude-hooks-install.d.ts.map +1 -0
- package/dist/orchestrator/claude-hooks-install.js +203 -0
- package/dist/orchestrator/claude-hooks-install.js.map +1 -0
- package/dist/orchestrator/lockstep-version.d.ts +15 -5
- package/dist/orchestrator/lockstep-version.d.ts.map +1 -1
- package/dist/orchestrator/lockstep-version.js +30 -17
- package/dist/orchestrator/lockstep-version.js.map +1 -1
- package/dist/orchestrator/project-initializer.d.ts +6 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +24 -0
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +4 -2
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/add-api.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +14 -16
- package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/design.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/feedback.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/locale.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/review.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +14 -10
- package/dist/orchestrator/templates/ai-src/config/claude.md +20 -7
- package/dist/orchestrator/templates/ai-src/config/copilot.md +20 -7
- package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
- package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
- package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
- package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/dist/utils/safe-yaml-parse.d.ts +8 -0
- package/dist/utils/safe-yaml-parse.d.ts.map +1 -0
- package/dist/utils/safe-yaml-parse.js +51 -0
- package/dist/utils/safe-yaml-parse.js.map +1 -0
- package/package.json +3 -3
- package/src/basis/anchor-grammar.ts +83 -0
- package/src/basis/anchor-hash.ts +27 -0
- package/src/basis/bm51-tables.ts +65 -0
- package/src/basis/extract-spec-anchors.ts +95 -0
- package/src/basis/migration-sentinel.ts +175 -0
- package/src/basis/spec-frontmatter.ts +68 -0
- package/src/basis/spec-sections.ts +35 -0
- package/src/basis/test-basis-schema.ts +81 -0
- package/src/capabilities/discover.ts +15 -2
- package/src/capabilities/registry.ts +16 -0
- package/src/cli/commands/audit.ts +10 -5
- package/src/cli/commands/capability.ts +4 -2
- package/src/cli/commands/contract-derive-command.ts +61 -0
- package/src/cli/commands/contract.ts +130 -0
- package/src/cli/commands/defect.ts +49 -0
- package/src/cli/commands/delivery.ts +92 -15
- package/src/cli/commands/generate.ts +3 -1
- package/src/cli/commands/journey.ts +41 -16
- package/src/cli/commands/next.ts +64 -10
- package/src/cli/commands/triage.ts +57 -0
- package/src/cli/commands/update.ts +35 -8
- package/src/cli/index.ts +24 -30
- package/src/cli/project-sungen-invocation.ts +39 -0
- package/src/contract/approve-contract.ts +94 -0
- package/src/contract/assertion-matcher-vocabulary.ts +93 -0
- package/src/contract/build-contract-verdict.ts +108 -0
- package/src/contract/build-trace-conformance.ts +100 -0
- package/src/contract/classify-contract-change.ts +92 -0
- package/src/contract/classify-contract-unit.ts +47 -0
- package/src/contract/classify-trace-conformance.ts +116 -0
- package/src/contract/contract-git.ts +106 -0
- package/src/contract/contract-hash.ts +34 -0
- package/src/contract/contract-report-file.ts +25 -0
- package/src/contract/contract-schema.ts +137 -0
- package/src/contract/contract-units.ts +52 -0
- package/src/contract/contracts-lock-file.ts +97 -0
- package/src/contract/data-normalize.ts +66 -0
- package/src/contract/derive-free-feature.ts +120 -0
- package/src/contract/field-semantic-redaction.ts +80 -0
- package/src/contract/free-feature-blocks.ts +56 -0
- package/src/contract/lock-secret-guard.ts +95 -0
- package/src/contract/lock-vs-git-head.ts +38 -0
- package/src/contract/normalize-contract-step.ts +74 -0
- package/src/contract/normalize-feature-steps.ts +93 -0
- package/src/contract/oracle-strength.ts +80 -0
- package/src/contract/project-contract-blockers.ts +36 -0
- package/src/contract/record-contract-approval.ts +70 -0
- package/src/contract/render-free-gherkin.ts +113 -0
- package/src/contract/render-trace-sentence.ts +98 -0
- package/src/contract/render-trace-target.ts +68 -0
- package/src/contract/resolve-unit-trace-identities.ts +35 -0
- package/src/contract/trace/collect-trace-evidence.ts +109 -0
- package/src/contract/trace/identity-cache.ts +61 -0
- package/src/contract/trace/select-final-attempt.ts +70 -0
- package/src/contract/trace/snapshot-html-renderer.ts +136 -0
- package/src/contract/trace/snapshot-resolver.ts +66 -0
- package/src/contract/trace/snapshot-store.ts +151 -0
- package/src/contract/trace/target-identity.ts +104 -0
- package/src/contract/trace/test-step-join.ts +104 -0
- package/src/contract/trace/trace-binding.ts +56 -0
- package/src/contract/trace/trace-file-reader.ts +133 -0
- package/src/contract/trace/trace-fingerprint.ts +68 -0
- package/src/contract/trace/trace-identity-resolution.ts +74 -0
- package/src/contract/trace/trace-run-record.ts +80 -0
- package/src/contract/trace/trace-steps.ts +88 -0
- package/src/contract/trace/trace-zip-limits.ts +77 -0
- package/src/contract/trace/trace-zip-reader.ts +127 -0
- package/src/contract/verify-approval-decisions.ts +60 -0
- package/src/decisions/append-decision.ts +35 -0
- package/src/decisions/confirmed-decision-commands.ts +149 -0
- package/src/decisions/decision-file.ts +93 -0
- package/src/decisions/decision-identity.ts +73 -0
- package/src/decisions/decision-integrity-check.ts +61 -0
- package/src/decisions/decision-schema.ts +76 -0
- package/src/decisions/decision-source.ts +14 -0
- package/src/decisions/exclusive-file-create.ts +42 -0
- package/src/decisions/git-head-trust.ts +32 -0
- package/src/decisions/human-confirmation.ts +119 -0
- package/src/decisions/legacy-waiver-migration.ts +135 -0
- package/src/decisions/read-decisions.ts +61 -0
- package/src/decisions/viewpoint-baseline-adapter.ts +74 -0
- package/src/decisions/waiver-decisions.ts +56 -0
- package/src/exporters/csv-exporter.ts +5 -1
- package/src/exporters/feature-parser.ts +12 -0
- package/src/exporters/matrix/build.ts +62 -18
- package/src/exporters/matrix/carry-manual-results.ts +70 -7
- package/src/exporters/matrix/export.ts +17 -2
- package/src/exporters/matrix/gates.ts +62 -129
- package/src/exporters/matrix/render-csv.ts +4 -1
- package/src/exporters/matrix/render-gate-overrides-sheet.ts +50 -0
- package/src/exporters/matrix/render-xlsx.ts +6 -0
- package/src/exporters/matrix/types.ts +9 -1
- package/src/exporters/matrix/xlsx-cells.ts +1 -1
- package/src/exporters/playwright-report-parser.ts +1 -0
- package/src/exporters/scenario-merger.ts +2 -1
- package/src/exporters/types.ts +5 -0
- package/src/generators/test-generator/code-generator.ts +13 -0
- package/src/graph/evaluate-graph.ts +66 -0
- package/src/graph/locate-finding.ts +93 -0
- package/src/graph/node-decl.ts +72 -0
- package/src/graph/nodes/core-node-catalog.ts +15 -0
- package/src/graph/nodes/test-case-contract-nodes.ts +74 -0
- package/src/graph/nodes/test-case-nodes.ts +68 -0
- package/src/graph/nodes/unit-audit-nodes.ts +95 -0
- package/src/graph/nodes/unit-contract-node.ts +89 -0
- package/src/graph/nodes/unit-design-nodes.ts +89 -0
- package/src/graph/nodes/unit-execution-nodes.ts +77 -0
- package/src/graph/test-case-identity.ts +75 -0
- package/src/graph/test-case-results.ts +90 -0
- package/src/graph/test-case-satisfied.ts +55 -0
- package/src/graph/test-case-state-shape.ts +62 -0
- package/src/graph/test-case-states.ts +84 -0
- package/src/graph/unit-artifact-probes.ts +77 -0
- package/src/graph/unit-state-facts.ts +112 -0
- package/src/harness/audit.ts +46 -11
- package/src/harness/catalog/gate-rules.yaml +647 -0
- package/src/harness/counted-assertions.ts +33 -0
- package/src/harness/defect-draft.ts +115 -0
- package/src/harness/defects.ts +94 -0
- package/src/harness/gates/audit-gate-terms.ts +80 -0
- package/src/harness/gates/audit-gate-verdict.ts +78 -0
- package/src/harness/gates/audit-input-hash.ts +55 -0
- package/src/harness/gates/audit-report-verification.ts +201 -0
- package/src/harness/gates/decisions-hash.ts +42 -0
- package/src/harness/gates/delivery-checklist.ts +120 -0
- package/src/harness/gates/delivery-decision-gate.ts +139 -0
- package/src/harness/gates/delivery-decision-step.ts +89 -0
- package/src/harness/gates/gate-override-report.ts +114 -0
- package/src/harness/gates/gate-override-scope.ts +66 -0
- package/src/harness/gates/gate-override-validation.ts +75 -0
- package/src/harness/gates/gate-rule-catalog.ts +82 -0
- package/src/harness/gates/gate-terms.ts +59 -0
- package/src/harness/gates/in-run-decision-check.ts +99 -0
- package/src/harness/gates/journey-gate-inputs.ts +89 -0
- package/src/harness/gates/migrated-waiver-review.ts +68 -0
- package/src/harness/gates/resolve-rule.ts +94 -0
- package/src/harness/gates/unit-gate-overrides.ts +99 -0
- package/src/harness/journey.ts +215 -38
- package/src/harness/manifest.ts +69 -45
- package/src/harness/next-step.ts +60 -170
- package/src/harness/parse.ts +40 -13
- package/src/harness/provenance.ts +99 -11
- package/src/harness/script-check.ts +27 -6
- package/src/harness/sensors.ts +73 -47
- package/src/harness/triage-signals.ts +46 -0
- package/src/harness/triage-unit.ts +113 -0
- package/src/harness/triage.ts +127 -0
- package/src/harness/viewpoint-ledger.ts +2 -2
- package/src/hooks/bash-write-targets.ts +109 -0
- package/src/hooks/claude-hook-entry.ts +85 -0
- package/src/hooks/claude-transcript-turn.ts +96 -0
- package/src/hooks/guard-delivery-contract-rule.ts +110 -0
- package/src/hooks/guard-protected-paths.ts +71 -0
- package/src/hooks/guard-rules.ts +98 -0
- package/src/hooks/guard-tty-spoof-rule.ts +31 -0
- package/src/hooks/hand-back-core.ts +112 -0
- package/src/hooks/hook-cli-command.ts +17 -0
- package/src/hooks/hook-registry.ts +24 -0
- package/src/hooks/hook-result-contract.ts +114 -0
- package/src/hooks/hook-toggles.ts +66 -0
- package/src/hooks/pre-tool-guard-hook.ts +67 -0
- package/src/hooks/session-start-unit-state-hook.ts +56 -0
- package/src/hooks/stop-next-step-hook.ts +37 -0
- package/src/hooks/sungen-project-root.ts +80 -0
- package/src/orchestrator/ai-skills/command-partial-includes.ts +72 -0
- package/src/orchestrator/ai-skills/commands.ts +22 -8
- package/src/orchestrator/ai-skills/golden-skills.test.ts +23 -0
- package/src/orchestrator/assets-drift.ts +12 -5
- package/src/orchestrator/claude-hooks-install.ts +168 -0
- package/src/orchestrator/lockstep-version.ts +28 -15
- package/src/orchestrator/project-initializer.ts +22 -0
- package/src/orchestrator/screen-manager.ts +3 -1
- package/src/orchestrator/templates/ai-src/commands/add-api.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
- package/src/orchestrator/templates/ai-src/commands/create-test.md +14 -16
- package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/delivery.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/design.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/feedback.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/locale.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/review.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/run-test.md +14 -10
- package/src/orchestrator/templates/ai-src/config/claude.md +20 -7
- package/src/orchestrator/templates/ai-src/config/copilot.md +20 -7
- package/src/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
- package/src/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
- package/src/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
- package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/src/utils/safe-yaml-parse.ts +44 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The snapshot that shows a call's target, rendered for replay (DOS-14.5; spike criterion 6).
|
|
3
|
+
*
|
|
4
|
+
* Playwright marks the element a call acted on with `__playwright_target__="<callId>"`. For an
|
|
5
|
+
* action that is the `input@` (v9: `action`) snapshot — the moment of the action; for a check the
|
|
6
|
+
* `after@` snapshot (the state it passed on). The order `input → before → after` is the spike's
|
|
7
|
+
* (R10: a child frame sometimes lacks one snapshot name; the fallback still found every target).
|
|
8
|
+
* No marked element in any snapshot → no target (identity `low`).
|
|
9
|
+
*/
|
|
10
|
+
import { createHash } from 'crypto';
|
|
11
|
+
import type { ParsedTrace } from './trace-file-reader';
|
|
12
|
+
import { renderSnapshot, RenderStats } from './snapshot-html-renderer';
|
|
13
|
+
import { attrsOf, FrameSnapshot, isEl, isRef, kidsOf, SnapNode, SnapshotStore } from './snapshot-store';
|
|
14
|
+
import type { TargetFacts } from './target-identity';
|
|
15
|
+
|
|
16
|
+
export interface CallTarget {
|
|
17
|
+
callId: string;
|
|
18
|
+
snapshotKey: string;
|
|
19
|
+
html: string;
|
|
20
|
+
/** sha256 of the rendered HTML — the key a driver identity is cached under. */
|
|
21
|
+
snapshotSha256: string;
|
|
22
|
+
viewport: { width: number; height: number };
|
|
23
|
+
stats: RenderStats;
|
|
24
|
+
/** What already forces `low`, whatever the driver says. */
|
|
25
|
+
capReasons: string[];
|
|
26
|
+
facts: TargetFacts;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const ORDER = ['input', 'before', 'after'];
|
|
30
|
+
|
|
31
|
+
/** `label[for]` texts of a snapshot, for the heuristic name of a labelled control. */
|
|
32
|
+
function labelTexts(store: SnapshotStore, snap: FrameSnapshot): Map<string, string> {
|
|
33
|
+
const out = new Map<string, string>();
|
|
34
|
+
const stats = { refs: 0, brokenRefs: 0 };
|
|
35
|
+
const stack: Array<{ n: SnapNode; s: FrameSnapshot }> = [{ n: snap.html, s: snap }];
|
|
36
|
+
while (stack.length) {
|
|
37
|
+
let { n, s } = stack.pop()!;
|
|
38
|
+
if (isRef(n)) { const d = store.deref(n, s, stats); if (!d) continue; n = d.n; s = d.snap; }
|
|
39
|
+
if (!isEl(n)) continue;
|
|
40
|
+
const a = attrsOf(n);
|
|
41
|
+
if (n[0].toUpperCase() === 'LABEL' && a.for) out.set(a.for, store.textOf(n, s));
|
|
42
|
+
for (const k of kidsOf(n)) stack.push({ n: k, s });
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function resolveCallTarget(store: SnapshotStore, trace: ParsedTrace, callId: string): CallTarget | null {
|
|
48
|
+
for (const phase of ORDER) {
|
|
49
|
+
for (const snap of store.byKey.get(`${phase}@${callId}`) ?? []) {
|
|
50
|
+
const hit = store.findTarget(snap, callId);
|
|
51
|
+
if (!hit) continue;
|
|
52
|
+
const { html, stats } = renderSnapshot(store, snap, (sha1) => trace.readResource(sha1));
|
|
53
|
+
const capReasons: string[] = [];
|
|
54
|
+
if (stats.stylesheetsMissing > 0) capReasons.push(`stylesheet-missing(${stats.stylesheetsMissing})`);
|
|
55
|
+
if (stats.brokenRefs > 0) capReasons.push(`broken-snapshot-refs(${stats.brokenRefs})`);
|
|
56
|
+
const attrs = Object.fromEntries(Object.entries(attrsOf(hit.el)).filter(([k]) => !k.startsWith('__playwright_')));
|
|
57
|
+
const facts: TargetFacts = { tag: hit.el[0], attrs, text: store.textOf(hit.el, hit.snap) };
|
|
58
|
+
if (attrs.id) facts.labelText = labelTexts(store, snap).get(attrs.id);
|
|
59
|
+
return {
|
|
60
|
+
callId, snapshotKey: snap.key, html, snapshotSha256: createHash('sha256').update(html).digest('hex'),
|
|
61
|
+
viewport: snap.viewport, stats, capReasons, facts,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The frame snapshots of a trace, indexed the way Playwright's trace viewer indexes them, so a
|
|
3
|
+
* snapshot can be rebuilt as static HTML for identity replay (DOS-14.5; phase 07 criterion 6).
|
|
4
|
+
*
|
|
5
|
+
* A snapshot reuses unchanged subtrees of an EARLIER snapshot of the same frame as `[[ago, idx]]`
|
|
6
|
+
* references; `idx` counts nodes in post-order (children first, then the element), exactly as the
|
|
7
|
+
* viewer numbers them. A reference that points outside its frame's history is counted as broken —
|
|
8
|
+
* a broken replay caps identity at `low`, never guesses.
|
|
9
|
+
*
|
|
10
|
+
* Snapshot naming differs by format: v8 names it `input@call@12`, v9 gives `{callId, phase}` with
|
|
11
|
+
* phase `before | action | after`. Both are keyed here as `<before|input|after>@<callId>`.
|
|
12
|
+
*/
|
|
13
|
+
import type { LibraryPart } from './trace-file-reader';
|
|
14
|
+
|
|
15
|
+
export type SnapNode = string | [[number, number]] | [string, Record<string, string>?, ...SnapNode[]];
|
|
16
|
+
export interface FrameSnapshot {
|
|
17
|
+
key: string; callId: string; frameId: string; frameUrl: string; doctype?: string; html: SnapNode;
|
|
18
|
+
viewport: { width: number; height: number }; timestamp: number; isMainFrame: boolean;
|
|
19
|
+
resourceOverrides: Array<{ url: string; sha1?: string; ref?: number }>;
|
|
20
|
+
part: LibraryPart; index: number;
|
|
21
|
+
}
|
|
22
|
+
export interface RefStats { refs: number; brokenRefs: number }
|
|
23
|
+
|
|
24
|
+
export const isRef = (n: unknown): n is [[number, number]] => Array.isArray(n) && Array.isArray(n[0]);
|
|
25
|
+
export const isEl = (n: unknown): n is [string, Record<string, string>?, ...SnapNode[]] => Array.isArray(n) && typeof n[0] === 'string';
|
|
26
|
+
export const attrsOf = (n: [string, Record<string, string>?, ...SnapNode[]]): Record<string, string> =>
|
|
27
|
+
(n[1] && typeof n[1] === 'object' && !Array.isArray(n[1]) ? n[1] : {}) as Record<string, string>;
|
|
28
|
+
export const kidsOf = (n: [string, Record<string, string>?, ...SnapNode[]]): SnapNode[] => n.slice(2) as SnapNode[];
|
|
29
|
+
|
|
30
|
+
const PHASE: Record<string, string> = { before: 'before', action: 'input', input: 'input', after: 'after' };
|
|
31
|
+
|
|
32
|
+
function keyOf(s: Record<string, unknown>): string | null {
|
|
33
|
+
if (typeof s.snapshotName === 'string') return s.snapshotName;
|
|
34
|
+
if (typeof s.callId === 'string' && typeof s.phase === 'string' && PHASE[s.phase]) return `${PHASE[s.phase]}@${s.callId}`;
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class SnapshotStore {
|
|
39
|
+
readonly frames = new Map<string, FrameSnapshot[]>();
|
|
40
|
+
readonly byKey = new Map<string, FrameSnapshot[]>();
|
|
41
|
+
private nodeCache = new Map<FrameSnapshot, SnapNode[]>();
|
|
42
|
+
|
|
43
|
+
constructor(parts: LibraryPart[]) {
|
|
44
|
+
for (const part of parts) {
|
|
45
|
+
for (const e of part.events) {
|
|
46
|
+
if (e.type !== 'frame-snapshot' || !e.snapshot || typeof e.snapshot !== 'object') continue;
|
|
47
|
+
const s = e.snapshot as Record<string, unknown>;
|
|
48
|
+
const key = keyOf(s);
|
|
49
|
+
if (!key || typeof s.frameId !== 'string') continue;
|
|
50
|
+
const list = this.frames.get(s.frameId) ?? [];
|
|
51
|
+
const vp = (s.viewport ?? {}) as { width?: number; height?: number };
|
|
52
|
+
const snap: FrameSnapshot = {
|
|
53
|
+
key, callId: key.slice(key.indexOf('@') + 1), frameId: s.frameId, frameUrl: String(s.frameUrl ?? ''),
|
|
54
|
+
doctype: typeof s.doctype === 'string' ? s.doctype : undefined, html: s.html as SnapNode,
|
|
55
|
+
viewport: { width: Number(vp.width) || 1280, height: Number(vp.height) || 800 }, timestamp: Number(s.timestamp) || 0,
|
|
56
|
+
isMainFrame: s.isMainFrame !== false, resourceOverrides: Array.isArray(s.resourceOverrides) ? s.resourceOverrides as FrameSnapshot['resourceOverrides'] : [],
|
|
57
|
+
part, index: list.length,
|
|
58
|
+
};
|
|
59
|
+
list.push(snap);
|
|
60
|
+
this.frames.set(s.frameId, list);
|
|
61
|
+
this.byKey.set(key, [...(this.byKey.get(key) ?? []), snap]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Non-reference nodes of a snapshot in post-order — Playwright's numbering for `[[ago, idx]]`. */
|
|
67
|
+
nodes(snap: FrameSnapshot): SnapNode[] {
|
|
68
|
+
const cached = this.nodeCache.get(snap);
|
|
69
|
+
if (cached) return cached;
|
|
70
|
+
const out: SnapNode[] = [];
|
|
71
|
+
const visit = (n: SnapNode): void => {
|
|
72
|
+
if (typeof n === 'string') out.push(n);
|
|
73
|
+
else if (isEl(n)) { kidsOf(n).forEach(visit); out.push(n); }
|
|
74
|
+
};
|
|
75
|
+
visit(snap.html);
|
|
76
|
+
this.nodeCache.set(snap, out);
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Follow references to a concrete node, or null (counted as broken). */
|
|
81
|
+
deref(n: SnapNode, snap: FrameSnapshot, stats: RefStats): { n: SnapNode; snap: FrameSnapshot } | null {
|
|
82
|
+
let cur = n;
|
|
83
|
+
let at = snap;
|
|
84
|
+
for (let guard = 0; isRef(cur) && guard < 10_000; guard++) {
|
|
85
|
+
const [ago, idx] = cur[0];
|
|
86
|
+
const list = this.frames.get(at.frameId) ?? [];
|
|
87
|
+
const target = list[at.index - ago];
|
|
88
|
+
if (!Number.isInteger(ago) || ago < 0 || !target) { stats.brokenRefs++; return null; }
|
|
89
|
+
const nodes = this.nodes(target);
|
|
90
|
+
if (!Number.isInteger(idx) || idx < 0 || idx >= nodes.length) { stats.brokenRefs++; return null; }
|
|
91
|
+
cur = nodes[idx];
|
|
92
|
+
at = target;
|
|
93
|
+
stats.refs++;
|
|
94
|
+
}
|
|
95
|
+
return isRef(cur) ? null : { n: cur, snap: at };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** The element Playwright marked as the target of `callId` in this snapshot, if any. */
|
|
99
|
+
findTarget(snap: FrameSnapshot, callId: string): { el: [string, Record<string, string>?, ...SnapNode[]]; snap: FrameSnapshot } | null {
|
|
100
|
+
const stats: RefStats = { refs: 0, brokenRefs: 0 };
|
|
101
|
+
const stack: Array<{ n: SnapNode; snap: FrameSnapshot }> = [{ n: snap.html, snap }];
|
|
102
|
+
while (stack.length) {
|
|
103
|
+
let { n, snap: at } = stack.pop()!;
|
|
104
|
+
if (isRef(n)) { const d = this.deref(n, at, stats); if (!d) continue; n = d.n; at = d.snap; }
|
|
105
|
+
if (!isEl(n)) continue;
|
|
106
|
+
// v8 marks the target with its call id; v9 snapshots belong to one call and mark it with ''.
|
|
107
|
+
const mark = attrsOf(n).__playwright_target__;
|
|
108
|
+
if (mark === callId || (mark === '' && snap.callId === callId)) return { el: n, snap: at };
|
|
109
|
+
for (const k of kidsOf(n)) stack.push({ n: k, snap: at });
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The visible text under a node (references resolved), whitespace collapsed. */
|
|
115
|
+
textOf(n: SnapNode, snap: FrameSnapshot): string {
|
|
116
|
+
const stats: RefStats = { refs: 0, brokenRefs: 0 };
|
|
117
|
+
const out: string[] = [];
|
|
118
|
+
const visit = (x: SnapNode, at: FrameSnapshot): void => {
|
|
119
|
+
if (isRef(x)) { const d = this.deref(x, at, stats); if (d) visit(d.n, d.snap); return; }
|
|
120
|
+
if (typeof x === 'string') { out.push(x); return; }
|
|
121
|
+
if (isEl(x) && !/^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE)$/i.test(x[0])) kidsOf(x).forEach((k) => visit(k, at));
|
|
122
|
+
};
|
|
123
|
+
visit(n, snap);
|
|
124
|
+
return out.join(' ').replace(/\s+/g, ' ').trim();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The stylesheet body for `href` as the page had it at this snapshot: override first, then network. */
|
|
128
|
+
stylesheetSha1(snap: FrameSnapshot, href: string): string | null {
|
|
129
|
+
let abs: string;
|
|
130
|
+
try { abs = new URL(href, snap.frameUrl).href.replace(/#.*$/, ''); } catch { return null; }
|
|
131
|
+
const list = this.frames.get(snap.frameId) ?? [];
|
|
132
|
+
let idx = snap.index;
|
|
133
|
+
for (let guard = 0; guard < 10_000 && list[idx]; guard++) {
|
|
134
|
+
const o = list[idx].resourceOverrides.find((x) => x.url === abs);
|
|
135
|
+
if (!o) break;
|
|
136
|
+
if (o.sha1) return o.sha1;
|
|
137
|
+
if (typeof o.ref !== 'number') break;
|
|
138
|
+
idx -= o.ref;
|
|
139
|
+
}
|
|
140
|
+
let same: string | null = null;
|
|
141
|
+
let other: string | null = null;
|
|
142
|
+
for (const r of snap.part.network) {
|
|
143
|
+
const s = (r.snapshot ?? {}) as { request?: { url?: string; method?: string }; response?: { status?: number; content?: { _sha1?: string; _file?: string } }; _monotonicTime?: number; _frameref?: string };
|
|
144
|
+
const body = s.response?.content?._sha1 ?? s.response?.content?._file; // v8: sha1 · v9: resources/<sha1>.<ext>
|
|
145
|
+
if (typeof s._monotonicTime === 'number' && s._monotonicTime >= snap.timestamp) continue;
|
|
146
|
+
if (s.request?.url !== abs || s.request?.method !== 'GET' || s.response?.status === 304 || !body) continue;
|
|
147
|
+
if (s._frameref === snap.frameId) same = body; else other = body;
|
|
148
|
+
}
|
|
149
|
+
return same ?? other;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who an action or a check was aimed at (DOS-14.5, SPI §4.5 `traceIdentity`).
|
|
3
|
+
*
|
|
4
|
+
* The identity of a target is role + accessible name from the RUNTIME's own accessibility engine:
|
|
5
|
+
* `@sungen/driver-ui` replays the snapshot in a real browser (Playwright `ariaSnapshot` +
|
|
6
|
+
* `getByRole`) through the `traceIdentity` slot, with `identityConfidence: high | low`. Core
|
|
7
|
+
* cannot run a browser; its own reading of the snapshot (below) is a HEURISTIC and therefore
|
|
8
|
+
* always `low` — and `low` is never `match` (red-team #4).
|
|
9
|
+
*
|
|
10
|
+
* `high` also needs: the page's stylesheets all found (G1), no broken snapshot reference, a semantic
|
|
11
|
+
* role with a non-empty name, and role+name resolving back to exactly the marked element — or,
|
|
12
|
+
* when it does not (G3, ~12% of actions: "Add to cart" ×34), a named scope (row, landmark, dialog)
|
|
13
|
+
* inside which it does.
|
|
14
|
+
*/
|
|
15
|
+
export type IdentityConfidence = 'high' | 'low';
|
|
16
|
+
export interface IdentityScope { role: string; name: string }
|
|
17
|
+
|
|
18
|
+
export interface TargetIdentity {
|
|
19
|
+
role: string;
|
|
20
|
+
name: string;
|
|
21
|
+
level?: number;
|
|
22
|
+
scope?: IdentityScope;
|
|
23
|
+
identityConfidence: IdentityConfidence;
|
|
24
|
+
reasons: string[];
|
|
25
|
+
source: 'driver' | 'heuristic';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** One snapshot to replay. `capReasons` are what core already knows forces `low` (missing CSS…). */
|
|
29
|
+
export interface TraceIdentityRequest {
|
|
30
|
+
key: string;
|
|
31
|
+
html: string;
|
|
32
|
+
viewport: { width: number; height: number };
|
|
33
|
+
targetSelector: string;
|
|
34
|
+
capReasons: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface TraceIdentityInput { requests: TraceIdentityRequest[] }
|
|
37
|
+
export interface TraceIdentityResult {
|
|
38
|
+
key: string; role: string; name: string; level?: number; scope?: IdentityScope;
|
|
39
|
+
identityConfidence: IdentityConfidence; reasons: string[];
|
|
40
|
+
}
|
|
41
|
+
export interface TraceIdentityOutput {
|
|
42
|
+
resolver: string;
|
|
43
|
+
/** The browser build that judged every result (e.g. `chromium 143.0.7499.4`), kept per cache entry. */
|
|
44
|
+
browser: string;
|
|
45
|
+
results: TraceIdentityResult[];
|
|
46
|
+
/** Requests the replay page attempted (all blocked). Reported, never trusted for anything. */
|
|
47
|
+
blockedRequests?: number;
|
|
48
|
+
}
|
|
49
|
+
export type TraceIdentityResolver = (input: TraceIdentityInput) => Promise<TraceIdentityOutput>;
|
|
50
|
+
|
|
51
|
+
/** What core can read off the snapshot about the marked element. */
|
|
52
|
+
export interface TargetFacts { tag: string; attrs: Record<string, string>; text: string; labelText?: string }
|
|
53
|
+
|
|
54
|
+
const INPUT_ROLE: Record<string, string> = {
|
|
55
|
+
checkbox: 'checkbox', radio: 'radio', submit: 'button', button: 'button', reset: 'button', image: 'button',
|
|
56
|
+
search: 'searchbox', number: 'spinbutton', range: 'slider',
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function heuristicRole(f: TargetFacts): string {
|
|
60
|
+
if (f.attrs.role) return f.attrs.role.split(/\s+/)[0].toLowerCase();
|
|
61
|
+
const tag = f.tag.toUpperCase();
|
|
62
|
+
if (tag === 'A' && f.attrs.href !== undefined) return 'link';
|
|
63
|
+
if (tag === 'BUTTON') return 'button';
|
|
64
|
+
if (tag === 'INPUT') return INPUT_ROLE[(f.attrs.type || 'text').toLowerCase()] ?? 'textbox';
|
|
65
|
+
if (tag === 'SELECT') return 'combobox';
|
|
66
|
+
if (tag === 'TEXTAREA') return 'textbox';
|
|
67
|
+
if (/^H[1-6]$/.test(tag)) return 'heading';
|
|
68
|
+
if (tag === 'IMG') return 'img';
|
|
69
|
+
return 'generic';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Core's own reading of the snapshot — never better than `low`. */
|
|
73
|
+
export function heuristicIdentity(f: TargetFacts | null, why: string): TargetIdentity {
|
|
74
|
+
if (!f) return { role: 'generic', name: '', identityConfidence: 'low', reasons: [why, 'no-target-in-snapshot'], source: 'heuristic' };
|
|
75
|
+
const role = heuristicRole(f);
|
|
76
|
+
const named = role === 'button' || role === 'link' || role === 'heading';
|
|
77
|
+
const name = f.attrs['aria-label'] || f.labelText || (named ? f.text : '') || f.attrs.placeholder || f.attrs.alt || f.attrs.title || '';
|
|
78
|
+
const level = /^H([1-6])$/i.exec(f.tag)?.[1];
|
|
79
|
+
return { role, name: name.replace(/\s+/g, ' ').trim(), ...(level ? { level: Number(level) } : {}), identityConfidence: 'low', reasons: [why], source: 'heuristic' };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const RESULT_KEYS = new Set(['key', 'role', 'name', 'level', 'scope', 'identityConfidence', 'reasons']);
|
|
83
|
+
const isObj = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
84
|
+
/** Bounded strings: an identity is a role and a name, never a payload. */
|
|
85
|
+
const str = (v: unknown, max: number): v is string => typeof v === 'string' && v.length <= max;
|
|
86
|
+
const ROLE_MAX = 64;
|
|
87
|
+
const NAME_MAX = 1000;
|
|
88
|
+
|
|
89
|
+
/** The only resolver whose answers the identity cache keeps (driver-ui's Playwright replay). */
|
|
90
|
+
export const TRUSTED_RESOLVER = /^driver-ui\/playwright-aria@\d+$/;
|
|
91
|
+
|
|
92
|
+
/** A resolver's result, checked strictly (unknown keys rejected) — null when it is not well-formed. */
|
|
93
|
+
export function validIdentityResult(raw: unknown): TraceIdentityResult | null {
|
|
94
|
+
if (!isObj(raw) || Object.keys(raw).some((k) => !RESULT_KEYS.has(k))) return null;
|
|
95
|
+
const { key, role, name, level, scope, identityConfidence, reasons } = raw;
|
|
96
|
+
if (!str(key, 128) || !str(role, ROLE_MAX) || !str(name, NAME_MAX)) return null;
|
|
97
|
+
if (identityConfidence !== 'high' && identityConfidence !== 'low') return null;
|
|
98
|
+
if (!Array.isArray(reasons) || reasons.length > 20 || !reasons.every((r) => str(r, 300))) return null;
|
|
99
|
+
if (level !== undefined && !(Number.isInteger(level) && (level as number) >= 1 && (level as number) <= 6)) return null;
|
|
100
|
+
if (scope !== undefined && !(isObj(scope) && str(scope.role, ROLE_MAX) && str(scope.name, NAME_MAX) && Object.keys(scope).length === 2)) return null;
|
|
101
|
+
// `high` with a reason is a contradiction: a reason is what makes an identity low.
|
|
102
|
+
if (identityConfidence === 'high' && reasons.length) return null;
|
|
103
|
+
return { key, role, name, ...(level !== undefined ? { level: level as number } : {}), ...(scope ? { scope: scope as unknown as IdentityScope } : {}), identityConfidence, reasons: reasons as string[] };
|
|
104
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Join the test runner's steps (test.trace) with the browser calls (<N>-trace.trace) — phase 07
|
|
3
|
+
* criterion 2, proven 114/114 on a real app. Up to format 9 a library call's `stepId` is the runner
|
|
4
|
+
* step's `callId`; from format 10 (Playwright 1.64) the two share ONE id and `stepId` is gone, so the
|
|
5
|
+
* call's own `callId` is the step. Walking the runner's `parentId` chain says where the call ran:
|
|
6
|
+
*
|
|
7
|
+
* body the test function itself, with the path of enclosing `test.step` titles
|
|
8
|
+
* hook a user `beforeEach` / `afterEach` (stage setup | teardown)
|
|
9
|
+
* fixture a fixture's setup or teardown (`Fixture "signedInPage"`)
|
|
10
|
+
* runner the runner's own Before/After Hooks plumbing (browser launch, context close)
|
|
11
|
+
*
|
|
12
|
+
* Only body and user `beforeEach` calls are the test's behaviour; fixtures and teardown are
|
|
13
|
+
* environment, kept apart so a shared fixture cannot leak into every test's contract.
|
|
14
|
+
*/
|
|
15
|
+
import type { ParsedTrace, StackFrame, TraceEvent } from './trace-file-reader';
|
|
16
|
+
|
|
17
|
+
export interface RunnerStep {
|
|
18
|
+
id: string; parentId?: string; method: string; title: string;
|
|
19
|
+
params: Record<string, unknown>; stack: StackFrame[]; failed: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type CallPhase =
|
|
23
|
+
| { phase: 'body'; stepPath: string[] }
|
|
24
|
+
| { phase: 'hook'; stage: 'setup' | 'teardown'; name: string }
|
|
25
|
+
| { phase: 'fixture'; stage: 'setup' | 'teardown'; name: string }
|
|
26
|
+
| { phase: 'runner'; stage: 'setup' | 'teardown'; name: string }
|
|
27
|
+
| { phase: 'unjoined' };
|
|
28
|
+
|
|
29
|
+
export interface JoinedCall {
|
|
30
|
+
part: string; callId: string; class: string; method: string;
|
|
31
|
+
params: Record<string, unknown>; stepId?: string; where: CallPhase; failed: boolean; startTime: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const str = (v: unknown): string => (typeof v === 'string' ? v : '');
|
|
35
|
+
const RUNNER_HOOKS = /^(Before Hooks|After Hooks|Worker Cleanup)$/;
|
|
36
|
+
|
|
37
|
+
function stackOf(e: TraceEvent): StackFrame[] {
|
|
38
|
+
const raw = Array.isArray(e.stack) ? e.stack : [];
|
|
39
|
+
return raw.filter((f): f is Record<string, unknown> => !!f && typeof f === 'object')
|
|
40
|
+
.map((f) => ({ file: str(f.file), line: Number(f.line) || 0, column: Number(f.column) || 0 }));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function indexRunnerSteps(runner: TraceEvent[]): Map<string, RunnerStep> {
|
|
44
|
+
const steps = new Map<string, RunnerStep>();
|
|
45
|
+
for (const e of runner) {
|
|
46
|
+
const id = str(e.callId);
|
|
47
|
+
if (e.type === 'before' && id) {
|
|
48
|
+
steps.set(id, {
|
|
49
|
+
id, parentId: str(e.parentId) || undefined, method: str(e.method), title: str(e.title),
|
|
50
|
+
params: (e.params && typeof e.params === 'object' ? e.params : {}) as Record<string, unknown>, stack: stackOf(e), failed: false,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (e.type === 'after' && steps.has(id) && e.error) steps.get(id)!.failed = true;
|
|
54
|
+
}
|
|
55
|
+
return steps;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The runner steps from `id` up to the root (self first). Cycles end the walk. */
|
|
59
|
+
export function ancestry(steps: Map<string, RunnerStep>, id: string): RunnerStep[] {
|
|
60
|
+
const chain: RunnerStep[] = [];
|
|
61
|
+
const seen = new Set<string>();
|
|
62
|
+
for (let cur = steps.get(id); cur && !seen.has(cur.id); cur = cur.parentId ? steps.get(cur.parentId) : undefined) {
|
|
63
|
+
seen.add(cur.id);
|
|
64
|
+
chain.push(cur);
|
|
65
|
+
}
|
|
66
|
+
return chain;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function classifyStep(steps: Map<string, RunnerStep>, stepId: string): CallPhase {
|
|
70
|
+
const chain = ancestry(steps, stepId);
|
|
71
|
+
if (!chain.length) return { phase: 'unjoined' };
|
|
72
|
+
const root = chain[chain.length - 1];
|
|
73
|
+
const stage = root.method === 'hook' && root.title === 'After Hooks' ? 'teardown' : 'setup';
|
|
74
|
+
const fixture = chain.find((s) => s.method === 'fixture');
|
|
75
|
+
if (fixture) return { phase: 'fixture', stage, name: fixture.title.replace(/^Fixture "(.*)"$/, '$1') };
|
|
76
|
+
const userHook = chain.find((s) => s.method === 'hook' && !RUNNER_HOOKS.test(s.title));
|
|
77
|
+
if (userHook) return { phase: 'hook', stage, name: userHook.title };
|
|
78
|
+
if (root.method === 'hook') return { phase: 'runner', stage, name: root.title };
|
|
79
|
+
return { phase: 'body', stepPath: chain.filter((s) => s.method === 'test.step').map((s) => s.title).reverse() };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Is this phase the test's own behaviour (body, or a user `beforeEach`)? */
|
|
83
|
+
export const isBehaviour = (w: CallPhase): boolean => w.phase === 'body' || (w.phase === 'hook' && w.stage === 'setup');
|
|
84
|
+
|
|
85
|
+
/** Every library call, joined to its runner step, in start order across parts. */
|
|
86
|
+
export function joinCalls(trace: ParsedTrace): { steps: Map<string, RunnerStep>; calls: JoinedCall[] } {
|
|
87
|
+
const steps = indexRunnerSteps(trace.runner);
|
|
88
|
+
const calls: JoinedCall[] = [];
|
|
89
|
+
for (const part of trace.library) {
|
|
90
|
+
const failed = new Set(part.events.filter((e) => e.type === 'after' && e.error).map((e) => str(e.callId)));
|
|
91
|
+
for (const e of part.events) {
|
|
92
|
+
if (e.type !== 'before') continue;
|
|
93
|
+
const callId = str(e.callId);
|
|
94
|
+
const stepId = str(e.stepId) || (part.version >= 10 ? callId : '') || undefined;
|
|
95
|
+
calls.push({
|
|
96
|
+
part: part.name, callId, class: str(e.class), method: str(e.method),
|
|
97
|
+
params: (e.params && typeof e.params === 'object' ? e.params : {}) as Record<string, unknown>,
|
|
98
|
+
stepId, where: stepId ? classifyStep(steps, stepId) : { phase: 'unjoined' }, failed: failed.has(callId), startTime: Number(e.startTime) || 0,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
calls.sort((a, b) => a.startTime - b.startTime);
|
|
103
|
+
return { steps, calls };
|
|
104
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* May THIS trace speak for THIS test's final attempt? (DOS-14.6, red-team #5; phase 07 criterion 5.)
|
|
3
|
+
* A good trace of another test, of the same test from another run, or from before the contract
|
|
4
|
+
* changed is the "green by swap" path — every link below must hold:
|
|
5
|
+
*
|
|
6
|
+
* run record the attempt (testId, retry) is in sungen's own record of the run, passed
|
|
7
|
+
* bytes sha256(trace.zip) equals what the record wrote at the end of that run
|
|
8
|
+
* code sha256 of the test file NOW equals the hash the record took at run start
|
|
9
|
+
* title every library part says `<file>:<line> › … › <title>` of exactly this test
|
|
10
|
+
* clock the trace started inside the attempt's window (±2 s)
|
|
11
|
+
* fresh the trace is newer than the .feature and the lock it is asked to prove
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from 'crypto';
|
|
14
|
+
import * as fs from 'fs';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
import type { ParsedTrace } from './trace-file-reader';
|
|
17
|
+
import type { RunRecord } from './trace-run-record';
|
|
18
|
+
import type { ReportResult, ReportTest } from './select-final-attempt';
|
|
19
|
+
|
|
20
|
+
export interface BindingInput {
|
|
21
|
+
projectRoot: string;
|
|
22
|
+
test: ReportTest;
|
|
23
|
+
result: ReportResult;
|
|
24
|
+
record: RunRecord;
|
|
25
|
+
trace: ParsedTrace;
|
|
26
|
+
/** Epoch ms: the newest mtime of the unit's .feature files and lock. */
|
|
27
|
+
notBefore: number;
|
|
28
|
+
}
|
|
29
|
+
export type Binding = { ok: true; specFile: string } | { ok: false; reason: string };
|
|
30
|
+
|
|
31
|
+
const CLOCK_SLACK_MS = 2_000;
|
|
32
|
+
|
|
33
|
+
export function bindTrace(i: BindingInput): Binding {
|
|
34
|
+
const fail = (reason: string): Binding => ({ ok: false, reason });
|
|
35
|
+
const attempt = i.record.attempts.find((a) => a.testId === i.test.testId && a.retry === i.result.retry);
|
|
36
|
+
if (!attempt) return fail(`run ${i.record.runId} has no record of this attempt (retry ${i.result.retry}) — the trace is not bound to a sungen run`);
|
|
37
|
+
if (attempt.status !== 'passed') return fail(`the run record says this attempt ${attempt.status}`);
|
|
38
|
+
if (!attempt.trace || attempt.trace.sha256 !== i.trace.sha256) {
|
|
39
|
+
return fail('this is not the trace the run recorded (sha256 differs) — swapped or edited after the run');
|
|
40
|
+
}
|
|
41
|
+
const specPath = path.join(i.projectRoot, attempt.file);
|
|
42
|
+
let now: string;
|
|
43
|
+
try { now = createHash('sha256').update(fs.readFileSync(specPath)).digest('hex'); } catch { return fail(`the test file ${attempt.file} is gone`); }
|
|
44
|
+
if (i.record.specs[attempt.file] !== now) return fail(`the test file ${attempt.file} changed since the run — re-run it`);
|
|
45
|
+
const prefix = `${i.test.file}:${i.test.line} › `;
|
|
46
|
+
if (!i.trace.titles.length) return fail('the trace names no test (no title in its header)');
|
|
47
|
+
const other = i.trace.titles.find((t) => !(t.startsWith(prefix) && t.endsWith(` › ${i.test.title}`)));
|
|
48
|
+
if (other) return fail(`the trace belongs to another test ("${other}")`);
|
|
49
|
+
const start = Date.parse(i.result.startTime);
|
|
50
|
+
const wall = i.trace.wallTime;
|
|
51
|
+
if (typeof wall !== 'number' || Number.isNaN(start) || wall < start - CLOCK_SLACK_MS || wall > start + i.result.duration + CLOCK_SLACK_MS) {
|
|
52
|
+
return fail('the trace was not recorded during this attempt (clock window)');
|
|
53
|
+
}
|
|
54
|
+
if (wall < i.notBefore) return fail('the trace is older than the .feature or the lock it should prove (stale) — re-run the test');
|
|
55
|
+
return { ok: true, specFile: attempt.file };
|
|
56
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One Playwright trace.zip → its parsed parts, after the zip limits and the format-version gate
|
|
3
|
+
* (DOS-14.6, DOS-14.7). Nothing past this point sees a trace that was not accepted here.
|
|
4
|
+
*
|
|
5
|
+
* test.trace the test runner's steps (test.step, hooks, fixtures, expect, pw:api)
|
|
6
|
+
* <N>-trace.trace a library part: the browser calls, frame snapshots, logs
|
|
7
|
+
* <N>-trace.network resources (stylesheets inlined into a replayed snapshot come from here)
|
|
8
|
+
* <N>-trace.stacks call id → source frames (`file:line` of an opaque step)
|
|
9
|
+
* resources/<sha1> resource bodies
|
|
10
|
+
*
|
|
11
|
+
* Every part that has a header (test.trace and each library part) must declare a supported version;
|
|
12
|
+
* a part without one is refused. Every JSONL line must parse — a line that does not is never skipped.
|
|
13
|
+
*/
|
|
14
|
+
import { createHash } from 'crypto';
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import { openZip, ZipArchive } from './trace-zip-reader';
|
|
17
|
+
import { SUPPORTED_TRACE_VERSIONS, traceZipLimits, TraceRejected, TraceZipLimits } from './trace-zip-limits';
|
|
18
|
+
|
|
19
|
+
export type TraceEvent = { type: string } & Record<string, unknown>;
|
|
20
|
+
export interface StackFrame { file: string; line: number; column: number }
|
|
21
|
+
/**
|
|
22
|
+
* One library part. `version` is its declared format (already accepted by the gate); `stacks` is
|
|
23
|
+
* keyed by call id — v8/v9 wrote a call NUMBER (`11` → `call@11`, Playwright's legacy id), v10 the
|
|
24
|
+
* call id itself, which it shares with the runner step (`ulgt@50`).
|
|
25
|
+
*/
|
|
26
|
+
export interface LibraryPart { name: string; version: number; events: TraceEvent[]; network: TraceEvent[]; stacks: Map<string, StackFrame[]> }
|
|
27
|
+
|
|
28
|
+
export interface ParsedTrace {
|
|
29
|
+
label: string;
|
|
30
|
+
sha256: string;
|
|
31
|
+
versions: Array<{ part: string; version: unknown }>;
|
|
32
|
+
runner: TraceEvent[];
|
|
33
|
+
library: LibraryPart[];
|
|
34
|
+
/** `wallTime` (epoch ms) of the runner's header: when the attempt started. */
|
|
35
|
+
wallTime: number | undefined;
|
|
36
|
+
/** `title` of every library part's header: `<file>:<line> › <describe…> › <test title>`. */
|
|
37
|
+
titles: string[];
|
|
38
|
+
/** A resource body by sha1 (v8) or entry name `resources/<sha1>.<ext>` (v9); null when absent. */
|
|
39
|
+
readResource(ref: string): string | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const CALL_ID = /^[\w@.:-]{1,128}$/;
|
|
43
|
+
|
|
44
|
+
function parseJsonl(zip: ZipArchive, name: string): TraceEvent[] {
|
|
45
|
+
const out: TraceEvent[] = [];
|
|
46
|
+
zip.readText(name).split('\n').forEach((line, i) => {
|
|
47
|
+
if (!line.trim()) return;
|
|
48
|
+
let v: unknown;
|
|
49
|
+
try { v = JSON.parse(line); } catch { throw new TraceRejected('trace.malformed', `${name} line ${i + 1} is not JSON`); }
|
|
50
|
+
if (!v || typeof v !== 'object' || Array.isArray(v) || typeof (v as { type?: unknown }).type !== 'string') {
|
|
51
|
+
throw new TraceRejected('trace.malformed', `${name} line ${i + 1} is not a trace event`);
|
|
52
|
+
}
|
|
53
|
+
// Call ids end up inside a CSS selector of the replay (`[__playwright_target__="…"]`).
|
|
54
|
+
const e = v as Record<string, unknown>;
|
|
55
|
+
const snap = e.snapshot && typeof e.snapshot === 'object' ? (e.snapshot as Record<string, unknown>).callId : undefined;
|
|
56
|
+
for (const id of [e.callId, e.stepId, e.parentId, snap]) {
|
|
57
|
+
if (id !== undefined && (typeof id !== 'string' || !CALL_ID.test(id))) throw new TraceRejected('trace.malformed', `${name} line ${i + 1}: ${JSON.stringify(String(id)).slice(0, 40)} is not a call id`);
|
|
58
|
+
}
|
|
59
|
+
out.push(v as TraceEvent);
|
|
60
|
+
});
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function parseStacks(zip: ZipArchive, name: string): Map<string, StackFrame[]> {
|
|
65
|
+
const out = new Map<string, StackFrame[]>();
|
|
66
|
+
if (!zip.has(name)) return out;
|
|
67
|
+
let doc: { files?: unknown; stacks?: unknown };
|
|
68
|
+
try { doc = JSON.parse(zip.readText(name)); } catch { throw new TraceRejected('trace.malformed', `${name} is not JSON`); }
|
|
69
|
+
const files = Array.isArray(doc.files) ? doc.files.map(String) : [];
|
|
70
|
+
for (const row of Array.isArray(doc.stacks) ? doc.stacks : []) {
|
|
71
|
+
if (!Array.isArray(row) || !Array.isArray(row[1])) continue;
|
|
72
|
+
const id = typeof row[0] === 'number' ? `call@${row[0]}` : row[0];
|
|
73
|
+
if (typeof id !== 'string' || !CALL_ID.test(id)) continue;
|
|
74
|
+
const frames = (row[1] as unknown[]).filter(Array.isArray).map((f) => {
|
|
75
|
+
const [fileIdx, line, column] = f as number[];
|
|
76
|
+
return { file: files[fileIdx] ?? '', line: Number(line) || 0, column: Number(column) || 0 };
|
|
77
|
+
});
|
|
78
|
+
out.set(id, frames);
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const headerOf = (events: TraceEvent[]): TraceEvent | undefined => events.find((e) => e.type === 'context-options');
|
|
84
|
+
|
|
85
|
+
export function readTraceBuffer(buf: Buffer, label: string, limits: TraceZipLimits = traceZipLimits()): ParsedTrace {
|
|
86
|
+
const zip = openZip(buf, limits);
|
|
87
|
+
if (!zip.has('test.trace')) throw new TraceRejected('trace.malformed', 'no test.trace — not a Playwright Test trace (runner steps are required)');
|
|
88
|
+
const runner = parseJsonl(zip, 'test.trace');
|
|
89
|
+
const library: LibraryPart[] = zip.names().filter((n) => /^\d+-trace\.trace$/.test(n)).sort().map((n) => {
|
|
90
|
+
const base = n.replace(/\.trace$/, '');
|
|
91
|
+
const events = parseJsonl(zip, n);
|
|
92
|
+
const version = headerOf(events)?.version;
|
|
93
|
+
return {
|
|
94
|
+
name: n,
|
|
95
|
+
version: typeof version === 'number' ? version : NaN, // a non-number is refused just below
|
|
96
|
+
events,
|
|
97
|
+
network: zip.has(`${base}.network`) ? parseJsonl(zip, `${base}.network`) : [],
|
|
98
|
+
stacks: parseStacks(zip, `${base}.stacks`),
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
const versions = [{ part: 'test.trace', version: headerOf(runner)?.version }, ...library.map((l) => ({ part: l.name, version: headerOf(l.events)?.version }))];
|
|
102
|
+
const bad = versions.filter((v) => typeof v.version !== 'number' || !SUPPORTED_TRACE_VERSIONS.has(v.version));
|
|
103
|
+
if (bad.length) {
|
|
104
|
+
throw new TraceRejected('trace.version-unsupported',
|
|
105
|
+
`${bad.map((v) => `${v.part}=${v.version === undefined ? 'missing' : JSON.stringify(v.version)}`).join(', ')} (supported: ${[...SUPPORTED_TRACE_VERSIONS].join(', ')})`);
|
|
106
|
+
}
|
|
107
|
+
const head = headerOf(runner);
|
|
108
|
+
const cache = new Map<string, string | null>();
|
|
109
|
+
return {
|
|
110
|
+
label,
|
|
111
|
+
sha256: createHash('sha256').update(buf).digest('hex'),
|
|
112
|
+
versions,
|
|
113
|
+
runner,
|
|
114
|
+
library,
|
|
115
|
+
wallTime: typeof head?.wallTime === 'number' ? head.wallTime : undefined,
|
|
116
|
+
titles: library.map((l) => headerOf(l.events)?.title).filter((t): t is string => typeof t === 'string'),
|
|
117
|
+
readResource(ref: string): string | null {
|
|
118
|
+
// v8 names a resource by its sha1; v9 by its entry, `resources/<sha1>.<ext>`.
|
|
119
|
+
const name = ref.replace(/^resources\//, '');
|
|
120
|
+
if (!/^[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(name)) return null;
|
|
121
|
+
if (!cache.has(name)) cache.set(name, zip.has(`resources/${name}`) ? zip.readText(`resources/${name}`) : null);
|
|
122
|
+
return cache.get(name) ?? null;
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Read a trace from disk: a regular file, size-checked BEFORE it is read into memory. */
|
|
128
|
+
export function readTraceFile(file: string, limits: TraceZipLimits = traceZipLimits()): ParsedTrace {
|
|
129
|
+
const st = fs.statSync(file);
|
|
130
|
+
if (!st.isFile()) throw new TraceRejected('zip.malformed', `${file} is not a regular file`);
|
|
131
|
+
if (st.size > limits.maxZipBytes) throw new TraceRejected('zip.too-large', `${st.size} B > ${limits.maxZipBytes}`);
|
|
132
|
+
return readTraceBuffer(fs.readFileSync(file), file, limits);
|
|
133
|
+
}
|