@1aboveio/skills 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -2
- package/bin/cli.mjs +14 -0
- package/bin/select-core.mjs +172 -0
- package/package.json +146 -4
- package/skills/app-dev/airflow/LICENSE +3 -0
- package/skills/app-dev/airflow/SKILL.md +199 -0
- package/skills/app-dev/airflow/release-check.mjs +93 -0
- package/skills/app-dev/android-foundation/LICENSE +3 -0
- package/skills/app-dev/android-foundation/SKILL.md +192 -0
- package/skills/app-dev/android-foundation/assets/android-ci-job.yml +217 -0
- package/skills/app-dev/android-foundation/references/ci.md +87 -0
- package/skills/app-dev/android-foundation/references/gotchas.md +221 -0
- package/skills/app-dev/android-foundation/references/setup.md +164 -0
- package/skills/app-dev/android-foundation/release-check.mjs +93 -0
- package/skills/app-dev/android-foundation/scripts/device-run.sh +176 -0
- package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +172 -0
- package/skills/app-dev/app-debug/LICENSE +3 -0
- package/skills/app-dev/app-debug/SKILL.md +110 -0
- package/skills/app-dev/app-debug/references/common-errors.md +128 -0
- package/skills/app-dev/app-debug/release-check.mjs +93 -0
- package/skills/app-dev/better-auth/LICENSE +3 -0
- package/skills/app-dev/better-auth/SKILL.md +598 -0
- package/skills/app-dev/better-auth/references/feishu-api.md +270 -0
- package/skills/app-dev/better-auth/release-check.mjs +93 -0
- package/skills/app-dev/data-catalog/LICENSE +3 -0
- package/skills/app-dev/data-catalog/SKILL.md +204 -0
- package/skills/app-dev/data-catalog/agents/openai.yaml +3 -0
- package/skills/app-dev/data-catalog/references/data-catalog-conventions.md +75 -0
- package/skills/app-dev/data-catalog/references/field-definitions.md +116 -0
- package/skills/app-dev/data-catalog/references/format.md +121 -0
- package/skills/app-dev/data-catalog/release-check.mjs +93 -0
- package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +36 -0
- package/skills/app-dev/data-catalog/scripts/data_catalog.py +1392 -0
- package/skills/app-dev/data-catalog/scripts/persist-conventions-core.mjs +117 -0
- package/skills/app-dev/data-catalog/scripts/persist-conventions.mjs +17 -0
- package/skills/app-dev/data-catalog/scripts/test_data_catalog.py +571 -0
- package/skills/app-dev/ios-foundation/LICENSE +3 -0
- package/skills/app-dev/ios-foundation/SKILL.md +184 -0
- package/skills/app-dev/ios-foundation/references/setup.md +243 -0
- package/skills/app-dev/ios-foundation/release-check.mjs +93 -0
- package/skills/app-dev/monorepo/LICENSE +3 -0
- package/skills/app-dev/monorepo/SKILL.md +462 -0
- package/skills/app-dev/monorepo/release-check.mjs +93 -0
- package/skills/app-dev/nextjs-fullstack/LICENSE +3 -0
- package/skills/app-dev/nextjs-fullstack/SKILL.md +211 -0
- package/skills/app-dev/nextjs-fullstack/conventions.md +318 -0
- package/skills/app-dev/nextjs-fullstack/frontend-conventions.md +61 -0
- package/skills/app-dev/nextjs-fullstack/nextjs16.md +287 -0
- package/skills/app-dev/nextjs-fullstack/release-check.mjs +93 -0
- package/skills/app-dev/nextjs-fullstack/server-actions.md +409 -0
- package/skills/app-dev/prisma-setup/LICENSE +3 -0
- package/skills/app-dev/prisma-setup/SKILL.md +181 -0
- package/skills/app-dev/prisma-setup/nextjs.md +258 -0
- package/skills/app-dev/prisma-setup/release-check.mjs +93 -0
- package/skills/app-dev/prisma-setup/turborepo.md +301 -0
- package/skills/app-dev/pyspark/LICENSE +3 -0
- package/skills/app-dev/pyspark/SKILL.md +127 -0
- package/skills/app-dev/pyspark/assets/templates/etl.py +748 -0
- package/skills/app-dev/pyspark/assets/templates/utils/__init__.py +1 -0
- package/skills/app-dev/pyspark/assets/templates/utils/hudi_metadata.py +14 -0
- package/skills/app-dev/pyspark/references/diagnosis-and-profiling.md +169 -0
- package/skills/app-dev/pyspark/references/etl-contract.md +129 -0
- package/skills/app-dev/pyspark/references/production-validation.md +131 -0
- package/skills/app-dev/pyspark/references/reconciliation.md +38 -0
- package/skills/app-dev/pyspark/references/transformation-design.md +190 -0
- package/skills/app-dev/pyspark/references/velocity-feature-calculation.md +193 -0
- package/skills/app-dev/pyspark/release-check.mjs +93 -0
- package/skills/app-dev/pyspark/scripts/spark_eventlog_summary.py +223 -0
- package/skills/app-dev/python-backend/LICENSE +3 -0
- package/skills/app-dev/python-backend/SKILL.md +325 -0
- package/skills/app-dev/python-backend/assets/uv-install.sh +48 -0
- package/skills/app-dev/python-backend/references/uv-installs.md +83 -0
- package/skills/app-dev/python-backend/release-check.mjs +93 -0
- package/skills/app-dev/shadcn/LICENSE +3 -0
- package/skills/app-dev/shadcn/SKILL.md +120 -0
- package/skills/app-dev/shadcn/assets/shadcn-small.png +0 -0
- package/skills/app-dev/shadcn/assets/shadcn.png +0 -0
- package/skills/app-dev/shadcn/cli.md +411 -0
- package/skills/app-dev/shadcn/customization.md +224 -0
- package/skills/app-dev/shadcn/mcp.md +101 -0
- package/skills/app-dev/shadcn/release-check.mjs +93 -0
- package/skills/app-dev/shadcn/rules/base-vs-radix.md +323 -0
- package/skills/app-dev/shadcn/rules/component-selection.md +67 -0
- package/skills/app-dev/shadcn/rules/composition.md +195 -0
- package/skills/app-dev/shadcn/rules/data-table.md +201 -0
- package/skills/app-dev/shadcn/rules/forms.md +255 -0
- package/skills/app-dev/shadcn/rules/icons.md +103 -0
- package/skills/app-dev/shadcn/rules/styling.md +167 -0
- package/skills/app-dev/zod-v4/LICENSE +3 -0
- package/skills/app-dev/zod-v4/SKILL.md +286 -0
- package/skills/app-dev/zod-v4/release-check.mjs +93 -0
- package/skills/cicd/cloud-build/LICENSE +3 -0
- package/skills/cicd/cloud-build/SKILL.md +707 -0
- package/skills/cicd/cloud-build/release-check.mjs +93 -0
- package/skills/cicd/cloud-debug/LICENSE +3 -0
- package/skills/cicd/cloud-debug/SKILL.md +315 -0
- package/skills/cicd/cloud-debug/references/build-failures.md +238 -0
- package/skills/cicd/cloud-debug/references/deploy-failures.md +376 -0
- package/skills/cicd/cloud-debug/references/pipeline-failures.md +378 -0
- package/skills/cicd/cloud-debug/release-check.mjs +93 -0
- package/skills/cicd/cloud-deploy/LICENSE +3 -0
- package/skills/cicd/cloud-deploy/SKILL.md +230 -0
- package/skills/cicd/cloud-deploy/references/config-templates.md +257 -0
- package/skills/cicd/cloud-deploy/release-check.mjs +93 -0
- package/skills/cicd/docker/LICENSE +3 -0
- package/skills/cicd/docker/SKILL.md +151 -0
- package/skills/cicd/docker/release-check.mjs +93 -0
- package/skills/cicd/github-actions/LICENSE +3 -0
- package/skills/cicd/github-actions/SKILL.md +111 -0
- package/skills/cicd/github-actions/references/audit-profile-optimize.md +150 -0
- package/skills/cicd/github-actions/references/ci-case-studies.md +141 -0
- package/skills/cicd/github-actions/references/conditional-ci.md +214 -0
- package/skills/cicd/github-actions/references/debugging.md +13 -0
- package/skills/cicd/github-actions/references/pipeline.md +87 -0
- package/skills/cicd/github-actions/references/post-deploy-and-publishing.md +33 -0
- package/skills/cicd/github-actions/references/runners.md +253 -0
- package/skills/cicd/github-actions/references/security.md +29 -0
- package/skills/cicd/github-actions/references/speed-and-audit.md +115 -0
- package/skills/cicd/github-actions/references/two-pass-reading.md +92 -0
- package/skills/cicd/github-actions/release-check.mjs +93 -0
- package/skills/cicd/github-actions/scripts/ci-run-audit-core.mjs +612 -0
- package/skills/cicd/github-actions/scripts/ci-run-audit.mjs +4 -0
- package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +637 -0
- package/skills/cicd/github-flow/LICENSE +3 -0
- package/skills/cicd/github-flow/SKILL.md +123 -0
- package/skills/cicd/github-flow/references/ci-conventions.md +14 -0
- package/skills/cicd/github-flow/release-check.mjs +93 -0
- package/skills/cicd/github-flow/scripts/flow-core.mjs +105 -0
- package/skills/cicd/github-flow/scripts/flow.mjs +81 -0
- package/skills/cicd/github-flow/scripts/flow.test.mjs +114 -0
- package/skills/cicd/github-flow/scripts/persist-conventions-core.mjs +117 -0
- package/skills/cicd/github-flow/scripts/persist-conventions.mjs +49 -0
- package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +108 -0
- package/skills/cicd/google-cloud/LICENSE +3 -0
- package/skills/cicd/google-cloud/SKILL.md +119 -0
- package/skills/cicd/google-cloud/references/gcs.md +469 -0
- package/skills/cicd/google-cloud/references/iam.md +451 -0
- package/skills/cicd/google-cloud/references/project.md +349 -0
- package/skills/cicd/google-cloud/references/secrets.md +336 -0
- package/skills/cicd/google-cloud/references/vpc.md +312 -0
- package/skills/cicd/google-cloud/release-check.mjs +93 -0
- package/skills/cicd/google-cloud/scripts/create-sa.sh +36 -0
- package/skills/cicd/google-cloud/scripts/gcp-config.sh +31 -0
- package/skills/cicd/google-cloud/scripts/grant-iap.sh +41 -0
- package/skills/cicd/google-cloud/scripts/setup-secrets.sh +48 -0
- package/skills/cicd/mergify/LICENSE +3 -0
- package/skills/cicd/mergify/SKILL.md +102 -0
- package/skills/cicd/mergify/assets/templates/mergify.yml +215 -0
- package/skills/cicd/mergify/assets/templates/ruleset.json +46 -0
- package/skills/cicd/mergify/references/branch-protection.md +282 -0
- package/skills/cicd/mergify/references/configuration.md +274 -0
- package/skills/cicd/mergify/references/diagnosis.md +109 -0
- package/skills/cicd/mergify/references/stacks.md +84 -0
- package/skills/cicd/mergify/references/traps.md +119 -0
- package/skills/cicd/mergify/references/watch-contract.md +274 -0
- package/skills/cicd/mergify/release-check.mjs +93 -0
- package/skills/cicd/mergify/scripts/audit-core.mjs +208 -0
- package/skills/cicd/mergify/scripts/audit.mjs +4 -0
- package/skills/cicd/mergify/scripts/audit.test.mjs +201 -0
- package/skills/cicd/mergify/scripts/entrypoints.test.mjs +106 -0
- package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +30 -0
- package/skills/cicd/mergify/scripts/stack-push-core.mjs +258 -0
- package/skills/cicd/mergify/scripts/stack-push.mjs +4 -0
- package/skills/cicd/mergify/scripts/stack-push.test.mjs +233 -0
- package/skills/cicd/mergify/scripts/watch-pr-delivery-core.mjs +1065 -0
- package/skills/cicd/mergify/scripts/watch-pr-delivery.mjs +4 -0
- package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +1826 -0
- package/skills/cicd/podman/LICENSE +3 -0
- package/skills/cicd/podman/SKILL.md +71 -0
- package/skills/cicd/podman/agents/openai.yaml +4 -0
- package/skills/cicd/podman/assets/templates/podman-compose-socket-directory.yml +6 -0
- package/skills/cicd/podman/assets/templates/podman-service-override.conf +3 -0
- package/skills/cicd/podman/references/compose-compatibility.md +70 -0
- package/skills/cicd/podman/references/networking-and-ports.md +74 -0
- package/skills/cicd/podman/references/rootless-services-and-sockets.md +156 -0
- package/skills/cicd/podman/references/troubleshooting.md +98 -0
- package/skills/cicd/podman/release-check.mjs +93 -0
- package/skills/content/article-review/LICENSE +3 -0
- package/skills/content/article-review/SKILL.md +66 -0
- package/skills/content/article-review/references/report-format.md +68 -0
- package/skills/content/article-review/references/template-guide.md +79 -0
- package/skills/content/article-review/references/template-wechat-payments.md +125 -0
- package/skills/content/article-review/release-check.mjs +93 -0
- package/skills/content/article-to-image/LICENSE +3 -0
- package/skills/content/article-to-image/SKILL.md +91 -0
- package/skills/content/article-to-image/references/formats.md +53 -0
- package/skills/content/article-to-image/release-check.mjs +93 -0
- package/skills/content/flowchart-svg/LICENSE +3 -0
- package/skills/content/flowchart-svg/SKILL.md +43 -0
- package/skills/content/flowchart-svg/release-check.mjs +93 -0
- package/skills/content/flowchart-svg/scripts/export_png.sh +8 -0
- package/skills/content/image-gen/LICENSE +3 -0
- package/skills/content/image-gen/SKILL.md +192 -0
- package/skills/content/image-gen/release-check.mjs +93 -0
- package/skills/content/image-gen/scripts/credentials.mjs +217 -0
- package/skills/content/image-gen/scripts/credentials.test.mjs +212 -0
- package/skills/content/image-gen/scripts/generate.mjs +240 -0
- package/skills/content/image-gen/scripts/options.mjs +293 -0
- package/skills/content/image-gen/scripts/options.test.mjs +245 -0
- package/skills/content/mermaid/LICENSE +3 -0
- package/skills/content/mermaid/SKILL.md +635 -0
- package/skills/content/mermaid/release-check.mjs +93 -0
- package/skills/content/wechat-article-writer/LICENSE +3 -0
- package/skills/content/wechat-article-writer/SKILL.md +92 -0
- package/skills/content/wechat-article-writer/references/style-selector.md +133 -0
- package/skills/content/wechat-article-writer/references/writing-rules.md +152 -0
- package/skills/content/wechat-article-writer/release-check.mjs +93 -0
- package/skills/content/wechat-article-writer/templates/wechat-comparison.md +52 -0
- package/skills/content/wechat-article-writer/templates/wechat-howto.md +51 -0
- package/skills/content/wechat-article-writer/templates/wechat-insight.md +50 -0
- package/skills/content/wechat-article-writer/templates/wechat-pitfall.md +52 -0
- package/skills/content/wechat-publisher/LICENSE +3 -0
- package/skills/content/wechat-publisher/SKILL.md +171 -0
- package/skills/content/wechat-publisher/references/api.md +105 -0
- package/skills/content/wechat-publisher/references/layout-rules.md +57 -0
- package/skills/content/wechat-publisher/references/wechat-safe-template.html +86 -0
- package/skills/content/wechat-publisher/release-check.mjs +93 -0
- package/skills/content/wechat-publisher/scripts/md_to_wechat_html.py +194 -0
- package/skills/content/wechat-publisher/scripts/publish.py +239 -0
- package/skills/content/wechat-search/LICENSE +3 -0
- package/skills/content/wechat-search/SKILL.md +211 -0
- package/skills/content/wechat-search/release-check.mjs +93 -0
- package/skills/content/wechat-search/scripts/start-chrome.sh +83 -0
- package/skills/content/xai-search/LICENSE +3 -0
- package/skills/content/xai-search/SKILL.md +79 -0
- package/skills/content/xai-search/release-check.mjs +93 -0
- package/skills/content/xai-search/scripts/xai_search.sh +187 -0
- package/skills/content/xai-search/tests/smoke_test.sh +36 -0
- package/skills/core/distill-writing/LICENSE +3 -0
- package/skills/core/distill-writing/SKILL.md +74 -0
- package/skills/core/distill-writing/references/extraction.md +95 -0
- package/skills/core/distill-writing/references/updating.md +46 -0
- package/skills/core/distill-writing/release-check.mjs +93 -0
- package/skills/core/doc-to-md/LICENSE +3 -0
- package/skills/core/doc-to-md/SKILL.md +78 -0
- package/skills/core/doc-to-md/release-check.mjs +93 -0
- package/skills/core/doc-to-md/scripts/convert.py +157 -0
- package/skills/core/editorial-review/LICENSE +3 -0
- package/skills/core/editorial-review/SKILL.md +79 -0
- package/skills/core/editorial-review/references/checklist.md +94 -0
- package/skills/core/editorial-review/release-check.mjs +93 -0
- package/skills/core/house-style/LICENSE +3 -0
- package/skills/core/house-style/SKILL.md +33 -0
- package/skills/core/house-style/references/defaults.md +66 -0
- package/skills/core/house-style/references/rules.md +267 -0
- package/skills/core/house-style/references/sources.md +27 -0
- package/skills/core/house-style/references/style-en.md +131 -0
- package/skills/core/house-style/references/style-zh.md +141 -0
- package/skills/core/house-style/references/terminology-zh.md +223 -0
- package/skills/core/house-style/release-check.mjs +93 -0
- package/skills/core/house-style/templates/brd.md +103 -0
- package/skills/core/house-style/templates/commercial-proposal.md +93 -0
- package/skills/core/house-style/templates/compliance-policy.md +109 -0
- package/skills/core/house-style/templates/gap-analysis.md +105 -0
- package/skills/core/house-style/templates/general.md +63 -0
- package/skills/core/house-style/templates/integration-guide.md +98 -0
- package/skills/core/house-style/templates/prd.md +81 -0
- package/skills/core/house-style/templates/risk-operations-procedure.md +94 -0
- package/skills/core/house-style/templates/technical-spec.md +96 -0
- package/skills/core/polish-cn/LICENSE +3 -0
- package/skills/core/polish-cn/SKILL.md +102 -0
- package/skills/core/polish-cn/references/brief.md +93 -0
- package/skills/core/polish-cn/references/models.md +76 -0
- package/skills/core/polish-cn/release-check.mjs +93 -0
- package/skills/core/polish-cn/scripts/polish-cn.test.mjs +244 -0
- package/skills/core/polish-cn/scripts/polish_blocks.py +489 -0
- package/skills/core/reg-parser/LICENSE +3 -0
- package/skills/core/reg-parser/SKILL.md +212 -0
- package/skills/core/reg-parser/references/checklist-schema.md +223 -0
- package/skills/core/reg-parser/references/checklists/hk-amlo-checklist.json +1306 -0
- package/skills/core/reg-parser/references/checklists/hk-amlo-checklist.md +469 -0
- package/skills/core/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.json +634 -0
- package/skills/core/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.md +233 -0
- package/skills/core/reg-parser/references/checklists/hk-mso-guideline-checklist.json +2194 -0
- package/skills/core/reg-parser/references/checklists/hk-mso-guideline-checklist.md +771 -0
- package/skills/core/reg-parser/references/checklists/kyc-aml-checklist.md +258 -0
- package/skills/core/reg-parser/references/checklists/visa-vars-checklist.md +1058 -0
- package/skills/core/reg-parser/references/mandates/hk-amlo-cap615.md +389 -0
- package/skills/core/reg-parser/references/mandates/visa-vars.md +205 -0
- package/skills/core/reg-parser/release-check.mjs +93 -0
- package/skills/core/reg-parser/scripts/compare_checklist.py +230 -0
- package/skills/core/reg-parser/scripts/dump_checklist.py +361 -0
- package/skills/core/reg-parser/scripts/preprocess-mandate.sh +187 -0
- package/skills/core/reg-parser/scripts/reg-parser.test.mjs +165 -0
- package/skills/core/reg-parser/scripts/test_quarantine.sh +105 -0
- package/skills/core/reg-parser/scripts/validate_checklist.py +563 -0
- package/skills/core/reg-parser/scripts/validate_mandate.py +273 -0
- package/skills/core/terminology/LICENSE +3 -0
- package/skills/core/terminology/SKILL.md +62 -0
- package/skills/core/terminology/references/format.md +50 -0
- package/skills/core/terminology/references/init.md +32 -0
- package/skills/core/terminology/release-check.mjs +93 -0
- package/skills/core/write-doc/LICENSE +3 -0
- package/skills/core/write-doc/SKILL.md +141 -0
- package/skills/core/write-doc/references/bilingual.md +60 -0
- package/skills/core/write-doc/release-check.mjs +93 -0
- package/skills/engineering/better-review/LICENSE +3 -0
- package/skills/engineering/better-review/SKILL.md +249 -0
- package/skills/engineering/better-review/agents/openai.yaml +9 -0
- package/skills/engineering/better-review/references/domain-hazards.md +53 -0
- package/skills/engineering/better-review/references/passes.md +147 -0
- package/skills/engineering/better-review/references/result.md +151 -0
- package/skills/engineering/better-review/release-check.mjs +93 -0
- package/skills/engineering/better-review/scripts/pr-context.mjs +212 -0
- package/skills/engineering/better-review/scripts/pr-context.test.mjs +168 -0
- package/skills/engineering/better-review/scripts/rereview-scope.mjs +503 -0
- package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +587 -0
- package/skills/engineering/better-review/scripts/scan-diff.mjs +365 -0
- package/skills/engineering/better-review/scripts/scan-diff.test.mjs +414 -0
- package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +96 -0
- package/skills/engineering/e2e-test/LICENSE +3 -0
- package/skills/engineering/e2e-test/SKILL.md +98 -0
- package/skills/engineering/e2e-test/assets/ci-gates.cloudbuild.yaml +24 -0
- package/skills/engineering/e2e-test/references/authoring/auth-flows.md +159 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-config.md +73 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-patterns.md +144 -0
- package/skills/engineering/e2e-test/references/ci-integration.md +25 -0
- package/skills/engineering/e2e-test/references/ci-playwright-container.md +290 -0
- package/skills/engineering/e2e-test/references/presentation-sweep.md +104 -0
- package/skills/engineering/e2e-test/references/reviewing.md +41 -0
- package/skills/engineering/e2e-test/references/route-manifest.md +51 -0
- package/skills/engineering/e2e-test/release-check.mjs +93 -0
- package/skills/engineering/e2e-test/scripts/detect-routes-nextjs.mjs +200 -0
- package/skills/engineering/e2e-test/scripts/presentation-checks.mjs +171 -0
- package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +106 -0
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.mjs +179 -0
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +117 -0
- package/skills/engineering/e2e-test/scripts/presentation-reachability.mjs +154 -0
- package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +69 -0
- package/skills/engineering/e2e-test/scripts/presentation-render-health.mjs +141 -0
- package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +98 -0
- package/skills/engineering/e2e-test/scripts/presentation-sweep.mjs +147 -0
- package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +71 -0
- package/skills/engineering/e2e-test/scripts/presentation-temporal.mjs +127 -0
- package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +59 -0
- package/skills/engineering/e2e-test/scripts/project-route-manifest.mjs +82 -0
- package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +76 -0
- package/skills/engineering/e2e-test/scripts/validate-manifest.mjs +106 -0
- package/skills/engineering/engineering-runtime/LICENSE +3 -0
- package/skills/engineering/engineering-runtime/SKILL.md +11 -0
- package/skills/engineering/engineering-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/engineering-runtime/coherence/workflow.json +597 -0
- package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +68 -0
- package/skills/engineering/engineering-runtime/release-check.mjs +93 -0
- package/skills/engineering/engineering-runtime/scripts/exact-head-artifact.mjs +131 -0
- package/skills/engineering/engineering-runtime/scripts/head-check-set.mjs +398 -0
- package/skills/engineering/engineering-runtime/scripts/invocation-policy.mjs +187 -0
- package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +95 -0
- package/skills/engineering/engineering-runtime/scripts/main-module.mjs +79 -0
- package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +288 -0
- package/skills/engineering/engineering-runtime/scripts/mergify-yaml.mjs +11 -0
- package/skills/engineering/engineering-runtime/scripts/package-lock.json +43 -0
- package/skills/engineering/engineering-runtime/scripts/package.json +10 -0
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.mjs +223 -0
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +96 -0
- package/skills/engineering/engineering-runtime/scripts/review-completion.mjs +56 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +595 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +189 -0
- package/skills/engineering/engineering-runtime/scripts/yaml-mapping.mjs +18 -0
- package/skills/engineering/ensure-coverage/LICENSE +3 -0
- package/skills/engineering/ensure-coverage/SKILL.md +129 -0
- package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +92 -0
- package/skills/engineering/ensure-coverage/references/breadth/inventory-contract.md +85 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +44 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +16 -0
- package/skills/engineering/ensure-coverage/references/depth/characterization.md +68 -0
- package/skills/engineering/ensure-coverage/references/depth/coverage.config.example.json +19 -0
- package/skills/engineering/ensure-coverage/references/depth/grading.md +35 -0
- package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +57 -0
- package/skills/engineering/ensure-coverage/references/depth/test-smells.md +39 -0
- package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +44 -0
- package/skills/engineering/ensure-coverage/references/examples/coverage-ledger.md +110 -0
- package/skills/engineering/ensure-coverage/references/examples/refund-flow.md +35 -0
- package/skills/engineering/ensure-coverage/references/presentation/axis.md +64 -0
- package/skills/engineering/ensure-coverage/references/process/audit-mode.md +27 -0
- package/skills/engineering/ensure-coverage/references/process/output-template.md +139 -0
- package/skills/engineering/ensure-coverage/references/process/test-strategy.md +56 -0
- package/skills/engineering/ensure-coverage/release-check.mjs +93 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-config.schema.json +67 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-file.schema.json +140 -0
- package/skills/engineering/ensure-coverage/scripts/README.md +99 -0
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.mjs +182 -0
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +96 -0
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.mjs +105 -0
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +47 -0
- package/skills/engineering/ensure-coverage/scripts/ci-audit.mjs +137 -0
- package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +86 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.mjs +674 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +447 -0
- package/skills/engineering/ensure-coverage/scripts/design-parity.mjs +591 -0
- package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +552 -0
- package/skills/engineering/ensure-coverage/scripts/lint-tests.mjs +282 -0
- package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +289 -0
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs +176 -0
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +119 -0
- package/skills/engineering/ensure-coverage/scripts/package.json +19 -0
- package/skills/engineering/golden-path/LICENSE +3 -0
- package/skills/engineering/golden-path/SKILL.md +230 -0
- package/skills/engineering/golden-path/agents/openai.yaml +3 -0
- package/skills/engineering/golden-path/assets/golden-paths.example.json +57 -0
- package/skills/engineering/golden-path/references/contract.md +239 -0
- package/skills/engineering/golden-path/references/migration.md +111 -0
- package/skills/engineering/golden-path/release-check.mjs +93 -0
- package/skills/engineering/golden-path/scripts/golden-path-core.mjs +1779 -0
- package/skills/engineering/golden-path/scripts/golden-path.mjs +6 -0
- package/skills/engineering/golden-path/scripts/golden-path.test.mjs +1457 -0
- package/skills/engineering/harness-runtime/LICENSE +3 -0
- package/skills/engineering/harness-runtime/SKILL.md +19 -0
- package/skills/engineering/harness-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/harness-runtime/bin/discover-models.mjs +4 -0
- package/skills/engineering/harness-runtime/bin/model-catalog.mjs +4 -0
- package/skills/engineering/harness-runtime/contracts.md +15 -0
- package/skills/engineering/harness-runtime/discover-models.mjs +392 -0
- package/skills/engineering/harness-runtime/discover-models.test.mjs +363 -0
- package/skills/engineering/harness-runtime/fixtures/native-question-schemas.json +33 -0
- package/skills/engineering/harness-runtime/fixtures/question-responses.json +54 -0
- package/skills/engineering/harness-runtime/harness-runtime.test.mjs +967 -0
- package/skills/engineering/harness-runtime/index.mjs +767 -0
- package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +829 -0
- package/skills/engineering/harness-runtime/model-catalog.mjs +787 -0
- package/skills/engineering/harness-runtime/model-catalog.test.mjs +366 -0
- package/skills/engineering/harness-runtime/native-question-contracts.md +37 -0
- package/skills/engineering/harness-runtime/references/model-catalog-seed.json +408 -0
- package/skills/engineering/harness-runtime/references/model-catalog.md +57 -0
- package/skills/engineering/harness-runtime/release-check.mjs +93 -0
- package/skills/engineering/resolve-issues/LICENSE +3 -0
- package/skills/engineering/resolve-issues/SKILL.md +250 -0
- package/skills/engineering/resolve-issues/agents/openai.yaml +9 -0
- package/skills/engineering/resolve-issues/plugin-hooks.json +17 -0
- package/skills/engineering/resolve-issues/references/canary.md +28 -0
- package/skills/engineering/resolve-issues/references/ci.md +105 -0
- package/skills/engineering/resolve-issues/references/done.md +25 -0
- package/skills/engineering/resolve-issues/references/dropbox.md +90 -0
- package/skills/engineering/resolve-issues/references/expire.md +318 -0
- package/skills/engineering/resolve-issues/references/exploration.md +202 -0
- package/skills/engineering/resolve-issues/references/implementation.md +303 -0
- package/skills/engineering/resolve-issues/references/preflight.md +445 -0
- package/skills/engineering/resolve-issues/references/review.md +228 -0
- package/skills/engineering/resolve-issues/references/shared-modules.md +44 -0
- package/skills/engineering/resolve-issues/references/task-plan.md +264 -0
- package/skills/engineering/resolve-issues/release-check.mjs +93 -0
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.mjs +364 -0
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +280 -0
- package/skills/engineering/resolve-issues/scripts/discover-models.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/dropbox.mjs +473 -0
- package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +346 -0
- package/skills/engineering/resolve-issues/scripts/findings-reuse.mjs +98 -0
- package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +88 -0
- package/skills/engineering/resolve-issues/scripts/github-reviews.mjs +384 -0
- package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +264 -0
- package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +135 -0
- package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +79 -0
- package/skills/engineering/resolve-issues/scripts/issue-tree.mjs +162 -0
- package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +107 -0
- package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +14 -0
- package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +149 -0
- package/skills/engineering/resolve-issues/scripts/next-actions.mjs +856 -0
- package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +915 -0
- package/skills/engineering/resolve-issues/scripts/plan-sync.mjs +269 -0
- package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +156 -0
- package/skills/engineering/resolve-issues/scripts/preflight-models.mjs +736 -0
- package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +448 -0
- package/skills/engineering/resolve-issues/scripts/ready-check.mjs +185 -0
- package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +217 -0
- package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +98 -0
- package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +91 -0
- package/skills/engineering/resolve-issues/scripts/review-verdict.mjs +509 -0
- package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +1060 -0
- package/skills/engineering/resolve-issues/scripts/size-check.mjs +492 -0
- package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +458 -0
- package/skills/engineering/resolve-release/LICENSE +3 -0
- package/skills/engineering/resolve-release/SKILL.md +215 -0
- package/skills/engineering/resolve-release/agents/openai.yaml +8 -0
- package/skills/engineering/resolve-release/flows/cloud-run-canary.md +13 -0
- package/skills/engineering/resolve-release/flows/cloud-run.md +7 -0
- package/skills/engineering/resolve-release/flows/root-tag-npm.md +13 -0
- package/skills/engineering/resolve-release/flows/workspace-npm.md +22 -0
- package/skills/engineering/resolve-release/references/canary.md +51 -0
- package/skills/engineering/resolve-release/references/candidate.md +41 -0
- package/skills/engineering/resolve-release/references/cut.md +131 -0
- package/skills/engineering/resolve-release/references/dark-launch.md +66 -0
- package/skills/engineering/resolve-release/references/flows.md +150 -0
- package/skills/engineering/resolve-release/references/preflight.md +154 -0
- package/skills/engineering/resolve-release/references/prepared-metadata.md +260 -0
- package/skills/engineering/resolve-release/references/promotion.md +82 -0
- package/skills/engineering/resolve-release/references/publish.md +232 -0
- package/skills/engineering/resolve-release/references/workspace-npm.md +103 -0
- package/skills/engineering/resolve-release/release-check.mjs +93 -0
- package/skills/engineering/resolve-release/scripts/apply.mjs +212 -0
- package/skills/engineering/resolve-release/scripts/apply.test.mjs +99 -0
- package/skills/engineering/resolve-release/scripts/dark-flags.mjs +134 -0
- package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +100 -0
- package/skills/engineering/resolve-release/scripts/flow.mjs +500 -0
- package/skills/engineering/resolve-release/scripts/flow.test.mjs +340 -0
- package/skills/engineering/resolve-release/scripts/green-head.mjs +231 -0
- package/skills/engineering/resolve-release/scripts/green-head.test.mjs +101 -0
- package/skills/engineering/resolve-release/scripts/npm-version-absence.mjs +138 -0
- package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +426 -0
- package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +659 -0
- package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +317 -0
- package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +291 -0
- package/skills/engineering/resolve-release/scripts/plan.mjs +806 -0
- package/skills/engineering/resolve-release/scripts/plan.test.mjs +428 -0
- package/skills/engineering/rush-issues/LICENSE +3 -0
- package/skills/engineering/rush-issues/SKILL.md +58 -0
- package/skills/engineering/rush-issues/agents/openai.yaml +8 -0
- package/skills/engineering/rush-issues/rehydrate.mjs +10 -0
- package/skills/engineering/rush-issues/release-check.mjs +93 -0
- package/skills/engineering/rush-release/LICENSE +3 -0
- package/skills/engineering/rush-release/SKILL.md +35 -0
- package/skills/engineering/rush-release/agents/openai.yaml +8 -0
- package/skills/engineering/rush-release/release-check.mjs +93 -0
- package/skills/engineering/test-quality/LICENSE +3 -0
- package/skills/engineering/test-quality/SKILL.md +79 -0
- package/skills/engineering/test-quality/references/audit.md +80 -0
- package/skills/engineering/test-quality/references/lint.md +24 -0
- package/skills/engineering/test-quality/references/principles.md +143 -0
- package/skills/engineering/test-quality/references/testing-conventions.md +9 -0
- package/skills/engineering/test-quality/release-check.mjs +93 -0
- package/skills/engineering/test-quality/scripts/lint-tests.mjs +574 -0
- package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +591 -0
- package/skills/engineering/test-quality/scripts/mock-policy-config.mjs +176 -0
- package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +119 -0
- package/skills/engineering/test-quality/scripts/persist-conventions-core.mjs +117 -0
- package/skills/engineering/test-quality/scripts/persist-conventions.mjs +17 -0
- package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +104 -0
- package/skills/risk-compliance/compliance-audit/LICENSE +3 -0
- package/skills/risk-compliance/compliance-audit/SKILL.md +439 -0
- package/skills/risk-compliance/compliance-audit/references/findings-schema.md +293 -0
- package/skills/risk-compliance/compliance-audit/references/normalization-rules.md +45 -0
- package/skills/risk-compliance/compliance-audit/references/vars-checklist.md +1068 -0
- package/skills/risk-compliance/compliance-audit/references/vars-findings-schema.md +398 -0
- package/skills/risk-compliance/compliance-audit/release-check.mjs +93 -0
- package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +14 -0
- package/skills/risk-compliance/compliance-audit/scripts/export_tracker_xlsx.py +221 -0
- package/skills/risk-compliance/compliance-audit/scripts/reconcile_tracker.py +458 -0
- package/skills/risk-compliance/compliance-audit/scripts/test_export_tracker_xlsx.py +97 -0
- package/skills/risk-compliance/compliance-audit/scripts/test_validate_tracker.py +157 -0
- package/skills/risk-compliance/compliance-audit/scripts/validate_tracker.py +829 -0
- package/skills/risk-compliance/contract-compare/LICENSE +3 -0
- package/skills/risk-compliance/contract-compare/SKILL.md +199 -0
- package/skills/risk-compliance/contract-compare/references/comparison-dimensions.md +209 -0
- package/skills/risk-compliance/contract-compare/release-check.mjs +93 -0
- package/skills/risk-compliance/contract-review/LICENSE +3 -0
- package/skills/risk-compliance/contract-review/SKILL.md +240 -0
- package/skills/risk-compliance/contract-review/references/review-criteria.md +223 -0
- package/skills/risk-compliance/contract-review/release-check.mjs +93 -0
- package/skills/risk-compliance/doc-authenticity/LICENSE +3 -0
- package/skills/risk-compliance/doc-authenticity/SKILL.md +160 -0
- package/skills/risk-compliance/doc-authenticity/agents/openai.yaml +8 -0
- package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +12 -0
- package/skills/risk-compliance/doc-authenticity/references/agreement.md +66 -0
- package/skills/risk-compliance/doc-authenticity/references/bank-statement.md +150 -0
- package/skills/risk-compliance/doc-authenticity/references/forensic-signals.md +157 -0
- package/skills/risk-compliance/doc-authenticity/references/image-signals.md +114 -0
- package/skills/risk-compliance/doc-authenticity/references/invoice.md +66 -0
- package/skills/risk-compliance/doc-authenticity/references/issuer-profiles.md +86 -0
- package/skills/risk-compliance/doc-authenticity/references/verdict-and-report.md +95 -0
- package/skills/risk-compliance/doc-authenticity/references/verdict.schema.json +81 -0
- package/skills/risk-compliance/doc-authenticity/release-check.mjs +93 -0
- package/skills/risk-compliance/doc-authenticity/scripts/image_forensics.py +294 -0
- package/skills/risk-compliance/doc-authenticity/scripts/pdf_forensics.py +401 -0
- package/skills/risk-compliance/doc-authenticity/scripts/validate_codes.py +224 -0
- package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.py +308 -0
- package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +212 -0
- package/skills/risk-compliance/fraud-analysis/LICENSE +3 -0
- package/skills/risk-compliance/fraud-analysis/SKILL.md +114 -0
- package/skills/risk-compliance/fraud-analysis/references/archetypes/authorized-payment-scam.md +41 -0
- package/skills/risk-compliance/fraud-analysis/references/archetypes/first-party-fraud.md +44 -0
- package/skills/risk-compliance/fraud-analysis/references/archetypes/third-party-fraud.md +27 -0
- package/skills/risk-compliance/fraud-analysis/references/contexts/bank-transfer.md +24 -0
- package/skills/risk-compliance/fraud-analysis/references/contexts/card-payment.md +30 -0
- package/skills/risk-compliance/fraud-analysis/references/contexts/payment-collection.md +20 -0
- package/skills/risk-compliance/fraud-analysis/references/contexts/payout.md +20 -0
- package/skills/risk-compliance/fraud-analysis/references/feature-engineering.md +158 -0
- package/skills/risk-compliance/fraud-analysis/references/mechanisms/account-takeover.md +36 -0
- package/skills/risk-compliance/fraud-analysis/references/report-rationale.md +45 -0
- package/skills/risk-compliance/fraud-analysis/references/report-template.md +190 -0
- package/skills/risk-compliance/fraud-analysis/references/review-checklist.md +175 -0
- package/skills/risk-compliance/fraud-analysis/references/taxonomy.md +79 -0
- package/skills/risk-compliance/fraud-analysis/references/terminology.md +108 -0
- package/skills/risk-compliance/fraud-analysis/references/workflow.md +175 -0
- package/skills/risk-compliance/fraud-analysis/release-check.mjs +93 -0
- package/skills/risk-compliance/payment-analysis/LICENSE +3 -0
- package/skills/risk-compliance/payment-analysis/SKILL.md +180 -0
- package/skills/risk-compliance/payment-analysis/references/auth-rate-actions.md +30 -0
- package/skills/risk-compliance/payment-analysis/references/chargebacks.md +208 -0
- package/skills/risk-compliance/payment-analysis/references/chinese-polish.md +51 -0
- package/skills/risk-compliance/payment-analysis/references/event-layers.md +127 -0
- package/skills/risk-compliance/payment-analysis/references/fx.md +59 -0
- package/skills/risk-compliance/payment-analysis/references/journey.md +79 -0
- package/skills/risk-compliance/payment-analysis/references/metrics.md +67 -0
- package/skills/risk-compliance/payment-analysis/references/report-template.md +119 -0
- package/skills/risk-compliance/payment-analysis/references/terminology.md +95 -0
- package/skills/risk-compliance/payment-analysis/references/visualization.md +56 -0
- package/skills/risk-compliance/payment-analysis/release-check.mjs +93 -0
- package/skills/risk-compliance/report-writing/LICENSE +3 -0
- package/skills/risk-compliance/report-writing/SKILL.md +220 -0
- package/skills/risk-compliance/report-writing/references/audit-report-template.md +121 -0
- package/skills/risk-compliance/report-writing/references/external-assessment-template.md +167 -0
- package/skills/risk-compliance/report-writing/references/management-report-template.md +145 -0
- package/skills/risk-compliance/report-writing/references/vars-report-template.md +224 -0
- package/skills/risk-compliance/report-writing/release-check.mjs +93 -0
- package/skills/risk-compliance/similar-domain/LICENSE +3 -0
- package/skills/risk-compliance/similar-domain/SKILL.md +203 -0
- package/skills/risk-compliance/similar-domain/references/entities.md +67 -0
- package/skills/risk-compliance/similar-domain/references/fingerprints.md +134 -0
- package/skills/risk-compliance/similar-domain/references/pivots.md +82 -0
- package/skills/risk-compliance/similar-domain/references/report-template.md +93 -0
- package/skills/risk-compliance/similar-domain/references/scoring.md +130 -0
- package/skills/risk-compliance/similar-domain/references/terminology.md +41 -0
- package/skills/risk-compliance/similar-domain/references/workflow.md +85 -0
- package/skills/risk-compliance/similar-domain/release-check.mjs +93 -0
- package/skills/risk-compliance/tld-detection/LICENSE +3 -0
- package/skills/risk-compliance/tld-detection/SKILL.md +245 -0
- package/skills/risk-compliance/tld-detection/agents/openai.yaml +9 -0
- package/skills/risk-compliance/tld-detection/references/chinese-polish.md +55 -0
- package/skills/risk-compliance/tld-detection/references/clean.md +51 -0
- package/skills/risk-compliance/tld-detection/references/clustering.md +235 -0
- package/skills/risk-compliance/tld-detection/references/decision.md +189 -0
- package/skills/risk-compliance/tld-detection/references/fx-conversion.md +232 -0
- package/skills/risk-compliance/tld-detection/references/report-template.md +272 -0
- package/skills/risk-compliance/tld-detection/references/streams.md +141 -0
- package/skills/risk-compliance/tld-detection/references/terminology.md +95 -0
- package/skills/risk-compliance/tld-detection/references/workflow.md +95 -0
- package/skills/risk-compliance/tld-detection/release-check.mjs +93 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.py +390 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +14 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.py +650 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +14 -0
- package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +134 -0
- package/skills/risk-compliance/tld-detection/tests/test_detect_streams.py +520 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Companion utilities for the bundled ETL template."""
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Safe default for repositories without a scoped Hudi metadata index.
|
|
2
|
+
|
|
3
|
+
Replace this helper with repository-owned read/write metadata configuration when
|
|
4
|
+
the target cluster maintains a Hudi metadata table. Returning no options keeps
|
|
5
|
+
the ETL template from enabling an index that writers may not maintain.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def hudi_metadata_write_options(table: str) -> Dict[str, str]:
|
|
12
|
+
"""Return no table-specific Hudi metadata overrides by default."""
|
|
13
|
+
del table
|
|
14
|
+
return {}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Diagnosis And Profiling
|
|
2
|
+
|
|
3
|
+
Use this reference to decide whether a Spark job is fast enough, identify the
|
|
4
|
+
largest performance gap, and determine whether a canary is ready for write and
|
|
5
|
+
reconciliation. Focus on evidence and outcome; choose environment-specific
|
|
6
|
+
commands from the available runtime.
|
|
7
|
+
|
|
8
|
+
## When Profiling Is Required
|
|
9
|
+
|
|
10
|
+
Profiling is optional during production validation. It is **required** when
|
|
11
|
+
**either**:
|
|
12
|
+
|
|
13
|
+
1. The small-sample canary (typically one month) wall time exceeds **5 minutes**
|
|
14
|
+
**and** the run was **not** resource-constrained (queued, under-provisioned
|
|
15
|
+
executors, competing warehouse work).
|
|
16
|
+
2. **Any** job — canary, authorized write, or a scheduled production run —
|
|
17
|
+
exceeds **30 minutes**. This is a hard gate. Resource contention does not
|
|
18
|
+
waive it.
|
|
19
|
+
|
|
20
|
+
Otherwise skip. When required, parse the event log and compare an isolated
|
|
21
|
+
baseline on the same sample and resource profile. Keep validate-only time
|
|
22
|
+
separate from write time.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
set -o pipefail
|
|
26
|
+
hdfs dfs -cat "$EVENT_LOG" | \
|
|
27
|
+
python {baseDir}/scripts/spark_eventlog_summary.py > canary-summary.json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Performance Target
|
|
31
|
+
|
|
32
|
+
Use this default target unless the repository defines a stricter one:
|
|
33
|
+
|
|
34
|
+
- A medium batch job with fewer than 10 million input records should complete
|
|
35
|
+
within 5 minutes under properly isolated profiling conditions.
|
|
36
|
+
- Measure one complete scheduled job, not a selected fast stage.
|
|
37
|
+
- Report compute/validation, publication, and end-to-end wall time separately.
|
|
38
|
+
- A validate-only canary must meet the 5-minute compute/validation target, but it
|
|
39
|
+
does not prove publication or end-to-end write performance.
|
|
40
|
+
- Define a separate explicit target for larger datasets, streaming jobs, or jobs
|
|
41
|
+
whose required behavior is inherently outside this workload class.
|
|
42
|
+
|
|
43
|
+
Treat the target as failed until comparable evidence proves it passed.
|
|
44
|
+
|
|
45
|
+
## Require An Isolated, Comparable Profile
|
|
46
|
+
|
|
47
|
+
Accept a baseline or candidate profile only when all of these are fixed and
|
|
48
|
+
recorded:
|
|
49
|
+
|
|
50
|
+
- exact code hash and Spark, Python, Java, and table-format runtimes;
|
|
51
|
+
- immutable source snapshot and input-row denominator;
|
|
52
|
+
- equivalent job mode, history scope, validation, and write mode;
|
|
53
|
+
- stable executor/resource configuration and YARN queue;
|
|
54
|
+
- no competing Spark or warehouse workload that can materially consume the
|
|
55
|
+
same CPU, memory, network, disk, metastore, or source systems;
|
|
56
|
+
- readable driver logs, executor/container logs, and retained Spark event log;
|
|
57
|
+
- explicit statement of whether scheduler/queue wait and publication are
|
|
58
|
+
included in the reported time.
|
|
59
|
+
|
|
60
|
+
If isolation or scope equivalence cannot be established, mark the comparison
|
|
61
|
+
inconclusive instead of attributing the difference to code.
|
|
62
|
+
|
|
63
|
+
## Improve Logic, Not Parameters
|
|
64
|
+
|
|
65
|
+
Apply these rules to every performance change:
|
|
66
|
+
|
|
67
|
+
- Reduce physical work at the same input scope, resource profile, and required
|
|
68
|
+
behavior.
|
|
69
|
+
- Prefer fewer scans, pairs, rows, passes, shuffles, sorts, Python crossings,
|
|
70
|
+
state copies, and writes.
|
|
71
|
+
- Fix unbounded joins, repeated computation, poor state shape, missing pruning,
|
|
72
|
+
hot-key algorithms, and write amplification in the job logic or data layout.
|
|
73
|
+
- Do not claim a performance fix from changing shuffle partitions, executor
|
|
74
|
+
count/cores/memory, timeouts, broadcast thresholds or hints, AQE switches,
|
|
75
|
+
repartition counts, cache/persistence, or retry settings. Raising Spark or
|
|
76
|
+
Hudi shuffle parallelism also creates small files on the write path; leave
|
|
77
|
+
those settings unset.
|
|
78
|
+
- Do not meet the target by dropping history, rows, columns, validations,
|
|
79
|
+
formulas, or publication work required by the job.
|
|
80
|
+
- Classify a proven cluster, storage, or configuration defect as an operational
|
|
81
|
+
issue. Correct and measure it separately; do not present it as a logic
|
|
82
|
+
optimization.
|
|
83
|
+
|
|
84
|
+
Accept a candidate only when its measured gain comes from a better computation
|
|
85
|
+
shape rather than more resources or relaxed work.
|
|
86
|
+
|
|
87
|
+
## Use The Evidence Source That Answers The Question
|
|
88
|
+
|
|
89
|
+
| Evidence source | Use it to determine |
|
|
90
|
+
|---|---|
|
|
91
|
+
| YARN ResourceManager, application report, and container status | Queue/allocation delay, application attempts, executor/container loss, resource contention, and final lifecycle state |
|
|
92
|
+
| Live Spark UI | Current jobs, stages, SQL executions, executors, task skew, shuffle, spill, GC, storage, and active bottlenecks |
|
|
93
|
+
| Spark History Server | The same Spark execution evidence after completion when retained event logs are available |
|
|
94
|
+
| Retained Spark event log and `scripts/spark_eventlog_summary.py` | Durable stage-attempt/task metrics, final adaptive plan-pattern counts, output evidence, and baseline/candidate comparison |
|
|
95
|
+
| Spark History Server REST API | Programmatic job, stage, task-summary, executor, SQL-plan, and environment evidence |
|
|
96
|
+
| YARN driver and executor/container logs | OOM, fetch failure, retries, executor loss, Python/JVM exceptions, writer behavior, and commit boundaries |
|
|
97
|
+
| Logical/physical plans and SQL runtime statistics | Scans, joins, exchanges, sorts, windows, Python nodes, estimated/runtime cardinality, and optimizer decisions |
|
|
98
|
+
| Source/table statistics, file/partition metadata, and table-format timeline | Input size, file shape, partition coverage, stale statistics, write amplification, and commit evidence |
|
|
99
|
+
| Cluster metrics such as Prometheus, Grafana, JMX, or node telemetry | CPU, memory, GC, disk, network, and infrastructure saturation outside the Spark plan |
|
|
100
|
+
| Code and test inspection | Unbounded joins, repeated actions, unnecessary scans, collect/explode growth, UDF boundaries, incorrect history scope, and missing plan-shape protection |
|
|
101
|
+
|
|
102
|
+
Use code inference to form a hypothesis when runtime evidence is incomplete.
|
|
103
|
+
Do not present inference alone as measured performance proof.
|
|
104
|
+
|
|
105
|
+
## Identify The Dominant Gap
|
|
106
|
+
|
|
107
|
+
Name the dominant gap before changing code. Classify it as one or more of:
|
|
108
|
+
|
|
109
|
+
- queue, allocation, startup, or dependency delay;
|
|
110
|
+
- source listing, scan, partition pruning, or small-file overhead;
|
|
111
|
+
- intermediate cardinality explosion from join, explode, or repeated grouping;
|
|
112
|
+
- shuffle, sort, exchange, or network transfer;
|
|
113
|
+
- hot-key or partition skew and straggler tasks;
|
|
114
|
+
- Python serialization, UDF, or whole-group memory overhead;
|
|
115
|
+
- JVM/Python memory pressure, GC, spill, or executor loss;
|
|
116
|
+
- driver collection, planning, or result-size pressure;
|
|
117
|
+
- repeated computation across Spark actions;
|
|
118
|
+
- table writer, file layout, commit, or downstream storage latency.
|
|
119
|
+
|
|
120
|
+
Require an evidence chain:
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
performance target gap
|
|
124
|
+
-> application/job/stage/task evidence
|
|
125
|
+
-> physical-plan or runtime operator
|
|
126
|
+
-> responsible transformation or infrastructure constraint
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Fix the earliest responsible cause in that chain. Do not tune unrelated Spark
|
|
130
|
+
settings merely because the slow work becomes visible at a later action.
|
|
131
|
+
|
|
132
|
+
## Resolution Workflow
|
|
133
|
+
|
|
134
|
+
1. **Measure performance:** capture an isolated baseline and quantify the gap to
|
|
135
|
+
the 5-minute target using aggregate-only evidence.
|
|
136
|
+
2. **Identify the gap:** locate the dominant job/stage/task and connect it to a
|
|
137
|
+
plan operator, code shape, data skew, writer, or infrastructure constraint.
|
|
138
|
+
3. **Make the fix:** reduce the responsible logical or physical work without
|
|
139
|
+
tuning parameters, adding resources, or weakening output identity, ordering,
|
|
140
|
+
boundaries, arithmetic, history, validation, or write behavior.
|
|
141
|
+
4. **Validate locally:** prove required behavior, boundary cases, and the
|
|
142
|
+
intended physical-plan change with focused tests. Do not treat local Spark as
|
|
143
|
+
cluster parity.
|
|
144
|
+
5. **Production validation:** one-month (typical) sample: canary, optional
|
|
145
|
+
profile (5-minute unconstrained canary **or** any job over 30 minutes),
|
|
146
|
+
authorized write, then reconciliation.
|
|
147
|
+
|
|
148
|
+
Repeat the loop when the target is still missed or the dominant gap moves.
|
|
149
|
+
|
|
150
|
+
## Minimum Evidence
|
|
151
|
+
|
|
152
|
+
- **Scope:** target, input-row denominator, snapshot/date range, and
|
|
153
|
+
validate-only or write-enabled mode.
|
|
154
|
+
- **Run identity:** baseline/candidate application IDs and code hashes, plus
|
|
155
|
+
confirmation of the same runtime, resources, and isolation conditions.
|
|
156
|
+
- **Performance:** wall time, dominant stage, maximum task, cardinality,
|
|
157
|
+
shuffle/spill, logic change, and pass/fail against the 5-minute target.
|
|
158
|
+
- **Correctness:** local plan/boundary results, canary blocker/output status,
|
|
159
|
+
and cluster reconciliation (aggregates + bidirectional parity).
|
|
160
|
+
- **Delivery:** cluster application IDs, published hash/commit, reconciliation
|
|
161
|
+
result when a write ran, and remaining limitations.
|
|
162
|
+
|
|
163
|
+
Keep evidence aggregate-only. Never print credentials or entity-level rows.
|
|
164
|
+
|
|
165
|
+
## Primary Spark References
|
|
166
|
+
|
|
167
|
+
- [Monitoring and Instrumentation](https://spark.apache.org/docs/latest/monitoring.html)
|
|
168
|
+
- [Running Spark on YARN](https://spark.apache.org/docs/latest/running-on-yarn.html)
|
|
169
|
+
- [Spark SQL Performance Tuning](https://spark.apache.org/docs/latest/sql-performance-tuning.html)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# ETL Contract
|
|
2
|
+
|
|
3
|
+
Read this reference during Step 1 before creating or changing a Spark ETL job.
|
|
4
|
+
Use [the complete ETL module](../assets/templates/etl.py) when the repository
|
|
5
|
+
does not already provide an equivalent base module. Prefer and extend an
|
|
6
|
+
established repository module instead of introducing a parallel framework.
|
|
7
|
+
|
|
8
|
+
The bundled `etl.py` is derived from a complete production implementation. It
|
|
9
|
+
retains every source adapter, session helper, and writer, with template-only
|
|
10
|
+
fixes for empty repartition settings, recursive CLI flags, logging, and a safe
|
|
11
|
+
Hudi metadata default.
|
|
12
|
+
|
|
13
|
+
## Included ETL Modules
|
|
14
|
+
|
|
15
|
+
| Module | Included behavior |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Spark session helpers | Native Spark and Spark Connect creation, active-runtime detection, nested leases, and ownership-safe shutdown |
|
|
18
|
+
| `Etl` | Date-scoped extraction, full/per-day execution, schema completion, partition preparation, Spark/Hudi publication, and CLI entry point |
|
|
19
|
+
| `MongoDbEtl` | MongoDB connector extraction with optional declared schema |
|
|
20
|
+
| `JdbcEtl` | Predicate-scoped JDBC extraction, fetch sizing, and partitioned reads when date bounds are available |
|
|
21
|
+
| `MySqlEtl` | MySQL JDBC driver specialization |
|
|
22
|
+
| `MsSqlEtl` | SQL Server quoting, URL-property handling, SSL defaults, and single-partition extraction for redirect-sensitive servers |
|
|
23
|
+
| `JsonEtl` | Recursive JSON extraction with optional schema |
|
|
24
|
+
| `CsvEtl` | Recursive/header-aware CSV extraction with optional schema |
|
|
25
|
+
|
|
26
|
+
## Declare The Contract Before Transformation Logic
|
|
27
|
+
|
|
28
|
+
| Surface | Required declarations | `etl.py` mapping |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| Input parameters | Names, defaults, validation, secrets by reference, and source scope | constructor and `run_from_cli`; `start_date`, `end_date`, `url`, `bulk` |
|
|
31
|
+
| Runtime | Exact Python and PySpark versions | deployment/runtime files outside the class; verify before session creation |
|
|
32
|
+
| Concurrency | Overlap policy, idempotency, lock ownership, and retry/restart behavior | `concurrency_mode`, `zookeeper`, Hudi lock key/options, scheduler policy |
|
|
33
|
+
| Output table | Destination and `spark_table` versus `hudi_table` | `dst_db`, `dst_tbl`, `path`, `table_type` |
|
|
34
|
+
| Output identity | Complete record key and schema | `id`, transformed DataFrame schema |
|
|
35
|
+
| Output layout | Partition columns and Hudi conflict order | `par_cols`, `ts` precombine field |
|
|
36
|
+
| Write behavior | Append, overwrite, upsert, bulk insert, or insert overwrite | `hudi_mode`, `hudi_mode_override`, `load_hudi`, `load_spark` |
|
|
37
|
+
| Spark runtime | Native Spark versus Spark Connect and session owner | `create_spark_session`, `managed_spark_session`, `spark_remote` |
|
|
38
|
+
| Processing scope | Full versus incremental/per-day | `bulk`, `filter_by`, `offset`, `start_date`, `end_date`, `process` |
|
|
39
|
+
| Incremental state | Watermark, lookback/checkpoint, restart boundary, and late-data behavior | `filter_by`, `offset`, subclass/checkpoint implementation |
|
|
40
|
+
|
|
41
|
+
Do not design the transformation until every applicable surface has an explicit
|
|
42
|
+
value. Reject defaults that can silently change data scope, key semantics,
|
|
43
|
+
concurrency, or publication behavior.
|
|
44
|
+
|
|
45
|
+
## Adapt Repository-Specific Dependencies
|
|
46
|
+
|
|
47
|
+
The complete module depends on its source warehouse. Resolve each dependency
|
|
48
|
+
before reuse:
|
|
49
|
+
|
|
50
|
+
- The bundled [`utils/hudi_metadata.py`](../assets/templates/utils/hudi_metadata.py)
|
|
51
|
+
returns no metadata overrides. Replace it only when the target repository
|
|
52
|
+
maintains a scoped Hudi metadata index on both reads and writes.
|
|
53
|
+
- Pin compatible PySpark, pandas, python-dateutil, Typer, and typing-extensions
|
|
54
|
+
versions.
|
|
55
|
+
- Provide the Hudi Spark bundle and Hive sync configuration expected by the
|
|
56
|
+
target cluster.
|
|
57
|
+
- Provide MongoDB, MySQL, and SQL Server connector/driver artifacts only for the
|
|
58
|
+
adapters the job uses.
|
|
59
|
+
- Replace Zookeeper lock endpoints, base path, port, and lock ownership with the
|
|
60
|
+
target repository's concurrency mechanism.
|
|
61
|
+
- Review Hudi key generator, complex-key encoding, metadata, schema reconcile,
|
|
62
|
+
initial-load fallback, and write operation against the deployed Hudi version.
|
|
63
|
+
- Route connection strings and credentials through the repository's secret
|
|
64
|
+
mechanism. Do not place secret values in class attributes, CLI examples, or
|
|
65
|
+
logs.
|
|
66
|
+
|
|
67
|
+
Remove unused adapters only after confirming no job imports them. Keep the
|
|
68
|
+
bundled asset as the reference and adapt a copy inside the target repository.
|
|
69
|
+
|
|
70
|
+
## Close Contract Gaps Before Use
|
|
71
|
+
|
|
72
|
+
The bundled module implements `extract -> transform -> load`. Before adopting
|
|
73
|
+
it as a job base, require the target repository to add or confirm:
|
|
74
|
+
|
|
75
|
+
- an aggregate validation boundary before every `load` path;
|
|
76
|
+
- an in-job validate-only guard that logs publication was skipped;
|
|
77
|
+
- complete output-identity and required-column checks;
|
|
78
|
+
- explicit overlapping-run and idempotency behavior;
|
|
79
|
+
- exact source snapshot/restart semantics for incremental runs;
|
|
80
|
+
- focused tests for native/Connect, full/incremental, and selected adapters;
|
|
81
|
+
- independent post-write reconciliation.
|
|
82
|
+
|
|
83
|
+
Do not hide these gaps in wrapper scripts. Validation and no-write controls
|
|
84
|
+
belong before the writer in the job process.
|
|
85
|
+
|
|
86
|
+
## Contract Rules
|
|
87
|
+
|
|
88
|
+
- Pin validation and publication to the same immutable source boundary.
|
|
89
|
+
- Treat `ts` as Hudi conflict-resolution/precombine order, not physical row
|
|
90
|
+
sort order.
|
|
91
|
+
- Declare partition columns independently from record keys.
|
|
92
|
+
- Reject Hudi output without a complete record key and precombine field.
|
|
93
|
+
- Reject incremental mode without a filter/watermark and exact restart boundary.
|
|
94
|
+
- Reject optimistic concurrency without a working lock provider.
|
|
95
|
+
- Do not rely on scheduler timing as the single-writer guarantee.
|
|
96
|
+
- Do not set `spark.sql.shuffle.partitions` or Hudi
|
|
97
|
+
`hoodie.insert.shuffle.parallelism` / `hoodie.upsert.shuffle.parallelism` /
|
|
98
|
+
`hoodie.bulkinsert.shuffle.parallelism`. A raised shuffle partition count
|
|
99
|
+
becomes one small file per task on the write path. Size files with
|
|
100
|
+
`HudiLayout` (default one ~128MB file per partition), not shuffle parallelism.
|
|
101
|
+
- Keep bulk inserts physically grouped and sorted by partition with
|
|
102
|
+
`hoodie.bulkinsert.sort.mode=PARTITION_PATH_REPARTITION_AND_SORT`; override it
|
|
103
|
+
through `extra_hudi_options` only when the job contract requires another layout.
|
|
104
|
+
|
|
105
|
+
### Repair small files
|
|
106
|
+
|
|
107
|
+
Existing tables written with high shuffle parallelism stay small-file until
|
|
108
|
+
rewritten. Use `Etl.rewrite_hudi_layout` (same keys, partitions, locks, and
|
|
109
|
+
`HudiLayout`). Restrict with a partition predicate when the table is large.
|
|
110
|
+
Do not set shuffle parallelism on the rewrite either.
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
job = MyEtl(start_date="2026-08-01", end_date="2026-08-02")
|
|
114
|
+
job.rewrite_hudi_layout("dt = '2026-08-01'") # one partition
|
|
115
|
+
# job.rewrite_hudi_layout() # whole table
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- Do not present `repartition`, JDBC partition count, fetch size, or writer
|
|
119
|
+
option changes as logic optimization; classify required configuration fixes
|
|
120
|
+
as separate operational work.
|
|
121
|
+
|
|
122
|
+
## Minimum Review Evidence
|
|
123
|
+
|
|
124
|
+
- Contract fields and runtime dependencies are explicit.
|
|
125
|
+
- The selected adapter is tested against its real connector/runtime.
|
|
126
|
+
- Writer options match table type, key, order, partitions, concurrency, and
|
|
127
|
+
write mode.
|
|
128
|
+
- Validation and validate-only controls precede every writer.
|
|
129
|
+
- Full/incremental and native/Connect paths used by the job are covered.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Production Validation
|
|
2
|
+
|
|
3
|
+
Playbook for workflow step 5: **canary → (optional) profile → write →
|
|
4
|
+
reconciliation** on the cluster. Use a **small sample**, typically **one month**
|
|
5
|
+
of source data. Bind canary and write to the same pinned snapshot. Local tests
|
|
6
|
+
do not substitute.
|
|
7
|
+
|
|
8
|
+
## Fail-Closed Admission
|
|
9
|
+
|
|
10
|
+
Do not launch until all applicable facts are recorded and valid:
|
|
11
|
+
|
|
12
|
+
- exact commit/module hash;
|
|
13
|
+
- production Spark, Python, Java, and table-format runtimes;
|
|
14
|
+
- source snapshot or date boundary (the one-month sample);
|
|
15
|
+
- scheduler pause/ownership state;
|
|
16
|
+
- zero competing warehouse work;
|
|
17
|
+
- explicit validate-only or write-enabled mode;
|
|
18
|
+
- durable writable log and event-log destination;
|
|
19
|
+
- restart/recovery plan for writes.
|
|
20
|
+
|
|
21
|
+
Classify existing processes and working-tree changes before touching them. Do
|
|
22
|
+
not kill or overwrite another operator's work.
|
|
23
|
+
|
|
24
|
+
## 1. Canary
|
|
25
|
+
|
|
26
|
+
Implement the validate-only guard **in the Spark job**, not only in a wrapper.
|
|
27
|
+
Validate with one aggregate action, then return before any writer.
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import json
|
|
31
|
+
|
|
32
|
+
from pyspark.sql import functions as F
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def validate_candidate(candidate):
|
|
36
|
+
# first() is a Spark action: it executes the lazy transform plan.
|
|
37
|
+
metrics = candidate.agg(
|
|
38
|
+
F.count("*").alias("row_count"),
|
|
39
|
+
F.countDistinct("event_id").alias("distinct_event_count"),
|
|
40
|
+
F.sum(
|
|
41
|
+
F.when(F.col("event_id").isNull(), 1).otherwise(0)
|
|
42
|
+
).alias("null_event_id_count"),
|
|
43
|
+
F.sum(
|
|
44
|
+
F.when(F.col("event_count_1h") < 0, 1).otherwise(0)
|
|
45
|
+
).alias("invalid_event_count_1h"),
|
|
46
|
+
F.count("amount_usd_1h").alias("non_null_amount_usd_1h_count"),
|
|
47
|
+
).first().asDict()
|
|
48
|
+
|
|
49
|
+
blockers = []
|
|
50
|
+
if metrics["row_count"] != metrics["distinct_event_count"]:
|
|
51
|
+
blockers.append("event_id is not unique")
|
|
52
|
+
if metrics["null_event_id_count"]:
|
|
53
|
+
blockers.append("event_id contains nulls")
|
|
54
|
+
if metrics["invalid_event_count_1h"]:
|
|
55
|
+
blockers.append("event_count_1h contains negative values")
|
|
56
|
+
if blockers:
|
|
57
|
+
raise RuntimeError(f"validation blocked: {blockers}")
|
|
58
|
+
return metrics
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def run(validate_only, source_snapshot):
|
|
62
|
+
source = extract(source_snapshot)
|
|
63
|
+
candidate = transform(source)
|
|
64
|
+
|
|
65
|
+
metrics = validate_candidate(candidate)
|
|
66
|
+
print(json.dumps(metrics, sort_keys=True))
|
|
67
|
+
|
|
68
|
+
if validate_only:
|
|
69
|
+
print("validate-only: skipping publication")
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
publish(candidate)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Pin every source read to the same immutable snapshot. If the source cannot be
|
|
76
|
+
pinned, the canary does not prove what the writer will publish. Reference every
|
|
77
|
+
derived output in at least one validation aggregate so Catalyst cannot prune it.
|
|
78
|
+
|
|
79
|
+
Launch through the production `spark-submit` path and runtimes:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
export PYSPARK_DRIVER_PYTHON="$DRIVER_PYTHON"
|
|
83
|
+
export PYSPARK_PYTHON="$EXECUTOR_PYTHON"
|
|
84
|
+
|
|
85
|
+
spark-submit \
|
|
86
|
+
--name "$CANARY_NAME" \
|
|
87
|
+
--conf spark.pyspark.driver.python="$DRIVER_PYTHON" \
|
|
88
|
+
--conf spark.pyspark.python="$EXECUTOR_PYTHON" \
|
|
89
|
+
--conf spark.eventLog.enabled=true \
|
|
90
|
+
job.py --validate-only
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Do not replace another operator's scheduler files in place.
|
|
94
|
+
|
|
95
|
+
Prove the canary did not write:
|
|
96
|
+
|
|
97
|
+
1. Validation completed with zero blockers.
|
|
98
|
+
2. The terminal log says publication was skipped.
|
|
99
|
+
3. The event log reports zero Spark output records and bytes.
|
|
100
|
+
|
|
101
|
+
Do not add `.cache()` or `.persist()` to warm the canary.
|
|
102
|
+
|
|
103
|
+
## 2. Profiling (optional)
|
|
104
|
+
|
|
105
|
+
After the canary, profile when **either** the small-sample canary exceeds
|
|
106
|
+
**5 minutes** without resource constraints, **or any job exceeds 30 minutes**
|
|
107
|
+
(hard gate). Otherwise skip. When required, follow
|
|
108
|
+
[Diagnosis And Profiling](diagnosis-and-profiling.md).
|
|
109
|
+
|
|
110
|
+
## 3. Write
|
|
111
|
+
|
|
112
|
+
Write-enabled only after a successful canary and **explicit authorization**.
|
|
113
|
+
Re-check admission. Publish the same pinned sample. Do not present canary time
|
|
114
|
+
as write performance.
|
|
115
|
+
|
|
116
|
+
If a write is cancelled, prove from logs/source that publication was not
|
|
117
|
+
reached. YARN `KILLED` alone does not prove no commit occurred.
|
|
118
|
+
|
|
119
|
+
## 4. Reconciliation
|
|
120
|
+
|
|
121
|
+
Independent cluster read of the published scope — not a reuse of canary
|
|
122
|
+
aggregates. Follow [Reconciliation](reconciliation.md). Fail closed on mismatch.
|
|
123
|
+
|
|
124
|
+
## Evidence And Ownership
|
|
125
|
+
|
|
126
|
+
Safe evidence: counts, null rates, distinct counts, min/max dates, hashes,
|
|
127
|
+
stage metrics, plan-node counts, commit IDs. Do not print credentials or
|
|
128
|
+
entity-level rows.
|
|
129
|
+
|
|
130
|
+
After the run: confirm processes are terminal, restore scheduler ownership,
|
|
131
|
+
and report compute/validation, publication, and end-to-end time separately.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Reconciliation
|
|
2
|
+
|
|
3
|
+
Cluster check after an authorized write in production validation. Use the **same
|
|
4
|
+
one-month sample** as the canary. Local fixtures do not prove this.
|
|
5
|
+
|
|
6
|
+
Independently read the published table or Hudi commit. Do not reuse canary
|
|
7
|
+
aggregates. Fail closed on mismatch.
|
|
8
|
+
|
|
9
|
+
## What To Reconcile
|
|
10
|
+
|
|
11
|
+
Against the canary metrics and the previous path/oracle:
|
|
12
|
+
|
|
13
|
+
- row count and distinct identity count
|
|
14
|
+
- schema and required columns
|
|
15
|
+
- date/partition coverage of the sample
|
|
16
|
+
- write mode, commit success, and downstream readability
|
|
17
|
+
- validation blockers still zero on the published scope
|
|
18
|
+
|
|
19
|
+
## Bidirectional Row Parity
|
|
20
|
+
|
|
21
|
+
Counts alone miss wrong values, swapped identities, and duplicate multiplicity.
|
|
22
|
+
Compare full rows both ways with `exceptAll`, not `subtract`:
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
expected = old_build(source).select(*OUTPUT_COLUMNS)
|
|
26
|
+
actual = published.select(*OUTPUT_COLUMNS)
|
|
27
|
+
|
|
28
|
+
assert expected.exceptAll(actual).count() == 0
|
|
29
|
+
assert actual.exceptAll(expected).count() == 0
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Pin `source` to the same snapshot the writer used. Keep the previous
|
|
33
|
+
implementation only as this oracle while parity is being proven.
|
|
34
|
+
|
|
35
|
+
## Evidence
|
|
36
|
+
|
|
37
|
+
Safe evidence: counts, distinct counts, null rates, min/max dates, hashes, and
|
|
38
|
+
commit IDs. Do not print credentials or entity-level production rows.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Transformation Design
|
|
2
|
+
|
|
3
|
+
Use this playbook when implementing or restructuring Spark transformations.
|
|
4
|
+
The snippets illustrate shapes; adapt names, schemas, and state to the job's
|
|
5
|
+
required behavior.
|
|
6
|
+
|
|
7
|
+
## Define Required Behavior Before Operators
|
|
8
|
+
|
|
9
|
+
Record output identity/cardinality, event-time and timezone, deterministic
|
|
10
|
+
ordering, time boundaries, null/tombstone behavior, arithmetic, and required
|
|
11
|
+
history. Performance work preserves this behavior unless the user explicitly
|
|
12
|
+
approves a change.
|
|
13
|
+
|
|
14
|
+
## Choose The Shallowest Sufficient Mechanism
|
|
15
|
+
|
|
16
|
+
Prefer, in order:
|
|
17
|
+
|
|
18
|
+
1. Built-in column expressions and aggregations.
|
|
19
|
+
2. Spark windows when state and partition size are bounded.
|
|
20
|
+
3. Exact temporal bucketing with overlap correction.
|
|
21
|
+
4. One sorted grouped sweep for stateful transitions.
|
|
22
|
+
5. Python/pandas UDFs only when they remove substantially more distributed work
|
|
23
|
+
than they add.
|
|
24
|
+
|
|
25
|
+
Measure rather than assuming a UDF, Arrow, or built-in rewrite is faster.
|
|
26
|
+
|
|
27
|
+
## Keep One DataFrame Boundary
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
def build_features(events: DataFrame, rules: DataFrame) -> DataFrame:
|
|
31
|
+
normalized = normalize_events(events, rules)
|
|
32
|
+
return add_stateful_features(normalized)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Put complex state transitions in pure functions with explicit input and output
|
|
36
|
+
schemas so boundary semantics can be tested without a cluster.
|
|
37
|
+
|
|
38
|
+
## Use Built-In Windows For Independent Aggregates
|
|
39
|
+
|
|
40
|
+
When the feature is a standard rolling aggregate and all same-time peers should
|
|
41
|
+
share the same frame, keep execution inside Catalyst:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from pyspark.sql import Window, functions as F
|
|
45
|
+
|
|
46
|
+
one_hour = (
|
|
47
|
+
Window.partitionBy("entity_id")
|
|
48
|
+
.orderBy(F.col("event_time").cast("long"))
|
|
49
|
+
.rangeBetween(-3600, 0)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
features = (
|
|
53
|
+
events.withColumn("event_count_1h", F.count(F.lit(1)).over(one_hour))
|
|
54
|
+
.withColumn("amount_usd_1h", F.sum("amount_usd").over(one_hour))
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Check peer semantics carefully: a time-only range frame includes every row with
|
|
59
|
+
the same timestamp. It is wrong when same-time visibility depends on stable
|
|
60
|
+
secondary keys.
|
|
61
|
+
|
|
62
|
+
## Keep Bounded State Native With Higher-Order Aggregation
|
|
63
|
+
|
|
64
|
+
For bounded per-key arrays and group-level state, `functions.aggregate` keeps
|
|
65
|
+
the fold in Catalyst and does not call Python per group:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
ordered = events.groupBy("entity_id").agg(
|
|
69
|
+
F.sort_array(
|
|
70
|
+
F.collect_list(
|
|
71
|
+
F.struct(
|
|
72
|
+
"event_time",
|
|
73
|
+
"event_id",
|
|
74
|
+
F.col("amount_usd").cast("double").alias("amount_usd"),
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
).alias("events")
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
initial = F.struct(
|
|
81
|
+
F.lit(0.0).alias("balance"),
|
|
82
|
+
F.lit(0).alias("event_count"),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
state = ordered.select(
|
|
86
|
+
"entity_id",
|
|
87
|
+
F.aggregate(
|
|
88
|
+
"events",
|
|
89
|
+
initial,
|
|
90
|
+
lambda acc, event: F.struct(
|
|
91
|
+
(acc["balance"] + event["amount_usd"]).alias("balance"),
|
|
92
|
+
(acc["event_count"] + 1).alias("event_count"),
|
|
93
|
+
),
|
|
94
|
+
).alias("state"),
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
This example emits final group state. Carrying one output per event inside the
|
|
99
|
+
accumulator grows an array and can become expensive, so use it only when group
|
|
100
|
+
size and output state are bounded.
|
|
101
|
+
|
|
102
|
+
## Choose The Stateful Execution API Deliberately
|
|
103
|
+
|
|
104
|
+
Arbitrary per-row FIFO and temporal eviction have no general Catalyst-native
|
|
105
|
+
PySpark batch operator. Choose based on the actual state shape:
|
|
106
|
+
|
|
107
|
+
| State shape | Preferred API | Main constraint |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| Independent rolling aggregates | `Window` | Same-time peer semantics must fit the frame |
|
|
110
|
+
| Bounded array fold or final group state | `functions.aggregate` | Collected array and accumulator must remain bounded |
|
|
111
|
+
| Bounded batch group needing Python | [`applyInPandas`](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.GroupedData.applyInPandas.html) | Full shuffle; each group is loaded into memory |
|
|
112
|
+
| Stateful streaming group | [`applyInPandasWithState`](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.GroupedData.applyInPandasWithState.html) | Streaming API, not a batch replacement |
|
|
113
|
+
| Large or unbounded sequential batch state | Redesign with exact bucketing, Scala `mapGroups`, or a stateful engine | More implementation and operational complexity |
|
|
114
|
+
|
|
115
|
+
Keep the transition function pure regardless of the execution API. If a Python
|
|
116
|
+
grouped path replaces a much worse relation, benchmark it against the same
|
|
117
|
+
snapshot and report Python serialization and maximum-group memory explicitly.
|
|
118
|
+
|
|
119
|
+
## Preserve Exact Output Columns And Row Identity
|
|
120
|
+
|
|
121
|
+
Follow these rules:
|
|
122
|
+
|
|
123
|
+
1. Declare the complete output identity before writing the transformation.
|
|
124
|
+
2. Carry every identity column through grouping, sorting, UDF, and explode
|
|
125
|
+
boundaries.
|
|
126
|
+
3. Require one grouped result per identity before joining it to the base rows.
|
|
127
|
+
4. Join on the complete identity. Do not substitute customer, timestamp, or
|
|
128
|
+
another non-unique lookup key.
|
|
129
|
+
5. Declare the required output columns and their order. Never use `select("*")`
|
|
130
|
+
for the final candidate.
|
|
131
|
+
6. Drop helper, duplicate, and intermediate columns at the final projection.
|
|
132
|
+
7. Fail tests and production validation on null, missing, or duplicate
|
|
133
|
+
identities and on unexpected output columns.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
IDENTITY_COLUMNS = ["event_id"]
|
|
137
|
+
BASE_OUTPUT_COLUMNS = [
|
|
138
|
+
"event_id",
|
|
139
|
+
"entity_id",
|
|
140
|
+
"event_time",
|
|
141
|
+
"amount_usd",
|
|
142
|
+
]
|
|
143
|
+
FEATURE_COLUMNS = ["event_count_1h", "amount_usd_1h"]
|
|
144
|
+
OUTPUT_COLUMNS = BASE_OUTPUT_COLUMNS + FEATURE_COLUMNS
|
|
145
|
+
|
|
146
|
+
feature_projection = features_by_event.select(
|
|
147
|
+
*IDENTITY_COLUMNS,
|
|
148
|
+
*FEATURE_COLUMNS,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
candidate = (
|
|
152
|
+
events.select(*BASE_OUTPUT_COLUMNS)
|
|
153
|
+
.join(feature_projection, on=IDENTITY_COLUMNS, how="left")
|
|
154
|
+
.select(*OUTPUT_COLUMNS)
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
assert candidate.columns == OUTPUT_COLUMNS
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
For composite identity, list every component, for example
|
|
161
|
+
`IDENTITY_COLUMNS = ["transaction_id", "transaction_leg_id"]`.
|
|
162
|
+
|
|
163
|
+
## Local proof
|
|
164
|
+
|
|
165
|
+
These checks belong in **local tests** (workflow step 4). Cluster row parity is
|
|
166
|
+
[Reconciliation](reconciliation.md) after a write.
|
|
167
|
+
|
|
168
|
+
Keep a bounded previous-path oracle on **synthetic** fixtures. Assert critical
|
|
169
|
+
rules directly so oracle and candidate cannot share the same mistake:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
by_id = {row.event_id: row for row in actual.collect()}
|
|
173
|
+
assert by_id["at-24h"].count_24h == 2 # inclusive lower boundary
|
|
174
|
+
assert by_id["after-24h"].count_24h == 1 # one unit outside
|
|
175
|
+
assert by_id["same-time-b"].count_1h == 2 # stable tie ordering
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Cover empty and single-event groups; exact boundaries and one unit beyond;
|
|
179
|
+
same-timestamp ties; null key/time/amount; open/close/eviction; floating-point
|
|
180
|
+
residue; one dense hot key; duplicate and missing identities.
|
|
181
|
+
|
|
182
|
+
Assert the expensive plan shape is absent without snapshotting the whole plan:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
plan = actual._jdf.queryExecution().executedPlan().toString().lower()
|
|
186
|
+
assert not ("join" in plan and "event_time" in plan and "interval" in plan)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Mutation-prove high-risk tests (cutoff direction, tie-breaker, pair join,
|
|
190
|
+
required column) so they fail when the rule is broken.
|