@akagilnc/pi-workflow-roles 0.1.4204 → 0.1.4228

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.
@@ -206,10 +206,75 @@ var init_collector_config = __esm({
206
206
  }
207
207
  });
208
208
 
209
+ // src/ticket-provenance-contracts.ts
210
+ function isRecord(value2) {
211
+ return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
212
+ }
213
+ function positiveInteger(value2) {
214
+ if (typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 1) return value2;
215
+ if (typeof value2 === "string" && /^[1-9][0-9]*$/.test(value2)) {
216
+ const parsed = Number(value2);
217
+ if (Number.isSafeInteger(parsed)) return parsed;
218
+ }
219
+ return void 0;
220
+ }
221
+ function projectBound(value2) {
222
+ if (!isRecord(value2)) return void 0;
223
+ const id = typeof value2.id === "string" && value2.id !== "" ? value2.id : void 0;
224
+ const line = positiveInteger(value2.line);
225
+ if (id === void 0 && line === void 0) return void 0;
226
+ return { ...id === void 0 ? {} : { id }, ...line === void 0 ? {} : { line } };
227
+ }
228
+ function projectTicketProvenanceSessions(value2) {
229
+ if (!Array.isArray(value2)) return void 0;
230
+ if (value2.length === 0) return [];
231
+ const sessions = [];
232
+ for (const raw of value2) {
233
+ if (!isRecord(raw)) return void 0;
234
+ const path7 = raw.path;
235
+ if (typeof path7 !== "string" || path7.trim() === "") return void 0;
236
+ if (!Array.isArray(raw.ranges) || raw.ranges.length === 0) return void 0;
237
+ const ranges = [];
238
+ for (const rawRange of raw.ranges) {
239
+ if (!isRecord(rawRange)) return void 0;
240
+ const from = projectBound(rawRange.from);
241
+ const to = projectBound(rawRange.to);
242
+ if (from === void 0 || to === void 0) return void 0;
243
+ ranges.push({ from, to });
244
+ }
245
+ sessions.push({ path: path7, ranges });
246
+ }
247
+ return sessions;
248
+ }
249
+ function projectTicketProvenanceHeader(value2) {
250
+ if (!isRecord(value2)) return void 0;
251
+ const ticket = positiveInteger(value2.ticket);
252
+ if (ticket === void 0) return void 0;
253
+ if (typeof value2.repo !== "string") return void 0;
254
+ if (typeof value2.createdAt !== "string" || typeof value2.updatedAt !== "string") {
255
+ return void 0;
256
+ }
257
+ const sessions = projectTicketProvenanceSessions(value2.sessions);
258
+ if (sessions === void 0) return void 0;
259
+ return {
260
+ repo: value2.repo,
261
+ ticket,
262
+ createdAt: value2.createdAt,
263
+ updatedAt: value2.updatedAt,
264
+ sessions
265
+ };
266
+ }
267
+ var init_ticket_provenance_contracts = __esm({
268
+ "src/ticket-provenance-contracts.ts"() {
269
+ "use strict";
270
+ }
271
+ });
272
+
209
273
  // src/diarist-contracts.ts
210
274
  var init_diarist_contracts = __esm({
211
275
  "src/diarist-contracts.ts"() {
212
276
  "use strict";
277
+ init_ticket_provenance_contracts();
213
278
  init_run_ticket_number();
214
279
  }
215
280
  });
@@ -254377,129 +254442,6 @@ var init_sitian_appender = __esm({
254377
254442
  }
254378
254443
  });
254379
254444
 
