patchsift
v0.1.1
Published
Reduce a Git diff to an observed 1-minimal failure-reproducing patch.
Maintainers
Readme
PatchSift
Thu gọn diff Git đã commit thành một bản vá nhỏ vẫn tái hiện đúng một lỗi cụ thể.
Trạng thái: PatchSift
0.1.1đã được phát hành trên npm. Dòng phiên bản0.1.xhiện tại gồm CLI, entrypoint thư viện không có side effect, JSON report có phiên bản, demo xác định, setup hook, cleanup worktree cũ và release gate.
PatchSift khác git bisect như thế nào?
git bisect trả lời commit nào bắt đầu gây lỗi? PatchSift trả lời những
thay đổi nào bên trong diff giữa hai snapshot là cần thiết để tái hiện lỗi?
git bisect PatchSift
────────── ─────────
Tìm trong lịch sử commit Tìm trong các unit của một endpoint diff
Trả về một commit Trả về bản vá tối giản có thể chia sẻ
Cần các commit good/bad Cần base PASS và target MATCH
Không tách nội dung commit Tách file text đã sửa thành các hunkPatchSift báo cáo observed 1-minimality, không khẳng định đã tìm ra bản vá
nhỏ nhất toàn cục. observed-1-minimal nghĩa là công cụ đã thử bỏ riêng từng
unit cuối cùng và không phép bỏ nào còn tái hiện lỗi. Nếu có phép thử không thể
kết luận, kết quả được ghi là best-found-unresolved.
Yêu cầu
- Node.js 22 trở lên.
- Git 2.25 trở lên.
- macOS hoặc Linux.
- Git worktree sạch và không phải bare repository.
- Lệnh oracle có tính xác định.
PatchSift không có runtime npm dependency.
Cài đặt và build
Cài CLI từ public npm registry:
npm install --global [email protected]
patchsift --versionĐể build cùng phiên bản đó từ mã nguồn:
npm ci --ignore-scripts
npm run build
node dist/cli.js --helpQuy trình build chỉ xóa thư mục dist/ thật bên trong repository trước khi
chạy TypeScript. Có thể kiểm tra đúng npm artifact mà không cần publish:
npm run pack:check
npm run test:consumers
npm run test:packedBắt đầu nhanh
Lệnh dưới đây giả định revision base chạy thành công và revision target in ra
Expected total: 1201 rồi thoát với mã khác 0:
patchsift minimize \
--base good-revision \
--target bad-revision \
--match-literal "Expected total: 1201" \
-- npm test -- pricing.test.tsAPI thư viện
Root của package là thư viện ESM không có side effect và đi kèm declaration.
Các đường dẫn module nội bộ không được export; chỉ import từ patchsift. API
lập trình cung cấp cùng minimization engine và thao tác cleanup có guard như
CLI, với run context và progress event rõ ràng.
import {
PATCHSIFT_VERSION,
minimize,
} from "patchsift";
import type { MinimizeOptions } from "patchsift";
const options: MinimizeOptions = {
repository: process.cwd(),
base: "demo-good",
target: "demo-bad",
oracle: { command: process.execPath, args: ["test-pricing.mjs"] },
matcher: {
kind: "literal",
text: "Expected total: 1201",
stream: "stderr",
},
timeoutMs: 30_000,
artifacts: {
patchPath: "./patchsift-min.patch",
reportPath: "./patchsift-report.json",
},
};
const result = await minimize(options, {
environment: { PATCHSIFT_DEMO: "1" },
onProgress(event) {
if (event.type === "warning") console.warn(event.message);
},
});
console.log(PATCHSIFT_VERSION, result.minimality, result.retainedUnitIds);Các runtime export chính xác là minimize, cleanup, PatchSiftError,
PATCHSIFT_VERSION và REPORT_SCHEMA_VERSION. Literal matcher dùng text;
regular-expression matcher dùng pattern cùng flags tùy chọn.
MinimizeOptions bắt buộc có repository và mô tả base, target, matcher, oracle,
giới hạn cùng artifact path tùy chọn. Mỗi run ưu tiên bộ nhớ: bỏ artifacts để
không ghi file và nhận verified patch cùng report trong kết quả trả về.
Nếu được cung cấp, artifacts phải yêu cầu patch path, report path hoặc cả hai.
RunContext cung cấp environment overlay, abort signal và progress callback
tùy chọn. Callback trả về Promise được await tuần tự; context không thay đổi
working directory của repository. Kết quả còn chứa minimality, exit code,
retained unit ID và các artifact path đã yêu cầu ghi.
Dùng cleanup({ repository, olderThanMs, dryRun }) để kiểm tra hoặc xóa các
owned worktree cũ bằng API.
Target mặc định là HEAD. PatchSift ghi artifact vào:
<repository>/.patchsift/runs/<run-id>/
├── minimal.patch
└── report.jsonTiến trình dành cho người đọc được ghi vào stderr. Dùng --json - để stdout
chỉ chứa JSON dành cho máy.
CLI
patchsift minimize
--base <revision>
[--target <revision>]
(--match-literal <text> |
--match-regex <pattern> [--regex-flags <imsu>])
[--match-stream either|stdout|stderr]
[--timeout <Nms|Ns|Nm|Nh>]
[--max-output <NB|NKiB|NMiB>]
[--setup <posix-shell-command>]
[--output <patch-path>]
[--json <report-path|->]
[--force]
[--quiet]
[--no-color]
-- <program> [arguments...]
patchsift cleanup [--older-than <duration>] [--dry-run] [--quiet]
patchsift --help
patchsift --versionHành vi quan trọng:
--match-literaltìm chuỗi chính xác và phân biệt hoa thường.--match-regexdùng JavaScript regular expression. Flags mặc định làu; chỉ chấp nhậni,m,s,u. Regex chạy trong worker có deadline để backtracking xấu không thể làm treo CLI.- stdout và stderr được kiểm tra riêng.
eitherkhông nối hai stream. --timeoutmặc định5mvà tối đa24h.--max-outputmặc định 8 MiB tổng cộng và tối đa 64 MiB.cleanup --older-thanchấp nhậnms,s,m,h,d; mặc định là24hvà tối đa365d.- Oracle sau
--được spawn trực tiếp bằng argv, không qua shell. --setupchủ động dùng/bin/sh -c; nó chạy sau khi áp dụng từng candidate và trước oracle tương ứng.--forcechỉ thay một artifact regular chưa được Git track. Nó không bỏ qua kiểm tra repository, symlink hoặc quyền sở hữu worktree.
Ví dụ dùng regex và cài dependency:
patchsift minimize \
--base main \
--target HEAD \
--match-regex "Expected total: 12[0-9]{2}" \
--regex-flags u \
--setup "npm ci --ignore-scripts" \
-- npm test -- pricing.test.tsCác kết quả của oracle
PatchSift không xem mọi exit khác 0 là bằng chứng lỗi mục tiêu vẫn tồn tại.
| Quan sát process | Kết quả |
| --- | --- |
| Exit 0 | PASS, kể cả khi output chứa matcher |
| Exit khác 0 và có đúng signature | MATCH |
| Exit khác 0 nhưng không có signature | UNRESOLVED/different-failure |
| Hết thời gian | UNRESOLVED/timeout |
| Bị signal | UNRESOLVED/signal |
| Vượt giới hạn output | UNRESOLVED/output-limit |
| Regex worker quá deadline | UNRESOLVED/matcher-timeout |
| Candidate không qua git apply --check | UNRESOLVED/invalid-patch |
| Setup thất bại | UNRESOLVED/setup-failed |
Chỉ MATCH cho phép minimizer loại thay đổi. Base preflight bắt buộc là PASS
và toàn bộ endpoint diff bắt buộc là MATCH.
Cách hoạt động
- Phân giải base và target đúng một lần thành commit object ID bất biến.
- Từ chối source worktree bẩn và metadata diff chưa được hỗ trợ.
- Tạo endpoint-tree diff canonical UTF-8.
- Xem mỗi hunk của file sửa là một unit; file thêm/xóa là unit atomic.
- Xác minh render toàn bộ unit khôi phục chính xác canonical diff.
- Tạo detached worktree ở base với ownership marker.
- Preflight candidate rỗng và candidate đầy đủ.
- Chạy
ddmintheo complement trước và cache kết quả xác định. - Restart lượt bỏ từng unit mỗi khi tìm thấy thêm một unit có thể bỏ.
- Sinh patch từ index của worktree xác minh mới, apply lại và chạy oracle mà không dùng candidate cache.
- Ghi atomic patch đã xác minh và JSON report có version.
Base và target không cần quan hệ ancestor. PatchSift thu gọn khác biệt tree của hai endpoint và kiểm tra trực tiếp hành vi của chúng.
Các loại thay đổi được hỗ trợ
Bản hiện tại hỗ trợ:
- các hunk trong regular text file UTF-8 đã sửa;
- regular text file UTF-8 được thêm/xóa dưới dạng atomic; và
- mode regular
100644và100755.
Công cụ từ chối rename/copy, binary, mode transition, symlink, submodule, combined diff, conflict, UTF-8 không hợp lệ và endpoint diff từ 64 MiB trở lên. Đây là giới hạn an toàn rõ ràng, không phải fallback âm thầm.
Mô hình an toàn
PatchSift không reset hoặc clean worktree của người dùng. Candidate chạy trong thư mục tạm có ownership marker liên kết run ID, base SHA, Git common directory, PID và real path chính xác. Mọi reset/clean/remove phá hủy dữ liệu đều xác minh lại marker trước.
Oracle chạy trong POSIX process group riêng. Khi timeout, PatchSift gửi
SIGTERM, chờ một giây rồi gửi SIGKILL theo best effort. SIGINT và
SIGTERM hủy lệnh đang chạy và kích hoạt cleanup.
Sau SIGKILL, crash hoặc mất điện, hãy xem trước khi dọn:
patchsift cleanup --dry-run
patchsift cleanup --older-than 24hCleanup chỉ xem xét temporary worktree không còn hoạt động, có ownership marker
hợp lệ và thuộc repository hiện tại. Công cụ không bao giờ tự chạy
git worktree prune trên toàn repository.
PatchSift chạy mã repository đáng tin bằng quyền của người dùng. Git worktree không phải security sandbox. Hãy đọc SECURITY.md trước khi chạy với mã lạ.
JSON report
Mọi report dùng schemaVersion: 1. Contract đã đóng băng và được phân phối tại
schemas/report-v1.json, đồng thời qua package subpath
patchsift/schemas/report-v1.json. Một report chứa:
- phiên bản tool/run, thời gian, status và exit code;
- input và SHA base/target đã đóng băng cùng hash full patch;
- oracle argv, matcher, setup, timeout và output limit;
- số unit ban đầu/còn lại cùng counter process/cache;
- ID unit xác định, path, hunk range, hash và trạng thái retained;
- phase của từng candidate, unit IDs, outcome, duration và cache hit;
- minimality cuối, unresolved removals và path/hash/size artifact.
Raw stdout và stderr không bao giờ được lưu. Report chỉ chứa số byte, SHA-256, metadata exit/signal và kết quả phân loại.
Exit codes
| Code | Ý nghĩa |
| ---: | --- |
| 0 | Patch observed-1-minimal đã được xác minh |
| 1 | Lỗi nội bộ không mong đợi |
| 2 | CLI hoặc cấu hình output không hợp lệ |
| 3 | Repository, unsupported diff hoặc preflight thất bại |
| 4 | Patch best-found-unresolved đã được xác minh |
| 5 | Fresh final verification thất bại |
| 130 / 143 | Bị ngắt bởi SIGINT / SIGTERM |
Demo “The Banker's Penny”
Demo xác định có đúng 14 text hunk trong 14 file. Mười hai hunk là thay đổi gây nhiễu trung tính. Hai hunk bắt buộc đổi rounding mode trong config và khiến mã pricing bắt đầu áp dụng config đó. Mỗi hunk đứng riêng đều PASS; kết hợp lại tạo:
Expected total: 1201
Received total: 1200Chạy demo cục bộ:
npm run build
node scripts/create-demo.mjs /tmp/patchsift-demo
cd /tmp/patchsift-demo
patchsift minimize \
--base demo-good \
--target demo-bad \
--match-literal "Expected total: 1201" \
-- node test-pricing.mjsAcceptance test yêu cầu literal và regex cùng giữ đúng hai hunk, hoàn tất dưới 60 giây và không quá 40 lần chạy oracle.
Phát triển
npm run typecheck
npm test
npm run test:coverage
npm run docs:check
npm run schema:check
npm run metadata:check
npm run test:consumers
npm run test:packed
npm run pack:check
npm run release:checkrelease:check chỉ chạy cục bộ và không publish. Lệnh xác minh metadata cùng
tính tương ứng của tài liệu EN/VI, chạy toàn bộ test, compile consumer
JavaScript và TypeScript từ tarball, kiểm tra packed CLI bằng cả hai matcher và
audit allowlist của tarball.
Bộ test bao phủ parser diff, file thêm/xóa, no-newline marker, Unicode path, tương tác ddmin, candidate unresolved, direct argv, timeout, output cap, regex worker, ownership guard, cleanup, JSON stdout, dirty-source rejection và toàn bộ demo 14→2.
Xem CONTRIBUTING.md để biết các invariant phải giữ.
Lộ trình
Cột mốc kế tiếp tập trung vào thu gọn phân cấp file → hunk → edit-group hoặc line. Xem lộ trình tiếng Anh hoặc lộ trình tiếng Việt để biết các cột mốc sau và phần được hoãn.
Giấy phép
MIT © 2026 MilkyVic.
