musubix3 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/.github/plugin/marketplace.json +2 -2
  2. package/.github/skills/sdd-change/SKILL.md +1 -2
  3. package/CHANGELOG.md +38 -0
  4. package/README-ja.md +3 -1
  5. package/README.md +76 -3
  6. package/dist/packages/analysis/src/approval-domains.d.ts +22 -0
  7. package/dist/packages/analysis/src/approval-domains.js +75 -0
  8. package/dist/packages/analysis/src/approval-domains.js.map +1 -0
  9. package/dist/packages/analysis/src/approval-record.d.ts +7 -1
  10. package/dist/packages/analysis/src/approval-record.js +23 -9
  11. package/dist/packages/analysis/src/approval-record.js.map +1 -1
  12. package/dist/packages/analysis/src/approval.d.ts +67 -5
  13. package/dist/packages/analysis/src/approval.js +226 -27
  14. package/dist/packages/analysis/src/approval.js.map +1 -1
  15. package/dist/packages/analysis/src/attestation.js +12 -0
  16. package/dist/packages/analysis/src/attestation.js.map +1 -1
  17. package/dist/packages/analysis/src/change-evidence.d.ts +91 -0
  18. package/dist/packages/analysis/src/change-evidence.js +172 -0
  19. package/dist/packages/analysis/src/change-evidence.js.map +1 -0
  20. package/dist/packages/analysis/src/change-waiver.d.ts +186 -0
  21. package/dist/packages/analysis/src/change-waiver.js +688 -0
  22. package/dist/packages/analysis/src/change-waiver.js.map +1 -0
  23. package/dist/packages/analysis/src/change.d.ts +11 -53
  24. package/dist/packages/analysis/src/change.js +210 -78
  25. package/dist/packages/analysis/src/change.js.map +1 -1
  26. package/dist/packages/analysis/src/config.d.ts +5 -0
  27. package/dist/packages/analysis/src/config.js +36 -3
  28. package/dist/packages/analysis/src/config.js.map +1 -1
  29. package/dist/packages/analysis/src/gate.d.ts +41 -1
  30. package/dist/packages/analysis/src/gate.js +61 -10
  31. package/dist/packages/analysis/src/gate.js.map +1 -1
  32. package/dist/packages/analysis/src/index.d.ts +7 -0
  33. package/dist/packages/analysis/src/index.js +7 -0
  34. package/dist/packages/analysis/src/index.js.map +1 -1
  35. package/dist/packages/analysis/src/mutation.js +11 -2
  36. package/dist/packages/analysis/src/mutation.js.map +1 -1
  37. package/dist/packages/analysis/src/order.d.ts +50 -2
  38. package/dist/packages/analysis/src/order.js +43 -6
  39. package/dist/packages/analysis/src/order.js.map +1 -1
  40. package/dist/packages/analysis/src/tdd.d.ts +30 -1
  41. package/dist/packages/analysis/src/tdd.js +236 -11
  42. package/dist/packages/analysis/src/tdd.js.map +1 -1
  43. package/dist/packages/analysis/src/workflow-types.d.ts +58 -0
  44. package/dist/packages/analysis/src/workflow-types.js +49 -0
  45. package/dist/packages/analysis/src/workflow-types.js.map +1 -0
  46. package/dist/packages/analysis/src/workflow-waiver.d.ts +131 -0
  47. package/dist/packages/analysis/src/workflow-waiver.js +339 -0
  48. package/dist/packages/analysis/src/workflow-waiver.js.map +1 -0
  49. package/dist/packages/analysis/src/workflow.d.ts +56 -58
  50. package/dist/packages/analysis/src/workflow.js +351 -123
  51. package/dist/packages/analysis/src/workflow.js.map +1 -1
  52. package/dist/packages/cli/src/main.js +142 -16
  53. package/dist/packages/cli/src/main.js.map +1 -1
  54. package/dist/packages/domain/src/types.d.ts +17 -0
  55. package/dist/packages/domain/src/types.js.map +1 -1
  56. package/package.json +1 -1
  57. package/plugin.json +1 -1
@@ -3,13 +3,13 @@
3
3
  "owner": { "name": "nahisaho" },
4
4
  "metadata": {
5
5
  "description": "GitHub Copilot CLI specification-driven development skills",
6
- "version": "0.1.16"
6
+ "version": "0.1.18"
7
7
  },
8
8
  "plugins": [
9
9
  {
10
10
  "name": "musubix3",
11
11
  "source": ".",
12
- "version": "0.1.16",
12
+ "version": "0.1.18",
13
13
  "description": "Evidence-driven SDD without duplicating native Copilot capabilities."
14
14
  }
15
15
  ]
@@ -68,8 +68,7 @@ Documentation/prototypes may omit TDD only when policy allows; record the reason
68
68
  use strict `Formal:` JSON for explicit conditional, numeric, temporal or
69
69
  transition semantics; report unsupported prose rather than claiming proof.
70
70
  A required `formal` check enforces modeled fraction and configured solver.
71
- 3. Run `gate --changed --json` and `status --json`. Repair failures, dangling
72
- links and stale evidence; never weaken requirements or policy to obtain green.
71
+ 3. Run `gate --changed --json` and `status --json`. Repair failures, dangling links and stale evidence; never weaken requirements or policy to obtain green. If `workflow` fails, run `workflow-verify` compatible mode against this session's live transcript, then `workflow waiver record-all` (bulk, all-or-nothing) for remaining declaration-scoped diagnostics (it cannot clear `WORKFLOW_INVOCATION_UNVERIFIED`), then rerun gate/status.
73
72
  4. Treat the first otherwise-passing gate as the release candidate. Run a `rubber-duck` review of the release/quality evidence summary and the CHANGE document; fix every reported issue and re-review until zero issues remain. Before any release operation, prepare/show its exact hash, ask one human approve/reject question and wait; record only that hash, then rerun gate/status.
