@ngockhoale/ukit 1.4.2 → 1.4.3

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.
@@ -49,6 +49,7 @@ async function main() {
49
49
  const rootDir = getRootDir(args);
50
50
  const sharedStatePath = path.join(rootDir, '.claude', 'ukit', 'skill-router-state.json');
51
51
  const routeCachePath = path.join(rootDir, '.claude', 'ukit', 'route-cache.json');
52
+ const routeAuditPath = path.join(rootDir, '.ukit', 'storage', 'cache', 'route-audit.json');
52
53
  const previousState = await readJson(sharedStatePath, {});
53
54
  const targetFile = readFlagValue(args, '--target');
54
55
  const taskType = readFlagValue(args, '--type');
@@ -147,6 +148,9 @@ async function main() {
147
148
  ),
148
149
  }
149
150
  : null;
151
+ if (rescuedRouteSummary) {
152
+ applyRescueBiasToRouteSummary(rescuedRouteSummary);
153
+ }
150
154
  const sharedState = {
151
155
  ...cachedRouteState,
152
156
  source: 'task-route',
@@ -156,6 +160,9 @@ async function main() {
156
160
  };
157
161
  sharedState.fingerprint = buildRouteStateFingerprint(sharedState);
158
162
  await writeJson(sharedStatePath, sharedState);
163
+ await appendRouteAuditEntry(routeAuditPath, buildRouteAuditEntry({
164
+ state: sharedState,
165
+ }));
159
166
  printRouteState(sharedState);
160
167
  return;
161
168
  }
@@ -194,6 +201,10 @@ async function main() {
194
201
  indexGeneratedAtMs,
195
202
  });
196
203
  await writeJson(sharedStatePath, sharedState);
204
+ await appendRouteAuditEntry(routeAuditPath, buildRouteAuditEntry({
205
+ route,
206
+ state: sharedState,
207
+ }));
197
208
  await writeRecentCacheEntry(routeCachePath, compactRouteCacheState(sharedState), {
198
209
  maxEntries: DEFAULT_RECENT_CACHE_MAX_ENTRIES,
199
210
  });
@@ -274,13 +285,20 @@ async function prepareTaskRoute({
274
285
  intentMode,
275
286
  taskType: inferredTaskType,
276
287
  });
288
+ const executionCandidates = buildExecutionModeCandidates({
289
+ promptText: normalizedPrompt,
290
+ commandText: normalizedCommand,
291
+ targetFile: normalizedTarget,
292
+ intentMode,
293
+ executionScores,
294
+ });
277
295
  const executionMode = deriveExecutionMode({
278
296
  promptText: normalizedPrompt,
279
297
  commandText: normalizedCommand,
280
298
  targetFile: normalizedTarget,
281
299
  intentMode,
282
- taskType: inferredTaskType,
283
300
  executionScores,
301
+ executionCandidates,
284
302
  });
285
303
  const preservedPrompt = normalizedPrompt || String(lastExplicitUserPromptText || '').trim();
286
304
 
@@ -297,6 +315,7 @@ async function prepareTaskRoute({
297
315
  taskType: inferredTaskType,
298
316
  intentMode,
299
317
  executionScores,
318
+ executionCandidates,
300
319
  executionMode,
301
320
  },
302
321
  };
