instar 1.3.511 → 1.3.512
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 +67 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +24 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/CoherenceJournal.d.ts +31 -1
- package/dist/core/CoherenceJournal.d.ts.map +1 -1
- package/dist/core/CoherenceJournal.js +49 -2
- package/dist/core/CoherenceJournal.js.map +1 -1
- package/dist/core/JournalSyncApplier.d.ts.map +1 -1
- package/dist/core/JournalSyncApplier.js +18 -0
- package/dist/core/JournalSyncApplier.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +44 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +5 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/types.d.ts +27 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/GreenPrAutoMerger.d.ts +188 -0
- package/dist/monitoring/GreenPrAutoMerger.d.ts.map +1 -0
- package/dist/monitoring/GreenPrAutoMerger.js +393 -0
- package/dist/monitoring/GreenPrAutoMerger.js.map +1 -0
- package/dist/monitoring/GuardLatchStore.d.ts +134 -0
- package/dist/monitoring/GuardLatchStore.d.ts.map +1 -0
- package/dist/monitoring/GuardLatchStore.js +255 -0
- package/dist/monitoring/GuardLatchStore.js.map +1 -0
- package/dist/monitoring/MergeRunner.d.ts +126 -0
- package/dist/monitoring/MergeRunner.d.ts.map +1 -0
- package/dist/monitoring/MergeRunner.js +296 -0
- package/dist/monitoring/MergeRunner.js.map +1 -0
- package/dist/monitoring/floorDriftCanary.d.ts +88 -0
- package/dist/monitoring/floorDriftCanary.d.ts.map +1 -0
- package/dist/monitoring/floorDriftCanary.js +89 -0
- package/dist/monitoring/floorDriftCanary.js.map +1 -0
- package/dist/monitoring/greenPrAutomergeWiring.d.ts +73 -0
- package/dist/monitoring/greenPrAutomergeWiring.d.ts.map +1 -0
- package/dist/monitoring/greenPrAutomergeWiring.js +273 -0
- package/dist/monitoring/greenPrAutomergeWiring.js.map +1 -0
- package/dist/monitoring/greenPrLogic.d.ts +121 -0
- package/dist/monitoring/greenPrLogic.d.ts.map +1 -0
- package/dist/monitoring/greenPrLogic.js +198 -0
- package/dist/monitoring/greenPrLogic.js.map +1 -0
- package/dist/monitoring/guardManifest.d.ts.map +1 -1
- package/dist/monitoring/guardManifest.js +12 -0
- package/dist/monitoring/guardManifest.js.map +1 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +2 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +16 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +5 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +112 -1
- package/dist/server/routes.js.map +1 -1
- package/dist/server/stopGate.d.ts +45 -0
- package/dist/server/stopGate.d.ts.map +1 -1
- package/dist/server/stopGate.js +74 -0
- package/dist/server/stopGate.js.map +1 -1
- package/package.json +1 -1
- package/scripts/safe-merge.mjs +449 -59
- package/src/data/builtin-manifest.json +64 -64
- package/upgrades/1.3.512.md +65 -0
- package/upgrades/side-effects/green-pr-automerge-enforcement.md +171 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MergeRunner — the act-path engine for the GreenPrAutoMerger (Step 4 of
|
|
3
|
+
* green-pr-automerge-enforcement §3.1/R5). Owns everything that touches a real
|
|
4
|
+
* process:
|
|
5
|
+
*
|
|
6
|
+
* - probeContract(): runs `safe-merge --capabilities`, pins the script's
|
|
7
|
+
* content hash + absolute path for the attempt (round-3 mid-run-swap defense),
|
|
8
|
+
* and re-verifies that hash IMMEDIATELY before exec (round-5: the spawn runs
|
|
9
|
+
* the verified bytes).
|
|
10
|
+
* - run(): writes a DURABLE two-phase in-flight record BEFORE the spawn (intent
|
|
11
|
+
* first, pid/pgid patched in after), spawns safe-merge in its OWN process
|
|
12
|
+
* group, hard-kills the group at mergeTimeoutMs + grace, parses the classified
|
|
13
|
+
* `safe-merge-result:` line, and confirms a `merged` outcome INDEPENDENTLY
|
|
14
|
+
* (B10). The record is cleared on classification.
|
|
15
|
+
* - reapOrphan(): at boot/warm-up, reaps a surviving orphan from a crash —
|
|
16
|
+
* verifies the recorded pid/pgid identity via a unique attempt token before
|
|
17
|
+
* signalling (pid-reuse safe), handles the dead-leader/live-group corner
|
|
18
|
+
* (orphan-reap-incomplete), and re-verifies PR state via gh. A pid-less
|
|
19
|
+
* in-flight record is treated as attempt-of-unknown-outcome (re-verify,
|
|
20
|
+
* never assume not-spawned).
|
|
21
|
+
*
|
|
22
|
+
* The guarantee survives the server's own death: the watcher's merges trigger
|
|
23
|
+
* releases → auto-update restarts, so a restart mid-attempt is a NORMAL
|
|
24
|
+
* condition. The durable record + own-process-group + shutdown group-kill +
|
|
25
|
+
* warm-up reap close the double-attempt / wedged-orphan classes.
|
|
26
|
+
*
|
|
27
|
+
* All process + fs + gh I/O is behind injected seams so the runner is testable
|
|
28
|
+
* without spawning anything.
|
|
29
|
+
*
|
|
30
|
+
* RULE 3.1 RATIONALE
|
|
31
|
+
* Criticality: high — this code drives an autonomous merge to main.
|
|
32
|
+
* Frequency: per-merge-attempt (at most one per ~10-minute tick).
|
|
33
|
+
* Stability: stable — parses safe-merge's OWN structured contract line
|
|
34
|
+
* (`safe-merge-result: {...}`), not human gh output; and
|
|
35
|
+
* `gh ... --json` structured responses, never regex over prose.
|
|
36
|
+
* Fallback: every parse failure is caught and resolves to a NON-merged
|
|
37
|
+
* outcome (fail-toward-skip); a `merged` outcome is never trusted
|
|
38
|
+
* without an INDEPENDENT `gh pr view` confirmation (B10).
|
|
39
|
+
* Verdict: deterministic; the act-time authority is safe-merge, which
|
|
40
|
+
* re-verifies, so a misread here can only refuse, never over-merge.
|
|
41
|
+
*/
|
|
42
|
+
import { spawn as realSpawn } from 'node:child_process';
|
|
43
|
+
import crypto from 'node:crypto';
|
|
44
|
+
import fs from 'node:fs';
|
|
45
|
+
import path from 'node:path';
|
|
46
|
+
import { SafeFsExecutor } from '../core/SafeFsExecutor.js';
|
|
47
|
+
export class DefaultMergeRunner {
|
|
48
|
+
cfg;
|
|
49
|
+
deps;
|
|
50
|
+
now;
|
|
51
|
+
/** Pinned per-attempt: the probed script's hash + path. */
|
|
52
|
+
pinnedHash = null;
|
|
53
|
+
constructor(cfg, deps) {
|
|
54
|
+
this.cfg = cfg;
|
|
55
|
+
this.deps = deps;
|
|
56
|
+
this.now = deps.now ?? (() => Date.now());
|
|
57
|
+
}
|
|
58
|
+
// ---- contract probe -----------------------------------------------------
|
|
59
|
+
async probeContract() {
|
|
60
|
+
try {
|
|
61
|
+
const out = await this.spawn({
|
|
62
|
+
command: this.cfg.nodePath ?? process.execPath,
|
|
63
|
+
args: [this.cfg.safeMergePath, '--capabilities'],
|
|
64
|
+
env: process.env,
|
|
65
|
+
deadlineMs: 30_000,
|
|
66
|
+
});
|
|
67
|
+
if (out.status !== 0)
|
|
68
|
+
return { ok: false };
|
|
69
|
+
const json = JSON.parse(out.stdout.trim());
|
|
70
|
+
const version = Number(json?.contract);
|
|
71
|
+
if (version !== this.cfg.expectedContractVersion)
|
|
72
|
+
return { ok: false, version };
|
|
73
|
+
// Pin the script's content hash for the attempt (re-verified before exec).
|
|
74
|
+
this.pinnedHash = this.hashScript();
|
|
75
|
+
return { ok: this.pinnedHash !== null, version };
|
|
76
|
+
}
|
|
77
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
78
|
+
return { ok: false };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
hashScript() {
|
|
82
|
+
try {
|
|
83
|
+
const buf = fs.readFileSync(this.cfg.safeMergePath);
|
|
84
|
+
return crypto.createHash('sha256').update(buf).digest('hex');
|
|
85
|
+
}
|
|
86
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// ---- run ----------------------------------------------------------------
|
|
91
|
+
async run(attempt) {
|
|
92
|
+
// Pre-exec hash re-verify (round-5): a checkout swap between probe and exec
|
|
93
|
+
// must refuse — the spawn runs the VERIFIED bytes.
|
|
94
|
+
const currentHash = this.hashScript();
|
|
95
|
+
if (!this.pinnedHash || currentHash !== this.pinnedHash) {
|
|
96
|
+
this.log(`safe-merge hash changed between probe and exec — refusing (${attempt.pr})`);
|
|
97
|
+
return { outcome: 'skipped:safe-merge-contract', confirmedMerged: false };
|
|
98
|
+
}
|
|
99
|
+
const attemptToken = crypto.randomBytes(8).toString('hex');
|
|
100
|
+
// Phase 1: durable intent record BEFORE the spawn.
|
|
101
|
+
const record = {
|
|
102
|
+
pr: attempt.pr, headRefOid: attempt.headRefOid, repo: this.cfg.repo,
|
|
103
|
+
attemptToken, startedAt: this.now(), pid: null, pgid: null,
|
|
104
|
+
};
|
|
105
|
+
this.writeInFlight(record);
|
|
106
|
+
let out;
|
|
107
|
+
try {
|
|
108
|
+
out = await this.spawn({
|
|
109
|
+
command: this.cfg.nodePath ?? process.execPath,
|
|
110
|
+
args: [
|
|
111
|
+
this.cfg.safeMergePath, String(attempt.pr),
|
|
112
|
+
'--repo', this.cfg.repo, '--squash', '--delete-branch', '--admin',
|
|
113
|
+
'--match-head-commit', attempt.headRefOid,
|
|
114
|
+
'--deadline-ms', String(this.cfg.mergeTimeoutMs),
|
|
115
|
+
],
|
|
116
|
+
env: { ...process.env, GREEN_PR_ATTEMPT_TOKEN: attemptToken },
|
|
117
|
+
deadlineMs: this.cfg.mergeTimeoutMs + this.cfg.mergeKillGraceMs,
|
|
118
|
+
onPid: (pid) => {
|
|
119
|
+
// Phase 2: patch pid/pgid (the child's pid IS its pgid when detached).
|
|
120
|
+
record.pid = pid;
|
|
121
|
+
record.pgid = pid;
|
|
122
|
+
this.writeInFlight(record);
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
catch (e) { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
127
|
+
this.clearInFlight();
|
|
128
|
+
return { outcome: `error:spawn-${String(e?.message).slice(0, 40)}`, confirmedMerged: false };
|
|
129
|
+
}
|
|
130
|
+
const outcome = parseResultLine(out.stdout) ?? (out.deadlineKilled ? 'refused:checks-timeout' : 'error:no-result-line');
|
|
131
|
+
let confirmedMerged = false;
|
|
132
|
+
if (outcome === 'merged') {
|
|
133
|
+
try {
|
|
134
|
+
confirmedMerged = await this.deps.confirmMerged(attempt.pr, this.cfg.repo);
|
|
135
|
+
}
|
|
136
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
137
|
+
confirmedMerged = false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
this.clearInFlight();
|
|
141
|
+
return { outcome, confirmedMerged, deadlineKilled: out.deadlineKilled };
|
|
142
|
+
}
|
|
143
|
+
// ---- orphan reap (boot/warm-up) ----------------------------------------
|
|
144
|
+
async reapOrphan() {
|
|
145
|
+
const record = this.readInFlight();
|
|
146
|
+
if (!record)
|
|
147
|
+
return { reaped: false };
|
|
148
|
+
const isAlive = this.deps.isAlive ?? ((pid) => { try {
|
|
149
|
+
process.kill(pid, 0);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
153
|
+
return false;
|
|
154
|
+
} });
|
|
155
|
+
const killGroup = this.deps.killGroup ?? ((pgid) => { try {
|
|
156
|
+
process.kill(-pgid, 'SIGKILL');
|
|
157
|
+
}
|
|
158
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */ /* best-effort */ } });
|
|
159
|
+
// A pid-less record = attempt-of-unknown-outcome (crash between phase 1 and 2).
|
|
160
|
+
if (record.pid === null || record.pgid === null) {
|
|
161
|
+
const cleared = await this.reverifyAndClear(record);
|
|
162
|
+
return { reaped: true, outcome: cleared };
|
|
163
|
+
}
|
|
164
|
+
if (isAlive(record.pid)) {
|
|
165
|
+
// Verify identity before signalling (pid-reuse safe): the live process must
|
|
166
|
+
// carry our attempt token. If we cannot confirm identity, do NOT kill an
|
|
167
|
+
// unrelated process — surface orphan-reap-incomplete and re-verify PR state.
|
|
168
|
+
const identityOk = this.verifyAttemptToken(record.pid, record.attemptToken);
|
|
169
|
+
if (identityOk) {
|
|
170
|
+
killGroup(record.pgid);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
this.log(`orphan pid ${record.pid} identity unconfirmed — not signalling (orphan-reap-incomplete)`);
|
|
174
|
+
// Leave the record; re-verify PR state so a completed merge is recorded.
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const outcome = await this.reverifyAndClear(record);
|
|
178
|
+
return { reaped: true, outcome };
|
|
179
|
+
}
|
|
180
|
+
async reverifyAndClear(record) {
|
|
181
|
+
let outcome = 'unknown';
|
|
182
|
+
try {
|
|
183
|
+
const st = await this.deps.prState(record.pr, record.repo);
|
|
184
|
+
outcome = st === 'MERGED' ? 'merged-by-other' : st === 'CLOSED' ? 'closed-by-other' : 'reaped-open';
|
|
185
|
+
}
|
|
186
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
187
|
+
outcome = 'reaped-unverified';
|
|
188
|
+
}
|
|
189
|
+
this.clearInFlight();
|
|
190
|
+
return outcome;
|
|
191
|
+
}
|
|
192
|
+
/** Best-effort identity check: does the live pid's argv carry our token? */
|
|
193
|
+
verifyAttemptToken(pid, token) {
|
|
194
|
+
// On Linux, /proc/<pid>/environ carries the token. On other platforms we
|
|
195
|
+
// cannot cheaply confirm — be conservative (return false → do not kill).
|
|
196
|
+
try {
|
|
197
|
+
const environ = fs.readFileSync(`/proc/${pid}/environ`, 'utf-8');
|
|
198
|
+
return environ.includes(`GREEN_PR_ATTEMPT_TOKEN=${token}`);
|
|
199
|
+
}
|
|
200
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ---- durable in-flight record ------------------------------------------
|
|
205
|
+
inFlightPath() {
|
|
206
|
+
return path.join(this.cfg.stateDir, 'state', 'green-pr-automerge-inflight.json');
|
|
207
|
+
}
|
|
208
|
+
writeInFlight(record) {
|
|
209
|
+
const p = this.inFlightPath();
|
|
210
|
+
try {
|
|
211
|
+
const dir = path.dirname(p);
|
|
212
|
+
if (!fs.existsSync(dir))
|
|
213
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
214
|
+
const tmp = p + '.tmp';
|
|
215
|
+
fs.writeFileSync(tmp, JSON.stringify(record), { mode: 0o600 });
|
|
216
|
+
fs.renameSync(tmp, p);
|
|
217
|
+
}
|
|
218
|
+
catch (e) { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
219
|
+
this.log(`in-flight write failed: ${e?.message}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
readInFlight() {
|
|
223
|
+
try {
|
|
224
|
+
const raw = fs.readFileSync(this.inFlightPath(), 'utf-8');
|
|
225
|
+
const obj = JSON.parse(raw);
|
|
226
|
+
if (typeof obj.pr === 'number' && typeof obj.attemptToken === 'string')
|
|
227
|
+
return obj;
|
|
228
|
+
}
|
|
229
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */ /* none */ }
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
clearInFlight() {
|
|
233
|
+
try {
|
|
234
|
+
SafeFsExecutor.safeRmSync(this.inFlightPath(), { force: true, operation: 'merge-runner:clear-in-flight' });
|
|
235
|
+
}
|
|
236
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */ /* best-effort */ }
|
|
237
|
+
}
|
|
238
|
+
// ---- spawn seam ---------------------------------------------------------
|
|
239
|
+
spawn(a) {
|
|
240
|
+
if (this.deps.spawn)
|
|
241
|
+
return this.deps.spawn(a);
|
|
242
|
+
return defaultSpawn(a);
|
|
243
|
+
}
|
|
244
|
+
log(msg) {
|
|
245
|
+
this.deps.logger?.(`[merge-runner] ${msg}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/** Parse safe-merge's classified `safe-merge-result: {...}` line from stdout. */
|
|
249
|
+
export function parseResultLine(stdout) {
|
|
250
|
+
const lines = stdout.split('\n');
|
|
251
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
252
|
+
const m = lines[i].match(/safe-merge-result:\s*(\{.*\})/);
|
|
253
|
+
if (m) {
|
|
254
|
+
try {
|
|
255
|
+
return String(JSON.parse(m[1]).result);
|
|
256
|
+
}
|
|
257
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
/** Real spawn: detached (own process group) + deadline hard-kill of the group. */
|
|
265
|
+
function defaultSpawn(a) {
|
|
266
|
+
return new Promise((resolve) => {
|
|
267
|
+
const child = realSpawn(a.command, a.args, { env: a.env, detached: true });
|
|
268
|
+
if (child.pid && a.onPid)
|
|
269
|
+
a.onPid(child.pid);
|
|
270
|
+
let stdout = '';
|
|
271
|
+
let stderr = '';
|
|
272
|
+
let deadlineKilled = false;
|
|
273
|
+
child.stdout?.on('data', (d) => { stdout += d.toString(); });
|
|
274
|
+
child.stderr?.on('data', (d) => { stderr += d.toString(); });
|
|
275
|
+
const timer = setTimeout(() => {
|
|
276
|
+
deadlineKilled = true;
|
|
277
|
+
if (child.pid) {
|
|
278
|
+
try {
|
|
279
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
280
|
+
}
|
|
281
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */ /* best-effort */ }
|
|
282
|
+
}
|
|
283
|
+
}, a.deadlineMs);
|
|
284
|
+
if (typeof timer.unref === 'function')
|
|
285
|
+
timer.unref();
|
|
286
|
+
child.on('close', (status, signal) => {
|
|
287
|
+
clearTimeout(timer);
|
|
288
|
+
resolve({ stdout, stderr, status: status ?? null, signal: signal ?? null, deadlineKilled, pid: child.pid ?? null });
|
|
289
|
+
});
|
|
290
|
+
child.on('error', () => {
|
|
291
|
+
clearTimeout(timer);
|
|
292
|
+
resolve({ stdout, stderr, status: null, signal: null, deadlineKilled, pid: child.pid ?? null });
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=MergeRunner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MergeRunner.js","sourceRoot":"","sources":["../../src/monitoring/MergeRunner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* floorDriftCanary — verifies the code-pinned required-contexts floor still
|
|
3
|
+
* matches reality, so a renamed workflow / split job / changed app slug surfaces
|
|
4
|
+
* as `floor-drift` instead of turning the watcher into a silent permanent
|
|
5
|
+
* refuser (green-pr-automerge-enforcement R8, L5(b)/P18). Observe-only.
|
|
6
|
+
*
|
|
7
|
+
* Per-family references (round-6 — the round-5 single-reference design was
|
|
8
|
+
* structurally unsatisfiable): the pinned floor mixes PR-triggered gates (eli16,
|
|
9
|
+
* decision-audit) whose runs attach to PR HEAD shas, never default-branch
|
|
10
|
+
* commits, and push-triggered contexts (CI suite) that DO run on main. So:
|
|
11
|
+
* - PR-triggered floor contexts validate against the head shas of recently
|
|
12
|
+
* MERGED agent-namespace PRs (newest-qualifying-wins).
|
|
13
|
+
* - push-triggered contexts validate against the most recent default-branch
|
|
14
|
+
* commit qualified INDEPENDENTLY of the pinned set (any completed non-skip-ci
|
|
15
|
+
* runs present — qualifying ON the pinned set would let a rename hide).
|
|
16
|
+
* No qualifying reference within a family's bound → `floor-drift-unverifiable`
|
|
17
|
+
* (distinct from `floor-drift`: "couldn't check" never wears the "drifted" label).
|
|
18
|
+
*
|
|
19
|
+
* All gh I/O is injected so this is unit-testable without the network.
|
|
20
|
+
*/
|
|
21
|
+
export interface FloorPin {
|
|
22
|
+
context: string;
|
|
23
|
+
workflowPath: string;
|
|
24
|
+
appSlug: string;
|
|
25
|
+
/** Which event the producing workflow fires on. */
|
|
26
|
+
trigger: 'pull_request' | 'push';
|
|
27
|
+
}
|
|
28
|
+
/** A completed check run on some commit (own + producer identity). */
|
|
29
|
+
export interface ReferenceCheckRun {
|
|
30
|
+
name: string;
|
|
31
|
+
conclusion: string;
|
|
32
|
+
appSlug: string | null;
|
|
33
|
+
workflowPath: string | null;
|
|
34
|
+
}
|
|
35
|
+
/** A candidate reference: a commit/head sha plus its completed check runs. */
|
|
36
|
+
export interface ReferenceCandidate {
|
|
37
|
+
sha: string;
|
|
38
|
+
checkRuns: ReferenceCheckRun[];
|
|
39
|
+
}
|
|
40
|
+
export interface FloorDriftDeps {
|
|
41
|
+
/**
|
|
42
|
+
* Recently MERGED agent-namespace PR heads, newest-first, bounded by
|
|
43
|
+
* `floorDriftLookbackPrs`. Each carries that head's completed check runs.
|
|
44
|
+
*/
|
|
45
|
+
recentMergedPrRefs(limit: number): Promise<ReferenceCandidate[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Recent default-branch commits, newest-first, bounded by
|
|
48
|
+
* `floorDriftLookbackCommits`, each with its completed check runs.
|
|
49
|
+
*/
|
|
50
|
+
recentDefaultBranchRefs(limit: number): Promise<ReferenceCandidate[]>;
|
|
51
|
+
}
|
|
52
|
+
export interface FloorDriftConfig {
|
|
53
|
+
floorDriftLookbackPrs: number;
|
|
54
|
+
floorDriftLookbackCommits: number;
|
|
55
|
+
}
|
|
56
|
+
export type FloorDriftClass = 'ok' | 'floor-drift' | 'floor-drift-unverifiable';
|
|
57
|
+
export interface FloorDriftFinding {
|
|
58
|
+
context: string;
|
|
59
|
+
cls: FloorDriftClass;
|
|
60
|
+
detail?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface FloorDriftResult {
|
|
63
|
+
findings: FloorDriftFinding[];
|
|
64
|
+
drifted: FloorDriftFinding[];
|
|
65
|
+
unverifiable: FloorDriftFinding[];
|
|
66
|
+
}
|
|
67
|
+
/** Does this candidate "qualify" as a reference for a push-triggered family? */
|
|
68
|
+
export declare function qualifiesAsPushReference(c: ReferenceCandidate): boolean;
|
|
69
|
+
/** A PR head qualifies as a PR-family reference if it carries any completed runs. */
|
|
70
|
+
export declare function qualifiesAsPrReference(c: ReferenceCandidate): boolean;
|
|
71
|
+
/** Is the pin satisfied at this reference (name + producer binding)? */
|
|
72
|
+
export declare function pinSatisfiedAt(pin: FloorPin, ref: ReferenceCandidate): boolean;
|
|
73
|
+
export declare class FloorDriftCanary {
|
|
74
|
+
private readonly pins;
|
|
75
|
+
private readonly deps;
|
|
76
|
+
private readonly cfg;
|
|
77
|
+
constructor(pins: FloorPin[], deps: FloorDriftDeps, cfg: FloorDriftConfig);
|
|
78
|
+
check(): Promise<FloorDriftResult>;
|
|
79
|
+
/**
|
|
80
|
+
* Newest-qualifying-wins (round-7 build note): walk references newest-first;
|
|
81
|
+
* the FIRST that qualifies is authoritative. If it satisfies the pin → ok;
|
|
82
|
+
* else → floor-drift. If NO reference in the bound qualifies →
|
|
83
|
+
* floor-drift-unverifiable (never floor-drift).
|
|
84
|
+
*/
|
|
85
|
+
private evaluate;
|
|
86
|
+
private safe;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=floorDriftCanary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floorDriftCanary.d.ts","sourceRoot":"","sources":["../../src/monitoring/floorDriftCanary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,OAAO,EAAE,cAAc,GAAG,MAAM,CAAC;CAClC;AAED,sEAAsE;AACtE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,8EAA8E;AAC9E,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACjE;;;OAGG;IACH,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,gBAAgB;IAC/B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,aAAa,GAAG,0BAA0B,CAAC;AAEhF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,eAAe,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,YAAY,EAAE,iBAAiB,EAAE,CAAC;CACnC;AAED,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAIvE;AAED,qFAAqF;AACrF,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAErE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAM9E;AAED,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAFH,IAAI,EAAE,QAAQ,EAAE,EAChB,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,gBAAgB;IAGlC,KAAK,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAkBxC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;YAUF,IAAI;CAGnB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* floorDriftCanary — verifies the code-pinned required-contexts floor still
|
|
3
|
+
* matches reality, so a renamed workflow / split job / changed app slug surfaces
|
|
4
|
+
* as `floor-drift` instead of turning the watcher into a silent permanent
|
|
5
|
+
* refuser (green-pr-automerge-enforcement R8, L5(b)/P18). Observe-only.
|
|
6
|
+
*
|
|
7
|
+
* Per-family references (round-6 — the round-5 single-reference design was
|
|
8
|
+
* structurally unsatisfiable): the pinned floor mixes PR-triggered gates (eli16,
|
|
9
|
+
* decision-audit) whose runs attach to PR HEAD shas, never default-branch
|
|
10
|
+
* commits, and push-triggered contexts (CI suite) that DO run on main. So:
|
|
11
|
+
* - PR-triggered floor contexts validate against the head shas of recently
|
|
12
|
+
* MERGED agent-namespace PRs (newest-qualifying-wins).
|
|
13
|
+
* - push-triggered contexts validate against the most recent default-branch
|
|
14
|
+
* commit qualified INDEPENDENTLY of the pinned set (any completed non-skip-ci
|
|
15
|
+
* runs present — qualifying ON the pinned set would let a rename hide).
|
|
16
|
+
* No qualifying reference within a family's bound → `floor-drift-unverifiable`
|
|
17
|
+
* (distinct from `floor-drift`: "couldn't check" never wears the "drifted" label).
|
|
18
|
+
*
|
|
19
|
+
* All gh I/O is injected so this is unit-testable without the network.
|
|
20
|
+
*/
|
|
21
|
+
/** Does this candidate "qualify" as a reference for a push-triggered family? */
|
|
22
|
+
export function qualifiesAsPushReference(c) {
|
|
23
|
+
// Any completed (non-skip-ci) check runs present — qualified INDEPENDENTLY of
|
|
24
|
+
// the pinned set, so a rename can still be observed as a mismatch.
|
|
25
|
+
return c.checkRuns.some((r) => r.conclusion && r.conclusion !== 'skipped' && r.conclusion !== 'neutral');
|
|
26
|
+
}
|
|
27
|
+
/** A PR head qualifies as a PR-family reference if it carries any completed runs. */
|
|
28
|
+
export function qualifiesAsPrReference(c) {
|
|
29
|
+
return c.checkRuns.some((r) => !!r.conclusion);
|
|
30
|
+
}
|
|
31
|
+
/** Is the pin satisfied at this reference (name + producer binding)? */
|
|
32
|
+
export function pinSatisfiedAt(pin, ref) {
|
|
33
|
+
return ref.checkRuns.some((r) => r.name === pin.context &&
|
|
34
|
+
String(r.conclusion).toLowerCase() === 'success' &&
|
|
35
|
+
(!pin.appSlug || r.appSlug === pin.appSlug) &&
|
|
36
|
+
(!pin.workflowPath || r.workflowPath === pin.workflowPath));
|
|
37
|
+
}
|
|
38
|
+
export class FloorDriftCanary {
|
|
39
|
+
pins;
|
|
40
|
+
deps;
|
|
41
|
+
cfg;
|
|
42
|
+
constructor(pins, deps, cfg) {
|
|
43
|
+
this.pins = pins;
|
|
44
|
+
this.deps = deps;
|
|
45
|
+
this.cfg = cfg;
|
|
46
|
+
}
|
|
47
|
+
async check() {
|
|
48
|
+
const prTriggered = this.pins.filter((p) => p.trigger === 'pull_request');
|
|
49
|
+
const pushTriggered = this.pins.filter((p) => p.trigger === 'push');
|
|
50
|
+
const prRefs = prTriggered.length > 0 ? await this.safe(() => this.deps.recentMergedPrRefs(this.cfg.floorDriftLookbackPrs)) : [];
|
|
51
|
+
const pushRefs = pushTriggered.length > 0 ? await this.safe(() => this.deps.recentDefaultBranchRefs(this.cfg.floorDriftLookbackCommits)) : [];
|
|
52
|
+
const findings = [];
|
|
53
|
+
for (const pin of prTriggered)
|
|
54
|
+
findings.push(this.evaluate(pin, prRefs, qualifiesAsPrReference));
|
|
55
|
+
for (const pin of pushTriggered)
|
|
56
|
+
findings.push(this.evaluate(pin, pushRefs, qualifiesAsPushReference));
|
|
57
|
+
return {
|
|
58
|
+
findings,
|
|
59
|
+
drifted: findings.filter((f) => f.cls === 'floor-drift'),
|
|
60
|
+
unverifiable: findings.filter((f) => f.cls === 'floor-drift-unverifiable'),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Newest-qualifying-wins (round-7 build note): walk references newest-first;
|
|
65
|
+
* the FIRST that qualifies is authoritative. If it satisfies the pin → ok;
|
|
66
|
+
* else → floor-drift. If NO reference in the bound qualifies →
|
|
67
|
+
* floor-drift-unverifiable (never floor-drift).
|
|
68
|
+
*/
|
|
69
|
+
evaluate(pin, refs, qualifies) {
|
|
70
|
+
for (const ref of refs) {
|
|
71
|
+
if (!qualifies(ref))
|
|
72
|
+
continue;
|
|
73
|
+
// First qualifying reference is authoritative (newest-wins).
|
|
74
|
+
if (pinSatisfiedAt(pin, ref))
|
|
75
|
+
return { context: pin.context, cls: 'ok' };
|
|
76
|
+
return { context: pin.context, cls: 'floor-drift', detail: `pinned ${pin.context} (${pin.appSlug} ${pin.workflowPath}) not satisfied at ${ref.sha.slice(0, 12)}` };
|
|
77
|
+
}
|
|
78
|
+
return { context: pin.context, cls: 'floor-drift-unverifiable', detail: `no qualifying reference within the lookback bound` };
|
|
79
|
+
}
|
|
80
|
+
async safe(fn) {
|
|
81
|
+
try {
|
|
82
|
+
return await fn();
|
|
83
|
+
}
|
|
84
|
+
catch { /* @silent-fallback-ok: green-pr-automerge fail-safe — skip/refuse, never over-merge; safe-merge is the act-time authority */
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=floorDriftCanary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floorDriftCanary.js","sourceRoot":"","sources":["../../src/monitoring/floorDriftCanary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* greenPrAutomergeWiring — builds the real gh / fs / lease / latch dependencies
|
|
3
|
+
* for the GreenPrAutoMerger (green-pr-automerge-enforcement). Extracted from
|
|
4
|
+
* server.ts so the dependency construction is itself unit-testable (Testing
|
|
5
|
+
* Integrity: wiring-integrity tests prove deps are real, not nulls/no-ops).
|
|
6
|
+
*
|
|
7
|
+
* Repo-gated: the watcher only runs in the dev/maintainer environment where an
|
|
8
|
+
* analyzable instar git repo AND scripts/safe-merge.mjs are present. On a plain
|
|
9
|
+
* npm install both are absent → the server constructs nothing → routes 503.
|
|
10
|
+
*
|
|
11
|
+
* All gh goes through `execFile` (no shell). The list query is pinned oldest-first
|
|
12
|
+
* server-side. Identity (R4) is `gh api user`. Audit is one JSONL line per
|
|
13
|
+
* transition. State is per-machine (machine-local BY DESIGN).
|
|
14
|
+
*
|
|
15
|
+
* RULE 3.1 RATIONALE
|
|
16
|
+
* Criticality: high — these adapters surface the PR/identity/protected-paths
|
|
17
|
+
* state the merge watcher acts on.
|
|
18
|
+
* Frequency: per-tick (≤ once per ~10-minute interval).
|
|
19
|
+
* Stability: stable — every read uses `gh ... --json`/`gh api --jq`
|
|
20
|
+
* STRUCTURED output, never regex over human gh text.
|
|
21
|
+
* Fallback: a failing/unparseable list call THROWS (→ the watcher's
|
|
22
|
+
* tick-failed canary feeds the breaker); protectedPaths failure →
|
|
23
|
+
* `unverifiable:true` (→ skip, never merge); identity unresolved →
|
|
24
|
+
* skip. Every path fails toward NOT merging.
|
|
25
|
+
* Verdict: deterministic; safe-merge re-verifies at act time, so a misread
|
|
26
|
+
* here can only cause a refusal, never an unintended merge.
|
|
27
|
+
*/
|
|
28
|
+
import { GuardLatchStore, type GuardLatchEntry } from './GuardLatchStore.js';
|
|
29
|
+
import { type GreenPrAutoMergerDeps } from './GreenPrAutoMerger.js';
|
|
30
|
+
/** Protected globs (round-4/6): a PR touching these never auto-merges. */
|
|
31
|
+
export declare const PROTECTED_PATH_PREFIXES: string[];
|
|
32
|
+
/** Gate scripts the floor contexts execute (extend, never shrink). */
|
|
33
|
+
export declare const PROTECTED_GATE_SCRIPTS: string[];
|
|
34
|
+
export declare function isAnalyzableGreenPrRepo(repoPath: string, safeMergePath: string): boolean;
|
|
35
|
+
/** Does any changed file touch a protected path? */
|
|
36
|
+
export declare function diffTouchesProtected(files: string[]): boolean;
|
|
37
|
+
export interface GreenPrWiringOpts {
|
|
38
|
+
repoPath: string;
|
|
39
|
+
safeMergePath: string;
|
|
40
|
+
stateDir: string;
|
|
41
|
+
machineId: string;
|
|
42
|
+
repo: string;
|
|
43
|
+
agentNamespace: string;
|
|
44
|
+
mergeTimeoutMs: number;
|
|
45
|
+
mergeKillGraceMs: number;
|
|
46
|
+
/** Lease accessors (single-machine: () => true / () => 0). */
|
|
47
|
+
holdsLease: () => boolean;
|
|
48
|
+
leaseEpoch: () => number;
|
|
49
|
+
/** Merged peer guard-latch view (single-machine: () => []). */
|
|
50
|
+
readPeerLatches?: () => GuardLatchEntry[];
|
|
51
|
+
/** Replication writer (optional). */
|
|
52
|
+
journal?: {
|
|
53
|
+
emitGuardLatch: (d: Record<string, unknown>) => void;
|
|
54
|
+
};
|
|
55
|
+
/** Attention sink — raise/refresh the ONE aggregated item. */
|
|
56
|
+
postAttentionAggregate: (lines: string[]) => Promise<void>;
|
|
57
|
+
auditPath: string;
|
|
58
|
+
now?: () => number;
|
|
59
|
+
logger?: (msg: string) => void;
|
|
60
|
+
/** Test seam: override the gh exec. */
|
|
61
|
+
ghExec?: (args: string[]) => Promise<{
|
|
62
|
+
stdout: string;
|
|
63
|
+
stderr: string;
|
|
64
|
+
code: number;
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
/** Build the GuardLatchStore for this install. */
|
|
68
|
+
export declare function buildGuardLatchStore(opts: GreenPrWiringOpts): GuardLatchStore;
|
|
69
|
+
/** Build the full GreenPrAutoMerger deps (real gh adapters). */
|
|
70
|
+
export declare function buildGreenPrDeps(opts: GreenPrWiringOpts, latches: GuardLatchStore): GreenPrAutoMergerDeps;
|
|
71
|
+
/** Derive a single SUCCESS|PENDING|FAILURE from the statusCheckRollup array. */
|
|
72
|
+
export declare function deriveRollup(rollup: unknown): string | null;
|
|
73
|
+
//# sourceMappingURL=greenPrAutomergeWiring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"greenPrAutomergeWiring.d.ts","sourceRoot":"","sources":["../../src/monitoring/greenPrAutomergeWiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE7E,OAAO,EACL,KAAK,qBAAqB,EAI3B,MAAM,wBAAwB,CAAC;AAGhC,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,UASnC,CAAC;AACF,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,UAElC,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAMxF;AAED,oDAAoD;AACpD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAE7D;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,8DAA8D;IAC9D,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,UAAU,EAAE,MAAM,MAAM,CAAC;IACzB,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,eAAe,EAAE,CAAC;IAC1C,qCAAqC;IACrC,OAAO,CAAC,EAAE;QAAE,cAAc,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;KAAE,CAAC;IACnE,8DAA8D;IAC9D,sBAAsB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,uCAAuC;IACvC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxF;AAUD,kDAAkD;AAClD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,eAAe,CAU7E;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,eAAe,GAAG,qBAAqB,CA6HzG;AAiBD,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAW3D"}
|