pi-daddy 0.24.0 → 0.25.0

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.
Files changed (67) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +11 -3
  3. package/contracts/ledger/v4/README.md +1 -1
  4. package/dist/daily-dashboard-host.d.ts +26 -2
  5. package/dist/daily-dashboard-host.d.ts.map +1 -1
  6. package/dist/daily-dashboard-host.js +78 -8
  7. package/dist/daily-dashboard-host.js.map +1 -1
  8. package/dist/dashboard-handshake.d.ts.map +1 -1
  9. package/dist/dashboard-handshake.js +13 -4
  10. package/dist/dashboard-handshake.js.map +1 -1
  11. package/dist/dashboard-harness.d.ts +1 -1
  12. package/dist/dashboard-harness.js +3 -3
  13. package/dist/dashboard-harness.js.map +1 -1
  14. package/dist/dashboard-herdr.d.ts +1 -0
  15. package/dist/dashboard-herdr.d.ts.map +1 -1
  16. package/dist/dashboard-herdr.js +10 -8
  17. package/dist/dashboard-herdr.js.map +1 -1
  18. package/dist/dashboard-host-contract.d.ts +10 -1
  19. package/dist/dashboard-host-contract.d.ts.map +1 -1
  20. package/dist/dashboard-host-contract.js +1 -1
  21. package/dist/dashboard-host-contract.js.map +1 -1
  22. package/dist/dashboard-host.d.ts +8 -0
  23. package/dist/dashboard-host.d.ts.map +1 -1
  24. package/dist/dashboard-host.js +24 -6
  25. package/dist/dashboard-host.js.map +1 -1
  26. package/dist/dashboard-observation.d.ts.map +1 -1
  27. package/dist/dashboard-observation.js +1 -0
  28. package/dist/dashboard-observation.js.map +1 -1
  29. package/dist/experiment.d.ts.map +1 -1
  30. package/dist/experiment.js +9 -4
  31. package/dist/experiment.js.map +1 -1
  32. package/dist/index.d.ts +3 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +3 -0
  35. package/dist/index.js.map +1 -1
  36. package/dist/intent-application.d.ts.map +1 -1
  37. package/dist/intent-application.js +3 -2
  38. package/dist/intent-application.js.map +1 -1
  39. package/dist/measured-order.d.ts +249 -0
  40. package/dist/measured-order.d.ts.map +1 -0
  41. package/dist/measured-order.js +251 -0
  42. package/dist/measured-order.js.map +1 -0
  43. package/dist/measured-session.d.ts +97 -0
  44. package/dist/measured-session.d.ts.map +1 -0
  45. package/dist/measured-session.js +134 -0
  46. package/dist/measured-session.js.map +1 -0
  47. package/dist/work-command.d.ts +2 -0
  48. package/dist/work-command.d.ts.map +1 -1
  49. package/dist/work-command.js +15 -2
  50. package/dist/work-command.js.map +1 -1
  51. package/extensions/daily-dashboard-session.ts +9 -8
  52. package/extensions/grants-command.ts +2 -0
  53. package/extensions/grants.ts +1 -1
  54. package/package.json +13 -1
  55. package/src/daily-dashboard-host.ts +49 -10
  56. package/src/dashboard-handshake.ts +14 -5
  57. package/src/dashboard-harness.ts +3 -3
  58. package/src/dashboard-herdr.ts +12 -9
  59. package/src/dashboard-host-contract.ts +5 -2
  60. package/src/dashboard-host.ts +14 -9
  61. package/src/dashboard-observation.ts +1 -0
  62. package/src/experiment.ts +8 -3
  63. package/src/index.ts +17 -0
  64. package/src/intent-application.ts +3 -2
  65. package/src/measured-order.ts +67 -0
  66. package/src/measured-session.ts +70 -0
  67. package/src/work-command.ts +8 -2
@@ -3,6 +3,7 @@ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
3
3
  import { dirname, isAbsolute, join, resolve } from "node:path";
4
4
  import { appendWorkLedgerEventOnce, buildWorkOccurrenceEvent, buildWorkRevisionEvent, buildWorkSnapshotEvent, parseWorkLedgerText, projectWorkLedger, } from "./work-ledger.js";
5
5
  import { withFileLock } from "./file-lock.js";
6
+ import { resolveWorkSnapshotText } from "./work-ledger-snapshot.js";
6
7
  const ID = /^[A-Za-z0-9][A-Za-z0-9._:/@+\-]{0,127}$/;
7
8
  const DIGEST = /^[a-f0-9]{64}$/;
8
9
  const sha256 = (value) => createHash("sha256").update(value).digest("hex");
