@openrig/cli 0.4.7 → 0.4.8

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 (149) hide show
  1. package/daemon/assets/plugins/openrig-core/skills/applying-a-permission-policy/SKILL.md +120 -0
  2. package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/precompact-hook.mjs +0 -0
  3. package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/restore-from-jsonl.mjs +0 -0
  4. package/daemon/assets/plugins/openrig-core/skills/delegating-work/SKILL.md +43 -0
  5. package/daemon/assets/plugins/openrig-core/skills/forming-an-openrig-mental-model/SKILL.md +2 -0
  6. package/daemon/assets/plugins/openrig-core/skills/mission-slice-sop/SKILL.md +4 -7
  7. package/daemon/assets/plugins/openrig-core/skills/openrig-skills/SKILL.md +50 -57
  8. package/daemon/assets/plugins/openrig-core/skills/openrig-user/SKILL.md +16 -2
  9. package/daemon/dist/adapters/claude-code-adapter.d.ts +0 -9
  10. package/daemon/dist/adapters/claude-code-adapter.d.ts.map +1 -1
  11. package/daemon/dist/adapters/claude-code-adapter.js +13 -46
  12. package/daemon/dist/adapters/claude-code-adapter.js.map +1 -1
  13. package/daemon/dist/adapters/claude-resume.d.ts +1 -1
  14. package/daemon/dist/adapters/claude-resume.d.ts.map +1 -1
  15. package/daemon/dist/adapters/claude-resume.js +8 -2
  16. package/daemon/dist/adapters/claude-resume.js.map +1 -1
  17. package/daemon/dist/adapters/codex-resume.d.ts +1 -1
  18. package/daemon/dist/adapters/codex-resume.d.ts.map +1 -1
  19. package/daemon/dist/adapters/codex-resume.js +4 -2
  20. package/daemon/dist/adapters/codex-resume.js.map +1 -1
  21. package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
  22. package/daemon/dist/adapters/codex-runtime-adapter.js +10 -5
  23. package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
  24. package/daemon/dist/adapters/pi-resume.d.ts +1 -1
  25. package/daemon/dist/adapters/pi-resume.d.ts.map +1 -1
  26. package/daemon/dist/adapters/pi-resume.js +7 -2
  27. package/daemon/dist/adapters/pi-resume.js.map +1 -1
  28. package/daemon/dist/adapters/pi-runtime-adapter.d.ts.map +1 -1
  29. package/daemon/dist/adapters/pi-runtime-adapter.js +4 -1
  30. package/daemon/dist/adapters/pi-runtime-adapter.js.map +1 -1
  31. package/daemon/dist/adapters/yolo-mode.d.ts +23 -0
  32. package/daemon/dist/adapters/yolo-mode.d.ts.map +1 -0
  33. package/daemon/dist/adapters/yolo-mode.js +49 -0
  34. package/daemon/dist/adapters/yolo-mode.js.map +1 -0
  35. package/daemon/dist/build-info.js +3 -3
  36. package/daemon/dist/db/migrations/055_node_permission_policy.d.ts +13 -0
  37. package/daemon/dist/db/migrations/055_node_permission_policy.d.ts.map +1 -0
  38. package/daemon/dist/db/migrations/055_node_permission_policy.js +17 -0
  39. package/daemon/dist/db/migrations/055_node_permission_policy.js.map +1 -0
  40. package/daemon/dist/db/migrations/056_rig_permission_policy.d.ts +13 -0
  41. package/daemon/dist/db/migrations/056_rig_permission_policy.d.ts.map +1 -0
  42. package/daemon/dist/db/migrations/056_rig_permission_policy.js +17 -0
  43. package/daemon/dist/db/migrations/056_rig_permission_policy.js.map +1 -0
  44. package/daemon/dist/db/migrations/057_node_policy_provenance.d.ts +19 -0
  45. package/daemon/dist/db/migrations/057_node_policy_provenance.d.ts.map +1 -0
  46. package/daemon/dist/db/migrations/057_node_policy_provenance.js +26 -0
  47. package/daemon/dist/db/migrations/057_node_policy_provenance.js.map +1 -0
  48. package/daemon/dist/db/migrations/058_rig_policy_provenance.d.ts +15 -0
  49. package/daemon/dist/db/migrations/058_rig_policy_provenance.d.ts.map +1 -0
  50. package/daemon/dist/db/migrations/058_rig_policy_provenance.js +22 -0
  51. package/daemon/dist/db/migrations/058_rig_policy_provenance.js.map +1 -0
  52. package/daemon/dist/domain/builtin-policy-reference.d.ts +13 -0
  53. package/daemon/dist/domain/builtin-policy-reference.d.ts.map +1 -0
  54. package/daemon/dist/domain/builtin-policy-reference.js +58 -0
  55. package/daemon/dist/domain/builtin-policy-reference.js.map +1 -0
  56. package/daemon/dist/domain/native-resume-probe.d.ts +1 -1
  57. package/daemon/dist/domain/native-resume-probe.d.ts.map +1 -1
  58. package/daemon/dist/domain/native-resume-probe.js +11 -4
  59. package/daemon/dist/domain/native-resume-probe.js.map +1 -1
  60. package/daemon/dist/domain/node-inventory.js +2 -2
  61. package/daemon/dist/domain/node-inventory.js.map +1 -1
  62. package/daemon/dist/domain/permission-policy/policy-ref.d.ts +89 -0
  63. package/daemon/dist/domain/permission-policy/policy-ref.d.ts.map +1 -0
  64. package/daemon/dist/domain/permission-policy/policy-ref.js +171 -0
  65. package/daemon/dist/domain/permission-policy/policy-ref.js.map +1 -0
  66. package/daemon/dist/domain/permission-policy/policy-spec.d.ts +34 -0
  67. package/daemon/dist/domain/permission-policy/policy-spec.d.ts.map +1 -0
  68. package/daemon/dist/domain/permission-policy/policy-spec.js +106 -0
  69. package/daemon/dist/domain/permission-policy/policy-spec.js.map +1 -0
  70. package/daemon/dist/domain/restore-orchestrator.d.ts +14 -0
  71. package/daemon/dist/domain/restore-orchestrator.d.ts.map +1 -1
  72. package/daemon/dist/domain/restore-orchestrator.js +90 -6
  73. package/daemon/dist/domain/restore-orchestrator.js.map +1 -1
  74. package/daemon/dist/domain/rig-expansion-service.d.ts.map +1 -1
  75. package/daemon/dist/domain/rig-expansion-service.js +10 -1
  76. package/daemon/dist/domain/rig-expansion-service.js.map +1 -1
  77. package/daemon/dist/domain/rig-repository.d.ts +45 -0
  78. package/daemon/dist/domain/rig-repository.d.ts.map +1 -1
  79. package/daemon/dist/domain/rig-repository.js +75 -1
  80. package/daemon/dist/domain/rig-repository.js.map +1 -1
  81. package/daemon/dist/domain/rigspec-codec.d.ts.map +1 -1
  82. package/daemon/dist/domain/rigspec-codec.js +6 -0
  83. package/daemon/dist/domain/rigspec-codec.js.map +1 -1
  84. package/daemon/dist/domain/rigspec-exporter.d.ts.map +1 -1
  85. package/daemon/dist/domain/rigspec-exporter.js +8 -0
  86. package/daemon/dist/domain/rigspec-exporter.js.map +1 -1
  87. package/daemon/dist/domain/rigspec-instantiator.d.ts +18 -1
  88. package/daemon/dist/domain/rigspec-instantiator.d.ts.map +1 -1
  89. package/daemon/dist/domain/rigspec-instantiator.js +187 -8
  90. package/daemon/dist/domain/rigspec-instantiator.js.map +1 -1
  91. package/daemon/dist/domain/rigspec-preflight.d.ts +11 -0
  92. package/daemon/dist/domain/rigspec-preflight.d.ts.map +1 -1
  93. package/daemon/dist/domain/rigspec-preflight.js +35 -1
  94. package/daemon/dist/domain/rigspec-preflight.js.map +1 -1
  95. package/daemon/dist/domain/rigspec-schema.d.ts.map +1 -1
  96. package/daemon/dist/domain/rigspec-schema.js +25 -0
  97. package/daemon/dist/domain/rigspec-schema.js.map +1 -1
  98. package/daemon/dist/domain/runtime-adapter.d.ts +5 -0
  99. package/daemon/dist/domain/runtime-adapter.d.ts.map +1 -1
  100. package/daemon/dist/domain/runtime-adapter.js.map +1 -1
  101. package/daemon/dist/domain/seat-handover-service.d.ts.map +1 -1
  102. package/daemon/dist/domain/seat-handover-service.js +7 -1
  103. package/daemon/dist/domain/seat-handover-service.js.map +1 -1
  104. package/daemon/dist/domain/successor-session-launcher.d.ts +4 -0
  105. package/daemon/dist/domain/successor-session-launcher.d.ts.map +1 -1
  106. package/daemon/dist/domain/successor-session-launcher.js +2 -0
  107. package/daemon/dist/domain/successor-session-launcher.js.map +1 -1
  108. package/daemon/dist/domain/types.d.ts +17 -0
  109. package/daemon/dist/domain/types.d.ts.map +1 -1
  110. package/daemon/dist/domain/types.js.map +1 -1
  111. package/daemon/dist/routes/agent-images.d.ts.map +1 -1
  112. package/daemon/dist/routes/agent-images.js +2 -0
  113. package/daemon/dist/routes/agent-images.js.map +1 -1
  114. package/daemon/dist/routes/rigs.js +8 -0
  115. package/daemon/dist/routes/rigs.js.map +1 -1
  116. package/daemon/dist/startup.d.ts.map +1 -1
  117. package/daemon/dist/startup.js +17 -1
  118. package/daemon/dist/startup.js.map +1 -1
  119. package/daemon/docs/reference/rig-spec.md +19 -0
  120. package/daemon/policies/builtin/locked.policy.md +24 -0
  121. package/daemon/policies/builtin/open.policy.md +24 -0
  122. package/daemon/policies/builtin/standard.policy.md +25 -0
  123. package/daemon/policies/builtin/yolo.policy.md +20 -0
  124. package/daemon/policies/examples/my-cautious-dev.policy.md +40 -0
  125. package/daemon/specs/agents/shared/runtime/claude-settings.fragment.json +1 -20
  126. package/daemon/specs/agents/shared/skills/core/openrig-architect/SKILL.md +0 -2
  127. package/daemon/specs/agents/shared/skills/process/systematic-debugging/find-polluter.sh +0 -0
  128. package/daemon/specs/agents/shared/skills/process/verification-before-completion/SKILL.md +1 -0
  129. package/dist/build-info.js +3 -3
  130. package/dist/commands/setup.d.ts +14 -0
  131. package/dist/commands/setup.d.ts.map +1 -1
  132. package/dist/commands/setup.js +131 -8
  133. package/dist/commands/setup.js.map +1 -1
  134. package/package.json +1 -1
  135. package/daemon/specs/agents/shared/skills/pm/backlog-capture/SKILL.md +0 -43
  136. package/daemon/specs/agents/shared/skills/pm/context-builder/SKILL.md +0 -87
  137. package/daemon/specs/agents/shared/skills/pm/exec-summary/SKILL.md +0 -84
  138. package/daemon/specs/agents/shared/skills/pm/office-hours/SKILL.md +0 -129
  139. package/daemon/specs/agents/shared/skills/pm/plan-review/SKILL.md +0 -98
  140. package/daemon/specs/agents/shared/skills/pm/requirements-writer/SKILL.md +0 -113
  141. package/daemon/specs/agents/shared/skills/pm/ui-mockup/SKILL.md +0 -76
  142. package/daemon/specs/agents/shared/skills/pods/development-team/SKILL.md +0 -148
  143. package/daemon/specs/agents/shared/skills/pods/orchestration-team/SKILL.md +0 -266
  144. package/daemon/specs/agents/shared/skills/pods/review-team/SKILL.md +0 -213
  145. package/daemon/specs/agents/shared/skills/process/systematic-debugging/CREATION-LOG.md +0 -119
  146. package/daemon/specs/agents/shared/skills/process/systematic-debugging/test-academic.md +0 -14
  147. package/daemon/specs/agents/shared/skills/process/systematic-debugging/test-pressure-1.md +0 -58
  148. package/daemon/specs/agents/shared/skills/process/systematic-debugging/test-pressure-2.md +0 -68
  149. package/daemon/specs/agents/shared/skills/process/systematic-debugging/test-pressure-3.md +0 -69
