@gitroll/tacitt-cli 0.6.8 → 0.6.9

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 (32) hide show
  1. package/README.md +1 -1
  2. package/dist/{agent-setup-YlFIJz-h.mjs → agent-setup-CODlN6zl.mjs} +1 -1
  3. package/dist/agent-setup-worker.mjs +4 -4
  4. package/dist/cli.mjs +5 -5
  5. package/dist/codex-title-worker.mjs +1 -1
  6. package/dist/configured-preview-worker.mjs +4 -4
  7. package/dist/configured-session-worker.mjs +4 -4
  8. package/dist/{heap-DsE74_-n.mjs → heap-Dt3-d27v.mjs} +2 -2
  9. package/dist/inspection-worker.mjs +3 -3
  10. package/dist/{job-CeSf9UCC.mjs → job-BQXssW46.mjs} +3 -3
  11. package/dist/{model-f_QnDyyb.mjs → model-CSx2dP_P.mjs} +1 -1
  12. package/dist/operation-executor.mjs +2 -2
  13. package/dist/preview-worker.mjs +1 -1
  14. package/dist/{query-CaBXQlpF.mjs → query-CfhcS4gd.mjs} +168 -112
  15. package/dist/{run-RA_8zZsL.mjs → run-xlOaKCk8.mjs} +2 -2
  16. package/dist/{src-BBjnljUs.mjs → src-BgsEnMsy.mjs} +3 -3
  17. package/dist/{src-d7n58sbH.mjs → src-DzKuzGVH.mjs} +183 -147
  18. package/dist/{src-p_uJNjV3.mjs → src-V9GHLZQs.mjs} +1 -1
  19. package/dist/store-database-worker.mjs +1 -1
  20. package/dist/web/assets/{index-B6kJ6XXF.js → index-9UfCT_2C.js} +1 -1
  21. package/dist/web/index.html +1 -1
  22. package/package.json +1 -1
  23. package/skills/tacitt/SKILL.md +3 -3
  24. package/skills/tacitt/references/commands.md +50 -11
  25. package/skills/tacitt/references/journey.md +1 -1
  26. package/skills/tacitt/references/parallel-review.md +21 -0
  27. package/skills/tacitt/scripts/INDEX.md +39 -36
  28. package/skills/tacitt/scripts/journey-scan-timing.d.mts +15 -0
  29. package/skills/tacitt/scripts/journey-scan-timing.mjs +153 -1
  30. package/skills/tacitt/scripts/journey.mjs +15 -0
  31. package/skills/tacitt/scripts/review.mjs +280 -36
  32. package/LICENSE +0 -11
@@ -1,10 +1,10 @@
1
- import { $ as createCleanup, B as parallelismLimits, C as readOriginalSearchFields, F as SessionWorkerError, G as processJourneyMetadataFields, H as privateJourneyDirectory, I as sessionWorkerFailure, K as staticMaskCategory, O as captureLogicalJourneySources, P as createSharedSessionPool, Q as removeNamedTemporarySpools, R as defaultParallelism, T as createCollectionArtifacts, U as readLogicalJourneyFinalMasks, W as readConfiguredOutputInfo, Z as createTemporary, _ as processJourneyMetadata, a as scanReviewFields, at as windowsOwnerOnly, c as readSessionScanRecords, g as readCapturedOriginalRows, i as buildWorkScanBatches, it as restrictToOwner, j as runConfiguredSessionJob, k as capturedJourneyScope, l as scanPreparedSession, m as openConfiguredUpload, n as verifyPreparedSessionSources, nt as makePrivateDirectory, o as createWorkPieces, ot as isWindowsAclFailure, p as configuredSessionUploads, q as readWorkspacePair, r as prepareSessionScans, rt as openPrivateFile, s as readSessionScanFields, st as windowsAclCodes, t as preparedScanConfiguration, v as readStaticSessionMasks, w as readConfiguredSearchFields, y as staticSessionJobs, z as gitSeedsProvider } from "./src-p_uJNjV3.mjs";
2
- import { A as createExecutionPort, C as saveRemoteState, D as createPackagingProgressPort, E as exportDelivery, F as loadDeliveryResults, L as inBackgroundStoreLane, M as withStateMutex, N as createDeliveryService, O as createStore, P as preflight, R as isBackgroundStatusPoll, S as readRemoteState, T as collectRemoteWorkers, _ as staticBaseProduction, a as writeJourneyOutput, b as workApproval, c as mergeHideIndexTokens, f as writeJourneyBase, g as staticBaseInputs, h as staticSessions, l as packRenderHideIndex, m as saveStaticSession, o as createHideIndexTokens, p as readStaticResult, s as hideIndexTexts, t as journeyOutputJob, u as journeyBaseJob, v as readSelectedCaptures, w as journeyDirectory, x as isRemoteImport, y as prepareSourcePlan, z as retrySharingViolation } from "./job-CeSf9UCC.mjs";
1
+ import { $ as createCleanup, B as parallelismLimits, C as readOriginalSearchFields, F as SessionWorkerError, G as processJourneyMetadataFields, H as privateJourneyDirectory, I as sessionWorkerFailure, K as staticMaskCategory, O as captureLogicalJourneySources, P as createSharedSessionPool, Q as removeNamedTemporarySpools, R as defaultParallelism, T as createCollectionArtifacts, U as readLogicalJourneyFinalMasks, W as readConfiguredOutputInfo, Z as createTemporary, _ as processJourneyMetadata, a as scanReviewFields, at as windowsOwnerOnly, c as readSessionScanRecords, g as readCapturedOriginalRows, i as buildWorkScanBatches, it as restrictToOwner, j as runConfiguredSessionJob, k as capturedJourneyScope, l as scanPreparedSession, m as openConfiguredUpload, n as verifyPreparedSessionSources, nt as makePrivateDirectory, o as createWorkPieces, ot as isWindowsAclFailure, p as configuredSessionUploads, q as readWorkspacePair, r as prepareSessionScans, rt as openPrivateFile, s as readSessionScanFields, st as windowsAclCodes, t as preparedScanConfiguration, v as readStaticSessionMasks, w as readConfiguredSearchFields, y as staticSessionJobs, z as gitSeedsProvider } from "./src-V9GHLZQs.mjs";
2
+ import { A as createExecutionPort, C as saveRemoteState, D as createPackagingProgressPort, E as exportDelivery, F as loadDeliveryResults, L as inBackgroundStoreLane, M as withStateMutex, N as createDeliveryService, O as createStore, P as preflight, R as isBackgroundStatusPoll, S as readRemoteState, T as collectRemoteWorkers, _ as staticBaseProduction, a as writeJourneyOutput, b as workApproval, c as mergeHideIndexTokens, f as writeJourneyBase, g as staticBaseInputs, h as staticSessions, l as packRenderHideIndex, m as saveStaticSession, o as createHideIndexTokens, p as readStaticResult, s as hideIndexTexts, t as journeyOutputJob, u as journeyBaseJob, v as readSelectedCaptures, w as journeyDirectory, x as isRemoteImport, y as prepareSourcePlan, z as retrySharingViolation } from "./job-BQXssW46.mjs";
3
3
  import { $t as safeField, Bt as sessionPeriodSchema, Dn as createStaticProcessor, Fn as entityDictionaryVersion, Ft as termTypeInfo, Gt as ownerProfileSchema, Kt as passportAddressSchema, Ot as privacyTermKey, Qt as safeCode, Sn as currentDetectorVersion, T as bLiteralTerms, Un as frameRecords, Wt as mergeOwnerProfile, Xt as ApplicationError, Zt as UnfinishedJourneyError, an as observeSource, ar as admitCustomTerm, c as textDigest, ir as createEntityMatcher, nn as reviewFamilies, or as admitGitName, qt as profileHasChoices, tn as familySelected, ur as ProcessingError, zt as filterInventoryByPeriod } from "./locate-BWkblijS.mjs";