74
73
  5. Complete only when required checks pass and `status.gate.ready` is true;
75
74
  otherwise report blockers. One-phase work must state downstream work.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.18 - 2026-09-13
4
+
5
+ New feature: bulk workflow-waiver recording, resolving the repeated
6
+ release-approval blocking pattern from `workflow-verify`/waiver reconciliation
7
+ friction (GitHub Issues #21/#22/#23, this change: #24).
8
+
9
+ - `musubix3 workflow waiver record-all --approver <name> --reason <text>
10
+ --confirm` waives every currently-outstanding waivable declaration-scoped
11
+ workflow diagnostic across the whole reconciliation report in one
12
+ all-or-nothing call, instead of requiring one `workflow waiver record`
13
+ invocation per diagnostic.
14
+ - Rejects (recording nothing) if any bulk waiver precondition fails first:
15
+ malformed waiver evidence, an invalid waiver chain, a blank
16
+ `--approver`/`--reason`, or an outstanding `WORKFLOW_INVOCATION_UNVERIFIED`
17
+ diagnostic (which only `workflow-verify` having actually run this session
18
+ can resolve).
19
+ - Idempotent: with zero remaining waivable candidates it succeeds and records
20
+ nothing.
21
+ - Spec: `REQ-WORKFLOW-WAIVER-BULK-001..004`,
22
+ `DES-WORKFLOW-WAIVER-BULK-001..003`, tracked end-to-end in `CHANGE-0012`.
23
+
24
+ ## 0.1.17 - 2026-09-13
25
+
26
+ `gate --changed` remediation for the change-evidence-waiver feature
27
+ (CHANGE-0012, GitHub Issue #1 item):
28
+
29
+ - Fixed a `TRACE_DUPLICATE` diagnostic caused by a duplicate trace `@id` on
30
+ two distinct annotations in `order.ts`.
31
+ - Added a missing `@implements REQ-TDD-CYCLE-VOID-013` trace annotation on
32
+ the voided-cycle handling in `tdd.ts`, closing a `CHANGE_COMPLETENESS_CODE`
33
+ gap for CHANGE-0011.
34
+ - Retroactively waived 166 historical `change-history`/`change-completeness`
35
+ diagnostics predating the CHANGE-0012 waiver mechanism as reviewed legacy
36
+ debt (CHANGE-0005, 0006, 0009, 0010, 0011).
37
+ - Performed a full retroactive TDD Red-Green ceremony (18 test/requirement
38
+ pairs across 15 tests in `tests/change-evidence-waiver.test.ts`), resolving
39
+ all `TDD_TEST_STALE`/`TDD_REQUIREMENT_UNCOVERED` diagnostics.
40
+
3
41
  ## 0.1.16 - 2026-09-12
4
42
 
5
43
  New feature: scaffold starter `requirements.md`/`design.md` files for a new
package/README-ja.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # musubix3
2
2
 
3
- **最新リリース v0.1.16 · GitHub Copilot CLI 専用 · Node.js ≥20 · TypeScript · MIT**
3
+ **最新リリース v0.1.17 · GitHub Copilot CLI 専用 · Node.js ≥20 · TypeScript · MIT**
4
4
 
5
5
  [English](README.md)
6
6
 
@@ -362,6 +362,8 @@ npx musubix3 tdd green TEST-EXAMPLE-002 --requirement REQ-EXAMPLE-002 --command
362
362
  | `tdd validate` | 保存済みRed/Green/Refactorの順序、指紋、実行時間、hash-chainを検証 |
363
363
  | `tdd red\|green\|refactor <TEST-ID> --requirement <REQ-ID> --command <name>` | 検証可能なTDDフェーズを実行・記録 |
364
364
  | `workflow-record <skill> <phase> --status <status>` | 自己申告のworkflow宣言を記録 |
365
+ | `workflow waiver record <code> --skill <skill> --phase <phase> --recorded-at <timestamp> [--index <n>] --approver <name> --reason <text> --confirm` | declaration単位のworkflow照合診断(`WORKFLOW_SKILL_NOT_INVOKED`、`WORKFLOW_INVOCATION_ORDER`、`WORKFLOW_INVOCATION_INCOMPLETE`、`WORKFLOW_INVOCATION_FAILED`、`WORKFLOW_INVOCATION_REUSED`のいずれか)1件を、監査可能な範囲でnon-blockingなwaived状態に降格記録する。同じdeclaration scopeを共有する`WORKFLOW_BINDING_MISSING`診断も同時に降格される。`WORKFLOW_INVOCATION_UNVERIFIED`はwaiveできず、そのsessionで実際に`workflow-verify`を実行した場合のみ解消できる |
366
+ | `workflow waiver record-all --approver <name> --reason <text> --confirm` | `workflow waiver record`の一括版。reconciliation report全体で現在waive可能なdeclaration scope診断を、1件ずつの`record`呼び出しの代わりに全件一括でall-or-nothingにwaiveする。不正なwaiver証拠、無効なwaiver chain、空の`--approver`/`--reason`、または`workflow-verify`が未解決の`WORKFLOW_INVOCATION_UNVERIFIED`診断のいずれかが事前条件チェックで検出された場合は何も記録せず拒否する(`workflow-verify`が一度も実行されていない場合、個別waiverも一括waiverもこれを代替できない)。waiveされた各declaration scope診断に対応する`WORKFLOW_BINDING_MISSING`も、既存の単体`record`コマンドと同様に同時に降格される。waive対象が0件(既にwaive済み、または該当なし)の場合は冪等に成功し、何も記録しない |
365
367
  | `workflow-sanitize <copilot.jsonl> <output-file> [--session-id <uuid>]` | reviewやstrict検証前にmessageとSkill以外のtool dataを除去 |
366
368
  | `workflow-verify <copilot.jsonl> [--strict] [--session-id <uuid>]` | Skillイベントを照合し、任意で完全な成功session transcriptを要求 |
367
369
  | `attestation oidc-audience --key-id <id> [--public-key-file <pem>]` | 署名鍵を許可するGitHub custom audienceを導出 |
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # musubix3
2
2
 
3
- **Latest release v0.1.16 · GitHub Copilot CLI only · Node.js ≥20 · TypeScript · MIT**
3
+ **Latest release v0.1.17 · GitHub Copilot CLI only · Node.js ≥20 · TypeScript · MIT**
4
4
 
5
5
  [日本語](README-ja.md)
6
6
 
@@ -410,14 +410,16 @@ validation/gate or requested solver failure, **2** usage, I/O or malformed confi
410
410
  | `mutation validate` | Revalidate requirement-scoped schema-v1 killed-mutant evidence |
411
411
  | `mutation identity <REQ-ID> <TEST-ID> <sourcePath> <operator> <line> <column>` | Print the deterministic `MUT-*` identity a mutation report must declare |
412
412
  | `tdd validate` | Validate persisted Red/Green/Refactor order, fingerprints, durations, and hash-chain evidence |
413
- | `tdd red\|green\|refactor <TEST-ID> --requirement <REQ-ID> --command <name>` | Execute and record a verified TDD phase |
413
+ | `tdd red\|green\|refactor <TEST-ID> --requirement <REQ-ID> --command <name>` | Execute and record a verified TDD phase. Recording the project's **first** `tdd` cycle (any `red` call while `.musubix/evidence/tdd.json` has zero cycles) makes `gate`'s `tdd` check required **project-wide**, for every mandatory requirement, not just the ones touched by the current change; each uncovered requirement then surfaces as `TDD_REQUIREMENT_UNCOVERED`. `approval record release` always runs the full (non-`--changed`) gate, so it is blocked by any resulting `TDD_REQUIREMENT_UNCOVERED` diagnostics. `tdd migrate` cannot be used to bulk-onboard previously-uncovered requirements: it only re-fingerprints a requirement that already has a valid Green cycle. `tdd red` prints/returns a `TDD_ADOPTION_PROJECT_WIDE` warning (in a `warnings` array, separate from `diagnostics`) the moment this first cycle is persisted, listing every other still-uncovered mandatory requirement. |
414
414
  | `workflow-record <skill> <phase> --status <status>` | Record a compact self-reported workflow declaration |
415
+ | `workflow waiver record <code> --skill <skill> --phase <phase> --recorded-at <timestamp> [--index <n>] --approver <name> --reason <text> --confirm` | Record an audited, bounded downgrade of one declaration-scoped workflow reconciliation diagnostic (`WORKFLOW_SKILL_NOT_INVOKED`, `WORKFLOW_INVOCATION_ORDER`, `WORKFLOW_INVOCATION_INCOMPLETE`, `WORKFLOW_INVOCATION_FAILED`, or `WORKFLOW_INVOCATION_REUSED`) to a non-blocking waived status; a paired `WORKFLOW_BINDING_MISSING` diagnostic sharing the same declaration scope is downgraded together with it. It cannot waive `WORKFLOW_INVOCATION_UNVERIFIED`, which only `workflow-verify` having actually run this session can resolve |
416
+ | `workflow waiver record-all --approver <name> --reason <text> --confirm` | Bulk variant of `workflow waiver record`: waives every currently-outstanding waivable declaration-scoped diagnostic across the whole reconciliation report in one all-or-nothing call, instead of one `record` invocation per diagnostic. Rejects (recording nothing) if any bulk waiver precondition fails first — malformed waiver evidence, an invalid waiver chain, a blank `--approver`/`--reason`, or a `WORKFLOW_INVOCATION_UNVERIFIED` diagnostic (which `workflow-verify` must resolve first; no per-declaration or bulk waiver can substitute for `workflow-verify` never having run). Each waived declaration-scoped diagnostic's paired `WORKFLOW_BINDING_MISSING` is downgraded together with it, identically to the existing single-record command. With zero remaining candidates (already waived, or none present) it succeeds idempotently and records nothing |
415
417
  | `workflow-sanitize <copilot.jsonl> <output-file> [--session-id <uuid>]` | Remove messages and non-Skill tool data before review or strict verification |
416
418
  | `workflow-verify <copilot.jsonl...> [--strict] [--session-id <uuid>]` | Reconcile Skill events; compatible mode accepts multiple transcript files (concatenated in chronological session order) so declarations whose invocation occurred in an earlier Copilot CLI session can be reconciled; `--strict`/`--session-id` still require exactly one file |
417
419
  | `attestation oidc-audience --key-id <id> [--public-key-file <pem>]` | Derive the GitHub custom audience that authorizes a signing key |
418
420
  | `attestation payload --provider <name> --run-id <id> --key-id <id> [--public-key-file <pem>] [--github-oidc-token-file <jwt>]` | Emit canonical unsigned CI payload for external signing |
419
421
  | `attestation verify` | Verify static-key or GitHub OIDC-authorized Ed25519 provenance |
420
- | `change-record <CHANGE-ID> <phase> --requirement <REQ-ID...>` | Record ordered artifact/TDD fingerprints for a staged change. `impact`/`requirements`/`design`/`quality` require the change's full requirement ID set; `red`/`implementation`/`green` also accept a proper non-empty subset, recorded as an independent per-requirement batch, so a multi-requirement change can be completed with an interleaved per-requirement Red-Implementation-Green loop instead of one global batch |
422
+ | `change-record <CHANGE-ID> <phase> --requirement <REQ-ID...> [--allow-unchanged] [--dry-run]` | Record ordered artifact/TDD fingerprints for a staged change. `impact`/`requirements`/`design`/`quality` require the change's full requirement ID set; `red`/`implementation`/`green` also accept a proper non-empty subset, recorded as an independent per-requirement batch, so a multi-requirement change can be completed with an interleaved per-requirement Red-Implementation-Green loop instead of one global batch. Rejects with a non-zero exit and a stable `*_UNCHANGED_AT_RECORD` diagnostic (leaving `changes.json`/`order.json` untouched) when a phase's fingerprint is byte-identical to the immediately preceding phase's, since that mistake is otherwise only caught much later by `trace check --strict`/`gate`, at which point the append-only evidence store makes it unfixable. `--allow-unchanged` bypasses this check for the `requirements` phase only (the one case `sdd-change` documents as legitimate: a defect fix that intentionally leaves its requirement unchanged) and persists a durable marker so later validation does not re-flag it. `--dry-run` previews the exact success/rejection outcome, including every existing check, without persisting anything. Each recorded phase/batch stores both `order` (the verified, `gate`-checked logical append sequence from `order.json` — the only field guaranteed correct and monotonic per change) and `recordedAt` (an independently captured wall-clock timestamp with no ordering guarantee relative to `order`); `gate` reports a non-blocking `CHANGE_RECORDEDAT_OUT_OF_ORDER` warning when a change's `recordedAt` values disagree with its `order` sequence |
421
423
  | `config lint` | Report configured commands whose `args` reference repository-relative paths that do not exist |
422
424
  | `config scaffold` | Propose native test-command entries for detected Go/Rust/Maven/Python/Node toolchains without writing `.musubix/config.json` |
423
425
  | `gate [--changed] [--feature <name>]` | Fresh full checks plus actual configured commands; persist evidence. `--feature` scopes requirements/design/trace/tdd/change-history/change-completeness checks to one feature as a diagnostic view; never a substitute for the repository-wide gate |
@@ -901,8 +903,79 @@ artifact identity. Excluding the attestation check from the quality head avoids
901
903
  a circular signature dependency. A missing `ci-required` attestation is reported
902
904
  as a failed/missing check, never as skipped local evidence.
903
905
 
906
+ #### Attestation evidence-head composition
907
+
908
+ `collectEvidenceHeads` (`packages/analysis/src/attestation.ts`) canonicalizes
909
+ up to ten independent evidence entries into stable per-entry digests. Each
910
+ entry's direct input/projection is:
911
+
912
+ - `tdd`: the last entry's `recordSha256` from `.musubix/evidence/tdd.json`'s
913
+ hash chain — a chain-tip digest, not a projection over every recorded
914
+ phase field.
915
+ - `workflow`: `workflowEvidenceHead`'s projection of
916
+ `.musubix/evidence/workflow.json`'s `verification` block only
917
+ (`eventsSha256`, `sourceSha256`, `transcriptSha256`, `mode`, `sessionId`,
918
+ `exitCode`, `terminalAt`, `eventCount`, `sourceBytes`,
919
+ `maxTranscriptBytes`, `maximumLineBytes`, `maxTranscriptLineBytes`, and
920
+ `invocations` (each entry's `skill`/`toolCallId`/`invokedAt`/
921
+ `completedAt`/`status`, unsorted/order-sensitive as stored), or just
922
+ `eventsSha256`/`sourceSha256` when `mode`, `transcriptSha256`, and
923
+ `sessionId` are all absent); the raw `events` log itself is excluded.
924
+ - `changes`: a canonical digest of `.musubix/evidence/changes.json`'s
925
+ `changes` array directly — not the `.musubix/changes/*.md` documents
926
+ themselves, which are a separate upstream input to that evidence.
927
+ - `order`: the last entry's `recordSha256` from `.musubix/evidence/order.json`'s
928
+ records — a chain-tip digest, not a projection over every recorded
929
+ declaration.
930
+ - `formal`: retains only `fingerprints`, `totalRequirements`,
931
+ `modeledRequirements`, `modeledFraction`, and the solver's
932
+ `artifact`/`status`/`result.consistency` from `.musubix/evidence/formal.json`,
933
+ excluding `generatedAt` and every other `result` field such as solver
934
+ duration, diagnostics, literals, and constraints.
935
+ - `performance`: `performanceEvidenceHead`'s projection of
936
+ `.musubix/evidence/performance.json`, retaining per execution
937
+ `commandName`/`commandSha256`/`reportPath`/`sourceKind`/`processStatus`/
938
+ `exitCode`/a canonically-sorted `tests` array (each test entry kept in
939
+ full), and per observation `requirementId`/`testId`/`counter`/`observed`/
940
+ `maximum`/`status`/an optional `provenance` object retaining exactly
941
+ `commandName`/`commandSha256`/`reportPath`/`sourceKind`/`testId`/
942
+ `testStatus`/`counter`/`value`/`processStatus`/`exitCode`; both the
943
+ `executions` and `observations` arrays are canonicalized
944
+ order-independently.
945
+ - `mutation`: `mutationEvidenceHead`'s equivalent projection of
946
+ `.musubix/evidence/mutation.json`, retaining per execution
947
+ `commandName`/`commandSha256`/`reportPath`/`processStatus`/`exitCode`/a
948
+ canonically-sorted `mutants` array (each mutant's full record); both the
949
+ `executions` and nested `mutants` arrays are canonicalized
950
+ order-independently.
951
+ - `modelCorrespondence`: `modelCorrespondenceEvidenceHead`'s projection of
952
+ `.musubix/evidence/model-correspondence.json`, retaining `schemaVersion`,
953
+ `formalEvidenceSha256`, `traceEvidenceSha256`, and a canonically-sorted
954
+ `entries` array (each retaining `requirementId`/`requirementPath`/
955
+ `formalSha256`/`modelSha256`/`traceSha256`/a canonically-sorted `tests`
956
+ array retaining exactly `testId`/`testPath`/`testSha256`/`commandName`/
957
+ `commandSha256`/`reportPath`, excluding `reportSha256`/`provenanceSha256`);
958
+ any other stored run metadata is excluded.
959
+ - `quality`: retains `schemaVersion`, `mode`, a derived pass/fail `status`,
960
+ and each non-`attestation` check's `name`/`required`/`status`/a narrow
961
+ `diagnostics` projection (`code`/`severity`/`path`/`line`), plus `metrics`
962
+ with the `attestation.errors` entry excluded; also excludes `generatedAt`,
963
+ `durationMs`, and `stdout`/`stderr`.
964
+ - `workspace`: not an evidence file at all — a content digest over the
965
+ non-evidence repository file set returned by `files(root)`, filtered by
966
+ `evidenceInputPaths`; `.musubix/evidence/**` itself is excluded from this
967
+ walk so writing evidence never perturbs the workspace snapshot it is
968
+ bound into.
969
+
970
+ See `collectEvidenceHeads` and the per-entry head functions it delegates to
971
+ (`workflowEvidenceHead`, `performanceEvidenceHead`, `mutationEvidenceHead`,
972
+ `modelCorrespondenceEvidenceHead`) for the authoritative implementation; this
973
+ list is a summary, not a substitute for reading the source when precision
974
+ matters.
975
+
904
976
  Example strict configuration:
905
977
 
978
+
906
979
  ```json
907
980
  {
908
981
  "attestation": {
@@ -0,0 +1,22 @@
1
+ import type { ApprovalConfig } from './config.js';
2
+ export interface ResolvedDomain {
3
+ name: string;
4
+ features: string[];
5
+ }
6
+ export declare function domainsConfigured(config: ApprovalConfig): boolean;
7
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-002
8
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-002 REQ-APPROVAL-DOMAIN-SCOPING-003 REQ-APPROVAL-DOMAIN-SCOPING-004
9
+ * @design DES-APPROVAL-DOMAIN-SCOPING-002
10
+ */
11
+ export declare function resolveDomains(root: string, config: ApprovalConfig): Promise<ResolvedDomain[]>;
12
+ export declare function domainOwning(resolved: ResolvedDomain[], slug: string): string | null;
13
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-014
14
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-016
15
+ * @design DES-APPROVAL-DOMAIN-SCOPING-005
16
+ */
17
+ export declare function featureOwningRequirement(root: string, requirementId: string): Promise<string>;
18
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-015
19
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-017
20
+ * @design DES-APPROVAL-DOMAIN-SCOPING-005
21
+ */
22
+ export declare function featureOwningDesignFile(file: string): string | null;
@@ -0,0 +1,75 @@
1
+ import { validateRequirements } from '../../domain/src/index.js';
2
+ import { matchGlob } from './graph.js';
3
+ import { files, readText } from './files.js';
4
+ const featureRequirementsPattern = /^\.musubix\/features\/([^/]+)\/requirements\.md$/;
5
+ const featureDesignPattern = /^\.musubix\/features\/([^/]+)\/design\.md$/;
6
+ export function domainsConfigured(config) {
7
+ return config.domains.length > 0;
8
+ }
9
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-002
10
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-002 REQ-APPROVAL-DOMAIN-SCOPING-003 REQ-APPROVAL-DOMAIN-SCOPING-004
11
+ * @design DES-APPROVAL-DOMAIN-SCOPING-002
12
+ */
13
+ export async function resolveDomains(root, config) {
14
+ const domains = config.domains;
15
+ if (domains.length === 0)
16
+ return [];
17
+ const slugs = [...new Set((await files(root))
18
+ .map((path) => featureRequirementsPattern.exec(path)?.[1])
19
+ .filter((slug) => !!slug))].sort();
20
+ const owners = new Map();
21
+ for (const slug of slugs) {
22
+ const matching = domains.filter((domain) => domain.featureGlobs.some((glob) => matchGlob(slug, glob)));
23
+ owners.set(slug, matching.map((domain) => domain.name).sort());
24
+ }
25
+ for (const slug of slugs) {
26
+ const matching = owners.get(slug);
27
+ if (matching.length === 0) {
28
+ throw new Error(`Feature "${slug}" is not owned by any configured approval domain; every feature directory must match exactly one domain's featureGlobs.`);
29
+ }
30
+ if (matching.length > 1) {
31
+ throw new Error(`Feature "${slug}" matches more than one configured approval domain: ${matching.join(', ')}; every feature directory must match exactly one domain.`);
32
+ }
33
+ }
34
+ const resolved = domains.map((domain) => ({
35
+ name: domain.name,
36
+ features: slugs.filter((slug) => owners.get(slug)[0] === domain.name).sort(),
37
+ }));
38
+ for (const domain of resolved) {
39
+ if (domain.features.length === 0) {
40
+ throw new Error(`Approval domain "${domain.name}" matches zero existing feature directories; remove it or add a matching feature.`);
41
+ }
42
+ }
43
+ return resolved;
44
+ }
45
+ export function domainOwning(resolved, slug) {
46
+ return resolved.find((domain) => domain.features.includes(slug))?.name ?? null;
47
+ }
48
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-014
49
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-016
50
+ * @design DES-APPROVAL-DOMAIN-SCOPING-005
51
+ */
52
+ export async function featureOwningRequirement(root, requirementId) {
53
+ const paths = (await files(root)).filter((path) => featureRequirementsPattern.test(path));
54
+ const owners = [];
55
+ for (const path of paths) {
56
+ const slug = featureRequirementsPattern.exec(path)[1];
57
+ const result = validateRequirements(await readText(root, path), path);
58
+ if (result.value.some((requirement) => requirement.id === requirementId))
59
+ owners.push(slug);
60
+ }
61
+ if (owners.length === 0)
62
+ throw new Error(`Requirement ${requirementId} was not found in any feature's requirements.md.`);
63
+ if (owners.length > 1)
64
+ throw new Error(`Requirement ${requirementId} is defined in more than one feature: ${owners.join(', ')}.`);
65
+ return owners[0];
66
+ }
67
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-015
68
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-017
69
+ * @design DES-APPROVAL-DOMAIN-SCOPING-005
70
+ */
71
+ export function featureOwningDesignFile(file) {
72
+ const match = featureDesignPattern.exec(file);
73
+ return match ? match[1] : null;
74
+ }
75
+ //# sourceMappingURL=approval-domains.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-domains.js","sourceRoot":"","sources":["../../../../packages/analysis/src/approval-domains.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,12 @@
1
+ import type { ApprovalConfig } from './config.js';
1
2
  import { type ApprovalEvidence, type ApprovalStage } from './approval.js';
