@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.
- package/README.md +12 -5
- package/package.json +1 -1
- package/runtime/skills/distribution/generated/recipes.json +220 -25
- package/runtime/skills/distribution/scripts/bundles.mjs +49 -5
- package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -0
- package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
- package/skills/cicd-pipeline/cloud-build/SKILL.md +6 -6
- package/skills/compliance/compliance-audit/LICENSE +3 -0
- package/skills/compliance/compliance-audit/SKILL.md +466 -0
- package/skills/compliance/compliance-audit/references/findings-schema.md +290 -0
- package/skills/compliance/compliance-audit/references/vars-checklist.md +1068 -0
- package/skills/compliance/compliance-audit/references/vars-findings-schema.md +395 -0
- package/skills/compliance/compliance-audit/scripts/reconcile_tracker.py +454 -0
- package/skills/compliance/compliance-audit/scripts/test_validate_tracker.py +90 -0
- package/skills/compliance/compliance-audit/scripts/validate_tracker.py +752 -0
- package/skills/compliance/doc-authenticity/LICENSE +3 -0
- package/skills/compliance/doc-authenticity/SKILL.md +158 -0
- package/skills/compliance/doc-authenticity/references/agreement.md +66 -0
- package/skills/compliance/doc-authenticity/references/bank-statement.md +150 -0
- package/skills/compliance/doc-authenticity/references/forensic-signals.md +157 -0
- package/skills/compliance/doc-authenticity/references/image-signals.md +114 -0
- package/skills/compliance/doc-authenticity/references/invoice.md +66 -0
- package/skills/compliance/doc-authenticity/references/issuer-profiles.md +86 -0
- package/skills/compliance/doc-authenticity/references/verdict-and-report.md +95 -0
- package/skills/compliance/doc-authenticity/references/verdict.schema.json +81 -0
- package/skills/compliance/doc-authenticity/scripts/image_forensics.py +294 -0
- package/skills/compliance/doc-authenticity/scripts/pdf_forensics.py +401 -0
- package/skills/compliance/doc-authenticity/scripts/validate_codes.py +224 -0
- package/skills/compliance/doc-authenticity/scripts/validate_verdict.py +308 -0
- package/skills/compliance/report-writing/LICENSE +3 -0
- package/skills/compliance/report-writing/SKILL.md +206 -0
- package/skills/compliance/report-writing/references/audit-report-template.md +121 -0
- package/skills/compliance/report-writing/references/external-assessment-template.md +167 -0
- package/skills/compliance/report-writing/references/management-report-template.md +145 -0
- package/skills/compliance/report-writing/references/vars-report-template.md +224 -0
- package/skills/document-utils/doc-to-md/LICENSE +3 -0
- package/skills/document-utils/doc-to-md/SKILL.md +77 -0
- package/skills/document-utils/doc-to-md/scripts/convert.py +157 -0
- package/skills/document-utils/reg-parser/LICENSE +3 -0
- package/skills/document-utils/reg-parser/SKILL.md +201 -0
- package/skills/document-utils/reg-parser/references/checklist-schema.md +223 -0
- package/skills/document-utils/reg-parser/references/checklists/hk-amlo-checklist.json +1306 -0
- package/skills/document-utils/reg-parser/references/checklists/hk-amlo-checklist.md +469 -0
- package/skills/document-utils/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.json +634 -0
- package/skills/document-utils/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.md +233 -0
- package/skills/document-utils/reg-parser/references/checklists/hk-mso-guideline-checklist.json +2194 -0
- package/skills/document-utils/reg-parser/references/checklists/hk-mso-guideline-checklist.md +771 -0
- package/skills/document-utils/reg-parser/references/checklists/kyc-aml-checklist.md +258 -0
- package/skills/document-utils/reg-parser/references/checklists/visa-vars-checklist.md +1058 -0
- package/skills/document-utils/reg-parser/references/mandates/hk-amlo-cap615.md +389 -0
- package/skills/document-utils/reg-parser/references/mandates/visa-vars.md +205 -0
- package/skills/document-utils/reg-parser/scripts/compare_checklist.py +228 -0
- package/skills/document-utils/reg-parser/scripts/dump_checklist.py +348 -0
- package/skills/document-utils/reg-parser/scripts/preprocess-mandate.sh +171 -0
- package/skills/document-utils/reg-parser/scripts/test_quarantine.sh +102 -0
- package/skills/document-utils/reg-parser/scripts/validate_checklist.py +532 -0
- package/skills/document-utils/reg-parser/scripts/validate_mandate.py +242 -0
- package/skills/engineering/engineering-runtime/coherence/workflow.json +17 -17
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
- package/skills/engineering/rush-release/SKILL.md +46 -25
- package/skills/engineering/rush-release/references/cut.md +21 -4
- package/skills/engineering/rush-release/references/preflight.md +25 -6
- package/skills/engineering/rush-release/references/promotion.md +70 -0
- package/skills/engineering/rush-release/references/publish.md +49 -16
- package/skills/engineering/rush-release/scripts/plan.mjs +33 -7
- package/skills/engineering/smoke/SKILL.md +4 -4
- package/skills/engineering/smoke/references/manifest.md +3 -3
- package/skills/payment/similar-domain/LICENSE +3 -0
- package/skills/payment/similar-domain/SKILL.md +178 -0
- package/skills/payment/similar-domain/references/entities.md +58 -0
- package/skills/payment/similar-domain/references/fingerprints.md +82 -0
- package/skills/payment/similar-domain/references/pivots.md +66 -0
- package/skills/payment/similar-domain/references/report-template.md +76 -0
- package/skills/payment/similar-domain/references/scoring.md +61 -0
- package/skills/payment/similar-domain/references/terminology.md +37 -0
- package/skills/payment/similar-domain/references/workflow.md +79 -0
- package/skills/payment/tld-detection/SKILL.md +76 -21
- package/skills/payment/tld-detection/references/clean.md +1 -1
- package/skills/payment/tld-detection/references/clustering.md +21 -6
- package/skills/payment/tld-detection/references/decision.md +7 -2
- package/skills/payment/tld-detection/references/fx-conversion.md +229 -0
- package/skills/payment/tld-detection/references/report-template.md +63 -27
- package/skills/payment/tld-detection/references/streams.md +90 -0
- package/skills/payment/tld-detection/references/terminology.md +15 -7
- package/skills/payment/tld-detection/references/workflow.md +1 -1
- package/skills/payment/tld-detection/scripts/detect_streams.py +542 -0
- package/skills/engineering/ensure-coverage/evals/evals.json +0 -125
- package/skills/engineering/rush-issues/evals/evals.json +0 -65
- package/skills/engineering/rush-release/evals/evals.json +0 -44
- package/skills/fullstack/shadcn/evals/evals.json +0 -90
- package/skills/payment/fraud-analysis/evals/evals.json +0 -40
- package/skills/payment/tld-detection/evals/evals.json +0 -107
- 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.
|
|
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.
|
|
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.
|
|
371
|
+
"version": "0.20.3"
|
|
372
372
|
},
|
|
373
|
-
"contentDigest": "
|
|
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.
|
|
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.
|
|
397
|
+
"version": "0.20.3"
|
|
398
398
|
},
|
|
399
|
-
"contentDigest": "
|
|
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.
|
|
410
|
+
"version": "0.20.3"
|
|
411
411
|
},
|
|
412
|
-
"contentDigest": "
|
|
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.
|
|
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.
|
|
436
|
+
"version": "0.20.3"
|
|
437
437
|
},
|
|
438
|
-
"contentDigest": "
|
|
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.
|
|
449
|
+
"version": "0.20.3"
|
|
450
450
|
},
|
|
451
|
-
"contentDigest": "
|
|
451
|
+
"contentDigest": "aa7b7dbeec2fd5d64883f4b6bf5ae99a3f77cad84f635cfbdf7cb1999de362e6",
|
|
452
452
|
"digestExcludes": [
|
|
453
453
|
"coherence/workflow.json"
|
|
454
454
|
]
|
|
455
455
|
}
|
|
456
456
|
],
|
|
457
|
-
"releaseIdentity": "
|
|
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.
|
|
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.
|
|
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);
|
|
@@ -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,
|
|
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
|
|
14
|
-
assemble a release branch
|
|
15
|
-
|
|
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
|
-
->
|
|
25
|
-
->
|
|
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
|
|
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
|
-
-
|
|
58
|
-
|
|
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
|
-
|
|
67
|
-
|
|
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`.
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
106
|
+
### 5. Merge and publish
|
|
87
107
|
|
|
88
|
-
Push the cut ref, merge its PR through the repository queue, verify the
|
|
89
|
-
merged SHA on `main
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
the
|
|
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
|
|
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,
|
|
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
|
|
4
|
-
files that carry the version. It does not pick the SHA, bump the
|
|
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
|
|
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
|
-
|
|
|
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
|
-
|
|
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
|
|