@soleur/opencode 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/.claude-plugin/agents.manifest.json +476 -0
- package/.claude-plugin/plugin.json +42 -0
- package/README.md +44 -2
- package/agents/community/.gitkeep +0 -0
- package/agents/engineering/cto.md +87 -0
- package/agents/engineering/design/ddd-architect.md +95 -0
- package/agents/engineering/discovery/agent-finder.md +214 -0
- package/agents/engineering/discovery/functional-discovery.md +182 -0
- package/agents/engineering/infra/infra-security.md +151 -0
- package/agents/engineering/infra/platform-strategist.md +109 -0
- package/agents/engineering/infra/terraform-architect.md +171 -0
- package/agents/engineering/prompt-engineer.md +37 -0
- package/agents/engineering/research/best-practices-researcher.md +115 -0
- package/agents/engineering/research/framework-docs-researcher.md +93 -0
- package/agents/engineering/research/git-history-analyzer.md +53 -0
- package/agents/engineering/research/learnings-researcher.md +285 -0
- package/agents/engineering/research/repo-research-analyst.md +118 -0
- package/agents/engineering/review/agent-native-reviewer.md +279 -0
- package/agents/engineering/review/architecture-strategist.md +61 -0
- package/agents/engineering/review/code-quality-analyst.md +92 -0
- package/agents/engineering/review/code-simplicity-reviewer.md +109 -0
- package/agents/engineering/review/data-integrity-guardian.md +82 -0
- package/agents/engineering/review/data-migration-expert.md +98 -0
- package/agents/engineering/review/deployment-verification-agent.md +183 -0
- package/agents/engineering/review/dhh-rails-reviewer.md +46 -0
- package/agents/engineering/review/kieran-rails-reviewer.md +87 -0
- package/agents/engineering/review/legacy-code-expert.md +55 -0
- package/agents/engineering/review/observability-coverage-reviewer.md +147 -0
- package/agents/engineering/review/pattern-recognition-specialist.md +59 -0
- package/agents/engineering/review/performance-oracle.md +130 -0
- package/agents/engineering/review/security-sentinel.md +167 -0
- package/agents/engineering/review/semgrep-sast.md +36 -0
- package/agents/engineering/review/test-design-reviewer.md +150 -0
- package/agents/engineering/review/user-impact-reviewer.md +70 -0
- package/agents/engineering/workflow/pr-comment-resolver.md +69 -0
- package/agents/finance/budget-analyst.md +29 -0
- package/agents/finance/cfo.md +44 -0
- package/agents/finance/financial-reporter.md +30 -0
- package/agents/finance/revenue-analyst.md +30 -0
- package/agents/legal/clo.md +115 -0
- package/agents/legal/legal-compliance-auditor.md +110 -0
- package/agents/legal/legal-document-generator.md +134 -0
- package/agents/marketing/analytics-analyst.md +25 -0
- package/agents/marketing/brand-architect.md +181 -0
- package/agents/marketing/cmo.md +76 -0
- package/agents/marketing/conversion-optimizer.md +19 -0
- package/agents/marketing/copywriter.md +20 -0
- package/agents/marketing/fact-checker.md +70 -0
- package/agents/marketing/growth-strategist.md +145 -0
- package/agents/marketing/paid-media-strategist.md +28 -0
- package/agents/marketing/pricing-strategist.md +17 -0
- package/agents/marketing/programmatic-seo-specialist.md +25 -0
- package/agents/marketing/retention-strategist.md +23 -0
- package/agents/marketing/seo-aeo-analyst.md +164 -0
- package/agents/operations/coo.md +50 -0
- package/agents/operations/ops-advisor.md +78 -0
- package/agents/operations/ops-provisioner.md +101 -0
- package/agents/operations/ops-research.md +52 -0
- package/agents/operations/service-automator.md +278 -0
- package/agents/product/business-validator.md +206 -0
- package/agents/product/competitive-intelligence.md +89 -0
- package/agents/product/cpo.md +63 -0
- package/agents/product/design/ux-design-lead.md +209 -0
- package/agents/product/spec-flow-analyzer.md +122 -0
- package/agents/sales/cro.md +44 -0
- package/agents/sales/deal-architect.md +29 -0
- package/agents/sales/outbound-strategist.md +29 -0
- package/agents/sales/pipeline-analyst.md +29 -0
- package/agents/support/cco.md +48 -0
- package/agents/support/community-manager.md +570 -0
- package/agents/support/ticket-triage.md +70 -0
- package/bin/soleur-opencode.js +29 -0
- package/commands/go.md +659 -0
- package/commands/help.md +273 -0
- package/commands/sync.md +977 -0
- package/commands/version.md +103 -0
- package/hooks/antigravity-hooks.json +84 -0
- package/hooks/antigravity-session-start.sh +15 -0
- package/hooks/bare-root-cwd-guard.sh +131 -0
- package/hooks/browser-snapshot-credential-guard.sh +200 -0
- package/hooks/codex-session-start.sh +9 -0
- package/hooks/compaction-state.sh +525 -0
- package/hooks/destructive-command-guard.sh +1387 -0
- package/hooks/devin-session-start.sh +90 -0
- package/hooks/ext-filter-detect.sh +171 -0
- package/hooks/hooks.json +133 -0
- package/hooks/lib/hook-tool-kind.sh +24 -0
- package/hooks/lib/log-rotation.sh +176 -0
- package/hooks/lib/shell-argv.pl +576 -0
- package/hooks/memory-backstop.sh +1114 -0
- package/hooks/operator-stage-approval.sh +391 -0
- package/hooks/stop-hook.sh +367 -0
- package/hooks/unkept-promise-hook.sh +383 -0
- package/hooks/version-banner.sh +127 -0
- package/hooks/welcome-hook.sh +50 -0
- package/install.js +108 -0
- package/lib/agent-registry.ts +154 -0
- package/lib/c4-canonical-cli.mjs +34 -0
- package/lib/c4-canonical.mjs +46 -0
- package/lib/c4-from-components.ts +554 -0
- package/lib/go-routing.ts +81 -0
- package/lib/grok-inspect-contract.ts +311 -0
- package/lib/harness-model-map.ts +101 -0
- package/lib/harness-parity.ts +726 -0
- package/lib/harness-tool-map.ts +180 -0
- package/lib/harness.ts +716 -0
- package/lib/heartbeat-live-reconcile.ts +1153 -0
- package/lib/heartbeat-manifest.ts +342 -0
- package/lib/kb-coverage.ts +252 -0
- package/lib/pr-merge-poll.ts +103 -0
- package/lib/workflow-fidelity.ts +388 -0
- package/opencode/INSTRUCTIONS.md +152 -0
- package/opencode/agents/engineering/cto.md +10 -0
- package/opencode/agents/engineering/design/ddd-architect.md +10 -0
- package/opencode/agents/engineering/discovery/agent-finder.md +10 -0
- package/opencode/agents/engineering/discovery/functional-discovery.md +10 -0
- package/opencode/agents/engineering/infra/infra-security.md +10 -0
- package/opencode/agents/engineering/infra/platform-strategist.md +10 -0
- package/opencode/agents/engineering/infra/terraform-architect.md +10 -0
- package/opencode/agents/engineering/prompt-engineer.md +10 -0
- package/opencode/agents/engineering/research/best-practices-researcher.md +10 -0
- package/opencode/agents/engineering/research/framework-docs-researcher.md +10 -0
- package/opencode/agents/engineering/research/git-history-analyzer.md +10 -0
- package/opencode/agents/engineering/research/learnings-researcher.md +10 -0
- package/opencode/agents/engineering/research/repo-research-analyst.md +10 -0
- package/opencode/agents/engineering/review/agent-native-reviewer.md +10 -0
- package/opencode/agents/engineering/review/architecture-strategist.md +10 -0
- package/opencode/agents/engineering/review/code-quality-analyst.md +10 -0
- package/opencode/agents/engineering/review/code-simplicity-reviewer.md +10 -0
- package/opencode/agents/engineering/review/data-integrity-guardian.md +10 -0
- package/opencode/agents/engineering/review/data-migration-expert.md +10 -0
- package/opencode/agents/engineering/review/deployment-verification-agent.md +10 -0
- package/opencode/agents/engineering/review/dhh-rails-reviewer.md +10 -0
- package/opencode/agents/engineering/review/kieran-rails-reviewer.md +10 -0
- package/opencode/agents/engineering/review/legacy-code-expert.md +10 -0
- package/opencode/agents/engineering/review/observability-coverage-reviewer.md +10 -0
- package/opencode/agents/engineering/review/pattern-recognition-specialist.md +10 -0
- package/opencode/agents/engineering/review/performance-oracle.md +10 -0
- package/opencode/agents/engineering/review/security-sentinel.md +10 -0
- package/opencode/agents/engineering/review/semgrep-sast.md +10 -0
- package/opencode/agents/engineering/review/test-design-reviewer.md +10 -0
- package/opencode/agents/engineering/review/user-impact-reviewer.md +10 -0
- package/opencode/agents/engineering/workflow/pr-comment-resolver.md +10 -0
- package/opencode/agents/finance/budget-analyst.md +10 -0
- package/opencode/agents/finance/cfo.md +10 -0
- package/opencode/agents/finance/financial-reporter.md +10 -0
- package/opencode/agents/finance/revenue-analyst.md +10 -0
- package/opencode/agents/legal/clo.md +10 -0
- package/opencode/agents/legal/legal-compliance-auditor.md +10 -0
- package/opencode/agents/legal/legal-document-generator.md +10 -0
- package/opencode/agents/marketing/analytics-analyst.md +10 -0
- package/opencode/agents/marketing/brand-architect.md +10 -0
- package/opencode/agents/marketing/cmo.md +10 -0
- package/opencode/agents/marketing/conversion-optimizer.md +10 -0
- package/opencode/agents/marketing/copywriter.md +10 -0
- package/opencode/agents/marketing/fact-checker.md +10 -0
- package/opencode/agents/marketing/growth-strategist.md +10 -0
- package/opencode/agents/marketing/paid-media-strategist.md +10 -0
- package/opencode/agents/marketing/pricing-strategist.md +10 -0
- package/opencode/agents/marketing/programmatic-seo-specialist.md +10 -0
- package/opencode/agents/marketing/retention-strategist.md +10 -0
- package/opencode/agents/marketing/seo-aeo-analyst.md +10 -0
- package/opencode/agents/operations/coo.md +10 -0
- package/opencode/agents/operations/ops-advisor.md +10 -0
- package/opencode/agents/operations/ops-provisioner.md +10 -0
- package/opencode/agents/operations/ops-research.md +10 -0
- package/opencode/agents/operations/service-automator.md +10 -0
- package/opencode/agents/product/business-validator.md +10 -0
- package/opencode/agents/product/competitive-intelligence.md +10 -0
- package/opencode/agents/product/cpo.md +10 -0
- package/opencode/agents/product/design/ux-design-lead.md +10 -0
- package/opencode/agents/product/spec-flow-analyzer.md +10 -0
- package/opencode/agents/sales/cro.md +10 -0
- package/opencode/agents/sales/deal-architect.md +10 -0
- package/opencode/agents/sales/outbound-strategist.md +10 -0
- package/opencode/agents/sales/pipeline-analyst.md +10 -0
- package/opencode/agents/support/cco.md +10 -0
- package/opencode/agents/support/community-manager.md +10 -0
- package/opencode/agents/support/ticket-triage.md +10 -0
- package/opencode/commands/go.md +10 -0
- package/opencode/commands/help.md +10 -0
- package/opencode/commands/sync.md +10 -0
- package/opencode/commands/version.md +11 -0
- package/opencode/opencode.json +8 -0
- package/opencode/plugin.ts +493 -0
- package/package.json +36 -4
- package/scripts/admin-merge-ready.sh +545 -0
- package/scripts/admin-merge-ready.test.sh +753 -0
- package/scripts/affected-tests.sh +908 -0
- package/scripts/affected-tests.test.sh +1797 -0
- package/scripts/alpha-metrics.sh +78 -0
- package/scripts/alpha-metrics.test.sh +115 -0
- package/scripts/ancestor-signal-helpers.baseline.txt +16 -0
- package/scripts/audit-flag-flip.sh +107 -0
- package/scripts/check-red-on-main.sh +316 -0
- package/scripts/ci-head-verdict.sh +363 -0
- package/scripts/cloud-detect.sh +193 -0
- package/scripts/delegation-verify.sh +657 -0
- package/scripts/delegation-verify.test.sh +1424 -0
- package/scripts/deploy-arm.sh +475 -0
- package/scripts/domain-model-drift.sh +419 -0
- package/scripts/emit-decision.sh +144 -0
- package/scripts/emit-decision.test.sh +144 -0
- package/scripts/ext-filter-divergence-corpus.txt +15 -0
- package/scripts/ext-filter-divergence.sh +189 -0
- package/scripts/generate-c4-from-components.ts +442 -0
- package/scripts/grok-fidelity-gate.sh +68 -0
- package/scripts/grok-pre-push-gate.sh +232 -0
- package/scripts/harness-discovery-smoke.ts +906 -0
- package/scripts/harness-parity-census.ts +92 -0
- package/scripts/inngest-luks-alert-armed-probe.ts +29 -0
- package/scripts/install-opencode-adapter.ts +520 -0
- package/scripts/lib/affected-tests/common.sh +365 -0
- package/scripts/lib/affected-tests/go.sh +157 -0
- package/scripts/lib/affected-tests/js.sh +188 -0
- package/scripts/lib/affected-tests/nx-turbo.sh +98 -0
- package/scripts/lib/affected-tests/python.sh +185 -0
- package/scripts/lib/context-sanitize.sh +49 -0
- package/scripts/lib/domain-model-lib.sh +180 -0
- package/scripts/lib/ext-filter-grammar.tsv +34 -0
- package/scripts/lib/operator-script.sh +1236 -0
- package/scripts/lib/proc.sh +580 -0
- package/scripts/lib/session-state.sh +748 -0
- package/scripts/lib/tmp-classify.sh +843 -0
- package/scripts/lib/wrapper-boundary.sh +47 -0
- package/scripts/lint-ratchet.py +1547 -0
- package/scripts/monitor-pr-checks.sh +441 -0
- package/scripts/pipeline-tally.sh +756 -0
- package/scripts/pipeline-tally.test.sh +740 -0
- package/scripts/plugin-version.sh +528 -0
- package/scripts/precommit-guard.sh +113 -0
- package/scripts/precommit-guard.test.sh +254 -0
- package/scripts/reconcile-live-heartbeats.ts +705 -0
- package/scripts/render-c4-model.sh +217 -0
- package/scripts/resolve-git-root.sh +55 -0
- package/scripts/resolve-regenerable-conflicts.sh +363 -0
- package/scripts/resolve-regenerable-conflicts.test.sh +780 -0
- package/scripts/ruff-requirements.txt +22 -0
- package/scripts/run-in-pid-namespace.sh +98 -0
- package/scripts/run-in-pid-namespace.test.sh +290 -0
- package/scripts/scan-ancestor-signal-helpers.py +556 -0
- package/scripts/scan-ancestor-signal-helpers.test.sh +670 -0
- package/scripts/setup-ralph-loop.sh +238 -0
- package/scripts/sync-cursor-name-map.ts +316 -0
- package/scripts/sync-grok-agent-compat.ts +188 -0
- package/scripts/sync-npm-package.ts +178 -0
- package/scripts/sync-opencode-adapter.ts +479 -0
- package/scripts/sync-pr-behind.sh +534 -0
- package/scripts/sync-pr-behind.test.sh +252 -0
- package/scripts/taste-profile-update.sh +180 -0
- package/scripts/taste-profile-update.test.sh +167 -0
- package/scripts/write-budget-marker.sh +23 -0
- package/scripts/write-kb-coverage.ts +113 -0
- package/skills/admin-ip-refresh/SKILL.md +81 -0
- package/skills/admin-ip-refresh/references/admin-ip-refresh-procedure.md +201 -0
- package/skills/agent-browser/SKILL.md +698 -0
- package/skills/agent-browser/scripts/playwright-mcp-profile-slot.sh +304 -0
- package/skills/agent-browser/scripts/playwright-mcp-redact-proxy.py +964 -0
- package/skills/agent-browser/scripts/redact-a11y-snapshot.py +443 -0
- package/skills/agent-browser/test/fixtures/capture-playwright-mcp-fixtures.py +217 -0
- package/skills/agent-browser/test/fixtures/fake-passthrough-proxy.py +24 -0
- package/skills/agent-browser/test/fixtures/fake-playwright-mcp.py +131 -0
- package/skills/agent-browser/test/fixtures/make-proxy-mutant.py +48 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/dialog-link-injection.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/empty-content.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-and-result.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-code-bool.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-code-string.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-message-tree.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-no-data.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-string.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-with-data.json +9 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/evaluate-escaped-object.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/invalid-utf8.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/link-result.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/list-two-results.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/meta-in-result.json +13 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/no-content.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/quoted-key.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/resource-block.json +18 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/result-and-method.json +11 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/result-string.json +3 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped-one-row.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/structured-content.json +13 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/tools-list-no-tools.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/tree-no-credential.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/two-text-blocks.json +14 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/unparsable-line.json +3 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-brace.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-link-substring.json +10 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/close.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/evaluate.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/find.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/framing.json +6 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/initialize.json +14 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate-link.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/roots-list-request.json +5 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/screenshot.json +17 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-filename.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-json.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-raw.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/tools-list.json +827 -0
- package/skills/agent-browser/test/fixtures/proxy-session-driver.py +138 -0
- package/skills/agent-browser/test/fixtures/session-facts.py +102 -0
- package/skills/agent-browser/test/playwright-mcp-lifetime.test.sh +1620 -0
- package/skills/agent-browser/test/playwright-mcp-redact-proxy.test.sh +1599 -0
- package/skills/agent-browser/test/redact-a11y-snapshot.test.sh +527 -0
- package/skills/agent-native-architecture/SKILL.md +479 -0
- package/skills/agent-native-architecture/references/action-parity-discipline.md +430 -0
- package/skills/agent-native-architecture/references/agent-execution-patterns.md +483 -0
- package/skills/agent-native-architecture/references/agent-native-testing.md +605 -0
- package/skills/agent-native-architecture/references/architecture-patterns.md +493 -0
- package/skills/agent-native-architecture/references/dynamic-context-injection.md +358 -0
- package/skills/agent-native-architecture/references/files-universal-interface.md +314 -0
- package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +381 -0
- package/skills/agent-native-architecture/references/mcp-tool-design.md +524 -0
- package/skills/agent-native-architecture/references/mobile-patterns.md +897 -0
- package/skills/agent-native-architecture/references/product-implications.md +478 -0
- package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +342 -0
- package/skills/agent-native-architecture/references/self-modification.md +294 -0
- package/skills/agent-native-architecture/references/shared-workspace-architecture.md +700 -0
- package/skills/agent-native-architecture/references/system-prompt-design.md +263 -0
- package/skills/agent-native-audit/SKILL.md +300 -0
- package/skills/agent-native-audit/workflows/agent-native-audit.workflow.js +423 -0
- package/skills/andrew-kane-gem-writer/SKILL.md +189 -0
- package/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
- package/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
- package/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
- package/skills/andrew-kane-gem-writer/references/resources.md +126 -0
- package/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
- package/skills/architecture/SKILL.md +436 -0
- package/skills/architecture/references/adr-template.md +154 -0
- package/skills/architecture/references/likec4-reference.md +136 -0
- package/skills/architecture/references/nfr-reference.md +126 -0
- package/skills/archive-kb/SKILL.md +86 -0
- package/skills/archive-kb/scripts/archive-kb.sh +300 -0
- package/skills/archive-kb/test/archive-kb-partial-run.test.sh +276 -0
- package/skills/atdd-developer/SKILL.md +65 -0
- package/skills/brainstorm/SKILL.md +701 -0
- package/skills/brainstorm/references/brainstorm-brand-workshop.md +153 -0
- package/skills/brainstorm/references/brainstorm-domain-config.md +63 -0
- package/skills/brainstorm/references/brainstorm-validation-workshop.md +65 -0
- package/skills/brainstorm/references/ui-surface-terms.md +42 -0
- package/skills/brainstorm-techniques/SKILL.md +231 -0
- package/skills/brainstorm-techniques/references/decision-principles.md +150 -0
- package/skills/brainstorm-techniques/references/phase-boundaries.md +103 -0
- package/skills/brainstorm-techniques/references/standing-delegation.md +407 -0
- package/skills/brainstorm-techniques/references/technical-ruling-delegation.md +174 -0
- package/skills/campaign-calendar/SKILL.md +145 -0
- package/skills/cf-token-scope/SKILL.md +164 -0
- package/skills/cf-token-scope/references/widen-playbook.md +114 -0
- package/skills/cf-token-scope/scripts/cf-token-scope.sh +253 -0
- package/skills/changelog/SKILL.md +142 -0
- package/skills/code-to-prd/SKILL.md +66 -0
- package/skills/code-to-prd/references/banner-template.md +12 -0
- package/skills/code-to-prd/references/prd-template.md +41 -0
- package/skills/code-to-prd/scripts/code-to-prd.sh +634 -0
- package/skills/code-to-prd/test/code-to-prd.test.sh +447 -0
- package/skills/code-to-prd/test/fixture/.env.example +7 -0
- package/skills/code-to-prd/test/fixture/app/about/page.tsx +11 -0
- package/skills/code-to-prd/test/fixture/app/api/health/route.ts +10 -0
- package/skills/code-to-prd/test/fixture/app/page.tsx +14 -0
- package/skills/code-to-prd/test/fixture/next.config.mjs +3 -0
- package/skills/code-to-prd/test/fixture/package.json +6 -0
- package/skills/cohort-status/SKILL.md +62 -0
- package/skills/community/SKILL.md +210 -0
- package/skills/community/scripts/bsky-community.sh +644 -0
- package/skills/community/scripts/bsky-setup.sh +631 -0
- package/skills/community/scripts/community-router.sh +93 -0
- package/skills/community/scripts/discord-community.sh +487 -0
- package/skills/community/scripts/discord-setup.sh +784 -0
- package/skills/community/scripts/github-community.sh +706 -0
- package/skills/community/scripts/hn-community.sh +233 -0
- package/skills/community/scripts/lib/hmac-sha1-b64.sh +126 -0
- package/skills/community/scripts/linkedin-community.sh +750 -0
- package/skills/community/scripts/linkedin-setup.sh +758 -0
- package/skills/community/scripts/x-community.sh +890 -0
- package/skills/community/scripts/x-setup.sh +713 -0
- package/skills/community/test/community-argv.test.sh +2922 -0
- package/skills/community/test/github-community.test.sh +981 -0
- package/skills/competitive-analysis/SKILL.md +69 -0
- package/skills/competitive-analysis/references/peer-plugin-audit.md +218 -0
- package/skills/compound/SKILL.md +673 -0
- package/skills/compound/scripts/token-efficiency-report.sh +334 -0
- package/skills/compound/test/phase-16.test.sh +379 -0
- package/skills/compound-capture/SKILL.md +791 -0
- package/skills/compound-capture/assets/critical-pattern-template.md +37 -0
- package/skills/compound-capture/assets/resolution-template.md +116 -0
- package/skills/compound-capture/references/yaml-schema.md +67 -0
- package/skills/compound-capture/schema.yaml +181 -0
- package/skills/constraint-scaffold/SKILL.md +175 -0
- package/skills/constraint-scaffold/references/boundary-readme.template +35 -0
- package/skills/constraint-scaffold/references/constraint-gates-workflow.template +69 -0
- package/skills/constraint-scaffold/references/depcruise-config.template +230 -0
- package/skills/constraint-scaffold/references/fix-constraints-stage-a.template +240 -0
- package/skills/constraint-scaffold/references/fix-constraints-stage-b.template +313 -0
- package/skills/constraint-scaffold/references/shared-runner.template +135 -0
- package/skills/constraint-scaffold/scripts/constraint-scaffold.sh +589 -0
- package/skills/constraint-scaffold/test/bite-proof.test.sh +1338 -0
- package/skills/constraint-scaffold/test/boundary.test.sh +734 -0
- package/skills/constraint-scaffold/test/emit-fix-constraints.test.sh +193 -0
- package/skills/constraint-scaffold/test/generator.test.sh +93 -0
- package/skills/constraint-scaffold/test/parity.test.sh +285 -0
- package/skills/content-writer/SKILL.md +242 -0
- package/skills/content-writer/scripts/blog-jargon-scan.sh +42 -0
- package/skills/cron-delete/SKILL.md +56 -0
- package/skills/cron-list/SKILL.md +54 -0
- package/skills/deepen-plan/SKILL.md +937 -0
- package/skills/deepen-plan/workflows/deepen-plan.workflow.js +488 -0
- package/skills/deploy/SKILL.md +115 -0
- package/skills/deploy/references/hetzner-setup.md +65 -0
- package/skills/deploy/scripts/deploy.sh +37 -0
- package/skills/deploy-docs/SKILL.md +95 -0
- package/skills/dhh-rails-style/SKILL.md +203 -0
- package/skills/dhh-rails-style/references/architecture.md +717 -0
- package/skills/dhh-rails-style/references/controllers.md +323 -0
- package/skills/dhh-rails-style/references/frontend.md +556 -0
- package/skills/dhh-rails-style/references/gems.md +316 -0
- package/skills/dhh-rails-style/references/models.md +388 -0
- package/skills/dhh-rails-style/references/testing.md +354 -0
- package/skills/discord-content/SKILL.md +126 -0
- package/skills/docs-site/SKILL.md +214 -0
- package/skills/drain-labeled-backlog/SKILL.md +203 -0
- package/skills/drain-labeled-backlog/scripts/group-by-area.sh +208 -0
- package/skills/drain-labeled-backlog/workflows/drain-labeled-backlog.workflow.js +433 -0
- package/skills/drain-prs/SKILL.md +142 -0
- package/skills/drain-prs/scripts/triage-prs.sh +192 -0
- package/skills/drain-prs/test/argv-ceiling.test.sh +183 -0
- package/skills/dspy-ruby/SKILL.md +634 -0
- package/skills/dspy-ruby/assets/config-template.rb +359 -0
- package/skills/dspy-ruby/assets/module-template.rb +326 -0
- package/skills/dspy-ruby/assets/signature-template.rb +143 -0
- package/skills/dspy-ruby/references/core-concepts.md +268 -0
- package/skills/dspy-ruby/references/optimization.md +623 -0
- package/skills/dspy-ruby/references/providers.md +335 -0
- package/skills/eval-harness/README.md +194 -0
- package/skills/eval-harness/SKILL.md +157 -0
- package/skills/eval-harness/enums/go-routes.json +13 -0
- package/skills/eval-harness/enums/incident-threshold.json +5 -0
- package/skills/eval-harness/enums/lane.json +5 -0
- package/skills/eval-harness/enums/tool-selection.json +20 -0
- package/skills/eval-harness/enums/triage-levels.json +5 -0
- package/skills/eval-harness/gated-skills.json +34 -0
- package/skills/eval-harness/models.generated.json +5 -0
- package/skills/eval-harness/promptfooconfig-go-routing.yaml +35 -0
- package/skills/eval-harness/promptfooconfig-incident-threshold.yaml +32 -0
- package/skills/eval-harness/promptfooconfig-lane-inference.yaml +33 -0
- package/skills/eval-harness/promptfooconfig-ticket-triage.yaml +34 -0
- package/skills/eval-harness/promptfooconfig-tool-selection.yaml +33 -0
- package/skills/eval-harness/prompts/go-baseline.txt +6 -0
- package/skills/eval-harness/prompts/go-skill.txt +21 -0
- package/skills/eval-harness/prompts/incident-threshold-baseline.txt +6 -0
- package/skills/eval-harness/prompts/incident-threshold-skill.txt +12 -0
- package/skills/eval-harness/prompts/lane-inference-baseline.txt +6 -0
- package/skills/eval-harness/prompts/lane-inference-skill.txt +15 -0
- package/skills/eval-harness/prompts/tool-selection-baseline.txt +19 -0
- package/skills/eval-harness/prompts/tool-selection-skill.txt +22 -0
- package/skills/eval-harness/prompts/triage-baseline.txt +7 -0
- package/skills/eval-harness/prompts/triage-skill.txt +10 -0
- package/skills/eval-harness/scripts/eval-gate.cjs +318 -0
- package/skills/eval-harness/scripts/extract-block.cjs +87 -0
- package/skills/eval-harness/scripts/gate-classification.cjs +28 -0
- package/skills/eval-harness/scripts/gen-models.sh +41 -0
- package/skills/eval-harness/scripts/gen-skill-prompt.cjs +177 -0
- package/skills/eval-harness/scripts/measure-classification.cjs +30 -0
- package/skills/eval-harness/scripts/parse-label.cjs +93 -0
- package/skills/eval-harness/scripts/verdict.cjs +132 -0
- package/skills/eval-harness/tasks/go-routing.jsonl +8 -0
- package/skills/eval-harness/tasks/incident-threshold.jsonl +7 -0
- package/skills/eval-harness/tasks/lane-inference.jsonl +7 -0
- package/skills/eval-harness/tasks/ticket-triage.jsonl +6 -0
- package/skills/eval-harness/tasks/tool-selection.jsonl +15 -0
- package/skills/eval-harness/test/eval-gate.test.sh +132 -0
- package/skills/eval-harness/test/extract-block.test.sh +87 -0
- package/skills/eval-harness/test/gate-classification.test.sh +77 -0
- package/skills/eval-harness/test/gen-models.test.sh +75 -0
- package/skills/eval-harness/test/measure-classification.test.sh +74 -0
- package/skills/eval-harness/test/parse-label.test.sh +129 -0
- package/skills/eval-harness/test/registry-completeness.test.sh +109 -0
- package/skills/eval-harness/test/verdict.test.sh +123 -0
- package/skills/every-style-editor/SKILL.md +142 -0
- package/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
- package/skills/feature-tweet/SKILL.md +199 -0
- package/skills/feature-video/SKILL.md +412 -0
- package/skills/feature-video/scripts/check_deps.sh +281 -0
- package/skills/file-todos/SKILL.md +267 -0
- package/skills/file-todos/assets/todo-template.md +166 -0
- package/skills/fix-issue/SKILL.md +278 -0
- package/skills/fix-issue/references/agent-authored-exclusion.md +118 -0
- package/skills/fix-issue/references/exclude-label-jq-snippet.md +96 -0
- package/skills/flag-bootstrap/SETUP.md +142 -0
- package/skills/flag-create/SKILL.md +145 -0
- package/skills/flag-create/scripts/create.sh +273 -0
- package/skills/flag-delete/SKILL.md +167 -0
- package/skills/flag-delete/scripts/delete.sh +288 -0
- package/skills/flag-list/SKILL.md +99 -0
- package/skills/flag-list/scripts/list.sh +275 -0
- package/skills/flag-set-role/SKILL.md +229 -0
- package/skills/flag-set-role/scripts/flip.sh +774 -0
- package/skills/frontend-anti-slop/SKILL.md +106 -0
- package/skills/frontend-anti-slop/references/anti-patterns.md +199 -0
- package/skills/frontend-anti-slop/references/slop-rules.md +65 -0
- package/skills/frontend-anti-slop/scripts/tier1-scan.ts +525 -0
- package/skills/frontend-design/SKILL.md +77 -0
- package/skills/gdpr-gate/NOTICE +136 -0
- package/skills/gdpr-gate/SKILL.md +341 -0
- package/skills/gdpr-gate/references/fields.md +160 -0
- package/skills/gdpr-gate/references/layers/api-layer.md +355 -0
- package/skills/gdpr-gate/references/layers/auth-sessions.md +290 -0
- package/skills/gdpr-gate/references/layers/data-in-transit.md +331 -0
- package/skills/gdpr-gate/references/layers/data-lifecycle.md +341 -0
- package/skills/gdpr-gate/references/layers/frontend.md +249 -0
- package/skills/gdpr-gate/references/layers/testing-seeding.md +256 -0
- package/skills/gdpr-gate/references/leakage-vectors.md +248 -0
- package/skills/gdpr-gate/references/legacy/legal-consent-v1-prose.md +48 -0
- package/skills/gdpr-gate/references/legal-consent.md +140 -0
- package/skills/gdpr-gate/references/non-negotiables.md +60 -0
- package/skills/gdpr-gate/scripts/gdpr-gate.sh +271 -0
- package/skills/gdpr-gate/scripts/notice-frontmatter.sh +337 -0
- package/skills/gdpr-gate/scripts/path-denylist.txt +39 -0
- package/skills/gdpr-gate/scripts/repo-scan.sh +158 -0
- package/skills/gdpr-gate/scripts/vendor-drift-classify.sh +120 -0
- package/skills/gdpr-gate/scripts/vendor-pin-integrity.sh +237 -0
- package/skills/gemini-imagegen/SKILL.md +283 -0
- package/skills/gemini-imagegen/requirements.txt +5 -0
- package/skills/gemini-imagegen/scripts/_error_handling.py +146 -0
- package/skills/gemini-imagegen/scripts/compose_images.py +150 -0
- package/skills/gemini-imagegen/scripts/edit_image.py +137 -0
- package/skills/gemini-imagegen/scripts/gemini_images.py +256 -0
- package/skills/gemini-imagegen/scripts/generate_image.py +147 -0
- package/skills/gemini-imagegen/scripts/multi_turn_chat.py +223 -0
- package/skills/gemini-imagegen/scripts/test_error_handling.py +179 -0
- package/skills/git-worktree/SKILL.md +534 -0
- package/skills/git-worktree/scripts/git-repo-readiness-diag.sh +98 -0
- package/skills/git-worktree/scripts/worktree-manager.sh +4773 -0
- package/skills/git-worktree/test/create-from-origin-main.test.sh +116 -0
- package/skills/git-worktree/test/lease-protects-active.test.sh +1056 -0
- package/skills/git-worktree/test/no-repo-fail-loud.test.sh +88 -0
- package/skills/git-worktree/test/orphan-reaper-honest-count.test.sh +379 -0
- package/skills/git-worktree/test/reap-archive-persistence.test.sh +725 -0
- package/skills/git-worktree/test/stale-lock-sweep.test.sh +176 -0
- package/skills/go/SKILL.md +54 -0
- package/skills/growth/SKILL.md +164 -0
- package/skills/harvest-debt/SKILL.md +78 -0
- package/skills/harvest-debt/scripts/harvest-debt.sh +114 -0
- package/skills/heal-skill/SKILL.md +173 -0
- package/skills/help/SKILL.md +46 -0
- package/skills/incident/NOTICE +39 -0
- package/skills/incident/SKILL.md +395 -0
- package/skills/incident/scripts/dry-run.sh +448 -0
- package/skills/incident/scripts/redact-engine.py +412 -0
- package/skills/incident/scripts/redact-sentinel.sh +44 -0
- package/skills/incident/templates/pir.md +139 -0
- package/skills/incident/test/fixtures/dry-run-incident.json +26 -0
- package/skills/incident/test/fixtures/dry-run-secret-leak.json +26 -0
- package/skills/incident/test/fixtures/legacy-bash-scanner.sh +82 -0
- package/skills/incident/test/fixtures/positive-corpus.md +87 -0
- package/skills/incident/test/redact-sentinel.test.sh +1420 -0
- package/skills/invoice/SKILL.md +206 -0
- package/skills/kb-glossary/SKILL.md +71 -0
- package/skills/kb-glossary/references/glossary-format.md +111 -0
- package/skills/kb-glossary/references/rejected-request-register.md +115 -0
- package/skills/kb-search/SKILL.md +276 -0
- package/skills/kb-search/scripts/kb-search-cache.sh +123 -0
- package/skills/legal-audit/SKILL.md +161 -0
- package/skills/legal-generate/NOTICE +242 -0
- package/skills/legal-generate/SKILL.md +244 -0
- package/skills/legal-generate/references/templates/advisor-agreement/template.md +12 -0
- package/skills/legal-generate/references/templates/business-associate-agreement/template.md +112 -0
- package/skills/legal-generate/references/templates/cookie-notice/template.md +82 -0
- package/skills/legal-generate/references/templates/dpa-global/template.md +439 -0
- package/skills/legal-generate/references/templates/dpa-us/template.md +222 -0
- package/skills/legal-generate/references/templates/employee-offer-letter/template.md +75 -0
- package/skills/legal-generate/references/templates/master-services-agreement/template.md +252 -0
- package/skills/legal-generate/references/templates/mutual-nda/template.md +66 -0
- package/skills/legal-generate/references/templates/one-way-nda/template.md +38 -0
- package/skills/legal-generate/references/templates/privacy-policy-gdpr/template.md +427 -0
- package/skills/legal-generate/references/templates/privacy-policy-us/template.md +313 -0
- package/skills/legal-generate/references/templates/terms-of-use/template.md +75 -0
- package/skills/legal-generate/scripts/strip-vendor-credit.sh +96 -0
- package/skills/linear-fetch/SKILL.md +247 -0
- package/skills/linear-fetch/scripts/assert-no-linear-telemetry.sh +66 -0
- package/skills/linear-fetch/scripts/redact-linear-urls.sh +51 -0
- package/skills/linear-fetch/scripts/render-caller-template.sh +36 -0
- package/skills/linear-fetch/test/assert-no-linear-telemetry.test.sh +113 -0
- package/skills/linear-fetch/test/parity.test.sh +112 -0
- package/skills/linear-fetch/test/persist-safe-integration.test.sh +191 -0
- package/skills/linear-fetch/test/redact-linear-urls.test.sh +226 -0
- package/skills/merge-pr/SKILL.md +668 -0
- package/skills/model-launch-review/SKILL.md +255 -0
- package/skills/model-launch-review/scripts/audit-models.sh +501 -0
- package/skills/one-shot/SKILL.md +316 -0
- package/skills/one-shot/references/token-discipline.md +74 -0
- package/skills/operator-bootstrap/SKILL.md +412 -0
- package/skills/operator-bootstrap/template.sh +439 -0
- package/skills/operator-digest/SKILL.md +287 -0
- package/skills/operator-digest/assets/operator-digest.workflow.yml +175 -0
- package/skills/operator-digest/scripts/digest-scrub.sh +119 -0
- package/skills/operator-digest/scripts/provision-operator-digest-repo.sh +147 -0
- package/skills/operator-rephrase/SKILL.md +98 -0
- package/skills/pencil-setup/SKILL.md +201 -0
- package/skills/pencil-setup/scripts/check_deps.sh +556 -0
- package/skills/pencil-setup/scripts/copy_adapter.sh +80 -0
- package/skills/pencil-setup/scripts/package-lock.json +1172 -0
- package/skills/pencil-setup/scripts/package.json +14 -0
- package/skills/pencil-setup/scripts/pencil-error-enrichment.mjs +21 -0
- package/skills/pencil-setup/scripts/pencil-mcp-adapter.mjs +733 -0
- package/skills/pencil-setup/scripts/pencil-response-classify.mjs +38 -0
- package/skills/pencil-setup/scripts/pencil-save-gate.mjs +26 -0
- package/skills/pencil-setup/scripts/sanitize-filename.mjs +25 -0
- package/skills/plan/SKILL.md +1140 -0
- package/skills/plan/references/differential-migration-testing.md +185 -0
- package/skills/plan/references/plan-community-discovery.md +42 -0
- package/skills/plan/references/plan-founder-check.md +137 -0
- package/skills/plan/references/plan-functional-overlap.md +25 -0
- package/skills/plan/references/plan-host-fanout.md +51 -0
- package/skills/plan/references/plan-issue-templates.md +779 -0
- package/skills/plan/references/plan-network-outage-checklist.md +131 -0
- package/skills/plan/references/plan-scope-check.md +126 -0
- package/skills/plan/references/plan-sharp-edges.md +325 -0
- package/skills/plan/references/plan-signoff-lifecycle.md +12 -0
- package/skills/plan/references/webapp-cwv-observability.md +143 -0
- package/skills/plan-review/SKILL.md +91 -0
- package/skills/plan-review/lib/named-panel.mjs +58 -0
- package/skills/plan-review/workflows/plan-review.workflow.js +477 -0
- package/skills/postmerge/SKILL.md +642 -0
- package/skills/postmerge/references/deploy-status-debugging.md +138 -0
- package/skills/postmerge/references/graceful-degradation.md +20 -0
- package/skills/postmerge/references/sentry-error-count-delta.md +137 -0
- package/skills/preflight/SKILL.md +1553 -0
- package/skills/preflight/references/check-13-founder-check.md +286 -0
- package/skills/preflight/scripts/founder-check.py +1640 -0
- package/skills/preflight/scripts/parse-form-a.awk +107 -0
- package/skills/preflight/scripts/probe-verb-gate.sh +108 -0
- package/skills/product-roadmap/SKILL.md +357 -0
- package/skills/product-roadmap/scripts/roadmap-reconcile.sh +327 -0
- package/skills/provision-cloudflare/SKILL.md +67 -0
- package/skills/provision-cloudflare/scripts/provision-cloudflare.sh +271 -0
- package/skills/provision-doppler/SKILL.md +58 -0
- package/skills/provision-doppler/scripts/provision-doppler.sh +358 -0
- package/skills/provision-github/SKILL.md +59 -0
- package/skills/provision-github/scripts/provision-github.sh +300 -0
- package/skills/provision-hetzner/SKILL.md +76 -0
- package/skills/provision-hetzner/scripts/provision-hetzner.sh +262 -0
- package/skills/provision-hetzner/test/fixture/knowledge-base/legal/tenant-dpa-register.md +26 -0
- package/skills/provision-hetzner/test/fixture/provision-hetzner-dry-run.golden +34 -0
- package/skills/provision-hetzner/test/provision-hetzner-characterization.test.sh +227 -0
- package/skills/qa/SKILL.md +263 -0
- package/skills/qa/references/browser-preflight.md +22 -0
- package/skills/questionnaire-generate/SKILL.md +328 -0
- package/skills/questionnaire-generate/references/questionnaire.template +60 -0
- package/skills/rclone/SKILL.md +162 -0
- package/skills/rclone/scripts/check_setup.sh +63 -0
- package/skills/release-announce/SKILL.md +65 -0
- package/skills/release-docs/SKILL.md +92 -0
- package/skills/reproduce-bug/SKILL.md +358 -0
- package/skills/resolve-debt/SKILL.md +85 -0
- package/skills/resolve-debt/scripts/resolve-debt.py +584 -0
- package/skills/resolve-parallel/SKILL.md +45 -0
- package/skills/resolve-parallel/workflows/resolve-parallel.workflow.js +415 -0
- package/skills/resolve-pr-parallel/SKILL.md +68 -0
- package/skills/resolve-pr-parallel/workflows/resolve-pr-parallel.workflow.js +419 -0
- package/skills/resolve-todo-parallel/SKILL.md +57 -0
- package/skills/resolve-todo-parallel/workflows/resolve-todo-parallel.workflow.js +398 -0
- package/skills/review/SKILL.md +1621 -0
- package/skills/review/references/anti-slop-scanner-hook.md +40 -0
- package/skills/review/references/defect-classes-migrations.md +9 -0
- package/skills/review/references/generated-input-oracle-surfaces.md +15 -0
- package/skills/review/references/review-e2e-testing.md +116 -0
- package/skills/review/references/review-todo-structure.md +165 -0
- package/skills/review/references/risk-tier-and-fix-rounds.md +95 -0
- package/skills/review/references/semgrep-custom-rules.yaml +174 -0
- package/skills/review/references/ultrathink-phases.md +98 -0
- package/skills/review/references/wfs.md +6 -0
- package/skills/review/scripts/emit-review-trailer.sh +499 -0
- package/skills/review/scripts/ensure-semgrep.sh +99 -0
- package/skills/review/scripts/fix-round-seats.sh +197 -0
- package/skills/review/test/emit-review-trailer.test.sh +387 -0
- package/skills/review/test/ensure-semgrep.test.sh +111 -0
- package/skills/review/test/fix-round-seats.test.sh +237 -0
- package/skills/review/workflows/README.md +147 -0
- package/skills/review/workflows/review.workflow.js +667 -0
- package/skills/schedule/SKILL.md +796 -0
- package/skills/seo-aeo/SKILL.md +139 -0
- package/skills/seo-aeo/scripts/validate-csp.sh +233 -0
- package/skills/seo-aeo/scripts/validate-seo.sh +262 -0
- package/skills/ship/SKILL.md +3022 -0
- package/skills/ship/references/adr-ordinal-collision.md +47 -0
- package/skills/ship/references/affected-gate-contract.md +115 -0
- package/skills/ship/references/ci-run-diagnosis.md +29 -0
- package/skills/ship/references/ci-workflow-authoring.md +68 -0
- package/skills/ship/references/counsel-review-clo-attestation.md +38 -0
- package/skills/ship/references/cto-ruling-armed-push.md +5 -0
- package/skills/ship/references/decision-challenges-render.md +71 -0
- package/skills/ship/references/detached-battery-verdict.md +13 -0
- package/skills/ship/references/feature-tweet-draft.md +42 -0
- package/skills/ship/references/followthrough-issue-body-template.md +47 -0
- package/skills/ship/references/followthrough-stub-template.sh +92 -0
- package/skills/ship/references/merge-queue-dequeue.md +39 -0
- package/skills/ship/references/operator-holds.md +149 -0
- package/skills/ship/references/pipeline-tally-render.md +43 -0
- package/skills/ship/references/pr-overlap.md +153 -0
- package/skills/ship/references/queue-mode.md +7 -0
- package/skills/ship/references/ready-run-wait.md +36 -0
- package/skills/ship/references/red-on-main-quarantine.md +110 -0
- package/skills/ship/references/register-update-pr-pattern.md +88 -0
- package/skills/ship/references/settle-then-admin-merge.md +130 -0
- package/skills/ship/references/supabase-column-probe.md +13 -0
- package/skills/ship/scripts/auto-close-scan.sh +76 -0
- package/skills/ship/scripts/battery-owed.sh +403 -0
- package/skills/ship/scripts/hold-gate-eval.sh +410 -0
- package/skills/ship/scripts/net-issue-flow.sh +665 -0
- package/skills/ship/scripts/pr-overlap-preflight.sh +483 -0
- package/skills/ship/scripts/ship-pir-action-items-gate.sh +246 -0
- package/skills/ship/scripts/technical-ruling-gate.sh +444 -0
- package/skills/skill-creator/SKILL.md +299 -0
- package/skills/skill-creator/references/api-security.md +248 -0
- package/skills/skill-creator/references/authoring-levers.md +110 -0
- package/skills/skill-creator/references/be-clear-and-direct.md +587 -0
- package/skills/skill-creator/references/best-practices.md +431 -0
- package/skills/skill-creator/references/common-patterns.md +639 -0
- package/skills/skill-creator/references/core-principles.md +193 -0
- package/skills/skill-creator/references/executable-code.md +188 -0
- package/skills/skill-creator/references/iteration-and-testing.md +509 -0
- package/skills/skill-creator/references/official-spec.md +193 -0
- package/skills/skill-creator/references/recommended-structure.md +180 -0
- package/skills/skill-creator/references/skill-structure.md +396 -0
- package/skills/skill-creator/references/using-scripts.md +122 -0
- package/skills/skill-creator/references/using-templates.md +120 -0
- package/skills/skill-creator/references/workflows-and-validation.md +541 -0
- package/skills/skill-creator/scripts/init_skill.py +322 -0
- package/skills/skill-creator/scripts/package_skill.py +110 -0
- package/skills/skill-creator/scripts/quick_validate.py +64 -0
- package/skills/skill-creator/templates/router-skill.md +73 -0
- package/skills/skill-creator/templates/simple-skill.md +34 -0
- package/skills/skill-creator/workflows/add-reference.md +96 -0
- package/skills/skill-creator/workflows/add-script.md +104 -0
- package/skills/skill-creator/workflows/add-template.md +83 -0
- package/skills/skill-creator/workflows/add-workflow.md +128 -0
- package/skills/skill-creator/workflows/audit-skill.md +159 -0
- package/skills/skill-creator/workflows/create-domain-expertise-skill.md +623 -0
- package/skills/skill-creator/workflows/create-new-skill.md +207 -0
- package/skills/skill-creator/workflows/get-guidance.md +134 -0
- package/skills/skill-creator/workflows/upgrade-to-router.md +170 -0
- package/skills/skill-creator/workflows/verify-skill.md +226 -0
- package/skills/skill-security-scan/SKILL.md +145 -0
- package/skills/skill-security-scan/references/disclaimer.md +21 -0
- package/skills/skill-security-scan/references/first-party-allowlist.yaml +38 -0
- package/skills/skill-security-scan/references/override-artifact-schema.json +68 -0
- package/skills/skill-security-scan/references/override-mechanism.md +171 -0
- package/skills/skill-security-scan/references/redirect-domains.yaml +27 -0
- package/skills/skill-security-scan/references/regex-patterns.md +136 -0
- package/skills/skill-security-scan/references/rules/code-exec.yaml +70 -0
- package/skills/skill-security-scan/references/rules/filesystem-boundary.yaml +29 -0
- package/skills/skill-security-scan/references/rules/manifest.yaml +44 -0
- package/skills/skill-security-scan/references/rules/supply-chain.yaml +36 -0
- package/skills/skill-security-scan/references/scan-meta-schema.json +63 -0
- package/skills/skill-security-scan/references/test-fixtures/clean-soleur-style.skill.md +23 -0
- package/skills/skill-security-scan/references/test-fixtures/clean-third-party.skill.md +26 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-codeexec.skill.md +23 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-curl-pipe-bash.skill.md +69 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-prompt-injection.skill.md +17 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-telemetry-beacon.skill.md +23 -0
- package/skills/skill-security-scan/references/typosquat-targets.yaml +65 -0
- package/skills/skill-security-scan/scripts/check-codeexec.sh +41 -0
- package/skills/skill-security-scan/scripts/check-filesystem-boundary.sh +19 -0
- package/skills/skill-security-scan/scripts/check-prompt-injection.sh +95 -0
- package/skills/skill-security-scan/scripts/check-supply-chain.sh +219 -0
- package/skills/skill-security-scan/scripts/check-telemetry-surface.sh +126 -0
- package/skills/skill-security-scan/scripts/lib.sh +197 -0
- package/skills/skill-security-scan/scripts/parse-override.sh +231 -0
- package/skills/skill-security-scan/scripts/run-scan.sh +342 -0
- package/skills/skill-security-scan/scripts/run-self-test.sh +95 -0
- package/skills/skill-security-scan/test/argv-ceiling.test.sh +180 -0
- package/skills/skill-security-scan/test/meta-dir-reap.test.sh +411 -0
- package/skills/skill-security-scan/test/parse-override.test.sh +607 -0
- package/skills/skill-security-scan/test/redact-pii-ghs-shape.test.sh +251 -0
- package/skills/social-distribute/SKILL.md +485 -0
- package/skills/spec-templates/SKILL.md +274 -0
- package/skills/sync/SKILL.md +49 -0
- package/skills/test-browser/SKILL.md +464 -0
- package/skills/test-browser/references/feature-map.md +161 -0
- package/skills/test-fix-loop/SKILL.md +159 -0
- package/skills/test-fix-loop/references/determinism-checklist.md +154 -0
- package/skills/triage/SKILL.md +402 -0
- package/skills/trigger-cron/SKILL.md +136 -0
- package/skills/trigger-cron/scripts/trigger.sh +198 -0
- package/skills/user-set-role/SKILL.md +147 -0
- package/skills/user-set-role/scripts/set-role.sh +218 -0
- package/skills/user-story-writer/SKILL.md +77 -0
- package/skills/ux-audit/SKILL.md +251 -0
- package/skills/ux-audit/references/finding.schema.json +62 -0
- package/skills/ux-audit/references/route-list.yaml +95 -0
- package/skills/ux-audit/scripts/bot-fixture.ts +270 -0
- package/skills/ux-audit/scripts/bot-signin.ts +135 -0
- package/skills/ux-audit/scripts/dedup-hash.ts +46 -0
- package/skills/work/SKILL.md +1479 -0
- package/skills/work/references/end-of-work-resume.md +7 -0
- package/skills/work/references/hook-test-main-cwd.md +24 -0
- package/skills/work/references/key-principles.md +83 -0
- package/skills/work/references/property-testing.md +122 -0
- package/skills/work/references/sql-security-definer-rpc-scaffold.sql +78 -0
- package/skills/work/references/work-agent-teams.md +97 -0
- package/skills/work/references/work-lifecycle-parallel.md +147 -0
- package/skills/work/references/work-lockfile-bumps.md +97 -0
- package/skills/work/references/work-scratch-sandboxes.md +212 -0
- package/skills/work/references/work-subagent-fanout.md +61 -0
- package/skills/work/references/work-test-harness-sharp-edges.md +73 -0
- package/skills/xcode-test/SKILL.md +360 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Deploy Status Debugging
|
|
2
|
+
|
|
3
|
+
When the release workflow's deploy step fails or times out, query `/hooks/deploy-status` to get the structured exit reason from ci-deploy.sh.
|
|
4
|
+
|
|
5
|
+
## Call Pattern
|
|
6
|
+
|
|
7
|
+
Run this as ONE Bash call (variables do not persist between calls). Fetch the credentials from Doppler `prd_terraform`, sign, then GET (read-only endpoint; the HMAC is computed over the empty body). The signature and the Access service-token pair ride curl's stdin config, never its argument list (argv shows in `/proc/<pid>/cmdline`). Bash only; `bash -x` would print them.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
WEBHOOK_SECRET=$(doppler secrets get WEBHOOK_DEPLOY_SECRET --project soleur --config prd_terraform --plain)
|
|
11
|
+
CF_ACCESS_CLIENT_ID=$(doppler secrets get CF_ACCESS_CLIENT_ID --project soleur --config prd_terraform --plain)
|
|
12
|
+
CF_ACCESS_CLIENT_SECRET=$(doppler secrets get CF_ACCESS_CLIENT_SECRET --project soleur --config prd_terraform --plain)
|
|
13
|
+
SIGNATURE=$(printf '' | HMAC_KEY="$WEBHOOK_SECRET" python3 -I -c 'import hashlib,hmac,os,sys;k=os.environb.get(b"HMAC_KEY");k or sys.exit(1);sys.stdout.write(hmac.new(k,sys.stdin.buffer.read(),hashlib.sha256).hexdigest())')
|
|
14
|
+
(LC_ALL=C; for n in SIGNATURE CF_ACCESS_CLIENT_ID CF_ACCESS_CLIENT_SECRET; do case "${!n}" in ''|*[!A-Za-z0-9._~+/=-]*) echo "$n unset or not [A-Za-z0-9._~+/=-] (refused, not sent)" >&2; exit 1;; esac; done) || exit 1
|
|
15
|
+
curl --disable --proto '=https' -m 30 -fsS -X GET --config - https://deploy.soleur.ai/hooks/deploy-status \
|
|
16
|
+
< <(printf 'header = "X-Signature-256: sha256=%s"\nheader = "CF-Access-Client-Id: %s"\nheader = "CF-Access-Client-Secret: %s"\n' "$SIGNATURE" "$CF_ACCESS_CLIENT_ID" "$CF_ACCESS_CLIENT_SECRET")
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## When NOT to use this probe
|
|
20
|
+
|
|
21
|
+
This runbook covers debugging the deploy-status webhook code path itself. Do NOT use this probe for **post-apply verification** of `terraform apply -target=terraform_data.deploy_pipeline_fix`. The HTTP probe is a proxy-layer signal: it observes "webhook is up + HMAC validates" but the post-apply question is provisioner-layer: "did the file provisioners write to disk and did remote-exec restart the service?" When CF Access landed in front of `/hooks/*`, the proxy-layer signal degraded silently — anonymous probes return 403 from Access — while provisioner-layer reality was unaffected. Eight prior remediations succeeded with a green AC marker that was actually red.
|
|
22
|
+
|
|
23
|
+
For post-apply verification, use the file+systemd contract:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
SERVER_IP=$(cd apps/web-platform/infra && terraform output -raw server_ip)
|
|
27
|
+
LOCAL_HASH=$(sha256sum apps/web-platform/infra/ci-deploy.sh | awk '{print $1}')
|
|
28
|
+
ssh -o ConnectTimeout=5 root@"$SERVER_IP" \
|
|
29
|
+
"sha256sum /usr/local/bin/ci-deploy.sh && systemctl is-active webhook"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The remote hash must equal `$LOCAL_HASH` and `systemctl is-active webhook` must return `active`. Extend the same pattern to `webhook.service`, `cat-deploy-state.sh`, and `hooks.json` if you want to verify all four provisioners landed (the `ci-deploy.sh` hash typically suffices because the provisioners run in sequence and any earlier failure aborts the resource creation).
|
|
33
|
+
|
|
34
|
+
The `soleur:ship` Phase 5.5 "Deploy Pipeline Fix Drift Gate" surfaces this contract automatically when a PR edits any of the four trigger files. See [`2026-04-29-deploy-pipeline-fix-postapply-verification-cf-access.md`](../../../../../knowledge-base/project/learnings/bug-fixes/2026-04-29-deploy-pipeline-fix-postapply-verification-cf-access.md) for the root cause and contract design.
|
|
35
|
+
|
|
36
|
+
## Reason Taxonomy
|
|
37
|
+
|
|
38
|
+
| reason | exit_code | Meaning | Remediation |
|
|
39
|
+
|---|---|---|---|
|
|
40
|
+
| `ok` | 0 | Deploy succeeded | None |
|
|
41
|
+
| `running` | -1 | ci-deploy.sh is in progress | Poll again |
|
|
42
|
+
| `no_prior_deploy` | -2 | State file missing (fresh server) | Trigger deploy |
|
|
43
|
+
| `insufficient_disk_space` | 1 | Less than 5GB free on server | Run disk-monitor, consider pruning docker images earlier |
|
|
44
|
+
| `lock_contention` | 1 | Another ci-deploy.sh holds flock | Wait for prior run to finish; if stuck >10min, SSH to kill |
|
|
45
|
+
| `doppler_unavailable` | 1 | doppler binary missing on server | Re-run terraform apply to reprovision |
|
|
46
|
+
| `doppler_token_missing` | 1 | DOPPLER_TOKEN env var not set | Check `/etc/default/webhook-deploy` on server |
|
|
47
|
+
| `doppler_fetch_failed` | 1 | Transient Doppler API failure | Retry deploy |
|
|
48
|
+
| `command_missing` | 1 | Empty SSH_ORIGINAL_COMMAND | Check webhook -> ssh trigger wiring |
|
|
49
|
+
| `command_malformed` | 1 | Wrong arg count | Check CI payload shape |
|
|
50
|
+
| `action_unknown` | 1 | Unknown action verb in command | Fix CI workflow |
|
|
51
|
+
| `component_unknown` | 1 | Unknown component name | Check ALLOWED_COMPONENTS allowlist |
|
|
52
|
+
| `image_mismatch` | 1 | Image doesn't match component | Check ALLOWED_IMAGES mapping |
|
|
53
|
+
| `tag_malformed` | 1 | Tag doesn't match semver | Check CI tag format |
|
|
54
|
+
| `canary_sandbox_failed` | 1 | bwrap verification failed on canary | Read the `DEPLOY_ROLLBACK: bwrap sandbox non-functional` row without SSH: `knowledge-base/engineering/operations/runbooks/canary-probe-set.md#blocking-bwrap-sandbox-probe--reading-its-self-report-8016-pr-8026` |
|
|
55
|
+
| `canary_sandbox_failed` | 1 | stderr `bwrap: Unexpected capabilities but not setuid, old file caps config?` (read `bwrap_err=` on the `DEPLOY_ROLLBACK: bwrap sandbox non-functional` journald row, Better Stack tag `ci-deploy` — the deploy-status JSON carries only `reason`) — a file-cap'd `/usr/bin/bwrap` OR ambient/bounding capabilities reaching a non-root exec (e.g. a stale installed `ci-deploy.sh` still passing `--cap-add SYS_ADMIN`); released bwrap 0.8–0.12 aborts on `real_uid != 0 && has_caps()` (upstream has no file-cap support) | Merged is not delivered: the host runs the INSTALLED `ci-deploy.sh` until `apply-deploy-pipeline-fix.yml` (push-triggered on `apps/web-platform/infra/ci-deploy.sh`; `workflow_dispatch` when the push arm is cancelled) delivers it — verify by comparing `.ci_deploy_sha256` in the deploy-status hook's JSON body against `git show origin/main:apps/web-platform/infra/ci-deploy.sh \| sha256sum` (or run `scripts/check-deploy-script-parity.sh`). If drifted, dispatch the apply; if the host script is current, the image itself still carries the `setcap` — confirm the deployed tag postdates the #9874 revert build. Resolution trail: incident #9871, apply run 37976212395, green deploy run 37980286319 |
|
|
56
|
+
| `canary_sandbox_failed` | 1 | stderr `/usr/local/bin/bwrap: line 424: /usr/bin/bwrap: Operation not permitted` (the shim's final `exec`; inner rc 126; read `bwrap_err=` on the `DEPLOY_ROLLBACK: bwrap sandbox non-functional` journald row, Better Stack tag `ci-deploy`) — execve EPERM: file caps on the real binary not covered by the container bounding set (capped image + clean container, no `--cap-add`) | Deploy the cap-free image tag (post-#9874 build — in #9871 the fix landed as `v0.334.1` after a rerun of the upstream flaked `test-scripts` job re-armed the `ci_not_green`-skipped deploy). If the image is clean but `--cap-add` symptoms persist, the host script is stale: merged is not delivered — the installed `ci-deploy.sh` runs until `apply-deploy-pipeline-fix.yml` delivers it; verify `.ci_deploy_sha256` in the deploy-status hook's JSON body vs `git show origin/main:apps/web-platform/infra/ci-deploy.sh \| sha256sum` (or `scripts/check-deploy-script-parity.sh`) and re-dispatch the apply on drift |
|
|
57
|
+
| `canary_failed` | 1 | Canary health-check failed 10x | Roll back; inspect canary container logs |
|
|
58
|
+
| `production_start_failed` | 1 | Production container didn't start post-swap | Check docker state; consider manual rollback |
|
|
59
|
+
| `plugin_seed_mount_unsafe` | 1 | The plugin-mount seed REFUSED to run: `PLUGIN_MOUNT_DIR` was not non-empty/absolute/under `/mnt/data/` ending `/plugins/soleur`. The seed's container-side `find -delete` runs as root on the bind source, so a wrong-path env value would be a recursive delete on an arbitrary host path — this reason means the guard caught that, not that the copy failed. Emits the stderr/journald marker `PLUGIN_SEED_MOUNT_UNSAFE` | Check what set `PLUGIN_MOUNT_DIR` (webhook.service env, `/etc/default/webhook-deploy`, an infra-config delivery) — the deploy never attempted the seed, so nothing was deleted. The correct value is `/mnt/data/plugins/soleur` |
|
|
60
|
+
| `plugin_seed_copy_failed` | 1 | The plugin-mount seed failed. Post-#8743 the seed is container-side (`docker run --rm -u 0 --entrypoint /bin/sh -v $PLUGIN_MOUNT_DIR:/plugin-mount`: clear → `cp -a` → `.seed-complete`, all inside the image), so a foreign-uid or root-seeded tree CANNOT wedge it the way the pre-#8743 deploy-uid `docker cp` did (the `fchmodat2 .claude-plugin: operation not permitted` EPERM that killed every web-2 deploy for 25 days — cloud-init's root-run seed produces a uid-1001 tree that uid-1000's client-side untar cannot chmod/delete) | Read the `PLUGIN_SEED_PROBE dst_owner=<u>:<g> marker=<u>:<g>\|absent findmnt=<src>` journald row emitted immediately before the mutation (Better Stack — ships only when the probe line reaches stderr/PRIORITY 3, the arm that admitted the fchmodat2 rows; discriminating uid/gid/mount-source probe — the facts the fchmodat2 root cause needed and could not get off-box). A post-#8743 `plugin_seed_copy_failed` with a seed that is ownership-agnostic means the mount itself is broken (read-only remount, missing dir, image missing `/opt/soleur/plugin`), not ownership — grep Better Stack for the container's stderr around the timestamp. Do NOT SSH the host. |
|
|
61
|
+
| `ok_peer_fanout_degraded` | 0 | Deploy SUCCEEDED locally, but a PEER web host did not ACCEPT the fan-out (missing 202: unreachable / HMAC-rejected / secret unreadable / signature uncomputable). Non-ACCEPTANCE, NOT peer-failed — the peer's own async verdict is the `.peers["<ip>"]` slot (see below) | Deploy is live on this host; the peer is the problem. Grep Better Stack (tag `ci-deploy`) for `FANOUT: peer <ip> NOT accepted`, `FANOUT: webhook secret unavailable`, `FANOUT: could not compute the request signature`. Check the peer's webhook on the private net (`:9000` firewall is private-only). Do NOT SSH the host. |
|
|
62
|
+
| `inngest_restart_failed` | 1 | `systemctl restart inngest-server.service` itself exited non-zero (restart path, before any health probe) | Check Sentry + Better Stack for OOM/unit errors around the timestamp; re-dispatch `restart-inngest-server.yml` once — repeated failures mean a unit/host problem, not a transient |
|
|
63
|
+
| `inngest_health_failed` | 1 | `/health` unreachable after the verify budget (`verify_inngest_health`) | **Post-#5159 the verify gates on `/health` (process liveness) only; a missing cron-plan is ADVISORY** (the cron-plan loop polls `/v1/functions` best-effort and returns success even with no cron re-armed) — so this reason now means the `inngest-server` process itself never came back healthy, NOT a de-planned registry. A standalone restart de-plans crons and CANNOT re-arm them (a loopback `PUT /api/inngest` returns `modified:false`, proven #5159), so do NOT re-dispatch `restart-inngest-server.yml` to fix missing crons. For a genuinely dead process: check Sentry + Better Stack for OOM/unit errors around the timestamp, then recover by **redeploying / restarting web-platform** (restarting the app container makes it reconnect; the inngest-server re-discovers it and re-arms crons — reconnection-driven, the SDK sets no `appVersion`. Re-run the latest **deploy-arm** `web-platform-release` run — `gh run rerun "$(gh run list --workflow=web-platform-release.yml --event workflow_run -L1 --json databaseId -q '.[0].databaseId')"`; `--event workflow_run` is required because since #5806/ADR-217 every merge also produces a push-arm run that only builds and publishes and restarts NOTHING — or `docker restart soleur-web-platform`). If the Sentry cron monitors (monitors API curl in postmerge SKILL.md) show persistent missed check-ins, that is real H9b — recover the same way (redeploy web-platform, immediate; or wait for the `--poll-interval` self-heal). Confirm host delivery the no-SSH way before re-dispatch (`apply-deploy-pipeline-fix.yml` run green for the merge SHA + infra-config-status per-file sha256 match, per the soleur:ship Deploy Pipeline Fix Drift Gate — NOT the SSH post-apply contract above) |
|
|
64
|
+
| `quiesced` | 0 | `quiesce inngest _ _` (op=quiesce-web, #6178) succeeded — inngest is not-serving AND unit-inactive AND not-enabled on this host, and (where the unit exists) the quiesce marker `/var/lib/inngest/quiesced-by-op` attributes it, so the tri-state reads `quiesced` (#6921) | None (the no-SSH web-host scheduler quiesce for the dedicated-host cutover 2.2 gap). Re-run `op=execute`. |
|
|
65
|
+
| `quiesce_capture_failed` | 1 | `quiesce inngest _ _` found the unit `active` and ran the bounded (120 s) capture of still-armed reminders BEFORE writing the marker or disabling/stopping; the capture failed or timed out, so the handler stopped NOTHING (#6921) | The scheduler is still running — no reminder is at risk. Read the cause from Better Stack (tag `ci-deploy`): `INNGEST_QUIESCE_CAPTURE_FAILED rc=… stderr_tail=…` — the tail is passed through `_cred_err_tail` and then a URI/DSN scrub before it is logged. If the unit is active but its loopback GQL is dead (the capture can never succeed), the unit is still `enabled`, so it is not quiesced and a restart is allowed: dispatch `restart-inngest-server.yml`, then re-dispatch `op=quiesce-web`. There is no override flag. Do NOT SSH the host. |
|
|
66
|
+
| `quiesce_capture_unavailable` | 1 | `quiesce inngest _ _` found the unit neither `active`, nor already quiesced, nor absent (`failed`, `activating`, `deactivating`, inactive-but-enabled, or `disabled_unattributed`), so there was no trustworthy capture to take; nothing was disabled or stopped (#6921). Journald (tag `ci-deploy`) `INNGEST_QUIESCE_CAPTURE_UNAVAILABLE unit= enabled= state=` | `state=disabled_unattributed` → dispatch `op=rollback`, then `op=quiesce-web`. `enabled=enabled` (unit failed/activating/inactive) → not quiesced, so dispatch `restart-inngest-server.yml` and re-dispatch `op=quiesce-web` once it serves. `unit=deactivating` → a stop is in flight; re-dispatch after 180 s. Do NOT SSH the host. |
|
|
67
|
+
| `quiesce_marker_write_failed` | 1 | the capture succeeded but the atomic write of the quiesce marker `/var/lib/inngest/quiesced-by-op` failed; nothing was disabled or stopped (#6921) | Re-dispatch `op=quiesce-web` (it captures again). If it repeats, the `/var/lib/inngest` write path on the host is broken: read the `ci-deploy` rows around the failure in Better Stack and file an issue with the run URL. Do NOT SSH the host. |
|
|
68
|
+
| `quiesced_shape_unrecognized` | 1 | `quiesce inngest _ _` verified not-serving + not-enabled, but on a host that has the unit the tri-state did not read `quiesced` (marker missing, unparseable, or voided) (#6921) | The unit is stopped and disabled, so no scheduler runs, but 2.2 will not certify it and 2.1 cannot resume. Dispatch `op=rollback` (retires the capture, removes any marker, re-enables), then a fresh `op=quiesce-web`. Do NOT SSH the host. |
|
|
69
|
+
| `inngest_still_serving` | 1 | quiesce ran but inngest is STILL serving `/health` OR the unit is still active (a scheduler executing queued jobs can outlive `/health`) | Persistent still-serving = the unit is being RESURRECTED. Pull `reason=` from `/hooks/deploy-status` + Better Stack (`logger -t ci-deploy`) and investigate what restarts it (e.g. a stray deploy). Do NOT SSH the host. |
|
|
70
|
+
| `inngest_still_enabled` | 1 | quiesce stopped inngest but the unit is STILL `enabled` (the `disable` failed on a unit WITH an `[Install]` section) — a reboot would re-arm the old scheduler | The enabled-state assertion caught what a serving-only verify would miss. Check Better Stack for the disable failure; a persistent case means the unit is being re-enabled (stray deploy). Do NOT SSH the host. |
|
|
71
|
+
| `quiesced_peer_fanout_unaccepted` | 1 | quiesce succeeded locally but a PEER web host did not ACCEPT the fan-out (missing 202: unreachable / HMAC-rejected). **NOTE: non-ACCEPTANCE, NOT peer-not-quiesced** — the peer's own quiesce verdict lands on the PEER's deploy-status slot (DI-C3, unreadable from here) | Check the peer host's reachability + the web→web:9000 firewall + the run log, then re-dispatch `op=quiesce-web`. Not always transient: the same reason is written when the originating host cannot read the `deploy-peer` secret from its own `hooks.json`, where a re-dispatch does not converge, and when the originating host cannot compute the request signature (python3 missing or the signer failing) — grep Better Stack for `FANOUT: webhook secret unavailable` and `FANOUT: could not compute the request signature` before re-dispatching. Do NOT SSH the host. |
|
|
72
|
+
| `inngest_quiesced_restart_refused` | 1 | `restart inngest` found the unit in the quiesced shape (`is-active` ∈ {`inactive`, `failed`} AND `is-enabled` = `disabled`) WITH a valid quiesce marker, and refused — a restart STARTS a disabled unit (#8077). Journald (tag `ci-deploy`) `INNGEST_RESTART_REFUSED` | Deliberate, not a fault: the web scheduler was quiesced by `op=quiesce-web` for the dedicated-host cutover. Only `op=rollback` (the `enable` verb) re-arms it; a restart never does. If the quiesce was not intended, dispatch `op=rollback`. Do NOT SSH the host. |
|
|
73
|
+
| `inngest_disabled_unattributed_restart_refused` | 1 | `restart inngest` found the stopped+disabled shape with NO valid quiesce marker (absent, unparseable, or voided because the unit started after it) and refused. The refusal is on the shape alone, so a lost marker never turns into a restart (#6921/#8077) | Not a deliberate quiesce: something else disabled the unit (typically a failed `systemctl enable` in `inngest-bootstrap.sh`, or a manual disable). The watchdog also reports it as `DISABLED_UNATTRIBUTED`. Dispatch `op=rollback` to re-enable and start it. Do NOT SSH the host. |
|
|
74
|
+
| `inngest_quiesced_deploy_refused` | 1 | `deploy inngest <tag>` found the quiesced shape with a valid quiesce marker and refused at the top of the arm, before the image pull and the bootstrap (which would `enable` and restart the unit) | Same as `inngest_quiesced_restart_refused`: only `op=rollback` re-arms a quiesced web scheduler. Re-run the image deploy after `op=rollback` if the scheduler is meant to serve again. Do NOT SSH the host. |
|
|
75
|
+
| `inngest_disabled_unattributed_deploy_refused` | 1 | `deploy inngest <tag>` found the stopped+disabled shape with NO valid quiesce marker and refused before the image pull | Same as `inngest_disabled_unattributed_restart_refused`: dispatch `op=rollback`, then re-run the image deploy. Do NOT SSH the host. |
|
|
76
|
+
| `enabled` | 0 | `enable inngest _ _` (op=rollback reverse, #6178) succeeded — the cutover capture was retired to `cutover-capture.json.retired-<epoch>` and the quiesce marker removed BEFORE enable, then inngest re-enabled + started + serving on this host (journald `INNGEST_ENABLE: retired capture=… marker_removed=…`) | None (the no-SSH reverse of quiesce; restores the `[Install]` symlink a quiesce-disable removed). |
|
|
77
|
+
| `inngest_enable_failed` | 1 | `systemctl enable inngest-server.service` itself exited non-zero (enable path) | On **web-2** this is expected: web-2 has no `inngest-server.service`, and the `op=rollback` fan-out writes this reason to web-2's own slot — tolerated, nothing to do. On web-1: check Better Stack for the unit error around the timestamp; re-dispatch `op=rollback`. Do NOT SSH the host. |
|
|
78
|
+
| `inngest_start_failed` | 1 | enable succeeded but `systemctl start inngest-server.service` exited non-zero | Check Better Stack + Sentry for OOM/unit errors; re-dispatch `op=rollback`. Do NOT SSH the host. |
|
|
79
|
+
| `inngest_reenable_unverified` | 1 | enable+start ran but the unit is not serving `/health` OR is not `enabled` afterward | Pull `reason=` from `/hooks/deploy-status` + Better Stack and investigate; re-dispatch `op=rollback`. Do NOT SSH the host. |
|
|
80
|
+
| `enabled_peer_fanout_unaccepted` | 1 | enable succeeded locally but a PEER did not ACCEPT the fan-out (non-ACCEPTANCE, NOT peer-not-enabled; DI-C3) | Check the peer host + firewall + run log, re-dispatch `op=rollback`. Do NOT SSH the host. |
|
|
81
|
+
| `component_not_quiescible` | 1 | `quiesce` targeted a non-inngest component | Only `quiesce inngest _ _` is valid (web-platform quiesce is docker-level). Fix the CI payload. |
|
|
82
|
+
| `component_not_enableable` | 1 | `enable` targeted a non-inngest component | Only `enable inngest _ _` is valid. Fix the CI payload. |
|
|
83
|
+
| `no_handler` | 1 | Component has no case handler in ci-deploy.sh | Add handler (code change) |
|
|
84
|
+
| `unhandled` | 1 | EXIT trap fired; specific reason not instrumented | Check journalctl; consider adding explicit final_write_state call |
|
|
85
|
+
| `timeout` | 124 | Wall-clock cap (`ci-deploy-wrapper.sh` 1800s, raised from 900s in #5061) sent SIGTERM and `ci-deploy.sh`'s TERM trap fired before bash exited (#3704) | SSH and run `journalctl -u webhook -t ci-deploy --since '-15m'` for the last successful step before silence; likely culprit is hung `docker pull`, `docker exec bwrap`, or canary probe. |
|
|
86
|
+
| `corrupt_state` | -3 | State file is unparseable JSON | Server-side disk issue; SSH to investigate |
|
|
87
|
+
|
|
88
|
+
## Response fields: `.peers` (per-fan-out-peer verdict merge)
|
|
89
|
+
|
|
90
|
+
`cat-deploy-state.sh` merges a top-level `peers` object when the state file
|
|
91
|
+
carries `fanout_peers` — written by the deploy arm when it fanned out. A
|
|
92
|
+
`deploy-peer`-received run writes no `fanout_peers` (no re-fan), so the merge is
|
|
93
|
+
inert on a peer and cannot recurse.
|
|
94
|
+
|
|
95
|
+
Each key is a peer private IP (`10.0.1.x`); each value is that peer's **whole**
|
|
96
|
+
deploy-status JSON, fetched `GET http://<ip>:9000/hooks/deploy-status` over the
|
|
97
|
+
private net with the shared `webhook_deploy_secret` HMAC (`curl --max-time 3`,
|
|
98
|
+
stdin `--config` — the `fan_out_to_peers` pattern). An unreadable peer fills its
|
|
99
|
+
slot with `{"error":"unreachable"|"http_<code>"|"not_json"|"unsigned"|"bad_peer"}`
|
|
100
|
+
— the merge never fails the hook; the release workflow owns the verdict.
|
|
101
|
+
|
|
102
|
+
Error-slot vocabulary: `unreachable` (connect/timeout), `http_<code>` (non-200),
|
|
103
|
+
`not_json` (200 but unparseable), `bad_peer` (the fanout_peers entry was not
|
|
104
|
+
`^[0-9.]+$` — it never reached curl), `unsigned` (web-1 could not sign the read
|
|
105
|
+
— its hooks.json deploy-status secret unreadable/uncomputable). The workflow
|
|
106
|
+
treats **`unsigned` as TERMINAL** (exit 1 on first sight — a credential defect
|
|
107
|
+
cannot heal inside the poll budget); every other class, a missing slot, and a
|
|
108
|
+
non-object `.peers` are polled until the budget exhausts. If the budget
|
|
109
|
+
exhausts while every body still lacks a `.peers` key entirely, web-1's
|
|
110
|
+
`cat-deploy-state.sh` predates the peers merge — its delivery rides
|
|
111
|
+
`apply-deploy-pipeline-fix.yml` / `terraform_data.deploy_pipeline_fix_web2`,
|
|
112
|
+
and that red is a delivery gap, not a peer failure.
|
|
113
|
+
|
|
114
|
+
The release workflow's `Verify peer deploy completion` step grades each expected
|
|
115
|
+
peer (every `WEB_HOST_PRIVATE_IPS` member except the `deploy.` ingress host):
|
|
116
|
+
`exit_code==0 && tag=="v$VERSION"` passes; `exit_code` in `-1/-2/-3` or a missing
|
|
117
|
+
slot keeps polling (the peer's deploy starts when web-1's ends — async by
|
|
118
|
+
design); any other `exit_code` or an `error` slot fails the run **fail-closed** —
|
|
119
|
+
a peer deploy failure now reaches the run result instead of hiding behind
|
|
120
|
+
web-1's `/health` (the gap that let #8743 burn 25 days).
|
|
121
|
+
|
|
122
|
+
Because the slot embeds the peer's own JSON, `.peers["10.0.1.11"].ci_deploy_sha256`
|
|
123
|
+
also answers "is web-2's installed script current" — the parity read
|
|
124
|
+
`scripts/check-deploy-script-parity.sh` formalizes.
|
|
125
|
+
|
|
126
|
+
## When NOT to SSH
|
|
127
|
+
|
|
128
|
+
Per AGENTS.md: SSH is for infrastructure provisioning (Terraform) only, never for logs. Use `/hooks/deploy-status` + Sentry API + Better Stack as the three observability layers. SSH is read-only last-resort diagnosis for `canary_sandbox_failed` only (bwrap capability errors live in journalctl).
|
|
129
|
+
|
|
130
|
+
## Rerun Safety
|
|
131
|
+
|
|
132
|
+
**Do not `gh run rerun --failed` while ci-deploy.sh may still be running on prod.** A new `/hooks/deploy` POST will hit `flock -n` failure and write `reason=lock_contention` -- masking the original deploy's actual fate. The advisory flock in ci-deploy.sh is held by FD 200 for the full lifetime of the script (release is implicit on FD close at process exit; there is no manual `flock -u` path that could leak). A `lock_contention` reason on rerun therefore means the prior invocation is **still in its critical section**, not a release-path leak.
|
|
133
|
+
|
|
134
|
+
**In-workflow self-gating (PR #3408).** `web-platform-release.yml`'s `deploy` job now begins with a `Pre-rerun lock probe` step that GETs `/hooks/deploy-status` before the deploy POST and short-circuits with an `::error::` annotation when the prior run is still in its critical section (`.exit_code == -1` and `(now - start_ts) <= 1800s` since #5061). The probe is degraded-permissive: any non-JSON / empty / HTTP-error response falls through to the deploy step. flock remains the load-bearing safety net; the probe is a fast-path UX improvement that surfaces "still running" up front instead of after an 1800s downstream-step timeout. `gh run rerun --failed` therefore self-gates against in-flight POSTs in the common case.
|
|
135
|
+
|
|
136
|
+
The operator-side advice below still applies for **out-of-workflow** scenarios (manual triggers, cross-component deploys, ad-hoc curl reruns) where the in-workflow probe doesn't run.
|
|
137
|
+
|
|
138
|
+
If the workflow's verify-completion step times out, **first poll `/hooks/deploy-status` directly** (per the call pattern at the top of this file) and confirm `exit_code` is no longer `-1` before retrying. The verify-completion ceiling is **1800s** as of #5061 (`STATUS_POLL_MAX_ATTEMPTS=360 × INTERVAL_S=5` in `.github/workflows/web-platform-release.yml`); the matching `Verify deploy health and version` ceiling is also 1800s (`HEALTH_POLL_MAX_ATTEMPTS=180 × INTERVAL_S=10`); the `Pre-rerun lock probe` `IN_FLIGHT_CEILING_S` is also 1800s and must be kept in sync with the verify-completion ceiling if either is changed. Wait at least that long before considering the workflow truly stuck. See [`2026-05-07-deploy-poll-ceiling-must-track-realistic-deploy-window.md`](../../../../../knowledge-base/project/learnings/best-practices/2026-05-07-deploy-poll-ceiling-must-track-realistic-deploy-window.md) for the recurrence pattern and prevention checklist, and issue [#3408](https://github.com/jikig-ai/soleur/issues/3408) for the workflow-level pre-rerun probe.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Graceful Degradation — postmerge prerequisites
|
|
2
|
+
|
|
3
|
+
Which postmerge phase degrades, and how, when a prerequisite is absent. Read this when a
|
|
4
|
+
phase reports a missing prerequisite and you need to know whether to skip, warn or abort;
|
|
5
|
+
it is a lookup table, not per-invocation instruction, so it is loaded on demand rather than
|
|
6
|
+
carried in every `soleur:postmerge` body (ADR-229).
|
|
7
|
+
|
|
8
|
+
| Missing Prerequisite | Behavior |
|
|
9
|
+
|---------------------|----------|
|
|
10
|
+
| No production URL | Skip health check with warning |
|
|
11
|
+
| No `SENTRY_AUTH_TOKEN` | Skip Sentry cron monitor check AND error-count delta with warning |
|
|
12
|
+
| No `SENTRY_ISSUE_RW_TOKEN` | Skip the entire error-count-delta + auto-resolve phase (the single-issue GET 403s on the `prd` `SENTRY_AUTH_TOKEN`, re-measured 2026-09-08); recommend manual resolution as today |
|
|
13
|
+
| Sentry API unreachable | Skip Sentry cron monitor check with warning |
|
|
14
|
+
| No Sentry issue identified in PR/linked issue | Skip error-count delta silently (nothing to measure) |
|
|
15
|
+
| Sentry issue not found via API | Skip error-count delta with warning |
|
|
16
|
+
| Playwright MCP unavailable | Skip browser verification with warning |
|
|
17
|
+
| CI run not found | Poll up to 5 minutes, then warn and proceed |
|
|
18
|
+
| No UI files in diff | Skip browser verification entirely |
|
|
19
|
+
| No linked issue | Skip issue comment |
|
|
20
|
+
| No `doppler`, or no `HCLOUD_TOKEN_READONLY` in `prd_terraform`, or no `apply-web-platform-infra.yml` run for the merge SHA (Phase 5.7) | Report `Sole-copy read-back: <missing-token / no word / not delivered>`; never dispatch an apply on a missing read; `missing-token` also files the O5 issue; no run within about 50 min is "not delivered or superseded": read back anyway |
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Phase 3.6: Sentry Error-Count Delta — procedure
|
|
2
|
+
|
|
3
|
+
Loaded by [postmerge SKILL.md](../SKILL.md) Phase 3.6 when the PR body or linked issue names a specific Sentry issue. The trigger, the report vocabulary and the Graceful Degradation rows stay in SKILL.md.
|
|
4
|
+
|
|
5
|
+
**Prerequisites:** the same `SENTRY_ORG` / `API_HOST` resolution as Phase 3.5 (the block below repeats it, so it runs on its own). **The single-issue GET needs an `event:read` token** — the `/organizations/<org>/issues/<id>/` endpoint returns `403` on the `SENTRY_AUTH_TOKEN`/`SENTRY_API_TOKEN` resolved from Doppler `soleur/prd` (Discover/ingest scope only). The GET uses the least-privilege `SENTRY_ISSUE_RO_TOKEN`, falling back to `SENTRY_ISSUE_RW_TOKEN` GET-only — the same ladder as [scripts/sentry-issue.sh](../../../../../scripts/sentry-issue.sh). The write-scoped RW token is used for the auto-resolve PUT only. No read token, or a failed GET, is `SKIPPED` — never `STILL-FIRING`.
|
|
6
|
+
|
|
7
|
+
> **Clarified 2026-09-08 (#7797) — `SENTRY_AUTH_TOKEN` names TWO different
|
|
8
|
+
> tokens, and only one of them 403s here.** An earlier revision of this
|
|
9
|
+
> block was "corrected" on the premise that the 403 claim above was false. That
|
|
10
|
+
> correction was withdrawn: it generalised a measurement taken on the
|
|
11
|
+
> `soleur/prd_terraform` token onto the `soleur/prd` token this phase actually
|
|
12
|
+
> resolves. Both measured 2026-09-08 against
|
|
13
|
+
> `GET /organizations/<org>/issues/<id>/`:
|
|
14
|
+
>
|
|
15
|
+
> - `soleur/prd` `SENTRY_AUTH_TOKEN` (what the code below reads) → **403**. The
|
|
16
|
+
> requirement above is correct and stays.
|
|
17
|
+
> - `soleur/prd_terraform` `SENTRY_AUTH_TOKEN` (the #7797 leaked credential, a
|
|
18
|
+
> personal token carrying org/project/team **admin**) → **200**.
|
|
19
|
+
>
|
|
20
|
+
> They are two different tokens sharing one variable name — the post-mortem
|
|
21
|
+
> records this explicitly. Do not treat a capability measured on one as evidence
|
|
22
|
+
> about the other, and do not widen this GET to an admin-scoped token: the
|
|
23
|
+
> least-privilege credential for it is `SENTRY_ISSUE_RO_TOKEN`
|
|
24
|
+
> (`event:read`, `org:read`, Doppler `soleur/prd`), and [scripts/sentry-issue.sh](../../../../../scripts/sentry-issue.sh)
|
|
25
|
+
> already implements the RO → RW ladder for this same URL.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# ISSUE_ID = the Sentry issue short-id or numeric id from the PR/issue body
|
|
29
|
+
# (a bare token: letters, digits, `-`, `_`). DEPLOY_TS = the merge commit's
|
|
30
|
+
# committer date (Phase 1 recorded the merge SHA) — the reference point for
|
|
31
|
+
# "did the error stop firing post-deploy?".
|
|
32
|
+
ISSUE_ID="<sentry-issue-id-from-pr-body>"
|
|
33
|
+
DEPLOY_TS=$(git show -s --format=%cI "<merge-commit-sha-from-phase-1>" 2>/dev/null || true)
|
|
34
|
+
# Same resolution as Phase 3.5 — this block runs on its own.
|
|
35
|
+
SENTRY_ORG=$(doppler secrets get SENTRY_ORG -p soleur -c prd --plain 2>/dev/null || echo "jikigai")
|
|
36
|
+
API_HOST="${SENTRY_ORG}.sentry.io"
|
|
37
|
+
# GET: least-privilege RO token, RW as a GET-only fallback (scripts/sentry-issue.sh's
|
|
38
|
+
# ladder). The prd SENTRY_AUTH_TOKEN 403s on /issues/<id>/ (#7797) — never use it here.
|
|
39
|
+
# RW is resolved separately: the auto-resolve PUT below needs it and nothing else does.
|
|
40
|
+
SENTRY_RO_TOKEN=$(doppler secrets get SENTRY_ISSUE_RO_TOKEN -p soleur -c prd --plain 2>/dev/null || true)
|
|
41
|
+
SENTRY_RW_TOKEN=$(doppler secrets get SENTRY_ISSUE_RW_TOKEN -p soleur -c prd --plain 2>/dev/null || true)
|
|
42
|
+
SENTRY_READ_TOKEN="${SENTRY_RO_TOKEN:-$SENTRY_RW_TOKEN}"
|
|
43
|
+
# Fail-safe defaults: anything below that does not complete leaves the phase SKIPPED
|
|
44
|
+
# and ISSUE_STOPPED=false, so the PUT cannot fire on missing data.
|
|
45
|
+
SENTRY_DELTA=SKIPPED; ISSUE_STOPPED=false; ISSUE_STATUS=""; ISSUE_JSON=""
|
|
46
|
+
if [[ -z "$SENTRY_READ_TOKEN" ]]; then
|
|
47
|
+
echo "WARNING: neither SENTRY_ISSUE_RO_TOKEN nor SENTRY_ISSUE_RW_TOKEN is set (the prd SENTRY_AUTH_TOKEN 403s on /issues/<id>/). Sentry error-count delta: SKIPPED."
|
|
48
|
+
elif [[ ! "$ISSUE_ID" =~ ^[A-Za-z0-9_-]+$ ]]; then
|
|
49
|
+
echo "WARNING: issue id '$ISSUE_ID' is not a bare token. Sentry error-count delta: SKIPPED."
|
|
50
|
+
elif ! (LC_ALL=C; case "$SENTRY_READ_TOKEN" in *[!A-Za-z0-9._~+/=-]*) exit 1;; esac); then
|
|
51
|
+
echo "WARNING: SENTRY_READ_TOKEN (SENTRY_ISSUE_RO_TOKEN or SENTRY_ISSUE_RW_TOKEN) not [A-Za-z0-9._~+/=-] (refused, not sent). Sentry error-count delta: SKIPPED."
|
|
52
|
+
else
|
|
53
|
+
# argv shows in /proc/<pid>/cmdline, so the token rides curl's stdin config. Bash only; `bash -x` would print the token.
|
|
54
|
+
# Query the issue; capture curl's rc — a failed GET is SKIPPED, not STILL-FIRING.
|
|
55
|
+
get_rc=0
|
|
56
|
+
ISSUE_JSON=$(curl --disable --proto '=https' -m 30 -fsS --config - \
|
|
57
|
+
"https://${API_HOST}/api/0/organizations/${SENTRY_ORG}/issues/${ISSUE_ID}/" \
|
|
58
|
+
< <(printf 'header = "Authorization: Bearer %s"\n' "$SENTRY_READ_TOKEN")) || get_rc=$?
|
|
59
|
+
if (( get_rc != 0 )) || ! ISSUE_STATUS=$(jq -er '.status' <<<"$ISSUE_JSON" 2>/dev/null); then
|
|
60
|
+
echo "WARNING: Sentry issue GET failed (curl rc=$get_rc, or no .status in the body). Sentry error-count delta: SKIPPED."
|
|
61
|
+
ISSUE_STATUS=""
|
|
62
|
+
else
|
|
63
|
+
jq '{shortId, status, count, lastSeen}' <<<"$ISSUE_JSON"
|
|
64
|
+
ISSUE_LASTSEEN=$(jq -r '.lastSeen' <<<"$ISSUE_JSON")
|
|
65
|
+
# Mechanical stopped-firing signal — this boolean, NOT the prose below, gates
|
|
66
|
+
# the auto-resolve PUT. True only when the issue is already resolved/ignored OR
|
|
67
|
+
# lastSeen predates the deploy. Any parse failure leaves it false (fail-safe:
|
|
68
|
+
# never auto-resolve on ambiguous data).
|
|
69
|
+
if [[ "$ISSUE_STATUS" == "resolved" || "$ISSUE_STATUS" == "ignored" ]]; then
|
|
70
|
+
ISSUE_STOPPED=true
|
|
71
|
+
elif [[ -n "$ISSUE_LASTSEEN" && "$ISSUE_LASTSEEN" != "null" ]]; then
|
|
72
|
+
# An empty DEPLOY_TS (wrong/unfetched SHA) or an unparseable date (BSD date has
|
|
73
|
+
# no -d) is SKIPPED: `date -d ""` is today's midnight and would read as STOPPED.
|
|
74
|
+
LASTSEEN_EPOCH=""; DEPLOY_EPOCH=""
|
|
75
|
+
if [[ -n "$DEPLOY_TS" ]]; then
|
|
76
|
+
LASTSEEN_EPOCH=$(date -d "$ISSUE_LASTSEEN" +%s 2>/dev/null || true)
|
|
77
|
+
DEPLOY_EPOCH=$(date -d "$DEPLOY_TS" +%s 2>/dev/null || true)
|
|
78
|
+
fi
|
|
79
|
+
if [[ -z "$LASTSEEN_EPOCH" || -z "$DEPLOY_EPOCH" ]]; then
|
|
80
|
+
echo "WARNING: deploy timestamp or lastSeen unparseable. Sentry error-count delta: SKIPPED."
|
|
81
|
+
ISSUE_STATUS=""
|
|
82
|
+
elif (( LASTSEEN_EPOCH < DEPLOY_EPOCH )); then
|
|
83
|
+
ISSUE_STOPPED=true
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
if [[ "$ISSUE_STOPPED" == "true" ]]; then SENTRY_DELTA=STOPPED
|
|
87
|
+
elif [[ -n "$ISSUE_STATUS" ]]; then SENTRY_DELTA=STILL-FIRING; fi
|
|
88
|
+
fi
|
|
89
|
+
fi
|
|
90
|
+
echo "Sentry error-count delta: $SENTRY_DELTA"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Interpretation (all outcomes are **WARN-only — never a merge blocker**):
|
|
94
|
+
|
|
95
|
+
- `lastSeen` is older than the deploy timestamp **or** `status` is `resolved`/`ignored` (`ISSUE_STOPPED=true`): "Sentry error-count delta: error appears to have stopped firing post-deploy." — the expected good outcome; report `STOPPED` (or `AUTO-RESOLVED` if the write below succeeds). **Auto-resolve runs in this branch only** (see below).
|
|
96
|
+
- `lastSeen` is after the deploy timestamp (`SENTRY_DELTA=STILL-FIRING` — the GET succeeded and `ISSUE_STOPPED=false`): "WARNING: Sentry issue `<shortId>` is still firing after the deploy (lastSeen <ts>). The fix may be ineffective or the root cause may differ from the diagnosis — recommend re-opening for investigation rather than closing." Report `STILL-FIRING` and surface it prominently in the Phase 7 report. **Never auto-resolve in this branch.**
|
|
97
|
+
- No read token, Sentry API unreachable / issue not found / non-200 (`SENTRY_DELTA=SKIPPED`): warn and report `SKIPPED`. A failed GET never reads as `STILL-FIRING`.
|
|
98
|
+
|
|
99
|
+
**Auto-resolve (expected-good-outcome branch only).** Run this block in the SAME shell invocation as the block above — it reads that block's variables, and the Bash tool keeps no shell state between calls. When the GET above shows the error has stopped firing (`lastSeen` older than the deploy **or** `status` already `resolved`/`ignored`) **and** the issue is not already `resolved`, PUT `status:"resolved"` so the historical issue leaves the active list automatically. This requires a dedicated write-scoped token — the `SENTRY_AUTH_TOKEN`/`SENTRY_API_TOKEN` read tokens resolved from `soleur/prd` lack `event:write`/`event:admin` and return 403 on the write endpoint, so resolve a separate token and **skip (do NOT fall back to a read token)** when it is absent:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# SENTRY_RW_TOKEN, API_HOST and SENTRY_ORG were resolved in the block above; the
|
|
103
|
+
# write-scoped RW token is used here and only here.
|
|
104
|
+
|
|
105
|
+
# Fire ONLY when the mechanical ISSUE_STOPPED signal is true (the still-firing
|
|
106
|
+
# branch is structurally unreachable here, never prose-gated), a write token is
|
|
107
|
+
# present, the issue is not already resolved, and ISSUE_ID is a bare token (the
|
|
108
|
+
# regex blocks a crafted id with `/`/`?` from retargeting a different issue on
|
|
109
|
+
# this state-mutating PUT). Body is discarded (-o /dev/null) — it returns the
|
|
110
|
+
# full issue object, which can carry production event data; only the HTTP code
|
|
111
|
+
# is load-bearing.
|
|
112
|
+
# The write token rides curl's stdin config, as in the GET: argv shows in /proc/<pid>/cmdline. Bash only;
|
|
113
|
+
# `bash -x` would print the token. A malformed token WARNS and skips the PUT (never sent anywhere).
|
|
114
|
+
RW_OK=false
|
|
115
|
+
if [[ -n "$SENTRY_RW_TOKEN" ]]; then
|
|
116
|
+
if (LC_ALL=C; case "$SENTRY_RW_TOKEN" in *[!A-Za-z0-9._~+/=-]*) exit 1;; esac); then RW_OK=true
|
|
117
|
+
else echo "WARNING: SENTRY_RW_TOKEN (SENTRY_ISSUE_RW_TOKEN) not [A-Za-z0-9._~+/=-] (refused, not sent). Sentry auto-resolve: SKIPPED."; fi
|
|
118
|
+
fi
|
|
119
|
+
if [[ "$RW_OK" == "true" && "$ISSUE_STOPPED" == "true" && "$ISSUE_STATUS" != "resolved" \
|
|
120
|
+
&& "$ISSUE_ID" =~ ^[A-Za-z0-9_-]+$ ]]; then
|
|
121
|
+
RESOLVE_HTTP=$(curl --disable --proto '=https' -m 30 -sS -o /dev/null -w '%{http_code}' -X PUT \
|
|
122
|
+
--config - -H "Content-Type: application/json" \
|
|
123
|
+
-d '{"status":"resolved"}' \
|
|
124
|
+
"https://${API_HOST}/api/0/organizations/${SENTRY_ORG}/issues/${ISSUE_ID}/" \
|
|
125
|
+
< <(printf 'header = "Authorization: Bearer %s"\n' "$SENTRY_RW_TOKEN"))
|
|
126
|
+
if [[ "$RESOLVE_HTTP" == "200" ]]; then
|
|
127
|
+
SENTRY_DELTA=AUTO-RESOLVED
|
|
128
|
+
echo "Sentry error-count delta: AUTO-RESOLVED issue ${ISSUE_ID}."
|
|
129
|
+
else
|
|
130
|
+
echo "WARNING: Sentry issue auto-resolve failed (${RESOLVE_HTTP}): verify SENTRY_ISSUE_RW_TOKEN has event:admin on ${SENTRY_ORG}; resolve manually in the UI."
|
|
131
|
+
fi
|
|
132
|
+
fi
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The PUT reuses the SAME `API_HOST`/`SENTRY_ORG` resolution as the GET above (Phase 3.5's, from Doppler `prd`). On any non-200 (403 under-scoped, transient) it emits a WARN and continues — **never blocks**. Report vocabulary for this phase is `$SENTRY_DELTA`: `AUTO-RESOLVED` (write succeeded) / `STOPPED` (stopped firing; no usable write token, already resolved, or the PUT returned non-200) / `STILL-FIRING` / `SKIPPED`.
|
|
136
|
+
|
|
137
|
+
**Why WARN-only, not a blocker:** a true pre/post delta needs the original error to actually re-fire in the brief post-merge window. Low-frequency bugs (daily-cron failures, rare-path exceptions) legitimately show zero events for hours after a correct fix, so a hard gate here would produce noisy false negatives that erode trust in the pipeline. The signal is a prompt to *look*, not a verdict. For high-frequency errors a continued-firing signal is strong evidence the fix missed; consider a `/loop` re-check 15–30 min out before marking the linked issue resolved.
|