session-orchestrator 3.20.0 → 3.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/rules/000-session-orchestrator.mdc +3 -2
- package/.cursor/rules/030-wave-execution.mdc +10 -8
- package/.cursor/rules/040-discovery.mdc +6 -6
- package/.cursor/rules/050-plan.mdc +8 -8
- package/CHANGELOG.md +515 -0
- package/README.md +16 -11
- package/agents/analyst.md +1 -1
- package/agents/architect-reviewer.md +1 -1
- package/agents/code-implementer.md +4 -2
- package/agents/db-specialist.md +1 -1
- package/agents/dialectic-deriver.md +1 -1
- package/agents/docs-writer.md +1 -1
- package/agents/memory-proposal-collector.md +7 -5
- package/agents/qa-strategist.md +1 -1
- package/agents/security-reviewer.md +1 -1
- package/agents/session-reviewer.md +42 -1
- package/agents/skill-applied-judge.md +1 -1
- package/agents/test-writer.md +1 -1
- package/agents/ui-developer.md +1 -1
- package/agents/ux-evaluator.md +1 -1
- package/commands/eli5.md +33 -0
- package/commands/release.md +62 -0
- package/commands/test.md +2 -2
- package/docs/components.md +6 -5
- package/docs/migration-v3.md +9 -6
- package/docs/persona-panel.md +3 -1
- package/docs/scope-collision-guard.md +167 -0
- package/docs/session-config-reference.md +31 -8
- package/hooks/_lib/lock-bootstrap.mjs +19 -13
- package/hooks/enforce-scope.mjs +103 -3
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks.json +21 -1
- package/hooks/on-session-end.mjs +76 -97
- package/hooks/on-session-start.mjs +195 -104
- package/hooks/on-stop.mjs +127 -12
- package/hooks/post-bash-write-verify.mjs +8 -32
- package/hooks/pre-auq-clarity.mjs +787 -0
- package/hooks/pre-bash-issue-budget.mjs +17 -18
- package/hooks/pre-task-scope-disjoint.mjs +1042 -0
- package/package.json +3 -1
- package/pi/prompts/eli5.md +12 -0
- package/pi/prompts/release.md +12 -0
- package/scripts/auq-audit.mjs +825 -0
- package/scripts/autopilot.mjs +10 -9
- package/scripts/emit-session.mjs +42 -0
- package/scripts/export-hw-learnings.mjs +61 -2
- package/scripts/lib/auq/clarity.mjs +1314 -0
- package/scripts/lib/auq/parse.mjs +1006 -0
- package/scripts/lib/auq/schema.mjs +1457 -0
- package/scripts/lib/autopilot/worktree-pipeline.mjs +5 -5
- package/scripts/lib/backlog-scan.mjs +106 -15
- package/scripts/lib/build-live-signals.mjs +7 -3
- package/scripts/lib/ci-status-banner.mjs +267 -77
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +32 -9
- package/scripts/lib/config/vault-integration.mjs +12 -1
- package/scripts/lib/dispatcher/rank.mjs +4 -7
- package/scripts/lib/gates/gate-full.mjs +3 -3
- package/scripts/lib/gates/gate-helpers.mjs +17 -6
- package/scripts/lib/git-config-drift.mjs +471 -0
- package/scripts/lib/harness-audit/categories/category6.mjs +65 -12
- package/scripts/lib/io.mjs +432 -7
- package/scripts/lib/issue-budget.mjs +63 -9
- package/scripts/lib/learnings/select.mjs +157 -3
- package/scripts/lib/memory-cleanup-stamp.mjs +132 -8
- package/scripts/lib/mirror-issues-banner.mjs +266 -0
- package/scripts/lib/named-vault-resolver.mjs +105 -16
- package/scripts/lib/owner-interview.mjs +78 -32
- package/scripts/lib/peer-cards/schema.mjs +6 -2
- package/scripts/lib/peer-discovery.mjs +73 -22
- package/scripts/lib/project-hygiene.mjs +64 -4
- package/scripts/lib/reconcile/renderer.mjs +17 -4
- package/scripts/lib/reconcile/writer.mjs +69 -30
- package/scripts/lib/redact-spans.mjs +89 -0
- package/scripts/lib/resource-probe/evaluate.mjs +330 -149
- package/scripts/lib/resource-probe/probe-platform.mjs +35 -0
- package/scripts/lib/resource-probe.mjs +18 -2
- package/scripts/lib/scope-baseline.mjs +77 -17
- package/scripts/lib/scope-gate.mjs +658 -0
- package/scripts/lib/secret-masker.mjs +262 -0
- package/scripts/lib/session-lock.mjs +34 -10
- package/scripts/lib/session-registry.mjs +9 -1
- package/scripts/lib/spiral-carryover.mjs +23 -2
- package/scripts/lib/state-md/mission-status.mjs +164 -58
- package/scripts/lib/tmux-layout/vcs-detector.mjs +108 -4
- package/scripts/lib/validate/check-agents.mjs +77 -5
- package/scripts/lib/validate/check-auq-clarity.mjs +274 -0
- package/scripts/lib/validate/check-commands.mjs +2 -20
- package/scripts/lib/validate/check-doc-cli-commands.mjs +514 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +48 -0
- package/scripts/lib/validate/check-owner-leakage.mjs +185 -17
- package/scripts/lib/validate/check-rules.mjs +153 -9
- package/scripts/lib/validate/check-skills.mjs +191 -0
- package/scripts/lib/validate/check-test-git-config-target.mjs +665 -0
- package/scripts/lib/validate/check-unicode-safety.mjs +22 -2
- package/scripts/lib/validate/check-untracked-test-deps.mjs +925 -0
- package/scripts/lib/validate/check-unwired-features.mjs +219 -11
- package/scripts/lib/validate/check-vcs-repo-flag.mjs +965 -0
- package/scripts/lib/validate/frontmatter-block.mjs +61 -0
- package/scripts/lib/validate/tier-inference.mjs +46 -8
- package/scripts/lib/vault-backfill/glab.mjs +91 -58
- package/scripts/lib/vault-backfill/manifest.mjs +28 -8
- package/scripts/lib/vault-mirror/namespace.mjs +146 -1
- package/scripts/lib/vault-mirror/process.mjs +264 -31
- package/scripts/lib/vault-mirror/render-sessions.mjs +115 -4
- package/scripts/lib/vault-status/board-writer.mjs +300 -56
- package/scripts/lib/vault-status/narrative-mirror.mjs +119 -5
- package/scripts/lib/vcs-repo-spec.mjs +680 -30
- package/scripts/lib/wave-resource-gate.mjs +67 -73
- package/scripts/materialize-wave-scope.mjs +281 -0
- package/scripts/print-learnings-index.mjs +30 -3
- package/scripts/release.mjs +983 -107
- package/scripts/run-quality-gate.mjs +14 -0
- package/scripts/site-numbers.mjs +1049 -0
- package/scripts/validate-plugin.mjs +64 -0
- package/scripts/validate-wave-scope.mjs +286 -12
- package/scripts/vault-backfill.mjs +32 -5
- package/scripts/vault-mirror.mjs +26 -1
- package/skills/_shared/monitor-patterns.md +24 -4
- package/skills/_shared/parallel-aware-auq.md +30 -24
- package/skills/_shared/parallel-aware-preamble.md +31 -2
- package/skills/_shared/state-ownership.md +49 -6
- package/skills/bootstrap/SKILL.md +2 -1
- package/skills/brainstorm/SKILL.md +18 -18
- package/skills/brainstorm/soul.md +12 -0
- package/skills/claude-md-drift-check/SKILL.md +9 -1
- package/skills/debug/SKILL.md +4 -1
- package/skills/discovery/SKILL.md +28 -24
- package/skills/discovery/issue-templates.md +4 -4
- package/skills/discovery/probes-code.md +2 -2
- package/skills/discovery/probes-feature.md +6 -6
- package/skills/discovery/probes-infra.md +2 -2
- package/skills/discovery/probes-session.md +5 -5
- package/skills/dispatcher/SKILL.md +10 -1
- package/skills/eli5/SKILL.md +43 -0
- package/skills/evolve/SKILL.md +8 -9
- package/skills/frontmatter-guard/SKILL.md +9 -1
- package/skills/gitlab-ops/SKILL.md +73 -59
- package/skills/gitlab-portfolio/SKILL.md +10 -1
- package/skills/grill/SKILL.md +6 -6
- package/skills/grill/soul.md +16 -0
- package/skills/memory-cleanup/SKILL.md +20 -7
- package/skills/npm-publish/SKILL.md +23 -51
- package/skills/peekaboo-driver/SKILL.md +3 -3
- package/skills/persona-panel/SKILL.md +3 -1
- package/skills/plan/SKILL.md +18 -16
- package/skills/plan/mode-feature.md +1 -1
- package/skills/plan/mode-new.md +42 -12
- package/skills/plan/soul.md +12 -0
- package/skills/reconcile/SKILL.md +3 -3
- package/skills/repo-audit/SKILL.md +10 -1
- package/skills/session-end/SKILL.md +97 -22
- package/skills/session-end/metrics-collection.md +1 -1
- package/skills/session-end/phase-3-6-tail.md +37 -2
- package/skills/session-end/session-metrics-write.md +4 -10
- package/skills/session-plan/SKILL.md +2 -2
- package/skills/session-plan/wave-template.md +1 -1
- package/skills/session-start/SKILL.md +82 -36
- package/skills/session-start/phase-2-5-docs-planning.md +8 -8
- package/skills/session-start/phase-4-5-resource-health.md +82 -19
- package/skills/session-start/soul.md +110 -0
- package/skills/spinout/SKILL.md +5 -1
- package/skills/sunset-review/SKILL.md +11 -1
- package/skills/test-runner/SKILL.md +2 -2
- package/skills/tmux-layout/SKILL.md +7 -2
- package/skills/using-orchestrator/SKILL.md +1 -1
- package/skills/vault-mirror/SKILL.md +10 -1
- package/skills/vault-sync/SKILL.md +10 -1
- package/skills/vault-sync/validator.mjs +55 -6
- package/skills/wave-executor/wave-loop.md +64 -12
- package/skills/write-executable-plan/SKILL.md +6 -6
- package/scripts/lib/mission-status-schema.mjs +0 -114
- package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +0 -8
- package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +0 -8
- package/skills/vault-sync/tests/fixtures/archive-test-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/live-note.md +0 -8
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/bad-type.md +0 -8
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +0 -8
- package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +0 -8
- package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +0 -10
- package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +0 -8
- package/skills/vault-sync/tests/fixtures/clean-vault/README.md +0 -3
- package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +0 -11
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/has-dangling.md +0 -9
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +0 -8
- package/skills/vault-sync/tests/fixtures/empty-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/missing-id.md +0 -7
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +0 -9
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/nested-tags-note.md +0 -11
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +0 -3
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +0 -3
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +0 -11
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/hello-world.md +0 -11
- package/skills/vault-sync/tests/schema-drift.test.mjs +0 -133
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* cpu_load_5m: 1.8,
|
|
19
19
|
* cpu_load_5m_pct: 45 | null, // 5m load-average as pct-of-cores; null on Windows/zero-load (#943)
|
|
20
20
|
* claude_processes_count: 3 | null,
|
|
21
|
+
* peer_sessions_count: 2 | null, // live peer SESSIONS from the registry, self excluded (#1089)
|
|
21
22
|
* codex_processes_count: 0 | null,
|
|
22
23
|
* other_node_processes: 12 | null,
|
|
23
24
|
* zombie_processes_count: 1 | null,
|
|
@@ -40,13 +41,14 @@
|
|
|
40
41
|
*/
|
|
41
42
|
|
|
42
43
|
import os from 'node:os';
|
|
43
|
-
import { ramSnapshot, cpuSnapshot, processCounts, swapUsedMb, memoryPressurePctFree, ramAvailableGb } from './resource-probe/probe-platform.mjs';
|
|
44
|
+
import { ramSnapshot, cpuSnapshot, processCounts, swapUsedMb, memoryPressurePctFree, ramAvailableGb, peerSessionsCount } from './resource-probe/probe-platform.mjs';
|
|
44
45
|
|
|
45
46
|
// ---------------------------------------------------------------------------
|
|
46
47
|
// Re-exports — preserve public API for all existing callers
|
|
47
48
|
// ---------------------------------------------------------------------------
|
|
48
49
|
|
|
49
|
-
export { evaluate } from './resource-probe/evaluate.mjs';
|
|
50
|
+
export { evaluate, PROCESSES_PER_SESSION, PRESSURE_HARD_PCT, PRESSURE_SOFT_PCT, PRESSURE_HEALTHY_PCT, DEFAULT_RESOURCE_THRESHOLDS } from './resource-probe/evaluate.mjs';
|
|
51
|
+
export { peerSessionsCount } from './resource-probe/probe-platform.mjs';
|
|
50
52
|
export { parseEtimeToMinutes, countZombieProcesses, countProcessMatches, parseSwapUsageOutput, parseMemoryPressureOutput, parseVmStatAvailableGb } from './resource-probe/parsers.mjs';
|
|
51
53
|
|
|
52
54
|
// ---------------------------------------------------------------------------
|
|
@@ -60,6 +62,9 @@ export { parseEtimeToMinutes, countZombieProcesses, countProcessMatches, parseSw
|
|
|
60
62
|
* @param {boolean} [opts.skipExtendedSignals] — skip swap + memory_pressure calls (faster in tests)
|
|
61
63
|
* @param {number|null} [opts.zombieThresholdMin] — when non-null, detect zombie Claude/Node
|
|
62
64
|
* processes older than this many minutes with low CPU. Default null (feature disabled).
|
|
65
|
+
* @param {string|null} [opts.sessionId] — own session id, excluded from `peer_sessions_count`
|
|
66
|
+
* (#1089). Omit and the count simply includes every live registry entry, which
|
|
67
|
+
* over-counts by exactly one — pass it whenever the caller knows its own id.
|
|
63
68
|
* @returns {Promise<object>}
|
|
64
69
|
*/
|
|
65
70
|
export async function probe(opts = {}) {
|
|
@@ -85,6 +90,13 @@ export async function probe(opts = {}) {
|
|
|
85
90
|
? { claude_processes_count: null, codex_processes_count: null, other_node_processes: null, zombie_processes_count: null }
|
|
86
91
|
: await processCounts(zombieThresholdMin);
|
|
87
92
|
|
|
93
|
+
// #1089: the registry-denominated concurrency signal. Gated on the same
|
|
94
|
+
// skipProcessCounts flag as the `ps` pass — both answer "who else is on this
|
|
95
|
+
// host", and tests that skip one always mean to skip the other.
|
|
96
|
+
const peer_sessions_count = opts.skipProcessCounts
|
|
97
|
+
? null
|
|
98
|
+
: await peerSessionsCount({ sessionId: opts.sessionId ?? null });
|
|
99
|
+
|
|
88
100
|
let swap_used_mb = null;
|
|
89
101
|
let memory_pressure_pct_free = null;
|
|
90
102
|
let ram_available_gb = null;
|
|
@@ -104,6 +116,10 @@ export async function probe(opts = {}) {
|
|
|
104
116
|
cpu_load_5m,
|
|
105
117
|
cpu_load_5m_pct,
|
|
106
118
|
...procs,
|
|
119
|
+
// Live peer SESSIONS (registry, self excluded) — the unit
|
|
120
|
+
// `concurrent-sessions-warn` is named for. null = registry unreadable, in
|
|
121
|
+
// which case evaluate() falls back to the rescaled process count (#1089).
|
|
122
|
+
peer_sessions_count,
|
|
107
123
|
swap_used_mb,
|
|
108
124
|
memory_pressure_pct_free,
|
|
109
125
|
// macOS-only numeric available-RAM (free + reclaimable) from vm_stat; null
|
|
@@ -124,6 +124,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
124
124
|
|
|
125
125
|
import { parseStateMd, serializeStateMd, resolveStateMdPath, writeStateMd } from './state-md.mjs';
|
|
126
126
|
import { pathMatchesPattern } from './scope-gate.mjs';
|
|
127
|
+
import { resolveBaselineRange, isQueryFailure } from './vcs-repo-spec.mjs';
|
|
127
128
|
|
|
128
129
|
// ---------------------------------------------------------------------------
|
|
129
130
|
// DRIFT_EXCLUDE_PATTERNS — the SINGLE filter source for both the denominator
|
|
@@ -472,23 +473,60 @@ export async function writeBaseline({ repoRoot, intent, ownerBoundary, plannedFi
|
|
|
472
473
|
*
|
|
473
474
|
* Skip precedence (first match wins, so `reason` is deterministic):
|
|
474
475
|
* `no-state-md` → `unreadable-state-md` → `no-baseline` →
|
|
475
|
-
* `stale-baseline` → `unresolvable-ref`
|
|
476
|
+
* `stale-baseline` → (`no-baseline-ref` | `unresolvable-ref`)
|
|
476
477
|
*
|
|
477
|
-
* `session-start-ref` handling —
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
* - Field present
|
|
483
|
-
*
|
|
478
|
+
* `session-start-ref` handling — THREE outcomes, deliberately distinct.
|
|
479
|
+
* `skills/_shared/state-ownership.md:28` declares the field OPTIONAL
|
|
480
|
+
* ("readers MUST tolerate their absence"), so the absent-field branch is a
|
|
481
|
+
* REACHABLE production path, not a defensive corner:
|
|
482
|
+
*
|
|
483
|
+
* - **Field present**, diff against it succeeds → measured; `refUsed`
|
|
484
|
+
* reports the bare ref verbatim (NOT a range — pre-existing contract,
|
|
485
|
+
* unchanged).
|
|
486
|
+
* - **Field absent** → the range is RESOLVED via `resolveBaselineRange()`
|
|
487
|
+
* (scripts/lib/vcs-repo-spec.mjs): preferred remote `R` →
|
|
488
|
+
* `refs/remotes/<R>/HEAD` → `refs/remotes/<R>/{main,master}` → local
|
|
489
|
+
* `{main,master}`. NOT a skip — `refUsed` reports the range actually
|
|
490
|
+
* resolved (`gitlab/main...HEAD`, `origin/master...HEAD`, …).
|
|
491
|
+
* This REPLACES the hard-coded `'origin/main...HEAD'` literal the
|
|
492
|
+
* function carried until #1039, which hard-coded BOTH the remote name
|
|
493
|
+
* AND the default branch in one string. In any repo whose remote is not
|
|
494
|
+
* named `origin`, or whose default branch is not `main`, that diff
|
|
495
|
+
* always failed → the tripwire skipped → and
|
|
496
|
+
* `skills/wave-executor/wave-loop.md` renders every `skipped === true`
|
|
497
|
+
* with NO WARN. A guard that neither bit nor reported that it was not
|
|
498
|
+
* biting.
|
|
499
|
+
* - **Field absent AND nothing resolves** (fresh `git init`, no remotes,
|
|
500
|
+
* no `main`/`master` anywhere) → skip with `reason: 'no-baseline-ref'`.
|
|
501
|
+
* This is an ABSENCE — there is genuinely no session base to measure
|
|
502
|
+
* against — and is deliberately NOT folded onto `unresolvable-ref`,
|
|
503
|
+
* which means the QUERY failed (not a git repo, git not on PATH, a
|
|
504
|
+
* present-but-dead `session-start-ref` after a rebase/force-push).
|
|
505
|
+
* The split follows `isQueryFailure()` from the same module, the single
|
|
506
|
+
* predicate that separates "I could not ask" from "I asked; the answer
|
|
507
|
+
* is no". Folding them was the pre-#1039 behaviour and made an operator
|
|
508
|
+
* unable to tell a broken checkout from a fresh repo.
|
|
509
|
+
*
|
|
510
|
+
* Named ceiling (BV-004) on the local-branch tail of the resolution chain:
|
|
511
|
+
* when the chain lands on a LOCAL `main`/`master` and HEAD is already that
|
|
512
|
+
* branch, `main...HEAD` has merge-base === HEAD and the diff is empty, so
|
|
513
|
+
* the ratio reads `0` instead of skipping. That is the honest floor of the
|
|
514
|
+
* available information (no remote-tracking ref exists to say where the
|
|
515
|
+
* session started) and it is harmless here because both a `0` ratio and a
|
|
516
|
+
* skip are silent under `wave-loop.md`'s WARN-on-breach rule. Revisit if
|
|
517
|
+
* this function ever gains a non-warn consumer that treats `skipped:false`
|
|
518
|
+
* as "measured successfully".
|
|
484
519
|
*
|
|
485
520
|
* @param {object} args
|
|
486
521
|
* @param {string|undefined} args.repoRoot
|
|
487
522
|
* @param {number} [args.threshold] — breach threshold, `>=` counts as
|
|
488
523
|
* breached (default `2.0`).
|
|
489
|
-
* @returns {{ ok: true, skipped: true, reason: 'no-state-md'|'unreadable-state-md'|'no-baseline'|'stale-baseline'|'unresolvable-ref' }
|
|
524
|
+
* @returns {{ ok: true, skipped: true, reason: 'no-state-md'|'unreadable-state-md'|'no-baseline'|'stale-baseline'|'no-baseline-ref'|'unresolvable-ref' }
|
|
490
525
|
* | { ok: true, skipped: false, filesRatio: number, plannedFiles: number,
|
|
491
526
|
* actualFiles: number, breached: boolean, threshold: number, refUsed: string }}
|
|
527
|
+
* Additive since #1039: `no-baseline-ref` is a NEW member of the skip-reason
|
|
528
|
+
* union. No existing member was renamed or removed, and the measured-result
|
|
529
|
+
* shape (all eight keys) is byte-identical to the pre-#1039 contract.
|
|
492
530
|
*/
|
|
493
531
|
export function computeDrift({ repoRoot, threshold = 2.0 } = {}) {
|
|
494
532
|
const parsedFm = readFrontmatterOrReason(repoRoot);
|
|
@@ -514,18 +552,40 @@ export function computeDrift({ repoRoot, threshold = 2.0 } = {}) {
|
|
|
514
552
|
? baseline.sessionStartRef
|
|
515
553
|
: null;
|
|
516
554
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
555
|
+
// Resolve the diff range. The `session-start-ref` branch keeps its exact
|
|
556
|
+
// pre-#1039 shape (two-dot `<ref>..HEAD`, `refUsed` = the bare ref); only
|
|
557
|
+
// the absent-field branch changed, from a hard-coded literal to a real
|
|
558
|
+
// resolution. See the JSDoc above for the three outcomes.
|
|
559
|
+
let diffRange;
|
|
560
|
+
let refUsed;
|
|
561
|
+
if (rawRef !== null) {
|
|
562
|
+
diffRange = `${rawRef}..HEAD`;
|
|
563
|
+
refUsed = rawRef;
|
|
564
|
+
} else {
|
|
565
|
+
const resolved = resolveBaselineRange({ repoRoot: cwd });
|
|
566
|
+
if (!resolved.ok) {
|
|
567
|
+
// `isQueryFailure()` is the frozen predicate that keeps the two causes
|
|
568
|
+
// apart: a broken/absent git ⇒ `unresolvable-ref` (degraded
|
|
569
|
+
// measurement), a repo that simply has no baseline ref ⇒
|
|
570
|
+
// `no-baseline-ref` (a real, benign repo state).
|
|
571
|
+
return {
|
|
572
|
+
ok: true,
|
|
573
|
+
skipped: true,
|
|
574
|
+
reason: isQueryFailure(resolved.reason) ? 'unresolvable-ref' : 'no-baseline-ref',
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
diffRange = resolved.range;
|
|
578
|
+
refUsed = resolved.range;
|
|
579
|
+
}
|
|
521
580
|
|
|
522
581
|
let stdout;
|
|
523
582
|
try {
|
|
524
|
-
stdout = execFileSync('git',
|
|
583
|
+
stdout = execFileSync('git', ['diff', '--name-only', diffRange], { cwd, encoding: 'utf8' });
|
|
525
584
|
} catch {
|
|
526
|
-
//
|
|
527
|
-
//
|
|
528
|
-
//
|
|
585
|
+
// The range resolved but the diff against it failed — a present-but-dead
|
|
586
|
+
// `session-start-ref` (rebase, force-push, deleted commit), or a
|
|
587
|
+
// resolved base that vanished between resolution and diff. Neither can
|
|
588
|
+
// produce a trustworthy numerator.
|
|
529
589
|
return { ok: true, skipped: true, reason: 'unresolvable-ref' };
|
|
530
590
|
}
|
|
531
591
|
|