@zq-silk/yui 0.11.3 → 0.12.1
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/ARCHITECTURE.md +23 -4
- package/README.md +44 -22
- package/dist/cli/commandCatalog.js +13 -10
- package/dist/cli/interactionPolicy.js +5 -6
- package/dist/cli/updateCommand.js +3 -1
- package/dist/cli/updateOrchestrator.js +173 -28
- package/dist/cli/updatePorts.js +137 -8
- package/dist/cli/upgradeCommand.js +19 -9
- package/dist/cli.js +156 -57
- package/dist/commands/configCommands.js +13 -46
- package/dist/commands/executionAuditCommands.js +3 -2
- package/dist/commands/jobCommands.js +4 -10
- package/dist/commands/taskCommands.js +234 -200
- package/dist/commands/taskCompletionGate.js +29 -54
- package/dist/commands/taskContextCommand.js +61 -13
- package/dist/commands/taskInputCommands.js +8 -5
- package/dist/commands/taskNextActionCommand.js +56 -6
- package/dist/commands/taskOverviewCommand.js +17 -31
- package/dist/commands/taskRoleRuntimeStatus.js +55 -7
- package/dist/commands/taskWorkspaceCommands.js +5 -2
- package/dist/config/configCatalog.js +3 -3
- package/dist/config/yuiConfig.js +3 -7
- package/dist/context/wakeNotification.js +20 -5
- package/dist/controller/agentRuntimeObserver.js +247 -51
- package/dist/controller/clientRuntime.js +39 -3
- package/dist/controller/controller.js +31 -27
- package/dist/controller/fileSchedulerStoreAdapter.js +390 -332
- package/dist/controller/runtime.js +58 -3
- package/dist/controller/runtimeEventInbox.js +17 -7
- package/dist/controller/runtimeEventProcessor.js +12 -19
- package/dist/controller/runtimeHookRunFence.js +19 -4
- package/dist/controller/runtimeObservationHook.js +45 -0
- package/dist/controller/structuredProviderObservation.js +20 -3
- package/dist/core/controllerClient.js +20 -2
- package/dist/core/controllerServer.js +1 -0
- package/dist/execution/resourceBroker.js +5 -4
- package/dist/executor/agentExecutor.js +52 -50
- package/dist/executor/effectiveLaunch.js +8 -48
- package/dist/executor/fileRoleLaunchPlanner.js +129 -45
- package/dist/executor/workspacePreflightClassification.js +23 -2
- package/dist/interaction/operatorPresentation.js +33 -89
- package/dist/lifecycle/exactRunTerminalization.js +69 -5
- package/dist/observability/executionAudit.js +5 -0
- package/dist/observability/orchestrationMetrics.js +8 -3
- package/dist/profile/agentProfile.js +1 -1
- package/dist/release/cliHomeReleaseFence.js +123 -0
- package/dist/release/runtimeRelease.js +20 -0
- package/dist/repository/taskWorkspacePreparer.js +176 -60
- package/dist/resources/sqliteResourceRegistry.js +1 -1
- package/dist/review/deltaRecheck.js +12 -51
- package/dist/review/reviewAcceptance.js +26 -0
- package/dist/review/reviewConfig.js +0 -31
- package/dist/review/reviewDecision.js +113 -0
- package/dist/review/reviewOutcomeClassifier.js +1 -1
- package/dist/review/reviewRound.js +1 -1
- package/dist/review/reviewerAvailability.js +69 -0
- package/dist/run/recoveryProjection.js +45 -6
- package/dist/runtime/agentDriverObservation.js +24 -10
- package/dist/runtime/agentHost.js +159 -85
- package/dist/runtime/builtinAgentDrivers.js +4 -3
- package/dist/runtime/builtinTranscriptObserver.js +301 -64
- package/dist/runtime/builtinTranscriptUsage.js +9 -7
- package/dist/runtime/conversationSwitch.js +277 -0
- package/dist/runtime/index.js +2 -1
- package/dist/runtime/launchBroker.js +12 -0
- package/dist/runtime/processExitOutbox.js +88 -0
- package/dist/runtime/providerRuntimeIdentity.js +29 -1
- package/dist/runtime/runtimeHealthPolicy.js +5 -5
- package/dist/runtime/runtimeObservation.js +28 -0
- package/dist/runtime/runtimeProjection.js +22 -32
- package/dist/runtime/sessionTokenMetrics.js +181 -0
- package/dist/runtime/structuredProviderHost.js +7 -1
- package/dist/runtime/tmuxAdapters.js +4 -1
- package/dist/scheduler/activeRoleRunDelivery.js +34 -199
- package/dist/scheduler/activeTaskProgress.js +7 -6
- package/dist/scheduler/leaderWakeupProcessor.js +42 -138
- package/dist/scheduler/operatorEvent.js +34 -0
- package/dist/scheduler/operatorInputNotificationProcessor.js +54 -94
- package/dist/scheduler/roleRunStall.js +53 -31
- package/dist/scheduler/taskExecutionProjection.js +97 -76
- package/dist/scheduler/taskObservabilityProjection.js +10 -11
- package/dist/storage/migration/productionRegistry.js +379 -0
- package/dist/storage/sqliteSchema.js +66 -23
- package/dist/storage/sqliteStore.js +46 -23
- package/dist/storage/storeRpc.js +0 -1
- package/dist/storage/taskStore.js +15 -30
- package/dist/storage/upgrade/homeClassification.js +52 -0
- package/dist/storage/upgrade/offlineUpgradeInventory.js +145 -7
- package/dist/storage/upgrade/recordVersions.js +3 -2
- package/dist/storage/upgrade/sqliteMigrationTarget.js +30 -8
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +23 -11
- package/dist/storage/upgrade/sqliteStateMigration.js +66 -8
- package/dist/storage/upgrade/upgradeOrchestrator.js +333 -12
- package/dist/task/completionReadiness.js +10 -6
- package/dist/task/nextAction.js +82 -58
- package/dist/telemetry/sqliteTelemetryStore.js +1 -1
- package/dist/web/assets/client/components.js +13 -3
- package/dist/web/assets/client/i18n.js +6 -2
- package/dist/web/webSnapshot.js +7 -1
- package/i18n/README.zh-CN.md +2 -2
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +60 -20
- package/skills/yui-operator/SKILL.md +13 -4
- package/skills/yui-reviewer/SKILL.md +35 -11
- package/dist/context/sessionContextBudget.js +0 -71
- package/dist/lifecycle/contextBudgetRollover.js +0 -81
- package/dist/lifecycle/taskRoleSessionReset.js +0 -126
- package/dist/scheduler/operatorNotification.js +0 -59
package/dist/task/nextAction.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { isDeepStrictEqual } from "node:util";
|
|
2
3
|
import { changeSetDeliverySettled, governingChangeSets } from "../integration/deliveryObligation.js";
|
|
3
|
-
import {
|
|
4
|
-
import { classifyReviewRoundOutcome
|
|
4
|
+
import { isAcceptedTaskReviewBaselineFromEvidence } from "../review/reviewAcceptance.js";
|
|
5
|
+
import { classifyReviewRoundOutcome } from "../review/reviewOutcomeClassifier.js";
|
|
5
6
|
import { actionableExecutionLaneRecoveries } from "../execution/executionHealth.js";
|
|
6
7
|
import { candidateConvergenceDisagreement, candidateConvergenceEvidenceSufficient, candidateConvergenceStageResultsValid } from "../execution/candidateConvergence.js";
|
|
7
8
|
import { executionStageSpendClosed, routeExecutionStage } from "../execution/resourceBroker.js";
|
|
9
|
+
import { sameTaskFinalReviewContract } from "../review/taskFinalReviewContract.js";
|
|
8
10
|
import { resolveRecordedTaskFinalReviewContract } from "../review/taskFinalReviewContractRebind.js";
|
|
9
11
|
import { currentWorkItemCandidate, currentWorkItemExecutionGroup, governingWorkItemCandidate } from "../workItem/workItem.js";
|
|
10
12
|
const OPEN_WORK_ITEM_STATUSES = new Set(["pending", "running", "awaiting_acceptance"]);
|
|
@@ -48,40 +50,6 @@ export function projectNextAction(facts) {
|
|
|
48
50
|
if (laneRecovery !== undefined) {
|
|
49
51
|
return buildExecutionLaneRecoveryAction(facts, laneRecovery);
|
|
50
52
|
}
|
|
51
|
-
// Quick Win (EXE-03): a resume Run that failed before durable Provider
|
|
52
|
-
// acceptance must not be retried against the same native Session. The
|
|
53
|
-
// authoritative next action is to replace the Session, not to retry the
|
|
54
|
-
// same delivery. The guard only applies while the failed resume Run is the
|
|
55
|
-
// *latest* Leader Run: once a newer Run exists (the fresh-Session launch),
|
|
56
|
-
// the historical failure is stale and must not keep recommending a Session
|
|
57
|
-
// replacement.
|
|
58
|
-
const latestLeaderRun = facts.leaderRuns.at(-1);
|
|
59
|
-
const failedResumeWithoutAcceptance = latestLeaderRun !== undefined
|
|
60
|
-
&& latestLeaderRun.mode === "resume"
|
|
61
|
-
&& latestLeaderRun.status === "failed"
|
|
62
|
-
&& latestLeaderRun.deliveredAt === undefined
|
|
63
|
-
? latestLeaderRun
|
|
64
|
-
: undefined;
|
|
65
|
-
if (failedResumeWithoutAcceptance !== undefined) {
|
|
66
|
-
return buildAction(facts, {
|
|
67
|
-
kind: "replace-leader-session",
|
|
68
|
-
reason: `Leader resume Run ${failedResumeWithoutAcceptance.id} failed before Provider acceptance; `
|
|
69
|
-
+ "the native Session is proven unusable for this delivery. Replace it with a fresh Session "
|
|
70
|
-
+ "after exact cleanup/reset.",
|
|
71
|
-
refs: [ref("agent-run", failedResumeWithoutAcceptance.id)],
|
|
72
|
-
preconditions: [
|
|
73
|
-
{ fact: "Resume Run failed without durable acceptance", satisfied: true, ref: ref("agent-run", failedResumeWithoutAcceptance.id) },
|
|
74
|
-
{ fact: "Old Session is cleaned up or reset before fresh launch", satisfied: false }
|
|
75
|
-
],
|
|
76
|
-
// The failed resume Run is already terminal, so `task run recover
|
|
77
|
-
// --action replace-session` (which requires an active Run) cannot act
|
|
78
|
-
// on it. The working recovery is to reset the Role's Session
|
|
79
|
-
// generation, then clear the Leader failure so the next wake launches
|
|
80
|
-
// a fresh Session (the failed-resume guard in the wakeup processor
|
|
81
|
-
// forces mode=new for the next launch).
|
|
82
|
-
recommendedCommand: `yui task role reset ${task.id} leader --reason "resume failed before acceptance" && yui jobs retry leader-recovery:${task.id}`
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
53
|
const activeLeader = facts.activeRuns.find((run) => run.roleName === "leader");
|
|
86
54
|
if (activeLeader !== undefined) {
|
|
87
55
|
return buildAction(facts, {
|
|
@@ -232,13 +200,15 @@ export function projectNextAction(facts) {
|
|
|
232
200
|
judgmentRequired: `Leader must judge Candidate ${candidateReady.id}/${candidate?.id ?? "unknown"} against the Task objective, acceptance criteria, and delivery risk.`
|
|
233
201
|
});
|
|
234
202
|
}
|
|
235
|
-
|
|
236
|
-
|
|
203
|
+
// AgentRun purpose owns routing. Review Runs remain attached to their exact
|
|
204
|
+
// ReviewRound branches below instead of being mistaken for Worker delivery.
|
|
205
|
+
const activeDelegatedExecutions = facts.activeRuns.filter((run) => (run.purpose === "execution" && run.roleName !== "leader"));
|
|
206
|
+
if (activeDelegatedExecutions.length > 0) {
|
|
237
207
|
return buildAction(facts, {
|
|
238
208
|
kind: "wait-for-owned-execution",
|
|
239
|
-
reason: `${
|
|
240
|
-
refs:
|
|
241
|
-
preconditions:
|
|
209
|
+
reason: `${activeDelegatedExecutions.length} delegated execution Run(s) are active; wait for their delivery.`,
|
|
210
|
+
refs: activeDelegatedExecutions.map((run) => ref("agent-run", run.id)),
|
|
211
|
+
preconditions: activeDelegatedExecutions.map((run) => ({ fact: `Execution Run ${run.id} is active`, satisfied: true, ref: ref("agent-run", run.id) }))
|
|
242
212
|
});
|
|
243
213
|
}
|
|
244
214
|
const failedWork = facts.workItems.find((item) => item.status === "failed");
|
|
@@ -386,7 +356,8 @@ export function projectNextAction(facts) {
|
|
|
386
356
|
});
|
|
387
357
|
}
|
|
388
358
|
const finalReviewRequired = taskFinalReviewRequired(facts);
|
|
389
|
-
const
|
|
359
|
+
const finalReviewContract = taskFinalReviewContract(facts);
|
|
360
|
+
const failedFinal = latestTaskFinalReview(facts.reviewRounds, finalReviewContract);
|
|
390
361
|
const failedFinalOutcome = failedFinal === undefined
|
|
391
362
|
? null
|
|
392
363
|
: classifyReviewRoundOutcome(failedFinal, nextActionReviewOutcomeEvidence(facts));
|
|
@@ -414,11 +385,38 @@ export function projectNextAction(facts) {
|
|
|
414
385
|
]
|
|
415
386
|
});
|
|
416
387
|
}
|
|
388
|
+
if (finalReviewRequired
|
|
389
|
+
&& failedFinal !== undefined
|
|
390
|
+
&& failedFinalOutcome?.kind === "semantic"
|
|
391
|
+
&& failedFinal.deltaRecheck?.disposition === "requires-full-review") {
|
|
392
|
+
return buildAction(facts, {
|
|
393
|
+
kind: "request-final-review",
|
|
394
|
+
reason: `Delta Recheck ${failedFinal.id} could not establish equivalence; Yui recorded the result and left the next Review action to the Leader.`,
|
|
395
|
+
refs: [ref("review-round", failedFinal.id)],
|
|
396
|
+
preconditions: [
|
|
397
|
+
{ fact: "Current frozen head has accepting final Review evidence", satisfied: false }
|
|
398
|
+
],
|
|
399
|
+
alternatives: [
|
|
400
|
+
{
|
|
401
|
+
kind: "request-full-review",
|
|
402
|
+
reason: "Request a full Review when independent evidence is still required.",
|
|
403
|
+
recommendedCommand: `yui task review request ${task.id} --role ${failedFinal.reviewerRoleName}`,
|
|
404
|
+
refs: [ref("review-round", failedFinal.id)]
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
kind: "continue-leader-work",
|
|
408
|
+
reason: "Inspect directly, change the candidate, or choose another Reviewer as Task risk requires.",
|
|
409
|
+
refs: [ref("review-round", failedFinal.id)]
|
|
410
|
+
}
|
|
411
|
+
],
|
|
412
|
+
judgmentRequired: "Leader must choose full Review, another Reviewer, direct inspection, or more development; Core will not auto-escalate."
|
|
413
|
+
});
|
|
414
|
+
}
|
|
417
415
|
if (finalReviewRequired
|
|
418
416
|
&& failedFinal !== undefined
|
|
419
417
|
&& failedFinalOutcome?.kind === "semantic"
|
|
420
418
|
&& ((failedFinal.checks ?? []).some(({ outcome }) => outcome === "failed")
|
|
421
|
-
||
|
|
419
|
+
|| failedFinal.deltaRecheck?.disposition === "finding")) {
|
|
422
420
|
return buildAction(facts, {
|
|
423
421
|
kind: "route-review-findings",
|
|
424
422
|
reason: `Task-final Review ${failedFinal.id} delivered semantic negative evidence; route its open findings into a repair wave on one frozen head.`,
|
|
@@ -429,7 +427,7 @@ export function projectNextAction(facts) {
|
|
|
429
427
|
recommendedCommand: `yui task review finding repair-wave ${task.id} --create`
|
|
430
428
|
});
|
|
431
429
|
}
|
|
432
|
-
const activeFinal = latestTaskFinalReview(facts.reviewRounds);
|
|
430
|
+
const activeFinal = latestTaskFinalReview(facts.reviewRounds, finalReviewContract);
|
|
433
431
|
if (activeFinal !== undefined
|
|
434
432
|
&& (activeFinal.status === "pending" || activeFinal.status === "running")) {
|
|
435
433
|
const reviewRef = ref("review-round", activeFinal.id);
|
|
@@ -475,12 +473,26 @@ export function projectNextAction(facts) {
|
|
|
475
473
|
}
|
|
476
474
|
return buildAction(facts, {
|
|
477
475
|
kind: "wait-for-owned-execution",
|
|
478
|
-
reason: `Reviewer Run ${reviewRun.id} is executing Task-final Review ${activeFinal.id}.`,
|
|
476
|
+
reason: `Reviewer Run ${reviewRun.id} is executing frozen Task-final Review ${activeFinal.id}; this Review does not globally pause Leader decisions on newer facts.`,
|
|
479
477
|
refs: [reviewRef, ref("agent-run", reviewRun.id)],
|
|
480
478
|
preconditions: [
|
|
481
479
|
{ fact: "Task-final ReviewRound is running", satisfied: true, ref: reviewRef },
|
|
482
480
|
{ fact: "Reviewer Run is active", satisfied: true, ref: ref("agent-run", reviewRun.id) }
|
|
483
|
-
]
|
|
481
|
+
],
|
|
482
|
+
alternatives: [
|
|
483
|
+
{
|
|
484
|
+
kind: "continue-leader-work",
|
|
485
|
+
reason: "Process new user input or advance a later candidate while preserving this frozen Review.",
|
|
486
|
+
refs: [reviewRef]
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
kind: "request-another-reviewer",
|
|
490
|
+
reason: "Use another available Reviewer slot when an independent view adds value.",
|
|
491
|
+
recommendedCommand: `yui task review request ${task.id} --role <other-reviewer-role>`,
|
|
492
|
+
refs: [reviewRef]
|
|
493
|
+
}
|
|
494
|
+
],
|
|
495
|
+
judgmentRequired: "Leader decides whether the current facts justify waiting, continuing development, direct review, or another Reviewer."
|
|
484
496
|
});
|
|
485
497
|
}
|
|
486
498
|
if (activeFinal.reviewerRunId !== undefined) {
|
|
@@ -530,11 +542,16 @@ export function projectNextAction(facts) {
|
|
|
530
542
|
}
|
|
531
543
|
const finalReviewOptional = !finalReviewRequired
|
|
532
544
|
&& !hasValidFinalReview(facts);
|
|
533
|
-
const
|
|
545
|
+
const unresolvedDelta = failedFinal?.deltaRecheck?.disposition === "requires-full-review";
|
|
546
|
+
const optionalReviewer = facts.reviewConfig?.roleName
|
|
547
|
+
?? (unresolvedDelta ? failedFinal?.reviewerRoleName : undefined);
|
|
548
|
+
const finalReviewAlternative = finalReviewOptional && optionalReviewer !== undefined
|
|
534
549
|
? [{
|
|
535
550
|
kind: "request-final-review",
|
|
536
|
-
reason:
|
|
537
|
-
|
|
551
|
+
reason: unresolvedDelta
|
|
552
|
+
? `Delta Recheck ${failedFinal.id} returned requires-full-review; request full independent evidence when the Leader judges it necessary.`
|
|
553
|
+
: "Request an independent Task-final Review when the Leader wants extra assurance before completion.",
|
|
554
|
+
recommendedCommand: `yui task review request ${task.id} --role ${optionalReviewer}`,
|
|
538
555
|
refs: [ref("task", task.id)]
|
|
539
556
|
}]
|
|
540
557
|
: [];
|
|
@@ -564,7 +581,9 @@ export function projectNextAction(facts) {
|
|
|
564
581
|
...(!finalReviewOptional
|
|
565
582
|
? {}
|
|
566
583
|
: {
|
|
567
|
-
judgmentRequired:
|
|
584
|
+
judgmentRequired: unresolvedDelta
|
|
585
|
+
? "Leader must route the non-accepting Delta result: full Review, another Reviewer, direct inspection, more development, or completion when policy permits."
|
|
586
|
+
: "Leader must decide whether the frozen Task result is safe to complete or needs one optional Task-final Review."
|
|
568
587
|
}),
|
|
569
588
|
recommendedCommand: `yui task complete ${task.id} --summary-file -`
|
|
570
589
|
});
|
|
@@ -1013,10 +1032,11 @@ function latestFailedReviewFor(rounds, workItemId) {
|
|
|
1013
1032
|
.reverse()
|
|
1014
1033
|
.find((round) => round.workItemId === workItemId && round.status === "failed");
|
|
1015
1034
|
}
|
|
1016
|
-
function latestTaskFinalReview(rounds) {
|
|
1035
|
+
function latestTaskFinalReview(rounds, contract) {
|
|
1017
1036
|
return [...rounds]
|
|
1018
1037
|
.reverse()
|
|
1019
|
-
.find((round) => (round.scope ?? "work-item") === "task"
|
|
1038
|
+
.find((round) => ((round.scope ?? "work-item") === "task"
|
|
1039
|
+
&& (contract === undefined || sameTaskFinalReviewContract(round.taskFinalReviewContract, contract))));
|
|
1020
1040
|
}
|
|
1021
1041
|
function needsChangeSetCapture(facts, item) {
|
|
1022
1042
|
if (item.status !== "completed")
|
|
@@ -1036,13 +1056,17 @@ function needsChangeSetCapture(facts, item) {
|
|
|
1036
1056
|
return candidate.workspace !== undefined || candidate.gitSnapshot !== undefined;
|
|
1037
1057
|
}
|
|
1038
1058
|
function hasValidFinalReview(facts) {
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1059
|
+
const contract = taskFinalReviewContract(facts);
|
|
1060
|
+
const final = [...facts.reviewRounds]
|
|
1061
|
+
.reverse()
|
|
1062
|
+
.find((round) => ((round.scope ?? "work-item") === "task"
|
|
1063
|
+
&& (contract === undefined || sameTaskFinalReviewContract(round.taskFinalReviewContract, contract))));
|
|
1064
|
+
if (final === undefined || !isAcceptedTaskReviewBaselineFromEvidence(final, nextActionReviewOutcomeEvidence(facts)))
|
|
1045
1065
|
return false;
|
|
1066
|
+
if (facts.currentTaskReviewCandidate !== undefined) {
|
|
1067
|
+
return facts.currentTaskReviewCandidate !== null
|
|
1068
|
+
&& isDeepStrictEqual(final.taskCandidate, facts.currentTaskReviewCandidate);
|
|
1069
|
+
}
|
|
1046
1070
|
const reviewedCommits = new Set((final.taskCandidate?.projects ?? []).map((project) => project.commit));
|
|
1047
1071
|
if (reviewedCommits.size === 0)
|
|
1048
1072
|
return false;
|
|
@@ -246,7 +246,7 @@ export class SqliteTelemetryStore {
|
|
|
246
246
|
db.pragma("foreign_keys = ON");
|
|
247
247
|
db.pragma("busy_timeout = 5000");
|
|
248
248
|
db.pragma("wal_autocheckpoint = 1000");
|
|
249
|
-
migrateSqliteSchema(db);
|
|
249
|
+
migrateSqliteSchema(db, { mode: "validate" });
|
|
250
250
|
this.#db = db;
|
|
251
251
|
return db;
|
|
252
252
|
}
|
|
@@ -114,9 +114,9 @@ export function executionBand(projection, t, locale) {
|
|
|
114
114
|
head.append(pill(t, "exec.status", projection.status));
|
|
115
115
|
head.append(node("span", "exec-band-owner",
|
|
116
116
|
t("exec.owner." + projection.owner) + " · " + t("exec.action." + projection.action)));
|
|
117
|
-
if (projection.
|
|
117
|
+
if (projection.activeRuns && projection.activeRuns.length > 0) {
|
|
118
118
|
head.append(node("span", "exec-band-executors",
|
|
119
|
-
projection.
|
|
119
|
+
projection.activeRuns.length + " " + t("exec.executors")));
|
|
120
120
|
}
|
|
121
121
|
if (projection.monitoring === "stopped") {
|
|
122
122
|
head.append(node("span", "exec-band-stopped", t("exec.monitoring.stopped")));
|
|
@@ -242,7 +242,6 @@ export function observabilityMetricCard(observability, t) {
|
|
|
242
242
|
card.append(metricTile(t("detail.wallClock"), cost.wallClockSeconds + "s"));
|
|
243
243
|
card.append(metricTile(t("detail.ready"), (observability.dag?.readyIds || []).length, { hot: true }));
|
|
244
244
|
card.append(metricTile(t("detail.contextSnapshots"), context.snapshotCount));
|
|
245
|
-
card.append(metricTile(t("detail.contextPeak"), context.observedInputPeakTokens));
|
|
246
245
|
const contextMeta = node("div", "record-meta observability-context-meta");
|
|
247
246
|
contextMeta.append(node("span", "", t("detail.contextBytes") + " · "
|
|
248
247
|
+ (context.totalBytes === null ? t("detail.partial") : context.totalBytes + " B")));
|
|
@@ -775,6 +774,17 @@ export function roleCard(role, task, t, locale, actions) {
|
|
|
775
774
|
card.append(eff);
|
|
776
775
|
}
|
|
777
776
|
|
|
777
|
+
if (role.sessionTokens) {
|
|
778
|
+
const tokenMeta = node("div", "record-meta");
|
|
779
|
+
const cumulative = role.sessionTokens.cumulativeTotal || {};
|
|
780
|
+
const maximum = role.sessionTokens.maximumRequestInput || {};
|
|
781
|
+
tokenMeta.append(node("span", "", t("detail.sessionTotalTokens") + " · "
|
|
782
|
+
+ (cumulative.status === "observed" ? cumulative.totalTokens : t("detail.unobserved"))));
|
|
783
|
+
tokenMeta.append(node("span", "", t("detail.maximumRequestInputTokens") + " · "
|
|
784
|
+
+ (maximum.status === "observed" ? maximum.inputTokens : t("detail.unobserved"))));
|
|
785
|
+
card.append(tokenMeta);
|
|
786
|
+
}
|
|
787
|
+
|
|
778
788
|
if (role.description) card.append(richText(null, role.description, t, { muted: true }));
|
|
779
789
|
|
|
780
790
|
const cols = node("div", "record-cols");
|
|
@@ -61,17 +61,19 @@ const messages = {
|
|
|
61
61
|
"detail.stageAttempt": "Attempt",
|
|
62
62
|
"detail.cost": "Cost",
|
|
63
63
|
"detail.tokens": "Tokens",
|
|
64
|
+
"detail.sessionTotalTokens": "Session total tokens",
|
|
65
|
+
"detail.maximumRequestInputTokens": "Maximum request input",
|
|
64
66
|
"detail.toolCalls": "Tool calls",
|
|
65
67
|
"detail.wallClock": "Wall clock",
|
|
66
68
|
"detail.ready": "Ready",
|
|
67
69
|
"detail.quorum": "Quorum",
|
|
68
70
|
"detail.contextSnapshots": "Context snapshots",
|
|
69
|
-
"detail.contextPeak": "Context peak",
|
|
70
71
|
"detail.contextBytes": "Context bytes",
|
|
71
72
|
"detail.compression": "Compression",
|
|
72
73
|
"detail.marginalValue": "Marginal value",
|
|
73
74
|
"detail.partial": "partial",
|
|
74
75
|
"detail.unavailable": "unavailable",
|
|
76
|
+
"detail.unobserved": "unobserved",
|
|
75
77
|
"detail.openFindings": "Open findings",
|
|
76
78
|
"detail.desired": "Desired launch",
|
|
77
79
|
"detail.desiredAgent": "Desired Agent",
|
|
@@ -397,17 +399,19 @@ const messages = {
|
|
|
397
399
|
"detail.stageAttempt": "阶段尝试",
|
|
398
400
|
"detail.cost": "成本",
|
|
399
401
|
"detail.tokens": "Token",
|
|
402
|
+
"detail.sessionTotalTokens": "Session 累计 Token",
|
|
403
|
+
"detail.maximumRequestInputTokens": "单次请求最大输入",
|
|
400
404
|
"detail.toolCalls": "工具调用",
|
|
401
405
|
"detail.wallClock": "墙钟时间",
|
|
402
406
|
"detail.ready": "可就绪",
|
|
403
407
|
"detail.quorum": "法定数量",
|
|
404
408
|
"detail.contextSnapshots": "上下文快照",
|
|
405
|
-
"detail.contextPeak": "上下文峰值",
|
|
406
409
|
"detail.contextBytes": "上下文字节",
|
|
407
410
|
"detail.compression": "压缩",
|
|
408
411
|
"detail.marginalValue": "边际价值",
|
|
409
412
|
"detail.partial": "部分可见",
|
|
410
413
|
"detail.unavailable": "不可用",
|
|
414
|
+
"detail.unobserved": "未观测",
|
|
411
415
|
"detail.openFindings": "未解决发现",
|
|
412
416
|
"detail.desired": "期望启动配置",
|
|
413
417
|
"detail.desiredAgent": "期望 Agent",
|
package/dist/web/webSnapshot.js
CHANGED
|
@@ -7,6 +7,7 @@ import { classifyRuntimeHealth, projectRuntimeTaskEvents } from "../runtime/runt
|
|
|
7
7
|
import { builtinDriverIdForAdapter } from "../runtime/builtinAgentDrivers.js";
|
|
8
8
|
import { formatAgentRunReceiptId } from "../task/taskRecordReference.js";
|
|
9
9
|
import { resolveRuntimeHealth } from "../config/yuiConfig.js";
|
|
10
|
+
import { projectSessionTokenMetrics, resolveSessionTokenIdentity } from "../runtime/sessionTokenMetrics.js";
|
|
10
11
|
export function buildWebDashboardSnapshot(store, now = new Date()) {
|
|
11
12
|
return store.transaction((reader) => {
|
|
12
13
|
const statusCounts = {
|
|
@@ -97,6 +98,9 @@ export function buildWebTaskDetail(store, taskId, now = new Date()) {
|
|
|
97
98
|
const effectiveLaunch = activeRun?.effective ?? activeSession?.effective ?? null;
|
|
98
99
|
return {
|
|
99
100
|
...role,
|
|
101
|
+
sessionTokens: projectSessionTokenMetrics(events, resolveSessionTokenIdentity(activeSession === undefined
|
|
102
|
+
? null
|
|
103
|
+
: { taskId, roleName: role.name, ...activeSession })),
|
|
100
104
|
effectiveLaunch,
|
|
101
105
|
effectiveLaunchSource: activeRun === undefined
|
|
102
106
|
? activeSession === undefined ? null : "session"
|
|
@@ -220,7 +224,9 @@ function projectWebRunRuntimeHealth(reader, taskId, run, events, now, policy) {
|
|
|
220
224
|
}
|
|
221
225
|
function latestStallField(events, runId, field) {
|
|
222
226
|
const stalled = events
|
|
223
|
-
.filter((event) => event.type === "run.stalled"
|
|
227
|
+
.filter((event) => event.type === "run.stalled"
|
|
228
|
+
&& event.payload.runId === runId
|
|
229
|
+
&& event.payload.status !== "diagnostic-only")
|
|
224
230
|
.sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt))[0];
|
|
225
231
|
return stalled?.payload[field];
|
|
226
232
|
}
|
package/i18n/README.zh-CN.md
CHANGED
|
@@ -308,7 +308,7 @@ yui task work group resolve <task-id>/<work-item-id> \
|
|
|
308
308
|
|
|
309
309
|
每个新阶段还会冻结一份 Resource Broker 契约:token、工具调用和墙钟预算,
|
|
310
310
|
quorum 与 deadline,straggler 窗口,以及继续增加 Lane 所需的最低边际价值。
|
|
311
|
-
|
|
311
|
+
省略这些参数时使用独立的执行成本默认值与 runtime-health 时间窗;同一阶段的 retry
|
|
312
312
|
累计原有花费并共享绝对 deadline。执行、Lane retry 和 Reviewer panel 准入统一核算
|
|
313
313
|
Home、Task、WorkItem、Group、Provider、Agent 和模型层级的活动 Lane;容量不足的
|
|
314
314
|
Lane 会耐久保留为 pending,不会把整个 Group 判失败。容量释放或 deadline 到达会沿
|
|
@@ -484,7 +484,7 @@ yui task input request <task-id> --question "默认使用哪种格式?" \
|
|
|
484
484
|
|
|
485
485
|
推荐项会明确展示给用户;如果截止时间前没有回答,独立的最近 deadline timer 会唤醒 Controller,原子采用这个确定选项,并排队恢复固定的 Leader session。自由文本和必须由用户回答的请求永远不会自动解决。
|
|
486
486
|
|
|
487
|
-
`task input list` 是权威的全局开放输入 Inbox;可附加 Task ID 限定范围,或使用 `--all` 查看已回答和已取消的请求。Controller
|
|
487
|
+
`task input list` 是权威的全局开放输入 Inbox;可附加 Task ID 限定范围,或使用 `--all` 查看已回答和已取消的请求。Task 完成、退役、Leader attention、stall 和开放输入只以不可变 TaskEvent 或 InputRequest 引用进入全局 Operator mailbox。Controller 把一个待处理 batch 合并成一条带回执的 `[Yui updates]` user message,仅投递给已有且 ready 的 Operator;Operator 再通过 CLI 读取引用记录,判断哪些信息值得呈现。Operator 正在运行或不可用时,Yui 不启动也不打断它,整批引用保持持久化,并在原生 turn 完成或后续 Controller 处理中重试。该路径是 user message,不是 tool call,也不会读取或分类 Agent 终端文本。用户和 Operator 都可回答。存在开放请求时,无关的 pending wake 不会绕过等待,Task 也不能 complete 或 archive。原 Leader 也可执行 `yui task input cancel <task-id> <input-id> --reason "..."`,取消会排队恢复该固定 Leader session。
|
|
488
488
|
|
|
489
489
|
```sh
|
|
490
490
|
yui task context <task-id>
|
package/package.json
CHANGED
|
@@ -323,12 +323,14 @@ Choose before creating the WorkItem:
|
|
|
323
323
|
Keep review execution separate from implementation. No global Reviewer is
|
|
324
324
|
required: when review is disabled, inspect and decide directly or delegate a
|
|
325
325
|
bounded review to a native subagent or ordinary Worker. When a managed
|
|
326
|
-
ReviewRound is explicitly
|
|
327
|
-
write-capable `reviewer` Profile
|
|
328
|
-
|
|
326
|
+
ReviewRound is explicitly requested, its reviewer uses the single built-in
|
|
327
|
+
write-capable `reviewer` Profile. Each Task Reviewer Role keeps one stable,
|
|
328
|
+
isolated Session and physical workspace slot; every ReviewRound updates that
|
|
329
|
+
slot to its exact frozen scope and records a new immutable ownership snapshot:
|
|
329
330
|
the assigned WorkItem Candidate or the committed Integration heads of a
|
|
330
331
|
Task-final Review. Never reuse the Candidate/Worker workspace or its
|
|
331
|
-
implementation Role Session.
|
|
332
|
+
implementation Role Session. Multiple Reviewer Roles use independent slots
|
|
333
|
+
and may run in parallel. Codex and Claude may use their normal configured
|
|
332
334
|
full capability in that isolated worktree; the behavioral boundary forbids
|
|
333
335
|
push, Integration, Task mutation, other workspaces, stable checkouts, and the
|
|
334
336
|
real Yui control-plane home. When
|
|
@@ -336,7 +338,9 @@ creating an explicit Task Role binding, also set and read back the required
|
|
|
336
338
|
model and effort instead of relying on CLI defaults.
|
|
337
339
|
Every managed reviewer must deliver through the current Run's exact
|
|
338
340
|
`--summary-file -` yield command; a final response alone is not a durable
|
|
339
|
-
handoff.
|
|
341
|
+
handoff. Read the completed result as one review batch and route all reported
|
|
342
|
+
findings together; do not manufacture another ReviewRound merely because one
|
|
343
|
+
finding was handled before the rest of the batch.
|
|
340
344
|
|
|
341
345
|
A direct or native-subagent WorkItem is roleless. A Task Role WorkItem must be
|
|
342
346
|
created with `--role <role>`; do not retrofit the Role later. Reuse a compatible
|
|
@@ -526,8 +530,8 @@ authorized expansions.
|
|
|
526
530
|
bounded evidence-gathering review to a native subagent or ordinary Worker,
|
|
527
531
|
then make the Leader-owned accept/reject decision. Do not create a Reviewer
|
|
528
532
|
Role merely to satisfy an old setup convention.
|
|
529
|
-
- `always`:
|
|
530
|
-
terminal.
|
|
533
|
+
- `always`: keep the Candidate decision pending until its required ReviewRound
|
|
534
|
+
is terminal. The Review does not globally pause unrelated Leader work.
|
|
531
535
|
- `leader`: decide whether the existing evidence is sufficient. Request Agent
|
|
532
536
|
review with `yui task work review <work-id>` when it adds useful evidence.
|
|
533
537
|
- `final`: keep WorkItem acceptance and integration independent. After all
|
|
@@ -535,10 +539,39 @@ authorized expansions.
|
|
|
535
539
|
Task-final ReviewRound over the frozen Task candidate. A Task contract may
|
|
536
540
|
require it. The final Reviewer evaluates the complete result across bound
|
|
537
541
|
Projects; it is not a second per-WorkItem approval protocol.
|
|
538
|
-
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
+
- Before choosing a Task-final Review action, read `task context` or
|
|
543
|
+
`task next-action` and inspect every active AgentRun's purpose and exact
|
|
544
|
+
WorkItem/ReviewRound binding, the current durable heads, active Reviews,
|
|
545
|
+
each Reviewer's availability, the latest accepted baseline, candidate
|
|
546
|
+
relation, and Delta facts. These are decision support, not an autopilot;
|
|
547
|
+
a Review Run is evidence in progress, not a global Task lock.
|
|
548
|
+
- A changed Task head may justify a new semantic Task-final Round. Reuse the
|
|
549
|
+
same Reviewer Role Session and stable workspace; Round id, full versus Delta
|
|
550
|
+
mode, desired revision, and frozen commit do not require a replacement
|
|
551
|
+
Session. Round identity still binds each Run to the exact frozen head.
|
|
552
|
+
- An active Task-final Review freezes candidate A only. Continue handling new
|
|
553
|
+
user input and, when appropriate, advance candidate B. Always consume A's
|
|
554
|
+
result, then route it as exact evidence for A, a baseline for descendant B,
|
|
555
|
+
or historical evidence for a diverged candidate. Do not cancel or discard A
|
|
556
|
+
merely because Task main moved.
|
|
557
|
+
- Read active Review facts directly from its ReviewRound: frozen Project
|
|
558
|
+
commits define that Review's evidence boundary; current candidate relation,
|
|
559
|
+
active Run, and workspace references describe current execution. Do not infer
|
|
560
|
+
a Task lock or wait for a synthetic freeze lifecycle before advancing Task
|
|
561
|
+
main.
|
|
562
|
+
- If Yui reports a Reviewer `busy`, wait for the suggested interval, select a
|
|
563
|
+
different Reviewer, review directly, or continue other work. Busy is a
|
|
564
|
+
scheduling fact, not a failed Review and not a reason to reset the Session.
|
|
565
|
+
- Prefer Delta Recheck for a technically available, contiguous change over an
|
|
566
|
+
accepted baseline when the semantic risk is bounded. Use the exact changed
|
|
567
|
+
files, line counts, diff, previous evidence, Task intent, and Project Policy
|
|
568
|
+
to choose full Review, Delta, direct Review, another Reviewer, or no Review;
|
|
569
|
+
Yui does not choose the mode from generic thresholds.
|
|
570
|
+
- Delta `requires-full-review` returns control to the Leader. Decide whether a
|
|
571
|
+
full Review, another Reviewer, direct inspection, or more development is
|
|
572
|
+
useful; Yui must not auto-create the next Round. `repeated-full-review` is a
|
|
573
|
+
cost advisory for an unchanged candidate/Reviewer intent, never an exhausted
|
|
574
|
+
budget or a prohibition on new evidence.
|
|
542
575
|
- A completed review is advice. Decide whether to accept, reject, review again,
|
|
543
576
|
or ask the user.
|
|
544
577
|
- Route a reachable final-Review finding to the original Worker while that
|
|
@@ -563,11 +596,16 @@ authorized expansions.
|
|
|
563
596
|
full Round over the identical frozen heads. It fails closed for every
|
|
564
597
|
semantic or ambiguous prior result; target the new failed Round explicitly
|
|
565
598
|
if another non-semantic failure occurs.
|
|
599
|
+
- For `review.failed-to-start`, open the referenced ReviewRound and inspect its
|
|
600
|
+
exact reason, frozen candidate, and workspace when present. Decide whether to
|
|
601
|
+
retry, explicitly clean a conflicting workspace, select another Reviewer, or
|
|
602
|
+
continue other work. Preserve the failed Round as request history and do not
|
|
603
|
+
turn these choices into an automatic retry or cleanup loop.
|
|
566
604
|
- Use `task next-action`'s derived Review outcome literally: non-semantic means
|
|
567
605
|
recover the same frozen head with `force-fresh`; ambiguous means diagnose the
|
|
568
606
|
inconsistent evidence without creating a Repair WorkItem; only semantic
|
|
569
|
-
negative evidence may create a repair wave.
|
|
570
|
-
|
|
607
|
+
negative evidence may create a repair wave. There is no semantic Review
|
|
608
|
+
budget; exact candidate/Reviewer/intent retries reuse existing evidence.
|
|
571
609
|
- If the same non-resource user choice or unavailable external fact repeats,
|
|
572
610
|
persist context and create an InputRequest instead of looping. Never use an
|
|
573
611
|
InputRequest to solicit authorization for an unrequested real-resource test;
|
|
@@ -612,10 +650,11 @@ accept an isolated result while any writable Project's latest ChangeSet is
|
|
|
612
650
|
unintegrated.
|
|
613
651
|
|
|
614
652
|
Workspace ownership is not Role ownership. The WorkItem owns its Develop
|
|
615
|
-
workspace even when a Task Role executes there;
|
|
616
|
-
|
|
617
|
-
its
|
|
618
|
-
|
|
653
|
+
workspace even when a Task Role executes there; a Task Reviewer Role keeps one
|
|
654
|
+
stable physical workspace while each ReviewRound owns the exact frozen
|
|
655
|
+
workspace evidence for its Run, and each IntegrationAttempt owns its candidate
|
|
656
|
+
worktree. Dispatch attaches snapshots only. Review workspace cleanup is
|
|
657
|
+
explicit, and review edits can never feed WorkItem ChangeSet capture.
|
|
619
658
|
|
|
620
659
|
Yui validates a candidate and advances the target with compare-and-swap. A
|
|
621
660
|
failed candidate does not advance the target. Inspect and resolve semantic
|
|
@@ -745,8 +784,9 @@ yui task complete <task-id> --summary "<outcome, validation, and remaining risks
|
|
|
745
784
|
```
|
|
746
785
|
|
|
747
786
|
Retire obsolete WorkItems with `yui task work retire <task>/<work> --summary
|
|
748
|
-
"..."`, optionally using `--replacement`. If the current
|
|
749
|
-
|
|
750
|
-
|
|
787
|
+
"..."`, optionally using `--replacement`. If the current Provider Conversation
|
|
788
|
+
cannot continue, request a bounded switch with
|
|
789
|
+
`yui task role session switch <task> <role> --reason "..."`; the current
|
|
790
|
+
Conversation remains authoritative until Yui safely binds the replacement. Archiving is a
|
|
751
791
|
separate global Operator lifecycle action. It performs the final Task-owned
|
|
752
792
|
runtime and clean-worktree teardown, including this Leader.
|
|
@@ -46,6 +46,15 @@ mind and avoid imposing a fixed heading, field, section, or character
|
|
|
46
46
|
template; one semantic event should have one concise summary unless a later
|
|
47
47
|
role adds a genuinely new decision or impact.
|
|
48
48
|
|
|
49
|
+
A `[Yui updates]` user message is only a wake envelope containing durable
|
|
50
|
+
InputRequest or TaskEvent references. Read those exact records through `yui`
|
|
51
|
+
before responding, merge related references into one user-level update, and
|
|
52
|
+
then end the turn normally. Never create or keep a Codex Goal, automatic
|
|
53
|
+
self-continuation, polling loop, or private follow-up task merely to monitor
|
|
54
|
+
Yui work. Future durable updates will wake the Operator with another user
|
|
55
|
+
message after the current Operator turn is ready; unchanged state needs no
|
|
56
|
+
response.
|
|
57
|
+
|
|
49
58
|
## Configure Yui through conversation
|
|
50
59
|
|
|
51
60
|
Treat configuration as an Operator-owned conversation, not a list of commands
|
|
@@ -336,10 +345,10 @@ the workflow without claiming that version was delivered.
|
|
|
336
345
|
conflicts on the Leader's behalf.
|
|
337
346
|
- Reconcile a disappeared native Session with `task reconcile`; inspect the Run
|
|
338
347
|
before retrying a confirmed failure.
|
|
339
|
-
- If the current
|
|
340
|
-
`yui task role
|
|
341
|
-
|
|
342
|
-
|
|
348
|
+
- If the current Provider Conversation cannot continue, use
|
|
349
|
+
`yui task role session switch <task> <role> --reason "..."`. The request is
|
|
350
|
+
audited, and Yui keeps the old Conversation authoritative until the exact
|
|
351
|
+
replacement bind succeeds; never reconstruct identities from terminal text.
|
|
343
352
|
- Retry only an explicitly failed recovery Job.
|
|
344
353
|
- When a Leader first-progress advisory is reported, inspect its native
|
|
345
354
|
generations and absence of durable progress. It is cost evidence rather than
|
|
@@ -18,13 +18,18 @@ reinterpret its scope:
|
|
|
18
18
|
anchor.
|
|
19
19
|
|
|
20
20
|
A Role is an executor, not a workspace owner: each ReviewRound owns an exact
|
|
21
|
-
workspace record. Consecutive Task-final Rounds for the same Reviewer
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
when the conversation continues; never reuse an earlier
|
|
25
|
-
are confined to that workspace, never modify the
|
|
21
|
+
workspace record. Consecutive Task-final Rounds for the same Reviewer reuse one
|
|
22
|
+
clean physical workspace and native Session while Yui updates the checkout and
|
|
23
|
+
records the new Round snapshot. Treat the new Run Context Pack and frozen head
|
|
24
|
+
as the authority even when the conversation continues; never reuse an earlier
|
|
25
|
+
verdict. Review edits are confined to that workspace, never modify the
|
|
26
26
|
WorkItem Develop workspace, and never become a ChangeSet source.
|
|
27
27
|
|
|
28
|
+
For a dispatched Review, the Run Context Pack identifies the ReviewRound,
|
|
29
|
+
frozen Project commits, and assigned workspace. Inspect those exact commits.
|
|
30
|
+
The current mutable Task-main checkout is context only and must never replace,
|
|
31
|
+
widen, or silently update the assigned Review scope.
|
|
32
|
+
|
|
28
33
|
## Separate infrastructure failure from review judgment
|
|
29
34
|
|
|
30
35
|
Verify the exact Run identity, Context Pack, frozen head, and ReviewRound-owned
|
|
@@ -44,10 +49,26 @@ binding fails before review begins:
|
|
|
44
49
|
|
|
45
50
|
Yui derives `semantic`, `non-semantic`, or `ambiguous` from the immutable
|
|
46
51
|
Round, Run receipt, completion Event, and finding evidence. Never write or
|
|
47
|
-
simulate a classification field. A non-semantic attempt
|
|
48
|
-
|
|
52
|
+
simulate a classification field. A non-semantic attempt cannot satisfy
|
|
53
|
+
acceptance; an ambiguous attempt requires
|
|
49
54
|
Leader diagnosis before another review or repair decision.
|
|
50
55
|
|
|
56
|
+
The Review scope remains the current Run's frozen candidate even if the Leader
|
|
57
|
+
handles new user input or advances Task main while this Review is running. Do
|
|
58
|
+
not switch to the newer head, cancel the current inspection, or claim the
|
|
59
|
+
result covers anything beyond the frozen candidate.
|
|
60
|
+
|
|
61
|
+
For a Delta Recheck, judge only the verified baseline plus the exact supplied
|
|
62
|
+
diff. Return exactly one explicit disposition with reasoning:
|
|
63
|
+
|
|
64
|
+
- `equivalent-and-accepted` when the new candidate preserves the accepted
|
|
65
|
+
semantics and evidence;
|
|
66
|
+
- `finding` for a reachable material defect;
|
|
67
|
+
- `requires-full-review` when equivalence cannot be established.
|
|
68
|
+
|
|
69
|
+
Never create or request a follow-up Round yourself: `requires-full-review`, a
|
|
70
|
+
finding, and every uncertainty return to the Leader for routing.
|
|
71
|
+
|
|
51
72
|
Keep the context layers distinct. Yui Core owns ReviewRound identity,
|
|
52
73
|
lifecycle, access, workspace, and exact-yield safety; this generic Skill owns
|
|
53
74
|
portable review behavior; Agent-native Project Skills and Project Policy and
|
|
@@ -67,10 +88,13 @@ only its named resource, effect, and isolation boundary; never broaden it. A
|
|
|
67
88
|
real Agent may develop or review code, but that does not authorize a real
|
|
68
89
|
provider/model test.
|
|
69
90
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
91
|
+
Complete the assigned frozen-scope review before yielding. Accumulate all
|
|
92
|
+
reachable findings, verification gaps, checks actually run, and bounded next
|
|
93
|
+
actions, then submit them together in one Review Run result; do not yield as
|
|
94
|
+
soon as the first finding is discovered. A review result is evidence for Leader
|
|
95
|
+
judgment; it does not accept the WorkItem or complete the Task. Preserve the
|
|
96
|
+
ReviewRound record and explicitly clean its workspace after the round is
|
|
97
|
+
terminal.
|
|
74
98
|
|
|
75
99
|
For normal software delivery, follow the applicable Project Policy. The
|
|
76
100
|
Leader decides whether risk warrants one independent Task-final Review of the
|