@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,342 @@
|
|
|
1
|
+
// The heartbeat arming manifest (#6242 Audit Matrix Deliverable A; extracted from
|
|
2
|
+
// heartbeat-reprovision-parity.test.ts for #6537).
|
|
3
|
+
//
|
|
4
|
+
// A heartbeat's "what feeds this?" answer used to live in a code COMMENT. #6537: the registry's
|
|
5
|
+
// said a probe cron had shipped; it had never been written, and the monitor sat inert for 9 days.
|
|
6
|
+
// A comment cannot fail CI, so `feeder` below is EXECUTABLE — every arming claim is a file plus a
|
|
7
|
+
// syntactic construct the parity test greps on every run. See ADR-117 for the decision, the
|
|
8
|
+
// rejected alternatives, and the states this does NOT cover.
|
|
9
|
+
|
|
10
|
+
/** How a heartbeat's ping is armed — keyed on the MONITORED HOST'S REMEDIATION (CTO, #6242). */
|
|
11
|
+
export type Arming =
|
|
12
|
+
| "dedicated-host-boot"
|
|
13
|
+
| "web-host-cron"
|
|
14
|
+
| "app-emit"
|
|
15
|
+
| "external-probe";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* What actually emits the ping.
|
|
19
|
+
*
|
|
20
|
+
* `cron`/`timer` carry EVIDENCE: a file, and the **arming construct** within it — the line that
|
|
21
|
+
* actually causes the feeder to run (`systemctl enable --now <unit>`, a `- path: /etc/cron.d/<x>`
|
|
22
|
+
* drop-in). Deliberately NOT the unit's bare name: `inngest-heartbeat.timer` appears three times
|
|
23
|
+
* in its bootstrap script, and one of them is a comment — so a bare-name check stays green after
|
|
24
|
+
* the arming line is deleted, i.e. prose alone would satisfy the guard built to kill prose.
|
|
25
|
+
* Matching runs against a COMMENT-STRIPPED view for the same reason.
|
|
26
|
+
*
|
|
27
|
+
* A `cron` row may instead name a WORKFLOW (`.github/workflows/<x>.yml`) and the `bash scripts/<x>.sh`
|
|
28
|
+
* line that runs the verifier (ADR-117 amendment 2026-10-11): `checkFeeders` then also requires a
|
|
29
|
+
* `schedule:` trigger or a `WATCHDOG_DISPATCH_TABLE` row, and that the script exists.
|
|
30
|
+
*
|
|
31
|
+
* `none` is the honest declaration that nothing pings this heartbeat yet. It is not a loophole: it
|
|
32
|
+
* costs a `tracking_issue`, and the guard asserts the heartbeat has no feeder by EITHER delivery
|
|
33
|
+
* route this repo uses (see `feederDeliveryProbes`).
|
|
34
|
+
*/
|
|
35
|
+
export type Feeder =
|
|
36
|
+
| {
|
|
37
|
+
kind: "cron" | "timer";
|
|
38
|
+
/** `file` is repo-root-relative; `pattern` is matched as a FIXED string (grep -F). */
|
|
39
|
+
evidence: { file: string; pattern: string };
|
|
40
|
+
}
|
|
41
|
+
| {
|
|
42
|
+
kind: "none";
|
|
43
|
+
/**
|
|
44
|
+
* The Doppler secret holding this heartbeat's ping URL, or null if none is provisioned.
|
|
45
|
+
* When non-null the guard asserts it has zero DEREFERENCING consumers.
|
|
46
|
+
*/
|
|
47
|
+
url_secret: string | null;
|
|
48
|
+
/** The issue that owns building the feeder — or deleting the heartbeat. */
|
|
49
|
+
tracking_issue: number;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export interface ManifestEntry {
|
|
53
|
+
/** The resource name (betteruptime_heartbeat.<name>). */
|
|
54
|
+
name: string;
|
|
55
|
+
arming: Arming;
|
|
56
|
+
/** DECLARED paused value; asserted equal to the value parsed from the .tf source. */
|
|
57
|
+
paused: boolean;
|
|
58
|
+
/** What pings it. Executable — see the Feeder docstring. */
|
|
59
|
+
feeder: Feeder;
|
|
60
|
+
/**
|
|
61
|
+
* Required IFF arming === "dedicated-host-boot". `choice` is the apply_target option; `server`
|
|
62
|
+
* is the `hcloud_server.<host>` the job -replaces.
|
|
63
|
+
*/
|
|
64
|
+
replace_target?: { choice: string; server: string };
|
|
65
|
+
/** Required for every entry whose arming is NOT dedicated-host-boot. */
|
|
66
|
+
exempt_reason?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Declares that this heartbeat's arming is DELIBERATELY deferred (created paused in Better Stack,
|
|
69
|
+
* to be armed out-of-band later — ADR-117 "FED-but-inert", a legal state at merge). When set, the
|
|
70
|
+
* nightly live-reconcile (#6549 item 2) does NOT raise the `fed-but-paused` alert for this row: a
|
|
71
|
+
* paused-yet-fed monitor is EXPECTED during the owner's deferred-arming window. It costs an owning
|
|
72
|
+
* issue — the honest-declaration idiom mirrors `feeder:{kind:"none", tracking_issue}`. Remove it
|
|
73
|
+
* (at cutover/arming) and a still-paused fed monitor fires for real. It does NOT suppress the
|
|
74
|
+
* `absent-live` alert — a declared-but-not-applied monitor is still surfaced.
|
|
75
|
+
*/
|
|
76
|
+
arming_pending?: { tracking_issue: number };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Regexes that detect a feeder for `<name>`, one per delivery route this repo actually uses.
|
|
81
|
+
* An unfed (`kind:"none"`) row must match NEITHER. Both are needed:
|
|
82
|
+
*
|
|
83
|
+
* - **deref**: the feeder reads the URL from a Doppler secret (`$INNGEST_HEARTBEAT_URL` in
|
|
84
|
+
* inngest-bootstrap.sh — the live, armed precedent). Anchored on the DEREFERENCE, never the
|
|
85
|
+
* bare name: a bare-name grep also matches the secret's own `name = "..."` definition and
|
|
86
|
+
* plain prose, so it reports feeders that do not exist — the very fiction being replaced.
|
|
87
|
+
* - **bake**: the feeder gets the URL baked in via `templatefile` (`liveness_heartbeat_url =
|
|
88
|
+
* betteruptime_heartbeat.registry_prd.url`), dereferencing nothing. This is the route #6537
|
|
89
|
+
* itself introduced, so a deref-only guard would be blind to the exact shape this repo now
|
|
90
|
+
* treats as canonical. `value = ...` is excluded: that is a doppler_secret/output DEFINITION,
|
|
91
|
+
* not a delivery into a template.
|
|
92
|
+
*/
|
|
93
|
+
export function feederDeliveryProbes(name: string, urlSecret: string | null): RegExp[] {
|
|
94
|
+
const esc = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
95
|
+
const probes: RegExp[] = [
|
|
96
|
+
new RegExp(`^\\s*(?!value\\s*=)[A-Za-z0-9_]+\\s*=\\s*betteruptime_heartbeat\\.${esc(name)}\\.url`, "m"),
|
|
97
|
+
];
|
|
98
|
+
if (urlSecret) probes.push(new RegExp(`\\$\\{?${esc(urlSecret)}\\}?`));
|
|
99
|
+
return probes;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// One row per heartbeat. Adding a heartbeat to the .tf files WITHOUT adding a row here FAILS the
|
|
103
|
+
// discovered⊆manifest assertion.
|
|
104
|
+
export const MANIFEST: ManifestEntry[] = [
|
|
105
|
+
{
|
|
106
|
+
name: "github_webhook_sig_failures",
|
|
107
|
+
arming: "app-emit",
|
|
108
|
+
paused: true,
|
|
109
|
+
// Its source comment claimed the webhook route "deliberately pings" this. Nothing does.
|
|
110
|
+
feeder: { kind: "none", url_secret: null, tracking_issue: 6549 },
|
|
111
|
+
exempt_reason:
|
|
112
|
+
"app/container would emit the ping; remediation is a container ci-deploy, not a dedicated-host reprovision. count=0 under the free tier (betterstack_paid_tier=false), so it is not provisioned live.",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "github_api_429_sustained",
|
|
116
|
+
arming: "app-emit",
|
|
117
|
+
paused: true,
|
|
118
|
+
// Structurally the same unfed shape as its sibling above, at a different cadence (900/120 vs
|
|
119
|
+
// 300/60) — and it never carried the false ping claim; that sat on only one of the two.
|
|
120
|
+
feeder: { kind: "none", url_secret: null, tracking_issue: 6549 },
|
|
121
|
+
exempt_reason:
|
|
122
|
+
"app/container would emit the ping; remediation is a container ci-deploy, not a dedicated-host reprovision. count=0 under the free tier (betterstack_paid_tier=false), so it is not provisioned live.",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "workspaces_luks",
|
|
126
|
+
// #6604 — the daily /workspaces LUKS at-rest probe heartbeat. Two pushers feed it:
|
|
127
|
+
// 1. luks-monitor.timer on web-1, delivered and armed by terraform_data.luks_monitor_install
|
|
128
|
+
// (workspaces-luks.tf) in the per-merge SSH apply (#8706). Until #8706 the only installer
|
|
129
|
+
// was the cutover script's tail, which no real cutover reached, so this pusher never ran
|
|
130
|
+
// (ADR-119 addendum 2026-09-27; ADR-117 amendment 2026-09-27).
|
|
131
|
+
// Terraform is the PRIMARY installer. The cutover tail still installs the same files, so it
|
|
132
|
+
// stays a redundant second installer for a future re-cut.
|
|
133
|
+
// 2. The daily workspaces-luks-verify.yml job, which ships its own copy of luks-monitor.sh.
|
|
134
|
+
// The shared beat cannot tell them apart. The runtime proof that pusher 1 runs is
|
|
135
|
+
// logtail_exploration_alert.luks_monitor_host_timer_dark (betterstack-logs-alerts.tf).
|
|
136
|
+
// web-1 is cx33-unrebuildable and never re-runs cloud-init, so there is NO host-replace path:
|
|
137
|
+
// web-host-cron, NOT dedicated-host-boot, and the replace_target requirement does not fire.
|
|
138
|
+
arming: "web-host-cron",
|
|
139
|
+
paused: true,
|
|
140
|
+
feeder: {
|
|
141
|
+
kind: "timer",
|
|
142
|
+
evidence: {
|
|
143
|
+
file: "apps/web-platform/infra/workspaces-luks.tf",
|
|
144
|
+
pattern: "systemctl enable --now luks-monitor.timer",
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
// No `arming_pending`: it is ARMED. This row carried `arming_pending: { tracking_issue: 6604 }`
|
|
148
|
+
// while the monitor waited for the cutover's first measured beat. The beat has pushed since
|
|
149
|
+
// 2026-08-04 (runbook workspaces-luks-cutover-6604.md, "Failure signals"), and a read-only
|
|
150
|
+
// GET /api/v2/heartbeats/478794 on 2026-09-27 (#8706) read soleur-workspaces-luks-prd
|
|
151
|
+
// `paused:false status:up`. Removal follows OBSERVED arming, not #6604 closing (the
|
|
152
|
+
// inngest_consumer precedent), so the live reconcile's `fed-but-paused` alarm is re-armed for
|
|
153
|
+
// this row: a pause from here on is a real finding. `paused: true` above is SOURCE state only.
|
|
154
|
+
exempt_reason:
|
|
155
|
+
"web-host-resident feeder (luks-monitor.timer on web-1) delivered and armed by the SSH terraform_data provisioner (terraform_data.luks_monitor_install, #8706) as the PRIMARY installer; the cutover script's tail still installs the same files as a redundant second installer for a future re-cut, and web-1 cloud-init boot is NOT a path — web-1 is cx33-unrebuildable and never re-runs cloud-init, so there is NO <host>-host-replace path. The second pusher is the workspaces-luks-verify.yml job; the runtime proof that the host timer fires is logtail_exploration_alert.luks_monitor_host_timer_dark. Not dedicated-host-boot, so ADR-103's replace_target requirement correctly does not fire.",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: "git_data_prd",
|
|
159
|
+
arming: "web-host-cron",
|
|
160
|
+
paused: true,
|
|
161
|
+
// #5274 PR C (#6548) SHIPPED the web-host probe — so this row is FLIPPED from the former
|
|
162
|
+
// {kind:"none", tracking_issue:6548} to a fed timer. The forcing function #6537 lacked fired
|
|
163
|
+
// exactly as designed: shipping web-git-data-probe.sh (which dereferences GIT_DATA_HEARTBEAT_URL)
|
|
164
|
+
// reddened the "still unfed by BOTH routes" tripwire, forcing this reconciliation. The feeder is
|
|
165
|
+
// the SSH-provisioner-delivered timer (terraform_data.git_data_probe_install in server.tf).
|
|
166
|
+
feeder: {
|
|
167
|
+
kind: "timer",
|
|
168
|
+
evidence: {
|
|
169
|
+
file: "apps/web-platform/infra/server.tf",
|
|
170
|
+
pattern: "systemctl enable --now web-git-data-probe.timer",
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
exempt_reason:
|
|
174
|
+
"web-host-resident feeder (web-git-data-probe.timer on web-1), delivered by the SSH terraform_data provisioner — NOT a git-data cloud-init cron. Reprovisioning git-data would not arm it; its remediation is web-host ci-deploy/provision. (git-data-host-replace exists for immutable-redeploy compliance, not to arm this heartbeat.)",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: "web_zot_consumer",
|
|
178
|
+
// #6438 §1 — the zot CONSUMER-perspective serviceability probe. web-host-cron (NOT dedicated-
|
|
179
|
+
// host-boot): web-1 is cx33-unrebuildable and never re-runs cloud-init, so the feeder is
|
|
180
|
+
// delivered by an SSH terraform_data provisioner — there is NO <host>-host-replace path, and
|
|
181
|
+
// ADR-103's replace_target requirement correctly does not fire (mirrors workspaces_luks/
|
|
182
|
+
// git_data_prd). for_each var.web_hosts, so the discovered resource name is web_zot_consumer.
|
|
183
|
+
arming: "web-host-cron",
|
|
184
|
+
// paused in source (ignore_changes=[paused]); the apply-workflow arm gate PATCHes it live after
|
|
185
|
+
// a measured beat (ADR-117 automated). Source stays paused, so this stays true (mirrors
|
|
186
|
+
// inngest_prd/registry_prd: source paused, live unpaused after a one-time measured PATCH).
|
|
187
|
+
paused: true,
|
|
188
|
+
feeder: {
|
|
189
|
+
kind: "timer",
|
|
190
|
+
evidence: {
|
|
191
|
+
file: "apps/web-platform/infra/server.tf",
|
|
192
|
+
pattern: "systemctl enable --now web-zot-consumer-probe.timer",
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
exempt_reason:
|
|
196
|
+
"web-host-resident feeder (web-zot-consumer-probe.timer on web-1) delivered by the SSH terraform_data provisioner (terraform_data.zot_consumer_probe_install), NOT web-1 cloud-init boot — web-1 is cx33-unrebuildable and never re-runs cloud-init, so there is NO <host>-host-replace path. Not dedicated-host-boot, so ADR-103's replace_target requirement correctly does not fire.",
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: "web_nic_guard",
|
|
200
|
+
// #6438 §3 — the private-NIC self-report's dedicated liveness beat (pinged every healthy guard
|
|
201
|
+
// run so the SOLEUR_PRIVATE_NIC emitter is observable-when-healthy). Same web-host-cron/SSH-
|
|
202
|
+
// provisioner delivery + arming shape as web_zot_consumer above; PERMANENT and independent of
|
|
203
|
+
// the zot beat (distinct failure domain — folding would re-introduce OR-masking).
|
|
204
|
+
arming: "web-host-cron",
|
|
205
|
+
paused: true,
|
|
206
|
+
feeder: {
|
|
207
|
+
kind: "timer",
|
|
208
|
+
evidence: {
|
|
209
|
+
file: "apps/web-platform/infra/server.tf",
|
|
210
|
+
pattern: "systemctl enable --now web-private-nic-guard.timer",
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
exempt_reason:
|
|
214
|
+
"web-host-resident feeder (web-private-nic-guard.timer on web-1) delivered by the SSH terraform_data provisioner (terraform_data.private_nic_guard_install), NOT web-1 cloud-init boot — web-1 is cx33-unrebuildable. No <host>-host-replace path, so ADR-103's replace_target requirement correctly does not fire.",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: "inngest_consumer",
|
|
218
|
+
// #7228 — the inngest CONSUMER-perspective serviceability beat. web-host-cron, not
|
|
219
|
+
// dedicated-host-boot, and that is the entire point of the design: its feeder runs on web-1
|
|
220
|
+
// and reads 10.0.1.40:8288 over the private net, so it detects a dark dedicated host WITHOUT
|
|
221
|
+
// depending on that host's bootstrap having run and WITHOUT a host replace. web-1 is
|
|
222
|
+
// cx33-unrebuildable and never re-runs cloud-init, so delivery is the SSH terraform_data
|
|
223
|
+
// provisioner and ADR-103's replace_target requirement correctly does not fire (mirrors
|
|
224
|
+
// web_zot_consumer / git_data_prd / workspaces_luks).
|
|
225
|
+
arming: "web-host-cron",
|
|
226
|
+
paused: true,
|
|
227
|
+
feeder: {
|
|
228
|
+
kind: "timer",
|
|
229
|
+
evidence: {
|
|
230
|
+
file: "apps/web-platform/infra/server.tf",
|
|
231
|
+
pattern: "systemctl enable --now inngest-consumer-probe.timer",
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
// No `arming_pending`: it is ARMED. This row carried `arming_pending: { tracking_issue: 7462 }`
|
|
235
|
+
// while the dedicated inngest host had not bound :8288 (the probe correctly suppressed every
|
|
236
|
+
// beat), and its removal was to follow OBSERVED arming, not #7462 closing. Observed 2026-09-15
|
|
237
|
+
// (#7884 review, read-only GET /api/v2/heartbeats): soleur-inngest-consumer-prd id 482259
|
|
238
|
+
// `paused:false status:up`, with #7462 CLOSED 2026-08-20. So the twice-daily live reconcile's
|
|
239
|
+
// `fed-but-paused` alarm is re-armed for this row: a pause from here on is a real finding.
|
|
240
|
+
exempt_reason:
|
|
241
|
+
"web-host-resident feeder (inngest-consumer-probe.timer on web-1) delivered by the SSH terraform_data provisioner (terraform_data.inngest_consumer_probe_install), NOT cloud-init boot on either host. It monitors the dedicated inngest host from the consumer side precisely so that arming it never requires an inngest-host-replace, so ADR-103's replace_target requirement correctly does not fire.",
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: "inngest_prd",
|
|
245
|
+
arming: "dedicated-host-boot",
|
|
246
|
+
// Source says paused=true; LIVE is paused=false / up (self-pulled from /api/v2/heartbeats).
|
|
247
|
+
// That divergence is the proof that source is not live: Terraform never sets paused=false, and
|
|
248
|
+
// ignore_changes=[paused] means it never reverts one. It was armed out-of-band once its feeder
|
|
249
|
+
// existed — exactly the step registry_prd never got.
|
|
250
|
+
paused: true,
|
|
251
|
+
feeder: {
|
|
252
|
+
kind: "timer",
|
|
253
|
+
evidence: {
|
|
254
|
+
file: "apps/web-platform/infra/inngest-bootstrap.sh",
|
|
255
|
+
pattern: "systemctl enable --now inngest-heartbeat.timer",
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
replace_target: { choice: "inngest-host-replace", server: "hcloud_server.inngest" },
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: "registry_prd",
|
|
262
|
+
// #6537: was `web-host-cron` + an exempt_reason citing an unshipped probe cron — the
|
|
263
|
+
// classification was the bug's hiding place. It is armed by the registry's OWN cloud-init now,
|
|
264
|
+
// so it is dedicated-host-boot, which makes ADR-103's replace_target requirement fire. That is
|
|
265
|
+
// intended: cloud-init is per-instance, so the feeder reaches the host only on a fresh boot.
|
|
266
|
+
arming: "dedicated-host-boot",
|
|
267
|
+
// Stays paused in source; live arming is a one-time API PATCH after a real beat is measured.
|
|
268
|
+
paused: true,
|
|
269
|
+
feeder: {
|
|
270
|
+
kind: "timer",
|
|
271
|
+
evidence: {
|
|
272
|
+
file: "apps/web-platform/infra/cloud-init-registry.yml",
|
|
273
|
+
pattern: "systemctl enable --now zot-liveness-heartbeat.timer",
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
replace_target: { choice: "registry-host-replace", server: "hcloud_server.registry" },
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: "git_data_host_prd",
|
|
280
|
+
// #9438: the git-data HOST's own recurring liveness beat (git-data-liveness.timer), distinct
|
|
281
|
+
// from git_data_prd above, which is fed by a web-host cron and proves only that some web host
|
|
282
|
+
// can open a TCP connection to the port. Armed by the host's OWN cloud-init, so it is
|
|
283
|
+
// dedicated-host-boot, which makes ADR-103's replace_target requirement fire: cloud-init is
|
|
284
|
+
// per-instance, so the feeder reaches the host only on a fresh boot (git-data-host-replace).
|
|
285
|
+
arming: "dedicated-host-boot",
|
|
286
|
+
// Born paused and stays paused in source; live arming is the owner-authorized, measured
|
|
287
|
+
// arm step after the replaced host's first beats (ADR-117, ADR-283).
|
|
288
|
+
paused: true,
|
|
289
|
+
feeder: {
|
|
290
|
+
kind: "timer",
|
|
291
|
+
evidence: {
|
|
292
|
+
file: "apps/web-platform/infra/cloud-init-git-data.yml",
|
|
293
|
+
pattern: "systemctl enable --now git-data-liveness.timer",
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
replace_target: { choice: "git-data-host-replace", server: "hcloud_server.git_data" },
|
|
297
|
+
// No `arming_pending` (record PR for #9438). This row carried `arming_pending: { tracking_issue: 9438 }`
|
|
298
|
+
// while the monitor was paused-yet-fed between the host replace and the arm. On 2026-10-12 a measured
|
|
299
|
+
// arm (`arm-heartbeats.sh --arm-one`, #9980) read `up` within 11 s; the verdict and the pre/post
|
|
300
|
+
// `--status` reads are on #9438. That is a dated record: the live state is read from Better Stack, not
|
|
301
|
+
// from this file. `paused: true` above stays: it is the source `.tf` state (born paused).
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: "registry_disk_prd",
|
|
305
|
+
arming: "dedicated-host-boot",
|
|
306
|
+
paused: false,
|
|
307
|
+
// The #6238 exemplar. NOTE its scope, which #6537 mis-stated: it pings on `df` alone, so it
|
|
308
|
+
// alarms HOST death by absence but stays GREEN with zot dead. registry_prd covers that gap.
|
|
309
|
+
// A cron.d drop-in is armed by existing, so its `- path:` delivery IS the arming construct.
|
|
310
|
+
feeder: {
|
|
311
|
+
kind: "cron",
|
|
312
|
+
evidence: {
|
|
313
|
+
file: "apps/web-platform/infra/cloud-init-registry.yml",
|
|
314
|
+
pattern: "- path: /etc/cron.d/zot-disk-heartbeat",
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
replace_target: { choice: "registry-host-replace", server: "hcloud_server.registry" },
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: "inngest_server_probe",
|
|
321
|
+
// #8516 — the dead-probe sibling of logtail_exploration_alert.inngest_luks_wrong_volume:
|
|
322
|
+
// a pusher beats it only while a fresh host_role=dedicated inngest-server-probe row
|
|
323
|
+
// reaches the warehouse (hourly emission cadence; period 3600 + grace 1800). FED and ARMED.
|
|
324
|
+
// No `arming_pending` (record PR for #9703). This row carried `arming_pending: { tracking_issue: 9703 }`
|
|
325
|
+
// while the monitor was paused-yet-fed. On 2026-10-12 the runbook arm block unpaused it; its read-back
|
|
326
|
+
// was `status=up paused=false`, and the feeder (scripts/inngest-probe-heartbeat-feeder.sh) then reported
|
|
327
|
+
// `verdict=beat` on runs 38264380002 (forced), 38265381453 and 38267189184 (clock-dispatched). That is a
|
|
328
|
+
// dated record: the live state is read from Better Stack, not from this file. `paused: true` below stays:
|
|
329
|
+
// it is the source `.tf` state (born paused).
|
|
330
|
+
arming: "external-probe",
|
|
331
|
+
paused: true,
|
|
332
|
+
feeder: {
|
|
333
|
+
kind: "cron",
|
|
334
|
+
evidence: {
|
|
335
|
+
file: ".github/workflows/scheduled-inngest-probe-heartbeat.yml",
|
|
336
|
+
pattern: "bash scripts/inngest-probe-heartbeat-feeder.sh",
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
exempt_reason:
|
|
340
|
+
"fed and armed (2026-10-12, #9703) — the feeder is a repo-side verifier workflow, remediation never requires an inngest-host-replace, precisely because a host push cannot see Vector-allowlist or sink failures (#6780). Not dedicated-host-boot, so ADR-103's replace_target requirement correctly does not fire.",
|
|
341
|
+
},
|
|
342
|
+
];
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// Coverage summary for /soleur:sync (#7332, plan Phase 3).
|
|
2
|
+
//
|
|
3
|
+
// Reports what Soleur EXPECTS a knowledge base to contain versus what is PRESENT,
|
|
4
|
+
// as a deterministic committed artifact plus a stdout marker.
|
|
5
|
+
//
|
|
6
|
+
// ‼️ WORDING IS A HARD CONSTRAINT, NOT A STYLE PREFERENCE. This file lands in the
|
|
7
|
+
// CUSTOMER's own repository, committed, timestamped by git, and permanently
|
|
8
|
+
// blamed. "missing: privacy policy" is a durable, discoverable assertion that a
|
|
9
|
+
// business lacks a compliance artifact — written by us, about them, into a record
|
|
10
|
+
// they cannot erase. "no `privacy-policy.md` present in this knowledge base" says
|
|
11
|
+
// the same operational thing about OUR expectation without asserting anything
|
|
12
|
+
// about their business. Every string below is written to that rule and a test
|
|
13
|
+
// enforces both halves of it (no deficiency framing AND the expectation phrasing
|
|
14
|
+
// present) — because a report can easily carry the right header and still emit a
|
|
15
|
+
// deficiency bullet per row.
|
|
16
|
+
//
|
|
17
|
+
// ‼️ DETERMINISM IS REQUIRED. No timestamp, no run id, sorted ordering. An
|
|
18
|
+
// unchanged KB must render byte-identically or every sync emits a one-field diff
|
|
19
|
+
// forever. knowledge-base/INDEX.md is the in-repo warning for exactly this shape.
|
|
20
|
+
//
|
|
21
|
+
// OBSERVABILITY: layer 7 (`cli-stdout-artifact`). The marker is emitted TWICE —
|
|
22
|
+
// on stdout, where the agent and operator read it in-session, and as a line in
|
|
23
|
+
// this artifact, so it survives the session. There is no Soleur-side sink for a
|
|
24
|
+
// self-hosted CLI run and there must not be one (ADR-171 §Observability
|
|
25
|
+
// boundary), which is why the durable artifact IS the queryable surface. The
|
|
26
|
+
// marker therefore carries COUNTS ONLY: no path, no filename, no repo URL.
|
|
27
|
+
|
|
28
|
+
import { existsSync } from "node:fs";
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
|
|
31
|
+
/** Marker sentinel. Kept identical on both surfaces so one grep finds either. */
|
|
32
|
+
export const PRODUCERS_MARKER = "SOLEUR_KB_SYNC_PRODUCERS";
|
|
33
|
+
export const ERROR_MARKER = "SOLEUR_KB_SYNC_ERROR";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The five counts, in emission order. Exported so the drift guard can assert the
|
|
37
|
+
* stdout marker and the artifact's marker line carry a byte-identical field set —
|
|
38
|
+
* the plan's discoverability_test greps the ARTIFACT, so a divergence would make
|
|
39
|
+
* that test silently verify something other than what the run reported.
|
|
40
|
+
*/
|
|
41
|
+
export const MARKER_FIELDS = [
|
|
42
|
+
"c4_elements",
|
|
43
|
+
"c4_relationships",
|
|
44
|
+
"domain_model_rows",
|
|
45
|
+
"coverage_present",
|
|
46
|
+
"coverage_expected",
|
|
47
|
+
] as const;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* ‼️ EVERY FIELD HERE IS A FUNCTION OF KB STATE, NEVER OF THE RUN.
|
|
51
|
+
*
|
|
52
|
+
* That is the invariant that makes this artifact deterministic, and the original
|
|
53
|
+
* design broke it in one place: `domain_model_rows` meant "rows appended by THIS
|
|
54
|
+
* run", which is N on a fresh register and 0 on the next sync once dedup no-ops.
|
|
55
|
+
* Since the marker is embedded in the committed file, an unchanged KB produced a
|
|
56
|
+
* guaranteed one-field diff on every second sync — AC11's byte-stability claim was
|
|
57
|
+
* false by construction, and the determinism test passed only because its fixture
|
|
58
|
+
* handed identical counts to both runs.
|
|
59
|
+
*
|
|
60
|
+
* The field now means "rows the register currently HOLDS", which is state, so
|
|
61
|
+
* determinism follows from the definition instead of from a fixture. Run-scoped
|
|
62
|
+
* facts ("appended 3 rows this run") belong on stdout, which is where run-scoped
|
|
63
|
+
* facts belong — the artifact is a snapshot, the stream is a log.
|
|
64
|
+
*
|
|
65
|
+
* Corollary for callers: derive these counts, do not pass them in. Flags that can be
|
|
66
|
+
* forgotten reconstruct the same failure — an absent `--c4-elements` silently
|
|
67
|
+
* produced `c4_elements=0`, byte-identical to the plan's headline failure mode.
|
|
68
|
+
*/
|
|
69
|
+
export type CoverageSources = {
|
|
70
|
+
/** Rendered model, if committed. Absent/unparseable ⇒ zeros, reported honestly. */
|
|
71
|
+
modelJson: string | null;
|
|
72
|
+
/** The domain-model register, if present. */
|
|
73
|
+
registerMarkdown: string | null;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type ProducerCounts = Record<(typeof MARKER_FIELDS)[number], number>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* What Soleur expects a populated knowledge base to contain, KB-relative.
|
|
80
|
+
*
|
|
81
|
+
* ‼️ Every entry must be a path a Soleur producer ACTUALLY writes. This shipped with
|
|
82
|
+
* `overview/constitution.md` while sync.md's Definition Sync reads and writes
|
|
83
|
+
* `project/constitution.md`, so Soleur's own knowledge base would have reported a
|
|
84
|
+
* permanent "no constitution present" line against a file one directory away — in
|
|
85
|
+
* every customer repo. Nothing caught it because every test indexed the constant it
|
|
86
|
+
* was pinning (`[0]`, `[1]`, `.length`), which is self-referential. A parity test now
|
|
87
|
+
* pins the constitution entry against sync.md.
|
|
88
|
+
*
|
|
89
|
+
* PR 1 keeps this a static list. PR 2 replaces it with the blueprint manifest —
|
|
90
|
+
* that substitution is the ONLY coupling between the two PRs, which is why the
|
|
91
|
+
* shape here is deliberately just an ordered string list.
|
|
92
|
+
*
|
|
93
|
+
* Sorted at module scope so ordering can never depend on edit history.
|
|
94
|
+
*/
|
|
95
|
+
export const EXPECTED_KB_PATHS: readonly string[] = [
|
|
96
|
+
"engineering/architecture/diagrams/model.likec4.json",
|
|
97
|
+
"engineering/architecture/domain-model.md",
|
|
98
|
+
"project/constitution.md",
|
|
99
|
+
"product/prd",
|
|
100
|
+
"project/README.md",
|
|
101
|
+
"project/components",
|
|
102
|
+
"project/learnings",
|
|
103
|
+
"project/rule-metrics.json",
|
|
104
|
+
"project/specs",
|
|
105
|
+
].slice().sort();
|
|
106
|
+
|
|
107
|
+
export type CoverageEntry = { path: string; present: boolean };
|
|
108
|
+
|
|
109
|
+
/** Probe each expected path under `kbRoot`. Order is the sorted expected order. */
|
|
110
|
+
export function assessCoverage(kbRoot: string): CoverageEntry[] {
|
|
111
|
+
return EXPECTED_KB_PATHS.map((path) => ({ path, present: existsSync(join(kbRoot, path)) }));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Count the rows the register currently holds under `## Auto-inferred (unreviewed)`.
|
|
116
|
+
*
|
|
117
|
+
* Auto-inferred ONLY — the curated `## Business Rules` table is hand-authored and is
|
|
118
|
+
* not coverage this sync produced, so counting it would make the number move when a
|
|
119
|
+
* human edits the register rather than when sync does.
|
|
120
|
+
*
|
|
121
|
+
* Stops at the next `## ` heading so a register whose Auto-inferred section precedes
|
|
122
|
+
* the curated one does not spill into it — the same section-boundary bug that let
|
|
123
|
+
* write-row append into the curated table.
|
|
124
|
+
*/
|
|
125
|
+
export function countAutoInferredRows(registerMarkdown: string | null): number {
|
|
126
|
+
if (!registerMarkdown) return 0;
|
|
127
|
+
let inSection = false;
|
|
128
|
+
let rows = 0;
|
|
129
|
+
for (const line of registerMarkdown.split("\n")) {
|
|
130
|
+
if (/^## Auto-inferred \(unreviewed\)/.test(line)) {
|
|
131
|
+
inSection = true;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (inSection && /^## /.test(line)) break;
|
|
135
|
+
if (!inSection) continue;
|
|
136
|
+
// A data row: starts with `|`, and is neither the header nor the `|---` rule.
|
|
137
|
+
if (/^\|/.test(line) && !/^\|[\s-]*-[\s-]*\|/.test(line) && !/^\|\s*Anchor\s*\|/.test(line)) {
|
|
138
|
+
rows++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return rows;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Derive every marker count from KB state. See `CoverageSources` for why these are
|
|
146
|
+
* derived rather than passed in.
|
|
147
|
+
*/
|
|
148
|
+
export function deriveCounts(
|
|
149
|
+
entries: CoverageEntry[],
|
|
150
|
+
sources: CoverageSources,
|
|
151
|
+
): ProducerCounts {
|
|
152
|
+
const model = sources.modelJson
|
|
153
|
+
? (() => {
|
|
154
|
+
try {
|
|
155
|
+
const m = JSON.parse(sources.modelJson) as Record<string, unknown>;
|
|
156
|
+
const size = (v: unknown) =>
|
|
157
|
+
v && typeof v === "object" && !Array.isArray(v) ? Object.keys(v).length : 0;
|
|
158
|
+
return { elements: size(m.elements), relationships: size(m.relations) };
|
|
159
|
+
} catch {
|
|
160
|
+
return { elements: 0, relationships: 0 };
|
|
161
|
+
}
|
|
162
|
+
})()
|
|
163
|
+
: { elements: 0, relationships: 0 };
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
c4_elements: model.elements,
|
|
167
|
+
c4_relationships: model.relationships,
|
|
168
|
+
domain_model_rows: countAutoInferredRows(sources.registerMarkdown),
|
|
169
|
+
coverage_present: entries.filter((e) => e.present).length,
|
|
170
|
+
coverage_expected: entries.length,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Collapse to one line — a marker must be greppable as a single record. */
|
|
175
|
+
function oneLine(s: string): string {
|
|
176
|
+
return s.replace(/\s+/g, " ").trim();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** The stdout marker. Counts only, in `MARKER_FIELDS` order. */
|
|
180
|
+
export function formatProducersMarker(counts: ProducerCounts): string {
|
|
181
|
+
const fields = MARKER_FIELDS.map((f) => `${f}=${counts[f]}`).join(" ");
|
|
182
|
+
return `${PRODUCERS_MARKER} ${fields}`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** The failure marker. Not `reportSilentFallback` — nothing under plugins/ imports Sentry. */
|
|
186
|
+
export function formatErrorMarker(producer: string, reason: string): string {
|
|
187
|
+
return oneLine(`${ERROR_MARKER} producer=${producer} reason="${oneLine(reason)}"`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Render the committed artifact.
|
|
192
|
+
*
|
|
193
|
+
* `degraded` rows are recorded here as well as on stdout, so a failed run survives
|
|
194
|
+
* the session — on this surface stdout is the only other signal and it evaporates.
|
|
195
|
+
*/
|
|
196
|
+
export function renderCoverageMarkdown(
|
|
197
|
+
entries: CoverageEntry[],
|
|
198
|
+
counts: ProducerCounts,
|
|
199
|
+
degraded: string[] = [],
|
|
200
|
+
): string {
|
|
201
|
+
const present = entries.filter((e) => e.present);
|
|
202
|
+
const notPresent = entries.filter((e) => !e.present);
|
|
203
|
+
|
|
204
|
+
const out: string[] = [
|
|
205
|
+
"# Knowledge base coverage",
|
|
206
|
+
"",
|
|
207
|
+
"What Soleur looks for in a knowledge base, and what is present in this one.",
|
|
208
|
+
"This is a description of Soleur's expectations — it is not an assessment of",
|
|
209
|
+
"the business, and it is not a compliance finding. Generated by",
|
|
210
|
+
"`/soleur:sync`; regenerated on every run.",
|
|
211
|
+
"",
|
|
212
|
+
`## Present (${present.length} of ${entries.length})`,
|
|
213
|
+
"",
|
|
214
|
+
];
|
|
215
|
+
|
|
216
|
+
if (present.length === 0) {
|
|
217
|
+
out.push("- none of the expected entries are present yet");
|
|
218
|
+
} else {
|
|
219
|
+
for (const e of present) out.push(`- \`${e.path}\``);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
out.push("", "## Not present", "");
|
|
223
|
+
|
|
224
|
+
if (notPresent.length === 0) {
|
|
225
|
+
out.push("- every expected entry is present");
|
|
226
|
+
} else {
|
|
227
|
+
// The exact expectation-vs-presence phrasing. Do not reword to a deficiency
|
|
228
|
+
// form — see the file header.
|
|
229
|
+
for (const e of notPresent) {
|
|
230
|
+
out.push(`- no \`${e.path}\` present in this knowledge base`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (degraded.length > 0) {
|
|
235
|
+
out.push("", "## Producers reporting degraded", "");
|
|
236
|
+
for (const d of degraded.slice().sort()) out.push(`- ${oneLine(d)}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
out.push(
|
|
240
|
+
"",
|
|
241
|
+
"## Run counts",
|
|
242
|
+
"",
|
|
243
|
+
"Emitted identically on sync stdout, so this artifact and the run agree.",
|
|
244
|
+
"",
|
|
245
|
+
"```",
|
|
246
|
+
formatProducersMarker(counts),
|
|
247
|
+
"```",
|
|
248
|
+
"",
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
return out.join("\n");
|
|
252
|
+
}
|