@@ -1,6 +1,7 @@
1
1
  import nodePath from "node:path";
2
2
  import { mkdirSync, writeFileSync } from "node:fs";
3
3
  import { assembleBundle } from "./context-packs/bundle-assembler.js";
4
+ import { resolvePermissionPolicyAttachment, resolvePermissionPolicyRefValue, } from "./permission-policy/policy-ref.js";
4
5
  import { deriveCanonicalSessionName, validateSessionComponents } from "./session-name.js";
5
6
  import { LegacyRigSpecSchema as RigSpecSchema } from "./rigspec-schema.js"; // TODO: AS-T08b — migrate to pod-aware RigSpec
6
7
  import { LegacyRigSpecCodec as RigSpecCodec } from "./rigspec-codec.js"; // TODO: AS-T08b — migrate to pod-aware RigSpec
@@ -277,6 +278,20 @@ export class PodRigInstantiator {
277
278
  this.db = deps.db;
278
279
  this.deps = deps;
279
280
  }
281
+ inheritedPermissionPolicy(targetRigId) {
282
+ if (!targetRigId)
283
+ return undefined;
284
+ const provenance = this.deps.rigRepo.getRigPolicyProvenance(targetRigId);
285
+ if (!provenance?.rigRef)
286
+ return undefined;
287
+ return {
288
+ ref: provenance.rigRef,
289
+ origin: provenance.origin,
290
+ launchPosture: provenance.launchPosture,
291
+ ...(provenance.resolvedTarget ? { resolvedTarget: provenance.resolvedTarget } : {}),
292
+ ...(provenance.declaringDir ? { declaringDir: provenance.declaringDir } : {}),
293
+ };
294
+ }
280
295
  async materialize(rigSpecYaml, rigRoot, opts) {
281
296
  let raw;
282
297
  try {
@@ -303,6 +318,7 @@ export class PodRigInstantiator {
303
318
  fsOps: this.deps.fsOps,
304
319
  rigNameOverride: targetRig?.rig.name,
305
320
  externalQualifiedIds: targetRig?.nodes.map((node) => node.logicalId),
321
+ inheritedPermissionPolicy: this.inheritedPermissionPolicy(opts?.targetRigId),
306
322
  exec: this.deps.exec,
307
323
  });
308
324
  if (!preflight.ready) {
@@ -312,7 +328,7 @@ export class PodRigInstantiator {
312
328
  // persistence CORE (createPod + create-node + edges + events, in one tx)
313
329
  // takes the already-parsed+validated spec so `expand` and the `add_member`
314
330
  // converge op compose it WITHOUT fabricating a synthetic rig spec.
315
- return this.materializeValidatedSpec(rigSpec, rigRoot, opts);
331
+ return this.materializeValidatedSpec(rigSpec, rigRoot, preflight.warnings, opts);
316
332
  }
317
333
  /**
318
334
  * materialize with a STRUCTURED front (OPR.0.3.3.24): the YAML-free sibling of
@@ -342,12 +358,13 @@ export class PodRigInstantiator {
342
358
  cwdOverride: opts?.cwdOverride,
343
359
  fsOps: this.deps.fsOps,
344
360
  rigNameOverride: targetRig?.rig.name,
361
+ inheritedPermissionPolicy: this.inheritedPermissionPolicy(opts?.targetRigId),
345
362
  exec: this.deps.exec,
346
363
  });
347
364
  if (!preflight.ready) {
348
365
  return { ok: false, code: "preflight_failed", errors: preflight.errors, warnings: preflight.warnings };
349
366
  }
350
- return this.materializeValidatedSpec(rigSpec, rigRoot, opts);
367
+ return this.materializeValidatedSpec(rigSpec, rigRoot, preflight.warnings, opts);
351
368
  }
352
369
  /**
353
370
  * materialize CORE (OPR.0.3.3.24): the persistence body of materialize, taking
@@ -359,7 +376,7 @@ export class PodRigInstantiator {
359
376
  * `add_member` reuse the exact create path — create+launch only, no identity
360
377
  * migration.
361
378
  */
362
- async materializeValidatedSpec(rigSpec, rigRoot, opts) {
379
+ async materializeValidatedSpec(rigSpec, rigRoot, preflightWarnings, opts) {
363
380
  const persistedEvents = [];
364
381
  const nodeResults = [];
365
382
  try {
@@ -374,6 +391,24 @@ export class PodRigInstantiator {
374
391
  if (rigSpec.workspace) {
375
392
  this.deps.rigRepo.setRigWorkspace(materializedRigId, rigSpec.workspace);
376
393
  }
394
+ // OPR.0.4.8.3 Seam B: persist the rig-level permission_policy REF (raw, like role) —
395
+ // this is ONE of TWO rig-persist sites (materializeValidatedSpec + instantiate); missing
396
+ // either drops the rig ref on that path (map correction, independently verified).
397
+ // Guard-F1: the RESOLVED rig attachment persists too (declaringDir = THIS rigRoot,
398
+ // the original declaring RigSpec dir) — restart-complete for organic seats,
399
+ // add-member under a different root, and successor continuity. STRICT (load-bearing).
400
+ if (rigSpec.permissionPolicy) {
401
+ this.deps.rigRepo.setRigPermissionPolicy(materializedRigId, rigSpec.permissionPolicy);
402
+ const rigAttachment = resolvePermissionPolicyAttachment(rigSpec.permissionPolicy, rigRoot, {
403
+ readFile: (p) => this.deps.fsOps.readFile(p),
404
+ });
405
+ this.deps.rigRepo.setRigPolicyProvenance(materializedRigId, {
406
+ origin: rigAttachment.origin,
407
+ resolvedTarget: rigAttachment.resolvedTarget ?? null,
408
+ declaringDir: rigAttachment.origin === "custom" ? rigRoot : null,
409
+ launchPosture: rigAttachment.launchPosture,
410
+ });
411
+ }
377
412
  const currentRig = this.deps.rigRepo.getRig(materializedRigId);
378
413
  const logicalIdToNodeId = new Map(currentRig.nodes.map((node) => [node.logicalId, node.id]));
379
414
  const existingPodIds = new Set(currentRig.nodes
@@ -415,6 +450,26 @@ export class PodRigInstantiator {
415
450
  cwdOverride: opts?.cwdOverride,
416
451
  });
417
452
  logicalIdToNodeId.set(qualifiedId, node.id);
453
+ // Seam B R2: restart-stable provenance persists AT MATERIALIZE (a
454
+ // materialized-but-never-launched seat must still restore its posture).
455
+ // R2 HIGH-1: expansion into an EXISTING rig materializes through a SYNTHETIC
456
+ // fragment with no rig-level ref — a ref-less member must inherit the
457
+ // PERSISTED target-rig attachment (original declaring dir), never lose it.
458
+ const materializeAttachment = this.resolveMemberPolicyAttachment(member.permissionPolicy, rigSpec.permissionPolicy, rigRoot);
459
+ if (materializeAttachment) {
460
+ this.persistNodePolicyProvenanceStrict(node.id, materializeAttachment);
461
+ }
462
+ else if (opts?.targetRigId) {
463
+ const rigProv = this.deps.rigRepo.getRigPolicyProvenance(materializedRigId);
464
+ if (rigProv) {
465
+ this.deps.rigRepo.setNodePolicyProvenance(node.id, {
466
+ origin: rigProv.origin,
467
+ resolvedTarget: rigProv.resolvedTarget,
468
+ declaringDir: rigProv.declaringDir,
469
+ launchPosture: rigProv.launchPosture,
470
+ });
471
+ }
472
+ }
418
473
  nodeResults.push({ logicalId: qualifiedId, status: "materialized" });
419
474
  persistedEvents.push(event);
420
475
  }
@@ -457,6 +512,7 @@ export class PodRigInstantiator {
457
512
  specName: rigSpec.name,
458
513
  specVersion: rigSpec.version,
459
514
  nodes: nodeResults,
515
+ warnings: preflightWarnings,
460
516
  },
461
517
  };
462
518
  }
@@ -632,6 +688,7 @@ export class PodRigInstantiator {
632
688
  cwdOverride: opts?.cwdOverride,
633
689
  fsOps: this.deps.fsOps,
634
690
  rigNameOverride: rig.rig.name,
691
+ inheritedPermissionPolicy: this.inheritedPermissionPolicy(rigId),
635
692
  exec: this.deps.exec,
636
693
  });
637
694
  if (!preflight.ready) {
@@ -692,6 +749,28 @@ export class PodRigInstantiator {
692
749
  });
693
750
  createdNodeId = node.id;
694
751
  createdEvent = event;
752
+ // Seam B Guard-F1: add_member runs under the CURRENT operation's root, which may
753
+ // differ from the ORIGINAL declaring RigSpec dir. A member OVERRIDE resolves against
754
+ // this operation's root (it is declared HERE); an INHERITED rig policy must reuse the
755
+ // PERSISTED rig attachment (original declaring root) — never re-resolve the raw rig
756
+ // ref against an unrelated root. STRICT persistence (load-bearing).
757
+ if (member.permissionPolicy) {
758
+ const memberAttachment = resolvePermissionPolicyAttachment(member.permissionPolicy, rigRoot, {
759
+ readFile: (p) => this.deps.fsOps.readFile(p),
760
+ });
761
+ this.persistNodePolicyProvenanceStrict(node.id, memberAttachment);
762
+ }
763
+ else {
764
+ const rigProv = this.deps.rigRepo.getRigPolicyProvenance(rigId);
765
+ if (rigProv) {
766
+ this.deps.rigRepo.setNodePolicyProvenance(node.id, {
767
+ origin: rigProv.origin,
768
+ resolvedTarget: rigProv.resolvedTarget,
769
+ declaringDir: rigProv.declaringDir,
770
+ launchPosture: rigProv.launchPosture,
771
+ });
772
+ }
773
+ }
695
774
  if (resolvedEdges.length > 0) {
696
775
  const logicalIdToNodeId = new Map(rig.nodes.map((n) => [n.logicalId, n.id]));
697
776
  logicalIdToNodeId.set(qualifiedId, node.id);
@@ -730,7 +809,7 @@ export class PodRigInstantiator {
730
809
  sessionName: launched.sessionName,
731
810
  },
732
811
  edges: resolvedEdges,
733
- warnings: launched.warnings,
812
+ warnings: [...preflight.warnings, ...(launched.warnings ?? [])],
734
813
  },
735
814
  };
736
815
  }