254380
- // src/ticket-provenance-contracts.ts
254381
- function isRecord3(value2) {
254382
- return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
254383
- }
254384
- function projectTicketProvenanceEntry(value2) {
254385
- if (!isRecord3(value2)) return void 0;
254386
- if (value2.recordClass === TICKET_PROVENANCE_RECORD_CLASS_DIAGNOSTIC) {
254387
- return void 0;
254388
- }
254389
- if (typeof value2.sourceKind !== "string" || typeof value2.transcript !== "string") {
254390
- return void 0;
254391
- }
254392
- return value2;
254393
- }
254394
- var TICKET_PROVENANCE_HUMAN_VIEW, TICKET_PROVENANCE_RECORD_CLASS_DIAGNOSTIC;
254395
- var init_ticket_provenance_contracts = __esm({
254396
- "src/ticket-provenance-contracts.ts"() {
254397
- "use strict";
254398
- TICKET_PROVENANCE_HUMAN_VIEW = "\u8D77\u5C45\u5F55.md";
254399
- TICKET_PROVENANCE_RECORD_CLASS_DIAGNOSTIC = "diagnostic";
254400
- }
254401
- });
254402
-
254403
- // src/sitian-reader.ts
254404
- var init_sitian_reader = __esm({
254405
- "src/sitian-reader.ts"() {
254406
- "use strict";
254407
- }
254408
- });
254409
-
254410
- // src/sitian-facade.ts
254411
- var init_sitian_facade = __esm({
254412
- "src/sitian-facade.ts"() {
254413
- "use strict";
254414
- init_sitian_appender();
254415
- init_sitian_contracts();
254416
- init_sitian_appender();
254417
- init_sitian_reader();
254418
- }
254419
- });
254420
-
254421
- // src/ticket-provenance.ts
254422
- function markdownFenceFor(text) {
254423
- let longest = 0;
254424
- const runs = text.match(/`+/g);
254425
- if (runs !== null) {
254426
- for (const run of runs) {
254427
- if (run.length > longest) longest = run.length;
254428
- }
254429
- }
254430
- return "`".repeat(Math.max(3, longest + 1));
254431
- }
254432
- function renderTicketProvenanceMarkdown(input) {
254433
- const unprojected = input.unprojected ?? [];
254434
- const lines = [
254435
- `# \u8D77\u5C45\u5F55 \xB7 #${input.ticketNumber}`,
254436
- "",
254437
- `\u6761\u76EE\u6570\uFF1A${input.entries.length + unprojected.length}`,
254438
- ""
254439
- ];
254440
- let index3 = 0;
254441
- for (const entry of input.entries) {
254442
- index3 += 1;
254443
- const sourceKind = typeof entry.sourceKind === "string" ? entry.sourceKind : "\u672A\u6295\u5F71";
254444
- const timestamp = typeof entry.timestamp === "string" ? entry.timestamp : "";
254445
- lines.push(`## ${index3}. ${sourceKind} \xB7 ${timestamp}`);
254446
- lines.push("");
254447
- const basis = entry.basis;
254448
- const method = typeof basis === "object" && basis !== null && !Array.isArray(basis) && typeof basis.method === "string" ? basis.method : "\u672A\u6295\u5F71";
254449
- lines.push(`- basis.method: \`${method}\``);
254450
- if (typeof basis === "object" && basis !== null && !Array.isArray(basis) && Array.isArray(basis.anchors) && basis.anchors.length > 0) {
254451
- lines.push(`- anchors: ${basis.anchors.map((a) => `\`${String(a)}\``).join(", ")}`);
254452
- }
254453
- if (typeof basis === "object" && basis !== null && !Array.isArray(basis) && basis.note !== void 0) {
254454
- lines.push(`- note: ${String(basis.note)}`);
254455
- }
254456
- const sourceRef = typeof entry.sourceRef === "object" && entry.sourceRef !== null && !Array.isArray(entry.sourceRef) ? entry.sourceRef : {};
254457
- const refParts = [];
254458
- if (sourceRef.sessionFile !== void 0) {
254459
- refParts.push(`sessionFile=${String(sourceRef.sessionFile)}`);
254460
- }
254461
- if (sourceRef.entryId !== void 0) {
254462
- refParts.push(`entryId=${String(sourceRef.entryId)}`);
254463
- }
254464
- if (sourceRef.path !== void 0) {
254465
- refParts.push(`path=${String(sourceRef.path)}`);
254466
- }
254467
- if (sourceRef.url !== void 0) {
254468
- refParts.push(`url=${String(sourceRef.url)}`);
254469
- }
254470
- if (refParts.length > 0) {
254471
- lines.push(`- sourceRef: ${refParts.join(" \xB7 ")}`);
254472
- }
254473
- lines.push("");
254474
- const transcript = typeof entry.transcript === "string" ? entry.transcript : JSON.stringify(entry);
254475
- const fence = markdownFenceFor(transcript);
254476
- lines.push(fence);
254477
- lines.push(transcript);
254478
- lines.push(fence);
254479
- lines.push("");
254480
- }
254481
- for (const payload of unprojected) {
254482
- index3 += 1;
254483
- lines.push(`## ${index3}. \u672A\u6295\u5F71`);
254484
- lines.push("");
254485
- const text = typeof payload === "string" ? payload : JSON.stringify(payload);
254486
- const fence = markdownFenceFor(text);
254487
- lines.push(fence);
254488
- lines.push(text);
254489
- lines.push(fence);
254490
- lines.push("");
254491
- }
254492
- return lines.join("\n");
254493
- }
254494
- var init_ticket_provenance = __esm({
254495
- "src/ticket-provenance.ts"() {
254496
- "use strict";
254497
- init_sitian_facade();
254498
- init_run_ticket_number();
254499
- init_ticket_provenance_contracts();
254500
- }
254501
- });
254502
-
254503
254445
  // scripts/migrate-book-topology.ts
254504
254446
  import { resolve as resolve8 } from "node:path";
254505
254447
 
@@ -254596,8 +254538,7 @@ async function migrateBookTopology(input) {
254596
254538
  await mkdir(booksDirectory);
254597
254539
  const context2 = {
254598
254540
  backupBooksDirectory,
254599
- booksDirectory,
254600
- touchedTicketsByBook: /* @__PURE__ */ new Map()
254541
+ booksDirectory
254601
254542
  };
254602
254543
  const partitions = [];
254603
254544
  for (const migrator of input.migrators) {
@@ -276895,7 +276836,7 @@ import { readdir as readdir4, readFile as readFile4 } from "node:fs/promises";
276895
276836
  import { basename as basename6, dirname as dirname6, isAbsolute as isAbsolute3, join as join11, relative as relative3, resolve as resolve5, sep as sep6 } from "node:path";
276896
276837
  var TICKET_NUMBER_RE = /^[1-9][0-9]*$/;
276897
276838
  var RUN_DIR_NAME_RE = /^([^@]+)@([^@]+)$/;
276898
- function isRecord(value2) {
276839
+ function isRecord2(value2) {
276899
276840
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
276900
276841
  }
276901
276842
  function isMigrationEnoent(error51) {
@@ -276941,7 +276882,7 @@ async function readProjectRootFromRun(runDirectory) {
276941
276882
  const path7 = join11(runDirectory, page);
276942
276883
  try {
276943
276884
  const raw = JSON.parse(await readFile4(path7, "utf8"));
276944
- if (!isRecord(raw)) continue;
276885
+ if (!isRecord2(raw)) continue;
276945
276886
  const projectRoot = raw.projectRoot;
276946
276887
  if (typeof projectRoot === "string" && projectRoot.length > 0) {
276947
276888
  return { projectRoot, sourcePage: page };
@@ -277175,7 +277116,7 @@ function runCoordsFromSessionParent(sessionParent) {
277175
277116
  }
277176
277117
  function runIdFromSubject(subject) {
277177
277118
  if (typeof subject === "string" && subject.length > 0) return subject;
277178
- if (isRecord(subject) && typeof subject.runId === "string" && subject.runId.length > 0) {
277119
+ if (isRecord2(subject) && typeof subject.runId === "string" && subject.runId.length > 0) {
277179
277120
  return subject.runId;
277180
277121
  }
277181
277122
  return void 0;
@@ -277184,7 +277125,7 @@ function ticketNumberFromSubject(subject) {
277184
277125
  if (typeof subject === "string" || typeof subject === "number") {
277185
277126
  return ticketNumberFromUnknown(subject);
277186
277127
  }
277187
- if (isRecord(subject)) return ticketNumberFromUnknown(subject.ticketNumber);
277128
+ if (isRecord2(subject)) return ticketNumberFromUnknown(subject.ticketNumber);
277188
277129
  return void 0;
277189
277130
  }
277190
277131
 
@@ -277196,7 +277137,7 @@ var SITIAN_MIXED_VOLUME_PARTITIONS = [
277196
277137
  "gate"
277197
277138
  ];
277198
277139
  var CURRENT_SESSION_LEDGER = "current-session.json";
277199
- function isRecord2(value2) {
277140
+ function isRecord3(value2) {
277200
277141
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
277201
277142
  }
277202
277143
  function posixRelative(from, to) {
@@ -277212,17 +277153,17 @@ function pathCandidatesFromRecord(record2) {
277212
277153
  const seen = /* @__PURE__ */ new Set();
277213
277154
  addPathCandidate(paths, seen, record2.sessionParent);
277214
277155
  addPathCandidate(paths, seen, record2.parentSession);
277215
- if (!isRecord2(record2.payload)) return paths;
277156
+ if (!isRecord3(record2.payload)) return paths;
277216
277157
  const payload = record2.payload;
277217
277158
  addPathCandidate(paths, seen, payload.sessionParent);
277218
277159
  addPathCandidate(paths, seen, payload.parentSession);
277219
277160
  addPathCandidate(paths, seen, payload.sessionFile);
277220
- if (isRecord2(payload.parent)) {
277161
+ if (isRecord3(payload.parent)) {
277221
277162
  addPathCandidate(paths, seen, payload.parent.sessionFile);
277222
277163
  addPathCandidate(paths, seen, payload.parent.sessionParent);
277223
277164
  addPathCandidate(paths, seen, payload.parent.parentSession);
277224
277165
  }
277225
- if (isRecord2(payload.data)) {
277166
+ if (isRecord3(payload.data)) {
277226
277167
  addPathCandidate(paths, seen, payload.data.sessionParent);
277227
277168
  addPathCandidate(paths, seen, payload.data.parentSession);
277228
277169
  addPathCandidate(paths, seen, payload.data.sessionFile);
@@ -277277,7 +277218,7 @@ function inspectWorkerSubmissionGateVolume(text, bookRoots) {
277277
277218
  malformedRows.push({ lineNumber: row.lineNumber, raw: row.raw });
277278
277219
  continue;
277279
277220
  }
277280
- if (!isRecord2(parsed)) {
277221
+ if (!isRecord3(parsed)) {
277281
277222
  malformedRows.push({ lineNumber: row.lineNumber, raw: row.raw });
277282
277223
  continue;
277283
277224
  }
@@ -277330,7 +277271,7 @@ async function migrateCurrentSessionPointer(input) {
277330
277271
  let sessionFile;
277331
277272
  try {
277332
277273
  const parsed = JSON.parse(raw);
277333
- if (isRecord2(parsed) && typeof parsed.sessionFile === "string" && parsed.sessionFile.length > 0) {
277274
+ if (isRecord3(parsed) && typeof parsed.sessionFile === "string" && parsed.sessionFile.length > 0) {
277334
277275
  sessionFile = parsed.sessionFile;
277335
277276
  }
277336
277277
  } catch {
@@ -277408,7 +277349,7 @@ async function migrateSitianMixedVolume(partition4, context2) {
277408
277349
  });
277409
277350
  continue;
277410
277351
  }
277411
- if (!isRecord2(parsed)) {
277352
+ if (!isRecord3(parsed)) {
277412
277353
  const dest2 = volumeDestinationFile(
277413
277354
  booksDirectory,
277414
277355
  bookKey,
@@ -278180,19 +278121,10 @@ import { appendFile as appendFile2, mkdir as mkdir4, readFile as readFile7, stat
278180
278121
  import { dirname as dirname9, join as join14, relative as relative6, sep as sep9 } from "node:path";
278181
278122
  init_sitian_appender();
278182
278123
  init_ticket_provenance_contracts();
278183
- init_ticket_provenance();
278184
278124
  var TICKET_PROVENANCE = "ticket-provenance";
278185
278125
  var SUBMISSION_LEDGER = "submission-ledger";
278186
278126
  var ATTEMPT_HISTORY = "attempt-history";
278187
278127
  var MISPLACED = "misplaced-record-class";
278188
- function noteTouchedTicket(context2, bookKey, ticketNumber) {
278189
- let set2 = context2.touchedTicketsByBook.get(bookKey);
278190
- if (set2 === void 0) {
278191
- set2 = /* @__PURE__ */ new Set();
278192
- context2.touchedTicketsByBook.set(bookKey, set2);
278193
- }
278194
- set2.add(ticketNumber);
278195
- }
278196
278128
  function isRecord4(value2) {
278197
278129
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
278198
278130
  }
@@ -278232,6 +278164,10 @@ async function ensureDir(path7) {
278232
278164
  }
278233
278165
  var RecordWriteCache = class {
278234
278166
  identities = /* @__PURE__ */ new Map();
278167
+ /** Dest paths written as whole #901 bare volumes — legacy must not append under them. */
278168
+ bareVolumeFiles = /* @__PURE__ */ new Set();
278169
+ /** Lines currently on a dest that are still claimed `placed` in outcomes. */
278170
+ destPlacements = /* @__PURE__ */ new Map();
278235
278171
  async load(recordFile) {
278236
278172
  const cached2 = this.identities.get(recordFile);
278237
278173
  if (cached2 !== void 0) return cached2;
@@ -278244,19 +278180,66 @@ var RecordWriteCache = class {
278244
278180
  this.identities.set(recordFile, set2);
278245
278181
  return set2;
278246
278182
  }
278247
- async append(recordFile, raw) {
278183
+ markBareVolume(recordFile) {
278184
+ this.bareVolumeFiles.add(recordFile);
278185
+ this.identities.set(recordFile, /* @__PURE__ */ new Set());
278186
+ }
278187
+ isBareVolume(recordFile) {
278188
+ return this.bareVolumeFiles.has(recordFile);
278189
+ }
278190
+ /**
278191
+ * After a bare whole-file write, register its lines so a later bare for the
278192
+ * same ticket can rehome them and flip dispositions (multi-bare honesty).
278193
+ */
278194
+ setDestPlacements(recordFile, placements) {
278195
+ this.destPlacements.set(recordFile, [...placements]);
278196
+ }
278197
+ /**
278198
+ * Install a bare volume as the sole ticket file. Any lines already placed on
278199
+ * this dest (legacy appends or a prior bare) are moved to unbound and their
278200
+ * outcomes flipped — report stays honest.
278201
+ */
278202
+ async replaceWholeBare(recordFile, body, outcomes, unboundFileForRaw) {
278203
+ const prior = this.destPlacements.get(recordFile) ?? [];
278204
+ for (const placement of prior) {
278205
+ await this.append(unboundFileForRaw(placement.raw), placement.raw);
278206
+ const previous = outcomes[placement.outcomeIndex];
278207
+ if (previous !== void 0) {
278208
+ outcomes[placement.outcomeIndex] = {
278209
+ disposition: "unbound",
278210
+ source: previous.source
278211
+ };
278212
+ }
278213
+ }
278214
+ this.destPlacements.delete(recordFile);
278215
+ await ensureDir(dirname9(recordFile));
278216
+ const text = body.endsWith("\n") ? body : `${body}
278217
+ `;
278218
+ await writeFile6(recordFile, text, "utf8");
278219
+ this.markBareVolume(recordFile);
278220
+ }
278221
+ async append(recordFile, raw, options) {
278248
278222
  await ensureDir(dirname9(recordFile));
278249
278223
  const line = raw.endsWith("\n") ? raw : `${raw}
278250
278224
  `;
278251
278225
  const parsed = parseJsonlLine(raw);
278252
278226
  if (parsed.ok && typeof parsed.value.identity === "string") {
278253
278227
  const existing = await this.load(recordFile);
278254
- if (existing.has(parsed.value.identity)) return;
278255
- existing.add(parsed.value.identity);
278256
- } else if (!this.identities.has(recordFile)) {
278257
- this.identities.set(recordFile, await this.load(recordFile));
278228
+ if (!existing.has(parsed.value.identity)) {
278229
+ existing.add(parsed.value.identity);
278230
+ await appendFile2(recordFile, line, "utf8");
278231
+ }
278232
+ } else {
278233
+ if (!this.identities.has(recordFile)) {
278234
+ this.identities.set(recordFile, await this.load(recordFile));
278235
+ }
278236
+ await appendFile2(recordFile, line, "utf8");
278237
+ }
278238
+ if (options?.outcomeIndex !== void 0 && !this.bareVolumeFiles.has(recordFile)) {
278239
+ const list = this.destPlacements.get(recordFile) ?? [];
278240
+ list.push({ raw, outcomeIndex: options.outcomeIndex });
278241
+ this.destPlacements.set(recordFile, list);
278258
278242
  }
278259
- await appendFile2(recordFile, line, "utf8");
278260
278243
  }
278261
278244
  };
278262
278245
  function roleFromPayload(payload) {
@@ -278392,7 +278375,7 @@ async function resolveRunDestination(context2, bookKey, runId, hints) {
278392
278375
  }
278393
278376
  return { kind: "unbound-key", key: stableKey(runId) };
278394
278377
  }
278395
- async function placeTicketProvenanceLine(context2, bookKey, writes, source, raw, value2) {
278378
+ async function placeTicketProvenanceLine(context2, bookKey, writes, source, raw, value2, outcomeIndex) {
278396
278379
  if (value2 === void 0) {
278397
278380
  await writes.append(unboundCategoryFile(context2.booksDirectory, bookKey, TICKET_PROVENANCE, stableKey(raw)), raw);
278398
278381
  return { disposition: "unbound", source, malformed: true, malformedRaw: raw };
@@ -278402,11 +278385,29 @@ async function placeTicketProvenanceLine(context2, bookKey, writes, source, raw,
278402
278385
  await writes.append(unboundCategoryFile(context2.booksDirectory, bookKey, TICKET_PROVENANCE, stableKey(raw)), raw);
278403
278386
  return { disposition: "unbound", source };
278404
278387
  }
278405
- await writes.append(
278406
- join14(context2.booksDirectory, bookKey, String(ticketNumber), "records.jsonl"),
278407
- raw
278388
+ const dest = join14(
278389
+ context2.booksDirectory,
278390
+ bookKey,
278391
+ String(ticketNumber),
278392
+ "records.jsonl"
278408
278393
  );
278409
- noteTouchedTicket(context2, bookKey, ticketNumber);
278394
+ if (writes.isBareVolume(dest)) {
278395
+ await writes.append(
278396
+ unboundCategoryFile(context2.booksDirectory, bookKey, TICKET_PROVENANCE, stableKey(raw)),
278397
+ raw
278398
+ );
278399
+ return { disposition: "unbound", source };
278400
+ }
278401
+ const existing = await readJsonlLines(dest);
278402
+ if (tryBareTicketProvenanceVolume(existing) !== void 0) {
278403
+ writes.markBareVolume(dest);
278404
+ await writes.append(
278405
+ unboundCategoryFile(context2.booksDirectory, bookKey, TICKET_PROVENANCE, stableKey(raw)),
278406
+ raw
278407
+ );
278408
+ return { disposition: "unbound", source };
278409
+ }
278410
+ await writes.append(dest, raw, { outcomeIndex });
278410
278411
  return { disposition: "placed", source };
278411
278412
  }
278412
278413
  async function placeRunOwnedLine(context2, bookKey, writes, category, source, raw, value2) {
@@ -278432,10 +278433,10 @@ async function placeRunOwnedLine(context2, bookKey, writes, category, source, ra
278432
278433
  await writes.append(join14(target.runDirectory, "session", category, "records.jsonl"), raw);
278433
278434
  return { disposition: target.disposition, source };
278434
278435
  }
278435
- async function placeRecordClassLine(context2, bookKey, writes, source, raw, value2, fallbackCategory) {
278436
+ async function placeRecordClassLine(context2, bookKey, writes, source, raw, value2, fallbackCategory, outcomeIndex) {
278436
278437
  const recordClass = recordClassOfKind(value2.kind);
278437
278438
  if (recordClass === TICKET_PROVENANCE) {
278438
- return placeTicketProvenanceLine(context2, bookKey, writes, source, raw, value2);
278439
+ return placeTicketProvenanceLine(context2, bookKey, writes, source, raw, value2, outcomeIndex);
278439
278440
  }
278440
278441
  if (recordClass === SUBMISSION_LEDGER || recordClass === ATTEMPT_HISTORY) {
278441
278442
  return placeRunOwnedLine(context2, bookKey, writes, recordClass, source, raw, value2);
@@ -278446,8 +278447,53 @@ async function placeRecordClassLine(context2, bookKey, writes, source, raw, valu
278446
278447
  );
278447
278448
  return { disposition: "unbound", source };
278448
278449
  }
278450
+ function tryBareTicketProvenanceVolume(lines) {
278451
+ const body = [];
278452
+ for (const raw of lines) {
278453
+ if (raw.trim() === "") continue;
278454
+ body.push(raw);
278455
+ }
278456
+ if (body.length === 0) return void 0;
278457
+ const first = parseJsonlLine(body[0]);
278458
+ if (!first.ok) return void 0;
278459
+ if (recordClassOfKind(first.value.kind) !== void 0) return void 0;
278460
+ const header = projectTicketProvenanceHeader(first.value);
278461
+ if (header === void 0) return void 0;
278462
+ return { ticket: header.ticket, body };
278463
+ }
278464
+ async function placeBareTicketProvenanceVolume(context2, bookKey, writes, filePath, bare, outcomes) {
278465
+ const dest = join14(
278466
+ context2.booksDirectory,
278467
+ bookKey,
278468
+ String(bare.ticket),
278469
+ "records.jsonl"
278470
+ );
278471
+ const body = bare.body.map((raw) => raw.endsWith("\n") ? raw : `${raw}
278472
+ `).join("");
278473
+ await writes.replaceWholeBare(
278474
+ dest,
278475
+ body,
278476
+ outcomes,
278477
+ (raw) => unboundCategoryFile(context2.booksDirectory, bookKey, TICKET_PROVENANCE, stableKey(raw))
278478
+ );
278479
+ const barePlacements = [];
278480
+ for (let index3 = 0; index3 < bare.body.length; index3 += 1) {
278481
+ const source = lineSource(context2.backupBooksDirectory, filePath, index3);
278482
+ const outcomeIndex = outcomes.length;
278483
+ outcomes.push({ disposition: "placed", source });
278484
+ barePlacements.push({ raw: bare.body[index3], outcomeIndex });
278485
+ }
278486
+ writes.setDestPlacements(dest, barePlacements);
278487
+ }
278449
278488
  async function migrateJsonlFileByKind(context2, bookKey, writes, filePath, fallbackCategory, outcomes) {
278450
278489
  const lines = await readJsonlLines(filePath);
278490
+ if (fallbackCategory === TICKET_PROVENANCE) {
278491
+ const bare = tryBareTicketProvenanceVolume(lines);
278492
+ if (bare !== void 0) {
278493
+ await placeBareTicketProvenanceVolume(context2, bookKey, writes, filePath, bare, outcomes);
278494
+ return;
278495
+ }
278496
+ }
278451
278497
  for (let index3 = 0; index3 < lines.length; index3 += 1) {
278452
278498
  const raw = lines[index3];
278453
278499
  if (raw.trim() === "") continue;
@@ -278455,14 +278501,33 @@ async function migrateJsonlFileByKind(context2, bookKey, writes, filePath, fallb
278455
278501
  const parsed = parseJsonlLine(raw);
278456
278502
  if (!parsed.ok) {
278457
278503
  if (fallbackCategory === TICKET_PROVENANCE) {
278458
- outcomes.push(await placeTicketProvenanceLine(context2, bookKey, writes, source, raw, void 0));
278504
+ outcomes.push(
278505
+ await placeTicketProvenanceLine(
278506
+ context2,
278507
+ bookKey,
278508
+ writes,
278509
+ source,
278510
+ raw,
278511
+ void 0,
278512
+ outcomes.length
278513
+ )
278514
+ );
278459
278515
  } else {
278460
278516
  outcomes.push(await placeRunOwnedLine(context2, bookKey, writes, fallbackCategory, source, raw, void 0));
278461
278517
  }
278462
278518
  continue;
278463
278519
  }
278464
278520
  outcomes.push(
278465
- await placeRecordClassLine(context2, bookKey, writes, source, raw, parsed.value, fallbackCategory)
278521
+ await placeRecordClassLine(
278522
+ context2,
278523
+ bookKey,
278524
+ writes,
278525
+ source,
278526
+ raw,
278527
+ parsed.value,
278528
+ fallbackCategory,
278529
+ outcomes.length
278530
+ )
278466
278531
  );
278467
278532
  }
278468
278533
  }
@@ -278483,47 +278548,10 @@ async function mergeOfferedIdentities(destDir, volumeDir, writes) {
278483
278548
  await writes.append(destFile, raw);
278484
278549
  }
278485
278550
  }
278486
- async function writeMergedTicketHumanView(destDir, ticketNumber) {
278487
- const lines = await readJsonlLines(join14(destDir, "records.jsonl"));
278488
- const entries = [];
278489
- const unprojected = [];
278490
- for (const raw of lines) {
278491
- if (raw.trim() === "") continue;
278492
- const parsed = parseJsonlLine(raw);
278493
- if (!parsed.ok) continue;
278494
- if (recordClassOfKind(parsed.value.kind) !== TICKET_PROVENANCE) continue;
278495
- const entry = projectTicketProvenanceEntry(parsed.value.payload);
278496
- if (entry === void 0) {
278497
- if (parsed.value.payload !== void 0) unprojected.push(parsed.value.payload);
278498
- continue;
278499
- }
278500
- entries.push(entry);
278501
- }
278502
- await ensureDir(destDir);
278503
- await writeFile6(
278504
- join14(destDir, TICKET_PROVENANCE_HUMAN_VIEW),
278505
- renderTicketProvenanceMarkdown({
278506
- ticketNumber,
278507
- entries,
278508
- ...unprojected.length > 0 ? { unprojected } : {}
278509
- }),
278510
- "utf8"
278511
- );
278512
- }
278513
- async function finalizeTicketCompanions(context2, bookKey, ticketNumbers) {
278514
- for (const ticketNumber of ticketNumbers) {
278515
- const destDir = join14(context2.booksDirectory, bookKey, String(ticketNumber));
278516
- try {
278517
- await stat4(join14(destDir, "records.jsonl"));
278518
- } catch (error51) {
278519
- if (isMigrationEnoent(error51)) continue;
278520
- throw error51;
278521
- }
278522
- await writeMergedTicketHumanView(destDir, ticketNumber);
278523
- }
278524
- }
278525
278551
  async function ticketNumbersInVolume(volumeDir) {
278526
278552
  const lines = await readJsonlLines(join14(volumeDir, "records.jsonl"));
278553
+ const bare = tryBareTicketProvenanceVolume(lines);
278554
+ if (bare !== void 0) return [bare.ticket];
278527
278555
  const out = [];
278528
278556
  const seen = /* @__PURE__ */ new Set();
278529
278557
  for (const raw of lines) {
@@ -278540,7 +278568,6 @@ async function ticketNumbersInVolume(volumeDir) {
278540
278568
  }
278541
278569
  async function mergeCompanionsFromVolume(context2, bookKey, volumeDir, writes) {
278542
278570
  for (const ticketNumber of await ticketNumbersInVolume(volumeDir)) {
278543
- noteTouchedTicket(context2, bookKey, ticketNumber);
278544
278571
  const destDir = join14(context2.booksDirectory, bookKey, String(ticketNumber));
278545
278572
  await ensureDir(destDir);
278546
278573
  await mergeOfferedIdentities(destDir, volumeDir, writes);
@@ -278572,7 +278599,6 @@ async function migrateHomePartitionBook(context2, bookKey, writes, category, out
278572
278599
  }
278573
278600
  await migrateJsonlFileByKind(context2, bookKey, writes, recordsFile, TICKET_PROVENANCE, outcomes);
278574
278601
  await mergeCompanionsFromVolume(context2, bookKey, volumeDir, writes);
278575
- noteTouchedTicket(context2, bookKey, Number(entry.name));
278576
278602
  }
278577
278603
  }
278578
278604
  }
@@ -278618,7 +278644,17 @@ async function migrateMisplacedBook(context2, bookKey, writes, outcomes) {
278618
278644
  if (isAlreadyHomeUnderOwningRun(withinBook, recordClass, parsed.value)) continue;
278619
278645
  const source = lineSource(context2.backupBooksDirectory, filePath, index3);
278620
278646
  if (recordClass === TICKET_PROVENANCE) {
278621
- outcomes.push(await placeTicketProvenanceLine(context2, bookKey, writes, source, raw, parsed.value));
278647
+ outcomes.push(
278648
+ await placeTicketProvenanceLine(
278649
+ context2,
278650
+ bookKey,
278651
+ writes,
278652
+ source,
278653
+ raw,
278654
+ parsed.value,
278655
+ outcomes.length
278656
+ )
278657
+ );
278622
278658
  } else {
278623
278659
  outcomes.push(
278624
278660
  await placeRunOwnedLine(context2, bookKey, writes, recordClass, source, raw, parsed.value)
@@ -278681,9 +278717,6 @@ var misplacedRecordClassPartitionMigrator = {
278681
278717
  async migrate(context2) {
278682
278718
  const outcomes = [];
278683
278719
  await forEachBook(context2, (bookKey, writes) => migrateMisplacedBook(context2, bookKey, writes, outcomes));
278684
- for (const [bookKey, tickets] of context2.touchedTicketsByBook) {
278685
- await finalizeTicketCompanions(context2, bookKey, tickets);
278686
- }
278687
278720
  return reconcileMigrationPartition(MISPLACED, "lines", outcomes);
278688
278721
  }
278689
278722
  };
@@ -40,7 +40,6 @@ export async function projectCaseDossierPointerSection(input) {
40
40
  CASE_DOSSIER_SECTION_HEADING,
41
41
  "",
42
42
  `票号:#${input.ticketNumber}`,
43
- `人读视图:${describeDossierFile(volume.humanViewFile)}`,
44
43
  `记录卷宗:${describeDossierFile(volume.recordFile)}`,
45
44
  ].join("\n");
46
45
  }