@akagilnc/pi-workflow-roles 0.1.3873 → 0.1.3886

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.
@@ -211,11 +211,10 @@ export type AdmittedReviewerInvocation = AdmittedRoleInvocationBase & {
211
211
  readonly authorityRefs: readonly string[];
212
212
  };
213
213
 
214
- /** Mechanical envelope derived from the active ordinary two-parent merge. */
214
+ /** Mechanical materials read from current Git state (may be empty). */
215
215
  export type DerivedMergerEnvelope = {
216
216
  readonly targetObjectId: string;
217
217
  readonly sourceObjectId: string;
218
- readonly automaticMergeTreeId: string;
219
218
  readonly expectedConflictPaths: readonly string[];
220
219
  readonly resolutionScope: readonly string[];
221
220
  };
@@ -810,17 +809,6 @@ export type ParseAnalystArgvResult =
810
809
  | ParseAnalystSweepArgv
811
810
  | ParseAnalystCohortArgv;
812
811
 
813
- /** Honest activation-class failure while deriving the active-merge envelope. */
814
- export class MergerEnvelopeDerivationError extends Error {
815
- readonly code = "merger-envelope-derivation" as const;
816
- /** Typed cause for #107 classifyPostAdmissionFailure (isTypedActivationError). */
817
- readonly knownCause = "activation" as const;
818
- constructor(message: string, options?: { cause?: unknown }) {
819
- super(message, options);
820
- this.name = "MergerEnvelopeDerivationError";
821
- }
822
- }
823
-
824
812
  /** Reject missing/blank path values so empty overrides cannot silently degrade. */
825
813
  function requireOptionPath(
826
814
  flag: string,
@@ -2868,7 +2856,7 @@ export function parseMergerArgv(args: readonly string[]): ParseMergerArgvResult
2868
2856
  token.startsWith("--resolutionScope=")
2869
2857
  ) {
2870
2858
  throw new CliUsageError(
2871
- "merger does not accept public packet fields; the adapter derives the active-merge envelope",
2859
+ "merger does not accept public packet fields; the adapter reads Git merge materials",
2872
2860
  );
2873
2861
  }
2874
2862
  if (token.startsWith("-") && token !== "-") {
@@ -2894,36 +2882,20 @@ function mergerMaterialFromUtf8(text: string): MergerInput["materials"]["task"]
2894
2882
  }
2895
2883
 
2896
2884
  /**
2897
- * Derive the mechanical Merger envelope from an already-active ordinary merge.
2898
- * Uses the production Git seam (HEAD, sole MERGE_HEAD, AUTO_MERGE, unmerged set).
2899
- * Failures are activation-class facts — not CLI semantic guesses.
2885
+ * Read merger materials from current Git state.
2886
+ * No in-progress merge / empty conflict set still yields materials (possibly empty);
2887
+ * code does not gate attendance on merge state (#827).
2900
2888
  */
