session-orchestrator 5.2.0 → 5.4.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/.agents/skills/architecture/SKILL.md +3 -1
- package/.agents/skills/autopilot/SKILL.md +5 -1
- package/.agents/skills/autopilot/agents/openai.yaml +5 -0
- package/.agents/skills/bootstrap/SKILL.md +5 -1
- package/.agents/skills/bootstrap/agents/openai.yaml +5 -0
- package/.agents/skills/brainstorm/SKILL.md +5 -1
- package/.agents/skills/brainstorm/agents/openai.yaml +5 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +4 -2
- package/.agents/skills/close/SKILL.md +5 -1
- package/.agents/skills/close/agents/openai.yaml +5 -0
- package/.agents/skills/convergence-monitoring/SKILL.md +4 -2
- package/.agents/skills/debug/SKILL.md +5 -1
- package/.agents/skills/debug/agents/openai.yaml +5 -0
- package/.agents/skills/discovery/SKILL.md +5 -1
- package/.agents/skills/discovery/agents/openai.yaml +5 -0
- package/.agents/skills/dispatcher/SKILL.md +5 -1
- package/.agents/skills/dispatcher/agents/openai.yaml +5 -0
- package/.agents/skills/docs-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ecosystem-health/SKILL.md +3 -1
- package/.agents/skills/eli5/SKILL.md +5 -1
- package/.agents/skills/eli5/agents/openai.yaml +5 -0
- package/.agents/skills/eval/SKILL.md +6 -2
- package/.agents/skills/eval/agents/openai.yaml +5 -0
- package/.agents/skills/evolve/SKILL.md +6 -2
- package/.agents/skills/evolve/agents/openai.yaml +5 -0
- package/.agents/skills/frontmatter-guard/SKILL.md +3 -1
- package/.agents/skills/gitlab-ops/SKILL.md +3 -1
- package/.agents/skills/gitlab-portfolio/SKILL.md +3 -1
- package/.agents/skills/go/SKILL.md +5 -1
- package/.agents/skills/go/agents/openai.yaml +5 -0
- package/.agents/skills/grill/SKILL.md +5 -1
- package/.agents/skills/grill/agents/openai.yaml +5 -0
- package/.agents/skills/harness-audit/SKILL.md +5 -1
- package/.agents/skills/harness-audit/agents/openai.yaml +5 -0
- package/.agents/skills/hook-development/SKILL.md +3 -1
- package/.agents/skills/mcp-builder/SKILL.md +3 -1
- package/.agents/skills/memory-cleanup/SKILL.md +5 -1
- package/.agents/skills/memory-cleanup/agents/openai.yaml +5 -0
- package/.agents/skills/mode-selector/SKILL.md +3 -1
- package/.agents/skills/navigator/SKILL.md +22 -0
- package/.agents/skills/navigator/agents/openai.yaml +5 -0
- package/.agents/skills/npm-publish/SKILL.md +4 -2
- package/.agents/skills/peekaboo-driver/SKILL.md +3 -1
- package/.agents/skills/persona-panel/SKILL.md +5 -1
- package/.agents/skills/persona-panel/agents/openai.yaml +5 -0
- package/.agents/skills/plan/SKILL.md +5 -1
- package/.agents/skills/plan/agents/openai.yaml +5 -0
- package/.agents/skills/playwright-driver/SKILL.md +3 -1
- package/.agents/skills/portfolio/SKILL.md +5 -1
- package/.agents/skills/portfolio/agents/openai.yaml +5 -0
- package/.agents/skills/quality-gates/SKILL.md +3 -1
- package/.agents/skills/reconcile/SKILL.md +5 -1
- package/.agents/skills/reconcile/agents/openai.yaml +5 -0
- package/.agents/skills/release/SKILL.md +5 -1
- package/.agents/skills/release/agents/openai.yaml +5 -0
- package/.agents/skills/remote-offload/SKILL.md +3 -1
- package/.agents/skills/repo-audit/SKILL.md +5 -1
- package/.agents/skills/repo-audit/agents/openai.yaml +5 -0
- package/.agents/skills/session/SKILL.md +21 -0
- package/.agents/skills/session/agents/openai.yaml +5 -0
- package/.agents/skills/session-end/SKILL.md +3 -1
- package/.agents/skills/session-plan/SKILL.md +3 -1
- package/.agents/skills/session-start/SKILL.md +3 -1
- package/.agents/skills/spinout/SKILL.md +5 -1
- package/.agents/skills/spinout/agents/openai.yaml +5 -0
- package/.agents/skills/sunset-review/SKILL.md +5 -1
- package/.agents/skills/sunset-review/agents/openai.yaml +5 -0
- package/.agents/skills/templates-ack/SKILL.md +21 -0
- package/.agents/skills/templates-ack/agents/openai.yaml +5 -0
- package/.agents/skills/test/SKILL.md +5 -1
- package/.agents/skills/test/agents/openai.yaml +5 -0
- package/.agents/skills/test-audit/SKILL.md +21 -0
- package/.agents/skills/test-audit/agents/openai.yaml +5 -0
- package/.agents/skills/test-runner/SKILL.md +3 -1
- package/.agents/skills/tmux-layout/SKILL.md +3 -1
- package/.agents/skills/using-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ux-grill/SKILL.md +5 -1
- package/.agents/skills/ux-grill/agents/openai.yaml +5 -0
- package/.agents/skills/vault-mirror/SKILL.md +3 -1
- package/.agents/skills/vault-sync/SKILL.md +3 -1
- package/.agents/skills/wave-executor/SKILL.md +3 -1
- package/.agents/skills/write-executable-plan/SKILL.md +3 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +4 -4
- package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -1
- package/.codex-plugin/skills/convergence-monitoring/SKILL.md +1 -3
- package/.codex-plugin/skills/eval/SKILL.md +1 -1
- package/.codex-plugin/skills/evolve/SKILL.md +1 -1
- package/.codex-plugin/skills/navigator/SKILL.md +22 -0
- package/.codex-plugin/skills/{convergence-monitoring → navigator}/agents/openai.yaml +2 -2
- package/.codex-plugin/skills/npm-publish/SKILL.md +1 -3
- package/.codex-plugin/skills/session/SKILL.md +1 -1
- package/.codex-plugin/skills/test-audit/SKILL.md +21 -0
- package/.codex-plugin/skills/{npm-publish → test-audit}/agents/openai.yaml +1 -1
- package/.cursor/commands/eval.md +1 -1
- package/.cursor/commands/navigator.md +15 -0
- package/.cursor/commands/session.md +1 -1
- package/.cursor/commands/test-audit.md +14 -0
- package/.cursor/rules/000-session-orchestrator.mdc +0 -2
- package/.cursor/rules/050-plan.mdc +1 -1
- package/.cursor/rules/060-evolve.mdc +27 -12
- package/.cursor/skills/claude-md-drift-check/SKILL.md +1 -1
- package/.cursor/skills/convergence-monitoring/SKILL.md +1 -0
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/navigator/SKILL.md +13 -0
- package/.cursor/skills/npm-publish/SKILL.md +1 -0
- package/.cursor/skills/test-audit/SKILL.md +12 -0
- package/.cursor-plugin/plugin.json +1 -1
- package/.orchestrator/policy/blocked-commands.json +12 -3
- package/AGENTS.md +9 -30
- package/CHANGELOG.md +206 -0
- package/README.md +13 -9
- package/SECURITY.md +12 -0
- package/agents/dialectic-deriver.md +13 -10
- package/agents/eval-judge.md +67 -45
- package/agents/skill-applied-judge.md +34 -19
- package/commands/session.md +7 -3
- package/docs/agent-authoring.md +2 -2
- package/docs/baseline.md +22 -7
- package/docs/ci-setup.md +57 -4
- package/docs/codex-setup.md +14 -2
- package/docs/components.md +12 -10
- package/docs/events-schema.md +65 -15
- package/docs/persona-panel.md +5 -4
- package/docs/rule-authoring.md +84 -17
- package/docs/scope-collision-guard.md +26 -4
- package/docs/session-config-reference.md +154 -12
- package/docs/session-config-template.md +41 -3
- package/docs/telemetry.md +2 -0
- package/hooks/_lib/hook-import-set.json +87 -6
- package/hooks/_lib/subagent-transcript.mjs +582 -31
- package/hooks/config-protection.mjs +11 -3
- package/hooks/cwd-change-restore.mjs +11 -3
- package/hooks/enforce-commands.mjs +70 -23
- package/hooks/enforce-scope.mjs +143 -33
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +5 -0
- package/hooks/hooks-pi.json +5 -0
- package/hooks/hooks.json +6 -1
- package/hooks/loop-guard.mjs +11 -3
- package/hooks/on-session-end.mjs +58 -23
- package/hooks/on-session-start.mjs +101 -11
- package/hooks/on-stop.mjs +170 -22
- package/hooks/operator-steer.mjs +11 -3
- package/hooks/post-bash-issue-budget-refund.mjs +18 -8
- package/hooks/post-bash-write-verify.mjs +3 -2
- package/hooks/post-edit-import-probe.mjs +17 -9
- package/hooks/post-edit-validate.mjs +13 -5
- package/hooks/post-subagent-discovery-validator.mjs +98 -13
- package/hooks/post-tool-batch-wave-signal.mjs +202 -38
- package/hooks/post-tool-failure-corrective-context.mjs +11 -5
- package/hooks/post-tooluse-frontend-slop.mjs +10 -4
- package/hooks/pre-auq-clarity.mjs +15 -2
- package/hooks/pre-bash-destructive-guard.mjs +80 -9
- package/hooks/pre-bash-issue-budget.mjs +16 -11
- package/hooks/pre-bash-memory-propose-audit.mjs +137 -56
- package/hooks/pre-bash-sessions-ledger-guard.mjs +419 -22
- package/hooks/pre-bash-staging-fence.mjs +335 -31
- package/hooks/pre-bash-templates-first.mjs +19 -14
- package/hooks/pre-edit-sessions-ledger-guard.mjs +162 -0
- package/hooks/pre-task-scope-disjoint.mjs +792 -74
- package/hooks/subagent-telemetry.mjs +111 -38
- package/hooks/wave-scope-commit-guard.mjs +197 -100
- package/monitors/monitors.json +1 -1
- package/output-styles/wave-summary.md +1 -1
- package/package.json +3 -3
- package/pi/prompts/eval.md +1 -1
- package/pi/prompts/navigator.md +12 -0
- package/pi/prompts/session.md +1 -1
- package/pi/prompts/test-audit.md +12 -0
- package/rules/README.md +7 -2
- package/rules/_index.md +3 -3
- package/rules/always-on/bash-harness-pitfalls.md +7 -1
- package/rules/opt-in-domain/prompt-caching.md +6 -2
- package/rules/opt-in-stack/backend-data.md +10 -2
- package/rules/opt-in-stack/backend.md +10 -4
- package/rules/opt-in-stack/frontend.md +7 -2
- package/rules/opt-in-stack/security-web.md +10 -4
- package/rules/opt-in-stack/swift.md +6 -2
- package/scripts/apply-session-learnings.mjs +492 -0
- package/scripts/archive-closed-prds.mjs +2 -1
- package/scripts/autopilot.mjs +70 -53
- package/scripts/backfill-abandoned-sessions.mjs +118 -16
- package/scripts/baseline-archetypes.mjs +1 -1
- package/scripts/check-package-manager.mjs +62 -5
- package/scripts/check-sessions-integrity.mjs +300 -0
- package/scripts/cursor-install.mjs +1 -4
- package/scripts/dialectic-deriver.mjs +50 -13
- package/scripts/emit-session.mjs +371 -31
- package/scripts/eval-session.mjs +65 -3
- package/scripts/export-hw-learnings.mjs +22 -3
- package/scripts/fleet-checkin.mjs +147 -0
- package/scripts/generate-agents-skills.mjs +102 -29
- package/scripts/generate-cursor-adapter.mjs +61 -16
- package/scripts/lib/agent-frontmatter.mjs +3 -3
- package/scripts/lib/agent-status.mjs +2 -31
- package/scripts/lib/auq/clarity.mjs +10 -2
- package/scripts/lib/auq/parse.mjs +12 -31
- package/scripts/lib/auq/schema.mjs +56 -41
- package/scripts/lib/auto-dialectic.mjs +304 -15
- package/scripts/lib/auto-dream.mjs +7 -6
- package/scripts/lib/autopilot/flags.mjs +18 -2
- package/scripts/lib/autopilot/kill-switches.mjs +6 -3
- package/scripts/lib/autopilot/loop.mjs +19 -2
- package/scripts/lib/autopilot/stall-sampler.mjs +80 -23
- package/scripts/lib/baseline-archetypes.mjs +41 -22
- package/scripts/lib/ci-status-banner.mjs +376 -16
- package/scripts/lib/command-blocker.mjs +275 -28
- package/scripts/lib/config/dialectic.mjs +12 -3
- package/scripts/lib/config/gate.mjs +74 -0
- package/scripts/lib/config/host-paths.mjs +79 -0
- package/scripts/lib/config/persona-gate-wave.mjs +3 -3
- package/scripts/lib/config/reaper.mjs +163 -0
- package/scripts/lib/config-schema.mjs +13 -0
- package/scripts/lib/config.mjs +85 -10
- package/scripts/lib/convergence-monitor.mjs +74 -11
- package/scripts/lib/ecosystem-health.mjs +11 -0
- package/scripts/lib/eval/engine.mjs +421 -53
- package/scripts/lib/eval/judge.mjs +463 -40
- package/scripts/lib/eval/schema.mjs +10 -1
- package/scripts/lib/events-rotation.mjs +221 -25
- package/scripts/lib/events-schema.mjs +114 -0
- package/scripts/lib/events.mjs +545 -7
- package/scripts/lib/fleet-protocol.mjs +270 -0
- package/scripts/lib/frontmatter-guard.mjs +21 -10
- package/scripts/lib/gates/gate-baseline.mjs +40 -5
- package/scripts/lib/gates/gate-full.mjs +35 -5
- package/scripts/lib/gates/gate-helpers.mjs +336 -23
- package/scripts/lib/gates/gate-incremental.mjs +49 -23
- package/scripts/lib/gates/gate-per-file.mjs +42 -8
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +6 -1
- package/scripts/lib/instruction-budget-guard.mjs +208 -8
- package/scripts/lib/io.mjs +42 -8
- package/scripts/lib/issue-close-strip-labels.mjs +207 -49
- package/scripts/lib/js-mask.mjs +197 -0
- package/scripts/lib/learnings/evolve-telemetry.mjs +11 -7
- package/scripts/lib/learnings/expiry-sweep.mjs +34 -3
- package/scripts/lib/learnings/io.mjs +154 -26
- package/scripts/lib/learnings/schema.mjs +163 -15
- package/scripts/lib/learnings/sizing-subject.mjs +2 -2
- package/scripts/lib/maintenance-due-banner.mjs +53 -88
- package/scripts/lib/memory-proposals/schema.mjs +11 -5
- package/scripts/lib/named-baseline-resolver.mjs +53 -28
- package/scripts/lib/named-vault-resolver.mjs +104 -5
- package/scripts/lib/orphan-reaper/defaults.mjs +41 -0
- package/scripts/lib/orphan-reaper/ps-snapshot.mjs +181 -0
- package/scripts/lib/orphan-reaper/reaper-audit.mjs +291 -0
- package/scripts/lib/orphan-reaper/reaper-decide.mjs +395 -0
- package/scripts/lib/orphan-reaper/scan-throttle.mjs +92 -0
- package/scripts/lib/orphan-reaper/scan.mjs +506 -0
- package/scripts/lib/orphan-reaper.mjs +316 -0
- package/scripts/lib/owner-yaml.mjs +104 -6
- package/scripts/lib/peer-cards/merger.mjs +48 -10
- package/scripts/lib/peer-cards/reader.mjs +78 -2
- package/scripts/lib/persona-panel/catalog-loader.mjs +1 -1
- package/scripts/lib/process-group.mjs +950 -0
- package/scripts/lib/project-hygiene.mjs +21 -1
- package/scripts/lib/quality-gate.mjs +152 -33
- package/scripts/lib/reconcile/backlog.mjs +368 -0
- package/scripts/lib/reconcile/engine.mjs +55 -188
- package/scripts/lib/reconcile/rule-expiry-sweep.mjs +302 -60
- package/scripts/lib/reconcile/sanitize.mjs +69 -3
- package/scripts/lib/reconcile-nudge-banner.mjs +138 -45
- package/scripts/lib/resource-probe/parsers.mjs +31 -0
- package/scripts/lib/resource-probe.mjs +1 -1
- package/scripts/lib/rule-loader.mjs +141 -74
- package/scripts/lib/rules-sync.mjs +27 -12
- package/scripts/lib/scope-baseline.mjs +3 -4
- package/scripts/lib/scope-echo.mjs +39 -2
- package/scripts/lib/scope-gate.mjs +605 -1
- package/scripts/lib/session-close-backfill.mjs +33 -6
- package/scripts/lib/session-id.mjs +9 -20
- package/scripts/lib/session-invocation.mjs +20 -0
- package/scripts/lib/session-record-repair.mjs +183 -26
- package/scripts/lib/session-registry.mjs +27 -2
- package/scripts/lib/session-schema/constants.mjs +56 -2
- package/scripts/lib/session-schema/normalizer.mjs +56 -4
- package/scripts/lib/session-schema/validator.mjs +28 -1
- package/scripts/lib/session-schema.mjs +8 -3
- package/scripts/lib/session-start-probes.mjs +95 -10
- package/scripts/lib/session-token-rollup.mjs +245 -52
- package/scripts/lib/sessions-canonical.mjs +118 -4
- package/scripts/lib/sessions-integrity-banner.mjs +7 -1
- package/scripts/lib/sessions-staleness-banner.mjs +193 -51
- package/scripts/lib/sh-quote.mjs +29 -0
- package/scripts/lib/skill-evidence-window.mjs +891 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +133 -12
- package/scripts/lib/skill-evolution/engine.mjs +18 -9
- package/scripts/lib/skill-judge.mjs +45 -3
- package/scripts/lib/subagents-schema.mjs +30 -3
- package/scripts/lib/tail-window.mjs +56 -0
- package/scripts/lib/telemetry/pricing.mjs +118 -71
- package/scripts/lib/telemetry/schema.mjs +30 -0
- package/scripts/lib/telemetry/sync.mjs +61 -6
- package/scripts/lib/telemetry-flush-health-banner.mjs +4 -22
- package/scripts/lib/test-runner/issue-reconcile.mjs +48 -16
- package/scripts/lib/tests-src-ratio.mjs +140 -23
- package/scripts/lib/tmux-layout/layouts.mjs +1 -11
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +72 -13
- package/scripts/lib/tmux-layout/tmux-shell.mjs +2 -11
- package/scripts/lib/user-invocable-skills.mjs +23 -3
- package/scripts/lib/ux-grill/reconcile.mjs +48 -22
- package/scripts/lib/validate/check-agents-skills.mjs +26 -15
- package/scripts/lib/validate/check-agents.mjs +1 -1
- package/scripts/lib/validate/check-cursor-adapter.mjs +1 -0
- package/scripts/lib/validate/check-entry-guard.mjs +13 -50
- package/scripts/lib/validate/check-hook-entry-guards.mjs +636 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +5 -0
- package/scripts/lib/validate/check-learnings-shell-writes.mjs +214 -0
- package/scripts/lib/validate/check-pi-prompts.mjs +1 -0
- package/scripts/lib/validate/check-rules.mjs +7 -5
- package/scripts/lib/validate/check-skill-links.mjs +9 -1
- package/scripts/lib/validate/check-skill-script-paths.mjs +239 -27
- package/scripts/lib/validate/check-test-git-config-target.mjs +24 -34
- package/scripts/lib/validate/check-test-value-bans.mjs +87 -14
- package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
- package/scripts/lib/validate/check-untracked-test-deps.mjs +7 -102
- package/scripts/lib/validate/check-unwired-features.mjs +130 -27
- package/scripts/lib/validate/check-validator-registration.mjs +34 -10
- package/scripts/lib/validate/confidential-names.mjs +10 -0
- package/scripts/lib/validate-vendored-rules.mjs +210 -84
- package/scripts/lib/vault-mirror/namespace.mjs +46 -8
- package/scripts/lib/vault-mirror/process.mjs +10 -3
- package/scripts/lib/vault-mirror/render-sessions.mjs +12 -2
- package/scripts/lib/vault-mirror/telemetry.mjs +8 -1
- package/scripts/lib/vault-status/board-writer.mjs +48 -11
- package/scripts/lib/vault-status/narrative-mirror.mjs +71 -16
- package/scripts/lib/vault-yaml.mjs +118 -0
- package/scripts/lib/wave-executor/dispatch-common.mjs +10 -18
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +1 -1
- package/scripts/lib/wave-executor/remote-dispatch.mjs +1 -1
- package/scripts/lib/wave-resource-gate.mjs +34 -8
- package/scripts/lib/worktree/lifecycle.mjs +153 -1
- package/scripts/memory-propose.mjs +18 -5
- package/scripts/release-session-lock.mjs +306 -0
- package/scripts/release.mjs +40 -8
- package/scripts/repair-invalid-sessions.mjs +37 -4
- package/scripts/resolve-session-invocation.mjs +59 -0
- package/scripts/run-migrate-v2-cross-repo.mjs +158 -30
- package/scripts/run-quality-gate.mjs +357 -197
- package/scripts/site-numbers.mjs +163 -5
- package/scripts/sweep-expired-learnings.mjs +56 -5
- package/scripts/sweep-expired-rules.mjs +16 -4
- package/scripts/validate-plugin.mjs +19 -0
- package/scripts/validate-wave-scope.mjs +32 -105
- package/scripts/vault-integration-watcher.mjs +2 -1
- package/scripts/vault-mirror.mjs +81 -47
- package/scripts/wave-scope-binding.mjs +2 -1
- package/skills/_shared/config-reading.md +3 -3
- package/skills/_shared/fleet-protocol.md +131 -0
- package/skills/_shared/platform-tools.md +23 -11
- package/skills/_shared/state-ownership.md +5 -0
- package/skills/autopilot/SKILL.md +47 -18
- package/skills/bootstrap/SKILL.md +1 -1
- package/skills/bootstrap/_shared-template.md +1 -1
- package/skills/bootstrap/fast-template.md +1 -1
- package/skills/bootstrap/private-contract.md +2 -1
- package/skills/bootstrap/public-fallback.md +6 -3
- package/skills/bootstrap/references/bootstrap-retroactive-flow.md +2 -1
- package/skills/claude-md-drift-check/SKILL.md +10 -10
- package/skills/claude-md-drift-check/checker.mjs +26 -18
- package/skills/convergence-monitoring/README.md +8 -1
- package/skills/convergence-monitoring/SIGNALS.md +50 -6
- package/skills/convergence-monitoring/SKILL.md +15 -6
- package/skills/eval/SKILL.md +39 -24
- package/skills/eval/rubric-v1.md +1 -0
- package/skills/eval/rubric-v2.md +457 -0
- package/skills/evolve/SKILL.md +3 -3
- package/skills/evolve/references/evolve-analyze-mode.md +10 -6
- package/skills/evolve/references/evolve-dialectic-mode.md +42 -25
- package/skills/gitlab-ops/SKILL.md +3 -2
- package/skills/memory-cleanup/SKILL.md +1 -1
- package/skills/navigator/SKILL.md +193 -0
- package/skills/navigator/references/account-check.sh +87 -0
- package/skills/navigator/references/fleet-decisions.mjs +231 -0
- package/skills/navigator/references/slot-check.sh +114 -0
- package/skills/npm-publish/SKILL.md +1 -1
- package/skills/persona-panel/SKILL.md +2 -2
- package/skills/persona-panel/persona-format.md +2 -2
- package/skills/persona-panel/presets/designer-lens.md +1 -1
- package/skills/persona-panel/presets/engineer-lens.md +1 -1
- package/skills/persona-panel/presets/pm-lens.md +1 -1
- package/skills/plan/mode-retro.md +19 -4
- package/skills/quality-gates/SKILL.md +6 -4
- package/skills/reconcile/SKILL.md +11 -0
- package/skills/remote-offload/SKILL.md +4 -2
- package/skills/session-end/SKILL.md +13 -16
- package/skills/session-end/discovery-scan.md +1 -1
- package/skills/session-end/learning-patterns.md +22 -12
- package/skills/session-end/metrics-collection.md +5 -6
- package/skills/session-end/phase-3-6-tail.md +55 -9
- package/skills/session-end/references/phase-3-documentation-updates.md +2 -2
- package/skills/session-end/references/phase-4a-worktree-cleanup.md +2 -0
- package/skills/session-end/references/phase-5-issue-cleanup.md +9 -14
- package/skills/session-end/references/session-summary-template.md +1 -1
- package/skills/session-end/session-metrics-write.md +32 -60
- package/skills/session-plan/SKILL.md +17 -8
- package/skills/session-plan/references/session-plan-task-classification.md +2 -2
- package/skills/session-start/SKILL.md +6 -0
- package/skills/session-start/references/operations-contract.md +4 -0
- package/skills/session-start/references/phase-1-7-vault-status-board.md +1 -1
- package/skills/session-start/references/phase-4-ssot-environment-check.md +4 -3
- package/skills/test-audit/SKILL.md +152 -0
- package/skills/test-audit/references/campaign.md +111 -0
- package/skills/test-audit/references/mutate.sh +50 -0
- package/skills/ux-grill/SKILL.md +1 -1
- package/skills/wave-executor/SKILL.md +9 -5
- package/skills/wave-executor/circuit-breaker.md +2 -0
- package/skills/wave-executor/references/wave-executor-state-init.md +8 -3
- package/skills/wave-executor/references/wave-loop-dispatch.md +5 -2
- package/skills/wave-executor/references/wave-loop-review.md +3 -5
- package/templates/personas/README.md +5 -5
- package/templates/personas/accounting-compliance.v1.md +1 -1
- package/templates/personas/accounting-tax-advisor.v1.md +1 -1
- package/templates/personas/buyer-p1-cto.v1.md +1 -1
- package/templates/personas/buyer-p2-kanzlei.v1.md +1 -1
- package/templates/personas/buyer-p3-build.v1.md +1 -1
- package/templates/personas/buyer-p4-tech-veto.v1.md +1 -1
- package/templates/personas/buyer-p5-solo.v1.md +1 -1
- package/templates/personas/buyer-p6-ld.v1.md +1 -1
- package/templates/personas/klima-ai-expert.v1.md +1 -1
- package/templates/personas/klima-physicist.v1.md +1 -1
- package/.cursor/commands/convergence-monitoring.md +0 -13
- package/.cursor/commands/npm-publish.md +0 -13
- package/pi/prompts/convergence-monitoring.md +0 -11
- package/pi/prompts/npm-publish.md +0 -11
|
@@ -462,7 +462,9 @@ export function checkStaleArtifacts(repoRoot, ageDays = DEFAULT_ARTIFACT_AGE_DAY
|
|
|
462
462
|
* H4 — CI configuration hygiene.
|
|
463
463
|
*
|
|
464
464
|
* Measured 5/6. Checks locally declared executable commands without evaluating
|
|
465
|
-
* pipeline conditions or external includes
|
|
465
|
+
* pipeline conditions or external includes; when no local audit step is found
|
|
466
|
+
* but `.gitlab-ci.yml` declares `include:`, the finding is downgraded to an
|
|
467
|
+
* unverifiable, non-fixable one. The dependency-audit gap is the load-bearing one: three
|
|
466
468
|
* of the tested repos carried known-vulnerable dependencies that no pipeline
|
|
467
469
|
* would ever surface.
|
|
468
470
|
*
|
|
@@ -506,6 +508,24 @@ export function checkCiConfig(repoRoot) {
|
|
|
506
508
|
}
|
|
507
509
|
|
|
508
510
|
if (ciConfigs.some(({ text }) => text) && !ciConfigs.some(hasAuditStep)) {
|
|
511
|
+
// Jobs supplied via include: (component/local/project/remote/template) are
|
|
512
|
+
// never resolved, so an audit may exist there — report it as unverifiable.
|
|
513
|
+
let includes = 0;
|
|
514
|
+
try {
|
|
515
|
+
const gitlabText = hasGitlab ? ciConfigs[0].text : '';
|
|
516
|
+
const include = yaml.loadAll(gitlabText, undefined, { schema: GITLAB_SCHEMA }).filter(isConfigMap).at(-1)?.include;
|
|
517
|
+
includes = Array.isArray(include) ? include.length : include ? 1 : 0;
|
|
518
|
+
} catch {
|
|
519
|
+
/* unparseable config — keep the plain missing-audit finding */
|
|
520
|
+
}
|
|
521
|
+
if (includes > 0) {
|
|
522
|
+
findings.push({
|
|
523
|
+
check: 'ci-audit-job',
|
|
524
|
+
fixable: false,
|
|
525
|
+
message: `CI dependency-audit step could not be verified: ${includes} include(s) not evaluated (.gitlab-ci.yml include:)`,
|
|
526
|
+
});
|
|
527
|
+
return findings;
|
|
528
|
+
}
|
|
509
529
|
findings.push({
|
|
510
530
|
check: 'ci-audit-job',
|
|
511
531
|
fixable: true,
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
* - Output collection: each gate captures the last ~50 lines of combined
|
|
27
27
|
* stdout+stderr (vs. `gate-helpers.mjs::runCheck` which truncates to 5).
|
|
28
28
|
* The longer tail flows into the diagnostics bundle and the fixer's
|
|
29
|
-
* failureContext.
|
|
29
|
+
* failureContext. Since #1427 the tail is cut by `process-group.mjs`'s own
|
|
30
|
+
* `OUTPUT_TAIL_LINES`, which is the same 50, and the full capture is
|
|
31
|
+
* byte-capped there instead of by `spawnSync`'s `maxBuffer`.
|
|
30
32
|
*
|
|
31
33
|
* - `last-green-sha.txt` lives at `.orchestrator/runtime/last-green-sha.txt`
|
|
32
34
|
* and is updated atomically after every successful gate. `changedFiles` is
|
|
@@ -61,12 +63,17 @@
|
|
|
61
63
|
|
|
62
64
|
import { spawnSync } from 'node:child_process';
|
|
63
65
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from 'node:fs';
|
|
64
|
-
import { dirname, join } from 'node:path';
|
|
66
|
+
import { dirname, join, resolve } from 'node:path';
|
|
65
67
|
import { fileURLToPath } from 'node:url';
|
|
66
68
|
|
|
67
69
|
import { emitEvent, sessionAttribution } from './events.mjs';
|
|
68
70
|
import { parsePorcelainZ } from './git-porcelain.mjs';
|
|
69
71
|
import { admitSuiteCounts, extractTestCounts } from './gates/gate-helpers.mjs';
|
|
72
|
+
import {
|
|
73
|
+
DEFAULT_GATE_TIMEOUT_MS,
|
|
74
|
+
buildCommandSignature,
|
|
75
|
+
spawnInGroup,
|
|
76
|
+
} from './process-group.mjs';
|
|
70
77
|
import { redactDiagnosticsBundle } from './quality-gate/diagnostics.mjs';
|
|
71
78
|
import { readProcessLocalSessionIds } from './session-identity/own-session.mjs';
|
|
72
79
|
|
|
@@ -86,17 +93,20 @@ const DEFAULT_COMMANDS = {
|
|
|
86
93
|
test: 'npm test',
|
|
87
94
|
};
|
|
88
95
|
|
|
89
|
-
/** Max lines of combined stdout+stderr retained per failure. */
|
|
90
|
-
const OUTPUT_TAIL_LINES = 50;
|
|
91
|
-
|
|
92
96
|
/** Max corrective_context entries forwarded to the fixer (most-recent). */
|
|
93
97
|
const CORRECTIVE_CONTEXT_TAIL = 5;
|
|
94
98
|
|
|
95
99
|
/** Hard ceiling on retries — defensive coercion. */
|
|
96
100
|
const MAX_RETRIES_HARD_CAP = 10;
|
|
97
101
|
|
|
98
|
-
/**
|
|
99
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Per-gate command timeout (15 min). Wave gates can be long; never infinite.
|
|
104
|
+
*
|
|
105
|
+
* Re-exported from `process-group.mjs` rather than re-spelled here: both gate
|
|
106
|
+
* paths are allowed exactly as long (PRD parameter `gate.timeout-path-b-ms`),
|
|
107
|
+
* and a second literal would drift from it silently.
|
|
108
|
+
*/
|
|
109
|
+
const GATE_TIMEOUT_MS = DEFAULT_GATE_TIMEOUT_MS;
|
|
100
110
|
|
|
101
111
|
// ---------------------------------------------------------------------------
|
|
102
112
|
// Internal helpers
|
|
@@ -110,7 +120,8 @@ const GATE_TIMEOUT_MS = 15 * 60 * 1000;
|
|
|
110
120
|
* @returns {string}
|
|
111
121
|
*/
|
|
112
122
|
function resolveRepoRoot(explicit) {
|
|
113
|
-
|
|
123
|
+
// Absolute on purpose: emitEvent refuses a relative root (#1468).
|
|
124
|
+
if (typeof explicit === 'string' && explicit.trim()) return resolve(explicit);
|
|
114
125
|
return process.cwd();
|
|
115
126
|
}
|
|
116
127
|
|
|
@@ -274,29 +285,48 @@ function resolveCommands(override, repoRoot) {
|
|
|
274
285
|
}
|
|
275
286
|
|
|
276
287
|
/**
|
|
277
|
-
* Run a
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
288
|
+
* Run a gate command as the leader of its OWN process group, capture
|
|
289
|
+
* stdout+stderr, return the last ~50 lines plus the exit code.
|
|
290
|
+
*
|
|
291
|
+
* ASYNC since #1427 A1/A2, and that is the point rather than an incidental
|
|
292
|
+
* refactor. The previous `spawnSync(cmd, { shell: true, timeout })` made the
|
|
293
|
+
* SHELL the child, so Node's timeout signalled the shell alone and every
|
|
294
|
+
* grandchild — `tsgo --noEmit`, Vitest workers — was reparented to PID 1 and
|
|
295
|
+
* kept running. That is the 2026-09-20 incident: four orphaned `tsgo`
|
|
296
|
+
* processes, two at PPID 1, up to 8.0 GB RSS each, host at 13% free memory.
|
|
297
|
+
* {@link spawnInGroup} spawns `detached: true` (the child becomes a process-GROUP
|
|
298
|
+
* leader) and signals `-pgid` along the SIGTERM → grace → SIGKILL → verify
|
|
299
|
+
* ladder, so the whole group is gone when this resolves — or reported as a
|
|
300
|
+
* survivor, never booked as success (PRD B6).
|
|
301
|
+
*
|
|
302
|
+
* Does NOT throw — failures are encoded in the return value. The three fields
|
|
303
|
+
* the pre-#1427 contract carried (`exitCode`, `output`, `timedOut`) are
|
|
304
|
+
* unchanged; `overflow`, `killSignals`, `survivors` and `pgid` are additive.
|
|
305
|
+
*
|
|
306
|
+
* Exit-code contract, preserved verbatim from the synchronous path:
|
|
307
|
+
* - timeout → `124`
|
|
308
|
+
* - output over the byte cap → `1` (what `spawnSync`'s ENOBUFS produced)
|
|
309
|
+
* - otherwise the child's own code.
|
|
281
310
|
*
|
|
282
311
|
* @param {string} cmd
|
|
283
312
|
* @param {string} cwd
|
|
284
|
-
* @
|
|
313
|
+
* @param {object} [opts]
|
|
314
|
+
* @param {number} [opts.timeoutMs] — wall-clock ceiling. Defaults to GATE_TIMEOUT_MS.
|
|
315
|
+
* @param {string|null} [opts.sessionId] — owner recorded in the gate-process ledger.
|
|
316
|
+
* @param {object} [opts.seams] — forwarded verbatim to {@link spawnInGroup}
|
|
317
|
+
* (`spawnFn`, `killFn`, `isAliveFn`, `sleepFn`, `killGraceMs`, `verifyWaitMs`).
|
|
318
|
+
* Test seam only; production passes nothing and gets the module defaults.
|
|
319
|
+
* @returns {Promise<{ exitCode: number, output: string, timedOut: boolean,
|
|
320
|
+
* overflow: boolean, killSignals: string[], survivors: number[], pgid: number }>}
|
|
285
321
|
*/
|
|
286
|
-
function runGate(cmd, cwd) {
|
|
322
|
+
async function runGate(cmd, cwd, opts = {}) {
|
|
287
323
|
try {
|
|
288
324
|
// Gate commands are executable configuration from the caller or local
|
|
289
325
|
// Session Config, not data interpolated into a command template. Shell
|
|
290
326
|
// syntax is intentional; callers must trust both command sources (including
|
|
291
327
|
// uncommitted config). See security.md: Session Config Command Trust.
|
|
292
|
-
|
|
293
|
-
const result = spawnSync(cmd, {
|
|
328
|
+
const result = await spawnInGroup(cmd, {
|
|
294
329
|
cwd,
|
|
295
|
-
shell: true,
|
|
296
|
-
encoding: 'utf8',
|
|
297
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
298
|
-
timeout: GATE_TIMEOUT_MS,
|
|
299
|
-
maxBuffer: 16 * 1024 * 1024, // 16 MiB cap
|
|
300
330
|
// #1360: gate runs are where worker over-subscription was measured to
|
|
301
331
|
// cause timeout failures (integration fixtures spawn their own Node/npm/
|
|
302
332
|
// git children on top of Vitest's workers). `vitest.config.mjs` reads this
|
|
@@ -305,19 +335,40 @@ function runGate(cmd, cwd) {
|
|
|
305
335
|
// Inherited by every gate subprocess, not only the test one — typecheck
|
|
306
336
|
// and lint ignore it, so setting it unconditionally costs nothing.
|
|
307
337
|
env: { ...process.env, SO_BOUNDED_WORKERS: '1' },
|
|
338
|
+
timeoutMs: typeof opts.timeoutMs === 'number' ? opts.timeoutMs : GATE_TIMEOUT_MS,
|
|
339
|
+
// The ledger (A4) is what lets the orphan-reaper tell a descendant of OUR
|
|
340
|
+
// gate from a foreign process before it signals anything.
|
|
341
|
+
repoRoot: cwd,
|
|
342
|
+
commandSignature: buildCommandSignature(cmd),
|
|
343
|
+
sessionId: opts.sessionId ?? null,
|
|
344
|
+
...(opts.seams ?? {}),
|
|
308
345
|
});
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
: (
|
|
315
|
-
|
|
346
|
+
|
|
347
|
+
// A process that outlived SIGKILL (one that `setsid`-ed out of the group) is
|
|
348
|
+
// SAID OUT LOUD on the channel the operator and the diagnostics bundle both
|
|
349
|
+
// read. Silence here would be the exact failure the ladder exists to expose.
|
|
350
|
+
const output = result.survivors.length > 0
|
|
351
|
+
? `${result.output}\ngate: ${result.survivors.length} process(es) survived SIGKILL: ${result.survivors.join(', ')}`.trim()
|
|
352
|
+
: result.output;
|
|
353
|
+
|
|
354
|
+
return {
|
|
355
|
+
exitCode: result.exitCode,
|
|
356
|
+
output,
|
|
357
|
+
timedOut: result.timedOut,
|
|
358
|
+
overflow: result.overflow,
|
|
359
|
+
killSignals: result.killSignals,
|
|
360
|
+
survivors: result.survivors,
|
|
361
|
+
pgid: result.pgid,
|
|
362
|
+
};
|
|
316
363
|
} catch (err) {
|
|
317
364
|
return {
|
|
318
365
|
exitCode: 1,
|
|
319
366
|
output: `quality-gate: failed to spawn command "${cmd}": ${err?.message ?? String(err)}`,
|
|
320
367
|
timedOut: false,
|
|
368
|
+
overflow: false,
|
|
369
|
+
killSignals: [],
|
|
370
|
+
survivors: [],
|
|
371
|
+
pgid: -1,
|
|
321
372
|
};
|
|
322
373
|
}
|
|
323
374
|
}
|
|
@@ -723,13 +774,44 @@ function coerceMaxRetries(n) {
|
|
|
723
774
|
// Public API
|
|
724
775
|
// ---------------------------------------------------------------------------
|
|
725
776
|
|
|
777
|
+
/**
|
|
778
|
+
* The kill-ladder fields of a `quality_gate.passed/.failed` record (#1439).
|
|
779
|
+
*
|
|
780
|
+
* ONE builder for BOTH emitters — this library's {@link emitGateEvent} and the
|
|
781
|
+
* `scripts/run-quality-gate.mjs` CLI — so the two can never publish different
|
|
782
|
+
* shapes under the same keys. From THIS builder all three keys are always
|
|
783
|
+
* present: `timed_out` `false`, `survivors` `0` and `kill_signals` `[]` are
|
|
784
|
+
* measurements ("not killed"), unlike `counts`, whose absence means "not
|
|
785
|
+
* measured". The CLI then passes the result through `joinGateKillFields()`
|
|
786
|
+
* (`scripts/lib/gates/gate-helpers.mjs`, #1457), which OR-joins the inner
|
|
787
|
+
* per-command ladders and MAY omit the three keys when that inner side was
|
|
788
|
+
* not measured and the outer ladder did not fire.
|
|
789
|
+
*
|
|
790
|
+
* - `timed_out` — the run hit its wall-clock ceiling and was killed (exit 124).
|
|
791
|
+
* - `survivors` — how many pids were still alive after the SIGKILL step; the
|
|
792
|
+
* pids themselves stay in the gate output / diagnostics bundle.
|
|
793
|
+
* - `kill_signals` — the signals actually sent, in order (`SIGTERM`, `SIGKILL`).
|
|
794
|
+
* Copied, because `spawnInGroup` records them at send time into a live array.
|
|
795
|
+
*
|
|
796
|
+
* @param {{timedOut?: boolean, killSignals?: string[], survivors?: number[]}|null|undefined} run
|
|
797
|
+
* @returns {{timed_out: boolean, survivors: number, kill_signals: string[]}}
|
|
798
|
+
*/
|
|
799
|
+
export function gateKillFields(run) {
|
|
800
|
+
return {
|
|
801
|
+
timed_out: run?.timedOut === true,
|
|
802
|
+
survivors: Array.isArray(run?.survivors) ? run.survivors.length : 0,
|
|
803
|
+
kill_signals: Array.isArray(run?.killSignals) ? [...run.killSignals] : [],
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
|
|
726
807
|
/**
|
|
727
808
|
* Emit exactly one `orchestrator.quality_gate.{passed,failed}` event per
|
|
728
809
|
* `runQualityGateWithRetry` CALL (#928b).
|
|
729
810
|
*
|
|
730
811
|
* NO DOUBLE-COUNTING. The two gate paths never nest:
|
|
731
812
|
* - `scripts/run-quality-gate.mjs` spawns `scripts/lib/gates/gate-*.mjs`
|
|
732
|
-
* directly
|
|
813
|
+
* directly; it imports only the pure `gateKillFields` helper from this
|
|
814
|
+
* module, never `runQualityGateWithRetry`, so it never reaches this emitter;
|
|
733
815
|
* - this module spawns the resolved gate COMMANDS (and `parse-config.mjs`)
|
|
734
816
|
* directly and does not invoke that wrapper.
|
|
735
817
|
* A single run therefore passes through exactly one emitter.
|
|
@@ -783,7 +865,7 @@ function coerceMaxRetries(n) {
|
|
|
783
865
|
* wrote it.
|
|
784
866
|
*
|
|
785
867
|
* Extraction margin: {@link suiteCountsFromOutput} sees only the
|
|
786
|
-
*
|
|
868
|
+
* 50-line tail `process-group.mjs` retains (`OUTPUT_TAIL_LINES` there). Measured on `npm test`
|
|
787
869
|
* (vitest 2026-07-31), the `Tests` summary line sits 5 lines from the end — 45
|
|
788
870
|
* lines of headroom. A runner epilogue longer than that (coverage table, long
|
|
789
871
|
* unhandled-error dump) pushes the summary out of the window; `counts` is then
|
|
@@ -796,8 +878,13 @@ function coerceMaxRetries(n) {
|
|
|
796
878
|
* @param {number} attempts
|
|
797
879
|
* @param {string|null} gate
|
|
798
880
|
* @param {{passed: number, failed: number, total: number}|null} [counts]
|
|
881
|
+
* @param {{timedOut?: boolean, killSignals?: string[], survivors?: number[]}|null} [killRun]
|
|
882
|
+
* the run that decided the verdict — the last attempt's failing gate; `null`
|
|
883
|
+
* on the passing path, where every gate exited 0 and so none was killed
|
|
884
|
+
* (`spawnInGroup` only starts its kill ladder on timeout or overflow, and
|
|
885
|
+
* both force a non-zero exit code).
|
|
799
886
|
*/
|
|
800
|
-
async function emitGateEvent(repoRoot, ok, attempts, gate, counts) {
|
|
887
|
+
async function emitGateEvent(repoRoot, ok, attempts, gate, counts, killRun = null) {
|
|
801
888
|
try {
|
|
802
889
|
await emitEvent(
|
|
803
890
|
`orchestrator.quality_gate.${ok ? 'passed' : 'failed'}`,
|
|
@@ -807,6 +894,7 @@ async function emitGateEvent(repoRoot, ok, attempts, gate, counts) {
|
|
|
807
894
|
attempts,
|
|
808
895
|
...(gate ? { gate } : {}),
|
|
809
896
|
...(counts ? { counts } : {}),
|
|
897
|
+
...gateKillFields(killRun),
|
|
810
898
|
...sessionAttribution(repoRoot),
|
|
811
899
|
},
|
|
812
900
|
{ repoRoot },
|
|
@@ -833,6 +921,14 @@ async function emitGateEvent(repoRoot, ok, attempts, gate, counts) {
|
|
|
833
921
|
* @param {string} [opts.repoRoot] — defaults to process.cwd().
|
|
834
922
|
* @param {{lint?: string, typecheck?: string, test?: string}} [opts.commands]
|
|
835
923
|
* — override individual gate commands.
|
|
924
|
+
* @param {number} [opts.gateTimeoutMs] — per-gate wall-clock ceiling. Defaults to
|
|
925
|
+
* GATE_TIMEOUT_MS (15 min). On expiry the gate's
|
|
926
|
+
* whole process GROUP gets SIGTERM → grace →
|
|
927
|
+
* SIGKILL and the gate reports exit 124.
|
|
928
|
+
* @param {object} [opts._processSeams] — TEST SEAM, forwarded verbatim to
|
|
929
|
+
* `spawnInGroup` (`spawnFn`, `killFn`,
|
|
930
|
+
* `isAliveFn`, `sleepFn`, `killGraceMs`,
|
|
931
|
+
* `verifyWaitMs`). Production passes nothing.
|
|
836
932
|
*
|
|
837
933
|
* @returns {Promise<{
|
|
838
934
|
* ok: boolean,
|
|
@@ -851,6 +947,24 @@ export async function runQualityGateWithRetry(opts) {
|
|
|
851
947
|
: async () => {};
|
|
852
948
|
const repoRoot = resolveRepoRoot(safeOpts.repoRoot);
|
|
853
949
|
const commands = resolveCommands(safeOpts.commands, repoRoot);
|
|
950
|
+
/**
|
|
951
|
+
* Per-gate spawn options, resolved ONCE per call.
|
|
952
|
+
*
|
|
953
|
+
* `sessionId` comes from the PROCESS-LOCAL witness only
|
|
954
|
+
* ({@link readOwnSessionIds} → `CLAUDE_CODE_SESSION_ID`), never from
|
|
955
|
+
* `.orchestrator/session.lock`: the lock is a repo-GLOBAL artefact any
|
|
956
|
+
* session in this working copy may hold, so reading it here would stamp a
|
|
957
|
+
* PEER's id onto our own gate processes and point the reaper at the wrong
|
|
958
|
+
* owner (`.claude/rules/identity-and-locks.md` — rank witnesses, never union
|
|
959
|
+
* them). No witness → `null`, which the ledger records as "owner unknown".
|
|
960
|
+
*/
|
|
961
|
+
const gateOpts = {
|
|
962
|
+
timeoutMs: typeof safeOpts.gateTimeoutMs === 'number' ? safeOpts.gateTimeoutMs : undefined,
|
|
963
|
+
sessionId: [...readOwnSessionIds()][0] ?? null,
|
|
964
|
+
seams: (typeof safeOpts._processSeams === 'object' && safeOpts._processSeams !== null)
|
|
965
|
+
? safeOpts._processSeams
|
|
966
|
+
: undefined,
|
|
967
|
+
};
|
|
854
968
|
|
|
855
969
|
// Accumulate per-attempt failure info for the diagnostics bundle.
|
|
856
970
|
const allFailures = [];
|
|
@@ -889,7 +1003,10 @@ export async function runQualityGateWithRetry(opts) {
|
|
|
889
1003
|
|
|
890
1004
|
for (const gate of GATE_ORDER) {
|
|
891
1005
|
const cmd = commands[gate];
|
|
892
|
-
|
|
1006
|
+
// `await` inside `for…of` is deliberate: the gates are fail-fast and
|
|
1007
|
+
// SEQUENTIAL (lint → typecheck → test), exactly as the synchronous path
|
|
1008
|
+
// ran them. Parallelising them would change the contract, not the plumbing.
|
|
1009
|
+
const result = await runGate(cmd, repoRoot, gateOpts);
|
|
893
1010
|
if (gate === 'test') {
|
|
894
1011
|
// The numbers are in hand right here — capture them at the seam rather
|
|
895
1012
|
// than letting them travel as prose (#954).
|
|
@@ -906,6 +1023,8 @@ export async function runQualityGateWithRetry(opts) {
|
|
|
906
1023
|
exitCode: result.exitCode,
|
|
907
1024
|
output: result.output,
|
|
908
1025
|
timedOut: result.timedOut,
|
|
1026
|
+
killSignals: result.killSignals,
|
|
1027
|
+
survivors: result.survivors,
|
|
909
1028
|
command: cmd,
|
|
910
1029
|
attempt,
|
|
911
1030
|
};
|
|
@@ -984,7 +1103,7 @@ export async function runQualityGateWithRetry(opts) {
|
|
|
984
1103
|
`❌ quality-gate exhausted retries (${attempt}), writing diagnostics to ${bundlePath ?? '<unwritable>'}\n`,
|
|
985
1104
|
);
|
|
986
1105
|
|
|
987
|
-
await emitGateEvent(repoRoot, false, attempt, lastFailure?.gate ?? null, testCounts);
|
|
1106
|
+
await emitGateEvent(repoRoot, false, attempt, lastFailure?.gate ?? null, testCounts, lastFailure);
|
|
988
1107
|
|
|
989
1108
|
const out = {
|
|
990
1109
|
ok: false,
|