@clossys/writer 0.3.9 → 0.5.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 (136) hide show
  1. package/README.md +647 -6
  2. package/dist/addressability.d.ts +11 -1
  3. package/dist/addressability.d.ts.map +1 -1
  4. package/dist/addressability.js +169 -3
  5. package/dist/addressability.js.map +1 -1
  6. package/dist/approval-bypass.d.ts +120 -0
  7. package/dist/approval-bypass.d.ts.map +1 -0
  8. package/dist/approval-bypass.js +2318 -0
  9. package/dist/approval-bypass.js.map +1 -0
  10. package/dist/approval.d.ts +62 -0
  11. package/dist/approval.d.ts.map +1 -0
  12. package/dist/approval.js +421 -0
  13. package/dist/approval.js.map +1 -0
  14. package/dist/approve-cli.d.ts +82 -0
  15. package/dist/approve-cli.d.ts.map +1 -0
  16. package/dist/approve-cli.js +430 -0
  17. package/dist/approve-cli.js.map +1 -0
  18. package/dist/cli.d.ts +15 -0
  19. package/dist/cli.d.ts.map +1 -1
  20. package/dist/cli.js +264 -22
  21. package/dist/cli.js.map +1 -1
  22. package/dist/field-options.d.ts +59 -0
  23. package/dist/field-options.d.ts.map +1 -0
  24. package/dist/field-options.js +109 -0
  25. package/dist/field-options.js.map +1 -0
  26. package/dist/fold-wallpaper-gate.d.ts +7 -0
  27. package/dist/fold-wallpaper-gate.d.ts.map +1 -0
  28. package/dist/fold-wallpaper-gate.js +29 -0
  29. package/dist/fold-wallpaper-gate.js.map +1 -0
  30. package/dist/front-door.check.d.ts +2 -0
  31. package/dist/front-door.check.d.ts.map +1 -0
  32. package/dist/front-door.check.js +8 -0
  33. package/dist/front-door.check.js.map +1 -0
  34. package/dist/front-door.d.ts +82 -0
  35. package/dist/front-door.d.ts.map +1 -0
  36. package/dist/front-door.js +271 -0
  37. package/dist/front-door.js.map +1 -0
  38. package/dist/generated/advisor-plan-contract.generated.d.ts +3 -0
  39. package/dist/generated/advisor-plan-contract.generated.d.ts.map +1 -0
  40. package/dist/generated/advisor-plan-contract.generated.js +430 -0
  41. package/dist/generated/advisor-plan-contract.generated.js.map +1 -0
  42. package/dist/generated/contract-schema.generated.d.ts +97 -0
  43. package/dist/generated/contract-schema.generated.d.ts.map +1 -0
  44. package/dist/generated/contract-schema.generated.js +496 -0
  45. package/dist/generated/contract-schema.generated.js.map +1 -0
  46. package/dist/index.d.ts +18 -2
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +26 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/live-copy-gate.d.ts +16 -0
  51. package/dist/live-copy-gate.d.ts.map +1 -0
  52. package/dist/live-copy-gate.js +135 -0
  53. package/dist/live-copy-gate.js.map +1 -0
  54. package/dist/messaging-kit.d.ts +113 -0
  55. package/dist/messaging-kit.d.ts.map +1 -0
  56. package/dist/messaging-kit.js +121 -0
  57. package/dist/messaging-kit.js.map +1 -0
  58. package/dist/passage.d.ts +2 -1
  59. package/dist/passage.d.ts.map +1 -1
  60. package/dist/passage.js +2 -1
  61. package/dist/passage.js.map +1 -1
  62. package/dist/plan-authority.d.ts +73 -0
  63. package/dist/plan-authority.d.ts.map +1 -0
  64. package/dist/plan-authority.js +126 -0
  65. package/dist/plan-authority.js.map +1 -0
  66. package/dist/plan-contract.d.ts +16 -0
  67. package/dist/plan-contract.d.ts.map +1 -0
  68. package/dist/plan-contract.js +33 -0
  69. package/dist/plan-contract.js.map +1 -0
  70. package/dist/plan-digest.d.ts +23 -0
  71. package/dist/plan-digest.d.ts.map +1 -0
  72. package/dist/plan-digest.js +82 -0
  73. package/dist/plan-digest.js.map +1 -0
  74. package/dist/plan-rules.d.ts +54 -0
  75. package/dist/plan-rules.d.ts.map +1 -0
  76. package/dist/plan-rules.js +145 -0
  77. package/dist/plan-rules.js.map +1 -0
  78. package/dist/render-registry-parity.d.ts +20 -0
  79. package/dist/render-registry-parity.d.ts.map +1 -0
  80. package/dist/render-registry-parity.js +45 -0
  81. package/dist/render-registry-parity.js.map +1 -0
  82. package/dist/resolve.d.ts +40 -6
  83. package/dist/resolve.d.ts.map +1 -1
  84. package/dist/resolve.js +144 -18
  85. package/dist/resolve.js.map +1 -1
  86. package/dist/scan.d.ts +32 -0
  87. package/dist/scan.d.ts.map +1 -1
  88. package/dist/scan.js +67 -6
  89. package/dist/scan.js.map +1 -1
  90. package/dist/schema.d.ts +1 -0
  91. package/dist/schema.d.ts.map +1 -1
  92. package/dist/schema.js +231 -5
  93. package/dist/schema.js.map +1 -1
  94. package/dist/site-identity.d.ts +88 -0
  95. package/dist/site-identity.d.ts.map +1 -0
  96. package/dist/site-identity.js +82 -0
  97. package/dist/site-identity.js.map +1 -0
  98. package/dist/treatment-word-budget.d.ts +31 -0
  99. package/dist/treatment-word-budget.d.ts.map +1 -0
  100. package/dist/treatment-word-budget.js +80 -0
  101. package/dist/treatment-word-budget.js.map +1 -0
  102. package/dist/types.d.ts +76 -7
  103. package/dist/types.d.ts.map +1 -1
  104. package/dist/types.js +9 -7
  105. package/dist/types.js.map +1 -1
  106. package/fit-signals.json +11 -0
  107. package/package.json +201 -11
  108. package/skill/SKILL.md +49 -0
  109. package/src/addressability.ts +186 -4
  110. package/src/approval-bypass.ts +2263 -0
  111. package/src/approval.ts +491 -0
  112. package/src/approve-cli.ts +474 -0
  113. package/src/cli.ts +274 -22
  114. package/src/field-options.ts +134 -0
  115. package/src/fold-wallpaper-gate.ts +29 -0
  116. package/src/front-door.check.ts +10 -0
  117. package/src/front-door.ts +312 -0
  118. package/src/generated/advisor-plan-contract.generated.ts +430 -0
  119. package/src/generated/contract-schema.generated.ts +520 -0
  120. package/src/index.ts +107 -1
  121. package/src/live-copy-gate.ts +150 -0
  122. package/src/messaging-kit.ts +195 -0
  123. package/src/passage.ts +2 -1
  124. package/src/plan-authority.ts +160 -0
  125. package/src/plan-contract.ts +45 -0
  126. package/src/plan-digest.ts +81 -0
  127. package/src/plan-rules.ts +179 -0
  128. package/src/render-registry-parity.ts +65 -0
  129. package/src/resolve.ts +185 -19
  130. package/src/scan.ts +97 -6
  131. package/src/schema.ts +247 -5
  132. package/src/site-identity.ts +125 -0
  133. package/src/treatment-word-budget.ts +100 -0
  134. package/src/types.ts +83 -7
  135. package/templates/front-door.en.json +426 -0
  136. package/CHANGELOG.md +0 -330