2901
2889
  export async function deriveMergerEnvelopeFromActiveMerge(
2902
2890
  projectRoot: string,
2903
2891
  gitState: MergerGitState = createProductionMergerGitState(projectRoot),
2904
2892
  ): Promise<DerivedMergerEnvelope> {
2905
- let state;
2906
- try {
2907
- state = await gitState.activeMerge();
2908
- } catch (error) {
2909
- const message =
2910
- error instanceof Error && error.message.trim() !== ""
2911
- ? error.message
2912
- : "Assigned repository does not have one ordinary in-progress merge";
2913
- throw new MergerEnvelopeDerivationError(message, { cause: error });
2914
- }
2915
- if (state.unmergedPaths.length === 0) {
2916
- throw new MergerEnvelopeDerivationError(
2917
- "Assigned repository does not have one ordinary in-progress merge with a complete conflict set",
2918
- );
2919
- }
2893
+ const state = await gitState.activeMerge();
2920
2894
  const expectedConflictPaths = Object.freeze([...state.unmergedPaths]);
2921
- // Scope is derived as the complete conflict set; the role may not broaden it.
2922
2895
  const resolutionScope = Object.freeze([...state.unmergedPaths]);
2923
2896
  return Object.freeze({
2924
2897
  targetObjectId: state.targetObjectId,
2925
2898
  sourceObjectId: state.sourceObjectId,
2926
- automaticMergeTreeId: state.automaticMergeTreeId,
2927
2899
  expectedConflictPaths,
2928
2900
  resolutionScope,
2929
2901
  });
@@ -2945,8 +2917,9 @@ export type AdmitMergerInvocationOptions = {
2945
2917
 
2946
2918
  /**
2947
2919
  * Admit a Merger Role run on the common Invocation request.
2948
- * Mechanical envelope (parents, AUTO_MERGE, conflicts, scope) is derived from
2949
- * the active merge — callers never supply public packet fields for those facts.
2920
+ * Git materials (parents, conflicts, scope) are read from the worktree and
2921
+ * handed to the role as assignment materials — including when empty (#827).
2922
+ * Callers never supply public packet fields for those facts.
2950
2923
  */
2951
2924
  export async function admitMergerInvocation(
2952
2925
  options: AdmitMergerInvocationOptions,
@@ -2960,8 +2933,6 @@ export async function admitMergerInvocation(
2960
2933
  }
2961
2934
 
2962
2935
  const projectRoot = resolve(options.project ?? options.cwd);
2963
- // Derive mechanical envelope before placing a run identity so no-merge/drift
2964
- // fails honestly without orphan ledger rows or guessed packet fields.
2965
2936
  const derived = await deriveMergerEnvelopeFromActiveMerge(
2966
2937
  projectRoot,
2967
2938
  options.gitState ?? createProductionMergerGitState(projectRoot),
@@ -2988,18 +2959,18 @@ export async function admitMergerInvocation(
2988
2959
  const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
2989
2960
 
2990
2961
  // Intent materials seed primary-source investigation; the method owns the work.
2962
+ const targetLabel = derived.targetObjectId === "" ? "(none observed)" : derived.targetObjectId;
2963
+ const sourceLabel = derived.sourceObjectId === "" ? "(none observed)" : derived.sourceObjectId;
2991
2964
  const targetIntent = mergerMaterialFromUtf8(
2992
- `Investigate primary sources for target parent ${derived.targetObjectId}. Do not invent intent.`,
2965
+ `Investigate primary sources for target parent ${targetLabel}. Do not invent intent.`,
2993
2966
  );
2994
2967
  const sourceIntent = mergerMaterialFromUtf8(
2995
- `Investigate primary sources for source parent ${derived.sourceObjectId}. Do not invent intent.`,
2968
+ `Investigate primary sources for source parent ${sourceLabel}. Do not invent intent.`,
2996
2969
  );
2997
2970
  const taskMaterial = mergerMaterialFromUtf8(instruction);
2998
2971
  const authorityMaterial = mergerMaterialFromUtf8(instruction);
2999
2972
 
3000
- // Validate merger envelope before placing admitted identity.
3001
2973
  const mergerInput = validateMergerInput({
3002
- version: 1,
3003
2974
  attemptId: runId,
3004
2975
  targetObjectId: derived.targetObjectId,
3005
2976
  sourceObjectId: derived.sourceObjectId,
@@ -3011,7 +2982,6 @@ export async function admitMergerInvocation(
3011
2982
  },
3012
2983
  expectedConflictPaths: [...derived.expectedConflictPaths],
3013
2984
  resolutionScope: [...derived.resolutionScope],
3014
- // Authorized checks remain available on the assignment; default none.
3015
2985
  authorizedChecks: [],
3016
2986
  });
3017
2987
 
@@ -3035,7 +3005,6 @@ export async function admitMergerInvocation(
3035
3005
  derived: {
3036
3006
  targetObjectId: derived.targetObjectId,
3037
3007
  sourceObjectId: derived.sourceObjectId,
3038
- automaticMergeTreeId: derived.automaticMergeTreeId,
3039
3008
  expectedConflictPaths: [...derived.expectedConflictPaths],
3040
3009
  resolutionScope: [...derived.resolutionScope],
3041
3010
  },
@@ -1,18 +1,13 @@
1
1
  /**
2
- * Public Merger Role run: derive active-merge envelope → force package
3
- * merge-only method → post-admission coordinator → settle Terminal result (#114 / #517).
2
+ * Public Merger Role run: read Git materials → force package merge-only method
3
+ * → post-admission coordinator → settle Terminal result (#114 / #517 / #827).
4
4
  * #526: execution via RoleTurnHost; argv is Pi adapter internal.
5
5
  */
6
6
  import type {
7
- DurablePrincipalAuthority,
8
7
  MethodBinding,
9
8
  RoleTurnKnownFailure,
10
9
  RoleTurnRequest,
11
10
  } from "../host-contracts.ts";
12
- import { mkdir, writeFile } from "node:fs/promises";
13
- import { join, resolve } from "node:path";
14
-
15
- import { ensureRealDirectoryTree } from "../activation-ledger-topology.ts";
16
11
  import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
17
12
  import {
18
13
  loadPackagedMethodSkillMaterial,
@@ -20,13 +15,10 @@ import {
20
15
  type PackagedMethodSkillMaterial,
21
16
  type PackagedMethodSkillProvenance,
22
17
  } from "../package-resources/method-skill.ts";
23
- import { uuidv7 } from "../uuidv7.ts";
24
18
  import { CliUsageError } from "./cli-errors.ts";
25
19
  import {
26
20
  admitMergerInvocation,
27
21
  buildMergerTransportPrompt,
28
- issueAdmissionPlacement,
29
- MergerEnvelopeDerivationError,
30
22
  type AdmittedMergerInvocation,
31
23
  } from "./invocation.ts";
32
24
  import {
@@ -116,82 +108,6 @@ async function loadMergerMethodMaterial(
116
108
  );
117
109
  }
118
110
 
119
- /**
120
- * Structural admit shell when envelope derivation fails: keeps role-correct
121
- * Terminal identity for honest activation-class settlement without inventing
122
- * parents/conflicts (those stay empty; the gate never receives a guessed packet).
123
- */
124
- async function admitMergerShellForActivationFailure(options: {
125
- home: string;
126
- cwd: string;
127
- instruction: string;
128
- project?: string;
129
- createRunId?: () => string;
130
- principalAuthority: DurablePrincipalAuthority;
131
- }): Promise<AdmittedMergerInvocation> {
132
- const projectRoot = resolve(options.project ?? options.cwd);
133
- const runId = (options.createRunId ?? uuidv7)();
134
- const {
135
- principal,
136
- sessionDirectory,
137
- sessionFile,
138
- runDirectory,
139
- ledgerHome,
140
- bookKey,
141
- } = issueAdmissionPlacement(options.principalAuthority, {
142
- cwd: projectRoot,
143
- runId,
144
- role: "merger",
145
- home: options.home,
146
- });
147
- ensureRealDirectoryTree(ledgerHome, sessionDirectory);
148
- await mkdir(runDirectory, { recursive: true });
149
- const emptyDerived = {
150
- targetObjectId: "",
151
- sourceObjectId: "",
152
- automaticMergeTreeId: "",
153
- expectedConflictPaths: [] as string[],
154
- resolutionScope: [] as string[],
155
- };
156
- const admittedRequestPath = join(runDirectory, "admitted-request.json");
157
- const mergerInputPath = join(runDirectory, "merger-input.json");
158
- await writeFile(
159
- admittedRequestPath,
160
- `${JSON.stringify(
161
- {
162
- role: "merger",
163
- runId,
164
- bookKey,
165
- projectRoot,
166
- instruction: options.instruction,
167
- instructionEmpty: false,
168
- mergerInputPath,
169
- derived: emptyDerived,
170
- attachments: [],
171
- sessionDirectory,
172
- sessionFile,
173
- },
174
- null,
175
- 2,
176
- )}\n`,
177
- "utf8",
178
- );
179
- return {
180
- role: "merger",
181
- runId,
182
- bookKey,
183
- projectRoot,
184
- instruction: options.instruction,
185
- instructionEmpty: false,
186
- attachments: [],
187
- runDirectory,
188
- principal,
189
- admittedRequestPath,
190
- mergerInputPath,
191
- derived: emptyDerived,
192
- };
193
- }
194
-
195
111
  function mergerTurnOptions(
196
112
  admitted: AdmittedMergerInvocation,
197
113
  env: MergerRunEnv,
@@ -263,33 +179,6 @@ export async function runPublicMerger(
263
179
  presentStructuralRejection(error, io);
264
180
  return { exitCode: 2 };
265
181
  }
266
- if (error instanceof MergerEnvelopeDerivationError) {
267
- const shell = await admitMergerShellForActivationFailure({
268
- home: env.home,
269
- principalAuthority: env.principalAuthority,
270
- cwd: env.cwd,
271
- instruction: parsed.instruction,
272
- ...(parsed.project === undefined ? {} : { project: parsed.project }),
273
- ...(env.createRunId === undefined
274
- ? {}
275
- : { createRunId: env.createRunId }),
276
- });
277
- await markRunAdmitted(shell, env.principalAuthority);
278
- return (await presentControlledFailure(
279
- shell,
280
- {
281
- timedOut: false,
282
- code: null,
283
- stderr: "",
284
- thrown: error,
285
- knownCause: "activation",
286
- knownDiagnostic: error.message,
287
- },
288
- mergerAdapters(env.packageRoot),
289
- env.principalAuthority,
290
- io,
291
- )) as { exitCode: number; admitted: AdmittedMergerInvocation; terminal: TerminalResult };
292
- }
293
182
  throw error;
294
183
  }
295
184
 
@@ -670,7 +670,7 @@ const NOTARY_OPTIONS = [
670
670
  ] as const satisfies readonly PublicOptionDefinition[];
671
671
 
672
672
  const MERGER_OPTIONS = [
673
- // Merger project face differs: requires an in-progress ordinary merge root.
673
+ // Merger project face: worktree whose Git materials are handed to the role.
674
674
  {
675
675
  id: "project",
676
676
  owner: "merger",
@@ -681,8 +681,8 @@ const MERGER_OPTIONS = [
681
681
  repeatable: false,
682
682
  form: "option",
683
683
  description: {
684
- en: "Project root with one ordinary in-progress merge (defaults to cwd).",
685
- zh: "已有进行中 ordinary merge 的项目根(默认 cwd)。",
684
+ en: "Project root whose Git merge materials are read (defaults to cwd).",
685
+ zh: "读取 Git merge 材料的项目根(默认 cwd)。",
686
686
  },
687
687
  },
688
688
  bindOwner("merger", SHARED_ATTACH_SEMANTICS),
@@ -1231,10 +1231,10 @@ const ROLE_COMMAND_HELP = {
1231
1231
  },
1232
1232
  merger: {
1233
1233
  command: "merger",
1234
- summary: "Resolve one ordinary merge already in conflict.",
1234
+ summary: "Reconcile merge materials in a worktree (escalate when nothing to merge).",
1235
1235
  usage: ["ak-role merger [options] <instruction>"],
1236
1236
  examples: [
1237
- 'ak-role merger --project /path/to/worktree "Reconcile the active merge."',
1237
+ 'ak-role merger --project /path/to/worktree "Reconcile the merge."',
1238
1238
  ],
1239
1239
  },
1240
1240
  inspector: {
@@ -1386,7 +1386,6 @@ async function loadResumableRunRecord(
1386
1386
  if (
1387
1387
  typeof d.targetObjectId === "string" &&
1388
1388
  typeof d.sourceObjectId === "string" &&
1389
- typeof d.automaticMergeTreeId === "string" &&
1390
1389
  Array.isArray(d.expectedConflictPaths) &&
1391
1390
  Array.isArray(d.resolutionScope) &&
1392
1391
  d.expectedConflictPaths.every((p) => typeof p === "string") &&
@@ -1395,7 +1394,6 @@ async function loadResumableRunRecord(
1395
1394
  derived = {
1396
1395
  targetObjectId: d.targetObjectId,
1397
1396
  sourceObjectId: d.sourceObjectId,
1398
- automaticMergeTreeId: d.automaticMergeTreeId,
1399
1397
  expectedConflictPaths: d.expectedConflictPaths as string[],
1400
1398
  resolutionScope: d.resolutionScope as string[],
1401
1399
  };
@@ -5,7 +5,6 @@ import { loadCanonicalSkillBinding as loadHomeCanonicalSkillBinding } from "./ca
5
5
  import { createGhCollectorGitHubTransport, createGhIssueSoftFetcher } from "./collector-github.ts";
6
6
  import { createPiDoctorAuditor } from "./doctor-auditor.ts";
7
7
  import { loadDoctorCase } from "./doctor-evidence.ts";
8
- import { createProductionMergerGitState } from "./merger-git-state.ts";
9
8
  import { createNativeNavigatorSessionFactory, createNavigatorAttendance } from "./navigator-attendance.ts";
10
9
  import { loadNavigatorWorkContext } from "./navigator-work-context.ts";
11
10
  import { loadNotarySourceRunLocator } from "./notary-source-run.ts";
@@ -53,7 +52,6 @@ export function createRoleRuntimeDependencies(packageRoot: string): RoleRuntimeD
53
52
  loadNotarySourceRun: loadNotarySourceRunLocator,
54
53
  loadMergerSoul: () => loadMainRoleSessionMaterials("merger"),
55
54
  loadMergerInput: async (path) => JSON.parse(await readFile(path, "utf8")),
56
- createMergerGitState: (repositoryRoot) => createProductionMergerGitState(repositoryRoot),
57
55
  async loadCanonicalSkillBinding(name) {
58
56
  if (name === "tdd") {
59
57
  return loadPackagedCanonicalSkillBinding(packageRoot, "tdd");
@@ -423,7 +423,7 @@ export { MERGER_INPUT_FLAG, createMergerRoleRuntime } from "./merger-role.ts";
423
423
  export { MERGER_OUTPUT_TOOL_NAME, mergerInputSchema, mergerOutputSchema, validateMergerInput, validateMergerOutput } from "./merger-contracts.ts";
424
424
  export type { MergerInput, MergerMaterial, MergerOutput } from "./merger-contracts.ts";
425
425
  export { createProductionMergerGitState } from "./merger-git-state.ts";
426
- export type { MergerGitState, ActiveMergerGitState, CompletedMergerGitState } from "./merger-git-state.ts";
426
+ export type { MergerGitState, ActiveMergerGitState } from "./merger-git-state.ts";
427
427
  export type { MergerRoleDependencies } from "./merger-role.ts";
428
428
 
429
429
  type WorkerArmable = {
@@ -627,8 +627,6 @@ export type RoleRuntimeDependencies = {
627
627
  loadDoctorCase?(path: string): Promise<import("./doctor-contracts.ts").DoctorCase>;
628
628
  loadMergerSoul?(): Promise<string>;
629
629
  loadMergerInput?(path: string): Promise<unknown>;
630
- mergerGitState?: MergerRoleDependencies["gitState"];
631
- createMergerGitState?(repositoryRoot: string): MergerRoleDependencies["gitState"];
632
630
  auditDoctorCompliance?(options: { context: HostContext; signal?: AbortSignal }): Promise<ComplianceDecision>;
633
631
  createCollectorClock?(): CollectorClock;
634
632
  createNavigatorAttendance?(options: { context: HostContext; role: string; phase: NavigatorPhase; subjectKey: string; subject: string; authority: string; contextError?: unknown; invocationId: string; onEvent: (event: import("./navigator-attendance.ts").NavigatorEvent, report: import("./navigator-attendance.ts").NavigatorReport) => void | Promise<void> }): NavigatorAttendanceDependency | Promise<NavigatorAttendanceDependency>;
@@ -1682,15 +1680,10 @@ export function createRoleRuntimeExtension(
1682
1680
  },
1683
1681
  },
1684
1682
  );
1685
- let sessionMergerGitState = dependencies.mergerGitState;
1686
1683
  const merger = createMergerRoleRuntime(roleHost, {
1687
1684
  async loadSoul() { if (!dependencies.loadMergerSoul) throw new Error("Merger runtime dependencies are not configured"); return dependencies.loadMergerSoul(); },
1688
1685
  async loadInput(path) { if (!dependencies.loadMergerInput) throw new Error("Merger runtime dependencies are not configured"); return dependencies.loadMergerInput(path); },
1689
- gitState: {
1690
- activeMerge() { if (!sessionMergerGitState) throw new Error("Merger runtime dependencies are not configured"); return sessionMergerGitState.activeMerge(); },
1691
- completedMerge(mergeCommitId, automaticMergeTreeId) { if (!sessionMergerGitState) throw new Error("Merger runtime dependencies are not configured"); return sessionMergerGitState.completedMerge(mergeCommitId, automaticMergeTreeId); },
1692
- },
1693
- }, hostActions);
1686
+ });
1694
1687
  // #676 E: shared envelope owns collector lifecycle (mode/fork, tool surface,
1695
1688
  // event gates). Role module supplies business activate/tools/materials only.
1696
1689
  let activeCollector: CollectorActivation | undefined;
@@ -1997,10 +1990,6 @@ export function createRoleRuntimeExtension(
1997
1990
  auditor,
1998
1991
  diarist,
1999
1992
  merger: async () => {
2000
- if (dependencies.mergerGitState === undefined) {
2001
- sessionMergerGitState = dependencies.createMergerGitState?.(ctx.cwd);
2002
- }
2003
- if (sessionMergerGitState === undefined) throw new Error("Merger runtime dependencies are not configured");
2004
1993
  await merger.activate();
2005
1994
  },
2006
1995
  };