@karmaniverous/jeeves-meta 0.15.7 → 0.15.8
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.
|
@@ -9356,6 +9356,8 @@ const serviceConfigSchema = metaConfigSchema.extend({
|
|
|
9356
9356
|
watcherHealthIntervalMs: z.number().int().min(0).default(60_000),
|
|
9357
9357
|
/** Logging configuration. */
|
|
9358
9358
|
logging: loggingSchema.default(() => loggingSchema.parse({})),
|
|
9359
|
+
/** Max number of all-fresh candidates to scan per tick in Tier 2 invalidation. */
|
|
9360
|
+
tier2ScanLimit: z.number().int().min(1).default(50),
|
|
9359
9361
|
/**
|
|
9360
9362
|
* Auto-seed policy: declarative rules for auto-creating .meta/ directories.
|
|
9361
9363
|
* Rules are evaluated in order; last match wins for steer/crossRefs.
|
|
@@ -10789,20 +10791,14 @@ function selectPhaseCandidate(metas, depthWeight) {
|
|
|
10789
10791
|
return rankPhaseCandidates(metas, depthWeight)[0] ?? null;
|
|
10790
10792
|
}
|
|
10791
10793
|
/**
|
|
10792
|
-
* Select
|
|
10793
|
-
*
|
|
10794
|
-
* have structural or steer changes detectable only via I/O.
|
|
10795
|
-
*
|
|
10796
|
-
* @param metas - Phase candidate inputs (after Tier 1 filtering).
|
|
10797
|
-
* @returns The stalest all-fresh candidate, or null if none exist.
|
|
10794
|
+
* Select all fully-fresh, non-disabled, non-locked metas sorted by staleness
|
|
10795
|
+
* (descending — stalest first) for Tier 2 invalidation scanning.
|
|
10798
10796
|
*/
|
|
10799
|
-
function
|
|
10800
|
-
|
|
10797
|
+
function selectAllTier2Candidates(metas) {
|
|
10798
|
+
return metas
|
|
10801
10799
|
.filter((m) => !m.locked && !m.disabled && isFullyFresh(m.phaseState))
|
|
10802
|
-
.sort((a, b) => b.actualStaleness - a.actualStaleness)
|
|
10803
|
-
|
|
10804
|
-
return null;
|
|
10805
|
-
return { node: eligible[0].node, meta: eligible[0].meta };
|
|
10800
|
+
.sort((a, b) => b.actualStaleness - a.actualStaleness)
|
|
10801
|
+
.map((m) => ({ node: m.node, meta: m.meta }));
|
|
10806
10802
|
}
|
|
10807
10803
|
|
|
10808
10804
|
/**
|
|
@@ -11185,8 +11181,9 @@ async function orchestratePhase(config, executor, watcher, targetPath, onProgres
|
|
|
11185
11181
|
// Select best phase candidate
|
|
11186
11182
|
const winner = selectPhaseCandidate(candidates, config.depthWeight);
|
|
11187
11183
|
if (!winner) {
|
|
11188
|
-
//
|
|
11189
|
-
|
|
11184
|
+
// Tier 2 is now handled by the scheduler; orchestratePhase only handles
|
|
11185
|
+
// targeted (override) paths and Tier 1 corpus-wide selection.
|
|
11186
|
+
return { executed: false };
|
|
11190
11187
|
}
|
|
11191
11188
|
// Acquire lock
|
|
11192
11189
|
if (!acquireLock(winner.node.metaPath)) {
|
|
@@ -11252,48 +11249,6 @@ async function orchestrateTargeted(config, executor, watcher, targetPath, onProg
|
|
|
11252
11249
|
releaseLock(node.metaPath);
|
|
11253
11250
|
}
|
|
11254
11251
|
}
|
|
11255
|
-
/**
|
|
11256
|
-
* Tier 2 invalidation fallback: pick the stalest all-fresh meta,
|
|
11257
|
-
* run computeInvalidation (structure hash, steer, cross-refs), and
|
|
11258
|
-
* either execute the owed phase or bump _generatedAt.
|
|
11259
|
-
*/
|
|
11260
|
-
async function orchestrateTier2(candidates, config, executor, watcher, onProgress, logger) {
|
|
11261
|
-
const tier2 = selectTier2Candidate(candidates);
|
|
11262
|
-
if (!tier2)
|
|
11263
|
-
return { executed: false };
|
|
11264
|
-
if (!acquireLock(tier2.node.metaPath)) {
|
|
11265
|
-
logger?.debug({ path: tier2.node.metaPath }, 'Tier 2 candidate is locked, skipping');
|
|
11266
|
-
return { executed: false };
|
|
11267
|
-
}
|
|
11268
|
-
try {
|
|
11269
|
-
const currentMeta = await readMetaJson(tier2.node.metaPath);
|
|
11270
|
-
const { scopeFiles } = await getScopeFiles(tier2.node, watcher);
|
|
11271
|
-
const { phaseState, structureHash } = await computeInvalidation(currentMeta, scopeFiles, config, tier2.node);
|
|
11272
|
-
const owedPhase = getOwedPhase(phaseState);
|
|
11273
|
-
if (owedPhase) {
|
|
11274
|
-
// Something changed — persist invalidated state and execute owed phase
|
|
11275
|
-
await persistPhaseState({
|
|
11276
|
-
metaPath: tier2.node.metaPath,
|
|
11277
|
-
current: currentMeta,
|
|
11278
|
-
config,
|
|
11279
|
-
structureHash,
|
|
11280
|
-
}, phaseState, {});
|
|
11281
|
-
return await executePhase(tier2.node, currentMeta, phaseState, owedPhase, config, executor, watcher, structureHash, onProgress, logger);
|
|
11282
|
-
}
|
|
11283
|
-
// Nothing changed — bump _generatedAt to delay re-checking
|
|
11284
|
-
await persistPhaseState({
|
|
11285
|
-
metaPath: tier2.node.metaPath,
|
|
11286
|
-
current: currentMeta,
|
|
11287
|
-
config,
|
|
11288
|
-
structureHash,
|
|
11289
|
-
}, phaseState, { _generatedAt: new Date().toISOString() });
|
|
11290
|
-
logger?.debug({ path: tier2.node.ownerPath }, 'Tier 2: no invalidation detected, bumped _generatedAt');
|
|
11291
|
-
return { executed: false };
|
|
11292
|
-
}
|
|
11293
|
-
finally {
|
|
11294
|
-
releaseLock(tier2.node.metaPath);
|
|
11295
|
-
}
|
|
11296
|
-
}
|
|
11297
11252
|
/**
|
|
11298
11253
|
* Execute exactly one phase on a meta.
|
|
11299
11254
|
*/
|
|
@@ -12271,7 +12226,7 @@ class Scheduler {
|
|
|
12271
12226
|
const candidates = buildPhaseCandidates(result.entries, this.config.architectEvery);
|
|
12272
12227
|
const winner = selectPhaseCandidate(candidates, this.config.depthWeight);
|
|
12273
12228
|
if (!winner)
|
|
12274
|
-
return
|
|
12229
|
+
return await this.discoverTier2Phase(candidates);
|
|
12275
12230
|
return {
|
|
12276
12231
|
path: winner.node.metaPath,
|
|
12277
12232
|
phase: winner.owedPhase,
|
|
@@ -12283,6 +12238,57 @@ class Scheduler {
|
|
|
12283
12238
|
return null;
|
|
12284
12239
|
}
|
|
12285
12240
|
}
|
|
12241
|
+
/**
|
|
12242
|
+
* Tier 2 invalidation: iterate all-fresh candidates (stalest first),
|
|
12243
|
+
* run computeInvalidation, and return the first that produces an owed phase.
|
|
12244
|
+
*/
|
|
12245
|
+
async discoverTier2Phase(candidates) {
|
|
12246
|
+
const allTier2 = selectAllTier2Candidates(candidates);
|
|
12247
|
+
const limit = this.config.tier2ScanLimit;
|
|
12248
|
+
const tier2Candidates = allTier2.slice(0, limit);
|
|
12249
|
+
if (allTier2.length > limit) {
|
|
12250
|
+
this.logger.debug({ total: allTier2.length, limit }, 'Tier 2 scan limit reached, scanning subset');
|
|
12251
|
+
}
|
|
12252
|
+
let dirty = false;
|
|
12253
|
+
for (const t2 of tier2Candidates) {
|
|
12254
|
+
if (!acquireLock(t2.node.metaPath))
|
|
12255
|
+
continue;
|
|
12256
|
+
try {
|
|
12257
|
+
const currentMeta = await readMetaJson(t2.node.metaPath);
|
|
12258
|
+
const { scopeFiles } = await getScopeFiles(t2.node, this.watcher);
|
|
12259
|
+
const result = await computeInvalidation(currentMeta, scopeFiles, this.config, t2.node);
|
|
12260
|
+
const owedPhase = getOwedPhase(result.phaseState);
|
|
12261
|
+
if (owedPhase) {
|
|
12262
|
+
await persistPhaseState({
|
|
12263
|
+
metaPath: t2.node.metaPath,
|
|
12264
|
+
current: currentMeta,
|
|
12265
|
+
config: this.config,
|
|
12266
|
+
structureHash: result.structureHash,
|
|
12267
|
+
}, result.phaseState, {});
|
|
12268
|
+
this.cache.invalidate();
|
|
12269
|
+
return {
|
|
12270
|
+
path: t2.node.metaPath,
|
|
12271
|
+
phase: owedPhase,
|
|
12272
|
+
band: getPriorityBand(result.phaseState),
|
|
12273
|
+
};
|
|
12274
|
+
}
|
|
12275
|
+
// No invalidation — bump _generatedAt to delay re-checking
|
|
12276
|
+
await persistPhaseState({
|
|
12277
|
+
metaPath: t2.node.metaPath,
|
|
12278
|
+
current: currentMeta,
|
|
12279
|
+
config: this.config,
|
|
12280
|
+
structureHash: result.structureHash,
|
|
12281
|
+
}, result.phaseState, { _generatedAt: new Date().toISOString() });
|
|
12282
|
+
dirty = true;
|
|
12283
|
+
}
|
|
12284
|
+
finally {
|
|
12285
|
+
releaseLock(t2.node.metaPath);
|
|
12286
|
+
}
|
|
12287
|
+
}
|
|
12288
|
+
if (dirty)
|
|
12289
|
+
this.cache.invalidate();
|
|
12290
|
+
return null;
|
|
12291
|
+
}
|
|
12286
12292
|
}
|
|
12287
12293
|
|
|
12288
12294
|
/**
|
package/dist/index.js
CHANGED
|
@@ -9050,6 +9050,8 @@ const serviceConfigSchema = metaConfigSchema.extend({
|
|
|
9050
9050
|
watcherHealthIntervalMs: z.number().int().min(0).default(60_000),
|
|
9051
9051
|
/** Logging configuration. */
|
|
9052
9052
|
logging: loggingSchema.default(() => loggingSchema.parse({})),
|
|
9053
|
+
/** Max number of all-fresh candidates to scan per tick in Tier 2 invalidation. */
|
|
9054
|
+
tier2ScanLimit: z.number().int().min(1).default(50),
|
|
9053
9055
|
/**
|
|
9054
9056
|
* Auto-seed policy: declarative rules for auto-creating .meta/ directories.
|
|
9055
9057
|
* Rules are evaluated in order; last match wins for steer/crossRefs.
|
|
@@ -10340,20 +10342,14 @@ function selectPhaseCandidate(metas, depthWeight) {
|
|
|
10340
10342
|
return rankPhaseCandidates(metas, depthWeight)[0] ?? null;
|
|
10341
10343
|
}
|
|
10342
10344
|
/**
|
|
10343
|
-
* Select
|
|
10344
|
-
*
|
|
10345
|
-
* have structural or steer changes detectable only via I/O.
|
|
10346
|
-
*
|
|
10347
|
-
* @param metas - Phase candidate inputs (after Tier 1 filtering).
|
|
10348
|
-
* @returns The stalest all-fresh candidate, or null if none exist.
|
|
10345
|
+
* Select all fully-fresh, non-disabled, non-locked metas sorted by staleness
|
|
10346
|
+
* (descending — stalest first) for Tier 2 invalidation scanning.
|
|
10349
10347
|
*/
|
|
10350
|
-
function
|
|
10351
|
-
|
|
10348
|
+
function selectAllTier2Candidates(metas) {
|
|
10349
|
+
return metas
|
|
10352
10350
|
.filter((m) => !m.locked && !m.disabled && isFullyFresh(m.phaseState))
|
|
10353
|
-
.sort((a, b) => b.actualStaleness - a.actualStaleness)
|
|
10354
|
-
|
|
10355
|
-
return null;
|
|
10356
|
-
return { node: eligible[0].node, meta: eligible[0].meta };
|
|
10351
|
+
.sort((a, b) => b.actualStaleness - a.actualStaleness)
|
|
10352
|
+
.map((m) => ({ node: m.node, meta: m.meta }));
|
|
10357
10353
|
}
|
|
10358
10354
|
|
|
10359
10355
|
/**
|
|
@@ -10736,8 +10732,9 @@ async function orchestratePhase(config, executor, watcher, targetPath, onProgres
|
|
|
10736
10732
|
// Select best phase candidate
|
|
10737
10733
|
const winner = selectPhaseCandidate(candidates, config.depthWeight);
|
|
10738
10734
|
if (!winner) {
|
|
10739
|
-
//
|
|
10740
|
-
|
|
10735
|
+
// Tier 2 is now handled by the scheduler; orchestratePhase only handles
|
|
10736
|
+
// targeted (override) paths and Tier 1 corpus-wide selection.
|
|
10737
|
+
return { executed: false };
|
|
10741
10738
|
}
|
|
10742
10739
|
// Acquire lock
|
|
10743
10740
|
if (!acquireLock(winner.node.metaPath)) {
|
|
@@ -10803,48 +10800,6 @@ async function orchestrateTargeted(config, executor, watcher, targetPath, onProg
|
|
|
10803
10800
|
releaseLock(node.metaPath);
|
|
10804
10801
|
}
|
|
10805
10802
|
}
|
|
10806
|
-
/**
|
|
10807
|
-
* Tier 2 invalidation fallback: pick the stalest all-fresh meta,
|
|
10808
|
-
* run computeInvalidation (structure hash, steer, cross-refs), and
|
|
10809
|
-
* either execute the owed phase or bump _generatedAt.
|
|
10810
|
-
*/
|
|
10811
|
-
async function orchestrateTier2(candidates, config, executor, watcher, onProgress, logger) {
|
|
10812
|
-
const tier2 = selectTier2Candidate(candidates);
|
|
10813
|
-
if (!tier2)
|
|
10814
|
-
return { executed: false };
|
|
10815
|
-
if (!acquireLock(tier2.node.metaPath)) {
|
|
10816
|
-
logger?.debug({ path: tier2.node.metaPath }, 'Tier 2 candidate is locked, skipping');
|
|
10817
|
-
return { executed: false };
|
|
10818
|
-
}
|
|
10819
|
-
try {
|
|
10820
|
-
const currentMeta = await readMetaJson(tier2.node.metaPath);
|
|
10821
|
-
const { scopeFiles } = await getScopeFiles(tier2.node, watcher);
|
|
10822
|
-
const { phaseState, structureHash } = await computeInvalidation(currentMeta, scopeFiles, config, tier2.node);
|
|
10823
|
-
const owedPhase = getOwedPhase(phaseState);
|
|
10824
|
-
if (owedPhase) {
|
|
10825
|
-
// Something changed — persist invalidated state and execute owed phase
|
|
10826
|
-
await persistPhaseState({
|
|
10827
|
-
metaPath: tier2.node.metaPath,
|
|
10828
|
-
current: currentMeta,
|
|
10829
|
-
config,
|
|
10830
|
-
structureHash,
|
|
10831
|
-
}, phaseState, {});
|
|
10832
|
-
return await executePhase(tier2.node, currentMeta, phaseState, owedPhase, config, executor, watcher, structureHash, onProgress, logger);
|
|
10833
|
-
}
|
|
10834
|
-
// Nothing changed — bump _generatedAt to delay re-checking
|
|
10835
|
-
await persistPhaseState({
|
|
10836
|
-
metaPath: tier2.node.metaPath,
|
|
10837
|
-
current: currentMeta,
|
|
10838
|
-
config,
|
|
10839
|
-
structureHash,
|
|
10840
|
-
}, phaseState, { _generatedAt: new Date().toISOString() });
|
|
10841
|
-
logger?.debug({ path: tier2.node.ownerPath }, 'Tier 2: no invalidation detected, bumped _generatedAt');
|
|
10842
|
-
return { executed: false };
|
|
10843
|
-
}
|
|
10844
|
-
finally {
|
|
10845
|
-
releaseLock(tier2.node.metaPath);
|
|
10846
|
-
}
|
|
10847
|
-
}
|
|
10848
10803
|
/**
|
|
10849
10804
|
* Execute exactly one phase on a meta.
|
|
10850
10805
|
*/
|
|
@@ -11822,7 +11777,7 @@ class Scheduler {
|
|
|
11822
11777
|
const candidates = buildPhaseCandidates(result.entries, this.config.architectEvery);
|
|
11823
11778
|
const winner = selectPhaseCandidate(candidates, this.config.depthWeight);
|
|
11824
11779
|
if (!winner)
|
|
11825
|
-
return
|
|
11780
|
+
return await this.discoverTier2Phase(candidates);
|
|
11826
11781
|
return {
|
|
11827
11782
|
path: winner.node.metaPath,
|
|
11828
11783
|
phase: winner.owedPhase,
|
|
@@ -11834,6 +11789,57 @@ class Scheduler {
|
|
|
11834
11789
|
return null;
|
|
11835
11790
|
}
|
|
11836
11791
|
}
|
|
11792
|
+
/**
|
|
11793
|
+
* Tier 2 invalidation: iterate all-fresh candidates (stalest first),
|
|
11794
|
+
* run computeInvalidation, and return the first that produces an owed phase.
|
|
11795
|
+
*/
|
|
11796
|
+
async discoverTier2Phase(candidates) {
|
|
11797
|
+
const allTier2 = selectAllTier2Candidates(candidates);
|
|
11798
|
+
const limit = this.config.tier2ScanLimit;
|
|
11799
|
+
const tier2Candidates = allTier2.slice(0, limit);
|
|
11800
|
+
if (allTier2.length > limit) {
|
|
11801
|
+
this.logger.debug({ total: allTier2.length, limit }, 'Tier 2 scan limit reached, scanning subset');
|
|
11802
|
+
}
|
|
11803
|
+
let dirty = false;
|
|
11804
|
+
for (const t2 of tier2Candidates) {
|
|
11805
|
+
if (!acquireLock(t2.node.metaPath))
|
|
11806
|
+
continue;
|
|
11807
|
+
try {
|
|
11808
|
+
const currentMeta = await readMetaJson(t2.node.metaPath);
|
|
11809
|
+
const { scopeFiles } = await getScopeFiles(t2.node, this.watcher);
|
|
11810
|
+
const result = await computeInvalidation(currentMeta, scopeFiles, this.config, t2.node);
|
|
11811
|
+
const owedPhase = getOwedPhase(result.phaseState);
|
|
11812
|
+
if (owedPhase) {
|
|
11813
|
+
await persistPhaseState({
|
|
11814
|
+
metaPath: t2.node.metaPath,
|
|
11815
|
+
current: currentMeta,
|
|
11816
|
+
config: this.config,
|
|
11817
|
+
structureHash: result.structureHash,
|
|
11818
|
+
}, result.phaseState, {});
|
|
11819
|
+
this.cache.invalidate();
|
|
11820
|
+
return {
|
|
11821
|
+
path: t2.node.metaPath,
|
|
11822
|
+
phase: owedPhase,
|
|
11823
|
+
band: getPriorityBand(result.phaseState),
|
|
11824
|
+
};
|
|
11825
|
+
}
|
|
11826
|
+
// No invalidation — bump _generatedAt to delay re-checking
|
|
11827
|
+
await persistPhaseState({
|
|
11828
|
+
metaPath: t2.node.metaPath,
|
|
11829
|
+
current: currentMeta,
|
|
11830
|
+
config: this.config,
|
|
11831
|
+
structureHash: result.structureHash,
|
|
11832
|
+
}, result.phaseState, { _generatedAt: new Date().toISOString() });
|
|
11833
|
+
dirty = true;
|
|
11834
|
+
}
|
|
11835
|
+
finally {
|
|
11836
|
+
releaseLock(t2.node.metaPath);
|
|
11837
|
+
}
|
|
11838
|
+
}
|
|
11839
|
+
if (dirty)
|
|
11840
|
+
this.cache.invalidate();
|
|
11841
|
+
return null;
|
|
11842
|
+
}
|
|
11837
11843
|
}
|
|
11838
11844
|
|
|
11839
11845
|
/**
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { type DerivationInputs, derivePhaseState } from './derivePhaseState.js';
|
|
7
7
|
export { type ArchitectInvalidator, computeInvalidation, type InvalidationResult, type StalenessInputs, } from './invalidate.js';
|
|
8
|
-
export { buildPhaseCandidates, type PhaseCandidate, type PhaseCandidateInput, rankPhaseCandidates, selectPhaseCandidate, selectTier2Candidate, type Tier2Candidate, } from './phaseScheduler.js';
|
|
8
|
+
export { buildPhaseCandidates, type PhaseCandidate, type PhaseCandidateInput, rankPhaseCandidates, selectAllTier2Candidates, selectPhaseCandidate, selectTier2Candidate, type Tier2Candidate, } from './phaseScheduler.js';
|
|
9
9
|
export { architectSuccess, builderSuccess, criticSuccess, enforceInvariant, freshPhaseState, getOwedPhase, getPriorityBand, initialPhaseState, invalidateArchitect, invalidateBuilder, isFullyFresh, phaseFailed, phaseRunning, retryAllFailed, retryPhase, } from './phaseTransitions.js';
|
|
@@ -69,3 +69,8 @@ export interface Tier2Candidate {
|
|
|
69
69
|
* @returns The stalest all-fresh candidate, or null if none exist.
|
|
70
70
|
*/
|
|
71
71
|
export declare function selectTier2Candidate(metas: PhaseCandidateInput[]): Tier2Candidate | null;
|
|
72
|
+
/**
|
|
73
|
+
* Select all fully-fresh, non-disabled, non-locked metas sorted by staleness
|
|
74
|
+
* (descending — stalest first) for Tier 2 invalidation scanning.
|
|
75
|
+
*/
|
|
76
|
+
export declare function selectAllTier2Candidates(metas: PhaseCandidateInput[]): Tier2Candidate[];
|
|
@@ -63,4 +63,9 @@ export declare class Scheduler {
|
|
|
63
63
|
* with weighted staleness as tiebreaker within a band.
|
|
64
64
|
*/
|
|
65
65
|
private discoverNextPhase;
|
|
66
|
+
/**
|
|
67
|
+
* Tier 2 invalidation: iterate all-fresh candidates (stalest first),
|
|
68
|
+
* run computeInvalidation, and return the first that produces an owed phase.
|
|
69
|
+
*/
|
|
70
|
+
private discoverTier2Phase;
|
|
66
71
|
}
|
package/dist/schema/config.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export declare const serviceConfigSchema: z.ZodObject<{
|
|
|
44
44
|
level: z.ZodDefault<z.ZodString>;
|
|
45
45
|
file: z.ZodOptional<z.ZodString>;
|
|
46
46
|
}, z.core.$strip>>;
|
|
47
|
+
tier2ScanLimit: z.ZodDefault<z.ZodNumber>;
|
|
47
48
|
autoSeed: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
48
49
|
match: z.ZodString;
|
|
49
50
|
steer: z.ZodOptional<z.ZodString>;
|