instar 1.3.491 → 1.3.492
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/init.d.ts.map +1 -1
- package/dist/commands/init.js +3 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +53 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +11 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/CartographerSweepEngine.d.ts +55 -11
- package/dist/core/CartographerSweepEngine.d.ts.map +1 -1
- package/dist/core/CartographerSweepEngine.js +276 -95
- package/dist/core/CartographerSweepEngine.js.map +1 -1
- package/dist/core/CartographerTree.d.ts +77 -1
- package/dist/core/CartographerTree.d.ts.map +1 -1
- package/dist/core/CartographerTree.js +257 -5
- package/dist/core/CartographerTree.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +13 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/cartographerDetect.d.ts +133 -0
- package/dist/core/cartographerDetect.d.ts.map +1 -0
- package/dist/core/cartographerDetect.js +431 -0
- package/dist/core/cartographerDetect.js.map +1 -0
- package/dist/core/cartographerDetect.worker.d.ts +2 -0
- package/dist/core/cartographerDetect.worker.d.ts.map +1 -0
- package/dist/core/cartographerDetect.worker.js +37 -0
- package/dist/core/cartographerDetect.worker.js.map +1 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +103 -25
- package/dist/server/routes.js.map +1 -1
- package/package.json +2 -2
- package/scripts/lint-no-direct-destructive.js +4 -0
- package/scripts/lint-no-mainthread-cartographer-walk.js +101 -0
- package/src/data/builtin-manifest.json +63 -63
- package/upgrades/1.3.492.md +31 -0
- package/upgrades/side-effects/cartographer-sweep-eventloop-safety.md +110 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { StalenessStatus } from './CartographerTree.js';
|
|
2
|
+
/**
|
|
3
|
+
* Every detect failure path sets `refused: true` + one of these reasons so it
|
|
4
|
+
* flows through the poller's `r.refused` branch and feeds the breaker — a
|
|
5
|
+
* refusal is NEVER mistaken for "genuinely nothing to do". `detect-timeout` and
|
|
6
|
+
* `detect-worker-start-failure` are set by the ENGINE (the worker can't report
|
|
7
|
+
* its own timeout/start failure); the rest are set here.
|
|
8
|
+
*/
|
|
9
|
+
export type DetectRefusalReason = 'detect-index-too-large' | 'detect-index-unreadable' | 'detect-git-error' | 'detect-timeout' | 'detect-worker-start-failure';
|
|
10
|
+
export interface DetectInput {
|
|
11
|
+
/** Absolute path to the cartographer index.json. */
|
|
12
|
+
indexPath: string;
|
|
13
|
+
/** Repo root the git plumbing runs against. */
|
|
14
|
+
projectDir: string;
|
|
15
|
+
/** Refuse (detect-index-too-large) above this on-disk byte size BEFORE parsing. */
|
|
16
|
+
maxIndexBytes: number;
|
|
17
|
+
/** Hard cap on the ordered candidate list this pass returns (maxNodesPerPass × headroom). */
|
|
18
|
+
maxCandidates: number;
|
|
19
|
+
/** Per-pass author budget — used for the anti-starvation front-bias cap (maxNodesPerPass/2). */
|
|
20
|
+
maxNodesPerPass: number;
|
|
21
|
+
/** A deferred dir at/above this defer count is force-promoted (anti-starvation). */
|
|
22
|
+
maxDeferredPasses: number;
|
|
23
|
+
/** How many oldest-fresh nodes to nominate for re-validation this pass. */
|
|
24
|
+
revalidateSamplePerPass: number;
|
|
25
|
+
/** Grace window for the never-authored-past-grace freshness split. */
|
|
26
|
+
graceMs: number;
|
|
27
|
+
/** Explicit git ls-tree maxBuffer (≥64MB) so a big tree never throws ENOBUFS. */
|
|
28
|
+
gitMaxBuffer: number;
|
|
29
|
+
/** Cap on the published stale sample written to the snapshot (the /stale surface). */
|
|
30
|
+
snapshotSampleMax: number;
|
|
31
|
+
/** Wall clock for the grace computation (injected for deterministic tests). */
|
|
32
|
+
nowMs: number;
|
|
33
|
+
}
|
|
34
|
+
export interface DetectCounts {
|
|
35
|
+
nodeCount: number;
|
|
36
|
+
authoredCount: number;
|
|
37
|
+
neverAuthored: number;
|
|
38
|
+
stale: number;
|
|
39
|
+
pathGone: number;
|
|
40
|
+
generatedAt: string | null;
|
|
41
|
+
headSha: string | null;
|
|
42
|
+
}
|
|
43
|
+
/** The full freshness aggregate (so `/cartographer/health` never recomputes it on the request thread). */
|
|
44
|
+
export interface DetectFreshness {
|
|
45
|
+
nodeCount: number;
|
|
46
|
+
authorableCount: number;
|
|
47
|
+
freshCount: number;
|
|
48
|
+
staleCount: number;
|
|
49
|
+
neverAuthoredCount: number;
|
|
50
|
+
neverAuthoredWithinGrace: number;
|
|
51
|
+
neverAuthoredPastGrace: number;
|
|
52
|
+
authorFailedCount: number;
|
|
53
|
+
freshRatio: number;
|
|
54
|
+
generatedAt: string | null;
|
|
55
|
+
}
|
|
56
|
+
export interface DetectResult {
|
|
57
|
+
refused: boolean;
|
|
58
|
+
refusalReason?: DetectRefusalReason;
|
|
59
|
+
/** Ordered, BOUNDED (≤ maxCandidates) author candidates (deepest/anti-starvation first). */
|
|
60
|
+
candidates: string[];
|
|
61
|
+
/** Count of dirs whose `staleSincePass` was incremented + persisted this pass. */
|
|
62
|
+
deferredApplied: number;
|
|
63
|
+
counts: DetectCounts;
|
|
64
|
+
freshness: DetectFreshness;
|
|
65
|
+
/** Oldest-authored fresh node paths to re-validate (≤ revalidateSamplePerPass). */
|
|
66
|
+
revalidationSample: string[];
|
|
67
|
+
/** Bounded, secret-filtered stale sample for the /cartographer/stale snapshot. */
|
|
68
|
+
staleSample: {
|
|
69
|
+
path: string;
|
|
70
|
+
status: StalenessStatus;
|
|
71
|
+
}[];
|
|
72
|
+
/** Total stale+never-authored candidates (the sample's `total` for truncation honesty). */
|
|
73
|
+
staleTotal: number;
|
|
74
|
+
/** Measured wall-clock of this detect (operators tune detectTimeoutMs from this). */
|
|
75
|
+
durationMs: number;
|
|
76
|
+
/** True when the index file did not exist (distinct from a refusal — boot scaffold builds it). */
|
|
77
|
+
indexMissing?: boolean;
|
|
78
|
+
}
|
|
79
|
+
/** The detect-health enum carried on the snapshot + both read routes. */
|
|
80
|
+
export type LastDetectStatus = 'ok' | 'timeout' | 'worker-start-failed' | 'index-too-large' | 'index-unreadable' | 'git-error' | 'not-lease-holder';
|
|
81
|
+
/**
|
|
82
|
+
* The small, per-host snapshot every /cartographer/* read route serves from —
|
|
83
|
+
* so no request path ever parses the 67MB index or walks the tree. Written
|
|
84
|
+
* atomically by the sweep engine after each detect; never committed (it is
|
|
85
|
+
* per-host state under .instar/cartographer/).
|
|
86
|
+
*/
|
|
87
|
+
export interface CartographerSnapshot {
|
|
88
|
+
generatedAt: string;
|
|
89
|
+
headSha: string | null;
|
|
90
|
+
counts: DetectCounts;
|
|
91
|
+
freshness: DetectFreshness;
|
|
92
|
+
staleSample: {
|
|
93
|
+
path: string;
|
|
94
|
+
status: StalenessStatus;
|
|
95
|
+
}[];
|
|
96
|
+
staleTotal: number;
|
|
97
|
+
staleSampleTruncated: boolean;
|
|
98
|
+
lastDetectStatus: LastDetectStatus;
|
|
99
|
+
lastDetectAt: string;
|
|
100
|
+
durationMs: number;
|
|
101
|
+
}
|
|
102
|
+
/** One authored-summary delta applied to the index in the single author-phase write. */
|
|
103
|
+
export interface IndexDelta {
|
|
104
|
+
path: string;
|
|
105
|
+
/** Present when the node's summary/codeHash changed (an author or fingerprint refresh). */
|
|
106
|
+
summaryUpdatedAt?: string | null;
|
|
107
|
+
codeHash?: string | null;
|
|
108
|
+
/** Reset to 0 on a successful author. */
|
|
109
|
+
staleSincePass?: number;
|
|
110
|
+
/** Quarantine bookkeeping (failure path). */
|
|
111
|
+
authorFailed?: boolean;
|
|
112
|
+
}
|
|
113
|
+
export interface ApplyDeltasInput {
|
|
114
|
+
indexPath: string;
|
|
115
|
+
maxIndexBytes: number;
|
|
116
|
+
deltas: IndexDelta[];
|
|
117
|
+
}
|
|
118
|
+
/** Internal: instrumentation surfaced for tests (peak heap + node-file reads). */
|
|
119
|
+
export interface DetectInstrumentation {
|
|
120
|
+
candidateHeapPeak: number;
|
|
121
|
+
starvedHeapPeak: number;
|
|
122
|
+
/** Always 0 — detect reads ZERO node files; the test asserts this. */
|
|
123
|
+
nodeFileReads: number;
|
|
124
|
+
}
|
|
125
|
+
export declare function runDetect(input: DetectInput, instr?: DetectInstrumentation): DetectResult;
|
|
126
|
+
export declare function writeSnapshot(snapshotPath: string, snap: CartographerSnapshot): void;
|
|
127
|
+
export declare function readSnapshot(snapshotPath: string): CartographerSnapshot | null;
|
|
128
|
+
export declare function applyIndexDeltas(input: ApplyDeltasInput): {
|
|
129
|
+
written: number;
|
|
130
|
+
refused: boolean;
|
|
131
|
+
refusalReason?: DetectRefusalReason;
|
|
132
|
+
};
|
|
133
|
+
//# sourceMappingURL=cartographerDetect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cartographerDetect.d.ts","sourceRoot":"","sources":["../../src/core/cartographerDetect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cartographerDetect — the PURE, importable detect/index-write logic for the
|
|
3
|
+
* doc-freshness sweep, extracted so it can run OFF the server's main event loop
|
|
4
|
+
* in a worker thread (fix instar#1069) while staying unit-testable in-process.
|
|
5
|
+
*
|
|
6
|
+
* THE INVARIANT THIS MODULE EXISTS TO HOLD (spec CARTOGRAPHER-SWEEP-EVENTLOOP-SAFETY):
|
|
7
|
+
* the cartographer index on a real tree is hundreds of thousands of nodes / tens
|
|
8
|
+
* of megabytes. Parsing it and walking it is an O(nodeCount)/O(67MB) synchronous
|
|
9
|
+
* operation that MUST NOT run on the server's main thread — doing so starves the
|
|
10
|
+
* event loop, `/health` stops answering, and the supervisor kill-loops the server.
|
|
11
|
+
* So:
|
|
12
|
+
* - This module is `import_type`-only against CartographerTree (no value import
|
|
13
|
+
* of the storage class), so a `worker_threads` worker can load the compiled
|
|
14
|
+
* `.js` without dragging the whole server in.
|
|
15
|
+
* - `runDetect()` reads + parses the index, derives staleness from ONE batched
|
|
16
|
+
* `git ls-tree` (explicit large maxBuffer — never the 10MB default that throws
|
|
17
|
+
* on a big tree), orders a BOUNDED candidate set via bounded heaps (never a
|
|
18
|
+
* full sort of a full materialized array), computes the freshness aggregate,
|
|
19
|
+
* applies the pass's anti-starvation defer increments, and writes the index
|
|
20
|
+
* ONCE. It reads ZERO per-node files (every field it needs — including the
|
|
21
|
+
* accumulated `staleSincePass`, the `firstSeenAt` grace anchor, and the
|
|
22
|
+
* `authorFailed` quarantine flag — is carried on the index entry).
|
|
23
|
+
* - `applyIndexDeltas()` is the author-phase write: it re-reads the index,
|
|
24
|
+
* applies the ≤maxNodesPerPass authored-summary deltas, and writes ONCE — so
|
|
25
|
+
* authoring N nodes is ONE off-thread 67MB write, not N per-node main-thread
|
|
26
|
+
* parse+serialize (closes the sixth starver).
|
|
27
|
+
*
|
|
28
|
+
* Both functions are shared VERBATIM by the worker wrapper AND the synchronous
|
|
29
|
+
* rollback path (`freshnessSweep.detectInWorker: false`): the byte-guard, the
|
|
30
|
+
* explicit git maxBuffer, the bounded heap ordering, and the refusal taxonomy are
|
|
31
|
+
* properties of THIS module, so the rollback runs the same bounded logic on the
|
|
32
|
+
* main thread (bounded — never the legacy `tree.staleNodes()` full walk).
|
|
33
|
+
*/
|
|
34
|
+
import fs from 'node:fs';
|
|
35
|
+
import crypto from 'node:crypto';
|
|
36
|
+
import { SafeGitExecutor } from './SafeGitExecutor.js';
|
|
37
|
+
import { isSecretBearingPath } from './cartographerSummary.js';
|
|
38
|
+
const GIT_OP = 'cartographer-detect';
|
|
39
|
+
// ── pure helpers (no I/O) ──────────────────────────────────────────────────
|
|
40
|
+
function deriveStatus(storedHash, currentOid) {
|
|
41
|
+
if (storedHash == null)
|
|
42
|
+
return 'never-authored';
|
|
43
|
+
if (currentOid == null)
|
|
44
|
+
return 'path-gone';
|
|
45
|
+
return currentOid === storedHash ? 'fresh' : 'stale';
|
|
46
|
+
}
|
|
47
|
+
function depthOf(p) {
|
|
48
|
+
if (p === '')
|
|
49
|
+
return 0;
|
|
50
|
+
return p.split('/').length;
|
|
51
|
+
}
|
|
52
|
+
function parentOf(p) {
|
|
53
|
+
if (p === '')
|
|
54
|
+
return '';
|
|
55
|
+
const i = p.lastIndexOf('/');
|
|
56
|
+
return i < 0 ? '' : p.slice(0, i);
|
|
57
|
+
}
|
|
58
|
+
function atomicWrite(filePath, contents) {
|
|
59
|
+
// Per-host-unique tmp suffix so a shared state dir across machines can't collide.
|
|
60
|
+
const tmp = `${filePath}.${process.pid}.${crypto.randomBytes(6).toString('hex')}.tmp`;
|
|
61
|
+
fs.writeFileSync(tmp, contents);
|
|
62
|
+
fs.renameSync(tmp, filePath);
|
|
63
|
+
}
|
|
64
|
+
// ── git plumbing (explicit large maxBuffer; failure → caller refuses) ────────
|
|
65
|
+
/** Throws on git failure so the caller can map it to a `detect-git-error` refusal. */
|
|
66
|
+
function readCurrentOids(projectDir, gitMaxBuffer) {
|
|
67
|
+
const map = new Map();
|
|
68
|
+
const rootTree = SafeGitExecutor.readSync(['rev-parse', 'HEAD^{tree}'], {
|
|
69
|
+
cwd: projectDir, operation: GIT_OP, maxBuffer: gitMaxBuffer,
|
|
70
|
+
});
|
|
71
|
+
if (rootTree)
|
|
72
|
+
map.set('', rootTree.trim());
|
|
73
|
+
const out = SafeGitExecutor.readSync(['ls-tree', '-r', '-t', '-z', 'HEAD'], {
|
|
74
|
+
cwd: projectDir, operation: GIT_OP, maxBuffer: gitMaxBuffer,
|
|
75
|
+
});
|
|
76
|
+
for (const entry of out.split('\0')) {
|
|
77
|
+
if (!entry)
|
|
78
|
+
continue;
|
|
79
|
+
const tab = entry.indexOf('\t');
|
|
80
|
+
if (tab < 0)
|
|
81
|
+
continue;
|
|
82
|
+
const meta = entry.slice(0, tab).split(' ');
|
|
83
|
+
const p = entry.slice(tab + 1);
|
|
84
|
+
const oid = meta[2];
|
|
85
|
+
if (oid && p)
|
|
86
|
+
map.set(p, oid);
|
|
87
|
+
}
|
|
88
|
+
return map;
|
|
89
|
+
}
|
|
90
|
+
function headShort(projectDir) {
|
|
91
|
+
try {
|
|
92
|
+
const out = SafeGitExecutor.readSync(['rev-parse', '--short', 'HEAD'], {
|
|
93
|
+
cwd: projectDir, operation: GIT_OP, maxBuffer: 1024 * 1024,
|
|
94
|
+
});
|
|
95
|
+
return out ? out.trim() : null;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// @silent-fallback-ok — headSha is provenance-only; absence is reported as null,
|
|
99
|
+
// never a refusal (the ls-tree read above is the one that gates the pass).
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// ── bounded top-N min-heap (keeps the N highest-priority items, O(N) memory) ──
|
|
104
|
+
/**
|
|
105
|
+
* A fixed-capacity min-heap keyed by a numeric priority where HIGHER priority =
|
|
106
|
+
* keep. Streaming every candidate through `offer()` keeps only the top `cap`
|
|
107
|
+
* without ever materializing or sorting the full candidate set — the structural
|
|
108
|
+
* guarantee that peak memory is O(cap), not O(nodeCount).
|
|
109
|
+
*/
|
|
110
|
+
class BoundedTopHeap {
|
|
111
|
+
cap;
|
|
112
|
+
heap = [];
|
|
113
|
+
peak = 0;
|
|
114
|
+
constructor(cap) {
|
|
115
|
+
this.cap = cap;
|
|
116
|
+
}
|
|
117
|
+
offer(key, tie, v) {
|
|
118
|
+
if (this.cap <= 0)
|
|
119
|
+
return;
|
|
120
|
+
if (this.heap.length < this.cap) {
|
|
121
|
+
this.heap.push({ key, tie, v });
|
|
122
|
+
this.siftUp(this.heap.length - 1);
|
|
123
|
+
}
|
|
124
|
+
else if (this.worseThanRoot(key, tie)) {
|
|
125
|
+
// new item outranks the current minimum → replace root
|
|
126
|
+
this.heap[0] = { key, tie, v };
|
|
127
|
+
this.siftDown(0);
|
|
128
|
+
}
|
|
129
|
+
if (this.heap.length > this.peak)
|
|
130
|
+
this.peak = this.heap.length;
|
|
131
|
+
}
|
|
132
|
+
/** Highest-priority first. */
|
|
133
|
+
drainSorted() {
|
|
134
|
+
return [...this.heap]
|
|
135
|
+
.sort((a, b) => b.key - a.key || a.tie.localeCompare(b.tie))
|
|
136
|
+
.map((e) => e.v);
|
|
137
|
+
}
|
|
138
|
+
peakSize() { return this.peak; }
|
|
139
|
+
worseThanRoot(key, tie) {
|
|
140
|
+
const r = this.heap[0];
|
|
141
|
+
return key > r.key || (key === r.key && tie.localeCompare(r.tie) < 0);
|
|
142
|
+
}
|
|
143
|
+
less(a, b) {
|
|
144
|
+
// min-heap: the WORST (lowest priority) item floats to the root so it's evicted first
|
|
145
|
+
return a.key < b.key || (a.key === b.key && a.tie.localeCompare(b.tie) > 0);
|
|
146
|
+
}
|
|
147
|
+
siftUp(i) {
|
|
148
|
+
while (i > 0) {
|
|
149
|
+
const p = (i - 1) >> 1;
|
|
150
|
+
if (this.less(this.heap[i], this.heap[p])) {
|
|
151
|
+
this.swap(i, p);
|
|
152
|
+
i = p;
|
|
153
|
+
}
|
|
154
|
+
else
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
siftDown(i) {
|
|
159
|
+
const n = this.heap.length;
|
|
160
|
+
for (;;) {
|
|
161
|
+
const l = 2 * i + 1, r = 2 * i + 2;
|
|
162
|
+
let s = i;
|
|
163
|
+
if (l < n && this.less(this.heap[l], this.heap[s]))
|
|
164
|
+
s = l;
|
|
165
|
+
if (r < n && this.less(this.heap[r], this.heap[s]))
|
|
166
|
+
s = r;
|
|
167
|
+
if (s === i)
|
|
168
|
+
break;
|
|
169
|
+
this.swap(i, s);
|
|
170
|
+
i = s;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
swap(i, j) { const t = this.heap[i]; this.heap[i] = this.heap[j]; this.heap[j] = t; }
|
|
174
|
+
}
|
|
175
|
+
export function runDetect(input, instr) {
|
|
176
|
+
const startedAt = Date.now();
|
|
177
|
+
const emptyCounts = {
|
|
178
|
+
nodeCount: 0, authoredCount: 0, neverAuthored: 0, stale: 0, pathGone: 0,
|
|
179
|
+
generatedAt: null, headSha: null,
|
|
180
|
+
};
|
|
181
|
+
const emptyFreshness = {
|
|
182
|
+
nodeCount: 0, authorableCount: 0, freshCount: 0, staleCount: 0,
|
|
183
|
+
neverAuthoredCount: 0, neverAuthoredWithinGrace: 0, neverAuthoredPastGrace: 0,
|
|
184
|
+
authorFailedCount: 0, freshRatio: 1, generatedAt: null,
|
|
185
|
+
};
|
|
186
|
+
const refuse = (reason) => ({
|
|
187
|
+
refused: true, refusalReason: reason, candidates: [], deferredApplied: 0,
|
|
188
|
+
counts: emptyCounts, freshness: emptyFreshness, revalidationSample: [],
|
|
189
|
+
staleSample: [], staleTotal: 0, durationMs: Date.now() - startedAt,
|
|
190
|
+
});
|
|
191
|
+
// Index missing → NOT a refusal (the boot scaffold builds it); honest empty result.
|
|
192
|
+
let stat;
|
|
193
|
+
try {
|
|
194
|
+
stat = fs.statSync(input.indexPath);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return {
|
|
198
|
+
refused: false, candidates: [], deferredApplied: 0, counts: emptyCounts,
|
|
199
|
+
freshness: emptyFreshness, revalidationSample: [], staleSample: [], staleTotal: 0,
|
|
200
|
+
durationMs: Date.now() - startedAt, indexMissing: true,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// Pre-parse byte guard — the REAL bound on the parse (terminate() cannot interrupt
|
|
204
|
+
// a synchronous JSON.parse already in flight). Refuse before attempting it.
|
|
205
|
+
if (stat.size > input.maxIndexBytes)
|
|
206
|
+
return refuse('detect-index-too-large');
|
|
207
|
+
let index;
|
|
208
|
+
try {
|
|
209
|
+
index = JSON.parse(fs.readFileSync(input.indexPath, 'utf8'));
|
|
210
|
+
if (!index || typeof index !== 'object' || !index.nodes)
|
|
211
|
+
return refuse('detect-index-unreadable');
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return refuse('detect-index-unreadable');
|
|
215
|
+
}
|
|
216
|
+
let current;
|
|
217
|
+
try {
|
|
218
|
+
current = readCurrentOids(input.projectDir, input.gitMaxBuffer);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
// A git read failure must be a NAMED refusal — never "every node path-gone"
|
|
222
|
+
// (that would silently mark the whole tree stale and author churn).
|
|
223
|
+
return refuse('detect-git-error');
|
|
224
|
+
}
|
|
225
|
+
const headSha = headShort(input.projectDir);
|
|
226
|
+
// ── Pass A: derive status for every node; accumulate counts + freshness;
|
|
227
|
+
// collect the candidate set; feed the oldest-fresh revalidation heap. ──
|
|
228
|
+
const entries = Object.entries(index.nodes);
|
|
229
|
+
const candidateSet = new Set();
|
|
230
|
+
const staleSample = [];
|
|
231
|
+
let authoredCount = 0, neverAuthored = 0, stale = 0, pathGone = 0;
|
|
232
|
+
let authorable = 0, fresh = 0, never = 0, neverWithin = 0, neverPast = 0, authorFailed = 0;
|
|
233
|
+
const revalHeap = new BoundedTopHeap(Math.max(0, input.revalidateSamplePerPass));
|
|
234
|
+
const sampleCap = Math.max(0, input.snapshotSampleMax);
|
|
235
|
+
const addCandidate = (p, status) => {
|
|
236
|
+
candidateSet.add(p);
|
|
237
|
+
// Secret-bearing path NAMES are excluded from the published sample so they are
|
|
238
|
+
// never surfaced via the /stale route or the Files tab (they are still authored-
|
|
239
|
+
// excluded by the engine; only their NAME is withheld from the snapshot).
|
|
240
|
+
if (staleSample.length < sampleCap && !isSecretBearingPath(p)) {
|
|
241
|
+
staleSample.push({ path: p, status });
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
for (const [p, entry] of entries) {
|
|
245
|
+
const status = deriveStatus(entry.codeHash, current.get(p));
|
|
246
|
+
if (entry.codeHash != null)
|
|
247
|
+
authoredCount += 1;
|
|
248
|
+
else
|
|
249
|
+
neverAuthored += 1;
|
|
250
|
+
if (status === 'path-gone') {
|
|
251
|
+
pathGone += 1;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
authorable += 1;
|
|
255
|
+
if (entry.authorFailed === true)
|
|
256
|
+
authorFailed += 1;
|
|
257
|
+
if (status === 'fresh') {
|
|
258
|
+
fresh += 1;
|
|
259
|
+
if (entry.summaryUpdatedAt != null) {
|
|
260
|
+
// Re-validation nominee priority: OLDEST summaryUpdatedAt first → higher
|
|
261
|
+
// priority = larger (nowMs - updatedAt), so older summaries win the heap.
|
|
262
|
+
const age = input.nowMs - Date.parse(entry.summaryUpdatedAt);
|
|
263
|
+
revalHeap.offer(Number.isFinite(age) ? age : 0, p, p);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else if (status === 'stale') {
|
|
267
|
+
stale += 1;
|
|
268
|
+
addCandidate(p, status);
|
|
269
|
+
}
|
|
270
|
+
else if (status === 'never-authored') {
|
|
271
|
+
never += 1;
|
|
272
|
+
const firstSeen = entry.firstSeenAt ? Date.parse(entry.firstSeenAt) : input.nowMs;
|
|
273
|
+
if (Number.isFinite(firstSeen) && input.nowMs - firstSeen > input.graceMs)
|
|
274
|
+
neverPast += 1;
|
|
275
|
+
else
|
|
276
|
+
neverWithin += 1;
|
|
277
|
+
addCandidate(p, status);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// ── childrenOf adjacency from PATH STRINGS in the parsed index (zero node-file
|
|
281
|
+
// reads) — needed for the dir-defer rule (author a dir after its candidate
|
|
282
|
+
// children). Derived from the index we already parsed, never the filesystem. ──
|
|
283
|
+
const childrenOf = new Map();
|
|
284
|
+
for (const [p] of entries) {
|
|
285
|
+
if (p === '')
|
|
286
|
+
continue;
|
|
287
|
+
const par = parentOf(p);
|
|
288
|
+
const arr = childrenOf.get(par);
|
|
289
|
+
if (arr)
|
|
290
|
+
arr.push(p);
|
|
291
|
+
else
|
|
292
|
+
childrenOf.set(par, [p]);
|
|
293
|
+
}
|
|
294
|
+
// ── Pass B: order candidates through bounded heaps (NEVER a full sort of the
|
|
295
|
+
// full set — peak memory O(maxCandidates), not O(nodeCount)). Deepest-first
|
|
296
|
+
// guarantees children are authored before their parent dir IN THE SAME pass.
|
|
297
|
+
// A starved dir (deferred past maxDeferredPasses) gets a capped front-bias
|
|
298
|
+
// lane. A dir that is evicted by the per-pass bound AND still has a candidate
|
|
299
|
+
// child is "deferred": its anti-starvation counter is bumped so a subtree
|
|
300
|
+
// perpetually pushed out by deeper churn is eventually promoted. ──
|
|
301
|
+
const frontCap = Math.max(1, Math.floor(input.maxNodesPerPass / 2));
|
|
302
|
+
const candidateHeap = new BoundedTopHeap(input.maxCandidates);
|
|
303
|
+
const starvedHeap = new BoundedTopHeap(frontCap);
|
|
304
|
+
for (const p of candidateSet) {
|
|
305
|
+
const entry = index.nodes[p];
|
|
306
|
+
const starved = entry.kind === 'dir' && (entry.staleSincePass ?? 0) >= input.maxDeferredPasses;
|
|
307
|
+
if (starved)
|
|
308
|
+
starvedHeap.offer(depthOf(p), p, p);
|
|
309
|
+
else
|
|
310
|
+
candidateHeap.offer(depthOf(p), p, p);
|
|
311
|
+
}
|
|
312
|
+
const starvedList = starvedHeap.drainSorted();
|
|
313
|
+
const normalList = candidateHeap.drainSorted();
|
|
314
|
+
const starvedSet = new Set(starvedList);
|
|
315
|
+
const candidates = [...starvedList, ...normalList.filter((p) => !starvedSet.has(p))].slice(0, input.maxCandidates);
|
|
316
|
+
// Anti-starvation: a dir candidate the bound pushed out, that still has a
|
|
317
|
+
// candidate child, gets its defer counter bumped (persisted in write (a)).
|
|
318
|
+
const selected = new Set(candidates);
|
|
319
|
+
let deferredApplied = 0;
|
|
320
|
+
for (const p of candidateSet) {
|
|
321
|
+
const entry = index.nodes[p];
|
|
322
|
+
if (entry.kind !== 'dir' || selected.has(p))
|
|
323
|
+
continue;
|
|
324
|
+
const kids = childrenOf.get(p);
|
|
325
|
+
if (kids && kids.some((c) => candidateSet.has(c))) {
|
|
326
|
+
entry.staleSincePass = (entry.staleSincePass ?? 0) + 1;
|
|
327
|
+
deferredApplied += 1;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (instr) {
|
|
331
|
+
instr.candidateHeapPeak = candidateHeap.peakSize();
|
|
332
|
+
instr.starvedHeapPeak = starvedHeap.peakSize();
|
|
333
|
+
instr.nodeFileReads = 0; // detect NEVER reads node files
|
|
334
|
+
}
|
|
335
|
+
// ── Detect-phase index write (a): persist the defer increments ONCE, off the
|
|
336
|
+
// main thread. The deferred set never crosses the worker boundary. ──
|
|
337
|
+
if (deferredApplied > 0) {
|
|
338
|
+
atomicWrite(input.indexPath, JSON.stringify(index, null, 2));
|
|
339
|
+
}
|
|
340
|
+
const ratioDenom = fresh + stale + neverPast;
|
|
341
|
+
return {
|
|
342
|
+
refused: false,
|
|
343
|
+
candidates,
|
|
344
|
+
deferredApplied,
|
|
345
|
+
counts: {
|
|
346
|
+
nodeCount: entries.length,
|
|
347
|
+
authoredCount,
|
|
348
|
+
neverAuthored,
|
|
349
|
+
stale,
|
|
350
|
+
pathGone,
|
|
351
|
+
generatedAt: index.generatedAt ?? null,
|
|
352
|
+
headSha,
|
|
353
|
+
},
|
|
354
|
+
freshness: {
|
|
355
|
+
nodeCount: entries.length,
|
|
356
|
+
authorableCount: authorable,
|
|
357
|
+
freshCount: fresh,
|
|
358
|
+
staleCount: stale,
|
|
359
|
+
neverAuthoredCount: never,
|
|
360
|
+
neverAuthoredWithinGrace: neverWithin,
|
|
361
|
+
neverAuthoredPastGrace: neverPast,
|
|
362
|
+
authorFailedCount: authorFailed,
|
|
363
|
+
freshRatio: ratioDenom === 0 ? 1 : fresh / ratioDenom,
|
|
364
|
+
generatedAt: index.generatedAt ?? null,
|
|
365
|
+
},
|
|
366
|
+
revalidationSample: revalHeap.drainSorted(),
|
|
367
|
+
staleSample,
|
|
368
|
+
staleTotal: candidateSet.size,
|
|
369
|
+
durationMs: Date.now() - startedAt,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
// ── snapshot read/write (the per-host file every read route serves from) ──────
|
|
373
|
+
export function writeSnapshot(snapshotPath, snap) {
|
|
374
|
+
atomicWrite(snapshotPath, JSON.stringify(snap, null, 2));
|
|
375
|
+
}
|
|
376
|
+
export function readSnapshot(snapshotPath) {
|
|
377
|
+
try {
|
|
378
|
+
const raw = fs.readFileSync(snapshotPath, 'utf8');
|
|
379
|
+
const snap = JSON.parse(raw);
|
|
380
|
+
if (!snap || typeof snap !== 'object' || !snap.counts)
|
|
381
|
+
return null;
|
|
382
|
+
return snap;
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
// @silent-fallback-ok — a missing/corrupt snapshot reads as "absent"; the
|
|
386
|
+
// routes serve snapshot:'absent' and the next detect rewrites it.
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// ── applyIndexDeltas (author-phase write — ONE off-thread 67MB write) ─────────
|
|
391
|
+
export function applyIndexDeltas(input) {
|
|
392
|
+
if (input.deltas.length === 0)
|
|
393
|
+
return { written: 0, refused: false };
|
|
394
|
+
let stat;
|
|
395
|
+
try {
|
|
396
|
+
stat = fs.statSync(input.indexPath);
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
return { written: 0, refused: true, refusalReason: 'detect-index-unreadable' };
|
|
400
|
+
}
|
|
401
|
+
if (stat.size > input.maxIndexBytes)
|
|
402
|
+
return { written: 0, refused: true, refusalReason: 'detect-index-too-large' };
|
|
403
|
+
let index;
|
|
404
|
+
try {
|
|
405
|
+
index = JSON.parse(fs.readFileSync(input.indexPath, 'utf8'));
|
|
406
|
+
if (!index || !index.nodes)
|
|
407
|
+
return { written: 0, refused: true, refusalReason: 'detect-index-unreadable' };
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
return { written: 0, refused: true, refusalReason: 'detect-index-unreadable' };
|
|
411
|
+
}
|
|
412
|
+
let written = 0;
|
|
413
|
+
for (const d of input.deltas) {
|
|
414
|
+
const entry = index.nodes[d.path];
|
|
415
|
+
if (!entry)
|
|
416
|
+
continue;
|
|
417
|
+
if (Object.prototype.hasOwnProperty.call(d, 'summaryUpdatedAt'))
|
|
418
|
+
entry.summaryUpdatedAt = d.summaryUpdatedAt ?? null;
|
|
419
|
+
if (Object.prototype.hasOwnProperty.call(d, 'codeHash'))
|
|
420
|
+
entry.codeHash = d.codeHash ?? null;
|
|
421
|
+
if (Object.prototype.hasOwnProperty.call(d, 'staleSincePass'))
|
|
422
|
+
entry.staleSincePass = d.staleSincePass;
|
|
423
|
+
if (Object.prototype.hasOwnProperty.call(d, 'authorFailed'))
|
|
424
|
+
entry.authorFailed = d.authorFailed;
|
|
425
|
+
written += 1;
|
|
426
|
+
}
|
|
427
|
+
if (written > 0)
|
|
428
|
+
atomicWrite(input.indexPath, JSON.stringify(index, null, 2));
|
|
429
|
+
return { written, refused: false };
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=cartographerDetect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cartographerDetect.js","sourceRoot":"","sources":["../../src/core/cartographerDetect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cartographerDetect.worker.d.ts","sourceRoot":"","sources":["../../src/core/cartographerDetect.worker.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cartographerDetect.worker — the TRIVIAL `worker_threads` entrypoint for the
|
|
3
|
+
* off-event-loop cartographer detect / index-write (fix instar#1069).
|
|
4
|
+
*
|
|
5
|
+
* It contains NO logic that can drift: it reads `workerData`, dispatches to the
|
|
6
|
+
* pure module (`runDetect` / `applyIndexDeltas` in cartographerDetect.ts), posts
|
|
7
|
+
* the bounded result back, and exits. The 67MB parse + O(nodeCount) walk happen
|
|
8
|
+
* HERE, on a worker thread — never on the server's main event loop.
|
|
9
|
+
*
|
|
10
|
+
* The engine spawns this with an explicit minimal `env` allowlist (NOT the parent
|
|
11
|
+
* process.env), so the Telegram token / Anthropic keys / Bearer authToken / PIN
|
|
12
|
+
* material are absent — the detect worker reads paths + git oids only, never blob
|
|
13
|
+
* content, so it needs none of them.
|
|
14
|
+
*/
|
|
15
|
+
import { parentPort, workerData } from 'node:worker_threads';
|
|
16
|
+
import { runDetect, applyIndexDeltas } from './cartographerDetect.js';
|
|
17
|
+
function main() {
|
|
18
|
+
const job = workerData;
|
|
19
|
+
if (!parentPort)
|
|
20
|
+
return; // not run as a worker — nothing to post to
|
|
21
|
+
try {
|
|
22
|
+
if (job.mode === 'detect') {
|
|
23
|
+
parentPort.postMessage({ ok: true, result: runDetect(job.input) });
|
|
24
|
+
}
|
|
25
|
+
else if (job.mode === 'apply-deltas') {
|
|
26
|
+
parentPort.postMessage({ ok: true, result: applyIndexDeltas(job.input) });
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
parentPort.postMessage({ ok: false, error: `unknown worker mode` });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
parentPort.postMessage({ ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
main();
|
|
37
|
+
//# sourceMappingURL=cartographerDetect.worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cartographerDetect.worker.js","sourceRoot":"","sources":["../../src/core/cartographerDetect.worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAA2C,MAAM,yBAAyB,CAAC;AAM/G,SAAS,IAAI;IACX,MAAM,GAAG,GAAG,UAAuB,CAAC;IACpC,IAAI,CAAC,UAAU;QAAE,OAAO,CAAC,2CAA2C;IACpE,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1B,UAAU,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACrE,CAAC;aAAM,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACvC,UAAU,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC5E,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,UAAU,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACjG,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|