session-orchestrator 3.24.0 → 4.0.1
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/.agents/skills/architecture/SKILL.md +18 -0
- package/.agents/skills/autopilot/SKILL.md +17 -0
- package/.agents/skills/bootstrap/SKILL.md +20 -0
- package/.agents/skills/brainstorm/SKILL.md +22 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +15 -0
- package/.agents/skills/convergence-monitoring/SKILL.md +22 -0
- package/.agents/skills/debug/SKILL.md +22 -0
- package/.agents/skills/discovery/SKILL.md +20 -0
- package/.agents/skills/dispatcher/SKILL.md +15 -0
- package/.agents/skills/docs-orchestrator/SKILL.md +18 -0
- package/.agents/skills/ecosystem-health/SKILL.md +20 -0
- package/.agents/skills/eli5/SKILL.md +20 -0
- package/.agents/skills/eval/SKILL.md +21 -0
- package/.agents/skills/evolve/SKILL.md +21 -0
- package/.agents/skills/frontmatter-guard/SKILL.md +15 -0
- package/.agents/skills/gitlab-ops/SKILL.md +20 -0
- package/.agents/skills/gitlab-portfolio/SKILL.md +15 -0
- package/.agents/skills/grill/SKILL.md +22 -0
- package/.agents/skills/hook-development/SKILL.md +15 -0
- package/.agents/skills/mcp-builder/SKILL.md +15 -0
- package/.agents/skills/memory-cleanup/SKILL.md +21 -0
- package/.agents/skills/mode-selector/SKILL.md +17 -0
- package/.agents/skills/npm-publish/SKILL.md +16 -0
- package/.agents/skills/peekaboo-driver/SKILL.md +18 -0
- package/.agents/skills/persona-panel/SKILL.md +17 -0
- package/.agents/skills/plan/SKILL.md +20 -0
- package/.agents/skills/playwright-driver/SKILL.md +20 -0
- package/.agents/skills/quality-gates/SKILL.md +20 -0
- package/.agents/skills/reconcile/SKILL.md +21 -0
- package/.agents/skills/remote-offload/SKILL.md +20 -0
- package/.agents/skills/repo-audit/SKILL.md +16 -0
- package/.agents/skills/session-end/SKILL.md +20 -0
- package/.agents/skills/session-plan/SKILL.md +20 -0
- package/.agents/skills/session-start/SKILL.md +20 -0
- package/.agents/skills/spinout/SKILL.md +16 -0
- package/.agents/skills/sunset-review/SKILL.md +16 -0
- package/.agents/skills/test-runner/SKILL.md +20 -0
- package/.agents/skills/tmux-layout/SKILL.md +21 -0
- package/.agents/skills/using-orchestrator/SKILL.md +17 -0
- package/.agents/skills/vault-mirror/SKILL.md +15 -0
- package/.agents/skills/vault-sync/SKILL.md +15 -0
- package/.agents/skills/wave-executor/SKILL.md +20 -0
- package/.agents/skills/write-executable-plan/SKILL.md +22 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +3 -2
- package/.codex-plugin/skills/architecture/SKILL.md +20 -0
- package/.codex-plugin/skills/autopilot/SKILL.md +21 -0
- package/.codex-plugin/skills/autopilot/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/bootstrap/SKILL.md +22 -0
- package/.codex-plugin/skills/bootstrap/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/brainstorm/SKILL.md +22 -0
- package/.codex-plugin/skills/brainstorm/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +17 -0
- package/.codex-plugin/skills/close/SKILL.md +21 -0
- package/.codex-plugin/skills/close/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/convergence-monitoring/SKILL.md +24 -0
- package/.codex-plugin/skills/debug/SKILL.md +21 -0
- package/.codex-plugin/skills/debug/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/discovery/SKILL.md +21 -0
- package/.codex-plugin/skills/discovery/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/dispatcher/SKILL.md +21 -0
- package/.codex-plugin/skills/dispatcher/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/docs-orchestrator/SKILL.md +20 -0
- package/.codex-plugin/skills/ecosystem-health/SKILL.md +22 -0
- package/.codex-plugin/skills/eli5/SKILL.md +21 -0
- package/.codex-plugin/skills/eli5/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/eval/SKILL.md +21 -0
- package/.codex-plugin/skills/eval/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/evolve/SKILL.md +21 -0
- package/.codex-plugin/skills/evolve/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/frontmatter-guard/SKILL.md +17 -0
- package/.codex-plugin/skills/gitlab-ops/SKILL.md +22 -0
- package/.codex-plugin/skills/gitlab-portfolio/SKILL.md +17 -0
- package/.codex-plugin/skills/go/SKILL.md +22 -0
- package/.codex-plugin/skills/go/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/grill/SKILL.md +21 -0
- package/.codex-plugin/skills/grill/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/harness-audit/SKILL.md +19 -0
- package/.codex-plugin/skills/harness-audit/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/hook-development/SKILL.md +17 -0
- package/.codex-plugin/skills/mcp-builder/SKILL.md +17 -0
- package/.codex-plugin/skills/memory-cleanup/SKILL.md +21 -0
- package/.codex-plugin/skills/memory-cleanup/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/mode-selector/SKILL.md +19 -0
- package/.codex-plugin/skills/npm-publish/SKILL.md +18 -0
- package/.codex-plugin/skills/peekaboo-driver/SKILL.md +20 -0
- package/.codex-plugin/skills/persona-panel/SKILL.md +22 -0
- package/.codex-plugin/skills/persona-panel/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/plan/SKILL.md +22 -0
- package/.codex-plugin/skills/plan/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/playwright-driver/SKILL.md +22 -0
- package/.codex-plugin/skills/portfolio/SKILL.md +21 -0
- package/.codex-plugin/skills/portfolio/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/quality-gates/SKILL.md +22 -0
- package/.codex-plugin/skills/reconcile/SKILL.md +21 -0
- package/.codex-plugin/skills/reconcile/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/release/SKILL.md +22 -0
- package/.codex-plugin/skills/release/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/remote-offload/SKILL.md +22 -0
- package/.codex-plugin/skills/repo-audit/SKILL.md +19 -0
- package/.codex-plugin/skills/repo-audit/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/session/SKILL.md +21 -0
- package/.codex-plugin/skills/session/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/session-end/SKILL.md +22 -0
- package/.codex-plugin/skills/session-plan/SKILL.md +22 -0
- package/.codex-plugin/skills/session-start/SKILL.md +22 -0
- package/.codex-plugin/skills/spinout/SKILL.md +21 -0
- package/.codex-plugin/skills/spinout/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/sunset-review/SKILL.md +21 -0
- package/.codex-plugin/skills/sunset-review/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/templates-ack/SKILL.md +21 -0
- package/.codex-plugin/skills/templates-ack/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/test/SKILL.md +21 -0
- package/.codex-plugin/skills/test/agents/openai.yaml +5 -0
- package/.codex-plugin/skills/test-runner/SKILL.md +22 -0
- package/.codex-plugin/skills/tmux-layout/SKILL.md +23 -0
- package/.codex-plugin/skills/using-orchestrator/SKILL.md +19 -0
- package/.codex-plugin/skills/vault-mirror/SKILL.md +17 -0
- package/.codex-plugin/skills/vault-sync/SKILL.md +17 -0
- package/.codex-plugin/skills/wave-executor/SKILL.md +22 -0
- package/.codex-plugin/skills/write-executable-plan/SKILL.md +24 -0
- package/.cursor/commands/autopilot.md +2 -2
- package/.cursor/commands/bootstrap.md +1 -1
- package/.cursor/commands/brainstorm.md +1 -1
- package/.cursor/commands/debug.md +1 -1
- package/.cursor/commands/discovery.md +1 -1
- package/.cursor/commands/dispatcher.md +2 -2
- package/.cursor/commands/eli5.md +2 -2
- package/.cursor/commands/eval.md +2 -2
- package/.cursor/commands/evolve.md +1 -1
- package/.cursor/commands/go.md +1 -1
- package/.cursor/commands/grill.md +2 -2
- package/.cursor/commands/memory-cleanup.md +2 -2
- package/.cursor/commands/persona-panel.md +1 -1
- package/.cursor/commands/plan.md +1 -1
- package/.cursor/commands/portfolio.md +1 -1
- package/.cursor/commands/reconcile.md +2 -2
- package/.cursor/commands/release.md +2 -2
- package/.cursor/commands/session.md +2 -2
- package/.cursor/commands/spinout.md +2 -2
- package/.cursor/commands/sunset-review.md +2 -2
- package/.cursor/commands/templates-ack.md +2 -2
- package/.cursor/commands/test.md +2 -2
- package/.cursor/skills/brainstorm/SKILL.md +1 -1
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/quality-gates/SKILL.md +1 -1
- package/.cursor/skills/remote-offload/SKILL.md +1 -1
- package/.cursor-plugin/plugin.json +30 -0
- package/.orchestrator/policy/blocked-commands.json +121 -0
- package/.orchestrator/policy/ecosystem.schema.json +66 -0
- package/.orchestrator/policy/quality-gates.example.json +16 -0
- package/.orchestrator/policy/quality-gates.schema.json +38 -0
- package/.orchestrator/policy/templates-policy.json +27 -0
- package/.orchestrator/policy/test-profiles.json +47 -0
- package/AGENTS.md +225 -0
- package/CHANGELOG.md +1314 -2
- package/NOTICE +11 -6
- package/README.md +135 -94
- package/agents/eval-judge.md +1 -1
- package/agents/skill-applied-judge.md +1 -1
- package/assets/wave-lifecycle.svg +98 -0
- package/commands/release.md +6 -3
- package/commands/session.md +18 -3
- package/docs/README.md +4 -0
- package/{agents/AGENTS.md → docs/agent-authoring.md} +19 -26
- package/docs/baseline.md +67 -0
- package/docs/ci-setup.md +108 -62
- package/docs/codex-setup.md +107 -29
- package/docs/components.md +38 -16
- package/docs/cursor-setup.md +6 -2
- package/docs/events-schema.md +9 -6
- package/docs/instruction-delivery.md +69 -0
- package/{agents/memory-proposal-collector.md → docs/memory-proposal-flow.md} +1 -8
- package/docs/migration-v4.md +365 -0
- package/docs/pi-setup.md +6 -1
- package/docs/plugin-architecture-v3.md +1 -1
- package/docs/rule-authoring.md +85 -19
- package/docs/scope-collision-guard.md +5 -5
- package/docs/session-config-reference.md +57 -56
- package/docs/session-config-template.md +6 -29
- package/docs/telemetry.md +157 -3
- package/docs/vault-docs-architecture.md +50 -11
- package/hooks/_lib/hook-import-set.json +1488 -0
- package/hooks/_lib/subagent-transcript.mjs +562 -0
- package/hooks/config-protection.mjs +2 -2
- package/hooks/cwd-change-restore.mjs +2 -2
- package/hooks/enforce-commands.mjs +69 -0
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +10 -0
- package/hooks/hooks-pi.json +5 -0
- package/hooks/hooks.json +6 -1
- package/hooks/loop-guard.mjs +3 -3
- package/hooks/on-session-end.mjs +2 -2
- package/hooks/on-session-start.mjs +103 -2
- package/hooks/on-stop.mjs +60 -14
- package/hooks/operator-steer.mjs +2 -2
- package/hooks/post-bash-write-verify.mjs +85 -0
- package/hooks/post-edit-import-probe.mjs +344 -0
- package/hooks/post-subagent-discovery-validator.mjs +187 -431
- package/hooks/post-tool-batch-wave-signal.mjs +118 -4
- package/hooks/post-tool-failure-corrective-context.mjs +2 -2
- package/hooks/post-tooluse-frontend-slop.mjs +3 -3
- package/hooks/pre-bash-destructive-guard.mjs +39 -13
- package/hooks/skill-invocation-telemetry.mjs +17 -5
- package/hooks/subagent-telemetry.mjs +13 -4
- package/monitors/monitors.json +3 -3
- package/package.json +9 -1
- package/pi/prompts/session.md +2 -2
- package/scripts/backfill-abandoned-sessions.mjs +50 -4
- package/scripts/backfill-learnings-from-vault.mjs +9 -3
- package/scripts/dialectic-deriver.mjs +73 -8
- package/scripts/export-hw-learnings.mjs +113 -1
- package/scripts/generate-agents-skills.mjs +378 -0
- package/scripts/generate-codex-skills.mjs +246 -0
- package/scripts/generate-cursor-adapter.mjs +45 -8
- package/scripts/generate-hook-import-set.mjs +292 -0
- package/scripts/lib/agent-status.mjs +13 -2
- package/scripts/lib/auto-dream.mjs +38 -36
- package/scripts/lib/autonomy/suitability.mjs +6 -0
- package/scripts/lib/autopilot/loop.mjs +2 -2
- package/scripts/lib/ci-status-banner.mjs +220 -75
- package/scripts/lib/codex/plugin-contract.mjs +88 -6
- package/scripts/lib/config/auto-dream.mjs +2 -1
- package/scripts/lib/config/block-header.mjs +8 -0
- package/scripts/lib/config/block-preprocess.mjs +177 -0
- package/scripts/lib/config/broken-window.mjs +2 -1
- package/scripts/lib/config/cold-start.mjs +2 -1
- package/scripts/lib/config/config-protection.mjs +22 -2
- package/scripts/lib/config/context-coverage.mjs +2 -1
- package/scripts/lib/config/cross-repo.mjs +2 -1
- package/scripts/lib/config/custom-phases.mjs +2 -1
- package/scripts/lib/config/dialectic.mjs +2 -1
- package/scripts/lib/config/discovery-validator.mjs +2 -1
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +24 -1
- package/scripts/lib/config/dispatcher-autonomy.mjs +2 -1
- package/scripts/lib/config/docs-orchestrator.mjs +2 -1
- package/scripts/lib/config/docs-staleness.mjs +2 -1
- package/scripts/lib/config/drift-check.mjs +2 -1
- package/scripts/lib/config/eval.mjs +2 -1
- package/scripts/lib/config/events-rotation.mjs +2 -1
- package/scripts/lib/config/evolve.mjs +8 -2
- package/scripts/lib/config/frontend-slop-hook.mjs +7 -3
- package/scripts/lib/config/gitlab-portfolio.mjs +2 -1
- package/scripts/lib/config/handover-gate.mjs +2 -1
- package/scripts/lib/config/health-endpoints.mjs +7 -2
- package/scripts/lib/config/host-paths.mjs +20 -4
- package/scripts/lib/config/issue-budget.mjs +2 -1
- package/scripts/lib/config/loop-guard.mjs +2 -1
- package/scripts/lib/config/memory.mjs +2 -1
- package/scripts/lib/config/moc-staleness.mjs +2 -1
- package/scripts/lib/config/persona-gate-wave.mjs +2 -1
- package/scripts/lib/config/private-config-dir.mjs +67 -0
- package/scripts/lib/config/reconcile.mjs +2 -1
- package/scripts/lib/config/remote-hosts.mjs +2 -1
- package/scripts/lib/config/section-extractor.mjs +7 -1
- package/scripts/lib/config/skill-evolution.mjs +2 -1
- package/scripts/lib/config/slopcheck.mjs +2 -1
- package/scripts/lib/config/state-md-lock.mjs +2 -1
- package/scripts/lib/config/templates-first.mjs +2 -1
- package/scripts/lib/config/test.mjs +2 -1
- package/scripts/lib/config/vault-integration.mjs +7 -1
- package/scripts/lib/config/vault-mirror-quality.mjs +2 -1
- package/scripts/lib/config/vault-staleness.mjs +2 -1
- package/scripts/lib/config/vault-sync.mjs +2 -1
- package/scripts/lib/config/verification-auto-fix.mjs +2 -1
- package/scripts/lib/config/wave-reviewers.mjs +2 -1
- package/scripts/lib/config/worktree-orphans.mjs +2 -1
- package/scripts/lib/convergence-monitor.mjs +82 -16
- package/scripts/lib/dispatcher/rank.mjs +124 -48
- package/scripts/lib/ecosystem-health.mjs +16 -2
- package/scripts/lib/eval/engine.mjs +9 -1
- package/scripts/lib/eval/session-resolve.mjs +23 -4
- package/scripts/lib/events.mjs +22 -6
- package/scripts/lib/frontmatter-guard.mjs +131 -13
- package/scripts/lib/gates/gate-full.mjs +30 -0
- package/scripts/lib/gates/gate-helpers.mjs +76 -0
- package/scripts/lib/hardware-pattern-detector.mjs +18 -1
- package/scripts/lib/harness-audit/categories/category4.mjs +31 -11
- package/scripts/lib/host-identity.mjs +50 -11
- package/scripts/lib/instruction-budget-guard.mjs +171 -5
- package/scripts/lib/learnings/evolve-telemetry.mjs +178 -0
- package/scripts/lib/learnings/io.mjs +60 -6
- package/scripts/lib/memory-proposals/store.mjs +30 -22
- package/scripts/lib/owner-config-banner.mjs +41 -6
- package/scripts/lib/owner-config-loader.mjs +21 -10
- package/scripts/lib/owner-interview.mjs +3 -3
- package/scripts/lib/owner-yaml.mjs +215 -15
- package/scripts/lib/platform.mjs +108 -15
- package/scripts/lib/plugin-update-banner.mjs +414 -0
- package/scripts/lib/project-hygiene.mjs +38 -2
- package/scripts/lib/qg-command-drift-banner.mjs +50 -12
- package/scripts/lib/quality-gate.mjs +133 -44
- package/scripts/lib/reconcile/emitter.mjs +68 -6
- package/scripts/lib/reconcile/engine.mjs +51 -11
- package/scripts/lib/reconcile/idempotency.mjs +37 -4
- package/scripts/lib/reconcile/writer.mjs +40 -18
- package/scripts/lib/session-close-backfill.mjs +67 -9
- package/scripts/lib/session-id.mjs +12 -23
- package/scripts/lib/session-identity/own-session.mjs +125 -10
- package/scripts/lib/session-lock-shape.mjs +43 -0
- package/scripts/lib/session-lock.mjs +5 -10
- package/scripts/lib/session-registry.mjs +25 -9
- package/scripts/lib/session-schema/constants.mjs +64 -3
- package/scripts/lib/session-schema/validator.mjs +38 -4
- package/scripts/lib/session-start-probes.mjs +30 -1
- package/scripts/lib/sessions-staleness-banner.mjs +18 -11
- package/scripts/lib/skill-health/join.mjs +17 -4
- package/scripts/lib/state-md.mjs +78 -0
- package/scripts/lib/sunset/walker.mjs +6 -0
- package/scripts/lib/telemetry/schema.mjs +202 -9
- package/scripts/lib/telemetry/sync.mjs +368 -12
- package/scripts/lib/telemetry-flush-health-banner.mjs +211 -0
- package/scripts/lib/validate/check-agents-skills.mjs +327 -0
- package/scripts/lib/validate/check-agents.mjs +3 -3
- package/scripts/lib/validate/check-codex-skills.mjs +191 -0
- package/scripts/lib/validate/check-cursor-adapter.mjs +234 -72
- package/scripts/lib/validate/check-hooks-symmetry.mjs +45 -16
- package/scripts/lib/validate/check-owner-leakage.mjs +319 -22
- package/scripts/lib/validate/check-skill-links.mjs +193 -0
- package/scripts/lib/validate/check-skill-script-paths.mjs +47 -28
- package/scripts/lib/validate/check-test-git-config-target.mjs +192 -12
- package/scripts/lib/validate/check-unwired-features.mjs +163 -15
- package/scripts/lib/validate/check-validator-registration.mjs +10 -4
- package/scripts/lib/validate/confidential-names.mjs +95 -30
- package/scripts/lib/validate/enumerate-repo-files.mjs +317 -0
- package/scripts/lib/validate/repo-files.mjs +48 -14
- package/scripts/lib/vault-backfill/template.mjs +63 -6
- package/scripts/lib/vault-mirror/process.mjs +165 -42
- package/scripts/lib/vault-mirror/telemetry.mjs +2 -2
- package/scripts/lib/vault-status/narrative-mirror.mjs +127 -18
- package/scripts/lib/wave-executor/dispatch-common.mjs +164 -0
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +7 -142
- package/scripts/lib/wave-executor/remote-dispatch.mjs +5 -7
- package/scripts/lib/wave-resource-gate.mjs +8 -2
- package/scripts/lib/wave-sizing.mjs +4 -1
- package/scripts/lib/wave-transcript-tail.mjs +118 -4
- package/scripts/materialize-wave-scope.mjs +12 -5
- package/scripts/memory-propose.mjs +19 -5
- package/scripts/migrate-cold-start-seed.mjs +4 -1
- package/scripts/parse-config.mjs +60 -3
- package/scripts/release.mjs +430 -31
- package/scripts/repair-invalid-sessions.mjs +3 -3
- package/scripts/run-quality-gate.mjs +128 -11
- package/scripts/site-numbers.mjs +344 -8
- package/scripts/sweep-expired-learnings.mjs +90 -0
- package/scripts/sync-vault-schema.mjs +3 -1
- package/scripts/telemetry.mjs +2 -2
- package/scripts/validate-plugin.mjs +164 -0
- package/scripts/validate-wave-scope.mjs +28 -8
- package/scripts/wave-scope-binding.mjs +215 -0
- package/skills/_shared/instruction-file-resolution.md +10 -0
- package/skills/_shared/parallel-aware-preamble.md +1 -0
- package/skills/_shared/platform-tools.md +1 -1
- package/skills/_shared/state-ownership.md +1 -1
- package/skills/architecture/SKILL.md +7 -5
- package/skills/{domain-model/SKILL.md → architecture/references/domain-model.md} +9 -9
- package/skills/autopilot/SKILL.md +4 -18
- package/skills/claude-md-drift-check/SKILL.md +5 -1
- package/skills/claude-md-drift-check/checker.mjs +62 -2
- package/skills/convergence-monitoring/SIGNALS.md +55 -0
- package/skills/discovery/probes/vault-staleness.mjs +37 -13
- package/skills/discovery/probes-arch.md +20 -18
- package/skills/dispatcher/SKILL.md +3 -2
- package/skills/evolve/SKILL.md +65 -26
- package/skills/frontmatter-guard/SKILL.md +11 -5
- package/skills/npm-publish/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +33 -0
- package/skills/remote-offload/SKILL.md +1 -1
- package/skills/session-end/SKILL.md +18 -905
- package/skills/session-end/phase-3-6-tail.md +10 -3
- package/skills/session-end/plan-verification.md +221 -155
- package/skills/session-end/references/phase-2-quality-gate.md +93 -0
- package/skills/session-end/references/phase-3-documentation-updates.md +229 -0
- package/skills/session-end/references/phase-4a-worktree-cleanup.md +120 -0
- package/skills/session-end/references/phase-4b-worktree-orphan-sweep.md +58 -0
- package/skills/session-end/references/phase-5-issue-cleanup.md +104 -0
- package/skills/session-end/references/session-summary-template.md +62 -0
- package/skills/session-plan/SKILL.md +49 -0
- package/skills/session-start/SKILL.md +22 -904
- package/skills/session-start/phase-8-5-express-path.md +1 -1
- package/skills/session-start/references/phase-1-1-dispatcher-autonomy-capture.md +55 -0
- package/skills/session-start/references/phase-1-2-session-lock.md +140 -0
- package/skills/session-start/references/phase-1-5-session-continuity.md +254 -0
- package/skills/session-start/references/phase-1-7-vault-status-board.md +53 -0
- package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +75 -0
- package/skills/session-start/references/phase-4-ssot-environment-check.md +160 -0
- package/skills/session-start/references/phase-6-5-forced-reads.md +75 -0
- package/skills/session-start/references/phase-6-6-project-intelligence.md +81 -0
- package/skills/session-start/references/phase-6-7-memory-banner-telemetry-consent.md +103 -0
- package/skills/vault-sync/SKILL.md +10 -0
- package/skills/vault-sync/validator.mjs +21 -27
- package/skills/wave-executor/SKILL.md +15 -1
- package/skills/wave-executor/references/wave-loop-dispatch.md +612 -0
- package/skills/wave-executor/references/wave-loop-review.md +570 -0
- package/skills/wave-executor/references/wave-loop-scope-manifest.md +162 -0
- package/skills/wave-executor/wave-loop.md +14 -1309
- package/templates/_shared/journey-manifest.md +10 -6
- package/.cursor/commands/autopilot-multi.md +0 -14
- package/.cursor/commands/contract-version-bump.md +0 -14
- package/.cursor/commands/journey-audit.md +0 -14
- package/.cursor/skills/contract-version-bump/SKILL.md +0 -12
- package/.cursor/skills/daily/SKILL.md +0 -12
- package/.cursor/skills/domain-model/SKILL.md +0 -13
- package/.cursor/skills/journey-audit/SKILL.md +0 -13
- package/.cursor/skills/skill-creator/SKILL.md +0 -13
- package/.cursor/skills/ubiquitous-language/SKILL.md +0 -13
- package/commands/autopilot-multi.md +0 -74
- package/commands/contract-version-bump.md +0 -28
- package/commands/journey-audit.md +0 -43
- package/pi/prompts/autopilot-multi.md +0 -12
- package/pi/prompts/contract-version-bump.md +0 -12
- package/pi/prompts/journey-audit.md +0 -12
- package/scripts/autopilot-multi.mjs +0 -885
- package/scripts/backfill-learnings-expires.mjs +0 -196
- package/scripts/backfill-learnings.mjs +0 -203
- package/scripts/fleet-instruction-scan.mjs +0 -141
- package/scripts/lib/autopilot/dep-graph.mjs +0 -417
- package/scripts/lib/autopilot/multi-killswitch.mjs +0 -184
- package/scripts/lib/webhook-url.mjs +0 -105
- package/scripts/lifecycle-sim-v6.mjs +0 -347
- package/scripts/migrate-learnings-jsonl.mjs +0 -189
- package/scripts/migrate-subagents-jsonl.mjs +0 -196
- package/scripts/upload-social-preview.mjs +0 -316
- package/skills/_shared/model-selection.md +0 -64
- package/skills/contract-version-bump/SKILL.md +0 -219
- package/skills/daily/SKILL.md +0 -222
- package/skills/daily/generate.sh +0 -92
- package/skills/daily/templates/daily.md.tpl +0 -36
- package/skills/journey-audit/SKILL.md +0 -270
- package/skills/skill-creator/SKILL.md +0 -168
- package/skills/ubiquitous-language/SKILL.md +0 -97
- package/skills/vault-sync/package-lock.json +0 -40
- /package/skills/{domain-model → architecture/references}/ADR-FORMAT.md +0 -0
- /package/skills/{domain-model → architecture/references}/CONTEXT-FORMAT.md +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Single source of truth for the parallel-session-detection preamble.
|
|
4
4
|
> Referenced by: autopilot, session-start, session-plan, wave-executor, session-end (5 orchestrator entry-points).
|
|
5
|
+
> Design history: the 2026-05-26 parallel-aware-sessions spec is superseded on lock liveness (heartbeat, not PID) — see `docs/README.md` § Superseded design notes.
|
|
5
6
|
|
|
6
7
|
## Purpose
|
|
7
8
|
|
|
@@ -70,7 +70,7 @@ Lifecycle: `spawn_agent` (launch, one per wave task) → `list_agents` (enumerat
|
|
|
70
70
|
- **session-reviewer** — quality review; spawn as a separate agent rather than reviewing in the main session
|
|
71
71
|
|
|
72
72
|
**On Cursor IDE:**
|
|
73
|
-
No native Agent() tool or typed agent roles inside the Composer session — wave tasks run sequentially there, and `agents-per-wave` is ignored. This is a statement about the IDE session only: coordinator-side foreign dispatch to Cursor models via the headless `cursor-agent` CLI does exist (`scripts/lib/wave-executor/foreign-dispatch.mjs`, #1150 — detached worktree, filesystem-measured result, `orchestrator.foreign_dispatch.completed` telemetry, mandatory Claude review, `NEVER_FOREIGN_ROLES` lock). Measured 2026-08-25 on `cursor-agent 2026.08.11-e8db854`. Slash commands live in `.cursor/commands/`. There is no Skill tool — Read `skills/<name>/SKILL.md` instead.
|
|
73
|
+
No native Agent() tool or typed agent roles inside the Composer session — wave tasks run sequentially there, and `agents-per-wave` is ignored. This is a statement about the IDE session only: coordinator-side foreign dispatch to Cursor models via the headless `cursor-agent` CLI does exist (`scripts/lib/wave-executor/foreign-dispatch.mjs`, #1150 — detached worktree, filesystem-measured result, `orchestrator.foreign_dispatch.completed` telemetry, mandatory Claude review, `NEVER_FOREIGN_ROLES` lock in `scripts/lib/wave-executor/dispatch-common.mjs`). Measured 2026-08-25 on `cursor-agent 2026.08.11-e8db854`. Slash commands live in `.cursor/commands/`. There is no Skill tool — Read `skills/<name>/SKILL.md` instead.
|
|
74
74
|
|
|
75
75
|
**On Pi:**
|
|
76
76
|
No Session Orchestrator Pi subagent dispatcher exists in v1. Execute wave tasks sequentially in the active Pi session. Treat `agents-per-wave` as advisory until the SDK-based dispatcher lands.
|
|
@@ -147,7 +147,7 @@ This is the wave-plan-time analog of PSA-007 (subagents never race the shared gi
|
|
|
147
147
|
|
|
148
148
|
The rule above deconflicts writers *inside one wave*. The same working copy is also shared across SESSIONS, and `<state-dir>/wave-scope.json` is the one control artefact that constrains writes rather than describing them. It lives in the working copy, not in the session — so before #1123 a manifest written by session A governed session B's every Edit. Measured 2026-08-22 (#1082): a Discovery wave's `allowedPaths: []` — prescribed for every Discovery wave — denied all writes of an unrelated parallel session, with a deny reason that could only tell it to fix a wave plan it does not own.
|
|
149
149
|
|
|
150
|
-
**The manifest is SESSION-BOUND since #1123.** The coordinator that writes it names itself in two optional fields, `
|
|
150
|
+
**The manifest is SESSION-BOUND since #1123.** The coordinator that writes it names itself in two optional fields, `session_id` (the raw harness session id) and `semantic_session_id` (renamed from `session` / `semantic_session` in #1153 P2 to match `session.lock` and `current-session.json`; the legacy pair is still READ until the next minor release), both from ONE `sessionAttribution(repoRoot)` call (`scripts/lib/events.mjs`) — see `skills/wave-executor/wave-loop.md` § Scope Manifest 1. `hooks/enforce-scope.mjs` Gate 3b classifies the manifest with `readProcessLocalSessionIds()` + `classifyManifestSession()` (`scripts/lib/session-identity/own-session.mjs`) — process-local tiers only (hook payload, `CLAUDE_CODE_SESSION_ID`), never the repo-global `session.lock`, which is shared by every session in the checkout and made a peer's manifest read `own` (#1194):
|
|
151
151
|
|
|
152
152
|
- **`foreign`** (ids present, none of them ours) → the gate ALLOWS the write and emits one `orchestrator.scope.foreign_session_ignored` event. A foreign manifest is somebody else's wave plan; it never had authority here, and the event keeps the skip counted rather than silent.
|
|
153
153
|
- **`own`** → enforce, unchanged.
|
|
@@ -30,7 +30,9 @@ Key principles (see [LANGUAGE.md](LANGUAGE.md) for the full list):
|
|
|
30
30
|
- **The interface is the test surface.**
|
|
31
31
|
- **One adapter = hypothetical seam. Two adapters = real seam.**
|
|
32
32
|
|
|
33
|
-
This skill is _informed_ by the project's domain model — `CONTEXT.md` and any `docs/adr/`. The domain language gives names to good seams; ADRs record decisions the skill should not re-litigate. See [CONTEXT-FORMAT.md](
|
|
33
|
+
This skill is _informed_ by the project's domain model — `CONTEXT.md` and any `docs/adr/`. The domain language gives names to good seams; ADRs record decisions the skill should not re-litigate. See [references/CONTEXT-FORMAT.md](./references/CONTEXT-FORMAT.md) and [references/ADR-FORMAT.md](./references/ADR-FORMAT.md).
|
|
34
|
+
|
|
35
|
+
**When to load [references/domain-model.md](./references/domain-model.md):** before this skill's first pass on a repo with no `CONTEXT.md` yet, or one too thin to name the seams below — run its grilling interview to establish the domain vocabulary first. Skip it once `CONTEXT.md` already reflects the domain.
|
|
34
36
|
|
|
35
37
|
## Process
|
|
36
38
|
|
|
@@ -45,7 +47,7 @@ If any of these files don't exist, proceed silently — don't flag their absence
|
|
|
45
47
|
|
|
46
48
|
**Optional pre-pass — export inventory injection (mapper-supported projects only):**
|
|
47
49
|
|
|
48
|
-
Before dispatching the Explore subagent,
|
|
50
|
+
Before dispatching the Explore subagent, read each known entry-point file (e.g. `index.ts`, `src/index.ts`, the main export barrel) and pass its contents to `extractSemanticSlices(filePath, content)` from `scripts/lib/language-mappers/index.mjs`. The signature is `(filePath, content, options?)` — the second argument is the raw file text, **not** an options object, and there is no slice-kind filter parameter. It resolves to an array of `SemanticSlice` records (`{ kind, name, exported, … }`); keep the ones with `exported === true`, format them as structured context, and inject that into the Explore subagent prompt. This gives the subagent an immediate map of the codebase's public surface without requiring it to grep manually.
|
|
49
51
|
|
|
50
52
|
```
|
|
51
53
|
## Export inventory (auto-generated)
|
|
@@ -53,7 +55,7 @@ Before dispatching the Explore subagent, call `extractSemanticSlices(filePath, {
|
|
|
53
55
|
- src/lib/bar.ts: exports `processBar`
|
|
54
56
|
```
|
|
55
57
|
|
|
56
|
-
This pre-pass is OPTIONAL — only activate when the entry-point file is mapper-supported (
|
|
58
|
+
This pre-pass is OPTIONAL — only activate when the entry-point file is mapper-supported (`.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs`, `.md`, `.mdx`, `.swift`, `.py` — the `EXT_TO_LANG` map in `index.mjs` is the source of truth). For any other extension `extractSemanticSlices` **throws** rather than returning an empty array, so wrap the call in a try/catch and skip the pre-pass silently on failure. Never block Explore dispatch on a mapper error.
|
|
57
59
|
|
|
58
60
|
Then use the Agent tool with `subagent_type=Explore` to walk the codebase. Don't follow rigid heuristics — explore organically and note where you experience friction:
|
|
59
61
|
|
|
@@ -86,7 +88,7 @@ Once the user picks a candidate, drop into a grilling conversation. Walk the des
|
|
|
86
88
|
|
|
87
89
|
Side effects happen inline as decisions crystallize:
|
|
88
90
|
|
|
89
|
-
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as
|
|
91
|
+
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as the domain-model grilling reference (see [references/CONTEXT-FORMAT.md](./references/CONTEXT-FORMAT.md)). Create the file lazily if it doesn't exist.
|
|
90
92
|
- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there.
|
|
91
|
-
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See [ADR-FORMAT.md](
|
|
93
|
+
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See [references/ADR-FORMAT.md](./references/ADR-FORMAT.md).
|
|
92
94
|
- **Want to explore alternative interfaces for the deepened module?** See [INTERFACE-DESIGN.md](INTERFACE-DESIGN.md).
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
model:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
# Domain-Model Grilling (reference)
|
|
2
|
+
|
|
3
|
+
> Reference material for the `architecture` skill — **not a skill of its own.**
|
|
4
|
+
> Merged here in v4.0.0 from the former `skills/domain-model/` (retired: zero
|
|
5
|
+
> telemetry, zero fleet invocations, reference-only usage — see
|
|
6
|
+
> `docs/audits/2026-09-06-360-audit.md` § 5A). Invoke it by reading this file
|
|
7
|
+
> from `/architecture`, not via a slash command.
|
|
8
|
+
>
|
|
9
|
+
> Adapted from [`mattpocock/skills@90ea8ee`](https://github.com/mattpocock/skills/tree/main/domain-model), MIT — Copyright (c) 2026 Matt Pocock. See the repo-root `NOTICE`.
|
|
10
10
|
|
|
11
11
|
Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.
|
|
12
12
|
|
|
@@ -377,24 +377,10 @@ identically by readers per the v1 schema additive convention).
|
|
|
377
377
|
|
|
378
378
|
## Configuration
|
|
379
379
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
bg-isolation: worktree # worktree | none (default: worktree) — see #431
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
### bg-isolation
|
|
388
|
-
|
|
389
|
-
**Type:** `worktree` | `none` — **Default:** `worktree`
|
|
390
|
-
|
|
391
|
-
Controls whether `autopilot --multi-story` creates a per-story git worktree before spawning sub-sessions.
|
|
392
|
-
|
|
393
|
-
`worktree` (default): Each story pipeline receives its own isolated git worktree via `EnterWorktree`. Parallel writes are safe because every agent edits a private working copy. Cost: disk space proportional to the number of concurrent stories plus the latency of worktree creation at story-start.
|
|
394
|
-
|
|
395
|
-
`none` (opt-in): No worktrees are created. Sub-sessions spawn directly in the main working tree. Useful for monorepos where worktree creation is impractical due to large `node_modules`, sparse-checkout setups, or build caches that must be shared. **Requires file-scope discipline:** when `max-stories > 1`, every story must edit a disjoint set of files. If two stories touch the same file simultaneously, edits will collide silently. To enforce acknowledgement of this discipline, `autopilot-multi` requires `--deconflict-paths=<glob>` whenever `bg-isolation: none` AND `max-stories > 1`; omitting the flag is a hard error (exit 1). See `.claude/rules/parallel-sessions.md` PSA-001/002/003.
|
|
396
|
-
|
|
397
|
-
**Operator-awareness note:** CC 2.1.133 silently flipped `worktree.baseRef` default from `head` to `origin/<default>`, breaking users who relied on unpushed commits being included in their worktree base. The same class of upstream change can affect `bg-isolation` semantics in a future CC release. Treat CC changelog entries related to worktree or `--bg` session behaviour as requiring a re-read of this section before upgrading.
|
|
380
|
+
Single-story `/autopilot` takes no Session Config block. Multi-story
|
|
381
|
+
(`autopilot.bg-isolation`, `--multi-story`, `--deconflict-paths`) was removed in
|
|
382
|
+
4.0.0 — see `docs/migration-v4.md` and `docs/session-config-reference.md` §
|
|
383
|
+
"Autopilot Multi-Story (#431) — removed".
|
|
398
384
|
|
|
399
385
|
## References
|
|
400
386
|
|
|
@@ -39,7 +39,7 @@ PHASE 1 IMPLEMENTED (2026-04-19). Session-end opt-in quality gate. Upstream of `
|
|
|
39
39
|
| 4 | `session-file-existence` | `50-sessions/YYYY-MM-DD-*.md` references anywhere in scope | `existsSync(vault/50-sessions/<file>)` |
|
|
40
40
|
| 5 | `command-count` | "N commands" / "N /commands" claims in prose | compare to `ls commands/*.md \| wc -l`; skipped if no `commands/` dir |
|
|
41
41
|
| 6 | `session-config-parity` | Top-level keys under `## Session Config` in `CLAUDE.md` / `AGENTS.md` | diff against `docs/session-config-template.md`; a missing MANDATORY (minimal-baseline) key is an error, a missing OPT-IN-baseline-only key is a warning |
|
|
42
|
-
| 7 | `vault-dir-parity` | `vault-integration.vault-dir` in BOTH `CLAUDE.md` AND `AGENTS.md` | reuse `_parseVaultIntegration`; flag when the two files disagree |
|
|
42
|
+
| 7 | `vault-dir-parity` | `vault-integration.vault-dir` in BOTH `CLAUDE.md` AND `AGENTS.md` | reuse `_parseVaultIntegration`; flag when the two files disagree. Short-circuits to PASS when the two are the SAME file by construction (symlink / same inode / byte-identical generated copy) |
|
|
43
43
|
| 8 | `generated-rule-staleness` *(WARN only)* | `.claude/rules/*.md` with `auto-generated: true` frontmatter | extract `learning-key`; WARN when the key is absent from `.orchestrator/metrics/learnings.jsonl` or its learning's `expires_at` is in the past; skipped silently when no auto-generated rules exist |
|
|
44
44
|
| 9 | `rule-scoping` | `.claude/rules/*.md` frontmatter + `## See Also` footers + `.claude/rules/<name>.md` citations in `CLAUDE.md`/`AGENTS.md` | five probes: `paths:` frontmatter (error), cited-but-missing rule citations (error), zero-match `globs:` patterns (warn), foreign PascalCase glob tokens (warn), unreadable rule files (warn — surfaced instead of silently skipped); skipped silently when `.claude/rules/` is absent |
|
|
45
45
|
| 10 | `docs-parity` | `docs/components.md` count-claims, Session Config key parity (`docs/session-config-template.md` vs `docs/session-config-reference.md`), `.claude/metrics/` stale-path references in `docs/*.md` / `docs/examples/*.md` | three sub-checks (a/b/c) — see below; skipped silently when `docs/components.md` is absent |
|
|
@@ -61,6 +61,10 @@ A local CLAUDE.md / AGENTS.md that omits any of these now surfaces a `session-co
|
|
|
61
61
|
|
|
62
62
|
Check 7 (issue #600) is the **only** check that intentionally reads BOTH instruction files rather than the single alias-resolved one. The alias rule (CLAUDE.md wins ties, AGENTS.md is the Codex alias) means `resolveInstructionFile()` picks exactly one — so a repo carrying both files can silently let `AGENTS.md` drift out of sync with `CLAUDE.md`. A sibling project ran for weeks with a correct `vault-integration.vault-dir` in `CLAUDE.md` and a dead path in `AGENTS.md`. Check 7 reads `vault-integration.vault-dir` from each file (reusing the `_parseVaultIntegration` parser from `scripts/lib/config/vault-integration.mjs` — no hand-rolled YAML) and flags a `vault-dir-parity` error when the two values diverge (the error is attributed to `AGENTS.md`, the secondary alias, and names both values). The check skips gracefully when only one instruction file is present (nothing to compare), when neither file declares a `vault-integration:` block, or when explicitly disabled via `--skip-vault-dir-parity`. Two files that both omit `vault-dir` (both unset) agree and pass.
|
|
63
63
|
|
|
64
|
+
**Alias-by-construction short-circuit.** Since this repo's root `AGENTS.md` became a GENERATED byte-identical copy of `CLAUDE.md` (`scripts/generate-agents-skills.mjs`), Check 7 no longer skips here — it RUNS on every invocation. Two files that cannot disagree have nothing to diff, so the check reports parity as satisfied without deriving one: `instructionFilesAreAliased()` recognises a symlink resolving to the same path, the same inode/device (hardlink or already-resolved symlink), and byte-identical content. Branch order is load-bearing: the "neither file has a `vault-integration:` block" skip is evaluated FIRST, because an absent subject is a different (and more informative) outcome than "the files cannot disagree". The error class the check exists for is untouched — two INDEPENDENT files that declare different `vault-dir` values still produce the `vault-dir-parity` error attributed to `AGENTS.md`.
|
|
65
|
+
|
|
66
|
+
The same predicate guards Check 9's probe 2a, which iterates `['CLAUDE.md', 'AGENTS.md']`: with an aliased `AGENTS.md` it scans `CLAUDE.md` only, because otherwise every dangling `.claude/rules/*.md` citation would be reported TWICE — one defect, two errors, and in `--mode strict` a doubled blocking surface against a file the operator is not allowed to edit.
|
|
67
|
+
|
|
64
68
|
Check 9 (`rule-scoping`) validates `.claude/rules/*.md` frontmatter against the `scripts/lib/rule-loader.mjs` contract, catching the class of defect where a rule silently drifts out of the activation pipeline the loader actually implements. Four probes: **(1) paths-presence** — a top-level `paths:` frontmatter key is not a key `rule-loader.mjs` recognises (it only reads `globs:`), so a rule with `paths:` silently loads ALWAYS-ON regardless of intended file scope; flagged as an error. **(2) cited-but-missing** — `(a)` `.claude/rules/<name>.md` citations inside `CLAUDE.md`/`AGENTS.md` that don't resolve to a file on disk, and `(b)` bare `<name>.md` tokens in a rule's own `## See Also` footer that don't exist as sibling rule files (tokens carrying a path separator, e.g. `../../skills/_shared/state-ownership.md`, are cross-directory references and explicitly out of scope); both flagged as errors. **(3) zero-match-globs** — a `globs:` pattern matching zero files in `git ls-files` (falls back to a manual directory walk when git is unavailable); flagged as a WARNING, not an error, because library/exemplar repos legitimately carry dead stack rules (this repo alone carries ~37 by design — Swift/Next.js/Supabase rules with no matching files in a pure-Node-ESM codebase). **(4) foreign-glob** — a glob pattern containing a PascalCase product-like token (regex `[A-Z][a-z]+[A-Z]`, e.g. `WalkAITalkieTests`) — a likely copy-paste leftover from another project's rule scope; flagged as a WARNING. Glob matching reuses the same picomatch-with-inline-fallback resolution `scripts/lib/rule-loader.mjs` uses (`parseGlobsFrontmatter` is imported directly; the picomatch resolution itself is duplicated locally since `rule-loader.mjs` does not export a public matcher function). The check is skipped silently (no `checks_run` entry, no `checks_skipped` entry) when `.claude/rules/` is absent, or explicitly via `--skip-rule-scoping`.
|
|
65
69
|
|
|
66
70
|
Check 10 (`docs-parity`, issue #780) validates the public docs surface against live repository state via three sub-checks, all reported under the single `docs-parity` check id: **(a) count-claims** — `docs/components.md`'s own heading counts ("## Skills (N user-facing)", "## Commands (N)", "## Agents (N typed sub-agents)", "## Hook event types (N)") are compared against the SAME actual on-disk derivation the surface-count family (Check 5) uses (`countSkills`/the commands-dir listing/`countAgents`/`readHookCounts`) — NOT Check 5's `claimRe` regexes, which are tuned for CLAUDE.md/README prose phrasing and verifiably do not match `components.md`'s own heading convention; a dedicated set of regexes tailored to the doc's actual authored structure is used instead. **(b) config-block-parity** — top-level Session Config keys documented in `docs/session-config-template.md` (opt-in baseline, via the Check 6 'last'-occurrence extractor) are compared against `docs/session-config-reference.md`; a key is considered documented in the reference when it appears in a `yaml` fence (any indent), a `##`/`###`/`####` heading, or the first cell of a markdown table row (`` | `key-name` | ... ``) — the reference's dominant documentation shape is one table row per field, so a naive fence-only extraction under-counts what it actually documents. Missing keys surface as `docs-parity` errors attributed to `docs/session-config-reference.md`. **(c) metrics-path-liveness** — any `.claude/metrics/` path reference (stale; canonical is `.orchestrator/metrics/`) found in root `docs/*.md` or `docs/examples/*.md` surfaces as an error at its exact file/line. The whole check is skipped silently (no `checks_run` entry, no `checks_skipped` entry) when `docs/components.md` is absent, or explicitly via `--skip-docs-parity`.
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* rule-loader.mjs uses); otherwise pure Node stdlib.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';
|
|
31
|
+
import { readFileSync, readdirSync, existsSync, statSync, lstatSync, realpathSync } from 'node:fs';
|
|
32
32
|
import { join, relative, resolve } from 'node:path';
|
|
33
33
|
import { execFileSync } from 'node:child_process';
|
|
34
34
|
import { createRequire } from 'node:module';
|
|
@@ -294,6 +294,45 @@ function readVaultIntegration(filePath) {
|
|
|
294
294
|
return { present, vaultDir: parsed['vault-dir'] };
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Are the two instruction files the SAME file by construction?
|
|
299
|
+
*
|
|
300
|
+
* Since the cross-harness portable surface landed, this repo's root `AGENTS.md`
|
|
301
|
+
* is GENERATED from `CLAUDE.md` (`scripts/generate-agents-skills.mjs`) as a
|
|
302
|
+
* byte-identical copy, and a consumer repo may instead symlink it. Three shapes
|
|
303
|
+
* therefore count as aliased: a symlink resolving to the same path, the same
|
|
304
|
+
* inode/device (symlink already resolved, or a hardlink), and byte-identical
|
|
305
|
+
* content.
|
|
306
|
+
*
|
|
307
|
+
* This matters because Check 7 exists to catch TWO INDEPENDENT files that
|
|
308
|
+
* disagree. Files that cannot disagree have nothing to diff — running the
|
|
309
|
+
* comparison on them would turn a check that skipped for years into a source of
|
|
310
|
+
* spurious findings the moment AGENTS.md appears. Check 9's probe 2a uses the
|
|
311
|
+
* same predicate to avoid reporting every CLAUDE.md defect twice.
|
|
312
|
+
*
|
|
313
|
+
* @param {string} pathA
|
|
314
|
+
* @param {string} pathB
|
|
315
|
+
* @returns {boolean}
|
|
316
|
+
*/
|
|
317
|
+
function instructionFilesAreAliased(pathA, pathB) {
|
|
318
|
+
if (!existsSync(pathA) || !existsSync(pathB)) return false;
|
|
319
|
+
try {
|
|
320
|
+
if (lstatSync(pathA).isSymbolicLink() || lstatSync(pathB).isSymbolicLink()) {
|
|
321
|
+
if (realpathSync(pathA) === realpathSync(pathB)) return true;
|
|
322
|
+
}
|
|
323
|
+
const a = statSync(pathA);
|
|
324
|
+
const b = statSync(pathB);
|
|
325
|
+
if (a.ino !== 0 && a.ino === b.ino && a.dev === b.dev) return true;
|
|
326
|
+
} catch {
|
|
327
|
+
// stat/realpath failure (race, permissions) — fall back to bytes
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
return readFileSync(pathA).equals(readFileSync(pathB));
|
|
331
|
+
} catch {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
297
336
|
function classifySection(heading) {
|
|
298
337
|
if (!heading) return null;
|
|
299
338
|
if (BACKWARD_HEADING_RE.test(heading)) return 'backward';
|
|
@@ -881,7 +920,19 @@ function main() {
|
|
|
881
920
|
const claudeVi = readVaultIntegration(claudePath);
|
|
882
921
|
const agentsVi = readVaultIntegration(agentsPath);
|
|
883
922
|
if (!claudeVi.present && !agentsVi.present) {
|
|
923
|
+
// Nothing to compare — the SUBJECT of the check is absent from both
|
|
924
|
+
// files. This branch precedes the alias short-circuit on purpose: an
|
|
925
|
+
// absent vault-integration block is a different (and more informative)
|
|
926
|
+
// outcome than "the files cannot disagree".
|
|
884
927
|
checksSkipped.push('vault-dir-parity: neither file has a vault-integration: block');
|
|
928
|
+
} else if (instructionFilesAreAliased(claudePath, agentsPath)) {
|
|
929
|
+
// Identical by construction (generated copy, symlink, or hardlink) —
|
|
930
|
+
// parity is SATISFIED, so the check RAN and found nothing. Reporting
|
|
931
|
+
// this as a skip would be wrong too: the invariant Check 7 guards is
|
|
932
|
+
// actively held here, it is simply held mechanically rather than by
|
|
933
|
+
// agreement, and re-deriving a diff between one file and itself can
|
|
934
|
+
// only manufacture noise.
|
|
935
|
+
vaultDirParityRan = true;
|
|
885
936
|
} else {
|
|
886
937
|
vaultDirParityRan = true;
|
|
887
938
|
const claudeDir = claudeVi.vaultDir;
|
|
@@ -1182,7 +1233,16 @@ function main() {
|
|
|
1182
1233
|
}
|
|
1183
1234
|
|
|
1184
1235
|
// --- Probe 2a: cited-but-missing (CLAUDE.md / AGENTS.md citations) → errors[] ---
|
|
1185
|
-
|
|
1236
|
+
// AGENTS.md is scanned as a SECOND file only when it is genuinely
|
|
1237
|
+
// independent. When it is an alias of CLAUDE.md (this repo generates it
|
|
1238
|
+
// byte-identically), scanning both would report every dangling citation
|
|
1239
|
+
// TWICE — one defect, two errors, and in `--mode strict` a doubled exit
|
|
1240
|
+
// surface for a file the operator cannot edit.
|
|
1241
|
+
const aliasedInstruction = instructionFilesAreAliased(
|
|
1242
|
+
join(vaultDir, 'CLAUDE.md'), join(vaultDir, 'AGENTS.md'),
|
|
1243
|
+
);
|
|
1244
|
+
const instrNames = aliasedInstruction ? ['CLAUDE.md'] : ['CLAUDE.md', 'AGENTS.md'];
|
|
1245
|
+
for (const instrName of instrNames) {
|
|
1186
1246
|
const filePath = join(vaultDir, instrName);
|
|
1187
1247
|
if (!existsSync(filePath) || !statSync(filePath).isFile()) continue;
|
|
1188
1248
|
const fcontent = readFileSync(filePath, 'utf8');
|
|
@@ -32,6 +32,34 @@ PEAK_DIFF_SIZE=$(jq -s 'map(.diff_size) | max' <<< "$WAVE_HISTORY_JSON")
|
|
|
32
32
|
SD_VALUE=$(echo "scale=3; $WAVE_DIFF_SIZE / $PEAK_DIFF_SIZE" | bc)
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
### Live monitor input (`scripts/lib/convergence-monitor.mjs`)
|
|
36
|
+
|
|
37
|
+
The `shrinking_diff` NDJSON signal compares `files_changed` across two
|
|
38
|
+
consecutive `orchestrator.wave.completed` records. Until 2026-09-05 **no
|
|
39
|
+
producer wrote that key** — 144 such records in
|
|
40
|
+
`.orchestrator/metrics/events.jsonl`, none carrying a measurement key, so the
|
|
41
|
+
signal was structurally dead. The emitter is now
|
|
42
|
+
`hooks/post-tool-batch-wave-signal.mjs` (#980): at an N→N+1 wave transition its
|
|
43
|
+
`orchestrator.wave.completed` for wave N carries
|
|
44
|
+
|
|
45
|
+
- `files_changed` — the DEDUPED count of `git diff --name-only <wave_start_sha>`
|
|
46
|
+
∪ `git ls-files --others --exclude-standard`, and
|
|
47
|
+
- `files_changed_source: 'worktree-vs-wave-start-sha'` — how it was measured.
|
|
48
|
+
|
|
49
|
+
`wave_start_sha` is the `git rev-parse HEAD` the same hook persists into
|
|
50
|
+
`.orchestrator/current-session.json` when wave N is opened. The comparison is
|
|
51
|
+
against the WORKING TREE, not `<sha>..HEAD`, because the coordinator commits at
|
|
52
|
+
session close rather than per wave.
|
|
53
|
+
|
|
54
|
+
**Both keys are optional, and absent is not zero.** Any git failure, a 1.5 s
|
|
55
|
+
timeout, or a missing `wave_start_sha` omits them; the monitor reads the absence
|
|
56
|
+
as `null` and `shrinking_diff` simply does not fire. Two records carry no
|
|
57
|
+
measurement by construction: the final wave's completion from
|
|
58
|
+
`hooks/on-session-end.mjs` (no wave-open transition ran there, so it has no
|
|
59
|
+
start sha) and any completion emitted from an explicit injected `wave_signal`.
|
|
60
|
+
The git/jq recipe above is the SKILL-level computation and is independent of the
|
|
61
|
+
monitor.
|
|
62
|
+
|
|
35
63
|
### Thresholds
|
|
36
64
|
|
|
37
65
|
| SD value | Interpretation |
|
|
@@ -99,6 +127,22 @@ PR_PRIOR=$(echo "$PASS_RATES" | jq '.[length - 2] // 0')
|
|
|
99
127
|
If `quality.incremental` events are absent (test runner not configured), set
|
|
100
128
|
`PR_confidence = 0.0` and trend = `plateau` (neutral; do not block on missing data).
|
|
101
129
|
|
|
130
|
+
### Live monitor input (`scripts/lib/convergence-monitor.mjs`)
|
|
131
|
+
|
|
132
|
+
The `pass_rate_plateau` NDJSON signal reads the **quality-gate envelope**:
|
|
133
|
+
`orchestrator.quality_gate.passed` / `.failed` records carrying BOTH
|
|
134
|
+
`wave_number` and a well-formed `counts` object. It folds `counts.passed` into
|
|
135
|
+
the wave's pass count (and `counts.failed` alongside it), then fires when two
|
|
136
|
+
consecutive waves report the identical pass count. Measured 2026-09-05: 33 such
|
|
137
|
+
records in `.orchestrator/metrics/events.jsonl`; the flat `test.passed` key the
|
|
138
|
+
reader also accepts has **0** producers and is kept only as an alias for a future
|
|
139
|
+
direct emitter.
|
|
140
|
+
|
|
141
|
+
The `wave_number` + `counts` pair is a type-AND-shape gate, not a prefix
|
|
142
|
+
widening: a session-level gate run (no `wave_number`) must stay invisible to the
|
|
143
|
+
monitor, because admitting it would instantiate a `WaveSummary` per gate run and
|
|
144
|
+
burn the once-per-wave emit keys before the real wave record arrives (#966).
|
|
145
|
+
|
|
102
146
|
### Thresholds
|
|
103
147
|
|
|
104
148
|
| PR value | Interpretation |
|
|
@@ -160,6 +204,17 @@ VEL_LINES=$(git diff --shortstat "$WAVE_START_REF" "$WAVE_END_REF" \
|
|
|
160
204
|
VEL_LINES_PRIOR=<read from events.jsonl for wave N-1>
|
|
161
205
|
```
|
|
162
206
|
|
|
207
|
+
### Live monitor input (`scripts/lib/convergence-monitor.mjs`)
|
|
208
|
+
|
|
209
|
+
The `velocity_drop` NDJSON signal counts **one `orchestrator.agent.stopped`
|
|
210
|
+
record per dispatched agent** (wave read from `wave` or `wave_number`) and fires
|
|
211
|
+
when the later wave stopped fewer agents than the earlier one. Measured
|
|
212
|
+
2026-09-05 over `.orchestrator/metrics/events.jsonl`: 11,754
|
|
213
|
+
`orchestrator.agent.stopped` records versus **0** for the `agent.dispatched` type
|
|
214
|
+
the reader also accepts — `agent.stopped` is the only per-agent record this repo
|
|
215
|
+
actually emits with a wave number. The git-based `VEL_COMMITS` / `VEL_LINES`
|
|
216
|
+
recipe above is the SKILL-level computation and is independent of the monitor.
|
|
217
|
+
|
|
163
218
|
### Thresholds
|
|
164
219
|
|
|
165
220
|
| Condition | Interpretation |
|
|
@@ -10,12 +10,21 @@
|
|
|
10
10
|
* Output: {findings[], metrics, duration_ms, [skipped_reason]}. Never throws.
|
|
11
11
|
* Also appends one JSONL summary record to .orchestrator/metrics/vault-staleness.jsonl.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
13
|
+
* Denominator (GitLab #1238): staleness is `lastCommit - lastSync` — how far the
|
|
14
|
+
* upstream repo advanced PAST the last sync — not `now - lastSync`. A mirror of a
|
|
15
|
+
* repo nobody has committed to in three weeks is CURRENT, not three weeks stale.
|
|
16
|
+
* `lastCommit` needs no slug→repo-path resolution: the vault sync writer already
|
|
17
|
+
* stamps it into the same `_overview.md` frontmatter it writes `lastSync` into,
|
|
18
|
+
* so both sides of the comparison come from one read of one file.
|
|
19
|
+
*
|
|
20
|
+
* Measured against the live vault before the fix (2026-09-05): 33 of 48 overviews
|
|
21
|
+
* reported "stale", 26 of them >7d, with a demonstrably healthy sync chain —
|
|
22
|
+
* because the clock, not the repo, was the denominator.
|
|
23
|
+
*
|
|
24
|
+
* Fallback: an overview WITHOUT `lastCommit` carries no repo-activity signal at
|
|
25
|
+
* all, so the wall-clock comparison is the only thing left. It is retained for
|
|
26
|
+
* that case only, marked `basis: 'probe-runtime'` in the evidence and carried at
|
|
27
|
+
* lower confidence, so a consumer can tell a measured delta from a guessed one.
|
|
19
28
|
*/
|
|
20
29
|
|
|
21
30
|
import { existsSync, readFileSync, readdirSync, mkdirSync, appendFileSync } from 'node:fs';
|
|
@@ -173,6 +182,7 @@ export async function runProbe(projectRoot, config) {
|
|
|
173
182
|
const slug = fm.slug || entry.name;
|
|
174
183
|
const tier = fm.tier || undefined;
|
|
175
184
|
const lastSync = fm.lastSync || undefined;
|
|
185
|
+
const lastCommit = fm.lastCommit || undefined;
|
|
176
186
|
|
|
177
187
|
if (!lastSync) {
|
|
178
188
|
metrics.stale_count++;
|
|
@@ -202,21 +212,33 @@ export async function runProbe(projectRoot, config) {
|
|
|
202
212
|
continue;
|
|
203
213
|
}
|
|
204
214
|
|
|
205
|
-
|
|
215
|
+
// #1238 — the denominator. `lastCommit` is the repo's own newest activity,
|
|
216
|
+
// so `lastCommit - lastSync` measures what the mirror actually MISSED.
|
|
217
|
+
// A negative or zero delta means the sync ran at or after the newest
|
|
218
|
+
// commit: current, whatever the wall clock says.
|
|
219
|
+
const lastCommitMs = lastCommit ? Date.parse(lastCommit) : NaN;
|
|
220
|
+
const haveCommitBasis = !isNaN(lastCommitMs);
|
|
221
|
+
const basis = haveCommitBasis ? 'lastCommit' : 'probe-runtime';
|
|
222
|
+
const delta = haveCommitBasis ? lastCommitMs - lastSyncMs : now - lastSyncMs;
|
|
223
|
+
|
|
206
224
|
if (delta > HOURS_24) {
|
|
207
225
|
const severity = delta > HOURS_168 ? 'medium' : 'low';
|
|
208
226
|
const dh = deltaHours(delta);
|
|
209
227
|
metrics.stale_count++;
|
|
210
228
|
findings.push({
|
|
211
229
|
severity,
|
|
212
|
-
|
|
230
|
+
// A repo-anchored delta is a measurement; a clock-anchored one is the
|
|
231
|
+
// best available guess about a repo this probe cannot see.
|
|
232
|
+
confidence: haveCommitBasis ? 0.9 : 0.6,
|
|
213
233
|
file_path: overviewPath,
|
|
214
234
|
title: `[vault-staleness] ${slug}: ${formatDelta(delta)} since last sync`,
|
|
215
|
-
description:
|
|
216
|
-
`
|
|
217
|
-
|
|
218
|
-
`
|
|
219
|
-
|
|
235
|
+
description: haveCommitBasis
|
|
236
|
+
? `The repo advanced ${formatDelta(delta)} past the last vault sync ` +
|
|
237
|
+
`(lastCommit ${lastCommit} vs lastSync ${lastSync}, threshold: 24h).`
|
|
238
|
+
: `lastSync is ${formatDelta(delta)} old (threshold: 24h). ` +
|
|
239
|
+
`No lastCommit in the frontmatter, so this compares against probe run time — ` +
|
|
240
|
+
`an idle repo reads as stale here. Add lastCommit to make the delta repo-anchored.`,
|
|
241
|
+
evidence: { slug, tier, lastSync, lastCommit, basis, delta_hours: dh },
|
|
220
242
|
});
|
|
221
243
|
}
|
|
222
244
|
}
|
|
@@ -237,6 +259,8 @@ export async function runProbe(projectRoot, config) {
|
|
|
237
259
|
slug: f.evidence.slug,
|
|
238
260
|
severity: f.severity,
|
|
239
261
|
last_sync: f.evidence.lastSync,
|
|
262
|
+
last_commit: f.evidence.lastCommit,
|
|
263
|
+
basis: f.evidence.basis,
|
|
240
264
|
delta_hours: f.evidence.delta_hours,
|
|
241
265
|
flag: 'stale-yes',
|
|
242
266
|
})),
|
|
@@ -8,23 +8,16 @@
|
|
|
8
8
|
|
|
9
9
|
**Detection Method:**
|
|
10
10
|
|
|
11
|
-
**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
for (const { resolved } of imports) {
|
|
22
|
-
adjacency.get(filePath).push(resolved);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
**Fallback (when language-mapper returns empty or for unsupported file types):**
|
|
11
|
+
> **The language-mapper does NOT produce import edges.** An earlier revision of this
|
|
12
|
+
> file described a "preferred" path calling
|
|
13
|
+
> `extractSemanticSlices(filePath, { type: 'imports' })`. Neither half of that call
|
|
14
|
+
> exists: the real signature is
|
|
15
|
+
> `extractSemanticSlices(filePath, content, options)` — the second parameter is the
|
|
16
|
+
> file's CONTENT, not an options object — and `'imports'` is not a slice kind.
|
|
17
|
+
> `SLICE_KINDS` (`scripts/lib/language-mappers/index.mjs`) is
|
|
18
|
+
> `function | class | interface | type | export | section`; there is no import kind
|
|
19
|
+
> and no `resolved` field, so no adjacency map can be built from it. The grep/madge
|
|
20
|
+
> method below is the only detection method this probe has.
|
|
28
21
|
|
|
29
22
|
```bash
|
|
30
23
|
# Build import graph from source files
|
|
@@ -39,7 +32,7 @@ Grep pattern: (import\s+.*from\s+["']([^"']+)["']|require\s*\(\s*["']([^"']+)["'
|
|
|
39
32
|
npx madge --circular --extensions ts,tsx,js,jsx src/ 2>/dev/null
|
|
40
33
|
```
|
|
41
34
|
|
|
42
|
-
Algorithm (cycle detection
|
|
35
|
+
Algorithm (cycle detection):
|
|
43
36
|
1. Build `{source_file -> [imported_file]}` adjacency map
|
|
44
37
|
2. Resolve relative imports to absolute paths
|
|
45
38
|
3. For each file, BFS through imports with depth limit of 10
|
|
@@ -56,6 +49,15 @@ Files Involved:
|
|
|
56
49
|
|
|
57
50
|
**Default Severity:** High.
|
|
58
51
|
|
|
52
|
+
**Related committed artefact (this repo only, and NOT a substitute):**
|
|
53
|
+
`hooks/_lib/hook-import-set.json`, regenerated by
|
|
54
|
+
`node scripts/generate-hook-import-set.mjs` (flags: `--plugin-root`, `--out`,
|
|
55
|
+
`--check`). It records `{file, reachable_from[]}` — which modules are transitively
|
|
56
|
+
reachable from a HOOK entry file — so it is a reachability allowlist scoped to
|
|
57
|
+
`hooks/`, not an edge list over the whole tree, and it cannot detect cycles. Use it
|
|
58
|
+
to answer "does an edit to this module reach a hook?", never as the adjacency map
|
|
59
|
+
above.
|
|
60
|
+
|
|
59
61
|
---
|
|
60
62
|
|
|
61
63
|
### Probe: complexity-hotspots
|
|
@@ -65,7 +65,7 @@ Compute the suitability verdict for **R** via the pure four-gate engine `compute
|
|
|
65
65
|
| `autonomy` | `resolveDispatcherAutonomy({ committed, env, ownerConfig })` from `scripts/lib/config/dispatcher-autonomy.mjs` | The effective dial. Defaults to `'off'` when unset (fail-closed). |
|
|
66
66
|
| `confidenceFloor` | the `confidence-floor` from the parsed `dispatcher-autonomy:` block (default 0.5) | Same source object as `autonomy`. |
|
|
67
67
|
| `confidence` | mode-selector `selectMode(signals).confidence` (0..1 float) for the recommended session-type | The same mode-selector the Phase-2 heuristic and autopilot use. |
|
|
68
|
-
| `ci` | `checkCiStatus({ repoRoot: R })` → `{ status }` \| `null` | **CRITICAL (NICE-b):** Phase-1 `rank.mjs` exposes only the BARE status string (`readiness.ciStatus`). The engine's G3 gate expects an OBJECT `{ status }` — wrap it as `{ status: ciStatus }` when you HAVE a status; on a CI
|
|
68
|
+
| `ci` | `checkCiStatus({ repoRoot: R })` → `{ status }` \| `null` | **CRITICAL (NICE-b):** Phase-1 `rank.mjs` exposes only the BARE status string (`readiness.ciStatus`). The engine's G3 gate expects an OBJECT `{ status }` — wrap it as `{ status: ciStatus }` when you HAVE a status; on a genuine ABSENCE (no CI configured) pass `ci = null`. **Since #1031 `checkCiStatus` no longer returns `null` on failure** — an unreadable state comes back as `{severity:'warn', ok:false, degraded:<reason>}`, and Phase-1 `rank.mjs` surfaces exactly that as `readiness.ciDegraded` with `readiness.ciStatus === 'unknown'`. Wrap that state as `{ status: 'unknown' }` (the engine warns `'CI signal unknown — treated as absent'` and G3 still passes) rather than flattening it to `null` — `null` claims a measured absence the probe never established. **Do NOT synthesize `{ status: undefined }`** (or `{}`): that present-but-unusable object hits the engine's MALFORMED branch (`'CI signal malformed — treated as absent'`) instead of the clean ABSENT branch (`'CI signal absent'`). Both pass G3 + warn, but `null` is the honest "no signal" — reserve the malformed branch for a genuinely unexpected shape. A bare string ALSO hits the malformed branch — always wrap or null. |
|
|
69
69
|
| `resourceVerdict` | the host resource verdict string (`'green'\|'warn'\|'degraded'\|'critical'`) from `rank.mjs` (`readiness.resourceVerdict`) or a fresh `evaluate(probe(), thresholds).verdict` | Host-level — already fetched once in Phase 1. **NICE-b:** on a genuine probe FAILURE (no signal), prefer `resourceVerdict = null` over synthesizing `'green'`. `null` = "no signal" ⇒ G4 passes + warns (`'resource signal absent'`) — honest. Synthesizing `'green'` fabricates a positive signal the host never reported and can let an autonomous launch proceed against an unknown host state. Pass the real verdict string when you have one; `null` when you do not. |
|
|
70
70
|
| `recentRuns` | `readRecentAutopilotRuns({ repoRoot: R })` from `scripts/lib/autopilot/recent-runs.mjs` | NEW reader. Reads `<R>/.orchestrator/metrics/autopilot.jsonl`, returns the most-recent records (newest-last), never throws (`[]` on missing/unreadable). Pass the TRUE count — the engine's G2 gate omits-with-warn below 5 runs and otherwise checks `fired/N < 0.2`. |
|
|
71
71
|
|
|
@@ -167,7 +167,8 @@ Data → stdout, warnings/errors → stderr (never mixed). Exit codes follow `.c
|
|
|
167
167
|
- **Running this from a subagent** — coordinator-only (AUQ is unavailable in subagents).
|
|
168
168
|
- **Fail-OPEN verdict gate (#682)** — keying the autonomous launch on `verdict.suitable` alone (ignoring `autonomy === 'autonomous-gated'`) auto-launches in `advisory`/`off` mode. ALWAYS gate on BOTH.
|
|
169
169
|
- **Feeding the bare CI string into the engine** — `rank.mjs` exposes `ciStatus` as a bare string; `computeSuitabilityVerdict` wants `{ status }`. Wrap it (`{ status: ciStatus }`) or pass `null` — a bare string silently hits the malformed-absent branch. A red CI fed as a bare string would PASS G3 (masked as malformed) instead of forcing the FORCED-fail branch (NICE-c).
|
|
170
|
-
- **
|
|
170
|
+
- **Flattening a DEGRADED CI reading to `null` (#1031)** — `readiness.ciDegraded` set (⇒ `readiness.ciStatus === 'unknown'`) means the state could NOT be read, which is weaker than absence, not equal to it. Pass `{ status: 'unknown' }`; `null` asserts a measured absence nothing established.
|
|
171
|
+
- **Synthesizing an absent signal instead of passing `null` (NICE-b)** — on a resource-probe failure, pass `resourceVerdict = null` (honest "no signal" ⇒ gate passes + warns). Do NOT synthesize `{ status: undefined }` (hits the malformed branch) and do NOT fabricate `'green'` / `{ status: 'green' }` (invents a positive signal the host never reported and can green-light an autonomous launch against an unknown state).
|
|
171
172
|
- **Pre-truncating `recentRuns` below 5** — passing fewer than the true on-disk count when ≥ 5 runs exist falsely triggers the engine's <5-run omission branch and skips the kill-switch gate. Pass the TRUE count; never call `readRecentAutopilotRuns` with `limit < 5` on the launch-gate read (the reader honours a small `limit` literally and will not clamp it upward).
|
|
172
173
|
- **Auto-launching against a non-green verdict** — a CI-red / resource-critical / low-confidence verdict ALWAYS falls to inform + ask, even under `autonomous-gated`. Never proceed straight to claim on a non-suitable verdict.
|
|
173
174
|
|