@oscharko-dev/keiko-quality-intelligence 0.2.0

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 (203) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/__tests__/_fixtureLoader.d.ts +9 -0
  3. package/dist/__tests__/_fixtureLoader.d.ts.map +1 -0
  4. package/dist/__tests__/_fixtureLoader.js +75 -0
  5. package/dist/domain/assertions.d.ts +61 -0
  6. package/dist/domain/assertions.d.ts.map +1 -0
  7. package/dist/domain/assertions.js +134 -0
  8. package/dist/domain/coverageRelevance.d.ts +73 -0
  9. package/dist/domain/coverageRelevance.d.ts.map +1 -0
  10. package/dist/domain/coverageRelevance.js +155 -0
  11. package/dist/domain/deduplication.d.ts +17 -0
  12. package/dist/domain/deduplication.d.ts.map +1 -0
  13. package/dist/domain/deduplication.js +95 -0
  14. package/dist/domain/figma/a11yBaseline.d.ts +17 -0
  15. package/dist/domain/figma/a11yBaseline.d.ts.map +1 -0
  16. package/dist/domain/figma/a11yBaseline.js +218 -0
  17. package/dist/domain/figma/cleanToScreenIr.d.ts +3 -0
  18. package/dist/domain/figma/cleanToScreenIr.d.ts.map +1 -0
  19. package/dist/domain/figma/cleanToScreenIr.js +62 -0
  20. package/dist/domain/figma/codeTargetAdapter.d.ts +30 -0
  21. package/dist/domain/figma/codeTargetAdapter.d.ts.map +1 -0
  22. package/dist/domain/figma/codeTargetAdapter.js +27 -0
  23. package/dist/domain/figma/color.d.ts +31 -0
  24. package/dist/domain/figma/color.d.ts.map +1 -0
  25. package/dist/domain/figma/color.js +99 -0
  26. package/dist/domain/figma/emissionPlan.d.ts +56 -0
  27. package/dist/domain/figma/emissionPlan.d.ts.map +1 -0
  28. package/dist/domain/figma/emissionPlan.js +87 -0
  29. package/dist/domain/figma/htmlCssAdapter.d.ts +13 -0
  30. package/dist/domain/figma/htmlCssAdapter.d.ts.map +1 -0
  31. package/dist/domain/figma/htmlCssAdapter.js +452 -0
  32. package/dist/domain/figma/index.d.ts +19 -0
  33. package/dist/domain/figma/index.d.ts.map +1 -0
  34. package/dist/domain/figma/index.js +31 -0
  35. package/dist/domain/figma/irTypes.d.ts +156 -0
  36. package/dist/domain/figma/irTypes.d.ts.map +1 -0
  37. package/dist/domain/figma/irTypes.js +8 -0
  38. package/dist/domain/figma/links.d.ts +6 -0
  39. package/dist/domain/figma/links.d.ts.map +1 -0
  40. package/dist/domain/figma/links.js +102 -0
  41. package/dist/domain/figma/navGraph.d.ts +74 -0
  42. package/dist/domain/figma/navGraph.d.ts.map +1 -0
  43. package/dist/domain/figma/navGraph.js +315 -0
  44. package/dist/domain/figma/normalize.d.ts +7 -0
  45. package/dist/domain/figma/normalize.d.ts.map +1 -0
  46. package/dist/domain/figma/normalize.js +252 -0
  47. package/dist/domain/figma/prune.d.ts +15 -0
  48. package/dist/domain/figma/prune.d.ts.map +1 -0
  49. package/dist/domain/figma/prune.js +65 -0
  50. package/dist/domain/figma/screenDetect.d.ts +8 -0
  51. package/dist/domain/figma/screenDetect.d.ts.map +1 -0
  52. package/dist/domain/figma/screenDetect.js +35 -0
  53. package/dist/domain/figma/screenIrTestBaseline.d.ts +52 -0
  54. package/dist/domain/figma/screenIrTestBaseline.d.ts.map +1 -0
  55. package/dist/domain/figma/screenIrTestBaseline.js +326 -0
  56. package/dist/domain/figma/semanticNaming.d.ts +24 -0
  57. package/dist/domain/figma/semanticNaming.d.ts.map +1 -0
  58. package/dist/domain/figma/semanticNaming.js +67 -0
  59. package/dist/domain/figma/sourceNode.d.ts +24 -0
  60. package/dist/domain/figma/sourceNode.d.ts.map +1 -0
  61. package/dist/domain/figma/sourceNode.js +26 -0
  62. package/dist/domain/figma/tokens.d.ts +11 -0
  63. package/dist/domain/figma/tokens.d.ts.map +1 -0
  64. package/dist/domain/figma/tokens.js +148 -0
  65. package/dist/domain/figma/visionAugmentation.d.ts +14 -0
  66. package/dist/domain/figma/visionAugmentation.d.ts.map +1 -0
  67. package/dist/domain/figma/visionAugmentation.js +48 -0
  68. package/dist/domain/intentDerivation.d.ts +21 -0
  69. package/dist/domain/intentDerivation.d.ts.map +1 -0
  70. package/dist/domain/intentDerivation.js +126 -0
  71. package/dist/domain/policyProfile.d.ts +37 -0
  72. package/dist/domain/policyProfile.d.ts.map +1 -0
  73. package/dist/domain/policyProfile.js +94 -0
  74. package/dist/domain/requirementExcerpt.d.ts +9 -0
  75. package/dist/domain/requirementExcerpt.d.ts.map +1 -0
  76. package/dist/domain/requirementExcerpt.js +39 -0
  77. package/dist/domain/staleness.d.ts +56 -0
  78. package/dist/domain/staleness.d.ts.map +1 -0
  79. package/dist/domain/staleness.js +313 -0
  80. package/dist/domain/testDesignModel.d.ts +38 -0
  81. package/dist/domain/testDesignModel.d.ts.map +1 -0
  82. package/dist/domain/testDesignModel.js +264 -0
  83. package/dist/domain/testQualityRubric.d.ts +20 -0
  84. package/dist/domain/testQualityRubric.d.ts.map +1 -0
  85. package/dist/domain/testQualityRubric.js +38 -0
  86. package/dist/domain/validation.d.ts +7 -0
  87. package/dist/domain/validation.d.ts.map +1 -0
  88. package/dist/domain/validation.js +145 -0
  89. package/dist/export/adapters/alm.d.ts +4 -0
  90. package/dist/export/adapters/alm.d.ts.map +1 -0
  91. package/dist/export/adapters/alm.js +75 -0
  92. package/dist/export/adapters/csv.d.ts +5 -0
  93. package/dist/export/adapters/csv.d.ts.map +1 -0
  94. package/dist/export/adapters/csv.js +55 -0
  95. package/dist/export/adapters/index.d.ts +13 -0
  96. package/dist/export/adapters/index.d.ts.map +1 -0
  97. package/dist/export/adapters/index.js +15 -0
  98. package/dist/export/adapters/jira.d.ts +5 -0
  99. package/dist/export/adapters/jira.d.ts.map +1 -0
  100. package/dist/export/adapters/jira.js +79 -0
  101. package/dist/export/adapters/json.d.ts +3 -0
  102. package/dist/export/adapters/json.d.ts.map +1 -0
  103. package/dist/export/adapters/json.js +54 -0
  104. package/dist/export/adapters/markdown.d.ts +3 -0
  105. package/dist/export/adapters/markdown.d.ts.map +1 -0
  106. package/dist/export/adapters/markdown.js +88 -0
  107. package/dist/export/adapters/plaintext.d.ts +3 -0
  108. package/dist/export/adapters/plaintext.d.ts.map +1 -0
  109. package/dist/export/adapters/plaintext.js +65 -0
  110. package/dist/export/adapters/polarion.d.ts +4 -0
  111. package/dist/export/adapters/polarion.d.ts.map +1 -0
  112. package/dist/export/adapters/polarion.js +67 -0
  113. package/dist/export/adapters/qtest.d.ts +4 -0
  114. package/dist/export/adapters/qtest.d.ts.map +1 -0
  115. package/dist/export/adapters/qtest.js +78 -0
  116. package/dist/export/adapters/qualityCenter.d.ts +3 -0
  117. package/dist/export/adapters/qualityCenter.d.ts.map +1 -0
  118. package/dist/export/adapters/qualityCenter.js +56 -0
  119. package/dist/export/adapters/spreadsheetSafeCsv.d.ts +36 -0
  120. package/dist/export/adapters/spreadsheetSafeCsv.d.ts.map +1 -0
  121. package/dist/export/adapters/spreadsheetSafeCsv.js +157 -0
  122. package/dist/export/adapters/traceability.d.ts +34 -0
  123. package/dist/export/adapters/traceability.d.ts.map +1 -0
  124. package/dist/export/adapters/traceability.js +142 -0
  125. package/dist/export/adapters/xray.d.ts +4 -0
  126. package/dist/export/adapters/xray.d.ts.map +1 -0
  127. package/dist/export/adapters/xray.js +72 -0
  128. package/dist/export/formats.d.ts +29 -0
  129. package/dist/export/formats.d.ts.map +1 -0
  130. package/dist/export/formats.js +34 -0
  131. package/dist/export/index.d.ts +4 -0
  132. package/dist/export/index.d.ts.map +1 -0
  133. package/dist/export/index.js +10 -0
  134. package/dist/export/serialize.d.ts +17 -0
  135. package/dist/export/serialize.d.ts.map +1 -0
  136. package/dist/export/serialize.js +56 -0
  137. package/dist/export/textSafety.d.ts +15 -0
  138. package/dist/export/textSafety.d.ts.map +1 -0
  139. package/dist/export/textSafety.js +30 -0
  140. package/dist/generation/candidateBounds.d.ts +10 -0
  141. package/dist/generation/candidateBounds.d.ts.map +1 -0
  142. package/dist/generation/candidateBounds.js +14 -0
  143. package/dist/generation/index.d.ts +4 -0
  144. package/dist/generation/index.d.ts.map +1 -0
  145. package/dist/generation/index.js +20 -0
  146. package/dist/generation/parseGeneratedCandidates.d.ts +27 -0
  147. package/dist/generation/parseGeneratedCandidates.d.ts.map +1 -0
  148. package/dist/generation/parseGeneratedCandidates.js +253 -0
  149. package/dist/generation/prompt.d.ts +16 -0
  150. package/dist/generation/prompt.d.ts.map +1 -0
  151. package/dist/generation/prompt.js +151 -0
  152. package/dist/generation/requirementsIngestion.d.ts +21 -0
  153. package/dist/generation/requirementsIngestion.d.ts.map +1 -0
  154. package/dist/generation/requirementsIngestion.js +70 -0
  155. package/dist/hardening/index.d.ts +6 -0
  156. package/dist/hardening/index.d.ts.map +1 -0
  157. package/dist/hardening/index.js +8 -0
  158. package/dist/hardening/oversizeGuards.d.ts +21 -0
  159. package/dist/hardening/oversizeGuards.d.ts.map +1 -0
  160. package/dist/hardening/oversizeGuards.js +35 -0
  161. package/dist/hardening/pathSafety.d.ts +19 -0
  162. package/dist/hardening/pathSafety.d.ts.map +1 -0
  163. package/dist/hardening/pathSafety.js +61 -0
  164. package/dist/hardening/promptInjectionScrub.d.ts +17 -0
  165. package/dist/hardening/promptInjectionScrub.d.ts.map +1 -0
  166. package/dist/hardening/promptInjectionScrub.js +72 -0
  167. package/dist/index.d.ts +22 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +44 -0
  170. package/dist/ingestion/adfParser.d.ts +61 -0
  171. package/dist/ingestion/adfParser.d.ts.map +1 -0
  172. package/dist/ingestion/adfParser.js +262 -0
  173. package/dist/ingestion/index.d.ts +6 -0
  174. package/dist/ingestion/index.d.ts.map +1 -0
  175. package/dist/ingestion/index.js +10 -0
  176. package/dist/ingestion/sourceMixPlanning.d.ts +36 -0
  177. package/dist/ingestion/sourceMixPlanning.d.ts.map +1 -0
  178. package/dist/ingestion/sourceMixPlanning.js +65 -0
  179. package/dist/ingestion/sourceReconciliation.d.ts +39 -0
  180. package/dist/ingestion/sourceReconciliation.d.ts.map +1 -0
  181. package/dist/ingestion/sourceReconciliation.js +74 -0
  182. package/dist/ingestion/untrustedContentNormalisation.d.ts +23 -0
  183. package/dist/ingestion/untrustedContentNormalisation.d.ts.map +1 -0
  184. package/dist/ingestion/untrustedContentNormalisation.js +121 -0
  185. package/dist/ingestion/workspaceAdapter.d.ts +55 -0
  186. package/dist/ingestion/workspaceAdapter.d.ts.map +1 -0
  187. package/dist/ingestion/workspaceAdapter.js +113 -0
  188. package/dist/review/auditEvents.d.ts +61 -0
  189. package/dist/review/auditEvents.d.ts.map +1 -0
  190. package/dist/review/auditEvents.js +50 -0
  191. package/dist/review/fourEyes.d.ts +24 -0
  192. package/dist/review/fourEyes.d.ts.map +1 -0
  193. package/dist/review/fourEyes.js +45 -0
  194. package/dist/review/index.d.ts +5 -0
  195. package/dist/review/index.d.ts.map +1 -0
  196. package/dist/review/index.js +14 -0
  197. package/dist/review/lifecyclePolicy.d.ts +21 -0
  198. package/dist/review/lifecyclePolicy.d.ts.map +1 -0
  199. package/dist/review/lifecyclePolicy.js +38 -0
  200. package/dist/review/stateMachine.d.ts +28 -0
  201. package/dist/review/stateMachine.d.ts.map +1 -0
  202. package/dist/review/stateMachine.js +71 -0
  203. package/package.json +31 -0
