@telora/daemon 0.22.181 → 0.22.189
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/build-info.json +9 -3
- package/dist/audit/audit-floor-policy.d.ts +188 -0
- package/dist/audit/audit-floor-policy.d.ts.map +1 -0
- package/dist/audit/audit-floor-policy.js +353 -0
- package/dist/audit/audit-floor-policy.js.map +1 -0
- package/dist/audit/audit-prompt.d.ts +4 -177
- package/dist/audit/audit-prompt.d.ts.map +1 -1
- package/dist/audit/audit-prompt.js +6 -329
- package/dist/audit/audit-prompt.js.map +1 -1
- package/dist/completion/escalations.d.ts.map +1 -1
- package/dist/completion/escalations.js +4 -1
- package/dist/completion/escalations.js.map +1 -1
- package/dist/completion/review-exit-phase.d.ts.map +1 -1
- package/dist/completion/review-exit-phase.js +11 -4
- package/dist/completion/review-exit-phase.js.map +1 -1
- package/dist/completion/standing-approval-convergence.d.ts.map +1 -1
- package/dist/completion/standing-approval-convergence.js +2 -1
- package/dist/completion/standing-approval-convergence.js.map +1 -1
- package/dist/focus/focus-executor.d.ts.map +1 -1
- package/dist/focus/focus-executor.js +2 -0
- package/dist/focus/focus-executor.js.map +1 -1
- package/dist/focus/focus-loop-registry.js +2 -2
- package/dist/focus/focus-loop-registry.js.map +1 -1
- package/dist/focus/session-health.d.ts.map +1 -1
- package/dist/focus/session-health.js +2 -1
- package/dist/focus/session-health.js.map +1 -1
- package/dist/focus-stage-lifecycle/planning-release.d.ts +52 -17
- package/dist/focus-stage-lifecycle/planning-release.d.ts.map +1 -1
- package/dist/focus-stage-lifecycle/planning-release.js +58 -70
- package/dist/focus-stage-lifecycle/planning-release.js.map +1 -1
- package/dist/focus-stage-lifecycle/ratify-bar-gate.d.ts +108 -0
- package/dist/focus-stage-lifecycle/ratify-bar-gate.d.ts.map +1 -0
- package/dist/focus-stage-lifecycle/ratify-bar-gate.js +174 -0
- package/dist/focus-stage-lifecycle/ratify-bar-gate.js.map +1 -0
- package/dist/git/merge-to-main.d.ts.map +1 -1
- package/dist/git/merge-to-main.js.map +1 -1
- package/dist/loops/llm-client.d.ts +1 -1
- package/dist/loops/llm-client.d.ts.map +1 -1
- package/dist/loops/llm-client.js +18 -105
- package/dist/loops/llm-client.js.map +1 -1
- package/dist/nexus/index.d.ts.map +1 -1
- package/dist/nexus/index.js +2 -1
- package/dist/nexus/index.js.map +1 -1
- package/dist/nexus/intake-prompt-sections.d.ts +70 -0
- package/dist/nexus/intake-prompt-sections.d.ts.map +1 -0
- package/dist/nexus/intake-prompt-sections.js +145 -0
- package/dist/nexus/intake-prompt-sections.js.map +1 -0
- package/dist/nexus/intake-spawn.d.ts +49 -13
- package/dist/nexus/intake-spawn.d.ts.map +1 -1
- package/dist/nexus/intake-spawn.js +45 -122
- package/dist/nexus/intake-spawn.js.map +1 -1
- package/dist/nexus/intake.d.ts +55 -0
- package/dist/nexus/intake.d.ts.map +1 -1
- package/dist/nexus/intake.js +62 -1
- package/dist/nexus/intake.js.map +1 -1
- package/dist/prd/arm-readiness.d.ts +93 -0
- package/dist/prd/arm-readiness.d.ts.map +1 -0
- package/dist/prd/arm-readiness.js +254 -0
- package/dist/prd/arm-readiness.js.map +1 -0
- package/dist/prd/arm-refusal.d.ts +149 -0
- package/dist/prd/arm-refusal.d.ts.map +1 -0
- package/dist/prd/arm-refusal.js +219 -0
- package/dist/prd/arm-refusal.js.map +1 -0
- package/dist/prd/controller-shared.d.ts +111 -0
- package/dist/prd/controller-shared.d.ts.map +1 -1
- package/dist/prd/controller-shared.js +3 -1
- package/dist/prd/controller-shared.js.map +1 -1
- package/dist/prd/controller.d.ts +16 -10
- package/dist/prd/controller.d.ts.map +1 -1
- package/dist/prd/controller.js +28 -35
- package/dist/prd/controller.js.map +1 -1
- package/dist/prd/frontier-arming.d.ts +151 -0
- package/dist/prd/frontier-arming.d.ts.map +1 -0
- package/dist/prd/frontier-arming.js +315 -0
- package/dist/prd/frontier-arming.js.map +1 -0
- package/dist/prd/index.d.ts +10 -1
- package/dist/prd/index.d.ts.map +1 -1
- package/dist/prd/index.js +9 -1
- package/dist/prd/index.js.map +1 -1
- package/dist/prd/scoping-prompt.d.ts +68 -0
- package/dist/prd/scoping-prompt.d.ts.map +1 -0
- package/dist/prd/scoping-prompt.js +86 -0
- package/dist/prd/scoping-prompt.js.map +1 -0
- package/dist/prompt/prompt-contradictions.d.ts +20 -1
- package/dist/prompt/prompt-contradictions.d.ts.map +1 -1
- package/dist/prompt/prompt-contradictions.js +35 -0
- package/dist/prompt/prompt-contradictions.js.map +1 -1
- package/dist/prompt/team-prompt-base.d.ts +18 -0
- package/dist/prompt/team-prompt-base.d.ts.map +1 -1
- package/dist/prompt/team-prompt-base.js +56 -11
- package/dist/prompt/team-prompt-base.js.map +1 -1
- package/dist/prompt-sections/persona-sections.d.ts +36 -13
- package/dist/prompt-sections/persona-sections.d.ts.map +1 -1
- package/dist/prompt-sections/persona-sections.js +93 -16
- package/dist/prompt-sections/persona-sections.js.map +1 -1
- package/dist/prompt-sections/scoping-sections.d.ts +19 -5
- package/dist/prompt-sections/scoping-sections.d.ts.map +1 -1
- package/dist/prompt-sections/scoping-sections.js +45 -38
- package/dist/prompt-sections/scoping-sections.js.map +1 -1
- package/dist/prompt-sections/shared.d.ts +8 -0
- package/dist/prompt-sections/shared.d.ts.map +1 -1
- package/dist/prompt-sections/shared.js.map +1 -1
- package/dist/queries/agent-resolvable-promotion.d.ts +12 -0
- package/dist/queries/agent-resolvable-promotion.d.ts.map +1 -1
- package/dist/queries/agent-resolvable-promotion.js +17 -6
- package/dist/queries/agent-resolvable-promotion.js.map +1 -1
- package/dist/queries/delivery-gate-state.d.ts +3 -0
- package/dist/queries/delivery-gate-state.d.ts.map +1 -1
- package/dist/queries/delivery-gate-state.js +1 -1
- package/dist/queries/delivery-gate-state.js.map +1 -1
- package/dist/queries/focus-criteria-standing.d.ts +170 -7
- package/dist/queries/focus-criteria-standing.d.ts.map +1 -1
- package/dist/queries/focus-criteria-standing.js +143 -8
- package/dist/queries/focus-criteria-standing.js.map +1 -1
- package/dist/queries/focus-ratify-release.d.ts +43 -0
- package/dist/queries/focus-ratify-release.d.ts.map +1 -0
- package/dist/queries/focus-ratify-release.js +45 -0
- package/dist/queries/focus-ratify-release.js.map +1 -0
- package/dist/queries/focuses.d.ts +0 -10
- package/dist/queries/focuses.d.ts.map +1 -1
- package/dist/queries/focuses.js +0 -14
- package/dist/queries/focuses.js.map +1 -1
- package/dist/queries/prd.d.ts +31 -0
- package/dist/queries/prd.d.ts.map +1 -1
- package/dist/queries/prd.js +26 -1
- package/dist/queries/prd.js.map +1 -1
- package/dist/queries/shared.js +1 -1
- package/dist/queries/verify-own-holds.d.ts +89 -0
- package/dist/queries/verify-own-holds.d.ts.map +1 -0
- package/dist/queries/verify-own-holds.js +93 -0
- package/dist/queries/verify-own-holds.js.map +1 -0
- package/dist/resolvers/focus-criteria-standing.d.ts.map +1 -1
- package/dist/resolvers/focus-criteria-standing.js +324 -25
- package/dist/resolvers/focus-criteria-standing.js.map +1 -1
- package/dist/security/security-auto-inject.d.ts +51 -0
- package/dist/security/security-auto-inject.d.ts.map +1 -1
- package/dist/security/security-auto-inject.js +101 -11
- package/dist/security/security-auto-inject.js.map +1 -1
- package/dist/security/security-scan-engine.d.ts +4 -4
- package/dist/security/security-scan-engine.d.ts.map +1 -1
- package/dist/security/security-scan-engine.js +6 -0
- package/dist/security/security-scan-engine.js.map +1 -1
- package/dist/session/session-lineage.d.ts.map +1 -1
- package/dist/session/session-lineage.js +2 -0
- package/dist/session/session-lineage.js.map +1 -1
- package/dist/shell/constants.d.ts +5 -0
- package/dist/shell/constants.d.ts.map +1 -1
- package/dist/shell/constants.js +5 -0
- package/dist/shell/constants.js.map +1 -1
- package/dist/shell/daemon-instance.d.ts +74 -64
- package/dist/shell/daemon-instance.d.ts.map +1 -1
- package/dist/shell/daemon-instance.js +16 -121
- package/dist/shell/daemon-instance.js.map +1 -1
- package/dist/shell/health-events.js +1 -1
- package/dist/shell/health-events.js.map +1 -1
- package/dist/shell/instance-liveness.d.ts +112 -0
- package/dist/shell/instance-liveness.d.ts.map +1 -0
- package/dist/shell/instance-liveness.js +205 -0
- package/dist/shell/instance-liveness.js.map +1 -0
- package/dist/shell/schema-version-gate.d.ts +22 -0
- package/dist/shell/schema-version-gate.d.ts.map +1 -1
- package/dist/shell/schema-version-gate.js +116 -6
- package/dist/shell/schema-version-gate.js.map +1 -1
- package/dist/shell/worker-pidfile.d.ts +21 -8
- package/dist/shell/worker-pidfile.d.ts.map +1 -1
- package/dist/shell/worker-pidfile.js +38 -9
- package/dist/shell/worker-pidfile.js.map +1 -1
- package/dist/spawn/lead-launch.d.ts.map +1 -1
- package/dist/spawn/lead-launch.js +2 -1
- package/dist/spawn/lead-launch.js.map +1 -1
- package/dist/spawn/one-shot-model.d.ts +145 -0
- package/dist/spawn/one-shot-model.d.ts.map +1 -0
- package/dist/spawn/one-shot-model.js +329 -0
- package/dist/spawn/one-shot-model.js.map +1 -0
- package/dist/spawn/one-shot-scoping-spawn.d.ts +51 -0
- package/dist/spawn/one-shot-scoping-spawn.d.ts.map +1 -0
- package/dist/spawn/one-shot-scoping-spawn.js +156 -0
- package/dist/spawn/one-shot-scoping-spawn.js.map +1 -0
- package/dist/spawn/process-spawn.d.ts +12 -0
- package/dist/spawn/process-spawn.d.ts.map +1 -1
- package/dist/spawn/process-spawn.js +1 -1
- package/dist/spawn/process-spawn.js.map +1 -1
- package/dist/spawn/prompt-assembly.d.ts +8 -0
- package/dist/spawn/prompt-assembly.d.ts.map +1 -1
- package/dist/spawn/prompt-assembly.js +15 -3
- package/dist/spawn/prompt-assembly.js.map +1 -1
- package/dist/spawn/review-hold-park.d.ts.map +1 -1
- package/dist/spawn/review-hold-park.js +7 -3
- package/dist/spawn/review-hold-park.js.map +1 -1
- package/dist/spawn/routing-decider-spawn.d.ts +30 -0
- package/dist/spawn/routing-decider-spawn.d.ts.map +1 -1
- package/dist/spawn/routing-decider-spawn.js +84 -2
- package/dist/spawn/routing-decider-spawn.js.map +1 -1
- package/dist/spawn/routing-decider.d.ts.map +1 -1
- package/dist/spawn/routing-decider.js +22 -0
- package/dist/spawn/routing-decider.js.map +1 -1
- package/dist/spawn/spawn-cooldown.d.ts +15 -1
- package/dist/spawn/spawn-cooldown.d.ts.map +1 -1
- package/dist/spawn/spawn-cooldown.js +67 -19
- package/dist/spawn/spawn-cooldown.js.map +1 -1
- package/dist/spawn/worktree-session.d.ts +24 -6
- package/dist/spawn/worktree-session.d.ts.map +1 -1
- package/dist/spawn/worktree-session.js +37 -14
- package/dist/spawn/worktree-session.js.map +1 -1
- package/dist/testing/arm-coverage-model.d.ts +75 -0
- package/dist/testing/arm-coverage-model.d.ts.map +1 -0
- package/dist/testing/arm-coverage-model.js +114 -0
- package/dist/testing/arm-coverage-model.js.map +1 -0
- package/dist/testing/fixtures/index.js +1 -1
- package/dist/types/index.js +1 -1
- package/dist/verify/ai-inspection-runner.d.ts.map +1 -1
- package/dist/verify/ai-inspection-runner.js +26 -7
- package/dist/verify/ai-inspection-runner.js.map +1 -1
- package/dist/verify/de-restatement.d.ts +9 -2
- package/dist/verify/de-restatement.d.ts.map +1 -1
- package/dist/verify/de-restatement.js +14 -76
- package/dist/verify/de-restatement.js.map +1 -1
- package/dist/verify/default-on-guards.d.ts +5 -2
- package/dist/verify/default-on-guards.d.ts.map +1 -1
- package/dist/verify/default-on-guards.js +5 -3
- package/dist/verify/default-on-guards.js.map +1 -1
- package/dist/verify/verification-boundary-env.d.ts +7 -2
- package/dist/verify/verification-boundary-env.d.ts.map +1 -1
- package/dist/verify/verification-boundary-env.js +9 -4
- package/dist/verify/verification-boundary-env.js.map +1 -1
- package/dist/verify/verification-deps-default.d.ts.map +1 -1
- package/dist/verify/verification-deps-default.js +6 -0
- package/dist/verify/verification-deps-default.js.map +1 -1
- package/dist/verify/verification-deps.d.ts +10 -0
- package/dist/verify/verification-deps.d.ts.map +1 -1
- package/dist/verify/verification-deterministic.d.ts +7 -0
- package/dist/verify/verification-deterministic.d.ts.map +1 -1
- package/dist/verify/verification-deterministic.js.map +1 -1
- package/dist/verify/verification-engine.d.ts +1 -20
- package/dist/verify/verification-engine.d.ts.map +1 -1
- package/dist/verify/verification-engine.js +24 -55
- package/dist/verify/verification-engine.js.map +1 -1
- package/dist/verify/verification-evidence-unavailable-feedback.d.ts +3 -1
- package/dist/verify/verification-evidence-unavailable-feedback.d.ts.map +1 -1
- package/dist/verify/verification-evidence-unavailable-feedback.js +3 -1
- package/dist/verify/verification-evidence-unavailable-feedback.js.map +1 -1
- package/dist/verify/verification-feedback.d.ts +4 -12
- package/dist/verify/verification-feedback.d.ts.map +1 -1
- package/dist/verify/verification-feedback.js +7 -12
- package/dist/verify/verification-feedback.js.map +1 -1
- package/dist/verify/verification-history-reset.d.ts.map +1 -1
- package/dist/verify/verification-history-reset.js +11 -3
- package/dist/verify/verification-history-reset.js.map +1 -1
- package/dist/verify/verification-model-unavailable-hold.d.ts +92 -0
- package/dist/verify/verification-model-unavailable-hold.d.ts.map +1 -0
- package/dist/verify/verification-model-unavailable-hold.js +207 -0
- package/dist/verify/verification-model-unavailable-hold.js.map +1 -0
- package/dist/verify/verification-strategies.d.ts +32 -0
- package/dist/verify/verification-strategies.d.ts.map +1 -0
- package/dist/verify/verification-strategies.js +47 -0
- package/dist/verify/verification-strategies.js.map +1 -0
- package/dist/verify/verify-reconciliation.d.ts.map +1 -1
- package/dist/verify/verify-reconciliation.js +2 -1
- package/dist/verify/verify-reconciliation.js.map +1 -1
- package/dist/verify/verify-restatement.d.ts.map +1 -1
- package/dist/verify/verify-restatement.js +21 -8
- package/dist/verify/verify-restatement.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
// PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
|
|
2
|
+
// Pinned by: packages/daemon/src/prd/prd-frontier-arming.test.ts
|
|
3
|
+
// PINNED-BY-END
|
|
4
|
+
import { readFocusArmReadiness } from './arm-readiness.js';
|
|
5
|
+
import { classifyArmFailure, clearArmRefusal, recordArmRefusal, } from './arm-refusal.js';
|
|
6
|
+
import { buildPrdScopingPrompt, readPhases } from './scoping-prompt.js';
|
|
7
|
+
import { createLogger } from '../shell/log.js';
|
|
8
|
+
const log = createLogger({ module: 'prd-controller' });
|
|
9
|
+
/**
|
|
10
|
+
* How long an in-flight scoping run is believed before a replacement is
|
|
11
|
+
* spawned (20 minutes).
|
|
12
|
+
*
|
|
13
|
+
* MUST be strictly greater than the shared spawn's kill timeout
|
|
14
|
+
* (SCOPING_AGENT_TIMEOUT_MS, 15m) plus its SIGKILL grace (10s), or a healthy
|
|
15
|
+
* long-running agent is double-spawned right as it finishes. Same relation
|
|
16
|
+
* nexus intake holds between DEFAULT_INTAKE_STALE_MS and its timeout; the
|
|
17
|
+
* window exists here for the case the exit callback never fires at all (a
|
|
18
|
+
* daemon that was restarted mid-run leaves no ledger entry, and one that lost
|
|
19
|
+
* the child leaves an entry nothing will ever close).
|
|
20
|
+
*/
|
|
21
|
+
export const PRD_SCOPING_STALE_MS = 20 * 60 * 1000;
|
|
22
|
+
/**
|
|
23
|
+
* Scoping attempts per focus per process. A scoping agent is a full Claude Code
|
|
24
|
+
* process; a focus whose scoping keeps producing nothing must stop costing one
|
|
25
|
+
* every tick. At the budget the focus is HELD un-scoped -- logged, not
|
|
26
|
+
* escalated -- and a daemon restart is what grants further attempts, exactly as
|
|
27
|
+
* a new arm is what grants further review cycles.
|
|
28
|
+
*/
|
|
29
|
+
export const PRD_SCOPING_MAX_ATTEMPTS = 3;
|
|
30
|
+
/**
|
|
31
|
+
* Process-lifetime scoping ledger (focusId -> run). Injected via deps for
|
|
32
|
+
* tests; defaults here. A restart resets it, which is safe: the scoping agent's
|
|
33
|
+
* own marker-in-the-focus-description guard makes a re-run extend the existing
|
|
34
|
+
* tree rather than author a second one.
|
|
35
|
+
*/
|
|
36
|
+
const scopingRunsDefault = new Map();
|
|
37
|
+
/**
|
|
38
|
+
* The decision, PURE.
|
|
39
|
+
*
|
|
40
|
+
* Reading order matters and is the contract:
|
|
41
|
+
* - An in-flight run OWNS the focus. We never arm underneath a running scoping
|
|
42
|
+
* agent, however ready the focus already looks: the agent is still writing,
|
|
43
|
+
* and an arm fixes its covered set at whatever exists mid-write. Past the
|
|
44
|
+
* staleness window the run is presumed lost and replaced.
|
|
45
|
+
* - A run that exited CLEAN and left a focus that states its future is the
|
|
46
|
+
* only path to an arm through this ledger.
|
|
47
|
+
* - Any other exit re-tries while the attempt budget lasts. Once the budget is
|
|
48
|
+
* spent the tree itself decides: ready -> arm (the bar is met, however messy
|
|
49
|
+
* the run that got there), not ready -> hold. A spent budget must never
|
|
50
|
+
* strand a focus that IS scoped.
|
|
51
|
+
* - No run at all, and ready: arm. This is the restart / human-scoped case --
|
|
52
|
+
* the focus states its future and no agent of ours is writing to it; the
|
|
53
|
+
* tree is the evidence, not our in-memory ledger.
|
|
54
|
+
*/
|
|
55
|
+
export function decidePrdFrontierAction(input) {
|
|
56
|
+
const { ready, run, nowMs, staleMs, maxAttempts } = input;
|
|
57
|
+
if (!run) {
|
|
58
|
+
return ready ? 'arm' : 'spawn_scoping';
|
|
59
|
+
}
|
|
60
|
+
if (run.status === 'in_flight') {
|
|
61
|
+
return nowMs - run.startedMs >= staleMs ? 'spawn_scoping' : 'await_scoping';
|
|
62
|
+
}
|
|
63
|
+
const exhausted = run.attempts >= maxAttempts;
|
|
64
|
+
if (ready && (run.status === 'exited_clean' || exhausted)) {
|
|
65
|
+
return 'arm';
|
|
66
|
+
}
|
|
67
|
+
return exhausted ? 'hold_unscoped' : 'spawn_scoping';
|
|
68
|
+
}
|
|
69
|
+
function outcome(action, armRefused = false) {
|
|
70
|
+
return {
|
|
71
|
+
action,
|
|
72
|
+
armed: action === 'arm' && !armRefused,
|
|
73
|
+
scopingSpawned: action === 'spawn_scoping',
|
|
74
|
+
heldUnscoped: action === 'hold_unscoped',
|
|
75
|
+
armRefused,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** The readiness answer used when the read is deliberately skipped. */
|
|
79
|
+
const NOT_READ = {
|
|
80
|
+
ready: false,
|
|
81
|
+
reason: 'a scoping run is in flight; readiness not read',
|
|
82
|
+
readyDeliveryIds: [],
|
|
83
|
+
};
|
|
84
|
+
/** The PRD's goal statement, from its goal node(s). Pure. */
|
|
85
|
+
export function readPrdGoal(nodes) {
|
|
86
|
+
const statements = nodes
|
|
87
|
+
.filter((n) => n.nodeType === 'goal')
|
|
88
|
+
.map((n) => n.statement.trim())
|
|
89
|
+
.filter((s) => s.length > 0);
|
|
90
|
+
return statements.length > 0 ? statements.join('\n') : null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Spawn one scoping agent for `focusId` and record the run.
|
|
94
|
+
*
|
|
95
|
+
* The ledger entry is written BEFORE the spawn so a slow or failed spawn cannot
|
|
96
|
+
* re-fire on the next tick (the same ordering nexus intake uses with its
|
|
97
|
+
* `intake_scoping_started_at` stamp). The exit callback only writes back if the
|
|
98
|
+
* ledger still holds THIS run: a later spawn replaced it, and a stale exit must
|
|
99
|
+
* not reopen a window that already moved on.
|
|
100
|
+
*/
|
|
101
|
+
async function spawnScopingFor(node, focusId, prd, prdGoal, deps, nowMs) {
|
|
102
|
+
const runs = deps.prdScopingRuns ?? scopingRunsDefault;
|
|
103
|
+
const previous = runs.get(focusId);
|
|
104
|
+
const run = {
|
|
105
|
+
focusId,
|
|
106
|
+
nodeId: node.id,
|
|
107
|
+
status: 'in_flight',
|
|
108
|
+
attempts: (previous?.attempts ?? 0) + 1,
|
|
109
|
+
startedMs: nowMs,
|
|
110
|
+
lastExitCode: null,
|
|
111
|
+
};
|
|
112
|
+
runs.set(focusId, run);
|
|
113
|
+
const prompt = buildPrdScopingPrompt({
|
|
114
|
+
focusId,
|
|
115
|
+
overcomeNodeId: node.id,
|
|
116
|
+
overcomeStatement: node.statement,
|
|
117
|
+
phases: readPhases(node),
|
|
118
|
+
prdId: prd.id,
|
|
119
|
+
prdTitle: prd.title,
|
|
120
|
+
prdGoal,
|
|
121
|
+
});
|
|
122
|
+
if (!deps.spawnPrdScopingAgent) {
|
|
123
|
+
// No spawner wired (a caller that opted out). The run is recorded so the
|
|
124
|
+
// attempt budget still bounds the tick, and the focus stays un-armed --
|
|
125
|
+
// never armed-by-default, which is the behaviour this module removed.
|
|
126
|
+
log.warn(`[prd-controller] focus ${focusId} (overcome ${node.id}) needs scoping but no scoping ` +
|
|
127
|
+
'spawner is wired -- leaving it UN-ARMED');
|
|
128
|
+
run.status = 'exited_failed';
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
await deps.spawnPrdScopingAgent({
|
|
133
|
+
focusId,
|
|
134
|
+
nodeId: node.id,
|
|
135
|
+
prompt,
|
|
136
|
+
onExit: (code) => {
|
|
137
|
+
if (runs.get(focusId) !== run)
|
|
138
|
+
return; // superseded by a later run
|
|
139
|
+
run.status = code === 0 ? 'exited_clean' : 'exited_failed';
|
|
140
|
+
run.lastExitCode = code;
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
log.info(`[prd-controller] scoping agent requested for focus ${focusId} (overcome ${node.id}, ` +
|
|
144
|
+
`attempt ${run.attempts}/${deps.prdScopingMaxAttempts ?? PRD_SCOPING_MAX_ATTEMPTS}) -- ` +
|
|
145
|
+
'the focus stays UN-ARMED until it states the future it asks for');
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
// The spawn never started: close the run so the next tick re-tries rather
|
|
149
|
+
// than waiting out the staleness window on a process that does not exist.
|
|
150
|
+
run.status = 'exited_failed';
|
|
151
|
+
log.warn(`[prd-controller] failed to spawn the scoping agent for focus ${focusId}: ${err.message}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Arm the focus -- and survive a write that refuses.
|
|
156
|
+
*
|
|
157
|
+
* Returns true when the arm LANDED, false when it was refused (or failed). It
|
|
158
|
+
* never throws: an arm the database refuses is a handled outcome, not the end
|
|
159
|
+
* of the tick. The three things it does on a refusal are the whole contract:
|
|
160
|
+
* 1. the focus is left materialized and UN-ARMED -- nothing is rolled back,
|
|
161
|
+
* nothing is latched off, and the next frontier tick re-attempts it;
|
|
162
|
+
* 2. the refusal CODE and the NODE LIST the database wrote are recorded on
|
|
163
|
+
* the focus, where an operator reads them (prd/arm-refusal.ts explains why
|
|
164
|
+
* there and not only in the log);
|
|
165
|
+
* 3. the caller continues, so a second frontier focus in the same tick is
|
|
166
|
+
* still advanced.
|
|
167
|
+
* No escalation is filed: the fix is a restatement on a tree node, and the
|
|
168
|
+
* scoping agent this module re-spawns is the actor that writes it.
|
|
169
|
+
*
|
|
170
|
+
* A SUCCESSFUL arm CLEARS the record, the same way a successful integration
|
|
171
|
+
* sync clears its conflict artifact -- the condition is gone, so the note goes
|
|
172
|
+
* with it.
|
|
173
|
+
*/
|
|
174
|
+
async function armOrRecordRefusal(args) {
|
|
175
|
+
const { node, focusId, prd, roleId, readiness, deps, nowMs } = args;
|
|
176
|
+
try {
|
|
177
|
+
await deps.armFocus(focusId, roleId);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
const failure = classifyArmFailure(err);
|
|
181
|
+
log.warn(`[prd-controller] the arm of focus ${focusId} (overcome ${node.id}) was REFUSED ` +
|
|
182
|
+
`[${failure.code ?? 'no code'}]: ${failure.detail} -- the focus stays materialized and ` +
|
|
183
|
+
'UN-ARMED; the frontier re-attempts it on a later tick');
|
|
184
|
+
// The live recorder never throws (prd/arm-refusal.ts); the seam is
|
|
185
|
+
// injectable, so the contract is enforced HERE rather than assumed. A
|
|
186
|
+
// record is the operator's view of a waiting state, not a step in the tick:
|
|
187
|
+
// losing it must never turn a survived refusal back into a lost tick.
|
|
188
|
+
try {
|
|
189
|
+
await (deps.recordArmRefusal ?? recordArmRefusal)({
|
|
190
|
+
focusId,
|
|
191
|
+
nodeId: node.id,
|
|
192
|
+
prdId: prd.id,
|
|
193
|
+
prdTitle: prd.title,
|
|
194
|
+
failure,
|
|
195
|
+
readinessReason: readiness.reason,
|
|
196
|
+
observedAt: new Date(nowMs).toISOString(),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch (recordErr) {
|
|
200
|
+
log.warn(`[prd-controller] could not record the refused arm of focus ${focusId}: ` +
|
|
201
|
+
`${recordErr.message}`);
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
log.info(`[prd-controller] armed focus ${focusId} (overcome ${node.id}): ${readiness.reason}`);
|
|
206
|
+
try {
|
|
207
|
+
await (deps.clearArmRefusal ?? clearArmRefusal)(focusId);
|
|
208
|
+
}
|
|
209
|
+
catch (clearErr) {
|
|
210
|
+
// A stale record on a focus that IS armed is a stale note, not a wedge.
|
|
211
|
+
log.debug(`[prd-controller] could not clear the arm-refusal record for focus ${focusId}: ` +
|
|
212
|
+
`${clearErr.message}`);
|
|
213
|
+
}
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Advance ONE materialized frontier focus by one act. Never throws for an
|
|
218
|
+
* ordinary not-yet-scoped focus, nor for an arm the write refuses; never files
|
|
219
|
+
* an escalation.
|
|
220
|
+
*/
|
|
221
|
+
export async function advancePrdFrontierFocus(args) {
|
|
222
|
+
const { node, focusId, prd, prdGoal, roleId, deps } = args;
|
|
223
|
+
const runs = deps.prdScopingRuns ?? scopingRunsDefault;
|
|
224
|
+
const nowMs = deps.nowMs?.() ?? Date.now();
|
|
225
|
+
const staleMs = deps.prdScopingStaleMs ?? PRD_SCOPING_STALE_MS;
|
|
226
|
+
const maxAttempts = deps.prdScopingMaxAttempts ?? PRD_SCOPING_MAX_ATTEMPTS;
|
|
227
|
+
const run = runs.get(focusId);
|
|
228
|
+
// Skip the readiness read entirely while a run owns the focus: it cannot
|
|
229
|
+
// change the decision, and it costs two API calls per frontier focus per tick.
|
|
230
|
+
const awaiting = run?.status === 'in_flight' && nowMs - run.startedMs < staleMs;
|
|
231
|
+
const readiness = awaiting
|
|
232
|
+
? NOT_READ
|
|
233
|
+
: await (deps.loadFocusArmReadiness ?? readFocusArmReadiness)(focusId);
|
|
234
|
+
const action = decidePrdFrontierAction({ ready: readiness.ready, run, nowMs, staleMs, maxAttempts });
|
|
235
|
+
let armRefused = false;
|
|
236
|
+
switch (action) {
|
|
237
|
+
case 'arm':
|
|
238
|
+
armRefused = !(await armOrRecordRefusal({
|
|
239
|
+
node, focusId, prd, roleId, readiness, deps, nowMs,
|
|
240
|
+
}));
|
|
241
|
+
break;
|
|
242
|
+
case 'spawn_scoping':
|
|
243
|
+
if (run && run.status !== 'in_flight') {
|
|
244
|
+
// A scoping run ENDED and the focus still does not state its future.
|
|
245
|
+
// Name the reason -- this is the whole diagnosis of a frontier that is
|
|
246
|
+
// not advancing, and it must not require reading the agent's transcript.
|
|
247
|
+
log.warn(`[prd-controller] focus ${focusId} (overcome ${node.id}) is NOT armable after a ` +
|
|
248
|
+
`scoping run (${run.status}, exit ${run.lastExitCode ?? '?'}): ${readiness.reason} -- re-scoping`);
|
|
249
|
+
}
|
|
250
|
+
await spawnScopingFor(node, focusId, prd, prdGoal, deps, nowMs);
|
|
251
|
+
break;
|
|
252
|
+
case 'await_scoping':
|
|
253
|
+
log.debug(`[prd-controller] focus ${focusId} is being scoped; not arming this tick`);
|
|
254
|
+
break;
|
|
255
|
+
case 'hold_unscoped':
|
|
256
|
+
// LOUD, but not an escalation: the frontier recomputes every tick and a
|
|
257
|
+
// restart grants a fresh attempt budget.
|
|
258
|
+
log.warn(`[prd-controller] focus ${focusId} (overcome ${node.id}) stays UN-ARMED after ` +
|
|
259
|
+
`${run?.attempts ?? 0} scoping attempt(s): ${readiness.reason}`);
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
return outcome(action, armRefused);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Walk the frontier: materialize what has no focus yet, then advance every
|
|
266
|
+
* materialized frontier focus by one act.
|
|
267
|
+
*
|
|
268
|
+
* A newly materialized focus is advanced in the SAME tick -- which, for a focus
|
|
269
|
+
* that has nothing in it, is the scoping spawn. It is never the arm: a focus
|
|
270
|
+
* created microseconds ago holds no delivery, so readiness cannot be true.
|
|
271
|
+
*/
|
|
272
|
+
export async function runFrontierArmingPass(args) {
|
|
273
|
+
const { prd, nodes, needsMaterialize, needsArm, roleId, deps } = args;
|
|
274
|
+
const result = {
|
|
275
|
+
materialized: 0, armed: 0, skippedNoRole: 0, scopingSpawned: 0, heldUnscoped: 0,
|
|
276
|
+
armRefused: 0,
|
|
277
|
+
};
|
|
278
|
+
const prdGoal = readPrdGoal(nodes);
|
|
279
|
+
const tally = (o) => {
|
|
280
|
+
if (o.armed)
|
|
281
|
+
result.armed += 1;
|
|
282
|
+
if (o.scopingSpawned)
|
|
283
|
+
result.scopingSpawned += 1;
|
|
284
|
+
if (o.heldUnscoped)
|
|
285
|
+
result.heldUnscoped += 1;
|
|
286
|
+
if (o.armRefused)
|
|
287
|
+
result.armRefused += 1;
|
|
288
|
+
};
|
|
289
|
+
for (const node of needsMaterialize) {
|
|
290
|
+
// Do NOT materialize a frontier overcome until the PRD is Played (roleId
|
|
291
|
+
// resolves): materialize mints the focus born status='active', so creating
|
|
292
|
+
// it before the Play commit would light up an active, unarmable focus.
|
|
293
|
+
if (!roleId) {
|
|
294
|
+
result.skippedNoRole += 1;
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const { focusId } = await deps.materializeOvercome(node.id);
|
|
298
|
+
// Carry the new anchor on the in-memory node so this tick's consumers (and
|
|
299
|
+
// the advance below) see a consistent view.
|
|
300
|
+
node.focusId = focusId;
|
|
301
|
+
result.materialized += 1;
|
|
302
|
+
tally(await advancePrdFrontierFocus({ node, focusId, prd, prdGoal, roleId, deps }));
|
|
303
|
+
}
|
|
304
|
+
for (const node of needsArm) {
|
|
305
|
+
if (node.focusId === null)
|
|
306
|
+
continue;
|
|
307
|
+
if (!roleId) {
|
|
308
|
+
result.skippedNoRole += 1;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
tally(await advancePrdFrontierFocus({ node, focusId: node.focusId, prd, prdGoal, roleId, deps }));
|
|
312
|
+
}
|
|
313
|
+
return result;
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=frontier-arming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontier-arming.js","sourceRoot":"","sources":["../../src/prd/frontier-arming.ts"],"names":[],"mappings":"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"}
|
package/dist/prd/index.d.ts
CHANGED
|
@@ -4,8 +4,12 @@
|
|
|
4
4
|
* Consumers import from `./prd/index.js`.
|
|
5
5
|
*
|
|
6
6
|
* Modules:
|
|
7
|
-
* - controller.ts -- PRD-lifecycle controller tick (frontier
|
|
7
|
+
* - controller.ts -- PRD-lifecycle controller tick (frontier walk, done sweep)
|
|
8
8
|
* - frontier.ts -- PRT frontier computation
|
|
9
|
+
* - frontier-arming.ts-- the frontier's three acts: materialize, scope, arm
|
|
10
|
+
* - scoping-prompt.ts -- the PURE prompt the one-shot PRD scoping agent is seeded with
|
|
11
|
+
* - arm-readiness.ts -- "is this focus scoped enough to arm?" (the gate on the arm)
|
|
12
|
+
* - arm-refusal.ts -- surviving an arm the WRITE refuses (classify + record it)
|
|
9
13
|
* - viability.ts -- pathway viability check
|
|
10
14
|
* - divergence.ts -- divergence detection + surviving-path selection
|
|
11
15
|
* - focus-pushdown.ts -- focus-milestone context pushdown
|
|
@@ -17,10 +21,15 @@
|
|
|
17
21
|
* duplicate-name ambiguity.
|
|
18
22
|
*/
|
|
19
23
|
export * from './frontier.js';
|
|
24
|
+
export * from './frontier-arming.js';
|
|
25
|
+
export * from './scoping-prompt.js';
|
|
26
|
+
export * from './arm-readiness.js';
|
|
27
|
+
export * from './arm-refusal.js';
|
|
20
28
|
export * from './viability.js';
|
|
21
29
|
export * from './divergence.js';
|
|
22
30
|
export * from './focus-pushdown.js';
|
|
23
31
|
export * from './steward.js';
|
|
24
32
|
export { STEWARD_CADENCE_MS, PRD_DONE_SWEEP_ABANDONED, DONE_SWEEP_MAX_ATTEMPTS, resolveArmRoleIdFromPrd, computeCompletedFocusIds, runPrdControllerTick, selfHealDonePrdFoci, runDonePrdSweepForProduct, runPrdControllerTickAll, } from './controller.js';
|
|
25
33
|
export type { PrdControllerDeps, PrdControllerTickResult, PrdControllerTickAllResult, } from './controller.js';
|
|
34
|
+
export type { PrdScopingRun, PrdScopingSpawnInput } from './controller-shared.js';
|
|
26
35
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/prd/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prd/index.ts"],"names":[],"mappings":"AAYA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prd/index.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAE7B,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,iBAAiB,EACjB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/prd/index.js
CHANGED
|
@@ -15,8 +15,12 @@
|
|
|
15
15
|
* Consumers import from `./prd/index.js`.
|
|
16
16
|
*
|
|
17
17
|
* Modules:
|
|
18
|
-
* - controller.ts -- PRD-lifecycle controller tick (frontier
|
|
18
|
+
* - controller.ts -- PRD-lifecycle controller tick (frontier walk, done sweep)
|
|
19
19
|
* - frontier.ts -- PRT frontier computation
|
|
20
|
+
* - frontier-arming.ts-- the frontier's three acts: materialize, scope, arm
|
|
21
|
+
* - scoping-prompt.ts -- the PURE prompt the one-shot PRD scoping agent is seeded with
|
|
22
|
+
* - arm-readiness.ts -- "is this focus scoped enough to arm?" (the gate on the arm)
|
|
23
|
+
* - arm-refusal.ts -- surviving an arm the WRITE refuses (classify + record it)
|
|
20
24
|
* - viability.ts -- pathway viability check
|
|
21
25
|
* - divergence.ts -- divergence detection + surviving-path selection
|
|
22
26
|
* - focus-pushdown.ts -- focus-milestone context pushdown
|
|
@@ -28,6 +32,10 @@
|
|
|
28
32
|
* duplicate-name ambiguity.
|
|
29
33
|
*/
|
|
30
34
|
export * from './frontier.js';
|
|
35
|
+
export * from './frontier-arming.js';
|
|
36
|
+
export * from './scoping-prompt.js';
|
|
37
|
+
export * from './arm-readiness.js';
|
|
38
|
+
export * from './arm-refusal.js';
|
|
31
39
|
export * from './viability.js';
|
|
32
40
|
export * from './divergence.js';
|
|
33
41
|
export * from './focus-pushdown.js';
|
package/dist/prd/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prd/index.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,sEAAsE;AACtE,sEAAsE;AACtE,uEAAuE;AACvE,+DAA+D;AAC/D,uEAAuE;AACvE,8DAA8D;AAC9D,4GAA4G;AAC5G,wGAAwG;AACxG,gDAAgD;AAChD,gBAAgB;AAEhB
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prd/index.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,sEAAsE;AACtE,sEAAsE;AACtE,uEAAuE;AACvE,+DAA+D;AAC/D,uEAAuE;AACvE,8DAA8D;AAC9D,4GAA4G;AAC5G,wGAAwG;AACxG,gDAAgD;AAChD,gBAAgB;AAEhB;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAE7B,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PRD frontier's scoping prompt -- PURE.
|
|
3
|
+
*
|
|
4
|
+
* A frontier overcome materializes into a focus that has NOTHING in it: no
|
|
5
|
+
* reality tree, no injections, no deliveries. Arming it in that state asks a
|
|
6
|
+
* human's go-signal to cover an empty set of effects, which is the defect this
|
|
7
|
+
* module exists to remove (see `docs/DECISIONS.md` 2026-09-20, "An arm covers
|
|
8
|
+
* what was agreed": what an arm covers is fixed AT THE ARM, so an arm placed
|
|
9
|
+
* before the tree covers zero effects forever and every delivery scoped
|
|
10
|
+
* afterwards rests at `planning` until someone re-arms).
|
|
11
|
+
*
|
|
12
|
+
* So the controller spawns a one-shot scoping agent FIRST and arms LATER. This
|
|
13
|
+
* builder is what that agent is seeded with. It is a pure string function,
|
|
14
|
+
* mirroring `nexus/intake-spawn.ts` `buildIntakeScopingPrompt`, so what the
|
|
15
|
+
* agent is told is unit-testable without spawning a process -- the four
|
|
16
|
+
* instructions that make the later arm meaningful (build the tree, declare a
|
|
17
|
+
* restatement on every target, anchor one planning delivery per injection, do
|
|
18
|
+
* NOT arm) are pinned by a test rather than trusted to prose review.
|
|
19
|
+
*
|
|
20
|
+
* THE PROMPT SAYS "DO NOT ARM" ON PURPOSE. The agent COULD set the focus's
|
|
21
|
+
* assignedAgentRoleId itself -- nothing refuses it. Arming is a human
|
|
22
|
+
* go-signal, and on the PRD path the human's go-signal is the PRD's Play; the
|
|
23
|
+
* controller holds that signal and spends it only once the focus states the
|
|
24
|
+
* future it covers. An agent that armed itself would spend the human's signal
|
|
25
|
+
* on its own half-finished work.
|
|
26
|
+
*/
|
|
27
|
+
import type { PrtNode } from '../queries/prd.js';
|
|
28
|
+
/**
|
|
29
|
+
* The stable marker the scoping agent writes into the focus description.
|
|
30
|
+
*
|
|
31
|
+
* Mirrors intake's marker-in-the-description idempotency guard: a re-spawned
|
|
32
|
+
* agent (a crashed prior run, a daemon restart) finds it and EXTENDS what is
|
|
33
|
+
* already there instead of authoring a second tree over the top of the first.
|
|
34
|
+
* The controller's own in-flight guard is its scoping-run ledger
|
|
35
|
+
* (`prd/frontier-arming.ts`); this marker is the AGENT's guard, for the window
|
|
36
|
+
* the ledger cannot see across (a restart).
|
|
37
|
+
*/
|
|
38
|
+
export declare function prdScopingMarker(overcomeNodeId: string): string;
|
|
39
|
+
/** What the PRD scoping agent is seeded with. */
|
|
40
|
+
export interface PrdScopingPromptInput {
|
|
41
|
+
/** The focus materialized from the overcome -- it already exists. */
|
|
42
|
+
focusId: string;
|
|
43
|
+
/** The overcome node this focus materialized from. */
|
|
44
|
+
overcomeNodeId: string;
|
|
45
|
+
/** The overcome statement: the capability this focus must deliver. */
|
|
46
|
+
overcomeStatement: string;
|
|
47
|
+
/** The delivery-phases the overcome was authored with (>=2 by the authoring gate). */
|
|
48
|
+
phases: string[];
|
|
49
|
+
prdId: string;
|
|
50
|
+
/** The PRD (milestone) title. */
|
|
51
|
+
prdTitle: string;
|
|
52
|
+
/** The PRD's goal -- the goal node's statement, or null when unreadable. */
|
|
53
|
+
prdGoal: string | null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Read an overcome node's authored phases.
|
|
57
|
+
*
|
|
58
|
+
* `prd_prt_nodes.phases` is JSONB and only overcome nodes populate it (by
|
|
59
|
+
* convention, not by constraint), so anything at all can be in the column. This
|
|
60
|
+
* keeps the strings and drops the rest rather than rendering `[object Object]`
|
|
61
|
+
* into a prompt.
|
|
62
|
+
*/
|
|
63
|
+
export declare function readPhases(node: Pick<PrtNode, 'phases'>): string[];
|
|
64
|
+
/**
|
|
65
|
+
* Build the PRD scoping prompt. PURE -- no I/O, no clock, no randomness.
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildPrdScopingPrompt(input: PrdScopingPromptInput): string;
|
|
68
|
+
//# sourceMappingURL=scoping-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scoping-prompt.d.ts","sourceRoot":"","sources":["../../src/prd/scoping-prompt.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,iDAAiD;AACjD,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,cAAc,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sFAAsF;IACtF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,CAMlE;AAaD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAuC1E"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
|
|
2
|
+
// Pinned by: packages/daemon/src/prd/prd-scoping-prompt.test.ts
|
|
3
|
+
// PINNED-BY-END
|
|
4
|
+
/**
|
|
5
|
+
* The stable marker the scoping agent writes into the focus description.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors intake's marker-in-the-description idempotency guard: a re-spawned
|
|
8
|
+
* agent (a crashed prior run, a daemon restart) finds it and EXTENDS what is
|
|
9
|
+
* already there instead of authoring a second tree over the top of the first.
|
|
10
|
+
* The controller's own in-flight guard is its scoping-run ledger
|
|
11
|
+
* (`prd/frontier-arming.ts`); this marker is the AGENT's guard, for the window
|
|
12
|
+
* the ledger cannot see across (a restart).
|
|
13
|
+
*/
|
|
14
|
+
export function prdScopingMarker(overcomeNodeId) {
|
|
15
|
+
return `PRD overcome scoping: ${overcomeNodeId}`;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Read an overcome node's authored phases.
|
|
19
|
+
*
|
|
20
|
+
* `prd_prt_nodes.phases` is JSONB and only overcome nodes populate it (by
|
|
21
|
+
* convention, not by constraint), so anything at all can be in the column. This
|
|
22
|
+
* keeps the strings and drops the rest rather than rendering `[object Object]`
|
|
23
|
+
* into a prompt.
|
|
24
|
+
*/
|
|
25
|
+
export function readPhases(node) {
|
|
26
|
+
if (!Array.isArray(node.phases))
|
|
27
|
+
return [];
|
|
28
|
+
return node.phases
|
|
29
|
+
.filter((p) => typeof p === 'string')
|
|
30
|
+
.map((p) => p.trim())
|
|
31
|
+
.filter((p) => p.length > 0);
|
|
32
|
+
}
|
|
33
|
+
/** The phases block, or an explicit statement that none were authored. */
|
|
34
|
+
function renderPhases(phases) {
|
|
35
|
+
if (phases.length === 0) {
|
|
36
|
+
return [
|
|
37
|
+
'_No phases were authored on this overcome._ Decompose the capability yourself:',
|
|
38
|
+
'name the phases the work naturally has, then anchor one delivery per phase.',
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
return phases.map((phase, i) => `${i + 1}. ${phase}`);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build the PRD scoping prompt. PURE -- no I/O, no clock, no randomness.
|
|
45
|
+
*/
|
|
46
|
+
export function buildPrdScopingPrompt(input) {
|
|
47
|
+
const marker = prdScopingMarker(input.overcomeNodeId);
|
|
48
|
+
const statement = input.overcomeStatement.trim() || '(no overcome statement authored)';
|
|
49
|
+
return [
|
|
50
|
+
`You are the PRD-frontier SCOPING agent for a milestone capability that has just been materialized into a focus.`,
|
|
51
|
+
`Your SOLE job is to make that focus STATE THE FUTURE IT ASKS FOR -- a reality tree and injection-anchored deliveries -- then exit.`,
|
|
52
|
+
`You author intent + structure via the telora_* MCP tools only -- you write NO application code here.`,
|
|
53
|
+
``,
|
|
54
|
+
`## The milestone`,
|
|
55
|
+
`- PRD: ${input.prdTitle} (prdId ${input.prdId})`,
|
|
56
|
+
`- PRD goal: ${input.prdGoal?.trim() || '(no goal node statement available -- read the PRD with telora_prd get)'}`,
|
|
57
|
+
`- The focus description carries the Vision this milestone derives from; read it first.`,
|
|
58
|
+
``,
|
|
59
|
+
`## The capability to scope (the overcome statement -- this focus's whole target)`,
|
|
60
|
+
statement,
|
|
61
|
+
``,
|
|
62
|
+
`## The delivery-phases this capability was authored with`,
|
|
63
|
+
...renderPhases(input.phases),
|
|
64
|
+
``,
|
|
65
|
+
`## The focus (it ALREADY EXISTS -- do not create another)`,
|
|
66
|
+
`- focusId: ${input.focusId}`,
|
|
67
|
+
`- It is UN-ARMED, and it must still be un-armed when you exit.`,
|
|
68
|
+
``,
|
|
69
|
+
`## IDEMPOTENCY (read first -- a previous scoping run for this overcome may have crashed)`,
|
|
70
|
+
`telora_product_focus get (focusId = ${input.focusId}) and check whether its description carries the marker "${marker}".`,
|
|
71
|
+
`- If it DOES, a prior run got part-way. EXTEND what exists -- reuse the tree, add only the missing injections/deliveries. Do NOT author a second tree.`,
|
|
72
|
+
`- If it does NOT, start at step 1 and make sure step 1 writes the marker.`,
|
|
73
|
+
``,
|
|
74
|
+
`## Steps (do these in order, verifying each with a follow-up read)`,
|
|
75
|
+
`1. telora_product_focus update -- append the marker line "${marker}" verbatim to the focus description, so a re-spawned run can find your work.`,
|
|
76
|
+
`2. telora_reality_tree create on the focus, then author the CRT: the undesired effects that exist today because this capability is missing, and the causal edges between them.`,
|
|
77
|
+
`3. Author the FRT: for EVERY node an injection will target, DECLARE A RESTATEMENT -- the frt_statement saying what that node reads as once the work lands. A target with no frt_statement states no future, and an arm that covers it covers nothing checkable. Use telora_reality_tree_node (frtStatement + frtNodeType) on each target.`,
|
|
78
|
+
`4. Author the injections: one per phase of the capability above. Each injection must draw a \`targets\` edge to the node(s) it flips.`,
|
|
79
|
+
`5. telora_product_delivery create -- ONE delivery per injection, each anchored to its injection (injectionNodeId) and created with executionStatus "planning". One injection, one delivery: the pairing is what lets a later arm say which effects it covers. Carry a workFacing label ("outward" for new ground, "inward" for improving existing ground).`,
|
|
80
|
+
`6. Verify your own work before exiting: re-read the focus's deliveries and confirm EVERY one is anchored to an injection, and that every node those injections target carries an frt_statement. The controller arms this focus only when that is true -- if it is not, your run leaves the focus un-armed and the work is re-scoped.`,
|
|
81
|
+
`7. Stop. Do NOT arm the focus (do NOT set assignedAgentRoleId), do NOT set any delivery to "queued", and do NOT begin implementing. Arming is the human go-signal the PRD's Play holds; the daemon spends it on the next tick once the focus states its future.`,
|
|
82
|
+
``,
|
|
83
|
+
`Refer to focuses/deliveries/issues by title in any prose, never by UUID. Follow CLAUDE.md.`,
|
|
84
|
+
].join('\n');
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=scoping-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scoping-prompt.js","sourceRoot":"","sources":["../../src/prd/scoping-prompt.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,gEAAgE;AAChE,gBAAgB;AA+BhB;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,cAAsB;IACrD,OAAO,yBAAyB,cAAc,EAAE,CAAC;AACnD,CAAC;AAmBD;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,IAA6B;IACtD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3C,OAAO,IAAI,CAAC,MAAM;SACf,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;SACjD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,0EAA0E;AAC1E,SAAS,YAAY,CAAC,MAAgB;IACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,gFAAgF;YAChF,6EAA6E;SAC9E,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAA4B;IAChE,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,kCAAkC,CAAC;IACvF,OAAO;QACL,iHAAiH;QACjH,oIAAoI;QACpI,sGAAsG;QACtG,EAAE;QACF,kBAAkB;QAClB,UAAU,KAAK,CAAC,QAAQ,WAAW,KAAK,CAAC,KAAK,GAAG;QACjD,eAAe,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,wEAAwE,EAAE;QAClH,wFAAwF;QACxF,EAAE;QACF,kFAAkF;QAClF,SAAS;QACT,EAAE;QACF,0DAA0D;QAC1D,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC;QAC7B,EAAE;QACF,2DAA2D;QAC3D,cAAc,KAAK,CAAC,OAAO,EAAE;QAC7B,gEAAgE;QAChE,EAAE;QACF,0FAA0F;QAC1F,uCAAuC,KAAK,CAAC,OAAO,2DAA2D,MAAM,IAAI;QACzH,wJAAwJ;QACxJ,2EAA2E;QAC3E,EAAE;QACF,oEAAoE;QACpE,6DAA6D,MAAM,8EAA8E;QACjJ,gLAAgL;QAChL,2UAA2U;QAC3U,uIAAuI;QACvI,4VAA4V;QAC5V,sUAAsU;QACtU,iQAAiQ;QACjQ,EAAE;QACF,4FAA4F;KAC7F,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -20,12 +20,20 @@
|
|
|
20
20
|
* ..."), are correct and are not flagged.
|
|
21
21
|
* 3. "database trigger" as the mechanism for queued->coding -- migration
|
|
22
22
|
* 20260614172757 removed that trigger; the reconciler owns the edge.
|
|
23
|
+
* 4. a scope-WIDENING mandate ("Create new deliveries via ...", "Do not ask
|
|
24
|
+
* for permission to rescope", the Scoping Mandate / Rescoping sections)
|
|
25
|
+
* delivered in the SAME prompt as the Review-Defect Remediation framing.
|
|
26
|
+
* No delivery is created in answer to a review finding (operator ruling
|
|
27
|
+
* 2026-09-22); a prompt that both forbids and mandates it forbids nothing.
|
|
28
|
+
* The framework builders withhold the scoping sections from a remediation
|
|
29
|
+
* or review pass (team-prompt-base.ts buildScopingSectionsForPass); this
|
|
30
|
+
* class pins that the pairing never returns.
|
|
23
31
|
*
|
|
24
32
|
* This module is the single scanner both the section-builder output and the
|
|
25
33
|
* seeded directive text are checked against (see prompt-contradictions.test.ts).
|
|
26
34
|
* It is pure and dependency-free so it can scan any string.
|
|
27
35
|
*/
|
|
28
|
-
export type ContradictionKind = 'action-suffixed-tool' | 'advancement-mandate' | 'database-trigger';
|
|
36
|
+
export type ContradictionKind = 'action-suffixed-tool' | 'advancement-mandate' | 'database-trigger' | 'scope-widening-in-remediation';
|
|
29
37
|
export interface Contradiction {
|
|
30
38
|
kind: ContradictionKind;
|
|
31
39
|
/** The exact offending substring. */
|
|
@@ -44,6 +52,17 @@ export interface Contradiction {
|
|
|
44
52
|
export declare const ACTION_SUFFIXED_TOOL_RE: RegExp;
|
|
45
53
|
/** "database trigger" as a mechanism claim. */
|
|
46
54
|
export declare const DATABASE_TRIGGER_RE: RegExp;
|
|
55
|
+
/** The heading of the remediation framing (persona-sections.ts). */
|
|
56
|
+
export declare const REMEDIATION_FRAMING_HEADING = "### Review-Defect Remediation";
|
|
57
|
+
/**
|
|
58
|
+
* Scope-widening mandate phrases (prompt-sections/scoping-sections.ts): the
|
|
59
|
+
* delivery-CREATING sentences a pass with `mayCreateDeliveries: false` is not
|
|
60
|
+
* handed. Deliberately NOT the section headings ("### Scoping Mandate",
|
|
61
|
+
* "### Rescoping and Splitting Deliveries"): those sections reach every pass
|
|
62
|
+
* for their issue-creation, criteria and escalation rules. Any of these
|
|
63
|
+
* phrases in the same text as REMEDIATION_FRAMING_HEADING is class 4.
|
|
64
|
+
*/
|
|
65
|
+
export declare const SCOPE_WIDENING_PHRASES: readonly string[];
|
|
47
66
|
/**
|
|
48
67
|
* Scan a string for spawn-prompt contradictions. Returns one Contradiction per
|
|
49
68
|
* offending occurrence (empty array = clean). Order: tool names, then
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-contradictions.d.ts","sourceRoot":"","sources":["../../src/prompt/prompt-contradictions.ts"],"names":[],"mappings":"AAKA
|
|
1
|
+
{"version":3,"file":"prompt-contradictions.d.ts","sourceRoot":"","sources":["../../src/prompt/prompt-contradictions.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,MAAM,MAAM,iBAAiB,GACzB,sBAAsB,GACtB,qBAAqB,GACrB,kBAAkB,GAClB,+BAA+B,CAAC;AAEpC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,QAC+E,CAAC;AAEpH,+CAA+C;AAC/C,eAAO,MAAM,mBAAmB,QAA2B,CAAC;AAE5D,oEAAoE;AACpE,eAAO,MAAM,2BAA2B,kCAAkC,CAAC;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAKnD,CAAC;AAiCF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAiCnE;AA4BD,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,CAKnF"}
|