@sun-asterisk/sungen 3.2.34 → 3.3.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/basis/anchor-grammar.d.ts +32 -0
- package/dist/basis/anchor-grammar.d.ts.map +1 -0
- package/dist/basis/anchor-grammar.js +82 -0
- package/dist/basis/anchor-grammar.js.map +1 -0
- package/dist/basis/anchor-hash.d.ts +6 -0
- package/dist/basis/anchor-hash.d.ts.map +1 -0
- package/dist/basis/anchor-hash.js +28 -0
- package/dist/basis/anchor-hash.js.map +1 -0
- package/dist/basis/bm51-tables.d.ts +20 -0
- package/dist/basis/bm51-tables.d.ts.map +1 -0
- package/dist/basis/bm51-tables.js +71 -0
- package/dist/basis/bm51-tables.js.map +1 -0
- package/dist/basis/extract-spec-anchors.d.ts +39 -0
- package/dist/basis/extract-spec-anchors.d.ts.map +1 -0
- package/dist/basis/extract-spec-anchors.js +81 -0
- package/dist/basis/extract-spec-anchors.js.map +1 -0
- package/dist/basis/migration-sentinel.d.ts +47 -0
- package/dist/basis/migration-sentinel.d.ts.map +1 -0
- package/dist/basis/migration-sentinel.js +219 -0
- package/dist/basis/migration-sentinel.js.map +1 -0
- package/dist/basis/spec-frontmatter.d.ts +18 -0
- package/dist/basis/spec-frontmatter.d.ts.map +1 -0
- package/dist/basis/spec-frontmatter.js +55 -0
- package/dist/basis/spec-frontmatter.js.map +1 -0
- package/dist/basis/spec-sections.d.ts +18 -0
- package/dist/basis/spec-sections.d.ts.map +1 -0
- package/dist/basis/spec-sections.js +27 -0
- package/dist/basis/spec-sections.js.map +1 -0
- package/dist/basis/test-basis-schema.d.ts +28 -0
- package/dist/basis/test-basis-schema.d.ts.map +1 -0
- package/dist/basis/test-basis-schema.js +141 -0
- package/dist/basis/test-basis-schema.js.map +1 -0
- package/dist/capabilities/discover.d.ts +4 -0
- package/dist/capabilities/discover.d.ts.map +1 -1
- package/dist/capabilities/discover.js +16 -2
- package/dist/capabilities/discover.js.map +1 -1
- package/dist/capabilities/registry.d.ts +15 -0
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +10 -5
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.d.ts.map +1 -1
- package/dist/cli/commands/capability.js +6 -2
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/contract-derive-command.d.ts +11 -0
- package/dist/cli/commands/contract-derive-command.d.ts.map +1 -0
- package/dist/cli/commands/contract-derive-command.js +99 -0
- package/dist/cli/commands/contract-derive-command.js.map +1 -0
- package/dist/cli/commands/contract.d.ts +17 -0
- package/dist/cli/commands/contract.d.ts.map +1 -0
- package/dist/cli/commands/contract.js +162 -0
- package/dist/cli/commands/contract.js.map +1 -0
- package/dist/cli/commands/defect.d.ts +7 -0
- package/dist/cli/commands/defect.d.ts.map +1 -0
- package/dist/cli/commands/defect.js +68 -0
- package/dist/cli/commands/defect.js.map +1 -0
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +96 -12
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +3 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/journey.d.ts.map +1 -1
- package/dist/cli/commands/journey.js +43 -15
- package/dist/cli/commands/journey.js.map +1 -1
- package/dist/cli/commands/next.d.ts +8 -0
- package/dist/cli/commands/next.d.ts.map +1 -1
- package/dist/cli/commands/next.js +68 -8
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/triage.d.ts +7 -0
- package/dist/cli/commands/triage.d.ts.map +1 -0
- package/dist/cli/commands/triage.js +98 -0
- package/dist/cli/commands/triage.js.map +1 -0
- package/dist/cli/commands/update.d.ts +11 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +31 -6
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.js +24 -33
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/project-sungen-invocation.d.ts +7 -0
- package/dist/cli/project-sungen-invocation.d.ts.map +1 -0
- package/dist/cli/project-sungen-invocation.js +76 -0
- package/dist/cli/project-sungen-invocation.js.map +1 -0
- package/dist/contract/approve-contract.d.ts +31 -0
- package/dist/contract/approve-contract.d.ts.map +1 -0
- package/dist/contract/approve-contract.js +87 -0
- package/dist/contract/approve-contract.js.map +1 -0
- package/dist/contract/assertion-matcher-vocabulary.d.ts +24 -0
- package/dist/contract/assertion-matcher-vocabulary.d.ts.map +1 -0
- package/dist/contract/assertion-matcher-vocabulary.js +100 -0
- package/dist/contract/assertion-matcher-vocabulary.js.map +1 -0
- package/dist/contract/build-contract-verdict.d.ts +32 -0
- package/dist/contract/build-contract-verdict.d.ts.map +1 -0
- package/dist/contract/build-contract-verdict.js +123 -0
- package/dist/contract/build-contract-verdict.js.map +1 -0
- package/dist/contract/build-trace-conformance.d.ts +18 -0
- package/dist/contract/build-trace-conformance.d.ts.map +1 -0
- package/dist/contract/build-trace-conformance.js +153 -0
- package/dist/contract/build-trace-conformance.js.map +1 -0
- package/dist/contract/classify-contract-change.d.ts +23 -0
- package/dist/contract/classify-contract-change.d.ts.map +1 -0
- package/dist/contract/classify-contract-change.js +98 -0
- package/dist/contract/classify-contract-change.js.map +1 -0
- package/dist/contract/classify-contract-unit.d.ts +18 -0
- package/dist/contract/classify-contract-unit.d.ts.map +1 -0
- package/dist/contract/classify-contract-unit.js +49 -0
- package/dist/contract/classify-contract-unit.js.map +1 -0
- package/dist/contract/classify-trace-conformance.d.ts +32 -0
- package/dist/contract/classify-trace-conformance.d.ts.map +1 -0
- package/dist/contract/classify-trace-conformance.js +117 -0
- package/dist/contract/classify-trace-conformance.js.map +1 -0
- package/dist/contract/contract-git.d.ts +24 -0
- package/dist/contract/contract-git.d.ts.map +1 -0
- package/dist/contract/contract-git.js +144 -0
- package/dist/contract/contract-git.js.map +1 -0
- package/dist/contract/contract-hash.d.ts +7 -0
- package/dist/contract/contract-hash.d.ts.map +1 -0
- package/dist/contract/contract-hash.js +38 -0
- package/dist/contract/contract-hash.js.map +1 -0
- package/dist/contract/contract-report-file.d.ts +4 -0
- package/dist/contract/contract-report-file.d.ts.map +1 -0
- package/dist/contract/contract-report-file.js +60 -0
- package/dist/contract/contract-report-file.js.map +1 -0
- package/dist/contract/contract-schema.d.ts +71 -0
- package/dist/contract/contract-schema.d.ts.map +1 -0
- package/dist/contract/contract-schema.js +102 -0
- package/dist/contract/contract-schema.js.map +1 -0
- package/dist/contract/contract-units.d.ts +12 -0
- package/dist/contract/contract-units.d.ts.map +1 -0
- package/dist/contract/contract-units.js +96 -0
- package/dist/contract/contract-units.js.map +1 -0
- package/dist/contract/contracts-lock-file.d.ts +24 -0
- package/dist/contract/contracts-lock-file.d.ts.map +1 -0
- package/dist/contract/contracts-lock-file.js +140 -0
- package/dist/contract/contracts-lock-file.js.map +1 -0
- package/dist/contract/data-normalize.d.ts +10 -0
- package/dist/contract/data-normalize.d.ts.map +1 -0
- package/dist/contract/data-normalize.js +110 -0
- package/dist/contract/data-normalize.js.map +1 -0
- package/dist/contract/derive-free-feature.d.ts +38 -0
- package/dist/contract/derive-free-feature.d.ts.map +1 -0
- package/dist/contract/derive-free-feature.js +154 -0
- package/dist/contract/derive-free-feature.js.map +1 -0
- package/dist/contract/field-semantic-redaction.d.ts +21 -0
- package/dist/contract/field-semantic-redaction.d.ts.map +1 -0
- package/dist/contract/field-semantic-redaction.js +118 -0
- package/dist/contract/field-semantic-redaction.js.map +1 -0
- package/dist/contract/free-feature-blocks.d.ts +10 -0
- package/dist/contract/free-feature-blocks.d.ts.map +1 -0
- package/dist/contract/free-feature-blocks.js +94 -0
- package/dist/contract/free-feature-blocks.js.map +1 -0
- package/dist/contract/lock-secret-guard.d.ts +22 -0
- package/dist/contract/lock-secret-guard.d.ts.map +1 -0
- package/dist/contract/lock-secret-guard.js +134 -0
- package/dist/contract/lock-secret-guard.js.map +1 -0
- package/dist/contract/lock-vs-git-head.d.ts +26 -0
- package/dist/contract/lock-vs-git-head.d.ts.map +1 -0
- package/dist/contract/lock-vs-git-head.js +28 -0
- package/dist/contract/lock-vs-git-head.js.map +1 -0
- package/dist/contract/normalize-contract-step.d.ts +21 -0
- package/dist/contract/normalize-contract-step.d.ts.map +1 -0
- package/dist/contract/normalize-contract-step.js +70 -0
- package/dist/contract/normalize-contract-step.js.map +1 -0
- package/dist/contract/normalize-feature-steps.d.ts +7 -0
- package/dist/contract/normalize-feature-steps.d.ts.map +1 -0
- package/dist/contract/normalize-feature-steps.js +127 -0
- package/dist/contract/normalize-feature-steps.js.map +1 -0
- package/dist/contract/oracle-strength.d.ts +12 -0
- package/dist/contract/oracle-strength.d.ts.map +1 -0
- package/dist/contract/oracle-strength.js +88 -0
- package/dist/contract/oracle-strength.js.map +1 -0
- package/dist/contract/project-contract-blockers.d.ts +10 -0
- package/dist/contract/project-contract-blockers.d.ts.map +1 -0
- package/dist/contract/project-contract-blockers.js +73 -0
- package/dist/contract/project-contract-blockers.js.map +1 -0
- package/dist/contract/record-contract-approval.d.ts +21 -0
- package/dist/contract/record-contract-approval.d.ts.map +1 -0
- package/dist/contract/record-contract-approval.js +98 -0
- package/dist/contract/record-contract-approval.js.map +1 -0
- package/dist/contract/render-free-gherkin.d.ts +40 -0
- package/dist/contract/render-free-gherkin.d.ts.map +1 -0
- package/dist/contract/render-free-gherkin.js +141 -0
- package/dist/contract/render-free-gherkin.js.map +1 -0
- package/dist/contract/render-trace-sentence.d.ts +20 -0
- package/dist/contract/render-trace-sentence.d.ts.map +1 -0
- package/dist/contract/render-trace-sentence.js +109 -0
- package/dist/contract/render-trace-sentence.js.map +1 -0
- package/dist/contract/render-trace-target.d.ts +14 -0
- package/dist/contract/render-trace-target.d.ts.map +1 -0
- package/dist/contract/render-trace-target.js +70 -0
- package/dist/contract/render-trace-target.js.map +1 -0
- package/dist/contract/resolve-unit-trace-identities.d.ts +8 -0
- package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -0
- package/dist/contract/resolve-unit-trace-identities.js +78 -0
- package/dist/contract/resolve-unit-trace-identities.js.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts +33 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.js +161 -0
- package/dist/contract/trace/collect-trace-evidence.js.map +1 -0
- package/dist/contract/trace/identity-cache.d.ts +19 -0
- package/dist/contract/trace/identity-cache.d.ts.map +1 -0
- package/dist/contract/trace/identity-cache.js +104 -0
- package/dist/contract/trace/identity-cache.js.map +1 -0
- package/dist/contract/trace/select-final-attempt.d.ts +27 -0
- package/dist/contract/trace/select-final-attempt.d.ts.map +1 -0
- package/dist/contract/trace/select-final-attempt.js +116 -0
- package/dist/contract/trace/select-final-attempt.js.map +1 -0
- package/dist/contract/trace/snapshot-html-renderer.d.ts +31 -0
- package/dist/contract/trace/snapshot-html-renderer.d.ts.map +1 -0
- package/dist/contract/trace/snapshot-html-renderer.js +172 -0
- package/dist/contract/trace/snapshot-html-renderer.js.map +1 -0
- package/dist/contract/trace/snapshot-resolver.d.ts +21 -0
- package/dist/contract/trace/snapshot-resolver.d.ts.map +1 -0
- package/dist/contract/trace/snapshot-resolver.js +65 -0
- package/dist/contract/trace/snapshot-resolver.js.map +1 -0
- package/dist/contract/trace/snapshot-store.d.ts +66 -0
- package/dist/contract/trace/snapshot-store.d.ts.map +1 -0
- package/dist/contract/trace/snapshot-store.js +173 -0
- package/dist/contract/trace/snapshot-store.js.map +1 -0
- package/dist/contract/trace/target-identity.d.ts +74 -0
- package/dist/contract/trace/target-identity.d.ts.map +1 -0
- package/dist/contract/trace/target-identity.js +68 -0
- package/dist/contract/trace/target-identity.js.map +1 -0
- package/dist/contract/trace/test-step-join.d.ts +65 -0
- package/dist/contract/trace/test-step-join.d.ts.map +1 -0
- package/dist/contract/trace/test-step-join.js +80 -0
- package/dist/contract/trace/test-step-join.js.map +1 -0
- package/dist/contract/trace/trace-binding.d.ts +21 -0
- package/dist/contract/trace/trace-binding.d.ts.map +1 -0
- package/dist/contract/trace/trace-binding.js +88 -0
- package/dist/contract/trace/trace-binding.js.map +1 -0
- package/dist/contract/trace/trace-file-reader.d.ts +41 -0
- package/dist/contract/trace/trace-file-reader.d.ts.map +1 -0
- package/dist/contract/trace/trace-file-reader.js +161 -0
- package/dist/contract/trace/trace-file-reader.js.map +1 -0
- package/dist/contract/trace/trace-fingerprint.d.ts +22 -0
- package/dist/contract/trace/trace-fingerprint.d.ts.map +1 -0
- package/dist/contract/trace/trace-fingerprint.js +96 -0
- package/dist/contract/trace/trace-fingerprint.js.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts +26 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.js +84 -0
- package/dist/contract/trace/trace-identity-resolution.js.map +1 -0
- package/dist/contract/trace/trace-run-record.d.ts +30 -0
- package/dist/contract/trace/trace-run-record.d.ts.map +1 -0
- package/dist/contract/trace/trace-run-record.js +121 -0
- package/dist/contract/trace/trace-run-record.js.map +1 -0
- package/dist/contract/trace/trace-steps.d.ts +19 -0
- package/dist/contract/trace/trace-steps.d.ts.map +1 -0
- package/dist/contract/trace/trace-steps.js +79 -0
- package/dist/contract/trace/trace-steps.js.map +1 -0
- package/dist/contract/trace/trace-zip-limits.d.ts +45 -0
- package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -0
- package/dist/contract/trace/trace-zip-limits.js +52 -0
- package/dist/contract/trace/trace-zip-limits.js.map +1 -0
- package/dist/contract/trace/trace-zip-reader.d.ts +10 -0
- package/dist/contract/trace/trace-zip-reader.d.ts.map +1 -0
- package/dist/contract/trace/trace-zip-reader.js +186 -0
- package/dist/contract/trace/trace-zip-reader.js.map +1 -0
- package/dist/contract/verify-approval-decisions.d.ts +5 -0
- package/dist/contract/verify-approval-decisions.d.ts.map +1 -0
- package/dist/contract/verify-approval-decisions.js +104 -0
- package/dist/contract/verify-approval-decisions.js.map +1 -0
- package/dist/decisions/append-decision.d.ts +12 -0
- package/dist/decisions/append-decision.d.ts.map +1 -0
- package/dist/decisions/append-decision.js +73 -0
- package/dist/decisions/append-decision.js.map +1 -0
- package/dist/decisions/confirmed-decision-commands.d.ts +41 -0
- package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -0
- package/dist/decisions/confirmed-decision-commands.js +190 -0
- package/dist/decisions/confirmed-decision-commands.js.map +1 -0
- package/dist/decisions/decision-file.d.ts +31 -0
- package/dist/decisions/decision-file.d.ts.map +1 -0
- package/dist/decisions/decision-file.js +139 -0
- package/dist/decisions/decision-file.js.map +1 -0
- package/dist/decisions/decision-identity.d.ts +12 -0
- package/dist/decisions/decision-identity.d.ts.map +1 -0
- package/dist/decisions/decision-identity.js +78 -0
- package/dist/decisions/decision-identity.js.map +1 -0
- package/dist/decisions/decision-integrity-check.d.ts +12 -0
- package/dist/decisions/decision-integrity-check.d.ts.map +1 -0
- package/dist/decisions/decision-integrity-check.js +102 -0
- package/dist/decisions/decision-integrity-check.js.map +1 -0
- package/dist/decisions/decision-schema.d.ts +42 -0
- package/dist/decisions/decision-schema.d.ts.map +1 -0
- package/dist/decisions/decision-schema.js +75 -0
- package/dist/decisions/decision-schema.js.map +1 -0
- package/dist/decisions/decision-source.d.ts +2 -0
- package/dist/decisions/decision-source.d.ts.map +1 -0
- package/dist/decisions/decision-source.js +18 -0
- package/dist/decisions/decision-source.js.map +1 -0
- package/dist/decisions/exclusive-file-create.d.ts +3 -0
- package/dist/decisions/exclusive-file-create.d.ts.map +1 -0
- package/dist/decisions/exclusive-file-create.js +84 -0
- package/dist/decisions/exclusive-file-create.js.map +1 -0
- package/dist/decisions/git-head-trust.d.ts +7 -0
- package/dist/decisions/git-head-trust.d.ts.map +1 -0
- package/dist/decisions/git-head-trust.js +76 -0
- package/dist/decisions/git-head-trust.js.map +1 -0
- package/dist/decisions/human-confirmation.d.ts +35 -0
- package/dist/decisions/human-confirmation.d.ts.map +1 -0
- package/dist/decisions/human-confirmation.js +161 -0
- package/dist/decisions/human-confirmation.js.map +1 -0
- package/dist/decisions/legacy-waiver-migration.d.ts +31 -0
- package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -0
- package/dist/decisions/legacy-waiver-migration.js +170 -0
- package/dist/decisions/legacy-waiver-migration.js.map +1 -0
- package/dist/decisions/read-decisions.d.ts +19 -0
- package/dist/decisions/read-decisions.d.ts.map +1 -0
- package/dist/decisions/read-decisions.js +90 -0
- package/dist/decisions/read-decisions.js.map +1 -0
- package/dist/decisions/viewpoint-baseline-adapter.d.ts +7 -0
- package/dist/decisions/viewpoint-baseline-adapter.d.ts.map +1 -0
- package/dist/decisions/viewpoint-baseline-adapter.js +109 -0
- package/dist/decisions/viewpoint-baseline-adapter.js.map +1 -0
- package/dist/decisions/waiver-decisions.d.ts +24 -0
- package/dist/decisions/waiver-decisions.d.ts.map +1 -0
- package/dist/decisions/waiver-decisions.js +46 -0
- package/dist/decisions/waiver-decisions.js.map +1 -0
- package/dist/exporters/csv-exporter.d.ts +4 -0
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +1 -1
- package/dist/exporters/csv-exporter.js.map +1 -1
- package/dist/exporters/feature-parser.d.ts +8 -0
- package/dist/exporters/feature-parser.d.ts.map +1 -1
- package/dist/exporters/feature-parser.js +12 -0
- package/dist/exporters/feature-parser.js.map +1 -1
- package/dist/exporters/matrix/build.d.ts +3 -0
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +59 -19
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/carry-manual-results.d.ts +19 -0
- package/dist/exporters/matrix/carry-manual-results.d.ts.map +1 -1
- package/dist/exporters/matrix/carry-manual-results.js +76 -6
- package/dist/exporters/matrix/carry-manual-results.js.map +1 -1
- package/dist/exporters/matrix/export.d.ts +8 -2
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +16 -3
- package/dist/exporters/matrix/export.js.map +1 -1
- package/dist/exporters/matrix/gates.d.ts +6 -1
- package/dist/exporters/matrix/gates.d.ts.map +1 -1
- package/dist/exporters/matrix/gates.js +57 -128
- package/dist/exporters/matrix/gates.js.map +1 -1
- package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
- package/dist/exporters/matrix/render-csv.js +4 -1
- package/dist/exporters/matrix/render-csv.js.map +1 -1
- package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts +13 -0
- package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-gate-overrides-sheet.js +44 -0
- package/dist/exporters/matrix/render-gate-overrides-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
- package/dist/exporters/matrix/render-xlsx.js +6 -0
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +9 -1
- package/dist/exporters/matrix/types.d.ts.map +1 -1
- package/dist/exporters/matrix/types.js.map +1 -1
- package/dist/exporters/matrix/xlsx-cells.js +1 -1
- package/dist/exporters/matrix/xlsx-cells.js.map +1 -1
- package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
- package/dist/exporters/playwright-report-parser.js +1 -0
- package/dist/exporters/playwright-report-parser.js.map +1 -1
- package/dist/exporters/scenario-merger.d.ts.map +1 -1
- package/dist/exporters/scenario-merger.js +2 -0
- package/dist/exporters/scenario-merger.js.map +1 -1
- package/dist/exporters/types.d.ts +5 -0
- package/dist/exporters/types.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +13 -0
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/graph/evaluate-graph.d.ts +23 -0
- package/dist/graph/evaluate-graph.d.ts.map +1 -0
- package/dist/graph/evaluate-graph.js +52 -0
- package/dist/graph/evaluate-graph.js.map +1 -0
- package/dist/graph/locate-finding.d.ts +20 -0
- package/dist/graph/locate-finding.d.ts.map +1 -0
- package/dist/graph/locate-finding.js +137 -0
- package/dist/graph/locate-finding.js.map +1 -0
- package/dist/graph/node-decl.d.ts +66 -0
- package/dist/graph/node-decl.d.ts.map +1 -0
- package/dist/graph/node-decl.js +8 -0
- package/dist/graph/node-decl.js.map +1 -0
- package/dist/graph/nodes/core-node-catalog.d.ts +7 -0
- package/dist/graph/nodes/core-node-catalog.d.ts.map +1 -0
- package/dist/graph/nodes/core-node-catalog.js +13 -0
- package/dist/graph/nodes/core-node-catalog.js.map +1 -0
- package/dist/graph/nodes/test-case-contract-nodes.d.ts +21 -0
- package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/test-case-contract-nodes.js +59 -0
- package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -0
- package/dist/graph/nodes/test-case-nodes.d.ts +26 -0
- package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/test-case-nodes.js +66 -0
- package/dist/graph/nodes/test-case-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-audit-nodes.d.ts +18 -0
- package/dist/graph/nodes/unit-audit-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/unit-audit-nodes.js +95 -0
- package/dist/graph/nodes/unit-audit-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-contract-node.d.ts +21 -0
- package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -0
- package/dist/graph/nodes/unit-contract-node.js +88 -0
- package/dist/graph/nodes/unit-contract-node.js.map +1 -0
- package/dist/graph/nodes/unit-design-nodes.d.ts +14 -0
- package/dist/graph/nodes/unit-design-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/unit-design-nodes.js +91 -0
- package/dist/graph/nodes/unit-design-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-execution-nodes.d.ts +16 -0
- package/dist/graph/nodes/unit-execution-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/unit-execution-nodes.js +79 -0
- package/dist/graph/nodes/unit-execution-nodes.js.map +1 -0
- package/dist/graph/test-case-identity.d.ts +13 -0
- package/dist/graph/test-case-identity.d.ts.map +1 -0
- package/dist/graph/test-case-identity.js +106 -0
- package/dist/graph/test-case-identity.js.map +1 -0
- package/dist/graph/test-case-results.d.ts +11 -0
- package/dist/graph/test-case-results.d.ts.map +1 -0
- package/dist/graph/test-case-results.js +137 -0
- package/dist/graph/test-case-results.js.map +1 -0
- package/dist/graph/test-case-satisfied.d.ts +25 -0
- package/dist/graph/test-case-satisfied.d.ts.map +1 -0
- package/dist/graph/test-case-satisfied.js +51 -0
- package/dist/graph/test-case-satisfied.js.map +1 -0
- package/dist/graph/test-case-state-shape.d.ts +67 -0
- package/dist/graph/test-case-state-shape.d.ts.map +1 -0
- package/dist/graph/test-case-state-shape.js +3 -0
- package/dist/graph/test-case-state-shape.js.map +1 -0
- package/dist/graph/test-case-states.d.ts +9 -0
- package/dist/graph/test-case-states.d.ts.map +1 -0
- package/dist/graph/test-case-states.js +116 -0
- package/dist/graph/test-case-states.js.map +1 -0
- package/dist/graph/unit-artifact-probes.d.ts +19 -0
- package/dist/graph/unit-artifact-probes.d.ts.map +1 -0
- package/dist/graph/unit-artifact-probes.js +133 -0
- package/dist/graph/unit-artifact-probes.js.map +1 -0
- package/dist/graph/unit-state-facts.d.ts +43 -0
- package/dist/graph/unit-state-facts.d.ts.map +1 -0
- package/dist/graph/unit-state-facts.js +87 -0
- package/dist/graph/unit-state-facts.js.map +1 -0
- package/dist/harness/audit.d.ts +11 -0
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +34 -9
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/catalog/gate-rules.yaml +647 -0
- package/dist/harness/counted-assertions.d.ts +2 -0
- package/dist/harness/counted-assertions.d.ts.map +1 -0
- package/dist/harness/counted-assertions.js +38 -0
- package/dist/harness/counted-assertions.js.map +1 -0
- package/dist/harness/defect-draft.d.ts +14 -0
- package/dist/harness/defect-draft.d.ts.map +1 -0
- package/dist/harness/defect-draft.js +143 -0
- package/dist/harness/defect-draft.js.map +1 -0
- package/dist/harness/defects.d.ts +24 -0
- package/dist/harness/defects.d.ts.map +1 -0
- package/dist/harness/defects.js +118 -0
- package/dist/harness/defects.js.map +1 -0
- package/dist/harness/gates/audit-gate-terms.d.ts +41 -0
- package/dist/harness/gates/audit-gate-terms.d.ts.map +1 -0
- package/dist/harness/gates/audit-gate-terms.js +72 -0
- package/dist/harness/gates/audit-gate-terms.js.map +1 -0
- package/dist/harness/gates/audit-gate-verdict.d.ts +31 -0
- package/dist/harness/gates/audit-gate-verdict.d.ts.map +1 -0
- package/dist/harness/gates/audit-gate-verdict.js +101 -0
- package/dist/harness/gates/audit-gate-verdict.js.map +1 -0
- package/dist/harness/gates/audit-input-hash.d.ts +4 -0
- package/dist/harness/gates/audit-input-hash.d.ts.map +1 -0
- package/dist/harness/gates/audit-input-hash.js +96 -0
- package/dist/harness/gates/audit-input-hash.js.map +1 -0
- package/dist/harness/gates/audit-report-verification.d.ts +41 -0
- package/dist/harness/gates/audit-report-verification.d.ts.map +1 -0
- package/dist/harness/gates/audit-report-verification.js +236 -0
- package/dist/harness/gates/audit-report-verification.js.map +1 -0
- package/dist/harness/gates/decisions-hash.d.ts +13 -0
- package/dist/harness/gates/decisions-hash.d.ts.map +1 -0
- package/dist/harness/gates/decisions-hash.js +72 -0
- package/dist/harness/gates/decisions-hash.js.map +1 -0
- package/dist/harness/gates/delivery-checklist.d.ts +21 -0
- package/dist/harness/gates/delivery-checklist.d.ts.map +1 -0
- package/dist/harness/gates/delivery-checklist.js +128 -0
- package/dist/harness/gates/delivery-checklist.js.map +1 -0
- package/dist/harness/gates/delivery-decision-gate.d.ts +33 -0
- package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -0
- package/dist/harness/gates/delivery-decision-gate.js +116 -0
- package/dist/harness/gates/delivery-decision-gate.js.map +1 -0
- package/dist/harness/gates/delivery-decision-step.d.ts +19 -0
- package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -0
- package/dist/harness/gates/delivery-decision-step.js +86 -0
- package/dist/harness/gates/delivery-decision-step.js.map +1 -0
- package/dist/harness/gates/gate-override-report.d.ts +59 -0
- package/dist/harness/gates/gate-override-report.d.ts.map +1 -0
- package/dist/harness/gates/gate-override-report.js +86 -0
- package/dist/harness/gates/gate-override-report.js.map +1 -0
- package/dist/harness/gates/gate-override-scope.d.ts +18 -0
- package/dist/harness/gates/gate-override-scope.d.ts.map +1 -0
- package/dist/harness/gates/gate-override-scope.js +98 -0
- package/dist/harness/gates/gate-override-scope.js.map +1 -0
- package/dist/harness/gates/gate-override-validation.d.ts +25 -0
- package/dist/harness/gates/gate-override-validation.d.ts.map +1 -0
- package/dist/harness/gates/gate-override-validation.js +81 -0
- package/dist/harness/gates/gate-override-validation.js.map +1 -0
- package/dist/harness/gates/gate-rule-catalog.d.ts +24 -0
- package/dist/harness/gates/gate-rule-catalog.d.ts.map +1 -0
- package/dist/harness/gates/gate-rule-catalog.js +112 -0
- package/dist/harness/gates/gate-rule-catalog.js.map +1 -0
- package/dist/harness/gates/gate-terms.d.ts +33 -0
- package/dist/harness/gates/gate-terms.d.ts.map +1 -0
- package/dist/harness/gates/gate-terms.js +41 -0
- package/dist/harness/gates/gate-terms.js.map +1 -0
- package/dist/harness/gates/in-run-decision-check.d.ts +21 -0
- package/dist/harness/gates/in-run-decision-check.d.ts.map +1 -0
- package/dist/harness/gates/in-run-decision-check.js +138 -0
- package/dist/harness/gates/in-run-decision-check.js.map +1 -0
- package/dist/harness/gates/journey-gate-inputs.d.ts +37 -0
- package/dist/harness/gates/journey-gate-inputs.d.ts.map +1 -0
- package/dist/harness/gates/journey-gate-inputs.js +81 -0
- package/dist/harness/gates/journey-gate-inputs.js.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts +6 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.js +116 -0
- package/dist/harness/gates/migrated-waiver-review.js.map +1 -0
- package/dist/harness/gates/resolve-rule.d.ts +59 -0
- package/dist/harness/gates/resolve-rule.d.ts.map +1 -0
- package/dist/harness/gates/resolve-rule.js +41 -0
- package/dist/harness/gates/resolve-rule.js.map +1 -0
- package/dist/harness/gates/unit-gate-overrides.d.ts +25 -0
- package/dist/harness/gates/unit-gate-overrides.d.ts.map +1 -0
- package/dist/harness/gates/unit-gate-overrides.js +122 -0
- package/dist/harness/gates/unit-gate-overrides.js.map +1 -0
- package/dist/harness/journey.d.ts +43 -1
- package/dist/harness/journey.d.ts.map +1 -1
- package/dist/harness/journey.js +207 -33
- package/dist/harness/journey.js.map +1 -1
- package/dist/harness/manifest.d.ts +12 -0
- package/dist/harness/manifest.d.ts.map +1 -1
- package/dist/harness/manifest.js +73 -45
- package/dist/harness/manifest.js.map +1 -1
- package/dist/harness/next-step.d.ts +37 -6
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +34 -174
- package/dist/harness/next-step.js.map +1 -1
- package/dist/harness/parse.d.ts +25 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +38 -13
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/provenance.d.ts +29 -0
- package/dist/harness/provenance.d.ts.map +1 -1
- package/dist/harness/provenance.js +109 -9
- package/dist/harness/provenance.js.map +1 -1
- package/dist/harness/script-check.d.ts.map +1 -1
- package/dist/harness/script-check.js +29 -6
- package/dist/harness/script-check.js.map +1 -1
- package/dist/harness/sensors.d.ts +14 -3
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +64 -44
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/triage-signals.d.ts +20 -0
- package/dist/harness/triage-signals.d.ts.map +1 -0
- package/dist/harness/triage-signals.js +30 -0
- package/dist/harness/triage-signals.js.map +1 -0
- package/dist/harness/triage-unit.d.ts +23 -0
- package/dist/harness/triage-unit.d.ts.map +1 -0
- package/dist/harness/triage-unit.js +142 -0
- package/dist/harness/triage-unit.js.map +1 -0
- package/dist/harness/triage.d.ts +28 -0
- package/dist/harness/triage.d.ts.map +1 -0
- package/dist/harness/triage.js +99 -0
- package/dist/harness/triage.js.map +1 -0
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +2 -1
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/hooks/bash-write-targets.d.ts +15 -0
- package/dist/hooks/bash-write-targets.d.ts.map +1 -0
- package/dist/hooks/bash-write-targets.js +173 -0
- package/dist/hooks/bash-write-targets.js.map +1 -0
- package/dist/hooks/claude-hook-entry.d.ts +11 -0
- package/dist/hooks/claude-hook-entry.d.ts.map +1 -0
- package/dist/hooks/claude-hook-entry.js +137 -0
- package/dist/hooks/claude-hook-entry.js.map +1 -0
- package/dist/hooks/claude-transcript-turn.d.ts +11 -0
- package/dist/hooks/claude-transcript-turn.d.ts.map +1 -0
- package/dist/hooks/claude-transcript-turn.js +143 -0
- package/dist/hooks/claude-transcript-turn.js.map +1 -0
- package/dist/hooks/guard-delivery-contract-rule.d.ts +10 -0
- package/dist/hooks/guard-delivery-contract-rule.d.ts.map +1 -0
- package/dist/hooks/guard-delivery-contract-rule.js +152 -0
- package/dist/hooks/guard-delivery-contract-rule.js.map +1 -0
- package/dist/hooks/guard-protected-paths.d.ts +9 -0
- package/dist/hooks/guard-protected-paths.d.ts.map +1 -0
- package/dist/hooks/guard-protected-paths.js +107 -0
- package/dist/hooks/guard-protected-paths.js.map +1 -0
- package/dist/hooks/guard-rules.d.ts +37 -0
- package/dist/hooks/guard-rules.d.ts.map +1 -0
- package/dist/hooks/guard-rules.js +61 -0
- package/dist/hooks/guard-rules.js.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts +15 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.js +21 -0
- package/dist/hooks/guard-tty-spoof-rule.js.map +1 -0
- package/dist/hooks/hand-back-core.d.ts +39 -0
- package/dist/hooks/hand-back-core.d.ts.map +1 -0
- package/dist/hooks/hand-back-core.js +122 -0
- package/dist/hooks/hand-back-core.js.map +1 -0
- package/dist/hooks/hook-cli-command.d.ts +9 -0
- package/dist/hooks/hook-cli-command.d.ts.map +1 -0
- package/dist/hooks/hook-cli-command.js +46 -0
- package/dist/hooks/hook-cli-command.js.map +1 -0
- package/dist/hooks/hook-registry.d.ts +10 -0
- package/dist/hooks/hook-registry.d.ts.map +1 -0
- package/dist/hooks/hook-registry.js +24 -0
- package/dist/hooks/hook-registry.js.map +1 -0
- package/dist/hooks/hook-result-contract.d.ts +50 -0
- package/dist/hooks/hook-result-contract.d.ts.map +1 -0
- package/dist/hooks/hook-result-contract.js +80 -0
- package/dist/hooks/hook-result-contract.js.map +1 -0
- package/dist/hooks/hook-toggles.d.ts +10 -0
- package/dist/hooks/hook-toggles.d.ts.map +1 -0
- package/dist/hooks/hook-toggles.js +107 -0
- package/dist/hooks/hook-toggles.js.map +1 -0
- package/dist/hooks/pre-tool-guard-hook.d.ts +10 -0
- package/dist/hooks/pre-tool-guard-hook.d.ts.map +1 -0
- package/dist/hooks/pre-tool-guard-hook.js +105 -0
- package/dist/hooks/pre-tool-guard-hook.js.map +1 -0
- package/dist/hooks/session-start-unit-state-hook.d.ts +13 -0
- package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -0
- package/dist/hooks/session-start-unit-state-hook.js +57 -0
- package/dist/hooks/session-start-unit-state-hook.js.map +1 -0
- package/dist/hooks/stop-next-step-hook.d.ts +16 -0
- package/dist/hooks/stop-next-step-hook.d.ts.map +1 -0
- package/dist/hooks/stop-next-step-hook.js +42 -0
- package/dist/hooks/stop-next-step-hook.js.map +1 -0
- package/dist/hooks/sungen-project-root.d.ts +19 -0
- package/dist/hooks/sungen-project-root.d.ts.map +1 -0
- package/dist/hooks/sungen-project-root.js +130 -0
- package/dist/hooks/sungen-project-root.js.map +1 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.d.ts +15 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.js +106 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.js.map +1 -0
- package/dist/orchestrator/ai-skills/commands.d.ts +5 -1
- package/dist/orchestrator/ai-skills/commands.d.ts.map +1 -1
- package/dist/orchestrator/ai-skills/commands.js +16 -6
- package/dist/orchestrator/ai-skills/commands.js.map +1 -1
- package/dist/orchestrator/ai-skills/golden-skills.test.js +29 -0
- package/dist/orchestrator/ai-skills/golden-skills.test.js.map +1 -1
- package/dist/orchestrator/assets-drift.d.ts +5 -0
- package/dist/orchestrator/assets-drift.d.ts.map +1 -1
- package/dist/orchestrator/assets-drift.js +12 -3
- package/dist/orchestrator/assets-drift.js.map +1 -1
- package/dist/orchestrator/claude-hooks-install.d.ts +27 -0
- package/dist/orchestrator/claude-hooks-install.d.ts.map +1 -0
- package/dist/orchestrator/claude-hooks-install.js +203 -0
- package/dist/orchestrator/claude-hooks-install.js.map +1 -0
- package/dist/orchestrator/lockstep-version.d.ts +15 -5
- package/dist/orchestrator/lockstep-version.d.ts.map +1 -1
- package/dist/orchestrator/lockstep-version.js +30 -17
- package/dist/orchestrator/lockstep-version.js.map +1 -1
- package/dist/orchestrator/project-initializer.d.ts +6 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +24 -0
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +4 -2
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/add-api.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +14 -16
- package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/design.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/feedback.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/locale.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/review.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +14 -10
- package/dist/orchestrator/templates/ai-src/config/claude.md +20 -7
- package/dist/orchestrator/templates/ai-src/config/copilot.md +20 -7
- package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
- package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
- package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
- package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/dist/utils/safe-yaml-parse.d.ts +8 -0
- package/dist/utils/safe-yaml-parse.d.ts.map +1 -0
- package/dist/utils/safe-yaml-parse.js +51 -0
- package/dist/utils/safe-yaml-parse.js.map +1 -0
- package/package.json +3 -3
- package/src/basis/anchor-grammar.ts +83 -0
- package/src/basis/anchor-hash.ts +27 -0
- package/src/basis/bm51-tables.ts +65 -0
- package/src/basis/extract-spec-anchors.ts +95 -0
- package/src/basis/migration-sentinel.ts +175 -0
- package/src/basis/spec-frontmatter.ts +68 -0
- package/src/basis/spec-sections.ts +35 -0
- package/src/basis/test-basis-schema.ts +81 -0
- package/src/capabilities/discover.ts +15 -2
- package/src/capabilities/registry.ts +16 -0
- package/src/cli/commands/audit.ts +10 -5
- package/src/cli/commands/capability.ts +4 -2
- package/src/cli/commands/contract-derive-command.ts +61 -0
- package/src/cli/commands/contract.ts +130 -0
- package/src/cli/commands/defect.ts +49 -0
- package/src/cli/commands/delivery.ts +92 -15
- package/src/cli/commands/generate.ts +3 -1
- package/src/cli/commands/journey.ts +41 -16
- package/src/cli/commands/next.ts +64 -10
- package/src/cli/commands/triage.ts +57 -0
- package/src/cli/commands/update.ts +35 -8
- package/src/cli/index.ts +24 -30
- package/src/cli/project-sungen-invocation.ts +39 -0
- package/src/contract/approve-contract.ts +94 -0
- package/src/contract/assertion-matcher-vocabulary.ts +93 -0
- package/src/contract/build-contract-verdict.ts +108 -0
- package/src/contract/build-trace-conformance.ts +100 -0
- package/src/contract/classify-contract-change.ts +92 -0
- package/src/contract/classify-contract-unit.ts +47 -0
- package/src/contract/classify-trace-conformance.ts +116 -0
- package/src/contract/contract-git.ts +106 -0
- package/src/contract/contract-hash.ts +34 -0
- package/src/contract/contract-report-file.ts +25 -0
- package/src/contract/contract-schema.ts +137 -0
- package/src/contract/contract-units.ts +52 -0
- package/src/contract/contracts-lock-file.ts +97 -0
- package/src/contract/data-normalize.ts +66 -0
- package/src/contract/derive-free-feature.ts +120 -0
- package/src/contract/field-semantic-redaction.ts +80 -0
- package/src/contract/free-feature-blocks.ts +56 -0
- package/src/contract/lock-secret-guard.ts +95 -0
- package/src/contract/lock-vs-git-head.ts +38 -0
- package/src/contract/normalize-contract-step.ts +74 -0
- package/src/contract/normalize-feature-steps.ts +93 -0
- package/src/contract/oracle-strength.ts +80 -0
- package/src/contract/project-contract-blockers.ts +36 -0
- package/src/contract/record-contract-approval.ts +70 -0
- package/src/contract/render-free-gherkin.ts +113 -0
- package/src/contract/render-trace-sentence.ts +98 -0
- package/src/contract/render-trace-target.ts +68 -0
- package/src/contract/resolve-unit-trace-identities.ts +35 -0
- package/src/contract/trace/collect-trace-evidence.ts +109 -0
- package/src/contract/trace/identity-cache.ts +61 -0
- package/src/contract/trace/select-final-attempt.ts +70 -0
- package/src/contract/trace/snapshot-html-renderer.ts +136 -0
- package/src/contract/trace/snapshot-resolver.ts +66 -0
- package/src/contract/trace/snapshot-store.ts +151 -0
- package/src/contract/trace/target-identity.ts +104 -0
- package/src/contract/trace/test-step-join.ts +104 -0
- package/src/contract/trace/trace-binding.ts +56 -0
- package/src/contract/trace/trace-file-reader.ts +133 -0
- package/src/contract/trace/trace-fingerprint.ts +68 -0
- package/src/contract/trace/trace-identity-resolution.ts +74 -0
- package/src/contract/trace/trace-run-record.ts +80 -0
- package/src/contract/trace/trace-steps.ts +88 -0
- package/src/contract/trace/trace-zip-limits.ts +77 -0
- package/src/contract/trace/trace-zip-reader.ts +127 -0
- package/src/contract/verify-approval-decisions.ts +60 -0
- package/src/decisions/append-decision.ts +35 -0
- package/src/decisions/confirmed-decision-commands.ts +149 -0
- package/src/decisions/decision-file.ts +93 -0
- package/src/decisions/decision-identity.ts +73 -0
- package/src/decisions/decision-integrity-check.ts +61 -0
- package/src/decisions/decision-schema.ts +76 -0
- package/src/decisions/decision-source.ts +14 -0
- package/src/decisions/exclusive-file-create.ts +42 -0
- package/src/decisions/git-head-trust.ts +32 -0
- package/src/decisions/human-confirmation.ts +119 -0
- package/src/decisions/legacy-waiver-migration.ts +135 -0
- package/src/decisions/read-decisions.ts +61 -0
- package/src/decisions/viewpoint-baseline-adapter.ts +74 -0
- package/src/decisions/waiver-decisions.ts +56 -0
- package/src/exporters/csv-exporter.ts +5 -1
- package/src/exporters/feature-parser.ts +12 -0
- package/src/exporters/matrix/build.ts +62 -18
- package/src/exporters/matrix/carry-manual-results.ts +70 -7
- package/src/exporters/matrix/export.ts +17 -2
- package/src/exporters/matrix/gates.ts +62 -129
- package/src/exporters/matrix/render-csv.ts +4 -1
- package/src/exporters/matrix/render-gate-overrides-sheet.ts +50 -0
- package/src/exporters/matrix/render-xlsx.ts +6 -0
- package/src/exporters/matrix/types.ts +9 -1
- package/src/exporters/matrix/xlsx-cells.ts +1 -1
- package/src/exporters/playwright-report-parser.ts +1 -0
- package/src/exporters/scenario-merger.ts +2 -1
- package/src/exporters/types.ts +5 -0
- package/src/generators/test-generator/code-generator.ts +13 -0
- package/src/graph/evaluate-graph.ts +66 -0
- package/src/graph/locate-finding.ts +93 -0
- package/src/graph/node-decl.ts +72 -0
- package/src/graph/nodes/core-node-catalog.ts +15 -0
- package/src/graph/nodes/test-case-contract-nodes.ts +74 -0
- package/src/graph/nodes/test-case-nodes.ts +68 -0
- package/src/graph/nodes/unit-audit-nodes.ts +95 -0
- package/src/graph/nodes/unit-contract-node.ts +89 -0
- package/src/graph/nodes/unit-design-nodes.ts +89 -0
- package/src/graph/nodes/unit-execution-nodes.ts +77 -0
- package/src/graph/test-case-identity.ts +75 -0
- package/src/graph/test-case-results.ts +90 -0
- package/src/graph/test-case-satisfied.ts +55 -0
- package/src/graph/test-case-state-shape.ts +62 -0
- package/src/graph/test-case-states.ts +84 -0
- package/src/graph/unit-artifact-probes.ts +77 -0
- package/src/graph/unit-state-facts.ts +112 -0
- package/src/harness/audit.ts +46 -11
- package/src/harness/catalog/gate-rules.yaml +647 -0
- package/src/harness/counted-assertions.ts +33 -0
- package/src/harness/defect-draft.ts +115 -0
- package/src/harness/defects.ts +94 -0
- package/src/harness/gates/audit-gate-terms.ts +80 -0
- package/src/harness/gates/audit-gate-verdict.ts +78 -0
- package/src/harness/gates/audit-input-hash.ts +55 -0
- package/src/harness/gates/audit-report-verification.ts +201 -0
- package/src/harness/gates/decisions-hash.ts +42 -0
- package/src/harness/gates/delivery-checklist.ts +120 -0
- package/src/harness/gates/delivery-decision-gate.ts +139 -0
- package/src/harness/gates/delivery-decision-step.ts +89 -0
- package/src/harness/gates/gate-override-report.ts +114 -0
- package/src/harness/gates/gate-override-scope.ts +66 -0
- package/src/harness/gates/gate-override-validation.ts +75 -0
- package/src/harness/gates/gate-rule-catalog.ts +82 -0
- package/src/harness/gates/gate-terms.ts +59 -0
- package/src/harness/gates/in-run-decision-check.ts +99 -0
- package/src/harness/gates/journey-gate-inputs.ts +89 -0
- package/src/harness/gates/migrated-waiver-review.ts +68 -0
- package/src/harness/gates/resolve-rule.ts +94 -0
- package/src/harness/gates/unit-gate-overrides.ts +99 -0
- package/src/harness/journey.ts +215 -38
- package/src/harness/manifest.ts +69 -45
- package/src/harness/next-step.ts +60 -170
- package/src/harness/parse.ts +40 -13
- package/src/harness/provenance.ts +99 -11
- package/src/harness/script-check.ts +27 -6
- package/src/harness/sensors.ts +73 -47
- package/src/harness/triage-signals.ts +46 -0
- package/src/harness/triage-unit.ts +113 -0
- package/src/harness/triage.ts +127 -0
- package/src/harness/viewpoint-ledger.ts +2 -2
- package/src/hooks/bash-write-targets.ts +109 -0
- package/src/hooks/claude-hook-entry.ts +85 -0
- package/src/hooks/claude-transcript-turn.ts +96 -0
- package/src/hooks/guard-delivery-contract-rule.ts +110 -0
- package/src/hooks/guard-protected-paths.ts +71 -0
- package/src/hooks/guard-rules.ts +98 -0
- package/src/hooks/guard-tty-spoof-rule.ts +31 -0
- package/src/hooks/hand-back-core.ts +112 -0
- package/src/hooks/hook-cli-command.ts +17 -0
- package/src/hooks/hook-registry.ts +24 -0
- package/src/hooks/hook-result-contract.ts +114 -0
- package/src/hooks/hook-toggles.ts +66 -0
- package/src/hooks/pre-tool-guard-hook.ts +67 -0
- package/src/hooks/session-start-unit-state-hook.ts +56 -0
- package/src/hooks/stop-next-step-hook.ts +37 -0
- package/src/hooks/sungen-project-root.ts +80 -0
- package/src/orchestrator/ai-skills/command-partial-includes.ts +72 -0
- package/src/orchestrator/ai-skills/commands.ts +22 -8
- package/src/orchestrator/ai-skills/golden-skills.test.ts +23 -0
- package/src/orchestrator/assets-drift.ts +12 -5
- package/src/orchestrator/claude-hooks-install.ts +168 -0
- package/src/orchestrator/lockstep-version.ts +28 -15
- package/src/orchestrator/project-initializer.ts +22 -0
- package/src/orchestrator/screen-manager.ts +3 -1
- package/src/orchestrator/templates/ai-src/commands/add-api.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
- package/src/orchestrator/templates/ai-src/commands/create-test.md +14 -16
- package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/delivery.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/design.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/feedback.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/locale.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/review.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/run-test.md +14 -10
- package/src/orchestrator/templates/ai-src/config/claude.md +20 -7
- package/src/orchestrator/templates/ai-src/config/copilot.md +20 -7
- package/src/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
- package/src/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
- package/src/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
- package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/src/utils/safe-yaml-parse.ts +44 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `decisionsHash` (OES-11.4, red-team #12): a fingerprint of the decisions that can change a unit's
|
|
3
|
+
* gate outcome. The audit records it; `next`, `gate` and `delivery` recompute it — a mismatch means
|
|
4
|
+
* the audit was measured under other decisions: stale, re-audit.
|
|
5
|
+
*
|
|
6
|
+
* What it covers, for one unit — the project's `qa/decisions/` plus the unit's own directory:
|
|
7
|
+
* - every `gate-override` entry that can apply to the unit (accepted, ineffective, rejected,
|
|
8
|
+
* superseded alike), by path and entry_hash
|
|
9
|
+
* - every file there that does not verify (unreadable, invalid, id or hash mismatch), by path,
|
|
10
|
+
* problem and content — it may be an override nobody can read
|
|
11
|
+
* What it does NOT cover: waivers. A waiver is bound to the audit by `evidence_hash = hash of the
|
|
12
|
+
* audit report`; folding it in here would make every waiver stale the audit that it waives.
|
|
13
|
+
*/
|
|
14
|
+
import { createHash } from 'crypto';
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import { canonicalJson } from '../../decisions/decision-identity';
|
|
18
|
+
import { DecisionProblem } from '../../decisions/decision-file';
|
|
19
|
+
|
|
20
|
+
export interface DecisionsHashItem {
|
|
21
|
+
path: string;
|
|
22
|
+
entryHash?: string;
|
|
23
|
+
problem?: string;
|
|
24
|
+
contentSha?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const sha256 = (s: string | Buffer): string => createHash('sha256').update(s).digest('hex');
|
|
28
|
+
|
|
29
|
+
export function computeDecisionsHash(items: DecisionsHashItem[]): string {
|
|
30
|
+
const sorted = [...items].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
31
|
+
return sha256(canonicalJson({ schema: 1, decisions: sorted }));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The hash of a unit with no decision that can touch its gates. */
|
|
35
|
+
export const EMPTY_DECISIONS_HASH = computeDecisionsHash([]);
|
|
36
|
+
|
|
37
|
+
/** A problem file as a hash item: its content counts, so editing it re-stales the audit. */
|
|
38
|
+
export function problemHashItem(projectRoot: string, p: DecisionProblem): DecisionsHashItem {
|
|
39
|
+
let contentSha = 'unreadable';
|
|
40
|
+
try { contentSha = sha256(fs.readFileSync(p.path)); } catch { /* gone or unreadable: the marker stands */ }
|
|
41
|
+
return { path: path.relative(projectRoot, p.path).split(path.sep).join('/'), problem: p.code, contentSha };
|
|
42
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The delivery checklist (P0 phase 09, takumi T6) — `sungen delivery` prints one block per delivered
|
|
3
|
+
* unit, and every box is read off a result REBUILT NOW, never from a report file and never by hand:
|
|
4
|
+
*
|
|
5
|
+
* audit verifyAuditReport: a report that counts and its gateStatus (`sungen audit` 0 | 2)
|
|
6
|
+
* script-check runScriptCheck: OK | FAIL (`sungen script-check` 0 | 2)
|
|
7
|
+
* contract check buildContractVerdict: pass | review | fail (`sungen contract check` 0 | 0 | 2)
|
|
8
|
+
* decisions evaluateDeliveryDecisions: problems, in-run decisions (what this delivery checks)
|
|
9
|
+
* triage testCaseStates: every red case classified, candidates decided
|
|
10
|
+
* A box that cannot apply is SKIPPED with its reason — never absent, never ticked. The checklist only
|
|
11
|
+
* reports: the gates before it decide whether the delivery runs, so no exit code moves because of it.
|
|
12
|
+
*/
|
|
13
|
+
import { buildContractVerdict } from '../../contract/build-contract-verdict';
|
|
14
|
+
import { readTextOrNull } from '../../contract/contract-git';
|
|
15
|
+
import { lockPathFor } from '../../contract/contracts-lock-file';
|
|
16
|
+
import { testCaseNeed } from '../../graph/test-case-satisfied';
|
|
17
|
+
import { testCaseStates } from '../../graph/test-case-states';
|
|
18
|
+
import { runScriptCheck, UnitKind } from '../script-check';
|
|
19
|
+
import { auditCounts, auditNotCountedReason, verifyAuditReport } from './audit-report-verification';
|
|
20
|
+
import { evaluateDeliveryDecisions } from './delivery-decision-gate';
|
|
21
|
+
import type { InRunAcceptance } from './gate-override-report';
|
|
22
|
+
|
|
23
|
+
export type BoxState = 'pass' | 'fail' | 'skipped';
|
|
24
|
+
export interface ChecklistBox { name: string; state: BoxState; evidence: string }
|
|
25
|
+
export interface ChecklistUnit { label: string; unitName: string; unitDir: string; kind: UnitKind; resultsPath: string | null }
|
|
26
|
+
|
|
27
|
+
/** `sungen contract check` judges traces with a generous deadline; the checklist states what it would say. */
|
|
28
|
+
const CONTRACT_TRACE_BUDGET_MS = 120_000;
|
|
29
|
+
const why = (e: unknown): string => (e instanceof Error ? e.message : String(e)).split('\n')[0].slice(0, 200);
|
|
30
|
+
const box = (name: string, state: BoxState, evidence: string): ChecklistBox => ({ name, state, evidence });
|
|
31
|
+
|
|
32
|
+
function auditBox(projectRoot: string, u: ChecklistUnit): ChecklistBox {
|
|
33
|
+
const v = verifyAuditReport(projectRoot, u.unitName);
|
|
34
|
+
if (!auditCounts(v)) return box('audit', 'fail', auditNotCountedReason(v, u.unitName));
|
|
35
|
+
const overall = (v.report?.score as { overall?: number } | undefined)?.overall;
|
|
36
|
+
const how = "verified against today's inputs";
|
|
37
|
+
return v.report?.gateStatus === 'PASS'
|
|
38
|
+
? box('audit', 'pass', `PASS ${overall ?? '?'}/10 — ${how}`)
|
|
39
|
+
: box('audit', 'fail', `FAIL ${overall ?? '?'}/10 — \`sungen audit\` exits 2 (${how}); an official delivery is blocked until it passes — --preview renders a draft`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The compiler prints progress on stdout; the checklist keeps the delivery output to itself. */
|
|
43
|
+
async function quietly<T>(fn: () => Promise<T>): Promise<T> {
|
|
44
|
+
const saved = { log: console.log, info: console.info, warn: console.warn };
|
|
45
|
+
console.log = console.info = console.warn = () => undefined;
|
|
46
|
+
try { return await fn(); } finally { Object.assign(console, saved); }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function scriptCheckBox(u: ChecklistUnit): Promise<ChecklistBox> {
|
|
50
|
+
try {
|
|
51
|
+
const r = await quietly(() => runScriptCheck(u.unitDir, u.unitName, u.kind));
|
|
52
|
+
if (!r.specPath) return box('script-check', 'skipped', 'no compiled spec to compare: nothing was compiled for this unit');
|
|
53
|
+
return r.status === 'OK'
|
|
54
|
+
? box('script-check', 'pass', `OK — the spec is a 1:1 of the .feature, no drift (${r.automatedScenarios} automated)`)
|
|
55
|
+
: box('script-check', 'fail', `FAIL — ${(r.findings[0] ?? 'not faithful').split(/ → |\. /)[0].slice(0, 160)} (\`sungen script-check\` exits 2)`);
|
|
56
|
+
} catch (e) {
|
|
57
|
+
return box('script-check', 'fail', `could not run: ${why(e)}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function contractBox(projectRoot: string, u: ChecklistUnit): ChecklistBox {
|
|
62
|
+
try {
|
|
63
|
+
const v = buildContractVerdict(projectRoot, { name: u.unitName, dir: u.unitDir }, { traceBudgetMs: CONTRACT_TRACE_BUDGET_MS });
|
|
64
|
+
if (readTextOrNull(lockPathFor(u.unitDir)) === null) {
|
|
65
|
+
return box('contract check', 'skipped', `no contracts.lock.yaml: ${v.scenarios.length} scenario(s) proposed, nothing approved to compare (never blocks)`);
|
|
66
|
+
}
|
|
67
|
+
const bad = v.scenarios.filter((s) => !['match', 'strengthened', 'proposed', 'nondeterministic'].includes(s.class));
|
|
68
|
+
if (v.verdict === 'pass') return box('contract check', 'pass', `pass — every approved scenario holds (\`sungen contract check\` exits 0)`);
|
|
69
|
+
const first = v.uncommitted[0] ? `${v.uncommitted[0].id} lock-uncommitted` : bad[0] ? `${bad[0].id} ${bad[0].class}` : v.verdict;
|
|
70
|
+
return v.verdict === 'review'
|
|
71
|
+
? box('contract check', 'fail', `review — ${bad.length} scenario(s), e.g. ${first}; exits 0 but blocks delivery until QA re-approves`)
|
|
72
|
+
: box('contract check', 'fail', `FAIL — ${first}${bad.length + v.uncommitted.length > 1 ? ` and ${bad.length + v.uncommitted.length - 1} more` : ''} (\`sungen contract check\` exits 2)`);
|
|
73
|
+
} catch (e) {
|
|
74
|
+
return box('contract check', 'fail', `could not be built: ${why(e)} (\`sungen contract check\` exits 1)`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function decisionsBox(projectRoot: string, u: ChecklistUnit, accepted?: InRunAcceptance): ChecklistBox {
|
|
79
|
+
try {
|
|
80
|
+
const g = evaluateDeliveryDecisions(projectRoot, [{ label: u.label, unitName: u.unitName, unitDir: u.unitDir, resultsPath: u.resultsPath }]);
|
|
81
|
+
if (g.blocking.length) return box('decisions', 'fail', `${g.blocking.length} decision problem(s) — ${g.blocking[0].slice(0, 160)}`);
|
|
82
|
+
if (g.inRun.length && !accepted) return box('decisions', 'fail', `${g.inRun.length} decision(s) recorded during the run (decision.in-run) — commit them through review and re-run, or a human passes --accept-in-run`);
|
|
83
|
+
const overrides = g.overridesFor(u.unitDir).length;
|
|
84
|
+
return box('decisions', 'pass', `no decision problem${g.inRun.length ? ` · ${g.inRun.length} in-run decision(s) accepted by ${accepted!.by} on a terminal` : ''}${overrides ? ` · ${overrides} gate override(s) in force` : ''}`);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
return box('decisions', 'fail', `could not be evaluated: ${why(e)}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function triageBox(projectRoot: string, u: ChecklistUnit): ChecklistBox {
|
|
91
|
+
try {
|
|
92
|
+
const cases = testCaseStates(projectRoot, u.unitName, { unitDir: u.unitDir });
|
|
93
|
+
if (!cases.some((c) => c.result !== 'never-run')) return box('triage', 'skipped', 'no run results to classify');
|
|
94
|
+
const owed = cases.filter((c) => testCaseNeed(c) === 'triage');
|
|
95
|
+
const decide = cases.filter((c) => testCaseNeed(c) === 'product-candidate');
|
|
96
|
+
const flag = u.kind === 'api' ? '--api' : '--screen';
|
|
97
|
+
if (owed.length) return box('triage', 'fail', `${owed.length} red test case(s) not classified — run \`sungen triage ${flag} ${u.unitName}\``);
|
|
98
|
+
if (decide.length) return box('triage', 'fail', `${decide.length} product-defect candidate(s) await a QA decision (\`sungen defect draft ${flag} ${u.unitName}\`)`);
|
|
99
|
+
const reds = cases.filter((c) => c.result === 'failed').length;
|
|
100
|
+
return box('triage', 'pass', reds ? `${reds} red test case(s), each classified or exempt` : 'no red test case');
|
|
101
|
+
} catch (e) {
|
|
102
|
+
return box('triage', 'fail', `could not be read: ${why(e)}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function unitChecklist(projectRoot: string, u: ChecklistUnit, accepted?: InRunAcceptance): Promise<ChecklistBox[]> {
|
|
107
|
+
return [auditBox(projectRoot, u), await scriptCheckBox(u), contractBox(projectRoot, u), decisionsBox(projectRoot, u, accepted), triageBox(projectRoot, u)];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const MARK: Record<BoxState, string> = { pass: '[x]', fail: '[ ]', skipped: '[-]' };
|
|
111
|
+
|
|
112
|
+
export function renderChecklist(rows: Array<{ label: string; boxes: ChecklistBox[] }>): string[] {
|
|
113
|
+
const out = ['⚒ Delivery checklist — each box from a real exit code or state, none ticked by hand'];
|
|
114
|
+
for (const r of rows) {
|
|
115
|
+
out.push(` ${r.label}`);
|
|
116
|
+
for (const b of r.boxes) out.push(` ${MARK[b.state]} ${b.name.padEnd(15)} ${b.state === 'skipped' ? `skipped — ${b.evidence}` : b.evidence}`);
|
|
117
|
+
}
|
|
118
|
+
out.push(' The gates above decided this delivery; the checklist only reports what holds now.');
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decision checks `sungen delivery` runs before it writes anything (OES-11.3–11.6):
|
|
3
|
+
*
|
|
4
|
+
* hard, block a decision in reach that does not verify or a committed one edited/deleted
|
|
5
|
+
* (decision.id-reuse / decision.mutated); a rejected override (gate.override-rejected);
|
|
6
|
+
* a decision recorded during the run (decision.in-run) — unless a human accepts it
|
|
7
|
+
* on a TTY with `--accept-in-run`
|
|
8
|
+
* no trusted no audit report, or one that does not count (stale, invalid, verdict-mismatch):
|
|
9
|
+
* audit a real delivery stops and asks for `sungen audit` (owner decision 2026-10-22);
|
|
10
|
+
* `--preview` / `--check` go on with a warning — the caller decides (`untrustedAudits`)
|
|
11
|
+
* failing a trusted audit whose verdict is FAIL (`sungen audit` exits 2): the same — a real
|
|
12
|
+
* audit delivery stops, naming the failing gate rules (#935, owner decision); `--preview`
|
|
13
|
+
* renders a DRAFT, `--check` reports it (`failingAudits`)
|
|
14
|
+
* It also hands each target its gate rules (catalog + overrides) for the matrix gates, and the
|
|
15
|
+
* override rows the XLSX may show. With no decision in reach nothing here changes the delivery.
|
|
16
|
+
*/
|
|
17
|
+
import { checkDecisionIntegrity, DecisionFinding } from '../../decisions/decision-integrity-check';
|
|
18
|
+
import { PROJECT_SCOPE } from '../../decisions/decision-file';
|
|
19
|
+
import { auditCounts, verifyAuditReport } from './audit-report-verification';
|
|
20
|
+
import { auditGateTerms, termSourcesOf } from './audit-gate-terms';
|
|
21
|
+
import { GateOverrideReport, gateOverrideReports, gateOverrideSummaryLine, InRunAcceptance } from './gate-override-report';
|
|
22
|
+
import { unitsCoveredByScope } from './gate-override-scope';
|
|
23
|
+
import { committedDecisionPaths, hasInRunKindDecisions, inRunDecisions, InRunDecision, IN_RUN_RULE, runStartOf } from './in-run-decision-check';
|
|
24
|
+
import { resolveRule, trackGateRules, TrackedGateRules } from './resolve-rule';
|
|
25
|
+
import { loadUnitGateOverrides, unitScopeOfDir, UnitGateOverrides } from './unit-gate-overrides';
|
|
26
|
+
|
|
27
|
+
export interface DeliveryUnitRef { label: string; unitName: string; unitDir: string; resultsPath: string | null }
|
|
28
|
+
|
|
29
|
+
interface UnitState {
|
|
30
|
+
ref: DeliveryUnitRef;
|
|
31
|
+
/** Every delivered run of the unit (one per feature file); a decision after ANY of their starts is in-run. */
|
|
32
|
+
resultsPaths: Array<string | null>;
|
|
33
|
+
overrides: UnitGateOverrides;
|
|
34
|
+
rules: TrackedGateRules;
|
|
35
|
+
auditTriggered: Set<string>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface DeliveryDecisionGate {
|
|
39
|
+
blocking: string[];
|
|
40
|
+
/** Units with no trusted audit — a real delivery stops on them, --preview / --check warn. */
|
|
41
|
+
untrustedAudits: string[];
|
|
42
|
+
/** Units whose trusted audit FAILs (#935) — a real delivery stops on them, --preview / --check warn. */
|
|
43
|
+
failingAudits: string[];
|
|
44
|
+
/** The unit's audit does not let it be delivered officially (untrusted or FAIL): its render is a DRAFT. */
|
|
45
|
+
auditDraft(unitDir: string): boolean;
|
|
46
|
+
notes: string[];
|
|
47
|
+
inRun: Array<InRunDecision & { unit: string }>;
|
|
48
|
+
/** The unit's tracked gate rules, for the matrix gates of its targets. */
|
|
49
|
+
rulesFor(unitDir: string): TrackedGateRules | undefined;
|
|
50
|
+
/** Every override touching the unit, with what changed an outcome (audit or matrix). */
|
|
51
|
+
overridesFor(unitDir: string): GateOverrideReport[];
|
|
52
|
+
summaryLines(): string[];
|
|
53
|
+
/** Set when a human accepted the in-run decisions on a terminal (--accept-in-run) — goes into the deliverable. */
|
|
54
|
+
acceptedInRun?: InRunAcceptance;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const reachOf = (scope: string | null): string[] => [`qa/decisions/`, ...(scope ? [`qa/${scope}/decisions/`] : [])];
|
|
58
|
+
|
|
59
|
+
/** The audit gate rules a FAIL report's own terms violate under the unit's overrides, gaps named. */
|
|
60
|
+
function failingGateRules(report: Record<string, unknown>, overrides: UnitGateOverrides): string {
|
|
61
|
+
const sources = termSourcesOf(report, true);
|
|
62
|
+
if (!sources) return 'its gate terms';
|
|
63
|
+
const gaps = (sources.gate.gaps as Array<{ theme?: unknown; status?: unknown }>)
|
|
64
|
+
.map((g) => `${g.status === 'shallow' ? 'SHALLOW' : 'MISSING'}: ${String(g.theme)}`);
|
|
65
|
+
const rules = auditGateTerms(sources).filter((t) => !t.holds && resolveRule(t.rule, overrides.context).blocking)
|
|
66
|
+
.map((t) => (t.rule === 'audit.viewpoint-coverage' && gaps.length ? `${t.rule} (${gaps.join(', ')})` : t.rule));
|
|
67
|
+
return rules.join(', ') || 'its gate terms';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function evaluateDeliveryDecisions(projectRoot: string, refs: DeliveryUnitRef[]): DeliveryDecisionGate {
|
|
71
|
+
const blocking: string[] = [];
|
|
72
|
+
const untrustedAudits: string[] = [];
|
|
73
|
+
const failingAudits: string[] = [];
|
|
74
|
+
const draftDirs = new Set<string>();
|
|
75
|
+
const notes: string[] = [];
|
|
76
|
+
const inRun: DeliveryDecisionGate['inRun'] = [];
|
|
77
|
+
const units = new Map<string, UnitState>();
|
|
78
|
+
for (const ref of refs) {
|
|
79
|
+
const known = units.get(ref.unitDir);
|
|
80
|
+
if (known) { known.resultsPaths.push(ref.resultsPath); continue; }
|
|
81
|
+
const overrides = loadUnitGateOverrides(projectRoot, unitScopeOfDir(projectRoot, ref.unitDir));
|
|
82
|
+
const audit = verifyAuditReport(projectRoot, ref.unitName);
|
|
83
|
+
const auditTriggered = new Set(auditCounts(audit) && Array.isArray(audit.report?.gateOverrides)
|
|
84
|
+
? (audit.report!.gateOverrides as GateOverrideReport[]).filter((g) => g?.triggered).map((g) => g.rule) : []);
|
|
85
|
+
units.set(ref.unitDir, { ref, resultsPaths: [ref.resultsPath], overrides, rules: trackGateRules(overrides.context), auditTriggered });
|
|
86
|
+
for (const r of overrides.rejected) blocking.push(`${ref.label}: gate.override-rejected — ${r.decisionId} (${r.path}): ${r.reason}`);
|
|
87
|
+
const flag = /[\\/]qa[\\/]api[\\/]/.test(ref.unitDir) ? '--api' : '--screen';
|
|
88
|
+
if (!auditCounts(audit)) {
|
|
89
|
+
const why = audit.state === 'absent' ? 'no audit report' : `the audit is ${audit.state === 'stale' ? 'stale' : 'not trusted'}: ${audit.problems.map((p) => p.message).join('; ')}`;
|
|
90
|
+
untrustedAudits.push(`${ref.label}: ${why} — re-run \`sungen audit ${flag} ${ref.unitName}\``);
|
|
91
|
+
draftDirs.add(ref.unitDir);
|
|
92
|
+
} else if (audit.report?.gateStatus !== 'PASS') {
|
|
93
|
+
const overall = (audit.report?.score as { overall?: number } | undefined)?.overall;
|
|
94
|
+
failingAudits.push(`${ref.label}: FAIL ${overall ?? '?'}/10 on ${failingGateRules(audit.report!, overrides)} — fix the suite, then re-run \`sungen audit ${flag} ${ref.unitName}\``);
|
|
95
|
+
draftDirs.add(ref.unitDir);
|
|
96
|
+
}
|
|
97
|
+
for (const n of audit.notes) notes.push(`${ref.label}: ${n}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const reach = new Set([...units.values()].flatMap((u) => reachOf(u.overrides.unitScope)));
|
|
101
|
+
const integrity: DecisionFinding[] = checkDecisionIntegrity(projectRoot).filter((f) => [...reach].some((r) => f.path.startsWith(r)));
|
|
102
|
+
for (const f of integrity) if (resolveRule(f.rule).blocking) blocking.push(`${f.rule} — ${f.path}: ${f.message}`);
|
|
103
|
+
|
|
104
|
+
const committed = committedDecisionPaths(projectRoot);
|
|
105
|
+
for (const u of units.values()) {
|
|
106
|
+
const scopes = [PROJECT_SCOPE, ...(u.overrides.unitScope ? [u.overrides.unitScope] : [])];
|
|
107
|
+
const starts = u.resultsPaths.map(runStartOf).filter((t): t is string => !!t).sort((x, y) => Date.parse(x) - Date.parse(y));
|
|
108
|
+
const runStart = starts[0] ?? null;
|
|
109
|
+
if (!committed && hasInRunKindDecisions(projectRoot, scopes)) {
|
|
110
|
+
notes.push(runStart
|
|
111
|
+
? `${u.ref.label}: no git repository — ${IN_RUN_RULE} is judged by the run start time only (lower confidence)`
|
|
112
|
+
: `${u.ref.label}: no git repository and no run results — ${IN_RUN_RULE} cannot be judged for its decisions`);
|
|
113
|
+
}
|
|
114
|
+
for (const d of inRunDecisions(projectRoot, scopes, runStart, committed)) {
|
|
115
|
+
if (!inRun.some((x) => x.id === d.id)) inRun.push({ ...d, unit: u.ref.label });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const reportsFor = (u: UnitState): GateOverrideReport[] =>
|
|
120
|
+
gateOverrideReports(u.overrides, new Set([...u.auditTriggered, ...u.rules.triggered()]));
|
|
121
|
+
return {
|
|
122
|
+
blocking,
|
|
123
|
+
untrustedAudits,
|
|
124
|
+
failingAudits,
|
|
125
|
+
auditDraft: (dir) => draftDirs.has(dir),
|
|
126
|
+
notes,
|
|
127
|
+
inRun,
|
|
128
|
+
rulesFor: (dir) => units.get(dir)?.rules,
|
|
129
|
+
overridesFor: (dir) => { const u = units.get(dir); return u ? reportsFor(u) : []; },
|
|
130
|
+
summaryLines: () => [...units.values()]
|
|
131
|
+
.map((u) => gateOverrideSummaryLine(u.ref.label, reportsFor(u), (scope) => unitsCoveredByScope(projectRoot, scope)))
|
|
132
|
+
.filter((l): l is string => !!l),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The in-run decisions, one line each, for the refusal or the TTY confirmation. */
|
|
137
|
+
export function inRunLines(inRun: DeliveryDecisionGate['inRun']): string[] {
|
|
138
|
+
return inRun.map((d) => `${d.unit}: ${d.kind} ${d.id} (${d.path}) — ${d.why.join('; ')}`);
|
|
139
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `sungen delivery` step for decisions (OES-11.5): evaluate, print, and either stop or go.
|
|
3
|
+
* In-run decisions stop the delivery unless a human passes `--accept-in-run` AND confirms on a TTY
|
|
4
|
+
* (DOS-13.4) — without a TTY the refusal prints the exact command for a human to run.
|
|
5
|
+
*/
|
|
6
|
+
import { gitUserName } from '../../decisions/decision-source';
|
|
7
|
+
import { ConfirmationIO, formatCommand, HumanConfirmationRefused, requireTypedConfirmation } from '../../decisions/human-confirmation';
|
|
8
|
+
import { DeliveryDecisionGate, DeliveryUnitRef, evaluateDeliveryDecisions, inRunLines } from './delivery-decision-gate';
|
|
9
|
+
import { IN_RUN_RULE } from './in-run-decision-check';
|
|
10
|
+
|
|
11
|
+
export interface DeliveryDecisionStepInput {
|
|
12
|
+
projectRoot: string;
|
|
13
|
+
refs: DeliveryUnitRef[];
|
|
14
|
+
acceptInRun: boolean;
|
|
15
|
+
/** The delivery command line to print for a human, without `--accept-in-run`. */
|
|
16
|
+
argv: string[];
|
|
17
|
+
io: ConfirmationIO;
|
|
18
|
+
log: (line: string) => void;
|
|
19
|
+
/**
|
|
20
|
+
* A real export needs, per unit, a trusted audit (owner decision 2026-10-22) that PASSes (#935);
|
|
21
|
+
* false for --preview / --check, which go on with a warning (a DRAFT render / a report).
|
|
22
|
+
*/
|
|
23
|
+
requireTrustedAudit: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The gate when the delivery may proceed; null when it must stop (already explained on `log`). */
|
|
27
|
+
export async function runDeliveryDecisionStep(i: DeliveryDecisionStepInput): Promise<DeliveryDecisionGate | null> {
|
|
28
|
+
const gate = evaluateDeliveryDecisions(i.projectRoot, i.refs);
|
|
29
|
+
for (const n of gate.notes) i.log(` · ${n}`);
|
|
30
|
+
if (gate.blocking.length) {
|
|
31
|
+
i.log(`✗ Delivery blocked by ${gate.blocking.length} decision problem(s) (hard rules):`);
|
|
32
|
+
for (const b of gate.blocking) i.log(` - ${b}`);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
// Every reason to stop is listed before stopping, so one run names all of them (audit and in-run).
|
|
36
|
+
let blocked = false;
|
|
37
|
+
if (gate.untrustedAudits.length) {
|
|
38
|
+
i.log(i.requireTrustedAudit
|
|
39
|
+
? `✗ Delivery blocked — ${gate.untrustedAudits.length} unit(s) without a trusted audit (a delivery stands on an audit that matches today's suite):`
|
|
40
|
+
: `⚠ Rendering ${gate.untrustedAudits.length} unit(s) without a trusted audit — a draft, not an official delivery:`);
|
|
41
|
+
for (const u of gate.untrustedAudits) i.log(` - ${u}`);
|
|
42
|
+
if (i.requireTrustedAudit) {
|
|
43
|
+
i.log(' Or render a watermarked draft with --preview.');
|
|
44
|
+
blocked = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (gate.failingAudits.length) {
|
|
48
|
+
i.log(i.requireTrustedAudit
|
|
49
|
+
? `✗ Delivery blocked — ${gate.failingAudits.length} unit(s) whose audit FAILs (\`sungen audit\` exits 2; an official delivery stands on a passing audit):`
|
|
50
|
+
: `⚠ Rendering ${gate.failingAudits.length} unit(s) whose audit FAILs — a draft, not an official delivery:`);
|
|
51
|
+
for (const u of gate.failingAudits) i.log(` - ${u}`);
|
|
52
|
+
if (i.requireTrustedAudit) {
|
|
53
|
+
i.log(' Fix the suite and re-run the audit, or render a watermarked draft with --preview.');
|
|
54
|
+
blocked = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (gate.inRun.length === 0) return blocked ? null : gate;
|
|
58
|
+
const acceptCommand = formatCommand([...i.argv, '--accept-in-run']);
|
|
59
|
+
if (!i.acceptInRun) {
|
|
60
|
+
i.log(`✗ Delivery blocked — ${gate.inRun.length} decision(s) recorded during the run (${IN_RUN_RULE}, hard):`);
|
|
61
|
+
for (const l of inRunLines(gate.inRun)) i.log(` - ${l}`);
|
|
62
|
+
i.log(' Commit them through review and re-run the tests, or have a human accept them on a terminal:');
|
|
63
|
+
i.log(` ${acceptCommand}`);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
if (blocked) return null; // nothing to accept on top of a delivery the audit already stops
|
|
67
|
+
try {
|
|
68
|
+
await requireTypedConfirmation({
|
|
69
|
+
what: `deliver with ${gate.inRun.length} decision(s) recorded during the run (${IN_RUN_RULE})`,
|
|
70
|
+
phrase: 'accept-in-run',
|
|
71
|
+
command: acceptCommand,
|
|
72
|
+
summary: [...inRunLines(gate.inRun), `accepted by: ${gitUserName(i.projectRoot)}`],
|
|
73
|
+
io: i.io,
|
|
74
|
+
});
|
|
75
|
+
} catch (err) {
|
|
76
|
+
if (!(err instanceof HumanConfirmationRefused)) throw err;
|
|
77
|
+
i.log(`✗ ${err.message}`);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const by = gitUserName(i.projectRoot);
|
|
81
|
+
i.log(` ✓ ${gate.inRun.length} in-run decision(s) accepted by ${by} on a terminal.`);
|
|
82
|
+
// Persisted into the deliverable's manifest (L5): who, when, which — internal ones only counted.
|
|
83
|
+
gate.acceptedInRun = {
|
|
84
|
+
by, at: new Date().toISOString(),
|
|
85
|
+
ids: gate.inRun.filter((d) => d.visibility === 'client').map((d) => d.id),
|
|
86
|
+
internalCount: gate.inRun.filter((d) => d.visibility !== 'client').length,
|
|
87
|
+
};
|
|
88
|
+
return gate;
|
|
89
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How gate overrides are SHOWN (OES-11.6, red-team #14): `audit.json` `gateOverrides[]`, the
|
|
3
|
+
* delivery's one-line summary, the XLSX "Gate overrides" sheet and the CSV manifest line, with the
|
|
4
|
+
* `PASS (overridden)` status. A `visibility: internal` decision is counted everywhere and exported
|
|
5
|
+
* nowhere (XLSX/CSV) — not even its id.
|
|
6
|
+
*/
|
|
7
|
+
import { GateSeverity, findGateRule } from './gate-rule-catalog';
|
|
8
|
+
import { OverrideIssue, UnitGateOverrides } from './unit-gate-overrides';
|
|
9
|
+
import { ActiveOverride } from './resolve-rule';
|
|
10
|
+
|
|
11
|
+
export type GateOverrideStatus = 'applied' | 'ineffective' | 'rejected';
|
|
12
|
+
|
|
13
|
+
export interface GateOverrideReport {
|
|
14
|
+
decisionId: string;
|
|
15
|
+
rule: string;
|
|
16
|
+
severity: string;
|
|
17
|
+
catalogSeverity: GateSeverity | null;
|
|
18
|
+
scope: string;
|
|
19
|
+
reason: string;
|
|
20
|
+
visibility: 'internal' | 'client';
|
|
21
|
+
by: string;
|
|
22
|
+
validFrom: string;
|
|
23
|
+
status: GateOverrideStatus;
|
|
24
|
+
/** An applied override that changed an outcome here (it lowered a condition that was met). */
|
|
25
|
+
triggered: boolean;
|
|
26
|
+
/** In git HEAD when this was written; null outside git. False = counted here, refused at release. */
|
|
27
|
+
committed: boolean | null;
|
|
28
|
+
detail?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const fromActive = (o: ActiveOverride, triggered: boolean): GateOverrideReport => ({
|
|
32
|
+
decisionId: o.decisionId, rule: o.rule, severity: o.severity, catalogSeverity: findGateRule(o.rule)?.severity ?? null,
|
|
33
|
+
scope: o.scope, reason: o.reason, visibility: o.visibility, by: o.by, validFrom: o.validFrom, status: 'applied', triggered,
|
|
34
|
+
committed: o.committed,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
function fromIssue(i: OverrideIssue, status: GateOverrideStatus): GateOverrideReport {
|
|
38
|
+
const p = (i.entry.payload ?? {}) as Record<string, unknown>;
|
|
39
|
+
const rule = typeof p.rule === 'string' ? p.rule : String(p.rule ?? '');
|
|
40
|
+
return {
|
|
41
|
+
decisionId: i.decisionId, rule, severity: String(p.severity ?? ''), catalogSeverity: findGateRule(rule)?.severity ?? null,
|
|
42
|
+
scope: String(p.scope ?? ''), reason: i.entry.reason, visibility: i.entry.visibility, by: i.entry.source.by,
|
|
43
|
+
validFrom: i.entry.valid_from, status, triggered: false, committed: i.committed, detail: i.reason,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Every override that touches the unit, in a stable order: applied, then ineffective, then rejected. */
|
|
48
|
+
export function gateOverrideReports(o: UnitGateOverrides, triggered: ReadonlySet<string>): GateOverrideReport[] {
|
|
49
|
+
return [
|
|
50
|
+
...o.inForce.map((x) => fromActive(x, triggered.has(x.rule))),
|
|
51
|
+
...o.ineffective.map((x) => fromIssue(x, 'ineffective')),
|
|
52
|
+
...o.rejected.map((x) => fromIssue(x, 'rejected')),
|
|
53
|
+
];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** `PASS (overridden)` when a pass leaned on at least one applied override. */
|
|
57
|
+
export function gateStatusLabel(status: 'PASS' | 'FAIL', reports: GateOverrideReport[]): string {
|
|
58
|
+
return status === 'PASS' && reports.some((r) => r.status === 'applied' && r.triggered) ? 'PASS (overridden)' : status;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** What a deliverable may carry: client-visible rows only, plus how many internal ones were withheld. */
|
|
62
|
+
export function exportableOverrides(reports: GateOverrideReport[]): { rows: GateOverrideReport[]; internalCount: number } {
|
|
63
|
+
return {
|
|
64
|
+
rows: reports.filter((r) => r.visibility === 'client'),
|
|
65
|
+
internalCount: reports.filter((r) => r.visibility !== 'client').length,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* One line for the delivery summary, or null when nothing touches the unit. With `unitsCovered`, each
|
|
71
|
+
* applied glob override also says how many units it reaches (L1) — a glob is easy to underestimate.
|
|
72
|
+
*/
|
|
73
|
+
export function gateOverrideSummaryLine(unit: string, reports: GateOverrideReport[], unitsCovered?: (scope: string) => number): string | null {
|
|
74
|
+
if (reports.length === 0) return null;
|
|
75
|
+
const count = (s: GateOverrideStatus) => reports.filter((r) => r.status === s).length;
|
|
76
|
+
const { rows, internalCount } = exportableOverrides(reports);
|
|
77
|
+
const globs = unitsCovered
|
|
78
|
+
? reports.filter((r) => r.status === 'applied' && /[*?]/.test(r.scope)).map((r) => ` · ${r.decisionId} (${r.scope}) covers ${unitsCovered(r.scope)} units`)
|
|
79
|
+
: [];
|
|
80
|
+
return `${unit}: gate overrides — ${count('applied')} applied (${reports.filter((r) => r.triggered).length} changed an outcome), `
|
|
81
|
+
+ `${count('ineffective')} ineffective, ${count('rejected')} rejected · ${rows.length} client-visible, ${internalCount} internal (counted, never exported)`
|
|
82
|
+
+ globs.join('');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Who accepted in-run decisions on a terminal for this delivery (L5) — ids of client-visible ones only. */
|
|
86
|
+
export interface InRunAcceptance { by: string; at: string; ids: string[]; internalCount: number }
|
|
87
|
+
|
|
88
|
+
/** What a matrix deliverable carries about overrides: client rows only, the internal count, and the status. */
|
|
89
|
+
export interface DeliverableGateOverrides {
|
|
90
|
+
status: string;
|
|
91
|
+
rows: GateOverrideReport[];
|
|
92
|
+
internalCount: number;
|
|
93
|
+
acceptedInRun?: InRunAcceptance;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The XLSX sheet / CSV manifest payload, or undefined when nothing touches the unit (no sheet at all). */
|
|
97
|
+
export function deliverableGateOverrides(reports: GateOverrideReport[], reviewPending: boolean, acceptedInRun?: InRunAcceptance): DeliverableGateOverrides | undefined {
|
|
98
|
+
if (reports.length === 0 && !acceptedInRun) return undefined;
|
|
99
|
+
const { rows, internalCount } = exportableOverrides(reports);
|
|
100
|
+
return {
|
|
101
|
+
status: reviewPending ? 'REVIEW PENDING (draft)' : gateStatusLabel('PASS', reports), rows, internalCount,
|
|
102
|
+
...(acceptedInRun ? { acceptedInRun } : {}),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** The CSV manifest lines (L4/L5): a CSV-only reader still learns what the delivery leaned on. */
|
|
107
|
+
export function overrideManifestLines(o: DeliverableGateOverrides | undefined): string[] {
|
|
108
|
+
if (!o) return [];
|
|
109
|
+
const rows = o.rows.map((r) => `${r.rule} ${r.catalogSeverity ?? '?'} → ${r.severity} (${r.decisionId}, ${r.scope})`).join('; ');
|
|
110
|
+
const lines = [`# gate overrides: ${o.status}${rows ? ` · ${rows}` : ''} · ${o.internalCount} internal not listed`];
|
|
111
|
+
const a = o.acceptedInRun;
|
|
112
|
+
if (a) lines.push(`# accepted in-run decisions: by ${a.by} at ${a.at}${a.ids.length ? ` — ${a.ids.join(', ')}` : ''}${a.internalCount ? ` (${a.internalCount} internal, ids withheld)` : ''}`);
|
|
113
|
+
return lines;
|
|
114
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `scope` of a gate override (OES-11.3, red-team #15): one unit, or a glob inside ONE kind.
|
|
3
|
+
*
|
|
4
|
+
* screens/login one unit api/flows/signup one api flow
|
|
5
|
+
* screens/log* every screen whose name matches flows/* every flow
|
|
6
|
+
* ** · screens/** rejected — a switch that turns the gate off for everything
|
|
7
|
+
* * /login · s*s/x rejected — the kind must be literal, so a scope never crosses kinds
|
|
8
|
+
*
|
|
9
|
+
* Only `*` and `?` are glob characters, and neither crosses a `/`; so `api/*` never reaches an api
|
|
10
|
+
* flow (`api/flows/<f>`), which is its own kind.
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
|
|
15
|
+
export const OVERRIDE_SCOPE_KINDS =['screens', 'flows', 'api', 'api/flows'] as const;
|
|
16
|
+
export type OverrideScopeKind = typeof OVERRIDE_SCOPE_KINDS[number];
|
|
17
|
+
|
|
18
|
+
export interface OverrideScope {
|
|
19
|
+
kind: OverrideScopeKind;
|
|
20
|
+
unit: string;
|
|
21
|
+
glob: boolean;
|
|
22
|
+
text: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const UNIT_RE = /^[A-Za-z0-9._*?-]+$/;
|
|
26
|
+
|
|
27
|
+
export function parseOverrideScope(scope: unknown): { scope: OverrideScope } | { error: string } {
|
|
28
|
+
if (typeof scope !== 'string' || !scope.trim()) return { error: 'scope is required: one unit (screens/login) or a glob inside one kind (screens/log*)' };
|
|
29
|
+
const text = scope.trim();
|
|
30
|
+
if (text.includes('**')) return { error: `scope "${text}" uses \`**\` — an override covers one unit or a glob inside one kind, never everything` };
|
|
31
|
+
const kind = text.startsWith('api/flows/') ? 'api/flows' : text.split('/')[0];
|
|
32
|
+
if (/[*?]/.test(kind)) return { error: `scope "${text}" globs the unit kind — a scope must stay inside one kind (screens, flows, api, api/flows)` };
|
|
33
|
+
if (!(OVERRIDE_SCOPE_KINDS as readonly string[]).includes(kind)) {
|
|
34
|
+
return { error: `scope "${text}" names no unit kind — start it with screens/, flows/, api/ or api/flows/` };
|
|
35
|
+
}
|
|
36
|
+
const unit = text.slice(kind.length + 1);
|
|
37
|
+
if (!unit || unit === '.' || unit === '..' || !UNIT_RE.test(unit)) {
|
|
38
|
+
return { error: `scope "${text}" must name one unit (or a glob of unit names with * and ?) after "${kind}/"` };
|
|
39
|
+
}
|
|
40
|
+
return { scope: { kind: kind as OverrideScopeKind, unit, glob: /[*?]/.test(unit), text } };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function globRegex(glob: string): RegExp {
|
|
44
|
+
const body = glob.replace(/[.+^${}()|[\]\\-]/g, '\\$&').replace(/\*/g, '[^/]*').replace(/\?/g, '[^/]');
|
|
45
|
+
return new RegExp(`^${body}$`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** How many of the project's units a (valid) scope reaches — 0 for an unparseable one. */
|
|
49
|
+
export function unitsCoveredByScope(projectRoot: string, scope: string): number {
|
|
50
|
+
const parsed = parseOverrideScope(scope);
|
|
51
|
+
if ('error' in parsed) return 0;
|
|
52
|
+
let names: string[] = [];
|
|
53
|
+
try {
|
|
54
|
+
names = fs.readdirSync(path.join(projectRoot, 'qa', ...parsed.scope.kind.split('/')), { withFileTypes: true })
|
|
55
|
+
.filter((e) => e.isDirectory() && !(parsed.scope.kind === 'api' && e.name === 'flows')).map((e) => e.name);
|
|
56
|
+
} catch { /* the project has no unit of that kind */ }
|
|
57
|
+
return names.filter((n) => overrideScopeMatches(parsed.scope, `${parsed.scope.kind}/${n}`)).length;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Does the override scope cover the unit whose decision scope is `unitScope` (e.g. `screens/login`)? */
|
|
61
|
+
export function overrideScopeMatches(s: OverrideScope, unitScope: string): boolean {
|
|
62
|
+
const kind = unitScope.startsWith('api/flows/') ? 'api/flows' : unitScope.split('/')[0];
|
|
63
|
+
if (kind !== s.kind) return false;
|
|
64
|
+
const unit = unitScope.slice(kind.length + 1);
|
|
65
|
+
return s.glob ? globRegex(s.unit).test(unit) : unit === s.unit;
|
|
66
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is a `gate-override` decision admissible, and for which unit? (OES-11.3, red-team #15, takumi T5)
|
|
3
|
+
*
|
|
4
|
+
* Shape: payload `{rule, severity: warning|info|off, scope, humanAccepted?}` + the entry's `reason`.
|
|
5
|
+
* rejected (gate.override-rejected, hard) — unknown rule or key, hard rule, severity outside
|
|
6
|
+
* warning|info|off, `off` on a rule without `offAllowed`, reason under 15 characters,
|
|
7
|
+
* a bad scope, a unit's own decision reaching another unit, humanAccepted not `true`
|
|
8
|
+
* ineffective — well-formed but `humanAccepted` absent: present means effective, so it relaxes
|
|
9
|
+
* nothing; and its absence alone blocks nothing either
|
|
10
|
+
* irrelevant — a valid scope that does not cover the unit being judged
|
|
11
|
+
* An unparseable scope cannot be placed, so it is rejected for every unit.
|
|
12
|
+
*/
|
|
13
|
+
import { PROJECT_SCOPE } from '../../decisions/decision-file';
|
|
14
|
+
import { ReadDecision } from '../../decisions/read-decisions';
|
|
15
|
+
import { findGateRule } from './gate-rule-catalog';
|
|
16
|
+
import { overrideScopeMatches, parseOverrideScope } from './gate-override-scope';
|
|
17
|
+
import { ActiveOverride, OverrideSeverity } from './resolve-rule';
|
|
18
|
+
|
|
19
|
+
export const OVERRIDE_SEVERITIES: readonly OverrideSeverity[] = ['warning', 'info', 'off'];
|
|
20
|
+
export const MIN_OVERRIDE_REASON = 15;
|
|
21
|
+
const PAYLOAD_KEYS = new Set(['rule', 'severity', 'scope', 'humanAccepted']);
|
|
22
|
+
|
|
23
|
+
export type OverrideJudgement =
|
|
24
|
+
| { status: 'irrelevant' }
|
|
25
|
+
| { status: 'rejected'; reason: string }
|
|
26
|
+
| { status: 'ineffective'; reason: string; override: ActiveOverride }
|
|
27
|
+
| { status: 'accepted'; override: ActiveOverride };
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Everything that makes an override inadmissible regardless of the unit being judged — the checks
|
|
31
|
+
* `journey --decide gate-override` runs BEFORE the prompt, so a human never confirms a rejected one.
|
|
32
|
+
* `humanAccepted` is checked separately: the confirmation sets it, a caller never supplies it.
|
|
33
|
+
*/
|
|
34
|
+
export function overridePayloadErrors(payload: unknown, reason: string, fileScope: string): string[] {
|
|
35
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return ['payload must be {rule, severity, scope}'];
|
|
36
|
+
const p = payload as Record<string, unknown>;
|
|
37
|
+
const errors: string[] = [];
|
|
38
|
+
for (const k of Object.keys(p)) if (!PAYLOAD_KEYS.has(k)) errors.push(`unknown payload key "${k}" (allowed: rule, severity, scope)`);
|
|
39
|
+
const parsed = parseOverrideScope(p.scope);
|
|
40
|
+
if ('error' in parsed) errors.push(parsed.error);
|
|
41
|
+
else if (fileScope !== PROJECT_SCOPE && (parsed.scope.glob || parsed.scope.text !== fileScope)) {
|
|
42
|
+
errors.push(`a decision recorded under qa/${fileScope}/ can only override ${fileScope} (scope is "${parsed.scope.text}") — record a wider one in qa/decisions/`);
|
|
43
|
+
}
|
|
44
|
+
const rule = typeof p.rule === 'string' ? findGateRule(p.rule) : undefined;
|
|
45
|
+
if (!rule) errors.push(`unknown rule "${String(p.rule)}" — it must be an id from harness/catalog/gate-rules.yaml`);
|
|
46
|
+
else if (rule.kind === 'hard') errors.push(`${rule.id} is a hard rule — it can never be overridden (${rule.rationale})`);
|
|
47
|
+
if (!OVERRIDE_SEVERITIES.includes(p.severity as OverrideSeverity)) errors.push(`severity must be warning | info | off (got ${JSON.stringify(p.severity)})`);
|
|
48
|
+
else if (p.severity === 'off' && rule && rule.kind === 'soft' && !rule.offAllowed) errors.push(`${rule.id} cannot be switched off (offAllowed: false) — lower it to warning or info instead`);
|
|
49
|
+
if (reason.trim().length < MIN_OVERRIDE_REASON) errors.push(`the reason must say why in at least ${MIN_OVERRIDE_REASON} characters`);
|
|
50
|
+
return errors;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function asOverride(e: ReadDecision, p: Record<string, unknown>): ActiveOverride {
|
|
54
|
+
return {
|
|
55
|
+
decisionId: e.id, rule: String(p.rule), severity: p.severity as OverrideSeverity, scope: String(p.scope).trim(),
|
|
56
|
+
reason: e.reason, visibility: e.visibility, by: e.source.by, validFrom: e.valid_from, path: e.path, committed: null,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function judgeOverride(e: ReadDecision, unitScope: string | null): OverrideJudgement {
|
|
61
|
+
const p = (e.payload ?? {}) as Record<string, unknown>;
|
|
62
|
+
const parsed = parseOverrideScope(p.scope);
|
|
63
|
+
if ('scope' in parsed && (!unitScope || !overrideScopeMatches(parsed.scope, unitScope))) {
|
|
64
|
+
// A unit's own decision that names another unit is still that unit's problem.
|
|
65
|
+
if (e.scope === PROJECT_SCOPE || e.scope !== unitScope) return { status: 'irrelevant' };
|
|
66
|
+
}
|
|
67
|
+
const errors = overridePayloadErrors(p, e.reason, e.scope);
|
|
68
|
+
if (p.humanAccepted !== undefined && p.humanAccepted !== true) errors.push('humanAccepted is set only by a TTY confirmation, and only to true');
|
|
69
|
+
if (errors.length) return { status: 'rejected', reason: errors.join('; ') };
|
|
70
|
+
const override = asOverride(e, p);
|
|
71
|
+
if (p.humanAccepted !== true) {
|
|
72
|
+
return { status: 'ineffective', reason: 'not confirmed by a human on a TTY (humanAccepted absent) — it relaxes nothing', override };
|
|
73
|
+
}
|
|
74
|
+
return { status: 'accepted', override };
|
|
75
|
+
}
|