@@ -0,0 +1,45 @@
1
+ // Quality Intelligence four-eyes pairing guard (Epic #270, Issue #282).
2
+ //
3
+ // Pure-domain check that two review records may be paired under four-eyes
4
+ // governance. The contract guarantees `reviewerLabel` is display-only with NO
5
+ // PII guarantee; this module compares labels as opaque strings only (post
6
+ // trim + case-fold for the same-label check) and never persists them.
7
+ export class QualityIntelligenceFourEyesViolationError extends Error {
8
+ code;
9
+ recordId;
10
+ candidateId;
11
+ constructor(code, record, candidate, detail) {
12
+ super(`[${code}] record="${record.id}" candidate="${candidate.id}": ${detail}`);
13
+ this.name = "QualityIntelligenceFourEyesViolationError";
14
+ this.code = code;
15
+ this.recordId = record.id;
16
+ this.candidateId = candidate.id;
17
+ }
18
+ }
19
+ const normaliseLabel = (label) => label.trim().toLowerCase();
20
+ /**
21
+ * Assert that `record` and `candidate` may be paired for four-eyes governance.
22
+ * Throws a typed `QualityIntelligenceFourEyesViolationError` on:
23
+ *
24
+ * * SELF_REVIEW_FORBIDDEN — both records have `reviewerKind === "human-author"`.
25
+ * A human author may not also be the four-eyes second reviewer of their own
26
+ * authored output.
27
+ * * SAME_REVIEWER_LABEL — both records share the same (trimmed, case-folded)
28
+ * `reviewerLabel`. Display-only string comparison; no identity guarantee.
29
+ * * ALREADY_PAIRED — either record already references a `fourEyesPairedRecordId`.
30
+ *
31
+ * Returns `void` on success. The caller is responsible for actually wiring
32
+ * `fourEyesPairedRecordId` on both records when pairing succeeds.
33
+ */
34
+ export const assertFourEyesPair = (record, candidate) => {
35
+ if (record.fourEyesPairedRecordId !== undefined ||
36
+ candidate.fourEyesPairedRecordId !== undefined) {
37
+ throw new QualityIntelligenceFourEyesViolationError("ALREADY_PAIRED", record, candidate, "One or both records already have fourEyesPairedRecordId set");
38
+ }
39
+ if (record.reviewerKind === "human-author" && candidate.reviewerKind === "human-author") {
40
+ throw new QualityIntelligenceFourEyesViolationError("SELF_REVIEW_FORBIDDEN", record, candidate, "Two human-author reviewers cannot pair under four-eyes governance");
41
+ }
42
+ if (normaliseLabel(record.reviewerLabel) === normaliseLabel(candidate.reviewerLabel)) {
43
+ throw new QualityIntelligenceFourEyesViolationError("SAME_REVIEWER_LABEL", record, candidate, "Both records share the same reviewerLabel");
44
+ }
45
+ };
@@ -0,0 +1,5 @@
1
+ export { applyReviewTransition, QualityIntelligenceReviewTransitionError, QUALITY_INTELLIGENCE_REVIEW_TRANSITION_EVENTS, type QualityIntelligenceReviewTransitionEvent, type QualityIntelligenceReviewTransitionErrorCode, type NextReviewState, } from "./stateMachine.js";
2
+ export { isTerminalReviewState, canPairForFourEyes } from "./lifecyclePolicy.js";
3
+ export { assertFourEyesPair, QualityIntelligenceFourEyesViolationError, type QualityIntelligenceFourEyesViolationCode, } from "./fourEyes.js";
4
+ export { buildReviewAuditEvent, transitionedPayloadFromNext, QUALITY_INTELLIGENCE_REVIEW_AUDIT_EVENT_SCHEMA_VERSION, QUALITY_INTELLIGENCE_REVIEW_AUDIT_EVENT_KINDS, type QualityIntelligenceReviewAuditEventKind, type QualityIntelligenceReviewOpenedPayload, type QualityIntelligenceReviewTransitionedPayload, type QualityIntelligenceReviewFourEyesPairedPayload, type QualityIntelligenceReviewTerminatedPayload, type QualityIntelligenceReviewAuditEventPayload, type QualityIntelligenceReviewAuditEvent, type BuildReviewAuditEventInput, } from "./auditEvents.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/review/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,qBAAqB,EACrB,wCAAwC,EACxC,6CAA6C,EAC7C,KAAK,wCAAwC,EAC7C,KAAK,4CAA4C,EACjD,KAAK,eAAe,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAEjF,OAAO,EACL,kBAAkB,EAClB,yCAAyC,EACzC,KAAK,wCAAwC,GAC9C,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,sDAAsD,EACtD,6CAA6C,EAC7C,KAAK,uCAAuC,EAC5C,KAAK,sCAAsC,EAC3C,KAAK,4CAA4C,EACjD,KAAK,8CAA8C,EACnD,KAAK,0CAA0C,EAC/C,KAAK,0CAA0C,EAC/C,KAAK,mCAAmC,EACxC,KAAK,0BAA0B,GAChC,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,14 @@
1
+ // Public barrel for the Quality Intelligence review sub-namespace (Epic #270, Issue #282).
2
+ //
3
+ // Pure-domain review governance: state machine, lifecycle policy, four-eyes pairing
4
+ // guard, and the producer half of the audit-event envelope. No IO, no persistence,
5
+ // no clock — callers supply `at` timestamps and `by` actor labels.
6
+ //
7
+ // Consumers:
8
+ // * Workflow runtime (#273) drives the state machine and emits audit events.
9
+ // * Evidence layer (#274) and audit ledger persist the emitted events.
10
+ // * UI (#280 follow-up) renders the resulting records.
11
+ export { applyReviewTransition, QualityIntelligenceReviewTransitionError, QUALITY_INTELLIGENCE_REVIEW_TRANSITION_EVENTS, } from "./stateMachine.js";
12
+ export { isTerminalReviewState, canPairForFourEyes } from "./lifecyclePolicy.js";
13
+ export { assertFourEyesPair, QualityIntelligenceFourEyesViolationError, } from "./fourEyes.js";
14
+ export { buildReviewAuditEvent, transitionedPayloadFromNext, QUALITY_INTELLIGENCE_REVIEW_AUDIT_EVENT_SCHEMA_VERSION, QUALITY_INTELLIGENCE_REVIEW_AUDIT_EVENT_KINDS, } from "./auditEvents.js";
@@ -0,0 +1,21 @@
1
+ import type { QualityIntelligence } from "@oscharko-dev/keiko-contracts";
2
+ /**
3
+ * Return true iff the supplied review state is terminal — i.e. no further
4
+ * transition is legal under `applyReviewTransition`.
5
+ *
6
+ * Terminal: `approved`, `rejected`, `withdrawn`. Non-terminal: `open`,
7
+ * `changes-requested`.
8
+ */
9
+ export declare const isTerminalReviewState: (state: QualityIntelligence.QualityIntelligenceReviewState) => boolean;
10
+ /**
11
+ * Return true iff `record` is eligible to be paired with a second review for
12
+ * four-eyes governance. A record is eligible when:
13
+ *
14
+ * * its state is non-terminal, AND
15
+ * * it has not already been paired (`fourEyesPairedRecordId` is absent).
16
+ *
17
+ * Eligibility is a structural predicate only — the actual reviewer-identity
18
+ * disjointness check lives in `assertFourEyesPair`.
19
+ */
20
+ export declare const canPairForFourEyes: (record: QualityIntelligence.QualityIntelligenceReviewRecord) => boolean;
21
+ //# sourceMappingURL=lifecyclePolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecyclePolicy.d.ts","sourceRoot":"","sources":["../../src/review/lifecyclePolicy.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAQzE;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAChC,OAAO,mBAAmB,CAAC,8BAA8B,KACxD,OAAqC,CAAC;AAEzC;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,mBAAmB,CAAC,+BAA+B,KAC1D,OAQF,CAAC"}
@@ -0,0 +1,38 @@
1
+ // Quality Intelligence review lifecycle policy (Epic #270, Issue #282).
2
+ //
3
+ // Pure predicates over the QualityIntelligenceReviewRecord contract. Used by
4
+ // the runtime (#273) and the audit ledger (#274) to decide whether a record is
5
+ // still live, whether it may be paired for four-eyes governance, and whether
6
+ // downstream consumers should treat its state as final.
7
+ const TERMINAL_STATES = new Set([
8
+ "approved",
9
+ "rejected",
10
+ "withdrawn",
11
+ ]);
12
+ /**
13
+ * Return true iff the supplied review state is terminal — i.e. no further
14
+ * transition is legal under `applyReviewTransition`.
15
+ *
16
+ * Terminal: `approved`, `rejected`, `withdrawn`. Non-terminal: `open`,
17
+ * `changes-requested`.
18
+ */
19
+ export const isTerminalReviewState = (state) => TERMINAL_STATES.has(state);
20
+ /**
21
+ * Return true iff `record` is eligible to be paired with a second review for
22
+ * four-eyes governance. A record is eligible when:
23
+ *
24
+ * * its state is non-terminal, AND
25
+ * * it has not already been paired (`fourEyesPairedRecordId` is absent).
26
+ *
27
+ * Eligibility is a structural predicate only — the actual reviewer-identity
28
+ * disjointness check lives in `assertFourEyesPair`.
29
+ */
30
+ export const canPairForFourEyes = (record) => {
31
+ if (isTerminalReviewState(record.state)) {
32
+ return false;
33
+ }
34
+ if (record.fourEyesPairedRecordId !== undefined) {
35
+ return false;
36
+ }
37
+ return true;
38
+ };
@@ -0,0 +1,28 @@
1
+ import type { QualityIntelligence } from "@oscharko-dev/keiko-contracts";
2
+ export type QualityIntelligenceReviewTransitionEvent = "approve" | "request-changes" | "reject" | "withdraw" | "revise";
3
+ export declare const QUALITY_INTELLIGENCE_REVIEW_TRANSITION_EVENTS: readonly QualityIntelligenceReviewTransitionEvent[];
4
+ export type QualityIntelligenceReviewTransitionErrorCode = "TRANSITION_NOT_ALLOWED" | "UNKNOWN_FROM_STATE" | "UNKNOWN_EVENT";
5
+ export declare class QualityIntelligenceReviewTransitionError extends Error {
6
+ readonly code: QualityIntelligenceReviewTransitionErrorCode;
7
+ readonly from: QualityIntelligence.QualityIntelligenceReviewState;
8
+ readonly event: QualityIntelligenceReviewTransitionEvent;
9
+ constructor(code: QualityIntelligenceReviewTransitionErrorCode, from: QualityIntelligence.QualityIntelligenceReviewState, event: QualityIntelligenceReviewTransitionEvent, detail: string);
10
+ }
11
+ export interface NextReviewState {
12
+ readonly state: QualityIntelligence.QualityIntelligenceReviewState;
13
+ readonly by: string;
14
+ readonly at: string;
15
+ readonly event: QualityIntelligenceReviewTransitionEvent;
16
+ readonly from: QualityIntelligence.QualityIntelligenceReviewState;
17
+ }
18
+ /**
19
+ * Apply a review transition. Returns the next state record on success; throws a
20
+ * typed `QualityIntelligenceReviewTransitionError` on every illegal combination
21
+ * (including unknown `from` state or unknown event).
22
+ *
23
+ * `by` and `at` are pass-through metadata for the caller's audit envelope —
24
+ * this function does not validate them beyond presence (it does not call
25
+ * `Date.parse`; that is the caller's responsibility).
26
+ */
27
+ export declare const applyReviewTransition: (currentState: QualityIntelligence.QualityIntelligenceReviewState, event: QualityIntelligenceReviewTransitionEvent, by: string, at: string) => NextReviewState;
28
+ //# sourceMappingURL=stateMachine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateMachine.d.ts","sourceRoot":"","sources":["../../src/review/stateMachine.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,MAAM,MAAM,wCAAwC,GAChD,SAAS,GACT,iBAAiB,GACjB,QAAQ,GACR,UAAU,GACV,QAAQ,CAAC;AAEb,eAAO,MAAM,6CAA6C,EAAE,SAAS,wCAAwC,EACpC,CAAC;AAE1E,MAAM,MAAM,4CAA4C,GACpD,wBAAwB,GACxB,oBAAoB,GACpB,eAAe,CAAC;AAEpB,qBAAa,wCAAyC,SAAQ,KAAK;IACjE,SAAgB,IAAI,EAAE,4CAA4C,CAAC;IACnE,SAAgB,IAAI,EAAE,mBAAmB,CAAC,8BAA8B,CAAC;IACzE,SAAgB,KAAK,EAAE,wCAAwC,CAAC;gBAG9D,IAAI,EAAE,4CAA4C,EAClD,IAAI,EAAE,mBAAmB,CAAC,8BAA8B,EACxD,KAAK,EAAE,wCAAwC,EAC/C,MAAM,EAAE,MAAM;CAQjB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC,8BAA8B,CAAC;IACnE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,wCAAwC,CAAC;IACzD,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC,8BAA8B,CAAC;CACnE;AA2BD;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,cAAc,mBAAmB,CAAC,8BAA8B,EAChE,OAAO,wCAAwC,EAC/C,IAAI,MAAM,EACV,IAAI,MAAM,KACT,eAiCF,CAAC"}
@@ -0,0 +1,71 @@
1
+ // Quality Intelligence review state machine (Epic #270, Issue #282).
2
+ //
3
+ // Pure-domain transitions over the QualityIntelligenceReviewState enum from
4
+ // @oscharko-dev/keiko-contracts. Inspired structurally by the review-governance
5
+ // scaffolding under Test Intelligence reference (TI) — modelled freshly here.
6
+ //
7
+ // No IO, no persistence, no clock. Callers pass `by` (display label of the actor)
8
+ // and `at` (ISO 8601 timestamp produced by the caller's clock). The function is
9
+ // total over the typed event enum: every illegal transition raises a typed
10
+ // `QualityIntelligenceReviewTransitionError` with the offending `from`, `event`,
11
+ // and a fail-closed reason code.
12
+ export const QUALITY_INTELLIGENCE_REVIEW_TRANSITION_EVENTS = ["approve", "request-changes", "reject", "withdraw", "revise"];
13
+ export class QualityIntelligenceReviewTransitionError extends Error {
14
+ code;
15
+ from;
16
+ event;
17
+ constructor(code, from, event, detail) {
18
+ super(`[${code}] from="${from}" event="${event}": ${detail}`);
19
+ this.name = "QualityIntelligenceReviewTransitionError";
20
+ this.code = code;
21
+ this.from = from;
22
+ this.event = event;
23
+ }
24
+ }
25
+ // Static transition table — pure data. Every legal `(from, event)` pair maps to
26
+ // the resulting state. Lookups against this table are O(1); absence raises a
27
+ // typed error.
28
+ const TRANSITIONS = new Map([
29
+ ["open|approve", "approved"],
30
+ ["open|request-changes", "changes-requested"],
31
+ ["open|reject", "rejected"],
32
+ ["open|withdraw", "withdrawn"],
33
+ ["changes-requested|revise", "open"],
34
+ ["changes-requested|withdraw", "withdrawn"],
35
+ ]);
36
+ const KNOWN_STATES = new Set([
37
+ "open",
38
+ "approved",
39
+ "changes-requested",
40
+ "rejected",
41
+ "withdrawn",
42
+ ]);
43
+ const KNOWN_EVENTS = new Set(QUALITY_INTELLIGENCE_REVIEW_TRANSITION_EVENTS);
44
+ /**
45
+ * Apply a review transition. Returns the next state record on success; throws a
46
+ * typed `QualityIntelligenceReviewTransitionError` on every illegal combination
47
+ * (including unknown `from` state or unknown event).
48
+ *
49
+ * `by` and `at` are pass-through metadata for the caller's audit envelope —
50
+ * this function does not validate them beyond presence (it does not call
51
+ * `Date.parse`; that is the caller's responsibility).
52
+ */
53
+ export const applyReviewTransition = (currentState, event, by, at) => {
54
+ if (!KNOWN_STATES.has(currentState)) {
55
+ throw new QualityIntelligenceReviewTransitionError("UNKNOWN_FROM_STATE", currentState, event, `State "${currentState}" is not a known review state`);
56
+ }
57
+ if (!KNOWN_EVENTS.has(event)) {
58
+ throw new QualityIntelligenceReviewTransitionError("UNKNOWN_EVENT", currentState, event, `Event "${event}" is not a known transition event`);
59
+ }
60
+ const next = TRANSITIONS.get(`${currentState}|${event}`);
61
+ if (next === undefined) {
62
+ throw new QualityIntelligenceReviewTransitionError("TRANSITION_NOT_ALLOWED", currentState, event, `No legal transition from "${currentState}" via "${event}"`);
63
+ }
64
+ return Object.freeze({
65
+ state: next,
66
+ by,
67
+ at,
68
+ event,
69
+ from: currentState,
70
+ });
71
+ };
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@oscharko-dev/keiko-quality-intelligence",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "license": "Apache-2.0",
6
+ "description": "Internal workspace package: pure-domain Keiko Quality Intelligence test-design logic. Not published independently.",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsc -b tsconfig.json",
17
+ "typecheck": "tsc -b tsconfig.json",
18
+ "test": "vitest run"
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "sideEffects": false,
24
+ "engines": {
25
+ "node": ">=22"
26
+ },
27
+ "dependencies": {
28
+ "@oscharko-dev/keiko-contracts": "0.2.0",
29
+ "@oscharko-dev/keiko-security": "0.2.0"
30
+ }
31
+ }