feat(uok,plan-slice): seed Q3-Q8 gate rows with schema-v2 ctx from autonomous session
Slice 3b of "Make UOK the SF Control Plane". handlePlanSlice now accepts an optional uokContext option and threads it into every insertGateRow call (Q3, Q4 slice gates; Q5, Q6, Q7 per task; Q8 slice closeout). executePlanSlice derives the ctx from the singleton autonomous session when one is active — currentTraceId becomes the v2 traceId/parentTrace, surface and runControl are pinned to "autonomous", permissionProfile follows session/prefs. Tools invoked outside an autonomous loop (interactive REPL, headless one-shot) pass uokContext=null and the seeded rows fall through to the legacy NULL-column shape, classified as "legacy" by status uok. Lazy import of auto/session.js keeps headless/test code paths from paying the session-singleton load cost when they don't need it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a2c55d5fde
commit
95ea9eecee
2 changed files with 56 additions and 2 deletions
|
|
@ -237,7 +237,7 @@ function validateParams(params) {
|
|||
tasks: validateTasks(params.tasks),
|
||||
};
|
||||
}
|
||||
export async function handlePlanSlice(rawParams, basePath) {
|
||||
export async function handlePlanSlice(rawParams, basePath, options = {}) {
|
||||
let params;
|
||||
try {
|
||||
params = validateParams(rawParams);
|
||||
|
|
@ -250,6 +250,16 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|||
: `validation failed: ${message}`,
|
||||
};
|
||||
}
|
||||
// Schema-v2 UOK run-context for the Q3/Q4/Q5/Q6/Q7/Q8 seed rows. When
|
||||
// the caller supplied a context (autonomous-loop dispatch chains it
|
||||
// through executePlanSlice), the gate rows land with surface/run_control/
|
||||
// permission_profile/trace_id populated and status-uok classifies them
|
||||
// as "ok". When absent (direct/legacy callers), the rows stay NULL and
|
||||
// classify as "legacy" — same shape as pre-v2.
|
||||
const uokContext =
|
||||
options && typeof options.uokContext === "object"
|
||||
? options.uokContext
|
||||
: null;
|
||||
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
||||
// Guards must be inside the transaction so the state they check cannot
|
||||
// change between the read and the write (#2723).
|
||||
|
|
@ -329,6 +339,7 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|||
sliceId: params.sliceId,
|
||||
gateId: gid,
|
||||
scope: "slice",
|
||||
uokContext,
|
||||
});
|
||||
}
|
||||
const taskGates = ["Q5", "Q6", "Q7"];
|
||||
|
|
@ -340,6 +351,7 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|||
gateId: gid,
|
||||
scope: "task",
|
||||
taskId: task.taskId,
|
||||
uokContext,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -348,6 +360,7 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|||
sliceId: params.sliceId,
|
||||
gateId: "Q8",
|
||||
scope: "slice",
|
||||
uokContext,
|
||||
});
|
||||
insertSliceEvidence(
|
||||
params.milestoneId,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { invalidateStateCache } from "../state.js";
|
|||
import { extractVerdict } from "../verdict-parser.js";
|
||||
import { logError, logWarning } from "../workflow-logger.js";
|
||||
import { handleCompleteMilestone } from "./complete-milestone.js";
|
||||
import { buildAutonomousUokContext } from "../uok/auto-uok-ctx.js";
|
||||
import { handleCompleteSlice } from "./complete-slice.js";
|
||||
import { handleCompleteTask } from "./complete-task.js";
|
||||
import { handlePlanMilestone } from "./plan-milestone.js";
|
||||
|
|
@ -722,6 +723,39 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
|
|||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Build a schema-v2 UOK run-context for plan_slice from the singleton
|
||||
* autonomous session, when one is active.
|
||||
*
|
||||
* Lazy-imports auto/session.js so headless/test code paths that never
|
||||
* touch the autonomous loop don't pay the load cost. Returns null when
|
||||
* no session is active or when buildAutonomousUokContext rejects the
|
||||
* inputs (e.g. missing traceId); callers treat null as "fall through to
|
||||
* the legacy NULL-column write".
|
||||
*/
|
||||
async function derivePlanSliceUokContext() {
|
||||
let s;
|
||||
try {
|
||||
const sessionModule = await import("../auto/session.js");
|
||||
s = sessionModule.getAutoSession?.();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
if (!s || typeof s !== "object") return null;
|
||||
const traceId = s.currentTraceId;
|
||||
if (typeof traceId !== "string" || traceId.length === 0) return null;
|
||||
// AutoSession exposes isYolo(); prefs are loaded at the loop level and
|
||||
// not stored on the session singleton, so we don't have them here. The
|
||||
// derivePermissionProfile helper degrades gracefully to "high" when
|
||||
// prefs is undefined and YOLO is off, which matches the autonomous
|
||||
// loop's default.
|
||||
return buildAutonomousUokContext({
|
||||
s,
|
||||
traceId,
|
||||
parentTrace: traceId,
|
||||
});
|
||||
}
|
||||
|
||||
export async function executePlanSlice(params, basePath = process.cwd()) {
|
||||
const dbAvailable = await ensureDbOpen(basePath);
|
||||
if (!dbAvailable) {
|
||||
|
|
@ -737,7 +771,14 @@ export async function executePlanSlice(params, basePath = process.cwd()) {
|
|||
};
|
||||
}
|
||||
try {
|
||||
const result = await handlePlanSlice(params, basePath);
|
||||
// Derive the schema-v2 UOK run-context from the autonomous session
|
||||
// when one is active. plan_slice runs as a tool inside an
|
||||
// autonomous unit, so the session's currentTraceId is the parent
|
||||
// flow id. When the tool is invoked outside an autonomous loop
|
||||
// (interactive REPL, headless one-shot), uokContext stays null and
|
||||
// the seeded gate rows fall through to the legacy null-column shape.
|
||||
const uokContext = await derivePlanSliceUokContext();
|
||||
const result = await handlePlanSlice(params, basePath, { uokContext });
|
||||
if ("error" in result) {
|
||||
return {
|
||||
content: [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue