@1aboveio/skills 0.20.1 → 0.20.3

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 (94) hide show
  1. package/README.md +12 -5
  2. package/package.json +1 -1
  3. package/runtime/skills/distribution/generated/recipes.json +220 -25
  4. package/runtime/skills/distribution/scripts/bundles.mjs +49 -5
  5. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -0
  6. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
  7. package/skills/cicd-pipeline/cloud-build/SKILL.md +6 -6
  8. package/skills/compliance/compliance-audit/LICENSE +3 -0
  9. package/skills/compliance/compliance-audit/SKILL.md +466 -0
  10. package/skills/compliance/compliance-audit/references/findings-schema.md +290 -0
  11. package/skills/compliance/compliance-audit/references/vars-checklist.md +1068 -0
  12. package/skills/compliance/compliance-audit/references/vars-findings-schema.md +395 -0
  13. package/skills/compliance/compliance-audit/scripts/reconcile_tracker.py +454 -0
  14. package/skills/compliance/compliance-audit/scripts/test_validate_tracker.py +90 -0
  15. package/skills/compliance/compliance-audit/scripts/validate_tracker.py +752 -0
  16. package/skills/compliance/doc-authenticity/LICENSE +3 -0
  17. package/skills/compliance/doc-authenticity/SKILL.md +158 -0
  18. package/skills/compliance/doc-authenticity/references/agreement.md +66 -0
  19. package/skills/compliance/doc-authenticity/references/bank-statement.md +150 -0
  20. package/skills/compliance/doc-authenticity/references/forensic-signals.md +157 -0
  21. package/skills/compliance/doc-authenticity/references/image-signals.md +114 -0
  22. package/skills/compliance/doc-authenticity/references/invoice.md +66 -0
  23. package/skills/compliance/doc-authenticity/references/issuer-profiles.md +86 -0
  24. package/skills/compliance/doc-authenticity/references/verdict-and-report.md +95 -0
  25. package/skills/compliance/doc-authenticity/references/verdict.schema.json +81 -0
  26. package/skills/compliance/doc-authenticity/scripts/image_forensics.py +294 -0
  27. package/skills/compliance/doc-authenticity/scripts/pdf_forensics.py +401 -0
  28. package/skills/compliance/doc-authenticity/scripts/validate_codes.py +224 -0
  29. package/skills/compliance/doc-authenticity/scripts/validate_verdict.py +308 -0
  30. package/skills/compliance/report-writing/LICENSE +3 -0
  31. package/skills/compliance/report-writing/SKILL.md +206 -0
  32. package/skills/compliance/report-writing/references/audit-report-template.md +121 -0
  33. package/skills/compliance/report-writing/references/external-assessment-template.md +167 -0
  34. package/skills/compliance/report-writing/references/management-report-template.md +145 -0
  35. package/skills/compliance/report-writing/references/vars-report-template.md +224 -0
  36. package/skills/document-utils/doc-to-md/LICENSE +3 -0
  37. package/skills/document-utils/doc-to-md/SKILL.md +77 -0
  38. package/skills/document-utils/doc-to-md/scripts/convert.py +157 -0
  39. package/skills/document-utils/reg-parser/LICENSE +3 -0
  40. package/skills/document-utils/reg-parser/SKILL.md +201 -0
  41. package/skills/document-utils/reg-parser/references/checklist-schema.md +223 -0
  42. package/skills/document-utils/reg-parser/references/checklists/hk-amlo-checklist.json +1306 -0
  43. package/skills/document-utils/reg-parser/references/checklists/hk-amlo-checklist.md +469 -0
  44. package/skills/document-utils/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.json +634 -0
  45. package/skills/document-utils/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.md +233 -0
  46. package/skills/document-utils/reg-parser/references/checklists/hk-mso-guideline-checklist.json +2194 -0
  47. package/skills/document-utils/reg-parser/references/checklists/hk-mso-guideline-checklist.md +771 -0
  48. package/skills/document-utils/reg-parser/references/checklists/kyc-aml-checklist.md +258 -0
  49. package/skills/document-utils/reg-parser/references/checklists/visa-vars-checklist.md +1058 -0
  50. package/skills/document-utils/reg-parser/references/mandates/hk-amlo-cap615.md +389 -0
  51. package/skills/document-utils/reg-parser/references/mandates/visa-vars.md +205 -0
  52. package/skills/document-utils/reg-parser/scripts/compare_checklist.py +228 -0
  53. package/skills/document-utils/reg-parser/scripts/dump_checklist.py +348 -0
  54. package/skills/document-utils/reg-parser/scripts/preprocess-mandate.sh +171 -0
  55. package/skills/document-utils/reg-parser/scripts/test_quarantine.sh +102 -0
  56. package/skills/document-utils/reg-parser/scripts/validate_checklist.py +532 -0
  57. package/skills/document-utils/reg-parser/scripts/validate_mandate.py +242 -0
  58. package/skills/engineering/engineering-runtime/coherence/workflow.json +17 -17
  59. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -0
  60. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
  61. package/skills/engineering/rush-release/SKILL.md +46 -25
  62. package/skills/engineering/rush-release/references/cut.md +21 -4
  63. package/skills/engineering/rush-release/references/preflight.md +25 -6
  64. package/skills/engineering/rush-release/references/promotion.md +70 -0
  65. package/skills/engineering/rush-release/references/publish.md +49 -16
  66. package/skills/engineering/rush-release/scripts/plan.mjs +33 -7
  67. package/skills/engineering/smoke/SKILL.md +4 -4
  68. package/skills/engineering/smoke/references/manifest.md +3 -3
  69. package/skills/payment/similar-domain/LICENSE +3 -0
  70. package/skills/payment/similar-domain/SKILL.md +178 -0
  71. package/skills/payment/similar-domain/references/entities.md +58 -0
  72. package/skills/payment/similar-domain/references/fingerprints.md +82 -0
  73. package/skills/payment/similar-domain/references/pivots.md +66 -0
  74. package/skills/payment/similar-domain/references/report-template.md +76 -0
  75. package/skills/payment/similar-domain/references/scoring.md +61 -0
  76. package/skills/payment/similar-domain/references/terminology.md +37 -0
  77. package/skills/payment/similar-domain/references/workflow.md +79 -0
  78. package/skills/payment/tld-detection/SKILL.md +76 -21
  79. package/skills/payment/tld-detection/references/clean.md +1 -1
  80. package/skills/payment/tld-detection/references/clustering.md +21 -6
  81. package/skills/payment/tld-detection/references/decision.md +7 -2
  82. package/skills/payment/tld-detection/references/fx-conversion.md +229 -0
  83. package/skills/payment/tld-detection/references/report-template.md +63 -27
  84. package/skills/payment/tld-detection/references/streams.md +90 -0
  85. package/skills/payment/tld-detection/references/terminology.md +15 -7
  86. package/skills/payment/tld-detection/references/workflow.md +1 -1
  87. package/skills/payment/tld-detection/scripts/detect_streams.py +542 -0
  88. package/skills/engineering/ensure-coverage/evals/evals.json +0 -125
  89. package/skills/engineering/rush-issues/evals/evals.json +0 -65
  90. package/skills/engineering/rush-release/evals/evals.json +0 -44
  91. package/skills/fullstack/shadcn/evals/evals.json +0 -90
  92. package/skills/payment/fraud-analysis/evals/evals.json +0 -40
  93. package/skills/payment/tld-detection/evals/evals.json +0 -107
  94. package/skills/payment/tld-detection/tests/test_detect_ladders.py +0 -132