@@ -381,6 +400,7 @@ async function finalizeTaskRoute({
381
400
  routeSummary.continuationState,
382
401
  previousRouteSummary?.continuationState ?? null,
383
402
  );
403
+ applyRescueBiasToRouteSummary(routeSummary);
384
404
  const approachSelector = routeSummary?.approachSelector ?? null;
385
405
 
386
406
  return {
@@ -828,7 +848,7 @@ function deriveIntentMode({ promptText = '', commandText = '', targetFile = null
828
848
  }
829
849
 
830
850
  if (concreteTask) {
831
- if (/\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|login|timeout)\b/.test(lower)) {
851
+ if (/\b(bug|debug|error|crash|broken|failing|stack trace|triage|fix|timeout)\b/.test(lower)) {
832
852
  return 'debug-specific';
833
853
  }
834
854
  if (/\b(review|audit|diff|pr feedback|code review|kiem tra|soat)\b/.test(raw)) {
@@ -1287,9 +1307,11 @@ function buildRouteSummary({
1287
1307
  && contextRecommendation.command.trim();
1288
1308
  const executionMode = routingContext.executionMode ?? null;
1289
1309
  const executionScores = routingContext.executionScores ?? null;
1310
+ const executionCandidates = routingContext.executionCandidates ?? null;
1290
1311
  const approachSelector = buildApproachSelectorResult({
1291
1312
  executionMode,
1292
1313
  executionScores,
1314
+ executionCandidates,
1293
1315
  });
1294
1316
  const executionContract = buildExecutionContract(executionMode);
1295
1317
  const completionState = buildCompletionState({
@@ -1328,6 +1350,7 @@ function buildRouteSummary({
1328
1350
  editGuardHint,
1329
1351
  executionMode,
1330
1352
  executionScores,
1353
+ executionCandidates,
1331
1354
  approachSelector,
1332
1355
  executionContract,
1333
1356
  completionState,
@@ -1362,6 +1385,12 @@ function deriveExecutionScores({
1362
1385
  const buildSignal = /\b(build|create|add|implement|feature)\b/.test(raw);
1363
1386
  const debugSignal = intentMode === 'debug-specific' || /\b(root cause|debug|triage|flaky|investigate|why)\b/.test(raw);
1364
1387
  const reviewSignal = intentMode === 'review-specific' || /\b(review|audit|verify|release readiness)\b/.test(raw);
1388
+ const failureSignal = /\b(failing|failed|broken|error|crash|timeout|undefined|exception|eacces|trace)\b/.test(raw);
1389
+ const impactSignal = /\b(map impact|impact|blast radius|all affected|across (?:runtime|templates|helpers|adapters|mirrors)|affected adapters|affected mirrors|inspect impact)\b/.test(raw);
1390
+ const boundedEditSignal = /\b(one[- ]line|small|tiny|single|local|guard|log line|loading message|label)\b/.test(raw);
1391
+ const implementSignal = /\b(implement|apply|update|modify|add|create|ship|deliver|fix)\b/.test(raw)
1392
+ || /\bchange\s+.+\s+to\s+.+\b/.test(raw);
1393
+ const explicitTarget = Boolean(targetFile);
1365
1394
 
1366
1395
  let editCertainty = 0;
1367
1396
  if (directTransformSignal) {
@@ -1375,7 +1404,7 @@ function deriveExecutionScores({
1375
1404
  let investigationNeed = 0;
1376
1405
  if (debugSignal) {
1377
1406
  investigationNeed = 3;
1378
- } else if (/\b(failing|broken|error|crash|timeout)\b/.test(raw)) {
1407
+ } else if (failureSignal) {
1379
1408
  investigationNeed = 2;
1380
1409
  }
1381
1410
 
@@ -1408,6 +1437,17 @@ function deriveExecutionScores({
1408
1437
  blastRadius,
1409
1438
  verificationBurden,
1410
1439
  ambiguity,
1440
+ sharedRisk,
1441
+ directTransformSignal,
1442
+ smallFixSignal,
1443
+ buildSignal,
1444
+ debugSignal,
1445
+ reviewSignal,
1446
+ failureSignal,
1447
+ impactSignal,
1448
+ boundedEditSignal,
1449
+ implementSignal,
1450
+ explicitTarget,
1411
1451
  };
1412
1452
  }
1413
1453
 
@@ -1417,40 +1457,64 @@ function deriveExecutionMode({
1417
1457
  targetFile = null,
1418
1458
  intentMode = null,
1419
1459
  executionScores = {},
1460
+ executionCandidates = null,
1420
1461
  } = {}) {
1421
1462
  const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
1422
1463
  const scores = executionScores;
1464
+ const candidates = executionCandidates ?? buildExecutionModeCandidates({
1465
+ promptText,
1466
+ commandText,
1467
+ targetFile,
1468
+ intentMode,
1469
+ executionScores,
1470
+ });
1423
1471
  const explicitReviewLead = /\b(review this|audit this|review\b.*\brelease readiness|verify\b.*\brelease readiness)\b/.test(raw);
1472
+ const strongImpactLead = scores.sharedRisk
1473
+ && (scores.impactSignal || /\b(check all affected|map all affected|across all affected)\b/.test(raw));
1474
+ const boundedLocalBuildCandidate = scores.buildSignal && scores.boundedEditSignal && scores.explicitTarget && !scores.sharedRisk;
1424
1475
 
1425
- if (intentMode === 'review-specific' || explicitReviewLead) {
1476
+ if ((intentMode === 'review-specific' || explicitReviewLead) && !scores.implementSignal) {
1426
1477
  return 'review-release';
1427
1478
  }
1428
1479
 
1429
- if (scores.blastRadius >= 3 && (scores.ambiguity >= 2 || scores.investigationNeed >= 2)) {
1480
+ if (strongImpactLead || (scores.blastRadius >= 3 && (scores.ambiguity >= 2 || scores.investigationNeed >= 2))) {
1430
1481
  return 'map-impact';
1431
1482
  }
1432
1483
 
1433
- if (scores.blastRadius >= 3 || isSharedImpactFile(targetFile)) {
1484
+ if (scores.sharedRisk && scores.failureSignal && scores.investigationNeed >= 2 && !scores.impactSignal) {
1434
1485
  return 'shared-edit';
1435
1486
  }
1436
1487
 
1437
- if (scores.investigationNeed >= 3) {
1488
+ if (scores.blastRadius >= 3 || scores.sharedRisk) {
1489
+ return 'shared-edit';
1490
+ }
1491
+
1492
+ if (scores.investigationNeed >= 3 || (scores.failureSignal && scores.investigationNeed >= 2)) {
1438
1493
  return 'find-cause';
1439
1494
  }
1440
1495
 
1496
+ if (scores.directTransformSignal && !scores.explicitTarget && scores.investigationNeed === 0 && !scores.sharedRisk) {
1497
+ return 'local-build';
1498
+ }
1499
+
1441
1500
  if (
1442
1501
  scores.editCertainty >= 3
1443
- && scores.ambiguity === 0
1502
+ && scores.ambiguity <= 1
1444
1503
  && scores.blastRadius === 0
1445
1504
  && scores.verificationBurden <= 1
1446
1505
  ) {
1447
1506
  return 'tiny-fix';
1448
1507
  }
1449
1508
 
1509
+ if (boundedLocalBuildCandidate && scores.investigationNeed === 0) {
1510
+ return 'local-fix';
1511
+ }
1512
+
1450
1513
  if (
1451
1514
  /\b(build|create|add|implement|feature|summary card)\b/.test(raw)
1452
1515
  && scores.investigationNeed === 0
1453
1516
  && scores.blastRadius < 3
1517
+ && !scores.boundedEditSignal
1454
1518
  ) {
1455
1519
  return 'local-build';
1456
1520
  }
@@ -1459,7 +1523,107 @@ function deriveExecutionMode({
1459
1523
  return 'local-fix';
1460
1524
  }
1461
1525
 
1462
- return 'local-build';
1526
+ return applySafeUpwardBias(candidates, 'local-build');
1527
+ }
1528
+
1529
+ function buildExecutionModeCandidates({
1530
+ promptText = '',
1531
+ commandText = '',
1532
+ targetFile = null,
1533
+ intentMode = null,
1534
+ executionScores = {},
1535
+ } = {}) {
1536
+ const scores = executionScores;
1537
+ const raw = `${promptText ?? ''}\n${commandText ?? ''}`.toLowerCase();
1538
+ const explicitReviewLead = (intentMode === 'review-specific' || /\b(review this|audit this|review\b.*\brelease readiness|verify\b.*\brelease readiness)\b/.test(raw))
1539
+ && !scores.implementSignal;
1540
+
1541
+ const modeScores = {
1542
+ 'tiny-fix': (
1543
+ (scores.editCertainty * 4)
1544
+ + (scores.directTransformSignal ? 4 : 0)
1545
+ + (scores.explicitTarget ? 1 : 0)
1546
+ - (scores.failureSignal ? 4 : 0)
1547
+ - (scores.blastRadius * 4)
1548
+ - (scores.ambiguity * 2)
1549
+ ),
1550
+ 'local-fix': (
1551
+ (scores.editCertainty * 3)
1552
+ + (scores.boundedEditSignal ? 3 : 0)
1553
+ + (scores.explicitTarget ? 1 : 0)
1554
+ - (scores.failureSignal ? 2 : 0)
1555
+ - (scores.blastRadius * 4)
1556
+ ),
1557
+ 'local-build': (
1558
+ (scores.buildSignal ? 6 : 0)
1559
+ + (scores.editCertainty * 1)
1560
+ + (scores.explicitTarget ? 1 : 0)
1561
+ - (scores.boundedEditSignal ? 3 : 0)
1562
+ - (scores.failureSignal ? 3 : 0)
1563
+ - (scores.blastRadius * 4)
1564
+ ),
1565
+ 'find-cause': (
1566
+ (scores.investigationNeed * 4)
1567
+ + (scores.failureSignal ? 3 : 0)
1568
+ + (scores.debugSignal ? 2 : 0)
1569
+ - (scores.blastRadius >= 3 ? 1 : 0)
1570
+ ),
1571
+ 'shared-edit': (
1572
+ (scores.sharedRisk ? 8 : 0)
1573
+ + (scores.editCertainty * 1)
1574
+ + (scores.buildSignal ? 1 : 0)
1575
+ - (scores.impactSignal ? 2 : 0)
1576
+ ),
1577
+ 'map-impact': (
1578
+ (scores.sharedRisk ? 7 : 0)
1579
+ + (scores.impactSignal ? 5 : 0)
1580
+ + (scores.ambiguity * 2)
1581
+ + scores.investigationNeed
1582
+ ),
1583
+ 'review-release': (
1584
+ (explicitReviewLead ? 10 : 0)
1585
+ + (scores.reviewSignal ? 3 : 0)
1586
+ - (scores.implementSignal ? 5 : 0)
1587
+ ),
1588
+ };
1589
+
1590
+ return Object.entries(modeScores)
1591
+ .map(([mode, score]) => ({ mode, score }))
1592
+ .sort((a, b) => b.score - a.score || executionModeRank(a.mode) - executionModeRank(b.mode));
1593
+ }
1594
+
1595
+ function applySafeUpwardBias(candidates = [], fallbackMode = 'local-build') {
1596
+ const [topCandidate, competingCandidate] = candidates;
1597
+ if (!topCandidate) {
1598
+ return fallbackMode;
1599
+ }
1600
+
1601
+ if (!competingCandidate) {
1602
+ return topCandidate.mode;
1603
+ }
1604
+
1605
+ const scoreGap = Number(topCandidate.score ?? 0) - Number(competingCandidate.score ?? 0);
1606
+ const rankGap = executionModeRank(competingCandidate.mode) - executionModeRank(topCandidate.mode);
1607
+ if (scoreGap <= 1 && rankGap === 1) {
1608
+ return competingCandidate.mode;
1609
+ }
1610
+
1611
+ return topCandidate.mode;
1612
+ }
1613
+
1614
+ function executionModeRank(mode = '') {
1615
+ const orderedModes = [
1616
+ 'tiny-fix',
1617
+ 'local-fix',
1618
+ 'local-build',
1619
+ 'find-cause',
1620
+ 'shared-edit',
1621
+ 'map-impact',
1622
+ 'review-release',
1623
+ ];
1624
+
1625
+ const index = orderedModes.indexOf(mode);
1626
+ return index >= 0 ? index : orderedModes.length;
1463
1627
  }
1464
1628
 
1465
1629
  function buildExecutionContract(executionMode = null) {
@@ -1531,6 +1695,7 @@ function buildExecutionContract(executionMode = null) {
1531
1695
  function buildApproachSelectorResult({
1532
1696
  executionMode = null,
1533
1697
  executionScores = null,
1698
+ executionCandidates = null,
1534
1699
  } = {}) {
1535
1700
  if (!executionMode) {
1536
1701
  return null;
@@ -1579,6 +1744,14 @@ function buildApproachSelectorResult({
1579
1744
  contextPolicy: selectedPolicy.contextPolicy,
1580
1745
  verificationPolicy: executionContract?.verificationPolicy ?? null,
1581
1746
  completionRule: executionContract?.completionRule ?? null,
1747
+ competingMode: executionCandidates?.[1]?.mode ?? null,
1748
+ competingScoreGap: executionCandidates?.length >= 2
1749
+ ? Number(executionCandidates[0]?.score ?? 0) - Number(executionCandidates[1]?.score ?? 0)
1750
+ : null,
1751
+ candidateModes: (executionCandidates ?? []).slice(0, 3).map((entry) => ({
1752
+ mode: entry.mode,
1753
+ score: entry.score,
1754
+ })),
1582
1755
  };
1583
1756
  }
1584
1757
 
@@ -1666,6 +1839,8 @@ function buildContinuationState({
1666
1839
  repeatCount: reasons.length > 0 ? 1 : 0,
1667
1840
  stuckRisk: null,
1668
1841
  rescueMode: null,
1842
+ wideningBlocked: false,
1843
+ milestonePriority: reasons.length > 0 ? 'normal' : null,
1669
1844
  };
1670
1845
  }
1671
1846
 
@@ -1680,6 +1855,8 @@ function advanceContinuationState(continuationState = null, previousContinuation
1680
1855
  repeatCount: 0,
1681
1856
  stuckRisk: null,
1682
1857
  rescueMode: null,
1858
+ wideningBlocked: false,
1859
+ milestonePriority: null,
1683
1860
  };
1684
1861
  }
1685
1862
 
@@ -1708,15 +1885,45 @@ function advanceContinuationState(continuationState = null, previousContinuation
1708
1885
  const stuckRisk = repeatCount >= 3
1709
1886
  ? 'high'
1710
1887
  : (repeatCount === 2 ? 'elevated' : null);
1888
+ const wideningBlocked = repeatCount >= 2 && Boolean(rescueMode);
1889
+ const nextMilestone = repeatCount >= 2 && currentReasons.includes('missing-write-evidence')
1890
+ ? 'finish-write-before-more-analysis'
1891
+ : (
1892
+ repeatCount >= 2 && currentReasons.includes('pending-bounded-context')
1893
+ ? 'finish-current-milestone-before-more-reading'
1894
+ : continuationState.nextMilestone
1895
+ );
1711
1896
 
1712
1897
  return {
1713
1898
  ...continuationState,
1899
+ nextMilestone,
1714
1900
  repeatCount,
1715
1901
  stuckRisk,
1716
1902
  rescueMode,
1903
+ wideningBlocked,
1904
+ milestonePriority: wideningBlocked ? 'execute-current-milestone' : 'normal',
1717
1905
  };
1718
1906
  }
1719
1907
 
1908
+ function applyRescueBiasToRouteSummary(routeSummary = null) {
1909
+ if (!routeSummary || typeof routeSummary !== 'object') {
1910
+ return routeSummary;
1911
+ }
1912
+
1913
+ const continuationState = routeSummary.continuationState;
1914
+ if (
1915
+ continuationState?.repeatCount >= 2
1916
+ && continuationState?.wideningBlocked
1917
+ && (continuationState.reasons ?? []).includes('missing-write-evidence')
1918
+ ) {
1919
+ routeSummary.nextActionType = 'execute-current-milestone';
1920
+ routeSummary.nextActionCommand = null;
1921
+ routeSummary.helperHint = null;
1922
+ }
1923
+
1924
+ return routeSummary;
1925
+ }
1926
+
1720
1927
  function deriveExecutionPolicy({
1721
1928
  taskType = 'simple',
1722
1929
  mode = 'minimal',
@@ -2368,6 +2575,67 @@ function shouldIncludeRecentOutput({
2368
2575
  return true;
2369
2576
  }
2370
2577
 
2578
+ function buildRouteAuditEntry({ route = null, state = null } = {}) {
2579
+ const routingContext = route?.routingContext ?? state?.routingContext ?? {};
2580
+ const routeSummary = route?.routeSummary ?? state?.routeSummary ?? {};
2581
+ const candidateModes = Array.isArray(routeSummary?.approachSelector?.candidateModes)
2582
+ ? routeSummary.approachSelector.candidateModes
2583
+ : [];
2584
+
2585
+ return {
2586
+ ts: Date.now(),
2587
+ source: state?.source ?? 'task-route',
2588
+ requestKey: state?.requestKey ?? null,
2589
+ adapter: routingContext.adapter ?? 'claude',
2590
+ promptFingerprint: stableMachineDigest({
2591
+ prompt: routingContext.lastExplicitUserPromptText ?? '',
2592
+ adapter: routingContext.adapter ?? 'claude',
2593
+ }),
2594
+ targetFile: route?.routingContext?.targetFile ?? null,
2595
+ taskType: routingContext.taskType ?? null,
2596
+ executionMode: routeSummary.executionMode ?? null,
2597
+ competingMode: routeSummary?.approachSelector?.competingMode ?? null,
2598
+ competingScoreGap: routeSummary?.approachSelector?.competingScoreGap ?? null,
2599
+ candidateModes: candidateModes.slice(0, 3),
2600
+ nextActionType: routeSummary.nextActionType ?? null,
2601
+ nextMilestone: routeSummary?.continuationState?.nextMilestone ?? null,
2602
+ repeatCount: routeSummary?.continuationState?.repeatCount ?? null,
2603
+ rescueMode: routeSummary?.continuationState?.rescueMode ?? null,
2604
+ wideningBlocked: routeSummary?.continuationState?.wideningBlocked ?? null,
2605
+ };
2606
+ }
2607
+
2608
+ async function appendRouteAuditEntry(filePath, entry) {
2609
+ if (!entry || typeof entry !== 'object') {
2610
+ return;
2611
+ }
2612
+
2613
+ const existing = await readJson(filePath, { entries: [] });
2614
+ const entries = Array.isArray(existing?.entries) ? existing.entries : [];
2615
+ const dedupeKey = stableMachineDigest({
2616
+ requestKey: entry.requestKey,
2617
+ executionMode: entry.executionMode,
2618
+ nextActionType: entry.nextActionType,
2619
+ nextMilestone: entry.nextMilestone,
2620
+ repeatCount: entry.repeatCount,
2621
+ rescueMode: entry.rescueMode,
2622
+ });
2623
+ const filtered = entries.filter((item) => {
2624
+ const itemKey = stableMachineDigest({
2625
+ requestKey: item?.requestKey ?? null,
2626
+ executionMode: item?.executionMode ?? null,
2627
+ nextActionType: item?.nextActionType ?? null,
2628
+ nextMilestone: item?.nextMilestone ?? null,
2629
+ repeatCount: item?.repeatCount ?? null,
2630
+ rescueMode: item?.rescueMode ?? null,
2631
+ });
2632
+ return itemKey !== dedupeKey;
2633
+ });
2634
+ await writeJson(filePath, {
2635
+ entries: [entry, ...filtered].slice(0, 40),
2636
+ });
2637
+ }
2638
+
2371
2639
  async function readJson(filePath, fallback = null) {
2372
2640
  try {
2373
2641
  return JSON.parse(await fs.readFile(filePath, 'utf8'));
@@ -66,9 +66,12 @@ async function main() {
66
66
  line.startsWith('- Recent routed lane:')
67
67
  || line.startsWith('- Current approach:')
68
68
  || line.startsWith('- Completion debt:')
69
+ || line.startsWith('- Execution rule:')
69
70
  || line.startsWith('- Continuation required:')
70
71
  || line.startsWith('- Stuck-lane rescue:')
72
+ || line.startsWith('- Rescue rule:')
71
73
  || line.startsWith('- Continue rule:')
74
+ || line.startsWith('- Decision rule:')
72
75
  || line.startsWith('- Previous context:')
73
76
  || line.startsWith('- Recent command output:')
74
77
  || line.startsWith('- Recent delegation hint:')
@@ -113,9 +116,9 @@ async function main() {
113
116
  compressEnabled
114
117
  ? compactContextBlock(bodyLines, {
115
118
  maxTokens,
116
- maxLines: 12,
117
- anchorLines: anchorLines.slice(0, 3),
118
- maxAnchors: 3,
119
+ maxLines: 14,
120
+ anchorLines: anchorLines.slice(0, 6),
121
+ maxAnchors: 6,
119
122
  })
120
123
  : {
121
124
  text: bodyLines.join('\n'),
@@ -284,7 +287,7 @@ function buildStaticGuidanceLines(state = {}, { compact = true } = {}) {
284
287
  '- Simple: read docs/MEMORY.md; use context resolver for related files.',
285
288
  '- Non-trivial: read docs/MEMORY.md + docs/PROJECT.md + docs/CODE_MAP.md.',
286
289
  '- WORKLOG: read only for continuation/debugging.',
287
- '- If confidence is low or the area is high-risk, escalate analysis or ask 1 short clarify question.',
290
+ '- If one safe path is clear, execute it; ask only when choices or risk need a user decision.',
288
291
  '- Reuse existing code. Use yarn. Run tests after code changes.',
289
292
  '- Scope-based verification: match verify effort to change scope.',
290
293
  '- Auto-activate matching project-local skills from prompt + tool/file signals.',
@@ -306,7 +309,7 @@ function buildStaticGuidanceLines(state = {}, { compact = true } = {}) {
306
309
  return [
307
310
  currentLaneLine,
308
311
  '- WORKLOG: read only for continuation/debugging.',
309
- '- If confidence is low or the area is high-risk, escalate analysis or ask 1 short clarify question.',
312
+ '- If one safe path is clear, execute it; ask only when choices or risk need a user decision.',
310
313
  '- Reuse existing code; use yarn; verify after changes with scope-matched effort.',
311
314
  '- Auto-activate matching project-local skills from prompt + tool/file signals.',
312
315
  ];
@@ -560,6 +563,9 @@ function buildApproachSelectorLines(state = {}) {
560
563
  || null;
561
564
  lines.push('- Completion debt: ' + missingEvidence.join(', ') + (completionRule ? ` | gate=${completionRule}` : ''));
562
565
  lines.push('- Continue rule: while completion debt remains, do not end with done/applied/fixed language unless a real blocker is found.');
566
+ if (missingEvidence.includes('write-evidence')) {
567
+ lines.push('- Execution rule: execute the next safe milestone first; explain only if blocked or the risk changes.');
568
+ }
563
569
  }
564
570
  }
565
571
 
@@ -573,6 +579,9 @@ function buildApproachSelectorLines(state = {}) {
573
579
  + (continuationState.stuckRisk ? ` | risk=${continuationState.stuckRisk}` : '')
574
580
  + (continuationState.rescueMode ? ` | mode=${continuationState.rescueMode}` : ''));
575
581
  }
582
+ if (continuationState.wideningBlocked) {
583
+ lines.push('- Rescue rule: do not widen reads yet; execute the current milestone before more analysis.');
584
+ }
576
585
  if ((continuationState.reasons ?? []).includes('pending-bounded-context')) {
577
586
  lines.push('- Continue rule: pull-indexed-context is an internal continuation step; after the bounded read, continue to edit/verify in the same turn when safe.');
578
587
  }
@@ -639,6 +648,8 @@ function deriveContinuationState(state = {}) {
639
648
  repeatCount: 1,
640
649
  stuckRisk: null,
641
650
  rescueMode: null,
651
+ wideningBlocked: false,
652
+ milestonePriority: 'normal',
642
653
  };
643
654
  }
644
655
 
@@ -12,7 +12,7 @@ Auto-generated by UKit for OpenAI Codex.
12
12
  - Do not make end users memorize skill names, helper scripts, or routing internals unless they are debugging UKit itself.
13
13
  - **Treat helper commands as internal orchestration. Do not ask end users to run them.**
14
14
 
15
- ## UKit v1.4.2 Shared Runtime
15
+ ## UKit v1.4.3 Shared Runtime
16
16
 
17
17
  - Shared runtime state lives in `.ukit/storage/`.
18
18
  - Treat `.ukit/storage/config.json` as the source of compact, token-pipeline, router, memory, validation, and Safe Patch guardrail toggles.
@@ -1,6 +1,6 @@
1
1
  # UKit Shared Runtime
2
2
 
3
- This folder stores shared UKit runtime state for v1.4.2 features.
3
+ This folder stores shared UKit runtime state for v1.4.3 features.
4
4
 
5
5
  - `storage/config.json` — runtime feature flags and defaults
6
6
  - `storage/cache/` — prompt-cache, compact history, compact pressure state, output summaries, and preserved raw tool outputs under `storage/cache/tee/`
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.4.2",
2
+ "version": "1.4.3",
3
3
  "agent": "claude-code",
4
4
  "autonomy": {
5
5
  "level": "balanced",