@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,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every scenario id of a unit, locked or current, with its ladder class (DOS-14.3, DOS-14.4).
|
|
3
|
+
*
|
|
4
|
+
* approved entry, one current copy classifyScenario (the ladder)
|
|
5
|
+
* approved entry, no current copy assertion-lost
|
|
6
|
+
* approved entry, several copies assertion-lost — the lock can no longer tell which copy QA
|
|
7
|
+
* approved, and picking one would let the others hide (M7)
|
|
8
|
+
* no approved entry proposed (never blocks); a tampered entry counts as none
|
|
9
|
+
* Scenario Outline (any lock state) at least hash-changed: the compiler does not support the
|
|
10
|
+
* construct, so the contract cannot judge its Examples
|
|
11
|
+
*/
|
|
12
|
+
import { classifyScenario, finding, ScenarioResult, severityOf } from './classify-contract-change';
|
|
13
|
+
import { ContractLock, ContractScenario, isHumanApproved } from './contract-schema';
|
|
14
|
+
|
|
15
|
+
const OUTLINE = 'Scenario Outline is not supported by the compiler — the contract cannot judge its Examples rows; rewrite it as @cases data';
|
|
16
|
+
|
|
17
|
+
function withOutlineFinding(r: ScenarioResult): ScenarioResult {
|
|
18
|
+
const findings = [...r.findings, finding('hash-changed', OUTLINE)];
|
|
19
|
+
return { ...r, class: severityOf(r.class) >= severityOf('hash-changed') ? r.class : 'hash-changed', findings };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function classifyUnit(
|
|
23
|
+
lock: ContractLock | null, current: ContractScenario[], untrusted: ReadonlySet<string> = new Set(),
|
|
24
|
+
): { results: ScenarioResult[]; warnings: string[] } {
|
|
25
|
+
const groups = new Map<string, ContractScenario[]>();
|
|
26
|
+
for (const sc of current) groups.set(sc.id, [...(groups.get(sc.id) ?? []), sc]);
|
|
27
|
+
const approvedIds = Object.entries(lock?.scenarios ?? {}).filter(([id, e]) => isHumanApproved(e) && !untrusted.has(id)).map(([id]) => id);
|
|
28
|
+
const results: ScenarioResult[] = [];
|
|
29
|
+
const warnings: string[] = [];
|
|
30
|
+
for (const id of [...new Set([...approvedIds, ...groups.keys()])].sort((a, b) => a.localeCompare(b, 'en'))) {
|
|
31
|
+
const entry = lock?.scenarios[id];
|
|
32
|
+
const copies = groups.get(id) ?? [];
|
|
33
|
+
const approved = isHumanApproved(entry) && !untrusted.has(id);
|
|
34
|
+
let mine: ScenarioResult[];
|
|
35
|
+
if (!approved) {
|
|
36
|
+
if (copies.length > 1) warnings.push(`scenario id ${id} is used by ${copies.length} scenarios — give each its own ID before approving`);
|
|
37
|
+
mine = copies.map((c) => ({ id, class: 'proposed', findings: [], file: c.source.file }));
|
|
38
|
+
} else if (copies.length > 1) {
|
|
39
|
+
mine = [{ id, class: 'assertion-lost', file: copies[0].source.file, findings: [finding('assertion-lost',
|
|
40
|
+
`the approved id ${id} is now carried by ${copies.length} scenarios — the lock cannot tell which one QA approved; give each its own ID`)] }];
|
|
41
|
+
} else {
|
|
42
|
+
mine = [classifyScenario(id, entry!, copies[0])];
|
|
43
|
+
}
|
|
44
|
+
results.push(...(copies.some((c) => c.source.outline) ? mine.map(withOutlineFinding) : mine));
|
|
45
|
+
}
|
|
46
|
+
return { results, warnings };
|
|
47
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A free / impl:code scenario's traces against its approved lock entry (DOS-14.5 – 14.6) — the SAME
|
|
3
|
+
* strength ladder as the Gherkin check (DOS-14.4, oracle-strength.ts), fed from the trace fingerprint.
|
|
4
|
+
*
|
|
5
|
+
* free classifyScenario(lock entry, fingerprint): equal hash → match, else the ladder
|
|
6
|
+
* impl:code group by group: each approved step must be realized inside the `test.step` titled
|
|
7
|
+
* with that step — identically (fine), weaker (hard), stronger (strengthened), changed
|
|
8
|
+
* (review); an approved check with no group or no check in its group → assertion-lost
|
|
9
|
+
* overlays a step whose target identity is `low` → opaque (review, never match, red-team #4);
|
|
10
|
+
* an opaque step → opaque with its verbatim text and file:line (contract.opaque-step) —
|
|
11
|
+
* unless the approved entry lists it as accepted by QA at its sha (#923, opaqueStepSha):
|
|
12
|
+
* then a note, not a finding. impl:code: a test.step whose only candidates are opaque is
|
|
13
|
+
* left to the overlay (judged on the ladder it could only read "changed"), which names the
|
|
14
|
+
* approved step the opaque one replaces
|
|
15
|
+
* runs no admissible trace → unproven (all inconclusive → inconclusive) when APPROVED, a
|
|
16
|
+
* warning while proposed (M5, M6); a trace refused beside an admissible one → a warning;
|
|
17
|
+
* several admissible traces that fingerprint differently → nondeterministic (worst wins)
|
|
18
|
+
*/
|
|
19
|
+
import { classifyScenario, ContractFinding, finding, ScenarioResult, severityOf } from './classify-contract-change';
|
|
20
|
+
import { canonicalJson, sameJson, sha256Hex } from './contract-hash';
|
|
21
|
+
import type { AcceptedOpaqueStep, ContractStep, Implementation, LockEntry, OpaqueStep, ScenarioClass } from './contract-schema';
|
|
22
|
+
import { compareAsserts } from './oracle-strength';
|
|
23
|
+
import { clip, RenderedStep } from './render-free-gherkin';
|
|
24
|
+
import type { TraceRun } from './trace/collect-trace-evidence';
|
|
25
|
+
import type { TraceFingerprint } from './trace/trace-fingerprint';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* `warnings` never change the verdict: a not-yet-approved scenario's trace problems, unused traces, an
|
|
29
|
+
* accepted opaque step. `opaque`: every opaque step of the admissible traces, accepted or not.
|
|
30
|
+
*/
|
|
31
|
+
export interface TraceOutcome { class: ScenarioClass; findings: ContractFinding[]; hashes: string[]; runs: string[]; warnings: string[]; opaque: OpaqueStep[] }
|
|
32
|
+
|
|
33
|
+
/** What an unjudgeable scenario becomes: hard when QA locked it (approved), a warning while it is proposed. */
|
|
34
|
+
export function notJudged(id: string, approved: boolean, cls: 'unproven' | 'inconclusive', reasons: string[]): TraceOutcome {
|
|
35
|
+
return approved
|
|
36
|
+
? { class: cls, findings: reasons.map((r) => finding(cls, r)), hashes: [], runs: [], warnings: [], opaque: [] }
|
|
37
|
+
: { class: 'proposed', findings: [], hashes: [], runs: [], warnings: reasons.map((r) => `${id} (not approved yet, so a warning): ${r}`), opaque: [] };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The sha a QA acceptance binds to (#923): the opaque step as rendered — its verbatim line or request,
|
|
42
|
+
* check or step, the `test.step` it sits in — and as normalized, with the implementation path. Any
|
|
43
|
+
* change to the step gives another sha, so the old acceptance no longer covers it.
|
|
44
|
+
*/
|
|
45
|
+
export function opaqueStepSha(implementation: Implementation, r: RenderedStep, step: ContractStep | undefined): string {
|
|
46
|
+
return sha256Hex(canonicalJson({ implementation, kind: r.kind, group: r.group ?? null, verbatim: r.opaque?.verbatim ?? null, step: step ?? null })).slice(0, 16);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** How a low target identity opens its finding — `next` reads it to offer `contract check --trace`. */
|
|
50
|
+
export const LOW_IDENTITY_FINDING = 'target identity is low';
|
|
51
|
+
|
|
52
|
+
const worstOf = (findings: ContractFinding[], start: ScenarioClass = 'match'): ScenarioClass =>
|
|
53
|
+
findings.reduce<ScenarioClass>((acc, f) => (severityOf(f.class as ScenarioClass) > severityOf(acc) ? f.class as ScenarioClass : acc), start);
|
|
54
|
+
|
|
55
|
+
type Judged = { findings: ContractFinding[]; opaque: OpaqueStep[] };
|
|
56
|
+
|
|
57
|
+
/** An approved step as a reader sees it: `see [My Account] heading with text "My Account"`. */
|
|
58
|
+
function approvedStepText(s: ContractStep): string {
|
|
59
|
+
const refs = [s.target?.ref, ...(s.target?.also ?? [])].filter((r): r is string => r !== undefined);
|
|
60
|
+
const values = (s.kind === 'assert' ? s.expected : s.value)?.split(' | ') ?? [];
|
|
61
|
+
let r = 0;
|
|
62
|
+
let v = 0;
|
|
63
|
+
return s.verb.replace(/\[\]/g, () => `[${refs[r++] ?? ''}]`).replace(/\{\}/g, () => (v < values.length ? `"${values[v++]}"` : '{}'));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function overlays(
|
|
67
|
+
fp: TraceFingerprint, implementation: Implementation, accepted: readonly AcceptedOpaqueStep[], used?: Set<number>, replaces?: ReadonlyMap<number, string>,
|
|
68
|
+
): Judged {
|
|
69
|
+
const findings: ContractFinding[] = [];
|
|
70
|
+
const opaque: OpaqueStep[] = [];
|
|
71
|
+
fp.rendered.forEach((r, i) => {
|
|
72
|
+
if (used && !used.has(i)) return;
|
|
73
|
+
if (r.opaque) {
|
|
74
|
+
const sha = opaqueStepSha(implementation, r, fp.steps[i]);
|
|
75
|
+
const isAccepted = accepted.some((a) => a.step === i + 1 && a.sha === sha);
|
|
76
|
+
const instead = replaces?.get(i);
|
|
77
|
+
opaque.push({ step: i + 1, sha, kind: r.kind, verbatim: r.opaque.verbatim, ...(r.opaque.where ? { where: r.opaque.where } : {}), ...(instead ? { replaces: instead } : {}), accepted: isAccepted });
|
|
78
|
+
if (!isAccepted) {
|
|
79
|
+
findings.push(finding('opaque', `"${r.opaque.verbatim}"${r.opaque.where ? ` at ${r.opaque.where}` : ''} — ${r.kind === 'assert' ? 'a check' : 'a step'} sungen cannot compare; QA reviews it${instead ? ` — replaces approved ${instead}` : ''}`, i + 1));
|
|
80
|
+
}
|
|
81
|
+
} else if (r.low) findings.push(finding('opaque', `${LOW_IDENTITY_FINDING} (${r.low}) — cannot prove "${r.sentence}" acts on the approved element`, i + 1));
|
|
82
|
+
});
|
|
83
|
+
return { findings, opaque };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function implCodeFindings(entry: LockEntry, fp: TraceFingerprint): { findings: ContractFinding[]; used: Set<number>; replaces: Map<number, string> } {
|
|
87
|
+
const findings: ContractFinding[] = [];
|
|
88
|
+
const used = new Set<number>();
|
|
89
|
+
const replaces = new Map<number, string>();
|
|
90
|
+
const taken = new Set<number>();
|
|
91
|
+
entry.steps.forEach((locked, i) => {
|
|
92
|
+
const g = fp.groups.findIndex((x, gi) => !taken.has(gi) && sameJson(x.titleStep, locked));
|
|
93
|
+
if (g < 0) {
|
|
94
|
+
findings.push(locked.kind === 'assert'
|
|
95
|
+
? finding('assertion-lost', `no test.step implements the approved check "${locked.verb}" (step ${i + 1})`)
|
|
96
|
+
: finding('hash-changed', `no test.step implements the approved step "${locked.verb}" (step ${i + 1})`));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
taken.add(g);
|
|
100
|
+
const members = fp.groups[g].members;
|
|
101
|
+
const same = members.find((m) => sameJson(fp.steps[m], locked));
|
|
102
|
+
if (same !== undefined) { used.add(same); return; }
|
|
103
|
+
const candidates = members.filter((m) => fp.steps[m].kind === locked.kind);
|
|
104
|
+
if (!candidates.length) {
|
|
105
|
+
findings.push(locked.kind === 'assert' ? finding('assertion-lost', `the test.step for "${locked.verb}" checks nothing`, i + 1)
|
|
106
|
+
: finding('hash-changed', `the test.step for "${locked.verb}" does nothing on the page`, i + 1));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
candidates.forEach((m) => used.add(m));
|
|
110
|
+
// Only steps sungen cannot compare implement this approved step: the overlay sends them to QA's
|
|
111
|
+
// review (#923), naming the approved step. On the ladder they could only read "changed", which
|
|
112
|
+
// re-approving never clears.
|
|
113
|
+
if (candidates.every((m) => fp.rendered[m].opaque)) {
|
|
114
|
+
for (const m of candidates) replaces.set(m, `step ${i + 1} "${clip(approvedStepText(locked))}"`);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (locked.kind === 'action') { findings.push(finding('hash-changed', `the code for "${locked.verb}" does something else: "${fp.rendered[candidates[0]].sentence}"`, i + 1)); return; }
|
|
118
|
+
const judged = candidates.map((m) => compareAsserts(locked, fp.steps[m] as ContractStep));
|
|
119
|
+
const rank = (k: string): number => (k === 'oracle-weakened' ? 0 : k === 'review' ? 1 : 2);
|
|
120
|
+
const best = judged.sort((a, b) => rank(b.class) - rank(a.class))[0];
|
|
121
|
+
findings.push(finding(best.class === 'review' ? 'hash-changed' : best.class, best.detail, i + 1));
|
|
122
|
+
});
|
|
123
|
+
fp.groups.forEach((g, gi) => { if (!taken.has(gi)) findings.push(finding('hash-changed', `test.step "${g.title}" implements no approved step`)); });
|
|
124
|
+
return { findings, used, replaces };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function classifyOne(id: string, implementation: Implementation, entry: LockEntry, fp: TraceFingerprint): Judged {
|
|
128
|
+
const accepted = entry.acceptedOpaque ?? [];
|
|
129
|
+
if (implementation === 'impl:code') {
|
|
130
|
+
const { findings, used, replaces } = implCodeFindings(entry, fp);
|
|
131
|
+
const o = overlays(fp, implementation, accepted, used, replaces);
|
|
132
|
+
return { findings: [...findings, ...o.findings], opaque: o.opaque };
|
|
133
|
+
}
|
|
134
|
+
const ladder: ScenarioResult = classifyScenario(id, entry, {
|
|
135
|
+
id, implementation, steps: fp.steps, hash: fp.hash, source: { file: '', name: id, hasId: true, lines: [], outline: false },
|
|
136
|
+
});
|
|
137
|
+
const o = overlays(fp, implementation, accepted);
|
|
138
|
+
return { findings: [...ladder.findings, ...o.findings], opaque: o.opaque };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const runLabel = (r: TraceRun): string => `${r.record?.runId ?? '?'}#${r.result?.retry ?? '?'}`;
|
|
142
|
+
|
|
143
|
+
export function classifyTraceRuns(
|
|
144
|
+
id: string, implementation: Implementation, entry: LockEntry | undefined, runs: TraceRun[], fingerprints: Map<TraceRun, TraceFingerprint>,
|
|
145
|
+
): TraceOutcome {
|
|
146
|
+
const admissible = runs.filter((r) => r.status === 'admissible' && fingerprints.has(r));
|
|
147
|
+
const others = runs.filter((r) => !admissible.includes(r));
|
|
148
|
+
const labels = admissible.map(runLabel);
|
|
149
|
+
const hashes = admissible.map((r) => fingerprints.get(r)!.hash);
|
|
150
|
+
if (!admissible.length) {
|
|
151
|
+
const allInconclusive = others.length > 0 && others.every((r) => r.status === 'inconclusive');
|
|
152
|
+
return { ...notJudged(id, !!entry, allInconclusive ? 'inconclusive' : 'unproven', others.map((r) => r.reason ?? r.status)), hashes, runs: labels };
|
|
153
|
+
}
|
|
154
|
+
// A trace that may not speak, beside one that may: the admissible one judges, the other is a warning.
|
|
155
|
+
const warnings = others.map((r) => `${id}: another trace of this scenario was not used — ${r.reason ?? r.status}`);
|
|
156
|
+
if (!entry) return { class: 'proposed', findings: [], hashes, runs: labels, warnings, opaque: [] };
|
|
157
|
+
const perRun = admissible.map((r) => classifyOne(id, implementation, entry, fingerprints.get(r)!));
|
|
158
|
+
const findings = perRun.flatMap((p) => p.findings);
|
|
159
|
+
const opaque = [...new Map(perRun.flatMap((p) => p.opaque).map((o) => [`${o.step}:${o.sha}`, o] as const)).values()]
|
|
160
|
+
.sort((a, b) => a.step - b.step || a.sha.localeCompare(b.sha));
|
|
161
|
+
for (const o of opaque.filter((x) => x.accepted)) {
|
|
162
|
+
warnings.push(`${id}: step ${o.step} — opaque ${o.kind === 'assert' ? 'check' : 'step'} "${clip(o.verbatim)}" accepted by QA (decision ${entry.decisionId}), not compared`);
|
|
163
|
+
}
|
|
164
|
+
let cls = worstOf(findings);
|
|
165
|
+
if (new Set(hashes).size > 1) {
|
|
166
|
+
findings.push(finding('nondeterministic', `${new Set(hashes).size} different fingerprints across ${admissible.length} runs — the runs took different branches`));
|
|
167
|
+
if (severityOf(cls) <= severityOf('strengthened')) cls = 'nondeterministic';
|
|
168
|
+
}
|
|
169
|
+
return { class: cls, findings, hashes, runs: labels, warnings, opaque };
|
|
170
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What git HEAD holds under `qa/`, for the contract (DOS-14.4) — with a timeout the caller picks
|
|
3
|
+
* (≈3 s inside the Claude Code guard, whose own budget is 5 s; 30 s for the CLI).
|
|
4
|
+
*
|
|
5
|
+
* Three answers, never confused:
|
|
6
|
+
* blobs one `git ls-tree -r -z HEAD -- qa`: every committed lock and decision with its blob id
|
|
7
|
+
* no git no `.git` at or above the project, or a repository without a first commit
|
|
8
|
+
* git FAILED `.git` is there but git errors, times out, refuses (dubious ownership) or is not
|
|
9
|
+
* installed — reported as `error`, so the caller can refuse to call a lock "clean"
|
|
10
|
+
*
|
|
11
|
+
* A file whose working bytes hash to its HEAD blob id IS its committed version: it is read from disk
|
|
12
|
+
* and needs no `git show`. git runs with fixed arguments, never through a shell.
|
|
13
|
+
*/
|
|
14
|
+
import { execFileSync } from 'child_process';
|
|
15
|
+
import { createHash } from 'crypto';
|
|
16
|
+
import * as fs from 'fs';
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
|
|
19
|
+
export const CLI_GIT_TIMEOUT_MS = 30_000;
|
|
20
|
+
export const GUARD_GIT_TIMEOUT_MS = 3_000;
|
|
21
|
+
|
|
22
|
+
export class GitUnavailableError extends Error {
|
|
23
|
+
constructor(detail: string) {
|
|
24
|
+
super(`git is unavailable in a checkout that has .git (${detail}) — the contract lock cannot be compared with HEAD`);
|
|
25
|
+
this.name = 'GitUnavailableError';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** One flat shape: the project compiles without strictNullChecks, where a boolean-tagged union does not narrow. */
|
|
30
|
+
interface GitRun { ok: boolean; out: string; timedOut: boolean; message: string }
|
|
31
|
+
|
|
32
|
+
function runGit(cwd: string, args: string[], timeoutMs: number): GitRun {
|
|
33
|
+
try {
|
|
34
|
+
const out = execFileSync('git', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: 64 * 1024 * 1024, timeout: timeoutMs }).toString('utf8');
|
|
35
|
+
return { ok: true, out, timedOut: false, message: '' };
|
|
36
|
+
} catch (e) {
|
|
37
|
+
const err = e as NodeJS.ErrnoException & { signal?: string; stderr?: Buffer };
|
|
38
|
+
const message = (err.stderr?.toString().trim() || err.message || String(e)).split('\n')[0];
|
|
39
|
+
return { ok: false, out: '', timedOut: err.code === 'ETIMEDOUT' || err.signal === 'SIGTERM', message };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function hasDotGit(start: string): boolean {
|
|
44
|
+
let dir = path.resolve(start);
|
|
45
|
+
for (let i = 0; i < 40; i++) {
|
|
46
|
+
if (fs.existsSync(path.join(dir, '.git'))) return true;
|
|
47
|
+
const parent = path.dirname(dir);
|
|
48
|
+
if (parent === dir) return false;
|
|
49
|
+
dir = parent;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface HeadSnapshot {
|
|
55
|
+
root: string;
|
|
56
|
+
timeoutMs: number;
|
|
57
|
+
/** Project-relative path → blob id of each committed lock and decision; null when there is nothing to compare with. */
|
|
58
|
+
blobs: Map<string, string> | null;
|
|
59
|
+
/** Set when git FAILED in a checkout that has .git (blobs is then null). */
|
|
60
|
+
error?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const RECORD = /^\d+ blob ([0-9a-f]+)\t(.+)$/s;
|
|
64
|
+
const KEEP = (p: string): boolean => p.endsWith('/contracts.lock.yaml') || /\/decisions\/[^/]+\.yaml$/.test(p);
|
|
65
|
+
|
|
66
|
+
export function headSnapshot(root: string, timeoutMs = CLI_GIT_TIMEOUT_MS): HeadSnapshot {
|
|
67
|
+
const r = runGit(root, ['ls-tree', '-r', '-z', 'HEAD', '--', 'qa'], timeoutMs);
|
|
68
|
+
if (r.ok) {
|
|
69
|
+
const blobs = new Map<string, string>();
|
|
70
|
+
for (const rec of r.out.split('\0')) { const m = rec.match(RECORD); if (m && KEEP(m[2])) blobs.set(m[2], m[1]); }
|
|
71
|
+
return { root, timeoutMs, blobs };
|
|
72
|
+
}
|
|
73
|
+
if (r.timedOut) return { root, timeoutMs, blobs: null, error: `git timed out after ${timeoutMs} ms` };
|
|
74
|
+
if (!hasDotGit(root)) return { root, timeoutMs, blobs: null };
|
|
75
|
+
const repo = runGit(root, ['rev-parse', '--git-dir'], timeoutMs);
|
|
76
|
+
if (repo.ok && !runGit(root, ['rev-parse', '--verify', '-q', 'HEAD'], timeoutMs).ok) return { root, timeoutMs, blobs: null }; // no first commit yet
|
|
77
|
+
return { root, timeoutMs, blobs: null, error: r.message || 'git failed' };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const gitBlobId = (text: string): string => {
|
|
81
|
+
const body = Buffer.from(text, 'utf8');
|
|
82
|
+
return createHash('sha1').update(Buffer.concat([Buffer.from(`blob ${body.length}\0`), body])).digest('hex');
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const posixRel = (root: string, abs: string): string => path.relative(root, abs).split(path.sep).join('/');
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The committed text of a project-relative path, or null when HEAD does not hold it. `workingText`
|
|
89
|
+
* (the file as it is on disk, if any) spares the `git show` when it is byte-identical to HEAD.
|
|
90
|
+
*/
|
|
91
|
+
export function headFileText(snap: HeadSnapshot, rel: string, workingText: string | null): string | null {
|
|
92
|
+
const blob = snap.blobs?.get(rel);
|
|
93
|
+
if (blob === undefined) return null;
|
|
94
|
+
if (workingText !== null && gitBlobId(workingText) === blob) return workingText;
|
|
95
|
+
const r = runGit(snap.root, ['show', `HEAD:./${rel}`], snap.timeoutMs);
|
|
96
|
+
if (!r.ok) throw new GitUnavailableError(`git show HEAD:${rel}: ${r.timedOut ? 'timed out' : r.message}`);
|
|
97
|
+
return r.out;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** A file's text, or null when it does not exist. */
|
|
101
|
+
export function readTextOrNull(file: string): string | null {
|
|
102
|
+
try { return fs.readFileSync(file, 'utf8'); } catch (e) {
|
|
103
|
+
if ((e as NodeJS.ErrnoException).code === 'ENOENT') return null;
|
|
104
|
+
throw e;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract hash (DOS-14.2): `sha256-12` of the normalized steps PLUS the implementation path, so
|
|
3
|
+
* retagging `@free` → none is a contract change (red-team #5).
|
|
4
|
+
*
|
|
5
|
+
* Canonical JSON is keys-sorted with absent fields dropped and NO other rewriting: a literal's
|
|
6
|
+
* whitespace is part of what the test types or expects, so two values that differ only in spaces
|
|
7
|
+
* hash apart rather than "matching" by normalization.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from 'crypto';
|
|
10
|
+
import type { ContractStep, Implementation } from './contract-schema';
|
|
11
|
+
|
|
12
|
+
function canonical(v: unknown): unknown {
|
|
13
|
+
if (Array.isArray(v)) return v.map(canonical);
|
|
14
|
+
if (v && typeof v === 'object') {
|
|
15
|
+
const out: Record<string, unknown> = {};
|
|
16
|
+
for (const k of Object.keys(v).sort()) {
|
|
17
|
+
const x = (v as Record<string, unknown>)[k];
|
|
18
|
+
if (x !== undefined) out[k] = canonical(x);
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
return v;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const canonicalJson = (v: unknown): string => JSON.stringify(canonical(v));
|
|
26
|
+
|
|
27
|
+
/** Structural equality, key order ignored. */
|
|
28
|
+
export const sameJson = (a: unknown, b: unknown): boolean => canonicalJson(a) === canonicalJson(b);
|
|
29
|
+
|
|
30
|
+
export const sha256Hex = (s: string): string => createHash('sha256').update(s).digest('hex');
|
|
31
|
+
|
|
32
|
+
export function contractHash(implementation: Implementation, steps: ContractStep[]): string {
|
|
33
|
+
return sha256Hex(canonicalJson({ implementation, steps })).slice(0, 12);
|
|
34
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.sungen/reports/<slug>-contract.json` — the contract verdict as OUTPUT (DOS-14.0, takumi T3).
|
|
3
|
+
*
|
|
4
|
+
* Written by `sungen contract check` from a verdict it just built; never read back as a source of
|
|
5
|
+
* truth. Anything that needs the verdict calls buildContractVerdict() and rebuilds it from the
|
|
6
|
+
* `.feature`, the lock and git HEAD — so editing this file to "pass" changes nothing, and the next
|
|
7
|
+
* check overwrites it. It records `inputsHash` so a reader can see the report is stale, and
|
|
8
|
+
* `exitCode` next to `verdict` (fail ⇔ exitCode ≠ 0).
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'fs';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import { writeFileAtomic } from '../harness/write-atomic';
|
|
13
|
+
import { reportSlug } from '../harness/unit-paths';
|
|
14
|
+
import type { ContractVerdict } from './build-contract-verdict';
|
|
15
|
+
|
|
16
|
+
export const contractReportPath = (projectRoot: string, unit: string): string =>
|
|
17
|
+
path.join(projectRoot, '.sungen', 'reports', `${reportSlug(unit)}-contract.json`);
|
|
18
|
+
|
|
19
|
+
export function writeContractReport(projectRoot: string, verdict: ContractVerdict): string {
|
|
20
|
+
const file = contractReportPath(projectRoot, verdict.unit);
|
|
21
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
22
|
+
const doc = { ...verdict, generatedBy: 'sungen contract check', generatedAt: new Date().toISOString() };
|
|
23
|
+
writeFileAtomic(file, `${JSON.stringify(doc, null, 2)}\n`);
|
|
24
|
+
return file;
|
|
25
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Test Contract's data model (DOS-14.1 – 14.4) and the strict check of a stored lock entry.
|
|
3
|
+
*
|
|
4
|
+
* step {kind: action|assert, verb, target?:{ref, also?, parent?, nth?}, value?, matcher?, expected?, negated?, table?}
|
|
5
|
+
* lock qa/<kind>/<unit>/contracts.lock.yaml → {schema: 1, scenarios: {<scenario id>: LockEntry}}
|
|
6
|
+
* entry {hash, steps, implementation, approvedAt, decisionId, humanApproved?, acceptedOpaque?}
|
|
7
|
+
*
|
|
8
|
+
* A stored entry is checked the way the decision layer checks its records: a wrong type or an
|
|
9
|
+
* UNKNOWN key is an error, because a field outside the hash could carry meaning the hash does not
|
|
10
|
+
* vouch for. `humanApproved` counts only when it is literally `true` (takumi T5).
|
|
11
|
+
*/
|
|
12
|
+
import { DECISION_ID_RE } from '../decisions/decision-schema';
|
|
13
|
+
|
|
14
|
+
export const IMPLEMENTATIONS = ['compiled', 'impl:code', 'free'] as const;
|
|
15
|
+
export type Implementation = typeof IMPLEMENTATIONS[number];
|
|
16
|
+
|
|
17
|
+
export interface ContractTarget {
|
|
18
|
+
/** The first `[Reference]` of the step, or the data path of an `expect {{x}} …` step. */
|
|
19
|
+
ref: string;
|
|
20
|
+
/** Further `[References]` in the order written (`drag [A] to [B]`, `all [Card] contain [Child]`). */
|
|
21
|
+
also?: string[];
|
|
22
|
+
/** The `in [Parent] <container>` scope, as `<container> [<Parent>]` plus its `with` tail. */
|
|
23
|
+
parent?: string;
|
|
24
|
+
nth?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ContractStep {
|
|
28
|
+
kind: 'action' | 'assert';
|
|
29
|
+
/** The sentence with the actor dropped, refs as `[]`, values as `{}`, lowercased — the step's exact form. */
|
|
30
|
+
verb: string;
|
|
31
|
+
target?: ContractTarget;
|
|
32
|
+
/** An action's input: `{{var}}` kept as written, a literal without its quotes; several joined by ` | `. */
|
|
33
|
+
value?: string;
|
|
34
|
+
/** An assertion's check, from the closed vocabulary in oracle-strength.ts (`unknown` when it has none). */
|
|
35
|
+
matcher?: string;
|
|
36
|
+
/** An assertion's expected value(s), same form as `value`. */
|
|
37
|
+
expected?: string;
|
|
38
|
+
negated?: true;
|
|
39
|
+
/** The step's data table, header row first. */
|
|
40
|
+
table?: string[][];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ContractScenario {
|
|
44
|
+
id: string;
|
|
45
|
+
implementation: Implementation;
|
|
46
|
+
steps: ContractStep[];
|
|
47
|
+
hash: string;
|
|
48
|
+
/** Where it was read — never hashed. `outline`: a Scenario Outline, which the compiler does not support. */
|
|
49
|
+
source: { file: string; name: string; hasId: boolean; lines: number[]; outline: boolean };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** A reviewed opaque trace step QA accepted (#923): its 1-based position in the trace's steps and its sha (opaqueStepSha). */
|
|
53
|
+
export interface AcceptedOpaqueStep { step: number; sha: string }
|
|
54
|
+
|
|
55
|
+
export interface LockEntry {
|
|
56
|
+
hash: string;
|
|
57
|
+
steps: ContractStep[];
|
|
58
|
+
implementation: Implementation;
|
|
59
|
+
approvedAt: string;
|
|
60
|
+
decisionId: string;
|
|
61
|
+
humanApproved?: true;
|
|
62
|
+
/** Opaque trace steps a QA accepted on a terminal (`contract approve --accept-opaque`) — vouched for by `decisionId`. */
|
|
63
|
+
acceptedOpaque?: AcceptedOpaqueStep[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* One opaque step of a scenario's trace(s), as `contract check` reports it and `--accept-opaque` shows it.
|
|
68
|
+
* `replaces` (impl:code): the approved step it stands in for — `step 5 "see [Title] heading"`.
|
|
69
|
+
*/
|
|
70
|
+
export interface OpaqueStep { step: number; sha: string; kind: 'action' | 'assert'; verbatim: string; where?: string; replaces?: string; accepted: boolean }
|
|
71
|
+
|
|
72
|
+
export const LOCK_SCHEMA = 1;
|
|
73
|
+
export interface ContractLock { schema: typeof LOCK_SCHEMA; scenarios: Record<string, LockEntry> }
|
|
74
|
+
|
|
75
|
+
export type LadderClass = 'match' | 'strengthened' | 'hash-changed' | 'oracle-weakened' | 'target-changed' | 'assertion-lost';
|
|
76
|
+
/** Classes only a trace can produce (DOS-14.6) — free / impl:code scenarios. */
|
|
77
|
+
export type TraceClass = 'opaque' | 'nondeterministic' | 'inconclusive' | 'unproven';
|
|
78
|
+
export type ScenarioClass = LadderClass | 'proposed' | TraceClass;
|
|
79
|
+
export type FindingClass = Exclude<LadderClass, 'match'> | 'lock-uncommitted' | TraceClass;
|
|
80
|
+
|
|
81
|
+
/** Exit ≠ 0 (DOS-14.4, DOS-14.6). `unproven` applies to free / impl:code only. */
|
|
82
|
+
export const HARD_CLASSES: ReadonlySet<string> = new Set(['oracle-weakened', 'target-changed', 'assertion-lost', 'lock-uncommitted', 'unproven']);
|
|
83
|
+
/** Exit 0, but delivery waits for QA (DOS-14.4): changed-not-weaker, checks no code can compare, and an
|
|
84
|
+
* approved free scenario whose final attempt did not pass (inconclusive — review decision M6). */
|
|
85
|
+
export const REVIEW_CLASSES: ReadonlySet<string> = new Set(['hash-changed', 'opaque', 'inconclusive']);
|
|
86
|
+
|
|
87
|
+
/** The catalog rule each class is reported under (gate-rules.yaml); `strengthened` has none. */
|
|
88
|
+
export const RULE_OF: Readonly<Partial<Record<FindingClass, string>>> = {
|
|
89
|
+
'hash-changed': 'contract.hash-changed',
|
|
90
|
+
'oracle-weakened': 'contract.oracle-weakened',
|
|
91
|
+
'target-changed': 'contract.target-changed',
|
|
92
|
+
'assertion-lost': 'contract.assertion-lost',
|
|
93
|
+
'lock-uncommitted': 'contract.lock-uncommitted',
|
|
94
|
+
opaque: 'contract.opaque-step',
|
|
95
|
+
nondeterministic: 'contract.nondeterministic',
|
|
96
|
+
inconclusive: 'contract.inconclusive',
|
|
97
|
+
unproven: 'contract.unproven',
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const STEP_KEYS = new Set(['kind', 'verb', 'target', 'value', 'matcher', 'expected', 'negated', 'table']);
|
|
101
|
+
const TARGET_KEYS = new Set(['ref', 'also', 'parent', 'nth']);
|
|
102
|
+
const ENTRY_KEYS = new Set(['hash', 'steps', 'implementation', 'approvedAt', 'decisionId', 'humanApproved', 'acceptedOpaque']);
|
|
103
|
+
const ACCEPTED_KEYS = new Set(['step', 'sha']);
|
|
104
|
+
const HASH_RE = /^[0-9a-f]{12}$/;
|
|
105
|
+
export const OPAQUE_SHA_RE = /^[0-9a-f]{16}$/;
|
|
106
|
+
|
|
107
|
+
const isObject = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
108
|
+
const isStringList = (v: unknown): v is string[] => Array.isArray(v) && v.every((x) => typeof x === 'string');
|
|
109
|
+
const unknownKeys = (o: Record<string, unknown>, allowed: Set<string>, at: string): string[] =>
|
|
110
|
+
Object.keys(o).filter((k) => !allowed.has(k)).map((k) => `${at}: unknown key "${k}"`);
|
|
111
|
+
|
|
112
|
+
function targetErrors(t: unknown, at: string): string[] {
|
|
113
|
+
if (!isObject(t)) return [`${at}: target must be a mapping`];
|
|
114
|
+
const e = unknownKeys(t, TARGET_KEYS, at);
|
|
115
|
+
if (typeof t.ref !== 'string') e.push(`${at}: target.ref must be a string`);
|
|
116
|
+
if (t.also !== undefined && !isStringList(t.also)) e.push(`${at}: target.also must be a list of strings`);
|
|
117
|
+
if (t.parent !== undefined && typeof t.parent !== 'string') e.push(`${at}: target.parent must be a string`);
|
|
118
|
+
if (t.nth !== undefined && !(Number.isInteger(t.nth) && (t.nth as number) > 0)) e.push(`${at}: target.nth must be a positive integer`);
|
|
119
|
+
return e;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function stepErrors(s: unknown, at: string): string[] {
|
|
123
|
+
if (!isObject(s)) return [`${at}: not a mapping`];
|
|
124
|
+
const e = unknownKeys(s, STEP_KEYS, at);
|
|
125
|
+
if (s.kind !== 'action' && s.kind !== 'assert') e.push(`${at}: kind must be action|assert`);
|
|
126
|
+
if (typeof s.verb !== 'string' || !s.verb) e.push(`${at}: verb is required`);
|
|
127
|
+
if (s.target !== undefined) e.push(...targetErrors(s.target, at));
|
|
128
|
+
for (const k of ['value', 'matcher', 'expected'] as const) if (s[k] !== undefined && typeof s[k] !== 'string') e.push(`${at}: ${k} must be a string`);
|
|
129
|
+
if (s.negated !== undefined && s.negated !== true) e.push(`${at}: negated is either true or absent`);
|
|
130
|
+
if (s.table !== undefined && !(Array.isArray(s.table) && s.table.every(isStringList))) e.push(`${at}: table must be rows of strings`);
|
|
131
|
+
return e;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function acceptedOpaqueErrors(v: unknown, at: string): string[] {
|
|
135
|
+
if (!Array.isArray(v) || !v.length) return [`${at}: acceptedOpaque must be a non-empty list`];
|
|
136
|
+
return v.flatMap((a, i) => {
|
|
137
|
+
const where = `${at} acceptedOpaque ${i + 1}`;
|
|
138
|
+
if (!isObject(a)) return [`${where}: not a mapping`];
|
|
139
|
+
const e = unknownKeys(a, ACCEPTED_KEYS, where);
|
|
140
|
+
if (!(Number.isInteger(a.step) && (a.step as number) > 0)) e.push(`${where}: step must be a positive integer`);
|
|
141
|
+
if (typeof a.sha !== 'string' || !OPAQUE_SHA_RE.test(a.sha)) e.push(`${where}: sha must be 16 hex characters`);
|
|
142
|
+
return e;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Errors in one stored lock entry (empty = well-formed). The hash itself is checked by the reader. */
|
|
147
|
+
export function lockEntryErrors(raw: unknown, id: string): string[] {
|
|
148
|
+
const at = `scenario ${id}`;
|
|
149
|
+
if (!isObject(raw)) return [`${at}: not a mapping`];
|
|
150
|
+
const e = unknownKeys(raw, ENTRY_KEYS, at);
|
|
151
|
+
if (typeof raw.hash !== 'string' || !HASH_RE.test(raw.hash)) e.push(`${at}: hash must be 12 hex characters`);
|
|
152
|
+
if (!IMPLEMENTATIONS.includes(raw.implementation as Implementation)) e.push(`${at}: implementation must be ${IMPLEMENTATIONS.join('|')}`);
|
|
153
|
+
if (typeof raw.approvedAt !== 'string' || Number.isNaN(Date.parse(raw.approvedAt))) e.push(`${at}: approvedAt must be an ISO-8601 timestamp`);
|
|
154
|
+
if (typeof raw.decisionId !== 'string' || !DECISION_ID_RE.test(raw.decisionId)) e.push(`${at}: decisionId must be D-<16 hex>`);
|
|
155
|
+
if (raw.humanApproved !== undefined && raw.humanApproved !== true) e.push(`${at}: humanApproved is either true or absent`);
|
|
156
|
+
if (raw.acceptedOpaque !== undefined) {
|
|
157
|
+
e.push(...acceptedOpaqueErrors(raw.acceptedOpaque, at));
|
|
158
|
+
if (raw.humanApproved !== true) e.push(`${at}: acceptedOpaque needs humanApproved: true`);
|
|
159
|
+
}
|
|
160
|
+
if (!Array.isArray(raw.steps)) e.push(`${at}: steps must be a list`);
|
|
161
|
+
else raw.steps.forEach((s, i) => e.push(...stepErrors(s, `${at} step ${i + 1}`)));
|
|
162
|
+
return e;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Approved by a human on a TTY — and nothing else counts (an absent field is `proposed`, T5). */
|
|
166
|
+
export const isHumanApproved = (entry: LockEntry | undefined): entry is LockEntry => entry?.humanApproved === true;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which units a contract command or a `sungen delivery` call touches — the same units `delivery`
|
|
3
|
+
* enumerates (cli/commands/delivery.ts `listAllTargets` / `resolveTargetsFromArg`), restated here
|
|
4
|
+
* so the guard does not load the whole delivery command; a test pins the two enumerations together.
|
|
5
|
+
*
|
|
6
|
+
* every unit qa/screens/*, qa/flows/*, qa/api/* (not `flows`), and qa/api/flows/* as `flows/<name>`
|
|
7
|
+
* a name EVERY directory it can mean (a screen and a flow of one name are both checked);
|
|
8
|
+
* for delivery only, a name that is no unit falls back to the units hosting a
|
|
9
|
+
* feature file of that basename
|
|
10
|
+
*
|
|
11
|
+
* Names come from untrusted input (a Bash command): they are only compared with enumerated directory
|
|
12
|
+
* names, never joined into a path.
|
|
13
|
+
*/
|
|
14
|
+
import * as fs from 'fs';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
import { featureFilesFor } from '../harness/unit-paths';
|
|
17
|
+
|
|
18
|
+
export interface ContractUnitRef { name: string; dir: string }
|
|
19
|
+
|
|
20
|
+
function subdirs(dir: string): string[] {
|
|
21
|
+
try { return fs.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort(); } catch { return []; }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function allContractUnits(root: string): ContractUnitRef[] {
|
|
25
|
+
const qa = path.join(root, 'qa');
|
|
26
|
+
const out: ContractUnitRef[] = [];
|
|
27
|
+
for (const kind of ['screens', 'flows', 'api']) {
|
|
28
|
+
for (const name of subdirs(path.join(qa, kind))) if (!(kind === 'api' && name === 'flows')) out.push({ name, dir: path.join(qa, kind, name) });
|
|
29
|
+
}
|
|
30
|
+
for (const name of subdirs(path.join(qa, 'api', 'flows'))) out.push({ name: `flows/${name}`, dir: path.join(qa, 'api', 'flows', name) });
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Every unit directory `name` can mean (`pay` matches a flow `pay` and an api flow `flows/pay`). */
|
|
35
|
+
export function contractUnitDirsNamed(root: string, name: string): ContractUnitRef[] {
|
|
36
|
+
return allContractUnits(root).filter((u) => u.name === name || u.name === `flows/${name}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The units `sungen delivery <name>` delivers. */
|
|
40
|
+
export function deliveryUnitsNamed(root: string, name: string): ContractUnitRef[] {
|
|
41
|
+
const direct = contractUnitDirsNamed(root, name);
|
|
42
|
+
if (direct.length) return direct;
|
|
43
|
+
return allContractUnits(root).filter((u) => featureFilesFor(u.dir, u.name).some((f) => path.basename(f, '.feature') === name && fs.existsSync(f)));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The one unit a contract command names; an unknown or ambiguous name is an error, never a guess. */
|
|
47
|
+
export function resolveContractUnit(root: string, name: string): ContractUnitRef {
|
|
48
|
+
const found = contractUnitDirsNamed(root, name);
|
|
49
|
+
if (found.length === 1) return found[0];
|
|
50
|
+
if (!found.length) throw new Error(`Not found: qa/screens/${name}, qa/flows/${name}, qa/api/${name} or qa/api/flows/${name}`);
|
|
51
|
+
throw new Error(`"${name}" names ${found.length} units (${found.map((u) => path.relative(root, u.dir)).join(', ')}) — rename one so the contract knows which`);
|
|
52
|
+
}
|