@soleur/opencode 0.0.0-stage → 3.354.2
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 +660 -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 +29 -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 +361 -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 +171 -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 +818 -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 +411 -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 +509 -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 +115 -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 +165 -0
- package/scripts/sync-opencode-adapter.ts +498 -0
- package/scripts/sync-pr-behind.sh +647 -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 +67 -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 +143 -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 +120 -0
- package/skills/fix-issue/references/exclude-label-jq-snippet.md +97 -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 +670 -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 +331 -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 +141 -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 +1620 -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-evidence-comment.md +36 -0
- package/skills/review/references/review-todo-structure.md +165 -0
- package/skills/review/references/risk-tier-and-fix-rounds.md +97 -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 +3023 -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/cleanup-merged-archival.md +39 -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/delegated-act-authoring-form.md +7 -0
- package/skills/ship/references/detached-battery-verdict.md +13 -0
- package/skills/ship/references/epic-close-sweep.md +62 -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 +179 -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/verification-scaffold/SKILL.md +73 -0
- package/skills/verification-scaffold/references/gitleaks.toml.template +13 -0
- package/skills/verification-scaffold/references/guardrail-audit.md +156 -0
- package/skills/verification-scaffold/references/guards/block-stash-hook.sh.template +72 -0
- package/skills/verification-scaffold/references/guards/commit-on-main-hook.sh.template +82 -0
- package/skills/verification-scaffold/references/guards/orphan-test-check.sh.template +102 -0
- package/skills/verification-scaffold/references/guards/precommit-guard.sh.template +115 -0
- package/skills/verification-scaffold/references/guards/secret-scan-hook.sh.template +176 -0
- package/skills/verification-scaffold/references/guards/verification-gates.yml.template +49 -0
- package/skills/verification-scaffold/references/guards/wrapper-boundary.sh.template +47 -0
- package/skills/verification-scaffold/references/guards.tsv +21 -0
- package/skills/verification-scaffold/references/verification-readme.template +55 -0
- package/skills/verification-scaffold/scripts/verification-scaffold.sh +785 -0
- package/skills/verification-scaffold/test/bite-proof.test.sh +159 -0
- package/skills/verification-scaffold/test/generator.test.sh +319 -0
- package/skills/verification-scaffold/test/manifest.test.sh +144 -0
- package/skills/work/SKILL.md +1480 -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,740 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Tests for plugins/soleur/scripts/pipeline-tally.sh — the per-branch pipeline
|
|
4
|
+
# activity ledger (seats / ci_cycles / fix_rounds / agent_rounds), its
|
|
5
|
+
# warn-then-STOP budget gate, and its fail-open UNKNOWN surface.
|
|
6
|
+
#
|
|
7
|
+
# Written from the BINDING CONTRACT, not the implementation (the SUT is built
|
|
8
|
+
# concurrently by a sibling agent — do not import its internals here):
|
|
9
|
+
# knowledge-base/project/specs/archive/20261013-062704-feat-one-shot-9403-cost-tally/interface-contract.md
|
|
10
|
+
# knowledge-base/project/plans/archive/20261013-062704-2026-10-01-feat-pipeline-cost-tally-plan.md
|
|
11
|
+
#
|
|
12
|
+
# AC map: AC1 selfcheck purity · AC2 init/incr/show counts · AC3+AC7 cap latch,
|
|
13
|
+
# --reset, and auto-reset (capped / >24h stale) · AC8 missing-file UNKNOWN ·
|
|
14
|
+
# AC9 flag rejects. Guard-1 arms: gate OK/WARN/STOP/UNKNOWN + capped-flag
|
|
15
|
+
# persistence. Guard-4 (stop-hook floor) lives in test/ralph-loop.test.sh.
|
|
16
|
+
#
|
|
17
|
+
# Fail-open discipline (contract §"Fail-open invariant"): every subcommand
|
|
18
|
+
# except `selfcheck` exits 0 even on internal error; errors surface as
|
|
19
|
+
# `SOLEUR_TALLY_ERROR reason=<k>` on stderr. Assertions therefore target stdout
|
|
20
|
+
# tokens, stderr markers, and counter-file state — never exit codes alone.
|
|
21
|
+
#
|
|
22
|
+
# Run: bash plugins/soleur/scripts/pipeline-tally.test.sh
|
|
23
|
+
|
|
24
|
+
set -uo pipefail
|
|
25
|
+
export TMPDIR="${TMPDIR:-/var/tmp}"
|
|
26
|
+
|
|
27
|
+
# Clear git env vars that leak when this test runs inside a git hook (e.g.,
|
|
28
|
+
# pre-push). Without this, `git branch --show-current` inside fixture repos
|
|
29
|
+
# resolves against the outer repo — same scrub idiom as test/ralph-loop.test.sh.
|
|
30
|
+
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_COMMON_DIR GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_NAMESPACE GIT_TEMPLATE_DIR GIT_EXEC_PATH 2>/dev/null || true
|
|
31
|
+
# An exported kill-switch would UNKNOWN every mutating fixture call; scrub it
|
|
32
|
+
# here (the dedicated arm below re-exports it on purpose).
|
|
33
|
+
unset SOLEUR_DISABLE_SESSION_STATE 2>/dev/null || true
|
|
34
|
+
|
|
35
|
+
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
36
|
+
SUT="$DIR/pipeline-tally.sh"
|
|
37
|
+
|
|
38
|
+
# Trap BEFORE sourcing test-helpers.sh so the helpers' composed EXIT trap
|
|
39
|
+
# stacks on ours instead of being clobbered by it (emit-decision.test.sh idiom).
|
|
40
|
+
TMP="$(mktemp -d -t tally.XXXXXXXX)" || { echo "FATAL: mktemp failed" >&2; exit 2; }
|
|
41
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
42
|
+
|
|
43
|
+
# shellcheck source=../test/test-helpers.sh
|
|
44
|
+
source "$DIR/../test/test-helpers.sh" || { echo "FATAL: could not source test-helpers.sh" >&2; exit 2; }
|
|
45
|
+
set +e -uo pipefail
|
|
46
|
+
assert_fixture_dir "$TMP"
|
|
47
|
+
|
|
48
|
+
[[ -f "$SUT" ]] || { printf '\n[FATAL] SUT missing at %s\n' "$SUT" >&2; exit 1; }
|
|
49
|
+
|
|
50
|
+
# --- Fixture helpers ----------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
# The contract's counter-file key: <slug> = `_safe_worktree_name(branch)` —
|
|
53
|
+
# every non-[a-zA-Z0-9._-] character collapsed to '-' — PLUS `-<sha1-6>` of
|
|
54
|
+
# the raw branch (feat/x and feat-x must land on DISTINCT ledgers). The
|
|
55
|
+
# fixture branch is deliberately slash-bearing so both halves are exercised.
|
|
56
|
+
BRANCH="feat/tally-probe"
|
|
57
|
+
tally_slug() {
|
|
58
|
+
local b="$1"
|
|
59
|
+
printf '%s' "$b" | tr -c 'A-Za-z0-9._-' '-'
|
|
60
|
+
printf -- '-%s' "$(printf '%s' "$b" | git hash-object --stdin | cut -c1-6)"
|
|
61
|
+
}
|
|
62
|
+
SLUG=$(tally_slug "$BRANCH")
|
|
63
|
+
|
|
64
|
+
new_repo() { # $1 = dir name under $TMP; prints the path
|
|
65
|
+
local d="$TMP/$1"
|
|
66
|
+
assert_fixture_dir "$d"
|
|
67
|
+
mkdir -p "$d"
|
|
68
|
+
git -C "$d" init -q -b "$BRANCH"
|
|
69
|
+
printf '%s' "$d"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# run_tally <repo> <state-root> <args...> — invoke the SUT as a skill would:
|
|
73
|
+
# cwd = the repo being tallied, session-state root redirected into the fixture
|
|
74
|
+
# (`SOLEUR_SESSION_STATE_ROOT` is the lib's documented test override).
|
|
75
|
+
# Captures stdout/stderr/rc into OUT/ERR/RC.
|
|
76
|
+
run_tally() {
|
|
77
|
+
local repo="$1" state="$2"; shift 2
|
|
78
|
+
local ef="$TMP/last-stderr"
|
|
79
|
+
OUT=$(cd "$repo" && SOLEUR_SESSION_STATE_ROOT="$state" bash "$SUT" "$@" 2>"$ef")
|
|
80
|
+
RC=$?
|
|
81
|
+
ERR=$(cat "$ef" 2>/dev/null)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Counter-file path the contract assigns this fixture: <root>/counters/<slug>.
|
|
85
|
+
cf_path() { printf '%s/counters/%s' "$1" "$SLUG"; }
|
|
86
|
+
|
|
87
|
+
# Flat key=value read, contract format (same grep+cut idiom as the lib).
|
|
88
|
+
cf_get() { grep "^$2=" "$1" 2>/dev/null | head -1 | cut -d= -f2-; }
|
|
89
|
+
|
|
90
|
+
assert_not_contains() {
|
|
91
|
+
local haystack="$1" needle="$2" msg="$3"
|
|
92
|
+
if [[ "$haystack" != *"$needle"* ]]; then
|
|
93
|
+
echo " PASS: $msg"; PASS=$((PASS + 1))
|
|
94
|
+
else
|
|
95
|
+
echo " FAIL: $msg"
|
|
96
|
+
echo " expected NOT to contain: '$needle'"
|
|
97
|
+
echo " actual: '$haystack'"
|
|
98
|
+
FAIL=$((FAIL + 1))
|
|
99
|
+
fi
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Path-absence assert for directories too (assert_file_not_exists is -f only).
|
|
103
|
+
assert_path_absent() {
|
|
104
|
+
local path="$1" msg="$2"
|
|
105
|
+
if [[ ! -e "$path" ]]; then
|
|
106
|
+
echo " PASS: $msg"; PASS=$((PASS + 1))
|
|
107
|
+
else
|
|
108
|
+
echo " FAIL: $msg (path exists: $path)"; FAIL=$((FAIL + 1))
|
|
109
|
+
fi
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
assert_rc0() { assert_eq "0" "$RC" "$1"; }
|
|
113
|
+
|
|
114
|
+
echo "=== pipeline-tally.sh contract tests ==="
|
|
115
|
+
echo ""
|
|
116
|
+
|
|
117
|
+
# --- Test 1: selfcheck purity (AC1) ------------------------------------------
|
|
118
|
+
# `selfcheck` prints SOLEUR_TALLY_OK, exit 0, writes NOTHING — safe in a
|
|
119
|
+
# read-only sandbox. Asserted twice: with the state root pointed at a path
|
|
120
|
+
# that does not exist, and without the override inside a real repo (where
|
|
121
|
+
# sourcing the lib must NOT mint .git/soleur-session-state/*).
|
|
122
|
+
echo "Test 1: selfcheck prints SOLEUR_TALLY_OK and writes nothing"
|
|
123
|
+
R1=$(new_repo r1)
|
|
124
|
+
GONE="$TMP/state-root-never-created"
|
|
125
|
+
OUT=$(cd "$R1" && SOLEUR_SESSION_STATE_ROOT="$GONE" bash "$SUT" selfcheck 2>"$TMP/e1")
|
|
126
|
+
RC=$?
|
|
127
|
+
ERR=$(cat "$TMP/e1" 2>/dev/null)
|
|
128
|
+
assert_rc0 "selfcheck exits 0"
|
|
129
|
+
assert_eq "SOLEUR_TALLY_OK" "$OUT" "selfcheck stdout is exactly SOLEUR_TALLY_OK"
|
|
130
|
+
assert_not_contains "$ERR" "SOLEUR_TALLY_ERROR" "selfcheck emits no error marker"
|
|
131
|
+
assert_path_absent "$GONE" "selfcheck creates nothing under the state root"
|
|
132
|
+
|
|
133
|
+
OUT=$(cd "$R1" && bash "$SUT" selfcheck 2>"$TMP/e1b")
|
|
134
|
+
RC=$?
|
|
135
|
+
assert_rc0 "selfcheck exits 0 without the env override (repo path)"
|
|
136
|
+
assert_eq "SOLEUR_TALLY_OK" "$OUT" "selfcheck stdout exact on the repo path"
|
|
137
|
+
assert_path_absent "$R1/.git/soleur-session-state" "selfcheck mints no .git/soleur-session-state tree"
|
|
138
|
+
DIRTY=$(cd "$R1" && git status --porcelain)
|
|
139
|
+
assert_eq "" "$DIRTY" "selfcheck leaves the worktree clean"
|
|
140
|
+
echo ""
|
|
141
|
+
|
|
142
|
+
# --- Test 2: init creates a zeroed ledger (fresh) -----------------------------
|
|
143
|
+
echo "Test 2: init on an absent file creates a zeroed ledger"
|
|
144
|
+
R2=$(new_repo r2); S2="$TMP/s2"; C2=$(cf_path "$S2")
|
|
145
|
+
run_tally "$R2" "$S2" init
|
|
146
|
+
assert_rc0 "init exits 0"
|
|
147
|
+
assert_contains "$OUT" "tally-init:" "init prints the tally-init line"
|
|
148
|
+
assert_contains "$OUT" "$SLUG" "init output carries the branch slug"
|
|
149
|
+
assert_contains "$OUT" "fresh" "init reports fresh for a new ledger"
|
|
150
|
+
assert_file_exists "$C2" "counter file created at counters/<slug>"
|
|
151
|
+
assert_eq "0" "$(cf_get "$C2" seats)" "seats initialized to 0"
|
|
152
|
+
assert_eq "0" "$(cf_get "$C2" ci_cycles)" "ci_cycles initialized to 0"
|
|
153
|
+
assert_eq "0" "$(cf_get "$C2" fix_rounds)" "fix_rounds initialized to 0"
|
|
154
|
+
assert_eq "0" "$(cf_get "$C2" agent_rounds)" "agent_rounds initialized to 0"
|
|
155
|
+
assert_eq "0" "$(cf_get "$C2" cap_seats)" "cap_seats initialized to 0 (unset)"
|
|
156
|
+
assert_eq "" "$(cf_get "$C2" capped)" "capped starts empty"
|
|
157
|
+
assert_eq "" "$(cf_get "$C2" started_at)" "no started_at key — staleness is mtime-keyed"
|
|
158
|
+
assert_eq "" "$(cf_get "$C2" run_id)" "no run_id key — dropped from the ledger schema"
|
|
159
|
+
echo ""
|
|
160
|
+
|
|
161
|
+
# --- Test 3: AC2 — init, incr n>1, show --------------------------------------
|
|
162
|
+
echo "Test 3: AC2 — init -> incr seats 3 -> incr ci_cycles 2 -> show"
|
|
163
|
+
R3=$(new_repo r3); S3="$TMP/s3"
|
|
164
|
+
run_tally "$R3" "$S3" init
|
|
165
|
+
run_tally "$R3" "$S3" incr seats 3
|
|
166
|
+
assert_rc0 "incr seats 3 exits 0"
|
|
167
|
+
assert_not_contains "$OUT" "UNKNOWN" "incr on a live ledger does not print UNKNOWN"
|
|
168
|
+
run_tally "$R3" "$S3" incr ci_cycles 2
|
|
169
|
+
assert_rc0 "incr ci_cycles 2 exits 0"
|
|
170
|
+
run_tally "$R3" "$S3" show
|
|
171
|
+
assert_eq "tally: seats=3 ci_cycles=2 fix_rounds=0 agent_rounds=0" "$OUT" \
|
|
172
|
+
"show prints the contract's exact tally line"
|
|
173
|
+
echo ""
|
|
174
|
+
|
|
175
|
+
# --- Test 4: incr default n=1, n>1, the ci-cycles alias, all four dims --------
|
|
176
|
+
echo "Test 4: incr defaults n=1, accepts n>1, aliases ci-cycles"
|
|
177
|
+
R4=$(new_repo r4); S4="$TMP/s4"
|
|
178
|
+
run_tally "$R4" "$S4" init
|
|
179
|
+
run_tally "$R4" "$S4" incr seats # default n=1
|
|
180
|
+
run_tally "$R4" "$S4" incr seats 4 # n>1
|
|
181
|
+
run_tally "$R4" "$S4" incr ci-cycles # hyphenated alias -> ci_cycles
|
|
182
|
+
run_tally "$R4" "$S4" incr fix_rounds 2
|
|
183
|
+
run_tally "$R4" "$S4" incr agent_rounds 3
|
|
184
|
+
run_tally "$R4" "$S4" show
|
|
185
|
+
assert_eq "tally: seats=5 ci_cycles=1 fix_rounds=2 agent_rounds=3" "$OUT" \
|
|
186
|
+
"all four dims accumulate; ci-cycles alias lands on ci_cycles"
|
|
187
|
+
echo ""
|
|
188
|
+
|
|
189
|
+
# --- Test 5: incr on a missing file (AC8, Guard-1 row 4) ----------------------
|
|
190
|
+
echo "Test 5: incr on a missing file -> UNKNOWN + missing-file, never auto-creates"
|
|
191
|
+
R5=$(new_repo r5); S5="$TMP/s5"; C5=$(cf_path "$S5")
|
|
192
|
+
run_tally "$R5" "$S5" incr seats
|
|
193
|
+
assert_rc0 "incr fail-opens with exit 0"
|
|
194
|
+
assert_eq "UNKNOWN" "$OUT" "stdout is UNKNOWN"
|
|
195
|
+
assert_contains "$ERR" "SOLEUR_TALLY_ERROR" "stderr carries the error marker"
|
|
196
|
+
assert_contains "$ERR" "missing-file" "error reason is missing-file"
|
|
197
|
+
assert_path_absent "$C5" "no counter file was auto-created"
|
|
198
|
+
echo ""
|
|
199
|
+
|
|
200
|
+
# --- Test 6: init merge — counters preserved, caps merged (AC7) ---------------
|
|
201
|
+
echo "Test 6: init on a live ledger merges caps and preserves counters"
|
|
202
|
+
R6=$(new_repo r6); S6="$TMP/s6"; C6=$(cf_path "$S6")
|
|
203
|
+
run_tally "$R6" "$S6" init --max-seats 5
|
|
204
|
+
assert_eq "5" "$(cf_get "$C6" cap_seats)" "--max-seats persists as cap_seats"
|
|
205
|
+
run_tally "$R6" "$S6" incr seats 2
|
|
206
|
+
run_tally "$R6" "$S6" init --max-ci-cycles 7
|
|
207
|
+
assert_rc0 "second init exits 0"
|
|
208
|
+
assert_contains "$OUT" "continued" "second init reports continued (no reset)"
|
|
209
|
+
assert_eq "2" "$(cf_get "$C6" seats)" "counters survive the second init"
|
|
210
|
+
assert_eq "5" "$(cf_get "$C6" cap_seats)" "cap_seats survives a caps merge"
|
|
211
|
+
assert_eq "7" "$(cf_get "$C6" cap_ci_cycles)" "new cap merges alongside the old"
|
|
212
|
+
echo ""
|
|
213
|
+
|
|
214
|
+
# --- Test 7: init --reset -----------------------------------------------------
|
|
215
|
+
echo "Test 7: init --reset forces a fresh ledger"
|
|
216
|
+
R7=$(new_repo r7); S7="$TMP/s7"; C7=$(cf_path "$S7")
|
|
217
|
+
run_tally "$R7" "$S7" init --max-seats 5
|
|
218
|
+
run_tally "$R7" "$S7" incr seats 9
|
|
219
|
+
run_tally "$R7" "$S7" init --reset
|
|
220
|
+
assert_rc0 "init --reset exits 0"
|
|
221
|
+
assert_contains "$OUT" "reset" "reports the reset tag"
|
|
222
|
+
assert_eq "0" "$(cf_get "$C7" seats)" "counts zeroed by --reset"
|
|
223
|
+
# CONTRACT AMBIGUITY (flagged to coordinator): "fresh ledger" does not say
|
|
224
|
+
# whether cap_* belongs to the reset state or to the merged config. This arm
|
|
225
|
+
# asserts PRESERVE — clearing caps on a plain `--reset` would silently drop the
|
|
226
|
+
# operator's declared budget on a documented resume path, which is the worse
|
|
227
|
+
# failure direction. If the contract means caps reset too, flip this assert.
|
|
228
|
+
assert_eq "5" "$(cf_get "$C7" cap_seats)" "caps preserved by --reset (budget is not silently dropped)"
|
|
229
|
+
run_tally "$R7" "$S7" init --reset --max-seats 9
|
|
230
|
+
assert_eq "9" "$(cf_get "$C7" cap_seats)" "--reset + new --max-* writes the new cap"
|
|
231
|
+
echo ""
|
|
232
|
+
|
|
233
|
+
# --- Test 8: bare-init continues a capped ledger; raised caps unlatch -------
|
|
234
|
+
# ADJUDICATED (coordinator, over the contract's literal "auto-reset" — since
|
|
235
|
+
# folded back into interface-contract.md): a bare init CONTINUES a capped
|
|
236
|
+
# ledger — the counts that produced the cap are the forensic record the PR
|
|
237
|
+
# tally ships, and the latch alone carries the re-STOP. `capped-reset` is
|
|
238
|
+
# reserved for capped + RAISED --max-* argv.
|
|
239
|
+
echo "Test 8: bare init continues a capped ledger; raised caps report capped-reset"
|
|
240
|
+
R8=$(new_repo r8); S8="$TMP/s8"; C8=$(cf_path "$S8")
|
|
241
|
+
assert_fixture_dir "$C8"
|
|
242
|
+
mkdir -p "$(dirname "$C8")"
|
|
243
|
+
cat > "$C8" <<EOF
|
|
244
|
+
seats=7
|
|
245
|
+
ci_cycles=0
|
|
246
|
+
fix_rounds=0
|
|
247
|
+
agent_rounds=0
|
|
248
|
+
cap_seats=5
|
|
249
|
+
cap_ci_cycles=0
|
|
250
|
+
cap_fix_rounds=0
|
|
251
|
+
cap_agent_rounds=0
|
|
252
|
+
warned_seats=0
|
|
253
|
+
warned_ci_cycles=0
|
|
254
|
+
warned_fix_rounds=0
|
|
255
|
+
warned_agent_rounds=0
|
|
256
|
+
capped=seats
|
|
257
|
+
run_id=seeded
|
|
258
|
+
started_at=$(date +%s)
|
|
259
|
+
EOF
|
|
260
|
+
run_tally "$R8" "$S8" init
|
|
261
|
+
assert_rc0 "init on a capped ledger exits 0"
|
|
262
|
+
assert_contains "$OUT" "continued" "bare init continues a capped ledger"
|
|
263
|
+
assert_eq "7" "$(cf_get "$C8" seats)" "counts preserved across bare init"
|
|
264
|
+
assert_eq "seats" "$(cf_get "$C8" capped)" "the capped latch persists (re-STOP, not unlock)"
|
|
265
|
+
run_tally "$R8" "$S8" gate seats
|
|
266
|
+
assert_eq "STOP" "$OUT" "gate still STOPs on the latched ledger"
|
|
267
|
+
# Raised caps via --max-* on a capped ledger -> capped-reset: latch clears,
|
|
268
|
+
# new cap stored, counts preserved for the final tally.
|
|
269
|
+
run_tally "$R8" "$S8" init --max-seats 20
|
|
270
|
+
assert_contains "$OUT" "capped-reset" "raised caps on a capped ledger report capped-reset"
|
|
271
|
+
assert_eq "" "$(cf_get "$C8" capped)" "capped-reset clears the latch"
|
|
272
|
+
assert_eq "20" "$(cf_get "$C8" cap_seats)" "capped-reset stores the raised cap"
|
|
273
|
+
assert_eq "7" "$(cf_get "$C8" seats)" "capped-reset preserves counts"
|
|
274
|
+
run_tally "$R8" "$S8" gate seats
|
|
275
|
+
assert_eq "OK" "$OUT" "gate OK after capped-reset (resume under raised caps)"
|
|
276
|
+
# Explicit --reset also clears the latch (Guard-4 row 3's resume shape).
|
|
277
|
+
R8b=$(new_repo r8b); S8b="$TMP/s8b"; C8b=$(cf_path "$S8b")
|
|
278
|
+
assert_fixture_dir "$C8b"
|
|
279
|
+
mkdir -p "$(dirname "$C8b")"
|
|
280
|
+
cp "$C8" "$C8b"
|
|
281
|
+
sed -i 's/^capped=.*/capped=seats/' "$C8b" # re-seed the latch; capped-reset cleared it
|
|
282
|
+
run_tally "$R8b" "$S8b" init --reset --max-seats 20
|
|
283
|
+
assert_eq "" "$(cf_get "$C8b" capped)" "explicit --reset clears the capped latch"
|
|
284
|
+
run_tally "$R8b" "$S8b" gate seats
|
|
285
|
+
assert_eq "OK" "$OUT" "gate OK after --reset (resume not trapped)"
|
|
286
|
+
echo ""
|
|
287
|
+
|
|
288
|
+
# --- Test 9: auto-reset on a stale ledger (>24h mtime inactivity) -------------
|
|
289
|
+
echo "Test 9: init auto-resets a ledger untouched for >24h (mtime)"
|
|
290
|
+
R9=$(new_repo r9); S9="$TMP/s9"; C9=$(cf_path "$S9")
|
|
291
|
+
assert_fixture_dir "$C9"
|
|
292
|
+
mkdir -p "$(dirname "$C9")"
|
|
293
|
+
OLD_TS=$(( $(date +%s) - 90000 )) # 25h ago — unambiguously over the 24h line
|
|
294
|
+
cat > "$C9" <<EOF
|
|
295
|
+
seats=9
|
|
296
|
+
ci_cycles=4
|
|
297
|
+
fix_rounds=0
|
|
298
|
+
agent_rounds=0
|
|
299
|
+
cap_seats=5
|
|
300
|
+
cap_ci_cycles=0
|
|
301
|
+
cap_fix_rounds=0
|
|
302
|
+
cap_agent_rounds=0
|
|
303
|
+
warned_seats=0
|
|
304
|
+
warned_ci_cycles=0
|
|
305
|
+
warned_fix_rounds=0
|
|
306
|
+
warned_agent_rounds=0
|
|
307
|
+
capped=
|
|
308
|
+
EOF
|
|
309
|
+
touch -d "25 hours ago" "$C9"
|
|
310
|
+
run_tally "$R9" "$S9" init
|
|
311
|
+
assert_rc0 "init on a stale ledger exits 0"
|
|
312
|
+
assert_contains "$OUT" "stale-reset" "reports the stale-reset tag"
|
|
313
|
+
assert_eq "0" "$(cf_get "$C9" seats)" "stale counts zeroed"
|
|
314
|
+
NEW_MT=$(stat -c %Y "$C9" 2>/dev/null || stat -f %m "$C9")
|
|
315
|
+
if [[ "$NEW_MT" =~ ^[0-9]+$ ]] && (( NEW_MT > OLD_TS )); then
|
|
316
|
+
PASS=$((PASS + 1)); echo " PASS: ledger mtime refreshed by the rewrite"
|
|
317
|
+
else
|
|
318
|
+
FAIL=$((FAIL + 1)); echo " FAIL: ledger mtime refreshed (old=$OLD_TS new=$NEW_MT)"
|
|
319
|
+
fi
|
|
320
|
+
# The inverse arm pins the semantic: an old-schema ledger still carrying a
|
|
321
|
+
# stale started_at key but a FRESH mtime must continue, not reset — staleness
|
|
322
|
+
# is inactivity, and a dead key must not resurrect the old behavior.
|
|
323
|
+
R9b=$(new_repo r9b); S9b="$TMP/s9b"; C9b=$(cf_path "$S9b")
|
|
324
|
+
mkdir -p "$(dirname "$C9b")"
|
|
325
|
+
cat > "$C9b" <<EOF
|
|
326
|
+
seats=7
|
|
327
|
+
ci_cycles=0
|
|
328
|
+
fix_rounds=0
|
|
329
|
+
agent_rounds=0
|
|
330
|
+
cap_seats=0
|
|
331
|
+
cap_ci_cycles=0
|
|
332
|
+
cap_fix_rounds=0
|
|
333
|
+
cap_agent_rounds=0
|
|
334
|
+
warned_seats=0
|
|
335
|
+
warned_ci_cycles=0
|
|
336
|
+
warned_fix_rounds=0
|
|
337
|
+
warned_agent_rounds=0
|
|
338
|
+
capped=
|
|
339
|
+
run_id=old-schema
|
|
340
|
+
started_at=$OLD_TS
|
|
341
|
+
EOF
|
|
342
|
+
run_tally "$R9b" "$S9b" init
|
|
343
|
+
assert_contains "$OUT" "continued" "fresh-mtime ledger continues despite stale started_at key"
|
|
344
|
+
assert_eq "7" "$(cf_get "$C9b" seats)" "dead started_at key does not trigger stale-reset"
|
|
345
|
+
assert_eq "" "$(cf_get "$C9b" started_at)" "rewrite drops the dead started_at key"
|
|
346
|
+
echo ""
|
|
347
|
+
|
|
348
|
+
# --- Test 10: 30-day sibling sweep --------------------------------------------
|
|
349
|
+
echo "Test 10: init sweeps sibling counter files with mtime > 30 days"
|
|
350
|
+
R10=$(new_repo r10); S10="$TMP/s10"
|
|
351
|
+
OLD_SIB="$S10/counters/some-old-branch"; FRESH_SIB="$S10/counters/some-other-branch"
|
|
352
|
+
assert_fixture_dir "$OLD_SIB"; assert_fixture_dir "$FRESH_SIB"
|
|
353
|
+
mkdir -p "$S10/counters"
|
|
354
|
+
printf 'seats=1\n' > "$OLD_SIB"
|
|
355
|
+
printf 'seats=2\n' > "$FRESH_SIB"
|
|
356
|
+
touch -d "31 days ago" "$OLD_SIB"
|
|
357
|
+
run_tally "$R10" "$S10" init
|
|
358
|
+
assert_rc0 "init exits 0 with siblings present"
|
|
359
|
+
assert_path_absent "$OLD_SIB" "sibling older than 30d is swept"
|
|
360
|
+
assert_file_exists "$FRESH_SIB" "fresh sibling is preserved"
|
|
361
|
+
assert_file_exists "$(cf_path "$S10")" "this branch's ledger still created"
|
|
362
|
+
echo ""
|
|
363
|
+
|
|
364
|
+
# --- Test 11: gate OK arms ----------------------------------------------------
|
|
365
|
+
echo "Test 11: gate prints OK with no cap, and under the warn threshold"
|
|
366
|
+
R11=$(new_repo r11); S11="$TMP/s11"
|
|
367
|
+
run_tally "$R11" "$S11" init
|
|
368
|
+
run_tally "$R11" "$S11" incr seats 99
|
|
369
|
+
run_tally "$R11" "$S11" gate seats
|
|
370
|
+
assert_eq "OK" "$OUT" "cap unset -> OK regardless of count"
|
|
371
|
+
run_tally "$R11" "$S11" init --max-seats 5
|
|
372
|
+
run_tally "$R11" "$S11" init --reset --max-seats 5 # fresh ledger carrying the cap
|
|
373
|
+
run_tally "$R11" "$S11" incr seats 3 # 3 < ceil(5*0.8)=4
|
|
374
|
+
run_tally "$R11" "$S11" gate seats
|
|
375
|
+
assert_eq "OK" "$OUT" "count below the warn threshold -> OK"
|
|
376
|
+
echo ""
|
|
377
|
+
|
|
378
|
+
# --- Test 12: gate WARN arms ---------------------------------------------------
|
|
379
|
+
# WARN at count >= ceil(cap*0.8): cap 5 warns at 4; cap 10 warns at 8 (ceil).
|
|
380
|
+
# WARN records warned_<dim> as the at-count of the FIRST fire (contract schema:
|
|
381
|
+
# "at-count recorded when WARN first fires; 0 = none").
|
|
382
|
+
echo "Test 12: gate warns at >=80% of cap and records warned_<dim>"
|
|
383
|
+
R12=$(new_repo r12); S12="$TMP/s12"; C12=$(cf_path "$S12")
|
|
384
|
+
run_tally "$R12" "$S12" init --max-seats 10
|
|
385
|
+
run_tally "$R12" "$S12" incr seats 8 # 8 == ceil(10*0.8): boundary
|
|
386
|
+
run_tally "$R12" "$S12" gate seats
|
|
387
|
+
assert_eq "WARN" "$OUT" "count at the 80% boundary -> WARN"
|
|
388
|
+
assert_eq "8" "$(cf_get "$C12" warned_seats)" "warned_seats records the at-count"
|
|
389
|
+
run_tally "$R12" "$S12" show
|
|
390
|
+
assert_contains "$OUT" "warned:seats=8" "show annotates warned:<dim>=<at>"
|
|
391
|
+
run_tally "$R12" "$S12" incr seats # 9, still under cap 10
|
|
392
|
+
run_tally "$R12" "$S12" gate seats
|
|
393
|
+
assert_eq "WARN" "$OUT" "WARN repeats while in the warn band"
|
|
394
|
+
assert_eq "8" "$(cf_get "$C12" warned_seats)" "warned_<dim> keeps the FIRST-fire at-count"
|
|
395
|
+
echo ""
|
|
396
|
+
|
|
397
|
+
# --- Test 13: gate STOP arms ----------------------------------------------------
|
|
398
|
+
echo "Test 13: gate stops at the cap, sets capped, and honors the ci-cycles alias"
|
|
399
|
+
R13=$(new_repo r13); S13="$TMP/s13"; C13=$(cf_path "$S13")
|
|
400
|
+
run_tally "$R13" "$S13" init --max-ci-cycles 1
|
|
401
|
+
run_tally "$R13" "$S13" incr ci_cycles 1
|
|
402
|
+
run_tally "$R13" "$S13" gate ci-cycles # AC3's hyphenated form
|
|
403
|
+
assert_eq "STOP" "$OUT" "count >= cap -> STOP"
|
|
404
|
+
assert_eq "ci_cycles" "$(cf_get "$C13" capped)" "STOP sets capped=<dim>"
|
|
405
|
+
run_tally "$R13" "$S13" show
|
|
406
|
+
assert_contains "$OUT" "capped:ci_cycles" "show annotates capped:<dim>"
|
|
407
|
+
run_tally "$R13" "$S13" gate seats # any dim STOPs while latched
|
|
408
|
+
assert_eq "STOP" "$OUT" "capped set (any dim) -> STOP for every gate"
|
|
409
|
+
echo ""
|
|
410
|
+
|
|
411
|
+
# --- Test 14: capped latch persists across gates (Guard-1 property) ------------
|
|
412
|
+
echo "Test 14: a seeded capped latch STOPs every gate until --reset"
|
|
413
|
+
R14=$(new_repo r14); S14="$TMP/s14"; C14=$(cf_path "$S14")
|
|
414
|
+
assert_fixture_dir "$C14"
|
|
415
|
+
mkdir -p "$(dirname "$C14")"
|
|
416
|
+
cat > "$C14" <<EOF
|
|
417
|
+
seats=0
|
|
418
|
+
ci_cycles=0
|
|
419
|
+
fix_rounds=0
|
|
420
|
+
agent_rounds=0
|
|
421
|
+
cap_seats=0
|
|
422
|
+
cap_ci_cycles=0
|
|
423
|
+
cap_fix_rounds=0
|
|
424
|
+
cap_agent_rounds=0
|
|
425
|
+
warned_seats=0
|
|
426
|
+
warned_ci_cycles=0
|
|
427
|
+
warned_fix_rounds=0
|
|
428
|
+
warned_agent_rounds=0
|
|
429
|
+
capped=fix_rounds
|
|
430
|
+
run_id=latched
|
|
431
|
+
started_at=$(date +%s)
|
|
432
|
+
EOF
|
|
433
|
+
run_tally "$R14" "$S14" gate seats
|
|
434
|
+
assert_eq "STOP" "$OUT" "gate seats STOPs under a foreign-dim latch"
|
|
435
|
+
run_tally "$R14" "$S14" gate agent_rounds
|
|
436
|
+
assert_eq "STOP" "$OUT" "gate agent_rounds STOPs under a foreign-dim latch"
|
|
437
|
+
echo ""
|
|
438
|
+
|
|
439
|
+
# --- Test 15: gate UNKNOWN on substrate failure --------------------------------
|
|
440
|
+
echo "Test 15: gate on a missing file -> UNKNOWN + SOLEUR_TALLY_ERROR, exit 0"
|
|
441
|
+
R15=$(new_repo r15); S15="$TMP/s15"
|
|
442
|
+
run_tally "$R15" "$S15" gate seats
|
|
443
|
+
assert_rc0 "gate fail-opens with exit 0"
|
|
444
|
+
assert_eq "UNKNOWN" "$OUT" "stdout is UNKNOWN"
|
|
445
|
+
assert_contains "$ERR" "SOLEUR_TALLY_ERROR" "stderr carries the error marker"
|
|
446
|
+
echo ""
|
|
447
|
+
|
|
448
|
+
# --- Test 16: flag rejects (AC9) ------------------------------------------------
|
|
449
|
+
echo "Test 16: --max-<dim> rejects 08 / -1 / 0 / abc (fail-open, no ledger written)"
|
|
450
|
+
R16=$(new_repo r16); S16="$TMP/s16"; C16=$(cf_path "$S16")
|
|
451
|
+
for BAD in 08 -1 0 abc; do
|
|
452
|
+
run_tally "$R16" "$S16" init --max-seats "$BAD"
|
|
453
|
+
assert_rc0 "init --max-seats $BAD still exits 0 (fail-open)"
|
|
454
|
+
assert_contains "$ERR" "SOLEUR_TALLY_ERROR" "bad flag '$BAD' surfaces the error marker"
|
|
455
|
+
assert_contains "$ERR" "bad-flag" "bad flag '$BAD' reports reason=bad-flag"
|
|
456
|
+
done
|
|
457
|
+
run_tally "$R16" "$S16" init --max-ci-cycles abc
|
|
458
|
+
assert_rc0 "bad flag on a second dim exits 0"
|
|
459
|
+
assert_contains "$ERR" "bad-flag" "reason=bad-flag on --max-ci-cycles abc"
|
|
460
|
+
assert_path_absent "$C16" "a rejected flag never mints a ledger"
|
|
461
|
+
run_tally "$R16" "$S16" init --max-seats
|
|
462
|
+
assert_rc0 "missing flag value exits 0 (fail-open)"
|
|
463
|
+
assert_contains "$ERR" "SOLEUR_TALLY_ERROR" "missing flag value surfaces the marker"
|
|
464
|
+
echo ""
|
|
465
|
+
|
|
466
|
+
# --- Test 17: 20-way concurrent incr under flock --------------------------------
|
|
467
|
+
echo "Test 17: 20 concurrent incr under flock -> count == 20"
|
|
468
|
+
if command -v flock >/dev/null 2>&1; then
|
|
469
|
+
R17=$(new_repo r17); S17="$TMP/s17"; C17=$(cf_path "$S17")
|
|
470
|
+
run_tally "$R17" "$S17" init
|
|
471
|
+
for _i in $(seq 1 20); do
|
|
472
|
+
(cd "$R17" && SOLEUR_SESSION_STATE_ROOT="$S17" bash "$SUT" incr seats >/dev/null 2>&1) &
|
|
473
|
+
done
|
|
474
|
+
wait
|
|
475
|
+
assert_eq "20" "$(cf_get "$C17" seats)" "no lost updates under 20-way contention"
|
|
476
|
+
else
|
|
477
|
+
echo " SKIP: flock unavailable — the substrate degrades to UNKNOWN by design (macOS)"
|
|
478
|
+
SKIPPED=$((SKIPPED + 1))
|
|
479
|
+
fi
|
|
480
|
+
echo ""
|
|
481
|
+
|
|
482
|
+
# --- Test 18: show on an absent ledger ------------------------------------------
|
|
483
|
+
echo "Test 18: show on a missing file -> UNKNOWN"
|
|
484
|
+
R18=$(new_repo r18); S18="$TMP/s18"
|
|
485
|
+
run_tally "$R18" "$S18" show
|
|
486
|
+
assert_rc0 "show fail-opens with exit 0"
|
|
487
|
+
assert_eq "UNKNOWN" "$OUT" "stdout is UNKNOWN"
|
|
488
|
+
echo ""
|
|
489
|
+
|
|
490
|
+
# --- Test 19: unknown dim / unknown subcommand fail open ------------------------
|
|
491
|
+
echo "Test 19: an unknown dim or subcommand surfaces the marker and exits 0"
|
|
492
|
+
R19=$(new_repo r19); S19="$TMP/s19"; C19=$(cf_path "$S19")
|
|
493
|
+
run_tally "$R19" "$S19" init
|
|
494
|
+
run_tally "$R19" "$S19" incr not_a_dim
|
|
495
|
+
assert_rc0 "incr with an unknown dim exits 0"
|
|
496
|
+
assert_contains "$ERR" "SOLEUR_TALLY_ERROR" "unknown dim surfaces the error marker"
|
|
497
|
+
assert_eq "0" "$(cf_get "$C19" seats)" "unknown dim mutates no counters"
|
|
498
|
+
run_tally "$R19" "$S19" bogus-subcommand
|
|
499
|
+
assert_rc0 "an unknown subcommand exits 0"
|
|
500
|
+
assert_contains "$ERR" "SOLEUR_TALLY_ERROR" "unknown subcommand surfaces the marker"
|
|
501
|
+
echo ""
|
|
502
|
+
|
|
503
|
+
# --- Test 20: incr n edge cases --------------------------------------------------
|
|
504
|
+
# Contract: "n default 1, `10#` normalized" — `08` is a DECIMAL 8 under 10#.
|
|
505
|
+
# (Flag-reject for `08` is specified only for init's --max-* flags; if the SUT
|
|
506
|
+
# rejects it on incr instead, this arm needs contract adjudication.)
|
|
507
|
+
echo "Test 20: incr normalizes n and rejects garbage without corrupting state"
|
|
508
|
+
R20=$(new_repo r20); S20="$TMP/s20"; C20=$(cf_path "$S20")
|
|
509
|
+
run_tally "$R20" "$S20" init
|
|
510
|
+
run_tally "$R20" "$S20" incr seats 08
|
|
511
|
+
assert_rc0 "incr seats 08 exits 0"
|
|
512
|
+
assert_eq "8" "$(cf_get "$C20" seats)" "10# normalization: 08 counts as 8"
|
|
513
|
+
run_tally "$R20" "$S20" incr seats abc
|
|
514
|
+
assert_rc0 "incr seats abc exits 0 (fail-open)"
|
|
515
|
+
assert_contains "$ERR" "SOLEUR_TALLY_ERROR" "non-numeric n surfaces the marker"
|
|
516
|
+
if [[ "$(cf_get "$C20" seats)" =~ ^[0-9]+$ ]]; then
|
|
517
|
+
PASS=$((PASS + 1)); echo " PASS: seats stays numeric after a bad incr"
|
|
518
|
+
else
|
|
519
|
+
FAIL=$((FAIL + 1)); echo " FAIL: seats corrupted by a bad incr (got '$(cf_get "$C20" seats)')"
|
|
520
|
+
fi
|
|
521
|
+
echo ""
|
|
522
|
+
|
|
523
|
+
# --- Test 21: no-dollar discipline (AC6) ----------------------------------------
|
|
524
|
+
# Contract §"Exit/stdout discipline": stdout lines are tally…/UNKNOWN/verdict
|
|
525
|
+
# tokens only — no `$`, no USD, no cost_usd on any local-loop output.
|
|
526
|
+
echo "Test 21: no dollar figures on any tally/gate/show output"
|
|
527
|
+
R21=$(new_repo r21); S21="$TMP/s21"
|
|
528
|
+
run_tally "$R21" "$S21" init --max-seats 2; ALL="$OUT"
|
|
529
|
+
run_tally "$R21" "$S21" incr seats 2; ALL="$ALL
|
|
530
|
+
$OUT"
|
|
531
|
+
run_tally "$R21" "$S21" gate seats; ALL="$ALL
|
|
532
|
+
$OUT"
|
|
533
|
+
run_tally "$R21" "$S21" show; ALL="$ALL
|
|
534
|
+
$OUT"
|
|
535
|
+
run_tally "$R21" "$S21" selfcheck; ALL="$ALL
|
|
536
|
+
$OUT"
|
|
537
|
+
assert_not_contains "$ALL" '$' "no \$ anywhere in stdout"
|
|
538
|
+
assert_not_contains "$ALL" "USD" "no USD in stdout"
|
|
539
|
+
assert_not_contains "$ALL" "cost_usd" "no cost_usd key in stdout"
|
|
540
|
+
echo ""
|
|
541
|
+
|
|
542
|
+
# --- Test 22: orphan-root fallback ---------------------------------------------
|
|
543
|
+
# When the state root resolves to the /tmp/soleur-session-state-orphan fallback
|
|
544
|
+
# (no git repo), the counters dir gains a -<repo-basename> suffix so repos don't
|
|
545
|
+
# collide. Skipped rather than red if the operator already has an orphan root —
|
|
546
|
+
# the arm must never disturb real state.
|
|
547
|
+
echo "Test 22: orphan fallback appends -<repo-basename> to the counters dir"
|
|
548
|
+
ORPHAN="/tmp/soleur-session-state-orphan"
|
|
549
|
+
if [[ -e "$ORPHAN" ]]; then
|
|
550
|
+
echo " SKIP: $ORPHAN already exists — refusing to touch real state"
|
|
551
|
+
SKIPPED=$((SKIPPED + 1))
|
|
552
|
+
else
|
|
553
|
+
NG="$TMP/notrepo"
|
|
554
|
+
assert_fixture_dir "$NG"
|
|
555
|
+
mkdir -p "$NG"
|
|
556
|
+
OUT=$(cd "$NG" && unset SOLEUR_SESSION_STATE_ROOT && bash "$SUT" init 2>"$TMP/orphan-stderr")
|
|
557
|
+
RC=$?
|
|
558
|
+
assert_rc0 "init outside a repo exits 0"
|
|
559
|
+
assert_contains "$OUT" "tally-init:" "orphan init still prints the init line"
|
|
560
|
+
assert_contains "$OUT" "HEAD" "detached/non-repo ledger keys on HEAD"
|
|
561
|
+
ORPHANED_LEDGER=$(compgen -G "$ORPHAN/counters-*/HEAD-*" || true)
|
|
562
|
+
if [[ -n "$ORPHANED_LEDGER" && "$ORPHANED_LEDGER" == *notrepo* ]]; then
|
|
563
|
+
PASS=$((PASS + 1)); echo " PASS: ledger at counters-<basename>/HEAD-<hash> ($ORPHANED_LEDGER)"
|
|
564
|
+
else
|
|
565
|
+
FAIL=$((FAIL + 1))
|
|
566
|
+
echo " FAIL: expected $ORPHAN/counters-*notrepo*/HEAD-<hash>; got '${ORPHANED_LEDGER:-nothing}'"
|
|
567
|
+
ls -la "$ORPHAN" 2>/dev/null | sed 's/^/ /'
|
|
568
|
+
fi
|
|
569
|
+
rm -rf "$ORPHAN" # this arm created it — verified absent above
|
|
570
|
+
fi
|
|
571
|
+
echo ""
|
|
572
|
+
|
|
573
|
+
# --- Test 23: --branch attribution + slug-hash isolation ----------------------
|
|
574
|
+
echo "Test 23: --branch posts to another branch's ledger; feat/x and feat-x do not share one"
|
|
575
|
+
R23=$(new_repo r23); S23="$TMP/s23"
|
|
576
|
+
FOREIGN_SLUG=$(tally_slug "feat/item-x")
|
|
577
|
+
C23F="$S23/counters/$FOREIGN_SLUG"
|
|
578
|
+
run_tally "$R23" "$S23" init --branch feat/item-x
|
|
579
|
+
assert_file_exists "$C23F" "init --branch mints the foreign-slug ledger"
|
|
580
|
+
assert_path_absent "$(cf_path "$S23")" "init --branch does not mint the local ledger"
|
|
581
|
+
run_tally "$R23" "$S23" incr agent_rounds --branch feat/item-x
|
|
582
|
+
run_tally "$R23" "$S23" show --branch feat/item-x
|
|
583
|
+
assert_contains "$OUT" "agent_rounds=1" "incr --branch lands on the foreign ledger"
|
|
584
|
+
# Slug-collision arm: feat/x and feat-x are distinct branches that sanitize
|
|
585
|
+
# identically — they must NOT share a ledger (a foreign capped latch would
|
|
586
|
+
# otherwise starve a healthy sibling).
|
|
587
|
+
X1="$S23/counters/$(tally_slug feat/x)"; X2="$S23/counters/$(tally_slug feat-x)"
|
|
588
|
+
run_tally "$R23" "$S23" init --branch feat/x
|
|
589
|
+
run_tally "$R23" "$S23" init --branch feat-x
|
|
590
|
+
if [[ "$X1" != "$X2" ]]; then
|
|
591
|
+
PASS=$((PASS + 1)); echo " PASS: feat/x and feat-x resolve distinct ledgers ($X1 vs $X2)"
|
|
592
|
+
else
|
|
593
|
+
FAIL=$((FAIL + 1)); echo " FAIL: feat/x and feat-x collide on $X1"
|
|
594
|
+
fi
|
|
595
|
+
run_tally "$R23" "$S23" init --branch '..'
|
|
596
|
+
assert_contains "$OUT" "UNKNOWN" "--branch '..' is refused (path outside counters/)"
|
|
597
|
+
run_tally "$R23" "$S23" init --branch --reset
|
|
598
|
+
assert_contains "$OUT" "UNKNOWN" "--branch consuming a flag is refused"
|
|
599
|
+
echo ""
|
|
600
|
+
|
|
601
|
+
# --- Test 24: stale+capped precedence (the >24h capped-resume dogfood) --------
|
|
602
|
+
echo "Test 24: raised-cap init on a stale capped ledger preserves counts (capped-reset beats stale)"
|
|
603
|
+
R24=$(new_repo r24); S24="$TMP/s24"; C24=$(cf_path "$S24")
|
|
604
|
+
mkdir -p "$(dirname "$C24")"
|
|
605
|
+
cat > "$C24" <<EOF
|
|
606
|
+
seats=13
|
|
607
|
+
ci_cycles=4
|
|
608
|
+
fix_rounds=1
|
|
609
|
+
agent_rounds=7
|
|
610
|
+
cap_seats=12
|
|
611
|
+
cap_ci_cycles=0
|
|
612
|
+
cap_fix_rounds=0
|
|
613
|
+
cap_agent_rounds=0
|
|
614
|
+
warned_seats=11
|
|
615
|
+
warned_ci_cycles=0
|
|
616
|
+
warned_fix_rounds=0
|
|
617
|
+
warned_agent_rounds=0
|
|
618
|
+
capped=seats
|
|
619
|
+
EOF
|
|
620
|
+
touch -d "25 hours ago" "$C24"
|
|
621
|
+
run_tally "$R24" "$S24" init --max-seats 20
|
|
622
|
+
assert_contains "$OUT" "capped-reset" "stale capped ledger + raised cap -> capped-reset, counts kept"
|
|
623
|
+
assert_eq "13" "$(cf_get "$C24" seats)" "the forensic tally survives the >24h resume"
|
|
624
|
+
assert_eq "" "$(cf_get "$C24" capped)" "the latch clears on capped-reset"
|
|
625
|
+
# Inverse: the SAME stale+capped file with a BARE init must still stale-reset —
|
|
626
|
+
# argv intent is what disambiguates resume from a fresh run. (sed BEFORE the
|
|
627
|
+
# touch: sed -i rewrites the file and refreshes mtime.)
|
|
628
|
+
sed -i 's/^capped=.*/capped=seats/; s/^seats=.*/seats=13/' "$C24"
|
|
629
|
+
touch -d "25 hours ago" "$C24"
|
|
630
|
+
run_tally "$R24" "$S24" init
|
|
631
|
+
assert_contains "$OUT" "stale-reset" "stale capped ledger + bare init -> stale-reset"
|
|
632
|
+
assert_eq "0" "$(cf_get "$C24" seats)" "bare init on a stale file zeroes counts"
|
|
633
|
+
echo ""
|
|
634
|
+
|
|
635
|
+
# --- Test 25: gate lookahead ---------------------------------------------------
|
|
636
|
+
echo "Test 25: gate <dim> <n> stops a fan-out that would overshoot, without latching"
|
|
637
|
+
R25=$(new_repo r25); S25="$TMP/s25"; C25=$(cf_path "$S25")
|
|
638
|
+
run_tally "$R25" "$S25" init --max-seats 12
|
|
639
|
+
run_tally "$R25" "$S25" incr seats 5
|
|
640
|
+
run_tally "$R25" "$S25" gate seats 8
|
|
641
|
+
assert_eq "STOP" "$OUT" "gate seats 8 STOPs: 5+8 > cap 12"
|
|
642
|
+
assert_eq "" "$(cf_get "$C25" capped)" "lookahead STOP does not latch capped"
|
|
643
|
+
run_tally "$R25" "$S25" gate seats 4
|
|
644
|
+
assert_eq "OK" "$OUT" "a smaller ask (5+4=9 < warn 10) still fits"
|
|
645
|
+
run_tally "$R25" "$S25" gate seats 5
|
|
646
|
+
assert_eq "WARN" "$OUT" "5+5=10 >= warn band (ceil 9.6 -> 10) warns on projection"
|
|
647
|
+
assert_eq "10" "$(cf_get "$C25" warned_seats)" "lookahead WARN records the projected level, not the count"
|
|
648
|
+
run_tally "$R25" "$S25" gate seats
|
|
649
|
+
assert_eq "OK" "$OUT" "n defaults to 0; count 5 alone stays under the warn band"
|
|
650
|
+
echo ""
|
|
651
|
+
|
|
652
|
+
# --- Test 26: ratchet guard + armed-cap disclosure -----------------------------
|
|
653
|
+
echo "Test 26: a lower --max-* cannot ratchet down a persisted cap without --reset"
|
|
654
|
+
R26=$(new_repo r26); S26="$TMP/s26"; C26=$(cf_path "$S26")
|
|
655
|
+
run_tally "$R26" "$S26" init --max-seats 20
|
|
656
|
+
assert_contains "$OUT" "armed: cap:seats=20" "init discloses armed caps"
|
|
657
|
+
run_tally "$R26" "$S26" init --max-seats 10
|
|
658
|
+
assert_contains "$OUT" "cap-kept: seats=20" "lowering a persisted cap surfaces cap-kept:<dim>=<kept-cap>"
|
|
659
|
+
assert_eq "20" "$(cf_get "$C26" cap_seats)" "the persisted cap is not ratcheted down"
|
|
660
|
+
run_tally "$R26" "$S26" init --reset --max-seats 10
|
|
661
|
+
assert_eq "10" "$(cf_get "$C26" cap_seats)" "--reset + new cap applies the lower budget"
|
|
662
|
+
run_tally "$R26" "$S26" init --max-seats 30
|
|
663
|
+
assert_eq "30" "$(cf_get "$C26" cap_seats)" "raising a cap always applies"
|
|
664
|
+
echo ""
|
|
665
|
+
|
|
666
|
+
# --- Test 27: corrupt-ledger validation ----------------------------------------
|
|
667
|
+
echo "Test 27: corrupt ledgers report unreadable/repaired, never the zero state"
|
|
668
|
+
R27=$(new_repo r27); S27="$TMP/s27"; C27=$(cf_path "$S27")
|
|
669
|
+
mkdir -p "$(dirname "$C27")"
|
|
670
|
+
for CORRUPT in 'garbage-line' 'seats=abc' 'cap_seats=5x' 'warned_seats=zzz' 'capped=nosuchdim' 'seats=99999999999999999999'; do
|
|
671
|
+
if [[ "$CORRUPT" == "garbage-line" ]]; then
|
|
672
|
+
printf 'not a ledger\n' > "$C27"
|
|
673
|
+
else
|
|
674
|
+
printf 'seats=3\nci_cycles=0\nfix_rounds=0\nagent_rounds=0\ncap_seats=0\ncap_ci_cycles=0\ncap_fix_rounds=0\ncap_agent_rounds=0\nwarned_seats=0\nwarned_ci_cycles=0\nwarned_fix_rounds=0\nwarned_agent_rounds=0\ncapped=\n' > "$C27"
|
|
675
|
+
case "$CORRUPT" in
|
|
676
|
+
seats=abc) sed -i 's/^seats=3/seats=abc/' "$C27" ;;
|
|
677
|
+
cap_seats=5x) sed -i 's/^cap_seats=0/cap_seats=5x/' "$C27" ;;
|
|
678
|
+
warned_seats=zzz) sed -i 's/^warned_seats=0/warned_seats=zzz/' "$C27" ;;
|
|
679
|
+
capped=nosuchdim) sed -i 's/^capped=$/capped=nosuchdim/' "$C27" ;;
|
|
680
|
+
seats=99999999999999999999) sed -i 's/^seats=3/seats=99999999999999999999/' "$C27" ;; # 20 digits — mod-2^64 wrap territory
|
|
681
|
+
esac
|
|
682
|
+
fi
|
|
683
|
+
run_tally "$R27" "$S27" show
|
|
684
|
+
assert_eq "UNKNOWN" "$OUT" "show on '$CORRUPT' -> UNKNOWN"
|
|
685
|
+
assert_contains "$ERR" "reason=unreadable" "show on '$CORRUPT' -> reason=unreadable"
|
|
686
|
+
run_tally "$R27" "$S27" gate seats
|
|
687
|
+
assert_eq "UNKNOWN" "$OUT" "gate on '$CORRUPT' -> UNKNOWN"
|
|
688
|
+
done
|
|
689
|
+
# init on the corrupt file: fail-open repair, never misreported `continued`.
|
|
690
|
+
printf 'corrupt bytes\n' > "$C27"
|
|
691
|
+
run_tally "$R27" "$S27" init
|
|
692
|
+
assert_contains "$OUT" "repaired" "init on a corrupt ledger reports repaired"
|
|
693
|
+
assert_contains "$ERR" "reason=unreadable" "repaired emits the unreadable marker"
|
|
694
|
+
assert_eq "0" "$(cf_get "$C27" seats)" "repaired ledger starts clean"
|
|
695
|
+
echo ""
|
|
696
|
+
|
|
697
|
+
# --- Test 28: flag-shape edge cases ---------------------------------------------
|
|
698
|
+
echo "Test 28: --max-ci_cycles alias, overflow reject, xtrace refusal, kill-switch"
|
|
699
|
+
R28=$(new_repo r28); S28="$TMP/s28"; C28=$(cf_path "$S28")
|
|
700
|
+
run_tally "$R28" "$S28" init --max-ci_cycles 8
|
|
701
|
+
assert_eq "8" "$(cf_get "$C28" cap_ci_cycles)" "--max-ci_cycles aliases --max-ci-cycles"
|
|
702
|
+
run_tally "$R28" "$S28" init --max-seats 99999999999999999999
|
|
703
|
+
assert_contains "$ERR" "bad-flag" "a cap that would wrap mod-2^64 is rejected"
|
|
704
|
+
assert_eq "0" "$(cf_get "$C28" cap_seats)" "wrapped cap never persisted"
|
|
705
|
+
# xtrace refusal: the linter-mandated arm — `bash -x` prints expanded values.
|
|
706
|
+
OUT=$(cd "$R28" && SOLEUR_SESSION_STATE_ROOT="$S28" bash -x "$SUT" selfcheck 2>"$TMP/x-err"); RC=$?
|
|
707
|
+
if (( RC == 78 )) && grep -q "refusing to run under xtrace" "$TMP/x-err"; then
|
|
708
|
+
PASS=$((PASS + 1)); echo " PASS: bash -x refuses with exit 78"
|
|
709
|
+
else
|
|
710
|
+
FAIL=$((FAIL + 1)); echo " FAIL: xtrace refusal (rc=$RC, err=$(head -1 "$TMP/x-err"))"
|
|
711
|
+
fi
|
|
712
|
+
# Kill-switch arm: an exported SOLEUR_DISABLE_SESSION_STATE disables the RMW —
|
|
713
|
+
# every mutating verb must UNKNOWN, never write the ledger.
|
|
714
|
+
OUT=$(cd "$R28" && SOLEUR_DISABLE_SESSION_STATE=1 SOLEUR_SESSION_STATE_ROOT="$S28" bash "$SUT" gate ci_cycles 2>/dev/null); RC=$?
|
|
715
|
+
assert_eq "UNKNOWN" "$OUT" "kill-switch exports -> gate UNKNOWN"
|
|
716
|
+
OUT=$(cd "$R28" && SOLEUR_DISABLE_SESSION_STATE=1 SOLEUR_SESSION_STATE_ROOT="$S28" bash "$SUT" incr seats 2>/dev/null)
|
|
717
|
+
assert_eq "UNKNOWN" "$OUT" "kill-switch exports -> incr UNKNOWN"
|
|
718
|
+
OUT=$(cd "$R28" && SOLEUR_DISABLE_SESSION_STATE=1 SOLEUR_SESSION_STATE_ROOT="$S28" bash "$SUT" init 2>/dev/null)
|
|
719
|
+
assert_eq "UNKNOWN" "$OUT" "kill-switch exports -> init UNKNOWN"
|
|
720
|
+
assert_eq "8" "$(cf_get "$C28" cap_ci_cycles)" "kill-switch writes nothing (cap unchanged)"
|
|
721
|
+
echo ""
|
|
722
|
+
|
|
723
|
+
# --- Test 29: gate refreshes ledger mtime --------------------------------------
|
|
724
|
+
# A quiet-but-live pipeline (polling through gate, no writes) must not later
|
|
725
|
+
# stale-reset — gate's touch is the liveness signal.
|
|
726
|
+
echo "Test 29: a gate read refreshes ledger mtime (no self-zero on quiet pipelines)"
|
|
727
|
+
R29=$(new_repo r29); S29="$TMP/s29"; C29=$(cf_path "$S29")
|
|
728
|
+
run_tally "$R29" "$S29" init --max-seats 20
|
|
729
|
+
run_tally "$R29" "$S29" incr seats 5
|
|
730
|
+
touch -d "25 hours ago" "$C29"
|
|
731
|
+
run_tally "$R29" "$S29" gate seats # read + touch — now fresh again
|
|
732
|
+
run_tally "$R29" "$S29" init
|
|
733
|
+
assert_contains "$OUT" "continued" "post-gate init continues (mtime refreshed), not stale-reset"
|
|
734
|
+
assert_eq "5" "$(cf_get "$C29" seats)" "counts survive the gate-touched init"
|
|
735
|
+
echo ""
|
|
736
|
+
|
|
737
|
+
# --- Summary -------------------------------------------------------------------
|
|
738
|
+
# Anti-vacuity floor: ~165 assertions execute on a full run (flock and orphan
|
|
739
|
+
# arms may each skip ~4-5 on hosts lacking flock or with a live orphan root).
|
|
740
|
+
print_results 90
|