2
3
  /** @id CODE-HUMAN-APPROVAL-GATES-002
3
4
  * @implements REQ-HUMAN-APPROVAL-GATES-001 REQ-HUMAN-APPROVAL-GATES-006
4
5
  * @design DES-APPROVAL-002 DES-APPROVAL-003
5
6
  */
6
- export declare function recordApproval(root: string, stage: ApprovalStage, approver: string, expectedArtifactSha256: string): Promise<ApprovalEvidence>;
7
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-016
8
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-005 REQ-APPROVAL-DOMAIN-SCOPING-006 REQ-APPROVAL-DOMAIN-SCOPING-007
9
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-013 REQ-APPROVAL-DOMAIN-SCOPING-014 REQ-APPROVAL-DOMAIN-SCOPING-015
10
+ * @design DES-APPROVAL-DOMAIN-SCOPING-004
11
+ */
12
+ export declare function recordApproval(root: string, stage: ApprovalStage, approver: string, expectedArtifactSha256: string, config: ApprovalConfig, domainName?: string): Promise<ApprovalEvidence>;
@@ -1,11 +1,16 @@
1
- import { approvalManifest, requireApproval, validateStageArtifacts, } from './approval.js';
1
+ import { approvalManifest, approvalPath, domainsConfigured, requireApproval, requireDomainOption, resolveDomains, validateStageArtifacts, } from './approval.js';
2
2
  import { writeJson } from './files.js';