@@ -777,6 +856,21 @@ export class PodRigInstantiator {
777
856
  if (rigSpec.workspace) {
778
857
  this.deps.rigRepo.setRigWorkspace(rigId, rigSpec.workspace);
779
858
  }
859
+ // OPR.0.4.8.3 Seam B: the SECOND rig-persist site (bootstrap instantiate path) —
860
+ // both sites must write or the rig ref silently drops on one instantiate path.
861
+ // Guard-F1: resolved rig attachment persists here too (declaringDir = rigRoot).
862
+ if (rigSpec.permissionPolicy) {
863
+ this.deps.rigRepo.setRigPermissionPolicy(rigId, rigSpec.permissionPolicy);
864
+ const rigAttachment = resolvePermissionPolicyAttachment(rigSpec.permissionPolicy, rigRoot, {
865
+ readFile: (p) => this.deps.fsOps.readFile(p),
866
+ });
867
+ this.deps.rigRepo.setRigPolicyProvenance(rigId, {
868
+ origin: rigAttachment.origin,
869
+ resolvedTarget: rigAttachment.resolvedTarget ?? null,
870
+ declaringDir: rigAttachment.origin === "custom" ? rigRoot : null,
871
+ launchPosture: rigAttachment.launchPosture,
872
+ });
873
+ }
780
874
  }