@@ -0,0 +1,242 @@
1
+ #!/usr/bin/env python3
2
+ """Validate a mandate (Mode A — Clause Annotation Extract) Markdown file.
3
+
4
+ Catches the failure modes specific to mandate extracts produced by the
5
+ `reg-parser` skill:
6
+
7
+ - Agent left the raw template scaffolding behind (Status: RAW, HTML
8
+ comment placeholders, the embedded raw-text fenced block).
9
+ - One of the four canonical sections is missing or silently empty.
10
+ - Header metadata (Source attribution, jurisdiction/version/date) is
11
+ missing.
12
+ - Notes section is empty or stub.
13
+
14
+ Optional --source <converted-md> enables citation-existence warnings:
15
+ each `§<ref>` cited in the extract is fuzzy-matched against the source
16
+ markdown. Missing citations emit warnings, not errors (refs are often
17
+ restyled during extraction).
18
+
19
+ Usage:
20
+ python3 validate_mandate.py <mandate.md> [--source <converted-md>]
21
+
22
+ Exit code 0 = valid. Non-zero = errors found.
23
+ """
24
+
25
+ import argparse
26
+ import re
27
+ import sys
28
+ import os
29
+
30
+ REQUIRED_SECTIONS = [
31
+ "Mandatory Downstream Agreement Clauses",
32
+ "Prohibited Conduct",
33
+ "Thresholds & Triggers",
34
+ "Audit & Oversight Rights",
35
+ "Notes",
36
+ ]
37
+
38
+ # Markers an agent may use to indicate a section legitimately has no entries.
39
+ EMPTY_MARKERS = ("_none_", "(none)", "n/a", "not applicable", "none.")
40
+
41
+ # Header metadata keywords — at least one must appear in the header block
42
+ # (between H1 and the first H2). Matches the conventions in the existing
43
+ # extracts (visa-vars.md, hk-amlo-cap615.md).
44
+ HEADER_KEYWORDS = ("source", "jurisdiction", "version", "effective", "updated", "date")
45
+
46
+ # Patterns that indicate the agent left raw template artifacts behind.
47
+ RAW_STATUS_RE = re.compile(r"^\s*>\s*\*?\*?Status:\*?\*?\s*RAW", re.IGNORECASE)
48
+ RAW_TEXT_HEADING_RE = re.compile(r"^##\s+Raw Text\b", re.IGNORECASE)
49
+ SCAFFOLDING_COMMENT_RES = [
50
+ re.compile(r"<!--\s*Agent:\s*replace", re.IGNORECASE),
51
+ re.compile(r"<!--\s*Format:\s*\*\*§\[ref\]"),
52
+ re.compile(r"<!--\s*Clauses the counterparty"),
53
+ re.compile(r"<!--\s*Explicitly prohibited"),
54
+ re.compile(r"<!--\s*Numeric thresholds"),
55
+ re.compile(r"<!--\s*Rights granted"),
56
+ re.compile(r"<!--\s*Jurisdiction scope, effective date"),
57
+ ]
58
+
59
+ # A §-style citation. Captures common forms: §AACQ.C2.1, §76E,
60
+ # §Sched.2 §2(1)(a), § 14(3)(b). The capturing group keeps just the
61
+ # alphanumeric/punctuation token; the leading § is consumed.
62
+ CITATION_RE = re.compile(r"§\s*([A-Za-z0-9][A-Za-z0-9.\-]*(?:\([^)]+\))*)")
63
+
64
+ H1_RE = re.compile(r"^#\s+(.+?)\s*$")
65
+ H2_RE = re.compile(r"^##\s+(.+?)\s*$")
66
+
67
+
68
+ def split_sections(lines: list[str]) -> tuple[list[str], dict[str, list[str]]]:
69
+ """Return (header_lines, {section_title: body_lines})."""
70
+ header: list[str] = []
71
+ sections: dict[str, list[str]] = {}
72
+ current: str | None = None
73
+ seen_h1 = False
74
+
75
+ for line in lines:
76
+ if not seen_h1 and H1_RE.match(line):
77
+ seen_h1 = True
78
+ continue
79
+ h2 = H2_RE.match(line)
80
+ if h2:
81
+ current = h2.group(1).strip()
82
+ sections.setdefault(current, [])
83
+ continue
84
+ if current is None:
85
+ header.append(line)
86
+ else:
87
+ sections[current].append(line)
88
+
89
+ return header, sections
90
+
91
+
92
+ def section_is_empty(body: list[str]) -> bool:
93
+ """A section is empty if it has no §-bullet entries AND no explicit
94
+ 'none' marker."""
95
+ text = "\n".join(body).strip()
96
+ if not text:
97
+ return True
98
+ lower = text.lower()
99
+ if any(marker in lower for marker in EMPTY_MARKERS):
100
+ return False
101
+ if "**§" in text or re.search(r"^\s*§", text, re.MULTILINE):
102
+ return False
103
+ if "§" in text and re.search(r"§\s*[A-Za-z0-9]", text):
104
+ return False
105
+ return True
106
+
107
+
108
+ def extract_citations(text: str) -> set[str]:
109
+ """Pull §-style citation tokens out of arbitrary text."""
110
+ return {m.group(1) for m in CITATION_RE.finditer(text)}
111
+
112
+
113
+ def fuzzy_present(token: str, haystack_lower: str) -> bool:
114
+ """Best-effort: token appears in source if either the literal token
115
+ or a heavily-normalized form (lowercased, punctuation stripped) does.
116
+ """
117
+ if token.lower() in haystack_lower:
118
+ return True
119
+ norm = re.sub(r"[^a-z0-9]", "", token.lower())
120
+ if not norm:
121
+ return False
122
+ norm_haystack = re.sub(r"[^a-z0-9]", "", haystack_lower)
123
+ return norm in norm_haystack
124
+
125
+
126
+ def validate(filepath: str, source_path: str | None) -> tuple[list[str], list[str]]:
127
+ """Return (errors, warnings)."""
128
+ errors: list[str] = []
129
+ warnings: list[str] = []
130
+
131
+ if not os.path.isfile(filepath):
132
+ return [f"File not found: {filepath}"], []
133
+
134
+ with open(filepath, "r", encoding="utf-8") as f:
135
+ raw = f.read()
136
+ lines = raw.splitlines()
137
+
138
+ # --- Raw template artifacts ---
139
+ for line_num, line in enumerate(lines, 1):
140
+ if RAW_STATUS_RE.match(line):
141
+ errors.append(
142
+ f"Line {line_num}: 'Status: RAW' marker still present — "
143
+ f"agent extraction not completed"
144
+ )
145
+ if RAW_TEXT_HEADING_RE.match(line):
146
+ errors.append(
147
+ f"Line {line_num}: '## Raw Text' section still present — "
148
+ f"remove the embedded raw-text dump after extraction"
149
+ )
150
+ for pat in SCAFFOLDING_COMMENT_RES:
151
+ if pat.search(line):
152
+ errors.append(
153
+ f"Line {line_num}: leftover template scaffolding comment"
154
+ )
155
+ break
156
+
157
+ # --- Structure ---
158
+ header_lines, sections = split_sections(lines)
159
+
160
+ if not any(H1_RE.match(line) for line in lines):
161
+ errors.append("Missing H1 title (expected '# <Source> — Contract Obligation Extract')")
162
+
163
+ # Header metadata: at least one of Source/Jurisdiction/Version/etc.
164
+ header_text = "\n".join(header_lines).lower()
165
+ if not any(kw in header_text for kw in HEADER_KEYWORDS):
166
+ errors.append(
167
+ "Header metadata block missing — expected blockquote with "
168
+ "Source / Jurisdiction / Version / Effective Date"
169
+ )
170
+
171
+ # The Source attribution specifically is critical.
172
+ if "source" not in header_text:
173
+ errors.append("Header missing 'Source:' attribution")
174
+
175
+ # Required sections present
176
+ for required in REQUIRED_SECTIONS:
177
+ if required not in sections:
178
+ errors.append(f"Missing required section: ## {required}")
179
+
180
+ # Required content sections non-empty
181
+ for required in REQUIRED_SECTIONS[:-1]: # everything except Notes
182
+ body = sections.get(required)
183
+ if body is not None and section_is_empty(body):
184
+ errors.append(
185
+ f"Section '## {required}' is empty — if there are no "
186
+ f"items, mark explicitly as '_None_'"
187
+ )
188
+
189
+ # Notes substance check
190
+ notes_body = sections.get("Notes")
191
+ if notes_body is not None:
192
+ notes_text = "\n".join(notes_body).strip()
193
+ if len(notes_text) < 50:
194
+ errors.append(
195
+ "Section '## Notes' is too short — include jurisdiction "
196
+ "scope, effective date, version, and caveats"
197
+ )
198
+
199
+ # --- Optional: citation existence check ---
200
+ if source_path:
201
+ if not os.path.isfile(source_path):
202
+ warnings.append(f"--source file not found: {source_path}")
203
+ else:
204
+ with open(source_path, "r", encoding="utf-8") as sf:
205
+ source_lower = sf.read().lower()
206
+ cites = extract_citations(raw)
207
+ missing = sorted(c for c in cites if not fuzzy_present(c, source_lower))
208
+ if missing:
209
+ preview = ", ".join(f"§{c}" for c in missing[:8])
210
+ more = "" if len(missing) <= 8 else f" (+{len(missing) - 8} more)"
211
+ warnings.append(
212
+ f"{len(missing)} citation(s) not found in source: {preview}{more}"
213
+ )
214
+
215
+ return errors, warnings
216
+
217
+
218
+ def main() -> None:
219
+ p = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
220
+ p.add_argument("filepath", help="Path to mandate Markdown file")
221
+ p.add_argument(
222
+ "--source",
223
+ help="Optional path to the converted source Markdown for citation checks",
224
+ )
225
+ args = p.parse_args()
226
+
227
+ errors, warnings = validate(args.filepath, args.source)
228
+
229
+ for w in warnings:
230
+ print(f" ⚠️ {w}", file=sys.stderr)
231
+
232
+ if errors:
233
+ print(f"❌ Validation failed for {args.filepath}:", file=sys.stderr)
234
+ for err in errors:
235
+ print(f" • {err}", file=sys.stderr)
236
+ sys.exit(1)
237
+ print(f"✅ {args.filepath} is valid.")
238
+ sys.exit(0)
239
+
240
+
241
+ if __name__ == "__main__":
242
+ main()
@@ -342,7 +342,7 @@
342
342
  "id": "first-party",
