peaks-loop 4.0.47 → 4.0.48
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/CHANGELOG.md +24 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/agents/karpathy-reviewer.md +11 -10
- package/dist/cli/cli-helpers.d.ts +34 -0
- package/dist/cli/cli-helpers.js +57 -0
- package/dist/cli/commands/code-job-shape-commands.js +8 -0
- package/dist/cli/commands/code-runtime-commands.js +48 -8
- package/dist/cli/commands/compact-command.js +112 -0
- package/dist/cli/commands/config-commands.js +15 -9
- package/dist/cli/commands/dashboard-long-run.js +6 -0
- package/dist/cli/commands/dispatch-commands.js +11 -1
- package/dist/cli/commands/doctor/invoke-from-code.js +6 -0
- package/dist/cli/commands/hooks-commands.js +4 -4
- package/dist/cli/commands/job-commands.js +8 -0
- package/dist/cli/commands/loop-eval-commands.js +15 -0
- package/dist/cli/commands/perf-audit-commands.js +2 -0
- package/dist/cli/commands/playwright-commands.js +12 -0
- package/dist/cli/commands/prd-commands.js +1 -1
- package/dist/cli/commands/qa-commands.js +22 -0
- package/dist/cli/commands/request-commands.js +8 -0
- package/dist/cli/commands/scan-commands.js +1 -1
- package/dist/cli/commands/security-audit-commands.js +2 -0
- package/dist/cli/commands/slice-integrate-commands.js +5 -0
- package/dist/cli/commands/statusline-commands.js +44 -4
- package/dist/cli/commands/sub-agent/detached.d.ts +14 -1
- package/dist/cli/commands/sub-agent/detached.js +47 -22
- package/dist/cli/commands/sub-agent-shutdown-commands.js +11 -0
- package/dist/cli/commands/verdict-aggregate-command.js +95 -13
- package/dist/cli/commands/workflow-commands.js +1 -1
- package/dist/cli/index.js +5 -45
- package/dist/services/artifacts/artifact-prerequisites.d.ts +38 -7
- package/dist/services/artifacts/artifact-prerequisites.js +130 -65
- package/dist/services/artifacts/request-artifact-service.d.ts +8 -0
- package/dist/services/artifacts/request-artifact-service.js +18 -8
- package/dist/services/artifacts/request-artifact-state-helpers.d.ts +57 -0
- package/dist/services/artifacts/request-artifact-state-helpers.js +91 -10
- package/dist/services/audit-independent/perf-audit-service.d.ts +9 -0
- package/dist/services/audit-independent/perf-audit-service.js +27 -5
- package/dist/services/audit-independent/security-audit-service.d.ts +12 -2
- package/dist/services/audit-independent/security-audit-service.js +28 -6
- package/dist/services/code/auto-compact-lifecycle.d.ts +119 -0
- package/dist/services/code/auto-compact-lifecycle.js +169 -0
- package/dist/services/code/auto-compact-orchestrator.js +13 -2
- package/dist/services/code/compact-event-settle.d.ts +122 -0
- package/dist/services/code/compact-event-settle.js +219 -0
- package/dist/services/compact-history/compact-history-service.d.ts +14 -0
- package/dist/services/config/config-restore.d.ts +12 -1
- package/dist/services/config/config-restore.js +35 -4
- package/dist/services/config/config-rollback.js +6 -1
- package/dist/services/context/harness-context-witness.d.ts +310 -0
- package/dist/services/context/harness-context-witness.js +606 -0
- package/dist/services/evidence/evidence-generator.js +86 -49
- package/dist/services/final-review/final-review-service.d.ts +9 -0
- package/dist/services/final-review/final-review-service.js +36 -12
- package/dist/services/ide/ide-registry.d.ts +19 -0
- package/dist/services/ide/ide-registry.js +21 -0
- package/dist/services/job/job-state-store.js +7 -0
- package/dist/services/polyrepo/polyrepo-dispatcher.js +11 -0
- package/dist/services/prd/handoff-auto-regen.js +31 -27
- package/dist/services/prd/handoff-frontmatter.d.ts +44 -0
- package/dist/services/prd/handoff-frontmatter.js +75 -0
- package/dist/services/prd/handoff-service.d.ts +41 -2
- package/dist/services/prd/handoff-service.js +81 -8
- package/dist/services/prd/handoff-types.d.ts +3 -2
- package/dist/services/prd/handoff-types.js +3 -2
- package/dist/services/qa/qa-business-review-state.js +9 -0
- package/dist/services/scan/karpathy-service.js +2 -2
- package/dist/services/session/session-checkpoint-service.js +8 -0
- package/dist/services/skill/resume-detector.js +29 -11
- package/dist/services/skills/hooks-codegate-superpowers.d.ts +6 -0
- package/dist/services/skills/hooks-codegate-superpowers.js +61 -2
- package/dist/services/skills/hooks-settings-service.js +14 -4
- package/dist/services/skills/session-start-hook-constants.d.ts +45 -0
- package/dist/services/skills/session-start-hook-constants.js +45 -0
- package/dist/services/skills/skill-statusline-service.d.ts +14 -0
- package/dist/services/slice/slice-check-service.js +29 -11
- package/dist/services/slice/slice-review-state.js +8 -0
- package/dist/services/workflow/pipeline-verify-gate-support.d.ts +47 -10
- package/dist/services/workflow/pipeline-verify-gate-support.js +212 -93
- package/dist/services/workflow/pipeline-verify-service.js +24 -23
- package/dist/services/workflow/pipeline-verify-types.d.ts +10 -3
- package/dist/services/workspace/claude-settings-template.d.ts +56 -8
- package/dist/services/workspace/claude-settings-template.js +98 -20
- package/dist/services/workspace/workspace-claude-settings-materializer.js +78 -7
- package/package.json +6 -6
- package/skills/bee/peaks-prd/SKILL.md +7 -5
- package/skills/bee/peaks-qa/SKILL.md +5 -5
- package/skills/bee/peaks-qa/references/qa-runbook.md +2 -2
- package/skills/bee/peaks-qa/references/qa-transition-gates.md +7 -7
- package/skills/bee/peaks-rd/SKILL.md +8 -6
- package/skills/bee/peaks-rd/references/artifact-per-request.md +2 -2
- package/skills/bee/peaks-rd/references/parallel-review-fanout.md +7 -5
- package/skills/bee/peaks-rd/references/rd-fanout-contracts.md +13 -13
- package/skills/bee/peaks-rd/references/rd-runbook.md +9 -5
- package/skills/bee/peaks-rd/references/rd-transition-gates.md +9 -7
- package/skills/bee/peaks-rd/references/writing-handoff-frontmatter.md +6 -6
- package/skills/peaks-code/SKILL.md +1 -1
- package/skills/peaks-code/references/a2a-artifact-mapping.md +3 -3
- package/skills/peaks-code/references/local-artifact-workspace.md +1 -1
- package/skills/peaks-code/references/resume-detection.md +13 -7
- package/skills/peaks-code/references/runbook.md +3 -2
- package/skills/peaks-code/references/session-overload-signal-index.md +2 -1
- package/skills/peaks-code/references/workflow-gates-and-types.md +8 -6
|
@@ -15,7 +15,12 @@ export function planRollback() {
|
|
|
15
15
|
export function executeRollback(opts) {
|
|
16
16
|
const plan = planRollback();
|
|
17
17
|
if (!plan.available) {
|
|
18
|
-
|
|
18
|
+
// rid 2026-09-13-two-decisions ①: a machine that never migrated has no
|
|
19
|
+
// `.bak`, and that is its normal state — `--apply` on such a machine is
|
|
20
|
+
// "nothing to roll back", not a failure. Returned instead of thrown so the
|
|
21
|
+
// exit status and the `available` key agree on every path; see
|
|
22
|
+
// `config-restore.ts` for the full rationale and the accepted cost.
|
|
23
|
+
return { ...plan, applied: false };
|
|
19
24
|
}
|
|
20
25
|
if (!opts.apply) {
|
|
21
26
|
return { ...plan, applied: false };
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import type { StatusLineStdin } from '../skills/skill-statusline-service.js';
|
|
2
|
+
export declare const HARNESS_CONTEXT_WITNESS_FILE = "harness-context-witness.json";
|
|
3
|
+
export declare const WITNESS_SCHEMA_VERSION = 2;
|
|
4
|
+
/**
|
|
5
|
+
* Contributor 1 of the budget: the harness reports a rounded percentage.
|
|
6
|
+
* "Pre-calculated percentage of context window used" is not documented as
|
|
7
|
+
* fractional, so the conservative reading is an integer percent, i.e. up to
|
|
8
|
+
* ±0.5 percentage points = ±0.005 of the window. If the real payload turns out
|
|
9
|
+
* to carry decimals this term shrinks tenfold and the guard gets sharper; the
|
|
10
|
+
* assumption is visible in the first witness file, where
|
|
11
|
+
* `usageTokens / modelWindowTokens` and `usedPercentage` must agree.
|
|
12
|
+
*/
|
|
13
|
+
export declare const WITNESS_PERCENT_ROUNDING_FRACTION = 0.005;
|
|
14
|
+
/**
|
|
15
|
+
* Contributor 2: the two sides do not sum exactly the same token quantities.
|
|
16
|
+
* MEASURED, not guessed — on 2026-09-13 the harness's own pre-compact count
|
|
17
|
+
* (963,306 tokens) exceeded peaks-loop's transcript estimate (961,658) by
|
|
18
|
+
* 1,648 tokens = 0.171%. Used as a fraction of the tokens, not of the window.
|
|
19
|
+
*/
|
|
20
|
+
export declare const WITNESS_NUMERATOR_FRACTION = 0.0017;
|
|
21
|
+
/**
|
|
22
|
+
* The smallest window difference this guard claims to detect, and therefore
|
|
23
|
+
* the yardstick for "is this sample sharp enough to answer at all".
|
|
24
|
+
*
|
|
25
|
+
* 3% is not arbitrary: the harness compacts a native-1M model at ~967,000 by
|
|
26
|
+
* default while peaks-loop writes the model ceiling, so 1,000,000 vs 967,000 —
|
|
27
|
+
* a 3.3% difference — is the smallest real-world disagreement between the two
|
|
28
|
+
* denominators today. Anything the guard reports as "agree" while its own
|
|
29
|
+
* budget is wider than that difference is a claim it cannot support.
|
|
30
|
+
*
|
|
31
|
+
* NOTE (repair cycle 2): the constant is a floor on the SAMPLE, and the sample
|
|
32
|
+
* it floors is the WITNESS's, not peaks-loop's — a gap of this size leaves a
|
|
33
|
+
* residual proportional to the witness's ratio, so a stale (or low) witness
|
|
34
|
+
* shrinks the signal while the budget's rounding term does not shrink with it.
|
|
35
|
+
* See `sampleSupportsAgreement`, which is where this constant is applied. At
|
|
36
|
+
* zero skew it was already correctly calibrated (measured onset 0.176 of the
|
|
37
|
+
* window against a predicted 0.177); the fault was that only zero skew was
|
|
38
|
+
* correctly calibrated.
|
|
39
|
+
*/
|
|
40
|
+
export declare const MIN_DETECTABLE_WINDOW_DIFFERENCE = 0.03;
|
|
41
|
+
/**
|
|
42
|
+
* Which of the two in-range readings of a raw percentage was taken, or that
|
|
43
|
+
* neither could be taken. `unestablished` is not a reading: the payload said a
|
|
44
|
+
* percentage and carried nothing that could settle which scale it is on.
|
|
45
|
+
*/
|
|
46
|
+
export type PercentageUnit = 'fraction' | 'percent' | 'unestablished';
|
|
47
|
+
/**
|
|
48
|
+
* A harness context snapshot, as written to
|
|
49
|
+
* `<projectRoot>/.peaks/_runtime/<sessionId>/harness-context-witness.json`.
|
|
50
|
+
*
|
|
51
|
+
* The path is peaks-loop's own session runtime directory — deliberately NOT
|
|
52
|
+
* the harness's settings file or any other harness-owned location.
|
|
53
|
+
*/
|
|
54
|
+
export interface HarnessContextWitness {
|
|
55
|
+
readonly schemaVersion: number;
|
|
56
|
+
/** When peaks-loop received the render payload. */
|
|
57
|
+
readonly capturedAt: string;
|
|
58
|
+
/**
|
|
59
|
+
* `context_window.used_percentage`, normalised to 0..1. `null` when this
|
|
60
|
+
* render's payload had no percentage this module could read — the record is
|
|
61
|
+
* still written, because "a render happened and carried nothing usable" is
|
|
62
|
+
* a different fact from "nothing rendered", and the two are told apart by
|
|
63
|
+
* exactly this file existing or not.
|
|
64
|
+
*/
|
|
65
|
+
readonly usedPercentage: number | null;
|
|
66
|
+
/**
|
|
67
|
+
* The payload's `used_percentage` VERBATIM, before any normalisation. Kept
|
|
68
|
+
* so a human can tell a unit misread from a real disagreement: the number
|
|
69
|
+
* above is a 0..1 fraction and this one is not, and only this one shows what
|
|
70
|
+
* the harness actually said.
|
|
71
|
+
*/
|
|
72
|
+
readonly usedPercentageRaw: number | null;
|
|
73
|
+
/** Which reading `usedPercentage` was normalised from, or why none was taken. */
|
|
74
|
+
readonly usedPercentageUnit: PercentageUnit | null;
|
|
75
|
+
/** `context_window.context_window_size`. Recorded, never the comparison's denominator. */
|
|
76
|
+
readonly modelWindowTokens: number | null;
|
|
77
|
+
/**
|
|
78
|
+
* Sum of the prompt-side `context_window.current_usage` components. This is
|
|
79
|
+
* the ALIGNMENT KEY: comparing it with a probe's `rawTokens` is how the
|
|
80
|
+
* guard learns whether the two numbers describe the same API response, and
|
|
81
|
+
* therefore how much of any difference is sampling skew rather than a real
|
|
82
|
+
* disagreement. `output_tokens` is excluded so the sum is the same quantity
|
|
83
|
+
* peaks-loop's transcript estimate sums.
|
|
84
|
+
*/
|
|
85
|
+
readonly usageTokens: number | null;
|
|
86
|
+
/** The harness session id from the payload, for the foreign-session check. */
|
|
87
|
+
readonly outerSessionId: string | null;
|
|
88
|
+
}
|
|
89
|
+
export type WitnessVerdict = 'absent' | 'foreign-session' | 'unverifiable' | 'agree' | 'disagree';
|
|
90
|
+
/**
|
|
91
|
+
* Why there is no witness to compare. The first two leave the same file system
|
|
92
|
+
* state — no file — so the caller, which knows the session directory, resolves
|
|
93
|
+
* which applies and this module turns it into a sentence.
|
|
94
|
+
*
|
|
95
|
+
* The third (`unreadable`, repair cycle 3) is decided by the READ, not by the
|
|
96
|
+
* directory, and it is the reason `readHarnessWitness` returns a tagged union
|
|
97
|
+
* rather than `null`: a file that exists but cannot be used is evidence that a
|
|
98
|
+
* render DID happen, so calling it `not-rendered` names the wrong cause — the
|
|
99
|
+
* exact mis-attribution §17-B was written to remove.
|
|
100
|
+
*/
|
|
101
|
+
export type WitnessAbsentCause = 'session-dir-missing' | 'not-rendered' | 'unreadable';
|
|
102
|
+
export interface HarnessWitnessComparison {
|
|
103
|
+
readonly verdict: WitnessVerdict;
|
|
104
|
+
/** Why the verdict is what it is, when it is not `agree` / `disagree`. */
|
|
105
|
+
readonly reason: string | null;
|
|
106
|
+
readonly harnessPct: number | null;
|
|
107
|
+
readonly peaksRatio: number;
|
|
108
|
+
/** `peaksRatio - harnessPct`; `null` when the harness side is unknown. */
|
|
109
|
+
readonly deviation: number | null;
|
|
110
|
+
/**
|
|
111
|
+
* The quantity the verdict is actually decided on: `deviation` minus the
|
|
112
|
+
* sampling skew the two token snapshots measure. Equal denominators put this
|
|
113
|
+
* at zero no matter how stale the witness is, so a non-zero residual is the
|
|
114
|
+
* window difference itself rather than the sample's age.
|
|
115
|
+
*/
|
|
116
|
+
readonly residual: number | null;
|
|
117
|
+
/** The budget `residual` was tested against, as a fraction of the window. */
|
|
118
|
+
readonly tolerance: number | null;
|
|
119
|
+
readonly witnessedAt: string | null;
|
|
120
|
+
readonly witnessTokens: number | null;
|
|
121
|
+
readonly peaksTokens: number | null;
|
|
122
|
+
/** The harness's raw `used_percentage`, verbatim — see `usedPercentageRaw`. */
|
|
123
|
+
readonly witnessRawPercentage: number | null;
|
|
124
|
+
/** Which reading produced `harnessPct`, so a unit misread is visible. */
|
|
125
|
+
readonly witnessPercentageUnit: PercentageUnit | null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Read the harness's context block out of a parsed statusline stdin payload.
|
|
129
|
+
* Returns `null` only when there was no payload at all (a render on a TTY, or
|
|
130
|
+
* a manual `peaks statusline`) — in which case there is nothing to record and
|
|
131
|
+
* nothing to say. A payload that arrived but carried no usable percentage is
|
|
132
|
+
* recorded, not dropped.
|
|
133
|
+
*/
|
|
134
|
+
export declare function parseHarnessWitness(input: {
|
|
135
|
+
readonly stdin: StatusLineStdin | null;
|
|
136
|
+
readonly nowMs: number;
|
|
137
|
+
}): HarnessContextWitness | null;
|
|
138
|
+
export declare function harnessWitnessPath(projectRoot: string, sessionId: string): string;
|
|
139
|
+
/**
|
|
140
|
+
* Write this render's record. Returns whether a file was written.
|
|
141
|
+
*
|
|
142
|
+
* This is the ONLY side effect on the statusline render path. It is bounded
|
|
143
|
+
* (one small file, inside peaks-loop's own session directory), it cannot
|
|
144
|
+
* influence any decision peaks-loop makes (nothing except the diagnostic in
|
|
145
|
+
* `peaks code context-now` reads it), and it never throws — a statusline that
|
|
146
|
+
* fails to render because an observability file could not be written would be
|
|
147
|
+
* a worse failure than a missing observation. A failed write is not swallowed:
|
|
148
|
+
* the next probe reports `absent`, which is the visible symptom.
|
|
149
|
+
*
|
|
150
|
+
* No `mkdir`: the session directory is created by the session layer, and a
|
|
151
|
+
* statusline render is the wrong place to be creating directories. Its absence
|
|
152
|
+
* is one of the honest reasons the witness can be missing.
|
|
153
|
+
*
|
|
154
|
+
* Written via temp + rename, not in place. A reader runs in ANOTHER process
|
|
155
|
+
* (the probe) and treats unreadable JSON as "no witness" — so a torn read
|
|
156
|
+
* would not be an error, it would be a SILENT loss of the comparison, which is
|
|
157
|
+
* the failure mode this whole slice exists to remove. The rename makes the
|
|
158
|
+
* partial state unobservable. Same shape as `atomicWriteJson` in
|
|
159
|
+
* statusline-settings-service.ts.
|
|
160
|
+
*
|
|
161
|
+
* The rename is not always available: on Windows it throws EPERM while another
|
|
162
|
+
* process holds the target open, which is exactly the reader this guard is
|
|
163
|
+
* written for. Dropping the sample then would be the silent loss the temp
|
|
164
|
+
* rename was introduced to remove, so the write falls back to in-place. The
|
|
165
|
+
* fallback gives up atomicity for that one write — the reader may see a
|
|
166
|
+
* half-written file and call it "no witness" — which is a narrower failure
|
|
167
|
+
* than never recording the sample at all, and the temp path stays the normal
|
|
168
|
+
* one.
|
|
169
|
+
*
|
|
170
|
+
* A LOWER-INFORMATION RECORD DOES NOT REPLACE A HIGHER-INFORMATION ONE (repair
|
|
171
|
+
* cycle 3). The render that carries no readable percentage is still recorded
|
|
172
|
+
* when there is nothing better on disk — that is what tells "rendered, nothing
|
|
173
|
+
* usable" apart from "never rendered" (§17-B) — but it does NOT overwrite a
|
|
174
|
+
* record whose percentage IS readable. Overwriting silences a real comparison:
|
|
175
|
+
* measured 2026-09-14, a witness giving a real 3.3% window gap reported
|
|
176
|
+
* `disagree` with its sentence, and one render whose payload lacked
|
|
177
|
+
* `context_window` turned the same comparison into `unverifiable` with the
|
|
178
|
+
* sentence suppressed. A render that says less must not delete a sample that
|
|
179
|
+
* says more.
|
|
180
|
+
*
|
|
181
|
+
* AND THE PARSE IS INSIDE A TRY (repair cycle 3). The module's contract at the
|
|
182
|
+
* top of this comment — "it never throws" — was true only by inspection: the
|
|
183
|
+
* `parseHarnessWitness` call sat above the only `try`, and a payload shape the
|
|
184
|
+
* guards did not anticipate escaped the function and killed the render (see
|
|
185
|
+
* `parseHarnessWitness` for the measured case). A nested `try` rather than a
|
|
186
|
+
* wider one, because the outer catch says something different: it is the
|
|
187
|
+
* temp+rename FALLBACK, and a parse failure has no JSON to fall back TO.
|
|
188
|
+
* A payload this module cannot read is a missing observation, which is the
|
|
189
|
+
* outcome the contract already prefers.
|
|
190
|
+
*/
|
|
191
|
+
export declare function writeHarnessWitness(input: {
|
|
192
|
+
readonly projectRoot: string | null;
|
|
193
|
+
readonly sessionId: string | null;
|
|
194
|
+
readonly stdin: StatusLineStdin | null;
|
|
195
|
+
readonly nowMs: number;
|
|
196
|
+
}): boolean;
|
|
197
|
+
/**
|
|
198
|
+
* What a read found.
|
|
199
|
+
*
|
|
200
|
+
* This used to be `HarnessContextWitness | null`, which collapsed FOUR file
|
|
201
|
+
* states — absent, unreadable, not JSON, not the shape this module writes —
|
|
202
|
+
* into one `null`. The caller then had to guess the cause from the directory
|
|
203
|
+
* alone and picked `not-rendered` whenever the directory existed, so a render
|
|
204
|
+
* whose record was merely unreadable was reported as "the statusline has not
|
|
205
|
+
* rendered here": the wrong-cause sentence §17-B was written to remove. The
|
|
206
|
+
* three states are named here instead of re-derived by a second look at the
|
|
207
|
+
* disk. Same shape, and deliberately the same words (`missing` / `valid` /
|
|
208
|
+
* `invalid`), as `CompactLifecycleRead` in
|
|
209
|
+
* `src/services/compact-statusline/compact-lifecycle-store.ts`, which reads a
|
|
210
|
+
* sibling file in the same directory for the same purpose.
|
|
211
|
+
*/
|
|
212
|
+
export type HarnessWitnessRead = {
|
|
213
|
+
readonly kind: 'missing';
|
|
214
|
+
} | {
|
|
215
|
+
readonly kind: 'valid';
|
|
216
|
+
readonly witness: HarnessContextWitness;
|
|
217
|
+
} | {
|
|
218
|
+
readonly kind: 'invalid';
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Read the record for a session. Anything that exists but cannot be used as a
|
|
222
|
+
* record reads as `invalid` — never as `missing`, which would erase the one
|
|
223
|
+
* fact the file's existence carries: a render happened here.
|
|
224
|
+
*/
|
|
225
|
+
export declare function readHarnessWitness(input: {
|
|
226
|
+
readonly projectRoot: string;
|
|
227
|
+
readonly sessionId: string;
|
|
228
|
+
}): HarnessWitnessRead;
|
|
229
|
+
/**
|
|
230
|
+
* The budget, in tokens: what a difference between the two ratios can be
|
|
231
|
+
* explained by WITHOUT the two denominators being different, once the
|
|
232
|
+
* sampling skew has been taken out (see `compareHarnessWitness`).
|
|
233
|
+
*
|
|
234
|
+
* rounding 0.005 x window — the harness's percentage is rounded
|
|
235
|
+
* numerator 0.0017 x usedTokens — measured disagreement of the two sums
|
|
236
|
+
*
|
|
237
|
+
* Sample skew is deliberately NOT a term here. It is not a budget at all: it
|
|
238
|
+
* is MEASURED per sample from the two token counts and SUBTRACTED from the
|
|
239
|
+
* deviation, because under equal denominators the token difference and the
|
|
240
|
+
* ratio difference are the same number — see `compareHarnessWitness`.
|
|
241
|
+
*/
|
|
242
|
+
export declare function witnessToleranceTokens(input: {
|
|
243
|
+
readonly windowTokens: number;
|
|
244
|
+
readonly usedTokens: number;
|
|
245
|
+
}): number;
|
|
246
|
+
/**
|
|
247
|
+
* Compare peaks-loop's ratio with the harness's own percentage.
|
|
248
|
+
*
|
|
249
|
+
* Two identifiers must match before any comparison is allowed:
|
|
250
|
+
* 1. the SESSION — a witness written by another harness session on the same
|
|
251
|
+
* project is not evidence about this one. Lenient in the same direction as
|
|
252
|
+
* the compact-event attribution: refused only when BOTH ids resolve and
|
|
253
|
+
* differ, because a guard that turns a missing field into a permanent
|
|
254
|
+
* "cannot tell" is the failure this whole slice exists to remove.
|
|
255
|
+
* 2. the MOMENT — a witness is a snapshot, and the harness documents that its
|
|
256
|
+
* percentage depends on when it was calculated. The token counts are what
|
|
257
|
+
* says whether the two numbers came from the same API response.
|
|
258
|
+
*
|
|
259
|
+
* THE MOMENT IS REMOVED, NOT BUDGETED (repair cycle 1). If the two ratios
|
|
260
|
+
* share a denominator W, the harness's count and peaks-loop's count differ by
|
|
261
|
+
* exactly the sampling skew, so
|
|
262
|
+
*
|
|
263
|
+
* peaksRatio - harnessPct == (peaksTokens - witnessTokens) / W
|
|
264
|
+
*
|
|
265
|
+
* holds identically — it is not a tolerance to be granted, it is an equality
|
|
266
|
+
* to be tested. Budgeting the skew instead (`tolerance += |skew|`) made the
|
|
267
|
+
* budget grow by `x` while the deviation grew by `x(1+g)`, so a real window
|
|
268
|
+
* difference `g` was cancelled for every skew large enough to absorb it: a
|
|
269
|
+
* measured 3.3% denominator gap read `agree` for skew in [12,400, 22,100]
|
|
270
|
+
* tokens, and gaps up to 5.3% never surfaced at all. Subtracting the skew from
|
|
271
|
+
* the deviation and testing the remainder against a budget that contains only
|
|
272
|
+
* rounding and numerator disagreement makes the test invariant to skew by
|
|
273
|
+
* construction, and leaves `-g x harnessPct/(1+g)` — the window difference
|
|
274
|
+
* itself — as the only thing the residual can be.
|
|
275
|
+
*
|
|
276
|
+
* AND THE RESIDUAL'S SIZE IS THE WITNESS'S, NOT PEAKS-LOOP'S (repair cycle 2).
|
|
277
|
+
* `-g x harnessPct/(1+g)` carries the witness's ratio, so a witness captured
|
|
278
|
+
* while the session was small cannot show a window difference that a bigger
|
|
279
|
+
* witness would. The three answers therefore do not share one gate: a residual
|
|
280
|
+
* past the budget is a `disagree` at any witness size, while `agree` needs the
|
|
281
|
+
* sample to be sharp enough to support it (`sampleSupportsAgreement`).
|
|
282
|
+
*/
|
|
283
|
+
export declare function compareHarnessWitness(input: {
|
|
284
|
+
readonly witness: HarnessContextWitness | null;
|
|
285
|
+
readonly peaksRatio: number;
|
|
286
|
+
readonly peaksTokens: number | null;
|
|
287
|
+
readonly peaksWindowTokens: number | null;
|
|
288
|
+
readonly outerSessionId: string | null;
|
|
289
|
+
readonly absentCause?: WitnessAbsentCause;
|
|
290
|
+
}): HarnessWitnessComparison;
|
|
291
|
+
/**
|
|
292
|
+
* One-way sentence for a disagreeing witness. Advising, never asking: an
|
|
293
|
+
* auto-compact observation must never become an `AskUserQuestion` (see
|
|
294
|
+
* `.peaks/memory/auto-compact-threshold-policy.md`).
|
|
295
|
+
*
|
|
296
|
+
* The sentence states the quantity that decided it (the residual, after the
|
|
297
|
+
* measured skew was removed) and the raw harness value with the reading that
|
|
298
|
+
* was taken from it. Both are there so a reader can tell a real denominator
|
|
299
|
+
* difference from a unit misread without going back to the file.
|
|
300
|
+
*/
|
|
301
|
+
export declare function describeHarnessWitness(comparison: HarnessWitnessComparison): string | null;
|
|
302
|
+
/** Convenience for the CLI: read + compare in one call. */
|
|
303
|
+
export declare function readAndCompareHarnessWitness(input: {
|
|
304
|
+
readonly projectRoot: string;
|
|
305
|
+
readonly sessionId: string;
|
|
306
|
+
readonly peaksRatio: number;
|
|
307
|
+
readonly peaksTokens: number | null;
|
|
308
|
+
readonly peaksWindowTokens: number | null;
|
|
309
|
+
readonly outerSessionId: string | null;
|
|
310
|
+
}): HarnessWitnessComparison;
|