@sun-asterisk/sungen 3.2.35 → 3.3.0-alpha.10
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/case-triage-hint.d.ts +14 -0
- package/dist/cli/case-triage-hint.d.ts.map +1 -0
- package/dist/cli/case-triage-hint.js +23 -0
- package/dist/cli/case-triage-hint.js.map +1 -0
- package/dist/cli/commands/audit.js +1 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.js +1 -1
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/contract-derive-command.d.ts +12 -0
- package/dist/cli/commands/contract-derive-command.d.ts.map +1 -0
- package/dist/cli/commands/contract-derive-command.js +113 -0
- package/dist/cli/commands/contract-derive-command.js.map +1 -0
- package/dist/cli/commands/contract.d.ts +20 -0
- package/dist/cli/commands/contract.d.ts.map +1 -0
- package/dist/cli/commands/contract.js +195 -0
- package/dist/cli/commands/contract.js.map +1 -0
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +109 -19
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/gate.d.ts.map +1 -1
- package/dist/cli/commands/gate.js +2 -1
- package/dist/cli/commands/gate.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +17 -3
- 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 +47 -17
- package/dist/cli/commands/journey.js.map +1 -1
- package/dist/cli/commands/next.d.ts +13 -0
- package/dist/cli/commands/next.d.ts.map +1 -1
- package/dist/cli/commands/next.js +98 -9
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/triage.d.ts +2 -1
- package/dist/cli/commands/triage.d.ts.map +1 -1
- package/dist/cli/commands/triage.js +45 -3
- package/dist/cli/commands/triage.js.map +1 -1
- 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 +37 -8
- 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/json-error-on-exit.d.ts +34 -0
- package/dist/cli/json-error-on-exit.d.ts.map +1 -0
- package/dist/cli/json-error-on-exit.js +63 -0
- package/dist/cli/json-error-on-exit.js.map +1 -0
- package/dist/cli/project-sungen-invocation.d.ts +13 -0
- package/dist/cli/project-sungen-invocation.d.ts.map +1 -0
- package/dist/cli/project-sungen-invocation.js +95 -0
- package/dist/cli/project-sungen-invocation.js.map +1 -0
- package/dist/cli/run-command-hints.d.ts +9 -0
- package/dist/cli/run-command-hints.d.ts.map +1 -0
- package/dist/cli/run-command-hints.js +84 -0
- package/dist/cli/run-command-hints.js.map +1 -0
- package/dist/cli/waiting-for-you-block.d.ts +18 -0
- package/dist/cli/waiting-for-you-block.d.ts.map +1 -0
- package/dist/cli/waiting-for-you-block.js +22 -0
- package/dist/cli/waiting-for-you-block.js.map +1 -0
- package/dist/contract/accept-opaque-steps.d.ts +3 -0
- package/dist/contract/accept-opaque-steps.d.ts.map +1 -0
- package/dist/contract/accept-opaque-steps.js +114 -0
- package/dist/contract/accept-opaque-steps.js.map +1 -0
- package/dist/contract/approve-contract.d.ts +38 -0
- package/dist/contract/approve-contract.d.ts.map +1 -0
- package/dist/contract/approve-contract.js +93 -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 +22 -0
- package/dist/contract/build-trace-conformance.d.ts.map +1 -0
- package/dist/contract/build-trace-conformance.js +151 -0
- package/dist/contract/build-trace-conformance.js.map +1 -0
- package/dist/contract/classify-contract-change.d.ts +24 -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 +47 -0
- package/dist/contract/classify-trace-conformance.d.ts.map +1 -0
- package/dist/contract/classify-trace-conformance.js +164 -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 +92 -0
- package/dist/contract/contract-schema.d.ts.map +1 -0
- package/dist/contract/contract-schema.js +124 -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 +141 -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 +49 -0
- package/dist/contract/derive-free-feature.d.ts.map +1 -0
- package/dist/contract/derive-free-feature.js +183 -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 +75 -0
- package/dist/contract/project-contract-blockers.js.map +1 -0
- package/dist/contract/record-contract-approval.d.ts +36 -0
- package/dist/contract/record-contract-approval.d.ts.map +1 -0
- package/dist/contract/record-contract-approval.js +126 -0
- package/dist/contract/record-contract-approval.js.map +1 -0
- package/dist/contract/render-free-gherkin.d.ts +42 -0
- package/dist/contract/render-free-gherkin.d.ts.map +1 -0
- package/dist/contract/render-free-gherkin.js +147 -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 +20 -0
- package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -0
- package/dist/contract/resolve-unit-trace-identities.js +62 -0
- package/dist/contract/resolve-unit-trace-identities.js.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts +44 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.js +219 -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/read-file-once.d.ts +20 -0
- package/dist/contract/trace/read-file-once.d.ts.map +1 -0
- package/dist/contract/trace/read-file-once.js +135 -0
- package/dist/contract/trace/read-file-once.js.map +1 -0
- package/dist/contract/trace/scenario-id-claims.d.ts +11 -0
- package/dist/contract/trace/scenario-id-claims.d.ts.map +1 -0
- package/dist/contract/trace/scenario-id-claims.js +89 -0
- package/dist/contract/trace/scenario-id-claims.js.map +1 -0
- package/dist/contract/trace/select-final-attempt.d.ts +29 -0
- package/dist/contract/trace/select-final-attempt.d.ts.map +1 -0
- package/dist/contract/trace/select-final-attempt.js +119 -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 +22 -0
- package/dist/contract/trace/trace-binding.d.ts.map +1 -0
- package/dist/contract/trace/trace-binding.js +91 -0
- package/dist/contract/trace/trace-binding.js.map +1 -0
- package/dist/contract/trace/trace-file-reader.d.ts +47 -0
- package/dist/contract/trace/trace-file-reader.d.ts.map +1 -0
- package/dist/contract/trace/trace-file-reader.js +137 -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-freshness.d.ts +27 -0
- package/dist/contract/trace/trace-freshness.d.ts.map +1 -0
- package/dist/contract/trace/trace-freshness.js +146 -0
- package/dist/contract/trace/trace-freshness.js.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts +28 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.js +87 -0
- package/dist/contract/trace/trace-identity-resolution.js.map +1 -0
- package/dist/contract/trace/trace-run-record.d.ts +32 -0
- package/dist/contract/trace/trace-run-record.d.ts.map +1 -0
- package/dist/contract/trace/trace-run-record.js +135 -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 +109 -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 +43 -0
- package/dist/decisions/decision-schema.d.ts.map +1 -0
- package/dist/decisions/decision-schema.js +76 -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 +19 -0
- package/dist/decisions/git-head-trust.d.ts.map +1 -0
- package/dist/decisions/git-head-trust.js +128 -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 +38 -0
- package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -0
- package/dist/decisions/legacy-waiver-migration.js +179 -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 +11 -2
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +8 -4
- package/dist/exporters/csv-exporter.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 +10 -9
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/export.d.ts +9 -1
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +13 -4
- 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 +3 -0
- 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 +3 -0
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +4 -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/test-data-resolver.d.ts.map +1 -1
- package/dist/exporters/test-data-resolver.js +2 -12
- package/dist/exporters/test-data-resolver.js.map +1 -1
- package/dist/exporters/xlsx-exporter.d.ts +3 -2
- package/dist/exporters/xlsx-exporter.d.ts.map +1 -1
- package/dist/exporters/xlsx-exporter.js +4 -4
- package/dist/exporters/xlsx-exporter.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +0 -1
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/contain-text-assertion.hbs +1 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -13
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -9
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +18 -4
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +3 -9
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +3 -9
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.d.ts +0 -8
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +8 -52
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.d.ts +0 -16
- package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.js +0 -59
- package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +2 -10
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/graph/board-human-actions.d.ts +5 -0
- package/dist/graph/board-human-actions.d.ts.map +1 -0
- package/dist/graph/board-human-actions.js +83 -0
- package/dist/graph/board-human-actions.js.map +1 -0
- package/dist/graph/evaluate-graph.d.ts +41 -0
- package/dist/graph/evaluate-graph.d.ts.map +1 -0
- package/dist/graph/evaluate-graph.js +77 -0
- package/dist/graph/evaluate-graph.js.map +1 -0
- package/dist/graph/human-action.d.ts +21 -0
- package/dist/graph/human-action.d.ts.map +1 -0
- package/dist/graph/human-action.js +3 -0
- package/dist/graph/human-action.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/manual-triage-decisions.d.ts +19 -0
- package/dist/graph/manual-triage-decisions.d.ts.map +1 -0
- package/dist/graph/manual-triage-decisions.js +53 -0
- package/dist/graph/manual-triage-decisions.js.map +1 -0
- package/dist/graph/node-decl.d.ts +75 -0
- package/dist/graph/node-decl.d.ts.map +1 -0
- package/dist/graph/node-decl.js +11 -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 +72 -0
- package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -0
- package/dist/graph/nodes/test-case-nodes.d.ts +29 -0
- package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/test-case-nodes.js +95 -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 +96 -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 +96 -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 +12 -0
- package/dist/graph/test-case-results.d.ts.map +1 -0
- package/dist/graph/test-case-results.js +161 -0
- package/dist/graph/test-case-results.js.map +1 -0
- package/dist/graph/test-case-satisfied.d.ts +26 -0
- package/dist/graph/test-case-satisfied.d.ts.map +1 -0
- package/dist/graph/test-case-satisfied.js +55 -0
- package/dist/graph/test-case-satisfied.js.map +1 -0
- package/dist/graph/test-case-state-shape.d.ts +73 -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 +135 -0
- package/dist/graph/unit-artifact-probes.js.map +1 -0
- package/dist/graph/unit-results-freshness.d.ts +29 -0
- package/dist/graph/unit-results-freshness.d.ts.map +1 -0
- package/dist/graph/unit-results-freshness.js +213 -0
- package/dist/graph/unit-results-freshness.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 +14 -2
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +20 -21
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/catalog/gate-rules.yaml +647 -0
- package/dist/harness/defect-draft.d.ts.map +1 -1
- package/dist/harness/defect-draft.js +12 -2
- package/dist/harness/defect-draft.js.map +1 -1
- package/dist/harness/defects.d.ts +14 -0
- package/dist/harness/defects.d.ts.map +1 -1
- package/dist/harness/defects.js +14 -10
- package/dist/harness/defects.js.map +1 -1
- package/dist/harness/flow-check.d.ts +9 -0
- package/dist/harness/flow-check.d.ts.map +1 -1
- package/dist/harness/flow-check.js +11 -0
- package/dist/harness/flow-check.js.map +1 -1
- 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 +102 -0
- package/dist/harness/gates/audit-gate-verdict.js.map +1 -0
- package/dist/harness/gates/audit-input-hash.d.ts +6 -0
- package/dist/harness/gates/audit-input-hash.d.ts.map +1 -0
- package/dist/harness/gates/audit-input-hash.js +124 -0
- package/dist/harness/gates/audit-input-hash.js.map +1 -0
- package/dist/harness/gates/audit-report-verification.d.ts +43 -0
- package/dist/harness/gates/audit-report-verification.d.ts.map +1 -0
- package/dist/harness/gates/audit-report-verification.js +241 -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 +24 -0
- package/dist/harness/gates/delivery-checklist.d.ts.map +1 -0
- package/dist/harness/gates/delivery-checklist.js +161 -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 +166 -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-import-bounds.d.ts +13 -0
- package/dist/harness/gates/migrated-waiver-import-bounds.d.ts.map +1 -0
- package/dist/harness/gates/migrated-waiver-import-bounds.js +141 -0
- package/dist/harness/gates/migrated-waiver-import-bounds.js.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts +16 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.js +114 -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 +64 -1
- package/dist/harness/journey.d.ts.map +1 -1
- package/dist/harness/journey.js +258 -34
- 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 +71 -43
- package/dist/harness/manifest.js.map +1 -1
- package/dist/harness/next-step.d.ts +58 -4
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +55 -204
- package/dist/harness/next-step.js.map +1 -1
- package/dist/harness/parse.d.ts +7 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +18 -2
- 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 +22 -5
- 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 +41 -38
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/triage-manual-classification.d.ts +32 -0
- package/dist/harness/triage-manual-classification.d.ts.map +1 -0
- package/dist/harness/triage-manual-classification.js +56 -0
- package/dist/harness/triage-manual-classification.js.map +1 -0
- package/dist/harness/unit-paths.d.ts +8 -0
- package/dist/harness/unit-paths.d.ts.map +1 -1
- package/dist/harness/unit-paths.js +23 -1
- package/dist/harness/unit-paths.js.map +1 -1
- package/dist/hooks/bash-read-only-segment.d.ts +9 -0
- package/dist/hooks/bash-read-only-segment.d.ts.map +1 -0
- package/dist/hooks/bash-read-only-segment.js +168 -0
- package/dist/hooks/bash-read-only-segment.js.map +1 -0
- package/dist/hooks/bash-write-targets.d.ts +25 -0
- package/dist/hooks/bash-write-targets.d.ts.map +1 -0
- package/dist/hooks/bash-write-targets.js +266 -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 +13 -0
- package/dist/hooks/guard-protected-paths.d.ts.map +1 -0
- package/dist/hooks/guard-protected-paths.js +116 -0
- package/dist/hooks/guard-protected-paths.js.map +1 -0
- package/dist/hooks/guard-rules.d.ts +20 -0
- package/dist/hooks/guard-rules.d.ts.map +1 -0
- package/dist/hooks/guard-rules.js +130 -0
- package/dist/hooks/guard-rules.js.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts +17 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.js +22 -0
- package/dist/hooks/guard-tty-spoof-rule.js.map +1 -0
- package/dist/hooks/hand-back-core.d.ts +42 -0
- package/dist/hooks/hand-back-core.d.ts.map +1 -0
- package/dist/hooks/hand-back-core.js +128 -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 +14 -0
- package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -0
- package/dist/hooks/session-start-unit-state-hook.js +60 -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 +43 -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/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- 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 +11 -3
- package/dist/orchestrator/ai-skills/commands.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/templates/ai-src/commands/add-api.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/add-flow.md +6 -26
- 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 +17 -16
- package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +4 -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 +4 -0
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +6 -8
- 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/partials/waiting-for-you.claude.md +11 -0
- package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.codex.md +11 -0
- package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.copilot.md +11 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +1 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +4 -5
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +8 -24
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +3 -4
- package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/dist/orchestrator/templates/specs-test-data.ts +4 -22
- 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/case-triage-hint.ts +31 -0
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/capability.ts +1 -1
- package/src/cli/commands/contract-derive-command.ts +72 -0
- package/src/cli/commands/contract.ts +164 -0
- package/src/cli/commands/delivery.ts +106 -19
- package/src/cli/commands/gate.ts +2 -1
- package/src/cli/commands/generate.ts +16 -3
- package/src/cli/commands/journey.ts +45 -18
- package/src/cli/commands/next.ts +92 -11
- package/src/cli/commands/triage.ts +41 -3
- package/src/cli/commands/update.ts +41 -10
- package/src/cli/index.ts +24 -30
- package/src/cli/json-error-on-exit.ts +72 -0
- package/src/cli/project-sungen-invocation.ts +59 -0
- package/src/cli/run-command-hints.ts +47 -0
- package/src/cli/waiting-for-you-block.ts +27 -0
- package/src/contract/accept-opaque-steps.ts +114 -0
- package/src/contract/approve-contract.ts +101 -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 +103 -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 +170 -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 +166 -0
- package/src/contract/contract-units.ts +52 -0
- package/src/contract/contracts-lock-file.ts +98 -0
- package/src/contract/data-normalize.ts +66 -0
- package/src/contract/derive-free-feature.ts +153 -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 +38 -0
- package/src/contract/record-contract-approval.ts +110 -0
- package/src/contract/render-free-gherkin.ts +118 -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 +58 -0
- package/src/contract/trace/collect-trace-evidence.ts +178 -0
- package/src/contract/trace/identity-cache.ts +61 -0
- package/src/contract/trace/read-file-once.ts +95 -0
- package/src/contract/trace/scenario-id-claims.ts +60 -0
- package/src/contract/trace/select-final-attempt.ts +77 -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 +59 -0
- package/src/contract/trace/trace-file-reader.ts +144 -0
- package/src/contract/trace/trace-fingerprint.ts +68 -0
- package/src/contract/trace/trace-freshness.ts +110 -0
- package/src/contract/trace/trace-identity-resolution.ts +77 -0
- package/src/contract/trace/trace-run-record.ts +96 -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 +64 -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 +77 -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 +76 -0
- package/src/decisions/human-confirmation.ts +119 -0
- package/src/decisions/legacy-waiver-migration.ts +146 -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 +12 -4
- package/src/exporters/matrix/build.ts +11 -9
- package/src/exporters/matrix/export.ts +16 -4
- package/src/exporters/matrix/gates.ts +62 -129
- package/src/exporters/matrix/render-csv.ts +3 -0
- package/src/exporters/matrix/render-gate-overrides-sheet.ts +50 -0
- package/src/exporters/matrix/render-xlsx.ts +3 -0
- package/src/exporters/matrix/types.ts +4 -1
- package/src/exporters/matrix/xlsx-cells.ts +1 -1
- package/src/exporters/test-data-resolver.ts +2 -10
- package/src/exporters/xlsx-exporter.ts +5 -4
- package/src/generators/gherkin-parser/index.ts +0 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/contain-text-assertion.hbs +1 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -13
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -9
- package/src/generators/test-generator/code-generator.ts +17 -4
- package/src/generators/test-generator/diagnostics.ts +3 -9
- package/src/generators/test-generator/patterns/types.ts +0 -2
- package/src/generators/test-generator/step-mapper.ts +9 -56
- package/src/generators/test-generator/utils/data-resolver.ts +0 -53
- package/src/generators/test-generator/utils/selector-resolver.ts +2 -10
- package/src/graph/board-human-actions.ts +80 -0
- package/src/graph/evaluate-graph.ts +97 -0
- package/src/graph/human-action.ts +33 -0
- package/src/graph/locate-finding.ts +93 -0
- package/src/graph/manual-triage-decisions.ts +55 -0
- package/src/graph/node-decl.ts +83 -0
- package/src/graph/nodes/core-node-catalog.ts +15 -0
- package/src/graph/nodes/test-case-contract-nodes.ts +90 -0
- package/src/graph/nodes/test-case-nodes.ts +100 -0
- package/src/graph/nodes/unit-audit-nodes.ts +96 -0
- package/src/graph/nodes/unit-contract-node.ts +100 -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 +111 -0
- package/src/graph/test-case-satisfied.ts +58 -0
- package/src/graph/test-case-state-shape.ts +67 -0
- package/src/graph/test-case-states.ts +84 -0
- package/src/graph/unit-artifact-probes.ts +79 -0
- package/src/graph/unit-results-freshness.ts +165 -0
- package/src/graph/unit-state-facts.ts +112 -0
- package/src/harness/audit.ts +31 -18
- package/src/harness/catalog/gate-rules.yaml +647 -0
- package/src/harness/defect-draft.ts +13 -2
- package/src/harness/defects.ts +22 -9
- package/src/harness/flow-check.ts +11 -0
- package/src/harness/gates/audit-gate-terms.ts +80 -0
- package/src/harness/gates/audit-gate-verdict.ts +79 -0
- package/src/harness/gates/audit-input-hash.ts +79 -0
- package/src/harness/gates/audit-report-verification.ts +206 -0
- package/src/harness/gates/decisions-hash.ts +42 -0
- package/src/harness/gates/delivery-checklist.ts +152 -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 +124 -0
- package/src/harness/gates/journey-gate-inputs.ts +89 -0
- package/src/harness/gates/migrated-waiver-import-bounds.ts +103 -0
- package/src/harness/gates/migrated-waiver-review.ts +121 -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 +287 -39
- package/src/harness/manifest.ts +67 -43
- package/src/harness/next-step.ts +91 -193
- package/src/harness/parse.ts +20 -2
- package/src/harness/provenance.ts +99 -11
- package/src/harness/script-check.ts +20 -5
- package/src/harness/sensors.ts +47 -40
- package/src/harness/triage-manual-classification.ts +76 -0
- package/src/harness/unit-paths.ts +19 -0
- package/src/hooks/bash-read-only-segment.ts +130 -0
- package/src/hooks/bash-write-targets.ts +195 -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 +80 -0
- package/src/hooks/guard-rules.ts +117 -0
- package/src/hooks/guard-tty-spoof-rule.ts +34 -0
- package/src/hooks/hand-back-core.ts +118 -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 +59 -0
- package/src/hooks/stop-next-step-hook.ts +38 -0
- package/src/hooks/sungen-project-root.ts +80 -0
- package/src/index.ts +1 -2
- package/src/orchestrator/ai-skills/command-partial-includes.ts +72 -0
- package/src/orchestrator/ai-skills/commands.ts +17 -5
- 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/templates/ai-src/commands/add-api.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/add-flow.md +6 -26
- 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 +17 -16
- package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/delivery.md +4 -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 +4 -0
- package/src/orchestrator/templates/ai-src/commands/run-test.md +6 -8
- 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/partials/waiting-for-you.claude.md +11 -0
- package/src/orchestrator/templates/ai-src/partials/waiting-for-you.codex.md +11 -0
- package/src/orchestrator/templates/ai-src/partials/waiting-for-you.copilot.md +11 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +1 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +4 -5
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +8 -24
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +3 -4
- package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/src/orchestrator/templates/specs-test-data.ts +4 -22
- package/src/utils/safe-yaml-parse.ts +44 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/expanded-assertion.hbs +0 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/date-picker-unsupported.hbs +0 -5
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/expanded-assertion.hbs +0 -12
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/expanded-assertion.hbs +0 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/date-picker-unsupported.hbs +0 -5
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/expanded-assertion.hbs +0 -12
|
@@ -0,0 +1,144 @@
|
|
|
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 { FileRead, readFileOnce } from './read-file-once';
|
|
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
|
+
/**
|
|
128
|
+
* A trace opened once (read-file-once.ts) → parsed: the size was checked on the descriptor BEFORE it
|
|
129
|
+
* was read into memory. `missing` / `outside` are the caller's to report; here they throw.
|
|
130
|
+
*/
|
|
131
|
+
export function traceFromRead(read: FileRead, label: string, limits: TraceZipLimits = traceZipLimits()): ParsedTrace {
|
|
132
|
+
switch (read.status) {
|
|
133
|
+
case 'read': return readTraceBuffer(read.bytes, read.real, limits);
|
|
134
|
+
case 'too-large': throw new TraceRejected('zip.too-large', `${read.size} B > ${limits.maxZipBytes}`);
|
|
135
|
+
case 'not-a-file': throw new TraceRejected('zip.malformed', `${label} is not a regular file`);
|
|
136
|
+
case 'missing': throw new TraceRejected('zip.malformed', `${label} does not exist`);
|
|
137
|
+
default: throw new TraceRejected('zip.malformed', `${label} was not read: ${read.why}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Read a trace from a trusted path (a fixture, a test): a regular file, opened once. */
|
|
142
|
+
export function readTraceFile(file: string, limits: TraceZipLimits = traceZipLimits()): ParsedTrace {
|
|
143
|
+
return traceFromRead(readFileOnce(file, limits.maxZipBytes), file, limits);
|
|
144
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A trace → its contract fingerprint: the rendered Gherkin steps normalized by the SAME parser and
|
|
3
|
+
* normalizer a hand-written `.feature` goes through (DOS-14.1), then hashed with the implementation
|
|
4
|
+
* path (DOS-14.2). So the fingerprint of a trace and the lock of the `.free.feature` derived from it
|
|
5
|
+
* are equal by construction — not by a second, parallel normalizer that could drift.
|
|
6
|
+
*
|
|
7
|
+
* The rendered steps are written to a throw-away `.feature` and read back with
|
|
8
|
+
* `scenariosOfFeatureFile`; nothing else in the pipeline parses Gherkin.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'fs';
|
|
11
|
+
import * as os from 'os';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { contractHash } from '../contract-hash';
|
|
14
|
+
import type { ContractStep, Implementation } from '../contract-schema';
|
|
15
|
+
import { scenariosOfFeatureFile } from '../normalize-feature-steps';
|
|
16
|
+
import type { RenderedStep } from '../render-free-gherkin';
|
|
17
|
+
|
|
18
|
+
const KEYWORD = /^(Given|When|Then|And|But)\s/;
|
|
19
|
+
|
|
20
|
+
/** Normalize several step lists in one parse; `lines[i]` are full Gherkin lines (keyword first). */
|
|
21
|
+
export function normalizeGherkinLines(blocks: string[][]): ContractStep[][] {
|
|
22
|
+
if (!blocks.length) return [];
|
|
23
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'sungen-fingerprint-'));
|
|
24
|
+
try {
|
|
25
|
+
const file = path.join(dir, 'fingerprint.feature');
|
|
26
|
+
const text = ['Feature: fingerprint', '', ...blocks.flatMap((lines, i) => [
|
|
27
|
+
` Scenario: FP-${i + 1}0`, ...lines.map((l) => ` ${KEYWORD.test(l.trim()) ? l.trim() : `When ${l.trim()}`}`), '',
|
|
28
|
+
])].join('\n');
|
|
29
|
+
fs.writeFileSync(file, text);
|
|
30
|
+
const parsed = scenariosOfFeatureFile(file);
|
|
31
|
+
if (parsed.length !== blocks.length) throw new Error(`fingerprint: ${blocks.length} step lists normalized to ${parsed.length} scenarios`);
|
|
32
|
+
return parsed.map((s) => s.steps);
|
|
33
|
+
} finally {
|
|
34
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface TraceFingerprint {
|
|
39
|
+
steps: ContractStep[];
|
|
40
|
+
hash: string;
|
|
41
|
+
rendered: RenderedStep[];
|
|
42
|
+
/** impl:code: each `test.step` title (normalized) and the indexes of the steps it holds. */
|
|
43
|
+
groups: Array<{ title: string; titleStep: ContractStep; members: number[] }>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Many fingerprints from ONE temp-file parse (a unit's scenarios × runs) — the guard path's cost. */
|
|
47
|
+
export function fingerprintsOf(items: Array<{ rendered: RenderedStep[]; implementation: Implementation }>): TraceFingerprint[] {
|
|
48
|
+
const blocks: string[][] = [];
|
|
49
|
+
const plan = items.map(({ rendered, implementation }) => {
|
|
50
|
+
const titles = implementation === 'impl:code' ? [...new Set(rendered.map((r) => r.group).filter((g): g is string => !!g))] : [];
|
|
51
|
+
const at = blocks.push(rendered.map((r) => `${r.keyword} ${r.sentence}`)) - 1;
|
|
52
|
+
const titlesAt = titles.length ? blocks.push(titles) - 1 : -1;
|
|
53
|
+
return { at, titlesAt, titles };
|
|
54
|
+
});
|
|
55
|
+
const normalized = normalizeGherkinLines(blocks);
|
|
56
|
+
return items.map(({ rendered, implementation }, i) => {
|
|
57
|
+
const { at, titlesAt, titles } = plan[i];
|
|
58
|
+
const steps = normalized[at];
|
|
59
|
+
const titleSteps = titlesAt >= 0 ? normalized[titlesAt] : [];
|
|
60
|
+
const groups = titles.map((title, k) => ({
|
|
61
|
+
title, titleStep: titleSteps[k], members: rendered.map((r, j) => (r.group === title ? j : -1)).filter((j) => j >= 0),
|
|
62
|
+
}));
|
|
63
|
+
return { steps, hash: contractHash(implementation, steps), rendered, groups };
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const fingerprintOf = (rendered: RenderedStep[], implementation: Implementation): TraceFingerprint =>
|
|
68
|
+
fingerprintsOf([{ rendered, implementation }])[0];
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is a trace newer than the contract it is asked to prove? (DOS-14.6: a trace older than the
|
|
3
|
+
* `.feature` or the lock is refused.) Judged by CONTENT, never by file time alone (#967): a `touch`,
|
|
4
|
+
* a checkout or a fresh clone changes no byte, so it stales nothing; an edit after the run always does.
|
|
5
|
+
*
|
|
6
|
+
* schema 2 record the reporter hashed every `.feature` and `contracts.lock.yaml` under `qa/` when
|
|
7
|
+
* the run started. Each of the unit's contract files must hash NOW to what the run
|
|
8
|
+
* saw: one that changed since, or did not exist yet, is newer than the trace → stale
|
|
9
|
+
* schema 1 record an older reporter recorded no content, so the files are dated against the run's
|
|
10
|
+
* start (the record's `startedAt`): one last written before it is older than the run;
|
|
11
|
+
* one written after it still is when git holds it unchanged and the commit that last
|
|
12
|
+
* changed it is an ancestor of HEAD committed before the run started (its bytes ARE
|
|
13
|
+
* that commit's). Anything else — edited, uncommitted, untracked, committed after the
|
|
14
|
+
* run started, no git, git failed or slow — is stale: fail closed.
|
|
15
|
+
*
|
|
16
|
+
* Limit of the schema-1 path: a commit time is what the committer's clock (or GIT_COMMITTER_DATE) said,
|
|
17
|
+
* so a backdated commit passes the time check — time-based checks cannot see through that. Schema 2
|
|
18
|
+
* compares content and retires this path: re-running the free tests once with the current reporter is
|
|
19
|
+
* the remedy.
|
|
20
|
+
*/
|
|
21
|
+
import { execFileSync } from 'child_process';
|
|
22
|
+
import { createHash } from 'crypto';
|
|
23
|
+
import * as fs from 'fs';
|
|
24
|
+
import * as path from 'path';
|
|
25
|
+
import { lockPathFor } from '../contracts-lock-file';
|
|
26
|
+
import { contractFeatureFiles } from '../normalize-feature-steps';
|
|
27
|
+
import type { RunRecord } from './trace-run-record';
|
|
28
|
+
|
|
29
|
+
interface ContractFile { rel: string; sha: string; mtimeMs: number }
|
|
30
|
+
interface LastCommit { sha: string; ms: number }
|
|
31
|
+
/** A unit's contract as it is NOW — its `.feature` files and lock, read once per verdict. */
|
|
32
|
+
export interface UnitContract {
|
|
33
|
+
projectRoot: string;
|
|
34
|
+
files: ContractFile[];
|
|
35
|
+
/** Schema 1 only, asked of git at most once: project path → the last commit that changed each file git holds unchanged. */
|
|
36
|
+
committed?: Map<string, LastCommit> | null;
|
|
37
|
+
/** Schema 1 only: commit → is it an ancestor of HEAD (asked once per commit). */
|
|
38
|
+
ancestors?: Map<string, boolean>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Inside the Claude Code guard too: a slow git leaves a schema-1 trace stale rather than the hook waiting. */
|
|
42
|
+
const GIT_TIMEOUT_MS = 2_000;
|
|
43
|
+
const posix = (p: string): string => p.split(path.sep).join('/');
|
|
44
|
+
|
|
45
|
+
export function unitContract(projectRoot: string, unit: { name: string; dir: string }): UnitContract {
|
|
46
|
+
const root = path.resolve(projectRoot);
|
|
47
|
+
const lock = path.resolve(lockPathFor(unit.dir));
|
|
48
|
+
const files = [...(fs.existsSync(lock) ? [lock] : []), ...contractFeatureFiles(unit.dir, unit.name)].map((abs) => {
|
|
49
|
+
let sha = 'unreadable'; // never equal to a recorded sha256: an unreadable contract file is stale
|
|
50
|
+
let mtimeMs = Number.POSITIVE_INFINITY;
|
|
51
|
+
try { sha = createHash('sha256').update(fs.readFileSync(abs)).digest('hex'); mtimeMs = fs.statSync(abs).mtimeMs; } catch { /* stale */ }
|
|
52
|
+
return { rel: posix(path.relative(root, abs)), sha, mtimeMs };
|
|
53
|
+
});
|
|
54
|
+
return { projectRoot: root, files };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function git(cwd: string, args: string[]): string | null {
|
|
58
|
+
try { return execFileSync('git', args, { cwd, stdio: ['ignore', 'pipe', 'ignore'], timeout: GIT_TIMEOUT_MS, maxBuffer: 16 * 1024 * 1024 }).toString('utf8'); } catch { return null; }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Each contract file git holds unchanged → the last commit (first-parent history, merges included)
|
|
63
|
+
* that changed it, with its committer time. Two git calls for the whole unit; null when git cannot say.
|
|
64
|
+
* Paths are passed as literal pathspecs: no glob or `:(magic)` reading of a unit's file names.
|
|
65
|
+
*/
|
|
66
|
+
function committedTimes(c: UnitContract): Map<string, LastCommit> | null {
|
|
67
|
+
if (c.committed !== undefined) return c.committed;
|
|
68
|
+
const rels = c.files.map((f) => f.rel);
|
|
69
|
+
const changed = git(c.projectRoot, ['--literal-pathspecs', 'diff', '--name-only', '--relative', '-z', 'HEAD', '--', ...rels]);
|
|
70
|
+
const log = git(c.projectRoot, ['-c', 'core.quotePath=false', '--literal-pathspecs', 'log', '--first-parent', '-m', '-n', '500', '--format=%x01%H %ct', '--name-only', '--relative', '--', ...rels]);
|
|
71
|
+
if (changed === null || log === null) return (c.committed = null);
|
|
72
|
+
const dirty = new Set(changed.split('\0').filter(Boolean));
|
|
73
|
+
const times = new Map<string, LastCommit>();
|
|
74
|
+
let at: LastCommit | null = null;
|
|
75
|
+
for (const raw of log.split('\n')) {
|
|
76
|
+
const line = raw.trim();
|
|
77
|
+
if (raw.startsWith('\x01')) {
|
|
78
|
+
const [sha, ct] = raw.slice(1).trim().split(' ');
|
|
79
|
+
at = /^[0-9a-f]{40,64}$/.test(sha ?? '') && Number(ct) > 0 ? { sha, ms: Number(ct) * 1000 } : null;
|
|
80
|
+
} else if (line && at && !times.has(line) && !dirty.has(line)) times.set(line, at);
|
|
81
|
+
}
|
|
82
|
+
return (c.committed = times);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Is `sha` an ancestor of HEAD? First-parent history says so already; asserted, never assumed. */
|
|
86
|
+
function isAncestorOfHead(c: UnitContract, sha: string): boolean {
|
|
87
|
+
if (!c.ancestors) c.ancestors = new Map();
|
|
88
|
+
if (!c.ancestors.has(sha)) c.ancestors.set(sha, git(c.projectRoot, ['merge-base', '--is-ancestor', sha, 'HEAD']) !== null);
|
|
89
|
+
return c.ancestors.get(sha)!;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Why a trace bound to `record` is older than the unit's contract — null when it is not. */
|
|
93
|
+
export function staleReason(c: UnitContract, record: RunRecord): string | null {
|
|
94
|
+
if (record.contract) {
|
|
95
|
+
const f = c.files.find((x) => record.contract![x.rel] !== x.sha);
|
|
96
|
+
if (!f) return null;
|
|
97
|
+
const why = record.contract[f.rel] === undefined ? 'it did not exist when the run started' : 'its content changed after the run';
|
|
98
|
+
return `the trace is older than ${f.rel}: ${why} (stale) — re-run the test`;
|
|
99
|
+
}
|
|
100
|
+
const runStart = Date.parse(record.startedAt); // unreadable → nothing is "before the run": stale
|
|
101
|
+
const late = c.files.filter((f) => !(f.mtimeMs <= runStart));
|
|
102
|
+
if (!late.length) return null;
|
|
103
|
+
const committed = committedTimes(c);
|
|
104
|
+
const vouched = (rel: string): boolean => {
|
|
105
|
+
const last = committed?.get(rel);
|
|
106
|
+
return !!last && last.ms <= runStart && isAncestorOfHead(c, last.sha);
|
|
107
|
+
};
|
|
108
|
+
const f = late.find((x) => !vouched(x.rel));
|
|
109
|
+
return f ? `the trace is older than ${f.rel}: it was written after the run, and no commit from before the run holds its bytes (stale) — re-run the test` : null;
|
|
110
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every target of a trace → its identity (DOS-14.5): the driver's answer from the identity cache
|
|
3
|
+
* when one exists for the exact HTML core rendered, otherwise core's heuristic (always `low`).
|
|
4
|
+
*
|
|
5
|
+
* `resolveWithDriver` is the only asynchronous part of trace conformance: it renders the snapshots,
|
|
6
|
+
* asks the registered `traceIdentity` resolver (driver-ui: a real browser, JS off, every request
|
|
7
|
+
* blocked) for the ones not cached yet, and writes the cache. Everything else stays a plain
|
|
8
|
+
* function of the files on disk, so the CLI and the Claude Code guard build the same verdict.
|
|
9
|
+
*/
|
|
10
|
+
import { CachedIdentity, IdentityCache, readIdentityCache, writeIdentityCache } from './identity-cache';
|
|
11
|
+
import { resolveCallTarget, CallTarget } from './snapshot-resolver';
|
|
12
|
+
import { SnapshotStore } from './snapshot-store';
|
|
13
|
+
import { heuristicIdentity, TraceIdentityRequest, TraceIdentityResolver, TRUSTED_RESOLVER, validIdentityResult } from './target-identity';
|
|
14
|
+
import type { ParsedTrace } from './trace-file-reader';
|
|
15
|
+
import { traceIntentSteps, IntentStep } from './trace-steps';
|
|
16
|
+
import type { ResolvedTarget } from '../render-free-gherkin';
|
|
17
|
+
|
|
18
|
+
const NO_DRIVER = 'no driver identity yet — run `sungen contract check --trace` (needs @sungen/driver-ui and a browser)';
|
|
19
|
+
|
|
20
|
+
/** Steps aimed at the page itself carry no element identity. */
|
|
21
|
+
export const isPageLevel = (s: IntentStep): boolean =>
|
|
22
|
+
s.method === 'goto' || /^keyboard/.test(s.method) || /^to\.have\.(url|title)$/.test(String(s.params.expression ?? '')) || s.kind.startsWith('opaque');
|
|
23
|
+
|
|
24
|
+
function targetCalls(trace: ParsedTrace, steps: IntentStep[]): Array<{ callId: string; target: CallTarget | null }> {
|
|
25
|
+
const store = new SnapshotStore(trace.library);
|
|
26
|
+
return steps.filter((s) => s.callId && !isPageLevel(s)).map((s) => ({ callId: s.callId!, target: resolveCallTarget(store, trace, s.callId!) }));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function identitiesFor(trace: ParsedTrace, steps: IntentStep[], cache: IdentityCache): Map<string, ResolvedTarget> {
|
|
30
|
+
const out = new Map<string, ResolvedTarget>();
|
|
31
|
+
for (const { callId, target } of targetCalls(trace, steps)) {
|
|
32
|
+
if (!target) { out.set(callId, { identity: heuristicIdentity(null, 'no snapshot marks this target') }); continue; }
|
|
33
|
+
const hit = cache.entries.get(target.snapshotSha256);
|
|
34
|
+
if (!hit) { out.set(callId, { identity: heuristicIdentity(target.facts, NO_DRIVER), facts: target.facts }); continue; }
|
|
35
|
+
// What core already knows (missing CSS, broken refs) caps the driver's answer, whatever it says.
|
|
36
|
+
const reasons = [...target.capReasons, ...hit.reasons];
|
|
37
|
+
out.set(callId, {
|
|
38
|
+
identity: { ...hit, identityConfidence: reasons.length ? 'low' : hit.identityConfidence, reasons, source: 'driver' },
|
|
39
|
+
facts: target.facts,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** One replay request per element target of a trace, keyed by the sha256 of its rendered HTML. */
|
|
46
|
+
export function identityRequestsFor(trace: ParsedTrace): TraceIdentityRequest[] {
|
|
47
|
+
return targetCalls(trace, traceIntentSteps(trace)).filter((t) => t.target).map(({ callId, target }) => ({
|
|
48
|
+
key: target!.snapshotSha256, html: target!.html, viewport: target!.viewport,
|
|
49
|
+
targetSelector: `[__playwright_target__="${callId}"]`, capReasons: target!.capReasons,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Ask the driver about every not-yet-cached target of these traces; rewrite the cache. */
|
|
54
|
+
/** `keys`: every target of the given traces (cached or asked) — what the caller reports on. */
|
|
55
|
+
export async function resolveWithDriver(projectRoot: string, traces: ParsedTrace[], resolver: TraceIdentityResolver): Promise<{ asked: number; resolver: string; blockedRequests: number; keys: string[] }> {
|
|
56
|
+
const { cache } = readIdentityCache(projectRoot);
|
|
57
|
+
// The cache is project-wide (every unit's traces): answers are only ever ADDED, never pruned here.
|
|
58
|
+
const keep = new Map<string, CachedIdentity>(cache.entries);
|
|
59
|
+
const all = traces.flatMap(identityRequestsFor);
|
|
60
|
+
const keys = [...new Set(all.map((req) => req.key))];
|
|
61
|
+
const requests = new Map<string, TraceIdentityRequest>();
|
|
62
|
+
for (const req of all) if (!keep.has(req.key)) requests.set(req.key, req);
|
|
63
|
+
if (!requests.size) return { asked: 0, resolver: cache.resolver, blockedRequests: 0, keys };
|
|
64
|
+
const answer = await resolver({ requests: [...requests.values()] });
|
|
65
|
+
if (!answer || !Array.isArray(answer.results)) throw new Error('the trace identity resolver returned no results');
|
|
66
|
+
if (!TRUSTED_RESOLVER.test(String(answer.resolver)) || typeof answer.browser !== 'string' || !answer.browser) {
|
|
67
|
+
throw new Error(`the trace identity resolver "${String(answer.resolver).slice(0, 40)}" is not driver-ui's, or named no browser — its answers are not kept`);
|
|
68
|
+
}
|
|
69
|
+
for (const raw of answer.results) {
|
|
70
|
+
const r = validIdentityResult(raw);
|
|
71
|
+
if (!r || !requests.has(r.key)) throw new Error(`the trace identity resolver returned a malformed or unasked-for result (${JSON.stringify(raw).slice(0, 120)})`);
|
|
72
|
+
const { key, ...rest } = r;
|
|
73
|
+
keep.set(key, { ...rest, browser: answer.browser.slice(0, 100) });
|
|
74
|
+
}
|
|
75
|
+
writeIdentityCache(projectRoot, answer.resolver, keep);
|
|
76
|
+
return { asked: requests.size, resolver: String(answer.resolver), blockedRequests: Number(answer.blockedRequests) || 0, keys };
|
|
77
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sungen's own run record (G5, DOS-14.6): written by `@sungen/driver-ui`'s run-record reporter
|
|
3
|
+
* next to the traces, read here STRICTLY — it is the only place a trace's run id and the hash of
|
|
4
|
+
* the code that produced it live, so an unknown key, a wrong type or a malformed hash means the
|
|
5
|
+
* record is not trusted at all (every trace it would vouch for is unbound).
|
|
6
|
+
*
|
|
7
|
+
* Found by convention: `<project>/test-results-free/sungen-run-record*.json` — the free-test config's
|
|
8
|
+
* own outputDir (#941) — or `<project>/test-results/sungen-run-record*.json` (one per run or shard).
|
|
9
|
+
* Playwright wipes its outputDir at the start of every run, so a record and its traces share a
|
|
10
|
+
* lifetime; the free run has its own so the compiled suite's next run cannot delete its traces.
|
|
11
|
+
*
|
|
12
|
+
* Schema 2 (#967) adds `contract`: the sha256 of every `.feature` and `contracts.lock.yaml` under `qa/`
|
|
13
|
+
* when the run started — what trace freshness compares by content. Schema 1 (an older reporter) has
|
|
14
|
+
* none; its traces are dated instead (trace-freshness.ts).
|
|
15
|
+
*/
|
|
16
|
+
import * as fs from 'fs';
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
|
|
19
|
+
export interface RunRecordAttempt {
|
|
20
|
+
testId: string; file: string; title: string; retry: number; status: string;
|
|
21
|
+
startTime: string; duration: number; trace: { sha256: string } | null;
|
|
22
|
+
}
|
|
23
|
+
export interface RunRecord {
|
|
24
|
+
file: string;
|
|
25
|
+
runId: string;
|
|
26
|
+
startedAt: string;
|
|
27
|
+
playwrightVersion: string;
|
|
28
|
+
shard: string | null;
|
|
29
|
+
report: string | null;
|
|
30
|
+
specs: Record<string, string>;
|
|
31
|
+
/** Schema 2: project path → sha256 of each contract file at run start. null: schema 1 (no content recorded). */
|
|
32
|
+
contract: Record<string, string> | null;
|
|
33
|
+
attempts: RunRecordAttempt[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const TOP_V1: ReadonlySet<string> = new Set(['schema', 'tool', 'runId', 'startedAt', 'playwrightVersion', 'shard', 'report', 'specs', 'attempts']);
|
|
37
|
+
const TOP_V2: ReadonlySet<string> = new Set([...TOP_V1, 'contract']);
|
|
38
|
+
const ATTEMPT = new Set(['testId', 'file', 'title', 'retry', 'status', 'startTime', 'duration', 'trace']);
|
|
39
|
+
const SHA = /^[0-9a-f]{64}$/;
|
|
40
|
+
const isObj = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
41
|
+
|
|
42
|
+
/** The free / impl:code run's own outputDir (the documented free-test config); compiled runs clear `test-results/`. */
|
|
43
|
+
export const FREE_RUN_DIR = 'test-results-free';
|
|
44
|
+
/** Where run records are read, in this order: the free run's dir, then Playwright's default (older configs). */
|
|
45
|
+
export const RUN_RECORD_DIRS: readonly string[] = [FREE_RUN_DIR, 'test-results'];
|
|
46
|
+
|
|
47
|
+
export function findRunRecords(projectRoot: string): string[] {
|
|
48
|
+
return RUN_RECORD_DIRS.flatMap((rel) => {
|
|
49
|
+
const dir = path.join(projectRoot, rel);
|
|
50
|
+
let names: string[];
|
|
51
|
+
try { names = fs.readdirSync(dir); } catch { return []; }
|
|
52
|
+
return names.filter((n) => /^sungen-run-record(?:\.[A-Za-z0-9._-]+)?\.json$/.test(n)).sort().map((n) => path.join(dir, n));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function attemptOf(raw: unknown, i: number): RunRecordAttempt {
|
|
57
|
+
const at = `attempt ${i + 1}`;
|
|
58
|
+
if (!isObj(raw)) throw new Error(`${at} is not an object`);
|
|
59
|
+
const extra = Object.keys(raw).find((k) => !ATTEMPT.has(k));
|
|
60
|
+
if (extra) throw new Error(`${at} has an unknown key "${extra}"`);
|
|
61
|
+
const { testId, file, title, retry, status, startTime, duration, trace } = raw;
|
|
62
|
+
if (typeof testId !== 'string' || typeof file !== 'string' || typeof title !== 'string' || typeof status !== 'string') throw new Error(`${at}: testId, file, title and status must be strings`);
|
|
63
|
+
if (!Number.isInteger(retry) || (retry as number) < 0 || typeof duration !== 'number' || typeof startTime !== 'string' || Number.isNaN(Date.parse(startTime))) {
|
|
64
|
+
throw new Error(`${at}: retry, duration and startTime are malformed`);
|
|
65
|
+
}
|
|
66
|
+
if (trace !== null && !(isObj(trace) && Object.keys(trace).length === 1 && typeof trace.sha256 === 'string' && SHA.test(trace.sha256))) throw new Error(`${at}: trace must be null or {sha256}`);
|
|
67
|
+
return { testId, file, title, retry: retry as number, status, startTime, duration, trace: trace as RunRecordAttempt['trace'] };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Read and check one record (`text`: its bytes, already read once by the caller); throws an Error naming what is wrong. */
|
|
71
|
+
export function readRunRecord(file: string, text?: string): RunRecord {
|
|
72
|
+
let raw: unknown;
|
|
73
|
+
try { raw = JSON.parse(text ?? fs.readFileSync(file, 'utf8')); } catch (e) { throw new Error(`not readable JSON (${(e as Error).message.split('\n')[0]})`); }
|
|
74
|
+
if (!isObj(raw)) throw new Error('not an object');
|
|
75
|
+
if (raw.tool === 'sungen-trace-run-record' && typeof raw.schema === 'number' && raw.schema > 2) {
|
|
76
|
+
// A newer driver-ui wrote it (mixed versions): say what to upgrade, not just "not a record".
|
|
77
|
+
throw new Error(`record schema ${raw.schema} is newer than this sungen — upgrade @sun-asterisk/sungen (core before or together with driver-ui)`);
|
|
78
|
+
}
|
|
79
|
+
const keys = raw.schema === 2 ? TOP_V2 : raw.schema === 1 ? TOP_V1 : null;
|
|
80
|
+
if (!keys || raw.tool !== 'sungen-trace-run-record') throw new Error('not a sungen run record (schema 1 or 2)');
|
|
81
|
+
const extra = Object.keys(raw).find((k) => !keys.has(k));
|
|
82
|
+
if (extra) throw new Error(`unknown key "${extra}"`);
|
|
83
|
+
if (typeof raw.runId !== 'string' || !raw.runId || typeof raw.startedAt !== 'string' || typeof raw.playwrightVersion !== 'string') throw new Error('runId, startedAt and playwrightVersion must be strings');
|
|
84
|
+
if (raw.shard !== null && typeof raw.shard !== 'string') throw new Error('shard must be a string or null');
|
|
85
|
+
if (raw.report !== null && typeof raw.report !== 'string') throw new Error('report must be a string or null');
|
|
86
|
+
if (!isObj(raw.specs) || !Object.values(raw.specs).every((v) => typeof v === 'string' && (v === '' || SHA.test(v)))) throw new Error('specs must map files to sha256');
|
|
87
|
+
if (raw.schema === 2 && !(isObj(raw.contract) && Object.values(raw.contract).every((v) => typeof v === 'string' && SHA.test(v)))) {
|
|
88
|
+
throw new Error('contract must map contract files to sha256 (schema 2)');
|
|
89
|
+
}
|
|
90
|
+
if (!Array.isArray(raw.attempts)) throw new Error('attempts must be a list');
|
|
91
|
+
return {
|
|
92
|
+
file, runId: raw.runId, startedAt: raw.startedAt, playwrightVersion: raw.playwrightVersion, shard: raw.shard as string | null,
|
|
93
|
+
report: raw.report as string | null, specs: raw.specs as Record<string, string>,
|
|
94
|
+
contract: raw.schema === 2 ? raw.contract as Record<string, string> : null, attempts: raw.attempts.map(attemptOf),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A trace → the test's INTENT, in order (phase 08 requirement 1). What is kept:
|
|
3
|
+
*
|
|
4
|
+
* action Frame goto / click / dblclick / fill / check / uncheck / selectOption / press /
|
|
5
|
+
* hover / setInputFiles / type / tap, and page keyboard presses
|
|
6
|
+
* assert Frame.expect — a check on an element or the page (url, title)
|
|
7
|
+
* opaque-assert a runner `expect` with no browser call behind it: `expect(await res.json())…`,
|
|
8
|
+
* a check on a JS value — cannot be compared, always review (DOS-14.6)
|
|
9
|
+
* opaque-action an API request, an `evaluate` (canvas…) — behaviour the contract cannot see into
|
|
10
|
+
*
|
|
11
|
+
* Dropped as implementation detail: waits (`waitForTimeout`, `waitFor*`), reads (`textContent`,
|
|
12
|
+
* `isVisible`…), context/page plumbing, and everything in fixtures, runner hooks and teardown —
|
|
13
|
+
* only the body and user `beforeEach` hooks are the test's behaviour. A focus click right before a
|
|
14
|
+
* fill on the same element is dropped later, once identities say "same element" (render step).
|
|
15
|
+
*/
|
|
16
|
+
import { classifyStep, isBehaviour, joinCalls, RunnerStep } from './test-step-join';
|
|
17
|
+
import type { ParsedTrace, StackFrame } from './trace-file-reader';
|
|
18
|
+
|
|
19
|
+
export type IntentKind = 'action' | 'assert' | 'opaque-action' | 'opaque-assert';
|
|
20
|
+
export interface IntentStep {
|
|
21
|
+
kind: IntentKind;
|
|
22
|
+
method: string;
|
|
23
|
+
callId?: string;
|
|
24
|
+
params: Record<string, unknown>;
|
|
25
|
+
/** Enclosing `test.step` titles, outermost first (impl:code compares by the first). */
|
|
26
|
+
group: string[];
|
|
27
|
+
location?: { file: string; line: number };
|
|
28
|
+
/** The runner's own words for an opaque step (`Expect "toMatchObject"`, `GET /api/health`). */
|
|
29
|
+
verbatim?: string;
|
|
30
|
+
startTime: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const FRAME_ACTIONS = new Set(['goto', 'click', 'dblclick', 'fill', 'check', 'uncheck', 'selectOption', 'press', 'hover', 'setInputFiles', 'type', 'tap']);
|
|
34
|
+
const PAGE_KEYS = new Set(['keyboardPress', 'keyboardType', 'keyboardInsertText']);
|
|
35
|
+
const EVALUATE = /^evaluate/;
|
|
36
|
+
|
|
37
|
+
/** The first frame in the test's own code (not a library, not the runner's `project#` marker). */
|
|
38
|
+
function firstFrame(frames: StackFrame[] | undefined): { file: string; line: number } | undefined {
|
|
39
|
+
const f = frames?.find((x) => x.file && !x.file.includes('node_modules') && !x.file.endsWith('#'));
|
|
40
|
+
return f ? { file: f.file, line: f.line } : undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function groupOf(steps: Map<string, RunnerStep>, stepId: string | undefined): string[] {
|
|
44
|
+
if (!stepId) return [];
|
|
45
|
+
const w = classifyStep(steps, stepId);
|
|
46
|
+
return w.phase === 'body' ? w.stepPath : [];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function traceIntentSteps(trace: ParsedTrace): IntentStep[] {
|
|
50
|
+
const { steps, calls } = joinCalls(trace);
|
|
51
|
+
const stacks = new Map(trace.library.map((l) => [l.name, l.stacks]));
|
|
52
|
+
const out: IntentStep[] = [];
|
|
53
|
+
const withCall = new Set(calls.map((c) => c.stepId).filter((s): s is string => !!s));
|
|
54
|
+
|
|
55
|
+
for (const c of calls) {
|
|
56
|
+
if (!isBehaviour(c.where)) continue;
|
|
57
|
+
let kind: IntentKind | null = null;
|
|
58
|
+
let verbatim: string | undefined;
|
|
59
|
+
if (c.class === 'Frame' && FRAME_ACTIONS.has(c.method)) kind = 'action';
|
|
60
|
+
else if (c.class === 'Frame' && c.method === 'expect') kind = 'assert';
|
|
61
|
+
else if (c.class === 'Page' && PAGE_KEYS.has(c.method)) kind = 'action';
|
|
62
|
+
else if (c.class === 'APIRequestContext' && c.method === 'fetch') {
|
|
63
|
+
kind = 'opaque-action';
|
|
64
|
+
verbatim = `${String(c.params.method ?? 'GET')} ${String(c.params.url ?? '')}`;
|
|
65
|
+
} else if (EVALUATE.test(c.method) && /^(Frame|Page|JSHandle|ElementHandle|Worker)$/.test(c.class)) {
|
|
66
|
+
kind = 'opaque-action';
|
|
67
|
+
verbatim = `${c.class}.${c.method}`;
|
|
68
|
+
}
|
|
69
|
+
if (!kind) continue;
|
|
70
|
+
const runner = c.stepId ? steps.get(c.stepId) : undefined;
|
|
71
|
+
out.push({
|
|
72
|
+
kind, method: c.method, callId: c.callId, params: c.params, group: groupOf(steps, c.stepId),
|
|
73
|
+
location: firstFrame(runner?.stack) ?? firstFrame(stacks.get(c.part)?.get(c.callId)),
|
|
74
|
+
...(verbatim ? { verbatim } : {}), startTime: c.startTime,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// A runner `expect` that drove no browser call checked a plain JS value: opaque.
|
|
79
|
+
const runnerStart = new Map(trace.runner.filter((e) => e.type === 'before').map((e) => [String(e.callId), Number(e.startTime) || 0]));
|
|
80
|
+
for (const s of steps.values()) {
|
|
81
|
+
if (s.method !== 'expect' || withCall.has(s.id) || !isBehaviour(classifyStep(steps, s.id))) continue;
|
|
82
|
+
out.push({
|
|
83
|
+
kind: 'opaque-assert', method: 'expect', params: s.params, group: groupOf(steps, s.id),
|
|
84
|
+
location: firstFrame(s.stack), verbatim: s.title, startTime: runnerStart.get(s.id) ?? 0,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return out.sort((a, b) => a.startTime - b.startTime);
|
|
88
|
+
}
|