343
343
  "type": "first-party",
344
344
  "package": "@1aboveio/skills",
345
- "version": "0.20.1"
345
+ "version": "0.20.3"
346
346
  },
347
347
  "contentDigest": "eff6c7b5931bce5b2265a619bccddd371a89df6ce7bc2edc74f11d00060a71dd",
348
348
  "digestExcludes": []
@@ -355,7 +355,7 @@
355
355
  "id": "first-party",
356
356
  "type": "first-party",
357
357
  "package": "@1aboveio/skills",
358
- "version": "0.20.1"
358
+ "version": "0.20.3"
359
359
  },
360
360
  "contentDigest": "d97abeff7bdc5ae2e4be2f631d09dba46d4753ce1e67334793364329af59f066",
361
361
  "digestExcludes": []
@@ -368,9 +368,9 @@
368
368
  "id": "first-party",
369
369
  "type": "first-party",
370
370
  "package": "@1aboveio/skills",
371
- "version": "0.20.1"
371
+ "version": "0.20.3"
372
372
  },
373
- "contentDigest": "00cfdd3e5bfbc3e37b1369ad93aae91161e671829760a8867ea9be25047ba461",
373
+ "contentDigest": "fe2ec3bae2bfec2dbef19db30ab0272391d7c1d9b6893341a76a9f339adefc57",
374
374
  "digestExcludes": []
