From 26c94eb3db62ec6eebbf8d22c11afe691d9520c4 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Sun, 13 Sep 2026 02:31:32 +0200 Subject: krino: release 0.0.1 — man pages, install, examples, cross and release, README, changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also: undo removes the directories its run created; a hardlink is never a duplicate of its own other name; a flag written before "undo" is honoured; --version prints no leading v. Duplicate conditions with different scopes not sharing an original is documented as a known limitation. --- docs/design.md | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) (limited to 'docs') diff --git a/docs/design.md b/docs/design.md index 8e4e914..9a15425 100644 --- a/docs/design.md +++ b/docs/design.md @@ -1,6 +1,6 @@ # krino design -Status: draft for review, 2026-09-11. Target release: **0.0.1**. +Status: describes krino 0.0.1, 2026-09-13. krino (from Greek κρίνω, "to separate, to judge, to decide") sorts files in chosen directories by rules. A rule tests a file's type, name, path, size, @@ -216,12 +216,22 @@ Candidates are the scanned files plus, for `(duplicate "DIR"...)`, every regular file under those directories (symlinks skipped). Files are grouped by size. Only groups of two or more are hashed: first the first and last 64 KiB, then SHA-256 of the whole file. Empty files are never duplicates. +Two names for the same file — the same device and inode, as a hardlink +creates — are never duplicates of each other; they may still both be +duplicates of a separate identical file. The **original** in each group is, in order of preference: a file under one of the given DIRs, then the oldest by mtime, then the shortest name, then the name that sorts first. `(duplicate)` is true for every other scanned file in the group. +`(duplicate)` conditions with different scopes do not share an original: +two conditions electing from different candidate sets can each treat a +different file as the original of the same content, and within one +directory's rules this can select every copy in a group for deletion. A +run-wide election that keeps at least one copy of every group is not in +0.0.1. + ## 6. Content extraction | Format | Method | @@ -427,9 +437,10 @@ not logged; declined files are. ## 10. Undo - `krino log` lists recent runs: id, time, directories, counts. -- `krino undo` reverses the most recent run that has not been undone, in - every directory it touched; `krino undo RUN` a specific one. Undo runs - cannot themselves be undone. +- `krino undo` reverses the most recent run, in every directory it + touched; if that run is itself an undo run, it is refused. An older run + is undone by naming it: `krino undo RUN`. Undo runs cannot themselves be + undone. - Undo builds a plan like any other, shown and approved the same way (`-y` and `-n` apply). @@ -526,17 +537,19 @@ Rules for the GUI to come: - Measured before release on a real downloads directory of a few hundred files, about half of them PDFs, and reported in the release notes. **No performance target for 0.0.1.** Measured throughput is dominated by the - external extractors, not by krino: on a real folder of 265 files, 164 of them - needing `pdftotext` at roughly 80 ms each, a full plan takes 12-17 s, while a - synthetic tree of 4405 files needing no extraction takes 1.09 s. A single - threshold would therefore describe poppler's speed and the shape of one - folder rather than anything about krino, and would fail or pass for reasons - outside its control. Report the measurement; promise nothing. `make bench` - runs the Go benchmarks on generated trees. + external extractors, not by krino: on a real folder of about 265 files, 164 + of them needing `pdftotext` at roughly 80 ms each, full plans measured + between about 13 and 20 s across runs, while a synthetic tree of 4405 files + needing no extraction takes 1.09 s. A single threshold would therefore + describe poppler's speed and the shape of one folder rather than anything + about krino, and would fail or pass for reasons outside its control. + Report the measurement; promise nothing. `make bench` runs the Go + benchmarks on generated trees. ## 14. Build, dependencies, release -- Go 1.24 or newer. `CGO_ENABLED=0`: static binaries. +- Go 1.24 or newer. `CGO_ENABLED=0`: static binaries on Linux and FreeBSD; + on OpenBSD Go links against the system libc, as that platform requires. - Go dependencies: `golang.org/x/term` (key-at-a-time input) and `golang.org/x/text` (Unicode normalisation for `fold`). Everything else is the standard library, including the s-expression reader and the gitignore @@ -571,8 +584,7 @@ Repository contents for 0.0.1: `README.md` (60-second quickstart), `LICENSE`, `CHANGELOG.md`, `Makefile`, `go.mod`, `cmd/`, `internal/`, `scripts/`, `man/krino.1`, `man/krino.conf.5`, `docs/design.md`, `docs/sexp-primer.md`, `examples/` (by type, invoices by tax number with -placeholder numbers, screenshots by date, cleaning up old installers), -`testdata/`. +placeholder numbers, screenshots by date, cleaning up old installers). ## 15. Testing @@ -583,8 +595,10 @@ placeholder numbers, screenshots by date, cleaning up old installers), path against `git check-ignore --no-index` (skipped if git is absent). - **Conditions:** truth tables; a property test that random condition trees give the same result with and without cost reordering. -- **Extraction:** small fixtures in `testdata/` for each format; PDF and - legacy-format tests skip when the tool is missing. +- **Extraction:** the tests generate their fixtures in temporary + directories and use fake tools for PDF and the legacy formats (doc, xls, + ppt); the real `pdftotext` test skips when the tool is missing. Real + office-suite files and real legacy-tool runs are not tested in 0.0.1. - **Plan, apply, undo:** in temporary directories: build a tree, plan, apply, check; undo; check the tree is identical to the start (paths, contents, modes, mtimes). A cross-filesystem move test runs when a tmpfs is @@ -629,8 +643,9 @@ keyword. Its defects shaped these decisions: remote is chosen, `go mod edit -module ` and one `sed` over the `"krino/internal/...` imports rename it; nothing else depends on it. `go install ...@v0.0.1` works only after that. -2. **License: GPL-3.0-or-later.** Full text in `LICENSE`; every source file - carries `// SPDX-License-Identifier: GPL-3.0-or-later`. +2. **License: GPL-3.0-or-later.** Full text in `LICENSE`; every Go file, + shell script and man page carries an + `SPDX-License-Identifier: GPL-3.0-or-later` line. ## Appendix A: type groups -- cgit v1.3