@@ -71,8 +72,8 @@ export async function declareWork(input) {
71
72
  if (!ID.test(input.id) || typeof input.outcome !== "string" || !input.outcome.trim())
72
73
  throw new TypeError("work declaration requires an identifier and non-empty outcome");
73
74
  const resolved = paths(input), outcomeDigest = sha256(input.outcome.trim());
74
- await mkdir(dirname(resolved.ledgerPath), { recursive: true });
75
- await mkdir(dirname(resolved.statePath), { recursive: true });
75
+ await mkdir(dirname(resolved.ledgerPath), { recursive: true, mode: 0o700 });
76
+ await mkdir(dirname(resolved.statePath), { recursive: true, mode: 0o700 });
76
77
  return withFileLock(resolved.statePath, "declared work", async () => {
77
78
  const existing = await loadDeclaredWork(resolved.statePath);
78
79
  if (existing) {
@@ -125,6 +126,18 @@ export async function declareWork(input) {
125
126
  return Object.freeze({ ...stored, statePath: resolved.statePath });
126
127
  });
127
128
  }
129
+ /** Persist an already-applied exact selection so the next governed dispatch cannot keep using the old cached declaration. */
130
+ export async function rebindDeclaredWork(state, selectedSnapshot) {
131
+ return withFileLock(state.statePath, "declared work rebind", async () => { const current = await loadDeclaredWork(state.statePath); if (!current || JSON.stringify(current.selectedSnapshot) !== JSON.stringify(state.selectedSnapshot))
132
+ throw Error("declared work rebind is stale; new dispatch remains unsupported"); const text = await readFile(state.ledgerPath, "utf8"), resolved = resolveWorkSnapshotText(text, selectedSnapshot), binding = resolved.snapshot?.bindings[0]; if (resolved.scopeState !== "valid" || !resolved.scope || !resolved.snapshot || !binding)
133
+ throw Error("applied declared selection cannot bind future dispatch"); const stored = { version: "pi-daddy-declared-work-v1", id: state.id, outcomeDigest: state.outcomeDigest, ledgerPath: state.ledgerPath, grantLedgerPath: state.grantLedgerPath, selectedSnapshot, scope: { kind: resolved.scope.kind, id: resolved.scope.id, revision: resolved.scope.revision, digest: resolved.scope.digest }, intent: binding.intent, obligation: binding.obligation, policy: binding.policy }; const temporary = `${state.statePath}.${process.pid}.${randomUUID()}.tmp`; try {
134
+ await writeFile(temporary, `${JSON.stringify(stored, null, 2)}\n`, { encoding: "utf8", mode: 0o600, flag: "wx" });
135
+ await rename(temporary, state.statePath);
136
+ }
137
+ finally {
138
+ await rm(temporary, { force: true });
139
+ } return Object.freeze({ ...stored, statePath: state.statePath }); });
140
+ }
128
141
  export async function appendDeclaredWorkOccurrence(state, identity, occurrenceState) {
129
142
  const { executionId, parentExecutionId, childId, variantId, now, ...rawLabels } = identity;
130
143
  const label = (name, value) => value === null ? null : ID.test(value) ? value : `${name}:${sha256(value)}`;
@@ -1 +1 @@
1
- {"version":3,"file":"work-command.js","sourceRoot":"","sources":["../src/work-command.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"work-command.js","sourceRoot":"","sources":["../src/work-command.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { createHash } from "node:crypto";
1
+ import { createHash, randomUUID } from "node:crypto";
2
2
  import { homedir } from "node:os";
3
3
  import { mkdir } from "node:fs/promises";
4
4
  import { join } from "node:path";
@@ -10,21 +10,22 @@ import type { OrdinaryChildren } from "../src/ordinary-children.ts";
10
10
 
11
11
  const BRIDGE=Symbol.for("skill-harness.dashboard-host.v1"),idPattern=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
12
12
  export function dailyDashboardPaths(cwd:string,id:string,home=homedir(),uid=process.getuid?.()??0){const key=createHash("sha256").update(`${cwd}\0${id}`).digest("hex");return {directory:join(home,".local","state","pi-daddy","hosts",key.slice(0,16)),socketDirectory:join("/tmp",`pi-daddy-${uid}`),socketPath:join("/tmp",`pi-daddy-${uid}`,`host-${key.slice(0,20)}.sock`)};}
13
- export function createDailyDashboardSession(input:{ordinary:()=>OrdinaryChildren;declared:()=>DeclaredWorkState|undefined;cwd:()=>string;env:Record<string,string|undefined>;author:string}){
14
- let current:null|Awaited<ReturnType<typeof startDailyDashboardHost>>=null,publishedSocket:string|undefined;
13
+ export function createDailyDashboardSession(input:{ordinary:()=>OrdinaryChildren;declared:()=>DeclaredWorkState|undefined;rebind:(state:DeclaredWorkState)=>void;cwd:()=>string;env:Record<string,string|undefined>;author:string}){
14
+ let current:null|Awaited<ReturnType<typeof startDailyDashboardHost>>=null,publishedSocket:string|undefined,closing:null|{present:true;closing:true;evidenceDigest:string;expiresAt:number}=null;
15
15
  return Object.freeze({
16
16
  async run(target:string){
17
17
  if(target==="stop"){
18
- if(!current)return "daily host is not running";await current.close();current=null;if(publishedSocket&&input.env[ENV_DASHBOARD_HOST_SOCKET]===publishedSocket)delete input.env[ENV_DASHBOARD_HOST_SOCKET];publishedSocket=undefined;return "daily host stopped; no child was cancelled";
18
+ if(!current)return "daily host is not running";await current.close();current=null;closing=null;if(publishedSocket&&input.env[ENV_DASHBOARD_HOST_SOCKET]===publishedSocket)delete input.env[ENV_DASHBOARD_HOST_SOCKET];publishedSocket=undefined;return "daily host stopped; no child was cancelled";
19
19
  }
20
- if(!idPattern.test(target))throw Error("usage — /grants host <fresh-id> | stop");if(current)throw Error("daily host already running in this session; stop it before selecting another fresh id");
20
+ if(target==="closing"){if(!current)throw Error("daily host is not running");const expiresAt=Date.now()+120_000;closing={present:true,closing:true,evidenceDigest:createHash("sha256").update(`${input.cwd()}\0${expiresAt}\0${randomUUID()}`).digest("hex"),expiresAt};return "explicit closing presence recorded for two minutes; pause new dispatch and finish/cancel active attempts, then choose prepare-case-cards in the dashboard. No card is counted as delivered until visibly acknowledged.";}
21
+ if(!idPattern.test(target))throw Error("usage — /grants host <fresh-id> | closing | stop");if(current)throw Error("daily host already running in this session; use closing or stop");
21
22
  const declared=input.declared();if(!declared)throw Error("declare current work first with pi-daddy work add, then reload");
22
23
  const bridge=(globalThis as Record<PropertyKey,unknown>)[BRIDGE];if(!bridge)throw Error("loaded skill-harness extension bridge unavailable; load the candidate skill-harness extension in this Pi session");
23
24
  const paths=dailyDashboardPaths(input.cwd(),target);await mkdir(join(homedir(),".local","state","pi-daddy","hosts"),{recursive:true,mode:0o700});await mkdir(paths.socketDirectory,{recursive:true,mode:0o700});
24
- current=await startDailyDashboardHost({id:target,cwd:input.cwd(),directory:paths.directory,socketPath:paths.socketPath,declared,ordinary:input.ordinary(),harness:adoptDashboardHarnessBridge(bridge) as never,author:input.author});
25
+ current=await startDailyDashboardHost({id:target,cwd:input.cwd(),directory:paths.directory,socketPath:paths.socketPath,declared,ordinary:input.ordinary(),harness:adoptDashboardHarnessBridge(bridge) as never,author:input.author,presence:()=>closing,onDeclaredWorkChanged:input.rebind});
25
26
  publishedSocket=current.socketPath;input.env[ENV_DASHBOARD_HOST_SOCKET]=publishedSocket;
26
- return `daily host started at ${publishedSocket}; current declared work/facts were captured. Run /grants dashboard, then use only its listed pause/resume/refresh action keys. Runtime remains unaccepted.`;
27
+ return `daily host started at ${publishedSocket}; current declared work/facts were captured. Run /grants dashboard, then use only its listed pause/resume/refresh/cancel/scope/priority/alternative action keys. Runtime remains unaccepted.`;
27
28
  },
28
- async close(){if(current)await current.close();if(publishedSocket&&input.env[ENV_DASHBOARD_HOST_SOCKET]===publishedSocket)delete input.env[ENV_DASHBOARD_HOST_SOCKET];current=null;publishedSocket=undefined;}
29
+ async close(){if(current)await current.close();if(publishedSocket&&input.env[ENV_DASHBOARD_HOST_SOCKET]===publishedSocket)delete input.env[ENV_DASHBOARD_HOST_SOCKET];current=null;closing=null;publishedSocket=undefined;}
29
30
  });
30
31
  }
@@ -102,6 +102,8 @@ handler: async (args: string, ctx: any) => {
102
102
  if (sub === "variants") {
103
103
  const lines=[`grants: ${variantRuns.size} retained primary/shadow run(s)`];
104
104
  for(const run of variantRuns.values())lines.push(` ${run.runId} ${run.state} — primary ${run.primaryExecutionId}; ${run.shadowExecutionIds.length} shadow(s)`+(!run.outcomes?"":` — ${run.outcomes.map(x=>`${x.role}:${x.ok?"completed":"failed"}`).join(", ")}`));
105
+ lines.push(" provider usage unavailable on the default child print transport; fan-out, output bytes and wall time remain controller-bounded");
106
+ lines.push(" opt-in measured no-tool sessions can retain Pi Usage for exact Sol/Terra attempts; this is not ordinary-child or subscription-billing coverage");
105
107
  ctx.ui.notify(lines.join("\n"),"info");return;
106
108
  }
107
109
 
@@ -65,7 +65,7 @@ export default function (pi: ExtensionAPI) {
65
65
 
66
66
  const session = createGrantsSession(extensionPath);
67
67
  associateOrdinaryHost(pi,session);
68
- const dailyHost=createDailyDashboardSession({ordinary:()=>ordinaryChildrenFor(pi),declared:()=>session.declaredWork,cwd:()=>session.cwd,env:process.env,author:"local-operator"});
68
+ const dailyHost=createDailyDashboardSession({ordinary:()=>ordinaryChildrenFor(pi),declared:()=>session.declaredWork,rebind:state=>{session.declaredWork=state;},cwd:()=>session.cwd,env:process.env,author:"local-operator"});
69
69
  const dashboardPluginRoot = fileURLToPath(new URL("../herdr-plugin/", import.meta.url));
70
70
  const dashboardPaths = defaultDashboardPaths(
71
71
  process.env.PI_CODING_AGENT_DIR?.trim() || join(homedir(), ".pi", "agent"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-daddy",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "Capability governance for pi sub-agents: spawn Agent Skills (SKILL.md) definitions whose allowed-tools becomes a grant that can only narrow going down a delegation tree, enforced by pi's own --tools allowlist, with an append-only ledger.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -53,6 +53,10 @@
53
53
  "types": "./dist/dashboard-harness.d.ts",
54
54
  "default": "./dist/dashboard-harness.js"
55
55
  },
56
+ "./daily-dashboard-host": {
57
+ "types": "./dist/daily-dashboard-host.d.ts",
58
+ "default": "./dist/daily-dashboard-host.js"
59
+ },
56
60
  "./dashboard-host": {
57
61
  "types": "./dist/dashboard-host.d.ts",
58
62
  "default": "./dist/dashboard-host.js"
@@ -94,6 +98,14 @@
94
98
  "types": "./dist/effect-profile.d.ts",
95
99
  "default": "./dist/effect-profile.js"
96
100
  },
101
+ "./measured-session": {
102
+ "types": "./dist/measured-session.d.ts",
103
+ "default": "./dist/measured-session.js"
104
+ },
105
+ "./measured-order": {
106
+ "types": "./dist/measured-order.d.ts",
107
+ "default": "./dist/measured-order.js"
108
+ },
97
109
  "./execution-retention": {
98
110
  "types": "./dist/execution-retention.d.ts",
99
111
  "default": "./dist/execution-retention.js"
@@ -4,16 +4,37 @@ import { isAbsolute, resolve, join } from "node:path";
4
4
  import { createDashboardHost, dashboardHostDigest, dashboardHostRequestDigest, type DashboardHostAuthority, type DashboardHostConfig, type DashboardHostRequest } from "./dashboard-host.ts";
5
5
  import type { DashboardHarness } from "./dashboard-host-contract.ts";
6
6
  import { loadedDashboardHarnessDigest } from "./dashboard-harness.ts";
7
- import { createDispatchBudget, openResourceBudget, resourceBindingDigest } from "./resource-budget.ts";
7
+ import { createIntentBudget, openResourceBudget, resourceBindingDigest } from "./resource-budget.ts";
8
8
  import { dispatchRequestDigest, type DispatchRequest } from "./dispatch-control.ts";
9
9
  import { serveDashboardHost } from "./dashboard-host-transport.ts";
10
- import type { DeclaredWorkState } from "./work-command.ts";
11
- import type { OrdinaryChildren } from "./ordinary-children.ts";
10
+ import { rebindDeclaredWork, type DeclaredWorkState } from "./work-command.ts";
11
+ import { ordinaryCancellation, ordinaryCancellationDigest, type OrdinaryChildren, type OrdinaryTarget } from "./ordinary-children.ts";
12
12
  import { dataDigest } from "./debrief-contract.ts";
13
+ import { bindWorkIntent } from "./intent-application.ts";
14
+ import { intentKey, intentRequest, intentRequestDigest, type IntentPriority, type IntentRequest, type IntentSelection } from "./intent-control.ts";
15
+ import { parseWorkLedgerText, type WorkRevisionEvent, type WorkSnapshotEvent } from "./work-ledger.ts";
16
+ import { resolveWorkSnapshotText } from "./work-ledger-snapshot.ts";
13
17
 
14
- export interface DailyDashboardHostInput {id:string;cwd:string;directory:string;socketPath?:string;declared:DeclaredWorkState;ordinary:OrdinaryChildren;harness:DashboardHarness;author:string}
18
+ export interface DailyIntentAction {key:string;label:string;action:"revise-scope"|"reprioritize"|"select-alternative";fromSelection:IntentSelection;events:(WorkRevisionEvent|WorkSnapshotEvent)[];selection:IntentSelection;priorities:IntentPriority[]}
19
+ export interface DailyDashboardHostInput {id:string;cwd:string;directory:string;socketPath?:string;declared:DeclaredWorkState;ordinary:OrdinaryChildren;harness:DashboardHarness;author:string;priorities?:IntentPriority[];intentActions?:DailyIntentAction[];presence?:()=>{present:boolean;closing:boolean;evidenceDigest:string;expiresAt:number}|null;onDeclaredWorkChanged?:(state:DeclaredWorkState)=>void|Promise<void>}
15
20
  const idPattern=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
16
21
  const hash=(value:string)=>createHash("sha256").update(value).digest("hex");
22
+ const same=(a:unknown,b:unknown)=>intentKey(a)===intentKey(b);
23
+ /** Recorded P01 snapshots become labelled proposals; choosing a label still traverses intent validation and exact host/CAS authority. */
24
+ export function discoverDailyIntentActions(text:string,selection:IntentSelection,priorities:readonly IntentPriority[]):DailyIntentAction[]{
25
+ const parsed=parseWorkLedgerText(text);if(!parsed.complete||parsed.events.length>512)throw Error("bounded complete recorded proposal ledger required");const label=(value:string)=>value.length<=80?value:`${value.slice(0,67)}…${hash(value).slice(0,12)}`;
26
+ const current=resolveWorkSnapshotText(text,selection);if(current.scopeState!=="valid"||!current.scope||!current.snapshot)throw Error("current declared work unavailable");
27
+ const actions:DailyIntentAction[]=[];for(const priority of priorities.slice(1)){
28
+ const ordered=[priority,...priorities.filter(x=>!same(x.obligation,priority.obligation))].map((x,rank)=>({...x,rank}));
29
+ actions.push({key:`priority-${hash(intentKey(priority.obligation)).slice(0,12)}`,label:`Put ${label(priority.obligation.id)} first`,action:"reprioritize",fromSelection:selection,events:[],selection,priorities:ordered});
30
+ }
31
+ for(const event of parsed.events){if(event.event!=="work_snapshot")continue;const candidate={snapshot:{id:event.payload.snapshot.snapshotId,digest:event.payload.snapshot.digest},event:{eventId:event.eventId,digest:event.digest}};if(same(candidate,selection))continue;
32
+ const next=resolveWorkSnapshotText(text,candidate);if(next.scopeState!=="valid"||!next.scope||!next.snapshot||next.snapshot.bindings.length>32)continue;
33
+ const action=next.scope.digest===current.scope.digest?"select-alternative":next.scope.predecessor&&same(next.scope.predecessor,{kind:current.scope.kind,id:current.scope.id,revision:current.scope.revision,digest:current.scope.digest})?"revise-scope":null;if(!action)continue;
34
+ actions.push({key:`${action==="revise-scope"?"scope":"alternative"}-${hash(intentKey(candidate)).slice(0,12)}`,label:`Select recorded ${action==="revise-scope"?"scope":"alternative"} ${label(event.payload.snapshot.snapshotId)}`,action,fromSelection:selection,events:[],selection:candidate,priorities:next.snapshot.bindings.map((b,rank)=>({obligation:b.obligation,rank}))});
35
+ }
36
+ return actions.sort((a,b)=>a.key.localeCompare(b.key)).slice(0,8);
37
+ }
17
38
 
18
39
  /** One explicitly started, process-owned daily host. No authority, controller or prior host is recovered from disk. */
19
40
  export async function startDailyDashboardHost(input:DailyDashboardHostInput){
@@ -22,7 +43,7 @@ export async function startDailyDashboardHost(input:DailyDashboardHostInput){
22
43
  if(input.declared.ledgerPath!==join(input.cwd,".pi","work.jsonl"))throw Error("current declared work must belong to this host project");
23
44
  await mkdir(input.directory,{mode:0o700});const archiveRoot=join(input.directory,"archive");await mkdir(archiveRoot,{mode:0o700});
24
45
  const reference=input.harness.retainArchiveSource(archiveRoot,{sourceId:`host-${input.id}-bootstrap`,parser:{id:"daily-host-bootstrap",version:"1"},retention:"exact",bytes:Buffer.from("explicit daily host bootstrap")});
25
- const component={kind:"detector",id:"retained-work",version:"1",population:`daily:${input.id}`};
46
+ const component={kind:"detector",id:"coverage_gap",version:"work-signals-v1:declared-work-v1",population:`daily:${input.id}`};
26
47
  const trustInput={archiveRoot,component,seed:hash(`daily-host\0${input.id}`),maxUnflagged:0,cohort:[{incidentId:"bootstrap",manifestId:reference.manifestId,flagged:true,split:"calibration"}],exposure:null};
27
48
  const trustPolicyId=input.harness.trustPolicyDigest(trustInput),trustDirectory=join(input.directory,"trust");input.harness.createTrustLifecycle(trustDirectory,trustInput,[trustPolicyId]);
28
49
  const workRelative="work.jsonl",factsRelative="facts.jsonl",workMirror=join(input.directory,workRelative);await writeFile(workMirror,await readFile(input.declared.ledgerPath),{mode:0o600,flag:"wx"});
@@ -30,18 +51,36 @@ export async function startDailyDashboardHost(input:DailyDashboardHostInput){
30
51
  const facts={scopeDigest:input.declared.selectedSnapshot.snapshot.digest,version:"declared-work-v1",population:`daily:${input.id}`,expectedWaits:[],checkpoints:[],violations:[],priorAccepted:[]};await writeFile(join(input.directory,factsRelative),JSON.stringify(facts)+"\n",{mode:0o600,flag:"wx"});
31
52
  const policy={version:"archive-policy-v2",id:`daily-${input.id}`,revision:"1",sourceRoot:input.directory,archiveRoot,maxBytes:8*1024*1024,retention:"exact",expiresAt:new Date(Date.now()+24*60*60*1000).toISOString(),sources:[{id:"work",path:workRelative,parser:{id:"pi-daddy-work-ledger",version:"4"},contentPolicy:"manifest-only"},{id:"facts",path:factsRelative,parser:{id:"pi-daddy-work-signal-facts",version:"1"},contentPolicy:"manifest-only"}]};
32
53
  const policyPath=join(input.directory,"archive-policy.json"),policyBytes=JSON.stringify(policy);await writeFile(policyPath,policyBytes,{mode:0o600,flag:"wx"});
33
- const authorityDigest=dataDigest({kind:"daily-dashboard-host",id:input.id,cwd:input.cwd}),budget=await createDispatchBudget({directory:join(input.directory,"budget"),authorityDigest,limits:{maxAttempts:6,maxInputBytes:65536,maxConcurrent:3}});
54
+ const authorityDigest=dataDigest({kind:"daily-dashboard-host",id:input.id,cwd:input.cwd}),initialPriorities=input.priorities??[{obligation:input.declared.obligation,rank:0}];
55
+ const workIntent=await bindWorkIntent({path:input.declared.ledgerPath,grantLedgerPath:input.declared.grantLedgerPath,selection:input.declared.selectedSnapshot,priorities:initialPriorities});
56
+ const budget=await createIntentBudget({directory:join(input.directory,"budget"),authorityDigest,limits:{maxAttempts:6,maxInputBytes:65536,maxConcurrent:3}},workIntent);
34
57
  const config:DashboardHostConfig={version:"producer-dashboard-host-v1",trustDirectory,trustPolicyId,archiveRoot,scope:`daily:${input.id}`,author:input.author,policyPath,policySha256:hash(policyBytes),sources:[{id:"work",kind:"work"},{id:"facts",kind:"facts"}],selection:input.declared.selectedSnapshot,cases:null,blind:null,budgetDigest:resourceBindingDigest(budget),experimentDigest:null,harnessArtifactDigest:harnessDigest,ordinaryDigest:input.ordinary.bindingDigest};
35
- const requestDigests=new Set<string>(),dispatchDigests=new Set<string>();let host:ReturnType<typeof createDashboardHost>,factsResultManifest:string|null=null;
36
- const authority=():DashboardHostAuthority=>({hostDigests:[dashboardHostDigest(config)],requestDigests:[...requestDigests],workContext:{selectedSnapshot:config.selection,authority:null},dispatch:{authorityDigest,requestDigests:[...dispatchDigests]},experiment:null});
58
+ const proposals=input.intentActions??[];if(proposals.length>8||new Set(proposals.map(x=>x.key)).size!==proposals.length||proposals.some(x=>!idPattern.test(x.key)||typeof x.label!=="string"||!x.label.trim()||Buffer.byteLength(x.label)>120))throw Error("bounded friendly intent actions required");
59
+ const requestDigests=new Set<string>(),dispatchDigests=new Set<string>(),ordinaryDigests=new Set<string>();let host:ReturnType<typeof createDashboardHost>,factsResultManifest:string|null=null,workSelection:IntentSelection=input.declared.selectedSnapshot,declaredState=input.declared,reboundSnapshotId:string|null=null;
60
+ const authority=():DashboardHostAuthority=>({hostDigests:[dashboardHostDigest(config)],requestDigests:[...requestDigests],workContext:{selectedSnapshot:workSelection,authority:null},dispatch:{authorityDigest,requestDigests:[...dispatchDigests]},experiment:null,ordinary:{bindingDigest:input.ordinary.bindingDigest,requestDigests:[...ordinaryDigests]}});
37
61
  const request=(context:{hostDigest:string;selectionDigest:string;tip:string},operation:DashboardHostRequest["operation"],payload:unknown,requestId:string):DashboardHostRequest=>({version:"1.0",requestId,hostDigest:context.hostDigest,selectionDigest:context.selectionDigest,expectedTip:context.tip,operation,payload});
38
62
  host=createDashboardHost({harness:input.harness,config,budget,ordinary:input.ordinary,authority,beforeObservation:sourceId=>sourceId==="work"?refreshWork():Promise.resolve(),humanActions:async context=>{
39
63
  const state=await openResourceBudget(budget).controls(null).inspect(),action=state.paused?"resume-dispatch":"pause-dispatch",key=state.paused?"resume-dispatch":"pause-new-dispatch";
40
64
  const native:DispatchRequest={version:"1.0",requestId:`${action}:${state.revision}`,bindingDigest:config.budgetDigest,expectedRevision:state.revision,action,targetExecutionId:null};dispatchDigests.add(dispatchRequestDigest(native));
41
65
  const hostRequest=request(context,"dispatch",native,`host-${action}:${state.revision}`);requestDigests.add(dashboardHostRequestDigest(hostRequest));
42
66
  const previous=context.observations.find(x=>x.sourceId==="work")?.checkpointId??null,refresh=request(context,"observe",{sourceId:"work",previousCheckpointId:previous,facts:context.observations.find(x=>x.sourceId==="facts")?.checkpointId?factsResultManifest:null},`refresh-work:${state.revision}:${context.tip.slice(0,12)}`);requestDigests.add(dashboardHostRequestDigest(refresh));
43
- return [{key,label:state.paused?"Resume new governed dispatch":"Pause new governed dispatch; running children continue",request:hostRequest},{key:"refresh-current-work",label:"Capture current declared work and attempts",request:refresh}];
44
- }});
67
+ const intentState=await openResourceBudget(budget).intentControls(null).inspect(),automatic=discoverDailyIntentActions(await readFile(input.declared.ledgerPath,"utf8"),intentState.selection,intentState.priorities);
68
+ const candidates=[...proposals,...automatic].filter((p,index,all)=>all.findIndex(x=>x.key===p.key)===index).filter(p=>p.action==="reprioritize"||Boolean(input.onDeclaredWorkChanged)).slice(0,8);
69
+ const intents=(input.ordinary.quiescent()?candidates:[]).filter(p=>intentKey(p.fromSelection)===intentKey(intentState.selection)).map(p=>{
70
+ const native=intentRequest({version:"intent-request-v1",requestId:`${p.key}:${intentState.revision}`,bindingDigest:config.budgetDigest,expectedRevision:intentState.revision,expectedSelection:intentState.selection,action:p.action,events:p.events,selection:p.selection,priorities:p.priorities});dispatchDigests.add(intentRequestDigest(native));
71
+ const proposed=request(context,"intent",native,`host-intent:${p.key}:${intentState.revision}`);requestDigests.add(dashboardHostRequestDigest(proposed));return {key:p.key,label:p.label,request:proposed};
72
+ });
73
+ const ordinary=input.ordinary.inspect() as {revision:number;children:{target:OrdinaryTarget;state:string}[]},accounting=await openResourceBudget(budget).inspect(),presence=input.presence?.();
74
+ const presentation:{key:string;label:string;request:DashboardHostRequest}[]=[];
75
+ if(context.preparedPresentationDigest){const shown=request(context,"presented",{frameDigest:context.preparedPresentationDigest},`host-presented:${state.revision}:${context.tip.slice(0,12)}`);requestDigests.add(dashboardHostRequestDigest(shown));presentation.push({key:"acknowledge-case-cards",label:"Acknowledge these case cards are visible",request:shown});}
76
+ else if(presence?.present===true&&presence.closing===true&&presence.expiresAt>Date.now()&&state.paused&&accounting.active===0&&!ordinary.children.some(row=>row.state==="active")){const present=request(context,"present",{userPresent:true,closing:true,evidenceDigest:presence.evidenceDigest,dispatchRevision:state.revision},`host-present:${state.revision}:${context.tip.slice(0,12)}`);requestDigests.add(dashboardHostRequestDigest(present));presentation.push({key:"prepare-case-cards",label:"Prepare up to five retained case cards",request:present});}
77
+ const cancellations=ordinary.children.filter(row=>row.state==="active").sort((a,b)=>a.target.executionId.localeCompare(b.target.executionId)).slice(0,8).map(row=>{
78
+ const native=ordinaryCancellation({version:"ordinary-cancel-v1",requestId:`cancel:${row.target.executionId.slice(5)}`,bindingDigest:input.ordinary.bindingDigest,expectedRevision:ordinary.revision,target:row.target});ordinaryDigests.add(ordinaryCancellationDigest(native));
79
+ const cancel=request(context,"ordinary-cancel",native,`host-cancel:${row.target.executionId.slice(5)}:${ordinary.revision}`);requestDigests.add(dashboardHostRequestDigest(cancel));
80
+ return {key:`cancel-${row.target.executionId.replace(":","-")}`,label:`Cancel running attempt ${row.target.executionId}`,request:cancel};
81
+ });
82
+ return [{key,label:state.paused?"Resume new governed dispatch":"Pause new governed dispatch; running children continue",request:hostRequest},{key:"refresh-current-work",label:reboundSnapshotId?`Capture rebound declared work; next dispatch uses ${reboundSnapshotId}`:"Capture current declared work and attempts",request:refresh},...intents,...presentation,...cancellations];
83
+ },afterIntentApplied:async selection=>{const rebound=await rebindDeclaredWork(declaredState,selection);declaredState=rebound;workSelection=selection;reboundSnapshotId=selection.snapshot.id;await input.onDeclaredWorkChanged?.(rebound);},presence:input.presence});
45
84
  const before=await host.frame(),observeFacts=request({hostDigest:host.hostDigest,selectionDigest:before.selectionDigest,tip:before.tip},"observe",{sourceId:"facts",previousCheckpointId:null,facts:null},"observe-current-facts");requestDigests.add(dashboardHostRequestDigest(observeFacts));const factsResult=await host.action(observeFacts) as {result:{sourceManifestId:string}};factsResultManifest=factsResult.result.sourceManifestId;
46
85
  const afterFacts=await host.frame(),observeWork=request({hostDigest:host.hostDigest,selectionDigest:afterFacts.selectionDigest,tip:afterFacts.tip},"observe",{sourceId:"work",previousCheckpointId:null,facts:factsResult.result.sourceManifestId},"observe-current-work");requestDigests.add(dashboardHostRequestDigest(observeWork));await host.action(observeWork);
47
86
  const socketPath=input.socketPath??join(input.directory,"dashboard.sock"),server=await serveDashboardHost(socketPath,host);
@@ -88,22 +88,31 @@ export async function offerDashboardHandshake(input: DashboardHandshakeInput): P
88
88
  if (preference) return "suppressed";
89
89
  const plugin = await inspectDashboardPlugin(exec, input.pluginRoot);
90
90
  if (plugin.state === "compatible") return "already-installed";
91
- if (plugin.state !== "absent") {
91
+ const replacingDifferentPackage = plugin.state === "incompatible" && plugin.incompatibility === "package-root";
92
+ if (plugin.state !== "absent" && !replacingDifferentPackage) {
92
93
  input.ui.notify(`pi-daddy dashboard: ${plugin.diagnostic}`, "error");
93
94
  return "failed";
94
95
  }
95
96
 
97
+ const affirmative = replacingDifferentPackage ? "Relink and open" : "Install and open";
98
+ const choices = replacingDifferentPackage ? [affirmative, "Not now"] : [affirmative, "Not now", "Never ask"];
96
99
  const choice = await input.ui.select(
97
- "Herdr detected. Install and open the pi-daddy dashboard?",
98
- ["Install and open", "Not now", "Never ask"],
100
+ replacingDifferentPackage
101
+ ? "The pi-daddy dashboard is linked from a different package. Relink this bundled copy and open it?"
102
+ : "Herdr detected. Install and open the pi-daddy dashboard?",
103
+ choices,
99
104
  );
100
- if (choice !== "Install and open" && choice !== "Not now" && choice !== "Never ask") {
105
+ if (!choices.includes(choice ?? "")) {
101
106
  // Escape, timeout and UI teardown return undefined. None is an operator choice, so none may become a
102
107
  // durable preference merely because the dialog disappeared.
103
108
  input.ui.notify("pi-daddy dashboard: installation prompt dismissed; no preference was stored.", "info");
104
109
  return "deferred";
105
110
  }
106
- if (choice !== "Install and open") {
111
+ if (choice !== affirmative) {
112
+ if (replacingDifferentPackage) {
113
+ input.ui.notify("pi-daddy dashboard: existing link unchanged; no preference was stored.", "info");
114
+ return "deferred";
115
+ }
107
116
  const recorded = choice === "Never ask" ? "never" : "not-now";
108
117
  await savePreference(input.preferencePath, recorded);
109
118
  input.ui.notify(
@@ -6,8 +6,8 @@ import { dataDigest,byteDigest,detached,sha } from "./debrief-contract.ts";
6
6
  import { DASHBOARD_HARNESS_PIN,type DashboardHarness } from "./dashboard-host-contract.ts";
7
7
  export interface DashboardHarnessArtifact {version:"dashboard-harness-artifact-v1";sourceCommit:typeof DASHBOARD_HARNESS_PIN;files:Record<string,string>;typeboxRoot:string;typeboxPackageSha256:string}
8
8
  const loaded=new WeakMap<object,string>();
9
- export const DASHBOARD_HARNESS_BRIDGE_SOURCE="127b349310dd8f28e5d6b12148a063fce66a77dd";
10
- const bridgeFunctions=["learningJournal","createTrustLifecycle","openTrustLifecycle","trustPolicyDigest","archivePolicyBinding","ingestPolicySource","readArchiveCheckpoint","readArchiveSource","retainArchiveSource","captureArchivedWorkSignals","readRetainedExecution","projectRetainedExecutions","createWorkCaseReviewer","createWorkSignalReviewer","retainBlindIntervention","openBlindIntervention"] as const;
9
+ export const DASHBOARD_HARNESS_BRIDGE_SOURCE="d123257e53d48a2cad6919708976b5371dc7590e";
10
+ const bridgeFunctions=["learningJournal","createTrustLifecycle","openTrustLifecycle","trustPolicyDigest","archivePolicyBinding","ingestPolicySource","readArchiveCheckpoint","readArchiveSource","retainArchiveSource","captureArchivedWorkSignals","readRetainedExecution","projectRetainedExecutions","createWorkCaseReviewer","createWorkSignalReviewer","retainBlindIntervention","openBlindIntervention","retainLearningLifecycle","readLearningLifecycle"] as const;
11
11
  /** Adopt the API published by the already-loaded skill-harness extension. Same-process source identity is not human authentication. */
12
12
  export function adoptDashboardHarnessBridge(input:unknown):DashboardHarness{
13
13
  const value=input as {version?:unknown;sourceCommit?:unknown;api?:unknown};
@@ -30,7 +30,7 @@ export async function loadDashboardHarness(artifactRoot:string,input:DashboardHa
30
30
  if(content.get("package.json")?.toString()!=='{"type":"module"}')throw Error("explicit ESM artifact root required");
31
31
  const directory=await mkdtemp(join(parent,"loaded-harness-"));for(const[p,b]of content){await mkdir(dirname(join(directory,p)),{recursive:true,mode:0o700});await writeFile(join(directory,p),b,{flag:"wx",mode:0o400});}
32
32
  await mkdir(join(directory,"node_modules"));await symlink(manifest.typeboxRoot,join(directory,"node_modules/typebox"));
33
- const names=["learning-journal","trust-lifecycle","archive-policy","archive-observer","archive-checkpoint","archived-work","execution-retention-archive","work-case-review","blind-intervention","evidence-archive","work-signal-observation","work-signal-cases","work-case-archive"];
33
+ const names=["learning-journal","trust-lifecycle","archive-policy","archive-observer","archive-checkpoint","archived-work","execution-retention-archive","work-case-review","blind-intervention","learning-lifecycle","evidence-archive","work-signal-observation","work-signal-cases","work-case-archive"];
34
34
  const api=Object.assign({},...await Promise.all([...names.map(n=>"packages/adapters/src/"+n+".js"),"core.js"].map(p=>{if(!content.has(p))throw Error("missing genuine harness entry");return import(pathToFileURL(join(directory,p)).href);}))) as DashboardHarness;
35
35
  for(const[p,digest]of files)if(byteDigest(await bytes(join(directory,p)))!==digest)throw Error("loaded harness bytes changed");
36
36
  Object.freeze(api);const digest=dataDigest(manifest);loaded.set(api,digest);return Object.freeze({api,artifactDigest:digest,directory,manifest});
@@ -97,6 +97,7 @@ export type DashboardPluginState = "absent" | "disabled" | "compatible" | "incom
97
97
  export interface DashboardPluginStatus {
98
98
  state: DashboardPluginState;
99
99
  diagnostic: string;
100
+ incompatibility?: "package-root" | "protocol";
100
101
  plugin?: Record<string, unknown>;
101
102
  }
102
103
 
@@ -116,15 +117,8 @@ export async function inspectDashboardPlugin(
116
117
  const plugins = Array.isArray(parsed.result?.plugins) ? parsed.result.plugins as Record<string, unknown>[] : [];
117
118
  const plugin = plugins.find((candidate) => candidate.plugin_id === DASHBOARD_PLUGIN_ID);
118
119
  if (!plugin) return { state: "absent", diagnostic: `Herdr plugin ${DASHBOARD_PLUGIN_ID} is not installed.` };
119
- // Provenance and protocol precede enabled state. Suggesting `plugin enable` for a same-id plugin from
120
- // another package would ask the operator to activate software this package explicitly refuses to invoke.
121
- if (expectedPluginRoot && (typeof plugin.plugin_root !== "string" || resolve(plugin.plugin_root) !== resolve(expectedPluginRoot))) {
122
- return {
123
- state: "incompatible",
124
- diagnostic: `Herdr plugin ${DASHBOARD_PLUGIN_ID} is linked from a different package; relink the bundled copy.`,
125
- plugin,
126
- };
127
- }
120
+ // Protocol and provenance both precede enabled state. A root-only repair is offered only when the
121
+ // registered manifest already speaks this core's protocol; unknown software is never replaced by guesswork.
128
122
  const major = protocolMajor(plugin.version);
129
123
  if (major !== DASHBOARD_PROTOCOL_VERSION) {
130
124
  return {
@@ -132,6 +126,15 @@ export async function inspectDashboardPlugin(
132
126
  diagnostic:
133
127
  `Herdr plugin ${DASHBOARD_PLUGIN_ID} uses protocol ${major ?? "unknown"}; ` +
134
128
  `this pi-daddy core requires ${DASHBOARD_PROTOCOL_VERSION}. Relink both from the same package.`,
129
+ incompatibility: "protocol",
130
+ plugin,
131
+ };
132
+ }
133
+ if (expectedPluginRoot && (typeof plugin.plugin_root !== "string" || resolve(plugin.plugin_root) !== resolve(expectedPluginRoot))) {
134
+ return {
135
+ state: "incompatible",
136
+ diagnostic: `Herdr plugin ${DASHBOARD_PLUGIN_ID} is linked from a different package; relink the bundled copy.`,
137
+ incompatibility: "package-root",
135
138
  plugin,
136
139
  };
137
140
  }
@@ -5,7 +5,7 @@ import type { WorkProjectionContext, WorkFrozen } from "./work-ledger.ts";
5
5
  import type { DispatchAuthority } from "./dispatch-control.ts";
6
6
  import type { OrdinaryAuthority } from "./ordinary-children.ts";
7
7
  import type { ExperimentAuthority } from "./experiment-contract.ts";
8
- export const DASHBOARD_HARNESS_PIN = "127b349310dd8f28e5d6b12148a063fce66a77dd";
8
+ export const DASHBOARD_HARNESS_PIN = "d123257e53d48a2cad6919708976b5371dc7590e";
9
9
  export interface HostEvent { id: string; prior: string | null; value: Record<string, unknown> }
10
10
  export interface HostJournal { read(): HostEvent[]; append(prior: string, value: Record<string, unknown>): HostEvent }
11
11
  /** Loaded trusted ports; an interface or caller-supplied pin is NOT module/human authentication. */
@@ -19,9 +19,11 @@ export interface DashboardHarness extends DebriefHarness {
19
19
  ingestPolicySource(path: string, source: string, previous?: string, expectedPolicy?: string): { checkpointId: string; sourceStatus: string; issues?: string[]; [key: string]: unknown };
20
20
  readArchiveCheckpoint(root: string, checkpoint: string): { checkpoint: { sourceManifestId: string; issues: string[]; [key: string]: unknown } };
21
21
  readArchiveSource(root: string, id: string): { status: string; bytes?: Uint8Array; reference?: { retention: string; sha256: string; [key: string]: unknown } };
22
- captureArchivedWorkSignals(root: string, id: string, context: WorkFrozen<WorkProjectionContext>, facts: unknown): { caseBatchId: string; observationId: string; linkageManifestId: string };
22
+ captureArchivedWorkSignals(root: string, id: string, context: WorkFrozen<WorkProjectionContext>, facts: unknown): { caseBatchId: string; observationId: string; linkageManifestId: string; runtimeFactsManifestId: string };
23
23
  readRetainedExecution(root: string, id: string): { projection: unknown };
24
24
  projectRetainedExecutions(values: readonly unknown[]): unknown;
25
+ retainLearningLifecycle(root:string,input:unknown):string;
26
+ readLearningLifecycle(root:string,id:string):{version:string;state:string;predecessorManifestId:string|null;links:Record<string,unknown>};
25
27
  }
26
28
  export interface DashboardHostConfig {
27
29
  version: "producer-dashboard-host-v1"; trustDirectory: string; trustPolicyId: string; archiveRoot: string; scope: string; author: string;
@@ -29,6 +31,7 @@ export interface DashboardHostConfig {
29
31
  selection: WorkProjectionContext["selectedSnapshot"]; cases: CaseSelection | null; blind: DurableBlindBinding | null;
30
32
  budgetDigest: string; experimentDigest: string | null; harnessArtifactDigest: string;
31
33
  ordinaryDigest?: string;
34
+ learningLifecycleId?: string;
32
35
  }
33
36
  export interface DashboardHostRequest { version: "1.0"; requestId: string; hostDigest: string; expectedTip: string; selectionDigest: string; operation: "observe" | "present" | "presented" | "defer" | "debrief" | "dispatch" | "intent" | "cancel" | "dispatch-reconcile" | "intent-reconcile" | "ordinary-cancel"; payload: unknown }
34
37
  export interface DashboardHostAuthority {
@@ -18,15 +18,18 @@ export const isDashboardHost=(value:unknown):value is DashboardHost=>typeof valu
18
18
  export type DashboardHost=ReturnType<typeof openDashboardHost>;
19
19
  export interface DashboardHostOptions { ordinary?:OrdinaryChildren; harness:DashboardHarness; config:DashboardHostConfig; budget:GovernedBudgetBinding; experiment?:ReturnType<typeof openExperiment>; authority:()=>DashboardHostAuthority|null;
20
20
  /** Exact actions constructed and authorized by the owner; the dashboard exposes only human labels/keys. */
21
- humanActions?:(context:{hostDigest:string;selectionDigest:string;tip:string;observations:readonly {sourceId:string;checkpointId:string}[]})=>readonly {key:string;label:string;request:DashboardHostRequest}[]|Promise<readonly {key:string;label:string;request:DashboardHostRequest}[]>;
21
+ humanActions?:(context:{hostDigest:string;selectionDigest:string;tip:string;observations:readonly {sourceId:string;checkpointId:string}[];preparedPresentationDigest:string|null})=>readonly {key:string;label:string;request:DashboardHostRequest}[]|Promise<readonly {key:string;label:string;request:DashboardHostRequest}[]>;
22
22
  /** Explicit approved observation effect only; refresh/frame never invokes it. */
23
23
  beforeObservation?:(sourceId:string)=>Promise<void>;
24
+ /** Owner callback after the exact intent journal reports applied; failure keeps host acknowledgement unknown. */
25
+ afterIntentApplied?:(selection:IntentRequest["selection"])=>void|Promise<void>;
24
26
  /** Independently sourced current declaration. Never inferred from idle, a PID, title or request fields. */
25
27
  presence?:()=>{present:boolean;closing:boolean;evidenceDigest:string;expiresAt:number}|null;
26
28
  }
27
29
  function configuration(input:DashboardHostConfig){
28
- const c=detached(input);controlShape(c,["version","trustDirectory","trustPolicyId","archiveRoot","scope","author","policyPath","policySha256","sources","selection","cases","blind","budgetDigest","experimentDigest","harnessArtifactDigest",...(Object.hasOwn(c,"ordinaryDigest")?["ordinaryDigest"]:[])]);
30
+ const c=detached(input);controlShape(c,["version","trustDirectory","trustPolicyId","archiveRoot","scope","author","policyPath","policySha256","sources","selection","cases","blind","budgetDigest","experimentDigest","harnessArtifactDigest",...(Object.hasOwn(c,"ordinaryDigest")?["ordinaryDigest"]:[]),...(Object.hasOwn(c,"learningLifecycleId")?["learningLifecycleId"]:[])]);
29
31
  if(Object.hasOwn(c,"ordinaryDigest")&&!sha(c.ordinaryDigest))throw Error("invalid ordinary binding digest");
32
+ if(Object.hasOwn(c,"learningLifecycleId")&&!sha(c.learningLifecycleId))throw Error("invalid learning lifecycle manifest");
30
33
  if(c.version!=="producer-dashboard-host-v1"||![c.trustDirectory,c.archiveRoot,c.policyPath].every(p=>typeof p==="string"&&isAbsolute(p))||![c.trustPolicyId,c.policySha256,c.budgetDigest,c.harnessArtifactDigest].every(sha)||!(c.experimentDigest===null||sha(c.experimentDigest))||typeof c.scope!=="string"||!c.scope||c.scope.length>128||typeof c.author!=="string"||!c.author||c.author.length>256||!Array.isArray(c.sources)||c.sources.length<1||c.sources.length>32||new Set(c.sources.map(s=>s.id)).size!==c.sources.length||c.sources.filter(s=>s.kind==="work").length>1||c.sources.some(s=>!/^[a-zA-Z0-9:_-]{1,128}$/.test(s.id)||!["work","retention","facts"].includes(s.kind)))throw Error("invalid explicit dashboard host binding");
31
34
  return freeze(c);
32
35
  }
@@ -56,7 +59,7 @@ export function openDashboardHost(options:DashboardHostOptions){
56
59
  const observation=dashboardObservations(h,c,journal.read),history=()=>journal.read();
57
60
  const append=(value:Record<string,unknown>)=>journal.append(history().at(-1)!.id,value);
58
61
  const saved=():DebriefCheckpoint|null=>{const rows=history().filter(e=>e.value.type==="checkpoint");return rows.length?detached(rows.at(-1)!.value.checkpoint) as DebriefCheckpoint:null;};
59
- let presenter:DebriefPresenter|undefined,busy=false,poisoned=false,presentationRevision:number|null=null,presenceDigest:string|null=null,attentionDeferred:string|null=null;
62
+ let presenter:DebriefPresenter|undefined,busy=false,poisoned=false,presentationRevision:number|null=null,presenceDigest:string|null=null,attentionDeferred:string|null=null,presentationAcknowledged=false;
60
63
  const ordinaryDispatchHoldKey=dataDigest({hostDigest,control:"pause-new-ordinary-dispatch"});
61
64
  let displayedActions:null|{tip:string;actions:{key:string;label:string;operation:DashboardHostRequest["operation"];request:DashboardHostRequest}[];digest:string}=null;
62
65
  const presence=()=>{const p=options.presence?.();return p&&p.present===true&&p.closing===true&&sha(p.evidenceDigest)&&Number.isFinite(p.expiresAt)&&p.expiresAt>Date.now()?p:null;};
@@ -73,7 +76,7 @@ export function openDashboardHost(options:DashboardHostOptions){
73
76
  const nativeRead=async()=>({dispatch:await budget.controls(null).inspect(),intent:budget.binding.intent?await budget.intentControls(null).inspect():null,experiment:experiment?await experiment.inspect():null,ordinary:ordinary?ordinary.inspect():null});
74
77
  const availableHumanActions=async()=>{
75
78
  const rows=history(),tip=rows.at(-1)!.id,selection=await currentSelection(),seen=new Set<string>();
76
- const declared=await options.humanActions?.({hostDigest,selectionDigest:dashboardSelectionDigest(selection),tip,observations:observation.latest().map(x=>({sourceId:x.sourceId,checkpointId:x.checkpointId}))})??[],a=authority();
79
+ const declared=await options.humanActions?.({hostDigest,selectionDigest:dashboardSelectionDigest(selection),tip,observations:observation.latest().map(x=>({sourceId:x.sourceId,checkpointId:x.checkpointId})),preparedPresentationDigest:presenter&&presentationRevision!==null&&!presentationAcknowledged?dataDigest(presenter.view()):null})??[],a=authority();
77
80
  return declared.map(value=>{const x=detached(value);controlShape(x,["key","label","request"]);const request=dashboardHostRequest(x.request);
78
81
  if(!/^[a-zA-Z0-9:_-]{1,64}$/.test(x.key)||typeof x.label!=="string"||!x.label.trim()||Buffer.byteLength(x.label)>120||seen.has(x.key))throw Error("invalid human dashboard action");seen.add(x.key);
79
82
  if(request.hostDigest!==hostDigest||request.expectedTip!==tip||request.selectionDigest!==dashboardSelectionDigest(selection)||!a?.requestDigests.includes(dashboardHostRequestDigest(request)))throw Error("human dashboard action is stale or not exactly authorized");
@@ -88,11 +91,12 @@ export function openDashboardHost(options:DashboardHostOptions){
88
91
  let debrief:unknown=null;
89
92
  if(a&&presenter&&presentationRevision!==null&&presence()?.evidenceDigest===presenceDigest){try{await paused(presentationRevision);debrief=presenter.view();}catch{debrief=null;}}
90
93
  let controls:unknown=null;try{controls=await nativeRead();}catch(e){error=String(e);}
94
+ let learning:unknown=null;if(c.learningLifecycleId)try{learning=h.readLearningLifecycle(c.archiveRoot,c.learningLifecycleId);}catch(e){error=String(e);}
91
95
  const attention=trust.inspect(Date.now());let actions:{key:string;label:string;operation:string}[]=[];
92
96
  try{const available=await availableHumanActions(),digest=dataDigest(available.map(({key,label,operation,request})=>({key,label,operation,requestDigest:dashboardHostRequestDigest(request)})));
93
97
  if(displayedActions?.tip===tip&&displayedActions.digest!==digest)throw Error("displayed dashboard actions changed before journal advance");
94
98
  displayedActions={tip,actions:available,digest};actions=available.map(({key,label,operation})=>({key,label,operation}));}catch(e){error=String(e);}
95
- return freeze(detached({version:"producer-dashboard-frame-v1",hostDigest,selectionDigest:dashboardSelectionDigest(selection),selectionState,tip,source,controls,debrief,attention,error,actions,
99
+ return freeze(detached({version:"producer-dashboard-frame-v1",hostDigest,selectionDigest:dashboardSelectionDigest(selection),selectionState,tip,source,controls,learning,debrief,attention,error,actions,
96
100
  requests:rows.filter(e=>["claim","result","presentation","defer","ordinary-intent-pending"].includes(String(e.value.type))).map(e=>e.value),
97
101
  control:rows.some(e=>e.value.type==="host-failure")?"failed":rows.some(e=>e.value.type==="claim"&&!rows.some(r=>r.value.type==="result"&&r.value.requestId===e.value.requestId))?"unknown":"not-assessed",
98
102
  acknowledgement:poisoned?"unknown":"readback-only",identity:"independently-declared-host; not human/module authentication",activeBranch:null,acceptance:"not-assessed",freshness:"snapshot-unknown",workerInteractions:0}));
@@ -132,11 +136,11 @@ export function openDashboardHost(options:DashboardHostOptions){
132
136
  attentionDeferred=null;const view=await presenter.open({mode:"manual",userPresent:true});await paused(p.dispatchRevision);
133
137
  if(attentionDeferred){presenter.close();presentationRevision=null;append({type:"defer",requestId:request.requestId,reason:attentionDeferred,weekly:true});result={state:"deferred",reason:attentionDeferred};}
134
138
  else {if(view.state!=="open")throw Error("presentation data/attention acknowledgement unavailable");
135
- presentationRevision=p.dispatchRevision;presenceDigest=p.evidenceDigest;const frameDigest=dataDigest(view);append({type:"presentation",requestId:request.requestId,evidence:p,frameDigest,state:"prepared-not-delivery",automatic:"unqualified"});result={state:"prepared",frameDigest};}
139
+ presentationRevision=p.dispatchRevision;presenceDigest=p.evidenceDigest;presentationAcknowledged=false;const frameDigest=dataDigest(view);append({type:"presentation",requestId:request.requestId,evidence:p,frameDigest,state:"prepared-not-delivery",automatic:"unqualified"});result={state:"prepared",frameDigest};}
136
140
  }
137
141
  }else if(request.operation==="presented"){
138
142
  const p=detached(request.payload) as {frameDigest:string};if(Object.keys(p).join()!=="frameDigest"||!presenter||presentationRevision===null)throw Error("original prepared presentation required");
139
- await paused(presentationRevision);if(presence()?.evidenceDigest!==presenceDigest)throw Error("user absent/presence changed");if(p.frameDigest!==dataDigest(presenter.view()))throw Error("stale presentation acknowledgement");result={state:"host-acknowledged-presentation",frameDigest:p.frameDigest,humanAuthentication:"unqualified"};
143
+ await paused(presentationRevision);if(presence()?.evidenceDigest!==presenceDigest)throw Error("user absent/presence changed");if(p.frameDigest!==dataDigest(presenter.view()))throw Error("stale presentation acknowledgement");presentationAcknowledged=true;result={state:"host-acknowledged-presentation",frameDigest:p.frameDigest,humanAuthentication:"unqualified"};
140
144
  }else if(request.operation==="defer"){
141
145
  presenter?.close();presentationRevision=null;append({type:"defer",requestId:request.requestId,weekly:true,evidence:request.payload});result={state:"deferred"};
142
146
  }else if(request.operation==="debrief"){
@@ -153,7 +157,7 @@ export function openDashboardHost(options:DashboardHostOptions){
153
157
  }else if(request.operation==="intent"||request.operation==="intent-reconcile"){
154
158
  const native=detached(intentRequest(request.payload as IntentRequest)) as IntentRequest,port=budget.intentControls(a!.dispatch),digest=intentRequestDigest(native);
155
159
  if(c.ordinaryDigest&&!ordinary)throw Error("original ordinary boundary unavailable; no recovery");
156
- if(!ordinary)result=request.operation==="intent"?await port.request(native):await port.reconcile(native);
160
+ if(!ordinary){result=request.operation==="intent"?await port.request(native):await port.reconcile(native);const snapshot=result as {selection:IntentRequest["selection"];records:{requestId:string;application:string}[]},outcome=snapshot.records.find(r=>r.requestId===native.requestId);if(outcome?.application==="applied")await options.afterIntentApplied?.(snapshot.selection);}
157
161
  else {
158
162
  const pending=history().filter(e=>e.value.type==="ordinary-intent-pending"&&e.value.nativeRequestId===native.requestId);
159
163
  if(pending.some(e=>e.value.digest!==digest))throw Error("immutable pending ordinary intent ID");
@@ -167,8 +171,9 @@ export function openDashboardHost(options:DashboardHostOptions){
167
171
  result={state:"pending-ordinary-boundary",nativeRequestId:native.requestId,application:"not-acknowledged"};
168
172
  }else{
169
173
  result=(request.operation==="intent"||pending.length>0&&!exists)?await port.request(native):await port.reconcile(native);
170
- const outcome=(result as {records:{requestId:string;application:string}[]}).records.find(r=>r.requestId===native.requestId);
174
+ const snapshot=result as {selection:IntentRequest["selection"];records:{requestId:string;application:string}[]},outcome=snapshot.records.find(r=>r.requestId===native.requestId);
171
175
  if(held&&!outcome)throw Error("native intent application acknowledgement unavailable");
176
+ if(outcome?.application==="applied")await options.afterIntentApplied?.(snapshot.selection);
172
177
  if(held&&["applied","not-applied"].includes(outcome!.application))releaseOrdinary=held.release;
173
178
  }
174
179
  }
@@ -25,6 +25,7 @@ export function dashboardObservations(h: DashboardHarness, c: DashboardHostConfi
25
25
  captured.factSourceManifestId=factSource?.sourceManifestId??null;captured.factBasis=factSource?"explicit-host-declarations-not-authenticated-truth":"derived-retained-work-only";
26
26
  if(dataDigest(authority.workContext.selectedSnapshot)!==dataDigest(selection))throw Error("independent source selection changed");
27
27
  try { const signals=h.captureArchivedWorkSignals(root,sourceManifestId,authority.workContext,facts);
28
+ captured.runtimeFactsManifestId=signals.runtimeFactsManifestId;
28
29
  cases={version:"work-signals-v1",batchId:signals.caseBatchId,observationId:signals.observationId};linkageManifestId=signals.linkageManifestId;
29
30
  } catch(error) { captured.semanticFailure=String(error); } // Retain checkpoint/gap even when nomination is unavailable.
30
31
  } else {if(input.facts!==null||captured.kind!=="execution-retention-v2")throw Error("retention source requires exact referenced-blobs policy");h.readRetainedExecution(root,captured.checkpointId);}
package/src/experiment.ts CHANGED
@@ -146,6 +146,12 @@ export function openExperiment(input: ExperimentBinding, hostAuthority: Experime
146
146
  let resolve!: (success: boolean) => void;
147
147
  return { promise: new Promise<boolean>(done => { resolve = done; }), done: (success: boolean) => resolve(success) };
148
148
  });
149
+ // Public readiness includes the durable spawn observation, not merely process creation.
150
+ // This closes the process-start -> spawn-ledger race for inspect and cancellation callers.
151
+ const observedStarted = reserved.map((run, i) => run.started.then(async value => {
152
+ if (value === "spawned") await append({ type: "spawn", executionId: c.variants[i].executionId });
153
+ return value;
154
+ }));
149
155
  const one = async (i: number) => {
150
156
  const v = c.variants[i]; let success = false, launched = false, primaryResult: VariantRecord | null = null;
151
157
  try {
@@ -155,8 +161,7 @@ export function openExperiment(input: ExperimentBinding, hostAuthority: Experime
155
161
  launched = true;
156
162
  const running = reserved[i].run(handles.get(v.executionId)!.signal);
157
163
  // Consume both promises even on bookkeeping failure. No untracked rejection or worker.
158
- const observed = reserved[i].started.then(async value => { if (value === "spawned") await append({ type: "spawn", executionId: v.executionId }); });
159
- const [result, observation] = await Promise.allSettled([running, observed]);
164
+ const [result, observation] = await Promise.allSettled([running, observedStarted[i]]);
160
165
  if (result.status === "rejected" || observation.status === "rejected") throw new Error("runtime/accounting/observation unknown");
161
166
  const data = Buffer.from(JSON.stringify(result.value) + "\n"), out = result.value.output;
162
167
  const cancelled = out.aborted && (Boolean(out.signal) || await reserved[i].started === "settled-without-spawn");
@@ -218,7 +223,7 @@ export function openExperiment(input: ExperimentBinding, hostAuthority: Experime
218
223
  }
219
224
  const view = await inspect().catch(unknown); primary.resolve(view.variants[0]); resolveBoundary(view); return view;
220
225
  })();
221
- live = Object.freeze({ primary: primary.promise, completion, boundary: c.order ? boundary : completion, started: Object.freeze(reserved.map(r => r.started)) }); return live;
226
+ live = Object.freeze({ primary: primary.promise, completion, boundary: c.order ? boundary : completion, started: Object.freeze(observedStarted) }); return live;
222
227
  } catch (error) {
223
228
  fault = true;
224
229
  for (const run of reserved) await run.run(AbortSignal.abort()).catch(() => {});