375
375
  },
376
376
  {
@@ -381,7 +381,7 @@
381
381
  "id": "first-party",
382
382
  "type": "first-party",
383
383
  "package": "@1aboveio/skills",
384
- "version": "0.20.1"
384
+ "version": "0.20.3"
385
385
  },
386
386
  "contentDigest": "58b0556228a9271cf9e33727a05fc08a4fdfd29512ec0936b169f0a55d60e6ef",
387
387
  "digestExcludes": []
@@ -394,9 +394,9 @@
394
394
  "id": "first-party",
395
395
  "type": "first-party",
396
396
  "package": "@1aboveio/skills",
397
- "version": "0.20.1"
397
+ "version": "0.20.3"
398
398
  },
399
- "contentDigest": "4664873230f22de2fcf46b7b529570cfedabdc850620031d8f96baf89fcdc5b4",
399
+ "contentDigest": "d28dd4d3c4394df0cc7e6b48d0e5daa7d2277701ea459e39fba99acf1d8ff670",
400
400
  "digestExcludes": []
401
401
  },
402
402
  {
@@ -407,9 +407,9 @@
407
407
  "id": "first-party",
408
408
  "type": "first-party",
409
409
  "package": "@1aboveio/skills",
410
- "version": "0.20.1"
410
+ "version": "0.20.3"
411
411
  },
