session-orchestrator 3.24.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.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 +1 -1
- 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/.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 +1125 -2
- package/NOTICE +11 -6
- package/README.md +127 -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 +65 -21
- package/docs/components.md +36 -15
- package/docs/cursor-setup.md +6 -2
- package/docs/events-schema.md +9 -6
- package/docs/instruction-delivery.md +62 -0
- package/{agents/memory-proposal-collector.md → docs/memory-proposal-flow.md} +1 -8
- package/docs/migration-v4.md +341 -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 +1487 -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 +36 -11
- 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/plugin.json +27 -0
- 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-cursor-adapter.mjs +45 -8
- package/scripts/generate-hook-import-set.mjs +249 -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 +82 -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/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 +26 -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 +43 -6
- package/scripts/lib/owner-config-loader.mjs +21 -10
- package/scripts/lib/owner-interview.mjs +3 -3
- package/scripts/lib/owner-yaml.mjs +207 -14
- package/scripts/lib/platform.mjs +108 -15
- package/scripts/lib/plugin-update-banner.mjs +406 -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 +13 -4
- 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 +36 -2
- package/scripts/lib/session-schema/validator.mjs +38 -4
- package/scripts/lib/session-start-probes.mjs +18 -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 +181 -9
- package/scripts/lib/telemetry/sync.mjs +368 -12
- package/scripts/lib/validate/check-agents-skills.mjs +327 -0
- package/scripts/lib/validate/check-agents.mjs +3 -3
- 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 +281 -20
- package/scripts/lib/validate/check-skill-links.mjs +163 -0
- package/scripts/lib/validate/check-skill-script-paths.mjs +47 -28
- package/scripts/lib/validate/check-unwired-features.mjs +0 -2
- package/scripts/lib/validate/check-validator-registration.mjs +10 -4
- package/scripts/lib/validate/enumerate-repo-files.mjs +317 -0
- 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 +337 -29
- package/scripts/repair-invalid-sessions.mjs +3 -3
- package/scripts/run-quality-gate.mjs +128 -11
- 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 +161 -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 +155 -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/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
|
@@ -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
|
|
package/skills/evolve/SKILL.md
CHANGED
|
@@ -46,7 +46,7 @@ Extract `persistence` from `$CONFIG`. If `persistence` is `false`, abort with me
|
|
|
46
46
|
|
|
47
47
|
> "Learnings require persistence to be enabled in Session Config. Add `persistence: true` to your Session Config block (CLAUDE.md for Claude Code, AGENTS.md for Codex CLI)."
|
|
48
48
|
|
|
49
|
-
**Telemetry on abort (#1200):** before stopping, emit the abort form of the run-completion event:
|
|
49
|
+
**Telemetry on abort (#1200, #1206):** before stopping, emit the abort form of the run-completion event. Kept as a minimal `emit-event.mjs` call, not routed through `scripts/sweep-expired-learnings.mjs` — no store-write CLI has run yet at this gate (it fires before Step 1.4 even reads `learnings.jsonl`), so there is no mechanical pipeline call site to fold this emit into, unlike the Step 3.5(5)/(6) success path below:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
node scripts/emit-event.mjs --type orchestrator.evolve.completed --payload \
|
|
@@ -100,7 +100,7 @@ Extract learnings from session history.
|
|
|
100
100
|
- Read all entries from `.orchestrator/metrics/sessions.jsonl` (or `<state-dir>/metrics/sessions.jsonl` if the v2 path does not exist — see Phase 1.4 fallback)
|
|
101
101
|
- Parse each JSONL line as JSON
|
|
102
102
|
- Sort by `completed_at` descending (most recent first)
|
|
103
|
-
- If no sessions found, abort: "No session data available. Complete at least one session before running evolve." **Telemetry on abort (#1200):** before stopping, emit:
|
|
103
|
+
- If no sessions found, abort: "No session data available. Complete at least one session before running evolve." **Telemetry on abort (#1200, #1206):** before stopping, emit — same minimal `emit-event.mjs` call as Phase 1.2's abort, and for the same reason: this gate fires before the Step 3.5(5) `sweep-expired-learnings.mjs --prune` call exists to fold the emit into:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
106
|
node scripts/emit-event.mjs --type orchestrator.evolve.completed --payload \
|
|
@@ -181,7 +181,7 @@ For each of the 9 built-in analyzer learning types, apply these heuristics:
|
|
|
181
181
|
- Read `.orchestrator/metrics/events.jsonl` (session + wave events) and the registry `sweep.log` at `~/.config/session-orchestrator/sessions/sweep.log`. Both are optional — missing files produce no candidates.
|
|
182
182
|
- Invoke `scripts/lib/hardware-pattern-detector.mjs` → `detectHardwarePatterns({events, sweepLogEntries, thresholds})`. Thresholds come from Session Config `resource-thresholds` when present, falling back to `DEFAULT_THRESHOLDS`.
|
|
183
183
|
- Five detection signals (aggregated per `(signal, host_class)` pair, ≥2 occurrences required):
|
|
184
|
-
- **oom-kill** — `orchestrator.session.stopped` with `exit_code: 137` or OOM-marker in `error`
|
|
184
|
+
- **oom-kill** — `orchestrator.turn.stopped` (or its deprecated alias `orchestrator.session.stopped`, which `hooks/on-stop.mjs` still emits with `deprecated: true` until **2027-03-06**) with `exit_code: 137` or OOM-marker in `error`. Both names are accepted for the deprecation window because every OOM record already on disk carries only the legacy name; the detector's set lives in `OOM_TERMINAL_EVENTS` (`scripts/lib/hardware-pattern-detector.mjs`) and drops the alias on that date.
|
|
185
185
|
- **heartbeat-gap** — registry sweep-log entries with `gap_minutes` above `resource-thresholds.zombie-threshold-min`
|
|
186
186
|
- **concurrent-session-pressure** — session-start events with `peer_count ≥ concurrent-sessions-warn`
|
|
187
187
|
- **disk-full** — events whose `error` matches `ENOSPC` / "no space left"
|
|
@@ -316,22 +316,34 @@ For confirmed learnings, use atomic rewrite strategy:
|
|
|
316
316
|
Write the full next-generation entry set (existing entries **with** the step-2/3 confidence
|
|
317
317
|
updates, **plus** the step-4 new learnings) as JSONL to a temp sidecar **via the Write tool**
|
|
318
318
|
(not a shell `>` redirect — the destructive-command guard blocks it), then invoke the
|
|
319
|
-
`--prune` subcommand of the sweep CLI
|
|
319
|
+
`--prune` subcommand of the sweep CLI. **This call is also `/evolve`'s ONLY
|
|
320
|
+
`orchestrator.evolve.completed` success emit (#1206)** — export `N` (Step 3.5(4)'s
|
|
321
|
+
new-learnings count), `M` (Step 3.5(2)'s reinforced-existing count) and `DURATION_MS`
|
|
322
|
+
(elapsed ms since the Phase 1 marker) as real shell variables before running this line;
|
|
323
|
+
`${N:-0}`-style expansion means an un-exported variable degrades to a safe `0` rather than
|
|
324
|
+
an argument error:
|
|
320
325
|
|
|
321
326
|
```bash
|
|
322
327
|
NEXT=".orchestrator/metrics/.learnings-next.jsonl" # written by the step above
|
|
323
|
-
node scripts/sweep-expired-learnings.mjs --prune --apply --json --entries "$NEXT"
|
|
328
|
+
node scripts/sweep-expired-learnings.mjs --prune --apply --json --entries "$NEXT" \
|
|
329
|
+
--appended "${N:-0}" --boosted "${M:-0}" --duration-ms "${DURATION_MS:-0}" \
|
|
330
|
+
--repo-root "$(pwd)" && rm -f "$NEXT"
|
|
324
331
|
```
|
|
325
332
|
|
|
326
333
|
`--file` / `--archive` default to the canonical store + archive paths — pass them only when
|
|
327
334
|
operating on a non-default pair. The command prints ONE JSON line; capture it as `$PRUNE` and
|
|
328
|
-
report its `{scanned, kept, archived, byReason}` in the final summary
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
>
|
|
335
|
+
report its `{scanned, kept, archived, byReason}` in the final summary — `$PRUNE.archived` is
|
|
336
|
+
also the `pruned` counter the emit above just wrote, so there is nothing left to compute for
|
|
337
|
+
the telemetry after this line. Preview first with `--prune --dry-run --json` (same counts,
|
|
338
|
+
zero writes, **no telemetry emit** — dry-run never claims a completed run) whenever the next
|
|
339
|
+
generation was hand-assembled.
|
|
340
|
+
|
|
341
|
+
> **This step is `/evolve`'s only store-write path, and (since #1206) its only
|
|
342
|
+
> `orchestrator.evolve.completed` success emit.** Until #1017 the store write lived here as
|
|
343
|
+
> an inline `node --input-type=module -e` block, and until #1206 the telemetry emit was a
|
|
344
|
+
> SEPARATE `emit-event.mjs` call further down this file — both were a mechanism hiding inside
|
|
345
|
+
> prose: no `--help`, no exit-code contract, no test, and (for the emit) forgettable
|
|
346
|
+
> independently of the write it reported on. Do not re-inline either, and do not hand-roll a
|
|
335
347
|
> `jq | ... > learnings.jsonl` pass — that bypasses every #721 safety net.
|
|
336
348
|
|
|
337
349
|
**Exit codes are the no-op rule.** `0` = applied (or a clean no-op). `1` = input error: the
|
|
@@ -394,12 +406,12 @@ For confirmed learnings, use atomic rewrite strategy:
|
|
|
394
406
|
|
|
395
407
|
Report: "Saved N new learnings, updated M existing. Total active: K."
|
|
396
408
|
|
|
397
|
-
**Telemetry (#1200):**
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
409
|
+
**Telemetry (#1200, #1206):** already emitted by `scripts/sweep-expired-learnings.mjs --prune`
|
|
410
|
+
at Step 3.5(5) above — no separate action here. `appended`/`boosted`/`duration_ms` are whatever
|
|
411
|
+
`$N`/`$M`/`$DURATION_MS` carried into that call, and `pruned` is `$PRUNE.archived` (the sweep
|
|
412
|
+
CLI's own returned total). `promoted` is always `0` from THIS call site: promotion to `public`
|
|
413
|
+
scope is the separate `npm run share:hw-learnings -- --promote` CLI, never invoked by
|
|
414
|
+
`/evolve analyze` itself — see `docs/events-schema.md`.
|
|
403
415
|
|
|
404
416
|
### Step 3.6: C2 Auto-Repair Feeder (opt-in — #647)
|
|
405
417
|
|
|
@@ -626,11 +638,27 @@ const result = await runDialecticDeriver({
|
|
|
626
638
|
- If `--apply`: call `mergePeerCard(existingBody, managedUpdates)` from `scripts/lib/peer-cards/merger.mjs` for each card target, then `writePeerCard(repoRoot, 'user', mergedUserCard)` and `writePeerCard(repoRoot, 'agent', mergedAgentCard)` from `scripts/lib/peer-cards/writer.mjs`. Update the `updated:` frontmatter.
|
|
627
639
|
- Report: `Dialectic-derived: M deltas to USER.md, N deltas to AGENT.md. Dry-run | Applied. Tokens: in=<X> out=<Y>.`
|
|
628
640
|
|
|
629
|
-
**Telemetry (#1200
|
|
641
|
+
**Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs`, not skill prose.**
|
|
642
|
+
The dry-run branch needs no action here: `runDialecticDeriver()` already emitted the success
|
|
643
|
+
form (`mode: 'dry-run'`) internally at Step 6.2, using `countManagedSections(diff)` on the SAME
|
|
644
|
+
diff this step presents — in dry-run the diff IS the final artefact, so the event and the
|
|
645
|
+
artefact are computed from the same value. The **apply** branch is the one case that pipeline
|
|
646
|
+
cannot record on its own: the merge above happens here, one layer up, so call
|
|
647
|
+
`recordDialecticRun()` (the sibling export beside `emitEvolveCompleted` in
|
|
648
|
+
`scripts/lib/learnings/evolve-telemetry.mjs`) immediately after the `writePeerCard()` calls,
|
|
649
|
+
using each target's `mergePeerCard()` `stats` for the deltas:
|
|
630
650
|
|
|
631
|
-
```
|
|
632
|
-
|
|
633
|
-
|
|
651
|
+
```javascript
|
|
652
|
+
await recordDialecticRun({
|
|
653
|
+
repoRoot,
|
|
654
|
+
status: 'ok',
|
|
655
|
+
mode: 'apply',
|
|
656
|
+
userDeltas: userMergeStats.replaced + userMergeStats.appended,
|
|
657
|
+
agentDeltas: agentMergeStats.replaced + agentMergeStats.appended,
|
|
658
|
+
tokensIn: result.usage?.input_tokens,
|
|
659
|
+
tokensOut: result.usage?.output_tokens,
|
|
660
|
+
durationMs: DURATION_MS,
|
|
661
|
+
});
|
|
634
662
|
```
|
|
635
663
|
|
|
636
664
|
### Step 6.5: Error Handling
|
|
@@ -640,11 +668,22 @@ node scripts/emit-event.mjs --type orchestrator.dialectic.completed --payload \
|
|
|
640
668
|
- `status: 'empty-input'` → exit clean with message "dialectic: skipped (no input)"
|
|
641
669
|
- subagent crash → log ⚠, exit cleanly (do NOT write to `.orchestrator/dialectic-pending.md`)
|
|
642
670
|
|
|
643
|
-
**Telemetry (#1200
|
|
671
|
+
**Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs` for THREE of the five
|
|
672
|
+
outcomes.** `budget-exceeded`, `would-empty-card`, and `empty-input` are `runDialecticDeriver()`
|
|
673
|
+
RETURN values, so the module records them itself, mechanically, at the exact return point —
|
|
674
|
+
nothing to do here for those three. The remaining two are THROWN, not returned, and can only be
|
|
675
|
+
caught one layer up:
|
|
644
676
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
677
|
+
- `unknown-model` — `validateModel()` throws synchronously before `runDialecticDeriver()` can
|
|
678
|
+
record anything about the call.
|
|
679
|
+
- `subagent-crash` — a `dispatchAgent`/`Agent()` failure propagates out of
|
|
680
|
+
`runDialecticDeriver()` uncaught (it has no status of its own for this case).
|
|
681
|
+
|
|
682
|
+
Catch both here and call the SAME `recordDialecticRun()` used in Step 6.4's apply branch,
|
|
683
|
+
passing the literal slug as `status` (the abort form: `{aborted: status, duration_ms}`):
|
|
684
|
+
|
|
685
|
+
```javascript
|
|
686
|
+
await recordDialecticRun({ repoRoot, status: 'unknown-model' /* or 'subagent-crash' */, durationMs: DURATION_MS });
|
|
648
687
|
```
|
|
649
688
|
|
|
650
689
|
Cross-reference: PRD #506 AC1-AC4 + EARS gates. Vault Integration: dialectic does NOT mirror to vault (#506 scope — peer cards are repo-local by design; vault mirror is for cross-repo sessions/learnings).
|
|
@@ -94,13 +94,19 @@ The output is stable across calls for the same schema version. Regenerate only w
|
|
|
94
94
|
|
|
95
95
|
## Schema Source Path
|
|
96
96
|
|
|
97
|
-
The canonical schema source is:
|
|
97
|
+
The canonical schema source is `packages/zod-schemas/src/vault-frontmatter.ts` inside a **projects-baseline** checkout. That checkout is **optional and private** — see [`docs/baseline.md`](../../docs/baseline.md) — so the path is RESOLVED, never hardcoded. `resolveSchemaSourcePath()` resolves it in two tiers and returns `null` when nothing resolves. When the EXPLICIT tier is set it is used **alone** — probing past a wrong explicit value would silently read a different baseline than the one named:
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
| Tier | Candidate | Set by |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| **explicit** (exclusive) | `<baseline-path>/packages/zod-schemas/src/vault-frontmatter.ts` | `SO_BASELINE_PATH` env, else `owner.yaml` `paths.baseline-path` (host-local, never committed) — via `resolveHostPath('baseline-path', …)` |
|
|
102
|
+
| convention 1 | `<repoRoot>/../projects-baseline/packages/…` | sibling-checkout convention, the same one `scripts/sync-vault-schema.mjs` uses |
|
|
103
|
+
| convention 2 | `~/Projects/projects-baseline/packages/…` | legacy default this module shipped with |
|
|
104
|
+
|
|
105
|
+
Before this was resolved, convention 2 was the ONLY path and it was hardcoded: on a host whose checkout lives anywhere else, `readVaultSchema()` returned `null` and `generateFrontmatterSnippet()` then died with `Cannot destructure property 'typeEnum' of 'schema' as it is undefined`.
|
|
106
|
+
|
|
107
|
+
`readVaultSchema()` reads the resolved file on every call unless the in-memory mtime cache is current. It returns `null` (no throw) when no candidate resolves or the file is unreadable.
|
|
102
108
|
|
|
103
|
-
`
|
|
109
|
+
**Degraded mode.** With `null`, `generateFrontmatterSnippet()` does not throw: it falls back to an in-module enum/field set mirroring `skills/vault-sync/validator.mjs` (this repo's own in-tree copy of the schema, and what `vault-sync` actually validates against) and writes ONE stderr WARN per process. `computeSchemaHash()` returns `null` in that state — never the SHA-256 of the empty string, which would look like a real measurement and compare equal across every baseline-less host.
|
|
104
110
|
|
|
105
111
|
The parsed output includes:
|
|
106
112
|
|
|
@@ -39,7 +39,7 @@ The script gates mechanics. These three are yours, and it will not make them for
|
|
|
39
39
|
|
|
40
40
|
**2. What a leak means when one is found.** A hit from the leakage gate is not a pattern to silence. Decide which of two it is: a real leak (fix `package.json` `files`, re-pack, re-check) or genuine over-matching (fix `LEAKAGE_PATTERNS` in `scripts/release.mjs` **with a test**). There is no third option, and neither is "publish anyway and clean it up in the next version" — an npm publish is not revocable, and unpublishing burns the version number permanently. Operator handling detail: `docs/distribution/npm-publish-checklist.md` § 3.
|
|
41
41
|
|
|
42
|
-
**3. When to abort instead of repair.** Abort — do not patch forward — when the failure is upstream of the target-confirmed npm receipt: a red preflight row, a lagging `github` mirror, CI not green on the exact commit, a dead token, or a publish that did not issue the target receipt. These are cheap to fix and re-run from the top. Repair-in-place is only appropriate *after* that receipt, where the version is already immutable: registry propagation, a missing GitHub release, or a lagging site deploy can be reconciled because npm already has the correct artifact. When `--publish` reports **Post-publish reconciliation required**, **do not rerun `--publish`**; repair the listed state directly. `commands/release.md` § Abort criteria is the operative list.
|
|
42
|
+
**3. When to abort instead of repair.** Abort — do not patch forward — when the failure is upstream of the target-confirmed npm receipt: a red preflight row, a lagging `github` mirror, CI not green on the exact commit **on either platform** (`--check` carries both `ci-green-on-head` for GitLab and `ci-green-on-head-github` for the mirror, whose macOS matrix leg has no GitLab equivalent), a dead token, or a publish that did not issue the target receipt. These are cheap to fix and re-run from the top. Repair-in-place is only appropriate *after* that receipt, where the version is already immutable: registry propagation, a missing GitHub release, or a lagging site deploy can be reconciled because npm already has the correct artifact. When `--publish` reports **Post-publish reconciliation required**, **do not rerun `--publish`**; repair the listed state directly. `commands/release.md` § Abort criteria is the operative list.
|
|
43
43
|
|
|
44
44
|
## Failure-mode table
|
|
45
45
|
|
|
@@ -356,6 +356,39 @@ If `written === 0` and `approved.length === 0`:
|
|
|
356
356
|
|
|
357
357
|
---
|
|
358
358
|
|
|
359
|
+
## Consolidating and Dropping Generated Rules (merge contract)
|
|
360
|
+
|
|
361
|
+
`.claude/rules/` grows one file per approved learning, so it accumulates. This
|
|
362
|
+
repo consolidated 43 generated files (112,443 B, 46.2 % frontmatter+provenance
|
|
363
|
+
overhead) into 8 thematic files plus 10 drops on 2026-09-06. Both operations
|
|
364
|
+
are safe ONLY under the contract below — the full authoring spec is
|
|
365
|
+
[`docs/rule-authoring.md`](../../docs/rule-authoring.md) § "Consolidated rules:
|
|
366
|
+
N provenance pairs in ONE file". The three facts that decide whether a
|
|
367
|
+
consolidation survives the next `/reconcile`:
|
|
368
|
+
|
|
369
|
+
- **A target file may carry N provenance bullet PAIRS.** Frontmatter
|
|
370
|
+
`learning-key:` is a scalar, so at most one marker fits there; the other N−1
|
|
371
|
+
live in the body as `` - learning-key: `…` `` + `` - learning-id: `…` ``
|
|
372
|
+
bullets, which `engine.mjs` reads via `BODY_LEARNING_KEY_RE` /
|
|
373
|
+
`BODY_LEARNING_ID_RE`. One pair per absorbed learning — a missing pair
|
|
374
|
+
regenerates that learning as a standalone file on the next run.
|
|
375
|
+
- **A merged file's `expires-at` is the EARLIEST of its parts**, never the
|
|
376
|
+
latest: it must not outlive its shortest-lived content.
|
|
377
|
+
- **A dropped learning must be STAMPED before deletion, or it regenerates.**
|
|
378
|
+
`rm .claude/rules/<slug>.md` alone leaves `isProcessed()` false and no
|
|
379
|
+
on-disk marker, so the engine re-proposes it. Stamp it terminal first with
|
|
380
|
+
`markCandidateProcessed({ learningKey, outcome: 'rejected', fallbackSlug,
|
|
381
|
+
repoRoot })` from `scripts/lib/reconcile/idempotency.mjs` — the ONLY
|
|
382
|
+
sanctioned writer of `.orchestrator/runtime/reconcile-candidates.jsonl`
|
|
383
|
+
(never append to that file by hand; the read-side shape guard drops foreign
|
|
384
|
+
records and `mergeCandidates` rewrites the store in full).
|
|
385
|
+
|
|
386
|
+
**Verify a consolidation with a dry run**, not by eye: `alreadyMaterialized`
|
|
387
|
+
must equal absorbed + dropped. If it equals only the absorbed count, the drops
|
|
388
|
+
were not stamped and the next run will resurrect them. Do the whole operation
|
|
389
|
+
while `reconcile.enabled: false` in Session Config, so nothing regenerates
|
|
390
|
+
underneath you mid-edit.
|
|
391
|
+
|
|
359
392
|
## Critical Rules
|
|
360
393
|
|
|
361
394
|
- **NEVER** call `writeApprovedRules` before the operator has confirmed via AUQ — this is the
|
|
@@ -33,7 +33,7 @@ The gate decides, not the coordinator. `applyOffloadDecision()` in `scripts/lib/
|
|
|
33
33
|
- `opts.remoteReady` — `{ [alias]: boolean }`, built from the SessionStart banner line `Offload <alias>: ready=yes …`, or
|
|
34
34
|
- `opts.probeFn` — an async `(alias) => boolean` fallback, consulted only for aliases `remoteReady` doesn't answer for (backed by `remoteDoctor()`, i.e. `offload doctor -H <alias> --brief` parsed by `parseDoctorLine()`).
|
|
35
35
|
|
|
36
|
-
With neither supplied, no host counts as ready and the wave stays local — the gate fails toward local, never toward an unverified host. A role in `NEVER_FOREIGN_ROLES` (`scripts/lib/wave-executor/
|
|
36
|
+
With neither supplied, no host counts as ready and the wave stays local — the gate fails toward local, never toward an unverified host. A role in `NEVER_FOREIGN_ROLES` (`scripts/lib/wave-executor/dispatch-common.mjs`: `impl-core`, `security-review`, `migration`, `release`, `secrets`) is never offloaded regardless of readiness.
|
|
37
37
|
|
|
38
38
|
## 2. What is declared where
|
|
39
39
|
|