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.
Files changed (39) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +9 -0
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/DriftSpendLedger.d.ts +112 -0
  5. package/dist/core/DriftSpendLedger.d.ts.map +1 -0
  6. package/dist/core/DriftSpendLedger.js +285 -0
  7. package/dist/core/DriftSpendLedger.js.map +1 -0
  8. package/dist/core/InitiativeTracker.d.ts +7 -2
  9. package/dist/core/InitiativeTracker.d.ts.map +1 -1
  10. package/dist/core/InitiativeTracker.js.map +1 -1
  11. package/dist/core/ProjectDriftChecker.d.ts +215 -0
  12. package/dist/core/ProjectDriftChecker.d.ts.map +1 -0
  13. package/dist/core/ProjectDriftChecker.js +572 -0
  14. package/dist/core/ProjectDriftChecker.js.map +1 -0
  15. package/dist/core/ProjectDriftCheckerCache.d.ts +118 -0
  16. package/dist/core/ProjectDriftCheckerCache.d.ts.map +1 -0
  17. package/dist/core/ProjectDriftCheckerCache.js +221 -0
  18. package/dist/core/ProjectDriftCheckerCache.js.map +1 -0
  19. package/dist/core/SessionManager.d.ts +5 -4
  20. package/dist/core/SessionManager.d.ts.map +1 -1
  21. package/dist/core/SessionManager.js +3 -2
  22. package/dist/core/SessionManager.js.map +1 -1
  23. package/dist/core/StuckInputSentinel.d.ts +160 -0
  24. package/dist/core/StuckInputSentinel.d.ts.map +1 -0
  25. package/dist/core/StuckInputSentinel.js +315 -0
  26. package/dist/core/StuckInputSentinel.js.map +1 -0
  27. package/dist/core/types.d.ts +40 -0
  28. package/dist/core/types.d.ts.map +1 -1
  29. package/dist/core/types.js.map +1 -1
  30. package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
  31. package/dist/lifeline/ServerSupervisor.js +8 -0
  32. package/dist/lifeline/ServerSupervisor.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/data/builtin-manifest.json +3 -3
  35. package/upgrades/0.28.93.md +126 -0
  36. package/upgrades/0.28.94.md +60 -0
  37. package/upgrades/side-effects/project-scope-phase1b-pr1.md +252 -0
  38. package/upgrades/side-effects/project-scope-phase1b-pr2.md +198 -0
  39. 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":"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"}