412
- "contentDigest": "01c192d8b4fd416af4ea02e8000e5fce0cee723a6ac2f8c0c48372087e1a262e",
412
+ "contentDigest": "56fb5843788c9073b0d5a65ffa72bd7d2fa80dc6a1ff06fb0e19fab513c51502",
413
413
  "digestExcludes": []
414
414
  },
415
415
  {
@@ -420,7 +420,7 @@
420
420
  "id": "first-party",
421
421
  "type": "first-party",
422
422
  "package": "@1aboveio/skills",
423
- "version": "0.20.1"
423
+ "version": "0.20.3"
424
424
  },
425
425
  "contentDigest": "f048fd00c69f2dc666fc7a3096cfeee6dfba73933bfb69602f3f0e26159798cc",
426
426
  "digestExcludes": []
@@ -433,9 +433,9 @@
433
433
  "id": "first-party",
434
434
  "type": "first-party",
435
435
  "package": "@1aboveio/skills",
436
- "version": "0.20.1"
436
+ "version": "0.20.3"
437
437
  },
438
- "contentDigest": "27861f6dac89c32a97a7d249ce2695cea2d3d80dd2e9bc0607b0c4048a0e3b25",
438
+ "contentDigest": "d533684db4483cfc90be2aa7161980b6548057ef18a4b54f0cdbcd53c79dd46d",
439
439
  "digestExcludes": []
440
440
  },
441
441
  {
@@ -446,15 +446,15 @@
446
446
  "id": "first-party",
447
447
  "type": "first-party",
448
448
  "package": "@1aboveio/skills",
449
- "version": "0.20.1"
449
+ "version": "0.20.3"
450
450
  },
451
- "contentDigest": "3e0952beee7078463464872943d414fa944b395ae723ec78b385a28a3548897a",
451
+ "contentDigest": "aa7b7dbeec2fd5d64883f4b6bf5ae99a3f77cad84f635cfbdf7cb1999de362e6",
452
452
  "digestExcludes": [
453
453
  "coherence/workflow.json"
454
454
  ]
455
455
  }
456
456
  ],
457
- "releaseIdentity": "baec385a2bc0414623c97a83ac4ebf3c44ede2654185b748a03ef955cb3f1c8d",
457
+ "releaseIdentity": "4804a31efab8c7a93325ebdfeee74ce04c89130470d4eb5a878b37ac183266cd",
458
458
  "lifecycleAuthority": "native-skills-cli",
