import type { RuntimeStateManager } from '../store/runtime-state-manager.js'; import type { PDRuntimeAdapter } from '../runtime-protocol.js'; import type { StoreEventEmitter } from '../store/event-emitter.js'; import type { RolloutReviewerOutputV1, RolloutReviewerValidator, RolloutReviewMode } from './rollout-reviewer-output.js'; import type { PIArtifactStore } from './pi-artifact.js'; import { type PDErrorCategory } from '../error-categories.js'; import { RunnerPhase } from '../runner/runner-phase.js'; import type { OutputLanguage } from '../language-directive.js'; export type RolloutReviewerRunnerResultStatus = 'succeeded' | 'failed' | 'retried'; export interface RolloutReviewerRunnerResult { readonly status: RolloutReviewerRunnerResultStatus; readonly taskId: string; readonly runId?: string; readonly artifactId?: string; readonly resultRef?: string; readonly contextHash?: string; readonly output?: RolloutReviewerOutputV1; readonly errorCategory?: PDErrorCategory; readonly failureReason?: string; readonly attemptCount: number; } export interface RolloutReviewerRunnerOptions { readonly pollIntervalMs?: number; readonly timeoutMs?: number; readonly defaultMaxAttempts?: number; readonly owner: string; readonly runtimeKind: string; readonly agentId?: string; /** * Owner's preferred language for review fields (PRI-714). Forwarded to * RolloutReviewerPromptBuilder so summary/requiredChanges/rolloutRisks/ * safetyChecks follow the owner's language. Undefined = no directive * (backward compatible). */ readonly outputLanguage?: OutputLanguage; } export interface ResolvedRolloutReviewerRunnerOptions { readonly pollIntervalMs: number; readonly timeoutMs: number; readonly defaultMaxAttempts: number; readonly owner: string; readonly runtimeKind: string; readonly agentId: string; /** Owner's preferred language for review fields (PRI-714). Undefined = no directive. */ readonly outputLanguage?: OutputLanguage; } declare const DEFAULT_ROLLOUT_REVIEWER_RUNNER_OPTIONS: Readonly>; export declare function resolveRolloutReviewerRunnerOptions(options: RolloutReviewerRunnerOptions): ResolvedRolloutReviewerRunnerOptions; export interface RolloutReviewerRunnerDeps { readonly stateManager: RuntimeStateManager; readonly runtimeAdapter: PDRuntimeAdapter; readonly eventEmitter: StoreEventEmitter; readonly validator: RolloutReviewerValidator; readonly artifactStore: PIArtifactStore; /** * P0-F (INV-06): approve_rollout → 自动 activation policy dispatch。 * 核心 runner 保持纯编排 (架构边界,同 PRI-509 seeder 模式); 由 host * (auto-consumer / run-once) 注入真实的 ActivationDispatcher 调用。 * 未注入 → 显式 degraded 事件 (rc-9), 不静默跳过。 */ readonly dispatchActivation?: (input: RolloutAutoDispatchInput) => Promise; /** * P0-E (INV-04): needs_revision → reopen 最近可修复 stage (scribe/artificer)。 * 未注入 → needs_human_review (Owner 注意队列, 不入 approval)。 */ readonly reopenRevisionTarget?: (input: RolloutRevisionRoutingInput) => Promise<{ ok: boolean; reason: string; reopenedTaskId?: string; }>; } /** approve_rollout 自动 dispatch 的输入 (host 负责接线 ActivationDispatcher) */ export interface RolloutAutoDispatchInput { /** 被评审且已 validated 的 principle/rule artifact (dispatch 目标) */ readonly artifactId: string; readonly channel: string; readonly confidence?: number; readonly rolloutTaskId: string; } export interface RolloutAutoDispatchOutcome { readonly decision: string; readonly activationId?: string; readonly reason?: string; } /** needs_revision 修订路由输入 (host 层经 orchestrator 的 revision-reopen 能力实现,注入式) */ export interface RolloutRevisionRoutingInput { readonly targetTaskId: string; readonly targetKind: 'scribe' | 'artificer'; readonly revisionFeedback: string; readonly revisionIteration: number; readonly sourceRolloutTaskId: string; readonly sourceArtifactId: string; } /** * PRI-720: resolves the review contract mode for a rollout task. * * - code_tool_hook/skill channels and any explicit `full_chain` override run * the legacy code-chain review (byte-compatible). * - prompt/defer_archive chains in the STANDARD topology run the principle * semantic review — recognized structurally by a scribe dependency and the * ABSENCE of an evaluator dependency (the graph never creates one there). * - A legacy (pre-PRI-720) prompt chain carries an evaluator dep; AC12 forbids * reinterpreting in-flight chains, so it keeps the code-chain contract. */ export declare function resolveRolloutReviewMode(channel?: string, pipelineMode?: string, dependencyTaskKinds?: readonly string[]): RolloutReviewMode; export declare class RolloutReviewerRunner { private phase; private readonly resolvedOptions; private readonly stateManager; private readonly runtimeAdapter; private readonly eventEmitter; private readonly validator; private readonly artifactStore; private readonly dispatchActivation?; private readonly reopenRevisionTarget?; constructor(deps: RolloutReviewerRunnerDeps, options: RolloutReviewerRunnerOptions); get currentPhase(): RunnerPhase; private emitRolloutReviewerEvent; run(taskId: string): Promise; /** * Reconcile LLM-echoed lineage fields with the runner-owned authoritative * values via the shared lineage echo gate (PRI-541, see * peer-runner-contracts.ts). Thin wrapper: this runner does not extend * BasePeerRunner, so it calls the shared helper directly and emits its own * telemetry (no automatic runnerName prefix). * * The prompt asks the model to copy taskId / the mode-specific source * artifact id / its sourceTrace counterpart verbatim, but long artifact IDs * are routinely truncated or altered on echo. Because a mismatch is * classified output_invalid (a permanent error — no retry), a bad echo * permanently blocks the candidate from reaching the approval queue. * Lineage is runner-owned metadata (rc-6): the authoritative values come * from the task record and the artifact store read in buildContext(). * PRI-720: in principle semantic mode the reviewed source is the scribe * artifact, so the reconciled fields are sourceScribeArtifactId / * sourceTrace.scribeArtifactId. * * Whenever an echo differed (or sourceTrace was missing), a * rollout_reviewer_lineage_echo_corrected telemetry event is emitted so * the correction rate stays observable (rc-9-no-silent-fallback). */ private reconcileLineageEcho; private buildContext; private static hashContextRefs; private resolveStoreRunId; private invokeRuntime; private pollUntilTerminal; private fetchAndParseOutput; private succeedTask; private static buildSucceededResult; /** * P0-1 (外部复核): 解析 activation 候选 artifact — 与 review source 分离。 * * 事实基线 (evaluator-runner 产物形状): * - evaluator 任务名下存在 kind='principle' 但 **pending** 的 evaluation * 输出 artifact (pi-art--),其 contentJson 是 EvaluatorOutputV1, * 不含可激活的 principleId/text —— 不是合法 activation 目标。 * - prompt/defer_archive 渠道的合法目标 = **scribe** 的 validated principle * artifact (evaluator approved 时被 updateValidationStatus 翻 validated)。 * - code_tool_hook 渠道的合法目标 = evaluator assemble 的 validated **rule** * artifact (pi-rule--, V2 对抗通过)。 * * PRI-634 (内容契约): kind+validated 不足以证明产物可激活 —— 数据修复或历史 * 脏数据可以造出 kind='rule'+validated 但内容是 artificer schema 的伪候选 * (有 implementationCode / goldenTraceCases / affectedTools,无 evaluator * assemble 才写入的 goldenTrace / ruleHostGateDecision)。放行它只会让失败 * 推迟到 RuleHostWriter.canActivate 以 no_golden_trace * 爆炸,Owner 侧只剩一个无解释力的 rollout_dispatch_refused。因此 rule 候选 * 在此按 checkRuleActivationContent 过滤,并把被筛掉的产物与缺口字段一并返回, * 进入事件与 humanReviewContext.detail。 * * 解析策略: 沿 dep 链 (rollout→evaluator→artificer→scribe) 收集各 source task * 的 artifacts,按 channel 期望的 kind+validated 过滤;恰好一个候选才接受; * 零候选或多个候选 (历史脏数据) 一律 unresolved → needs_human_review, * 禁止 firstArtifact/created_at 猜测。 */ private resolveActivationCandidate; /** 收集 lineage 上所有 source task id (BFS 沿 dependencyTaskIds, 有界深度)。 */ private static readonly LINEAGE_MAX_DEPTH; private collectLineageSourceTaskIds; /** * PRI-720 C3: flip the exact reviewed scribe principle artifact to * `validated` on semantic approve. Mirrors the evaluator's approved-path * behavior (evaluator-runner.ts): idempotent updateValidationStatus; * a `false` return is a deterministic store inconsistency surfaced via * structured telemetry (the activation resolver then fails closed to * needs_human_review); a store throw retries (the write is a required * effect of the approve verdict — resume replays it, never a second LLM * verdict). */ private validateReviewedScribeArtifactOrThrow; /** * P0-2 (外部复核): dispatch + 结果分类。 * 返回 true = governance transition 完成 (activated / already_activated / * queued_for_approval);false = 已转入 needs_human_review。 * transient 异常直接冒泡 (caller → retryOrFail → retry_wait 自动重试)。 */ private dispatchOrRouteFailure; /** * P0-E: needs_revision → reopen 最近可修复 stage (INV-04, 禁止入 approval)。 * 路由: code_tool_hook → artificer (规则实现); 其他 channel → scribe (原则措辞)。 * * P0 (verdict drift): iteration 由 completion intent 注入 — record 阶段已按 * "已 APPLIED 的 rolloutRevisionPayload" 锁定本轮 N。同一 completion 的 * fresh 执行与 crash resume 使用同一 N,消除"applied 载荷属于上一轮还是 * 本轮"的歧义;budget 判定不在本方法内。 * * 返回 true = revision transition 完成 (target 已 reopen);false = 任务已 * 转入 needs_human_review。transient 错误 throw → retryOrFail → retry_wait * → 入口门 resume 同一 completion (无 LLM 重问)。 */ private handleRevisionRouting; /** * 解析修订目标任务 (只读遍历 dep 链): * rollout → evaluator → artificer → scribe (code 链); * rollout → scribe (PRI-720 principle 语义链: scribe 是直接依赖)。 * code_tool_hook → artificer; 其他 → scribe (走到底)。 */ private resolveRevisionTarget; private static formatRevisionFeedback; /** * P0 (INV-2): needs_human_review 是 completion effect 的 materialize 操作 — * fail-closed。写失败/读回不一致必须 throw (→ retry_wait → 入口门 resume * 同一 effect,不问 LLM),禁止 catch+swallow 后让 caller 把 intent 标 * applied (intent applied ⇔ 其 durable effect 已 materialize)。 */ /** * @param review.detail PRI-634: 规范 reasonCode 之外的具体原因,写入 * humanReviewContext.detail 供 Owner 展示;不参与 reviewKey 计算。 */ private markNeedsHumanReviewOrThrow; /** B: 读取已持久化的 revision intent (无 → null;旧形状缺 status 视为 applied) */ private readRolloutRevisionPayload; /** * verdict + completion intent 原子落库 (单次 metadata 写)。 * needs_revision 同时锁定本轮 iteration: * - stored payload pending → 沿用其 iteration (同 epoch 在途修订继续, * 兼容旧形状 crash 态,B1); * - stored applied → iteration + 1;appliedCount ≥ 2 → budget_exhausted * (P0-A: 也必须记 completion intent,effect=needs_human_review — * decision durable 而 crash before needs_human_review 写入时,retry * 不得重问 LLM 漂移 verdict)。 */ private recordCompletionOrThrow; /** * 执行 decision 的治理效果 (fresh 与 resume 共用,幂等): * approve → activation dispatch (幂等 key,重放 already_activated); * needs_revision → revision routing (iteration 由 intent 注入); * reject → 无效果 (terminal)。 */ private applyDecisionEffects; /** intent APPLIED 后才允许 terminal (P0 invariant 5)。写失败 fail loud。 */ private markCompletionIntentAppliedOrThrow; /** * PRI-720: dep-aware review mode for a hydrated task (resume/owner-override * paths, where buildContext did not run). Structural rule — see * resolveRolloutReviewMode: a scribe dep without an evaluator dep is a * principle semantic chain; anything else keeps the code-chain contract. */ private resolveReviewModeForTask; /** * 入口恢复门: pending completion intent (同 epoch) 是 recovery authority。 * 返回非 null = 本次 run 以 resume 完成 (LLM 未被调用); * 返回 null = 走正常 LLM 管线。epoch 不匹配的残留 intent 视为 stale。 */ private maybeResumePendingIntent; /** * PRI-629: 应用 Owner verdict override 并收敛 terminal。 * * accept_current → effectiveDecision='approve_rollout' — 仍走 * resolveActivationCandidate → dispatchActivation → ActivationDispatcher * 的完整通道风险门:低风险正常 policy,高风险 queued_for_approval * (INV-08: Owner review ≠ deployment approval,安全边界不穿透)。 * reject_current → 'reject' — terminal,无 dispatch、无 approval、无 activation。 * 顺序: 恢复 durable output → 幂等效果 → intent applied → resolution * applied → markTaskSucceeded;任何 crash 窗口重放同一 resolution,无 LLM。 */ private applyOwnerVerdictOverrideAndFinalize; /** * P0 (INV-1/INV-5): applied intent 的补 terminal — effects 已 materialize * (applied ⇒ INV-2 保证),仅 markTaskSucceeded 缺失。不调用 LLM。 */ private finalizeAppliedIntentTerminal; /** * 从 runs 表恢复 intent 落库前已持久化的 validated output。 * intent 的存在保证 updateRunOutput 曾成功 (顺序: output → artifact → * decision+intent);缺失/损坏 = authority 记录的存储腐坏 → fail loud * (storage_unavailable → retryOrFail → max attempts → failed,人工介入)。 */ private recoverIntentOutput; private static buildResumeResult; /** * B: intent 标 APPLIED — transition 已 materialize 后的持久化确认。 * 写失败 throw (fail loud): 重放会经 materialize 检查安全收敛。 */ private markRevisionIntentAppliedOrThrow; /** 记录修订路由 (budget 依据) */ private recordRolloutRevisionRouting; /** C: 显式 fail-loud 包装 — routing intent 是 transition 的组成部分。 */ private recordRolloutRevisionRoutingOrThrow; private handleRuntimeFailure; private handleValidationError; private handleLeaseOrPhaseError; private handlePostLeaseError; private retryOrFail; private isPermanentError; private classifyError; private mapRunStatusToErrorCategory; private sleep; } export { DEFAULT_ROLLOUT_REVIEWER_RUNNER_OPTIONS }; //# sourceMappingURL=rollout-reviewer-runner.d.ts.map