@1aboveio/skills 1.0.10 → 1.0.11
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/.codex-plugin/plugin.json +1 -1
- package/.codex-plugin/resources.json +297 -216
- package/README.md +3 -3
- package/package.json +10 -8
- package/skills/app-dev/airflow/SKILL.md +1 -1
- package/skills/app-dev/android-foundation/SKILL.md +35 -37
- package/skills/app-dev/android-foundation/references/delivery-focus.md +4 -2
- package/skills/app-dev/android-foundation/references/feature-work.md +50 -0
- package/skills/app-dev/android-foundation/references/setup.md +24 -9
- package/skills/app-dev/android-foundation/references/workspace.md +81 -0
- package/skills/app-dev/android-foundation/scripts/workspace-runtime/bin/workspaces.mjs +52 -0
- package/skills/app-dev/android-foundation/scripts/workspace-runtime/native-workspace.mjs +239 -0
- package/skills/app-dev/android-foundation/scripts/workspace-runtime/workspace-lifecycle.mjs +2154 -0
- package/skills/app-dev/app-debug/SKILL.md +1 -1
- package/skills/app-dev/better-auth/SKILL.md +1 -1
- package/skills/app-dev/data-catalog/SKILL.md +1 -1
- package/skills/app-dev/data-quality/SKILL.md +1 -1
- package/skills/app-dev/ios-foundation/SKILL.md +15 -10
- package/skills/app-dev/ios-foundation/references/setup.md +25 -9
- package/skills/app-dev/ios-foundation/references/workspace.md +82 -0
- package/skills/app-dev/ios-foundation/scripts/workspace-runtime/bin/workspaces.mjs +52 -0
- package/skills/app-dev/ios-foundation/scripts/workspace-runtime/native-workspace.mjs +239 -0
- package/skills/app-dev/ios-foundation/scripts/workspace-runtime/workspace-lifecycle.mjs +2154 -0
- package/skills/app-dev/monorepo/SKILL.md +1 -1
- package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
- package/skills/app-dev/prisma-setup/SKILL.md +1 -1
- package/skills/app-dev/pyspark/SKILL.md +1 -1
- package/skills/app-dev/python-backend/SKILL.md +1 -1
- package/skills/app-dev/shadcn/SKILL.md +1 -1
- package/skills/app-dev/zod-v4/SKILL.md +1 -1
- package/skills/cicd/cloud-build/SKILL.md +1 -1
- package/skills/cicd/cloud-debug/SKILL.md +1 -1
- package/skills/cicd/cloud-deploy/SKILL.md +1 -1
- package/skills/cicd/docker/SKILL.md +1 -1
- package/skills/cicd/github-actions/SKILL.md +1 -1
- package/skills/cicd/github-flow/SKILL.md +1 -1
- package/skills/cicd/google-cloud/SKILL.md +1 -1
- package/skills/cicd/mergify/SKILL.md +1 -1
- package/skills/cicd/podman/SKILL.md +1 -1
- package/skills/content/article-review/SKILL.md +1 -1
- package/skills/content/article-to-image/SKILL.md +1 -1
- package/skills/content/flowchart-svg/SKILL.md +1 -1
- package/skills/content/image-gen/SKILL.md +1 -1
- package/skills/content/mermaid/SKILL.md +1 -1
- package/skills/content/wechat-article-writer/SKILL.md +1 -1
- package/skills/content/wechat-publisher/SKILL.md +1 -1
- package/skills/content/wechat-search/SKILL.md +1 -1
- package/skills/content/xai-search/SKILL.md +1 -1
- package/skills/core/distill-writing/SKILL.md +3 -3
- package/skills/core/distill-writing/references/extraction.md +1 -1
- package/skills/core/doc-to-md/SKILL.md +1 -1
- package/skills/core/editorial-review/SKILL.md +82 -12
- package/skills/core/editorial-review/references/checklist.md +26 -1
- package/skills/core/house-style/SKILL.md +8 -3
- package/skills/core/house-style/references/analytical-reporting.md +123 -0
- package/skills/core/house-style/references/analytical-writing-patterns.md +79 -0
- package/skills/core/house-style/references/analytical-writing-research.md +129 -0
- package/skills/core/{write-doc → house-style}/references/bilingual.md +7 -5
- package/skills/core/house-style/references/definitions-and-metrics.md +86 -0
- package/skills/core/house-style/references/document-workflow.md +193 -0
- package/skills/core/house-style/references/initialization.md +66 -0
- package/skills/core/house-style/references/persistence.md +9 -4
- package/skills/core/house-style/references/rules.md +11 -4
- package/skills/core/house-style/scripts/init-guidance.mjs +213 -0
- package/skills/core/house-style/templates/analytical-report.md +54 -0
- package/skills/core/house-style/templates/gap-analysis.md +1 -1
- package/skills/core/plain-language/SKILL.md +2 -2
- package/skills/core/polish-cn/SKILL.md +9 -2
- package/skills/core/reg-parser/SKILL.md +3 -3
- package/skills/core/terminology/SKILL.md +8 -4
- package/skills/core/write-doc/SKILL.md +40 -151
- package/skills/core/write-report/SKILL.md +129 -0
- package/skills/core/{write-doc → write-report}/references/compliance-reports.md +4 -4
- package/skills/engineering/better-review/SKILL.md +37 -37
- package/skills/engineering/better-review/references/passes.md +35 -41
- package/skills/engineering/better-review/references/result.md +10 -9
- package/skills/engineering/e2e-test/SKILL.md +17 -17
- package/skills/engineering/e2e-test/references/authoring/playwright-config.md +11 -13
- package/skills/engineering/e2e-test/references/presentation-sweep.md +7 -7
- package/skills/engineering/e2e-test/references/reviewing.md +9 -11
- package/skills/engineering/e2e-test/references/route-manifest.md +1 -1
- package/skills/engineering/engineering/SKILL.md +124 -0
- package/skills/engineering/engineering/references/engineering-conventions.md +32 -0
- package/skills/engineering/engineering/references/feature-delivery.md +8 -0
- package/skills/engineering/engineering/references/init-scope.md +37 -0
- package/skills/engineering/engineering/scripts/init.mjs +160 -0
- package/skills/engineering/{contributing → engineering}/scripts/persist-conventions.mjs +1 -1
- package/skills/engineering/engineering-runtime/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +19 -19
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
- package/skills/engineering/ensure-coverage/SKILL.md +22 -109
- package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +7 -5
- package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +4 -4
- package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +3 -3
- package/skills/engineering/ensure-coverage/references/depth/characterization.md +4 -65
- package/skills/engineering/ensure-coverage/references/depth/grading.md +5 -7
- package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +6 -12
- package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +1 -1
- package/skills/engineering/ensure-coverage/references/presentation/axis.md +6 -6
- package/skills/engineering/ensure-coverage/references/process/audit-mode.md +7 -23
- package/skills/engineering/ensure-coverage/references/process/output-template.md +18 -133
- package/skills/engineering/ensure-coverage/references/process/test-strategy.md +7 -12
- package/skills/engineering/ensure-coverage/scripts/README.md +12 -4
- package/skills/engineering/golden-path/SKILL.md +1 -1
- package/skills/engineering/harness-runtime/SKILL.md +3 -1
- package/skills/engineering/harness-runtime/bin/workspaces.mjs +52 -0
- package/skills/engineering/harness-runtime/native-workspace.mjs +239 -0
- package/skills/engineering/harness-runtime/references/workspaces.md +78 -0
- package/skills/engineering/harness-runtime/workspace-lifecycle.mjs +2154 -0
- package/skills/engineering/resolve-issues/SKILL.md +40 -61
- package/skills/engineering/resolve-issues/references/ci.md +13 -3
- package/skills/engineering/resolve-issues/references/delivery-progress.md +4 -3
- package/skills/engineering/resolve-issues/references/done.md +11 -2
- package/skills/engineering/resolve-issues/references/expire.md +9 -2
- package/skills/engineering/resolve-issues/references/implementation.md +33 -17
- package/skills/engineering/resolve-issues/references/preflight.md +3 -1
- package/skills/engineering/resolve-issues/references/principles.md +52 -0
- package/skills/engineering/resolve-issues/references/review.md +25 -15
- package/skills/engineering/resolve-issues/references/task-plan.md +64 -27
- package/skills/engineering/resolve-issues/references/workspaces.md +164 -0
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.mjs +185 -317
- package/skills/engineering/resolve-issues/scripts/next-actions.mjs +44 -7
- package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +36 -2
- package/skills/engineering/resolve-issues/scripts/review-verdict.mjs +9 -8
- package/skills/engineering/resolve-issues/scripts/workspace-lifecycle.mjs +1 -0
- package/skills/engineering/resolve-release/SKILL.md +1 -1
- package/skills/engineering/rush-issues/SKILL.md +7 -5
- package/skills/engineering/rush-release/SKILL.md +1 -1
- package/skills/engineering/test-quality/SKILL.md +19 -4
- package/skills/engineering/test-quality/references/lint.md +1 -1
- package/skills/engineering/test-quality/references/principles.md +2 -2
- package/skills/engineering/test-quality/references/testing-conventions.md +1 -1
- package/skills/risk-compliance/compliance-audit/SKILL.md +4 -8
- package/skills/risk-compliance/compliance-audit/references/audience-and-reports.md +12 -0
- package/skills/risk-compliance/contract-compare/SKILL.md +17 -1
- package/skills/risk-compliance/contract-review/SKILL.md +6 -1
- package/skills/risk-compliance/contract-review/references/report-stage.md +17 -0
- package/skills/risk-compliance/doc-authenticity/SKILL.md +11 -1
- package/skills/risk-compliance/fraud-detection/LICENSE +3 -0
- package/skills/risk-compliance/fraud-detection/SKILL.md +148 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/archetypes/first-party-fraud.md +3 -2
- package/skills/risk-compliance/fraud-detection/references/archetypes/third-party-fraud.md +47 -0
- package/skills/risk-compliance/fraud-detection/references/collection-payout-features.md +151 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/contexts/bank-transfer.md +4 -3
- package/skills/risk-compliance/fraud-detection/references/contexts/card-payment.md +70 -0
- package/skills/risk-compliance/fraud-detection/references/contexts/payment-collection.md +34 -0
- package/skills/risk-compliance/fraud-detection/references/contexts/payout.md +34 -0
- package/skills/risk-compliance/fraud-detection/references/enrichment.md +74 -0
- package/skills/risk-compliance/fraud-detection/references/entities.md +48 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/feature-engineering.md +69 -33
- package/skills/risk-compliance/fraud-detection/references/feature-sql.md +150 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/report-rationale.md +4 -2
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/report-template.md +45 -23
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/review-checklist.md +60 -20
- package/skills/risk-compliance/fraud-detection/references/workflow.md +216 -0
- package/skills/risk-compliance/fraud-detection/release-check.mjs +95 -0
- package/skills/risk-compliance/payment-analysis/SKILL.md +36 -17
- package/skills/risk-compliance/payment-analysis/references/auth-rate-actions.md +2 -2
- package/skills/risk-compliance/payment-analysis/references/report-template.md +10 -2
- package/skills/risk-compliance/payment-analysis/references/visualization.md +11 -1
- package/skills/risk-compliance/portfolio-payment-analysis/LICENSE +3 -0
- package/skills/risk-compliance/portfolio-payment-analysis/SKILL.md +170 -0
- package/skills/risk-compliance/portfolio-payment-analysis/references/identity-and-reconciliation.md +46 -0
- package/skills/risk-compliance/portfolio-payment-analysis/references/metrics-and-reporting.md +170 -0
- package/skills/risk-compliance/portfolio-payment-analysis/references/risk-history.md +89 -0
- package/skills/risk-compliance/portfolio-payment-analysis/release-check.mjs +95 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/analyze.py +636 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/build_report.py +386 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/comparison_charts.py +425 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/csv_export.py +52 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/render.py +160 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/risk_history.py +435 -0
- package/skills/risk-compliance/similar-domain/SKILL.md +9 -4
- package/skills/risk-compliance/tld-detection/SKILL.md +124 -239
- package/skills/risk-compliance/tld-detection/agents/openai.yaml +1 -1
- package/skills/risk-compliance/tld-detection/references/clean.md +18 -51
- package/skills/risk-compliance/tld-detection/references/fx-conversion.md +56 -219
- package/skills/risk-compliance/tld-detection/references/metric-contract.md +109 -0
- package/skills/risk-compliance/tld-detection/references/pattern.md +99 -0
- package/skills/risk-compliance/tld-detection/references/report-template.md +49 -272
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.py +46 -13
- package/skills/risk-compliance/tld-detection/scripts/detect_patterns.py +346 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.py +51 -19
- package/skills/risk-compliance/tld-detection/scripts/profile_groups.py +109 -0
- package/skills/risk-compliance/tld-detection/scripts/render_charts.py +218 -0
- package/skills/risk-compliance/tld-detection/scripts/tld_common.py +243 -0
- package/skills/engineering/contributing/SKILL.md +0 -70
- package/skills/risk-compliance/fraud-analysis/SKILL.md +0 -114
- package/skills/risk-compliance/fraud-analysis/references/archetypes/third-party-fraud.md +0 -27
- package/skills/risk-compliance/fraud-analysis/references/contexts/card-payment.md +0 -30
- package/skills/risk-compliance/fraud-analysis/references/contexts/payment-collection.md +0 -20
- package/skills/risk-compliance/fraud-analysis/references/contexts/payout.md +0 -20
- package/skills/risk-compliance/fraud-analysis/references/workflow.md +0 -175
- package/skills/risk-compliance/tld-detection/references/chinese-polish.md +0 -55
- package/skills/risk-compliance/tld-detection/references/clustering.md +0 -235
- package/skills/risk-compliance/tld-detection/references/decision.md +0 -189
- package/skills/risk-compliance/tld-detection/references/streams.md +0 -141
- package/skills/risk-compliance/tld-detection/references/terminology.md +0 -95
- package/skills/risk-compliance/tld-detection/references/workflow.md +0 -95
- /package/skills/{engineering/contributing → core/write-report}/LICENSE +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/audit-report-template.md +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/external-assessment-template.md +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/management-report-template.md +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/vars-report-template.md +0 -0
- /package/skills/{engineering/contributing → core/write-report}/release-check.mjs +0 -0
- /package/skills/{risk-compliance/fraud-analysis → engineering/engineering}/LICENSE +0 -0
- /package/skills/engineering/{contributing → engineering}/references/tracker-conventions.md +0 -0
- /package/skills/{risk-compliance/fraud-analysis → engineering/engineering}/release-check.mjs +0 -0
- /package/skills/engineering/{contributing → engineering}/scripts/persist-conventions-core.mjs +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/archetypes/authorized-payment-scam.md +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/mechanisms/account-takeover.md +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/taxonomy.md +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/terminology.md +0 -0
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
//
|
|
12
12
|
// add-unit, drop-unit, set-deps, move-link, blocked-outside, cycle
|
|
13
13
|
// the plan differs from the spec's GitHub issue tree (plan-sync.mjs): apply
|
|
14
|
-
// it through
|
|
14
|
+
// it through the available checkpoint mechanism. --resume and --sync fetch the tree (one GraphQL
|
|
15
15
|
// query) and save it; every other call diffs the saved tree, with no
|
|
16
16
|
// GitHub call. Sync after the run files an issue
|
|
17
17
|
// unblock a unit marked blocked without a reason from BLOCK_REASONS
|
|
@@ -176,6 +176,12 @@ export function normalizeCapacity(input) {
|
|
|
176
176
|
const hasWorker = (u) => u.worker !== undefined && u.worker !== null && u.worker !== ''
|
|
177
177
|
const codeDone = (u) => u.stage === 'done'
|
|
178
178
|
|
|
179
|
+
export function workspaceCleanupSettled(unit) {
|
|
180
|
+
const result = unit.lifecycle?.cleanup
|
|
181
|
+
return typeof unit.headSha === 'string' && unit.headSha.length > 0 && result?.headSha === unit.headSha &&
|
|
182
|
+
(result.state === 'complete' || (result.state === 'retained' && typeof result.reason === 'string' && result.reason.trim().length > 0))
|
|
183
|
+
}
|
|
184
|
+
|
|
179
185
|
// Pure decision from the plan and each unit's newest review round.
|
|
180
186
|
// `capacity`: a fresh Harness snapshot, or an explicitly reconciled total workflow budget.
|
|
181
187
|
// Snapshot availableSlots is already net of all running and reserved workers.
|
|
@@ -191,6 +197,10 @@ const codeDone = (u) => u.stage === 'done'
|
|
|
191
197
|
// `key` is the result file, relative to the run, that a `decisions` entry's `answers` names.
|
|
192
198
|
export function nextActions(plan, reviews = {}, capacity, { resume = false, now, activity = {}, quietMinutes = DEFAULT_QUIET_MINUTES, sync = null, seen = {}, questions = {} } = {}) {
|
|
193
199
|
const effectiveCapacity = normalizeCapacity(capacity)
|
|
200
|
+
if (Array.isArray(plan?.units) && Array.isArray(plan?.issues) && JSON.stringify(plan.units) !== JSON.stringify(plan.issues)) {
|
|
201
|
+
throw new NextActionsError('task plan has conflicting units and issues rosters')
|
|
202
|
+
}
|
|
203
|
+
if (plan?.workspaceLifecycle !== undefined && plan.workspaceLifecycle !== 1) throw new NextActionsError('unsupported workspaceLifecycle version')
|
|
194
204
|
const saved = (Array.isArray(plan?.units) ? plan.units : plan?.issues) ?? []
|
|
195
205
|
if (!Array.isArray(saved) || saved.length === 0) throw new NextActionsError('task plan has no units')
|
|
196
206
|
const excluded = excludedIds(plan)
|
|
@@ -328,6 +338,17 @@ export function nextActions(plan, reviews = {}, capacity, { resume = false, now,
|
|
|
328
338
|
}
|
|
329
339
|
const actions = []
|
|
330
340
|
const add = (action, u, detail) => actions.push({ action, unit: String(u.id), detail })
|
|
341
|
+
const managed = (u) => plan.workspaceLifecycle === 1 || u.lifecycle?.version === 1
|
|
342
|
+
for (const u of units) {
|
|
343
|
+
if (TERMINAL.has(u.status) && hasWorker(u) && (u.status !== 'blocked' || reasonOk(u))) {
|
|
344
|
+
add('check-worker', u, `unit ${u.id} is ${u.status} but still records worker ${u.worker}: collect its terminal result and stop its owned services before handoff or workspace cleanup; never remove a running environment`)
|
|
345
|
+
continue
|
|
346
|
+
}
|
|
347
|
+
if (!managed(u) || u.status !== 'succeeded' || !u.workspace) continue
|
|
348
|
+
if (!hasWorker(u) && !workspaceCleanupSettled(u)) {
|
|
349
|
+
add('cleanup-workspace', u, `unit ${u.id} landed: record lifecycle.cleanup with state applying and headSha ${u.headSha ?? '(record the delivered HEAD first)'}, then run cleanup-runs.mjs cleanup --run <run> --unit ${u.id} --revision <saved planRevision> --apply --json; inspect and persist the returned lifecycle. A refusal is retained with its reason, never complete; do this before finish and alongside independent units`)
|
|
350
|
+
}
|
|
351
|
+
}
|
|
331
352
|
const chainReady = []
|
|
332
353
|
const chainOpen = (u) => {
|
|
333
354
|
const id = String(u.id)
|
|
@@ -385,6 +406,7 @@ export function nextActions(plan, reviews = {}, capacity, { resume = false, now,
|
|
|
385
406
|
const quietMs = quietMinutes * 60_000
|
|
386
407
|
for (const u of units) {
|
|
387
408
|
if (!hasWorker(u)) continue
|
|
409
|
+
if (TERMINAL.has(u.status)) continue
|
|
388
410
|
const since = Date.parse(u.workerSince ?? '')
|
|
389
411
|
if (!Number.isFinite(since)) continue
|
|
390
412
|
const last = Math.max(since, activity[String(u.id)] ?? 0)
|
|
@@ -610,7 +632,7 @@ export function nextActions(plan, reviews = {}, capacity, { resume = false, now,
|
|
|
610
632
|
}
|
|
611
633
|
const SYNC = ['drop-unit', 'add-unit', 'set-deps', 'move-link', 'blocked-outside', 'cycle']
|
|
612
634
|
for (const a of sync?.actions ?? []) actions.push({ action: a.action, unit: a.unit, detail: a.detail })
|
|
613
|
-
const order = [...SYNC, 'worker-kind', 'decide', 'split', 'unblock', 'check-worker', 'restack', 'carry', 'review-verdict', 'start-fix', 'start-review', 'deliver', 'open-pr', 'resume', 'fill-slot']
|
|
635
|
+
const order = [...SYNC, 'worker-kind', 'decide', 'split', 'unblock', 'check-worker', 'cleanup-workspace', 'restack', 'carry', 'review-verdict', 'start-fix', 'start-review', 'deliver', 'open-pr', 'resume', 'fill-slot']
|
|
614
636
|
actions.sort((a, b) => order.indexOf(a.action) - order.indexOf(b.action))
|
|
615
637
|
// One restack per unit per pass: the first reason found; the next pass sees the new HEAD.
|
|
616
638
|
const restacked = new Set()
|
|
@@ -625,7 +647,18 @@ export function nextActions(plan, reviews = {}, capacity, { resume = false, now,
|
|
|
625
647
|
const waiting = []
|
|
626
648
|
for (const a of actions) {
|
|
627
649
|
if (!NEEDS_SLOT.has(a.action)) { due.push(a); continue }
|
|
628
|
-
if (free > 0) {
|
|
650
|
+
if (free > 0) {
|
|
651
|
+
const u = byId.get(a.unit)
|
|
652
|
+
const reviewReady = a.action !== 'start-review' || u.lifecycle?.resources?.some((r) => r.role === 'review' && r.state === 'ready')
|
|
653
|
+
const needsPreparation = managed(u) && (u.lifecycle?.workspace?.state !== 'ready' || !reviewReady)
|
|
654
|
+
const removalPending = managed(u) && u.lifecycle?.cleanup?.state === 'applying'
|
|
655
|
+
const admitted = removalPending ? { action: 'recover-workspace', unit: a.unit,
|
|
656
|
+
detail: `before ${a.action} for unit ${a.unit}, resolve its applying cleanup: inspect cleanup-runs.mjs recover --repo <repo-root> --json, collect any running cleanup operation's terminal result, and verify its receipt and every owned resource before updating lifecycle. Never admit a worker while removal of its environment is unresolved` }
|
|
657
|
+
: needsPreparation ? { action: 'prepare-workspace', unit: a.unit,
|
|
658
|
+
detail: `before ${a.action} for unit ${a.unit}, record its exact workspace, branch, base SHA and lifecycle preparation intent${reviewReady ? '' : ', including its one review clone'}; run cleanup-runs.mjs prepare --run <run> --unit ${a.unit} --revision <saved planRevision> --apply --json and persist its returned ready identity. Reuse an existing matching workspace; never reset, replace or create another one on retry` } : a
|
|
659
|
+
due.push(unlimited ? { ...admitted, detail: `${admitted.detail} [needs a free worker slot]` } : admitted)
|
|
660
|
+
free--
|
|
661
|
+
} else waiting.push(a)
|
|
629
662
|
}
|
|
630
663
|
if (native) oneChange(due)
|
|
631
664
|
const treeChanged = (sync?.actions ?? []).length > 0
|
|
@@ -645,7 +678,8 @@ export function nextActions(plan, reviews = {}, capacity, { resume = false, now,
|
|
|
645
678
|
const parked = units.filter(notStarted).map((u) => `${u.id} (waits on ${waitsOn(u)})`)
|
|
646
679
|
const built = units.filter((u) => builtWaiting(u) && !u.pr).map((u) => `${u.id} (waits on ${waitsOn(u)})`)
|
|
647
680
|
const openWaiting = units.filter((u) => builtWaiting(u) && u.pr).map((u) => `${u.id} (${u.pr}, waits on ${waitsOn(u)})`)
|
|
648
|
-
|
|
681
|
+
const cleanupPending = due.some((a) => a.action === 'cleanup-workspace')
|
|
682
|
+
if (!ready.length && !cleanupPending && units.every((u) => !hasWorker(u) && (TERMINAL.has(u.status) || notStarted(u) || builtWaiting(u)) && settledBlock(u) && !sizeHeld(u) && !deciding(u)) && !treeChanged) {
|
|
649
683
|
if (sync?.fetchError) due.push({ action: 'sync', unit: null, detail: `every unit is settled, but the issue tree could not be read (${sync.fetchError.map((e) => e.error).join('; ')}): rerun with --sync until it reads; never finish on a tree you could not read` })
|
|
650
684
|
else if (sync && !String(sync.source).startsWith('live')) due.push({ action: 'sync', unit: null, detail: 'every unit is settled: rerun with --sync to check the issue tree for new issues before finishing' })
|
|
651
685
|
else if (retryable.some((u) => !u.blockedAt || !Number.isFinite(now))) {
|
|
@@ -653,7 +687,10 @@ export function nextActions(plan, reviews = {}, capacity, { resume = false, now,
|
|
|
653
687
|
} else if (retryable.length) {
|
|
654
688
|
const next = retryable.reduce((a, u) => (dueAt(u) < dueAt(a) ? u : a))
|
|
655
689
|
due.push({ action: 'wait', unit: String(next.id), detail: `unit ${next.id} is blocked (${next.blockedReason}); its next automatic attempt is at ${new Date(dueAt(next)).toISOString()}: keep a heartbeat until then and do not finish` })
|
|
656
|
-
} else
|
|
690
|
+
} else {
|
|
691
|
+
const retained = units.filter((u) => managed(u) && u.lifecycle?.cleanup?.state === 'retained').map((u) => `${u.id}: ${u.lifecycle.cleanup.reason}`)
|
|
692
|
+
due.push({ action: 'finish', unit: null, detail: `every unit is delivered, blocked, cancelled, or not started behind one of those: write the handoff${parked.length ? `; not started: ${parked.join(', ')}` : ''}${built.length ? `; built, PR not opened: ${built.join(', ')}` : ''}${openWaiting.length ? `; PR open, cannot land: ${openWaiting.join(', ')}` : ''}${retained.length ? `; retained environments (not cleaned): ${retained.join('; ')}` : ''}` })
|
|
693
|
+
}
|
|
657
694
|
}
|
|
658
695
|
// How long each due action has gone undone, from when it was first printed.
|
|
659
696
|
const nextSeen = {}
|
|
@@ -823,7 +860,7 @@ if (isMainModule(import.meta.url)) {
|
|
|
823
860
|
if (opts.json) process.stdout.write(`${JSON.stringify({ ...result, mode, exitDue }, null, 2)}\n`)
|
|
824
861
|
else if (mode !== 'full') {
|
|
825
862
|
const view = narrowView(plan, result)
|
|
826
|
-
const guardNames = [...new Set(result.due.filter((a) => /^guards: (?!none)/m.test(view) && ['decide', 'review-verdict', 'unblock', 'worker-kind', 'split', 'sync', 'add-unit', 'drop-unit', 'set-deps', 'move-link', 'blocked-outside'].includes(a.action)).map((a) => a.action))]
|
|
863
|
+
const guardNames = [...new Set(result.due.filter((a) => /^guards: (?!none)/m.test(view) && ['recover-workspace', 'prepare-workspace', 'cleanup-workspace', 'decide', 'review-verdict', 'unblock', 'worker-kind', 'split', 'sync', 'add-unit', 'drop-unit', 'set-deps', 'move-link', 'blocked-outside'].includes(a.action)).map((a) => a.action))]
|
|
827
864
|
process.stdout.write(`${mode === 'off' ? `${view.split('\n')[0].replace(/: .*$/, '')}${guardNames.length ? ` (clear first: ${guardNames.join(', ')})` : ''}` : view}\n`)
|
|
828
865
|
process.stdout.write(`${budgetLine(result.capacity)}\n`)
|
|
829
866
|
process.stdout.write(rulesLine(`${mode === 'off' ? 'Scheduler mode off: plan every step yourself from the plan and results.' : 'Scheduler mode narrow: clear the guards, then choose each unit\'s next step yourself.'} The run ends only when this prints "run done".`))
|
|
@@ -843,7 +880,7 @@ if (isMainModule(import.meta.url)) {
|
|
|
843
880
|
// The narrow view: whether the run is done, which units have work, the guards, and what waits on
|
|
844
881
|
// the human. It leaves each unit's next step to the coordinator.
|
|
845
882
|
export function narrowView(plan, result) {
|
|
846
|
-
const GUARDS = new Set(['decide', 'review-verdict', 'unblock', 'worker-kind', 'split', 'sync', 'add-unit', 'drop-unit', 'set-deps', 'move-link', 'blocked-outside'])
|
|
883
|
+
const GUARDS = new Set(['recover-workspace', 'prepare-workspace', 'cleanup-workspace', 'decide', 'review-verdict', 'unblock', 'worker-kind', 'split', 'sync', 'add-unit', 'drop-unit', 'set-deps', 'move-link', 'blocked-outside'])
|
|
847
884
|
const units = new Map((plan.units ?? []).map((u) => [String(u.id), u]))
|
|
848
885
|
const guards = result.due.filter((a) => GUARDS.has(a.action)).map((a) => `${a.unit ?? 'run'}: ${a.detail}`)
|
|
849
886
|
const work = [...new Set([...result.due, ...result.waiting].filter((a) => a.unit && !GUARDS.has(a.action) && a.action !== 'wait').map((a) => a.unit))]
|
|
@@ -22,7 +22,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
22
22
|
|
|
23
23
|
import { workerResources } from '../../engineering-runtime/scripts/installation-resolver.mjs'
|
|
24
24
|
import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
|
|
25
|
-
import { RULES, SKILL_PATH } from './next-actions.mjs'
|
|
25
|
+
import { RULES, RUN_SKILLS, SKILL_PATH, workspaceCleanupSettled } from './next-actions.mjs'
|
|
26
26
|
|
|
27
27
|
export const ACTIVE_HOURS = 24
|
|
28
28
|
const SCRIPTS = dirname(fileURLToPath(import.meta.url))
|
|
@@ -52,6 +52,7 @@ export function activeRuns(cwd, now = Date.now(), hours = ACTIVE_HOURS) {
|
|
|
52
52
|
if (now - mtime > hours * 3_600_000) continue
|
|
53
53
|
let plan
|
|
54
54
|
try { plan = JSON.parse(readFileSync(file, 'utf8')) } catch { continue }
|
|
55
|
+
if (plan.skill !== undefined && !RUN_SKILLS.includes(plan.skill)) continue
|
|
55
56
|
const units = (Array.isArray(plan?.units) ? plan.units : plan?.issues) ?? []
|
|
56
57
|
const open = units.filter((u) => !DONE.has(u?.status)).length
|
|
57
58
|
if (!open) continue
|
|
@@ -61,6 +62,39 @@ export function activeRuns(cwd, now = Date.now(), hours = ACTIVE_HOURS) {
|
|
|
61
62
|
return runs.sort((a, b) => b.mtime - a.mtime).map(({ mtime, ...r }) => r)
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
// Recovery discovery must not activate a workflow, and has no age cutoff.
|
|
66
|
+
export function cleanupRuns(cwd) {
|
|
67
|
+
const root = runsRoot(cwd)
|
|
68
|
+
if (!root) return []
|
|
69
|
+
let names
|
|
70
|
+
try { names = readdirSync(root) } catch { return [] }
|
|
71
|
+
const out = []
|
|
72
|
+
for (const name of names) {
|
|
73
|
+
const dir = join(root, name)
|
|
74
|
+
let plan
|
|
75
|
+
try { plan = JSON.parse(readFileSync(join(dir, 'task-plan.json'), 'utf8')) } catch { continue }
|
|
76
|
+
if (Array.isArray(plan.units) && Array.isArray(plan.issues) && JSON.stringify(plan.units) !== JSON.stringify(plan.issues)) {
|
|
77
|
+
out.push({ dir, units: [], reason: 'conflicting units and issues rosters; ownership requires reconciliation' })
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
const units = Array.isArray(plan.units) ? plan.units : plan.issues
|
|
81
|
+
if (!Array.isArray(units)) continue
|
|
82
|
+
const pending = units.filter((u) => u.status === 'succeeded' && u.delivery === 'merged' && u.workspace && !workspaceCleanupSettled(u))
|
|
83
|
+
if (pending.length) out.push({ dir, units: pending.map((u) => String(u.id)),
|
|
84
|
+
...(pending.some((u) => plan.workspaceLifecycle !== 1 && u.lifecycle?.version !== 1) ? { reason: 'legacy workspace ownership is unresolved; inventory only, never automatic adoption or deletion' } : {}) })
|
|
85
|
+
}
|
|
86
|
+
return out.sort((a, b) => a.dir.localeCompare(b.dir))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function cleanupMessage(runs) {
|
|
90
|
+
if (!runs.length) return ''
|
|
91
|
+
return [
|
|
92
|
+
'Read-only recovery notice: these delivered units still have pending or interrupted workspace cleanup:',
|
|
93
|
+
...runs.map((r) => `- ${r.dir}: ${r.units.join(', ') || 'ownership unresolved'}${r.reason ? ` (${r.reason})` : ''}`),
|
|
94
|
+
'This notice does not activate a workflow or authorize deletion. When the owning work resumes, inspect cleanup-runs.mjs recover --repo <owning repo> --json, then use its recorded ownership and current revision. Never infer completed cleanup from age or an absent path.',
|
|
95
|
+
].join('\n')
|
|
96
|
+
}
|
|
97
|
+
|
|
64
98
|
export function message(runs, { skillPath = SKILL_PATH, rushSkillPath = RUSH_SKILL_PATH } = {}) {
|
|
65
99
|
if (!runs.length) return ''
|
|
66
100
|
if (runs.some((run) => run.installation)) {
|
|
@@ -103,7 +137,7 @@ export function main(argv) {
|
|
|
103
137
|
if (hook) {
|
|
104
138
|
try { cwd = JSON.parse(readFileSync(0, 'utf8'))?.cwd || cwd } catch { /* no input: keep cwd */ }
|
|
105
139
|
}
|
|
106
|
-
const text = message(activeRuns(cwd))
|
|
140
|
+
const text = [message(activeRuns(cwd)), cleanupMessage(cleanupRuns(cwd))].filter(Boolean).join('\n\n')
|
|
107
141
|
if (text) process.stdout.write(hook ? `${hookOutput(text)}\n` : `${text}\n`)
|
|
108
142
|
} catch (error) {
|
|
109
143
|
process.stderr.write(`rehydrate: ${error.message}\n`)
|
|
@@ -32,15 +32,16 @@
|
|
|
32
32
|
// the fix worker's whole finding list. `action` says how to fix, from a
|
|
33
33
|
// comparison with the previous round's file (`<unit>-r<N-1>.json` beside
|
|
34
34
|
// it, or --prior):
|
|
35
|
-
// fix first blocking round: fix each finding's rule
|
|
36
|
-
//
|
|
35
|
+
// fix first blocking round: fix each finding's rule across its
|
|
36
|
+
// applicable paths and close every row
|
|
37
37
|
// test-first a P0/P1 came back after a fix: name the rule it breaks,
|
|
38
|
-
// list
|
|
39
|
-
//
|
|
38
|
+
// list the applicable paths, reuse sufficient tests and add
|
|
39
|
+
// focused cases for missing proof, see the open cases fail,
|
|
40
|
+
// then fix until all pass, with the
|
|
40
41
|
// escalation model
|
|
41
42
|
// one-by-one only new P0/P1, introduced by the last fix: one finding
|
|
42
43
|
// per fix worker, in turn, the smallest change that closes
|
|
43
|
-
// every row
|
|
44
|
+
// every row across the applicable paths
|
|
44
45
|
// 5 wait: no P0/P1 is open, but a GitHub reviewer whose changes request a fix brief
|
|
45
46
|
// already carried has not re-reviewed (`awaiting`, from github-reviews.mjs merge);
|
|
46
47
|
// request their re-review and run the merge and this verdict again when it lands
|
|
@@ -332,9 +333,9 @@ export function carryRecord(prior, head, identity = {}) {
|
|
|
332
333
|
}
|
|
333
334
|
|
|
334
335
|
const INSTRUCTIONS = {
|
|
335
|
-
'fix': 'Fix only these findings. For each, fix its `rule`
|
|
336
|
-
'test-first': 'The findings listed in `recurring` survived a fix: the last fix closed one path and missed others. For each, before changing code: name the rule the bug breaks; list every code path that can break it, including the trigger of this finding id in each earlier round\'s review file beside this one;
|
|
337
|
-
'one-by-one': 'The last fix introduced these findings. Fix them one at a time, one fix worker each, with the smallest change that closes every row of its `paths
|
|
336
|
+
'fix': 'Fix only these findings. For each, make the smallest complete fix for its `rule` across the applicable paths and close every row in its `paths`. Use a shared owner when useful, but do not require a refactor; focused fixes on individual paths are acceptable.',
|
|
337
|
+
'test-first': 'The findings listed in `recurring` survived a fix: the last fix closed one path and missed others. For each, before changing code: name the rule the bug breaks; list every code path that can break it, including the trigger of this finding id in each earlier round\'s review file beside this one; reuse sufficient tests and add focused cases from the concrete triggers, then run them to see it fail on each open path. One table-driven test may cover several paths. Then make the smallest complete fix across the applicable paths until every test passes. Use a shared owner when useful, but do not require a refactor; focused fixes on individual paths are acceptable. "Fixed" is every path\'s test passing. Fix the rest as usual.',
|
|
338
|
+
'one-by-one': 'The last fix introduced these findings. Fix them one at a time, one fix worker each, with the smallest complete change that closes every row of its `paths`. Use a shared owner when useful, but do not require a refactor; focused fixes on individual paths are acceptable. Touch nothing else.',
|
|
338
339
|
}
|
|
339
340
|
|
|
340
341
|
// The fix worker's brief carries only P0/P1 findings; P2/P3 never reach it.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../../harness-runtime/workspace-lifecycle.mjs'
|
|
@@ -4,7 +4,7 @@ description: "Slash/explicit-only (/resolve-release). Full GitHub Flow release f
|
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
metadata:
|
|
6
6
|
workflow-role: coordinator
|
|
7
|
-
release-version: 0.
|
|
7
|
+
release-version: 0.45.0
|
|
8
8
|
---
|
|
9
9
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
10
10
|
# Resolve release
|
|
@@ -6,7 +6,7 @@ metadata:
|
|
|
6
6
|
workflow-role: coordinator
|
|
7
7
|
dependencies:
|
|
8
8
|
- resolve-issues
|
|
9
|
-
release-version: 0.
|
|
9
|
+
release-version: 0.45.0
|
|
10
10
|
---
|
|
11
11
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
12
12
|
# Rush issues (shortcut of resolve-issues)
|
|
@@ -55,7 +55,9 @@ question.
|
|
|
55
55
|
mode too: keep one immediate checkpoint per active unit, justify infrastructure and
|
|
56
56
|
reassess repeated non-convergence. More worker activity is not a reason to reset it.
|
|
57
57
|
The shared [task-plan checkpoints](../resolve-issues/references/task-plan.md#checkpoints)
|
|
58
|
-
apply too:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
apply too: when `update_todo` is advertised, capture the known outcome before
|
|
59
|
+
substantive work, then bind or reload with the absolute workflow path and
|
|
60
|
+
persisted revision. No event means the plan is read-only; save transitions
|
|
61
|
+
through its `workflow` payload. Never edit a bound plan directly. When the
|
|
62
|
+
optional tool is absent or disabled, use the workflow's file transition; never
|
|
63
|
+
enable the interface as a precondition.
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test-quality
|
|
3
3
|
description: "Seven principles for tests that catch real bugs, and an audit that reports weak, redundant, and not-coverage tests without fixing them. Use when writing, changing, or reviewing tests, or when asked whether tests are useful, redundant, over-mocked, flaky, only assert static text, or test config files, or asked to make a slow test suite faster without losing coverage, or when the user asks to write the testing conventions into a repo's CONTRIBUTING.md. NOT defining what a spec must prove (ensure-coverage) or authoring browser tests (e2e-test)."
|
|
4
|
-
release-version: 0.
|
|
4
|
+
release-version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
7
7
|
# Test Quality
|
|
8
8
|
|
|
9
9
|
A test is worth keeping when it fails for a real bug and stays green through a harmless change. This skill states seven principles that decide that and audits a suite against them. Each principle's examples, common failures, and look-alikes: [references/principles.md](references/principles.md).
|
|
10
10
|
|
|
11
|
-
- **Write mode**:
|
|
11
|
+
- **Write mode**: judge the tests needed for the requested behavior using the principles and the one question. Run `node "$SKILL_DIR/scripts/lint-tests.mjs" --diff <base>` when requested or required by the repository ([lint](#the-lint)); it covers uncommitted and untracked tests. An optional lint result does not create a new acceptance gate.
|
|
12
12
|
- **Audit mode**: reviewer subagents sweep a suite or a diff and report findings, quick by default ([audit](#audit-mode)). The audit **never edits, rewrites, or deletes a test**. It names the principle broken and the evidence; the fix belongs to the implementer.
|
|
13
13
|
- **Persist mode**: only when the user asks, write the principles into the repo's `CONTRIBUTING.md` ([persist](#persist-mode)).
|
|
14
14
|
|
|
@@ -22,6 +22,21 @@ A test is worth keeping when it fails for a real bug and stays green through a h
|
|
|
22
22
|
| 6 | [Don't test config files](references/principles.md#6-dont-test-config-files) | Restating a config file in a test | a Dockerfile, workflow, `cloudbuild.yaml`, `.mergify.yml`, `package.json`, or other JSON/YAML/TOML config read, then any assertion |
|
|
23
23
|
| 7 | [Same code, same result](references/principles.md#7-same-code-same-result) | A result that depends on luck | `Math.random`/`uuid()`/`Date.now()` in checked output; `sleep(…)`; passes in the suite, fails alone; scratch files under the repo or `cwd` |
|
|
24
24
|
|
|
25
|
+
## Scope while writing
|
|
26
|
+
|
|
27
|
+
Use these principles to judge the tests the task needs, not to start a suite-wide
|
|
28
|
+
cleanup. First identify the requested behavior or concrete regression and reuse
|
|
29
|
+
existing tests that prove it. Add focused assertions at the lowest level that
|
|
30
|
+
observes the real outcome; do not automatically duplicate them across test layers.
|
|
31
|
+
|
|
32
|
+
Before testing a defensive branch, check that its behavior belongs to the supported
|
|
33
|
+
contract. A new guard or fallback does not create its own testing requirement.
|
|
34
|
+
Speculative failures, coverage percentages, and test counts do not justify expanding
|
|
35
|
+
a feature into a harness, framework, or gate project. Keep binding checks and material
|
|
36
|
+
security, money, tenancy, and data-integrity proof; report unrelated debt rather than
|
|
37
|
+
fixing it. Stop once the agreed behavior is sufficiently proven. Broad audits and
|
|
38
|
+
convention persistence remain separate, explicitly requested tasks.
|
|
39
|
+
|
|
25
40
|
## The one question
|
|
26
41
|
|
|
27
42
|
For every assertion, answer both halves:
|
|
@@ -35,7 +50,7 @@ A good assertion has a concrete answer to (1) and none to (2). An assertion with
|
|
|
35
50
|
|
|
36
51
|
1. **Test behavior, not text.** Run the code and observe what it does. The text of a doc, prompt, source file, or migration is not behavior. A test whose only assertions are text matches over checked-in files is **`Not coverage`** for the behavior the text describes, never partial proof.
|
|
37
52
|
2. **The expected value comes from somewhere other than the code under test.** Take it from the spec, an external contract, a separately written simpler model, or the input: never from the code under test or a literal copied out of it. When a version really is the contract, pin the major only.
|
|
38
|
-
3. **Fake only what you don't own.**
|
|
53
|
+
3. **Fake only what you don't own for boundary proof.** Use real database and service behavior when proving transactions, tenant filters, locking, or idempotency; fake external providers, clock, and randomness. A focused unit test may isolate an internal collaborator, but proves only behavior it actually executes. An over-mocked test is `Not coverage` for the behavior the fake hides. Follow stricter adopted repo rules where required.
|
|
39
54
|
4. **An assertion must be able to fail.** Every test can go red and checks what its name promises: read the name's verbs ("atomically", "then", "corrected to") and find the assertion for each.
|
|
40
55
|
5. **Test each behavior once, and only for code that still runs.** Prove each behavior once, at the lowest level that proves it for real. Layering (a pure unit for the decision table plus one real-DB test per rule) is not duplication; many similar cases merge into a table rather than being deleted.
|
|
41
56
|
6. **Don't test config files.** Dockerfiles, `cloudbuild.yaml`, `.github/workflows/*`, `.mergify.yml`, `package.json`, `tsconfig.json`, `pyproject.toml`, `.env`, and any other JSON, YAML, or TOML a tool reads get no tests: the tool that reads the file is the test. Test the code that reads config; run scripts, because scripts are code. A pin added after a real bug is still a config test: delete it and name the missing behavior check as a follow-up. JSON the app loads as data (locales, price tables) is not config.
|
|
@@ -69,7 +84,7 @@ It writes the seven principles ([references/testing-conventions.md](references/t
|
|
|
69
84
|
|
|
70
85
|
## The lint
|
|
71
86
|
|
|
72
|
-
Scripts live under **this skill's directory**: set `SKILL_DIR` to the directory you read this file from, never your CWD. `node "$SKILL_DIR/scripts/lint-tests.mjs"` scans the tree; `--diff <base>` only lines changed since the merge-base. A **gate** rule
|
|
87
|
+
Scripts live under **this skill's directory**: set `SKILL_DIR` to the directory you read this file from, never your CWD. `node "$SKILL_DIR/scripts/lint-tests.mjs"` scans the tree; `--diff <base>` only lines changed since the merge-base. A tool-local **gate** rule fails the command's exit status; it is not automatically a repository merge requirement. Assess optional hits in context and preserve existing adopted gates. Rules, flags, and what a clean run proves (little, for Python and Go): [references/lint.md](references/lint.md).
|
|
73
88
|
|
|
74
89
|
## Common wrong answers
|
|
75
90
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Scripts live under **this skill's directory**. Set `SKILL_DIR` to the directory you read this file from and run `node "$SKILL_DIR/scripts/lint-tests.mjs"`. Never resolve against your CWD. A missing script in the audited repo is not a blocker; the scripts belong to this skill.
|
|
6
6
|
|
|
7
|
-
A **gate** rule
|
|
7
|
+
A tool-local **gate** rule fails the command's exit status; a **lead** rule reports a pattern for inspection. Run this optional tool when requested or required by the repository, scoped to the task. Its classifier detects syntax, not whether a test proves its claimed behavior. An optional hit does not create a new merge requirement or require replacing valid unit isolation with infrastructure. Preserve adopted repo gates and report their actual failures; changing those gates requires approval.
|
|
8
8
|
|
|
9
9
|
| rule | principle | severity | finds |
|
|
10
10
|
|---|---|---|---|
|
|
@@ -49,14 +49,14 @@
|
|
|
49
49
|
|
|
50
50
|
## 3. Fake only what you don't own
|
|
51
51
|
|
|
52
|
-
**Principle.**
|
|
52
|
+
**Principle.** For proof of a real boundary, use real internals and fake externals: third-party APIs, providers, clock, and randomness. A fake database cannot prove transactions, tenant filters, locking, or idempotency. A focused unit test may isolate an internal collaborator to exercise the caller's own decision logic; it does not prove the collaborator's behavior. Existing stricter repo rules remain binding.
|
|
53
53
|
|
|
54
54
|
**Done right.**
|
|
55
55
|
- Real Postgres with migrations; only the payment provider faked.
|
|
56
56
|
- A spy at an external boundary where **the call is the behavior**: the backoff delay, the precondition header sent to storage, "the provider was not called after validation failed".
|
|
57
57
|
|
|
58
58
|
**Common failures.**
|
|
59
|
-
- *First-party mock:* `vi.mock('@/lib/prisma')
|
|
59
|
+
- *First-party mock counted as boundary proof:* `vi.mock('@/lib/prisma')` cannot prove real persistence; patching a private helper cannot prove the code replaced. The `mock-internal-seam` scanner flags the JS module form, but an optional hit needs this semantic check. Your own thin adapter around a provider (`@/lib/stripe-client`) is the external boundary; declare it in `coverage.config.json` under `mockPolicy.externals` where the repo uses that topology.
|
|
60
60
|
- *Blind injected fake:* a `deps` fake returns rows whatever the query says, and the test asserts `findUnique({ where: { id } })`. Delete the tenant check and it stays green. No rule sees `deps` injection; read for it.
|
|
61
61
|
- *Mocked transaction:* "updates atomically" with `$transaction: (fn) => fn()`.
|
|
62
62
|
- *Layout in jsdom:* `toHaveClass('min-h-11')` to prove a 44px target. jsdom has no layout.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
1. Run the code and assert what it does; never match the text of docs, prompts, source files, or migrations.
|
|
4
4
|
2. Take expected values from the spec, an external contract, or the input, never from the code under test; pin versions to the major only.
|
|
5
|
-
3.
|
|
5
|
+
3. Prove transactions, tenant filters, locking, and idempotency against real database and service behavior; fake external providers, the clock, and randomness. Internal unit-test substitutes prove only the caller behavior they execute, not the replaced boundary. Preserve stricter adopted repository requirements.
|
|
6
6
|
4. Make every assertion able to fail, and assert everything the test name promises.
|
|
7
7
|
5. Test each behavior once, at the lowest level that proves it; delete tests of dead code.
|
|
8
8
|
6. Don't test config files (Dockerfiles, CI workflows, `cloudbuild.yaml`, merge-queue config, `package.json`, other JSON/YAML/TOML a tool reads); test the code that reads them.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: compliance-audit
|
|
3
3
|
version: 2.9.0
|
|
4
4
|
description: "Audit operations against financial-compliance checklists (AML/KYC, VARS, PCI-DSS, TPA oversight, onboarding, transaction monitoring). Produces tracker.md (with a tracker.xlsx export) and phase-trail.md with layered validation; cites evidence by original filename. Input: reg-parser or the built-in VARS checklist."
|
|
5
|
-
release-version: 0.
|
|
5
|
+
release-version: 0.45.0
|
|
6
6
|
---
|
|
7
7
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
8
8
|
# Compliance Audit
|
|
@@ -12,13 +12,9 @@ keyed by control item that the client can update through remediation —
|
|
|
12
12
|
alongside a phase trail companion file (work product) that preserves what each
|
|
13
13
|
phase saw before the tracker was finalised.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
services — payments, banking, fintech, insurance. They audit against financial
|
|
19
|
-
regulatory frameworks: AML regulations, KYC requirements, financial reporting
|
|
20
|
-
standards, local financial authority rules, and card-scheme standards such as
|
|
21
|
-
VARS.
|
|
15
|
+
Read [audience and report handoff](references/audience-and-reports.md) before starting;
|
|
16
|
+
it defines the auditor audience and the optional report-writing handoff without replacing
|
|
17
|
+
this assessment or its validation.
|
|
22
18
|
|
|
23
19
|
## Audit Workflow
|
|
24
20
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Audience and report handoff
|
|
2
|
+
|
|
3
|
+
The user is a **compliance auditor or analyst** working in regulated financial
|
|
4
|
+
services -- payments, banking, fintech, insurance. They audit against financial
|
|
5
|
+
regulatory frameworks: AML regulations, KYC requirements, financial reporting
|
|
6
|
+
standards, local financial authority rules, and card-scheme standards such as
|
|
7
|
+
VARS.
|
|
8
|
+
|
|
9
|
+
When the user also requests an analytical report, hand the validated tracker and phase trail
|
|
10
|
+
to `write-report` when installed. Its compliance branch owns audit, external, management and
|
|
11
|
+
VARS report writing; it does not replace this assessment or its validation. Without that skill,
|
|
12
|
+
deliver the audit artifacts and state that the report-writing stage remains outstanding.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: contract-compare
|
|
3
3
|
description: "Compare two or more contracts side-by-side for structured diff, gap analysis, and benchmarking. Use when: comparing contracts or agreements, contract diff, compare terms, vendor-vs-vendor, compare our template vs theirs, compliance gap between contracts. NOT for single-contract risk review — use contract-review for that."
|
|
4
|
-
release-version: 0.
|
|
4
|
+
release-version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
7
7
|
# Contract Compare
|
|
@@ -97,6 +97,22 @@ Wait for all dimension subagents to return.
|
|
|
97
97
|
|
|
98
98
|
## Step 4: Build Comparison Report
|
|
99
99
|
|
|
100
|
+
Required report-stage resource: the installed `house-style` skill. This skill remains available
|
|
101
|
+
as an ungrouped native selection; native Skills CLI does not install dependencies automatically.
|
|
102
|
+
Select `house-style` with `contract-compare`, or install the Core and Risk & Compliance npm packages.
|
|
103
|
+
Resolve its installed base directory, not a repository-only `skills/writing/` path.
|
|
104
|
+
|
|
105
|
+
Before drafting or substantively reviewing an analytical report, read
|
|
106
|
+
`{house-style baseDir}/references/analytical-reporting.md`,
|
|
107
|
+
`{house-style baseDir}/references/analytical-writing-patterns.md`, and
|
|
108
|
+
`{house-style baseDir}/references/definitions-and-metrics.md` directly. Follow their
|
|
109
|
+
loading and delegation instructions; report a missing or unreadable reference as a
|
|
110
|
+
blocker rather than claiming the report stage is complete. Apply them within the
|
|
111
|
+
requested scope, including a chat-only response; do not create a report for an
|
|
112
|
+
audit-only or narrower request. Preserve the selected dimensions, clause evidence,
|
|
113
|
+
assessments, legal caveats, optional mandate tracing, and the required report format.
|
|
114
|
+
Generic editorial checks do not replace specialist legal review.
|
|
115
|
+
|
|
100
116
|
**House style.** Use the nearest `WRITING.md`: start in the first contract's folder (pasted text: the output
|
|
101
117
|
folder, else the working directory), then parents up to the repository root; never the home
|
|
102
118
|
directory or above. Rate every issue from the evidence first; the style changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: contract-review
|
|
3
3
|
description: "Review contracts for legal, commercial, and compliance risks via convert → chunk review → merge → validate (+ optional mandate preprocessing). Use for reviewing, auditing, or checking any contract, agreement, NDA, MSA, or SLA; input a file path (PDF/DOCX/TXT) or pasted text."
|
|
4
|
-
release-version: 0.
|
|
4
|
+
release-version: 0.45.0
|
|
5
5
|
---
|
|
6
6
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
7
7
|
# Contract Review
|
|
@@ -106,6 +106,10 @@ Start all chunk subagents in parallel and wait for all to complete.
|
|
|
106
106
|
|
|
107
107
|
## Step 3: Merge Results
|
|
108
108
|
|
|
109
|
+
Before drafting or substantively reviewing the report, read and follow
|
|
110
|
+
[the analytical report-stage instructions](references/report-stage.md), including all three
|
|
111
|
+
required `house-style` references and their loading/delegation rules. Preserve Step 4 validation.
|
|
112
|
+
|
|
109
113
|
**House style.** Use the nearest `WRITING.md`: start in the contract file's folder (pasted text: the output
|
|
110
114
|
folder, else the working directory), then parents up to the repository root; never the home
|
|
111
115
|
directory or above. Rate every issue from the evidence first: the style changes wording, never a rating,
|
|
@@ -182,6 +186,7 @@ Substitute `{contract-review baseDir}` and `{reg-parser baseDir}` as in Step 2:
|
|
|
182
186
|
You are validating a contract review report for completeness and consistency.
|
|
183
187
|
|
|
184
188
|
Load the review criteria from: {contract-review baseDir}/references/review-criteria.md
|
|
189
|
+
Load the analytical reporting instructions from: {house-style baseDir}/references/analytical-reporting.md, {house-style baseDir}/references/analytical-writing-patterns.md, and {house-style baseDir}/references/definitions-and-metrics.md
|
|
185
190
|
Load any preprocessed mandate files from: {reg-parser baseDir}/references/mandates/ (read all .md files present)
|
|
186
191
|
Use mandate files to verify P10 annotations ([Mandated]/[Permitted]/[Counterparty-Added]) are accurate.
|
|
187
192
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Analytical report stage
|
|
2
|
+
|
|
3
|
+
Required report-stage resource: the installed `house-style` skill. This skill remains available
|
|
4
|
+
as an ungrouped native selection; native Skills CLI does not install dependencies automatically.
|
|
5
|
+
Select `house-style` with `contract-review`, or install the Core and Risk & Compliance npm packages.
|
|
6
|
+
Resolve its installed base directory, not a repository-only `skills/writing/` path.
|
|
7
|
+
|
|
8
|
+
Before drafting or substantively reviewing an analytical report, read
|
|
9
|
+
`{house-style baseDir}/references/analytical-reporting.md`,
|
|
10
|
+
`{house-style baseDir}/references/analytical-writing-patterns.md`, and
|
|
11
|
+
`{house-style baseDir}/references/definitions-and-metrics.md` directly. Follow their
|
|
12
|
+
loading and delegation instructions; report a missing or unreadable reference as a
|
|
13
|
+
blocker rather than claiming the report stage is complete. Apply them within the
|
|
14
|
+
requested scope, including a chat-only response; do not create a report for an
|
|
15
|
+
audit-only or narrower request. Preserve this skill's review criteria, evidence,
|
|
16
|
+
severity ratings, mandated layout, and Step 4 specialist validation. Generic editorial
|
|
17
|
+
checks do not replace legal validation.
|
|
@@ -3,7 +3,7 @@ name: doc-authenticity
|
|
|
3
3
|
version: 0.4.1
|
|
4
4
|
description: "Screen PDF documents and raster images for fabrication, tampering, Photoshop or other image-editor use, and content validity. Detects file type, runs format-specific authenticity forensics, classifies bank statements, conversation logs, invoices, agreements, and other documents, then applies type-specific validity checks. Produces separate authenticity (NO_EVIDENCE_OF_MODIFICATION / SUSPICIOUS / LIKELY_MODIFIED / INCONCLUSIVE) and validity (VALID / INVALID / INCONCLUSIVE) verdicts. Use whenever a user asks whether a document, screenshot, scan, statement, invoice, contract, chat log, receipt, or payment evidence is genuine, original, edited, Photoshopped, manipulated, fake, or valid."
|
|
5
5
|
disable-model-invocation: true
|
|
6
|
-
release-version: 0.
|
|
6
|
+
release-version: 0.45.0
|
|
7
7
|
---
|
|
8
8
|
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
9
9
|
# Document and Image Authenticity
|
|
@@ -117,6 +117,16 @@ future specialized profile is added.
|
|
|
117
117
|
|
|
118
118
|
### 5. Verdict and report
|
|
119
119
|
|
|
120
|
+
Before drafting or substantively reviewing an analytical report, read
|
|
121
|
+
`{house-style baseDir}/references/analytical-reporting.md`,
|
|
122
|
+
`{house-style baseDir}/references/analytical-writing-patterns.md`, and
|
|
123
|
+
`{house-style baseDir}/references/definitions-and-metrics.md` directly. Follow their
|
|
124
|
+
loading and delegation instructions; report a missing or unreadable reference as a
|
|
125
|
+
blocker rather than claiming the report stage is complete. Apply them within the
|
|
126
|
+
requested scope, including a chat-only response; do not create a report for an
|
|
127
|
+
audit-only or narrower request. Preserve forensic and validity methods, evidence,
|
|
128
|
+
independent verdicts, required checks, report layout, schema, and validation.
|
|
129
|
+
|
|
120
130
|
Read `references/verdict-and-report.md`. Apply its rubrics independently to:
|
|
121
131
|
|
|
122
132
|
- authenticity: `NO_EVIDENCE_OF_MODIFICATION | SUSPICIOUS | LIKELY_MODIFIED | INCONCLUSIVE`
|