@fern-api/replay 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -210,6 +210,31 @@ declare class ReplayDetector {
210
210
  readonly warnings: string[];
211
211
  constructor(git: GitClient, lockManager: LockfileManager, sdkOutputDir: string);
212
212
  detectNewPatches(): Promise<DetectionResult>;
213
+ /**
214
+ * FER-10201 — Non-linear-history detection via `merge-base(prevGen, HEAD)`.
215
+ *
216
+ * After a squash-merge of a Fern-bot PR, `lastGen.commit_sha` (the previous
217
+ * `[fern-generated]`) is orphaned but still in git's object database. The
218
+ * merge-base is the commit on main from which the bot's branch was created —
219
+ * a reachable ancestor of HEAD. Walking that range and classifying each
220
+ * commit via `isGenerationCommit` mirrors the linear path and eliminates
221
+ * the bug class where pipeline-driven changes (autoversion, replay,
222
+ * generation) get bundled as customer customizations.
223
+ *
224
+ * Falls through to the legacy composite path when no common ancestor exists
225
+ * (truly disjoint history — orphan branches with no shared root).
226
+ */
227
+ private detectPatchesViaMergeBase;
228
+ /**
229
+ * FER-10201 — Walk `${rangeStart}..HEAD`, classify each commit, emit one
230
+ * `StoredPatch` per customer commit. Body shared by the linear path
231
+ * (rangeStart = lastGen.commit_sha) and the merge-base path.
232
+ *
233
+ * Patch `base_generation` is always `lastGen.commit_sha` — the
234
+ * lockfile-tracked reference the applicator uses to fetch base file
235
+ * content, regardless of where the walk actually started.
236
+ */
237
+ private detectPatchesInRange;
213
238
  /**
214
239
  * Compute content hash for deduplication.
215
240
  *
package/dist/index.d.ts CHANGED
@@ -210,6 +210,31 @@ declare class ReplayDetector {
210
210
  readonly warnings: string[];
211
211
  constructor(git: GitClient, lockManager: LockfileManager, sdkOutputDir: string);
212
212
  detectNewPatches(): Promise<DetectionResult>;
213
+ /**
214
+ * FER-10201 — Non-linear-history detection via `merge-base(prevGen, HEAD)`.
215
+ *
216
+ * After a squash-merge of a Fern-bot PR, `lastGen.commit_sha` (the previous
217
+ * `[fern-generated]`) is orphaned but still in git's object database. The
218
+ * merge-base is the commit on main from which the bot's branch was created —
219
+ * a reachable ancestor of HEAD. Walking that range and classifying each
220
+ * commit via `isGenerationCommit` mirrors the linear path and eliminates
221
+ * the bug class where pipeline-driven changes (autoversion, replay,
222
+ * generation) get bundled as customer customizations.
223
+ *
224
+ * Falls through to the legacy composite path when no common ancestor exists
225
+ * (truly disjoint history — orphan branches with no shared root).
226
+ */
227
+ private detectPatchesViaMergeBase;
228
+ /**
229
+ * FER-10201 — Walk `${rangeStart}..HEAD`, classify each commit, emit one
230
+ * `StoredPatch` per customer commit. Body shared by the linear path
231
+ * (rangeStart = lastGen.commit_sha) and the merge-base path.
232
+ *
233
+ * Patch `base_generation` is always `lastGen.commit_sha` — the
234
+ * lockfile-tracked reference the applicator uses to fetch base file
235
+ * content, regardless of where the walk actually started.
236
+ */
237
+ private detectPatchesInRange;
213
238
  /**
214
239
  * Compute content hash for deduplication.
215
240
  *
package/dist/index.js CHANGED
@@ -708,17 +708,57 @@ var ReplayDetector = class {
708
708
  }
709
709
  const isAncestor = await this.git.isAncestor(lastGen.commit_sha, "HEAD");
710
710
  if (!isAncestor) {
711
+ return this.detectPatchesViaMergeBase(lastGen, lock);
712
+ }
713
+ return this.detectPatchesInRange(lastGen.commit_sha, lastGen, lock);
714
+ }
715
+ /**
716
+ * FER-10201 — Non-linear-history detection via `merge-base(prevGen, HEAD)`.
717
+ *
718
+ * After a squash-merge of a Fern-bot PR, `lastGen.commit_sha` (the previous
719
+ * `[fern-generated]`) is orphaned but still in git's object database. The
720
+ * merge-base is the commit on main from which the bot's branch was created —
721
+ * a reachable ancestor of HEAD. Walking that range and classifying each
722
+ * commit via `isGenerationCommit` mirrors the linear path and eliminates
723
+ * the bug class where pipeline-driven changes (autoversion, replay,
724
+ * generation) get bundled as customer customizations.
725
+ *
726
+ * Falls through to the legacy composite path when no common ancestor exists
727
+ * (truly disjoint history — orphan branches with no shared root).
728
+ */
729
+ async detectPatchesViaMergeBase(lastGen, lock) {
730
+ let mergeBase = "";
731
+ try {
732
+ mergeBase = (await this.git.exec(["merge-base", lastGen.commit_sha, "HEAD"])).trim();
733
+ } catch {
734
+ }
735
+ if (!mergeBase) {
736
+ this.warnings.push(
737
+ `No common ancestor between previous generation ${lastGen.commit_sha.slice(0, 7)} and HEAD. Falling back to composite tree-diff detection.`
738
+ );
711
739
  return this.detectPatchesViaTreeDiff(
712
740
  lastGen,
713
741
  /* commitKnownMissing */
714
742
  false
715
743
  );
716
744
  }
745
+ return this.detectPatchesInRange(mergeBase, lastGen, lock);
746
+ }
747
+ /**
748
+ * FER-10201 — Walk `${rangeStart}..HEAD`, classify each commit, emit one
749
+ * `StoredPatch` per customer commit. Body shared by the linear path
750
+ * (rangeStart = lastGen.commit_sha) and the merge-base path.
751
+ *
752
+ * Patch `base_generation` is always `lastGen.commit_sha` — the
753
+ * lockfile-tracked reference the applicator uses to fetch base file
754
+ * content, regardless of where the walk actually started.
755
+ */
756
+ async detectPatchesInRange(rangeStart, lastGen, lock) {
717
757
  const log = await this.git.exec([
718
758
  "log",
719
759
  "--first-parent",
720
760
  "--format=%H%x00%an%x00%ae%x00%s",
721
- `${lastGen.commit_sha}..HEAD`,
761
+ `${rangeStart}..HEAD`,
722
762
  "--",
723
763
  this.sdkOutputDir
724
764
  ]);