instar 0.28.92 → 0.28.94
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +9 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/core/DriftSpendLedger.d.ts +112 -0
- package/dist/core/DriftSpendLedger.d.ts.map +1 -0
- package/dist/core/DriftSpendLedger.js +285 -0
- package/dist/core/DriftSpendLedger.js.map +1 -0
- package/dist/core/InitiativeTracker.d.ts +7 -2
- package/dist/core/InitiativeTracker.d.ts.map +1 -1
- package/dist/core/InitiativeTracker.js.map +1 -1
- package/dist/core/ProjectDriftChecker.d.ts +215 -0
- package/dist/core/ProjectDriftChecker.d.ts.map +1 -0
- package/dist/core/ProjectDriftChecker.js +572 -0
- package/dist/core/ProjectDriftChecker.js.map +1 -0
- package/dist/core/ProjectDriftCheckerCache.d.ts +118 -0
- package/dist/core/ProjectDriftCheckerCache.d.ts.map +1 -0
- package/dist/core/ProjectDriftCheckerCache.js +221 -0
- package/dist/core/ProjectDriftCheckerCache.js.map +1 -0
- package/dist/core/SessionManager.d.ts +5 -4
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +3 -2
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/StuckInputSentinel.d.ts +160 -0
- package/dist/core/StuckInputSentinel.d.ts.map +1 -0
- package/dist/core/StuckInputSentinel.js +315 -0
- package/dist/core/StuckInputSentinel.js.map +1 -0
- package/dist/core/types.d.ts +40 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
- package/dist/lifeline/ServerSupervisor.js +8 -0
- package/dist/lifeline/ServerSupervisor.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +3 -3
- package/upgrades/0.28.93.md +126 -0
- package/upgrades/0.28.94.md +60 -0
- package/upgrades/side-effects/project-scope-phase1b-pr1.md +252 -0
- package/upgrades/side-effects/project-scope-phase1b-pr2.md +198 -0
- package/upgrades/side-effects/stuck-input-sentinel.md +137 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProjectDriftChecker — signal-only drift detection for project-scope rounds.
|
|
3
|
+
*
|
|
4
|
+
* Spec: docs/specs/PROJECT-SCOPE-SPEC.md Phase 1.4.
|
|
5
|
+
*
|
|
6
|
+
* What this does:
|
|
7
|
+
* Given a spec + the files it references, ask the LLM whether the spec's
|
|
8
|
+
* stated premises still match what's on disk today. Returns one of four
|
|
9
|
+
* verdicts: no-drift, minor-drift, premise-violated, manual-review-required.
|
|
10
|
+
*
|
|
11
|
+
* Authority model (P1, signal-vs-authority):
|
|
12
|
+
* This is a *signal* producer only. The verdict is recorded on the round
|
|
13
|
+
* as `lastDriftVerdict` and surfaced in the digest. The decision to start
|
|
14
|
+
* or block a round is made by ProjectRoundRunner using verifiable
|
|
15
|
+
* artifacts (frontmatter tags, `gh pr view`, CI status). The drift verdict
|
|
16
|
+
* alone never authorizes or blocks a transition.
|
|
17
|
+
*
|
|
18
|
+
* Hardening:
|
|
19
|
+
* - All file paths are jailed under `targetRepoPath` (jailPath utility
|
|
20
|
+
* from StageTransitionValidator). `../`, absolute paths, and symlinks
|
|
21
|
+
* that escape are rejected.
|
|
22
|
+
* - Spec body is wrapped in `<UNTRUSTED_SPEC_BODY>...</UNTRUSTED_SPEC_BODY>`;
|
|
23
|
+
* each referenced file in `<UNTRUSTED_FILE_CONTENT path="..." hash="...">`.
|
|
24
|
+
* The system prompt explicitly distrusts content inside these blocks.
|
|
25
|
+
* - LLM output is JSON.parse'd and structurally validated against the
|
|
26
|
+
* DriftVerdict shape. Anything malformed → `manual-review-required`
|
|
27
|
+
* (reason `schema-fail`).
|
|
28
|
+
* - Each evidenceCitation is re-verified by the checker: open the file,
|
|
29
|
+
* check byteRange in bounds, render slice as `excerpt`. Citations that
|
|
30
|
+
* don't resolve are dropped. If ALL citations drop (and at least one
|
|
31
|
+
* was claimed), verdict is downgraded to `manual-review-required`
|
|
32
|
+
* with reason `failed-citation-verification`. The verified excerpt
|
|
33
|
+
* is what gets shown — never the LLM-claimed text.
|
|
34
|
+
*
|
|
35
|
+
* Input bounds (normative; spec § Phase 1.4):
|
|
36
|
+
* - Max 5 files referenced per spec
|
|
37
|
+
* - Per-file cap: 2,000 lines OR 80 KB (whichever is smaller)
|
|
38
|
+
* - Total prompt budget: 50,000 tokens, estimated as chars / 4
|
|
39
|
+
* - Over-budget → `manual-review-required` with reason `over-budget`.
|
|
40
|
+
* Never silently summarize.
|
|
41
|
+
*
|
|
42
|
+
* Failure modes:
|
|
43
|
+
* - LLM timeout (30s, configurable): one retry; if both fail, return
|
|
44
|
+
* `manual-review-required` with reason `timeout`.
|
|
45
|
+
* - Empty/missing spec body → `manual-review-required` (`empty-spec`).
|
|
46
|
+
* - All referenced files missing → `manual-review-required`
|
|
47
|
+
* (`deleted-files`).
|
|
48
|
+
* - No IntelligenceProvider configured → `manual-review-required`
|
|
49
|
+
* (`no-provider`). The round-runner halts the round; user attention.
|
|
50
|
+
*
|
|
51
|
+
* NOT in this PR (lands in Phase 1b PR 2):
|
|
52
|
+
* - Cost ledger with file lock (advisory flock on .instar/local/drift-spend.lock)
|
|
53
|
+
* - Cache (sha256 key from promptTemplateVersion+modelId+specBodySha+filehashes)
|
|
54
|
+
* - Mtime fast-path
|
|
55
|
+
* These are additive; the checker as written returns a correct verdict
|
|
56
|
+
* on every call, just without rate-limit or memoization protection. The
|
|
57
|
+
* round-runner (Phase 1.5) is the consumer; until it ships, no caller
|
|
58
|
+
* wires this up.
|
|
59
|
+
*/
|
|
60
|
+
import type { DriftVerdict, IntelligenceProvider, VerifiedCitation } from './types.js';
|
|
61
|
+
import type { ProjectDriftCheckerCache } from './ProjectDriftCheckerCache.js';
|
|
62
|
+
import { DriftSpendLedger } from './DriftSpendLedger.js';
|
|
63
|
+
/** Bumped whenever the system prompt changes; part of the future cache key. */
|
|
64
|
+
export declare const DRIFT_PROMPT_TEMPLATE_VERSION = 1;
|
|
65
|
+
/** Hard limits per spec § Phase 1.4. Exported so tests can dial them down. */
|
|
66
|
+
export declare const DRIFT_LIMITS: {
|
|
67
|
+
readonly maxReferencedFiles: 5;
|
|
68
|
+
readonly perFileBytes: number;
|
|
69
|
+
readonly perFileLines: 2000;
|
|
70
|
+
readonly totalTokenBudget: 50000;
|
|
71
|
+
/** Rough char→token estimate; 4 chars per token is a conservative upper bound. */
|
|
72
|
+
readonly charsPerToken: 4;
|
|
73
|
+
readonly defaultTimeoutMs: 30000;
|
|
74
|
+
readonly excerptDisplayCap: 240;
|
|
75
|
+
};
|
|
76
|
+
export interface DriftCheckInput {
|
|
77
|
+
/** Project id — used for telemetry/audit only; the checker does no project lookup. */
|
|
78
|
+
projectId: string;
|
|
79
|
+
/** Round index within the project — telemetry only. */
|
|
80
|
+
roundIndex: number;
|
|
81
|
+
/**
|
|
82
|
+
* Absolute target repo root. Every file path in this call must resolve
|
|
83
|
+
* inside this directory after realpath.
|
|
84
|
+
*/
|
|
85
|
+
targetRepoPath: string;
|
|
86
|
+
/** Spec markdown path; absolute or relative to targetRepoPath. Jailed. */
|
|
87
|
+
specPath: string;
|
|
88
|
+
/**
|
|
89
|
+
* Files the spec claims to depend on — typically extracted from spec
|
|
90
|
+
* frontmatter `referencedFiles` or `sourceDocs`. Caller is responsible
|
|
91
|
+
* for the list; the checker is responsible for enforcing the limits.
|
|
92
|
+
*/
|
|
93
|
+
referencedFiles: string[];
|
|
94
|
+
/** Optional override for the 30s timeout (tests dial this down). */
|
|
95
|
+
timeoutMs?: number;
|
|
96
|
+
/**
|
|
97
|
+
* Resolved model id, surfaced into the prompt so a future cache key can
|
|
98
|
+
* key on it. Not used at the call site today (the provider chooses the
|
|
99
|
+
* model based on `options.model`), but the spec requires it be part of
|
|
100
|
+
* the cache key — passing it through here keeps the contract aligned.
|
|
101
|
+
*/
|
|
102
|
+
modelId?: string;
|
|
103
|
+
}
|
|
104
|
+
interface PreparedFile {
|
|
105
|
+
/** Path the LLM sees, relative to targetRepoPath. */
|
|
106
|
+
relPath: string;
|
|
107
|
+
/** Absolute, jailed path. */
|
|
108
|
+
absPath: string;
|
|
109
|
+
/** Raw bytes read. */
|
|
110
|
+
bytes: Buffer;
|
|
111
|
+
/** sha256 of the bytes, displayed in the untrusted block header. */
|
|
112
|
+
hash: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Lightweight container for LLM-returned citations BEFORE verification.
|
|
116
|
+
* After verification the shape is `VerifiedCitation` (exported from types).
|
|
117
|
+
*/
|
|
118
|
+
interface UnverifiedCitation {
|
|
119
|
+
file?: unknown;
|
|
120
|
+
byteRange?: unknown;
|
|
121
|
+
excerpt?: unknown;
|
|
122
|
+
}
|
|
123
|
+
interface ParsedLlmResponse {
|
|
124
|
+
verdict?: unknown;
|
|
125
|
+
rationale?: unknown;
|
|
126
|
+
evidenceCitations?: unknown;
|
|
127
|
+
}
|
|
128
|
+
export interface ProjectDriftCheckerConfig {
|
|
129
|
+
intelligence?: IntelligenceProvider;
|
|
130
|
+
/** Defaults to spec § Phase 1.4 hard limits; tests can override. */
|
|
131
|
+
limits?: Partial<typeof DRIFT_LIMITS>;
|
|
132
|
+
/** Optional verdict cache. When absent, every call recomputes from scratch. */
|
|
133
|
+
cache?: ProjectDriftCheckerCache;
|
|
134
|
+
/** Optional spend ledger. When absent, no cap enforcement. */
|
|
135
|
+
ledger?: DriftSpendLedger;
|
|
136
|
+
/**
|
|
137
|
+
* Best-effort cost estimate per call in USD; ledger pre-reserves this
|
|
138
|
+
* amount before the LLM call. Default $0.01 — conservative for the
|
|
139
|
+
* 'balanced' tier on the 50k-token-budget cap.
|
|
140
|
+
*/
|
|
141
|
+
estimatedCostPerCallUsd?: number;
|
|
142
|
+
}
|
|
143
|
+
export declare class ProjectDriftChecker {
|
|
144
|
+
private intelligence?;
|
|
145
|
+
private limits;
|
|
146
|
+
private cache?;
|
|
147
|
+
private ledger?;
|
|
148
|
+
private estimatedCostPerCallUsd;
|
|
149
|
+
constructor(config?: ProjectDriftCheckerConfig);
|
|
150
|
+
run(input: DriftCheckInput): Promise<DriftVerdict>;
|
|
151
|
+
}
|
|
152
|
+
declare class TimeoutError extends Error {
|
|
153
|
+
constructor(ms: number);
|
|
154
|
+
}
|
|
155
|
+
interface PromptInput {
|
|
156
|
+
specBody: string;
|
|
157
|
+
files: PreparedFile[];
|
|
158
|
+
modelId?: string;
|
|
159
|
+
templateVersion: number;
|
|
160
|
+
deletedFiles: string[];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Build the LLM prompt. The system block tells the model to distrust
|
|
164
|
+
* everything inside the UNTRUSTED_* blocks and to respond ONLY with a JSON
|
|
165
|
+
* object of the documented shape.
|
|
166
|
+
*/
|
|
167
|
+
export declare function buildPrompt(input: PromptInput): string;
|
|
168
|
+
/**
|
|
169
|
+
* Extract the first JSON object from a raw LLM response. Tolerates leading
|
|
170
|
+
* prose, code fences, etc. Returns null on no match or parse failure.
|
|
171
|
+
*/
|
|
172
|
+
export declare function extractJson(raw: string): ParsedLlmResponse | null;
|
|
173
|
+
type VerdictValidation = {
|
|
174
|
+
ok: true;
|
|
175
|
+
verdict: 'no-drift' | 'minor-drift' | 'premise-violated';
|
|
176
|
+
rationale: string;
|
|
177
|
+
citations: UnverifiedCitation[];
|
|
178
|
+
} | {
|
|
179
|
+
ok: false;
|
|
180
|
+
reason: string;
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Hand-rolled structural validator for the LLM's JSON output. Returns the
|
|
184
|
+
* normalized fields on success; a `reason` on failure. We avoid Ajv to keep
|
|
185
|
+
* the dep footprint flat.
|
|
186
|
+
*/
|
|
187
|
+
export declare function validateVerdict(parsed: ParsedLlmResponse): VerdictValidation;
|
|
188
|
+
/**
|
|
189
|
+
* Re-verify each LLM-proposed citation against the prepared file bytes.
|
|
190
|
+
* Drops citations that don't resolve. Returns the verified slice itself —
|
|
191
|
+
* the LLM-claimed `excerpt` field is intentionally discarded.
|
|
192
|
+
*/
|
|
193
|
+
export declare function verifyCitations(claimed: UnverifiedCitation[], files: PreparedFile[], excerptCap: number): VerifiedCitation[];
|
|
194
|
+
/**
|
|
195
|
+
* Stable cache key inputs for a drift check call. Exported so Phase 1b PR 2
|
|
196
|
+
* (cache + cost ledger) can wire this up without forking the implementation.
|
|
197
|
+
* Returns the inputs as an object — the consumer hashes them.
|
|
198
|
+
*/
|
|
199
|
+
export declare function cacheKeyInputs(promptTemplateVersion: number, modelId: string, specBytes: Buffer, referencedFileBytes: Array<{
|
|
200
|
+
relPath: string;
|
|
201
|
+
bytes: Buffer;
|
|
202
|
+
}>): {
|
|
203
|
+
promptTemplateVersion: number;
|
|
204
|
+
modelId: string;
|
|
205
|
+
specBodySha: string;
|
|
206
|
+
sortedFileHashes: string[];
|
|
207
|
+
};
|
|
208
|
+
export { TimeoutError };
|
|
209
|
+
/**
|
|
210
|
+
* Path used by the StageTransitionValidator's `jailPath` is the same one
|
|
211
|
+
* we use here; explicit re-export so other modules can import it from this
|
|
212
|
+
* file without depending on StageTransitionValidator directly.
|
|
213
|
+
*/
|
|
214
|
+
export { jailPath } from './StageTransitionValidator.js';
|
|
215
|
+
//# sourceMappingURL=ProjectDriftChecker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProjectDriftChecker.d.ts","sourceRoot":"","sources":["../../src/core/ProjectDriftChecker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAmB,MAAM,uBAAuB,CAAC;AAE1E,+EAA+E;AAC/E,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,8EAA8E;AAC9E,eAAO,MAAM,YAAY;;;;;IAKvB,kFAAkF;;;;CAI1E,CAAC;AAIX,MAAM,WAAW,eAAe;IAC9B,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,YAAY;IACpB,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,UAAU,kBAAkB;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,yBAAyB;IACxC,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,YAAY,CAAC,CAAC;IACtC,+EAA+E;IAC/E,KAAK,CAAC,EAAE,wBAAwB,CAAC;IACjC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,YAAY,CAAC,CAAuB;IAC5C,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,KAAK,CAAC,CAA2B;IACzC,OAAO,CAAC,MAAM,CAAC,CAAmB;IAClC,OAAO,CAAC,uBAAuB,CAAS;gBAE5B,MAAM,GAAE,yBAA8B;IAQ5C,GAAG,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;CA2RzD;AAYD,cAAM,YAAa,SAAQ,KAAK;gBAClB,EAAE,EAAE,MAAM;CAIvB;AAkBD,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAgDtD;AAMD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CA0CjE;AAED,KAAK,iBAAiB,GAClB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,UAAU,GAAG,aAAa,GAAG,kBAAkB,CAAC;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,kBAAkB,EAAE,CAAC;CACjC,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CA2B5E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,kBAAkB,EAAE,EAC7B,KAAK,EAAE,YAAY,EAAE,EACrB,UAAU,EAAE,MAAM,GACjB,gBAAgB,EAAE,CAuBpB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,qBAAqB,EAAE,MAAM,EAC7B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,mBAAmB,EAAE,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7D;IAAE,qBAAqB,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,EAAE,CAAA;CAAE,CAMrG;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;;;GAIG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC"}
|