@@ -0,0 +1,126 @@
1
+ // Whether the bytes of an Advisor plan record authorize copy a delegate
2
+ // approved on production (issue #1586). The plan's optional
3
+ // `delegatedCopyApproval` declares that grant, and an approval binds the plan
4
+ // it grants for: this reads the field only through a latest decision that
5
+ // names the plan's own canonical digest. Two files define what is read, both
6
+ // in the public repository, not shipped in this package: the plan contract,
7
+ // docs/contracts/advisor-plan.json (see its DELEGATED COPY APPROVAL and
8
+ // APPROVAL BINDING sections), and the digest definition,
9
+ // docs/contracts/advisor-plan-digest.md.
10
+ //
11
+ // It is a pure function of the bytes: it reads no file, keeps nothing between
12
+ // calls and never looks at the clock, because a plan approval has no expiry
13
+ // of its own. It takes bytes, not a parsed object, because the digest is
14
+ // defined only over a plan that was read strictly, and an object a caller
15
+ // built can carry getters or proxies that answer validation, the digest and
16
+ // the scope check differently. What it does not prove is who wrote the
17
+ // decision, or where the bytes came from: see this package's README.
18
+ import { readContractDocument } from "./generated/contract-schema.generated.js";
19
+ import { planViolations } from "./plan-contract.js";
20
+ import { digestOfValidPlan } from "./plan-digest.js";
21
+ const SUBJECT_DIGEST = /^sha256:[0-9a-f]{64}$/;
22
+ function refuse(refusal, violations) {
23
+ if (violations === undefined)
24
+ return Object.freeze({ authorized: false, refusal });
25
+ return Object.freeze({ authorized: false, refusal, violations: Object.freeze(violations.map((violation) => Object.freeze({ rule: violation.rule, path: violation.path }))) });
26
+ }
27
+ /**
28
+ * The positions of the decisions made at the latest instant, by `at` and
29
+ * never by array position, in array order. Times are compared as instants
30
+ * (`Date.parse`), so `2026-09-21T00:00:00Z` and `2026-09-21T02:00:00+02:00`
31
+ * tie. Null when there are no decisions, or when any `at` does not parse to a
32
+ * finite time, because then time cannot say which is latest. Exported for
33
+ * tests, not from the package entry point.
34
+ */
35
+ export function latestDecisionIndices(decisions) {
36
+ if (decisions.length === 0)
37
+ return null;
38
+ const times = decisions.map((decision) => Date.parse(decision.at));
39
+ if (!times.every(Number.isFinite))
40
+ return null;
41
+ // A reduce, not Math.max(...times): spreading a very long list into arguments throws a RangeError.
42
+ const latest = times.reduce((highest, time) => (time > highest ? time : highest), Number.NEGATIVE_INFINITY);
43
+ const indices = [];
44
+ times.forEach((time, index) => {
45
+ if (time === latest)
46
+ indices.push(index);
47
+ });
48
+ return indices;
49
+ }
50
+ /** True for a real `Uint8Array` (a Node `Buffer` is one), never a `DataView`, another typed array or a proxy. */
51
+ export function isPlanBytes(value) {
52
+ try {
53
+ return value instanceof Uint8Array && ArrayBuffer.isView(value);
54
+ }
55
+ catch {
56
+ return false; // instanceof throws on a revoked proxy
57
+ }
58
+ }
59
+ /**
60
+ * Whether the bytes of a plan record authorize delegate-approved copy on
61
+ * production. Checks run in this order and the first that fails refuses:
62
+ *
63
+ * 1. the argument is a `Uint8Array` (`plan-not-bytes`);
64
+ * 2. the bytes are strict JSON (`plan-unreadable`);
65
+ * 3. the plan validates against the plan contract, R1-R12 included
66
+ * (`plan-invalid`, with each violation's rule and position);
67
+ * 4. the plan declares `delegatedCopyApproval` (`delegated-copy-approval-absent`);
68
+ * 5-9. the plan's latest decision, found by time and never by array
69
+ * position, has chosen "approved" and names one sha256 `subjectDigest`.
70
+ * When several decisions share the latest instant, every one is examined:
71
+ * the outcome does not depend on their order;
72
+ * 10. that digest equals the plan's own canonical digest, computed here from
73
+ * the same bytes (`subject-digest-mismatch`). The digest covers
74
+ * `delegatedCopyApproval`, so a declaration added, removed or edited after
75
+ * the approval leaves the plan unapproved for this purpose.
76
+ *
77
+ * Never throws for a bad argument and never echoes plan text. The result and
78
+ * everything in it is frozen, and copied from the bytes, which are copied
79
+ * before they are read.
80
+ */
81
+ export function planDelegateCopyAuthority(planBytes) {
82
+ if (!isPlanBytes(planBytes))
83
+ return refuse("plan-not-bytes");
84
+ // A copy, so nothing the caller does to its buffer during or after this call changes what is read.
85
+ const bytes = new Uint8Array(planBytes);
86
+ let value;
87
+ try {
88
+ value = readContractDocument(bytes);
89
+ }
90
+ catch {
91
+ return refuse("plan-unreadable");
92
+ }
93
+ const violations = planViolations(value);
94
+ if (violations.length > 0)
95
+ return refuse("plan-invalid", violations);
96
+ const plan = value;
97
+ if (!Object.hasOwn(plan, "delegatedCopyApproval"))
98
+ return refuse("delegated-copy-approval-absent");
99
+ if (plan.decisions.length === 0)
100
+ return refuse("no-decisions");
101
+ const latestIndices = latestDecisionIndices(plan.decisions);
102
+ if (latestIndices === null)
103
+ return refuse("decision-time-unparseable");
104
+ const latest = latestIndices.map((index) => plan.decisions[index]);
105
+ if (latest.some((decision) => decision.chosen !== "approved"))
106
+ return refuse("latest-decision-not-approved");
107
+ const subjects = latest.map((decision) => (Object.hasOwn(decision, "subjectDigest") ? decision.subjectDigest : undefined));
108
+ if (subjects.some((subject) => typeof subject !== "string" || !SUBJECT_DIGEST.test(subject)))
109
+ return refuse("approval-without-subject-digest");
110
+ if (subjects.some((subject) => subject !== subjects[0]))
111
+ return refuse("latest-decisions-disagree");
112
+ let digest;
113
+ try {
114
+ digest = digestOfValidPlan(plan);
115
+ }
116
+ catch {
117
+ return refuse("plan-invalid", []);
118
+ }
119
+ if (subjects[0] !== digest)
120
+ return refuse("subject-digest-mismatch");
121
+ const declaration = plan.delegatedCopyApproval;
122
+ if (!Object.hasOwn(declaration, "scopes") || declaration.scopes === undefined)
123
+ return Object.freeze({ authorized: true, planDigest: digest });
124
+ return Object.freeze({ authorized: true, planDigest: digest, scopes: Object.freeze([...declaration.scopes]) });
125
+ }
126
+ //# sourceMappingURL=plan-authority.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-authority.js","sourceRoot":"","sources":["../src/plan-authority.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,4DAA4D;AAC5D,8EAA8E;AAC9E,0EAA0E;AAC1E,6EAA6E;AAC7E,4EAA4E;AAC5E,wEAAwE;AACxE,yDAAyD;AACzD,yCAAyC;AACzC,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,yEAAyE;AACzE,0EAA0E;AAC1E,4EAA4E;AAC5E,uEAAuE;AACvE,qEAAqE;AAErE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAyCrD,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAE/C,SAAS,MAAM,CAAC,OAAgC,EAAE,UAAwE;IACxH,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACnF,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAChL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAA6C;IACjF,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IACnE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,mGAAmG;IACnG,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAC5G,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,IAAI,IAAI,KAAK,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,CAAC;QACH,OAAO,KAAK,YAAY,UAAU,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,CAAC,uCAAuC;IACvD,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,yBAAyB,CAAC,SAA+B;IACvE,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;QAAE,OAAO,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC7D,mGAAmG;IACnG,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;IAExC,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IACrE,MAAM,IAAI,GAAG,KAAqB,CAAC;IAEnC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,uBAAuB,CAAC;QAAE,OAAO,MAAM,CAAC,gCAAgC,CAAC,CAAC;IACnG,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,cAAc,CAAC,CAAC;IAE/D,MAAM,aAAa,GAAG,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5D,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC,2BAA2B,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAE,CAAC,CAAC;IACpE,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,KAAK,UAAU,CAAC;QAAE,OAAO,MAAM,CAAC,8BAA8B,CAAC,CAAC;IAE7G,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3H,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,iCAAiC,CAAC,CAAC;IAC/I,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAEpG,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,iBAAiB,CAAC,IAAoD,CAAC,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACpC,CAAC;IACD,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAErE,MAAM,WAAW,GAAG,IAAI,CAAC,qBAAsB,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9I,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;AACjH,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { PlanRuleId } from "./plan-rules.js";
2
+ /** One reason a plan is refused: `rule` is "schema" for the contract's keywords, else the code rule's id. */
3
+ export interface PlanViolation {
4
+ readonly rule: "schema" | PlanRuleId;
5
+ /** The field at fault, like `staffing[1].repository`, or "" for the document itself. */
6
+ readonly path: string;
7
+ /** The whole message, starting with `plan` and the path; it never quotes a value. */
8
+ readonly message: string;
9
+ }
10
+ /**
11
+ * Every reason `value` is not a valid plan: the plan contract's schema, then,
12
+ * once that passes, its code rules R1-R12. Empty means valid. Never throws
13
+ * for a bad value, and no message echoes a value from the plan.
14
+ */
15
+ export declare function planViolations(value: unknown): PlanViolation[];
16
+ //# sourceMappingURL=plan-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-contract.d.ts","sourceRoot":"","sources":["../src/plan-contract.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEhE,6GAA6G;AAC7G,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IACrC,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAOD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,EAAE,CAW9D"}
@@ -0,0 +1,33 @@
1
+ // Reads a plan record (issue #1586) against the shared plan contract
2
+ // docs/contracts/advisor-plan.json -- in the public repository, not shipped in
3
+ // this package. This package's build packs that contract into src/generated/
4
+ // as plain data, with a generated copy of the one contract checker every
5
+ // other reader of a plan also uses (packages/advisor/src/contract-schema.ts,
6
+ // likewise in the public repository, not shipped in this package), so
7
+ // Writer validates against the same definition with no runtime dependency on
8
+ // any other package.
9
+ import { ADVISOR_PLAN_CONTRACT } from "./generated/advisor-plan-contract.generated.js";
10
+ import { formatContractViolation, validateAgainstContract } from "./generated/contract-schema.generated.js";
11
+ import { planRuleViolations } from "./plan-rules.js";
12
+ /** The plan contract refers to no other contract file, so every name is refused. */
13
+ function refuseEveryName(name) {
14
+ throw new Error(`the plan contract refers to no other contract, but the checker asked for ${JSON.stringify(name)}`);
15
+ }
16
+ /**
17
+ * Every reason `value` is not a valid plan: the plan contract's schema, then,
18
+ * once that passes, its code rules R1-R12. Empty means valid. Never throws
19
+ * for a bad value, and no message echoes a value from the plan.
20
+ */
21
+ export function planViolations(value) {
22
+ const schema = validateAgainstContract(ADVISOR_PLAN_CONTRACT, value, refuseEveryName);
23
+ if (schema.length > 0) {
24
+ return schema.map((violation) => ({ rule: "schema", path: violation.path, message: formatContractViolation("plan", violation) }));
25
+ }
26
+ // The code rules relate fields to one another, so they run only on a plan whose shape is known good.
27
+ return planRuleViolations(value).map((violation) => ({
28
+ rule: violation.rule,
29
+ path: violation.path,
30
+ message: `plan.${violation.path} ${violation.message} (rule ${violation.rule})`,
31
+ }));
32
+ }
33
+ //# sourceMappingURL=plan-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-contract.js","sourceRoot":"","sources":["../src/plan-contract.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,+EAA+E;AAC/E,6EAA6E;AAC7E,yEAAyE;AACzE,6EAA6E;AAC7E,sEAAsE;AACtE,6EAA6E;AAC7E,qBAAqB;AAErB,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AACvF,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AAC5G,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAYrD,oFAAoF;AACpF,SAAS,eAAe,CAAC,IAAY;IACnC,MAAM,IAAI,KAAK,CAAC,4EAA4E,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACtH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,MAAM,MAAM,GAAG,uBAAuB,CAAC,qBAAqB,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;IACtF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,uBAAuB,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;IACpI,CAAC;IACD,qGAAqG;IACrG,OAAO,kBAAkB,CAAC,KAAqB,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACnE,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,OAAO,EAAE,QAAQ,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,OAAO,UAAU,SAAS,CAAC,IAAI,GAAG;KAChF,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,23 @@
1
+ /** The top-level plan members the digest leaves out: when the file was written, and the decisions an approval is recorded in. */
2
+ export declare const PLAN_DIGEST_EXCLUDED_FIELDS: readonly string[];
3
+ /**
4
+ * RFC 8785 (JSON Canonicalization Scheme) serialization: no whitespace,
5
+ * object members sorted by UTF-16 code units, strings escaped only where
6
+ * JSON requires, numbers as ECMAScript writes them. Throws on anything JSON
7
+ * cannot carry (undefined, a function, a bigint, a non-finite number, a hole
8
+ * in an array) and on a lone surrogate, rather than silently dropping or
9
+ * repairing it.
10
+ */
11
+ export declare function canonicalJson(value: unknown): string;
12
+ /**
13
+ * `sha256:` and the lowercase hex SHA-256 of the canonical JSON of a plan
14
+ * without `asOf` and `decisions`. Assumes `plan` already passed
15
+ * `planViolations()`: it checks nothing itself.
16
+ */
17
+ export declare function digestOfValidPlan(plan: Readonly<Record<string, unknown>>): string;
18
+ /**
19
+ * The plan digest. Throws when the plan does not validate against the plan
20
+ * contract, rules included: an invalid plan has no digest.
21
+ */
22
+ export declare function planDigest(plan: unknown): string;
23
+ //# sourceMappingURL=plan-digest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-digest.d.ts","sourceRoot":"","sources":["../src/plan-digest.ts"],"names":[],"mappings":"AAcA,iIAAiI;AACjI,eAAO,MAAM,2BAA2B,EAAE,SAAS,MAAM,EAA0B,CAAC;AAUpF;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA0BpD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAIjF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAIhD"}
@@ -0,0 +1,82 @@
1
+ // The canonical plan digest (issue #1586), implemented from its one
2
+ // definition, docs/contracts/advisor-plan-digest.md -- in the public repository, not shipped in this package.
3
+ // An approval binds this value, so it names exactly which plan was approved.
4
+ // Every other reader of a plan implements the same definition separately, and
5
+ // each is tested against the same fixture corpus,
6
+ // docs/contracts/advisor-plan-digest.fixture.json (likewise in the public repository, not shipped in this package),
7
+ // so all of them compute identical digests.
8
+ // This is a third, separate reading of RFC 8785: strings go through
9
+ // JSON.stringify, whose output for well-formed text is exactly the escaping
10
+ // RFC 8785 requires, with a lone surrogate refused before it.
11
+ import { createHash } from "node:crypto";
12
+ import { planViolations } from "./plan-contract.js";
13
+ /** The top-level plan members the digest leaves out: when the file was written, and the decisions an approval is recorded in. */
14
+ export const PLAN_DIGEST_EXCLUDED_FIELDS = ["asOf", "decisions"];
15
+ const LONE_SURROGATE_CHECK = /[\uD800-\uDFFF]/u;
16
+ /** A string as RFC 8785 writes it. Throws on a string that is not well-formed Unicode. */
17
+ function canonicalString(text) {
18
+ if (LONE_SURROGATE_CHECK.test(text))
19
+ throw new TypeError("canonical JSON refuses a string that is not well-formed Unicode (a lone surrogate)");
20
+ return JSON.stringify(text);
21
+ }
22
+ /**
23
+ * RFC 8785 (JSON Canonicalization Scheme) serialization: no whitespace,
24
+ * object members sorted by UTF-16 code units, strings escaped only where
25
+ * JSON requires, numbers as ECMAScript writes them. Throws on anything JSON
26
+ * cannot carry (undefined, a function, a bigint, a non-finite number, a hole
27
+ * in an array) and on a lone surrogate, rather than silently dropping or
28
+ * repairing it.
29
+ */
30
+ export function canonicalJson(value) {
31
+ if (value === null)
32
+ return "null";
33
+ switch (typeof value) {
34
+ case "boolean":
35
+ return value ? "true" : "false";
36
+ case "number":
37
+ if (!Number.isFinite(value))
38
+ throw new TypeError("canonical JSON refuses a non-finite number");
39
+ return String(value);
40
+ case "string":
41
+ return canonicalString(value);
42
+ case "object": {
43
+ if (Array.isArray(value)) {
44
+ const items = [];
45
+ for (let index = 0; index < value.length; index += 1)
46
+ items.push(canonicalJson(value[index]));
47
+ return `[${items.join(",")}]`;
48
+ }
49
+ const record = value;
50
+ // The default sort compares UTF-16 code units, which is the order RFC 8785 requires.
51
+ const members = Object.keys(record)
52
+ .sort()
53
+ .map((key) => `${canonicalString(key)}:${canonicalJson(record[key])}`);
54
+ return `{${members.join(",")}}`;
55
+ }
56
+ default:
57
+ throw new TypeError(`canonical JSON refuses a value of type ${typeof value}`);
58
+ }
59
+ }
60
+ /**
61
+ * `sha256:` and the lowercase hex SHA-256 of the canonical JSON of a plan
62
+ * without `asOf` and `decisions`. Assumes `plan` already passed
63
+ * `planViolations()`: it checks nothing itself.
64
+ */
65
+ export function digestOfValidPlan(plan) {
66
+ const subject = {};
67
+ for (const key of Object.keys(plan))
68
+ if (!PLAN_DIGEST_EXCLUDED_FIELDS.includes(key))
69
+ subject[key] = plan[key];
70
+ return `sha256:${createHash("sha256").update(canonicalJson(subject), "utf8").digest("hex")}`;
71
+ }
72
+ /**
73
+ * The plan digest. Throws when the plan does not validate against the plan
74
+ * contract, rules included: an invalid plan has no digest.
75
+ */
76
+ export function planDigest(plan) {
77
+ const violations = planViolations(plan);
78
+ if (violations.length > 0)
79
+ throw new TypeError(`an invalid plan has no digest: ${violations.map((violation) => violation.message).join("; ")}`);
80
+ return digestOfValidPlan(plan);
81
+ }
82
+ //# sourceMappingURL=plan-digest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-digest.js","sourceRoot":"","sources":["../src/plan-digest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /** A code rule of the plan contract. */
2
+ export type PlanRuleId = "R1" | "R2" | "R3" | "R4" | "R5" | "R6" | "R7" | "R8" | "R9" | "R10" | "R11" | "R12";
3
+ /**
4
+ * The roles whose package lives in the engagement hub only, read from the
5
+ * packed plan contract's `definitions.hubOnlyRoles`, the one list every
6
+ * reader of a plan uses. Code rules R2 and R11 use it. A packed contract
7
+ * without a well-formed list is a build defect, so loading this module throws
8
+ * rather than judge plans against a guess.
9
+ */
10
+ export declare const HUB_ONLY_ROLES: readonly string[];
11
+ /**
12
+ * The members of a plan these rules and the authority read, and no more. A
13
+ * plan that passed the contract's schema has this shape; it is a structural
14
+ * view, not the contract, and it validates nothing.
15
+ */
16
+ export interface PlanDocument {
17
+ readonly mandate: {
18
+ readonly roles: readonly string[];
19
+ };
20
+ readonly staffing?: readonly {
21
+ readonly repository: string;
22
+ readonly roles: readonly string[];
23
+ }[];
24
+ readonly packages?: readonly {
25
+ readonly planItem: string;
26
+ readonly repository: string;
27
+ readonly act: string;
28
+ readonly name: string;
29
+ readonly placement: string;
30
+ }[];
31
+ readonly kits?: readonly {
32
+ readonly id: string;
33
+ }[];
34
+ readonly resolution?: unknown;
35
+ readonly delegatedCopyApproval?: {
36
+ readonly target: "production";
37
+ readonly scopes?: readonly string[];
38
+ };
39
+ readonly decisions: readonly {
40
+ readonly at: string;
41
+ readonly chosen: string;
42
+ readonly subjectDigest?: string;
43
+ }[];
44
+ }
45
+ export interface PlanRuleViolation {
46
+ readonly rule: PlanRuleId;
47
+ /** The field at fault, such as `staffing[1].repository`. */
48
+ readonly path: string;
49
+ /** What is wrong, by position only. */
50
+ readonly message: string;
51
+ }
52
+ /** Every violation of R1-R12, for a plan that already passed the plan contract's schema. */
53
+ export declare function planRuleViolations(plan: PlanDocument): PlanRuleViolation[];
54
+ //# sourceMappingURL=plan-rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-rules.d.ts","sourceRoot":"","sources":["../src/plan-rules.ts"],"names":[],"mappings":"AAmBA,wCAAwC;AACxC,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAE9G;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAOxC,CAAC;AAEL;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IACxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IAClG,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS;QAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC5B,EAAE,CAAC;IACJ,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnD,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,qBAAqB,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IACxG,QAAQ,CAAC,SAAS,EAAE,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAClH;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AA0BD,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,iBAAiB,EAAE,CAsF1E"}
@@ -0,0 +1,145 @@
1
+ // The plan contract's code rules R1-R12 (issue #1178, read here for issue
2
+ // #1586): the checks the contract's JSON Schema keywords cannot express,
3
+ // because each one relates one field to another. They are defined once, as
4
+ // prose in the description of the shared contract
5
+ // docs/contracts/advisor-plan.json -- in the public repository, not shipped
6
+ // in this package. This is @clossys/writer's own implementation, written from
7
+ // that text; every other reader of a plan implements the rules separately,
8
+ // and each is tested against one corpus,
9
+ // docs/contracts/advisor-plan-rules.fixture.json (likewise in the public
10
+ // repository, not shipped in this package), so a plan one of them accepts,
11
+ // they all accept, and the reverse.
12
+ //
13
+ // These functions assume the value already passed the plan contract's
14
+ // schema: plan-contract.ts runs them only then. A violation names its rule and
15
+ // the position of the field at fault, never a value, because a plan can carry
16
+ // founder text.
17
+ import { ADVISOR_PLAN_CONTRACT } from "./generated/advisor-plan-contract.generated.js";
18
+ /**
19
+ * The roles whose package lives in the engagement hub only, read from the
20
+ * packed plan contract's `definitions.hubOnlyRoles`, the one list every
21
+ * reader of a plan uses. Code rules R2 and R11 use it. A packed contract
22
+ * without a well-formed list is a build defect, so loading this module throws
23
+ * rather than judge plans against a guess.
24
+ */
25
+ export const HUB_ONLY_ROLES = (() => {
26
+ const definitions = ADVISOR_PLAN_CONTRACT.definitions;
27
+ const roles = definitions?.hubOnlyRoles?.const;
28
+ if (!Array.isArray(roles) || roles.some((role) => typeof role !== "string")) {
29
+ throw new Error("the packed plan contract has no well-formed definitions.hubOnlyRoles");
30
+ }
31
+ return Object.freeze([...roles]);
32
+ })();
33
+ /**
34
+ * The position of every item whose key an earlier item already had, with the
35
+ * position of the first item that had it. Items keep their order.
36
+ */
37
+ function repeats(keys) {
38
+ const seenAt = new Map();
39
+ const found = [];
40
+ keys.forEach((key, index) => {
41
+ const first = seenAt.get(key);
42
+ if (first === undefined)
43
+ seenAt.set(key, index);
44
+ else
45
+ found.push({ index, first });
46
+ });
47
+ return found;
48
+ }
49
+ /**
50
+ * A plan's own member, or undefined. The schema checker sees only own
51
+ * members, so these rules read only those too: a member inherited from a
52
+ * prototype is ignored, never judged.
53
+ */
54
+ function ownMember(document, name) {
55
+ return Object.hasOwn(document, name) ? document[name] : undefined;
56
+ }
57
+ /** Every violation of R1-R12, for a plan that already passed the plan contract's schema. */
58
+ export function planRuleViolations(plan) {
59
+ const found = [];
60
+ const report = (rule, path, message) => {
61
+ found.push({ rule, path, message });
62
+ };
63
+ const staffing = ownMember(plan, "staffing");
64
+ const acts = ownMember(plan, "packages");
65
+ const kits = ownMember(plan, "kits");
66
+ const mandateRoles = plan.mandate.roles;
67
+ const lower = (text) => text.toLowerCase();
68
+ if (staffing !== undefined) {
69
+ // R1: one staffing entry per repository; ids compare case-insensitively.
70
+ for (const { index, first } of repeats(staffing.map((entry) => lower(entry.repository)))) {
71
+ report("R1", `staffing[${index}].repository`, `names the same repository as staffing[${first}].repository (repository ids compare case-insensitively)`);
72
+ }
73
+ // R2: staffed roles and mandate roles agree in both directions; a hub-only role is never required to be staffed.
74
+ const mandated = new Set(mandateRoles);
75
+ const staffed = new Set(staffing.flatMap((entry) => entry.roles));
76
+ staffing.forEach((entry, index) => {
77
+ entry.roles.forEach((role, position) => {
78
+ if (!mandated.has(role))
79
+ report("R2", `staffing[${index}].roles[${position}]`, "is not one of mandate.roles");
80
+ });
81
+ });
82
+ mandateRoles.forEach((role, position) => {
83
+ if (!staffed.has(role) && !HUB_ONLY_ROLES.includes(role))
84
+ report("R2", `mandate.roles[${position}]`, "is not staffed in any staffing entry");
85
+ });
86
+ staffing.forEach((entry, index) => {
87
+ // R8: no role twice within one staffing entry.
88
+ for (const { index: position, first } of repeats(entry.roles)) {
89
+ report("R8", `staffing[${index}].roles[${position}]`, `repeats staffing[${index}].roles[${first}]`);
90
+ }
91
+ // R11: a hub-only role is never staffed in a repository.
92
+ entry.roles.forEach((role, position) => {
93
+ if (HUB_ONLY_ROLES.includes(role))
94
+ report("R11", `staffing[${index}].roles[${position}]`, "is a hub-only role, which works from the hub and is never staffed in a repository");
95
+ });
96
+ });
97
+ }
98
+ if (acts !== undefined) {
99
+ // R3: every act names a staffed repository, spelled exactly the same.
100
+ const staffedRepositories = new Set((staffing ?? []).map((entry) => entry.repository));
101
+ acts.forEach((act, index) => {
102
+ if (!staffedRepositories.has(act.repository))
103
+ report("R3", `packages[${index}].repository`, "is not spelled exactly as any staffing[].repository");
104
+ });
105
+ // R4: planItem ids are unique.
106
+ for (const { index, first } of repeats(acts.map((act) => act.planItem))) {
107
+ report("R4", `packages[${index}].planItem`, `repeats packages[${first}].planItem`);
108
+ }
109
+ // R5: one act per (repository, name); repositories compare case-insensitively.
110
+ for (const { index, first } of repeats(acts.map((act) => JSON.stringify([lower(act.repository), act.name])))) {
111
+ report("R5", `packages[${index}].name`, `repeats the repository and name of packages[${first}] (repositories compare case-insensitively)`);
112
+ }
113
+ // R12: every planItem is exactly its act's repository, a colon and its name, in the same letter case.
114
+ acts.forEach((act, index) => {
115
+ if (act.planItem !== `${act.repository}:${act.name}`)
116
+ report("R12", `packages[${index}].planItem`, "is not this act's repository, a colon and its name, in the same letter case");
117
+ });
118
+ // R10: at most one pin-starter act per repository (compared case-insensitively), and it is a devDependency.
119
+ const pinAt = acts.flatMap((act, index) => (act.act === "pin-starter" ? [index] : []));
120
+ for (const { index, first } of repeats(pinAt.map((position) => lower(acts[position].repository)))) {
121
+ report("R10", `packages[${pinAt[index]}].act`, `is a second act of this kind for the repository of packages[${pinAt[first]}] (repositories compare case-insensitively)`);
122
+ }
123
+ for (const position of pinAt) {
124
+ if (acts[position].placement !== "devDependencies")
125
+ report("R10", `packages[${position}].placement`, "must be devDependencies for a pin-starter act");
126
+ }
127
+ }
128
+ // R6: resolution is present exactly when packages is.
129
+ const hasPackages = Object.hasOwn(plan, "packages");
130
+ const hasResolution = Object.hasOwn(plan, "resolution");
131
+ if (hasPackages && !hasResolution)
132
+ report("R6", "resolution", "is required when packages is present");
133
+ if (!hasPackages && hasResolution)
134
+ report("R6", "resolution", "must be absent when there are no packages");
135
+ // R7: kit ids are unique.
136
+ for (const { index, first } of repeats((kits ?? []).map((kit) => kit.id))) {
137
+ report("R7", `kits[${index}].id`, `repeats kits[${first}].id`);
138
+ }
139
+ // R9: no role twice in mandate.roles.
140
+ for (const { index, first } of repeats(mandateRoles)) {
141
+ report("R9", `mandate.roles[${index}]`, `repeats mandate.roles[${first}]`);
142
+ }
143
+ return found;
144
+ }
145
+ //# sourceMappingURL=plan-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-rules.js","sourceRoot":"","sources":["../src/plan-rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Ensures the registry file `writer-check` reads is the same store a surface
3
+ * passes to `createCopyResolver` at render — never a second, request-scoped
4
+ * module the CLI does not scan.
5
+ */
6
+ import type { CopyRegistry } from "./types.js";
7
+ export type RenderRegistryParityReason = "render-registry-path-mismatch" | "record-not-copy-registry";
8
+ export interface RenderRegistryParityResult {
9
+ ok: boolean;
10
+ reason?: RenderRegistryParityReason;
11
+ detail?: string;
12
+ registry?: CopyRegistry;
13
+ }
14
+ /**
15
+ * Confirms `recordFile` is a `CopyRegistry` and, when `renderRegistryFile`
16
+ * is supplied, that both paths resolve to the same file (the render store
17
+ * and the gate store must be one file).
18
+ */
19
+ export declare function checkRenderRegistryParity(recordFile: string, recordValue: unknown, renderRegistryFile?: string): RenderRegistryParityResult;
20
+ //# sourceMappingURL=render-registry-parity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-registry-parity.d.ts","sourceRoot":"","sources":["../src/render-registry-parity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,MAAM,0BAA0B,GAClC,+BAA+B,GAC/B,0BAA0B,CAAC;AAE/B,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,0BAA0B,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,EACpB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,0BAA0B,CAyB5B"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Ensures the registry file `writer-check` reads is the same store a surface
3
+ * passes to `createCopyResolver` at render — never a second, request-scoped
4
+ * module the CLI does not scan.
5
+ */
6
+ import { realpathSync } from "node:fs";
7
+ import { resolve } from "node:path";
8
+ import { validateCopyRegistryShape } from "./schema.js";
9
+ /**
10
+ * Confirms `recordFile` is a `CopyRegistry` and, when `renderRegistryFile`
11
+ * is supplied, that both paths resolve to the same file (the render store
12
+ * and the gate store must be one file).
13
+ */
14
+ export function checkRenderRegistryParity(recordFile, recordValue, renderRegistryFile) {
15
+ const registryFindings = validateCopyRegistryShape(recordValue);
16
+ if (registryFindings.length > 0) {
17
+ const detail = registryFindings.map((f) => f.message).join("; ");
18
+ return {
19
+ ok: false,
20
+ reason: "record-not-copy-registry",
21
+ detail: `record-file is not a CopyRegistry (the store createCopyResolver reads): ${detail}`,
22
+ };
23
+ }
24
+ if (renderRegistryFile !== undefined) {
25
+ const recordReal = safeRealpath(resolve(recordFile));
26
+ const renderReal = safeRealpath(resolve(renderRegistryFile));
27
+ if (recordReal !== renderReal) {
28
+ return {
29
+ ok: false,
30
+ reason: "render-registry-path-mismatch",
31
+ detail: "record-file and --render-registry must be the same file — a second approved store the CLI does not read is not an approved registry.",
32
+ };
33
+ }
34
+ }
35
+ return { ok: true, registry: recordValue };
36
+ }
37
+ function safeRealpath(path) {
38
+ try {
39
+ return realpathSync(path);
40
+ }
41
+ catch {
42
+ return path;
43
+ }
44
+ }
45
+ //# sourceMappingURL=render-registry-parity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-registry-parity.js","sourceRoot":"","sources":["../src/render-registry-parity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAcxD;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAkB,EAClB,WAAoB,EACpB,kBAA2B;IAE3B,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,WAAW,CAAC,CAAC;IAChE,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjE,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,0BAA0B;YAClC,MAAM,EAAE,2EAA2E,MAAM,EAAE;SAC5F,CAAC;IACJ,CAAC;IAED,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QACrD,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAC7D,IAAI,UAAU,KAAK,UAAU,EAAE,CAAC;YAC9B,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,+BAA+B;gBACvC,MAAM,EACJ,sIAAsI;aACzI,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAA2B,EAAE,CAAC;AAC7D,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}