459
459
  "repairRecipe": {
460
460
  "id": "engineering-workflow-dependency-first",
@@ -512,7 +512,7 @@
512
512
  "sourceId": "first-party",
513
513
  "sourceType": "first-party",
514
514
  "package": "@1aboveio/skills",
515
- "version": "0.20.1",
515
+ "version": "0.20.3",
516
516
  "installPath": null,
517
517
  "members": [
518
518
  "harness-runtime",
@@ -528,7 +528,7 @@
528
528
  "commands": [
529
529
  {
530
530
  "transport": "npm",
531
- "command": "npx @1aboveio/skills@0.20.1 install --group engineering-workflow --yes"
531
+ "command": "npx @1aboveio/skills@0.20.3 install --group engineering-workflow --yes"
532
532
  }
533
533
  ],
534
534
  "onFailure": {
@@ -154,6 +154,10 @@ const TEST_FIXTURE = /\.fixtures?\.[^.]+$/;
154
154
  export function publishedContentExcluded(name) {
155
155
  return name.startsWith('.')
156
156
  || name === 'node_modules'
157
+ || name === '__pycache__'
158
+ || name === 'evals'
159
+ || name === 'samples'
160
+ || name === 'tests'
157
161
  || name.endsWith('-workspace')
158
162
  || name.endsWith('.test.mjs')
159
163
  || TEST_FIXTURE.test(name);
@@ -86,7 +86,7 @@ export const WORKFLOW_TRUSTED_SOURCES = deepFreeze({
86
86
  id: 'first-party',
87
87
  type: 'first-party',
88
88
  package: '@1aboveio/skills',
89
- version: '0.20.1',
89
+ version: '0.20.3',
90
90
  },
91
91
  matt: {
92
92
  id: 'matt-pocock',
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: rush-release
3
- description: "Slash/explicit-only (/rush-release). Cut a GitHub Flow release from main: freeze the latest CI-green trunk SHA, write the changelog, choose SemVer, merge the metadata cut through a verified PR, tag the exact merged main SHA, and watch Cloud Build or npm publish. Do not auto-select. Use only on explicit user/orchestrator invoke. NOT for GitFlow/release-branch/0%-traffic promotion (resolve-release) and NOT for implementing a spec (rush-issues)."
3
+ description: "Slash/explicit-only (/rush-release). Cut a GitHub Flow release from main: freeze the latest CI-green trunk SHA, write the changelog, choose SemVer, merge the metadata cut through a verified PR, publish npm artifacts, or validate a Cloud Run candidate at 0% before shifting it to 100%. One complete-plan confirmation covers the conditional release. Do not auto-select. Use only on explicit user/orchestrator invoke. NOT for GitFlow/release-branch promotion and NOT for implementing a spec (rush-issues)."
4
4
  disable-model-invocation: true
5
5
  ---
6
6
 
@@ -10,9 +10,10 @@ Cut a **GitHub Flow** release from **main**. Freeze one already-green trunk
10
10
  SHA, write a metadata-only version cut on that parent, merge it through a
11
11
  verified PR, tag the exact merged SHA on `main`, and watch the publisher.
12
12
 
13
- The orchestrator sequences local programs and one confirmation. It does not
14
- assemble a release branch, shift traffic, or verify production like
15
- `resolve-release`.
13
+ The orchestrator sequences local programs and exactly one user confirmation per
14
+ release plan. It does not assemble a long-lived release branch. For Cloud Run,
15
+ it owns one bounded candidate-at-0% -> validate -> shift-to-100% -> verify-live
16
+ sequence; the confirmation conditionally authorizes that whole sequence.
16
17
 
17
18
  ```text
18
19
  preflight (main + publisher)
@@ -21,8 +22,9 @@ preflight (main + publisher)
21
22
  -> confirm
22
23
  -> bump version files + commit the cut
23
24
  -> merge metadata PR + verify merged main SHA
24
- -> annotated tag on the merged SHA
25
- -> push tag -> watch Cloud Build or npm
25
+ -> npm: final tag -> watch publish
26
+ -> Cloud Run: rc tag -> candidate at 0% -> validate -> shift to 100%
27
+ -> verify live -> final tag
26
28
  ```
27
29
 
28
30
  This file is the workflow and index. Read the linked procedure immediately
@@ -33,7 +35,8 @@ before its stage; do not invent an unlinked substitute.
33
35
  | Trunk, publisher, version files | [references/preflight.md](references/preflight.md) |
34
36
  | Latest CI-green HEAD | [references/candidate.md](references/candidate.md) |
35
37
  | Changelog, SemVer, file bump, commit | [references/cut.md](references/cut.md) |
36
- | Tag, push, watch deploy | [references/publish.md](references/publish.md) |
38
+ | Tag, push, watch publisher | [references/publish.md](references/publish.md) |
39
+ | Cloud Run 0% -> 100%, verification, rollback | [references/promotion.md](references/promotion.md) |
37
40
 
38
41
  Run every script as
39
42
  `node <skillsRoot>/rush-release/scripts/<name>.mjs …` with the absolute skill
@@ -54,8 +57,22 @@ target repo and will not find these files.
54
57
  release tree's CI evidence.
55
58
  - Tags are immutable annotated `vMAJOR.MINOR.PATCH` names. Do not move, delete,
56
59
  or force-push a tag that reached a remote.
57
- - Show the plan and wait for confirmation before any git mutation or push.
58
- - A failed watch is a hand-back. This lane does not roll back production.
60
+ - A Cloud Run release uses one immutable `vMAJOR.MINOR.PATCH-rc.N` tag to build
61
+ the candidate at 0%. The final tag is created only after that exact candidate
62
+ serves 100% and passes live verification; it must not trigger another deploy.
63
+ - Ask once, on the complete plan, before any git mutation or push. That answer
64
+ authorizes the listed branch/commit, metadata PR delivery, candidate build,
65
+ conditional traffic shift, rollback, final tag, optional GitHub Release, and
66
+ publisher watch as one operation. Do not ask separate cut, merge, RC,
67
+ exposure, tag, finalization, or publish questions.
68
+ - Preflight facts are detected, not confirmed by the user. Fold any genuinely
69
+ missing choice into the one plan question instead of asking a preliminary
70
+ question. If the plan's frozen SHA, version/tag, metadata diff, publisher, or
71
+ outward actions later change, stop and present one replacement plan; otherwise
72
+ continue without re-confirming.
73
+ - A pre-exposure failure is a hand-back with production untouched. A known
74
+ post-exposure failure automatically restores and verifies the recorded
75
+ incumbent. Ambiguous production state is a stop for operator recovery.
59
76
  - The cut is metadata only (changelog + version identity files). Refuse a
60
77
  cut that changes product code.
61
78
 
@@ -63,8 +80,8 @@ target repo and will not find these files.
63
80
 
64
81
  ### 1. Preflight
65
82
 
66
- Confirm `main` is the trunk, detect whether the tag should fire Cloud Build,
67
- npm, or both, and list the files that carry the version. Details:
83
+ Verify `main` is the trunk, detect npm and/or the staged Cloud Run contract,
84
+ and list the files that carry the version. Details:
68
85
  [preflight.md](references/preflight.md).
69
86
 
70
87
  ### 2. Candidate
@@ -72,28 +89,32 @@ npm, or both, and list the files that carry the version. Details:
72
89
  Fetch `origin/main` and pick the newest green SHA. Freeze it. Details:
73
90
  [candidate.md](references/candidate.md).
74
91
 
75
- ### 3. Plan and confirm
92
+ ### 3. Plan and confirm once
76
93
 
77
- Derive the changelog and SemVer bump from `baselineTag..frozenSHA`. Show SHA,
78
- bump, version, tag, files, publisher, and notes. Do not mutate until the human
79
- confirms. Details: [cut.md](references/cut.md).
94
+ Derive the changelog and SemVer bump from `baselineTag..frozenSHA`. For Cloud
95
+ Run, pass `--cloud-run` so the plan also reserves the next unused RC tag. Show
96
+ SHA, bump, version, tags, files, publisher, notes, and every outward action. Ask one
97
+ question that both settles any unresolved choice and authorizes the whole listed
98
+ sequence. Do not mutate until the human confirms, and do not ask again while the
99
+ approved plan remains unchanged. Details: [cut.md](references/cut.md).
80
100
 
81
101
  ### 4. Cut
82
102
 
83
103
  Branch from the frozen SHA, apply the changelog and version files, commit.
84
104
  Keep the diff metadata-only.
85
105
 
86
- ### 5. Merge, tag, and watch
106
+ ### 5. Merge and publish
87
107
 
88
- Push the cut ref, merge its PR through the repository queue, verify the exact
89
- merged SHA on `main`, create the annotated tag on that SHA, push
90
- `refs/tags/<tag>` with hook-safe `--no-verify`, then watch Cloud Build and/or
91
- npm. Details: [publish.md](references/publish.md).
108
+ Push the cut ref, merge its PR through the repository queue, and verify the
109
+ exact merged SHA on `main`. An artifact-only release pushes the final tag and
110
+ watches npm. A staged Cloud Run release pushes its RC tag, executes
111
+ [promotion.md](references/promotion.md), and creates the final tag only after
112
+ live verification. Details: [publish.md](references/publish.md).
92
113
 
93
114
  ## Done
94
115
 
95
- Success is the confirmed version tagged at the verified merged `main` SHA, the tag visible on the
96
- remote, and the chosen publisher reporting that version (Cloud Build SUCCESS
97
- and/or `npm view <pkg>@<version>`). Hand back the cut SHA, merged SHA, tag,
98
- changelog excerpt, publisher evidence, and the merged metadata PR. A publisher failure hands back the same identities without claiming
99
- the version shipped to users.
116
+ Success is the confirmed version tagged at the verified merged `main` SHA and
117
+ visible on the remote. npm must report the version when selected. Cloud Run
118
+ must report the exact candidate serving 100%, the incumbent at 0%, and an ALIVE
119
+ `prod-active` verdict. Hand back the cut SHA, merged SHA, RC/final tags,
120
+ changelog excerpt, publisher and traffic evidence, and the merged metadata PR.
@@ -8,10 +8,16 @@ along for the ride.
8
8
  ```bash
9
9
  node <skillsRoot>/rush-release/scripts/plan.mjs --sha <candidateSha> --json \
10
10
  > /tmp/rush-release-plan.json
11
+ # Add --cloud-run when preflight selected cloud-run-staged.
11
12
  ```
12
13
 
13
14
  The plan names `baselineTag`, `currentVersion`, `bump`, `reason`,
14
- `nextVersion`, `tag`, `changelogMarkdown`, and `versionFiles`.
15
+ `nextVersion`, final `tag`, optional `candidateTag`, `changelogMarkdown`, and
16
+ `versionFiles`.
17
+
18
+ Before showing the plan, use `git ls-remote --tags origin` to prove the proposed
19
+ candidate and final tags are both unused remotely. Local tag discovery chooses
20
+ the next RC ordinal; remote absence is the collision authority.
15
21
 
16
22
  SemVer (0.x treats breaking as minor unless the human asks for strict):
17
23
 
@@ -26,13 +32,24 @@ Changelog entries come from conventional-commit subjects in
26
32
  tag). Keep an existing `## [Unreleased]` body — derived entries merge with it,
27
33
  they do not replace it.
28
34
 
29
- ## 2. Confirm
35
+ ## 2. Confirm once
30
36
 
31
- Show the frozen SHA, proposed version/tag, bump reason, changelog, version
32
- files, and publisher. Wait for confirmation. A different bump the human names
37
+ Show the frozen SHA, proposed version/tag(s), bump reason, changelog, version
38
+ files, publisher/deployment mode, and the complete outward-action sequence: create the cut
39
+ branch/commit, push it, deliver its metadata PR through the queue, push the
40
+ immutable tag(s), validate and conditionally promote Cloud Run when applicable,
41
+ create a GitHub Release when required, and watch the publisher.
42
+ Ask exactly one question. Its answer both settles any displayed unresolved
43
+ choice and authorizes that entire sequence. A different bump the human names
33
44
  wins, as long as it is still SemVer.
34
45
 
35
46
  Do not create a branch, edit files, or tag before that confirmation.
47
+ After it, proceed through publication without asking separate cut, merge, RC,
48
+ exposure, tag, finalization, or publish questions. Repository/provider checks
49
+ are gates the orchestrator evaluates, not reasons to ask the human to confirm
50
+ facts. Ask again only by replacing the whole plan when its frozen SHA,
51
+ version/tag, metadata diff, publisher, or outward actions change. A retry or
52
+ resume of the unchanged plan inherits the original authorization.
36
53
 
37
54
  ## 3. Apply and commit
38
55
 
@@ -1,12 +1,15 @@
1
1
  # Preflight
2
2
 
3
- Preflight has three outputs: trunk `main`, the publisher to watch, and the
4
- files that carry the version. It does not pick the SHA, bump the version, or
5
- push.
3
+ Preflight outputs trunk `main`, publishers, deployment mode, release commands,
4
+ and the files that carry the version. It does not pick the SHA, bump the
5
+ version, or push. Resolve these facts from repository and provider state without asking the
6
+ human to confirm each one. If a required choice cannot be inferred, carry it
7
+ into the single complete-plan question in [cut.md](cut.md); do not create a
8
+ separate preflight confirmation.
6
9
 
7
10
  ## 1. Trunk
8
11
 
9
- Fetch `origin`. Confirm the release trunk is `main` from those fetched refs
12
+ Fetch `origin/main` and all remote tags. Verify the release trunk is `main` from those fetched refs
10
13
  (`origin/main` exists). A repo whose production branch is `master` or `release`
11
14
  is not this workflow.
12
15
 
@@ -17,12 +20,28 @@ otherwise look at the tree:
17
20
 
18
21
  | Signal | Publisher |
19
22
  |---|---|
20
- | `cloudbuild.yaml` / `cloudbuild.json`, or a Cloud Build trigger on `v*` / `v*-rc.*` tags | `cloudbuild` |
23
+ | Cloud Build production trigger matching only `v*-rc.*`, whose prod path emits immutable candidate coordinates after `--no-traffic` | `cloudbuild`, mode `cloud-run-staged` |
21
24
  | `package.json` with a publish workflow, `publishConfig`, or an explicit npm release | `npm` |
22
25
  | both | watch both |
23
26
  | neither, and the human did not name one | refuse — nothing to watch |
24
27
 
25
- Record `publisher` as `cloudbuild`, `npm`, or `both`. If a GitHub Actions
28
+ Cloud Build presence alone is not a staged contract. For `cloud-run-staged`,
29
+ verify from repository policy and live trigger configuration:
30
+
31
+ - the production trigger matches RC tags and excludes the final `vX.Y.Z` tag;
32
+ - each affected service deploys an immutable revision with `--no-traffic` and
33
+ publishes one receipt binding RC tag, merged SHA, revision, image digest, and
34
+ candidate URL;
35
+ - `smoke.manifest.json` defines read-only `prod-preview` and `prod-active`
36
+ profiles with at least one eligible path;
37
+ - exact inspect, traffic-shift, rollback, and candidate-delete commands are
38
+ documented, including service dependency order;
39
+ - any durable processing affected by a shift has exact pause, quiescence,
40
+ resume, and restoration checks.
41
+
42
+ Refuse staged release when any applicable item is absent; never improvise
43
+ production commands. Record `publisher` as `cloudbuild`, `npm`, or `both` and
44
+ `deploymentMode` as `artifact-only` or `cloud-run-staged`. If a GitHub Actions
26
45
  workflow publishes on `release: published` rather than on tag push, note that
27
46
  `gh release create` is required at publish time.
28
47