@adeu/core 1.17.2 → 1.18.1
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.cjs +250 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +250 -87
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/engine.bugs.test.ts +12 -14
- package/src/engine.feedback.test.ts +34 -2
- package/src/engine.issue23.test.ts +23 -18
- package/src/engine.ts +359 -98
- package/src/reject_and_nested_redline.test.ts +137 -0
- package/src/repro.report.test.ts +11 -9
- package/src/repro_qa_report_v3.test.ts +19 -27
- package/src/repro_report_boundary_failures.test.ts +108 -0
package/package.json
CHANGED
package/src/engine.bugs.test.ts
CHANGED
|
@@ -418,7 +418,7 @@ describe("Resolved Bugs Core Engine Verification", () => {
|
|
|
418
418
|
expect(pTarget.parentNode).toBeNull();
|
|
419
419
|
});
|
|
420
420
|
|
|
421
|
-
it("BUG-EXPLORE-2:
|
|
421
|
+
it("BUG-EXPLORE-2: a strict edit inside a foreign author's insertion applies (nested change)", async () => {
|
|
422
422
|
const doc = await createTestDocument();
|
|
423
423
|
addParagraph(doc, "Original baseline.");
|
|
424
424
|
|
|
@@ -432,20 +432,18 @@ describe("Resolved Bugs Core Engine Verification", () => {
|
|
|
432
432
|
},
|
|
433
433
|
]);
|
|
434
434
|
|
|
435
|
-
// Author B
|
|
435
|
+
// Author B modifies Author A's pending insertion — this now applies: the
|
|
436
|
+
// enclosing <w:ins> is split and Author B's change nested inside it.
|
|
436
437
|
const engineB = new RedlineEngine(doc, "Author B");
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
}).toThrowError(
|
|
447
|
-
/Accept that change first or scope your edit outside of it/,
|
|
448
|
-
);
|
|
438
|
+
const result = engineB.process_batch([
|
|
439
|
+
{
|
|
440
|
+
type: "modify",
|
|
441
|
+
target_text: "Inserted by A.",
|
|
442
|
+
new_text: "Modified by B.",
|
|
443
|
+
},
|
|
444
|
+
]);
|
|
445
|
+
expect(result.edits_applied).toBe(1);
|
|
446
|
+
expect(result.edits_skipped).toBe(0);
|
|
449
447
|
});
|
|
450
448
|
|
|
451
449
|
it("BUG-CROSS-PARA-1: Cross-paragraph modify coalesces paragraphs and tracks para-mark deletion", async () => {
|
|
@@ -31,7 +31,11 @@ describe("Feedback Layer & Dry Run Verification", () => {
|
|
|
31
31
|
expect(stats.version).toBeDefined();
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
it("punctuation anchor
|
|
34
|
+
it("punctuation anchor: no warning on clean apply", async () => {
|
|
35
|
+
// A punctuated anchor that matches and applies cleanly must NOT raise the
|
|
36
|
+
// tokenization-splitting warning. The redline preview already reports the
|
|
37
|
+
// change; a warning here is a false positive that pushes agents into
|
|
38
|
+
// needless "cleaner anchor" retries.
|
|
35
39
|
const doc = await createTestDocument();
|
|
36
40
|
addParagraph(doc, "Refer to sample_term_name in Section 4.");
|
|
37
41
|
const engine = new RedlineEngine(doc, "Reviewer TS");
|
|
@@ -41,9 +45,37 @@ describe("Feedback Layer & Dry Run Verification", () => {
|
|
|
41
45
|
]);
|
|
42
46
|
|
|
43
47
|
const report = stats.edits[0];
|
|
48
|
+
expect(report.status).toBe("applied");
|
|
49
|
+
expect(report.warning).toBeNull();
|
|
50
|
+
|
|
51
|
+
// Same expectation under dry_run.
|
|
52
|
+
const doc2 = await createTestDocument();
|
|
53
|
+
addParagraph(doc2, "Refer to sample_term_name in Section 4.");
|
|
54
|
+
const engine2 = new RedlineEngine(doc2, "Reviewer TS");
|
|
55
|
+
const dryStats = (engine2 as any).process_batch([
|
|
56
|
+
{ type: "modify", target_text: "sample_term_name", new_text: "validated_term_name" }
|
|
57
|
+
], true);
|
|
58
|
+
const dryReport = dryStats.edits[0];
|
|
59
|
+
expect(dryReport.status).toBe("applied");
|
|
60
|
+
expect(dryReport.warning).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("punctuation anchor: warns only when match fails", async () => {
|
|
64
|
+
// When a punctuated anchor fails to match, the warning IS surfaced as
|
|
65
|
+
// recovery context (the punctuation may be why the match missed).
|
|
66
|
+
const doc = await createTestDocument();
|
|
67
|
+
addParagraph(doc, "Refer to sample_term_name in Section 4.");
|
|
68
|
+
const engine = new RedlineEngine(doc, "Reviewer TS");
|
|
69
|
+
|
|
70
|
+
const stats = (engine as any).process_batch([
|
|
71
|
+
{ type: "modify", target_text: "phantom_term-x", new_text: "anything" }
|
|
72
|
+
], true);
|
|
73
|
+
|
|
74
|
+
const report = stats.edits[0];
|
|
75
|
+
expect(report.status).toBe("failed");
|
|
44
76
|
expect(report.warning).not.toBeNull();
|
|
45
77
|
expect(report.warning.toLowerCase()).toContain("punctuation");
|
|
46
|
-
expect(report.warning).toContain("
|
|
78
|
+
expect(report.warning).toContain("phantom_term-x");
|
|
47
79
|
});
|
|
48
80
|
|
|
49
81
|
it("dry_run does not mutate and reports safely", async () => {
|
|
@@ -422,31 +422,36 @@ describe("BUG-23-4: multi-paragraph target_text must produce actionable feedback
|
|
|
422
422
|
}
|
|
423
423
|
});
|
|
424
424
|
|
|
425
|
-
it("BUG-23-4-NN:
|
|
425
|
+
it("BUG-23-4-NN: applies balanced plain-paragraph N->N modifications per paragraph, preserving the boundary", async () => {
|
|
426
426
|
const doc = await createTestDocument();
|
|
427
427
|
addParagraph(doc, "Clause 1 ends here.");
|
|
428
428
|
addParagraph(doc, "Clause 2 begins here.");
|
|
429
429
|
|
|
430
430
|
const engine = new RedlineEngine(doc, "Test Author");
|
|
431
431
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
432
|
+
// Both target and replacement carry the same number of \n\n breaks, so the
|
|
433
|
+
// paragraph structure is preserved. The engine splits this into one sub-edit
|
|
434
|
+
// per paragraph and applies it as a single logical edit. (Unbalanced
|
|
435
|
+
// merges/splits are still rejected — see the regex case in engine.qa.test.)
|
|
436
|
+
const result = engine.process_batch([
|
|
437
|
+
{
|
|
438
|
+
type: "modify",
|
|
439
|
+
target_text: "ends here.\n\nClause 2 begins",
|
|
440
|
+
new_text: "ends here. MERGED\n\nClause 2 begins CHANGED",
|
|
441
|
+
},
|
|
442
|
+
]);
|
|
444
443
|
|
|
445
|
-
expect(
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
444
|
+
expect(result.edits_applied).toBe(1);
|
|
445
|
+
expect(result.edits_skipped).toBe(0);
|
|
446
|
+
|
|
447
|
+
const buf = await doc.save();
|
|
448
|
+
const text = await extractTextFromBuffer(buf);
|
|
449
|
+
// The paragraph boundary must survive — the two clauses are NOT merged.
|
|
450
|
+
expect(text).not.toContain("ends here.Clause 2 begins");
|
|
451
|
+
expect(text).not.toContain("ends here. Clause 2 begins");
|
|
452
|
+
// Both per-paragraph insertions land.
|
|
453
|
+
expect(text).toContain("MERGED");
|
|
454
|
+
expect(text).toContain("CHANGED");
|
|
450
455
|
});
|
|
451
456
|
});
|
|
452
457
|
|