sela-core 0.1.0-alpha.45 → 0.1.0-alpha.47
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/config/ConfigLoader.d.ts +3 -4
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +35 -30
- package/dist/config/HealingGovernance.d.ts.map +1 -1
- package/dist/config/HealingGovernance.js +46 -7
- package/dist/config/SelaConfig.d.ts +54 -28
- package/dist/config/SelaConfig.d.ts.map +1 -1
- package/dist/config/SelaConfig.js +38 -4
- package/dist/engine/HealingRegistry.d.ts +8 -2
- package/dist/engine/HealingRegistry.d.ts.map +1 -1
- package/dist/engine/HealingRegistry.js +20 -7
- package/dist/engine/SelaEngine.d.ts +8 -0
- package/dist/engine/SelaEngine.d.ts.map +1 -1
- package/dist/engine/SelaEngine.js +89 -60
- package/dist/engine/lifecycle/SelaLifecycleStateManager.d.ts +10 -0
- package/dist/engine/lifecycle/SelaLifecycleStateManager.d.ts.map +1 -1
- package/dist/engine/lifecycle/SelaLifecycleStateManager.js +26 -8
- package/dist/errors/FailureClassifier.d.ts +20 -0
- package/dist/errors/FailureClassifier.d.ts.map +1 -1
- package/dist/errors/FailureClassifier.js +77 -12
- package/dist/errors/SelectorForensics.d.ts +13 -2
- package/dist/errors/SelectorForensics.d.ts.map +1 -1
- package/dist/errors/SelectorForensics.js +33 -3
- package/dist/fixtures/expectProxy.d.ts.map +1 -1
- package/dist/fixtures/expectProxy.js +19 -5
- package/dist/fixtures/index.d.ts +41 -1
- package/dist/fixtures/index.d.ts.map +1 -1
- package/dist/fixtures/index.js +461 -144
- package/dist/fixtures/proxyTag.d.ts +1 -1
- package/dist/fixtures/proxyTag.d.ts.map +1 -1
- package/dist/fixtures/proxyTag.js +2 -0
- package/dist/forensics/SelectorForensics.d.ts +3 -0
- package/dist/forensics/SelectorForensics.d.ts.map +1 -0
- package/dist/forensics/SelectorForensics.js +25 -0
- package/dist/heuristics/AnnotationScanner.d.ts +26 -0
- package/dist/heuristics/AnnotationScanner.d.ts.map +1 -0
- package/dist/heuristics/AnnotationScanner.js +180 -0
- package/dist/heuristics/VetoEngine.d.ts +64 -0
- package/dist/heuristics/VetoEngine.d.ts.map +1 -0
- package/dist/heuristics/VetoEngine.js +132 -0
- package/dist/reporter/SelaReporter.d.ts +4 -50
- package/dist/reporter/SelaReporter.d.ts.map +1 -1
- package/dist/reporter/SelaReporter.js +38 -262
- package/dist/services/ASTSourceUpdater.d.ts +7 -0
- package/dist/services/ASTSourceUpdater.d.ts.map +1 -1
- package/dist/services/ASTSourceUpdater.js +43 -93
- package/dist/services/AggregatorCRDT.d.ts +57 -0
- package/dist/services/AggregatorCRDT.d.ts.map +1 -0
- package/dist/services/AggregatorCRDT.js +0 -0
- package/dist/services/AnchorResolver.d.ts +10 -0
- package/dist/services/AnchorResolver.d.ts.map +1 -1
- package/dist/services/AnchorResolver.js +22 -7
- package/dist/services/ArtifactAggregator.d.ts.map +1 -1
- package/dist/services/ArtifactAggregator.js +11 -0
- package/dist/services/ArtifactNaming.d.ts +0 -31
- package/dist/services/ArtifactNaming.d.ts.map +1 -1
- package/dist/services/ArtifactNaming.js +0 -55
- package/dist/services/AtomicChainMutator.d.ts +73 -0
- package/dist/services/AtomicChainMutator.d.ts.map +1 -0
- package/dist/services/AtomicChainMutator.js +205 -0
- package/dist/services/DnaSyncService.d.ts.map +1 -1
- package/dist/services/DnaSyncService.js +46 -11
- package/dist/services/HealBudget.d.ts.map +1 -1
- package/dist/services/HealBudget.js +15 -1
- package/dist/services/HealCircuitBreaker.d.ts.map +1 -1
- package/dist/services/HealCircuitBreaker.js +16 -2
- package/dist/services/HealingCacheService.d.ts.map +1 -1
- package/dist/services/HealingCacheService.js +17 -2
- package/dist/services/LedgerAnchor.js +1 -1
- package/dist/services/MutationApplier.d.ts.map +1 -1
- package/dist/services/MutationApplier.js +26 -13
- package/dist/services/PRAutomationService.d.ts.map +1 -1
- package/dist/services/PRAutomationService.js +27 -9
- package/dist/services/ReportMergeService.d.ts.map +1 -1
- package/dist/services/ReportMergeService.js +25 -12
- package/dist/services/SafetyGuard.d.ts +1 -0
- package/dist/services/SafetyGuard.d.ts.map +1 -1
- package/dist/services/SafetyGuard.js +29 -0
- package/dist/services/SessionContext.d.ts +53 -0
- package/dist/services/SessionContext.d.ts.map +1 -0
- package/dist/services/SessionContext.js +147 -0
- package/dist/services/TestDeadline.d.ts +58 -0
- package/dist/services/TestDeadline.d.ts.map +1 -0
- package/dist/services/TestDeadline.js +112 -0
- package/dist/services/TraceBackEngine.d.ts +1 -1
- package/dist/services/TraceBackEngine.d.ts.map +1 -1
- package/dist/services/TraceBackEngine.js +78 -34
- package/dist/services/vcs/VCSProviderFactory.js +3 -3
- package/dist/utils/DOMUtils.d.ts.map +1 -1
- package/dist/utils/DOMUtils.js +13 -0
- package/dist/utils/SourceNormalizer.d.ts +67 -0
- package/dist/utils/SourceNormalizer.d.ts.map +1 -0
- package/dist/utils/SourceNormalizer.js +125 -0
- package/package.json +34 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { SelaConfig, ResolvedConfig } from "./SelaConfig";
|
|
2
2
|
export declare class ConfigLoader {
|
|
3
|
-
private static
|
|
4
|
-
private static
|
|
5
|
-
private static rawUserConfig;
|
|
3
|
+
private static readonly SESSION_SLOT;
|
|
4
|
+
private static cache;
|
|
6
5
|
/**
|
|
7
6
|
* Returns the fully resolved config. First call does all I/O; subsequent
|
|
8
7
|
* calls return the cached result at zero cost.
|
|
@@ -22,7 +21,7 @@ export declare class ConfigLoader {
|
|
|
22
21
|
private static logEnvBanners;
|
|
23
22
|
/** Returns the detected Git branch name, or null if detection failed. */
|
|
24
23
|
static getBranch(): string | null;
|
|
25
|
-
/** Clears the
|
|
24
|
+
/** Clears the session's config cache - useful for testing. */
|
|
26
25
|
static reset(): void;
|
|
27
26
|
}
|
|
28
27
|
//# sourceMappingURL=ConfigLoader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../src/config/ConfigLoader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../src/config/ConfigLoader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AA2SzE,qBAAa,YAAY;IAMvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAA0C;IAE9E,OAAO,CAAC,MAAM,CAAC,KAAK;IAQpB;;;;;;;;OAQG;IACH,MAAM,CAAC,WAAW,IAAI,cAAc;IAsCpC;;;;OAIG;IACH,MAAM,CAAC,YAAY,IAAI,UAAU;IAKjC,OAAO,CAAC,MAAM,CAAC,aAAa;IAsB5B,yEAAyE;IACzE,MAAM,CAAC,SAAS,IAAI,MAAM,GAAG,IAAI;IAKjC,8DAA8D;IAC9D,MAAM,CAAC,KAAK,IAAI,IAAI;CAMrB"}
|
|
@@ -43,6 +43,7 @@ const path = __importStar(require("path"));
|
|
|
43
43
|
const child_process_1 = require("child_process");
|
|
44
44
|
const SelaConfig_1 = require("./SelaConfig");
|
|
45
45
|
const logger_1 = require("../utils/logger");
|
|
46
|
+
const SessionContext_1 = require("../services/SessionContext");
|
|
46
47
|
// All public top-level keys of SelaConfig — used to catch typos at load time.
|
|
47
48
|
const KNOWN_CONFIG_KEYS = new Set([
|
|
48
49
|
"healingPolicy",
|
|
@@ -63,7 +64,6 @@ const KNOWN_CONFIG_KEYS = new Set([
|
|
|
63
64
|
"branchOverrides",
|
|
64
65
|
"llm",
|
|
65
66
|
"healing",
|
|
66
|
-
"reporting",
|
|
67
67
|
]);
|
|
68
68
|
// ─────────────────────────────────────────────────────────────────
|
|
69
69
|
// FILE DISCOVERY
|
|
@@ -277,17 +277,20 @@ function deepMerge(base, override) {
|
|
|
277
277
|
}
|
|
278
278
|
return result;
|
|
279
279
|
}
|
|
280
|
-
// ─────────────────────────────────────────────────────────────────
|
|
281
|
-
// SINGLETON LOADER
|
|
282
|
-
// ─────────────────────────────────────────────────────────────────
|
|
283
280
|
class ConfigLoader {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
//
|
|
287
|
-
//
|
|
288
|
-
// the
|
|
289
|
-
|
|
290
|
-
static
|
|
281
|
+
// Session-scoped resolution cache. Under a plain worker (no `runInSession`)
|
|
282
|
+
// this is the process-default session's single bundle — identical to the
|
|
283
|
+
// historical process-lifetime singleton. Under Chronos, each session resolves
|
|
284
|
+
// config against its OWN cwd/branch without a second session's resolution
|
|
285
|
+
// clobbering the first's cached bundle.
|
|
286
|
+
static SESSION_SLOT = Symbol.for("sela.session.configCache");
|
|
287
|
+
static cache() {
|
|
288
|
+
return (0, SessionContext_1.sessionSlot)(ConfigLoader.SESSION_SLOT, () => ({
|
|
289
|
+
resolved: null,
|
|
290
|
+
branch: null,
|
|
291
|
+
rawUserConfig: null,
|
|
292
|
+
}));
|
|
293
|
+
}
|
|
291
294
|
/**
|
|
292
295
|
* Returns the fully resolved config. First call does all I/O; subsequent
|
|
293
296
|
* calls return the cached result at zero cost.
|
|
@@ -298,19 +301,20 @@ class ConfigLoader {
|
|
|
298
301
|
* - `SELA_DRY_RUN` / `SELA_NO_CACHE` contain an unrecognised value.
|
|
299
302
|
*/
|
|
300
303
|
static getInstance() {
|
|
301
|
-
|
|
302
|
-
|
|
304
|
+
const cache = ConfigLoader.cache();
|
|
305
|
+
if (cache.resolved)
|
|
306
|
+
return cache.resolved;
|
|
303
307
|
const configPath = findConfigFile(process.cwd());
|
|
304
308
|
if (!configPath) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
ConfigLoader.logEnvBanners(
|
|
308
|
-
return
|
|
309
|
+
cache.rawUserConfig = {};
|
|
310
|
+
cache.resolved = (0, SelaConfig_1.resolveConfig)({});
|
|
311
|
+
ConfigLoader.logEnvBanners(cache.resolved);
|
|
312
|
+
return cache.resolved;
|
|
309
313
|
}
|
|
310
314
|
logger_1.logger.debug(`Loaded config from: ${path.relative(process.cwd(), configPath)}`);
|
|
311
315
|
let rawConfig = loadRawConfig(configPath);
|
|
312
316
|
const detectedBranch = getCurrentBranch();
|
|
313
|
-
|
|
317
|
+
cache.branch = detectedBranch;
|
|
314
318
|
if (rawConfig.branchOverrides && detectedBranch) {
|
|
315
319
|
const override = rawConfig.branchOverrides[detectedBranch];
|
|
316
320
|
if (override) {
|
|
@@ -318,10 +322,10 @@ class ConfigLoader {
|
|
|
318
322
|
rawConfig = deepMerge(rawConfig, override);
|
|
319
323
|
}
|
|
320
324
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
ConfigLoader.logEnvBanners(
|
|
324
|
-
return
|
|
325
|
+
cache.rawUserConfig = rawConfig;
|
|
326
|
+
cache.resolved = (0, SelaConfig_1.resolveConfig)(rawConfig);
|
|
327
|
+
ConfigLoader.logEnvBanners(cache.resolved);
|
|
328
|
+
return cache.resolved;
|
|
325
329
|
}
|
|
326
330
|
/**
|
|
327
331
|
* Returns the raw, pre-resolution user config (after branch-override merge).
|
|
@@ -329,9 +333,9 @@ class ConfigLoader {
|
|
|
329
333
|
* for normal reads use {@link getInstance} (resolved + defaulted).
|
|
330
334
|
*/
|
|
331
335
|
static getRawConfig() {
|
|
332
|
-
if (!ConfigLoader.resolved)
|
|
336
|
+
if (!ConfigLoader.cache().resolved)
|
|
333
337
|
ConfigLoader.getInstance();
|
|
334
|
-
return ConfigLoader.rawUserConfig ?? {};
|
|
338
|
+
return ConfigLoader.cache().rawUserConfig ?? {};
|
|
335
339
|
}
|
|
336
340
|
static logEnvBanners(resolved) {
|
|
337
341
|
if (resolved.bypass) {
|
|
@@ -350,15 +354,16 @@ class ConfigLoader {
|
|
|
350
354
|
}
|
|
351
355
|
/** Returns the detected Git branch name, or null if detection failed. */
|
|
352
356
|
static getBranch() {
|
|
353
|
-
if (!ConfigLoader.resolved)
|
|
357
|
+
if (!ConfigLoader.cache().resolved)
|
|
354
358
|
ConfigLoader.getInstance();
|
|
355
|
-
return ConfigLoader.branch;
|
|
359
|
+
return ConfigLoader.cache().branch;
|
|
356
360
|
}
|
|
357
|
-
/** Clears the
|
|
361
|
+
/** Clears the session's config cache - useful for testing. */
|
|
358
362
|
static reset() {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
363
|
+
const cache = ConfigLoader.cache();
|
|
364
|
+
cache.resolved = null;
|
|
365
|
+
cache.branch = null;
|
|
366
|
+
cache.rawUserConfig = null;
|
|
362
367
|
}
|
|
363
368
|
}
|
|
364
369
|
exports.ConfigLoader = ConfigLoader;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HealingGovernance.d.ts","sourceRoot":"","sources":["../../src/config/HealingGovernance.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"HealingGovernance.d.ts","sourceRoot":"","sources":["../../src/config/HealingGovernance.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAG1D,MAAM,MAAM,kBAAkB,GAC1B,qBAAqB,GACrB,0BAA0B,GAC1B,+BAA+B,GAC/B,gCAAgC,GAChC,uBAAuB,CAAC;AAE5B,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAsCD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAwB;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAc;IAC7C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAwC;IACxE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsC;gBAEpD,GAAG,EAAE,qBAAqB,EAAE,GAAG,GAAE,MAAsB;IA8BnE,cAAc,IAAI,OAAO;IAIzB,yDAAyD;IACzD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAUzC,2EAA2E;IAC3E,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAoCrD,oFAAoF;IACpF,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAanE,gFAAgF;IAChF,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,cAAc,GAAG,IAAI;CAyB1D;AAWD,wBAAgB,gBAAgB,IAAI,iBAAiB,GAAG,IAAI,CAQ3D;AAED,2EAA2E;AAC3E,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
|
|
@@ -55,10 +55,37 @@ const path = __importStar(require("path"));
|
|
|
55
55
|
const minimatch_1 = require("minimatch");
|
|
56
56
|
const ConfigLoader_1 = require("./ConfigLoader");
|
|
57
57
|
const PathScopeGuard_1 = require("./PathScopeGuard");
|
|
58
|
+
const logger_1 = require("../utils/logger");
|
|
58
59
|
const REGEX_LITERAL = /^\/(.+)\/$/;
|
|
59
60
|
function escapeRegExp(s) {
|
|
60
61
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
61
62
|
}
|
|
63
|
+
function sanitizeStringArray(value) {
|
|
64
|
+
return Array.isArray(value)
|
|
65
|
+
? value.filter((v) => typeof v === "string")
|
|
66
|
+
: [];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Defense-in-depth (CLAUDE.md Zero-Crash Policy): production always feeds
|
|
70
|
+
* this class a `resolveHealing()`-validated config, but the class is also
|
|
71
|
+
* constructed directly (tests, future call sites) — a missing/malformed
|
|
72
|
+
* field here must degrade gracefully, never crash the constructor. A single
|
|
73
|
+
* bad field crashing construction would otherwise take out ALL governance
|
|
74
|
+
* for that instance (see `sharedGovernance()`'s catch-to-null below), not
|
|
75
|
+
* just the one bad entry.
|
|
76
|
+
*/
|
|
77
|
+
function sanitizeHealingConfig(cfg) {
|
|
78
|
+
const c = (cfg ?? {});
|
|
79
|
+
return {
|
|
80
|
+
enabled: c.enabled ?? true,
|
|
81
|
+
exclude: sanitizeStringArray(c.exclude),
|
|
82
|
+
protectedSelectors: sanitizeStringArray(c.protectedSelectors),
|
|
83
|
+
protectedAttributes: sanitizeStringArray(c.protectedAttributes),
|
|
84
|
+
triggers: c.triggers ?? { interactionBlocked: "refuse" },
|
|
85
|
+
criticality: c.criticality ?? {},
|
|
86
|
+
annotations: c.annotations ?? true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
62
89
|
class HealingGovernance {
|
|
63
90
|
cfg;
|
|
64
91
|
cwd;
|
|
@@ -66,16 +93,25 @@ class HealingGovernance {
|
|
|
66
93
|
selectorRegexes;
|
|
67
94
|
attrLocks;
|
|
68
95
|
constructor(cfg, cwd = process.cwd()) {
|
|
69
|
-
this.cfg = cfg;
|
|
96
|
+
this.cfg = sanitizeHealingConfig(cfg);
|
|
70
97
|
this.cwd = cwd;
|
|
71
|
-
this.exactSelectors = new Set(cfg.protectedSelectors.filter((s) => !REGEX_LITERAL.test(s)));
|
|
72
|
-
this.selectorRegexes = cfg.protectedSelectors
|
|
98
|
+
this.exactSelectors = new Set(this.cfg.protectedSelectors.filter((s) => !REGEX_LITERAL.test(s)));
|
|
99
|
+
this.selectorRegexes = this.cfg.protectedSelectors
|
|
73
100
|
.map((s) => REGEX_LITERAL.exec(s))
|
|
74
101
|
.filter((m) => m !== null)
|
|
75
|
-
.map((m) =>
|
|
102
|
+
.map((m) => {
|
|
103
|
+
try {
|
|
104
|
+
return { source: m[0], re: new RegExp(m[1]) };
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
logger_1.logger.warn(`[Sela Warning]: Skipping gracefully — invalid protectedSelectors regex literal ${m[0]} (${e instanceof Error ? e.message : String(e)})`);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
.filter((entry) => entry !== null);
|
|
76
112
|
// Matches `[attr=`, `[attr~=`, `[attr^=` … — the CSS attribute anchor
|
|
77
113
|
// forms, including the getByTestId → [data-testid="…"] fixture mapping.
|
|
78
|
-
this.attrLocks = cfg.protectedAttributes.map((attr) => ({
|
|
114
|
+
this.attrLocks = this.cfg.protectedAttributes.map((attr) => ({
|
|
79
115
|
attr,
|
|
80
116
|
re: new RegExp(`\\[\\s*${escapeRegExp(attr)}\\s*[*^$~|]?=`, "i"),
|
|
81
117
|
}));
|
|
@@ -144,7 +180,10 @@ class HealingGovernance {
|
|
|
144
180
|
testOptedOut(info) {
|
|
145
181
|
if (!this.cfg.annotations)
|
|
146
182
|
return null;
|
|
147
|
-
const
|
|
183
|
+
const safeInfo = info ?? {};
|
|
184
|
+
const annotations = Array.isArray(safeInfo.annotations) ? safeInfo.annotations : [];
|
|
185
|
+
const tags = Array.isArray(safeInfo.tags) ? safeInfo.tags : [];
|
|
186
|
+
const annotated = annotations.some((a) => a?.type === "sela" &&
|
|
148
187
|
typeof a.description === "string" &&
|
|
149
188
|
/\bno-?heal\b/i.test(a.description));
|
|
150
189
|
if (annotated) {
|
|
@@ -153,7 +192,7 @@ class HealingGovernance {
|
|
|
153
192
|
reason: "test carries annotation { type: 'sela', description: 'no-heal' }",
|
|
154
193
|
};
|
|
155
194
|
}
|
|
156
|
-
if (
|
|
195
|
+
if (tags.includes("@sela-no-heal")) {
|
|
157
196
|
return {
|
|
158
197
|
kind: "GOVERNANCE_ANNOTATION",
|
|
159
198
|
reason: "test is tagged @sela-no-heal",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type ReportMode } from "../services/ArtifactNaming";
|
|
2
1
|
export type PRStrategy = "directCommit" | "pr" | "draftPR" | "readOnly";
|
|
3
2
|
export type BugAction = "failCI" | "createIssue" | "labelOnly";
|
|
4
3
|
export interface SelaPRAutomationConfig {
|
|
@@ -155,27 +154,9 @@ export interface SelaHealingConfig {
|
|
|
155
154
|
/** Honor `@sela-no-heal` tags / `{ type:'sela' }` annotations. Default true. */
|
|
156
155
|
annotations?: boolean;
|
|
157
156
|
}
|
|
158
|
-
/**
|
|
159
|
-
* Two-Phase Reporting (RFC: docs/rfc-two-phase-reporting.md).
|
|
160
|
-
* Controls WHEN the HTML report + git/PR flow execute.
|
|
161
|
-
*/
|
|
162
|
-
export interface SelaReportingConfig {
|
|
163
|
-
/**
|
|
164
|
-
* - 'auto' (default): local runs and single-machine CI stay eager
|
|
165
|
-
* (report + PR flow in the reporter's onEnd); CI runs with a shard
|
|
166
|
-
* signal (`--shard=N/M` or `SELA_SHARD_ID`) defer to the fan-in job.
|
|
167
|
-
* - 'eager': always finalize in onEnd (legacy behavior).
|
|
168
|
-
* - 'deferred': onEnd only emits raw JSON artifacts under `.sela/artifacts/`;
|
|
169
|
-
* `sela report generate` + `sela pr generate` own the fan-in.
|
|
170
|
-
* Env `SELA_REPORT_MODE` overrides this value.
|
|
171
|
-
*/
|
|
172
|
-
mode?: ReportMode;
|
|
173
|
-
}
|
|
174
157
|
export interface SelaConfig {
|
|
175
158
|
/** Shorthand preset that expands to concrete threshold values. */
|
|
176
159
|
healingPolicy?: "conservative" | "balanced" | "aggressive";
|
|
177
|
-
/** Two-phase reporting mode (Allure pattern). Default: { mode: 'auto' }. */
|
|
178
|
-
reporting?: SelaReportingConfig;
|
|
179
160
|
/** Fine-grained threshold overrides. Explicit values always win over preset expansion. */
|
|
180
161
|
thresholds?: {
|
|
181
162
|
/** Minimum AI confidence to attempt a heal. Default: 85. Maps to CONFIDENCE_HARD_STOP. */
|
|
@@ -296,6 +277,40 @@ export interface SelaConfig {
|
|
|
296
277
|
* env vars (backward-compatible with all existing setups).
|
|
297
278
|
*/
|
|
298
279
|
llm?: LLMConfig;
|
|
280
|
+
/**
|
|
281
|
+
* Deadline-aware healing timing (RFC timing-interception). Controls the
|
|
282
|
+
* first-attempt budget tightening near the test deadline (Mechanism A) and
|
|
283
|
+
* the anti-guillotine test-timeout extension that buys healing runway
|
|
284
|
+
* (Mechanism B). Omit for the defaults; all fields are individually
|
|
285
|
+
* overridable and the whole feature is kill-switchable via SELA_TIMING_DISABLE.
|
|
286
|
+
*/
|
|
287
|
+
timing?: SelaTimingConfig;
|
|
288
|
+
}
|
|
289
|
+
/** Deadline-aware healing timing (RFC timing-interception §8). */
|
|
290
|
+
export interface SelaTimingConfig {
|
|
291
|
+
/**
|
|
292
|
+
* Extend the running test's total timeout when a heal begins, so DOM
|
|
293
|
+
* extraction + LLM + verified retry complete before the native guillotine.
|
|
294
|
+
* Default: true.
|
|
295
|
+
*/
|
|
296
|
+
extendTestTimeout?: boolean;
|
|
297
|
+
/**
|
|
298
|
+
* Safety margin (ms) subtracted from the remaining test time when Sela
|
|
299
|
+
* tightens the first-attempt budget, guaranteeing the action fails — handing
|
|
300
|
+
* control to the heal pipeline — strictly BEFORE the page is torn down.
|
|
301
|
+
* Default: 2000.
|
|
302
|
+
*/
|
|
303
|
+
deadlineBufferMs?: number;
|
|
304
|
+
/** Milliseconds of fresh runway added to the test timeout per heal. Default: 30000. */
|
|
305
|
+
healRunwayMs?: number;
|
|
306
|
+
/**
|
|
307
|
+
* Floor (ms) below which the first-attempt budget is never tightened — keeps
|
|
308
|
+
* auto-wait able to distinguish "slow to appear" from "genuinely gone".
|
|
309
|
+
* Default: 1000.
|
|
310
|
+
*/
|
|
311
|
+
minActionFloorMs?: number;
|
|
312
|
+
/** Max test-timeout extensions per test (bounds a multi-heal test). Default: 3. */
|
|
313
|
+
maxExtensionsPerTest?: number;
|
|
299
314
|
}
|
|
300
315
|
export interface ResolvedVectorThresholds {
|
|
301
316
|
/** Minimum DNA Architectural Match score (0–100). null = disabled. */
|
|
@@ -368,17 +383,8 @@ export interface ResolvedPlaywrightRules {
|
|
|
368
383
|
testIdAttribute: string;
|
|
369
384
|
preferGetByRoleOverCss: boolean;
|
|
370
385
|
}
|
|
371
|
-
export interface ResolvedReporting {
|
|
372
|
-
/**
|
|
373
|
-
* The CONFIGURED mode after the `SELA_REPORT_MODE` env override. `auto` is
|
|
374
|
-
* collapsed into eager/deferred at the reporter layer, where the Playwright
|
|
375
|
-
* shard signal is known (see ArtifactNaming.resolveEffectiveReportMode).
|
|
376
|
-
*/
|
|
377
|
-
mode: ReportMode;
|
|
378
|
-
}
|
|
379
386
|
export interface ResolvedConfig {
|
|
380
387
|
thresholds: ResolvedThresholds;
|
|
381
|
-
reporting: ResolvedReporting;
|
|
382
388
|
updateStrategy: "inPlace" | "commentOnly" | "branch";
|
|
383
389
|
autoCommit: boolean;
|
|
384
390
|
dnaStoragePath: string;
|
|
@@ -448,6 +454,18 @@ export interface ResolvedConfig {
|
|
|
448
454
|
* `undefined` when not set.
|
|
449
455
|
*/
|
|
450
456
|
regressionManifestPath: string | undefined;
|
|
457
|
+
/** Resolved deadline-aware healing timing (always defaulted). */
|
|
458
|
+
timing: ResolvedTiming;
|
|
459
|
+
}
|
|
460
|
+
/** Resolved deadline-aware healing timing (RFC timing-interception §8). */
|
|
461
|
+
export interface ResolvedTiming {
|
|
462
|
+
/** Master switch. `false` (via SELA_TIMING_DISABLE) ⇒ pure legacy pass-through. */
|
|
463
|
+
enabled: boolean;
|
|
464
|
+
extendTestTimeout: boolean;
|
|
465
|
+
deadlineBufferMs: number;
|
|
466
|
+
healRunwayMs: number;
|
|
467
|
+
minActionFloorMs: number;
|
|
468
|
+
maxExtensionsPerTest: number;
|
|
451
469
|
}
|
|
452
470
|
export declare function resolveThresholds(config: SelaConfig): ResolvedThresholds;
|
|
453
471
|
export declare function parseEnvBoolean(varName: string, rawValue: string | undefined): boolean;
|
|
@@ -470,6 +488,14 @@ export declare function resolveSmartPrune(configValue: boolean | undefined, envV
|
|
|
470
488
|
* Trust-Engine refusal semantics. undefined => 5000.
|
|
471
489
|
*/
|
|
472
490
|
export declare function resolveLargeDomNodeThreshold(value: number | undefined): number;
|
|
491
|
+
/**
|
|
492
|
+
* Resolves deadline-aware healing timing. Env wins over config. A positive-
|
|
493
|
+
* integer env override is required for the numeric knobs (fail-fast on
|
|
494
|
+
* garbage, mirroring resolveLargeDomNodeThreshold). Master kill switch:
|
|
495
|
+
* SELA_TIMING_DISABLE=true ⇒ enabled:false ⇒ the proxy stays pure legacy
|
|
496
|
+
* pass-through (no injection, no extension).
|
|
497
|
+
*/
|
|
498
|
+
export declare function resolveTiming(config: SelaConfig, env?: NodeJS.ProcessEnv): ResolvedTiming;
|
|
473
499
|
export interface ResolvedHealingConfig {
|
|
474
500
|
enabled: boolean;
|
|
475
501
|
exclude: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelaConfig.d.ts","sourceRoot":"","sources":["../../src/config/SelaConfig.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SelaConfig.d.ts","sourceRoot":"","sources":["../../src/config/SelaConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,9 +7,9 @@ exports.parseEnvBoolean = parseEnvBoolean;
|
|
|
7
7
|
exports.resolveMaxHealsPerRun = resolveMaxHealsPerRun;
|
|
8
8
|
exports.resolveSmartPrune = resolveSmartPrune;
|
|
9
9
|
exports.resolveLargeDomNodeThreshold = resolveLargeDomNodeThreshold;
|
|
10
|
+
exports.resolveTiming = resolveTiming;
|
|
10
11
|
exports.resolveHealing = resolveHealing;
|
|
11
12
|
exports.resolveConfig = resolveConfig;
|
|
12
|
-
const ArtifactNaming_1 = require("../services/ArtifactNaming");
|
|
13
13
|
const PRESET_MAP = {
|
|
14
14
|
conservative: {
|
|
15
15
|
minHealerConfidence: 92,
|
|
@@ -214,6 +214,42 @@ function resolveLargeDomNodeThreshold(value) {
|
|
|
214
214
|
}
|
|
215
215
|
return value;
|
|
216
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Resolves deadline-aware healing timing. Env wins over config. A positive-
|
|
219
|
+
* integer env override is required for the numeric knobs (fail-fast on
|
|
220
|
+
* garbage, mirroring resolveLargeDomNodeThreshold). Master kill switch:
|
|
221
|
+
* SELA_TIMING_DISABLE=true ⇒ enabled:false ⇒ the proxy stays pure legacy
|
|
222
|
+
* pass-through (no injection, no extension).
|
|
223
|
+
*/
|
|
224
|
+
function resolveTiming(config, env = process.env) {
|
|
225
|
+
const t = config.timing ?? {};
|
|
226
|
+
const numeric = (envName, rawValue, configValue, fallback) => {
|
|
227
|
+
if (rawValue !== undefined) {
|
|
228
|
+
const n = Number(rawValue.trim());
|
|
229
|
+
if (!Number.isInteger(n) || n < 0) {
|
|
230
|
+
throw new Error(`[Sela] Invalid value for env var "${envName}": "${rawValue}". ` +
|
|
231
|
+
`Expected a non-negative integer.`);
|
|
232
|
+
}
|
|
233
|
+
return n;
|
|
234
|
+
}
|
|
235
|
+
if (configValue !== undefined) {
|
|
236
|
+
if (typeof configValue !== "number" || !Number.isInteger(configValue) || configValue < 0) {
|
|
237
|
+
throw new Error(`[Sela] Invalid timing value: ${JSON.stringify(configValue)}. ` +
|
|
238
|
+
`Expected a non-negative integer.`);
|
|
239
|
+
}
|
|
240
|
+
return configValue;
|
|
241
|
+
}
|
|
242
|
+
return fallback;
|
|
243
|
+
};
|
|
244
|
+
return {
|
|
245
|
+
enabled: !parseEnvBoolean("SELA_TIMING_DISABLE", env.SELA_TIMING_DISABLE),
|
|
246
|
+
extendTestTimeout: t.extendTestTimeout ?? true,
|
|
247
|
+
deadlineBufferMs: numeric("SELA_DEADLINE_BUFFER_MS", env.SELA_DEADLINE_BUFFER_MS, t.deadlineBufferMs, 2000),
|
|
248
|
+
healRunwayMs: numeric("SELA_HEAL_RUNWAY_MS", env.SELA_HEAL_RUNWAY_MS, t.healRunwayMs, 30000),
|
|
249
|
+
minActionFloorMs: numeric("SELA_MIN_ACTION_FLOOR_MS", env.SELA_MIN_ACTION_FLOOR_MS, t.minActionFloorMs, 1000),
|
|
250
|
+
maxExtensionsPerTest: numeric(undefined, undefined, t.maxExtensionsPerTest, 3),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
217
253
|
const CRITICALITY_TIERS = new Set([
|
|
218
254
|
"critical",
|
|
219
255
|
"high",
|
|
@@ -280,9 +316,6 @@ function resolveConfig(config, env = process.env) {
|
|
|
280
316
|
const largeDomNodeThreshold = resolveLargeDomNodeThreshold(config.largeDomNodeThreshold);
|
|
281
317
|
return {
|
|
282
318
|
thresholds: resolveThresholds(config),
|
|
283
|
-
reporting: {
|
|
284
|
-
mode: (0, ArtifactNaming_1.resolveConfiguredReportMode)(config.reporting?.mode, env),
|
|
285
|
-
},
|
|
286
319
|
updateStrategy: config.updateStrategy ?? "inPlace",
|
|
287
320
|
autoCommit,
|
|
288
321
|
dnaStoragePath: config.dnaStoragePath ?? ".sela/snapshots",
|
|
@@ -311,5 +344,6 @@ function resolveConfig(config, env = process.env) {
|
|
|
311
344
|
bypass,
|
|
312
345
|
regressionActive,
|
|
313
346
|
regressionManifestPath,
|
|
347
|
+
timing: resolveTiming(config, env),
|
|
314
348
|
};
|
|
315
349
|
}
|
|
@@ -6,7 +6,13 @@ export interface SelectorContext {
|
|
|
6
6
|
parentChain?: string[];
|
|
7
7
|
}
|
|
8
8
|
export declare class HealingRegistry {
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Session-scoped slot key. `getInstance()` resolves the registry from the
|
|
11
|
+
* ACTIVE session (process-default when no `runInSession` is active), so a
|
|
12
|
+
* heal broadcast in one Chronos session never reaches a concurrent session's
|
|
13
|
+
* listeners or overwrites its call-site map.
|
|
14
|
+
*/
|
|
15
|
+
private static readonly SESSION_SLOT;
|
|
10
16
|
private readonly listeners;
|
|
11
17
|
/**
|
|
12
18
|
* Two-level store:
|
|
@@ -19,7 +25,7 @@ export declare class HealingRegistry {
|
|
|
19
25
|
private readonly healMap;
|
|
20
26
|
private constructor();
|
|
21
27
|
static getInstance(): HealingRegistry;
|
|
22
|
-
static fingerprint(ctx: SelectorContext): string;
|
|
28
|
+
static fingerprint(ctx: SelectorContext | null | undefined): string;
|
|
23
29
|
broadcast(ctx: SelectorContext, oldSelector: string, newSelector: string): void;
|
|
24
30
|
broadcastCascade(ctx: SelectorContext, pairs: Array<{
|
|
25
31
|
oldSelector: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HealingRegistry.d.ts","sourceRoot":"","sources":["../../src/engine/HealingRegistry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HealingRegistry.d.ts","sourceRoot":"","sources":["../../src/engine/HealingRegistry.ts"],"names":[],"mappings":"AAMA,KAAK,YAAY,GAAG,CAClB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,KAChB,IAAI,CAAC;AAEV,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,qBAAa,eAAe;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAElC;IAEF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IAErD;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAElE,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,eAAe;IASrC,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM;IAmBnE,SAAS,CACP,GAAG,EAAE,eAAe,EACpB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,IAAI;IAqBP,gBAAgB,CACd,GAAG,EAAE,eAAe,EACpB,KAAK,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,GACzD,IAAI;IAMP;;;;;;;OAOG;IACH,IAAI,CACF,OAAO,EAAE,KAAK,CAAC;QACb,GAAG,EAAE,eAAe,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,GACD,IAAI;IAcP,SAAS,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,IAAI;IAK7C;;;;OAIG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,eAAe,GAAG,MAAM;IAYhE,OAAO,CAAC,SAAS;IAWjB,YAAY,IAAI,IAAI;IAMpB,QAAQ,IAAI,IAAI;CAIjB"}
|
|
@@ -4,8 +4,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.HealingRegistry = void 0;
|
|
5
5
|
const crypto_1 = require("crypto");
|
|
6
6
|
const logger_1 = require("../utils/logger");
|
|
7
|
+
const SessionContext_1 = require("../services/SessionContext");
|
|
7
8
|
class HealingRegistry {
|
|
8
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Session-scoped slot key. `getInstance()` resolves the registry from the
|
|
11
|
+
* ACTIVE session (process-default when no `runInSession` is active), so a
|
|
12
|
+
* heal broadcast in one Chronos session never reaches a concurrent session's
|
|
13
|
+
* listeners or overwrites its call-site map.
|
|
14
|
+
*/
|
|
15
|
+
static SESSION_SLOT = Symbol.for("sela.session.healingRegistry");
|
|
9
16
|
listeners = new Set();
|
|
10
17
|
/**
|
|
11
18
|
* Two-level store:
|
|
@@ -18,16 +25,22 @@ class HealingRegistry {
|
|
|
18
25
|
healMap = new Map();
|
|
19
26
|
constructor() { }
|
|
20
27
|
static getInstance() {
|
|
21
|
-
|
|
22
|
-
HealingRegistry.instance = new HealingRegistry();
|
|
23
|
-
}
|
|
24
|
-
return HealingRegistry.instance;
|
|
28
|
+
return (0, SessionContext_1.sessionSlot)(HealingRegistry.SESSION_SLOT, () => new HealingRegistry());
|
|
25
29
|
}
|
|
26
30
|
// ── Fingerprint generation ───────────────────────────────────
|
|
27
31
|
static fingerprint(ctx) {
|
|
28
|
-
|
|
32
|
+
// Single shared funnel: broadcast/broadcastCascade/seed/resolveSelector
|
|
33
|
+
// all call this method to derive their map key, so sanitizing HERE
|
|
34
|
+
// (rather than at each call site) closes totality for all four at once.
|
|
35
|
+
// A malformed ctx (null/undefined, or a parentChain that isn't actually
|
|
36
|
+
// an array — e.g. a corrupted/version-skewed ledger record) must never
|
|
37
|
+
// crash the host suite (CLAUDE.md Zero-Crash / Safe Backoff).
|
|
38
|
+
const safeCtx = ctx ?? {};
|
|
39
|
+
const chain = Array.isArray(safeCtx.parentChain)
|
|
40
|
+
? safeCtx.parentChain.join("||")
|
|
41
|
+
: "";
|
|
29
42
|
return (0, crypto_1.createHash)("sha1")
|
|
30
|
-
.update(`${
|
|
43
|
+
.update(`${safeCtx.filePath}:${safeCtx.line}:${chain}`)
|
|
31
44
|
.digest("hex")
|
|
32
45
|
.slice(0, 16);
|
|
33
46
|
}
|
|
@@ -68,6 +68,14 @@ export declare class SelaEngine {
|
|
|
68
68
|
/** Override for the human explanation (e.g. governance locks). */
|
|
69
69
|
explanation?: string;
|
|
70
70
|
}): void;
|
|
71
|
+
/**
|
|
72
|
+
* Teardown-race refusal (Mechanism C, RFC timing-interception §7). Records a
|
|
73
|
+
* FAILED report event when DOM extraction is impossible because the page is
|
|
74
|
+
* already closed, then lets heal() return "" so the caller rethrows the
|
|
75
|
+
* original Playwright error. Never throws — transparency must not itself
|
|
76
|
+
* crash the surfaced failure.
|
|
77
|
+
*/
|
|
78
|
+
private _recordTeardownRefusal;
|
|
71
79
|
heal(page: Page, fullSelector: string, elementSelectorOnly: string, stableId: string, filePath: string, line: number, healMode?: HealMode, originalMethod?: string, ancestryContext?: {
|
|
72
80
|
descendantChain: string;
|
|
73
81
|
}, failure?: FailureEvidence): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelaEngine.d.ts","sourceRoot":"","sources":["../../src/engine/SelaEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAsBxC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"SelaEngine.d.ts","sourceRoot":"","sources":["../../src/engine/SelaEngine.ts"],"names":[],"mappings":"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"}
|