781
875
  catch (err) {
782
876
  return { ok: false, code: "instantiate_error", message: err.message };
@@ -785,7 +879,7 @@ export class PodRigInstantiator {
785
879
  const nodeResults = [];
786
880
  const nodeIdMap = {}; // "pod.member" -> node DB id
787
881
  const launchedSessionNames = []; // Track for orphan cleanup on total failure
788
- const podInstantiateWarnings = [];
882
+ const podInstantiateWarnings = preflight.warnings;
789
883
  // Store per-member context for deferred launch
790
884
  const memberContext = new Map();
791
885
  // Phase 1: Create all pods and collect member entries
@@ -858,8 +952,7 @@ export class PodRigInstantiator {
858
952
  continue;
859
953
  }
860
954
  // Create node
861
- let nodeId;
862
- try {
955
+ const createUnit = this.db.transaction(() => {
863
956
  const node = this.deps.rigRepo.addNode(rigId, qualifiedId, {
864
957
  // OPR.0.4.6.FAC1 (VM-caught): the pod-aware bootstrap
865
958
  // instantiate-from-YAML path (`rig up <spec>`) creates agent
@@ -874,6 +967,10 @@ export class PodRigInstantiator {
874
967
  runtime: member.runtime,
875
968
  model: member.model,
876
969
  codexConfigProfile: member.codexConfigProfile,
970
+ // OPR.0.4.8.3 Seam B: bootstrap inline addNode is the FOURTH node-creation
971
+ // site (see the role wire note above) — same member-ref persistence as
972
+ // createMemberNode or `rig up <spec>` seats lose their policy ref.
973
+ permissionPolicy: member.permissionPolicy,
877
974
  cwd: configResult.config.cwd,
878
975
  restorePolicy: configResult.config.restorePolicy,
879
976
  podId,
@@ -884,7 +981,21 @@ export class PodRigInstantiator {
884
981
  resolvedSpecVersion: configResult.config.resolvedSpecVersion,
885
982
  resolvedSpecHash: configResult.config.resolvedSpecHash,
886
983
  });
887
- nodeId = node.id;
984
+ // Guard multi-seat correction (16e853a7): node creation + required provenance
985
+ // are ONE ATOMIC UNIT (SQLite savepoint). A setter fault rolls the INSERT back
986
+ // too — under partial-success semantics the sibling may proceed, but a failed
987
+ // member can never survive as a half-created node whose restore posture would
988
+ // widen to the rig attachment. (Previously the row survived with provenance
989
+ // null, and resolveRestorePosture fell through to rig full_bypass.)
990
+ const bootstrapAttachment = this.resolveMemberPolicyAttachment(member.permissionPolicy, rigSpec.permissionPolicy, rigRoot);
991
+ if (bootstrapAttachment)
992
+ this.persistNodePolicyProvenanceStrict(node.id, bootstrapAttachment);
993
+ return node.id;
994
+ });
995
+ let nodeId;
996
+ try {
997
+ nodeId = createUnit();
998
+ // nodeIdMap only AFTER the atomic unit succeeds (Guard contract item 2).
888
999
  nodeIdMap[qualifiedId] = nodeId;
889
1000
  }
890
1001
  catch (err) {
@@ -1158,6 +1269,9 @@ export class PodRigInstantiator {
1158
1269
  runtime: input.member.runtime,
1159
1270
  model: input.member.model,
1160
1271
  codexConfigProfile: input.member.codexConfigProfile,
1272
+ // OPR.0.4.8.3 Seam B: the member's OWN raw ref persists on the node (like role);
1273
+ // rig-level lives on the rig row; precedence applies at RESOLUTION, not storage.
1274
+ permissionPolicy: input.member.permissionPolicy,
1161
1275
  cwd: effectiveCwd,
1162
1276
  restorePolicy: input.member.restorePolicy,
1163
1277
  podId: input.podId,
@@ -1187,6 +1301,40 @@ export class PodRigInstantiator {
1187
1301
  ? this.launchExistingTerminalMember(input)
1188
1302
  : this.launchExistingAgentMember(input);
1189
1303
  }
1304
+ /**
1305
+ * OPR.0.4.8.3 Seam B — the ONE precedence + resolution point for a seat's permission
1306
+ * policy at launch: member ref > rig ref > absent (undefined = the env-driven floor).
1307
+ * Custom refs resolve relative to the rig root (the declaring RigSpec's directory in a
1308
+ * materialized rig). Returns undefined when no ref is attached at either level.
1309
+ */
1310
+ resolveMemberPolicyAttachment(memberRef, rigRef, rigRoot) {
1311
+ const ref = resolvePermissionPolicyRefValue(memberRef, rigRef);
1312
+ if (!ref)
1313
+ return undefined;
1314
+ return resolvePermissionPolicyAttachment(ref, rigRoot, {
1315
+ readFile: (p) => this.deps.fsOps.readFile(p),
1316
+ });
1317
+ }
1318
+ /** Seam B Guard-F2: the STRICT materialize/add-member persist — provenance here is
1319
+ * LOAD-BEARING restart state; a real write failure must fail the surrounding
1320
+ * transaction, never commit a node without it. (The repository setter itself still
1321
+ * no-ops on pre-057 legacy fixture DBs — that narrow compatibility is preserved.) */
1322
+ persistNodePolicyProvenanceStrict(nodeId, attachment) {
1323
+ this.deps.rigRepo.setNodePolicyProvenance(nodeId, {
1324
+ origin: attachment.origin,
1325
+ resolvedTarget: attachment.resolvedTarget ?? null,
1326
+ declaringDir: attachment.declaringDir ?? null,
1327
+ launchPosture: attachment.launchPosture,
1328
+ });
1329
+ }
1330
+ /** Seam B: the LAUNCH-time refresh stays best-effort (idempotent re-write on an already-
1331
+ * materialized node; a transient failure must not block a launch). */
1332
+ persistNodePolicyProvenance(nodeId, attachment) {
1333
+ try {
1334
+ this.persistNodePolicyProvenanceStrict(nodeId, attachment);
1335
+ }
1336
+ catch { /* best-effort on launch refresh only */ }
1337
+ }
1190
1338
  async launchExistingAgentMember(input) {
1191
1339
  const resolveResult = input.resolveResult ?? resolveAgentRef(input.member.agentRef, input.rigRoot, this.deps.fsOps);
1192
1340
  if (!resolveResult.ok) {
@@ -1210,6 +1358,24 @@ export class PodRigInstantiator {
1210
1358
  return { status: "failed", error: configResult.errors.join("; ") };
1211
1359
  }
1212
1360
  this.updateNodeResolvedConfig(input.nodeId, configResult.config);
1361
+ // OPR.0.4.8.3 Seam B: resolve the seat's permission-policy attachment once for this
1362
+ // launch (member > rig precedence; declaring dir = the rig root, where the declaring
1363
+ // RigSpec + its relative policy files live). Also persists restart-stable provenance.
1364
+ // R2 HIGH-1: the LIVE binding must AGREE with persisted provenance — structured
1365
+ // add-member/expansion launch with a SYNTHETIC minimal spec (no rig-level ref), so
1366
+ // when the in-memory spec resolves nothing, the PERSISTED node provenance (written in
1367
+ // the creation tx) and then the PERSISTED rig attachment are the binding's truth.
1368
+ const policyAttachment = this.resolveMemberPolicyAttachment(input.member.permissionPolicy, input.rigSpec.permissionPolicy, input.rigRoot);
1369
+ if (policyAttachment)
1370
+ this.persistNodePolicyProvenance(input.nodeId, policyAttachment);
1371
+ // R2 terminal (954d97a0): TRUE ABSENCE binds the locked MINIMUM FLOOR explicitly
1372
+ // (README v4 "DEFAULT IF NONE ATTACHED = the minimum floor"; FINAL2) — ambient
1373
+ // OPENRIG_YOLO must never widen a seat with no attachment. Absence stays honest
1374
+ // (no fabricated attachment/provenance); only the lifecycle BINDING is explicit.
1375
+ const launchPosture = policyAttachment?.launchPosture
1376
+ ?? this.deps.rigRepo.getNodePolicyProvenance(input.nodeId)?.launchPosture
1377
+ ?? this.deps.rigRepo.getRigPolicyProvenance(input.rigId)?.launchPosture
1378
+ ?? "floor";
1213
1379
  const sessionNameErrors = validateSessionComponents(input.pod.id, input.member.id, input.rigSpec.name);
1214
1380
  if (sessionNameErrors.length > 0) {
1215
1381
  return { status: "failed", error: sessionNameErrors.join("; ") };
@@ -1256,6 +1422,9 @@ export class PodRigInstantiator {
1256
1422
  cwd: configResult.config.cwd,
1257
1423
  model: configResult.config.model,
1258
1424
  codexConfigProfile: input.member.codexConfigProfile,
1425
+ // OPR.0.4.8.3 Seam B: resolved launch posture (member > rig > persisted > FLOOR)
1426
+ // binds per-seat explicitly; adapters thread it into the yolo-mode helpers.
1427
+ launchPosture,
1259
1428
  };
1260
1429
  // session_source dispatch: fork (native runtime fork) vs rebuild (artifact-
1261
1430
  // injected fresh launch) vs agent_image (PL-016 Item 4: dispatch through
@@ -1418,6 +1587,13 @@ export class PodRigInstantiator {
1418
1587
  }
1419
1588
  async launchExistingTerminalMember(input) {
1420
1589
  const effectiveCwd = resolveLaunchCwd(input.member.cwd, input.rigRoot, input.cwdOverride);
1590
+ const terminalPolicyAttachment = this.resolveMemberPolicyAttachment(input.member.permissionPolicy, input.rigSpec.permissionPolicy, input.rigRoot);
1591
+ if (terminalPolicyAttachment)
1592
+ this.persistNodePolicyProvenance(input.nodeId, terminalPolicyAttachment);
1593
+ const terminalLaunchPosture = terminalPolicyAttachment?.launchPosture
1594
+ ?? this.deps.rigRepo.getNodePolicyProvenance(input.nodeId)?.launchPosture
1595
+ ?? this.deps.rigRepo.getRigPolicyProvenance(input.rigId)?.launchPosture
1596
+ ?? "floor"; // R2 terminal: absence = the locked floor, explicitly
1421
1597
  const sessionNameErrors = validateSessionComponents(input.pod.id, input.member.id, input.rigSpec.name);
1422
1598
  if (sessionNameErrors.length > 0) {
1423
1599
  return { status: "failed", error: sessionNameErrors.join("; ") };
@@ -1457,6 +1633,9 @@ export class PodRigInstantiator {
1457
1633
  cmuxSurface: null,
1458
1634
  updatedAt: "",
1459
1635
  cwd: effectiveCwd,
1636
+ // Seam B: a terminal seat has no harness posture flag, but the resolved/persisted
1637
+ // posture (floor when absent) still binds for provenance-consuming consumers.
1638
+ launchPosture: terminalLaunchPosture,
1460
1639
  };
1461
1640
  const adapter = this.deps.adapters["terminal"];
1462
1641
  if (!adapter) {