3
3
  import { runGate } from './gate.js';
4
4
  /** @id CODE-HUMAN-APPROVAL-GATES-002
5
5
  * @implements REQ-HUMAN-APPROVAL-GATES-001 REQ-HUMAN-APPROVAL-GATES-006
6
6
  * @design DES-APPROVAL-002 DES-APPROVAL-003
7
7
  */
8
- export async function recordApproval(root, stage, approver, expectedArtifactSha256) {
8
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-016
9
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-005 REQ-APPROVAL-DOMAIN-SCOPING-006 REQ-APPROVAL-DOMAIN-SCOPING-007
10
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-013 REQ-APPROVAL-DOMAIN-SCOPING-014 REQ-APPROVAL-DOMAIN-SCOPING-015
11
+ * @design DES-APPROVAL-DOMAIN-SCOPING-004
12
+ */
13
+ export async function recordApproval(root, stage, approver, expectedArtifactSha256, config, domainName) {
9
14
  const normalizedApprover = approver.trim();
10
15
  if (!normalizedApprover || normalizedApprover.includes('\0')) {
11
16
  throw new Error('Approver must be a nonempty name without NUL bytes.');
@@ -13,19 +18,28 @@ export async function recordApproval(root, stage, approver, expectedArtifactSha2
13
18
  if (!/^[a-f0-9]{64}$/.test(expectedArtifactSha256)) {
14
19
  throw new Error('Expected approval artifact SHA-256 must be 64 lowercase hexadecimal characters.');
15
20
  }
16
- await validateStageArtifacts(root, stage);
17
- const requiredApproval = { mode: 'required' };
18
- if (stage === 'design' || stage === 'release')
19
- await requireApproval(root, 'requirements', requiredApproval);
21
+ requireDomainOption(config, stage, domainName);
22
+ const resolved = domainsConfigured(config) ? await resolveDomains(root, config) : [];
23
+ const domain = domainName ? resolved.find((d) => d.name === domainName) : undefined;
24
+ await validateStageArtifacts(root, stage, domain);
25
+ const requiredApproval = { mode: 'required', domains: [] };
26
+ if (stage === 'design') {
27
+ await requireApproval(root, 'requirements', requiredApproval, domain);
28
+ }
20
29
  if (stage === 'release') {
21
- await requireApproval(root, 'design', requiredApproval);
30
+ for (const d of resolved) {
31
+ await requireApproval(root, 'requirements', requiredApproval, d);
32
+ await requireApproval(root, 'design', requiredApproval, d);
33
+ }
34
+ if (!resolved.length)
35
+ await requireApproval(root, 'design', requiredApproval);
22
36
  const quality = await runGate(root);
23
37
  const blockers = quality.checks.filter((check) => check.name !== 'approval' && check.required && check.status !== 'pass');
24
38
  if (blockers.length) {
25
39
  throw new Error(`Release approval requires passing non-approval quality checks: ${blockers.map((check) => check.name).join(', ')}.`);
26
40
  }
27
41
  }
28
- const manifest = await approvalManifest(root, stage);
42
+ const manifest = await approvalManifest(root, stage, domain);
29
43
  if (!Object.keys(manifest.artifacts).length)
30
44
  throw new Error(`No artifacts are available for ${stage} approval.`);
31
45
  if (manifest.artifactSha256 !== expectedArtifactSha256) {
@@ -37,7 +51,7 @@ export async function recordApproval(root, stage, approver, expectedArtifactSha2
37
51
  approver: normalizedApprover,
38
52
  approvedAt: new Date().toISOString(),
39
53
  };
40
- await writeJson(root, `.musubix/evidence/approvals/${stage}.json`, evidence);
54
+ await writeJson(root, approvalPath(stage, domainName), evidence);
41
55
  return evidence;
42
56
  }
43
57
  //# sourceMappingURL=approval-record.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"approval-record.js","sourceRoot":"","sources":["../../../../packages/analysis/src/approval-record.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAAE,eAAe,EAAE,sBAAsB,GAE1D,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,KAAoB,EACpB,QAAgB,EAChB,sBAA8B;IAE9B,MAAM,kBAAkB,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,kBAAkB,IAAI,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,iFAAiF,CAAC,CAAC;IACrG,CAAC;IACD,MAAM,sBAAsB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC1C,MAAM,gBAAgB,GAAmB,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAC9D,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,gBAAgB,CAAC,CAAC;IAC7G,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAC/C,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QAC1E,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,kEAAkE,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvI,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,KAAK,YAAY,CAAC,CAAC;IAClH,IAAI,QAAQ,CAAC,cAAc,KAAK,sBAAsB,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,gDAAgD,sBAAsB,aAAa,QAAQ,CAAC,cAAc,iDAAiD,CAAC,CAAC;IAC/K,CAAC;IACD,MAAM,QAAQ,GAAqB;QACjC,aAAa,EAAE,CAAC;QAChB,GAAG,QAAQ;QACX,QAAQ,EAAE,kBAAkB;QAC5B,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;IACF,MAAM,SAAS,CAAC,IAAI,EAAE,+BAA+B,KAAK,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7E,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"approval-record.js","sourceRoot":"","sources":["../../../../packages/analysis/src/approval-record.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,14 @@
1
1
  import { type Diagnostic } from '../../domain/src/index.js';
2
2
  import type { ApprovalConfig } from './config.js';
3
+ import { type ResolvedDomain } from './approval-domains.js';
4
+ export { domainsConfigured, domainOwning, featureOwningDesignFile, featureOwningRequirement, resolveDomains, type ResolvedDomain, } from './approval-domains.js';
3
5
  export declare const approvalStages: readonly ["requirements", "design", "release"];
4
6
  export type ApprovalStage = typeof approvalStages[number];
5
7
  export type ApprovalStatus = 'approved' | 'missing' | 'stale';
6
8
  export interface ApprovalManifest {
7
9
  stage: ApprovalStage;
10
+ domain?: string;
11
+ features?: string[];
8
12
  artifacts: Record<string, string>;
9
13
  artifactSha256: string;
10
14
  }
@@ -15,6 +19,7 @@ export interface ApprovalEvidence extends ApprovalManifest {
15
19
  }
16
20
  export interface ApprovalStageValidation {
17
21
  stage: ApprovalStage;
22
+ domain?: string;
18
23
  required: boolean;
19
24
  present: boolean;
20
25
  status: ApprovalStatus;
@@ -22,27 +27,84 @@ export interface ApprovalStageValidation {
22
27
  currentArtifactSha256: string;
23
28
  diagnostics: Diagnostic[];
24
29
  }
30
+ export interface DomainApprovalValidation {
31
+ name: string;
32
+ stages: ApprovalStageValidation[];
33
+ }
25
34
  export interface ApprovalValidation {
26
35
  schemaVersion: 1;
27
36
  mode: ApprovalConfig['mode'];
28
37
  present: boolean;
29
38
  valid: boolean;
30
39
  stages: ApprovalStageValidation[];
40
+ domain?: string;
41
+ domains?: DomainApprovalValidation[];
42
+ release?: ApprovalStageValidation;
31
43
  diagnostics: Diagnostic[];
32
44
  }
45
+ export declare function approvalPath(stage: ApprovalStage, domain?: string): string;
33
46
  /** @id CODE-HUMAN-APPROVAL-GATES-001
34
47
  * @implements REQ-HUMAN-APPROVAL-GATES-001 REQ-HUMAN-APPROVAL-GATES-002 REQ-HUMAN-APPROVAL-GATES-003
35
48
  * @implements REQ-HUMAN-APPROVAL-GATES-004 REQ-HUMAN-APPROVAL-GATES-005 REQ-HUMAN-APPROVAL-GATES-006
36
49
  * @implements REQ-HUMAN-APPROVAL-GATES-007 REQ-HUMAN-APPROVAL-GATES-008
37
50
  * @design DES-APPROVAL-001 DES-APPROVAL-002 DES-APPROVAL-003
38
51
  */
39
- export declare function approvalManifest(root: string, stage: ApprovalStage): Promise<ApprovalManifest>;
40
- export declare function loadApproval(root: string, stage: ApprovalStage): Promise<ApprovalEvidence | null>;
41
- export declare function validateApprovalStage(root: string, stage: ApprovalStage, config: ApprovalConfig): Promise<ApprovalStageValidation>;
52
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-007
53
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-011 REQ-APPROVAL-DOMAIN-SCOPING-012 REQ-APPROVAL-DOMAIN-SCOPING-013
54
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-014 REQ-APPROVAL-DOMAIN-SCOPING-023 REQ-APPROVAL-DOMAIN-SCOPING-024
55
+ * @design DES-APPROVAL-DOMAIN-SCOPING-003
56
+ */
57
+ export declare function approvalManifest(root: string, stage: ApprovalStage, domain?: ResolvedDomain): Promise<ApprovalManifest>;
58
+ export declare function loadApproval(root: string, stage: ApprovalStage, domain?: string): Promise<ApprovalEvidence | null>;
59
+ export declare function validateApprovalStage(root: string, stage: ApprovalStage, config: ApprovalConfig, domain?: ResolvedDomain): Promise<ApprovalStageValidation>;
60
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-004
61
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-008 REQ-APPROVAL-DOMAIN-SCOPING-021 REQ-APPROVAL-DOMAIN-SCOPING-022
62
+ * @design DES-APPROVAL-DOMAIN-SCOPING-004
63
+ */
42
64
  export declare function validateApprovals(root: string, config: ApprovalConfig): Promise<ApprovalValidation>;
65
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-008
66
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-009 REQ-APPROVAL-DOMAIN-SCOPING-010
67
+ * @design DES-APPROVAL-DOMAIN-SCOPING-004
68
+ */
69
+ export declare function validateApprovalsForDomain(root: string, config: ApprovalConfig, domainName: string): Promise<ApprovalValidation>;
70
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-006
71
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-019 REQ-APPROVAL-DOMAIN-SCOPING-020
72
+ * @design DES-APPROVAL-DOMAIN-SCOPING-006
73
+ */
74
+ export declare function validateApprovalsForFeatureGate(root: string, config: ApprovalConfig, domainName: string): Promise<ApprovalValidation>;
75
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-009
76
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-005 REQ-APPROVAL-DOMAIN-SCOPING-006 REQ-APPROVAL-DOMAIN-SCOPING-007
77
+ * @design DES-APPROVAL-DOMAIN-SCOPING-004
78
+ */
79
+ export declare function requireDomainOption(config: ApprovalConfig, stage: ApprovalStage, domain: string | undefined): void;
80
+ export declare function requireValidateDomainOption(config: ApprovalConfig, domain: string | undefined): void;
43
81
  /** @id CODE-CLI-WORKFLOW-UX-003
44
82
  * @implements REQ-CLI-WORKFLOW-UX-003
45
83
  * @design DES-CLI-WORKFLOW-UX-003
46
84
  */
47
- export declare function requireApproval(root: string, stage: ApprovalStage, config: ApprovalConfig): Promise<void>;
48
- export declare function validateStageArtifacts(root: string, stage: ApprovalStage): Promise<void>;
85
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-005
86
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-016 REQ-APPROVAL-DOMAIN-SCOPING-017 REQ-APPROVAL-DOMAIN-SCOPING-018
87
+ * @design DES-APPROVAL-DOMAIN-SCOPING-005
88
+ */
89
+ export declare function requireApproval(root: string, stage: ApprovalStage, config: ApprovalConfig, domain?: ResolvedDomain): Promise<void>;
90
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-010
91
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-016 REQ-APPROVAL-DOMAIN-SCOPING-017 REQ-APPROVAL-DOMAIN-SCOPING-018
92
+ * @design DES-APPROVAL-DOMAIN-SCOPING-005
93
+ */
94
+ export declare function resolveOwningDomainOrThrow(root: string, config: ApprovalConfig, slug: string): Promise<ResolvedDomain | undefined>;
95
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-011
96
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-005 REQ-APPROVAL-DOMAIN-SCOPING-013
97
+ * @design DES-APPROVAL-DOMAIN-SCOPING-004
98
+ */
99
+ export declare function resolveNamedDomain(root: string, config: ApprovalConfig, domainName: string): Promise<ResolvedDomain>;
100
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-012
101
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-017
102
+ * @design DES-APPROVAL-DOMAIN-SCOPING-005
103
+ */
104
+ export declare function resolveDesignFileDomain(root: string, config: ApprovalConfig, file: string): Promise<ResolvedDomain | undefined>;
105
+ /** @id CODE-APPROVAL-DOMAIN-SCOPING-013
106
+ * @implements REQ-APPROVAL-DOMAIN-SCOPING-016
107
+ * @design DES-APPROVAL-DOMAIN-SCOPING-005
108
+ */
109
+ export declare function resolveRequirementDomain(root: string, config: ApprovalConfig, requirementId: string): Promise<ResolvedDomain | undefined>;
110
+ export declare function validateStageArtifacts(root: string, stage: ApprovalStage, domain?: ResolvedDomain): Promise<void>;