4
- import { a as mainTextChunks, c as previewInWorker, i as nearestSortingRepository, l as createNativeAdapters, n as createProjectEvidenceCollector, o as mainTextFields, r as sortingRepositoryId, s as textChunks, t as createHarnesses, u as createGitNameSeedProvider } from "./src-BBjnljUs.mjs";
5
- import { $ as settingsBatchSchema, A as deviceAuthorizationSchema, Ar as staticReviewDigest, B as inspectionStartSchema, Br as sendResolutionSchema, Bt as classificationWorks, Ct as sendPrepareSchema, Dt as currentJourneyAdapters, Fn as bTermMatcher, Fr as agentSourcesSchema, Gn as retireWorkDescription, Gr as isReadingComplete, Hn as journeyConfirmedHides, Hr as hasCompleteWorkDescription, Ht as newJourneyWork, Ir as journeySendSchema, Jn as workCorrectionBinding, Kn as workDecisionDigest, Kr as isSelectedWork, Lr as sendArtifactSchema, M as profileUrlMatchesIdentity, N as readAccountAvatarUrl, O as createAccount, Ot as obsoleteJourney, P as storedCredentialSchema, Pr as agentSourceSchema, Pt as applyClassification, R as createApplication, Rr as sendReceiptSchema, St as sendChoiceSchema, Tr as privacyDecisionDigest, Tt as sendStartSchema, Ur as isClassifying, V as validateInspectionBatch, Vr as sendSettingsSchema, Vt as retireScanGeneration, W as inspectionQuerySchema, Wr as isIncludedWork, Yr as withReadingProgress, Yt as journeySearchResultSchema, Zt as searchScopeDigest, _ as changeJourney, _r as emptyPreparationFacts, _t as emptyTermsRevision, ai as selectionSchema, ar as scanPreparationDigest, bt as replaceSensitiveTermsSchema, cr as scanGitSeedsResource, et as settingsQuerySchema, ft as manualUploadChoiceSchema, h as hideScopeDigest, ht as manualUploadStartSchema, ii as selectionBatchSchema, j as deviceProfileScopeSchema, k as accountProfileSchema, kr as hasCurrentStaticReview, lr as verifiedScanGitSeeds, lt as validateFailureLocation, m as activeJourneyTerms, mt as manualUploadSchema, ni as commandSchema, or as scanSessionResourceSchema, pt as manualUploadPrepareSchema, ri as packageCommandSchema, rt as appendSensitiveTerms, si as producerVersion, sr as scanGitSeedsId, st as artifactFailureDetailSchema, ui as recommendParallelism, ur as scanExclusionResourceSchema, ut as manualUploadActionSchema, wr as assertJourneyPrivacyReady, wt as sendRequestSchema, xt as sendActionSchema, yt as normalizeSensitiveTerms, z as inspectionCancelSchema, zn as confirmedHideKinds, zr as sendReplaceResultSchema, zt as classificationPartition } from "./src-d7n58sbH.mjs";
6
- import { _t as isCoordinationBusy } from "./heap-DsE74_-n.mjs";
7
- import { t as createAgentSetupPort } from "./agent-setup-YlFIJz-h.mjs";
4
+ import { a as mainTextChunks, c as previewInWorker, i as nearestSortingRepository, l as createNativeAdapters, n as createProjectEvidenceCollector, o as mainTextFields, r as sortingRepositoryId, s as textChunks, t as createHarnesses, u as createGitNameSeedProvider } from "./src-BgsEnMsy.mjs";
5
+ import { $ as settingsBatchSchema, $r as isReadingComplete, A as deviceAuthorizationSchema, B as inspectionStartSchema, Bt as classificationWorks, Ct as sendPrepareSchema, Dt as currentJourneyAdapters, Fn as bTermMatcher, Gn as retireWorkDescription, Gr as sendArtifactSchema, Hn as journeyConfirmedHides, Hr as agentSourceSchema, Ht as newJourneyWork, Jn as workCorrectionBinding, Jr as sendResolutionSchema, Kn as workDecisionDigest, Kr as sendReceiptSchema, Lr as hasCurrentStaticReview, M as profileUrlMatchesIdentity, Mr as privacyDecisionDigest, N as readAccountAvatarUrl, O as createAccount, Or as displayedScopeDigest, Ot as obsoleteJourney, P as storedCredentialSchema, Pt as applyClassification, Qr as isIncludedWork, R as createApplication, Rr as staticReviewDigest, St as sendChoiceSchema, Tt as sendStartSchema, Ur as agentSourcesSchema, V as validateInspectionBatch, Vt as retireScanGeneration, W as inspectionQuerySchema, Wr as journeySendSchema, Xr as hasCompleteWorkDescription, Yr as sendSettingsSchema, Yt as journeySearchResultSchema, Zr as isClassifying, Zt as searchScopeDigest, _ as changeJourney, _r as emptyPreparationFacts, _t as emptyTermsRevision, ai as packageCommandSchema, ar as scanPreparationDigest, bt as replaceSensitiveTermsSchema, cr as scanGitSeedsResource, ei as isSelectedWork, et as settingsQuerySchema, fi as recommendParallelism, ft as manualUploadChoiceSchema, h as hideScopeDigest, ht as manualUploadStartSchema, ii as commandSchema, j as deviceProfileScopeSchema, jr as assertJourneyPrivacyReady, k as accountProfileSchema, kr as requestedScope, li as producerVersion, lr as verifiedScanGitSeeds, lt as validateFailureLocation, m as activeJourneyTerms, mt as manualUploadSchema, oi as selectionBatchSchema, or as scanSessionResourceSchema, pt as manualUploadPrepareSchema, qr as sendReplaceResultSchema, ri as withReadingProgress, rt as appendSensitiveTerms, si as selectionSchema, sr as scanGitSeedsId, st as artifactFailureDetailSchema, ur as scanExclusionResourceSchema, ut as manualUploadActionSchema, wt as sendRequestSchema, xt as sendActionSchema, yt as normalizeSensitiveTerms, z as inspectionCancelSchema, zn as confirmedHideKinds, zt as classificationPartition } from "./src-DzKuzGVH.mjs";
6
+ import { _t as isCoordinationBusy } from "./heap-Dt3-d27v.mjs";
7
+ import { t as createAgentSetupPort } from "./agent-setup-CODlN6zl.mjs";
8
8
  import { t as workerMessageSchema } from "./messages-D3m3bhva.mjs";
