session-orchestrator 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +29 -0
- package/.claude-plugin/plugin.json +18 -0
- package/.codex-plugin/agents/explorer.toml +14 -0
- package/.codex-plugin/agents/session-reviewer.toml +23 -0
- package/.codex-plugin/agents/wave-worker.toml +15 -0
- package/.codex-plugin/config.toml +20 -0
- package/.codex-plugin/plugin.json +37 -0
- package/.cursor/rules/000-session-orchestrator.mdc +73 -0
- package/.cursor/rules/010-session-workflow.mdc +170 -0
- package/.cursor/rules/020-quality-gates.mdc +128 -0
- package/.cursor/rules/030-wave-execution.mdc +216 -0
- package/.cursor/rules/040-discovery.mdc +242 -0
- package/.cursor/rules/050-plan.mdc +235 -0
- package/.cursor/rules/060-evolve.mdc +232 -0
- package/.cursor/rules/070-gitlab-ops.mdc +246 -0
- package/.cursor/rules/080-ecosystem-health.mdc +145 -0
- package/.mcp.json +8 -0
- package/CHANGELOG.md +1544 -0
- package/LICENSE +21 -0
- package/NOTICE +64 -0
- package/README.md +242 -0
- package/SECURITY.md +90 -0
- package/agents/AGENTS.md +136 -0
- package/agents/analyst.md +99 -0
- package/agents/architect-reviewer.md +93 -0
- package/agents/code-implementer.md +106 -0
- package/agents/db-specialist.md +104 -0
- package/agents/dialectic-deriver.md +139 -0
- package/agents/docs-writer.md +113 -0
- package/agents/eval-judge.md +146 -0
- package/agents/memory-proposal-collector.md +297 -0
- package/agents/qa-strategist.md +102 -0
- package/agents/schemas/analyst.schema.json +46 -0
- package/agents/schemas/architect-reviewer.schema.json +50 -0
- package/agents/schemas/code-implementer.schema.json +61 -0
- package/agents/schemas/db-specialist.schema.json +80 -0
- package/agents/schemas/docs-writer.schema.json +56 -0
- package/agents/schemas/persona-panel-sidecar.schema.json +245 -0
- package/agents/schemas/qa-strategist.schema.json +46 -0
- package/agents/schemas/security-reviewer.schema.json +86 -0
- package/agents/schemas/session-reviewer.schema.json +69 -0
- package/agents/schemas/test-writer.schema.json +69 -0
- package/agents/schemas/ui-developer.schema.json +90 -0
- package/agents/schemas/ux-evaluator.schema.json +51 -0
- package/agents/security-reviewer.md +236 -0
- package/agents/session-reviewer.md +201 -0
- package/agents/skill-applied-judge.md +122 -0
- package/agents/test-writer.md +123 -0
- package/agents/ui-developer.md +109 -0
- package/agents/ux-evaluator.md +161 -0
- package/assets/icon.svg +11 -0
- package/assets/og-card.png +0 -0
- package/assets/og-card.svg +47 -0
- package/commands/autopilot-multi.md +74 -0
- package/commands/autopilot.md +80 -0
- package/commands/bootstrap.md +56 -0
- package/commands/brainstorm.md +48 -0
- package/commands/close.md +24 -0
- package/commands/debug.md +36 -0
- package/commands/discovery.md +32 -0
- package/commands/dispatcher.md +59 -0
- package/commands/eval.md +28 -0
- package/commands/evolve.md +10 -0
- package/commands/go.md +41 -0
- package/commands/grill.md +45 -0
- package/commands/harness-audit.md +26 -0
- package/commands/memory-cleanup.md +25 -0
- package/commands/persona-panel.md +121 -0
- package/commands/plan.md +15 -0
- package/commands/portfolio.md +97 -0
- package/commands/reconcile.md +23 -0
- package/commands/repo-audit.md +24 -0
- package/commands/session.md +30 -0
- package/commands/spinout.md +15 -0
- package/commands/sunset-review.md +27 -0
- package/commands/templates-ack.md +96 -0
- package/commands/test.md +97 -0
- package/docs/README.md +105 -0
- package/docs/USER-GUIDE.md +1403 -0
- package/docs/ci-setup.md +81 -0
- package/docs/codex-setup.md +142 -0
- package/docs/components.md +74 -0
- package/docs/cursor-setup.md +104 -0
- package/docs/events-schema.md +81 -0
- package/docs/migration-v3.md +148 -0
- package/docs/owner-config-schema.md +154 -0
- package/docs/persona-panel.md +433 -0
- package/docs/pi-setup.md +115 -0
- package/docs/plugin-architecture-v3.md +296 -0
- package/docs/pm-skills-marketplace.md +114 -0
- package/docs/policy-cache-validation-2026-04-28.md +118 -0
- package/docs/rule-authoring.md +316 -0
- package/docs/session-config-reference.md +1439 -0
- package/docs/session-config-template.md +961 -0
- package/docs/vault-docs-architecture.md +297 -0
- package/hooks/_lib/lock-bootstrap.mjs +272 -0
- package/hooks/_lib/lock-reconcile.mjs +93 -0
- package/hooks/_lib/profile-gate.mjs +95 -0
- package/hooks/_lib/transcript-history.mjs +211 -0
- package/hooks/agent-teams-h3-test.sh +362 -0
- package/hooks/config-protection.mjs +0 -0
- package/hooks/cwd-change-restore.mjs +131 -0
- package/hooks/enforce-commands.mjs +179 -0
- package/hooks/enforce-scope.mjs +273 -0
- package/hooks/hooks-codex.json +60 -0
- package/hooks/hooks-cursor.json +15 -0
- package/hooks/hooks-pi.json +115 -0
- package/hooks/hooks.json +215 -0
- package/hooks/loop-guard.mjs +260 -0
- package/hooks/on-session-end.mjs +217 -0
- package/hooks/on-session-start.mjs +660 -0
- package/hooks/on-stop.mjs +294 -0
- package/hooks/operator-steer.mjs +64 -0
- package/hooks/post-edit-validate.mjs +225 -0
- package/hooks/post-subagent-discovery-validator.mjs +398 -0
- package/hooks/post-tool-batch-wave-signal.mjs +328 -0
- package/hooks/post-tool-failure-corrective-context.mjs +248 -0
- package/hooks/post-tooluse-frontend-slop.mjs +184 -0
- package/hooks/pre-bash-destructive-guard.mjs +515 -0
- package/hooks/pre-bash-memory-propose-audit.mjs +206 -0
- package/hooks/pre-bash-staging-fence.mjs +223 -0
- package/hooks/pre-bash-templates-first.mjs +404 -0
- package/hooks/run-node.sh +72 -0
- package/hooks/skill-invocation-telemetry.mjs +99 -0
- package/hooks/subagent-telemetry.mjs +249 -0
- package/hooks/wave-scope-commit-guard.mjs +191 -0
- package/monitors/monitors.json +14 -0
- package/output-styles/finding-report.md +48 -0
- package/output-styles/session-report.md +53 -0
- package/output-styles/wave-summary.md +38 -0
- package/package.json +94 -0
- package/pi/extensions/session-orchestrator.ts +25 -0
- package/pi/prompts/autopilot-multi.md +12 -0
- package/pi/prompts/autopilot.md +12 -0
- package/pi/prompts/bootstrap.md +12 -0
- package/pi/prompts/brainstorm.md +12 -0
- package/pi/prompts/close.md +11 -0
- package/pi/prompts/debug.md +12 -0
- package/pi/prompts/discovery.md +12 -0
- package/pi/prompts/dispatcher.md +12 -0
- package/pi/prompts/eval.md +12 -0
- package/pi/prompts/evolve.md +12 -0
- package/pi/prompts/go.md +12 -0
- package/pi/prompts/grill.md +12 -0
- package/pi/prompts/harness-audit.md +12 -0
- package/pi/prompts/memory-cleanup.md +12 -0
- package/pi/prompts/persona-panel.md +12 -0
- package/pi/prompts/plan.md +12 -0
- package/pi/prompts/portfolio.md +12 -0
- package/pi/prompts/reconcile.md +12 -0
- package/pi/prompts/repo-audit.md +12 -0
- package/pi/prompts/session.md +12 -0
- package/pi/prompts/spinout.md +12 -0
- package/pi/prompts/sunset-review.md +12 -0
- package/pi/prompts/templates-ack.md +12 -0
- package/pi/prompts/test.md +12 -0
- package/rules/_index.md +51 -0
- package/rules/always-on/commit-discipline.md +26 -0
- package/rules/always-on/npm-quality-gates.md +26 -0
- package/rules/always-on/parallel-sessions.md +43 -0
- package/rules/opt-in-domain/prompt-caching.md +270 -0
- package/rules/opt-in-stack/backend-data.md +188 -0
- package/rules/opt-in-stack/backend.md +390 -0
- package/rules/opt-in-stack/frontend.md +98 -0
- package/rules/opt-in-stack/security-web.md +194 -0
- package/rules/opt-in-stack/swift.md +65 -0
- package/scripts/archive-closed-prds.mjs +416 -0
- package/scripts/autopilot-multi.mjs +802 -0
- package/scripts/autopilot.mjs +383 -0
- package/scripts/backfill-abandoned-sessions.mjs +265 -0
- package/scripts/backfill-learnings-expires.mjs +196 -0
- package/scripts/backfill-learnings.mjs +203 -0
- package/scripts/backfill-sessions.mjs +282 -0
- package/scripts/check-doc-consistency.sh +279 -0
- package/scripts/check-package-manager.mjs +445 -0
- package/scripts/ci/assert-vitest-green.mjs +267 -0
- package/scripts/codex-install.mjs +435 -0
- package/scripts/compute-grounding-injection.sh +186 -0
- package/scripts/cursor-install.mjs +113 -0
- package/scripts/dialectic-deriver.mjs +573 -0
- package/scripts/emit-event.mjs +160 -0
- package/scripts/emit-session.mjs +212 -0
- package/scripts/eval-session.mjs +262 -0
- package/scripts/export-hw-learnings.mjs +437 -0
- package/scripts/gc-stale-worktrees.mjs +666 -0
- package/scripts/generate-pi-prompts.mjs +127 -0
- package/scripts/harness-audit.mjs +287 -0
- package/scripts/lib/agent-frontmatter.mjs +266 -0
- package/scripts/lib/agent-output-schema.mjs +166 -0
- package/scripts/lib/agent-status.mjs +303 -0
- package/scripts/lib/ajv-loader.mjs +34 -0
- package/scripts/lib/auto-dialectic.mjs +382 -0
- package/scripts/lib/auto-dream.mjs +471 -0
- package/scripts/lib/autonomy/suitability.mjs +212 -0
- package/scripts/lib/autopilot/dep-graph.mjs +417 -0
- package/scripts/lib/autopilot/durable-telemetry.mjs +121 -0
- package/scripts/lib/autopilot/flags.mjs +104 -0
- package/scripts/lib/autopilot/kill-switches.mjs +174 -0
- package/scripts/lib/autopilot/loop.mjs +320 -0
- package/scripts/lib/autopilot/mr-draft.mjs +520 -0
- package/scripts/lib/autopilot/multi-killswitch.mjs +184 -0
- package/scripts/lib/autopilot/recent-runs.mjs +106 -0
- package/scripts/lib/autopilot/stall-sampler.mjs +97 -0
- package/scripts/lib/autopilot/telemetry.mjs +224 -0
- package/scripts/lib/autopilot/worktree-pipeline.mjs +605 -0
- package/scripts/lib/autopilot-telemetry.mjs +11 -0
- package/scripts/lib/autopilot.mjs +39 -0
- package/scripts/lib/backlog-scan.mjs +179 -0
- package/scripts/lib/bootstrap-lock-freshness.mjs +260 -0
- package/scripts/lib/bootstrap-lock-refresh.mjs +186 -0
- package/scripts/lib/build-live-signals.mjs +150 -0
- package/scripts/lib/ci-status-banner.mjs +425 -0
- package/scripts/lib/claude-md-budget-lint.mjs +246 -0
- package/scripts/lib/cli-flags.mjs +158 -0
- package/scripts/lib/codex/plugin-contract.mjs +610 -0
- package/scripts/lib/cold-start-detector.mjs +240 -0
- package/scripts/lib/command-blocker.mjs +458 -0
- package/scripts/lib/common.mjs +333 -0
- package/scripts/lib/config/auto-dream.mjs +77 -0
- package/scripts/lib/config/block-header.mjs +94 -0
- package/scripts/lib/config/broken-window.mjs +114 -0
- package/scripts/lib/config/coercers.mjs +248 -0
- package/scripts/lib/config/cold-start.mjs +92 -0
- package/scripts/lib/config/config-protection.mjs +120 -0
- package/scripts/lib/config/cross-repo.mjs +104 -0
- package/scripts/lib/config/custom-phases.mjs +213 -0
- package/scripts/lib/config/dialectic.mjs +92 -0
- package/scripts/lib/config/discovery-validator.mjs +75 -0
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +240 -0
- package/scripts/lib/config/dispatcher-autonomy.mjs +152 -0
- package/scripts/lib/config/docs-orchestrator.mjs +90 -0
- package/scripts/lib/config/docs-staleness.mjs +96 -0
- package/scripts/lib/config/drift-check.mjs +155 -0
- package/scripts/lib/config/eval.mjs +130 -0
- package/scripts/lib/config/events-rotation.mjs +74 -0
- package/scripts/lib/config/evolve.mjs +308 -0
- package/scripts/lib/config/frontend-slop-hook.mjs +104 -0
- package/scripts/lib/config/gitlab-portfolio.mjs +150 -0
- package/scripts/lib/config/handover-gate.mjs +106 -0
- package/scripts/lib/config/host-paths.mjs +76 -0
- package/scripts/lib/config/io.mjs +54 -0
- package/scripts/lib/config/loop-guard.mjs +117 -0
- package/scripts/lib/config/memory.mjs +150 -0
- package/scripts/lib/config/persona-gate-wave.mjs +258 -0
- package/scripts/lib/config/reconcile.mjs +205 -0
- package/scripts/lib/config/section-extractor.mjs +100 -0
- package/scripts/lib/config/skill-evolution.mjs +112 -0
- package/scripts/lib/config/slopcheck.mjs +99 -0
- package/scripts/lib/config/state-md-lock.mjs +83 -0
- package/scripts/lib/config/templates-first.mjs +94 -0
- package/scripts/lib/config/test.mjs +113 -0
- package/scripts/lib/config/vault-integration.mjs +201 -0
- package/scripts/lib/config/vault-mirror-quality.mjs +99 -0
- package/scripts/lib/config/vault-staleness.mjs +84 -0
- package/scripts/lib/config/vault-sync.mjs +96 -0
- package/scripts/lib/config/verification-auto-fix.mjs +84 -0
- package/scripts/lib/config/wave-reviewers.mjs +133 -0
- package/scripts/lib/config-schema.mjs +345 -0
- package/scripts/lib/config.mjs +474 -0
- package/scripts/lib/convergence-monitor.mjs +389 -0
- package/scripts/lib/coordinator-snapshot.mjs +371 -0
- package/scripts/lib/crypto-digest-utils.mjs +91 -0
- package/scripts/lib/discovery/helpers.mjs +127 -0
- package/scripts/lib/discovery/triage-state.mjs +279 -0
- package/scripts/lib/dispatcher/cli.mjs +257 -0
- package/scripts/lib/dispatcher/enumerate.mjs +243 -0
- package/scripts/lib/dispatcher/rank.mjs +363 -0
- package/scripts/lib/ecosystem-health.mjs +224 -0
- package/scripts/lib/ecosystem-wizard/ci-detector.mjs +18 -0
- package/scripts/lib/ecosystem-wizard/config-parser.mjs +54 -0
- package/scripts/lib/ecosystem-wizard/config-writer.mjs +287 -0
- package/scripts/lib/ecosystem-wizard/package-manager-detector.mjs +42 -0
- package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +246 -0
- package/scripts/lib/ecosystem-wizard.mjs +48 -0
- package/scripts/lib/env-check.mjs +89 -0
- package/scripts/lib/eval/engine.mjs +605 -0
- package/scripts/lib/eval/judge.mjs +433 -0
- package/scripts/lib/eval/report.mjs +367 -0
- package/scripts/lib/eval/schema.mjs +618 -0
- package/scripts/lib/eval/session-resolve.mjs +137 -0
- package/scripts/lib/eval/sink.mjs +77 -0
- package/scripts/lib/events-rotation.mjs +86 -0
- package/scripts/lib/events-schema.mjs +81 -0
- package/scripts/lib/events.mjs +80 -0
- package/scripts/lib/evolve/autonomy-verdict.mjs +461 -0
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +293 -0
- package/scripts/lib/exclusivity-matrix.mjs +68 -0
- package/scripts/lib/fetch-baseline.mjs +311 -0
- package/scripts/lib/file-lock.mjs +512 -0
- package/scripts/lib/frontend-detect/detect.mjs +138 -0
- package/scripts/lib/frontend-detect/rules.mjs +295 -0
- package/scripts/lib/frontmatter-guard.mjs +241 -0
- package/scripts/lib/gates/echo-stub-detect.mjs +39 -0
- package/scripts/lib/gates/gate-baseline.mjs +42 -0
- package/scripts/lib/gates/gate-full.mjs +85 -0
- package/scripts/lib/gates/gate-helpers.mjs +231 -0
- package/scripts/lib/gates/gate-incremental.mjs +76 -0
- package/scripts/lib/gates/gate-per-file.mjs +55 -0
- package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +447 -0
- package/scripts/lib/gitlab-portfolio/aggregator.mjs +383 -0
- package/scripts/lib/gitlab-portfolio/cli.mjs +428 -0
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +289 -0
- package/scripts/lib/gitlab-portfolio/vcs-detect.mjs +182 -0
- package/scripts/lib/handover-gate.mjs +222 -0
- package/scripts/lib/hardening.mjs +43 -0
- package/scripts/lib/hardware-pattern-detector.mjs +238 -0
- package/scripts/lib/harness-audit/categories/category1.mjs +123 -0
- package/scripts/lib/harness-audit/categories/category2.mjs +145 -0
- package/scripts/lib/harness-audit/categories/category3.mjs +143 -0
- package/scripts/lib/harness-audit/categories/category4.mjs +202 -0
- package/scripts/lib/harness-audit/categories/category5.mjs +152 -0
- package/scripts/lib/harness-audit/categories/category6.mjs +211 -0
- package/scripts/lib/harness-audit/categories/category7.mjs +125 -0
- package/scripts/lib/harness-audit/categories/category8.mjs +328 -0
- package/scripts/lib/harness-audit/categories/category9.mjs +294 -0
- package/scripts/lib/harness-audit/categories/helpers.mjs +165 -0
- package/scripts/lib/harness-audit/categories.mjs +19 -0
- package/scripts/lib/historical-guard.mjs +15 -0
- package/scripts/lib/host-identity.mjs +262 -0
- package/scripts/lib/instruction-budget-guard.mjs +332 -0
- package/scripts/lib/io.mjs +304 -0
- package/scripts/lib/issue-close-strip-labels.mjs +161 -0
- package/scripts/lib/language-mappers/README.md +57 -0
- package/scripts/lib/language-mappers/index.mjs +165 -0
- package/scripts/lib/language-mappers/markdown.mjs +149 -0
- package/scripts/lib/language-mappers/python.mjs +249 -0
- package/scripts/lib/language-mappers/swift.mjs +201 -0
- package/scripts/lib/language-mappers/typescript.mjs +433 -0
- package/scripts/lib/learnings/expiry-sweep.mjs +164 -0
- package/scripts/lib/learnings/filters.mjs +43 -0
- package/scripts/lib/learnings/io.mjs +255 -0
- package/scripts/lib/learnings/schema.mjs +518 -0
- package/scripts/lib/learnings/surface.mjs +207 -0
- package/scripts/lib/learnings.mjs +42 -0
- package/scripts/lib/lock-reaper.mjs +648 -0
- package/scripts/lib/locks/index.mjs +31 -0
- package/scripts/lib/locks/lock-body.mjs +62 -0
- package/scripts/lib/locks/staging-fence-lock.mjs +267 -0
- package/scripts/lib/locks/state-md-lock.mjs +351 -0
- package/scripts/lib/loop-readiness-banner.mjs +144 -0
- package/scripts/lib/memory-banner.mjs +478 -0
- package/scripts/lib/memory-cleanup/worktree-sweep.mjs +108 -0
- package/scripts/lib/memory-cleanup-stamp.mjs +56 -0
- package/scripts/lib/memory-paths.mjs +31 -0
- package/scripts/lib/memory-proposals/collector.mjs +334 -0
- package/scripts/lib/memory-proposals/schema.mjs +289 -0
- package/scripts/lib/memory-proposals/sink.mjs +507 -0
- package/scripts/lib/memory-proposals/store.mjs +441 -0
- package/scripts/lib/mission-status-schema.mjs +114 -0
- package/scripts/lib/mode-selector/alternatives.mjs +64 -0
- package/scripts/lib/mode-selector/constants.mjs +29 -0
- package/scripts/lib/mode-selector/context-pressure.mjs +157 -0
- package/scripts/lib/mode-selector/rationale.mjs +55 -0
- package/scripts/lib/mode-selector/scoring.mjs +221 -0
- package/scripts/lib/mode-selector-accuracy.mjs +121 -0
- package/scripts/lib/mode-selector.mjs +160 -0
- package/scripts/lib/multi-provider-build/providers.mjs +64 -0
- package/scripts/lib/multi-provider-build/templating.mjs +130 -0
- package/scripts/lib/named-baseline-resolver.mjs +233 -0
- package/scripts/lib/named-vault-resolver.mjs +433 -0
- package/scripts/lib/owner-config/coerce.mjs +29 -0
- package/scripts/lib/owner-config/constants.mjs +21 -0
- package/scripts/lib/owner-config/defaults.mjs +50 -0
- package/scripts/lib/owner-config/error.mjs +19 -0
- package/scripts/lib/owner-config/index.mjs +13 -0
- package/scripts/lib/owner-config/merge.mjs +52 -0
- package/scripts/lib/owner-config/validate.mjs +259 -0
- package/scripts/lib/owner-config-banner.mjs +126 -0
- package/scripts/lib/owner-config-loader.mjs +159 -0
- package/scripts/lib/owner-config.example.yaml +72 -0
- package/scripts/lib/owner-config.mjs +28 -0
- package/scripts/lib/owner-interview.mjs +243 -0
- package/scripts/lib/owner-yaml.mjs +571 -0
- package/scripts/lib/package-manager.mjs +160 -0
- package/scripts/lib/path-utils.mjs +217 -0
- package/scripts/lib/peer-cards/merger.mjs +310 -0
- package/scripts/lib/peer-cards/reader.mjs +125 -0
- package/scripts/lib/peer-cards/schema.mjs +230 -0
- package/scripts/lib/peer-cards/staleness-banner.mjs +86 -0
- package/scripts/lib/peer-cards/writer.mjs +138 -0
- package/scripts/lib/peer-discovery.mjs +200 -0
- package/scripts/lib/persona-panel/catalog-loader.mjs +577 -0
- package/scripts/lib/persona-panel/consolidator.mjs +370 -0
- package/scripts/lib/persona-panel/persona-runner.mjs +375 -0
- package/scripts/lib/persona-panel/threshold.mjs +130 -0
- package/scripts/lib/pi-hook-bridge.mjs +328 -0
- package/scripts/lib/platform.mjs +266 -0
- package/scripts/lib/playwright-driver/runner.mjs +297 -0
- package/scripts/lib/plugin-root.mjs +210 -0
- package/scripts/lib/pre-dispatch-check.mjs +126 -0
- package/scripts/lib/product-repo-detect.mjs +121 -0
- package/scripts/lib/profiles/registry.mjs +176 -0
- package/scripts/lib/profiles/schema.mjs +209 -0
- package/scripts/lib/qg-command-drift-banner.mjs +88 -0
- package/scripts/lib/quality-gate/diagnostics.mjs +92 -0
- package/scripts/lib/quality-gate.mjs +536 -0
- package/scripts/lib/quality-gates-cache.mjs +228 -0
- package/scripts/lib/quality-gates-policy.mjs +95 -0
- package/scripts/lib/recommendations-v0.mjs +156 -0
- package/scripts/lib/reconcile/eligibility.mjs +203 -0
- package/scripts/lib/reconcile/emitter.mjs +244 -0
- package/scripts/lib/reconcile/engine.mjs +412 -0
- package/scripts/lib/reconcile/idempotency.mjs +239 -0
- package/scripts/lib/reconcile/renderer.mjs +211 -0
- package/scripts/lib/reconcile/writer.mjs +293 -0
- package/scripts/lib/reconcile-nudge-banner.mjs +284 -0
- package/scripts/lib/resource-probe/evaluate.mjs +190 -0
- package/scripts/lib/resource-probe/parsers.mjs +181 -0
- package/scripts/lib/resource-probe/probe-platform.mjs +300 -0
- package/scripts/lib/resource-probe.mjs +95 -0
- package/scripts/lib/rule-loader.mjs +552 -0
- package/scripts/lib/rules-sync.mjs +439 -0
- package/scripts/lib/scope-gate.mjs +496 -0
- package/scripts/lib/session-close-backfill.mjs +539 -0
- package/scripts/lib/session-discovery.mjs +256 -0
- package/scripts/lib/session-end/phase-skip.mjs +357 -0
- package/scripts/lib/session-end/worktree-cleanup.mjs +112 -0
- package/scripts/lib/session-id.mjs +362 -0
- package/scripts/lib/session-lock.mjs +703 -0
- package/scripts/lib/session-registry.mjs +355 -0
- package/scripts/lib/session-schema/aliases.mjs +71 -0
- package/scripts/lib/session-schema/constants.mjs +115 -0
- package/scripts/lib/session-schema/normalizer.mjs +66 -0
- package/scripts/lib/session-schema/timestamps.mjs +64 -0
- package/scripts/lib/session-schema/validator.mjs +453 -0
- package/scripts/lib/session-schema.mjs +71 -0
- package/scripts/lib/session-token-rollup.mjs +137 -0
- package/scripts/lib/sessions-staleness-banner.mjs +247 -0
- package/scripts/lib/skill-evolution/blast-radius-classifier.mjs +114 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +270 -0
- package/scripts/lib/skill-evolution/config-validation-gate.mjs +279 -0
- package/scripts/lib/skill-evolution/engine.mjs +719 -0
- package/scripts/lib/skill-evolution/idempotency.mjs +279 -0
- package/scripts/lib/skill-evolution/mr-opener.mjs +507 -0
- package/scripts/lib/skill-health/join.mjs +181 -0
- package/scripts/lib/skill-health/score.mjs +123 -0
- package/scripts/lib/skill-invocations-schema.mjs +214 -0
- package/scripts/lib/skill-judge.mjs +348 -0
- package/scripts/lib/skill-judgments-schema.mjs +264 -0
- package/scripts/lib/slopcheck.mjs +501 -0
- package/scripts/lib/soul-resolve.mjs +118 -0
- package/scripts/lib/spiral-carryover.mjs +495 -0
- package/scripts/lib/state-md/body-sections.mjs +851 -0
- package/scripts/lib/state-md/frontmatter-mutators.mjs +453 -0
- package/scripts/lib/state-md/mission-status.mjs +247 -0
- package/scripts/lib/state-md/recommendations.mjs +57 -0
- package/scripts/lib/state-md/yaml-parser.mjs +234 -0
- package/scripts/lib/state-md-peer-guard.mjs +232 -0
- package/scripts/lib/state-md.mjs +53 -0
- package/scripts/lib/subagents-schema.mjs +309 -0
- package/scripts/lib/sunset/walker.mjs +1192 -0
- package/scripts/lib/test-runner/artifact-paths.mjs +94 -0
- package/scripts/lib/test-runner/fingerprint.mjs +33 -0
- package/scripts/lib/test-runner/issue-reconcile.mjs +770 -0
- package/scripts/lib/tmux-layout/layouts.mjs +224 -0
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +100 -0
- package/scripts/lib/tmux-layout/telemetry.mjs +88 -0
- package/scripts/lib/tmux-layout/tmux-shell.mjs +82 -0
- package/scripts/lib/tmux-layout/vcs-detector.mjs +88 -0
- package/scripts/lib/validate/check-agents.mjs +457 -0
- package/scripts/lib/validate/check-codex-plugin.mjs +37 -0
- package/scripts/lib/validate/check-commands.mjs +148 -0
- package/scripts/lib/validate/check-component-paths.mjs +112 -0
- package/scripts/lib/validate/check-dead-bridge.mjs +180 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +258 -0
- package/scripts/lib/validate/check-json-files.mjs +116 -0
- package/scripts/lib/validate/check-owner-leakage.mjs +1011 -0
- package/scripts/lib/validate/check-path-utils-canary.mjs +175 -0
- package/scripts/lib/validate/check-peekaboo-driver-canary.mjs +201 -0
- package/scripts/lib/validate/check-pi-package.mjs +110 -0
- package/scripts/lib/validate/check-pi-prompts.mjs +43 -0
- package/scripts/lib/validate/check-playwright-mcp-canary.mjs +154 -0
- package/scripts/lib/validate/check-plugin-json.mjs +96 -0
- package/scripts/lib/validate/check-plugin-monitors.mjs +206 -0
- package/scripts/lib/validate/check-plugin-schema.mjs +137 -0
- package/scripts/lib/validate/check-rules.mjs +143 -0
- package/scripts/lib/validate/check-session-plan-routing.mjs +154 -0
- package/scripts/lib/validate/check-test-fixture-shapes.mjs +280 -0
- package/scripts/lib/validate/check-unicode-safety.mjs +533 -0
- package/scripts/lib/validate/confidential-names.mjs +169 -0
- package/scripts/lib/validate/dead-bridge-corpus.mjs +141 -0
- package/scripts/lib/validate/dead-bridge-detectors.mjs +568 -0
- package/scripts/lib/validate/tier-inference.mjs +100 -0
- package/scripts/lib/validate-vendored-rules.mjs +519 -0
- package/scripts/lib/vault-archive.mjs +404 -0
- package/scripts/lib/vault-backfill/glab.mjs +164 -0
- package/scripts/lib/vault-backfill/manifest.mjs +75 -0
- package/scripts/lib/vault-backfill/template.mjs +130 -0
- package/scripts/lib/vault-consolidate-fs.mjs +331 -0
- package/scripts/lib/vault-migration-rules.mjs +155 -0
- package/scripts/lib/vault-mirror/auto-commit.mjs +203 -0
- package/scripts/lib/vault-mirror/namespace.mjs +152 -0
- package/scripts/lib/vault-mirror/process.mjs +567 -0
- package/scripts/lib/vault-mirror/pseudonym-map.mjs +164 -0
- package/scripts/lib/vault-mirror/render-learnings.mjs +201 -0
- package/scripts/lib/vault-mirror/render-sessions.mjs +367 -0
- package/scripts/lib/vault-mirror/render.mjs +8 -0
- package/scripts/lib/vault-mirror/utils.mjs +217 -0
- package/scripts/lib/vault-relocation-rules.mjs +555 -0
- package/scripts/lib/vault-repo-backfill.mjs +235 -0
- package/scripts/lib/vault-staleness-banner.mjs +142 -0
- package/scripts/lib/vault-status/board-writer.mjs +769 -0
- package/scripts/lib/vault-status/narrative-mirror.mjs +544 -0
- package/scripts/lib/vault-sync-baseline.mjs +152 -0
- package/scripts/lib/wave-context.mjs +29 -0
- package/scripts/lib/wave-executor/pool.mjs +248 -0
- package/scripts/lib/wave-resource-gate.mjs +204 -0
- package/scripts/lib/wave-sizing.mjs +75 -0
- package/scripts/lib/webhook-url.mjs +105 -0
- package/scripts/lib/workspace.mjs +198 -0
- package/scripts/lib/worktree/constants.mjs +35 -0
- package/scripts/lib/worktree/index.mjs +17 -0
- package/scripts/lib/worktree/lifecycle.mjs +287 -0
- package/scripts/lib/worktree/listing.mjs +118 -0
- package/scripts/lib/worktree/meta.mjs +64 -0
- package/scripts/lib/worktree-freshness.mjs +313 -0
- package/scripts/lib/worktree.mjs +15 -0
- package/scripts/lifecycle-sim-v6.mjs +347 -0
- package/scripts/lock-reaper.mjs +185 -0
- package/scripts/mcp-server.sh +241 -0
- package/scripts/measure-policy-cache-effectiveness.mjs +427 -0
- package/scripts/memory-propose.mjs +464 -0
- package/scripts/migrate-cold-start-seed.mjs +404 -0
- package/scripts/migrate-learnings-jsonl.mjs +189 -0
- package/scripts/migrate-legacy-learnings.sh +61 -0
- package/scripts/migrate-sessions-jsonl.mjs +448 -0
- package/scripts/migrate-subagents-jsonl.mjs +196 -0
- package/scripts/migrate-vault-paths.mjs +796 -0
- package/scripts/parse-config.mjs +149 -0
- package/scripts/pi-install.mjs +117 -0
- package/scripts/print-applicable-rules.mjs +247 -0
- package/scripts/promote-vault-strict.mjs +496 -0
- package/scripts/relocate-vault-corpus.mjs +1178 -0
- package/scripts/run-migrate-v2-cross-repo.mjs +385 -0
- package/scripts/run-quality-gate.mjs +216 -0
- package/scripts/spikes/h3-agent-teams/preflight.sh +53 -0
- package/scripts/spikes/h3-agent-teams/run-h3.sh +112 -0
- package/scripts/spikes/h3-agent-teams/setup.sh +137 -0
- package/scripts/spikes/h3-agent-teams/toggle.sh +38 -0
- package/scripts/sweep-expired-learnings.mjs +135 -0
- package/scripts/sync-vault-schema.mjs +376 -0
- package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +8 -0
- package/scripts/tmux-layout.mjs +245 -0
- package/scripts/token-audit.sh +191 -0
- package/scripts/typecheck.mjs +42 -0
- package/scripts/upload-social-preview.mjs +316 -0
- package/scripts/validate-config.mjs +46 -0
- package/scripts/validate-plugin-manifests.mjs +163 -0
- package/scripts/validate-plugin.mjs +264 -0
- package/scripts/validate-wave-scope.mjs +289 -0
- package/scripts/vault-backfill.mjs +404 -0
- package/scripts/vault-consolidate.mjs +596 -0
- package/scripts/vault-integration-watcher.mjs +394 -0
- package/scripts/vault-mirror.mjs +430 -0
- package/skills/_shared/bootstrap-gate.md +111 -0
- package/skills/_shared/config-reading.md +226 -0
- package/skills/_shared/instruction-file-resolution.md +79 -0
- package/skills/_shared/model-selection.md +64 -0
- package/skills/_shared/monitor-patterns.md +300 -0
- package/skills/_shared/parallel-aware-auq.md +121 -0
- package/skills/_shared/parallel-aware-preamble.md +185 -0
- package/skills/_shared/platform-tools.md +96 -0
- package/skills/_shared/state-ownership.md +221 -0
- package/skills/architecture/DEEPENING.md +37 -0
- package/skills/architecture/INTERFACE-DESIGN.md +44 -0
- package/skills/architecture/LANGUAGE.md +53 -0
- package/skills/architecture/SKILL.md +92 -0
- package/skills/autopilot/SKILL.md +419 -0
- package/skills/bootstrap/SKILL.md +592 -0
- package/skills/bootstrap/STATE.md.template +24 -0
- package/skills/bootstrap/_shared-template.md +243 -0
- package/skills/bootstrap/deep-template.md +659 -0
- package/skills/bootstrap/fast-template.md +251 -0
- package/skills/bootstrap/intensity-heuristic.md +80 -0
- package/skills/bootstrap/public-fallback.md +342 -0
- package/skills/bootstrap/standard-template.md +736 -0
- package/skills/bootstrap/templates/agents/project-code-review.md +18 -0
- package/skills/bootstrap/templates/agents/project-discovery.md +18 -0
- package/skills/bootstrap/templates/agents/project-quality-gate.md +18 -0
- package/skills/brainstorm/SKILL.md +268 -0
- package/skills/brainstorm/soul.md +49 -0
- package/skills/claude-md-drift-check/SKILL.md +186 -0
- package/skills/claude-md-drift-check/checker.mjs +1380 -0
- package/skills/claude-md-drift-check/checker.sh +37 -0
- package/skills/claude-md-drift-check/package.json +16 -0
- package/skills/convergence-monitoring/README.md +39 -0
- package/skills/convergence-monitoring/SIGNALS.md +246 -0
- package/skills/convergence-monitoring/SKILL.md +285 -0
- package/skills/daily/SKILL.md +222 -0
- package/skills/daily/generate.sh +92 -0
- package/skills/daily/templates/daily.md.tpl +36 -0
- package/skills/debug/SKILL.md +188 -0
- package/skills/debug/soul.md +35 -0
- package/skills/discovery/SKILL.md +567 -0
- package/skills/discovery/issue-templates.md +237 -0
- package/skills/discovery/probes/docs-staleness.mjs +195 -0
- package/skills/discovery/probes/frontend-slop.mjs +186 -0
- package/skills/discovery/probes/ssot-code-diff.mjs +310 -0
- package/skills/discovery/probes/supply-chain-slopcheck.mjs +440 -0
- package/skills/discovery/probes/vault-narrative-staleness.mjs +355 -0
- package/skills/discovery/probes/vault-staleness.mjs +272 -0
- package/skills/discovery/probes-arch.md +252 -0
- package/skills/discovery/probes-audit.md +95 -0
- package/skills/discovery/probes-code.md +329 -0
- package/skills/discovery/probes-docs.md +76 -0
- package/skills/discovery/probes-feature.md +150 -0
- package/skills/discovery/probes-infra.md +138 -0
- package/skills/discovery/probes-intro.md +25 -0
- package/skills/discovery/probes-session.md +495 -0
- package/skills/discovery/probes-supply-chain.md +94 -0
- package/skills/discovery/probes-ui.md +147 -0
- package/skills/discovery/probes-vault.md +64 -0
- package/skills/discovery/slop-patterns.md +115 -0
- package/skills/dispatcher/SKILL.md +173 -0
- package/skills/docs-orchestrator/SKILL.md +362 -0
- package/skills/docs-orchestrator/audience-mapping.md +140 -0
- package/skills/domain-model/ADR-FORMAT.md +47 -0
- package/skills/domain-model/CONTEXT-FORMAT.md +77 -0
- package/skills/domain-model/SKILL.md +85 -0
- package/skills/ecosystem-health/SKILL.md +119 -0
- package/skills/ecosystem-health/wizard.md +193 -0
- package/skills/eval/SKILL.md +293 -0
- package/skills/eval/rubric-v1.md +218 -0
- package/skills/evolve/SKILL.md +546 -0
- package/skills/frontmatter-guard/SKILL.md +126 -0
- package/skills/gitlab-ops/SKILL.md +368 -0
- package/skills/gitlab-portfolio/SKILL.md +196 -0
- package/skills/grill/SKILL.md +185 -0
- package/skills/grill/soul.md +55 -0
- package/skills/hook-development/SKILL.md +413 -0
- package/skills/mcp-builder/SKILL.md +260 -0
- package/skills/memory-cleanup/SKILL.md +310 -0
- package/skills/mode-selector/SKILL.md +226 -0
- package/skills/peekaboo-driver/SKILL.md +237 -0
- package/skills/peekaboo-driver/soul.md +32 -0
- package/skills/persona-panel/SKILL.md +365 -0
- package/skills/persona-panel/persona-format.md +205 -0
- package/skills/persona-panel/presets/designer-lens.md +87 -0
- package/skills/persona-panel/presets/engineer-lens.md +88 -0
- package/skills/persona-panel/presets/pm-lens.md +86 -0
- package/skills/plan/SKILL.md +496 -0
- package/skills/plan/mode-feature.md +141 -0
- package/skills/plan/mode-new.md +297 -0
- package/skills/plan/mode-retro.md +271 -0
- package/skills/plan/prd-feature-template.md +132 -0
- package/skills/plan/prd-full-template.md +151 -0
- package/skills/plan/prd-reviewer-prompt.md +103 -0
- package/skills/plan/retro-template.md +75 -0
- package/skills/plan/soul.md +62 -0
- package/skills/playwright-driver/SKILL.md +226 -0
- package/skills/playwright-driver/soul.md +30 -0
- package/skills/quality-gates/SKILL.md +212 -0
- package/skills/reconcile/SKILL.md +324 -0
- package/skills/repo-audit/SKILL.md +272 -0
- package/skills/session-end/SKILL.md +1044 -0
- package/skills/session-end/discovery-scan.md +37 -0
- package/skills/session-end/drift-operations.md +97 -0
- package/skills/session-end/learning-patterns.md +78 -0
- package/skills/session-end/metrics-collection.md +175 -0
- package/skills/session-end/phase-3-2-docs-verification.md +148 -0
- package/skills/session-end/phase-3-6-tail.md +344 -0
- package/skills/session-end/phase-3-7a-recommendations.md +86 -0
- package/skills/session-end/plan-verification.md +288 -0
- package/skills/session-end/session-metrics-write.md +223 -0
- package/skills/session-end/vault-operations.md +50 -0
- package/skills/session-end/verification-checklist.md +20 -0
- package/skills/session-plan/SKILL.md +554 -0
- package/skills/session-plan/wave-template.md +37 -0
- package/skills/session-start/SKILL.md +1043 -0
- package/skills/session-start/phase-2-5-docs-planning.md +119 -0
- package/skills/session-start/phase-4-5-resource-health.md +49 -0
- package/skills/session-start/phase-7-1-premise-check.md +47 -0
- package/skills/session-start/phase-7-5-mode-selector.md +237 -0
- package/skills/session-start/phase-8-5-express-path.md +61 -0
- package/skills/session-start/presentation-format.md +81 -0
- package/skills/session-start/soul.md +57 -0
- package/skills/skill-creator/SKILL.md +168 -0
- package/skills/spinout/SKILL.md +76 -0
- package/skills/sunset-review/SKILL.md +96 -0
- package/skills/test-runner/SKILL.md +362 -0
- package/skills/test-runner/rubric-v1.md +388 -0
- package/skills/test-runner/soul.md +46 -0
- package/skills/tmux-layout/SKILL.md +104 -0
- package/skills/ubiquitous-language/SKILL.md +97 -0
- package/skills/using-orchestrator/SKILL.md +144 -0
- package/skills/vault-mirror/SKILL.md +234 -0
- package/skills/vault-sync/SKILL.md +319 -0
- package/skills/vault-sync/package-lock.json +40 -0
- package/skills/vault-sync/package.json +11 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +8 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/live-note.md +8 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/bad-type.md +8 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +10 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +11 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/has-dangling.md +9 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +8 -0
- package/skills/vault-sync/tests/fixtures/empty-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/missing-id.md +7 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +9 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/nested-tags-note.md +11 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +11 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/hello-world.md +11 -0
- package/skills/vault-sync/tests/schema-drift.test.mjs +133 -0
- package/skills/vault-sync/validator.mjs +658 -0
- package/skills/vault-sync/validator.sh +55 -0
- package/skills/wave-executor/SKILL.md +496 -0
- package/skills/wave-executor/circuit-breaker.md +169 -0
- package/skills/wave-executor/wave-loop.md +1043 -0
- package/skills/write-executable-plan/SKILL.md +237 -0
- package/skills/write-executable-plan/plan-template.md +154 -0
- package/templates/_minimal/CLAUDE.md.tmpl +41 -0
- package/templates/_minimal/README.md.tmpl +15 -0
- package/templates/_minimal/gitignore.tmpl +47 -0
- package/templates/_shared/harte-regeln.md +16 -0
- package/templates/_shared/loop.md +90 -0
- package/templates/_shared/rules/parallel-sessions.md +77 -0
- package/templates/nextjs-minimal/README.md +30 -0
- package/templates/nextjs-minimal/app/layout.tsx +18 -0
- package/templates/nextjs-minimal/app/page.tsx +7 -0
- package/templates/nextjs-minimal/eslint.config.mjs +16 -0
- package/templates/nextjs-minimal/next.config.mjs +4 -0
- package/templates/nextjs-minimal/package.json +27 -0
- package/templates/nextjs-minimal/tsconfig.json +23 -0
- package/templates/node-minimal/README.md +33 -0
- package/templates/node-minimal/eslint.config.mjs +10 -0
- package/templates/node-minimal/package.json +21 -0
- package/templates/node-minimal/src/index.ts +1 -0
- package/templates/node-minimal/tests/sanity.test.ts +5 -0
- package/templates/node-minimal/tsconfig.json +17 -0
- package/templates/personas/README.md +150 -0
- package/templates/personas/accounting-compliance.v1.md +120 -0
- package/templates/personas/accounting-tax-advisor.v1.md +116 -0
- package/templates/personas/buyer-p1-cto.v1.md +125 -0
- package/templates/personas/buyer-p2-kanzlei.v1.md +134 -0
- package/templates/personas/buyer-p3-build.v1.md +130 -0
- package/templates/personas/buyer-p4-tech-veto.v1.md +130 -0
- package/templates/personas/buyer-p5-solo.v1.md +132 -0
- package/templates/personas/buyer-p6-ld.v1.md +130 -0
- package/templates/personas/klima-ai-expert.v1.md +114 -0
- package/templates/personas/klima-physicist.v1.md +117 -0
- package/templates/python-uv/README.md +28 -0
- package/templates/python-uv/pyproject.toml +32 -0
- package/templates/python-uv/src/__PROJECT_NAME__/__init__.py +0 -0
- package/templates/python-uv/src/__PROJECT_NAME__/main.py +6 -0
- package/templates/python-uv/tests/test_sanity.py +2 -0
- package/templates/static-html/README.md +19 -0
- package/templates/static-html/index.html +15 -0
- package/templates/static-html/script.js +1 -0
- package/templates/static-html/styles.css +26 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context-pressure signal computation (#332).
|
|
3
|
+
*
|
|
4
|
+
* Extracted from scripts/lib/mode-selector.mjs (issue #358).
|
|
5
|
+
* Pure function: no I/O, no side effects.
|
|
6
|
+
*
|
|
7
|
+
* Per W1 D3 risk warning, scorer split deferred; only `computeContextPressure`
|
|
8
|
+
* extracted this session.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Local helpers (inlined — clamp/round2/safeArray are <5 lines each and are
|
|
13
|
+
// also used by the parent mode-selector.mjs; inlining avoids a circular import
|
|
14
|
+
// or a shared-helper re-export).
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Clamp a number to [min, max].
|
|
19
|
+
* @param {number} v
|
|
20
|
+
* @param {number} min
|
|
21
|
+
* @param {number} max
|
|
22
|
+
* @returns {number}
|
|
23
|
+
*/
|
|
24
|
+
function clamp(v, min, max) {
|
|
25
|
+
return Math.min(max, Math.max(min, v));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Round to 2 decimal places (avoids floating-point drift in comparisons).
|
|
30
|
+
* @param {number} v
|
|
31
|
+
* @returns {number}
|
|
32
|
+
*/
|
|
33
|
+
function round2(v) {
|
|
34
|
+
return Math.round(v * 100) / 100;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Safely coerce to an array (returns [] for non-arrays, null, undefined).
|
|
39
|
+
* @param {unknown} v
|
|
40
|
+
* @returns {any[]}
|
|
41
|
+
*/
|
|
42
|
+
function safeArray(v) {
|
|
43
|
+
return Array.isArray(v) ? v : [];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Regex
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Regex for cross-cutting keyword detection in task description text.
|
|
52
|
+
* Matches phrases that indicate large, scope-spanning work.
|
|
53
|
+
*/
|
|
54
|
+
const CROSS_CUTTING_PATTERN =
|
|
55
|
+
/across all|every (skill|agent|repo)|repo-?wide|cross-cutting|rename across|massive refactor/i;
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Public API
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @typedef {Object} ContextPressureComponents
|
|
63
|
+
* @property {number} scope - Scope component contribution (0.0–0.5).
|
|
64
|
+
* @property {number} keywords - Cross-cutting keyword component contribution (0 or 0.25).
|
|
65
|
+
* @property {number} carryover - Carryover component contribution (0.0–0.25).
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @typedef {Object} ContextPressureResult
|
|
70
|
+
* @property {number} score - Aggregate pressure score 0.0–1.0.
|
|
71
|
+
* @property {ContextPressureComponents} components - Per-component breakdown.
|
|
72
|
+
* @property {'low'|'medium'|'high'} level - Bucketed level from score.
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Compute context-pressure score (0.0–1.0) for the proposed work.
|
|
77
|
+
* High pressure → recommend deferring scope or preferring deep mode over feature.
|
|
78
|
+
*
|
|
79
|
+
* Inputs (read from signals):
|
|
80
|
+
* - signals.topPriorities: number[]|undefined — count used as proxy for scope
|
|
81
|
+
* - signals.recentSessions: array — tail-5 used to derive carryover_ratio from
|
|
82
|
+
* session.effectiveness.carryover / session.effectiveness.planned_issues
|
|
83
|
+
* - signals.taskDescriptionText: string|undefined — joined PRD/issue body for keyword scan
|
|
84
|
+
*
|
|
85
|
+
* Score components (additive, clamped to [0, 1]):
|
|
86
|
+
* - scope: min(0.5, max(0, (priorityCount - 3) / 10))
|
|
87
|
+
* - keywords: +0.25 if CROSS_CUTTING_PATTERN matches taskDescriptionText
|
|
88
|
+
* - carryover: min(0.25, max(0, carryoverRatio - 0.3))
|
|
89
|
+
*
|
|
90
|
+
* Returns level buckets: score < 0.3 → 'low'; 0.3–0.7 → 'medium'; ≥ 0.7 → 'high'.
|
|
91
|
+
*
|
|
92
|
+
* Pure function: no I/O, no side effects. Missing/invalid fields → 0 contribution.
|
|
93
|
+
*
|
|
94
|
+
* @param {object|null|undefined} signals
|
|
95
|
+
* @returns {ContextPressureResult}
|
|
96
|
+
*/
|
|
97
|
+
export function computeContextPressure(signals) {
|
|
98
|
+
// --- Scope component ---
|
|
99
|
+
const priorities = safeArray(signals?.topPriorities);
|
|
100
|
+
const priorityCount = priorities.length;
|
|
101
|
+
const scopeComponent = clamp((priorityCount - 3) / 10, 0, 0.5);
|
|
102
|
+
|
|
103
|
+
// --- Cross-cutting keywords component ---
|
|
104
|
+
const text = typeof signals?.taskDescriptionText === 'string' ? signals.taskDescriptionText : '';
|
|
105
|
+
const keywordsComponent = text.length > 0 && CROSS_CUTTING_PATTERN.test(text) ? 0.25 : 0;
|
|
106
|
+
|
|
107
|
+
// --- Carryover component ---
|
|
108
|
+
// Derive carryover ratio from tail-5 recent sessions using
|
|
109
|
+
// effectiveness.carryover / effectiveness.planned_issues (sessions.jsonl schema).
|
|
110
|
+
// Falls back gracefully when fields are absent (contributes 0).
|
|
111
|
+
const recentSessions = safeArray(signals?.recentSessions);
|
|
112
|
+
const last5 = recentSessions.slice(-5);
|
|
113
|
+
let derivedCarryoverRatio = 0;
|
|
114
|
+
if (last5.length > 0) {
|
|
115
|
+
let validCount = 0;
|
|
116
|
+
let ratioSum = 0;
|
|
117
|
+
for (const session of last5) {
|
|
118
|
+
if (session === null || typeof session !== 'object') continue;
|
|
119
|
+
const eff = session.effectiveness;
|
|
120
|
+
if (eff === null || typeof eff !== 'object') continue;
|
|
121
|
+
const carryover =
|
|
122
|
+
typeof eff.carryover === 'number' && !Number.isNaN(eff.carryover) ? eff.carryover : null;
|
|
123
|
+
const planned =
|
|
124
|
+
typeof eff.planned_issues === 'number' &&
|
|
125
|
+
!Number.isNaN(eff.planned_issues) &&
|
|
126
|
+
eff.planned_issues > 0
|
|
127
|
+
? eff.planned_issues
|
|
128
|
+
: null;
|
|
129
|
+
if (carryover !== null && planned !== null) {
|
|
130
|
+
ratioSum += carryover / planned;
|
|
131
|
+
validCount++;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (validCount > 0) {
|
|
135
|
+
derivedCarryoverRatio = ratioSum / validCount;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const carryoverComponent = clamp(derivedCarryoverRatio - 0.3, 0, 0.25);
|
|
139
|
+
|
|
140
|
+
const score = round2(clamp(scopeComponent + keywordsComponent + carryoverComponent, 0, 1));
|
|
141
|
+
|
|
142
|
+
/** @type {'low'|'medium'|'high'} */
|
|
143
|
+
let level;
|
|
144
|
+
if (score < 0.3) level = 'low';
|
|
145
|
+
else if (score < 0.7) level = 'medium';
|
|
146
|
+
else level = 'high';
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
score,
|
|
150
|
+
components: {
|
|
151
|
+
scope: round2(scopeComponent),
|
|
152
|
+
keywords: round2(keywordsComponent),
|
|
153
|
+
carryover: round2(carryoverComponent),
|
|
154
|
+
},
|
|
155
|
+
level,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rationale-string builder for the mode-selector passthrough branch (W1A2 split, issue #358).
|
|
3
|
+
*
|
|
4
|
+
* Exports: buildPassthroughRationale.
|
|
5
|
+
* Imports: constants (leaf). Shared helpers inlined per Option B.
|
|
6
|
+
*
|
|
7
|
+
* Pure function: no I/O, no side effects.
|
|
8
|
+
* 120-char clamp is enforced on every returned string.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { TIER_MODE_MAP } from './constants.mjs';
|
|
12
|
+
import { safeArray, safeBootstrapLock } from './scoring.mjs';
|
|
13
|
+
import { hasActiveSignals } from './alternatives.mjs';
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Public API
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Build a rationale string for branch 3 (passthrough-weighted) based on the
|
|
21
|
+
* dominant factor. Result is deterministic for the same (mode, signals) pair.
|
|
22
|
+
* Always ≤120 chars.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} mode
|
|
25
|
+
* @param {number} confidence
|
|
26
|
+
* @param {object} signals
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
export function buildPassthroughRationale(mode, confidence, signals) {
|
|
30
|
+
const recentSessions = safeArray(signals.recentSessions);
|
|
31
|
+
const last3 = recentSessions.slice(-3);
|
|
32
|
+
const bootstrapLock = safeBootstrapLock(signals);
|
|
33
|
+
const tier = bootstrapLock && typeof bootstrapLock.tier === 'string' ? bootstrapLock.tier : null;
|
|
34
|
+
|
|
35
|
+
const hasTrend = last3.length >= 3 &&
|
|
36
|
+
last3.every((s) => typeof s === 'object' && s !== null && s.session_type === mode);
|
|
37
|
+
const hasTierAlign = tier !== null && TIER_MODE_MAP[tier] === mode;
|
|
38
|
+
const hasSignals = hasActiveSignals(signals);
|
|
39
|
+
|
|
40
|
+
let rationale;
|
|
41
|
+
if (!hasSignals) {
|
|
42
|
+
rationale = 'passthrough of Phase A recommended-mode — stale signals';
|
|
43
|
+
} else if (hasTrend && hasTierAlign) {
|
|
44
|
+
rationale = 'passthrough reinforced by recent-sessions trend + bootstrap tier';
|
|
45
|
+
} else if (hasTrend) {
|
|
46
|
+
rationale = 'passthrough reinforced by recent-sessions trend';
|
|
47
|
+
} else if (hasTierAlign) {
|
|
48
|
+
rationale = `passthrough reinforced by bootstrap tier (${tier})`;
|
|
49
|
+
} else {
|
|
50
|
+
rationale = 'passthrough of Phase A recommended-mode';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Clamp to 120 chars (safety net)
|
|
54
|
+
return rationale.slice(0, 120);
|
|
55
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mode-scoring logic for the mode-selector heuristic (W1A2 split, issue #358).
|
|
3
|
+
*
|
|
4
|
+
* Exports: computeDelta, scoreMode.
|
|
5
|
+
* Imports: constants (leaf). Shared helpers inlined per Option B (avoids cycle
|
|
6
|
+
* risk; matches context-pressure.mjs precedent).
|
|
7
|
+
*
|
|
8
|
+
* Pure functions: no I/O, no side effects.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { ALL_MODES, TIER_MODE_MAP } from './constants.mjs';
|
|
12
|
+
import { computeContextPressure } from './context-pressure.mjs';
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Non-execution (read-only precursor) modes — PRD §2 Out-of-Scope (line 56),
|
|
16
|
+
// §4 line 244, P2.4 (issue #678).
|
|
17
|
+
//
|
|
18
|
+
// `discovery` (routes to /discovery) and `plan-retro` (routes to /plan) are
|
|
19
|
+
// READ-ONLY precursors. The dispatcher MENU routes to them and the
|
|
20
|
+
// recommendation engine may SUGGEST them, but they must NEVER become a
|
|
21
|
+
// scoring-promoted execution-wave `mode` (the primary that session-start /
|
|
22
|
+
// wave-executor would RUN as a build-and-commit wave).
|
|
23
|
+
//
|
|
24
|
+
// Exported so the mode-selector guardrail (global-max swap) and the dispatcher
|
|
25
|
+
// suggestion surface (recommendations-v0.mjs) share a single source of truth.
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
/** @type {ReadonlySet<string>} */
|
|
29
|
+
export const NON_EXECUTION_MODES = Object.freeze(new Set(['discovery', 'plan-retro']));
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* True when `mode` is a read-only precursor (discovery / plan-retro) that must
|
|
33
|
+
* never be scoring-promoted into the primary executed `mode`.
|
|
34
|
+
* @param {unknown} mode
|
|
35
|
+
* @returns {boolean}
|
|
36
|
+
*/
|
|
37
|
+
export function isNonExecutionMode(mode) {
|
|
38
|
+
return typeof mode === 'string' && NON_EXECUTION_MODES.has(mode);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Inlined helpers (clamp, round2, safeArray, safeBootstrapLock)
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Clamp a number to [min, max].
|
|
47
|
+
* @param {number} v
|
|
48
|
+
* @param {number} min
|
|
49
|
+
* @param {number} max
|
|
50
|
+
* @returns {number}
|
|
51
|
+
*/
|
|
52
|
+
function clamp(v, min, max) {
|
|
53
|
+
return Math.min(max, Math.max(min, v));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Round to 2 decimal places (avoids floating-point drift in comparisons).
|
|
58
|
+
* @param {number} v
|
|
59
|
+
* @returns {number}
|
|
60
|
+
*/
|
|
61
|
+
export function round2(v) {
|
|
62
|
+
return Math.round(v * 100) / 100;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Safely coerce to an array (returns [] for non-arrays, null, undefined).
|
|
67
|
+
* @param {unknown} v
|
|
68
|
+
* @returns {any[]}
|
|
69
|
+
*/
|
|
70
|
+
export function safeArray(v) {
|
|
71
|
+
return Array.isArray(v) ? v : [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Return signals.bootstrapLock when it is a non-null object, otherwise null.
|
|
76
|
+
* @param {object} signals
|
|
77
|
+
* @returns {object|null}
|
|
78
|
+
*/
|
|
79
|
+
export function safeBootstrapLock(signals) {
|
|
80
|
+
return (signals.bootstrapLock !== null && typeof signals.bootstrapLock === 'object')
|
|
81
|
+
? signals.bootstrapLock
|
|
82
|
+
: null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// Public API
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Compute the bonus+penalty score delta for a candidate mode given the
|
|
91
|
+
* provided signals. Returns a number in the range (-0.30, +0.35).
|
|
92
|
+
*
|
|
93
|
+
* @param {string} candidateMode
|
|
94
|
+
* @param {object} signals
|
|
95
|
+
* @returns {number} delta (positive bonuses − negative penalties)
|
|
96
|
+
*/
|
|
97
|
+
export function computeDelta(candidateMode, signals) {
|
|
98
|
+
const recentSessions = safeArray(signals.recentSessions);
|
|
99
|
+
const learnings = safeArray(signals.learnings);
|
|
100
|
+
const bootstrapLock = safeBootstrapLock(signals);
|
|
101
|
+
|
|
102
|
+
// --- Recent-sessions trend bonus (max +0.15) ---
|
|
103
|
+
let trendBonus = 0;
|
|
104
|
+
const last3 = recentSessions.slice(-3);
|
|
105
|
+
if (last3.length >= 3) {
|
|
106
|
+
const allMatch = last3.every(
|
|
107
|
+
(s) => typeof s === 'object' && s !== null && s.session_type === candidateMode,
|
|
108
|
+
);
|
|
109
|
+
if (allMatch) {
|
|
110
|
+
const avgCompletion =
|
|
111
|
+
last3.reduce((sum, s) => sum + (typeof s.completion_rate === 'number' ? s.completion_rate : 0), 0) /
|
|
112
|
+
3;
|
|
113
|
+
trendBonus = avgCompletion >= 0.9 ? 0.15 : 0.075;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// --- Bootstrap-tier alignment bonus (max +0.10) ---
|
|
118
|
+
let tierBonus = 0;
|
|
119
|
+
if (bootstrapLock !== null) {
|
|
120
|
+
const tier = typeof bootstrapLock.tier === 'string' ? bootstrapLock.tier : null;
|
|
121
|
+
if (tier !== null && TIER_MODE_MAP[tier] === candidateMode) {
|
|
122
|
+
tierBonus = 0.10;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// --- Learnings-hint bonus (max +0.10) ---
|
|
127
|
+
let learningsBonus = 0;
|
|
128
|
+
const HINT_TYPES = new Set(['effective-sizing', 'scope-guidance']);
|
|
129
|
+
const modeKeyword = candidateMode.toLowerCase();
|
|
130
|
+
for (const learning of learnings) {
|
|
131
|
+
if (
|
|
132
|
+
typeof learning === 'object' &&
|
|
133
|
+
learning !== null &&
|
|
134
|
+
typeof learning.type === 'string' &&
|
|
135
|
+
HINT_TYPES.has(learning.type) &&
|
|
136
|
+
typeof learning.subject === 'string' &&
|
|
137
|
+
learning.subject.toLowerCase().includes(modeKeyword)
|
|
138
|
+
) {
|
|
139
|
+
learningsBonus = Math.min(learningsBonus + 0.05, 0.10);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// --- Conflict penalties (max −0.30) ---
|
|
144
|
+
let penalty = 0;
|
|
145
|
+
|
|
146
|
+
// Penalty: recent sessions trend strongly suggests a DIFFERENT mode
|
|
147
|
+
if (last3.length >= 3) {
|
|
148
|
+
const otherModes = ALL_MODES.filter((m) => m !== candidateMode);
|
|
149
|
+
for (const otherMode of otherModes) {
|
|
150
|
+
const allOther = last3.every(
|
|
151
|
+
(s) => typeof s === 'object' && s !== null && s.session_type === otherMode,
|
|
152
|
+
);
|
|
153
|
+
if (allOther) {
|
|
154
|
+
const avgCompletion =
|
|
155
|
+
last3.reduce((sum, s) => sum + (typeof s.completion_rate === 'number' ? s.completion_rate : 0), 0) /
|
|
156
|
+
3;
|
|
157
|
+
if (avgCompletion >= 0.9) {
|
|
158
|
+
penalty += 0.10;
|
|
159
|
+
break; // only one other dominant mode possible
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Penalty: bootstrap tier maps to a different mode than candidateMode
|
|
166
|
+
if (bootstrapLock !== null) {
|
|
167
|
+
const tier = typeof bootstrapLock.tier === 'string' ? bootstrapLock.tier : null;
|
|
168
|
+
if (tier !== null) {
|
|
169
|
+
const alignedMode = TIER_MODE_MAP[tier];
|
|
170
|
+
if (alignedMode !== undefined && alignedMode !== candidateMode) {
|
|
171
|
+
penalty += 0.10;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Penalty: high carryover but not in 'deep' mode
|
|
177
|
+
const carryoverRatio =
|
|
178
|
+
typeof signals.carryoverRatio === 'number' && !Number.isNaN(signals.carryoverRatio)
|
|
179
|
+
? signals.carryoverRatio
|
|
180
|
+
: null;
|
|
181
|
+
if (carryoverRatio !== null && carryoverRatio >= 0.2 && candidateMode !== 'deep') {
|
|
182
|
+
penalty += 0.10;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// --- Context-pressure modulation (#332) ---
|
|
186
|
+
// Pure additive delta on top of existing signal modulation.
|
|
187
|
+
// Only applies when at least one context-pressure input is explicitly present.
|
|
188
|
+
// When all inputs are absent, pressure is undefined → treat as neutral (no adjustment).
|
|
189
|
+
// This preserves backward-compatibility for callers that do not yet supply the new fields.
|
|
190
|
+
const hasPressureInputs =
|
|
191
|
+
(signals.topPriorities !== null && signals.topPriorities !== undefined) ||
|
|
192
|
+
(typeof signals.taskDescriptionText === 'string' && signals.taskDescriptionText.length > 0) ||
|
|
193
|
+
safeArray(signals.recentSessions).some(
|
|
194
|
+
(s) => s !== null && typeof s === 'object' && typeof s.effectiveness === 'object' && s.effectiveness !== null,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
let pressureDelta = 0;
|
|
198
|
+
if (hasPressureInputs) {
|
|
199
|
+
const pressure = computeContextPressure(signals);
|
|
200
|
+
if (pressure.level === 'high') {
|
|
201
|
+
if (candidateMode === 'feature') pressureDelta = -0.15;
|
|
202
|
+
else if (candidateMode === 'housekeeping') pressureDelta = -0.10;
|
|
203
|
+
} else if (pressure.level === 'low') {
|
|
204
|
+
if (candidateMode === 'feature') pressureDelta = +0.05;
|
|
205
|
+
}
|
|
206
|
+
// level === 'medium': no adjustment
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return trendBonus + tierBonus + learningsBonus - penalty + pressureDelta;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Score a candidate mode: base 0.5 + delta, clamped to [0.0, 0.9].
|
|
214
|
+
*
|
|
215
|
+
* @param {string} candidateMode
|
|
216
|
+
* @param {object} signals
|
|
217
|
+
* @returns {number}
|
|
218
|
+
*/
|
|
219
|
+
export function scoreMode(candidateMode, signals) {
|
|
220
|
+
return round2(clamp(0.5 + computeDelta(candidateMode, signals), 0.0, 0.9));
|
|
221
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mode-selector-accuracy.mjs — Mode-Selector feedback-loop helper (Phase B-4, issue #294).
|
|
3
|
+
*
|
|
4
|
+
* After session-start renders a Mode-Selector recommendation and the user
|
|
5
|
+
* confirms or overrides it, call `recordAccuracy({recommended, chosen, sessionId})`
|
|
6
|
+
* to append a `mode-selector-accuracy` learning to the project's learnings.jsonl.
|
|
7
|
+
*
|
|
8
|
+
* Lifecycle (handled by skills/evolve + skills/session-end on subsequent reads,
|
|
9
|
+
* NOT by this helper):
|
|
10
|
+
* - Same (type, subject) seen again → +0.15 confidence (confirmed)
|
|
11
|
+
* - Contradicted by new evidence → -0.20 confidence
|
|
12
|
+
*
|
|
13
|
+
* Subject pattern encodes the outcome class:
|
|
14
|
+
* `<recommended>-selected-vs-<chosen>`
|
|
15
|
+
*
|
|
16
|
+
* Examples:
|
|
17
|
+
* recommended=feature, chosen=feature → "feature-selected-vs-feature" (agreement)
|
|
18
|
+
* recommended=feature, chosen=deep → "feature-selected-vs-deep" (override)
|
|
19
|
+
*
|
|
20
|
+
* Same-pair recurrence in future sessions hits the dedupe path in evolve and
|
|
21
|
+
* confirms; novel pairs land at confidence 0.5 and accumulate from there.
|
|
22
|
+
*
|
|
23
|
+
* AC contract (from issue #294):
|
|
24
|
+
* - Learning written only when user actively chooses (caller decides).
|
|
25
|
+
* - Confidence starts at 0.5 (initial value; lifecycle handles increment/decrement).
|
|
26
|
+
* - No-op when `recommended` is null/undefined (selector did not render a banner).
|
|
27
|
+
*
|
|
28
|
+
* The helper is a thin wrapper around `appendLearning` from `learnings.mjs`. It
|
|
29
|
+
* never throws on validation issues — those bubble back to the caller as a
|
|
30
|
+
* resolved-error return value (`{ok: false, reason}`) so session-start can
|
|
31
|
+
* log to sweep.log without halting the session.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { appendLearning } from './learnings.mjs';
|
|
35
|
+
import { isValidMode } from './recommendations-v0.mjs';
|
|
36
|
+
|
|
37
|
+
export const LEARNING_TYPE = 'mode-selector-accuracy';
|
|
38
|
+
export const INITIAL_CONFIDENCE = 0.5;
|
|
39
|
+
export const DEFAULT_EXPIRY_DAYS = 30;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Build the canonical subject string for a (recommended, chosen) pair.
|
|
43
|
+
* @param {string} recommended
|
|
44
|
+
* @param {string} chosen
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
export function buildSubject(recommended, chosen) {
|
|
48
|
+
return `${recommended}-selected-vs-${chosen}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Record a Mode-Selector accuracy learning.
|
|
53
|
+
*
|
|
54
|
+
* @param {{
|
|
55
|
+
* recommended: string|null,
|
|
56
|
+
* chosen: string,
|
|
57
|
+
* sessionId: string,
|
|
58
|
+
* filePath?: string,
|
|
59
|
+
* nowMs?: number,
|
|
60
|
+
* expiryDays?: number,
|
|
61
|
+
* confidence?: number,
|
|
62
|
+
* }} opts
|
|
63
|
+
* @returns {Promise<{ok: true, entry: object} | {ok: false, reason: string}>}
|
|
64
|
+
*/
|
|
65
|
+
export async function recordAccuracy(opts) {
|
|
66
|
+
const recommended = opts?.recommended;
|
|
67
|
+
const chosen = opts?.chosen;
|
|
68
|
+
const sessionId = opts?.sessionId;
|
|
69
|
+
const filePath = opts?.filePath || '.orchestrator/metrics/learnings.jsonl';
|
|
70
|
+
|
|
71
|
+
// No-op when the selector did not render a recommendation (banner suppressed,
|
|
72
|
+
// confidence 0.0, etc). Caller passes recommended=null in that case.
|
|
73
|
+
if (recommended === null || recommended === undefined || recommended === '') {
|
|
74
|
+
return { ok: false, reason: 'no-recommendation' };
|
|
75
|
+
}
|
|
76
|
+
if (typeof recommended !== 'string' || typeof chosen !== 'string') {
|
|
77
|
+
return { ok: false, reason: 'invalid-mode-type' };
|
|
78
|
+
}
|
|
79
|
+
if (!isValidMode(recommended) || !isValidMode(chosen)) {
|
|
80
|
+
return { ok: false, reason: 'unknown-mode' };
|
|
81
|
+
}
|
|
82
|
+
if (typeof sessionId !== 'string' || sessionId.length === 0) {
|
|
83
|
+
return { ok: false, reason: 'missing-session-id' };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const nowMs = typeof opts.nowMs === 'number' ? opts.nowMs : Date.now();
|
|
87
|
+
const expiryDays = Number.isInteger(opts.expiryDays) && opts.expiryDays > 0
|
|
88
|
+
? opts.expiryDays
|
|
89
|
+
: DEFAULT_EXPIRY_DAYS;
|
|
90
|
+
const confidence = typeof opts.confidence === 'number'
|
|
91
|
+
? opts.confidence
|
|
92
|
+
: INITIAL_CONFIDENCE;
|
|
93
|
+
|
|
94
|
+
const subject = buildSubject(recommended, chosen);
|
|
95
|
+
const agreement = recommended === chosen;
|
|
96
|
+
const insight = agreement
|
|
97
|
+
? `User confirmed Mode-Selector recommendation (${recommended}).`
|
|
98
|
+
: `User overrode Mode-Selector recommendation (${recommended}) with ${chosen}.`;
|
|
99
|
+
|
|
100
|
+
const created_at = new Date(nowMs).toISOString();
|
|
101
|
+
const expires_at = new Date(nowMs + expiryDays * 86_400_000).toISOString();
|
|
102
|
+
|
|
103
|
+
const entry = {
|
|
104
|
+
id: `${LEARNING_TYPE}-${subject}-${sessionId}`,
|
|
105
|
+
type: LEARNING_TYPE,
|
|
106
|
+
subject,
|
|
107
|
+
insight,
|
|
108
|
+
evidence: [`${sessionId}: recommended=${recommended} chosen=${chosen}`],
|
|
109
|
+
confidence,
|
|
110
|
+
source_session: sessionId,
|
|
111
|
+
created_at,
|
|
112
|
+
expires_at,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
const validated = await appendLearning(filePath, entry);
|
|
117
|
+
return { ok: true, entry: validated };
|
|
118
|
+
} catch (err) {
|
|
119
|
+
return { ok: false, reason: `append-failed: ${err?.message ?? String(err)}` };
|
|
120
|
+
}
|
|
121
|
+
}
|