9
9
  import { constants, write } from "node:fs";
10
10
  import { z } from "zod";
@@ -2603,18 +2603,24 @@ function createJourneyPreparation(options) {
2603
2603
  const scanWorks = scanRequested && state.scope.status === "confirmed" ? state.works : [];
2604
2604
  if (scanWorks.length) run = await runWorkers(options.workers);
2605
2605
  const frozen = state;
2606
- const blockWork = (work, error) => changeJourney(storage, journeyId, "snapshot", (before) => {
2607
- if (before.phase === "paused") throw new ApplicationError("OPERATION_CANCELED");
2608
- if (before.phase === "sending" || before.phase === "completed") return before;
2609
- return withReadingProgress({
2610
- ...before,
2611
- works: before.works.map((item) => item.id === work.id && item.inputRevision === work.inputRevision && !item.blockedCodes.includes("PRIVACY_CHANGE_PENDING") ? {
2612
- ...item,
2613
- status: "blocked",
2614
- blockedCodes: blockedCodes(error, safeCode(error))
2615
- } : item)
2616
- });
2617
- }, 100);
2606
+ const blockedForRetry = new Set(state.works.filter((work) => work.status === "blocked").map((work) => `${work.id}:${work.inputRevision}`));
2607
+ const deferredForHide = /* @__PURE__ */ new Set();
2608
+ const blockWork = async (work, error) => {
2609
+ const blocked = await changeJourney(storage, journeyId, "snapshot", (before) => {
2610
+ if (before.phase === "paused") throw new ApplicationError("OPERATION_CANCELED");
2611
+ if (before.phase === "sending" || before.phase === "completed") return before;
2612
+ return withReadingProgress({
2613
+ ...before,
2614
+ works: before.works.map((item) => item.id === work.id && item.inputRevision === work.inputRevision && !item.blockedCodes.includes("PRIVACY_CHANGE_PENDING") ? {
2615
+ ...item,
2616
+ status: "blocked",
2617
+ blockedCodes: blockedCodes(error, safeCode(error))
2618
+ } : item)
2619
+ });
2620
+ }, 100);
2621
+ if (blocked.works.some((item) => item.id === work.id && item.inputRevision === work.inputRevision && item.status === "blocked")) blockedForRetry.add(`${work.id}:${work.inputRevision}`);
2622
+ return blocked;
2623
+ };
2618
2624
  const retryLimit = options.retryLimit ?? workRetryDelaysMs.length;
2619
2625
  const generation = (work) => `${work.id}:${work.inputRevision}`;
2620
2626
  let serialAdmission = Promise.resolve();
@@ -2638,11 +2644,14 @@ function createJourneyPreparation(options) {
2638
2644
  await (options.retryDelay ?? waitForWorkRetry)(delay, abort.signal);
2639
2645
  abort.signal.throwIfAborted();
2640
2646
  let resumed = false;
2641
- await changeJourney(storage, journeyId, "snapshot", (before) => {
2647
+ let deferred = false;
2648
+ const committed = await changeJourney(storage, journeyId, "snapshot", (before) => {
2642
2649
  resumed = false;
2650
+ deferred = false;
2643
2651
  const target = before.works.find((item) => item.id === work.id);
2644
2652
  if (before.phase === "sending" || before.phase === "completed" || before.phase === "paused" || !target || !isSelectedWork(target) || target.inputRevision !== work.inputRevision || target.status !== "blocked" || target.blockedCodes.includes("PRIVACY_CHANGE_PENDING")) return before;
2645
2653
  resumed = !before.pendingHideId;
2654
+ deferred = !resumed;
2646
2655
  return withReadingProgress({
2647
2656
  ...before,
2648
2657
  privacy: {
@@ -2656,6 +2665,7 @@ function createJourneyPreparation(options) {
2656
2665
  } : item)
2657
2666
  });
2658
2667
  }, 100);
2668
+ if (deferred && committed.pendingHideId && committed.works.some((item) => generation(item) === generation(work) && item.status === "pending")) deferredForHide.add(generation(work));
2659
2669
  return resumed;
2660
2670
  };
2661
2671
  const readRetries = /* @__PURE__ */ new Map();
@@ -2693,6 +2703,7 @@ function createJourneyPreparation(options) {
2693
2703
  "reading",
2694
2704
  "review"
2695
2705
  ].includes(work.status)) return false;
2706
+ blockedForRetry.delete(generation(work));
2696
2707
  prepared.add(generation(work));
2697
2708
  await prepareClassificationMetadata(storage, latest, work, options.processing, abort.signal, plan);
2698
2709
  let failures = collectPreparationFailures(plan.approval.inventory, work.rootSessionIds, {
@@ -2802,7 +2813,15 @@ function createJourneyPreparation(options) {
2802
2813
  abort.abort(error);
2803
2814
  };
2804
2815
  const statics = [];
2816
+ const priorStatics = /* @__PURE__ */ new Map();
2805
2817
  const reads = [];
2818
+ const activeReads = /* @__PURE__ */ new Set();
2819
+ const activeStatics = /* @__PURE__ */ new Set();
2820
+ let workSettled = Promise.withResolvers();
2821
+ const notifySettled = () => {
2822
+ workSettled.resolve();
2823
+ workSettled = Promise.withResolvers();
2824
+ };
2806
2825
  const pass = async (works) => {
2807
2826
  let submittedWorks = 0;
2808
2827
  const submitted = Promise.withResolvers();
@@ -2826,6 +2845,7 @@ function createJourneyPreparation(options) {
2826
2845
  releaseAdmission.set(planned.id, () => released.resolve());
2827
2846
  const onSubmitted = submission();
2828
2847
  const read = async () => {
2848
+ await priorStatics.get(planned.id);
2829
2849
  if (!run.pool) await previous;
2830
2850
  if (fatal) {
2831
2851
  onSubmitted();
@@ -2840,25 +2860,45 @@ function createJourneyPreparation(options) {
2840
2860
  onSubmitted();
2841
2861
  released.resolve();
2842
2862
  }
2843
- statics.push(retryContention(() => staticWork(planned, passSubmitted), (error) => options.onFailure(error), abort.signal).catch(stop));
2863
+ activeStatics.add(planned.id);
2864
+ const staticResult = retryContention(() => staticWork(planned, passSubmitted), (error) => options.onFailure(error), abort.signal).catch(stop).finally(() => {
2865
+ activeStatics.delete(planned.id);
2866
+ notifySettled();
2867
+ });
2868
+ priorStatics.set(planned.id, staticResult);
2869
+ statics.push(staticResult);
2844
2870
  };
2845
- reads.push(read());
2871
+ activeReads.add(planned.id);
2872
+ reads.push(read().finally(() => {
2873
+ activeReads.delete(planned.id);
2874
+ notifySettled();
2875
+ }));
2846
2876
  }
2847
2877
  await Promise.all(admissions);
2848
2878
  };
2849
- /** Selected Works this run has not prepared yet, waiting while grouping continues (E2). */
2879
+ /** Admit newly grouped and explicitly retried Works until both read and static work drain. */
2850
2880
  const later = async () => {
2851
2881
  for (;;) {
2852
2882
  abort.signal.throwIfAborted();
2883
+ const settled = workSettled.promise;
2853
2884
  const latest = await storage.current(journeyId);
2854
2885
  if (!latest || latest.phase === "paused" || latest.scope.status !== "confirmed") return [];
2886
+ for (const work of latest.works) if (work.status === "blocked") blockedForRetry.add(generation(work));
2855
2887
  const ready = latest.works.filter((work) => isSelectedWork(work) && [
2856
2888
  "pending",
2857
2889
  "reading",
2858
2890
  "review"
2859
- ].includes(work.status) && !prepared.has(`${work.id}:${work.inputRevision}`));
2860
- if (ready.length || !isClassifying(latest)) return ready;
2861
- await setTimeout$1(laterWorksPollMs, void 0, { signal: abort.signal }).catch(() => abort.signal.throwIfAborted());
2891
+ ].includes(work.status) && !activeReads.has(work.id) && !activeStatics.has(work.id) && !deferredForHide.has(generation(work)) && (!prepared.has(generation(work)) && !hasCurrentStaticReview(latest, work) || work.status === "pending" && blockedForRetry.has(generation(work))));
2892
+ if (ready.length || !isClassifying(latest) && !activeReads.size && !activeStatics.size) return ready;
2893
+ const polling = new AbortController();
2894
+ try {
2895
+ await Promise.race([settled, setTimeout$1(laterWorksPollMs, void 0, { signal: AbortSignal.any([abort.signal, polling.signal]) })]);
2896
+ } catch (error) {
2897
+ abort.signal.throwIfAborted();
2898
+ throw error;
2899
+ } finally {
2900
+ polling.abort();
2901
+ }
2862
2902
  }
2863
2903
  };
2864
2904
  try {
@@ -2971,7 +3011,16 @@ async function packageBase(storage, state, work, processing, directory, signal,
2971
3011
  if (after.phase === "paused") throw new ApplicationError("OPERATION_CANCELED");
2972
3012
  assertJourneyPrivacyReady(after, true);
2973
3013
  }
2974
- await assertCurrent();
3014
+ try {
3015
+ await assertCurrent();
3016
+ } catch (error) {
3017
+ await Promise.all([
3018
+ base.primary,
3019
+ base.companion,
3020
+ base.maskLedger
3021
+ ].map((file) => rm(file.path, { force: true })));
3022
+ throw error;
3023
+ }
2975
3024
  try {
2976
3025
  await storage.saveResource(base);
2977
3026
  return base;
@@ -7201,10 +7250,10 @@ function usesSessionSend(dependencies, send) {
7201
7250
  if (send.items.some((item) => item.sessionUpload !== void 0 || item.sessionMembership || item.sessionAssembly)) return true;
7202
7251
  return !send.items.some((item) => item.receipt || item.reservation || item.previousReceipts.length > 0);
7203
7252
  }
7204
- async function saveSend(dependencies, snapshot, next, action) {
7253
+ async function saveSend(dependencies, snapshot, next, action, expectedJourneyRevision = action?.expectedJourneyRevision ?? snapshot.journey.revision) {
7205
7254
  return dependencies.storage.commitSend({
7206
7255
  journeyId: snapshot.journey.journeyId,
7207
- expectedJourneyRevision: action?.expectedJourneyRevision ?? snapshot.journey.revision,
7256
+ expectedJourneyRevision,
7208
7257
  expectedSendRevision: action?.expectedSendRevision ?? (snapshot.send?.id === next.id ? snapshot.send.revision : null),
7209
7258
  requestKey: action?.idempotencyKey ?? randomUUID(),
7210
7259
  requestHash: hash$1(action ?? next),
@@ -9244,89 +9293,91 @@ const sendRecoveryCodes = [
9244
9293
  ];
9245
9294
  //#endregion
9246
9295
  //#region apps/cli/src/account/journey/request.ts
9247
- /** Artifact-independent authorization: packaging progress cannot expand this scope. */
9248
- function requestedScope(journey) {
9249
- return hash$1({
9250
- privacy: privacyDecisionDigest(journey),
9251
- configurationId: journey.configurationId,
9252
- confirmedHideRevision: journey.confirmedHideRevision ?? 0,
9253
- consent: journey.consent,
9254
- profile: journey.profile,
9255
- works: journey.works.map((work) => ({
9256
- id: work.id,
9257
- inputRevision: work.inputRevision,
9258
- access: work.access,
9259
- accessConfirmed: work.accessConfirmed,
9260
- included: isIncludedWork(work),
9261
- placement: work.placement,
9262
- suggestion: work.suggestion
9263
- }))
9264
- });
9265
- }
9266
9296
  function requestMatches(send, journey) {
9267
9297
  return send.request?.scopeDigest === requestedScope(journey) && !journey.pendingHideId && journey.phase !== "paused" && !journey.abandonedAt;
9268
9298
  }
9269
9299
  async function requestSend(dependencies, raw, hostId, source) {
9270
9300
  const input = sendRequestSchema.parse(raw);
9271
- const current = await dependencies.storage.loadSend(input.journeyId);
9272
- if (!current) throw new ApplicationError("UNKNOWN_ITEM");
9273
- const recorded = current.send?.id === input.idempotencyKey ? current : await dependencies.storage.loadSend(input.journeyId, input.idempotencyKey);
9274
- if (recorded?.send) return dependencies.storage.commitSend({
9275
- journeyId: input.journeyId,
9276
- expectedJourneyRevision: input.expectedJourneyRevision,
9277
- expectedSendRevision: null,
9278
- requestKey: input.idempotencyKey,
9279
- requestHash: hash$1(input),
9280
- state: recorded.send,
9281
- at: dependencies.now()
9282
- });
9283
- if (current.journey.revision !== input.expectedJourneyRevision) return {
9284
- ...current,
9285
- status: "stale"
9286
- };
9287
- assertJourneyPrivacyReady(current.journey);
9288
- if (current.journey.pendingHideId || current.journey.phase === "paused") throw new ApplicationError("SCOPE_NOT_READY");
9289
- if (current.send && ([
9290
- "awaiting-packaging",
9291
- "sending",
9292
- "waiting",
9293
- "sign-in",
9294
- "review"
9295
- ].includes(current.send.status) || current.send.items.some((item) => item.recoveryReview) || current.send.status === "paused" && current.send.confirmedAt !== null && current.send.scopeDigest === scopeDigest(current.journey))) throw new ApplicationError("INVALID_TRANSITION");
9296
- if (!hostId) throw new ApplicationError("INVALID_TRANSITION");
9297
- const included = current.journey.works.filter(isIncludedWork);
9298
- if (!sameIds$1(input.included.map((work) => work.workId), included.map((work) => work.id)) || !input.included.every((item) => included.some((work) => work.id === item.workId && work.access === item.access && work.accessConfirmed)) || !sameIds$1(input.omittedWorkIds, current.journey.works.filter((work) => !isIncludedWork(work)).map((work) => work.id))) throw new ApplicationError("CONFIRMATION_REQUIRED");
9299
- const subject = (await dependencies.auth.connect(new AbortController().signal))?.subject ?? null;
9300
- const at = dependencies.now();
9301
- return dependencies.storage.commitSend({
9302
- journeyId: input.journeyId,
9303
- expectedJourneyRevision: input.expectedJourneyRevision,
9304
- expectedSendRevision: null,
9305
- requestKey: input.idempotencyKey,
9306
- requestHash: hash$1(input),
9307
- state: {
9308
- id: input.idempotencyKey,
9301
+ let expectedScope = input.displayedScopeDigest;
9302
+ let binding;
9303
+ let firstSendId = null;
9304
+ for (let attempt = 0;; attempt += 1) {
9305
+ const current = await dependencies.storage.loadSend(input.journeyId);
9306
+ if (!current) throw new ApplicationError("UNKNOWN_ITEM");
9307
+ if (attempt === 0) firstSendId = current.send?.id ?? null;
9308
+ const recorded = current.send?.id === input.idempotencyKey ? current : await dependencies.storage.loadSend(input.journeyId, input.idempotencyKey);
9309
+ if (recorded?.send) return dependencies.storage.commitSend({
9309
9310
  journeyId: input.journeyId,
9310
- revision: 0,
9311
- scopeDigest: requestedScope(current.journey),
9312
- subject,
9313
- confirmedAt: null,
9314
- status: "awaiting-packaging",
9315
- items: [],
9316
- omitted: [],
9317
- error: null,
9318
- request: {
9319
- requestedAt: at,
9320
- subject,
9321
- hostId,
9322
- source,
9311
+ expectedJourneyRevision: input.expectedJourneyRevision,
9312
+ expectedSendRevision: null,
9313
+ requestKey: input.idempotencyKey,
9314
+ requestHash: hash$1(input),
9315
+ state: recorded.send,
9316
+ at: dependencies.now()
9317
+ });
9318
+ if (attempt > 0 && (current.send?.id ?? null) !== firstSendId) return {
9319
+ ...current,
9320
+ status: "stale"
9321
+ };
9322
+ if (expectedScope === void 0) {
9323
+ if (current.journey.revision !== input.expectedJourneyRevision) return {
9324
+ ...current,
9325
+ status: "stale"
9326
+ };
9327
+ expectedScope = displayedScopeDigest(current.journey);
9328
+ }
9329
+ if (displayedScopeDigest(current.journey) !== expectedScope) return {
9330
+ ...current,
9331
+ status: "stale"
9332
+ };
9333
+ assertJourneyPrivacyReady(current.journey);
9334
+ if (current.journey.pendingHideId || current.journey.phase === "paused") throw new ApplicationError("SCOPE_NOT_READY");
9335
+ if (current.send && ([
9336
+ "awaiting-packaging",
9337
+ "sending",
9338
+ "waiting",
9339
+ "sign-in",
9340
+ "review"
9341
+ ].includes(current.send.status) || current.send.items.some((item) => item.recoveryReview) || current.send.status === "paused" && current.send.confirmedAt !== null && scopeDigest(current.journey) === current.send.scopeDigest)) throw new ApplicationError("INVALID_TRANSITION");
9342
+ if (!hostId) throw new ApplicationError("INVALID_TRANSITION");
9343
+ const included = current.journey.works.filter(isIncludedWork);
9344
+ if (!sameIds$1(input.included.map((work) => work.workId), included.map((work) => work.id)) || !input.included.every((item) => included.some((work) => work.id === item.workId && work.access === item.access && work.accessConfirmed)) || !sameIds$1(input.omittedWorkIds, current.journey.works.filter((work) => !isIncludedWork(work)).map((work) => work.id))) throw new ApplicationError("CONFIRMATION_REQUIRED");
9345
+ if (!binding) binding = {
9346
+ subject: (await dependencies.auth.connect(new AbortController().signal))?.subject ?? null,
9347
+ at: dependencies.now()
9348
+ };
9349
+ const { subject, at } = binding;
9350
+ const result = await dependencies.storage.commitSend({
9351
+ journeyId: input.journeyId,
9352
+ expectedJourneyRevision: current.journey.revision,
9353
+ expectedSendRevision: null,
9354
+ requestKey: input.idempotencyKey,
9355
+ requestHash: hash$1(input),
9356
+ state: {
9357
+ id: input.idempotencyKey,
9358
+ journeyId: input.journeyId,
9359
+ revision: 0,
9323
9360
  scopeDigest: requestedScope(current.journey),
9324
- included: input.included,
9325
- omittedWorkIds: input.omittedWorkIds
9326
- }
9327
- },
9328
- at
9329
- });
9361
+ subject,
9362
+ confirmedAt: null,
9363
+ status: "awaiting-packaging",
9364
+ items: [],
9365
+ omitted: [],
9366
+ error: null,
9367
+ request: {
9368
+ requestedAt: at,
9369
+ subject,
9370
+ hostId,
9371
+ source,
9372
+ scopeDigest: requestedScope(current.journey),
9373
+ included: input.included,
9374
+ omittedWorkIds: input.omittedWorkIds
9375
+ }
9376
+ },
9377
+ at
9378
+ });
9379
+ if (result.status !== "stale" || attempt === 1) return result;
9380
+ }
9330
9381
  }
9331
9382
  /**
9332
9383
  * Previously sent Works with unchanged access remain part of the displayed authorization. Keep
@@ -9488,7 +9539,7 @@ function createJourneySender(dependencies, phases = 3, host = {
9488
9539
  const snapshot = await dependencies.storage.loadSend(input.journeyId);
9489
9540
  sessionFacts.retain(input.journeyId, snapshot?.send ?? null);
9490
9541
  if (!snapshot) throw new ApplicationError("UNKNOWN_ITEM");
9491
- if (snapshot.journey.revision !== input.expectedJourneyRevision) return {
9542
+ if (input.displayedScopeDigest ? displayedScopeDigest(snapshot.journey) !== input.displayedScopeDigest : snapshot.journey.revision !== input.expectedJourneyRevision) return {
9492
9543
  ...snapshot,
9493
9544
  status: "stale"
9494
9545
  };
@@ -9530,7 +9581,7 @@ function createJourneySender(dependencies, phases = 3, host = {
9530
9581
  await connection.assertCurrent(signal);
9531
9582
  }
9532
9583
  }
9533
- const canReuseExistingSend = !(snapshot.send?.confirmedAt && ["blocked", "paused"].includes(snapshot.send.status)) && !recover && snapshot.send?.scopeDigest === draft.scopeDigest && snapshot.send.subject === draft.subject;
9584
+ const canReuseExistingSend = !(snapshot.send?.confirmedAt && ["blocked", "paused"].includes(snapshot.send.status)) && !recover && snapshot.send && scopeDigest(snapshot.journey) === snapshot.send.scopeDigest && snapshot.send.subject === draft.subject;
9534
9585
  const next = pending ? {
9535
9586
  ...draft,
9536
9587
  id: pending.id,
@@ -9542,7 +9593,7 @@ function createJourneySender(dependencies, phases = 3, host = {
9542
9593
  } : draft;
9543
9594
  const result = await dependencies.storage.commitSend({
9544
9595
  journeyId: input.journeyId,
9545
- expectedJourneyRevision: input.expectedJourneyRevision,
9596
+ expectedJourneyRevision: snapshot.journey.revision,
9546
9597
  expectedSendRevision: pending?.revision ?? (canReuseExistingSend && snapshot.send ? snapshot.send.revision : null),
9547
9598
  requestKey: input.idempotencyKey,
9548
9599
  requestHash: hash$1(input),
@@ -9555,7 +9606,12 @@ function createJourneySender(dependencies, phases = 3, host = {
9555
9606
  async start(raw, signal) {
9556
9607
  const input = sendStartSchema.parse(raw);
9557
9608
  const snapshot = await load(input);
9558
- if (!matchesAction(snapshot, input)) return saveSend(dependencies, snapshot, snapshot.send, input);
9609
+ if (snapshot.send.revision !== input.expectedSendRevision || !input.displayedScopeDigest && snapshot.journey.revision !== input.expectedJourneyRevision) return saveSend(dependencies, snapshot, snapshot.send, input);
9610
+ if (input.displayedScopeDigest && displayedScopeDigest(snapshot.journey) !== input.displayedScopeDigest) return {
9611
+ ...snapshot,
9612
+ status: "stale"
9613
+ };
9614
+ const saveStart = (next) => saveSend(dependencies, snapshot, next, input, snapshot.journey.revision);
9559
9615
  if (pendingElsewhere(snapshot.send)) return {
9560
9616
  ...snapshot,
9561
9617
  status: "applied"
@@ -9564,7 +9620,7 @@ function createJourneySender(dependencies, phases = 3, host = {
9564
9620
  if (snapshot.send.request && !snapshot.send.confirmedAt && (authorizationError || !requestMatches(snapshot.send, snapshot.journey))) return block(snapshot, snapshot.send, authorizationError ?? "REVISION_CONFLICT");
9565
9621
  assertScope(snapshot.journey, snapshot.send);
9566
9622
  if (!sameIds$1(input.confirmedWorkIds, snapshot.send.items.map((item) => item.workId)) || !sameIds$1(input.confirmedOmittedWorkIds, snapshot.send.omitted.map((item) => item.workId)) || input.scopeDigest !== snapshot.send.scopeDigest || snapshot.send.items.length === 0) throw new ApplicationError("CONFIRMATION_REQUIRED");
9567
- if (snapshot.send.confirmedAt !== null) return saveSend(dependencies, snapshot, snapshot.send, input);
9623
+ if (snapshot.send.confirmedAt !== null) return saveStart(snapshot.send);
9568
9624
  const connection = await dependencies.auth.connect(signal);
9569
9625
  if (snapshot.send.request && (connection?.subject ?? null) !== snapshot.send.request.subject) return saveSend(dependencies, snapshot, {
9570
9626
  ...snapshot.send,
@@ -9580,18 +9636,18 @@ function createJourneySender(dependencies, phases = 3, host = {
9580
9636
  if (connection) try {
9581
9637
  profile = await prepareProfile(dependencies, snapshot, connection, signal);
9582
9638
  } catch (error) {
9583
- if (error instanceof ApplicationError && error.code === "REVISION_CONFLICT") return saveSend(dependencies, snapshot, snapshot.send, input);
9639
+ if (error instanceof ApplicationError && error.code === "REVISION_CONFLICT") return saveStart(snapshot.send);
9584
9640
  throw error;
9585
9641
  }
9586
9642
  signal.throwIfAborted();
9587
9643
  const finalAuthorizationError = await requestError(dependencies, snapshot.send, hostId, signal);
9588
9644
  if (finalAuthorizationError) return block(snapshot, snapshot.send, finalAuthorizationError);
9589
- return saveSend(dependencies, snapshot, {
9645
+ return saveStart({
9590
9646
  ...snapshot.send,
9591
9647
  subject: connection?.subject ?? snapshot.send.subject,
9592
9648
  confirmedAt: snapshot.send.request && !connection ? null : dependencies.now(),
9593
9649
  ...profile
9594
- }, input);
9650
+ });
9595
9651
  },
9596
9652
  async respond(raw) {
9597
9653
  const input = sendChoiceSchema.parse(raw);
@@ -1,7 +1,7 @@
1
1
  import { ln as sessionSchema } from "./locate-BWkblijS.mjs";
2
2
  import { t as createZstdFrameCheck$1 } from "./frame-Dj5Zs6UW.mjs";
3
- import "./src-d7n58sbH.mjs";
4
- import { a as isRecord } from "./model-f_QnDyyb.mjs";
3
+ import "./src-DzKuzGVH.mjs";
4
+ import { a as isRecord } from "./model-CSx2dP_P.mjs";
5
5
  import { constants } from "node:fs";
6
6
  import { z } from "zod";
7
7
  import { lstat, open, stat } from "node:fs/promises";
@@ -1,7 +1,7 @@
1
1
  import { Bn as nativeItems, En as walkNativeFields, Nn as parseNativeRecord, Rn as nativeBoolean, Vn as nativeText, Wn as retainedMainTextNodes, Xn as defaultLimits, an as observeSource, on as sourceSnapshotId, ur as ProcessingError, zn as nativeField } from "./locate-BWkblijS.mjs";
2
- import { At as nativeAdapterVersions, nt as reviewInventory, oi as gitMetadataBudgetBytes } from "./src-d7n58sbH.mjs";
3
- import { a as isRecord, i as errorCode, n as checkDiscoveryAbort, o as unresolvedMetadata, r as discoveryBounds, t as DiscoveryWarnings } from "./model-f_QnDyyb.mjs";
4
- import { c as previewLimits, d as checkOpenSource, f as checkSource, h as openSource, i as pageFits, l as previewSourceVersion, m as noSymlinks, p as fileSnapshot, r as previewHeapLimits, s as previewMessageSchema, u as createZstdFrameCheck } from "./run-RA_8zZsL.mjs";
2
+ import { At as nativeAdapterVersions, ci as gitMetadataBudgetBytes, nt as reviewInventory } from "./src-DzKuzGVH.mjs";
3
+ import { a as isRecord, i as errorCode, n as checkDiscoveryAbort, o as unresolvedMetadata, r as discoveryBounds, t as DiscoveryWarnings } from "./model-CSx2dP_P.mjs";
4
+ import { c as previewLimits, d as checkOpenSource, f as checkSource, h as openSource, i as pageFits, l as previewSourceVersion, m as noSymlinks, p as fileSnapshot, r as previewHeapLimits, s as previewMessageSchema, u as createZstdFrameCheck } from "./run-xlOaKCk8.mjs";
5
5
  import { a as titleHintLimits, n as titleHeapLimits, o as titleInputSchema, r as decodeTitleError, s as titleReplySchema } from "./heap-1FYhGds4.mjs";
6
6
  import { constants } from "node:fs";
7
7
  import { lstat, open, opendir, readFile, readdir, realpath, stat } from "node:fs/promises";