feat(fields): --time-format sets the default time-field format (config phase D4b) - #109
Merged
Conversation
…g phase D4b)
Add --time-format=NAME, the companion to --timezone: it sets the default format
for a time field rendered without an explicit {:qualifier}. Respected in every
style (it is a global, never gated by the find-style filter).
- RenderContext/EvalContext carry time_format; the four time-field renderers use
it when the {field} has no qualifier, and an explicit {mtime:iso} still wins.
- run.cc resolves the last --time-format (last wins; any value accepted verbatim -
an unknown name renders literally, like printf) and threads it to the
implicit-print template and the -exec/-execdir/-capture field contexts.
Also resolves the #71 open decision: the modern default time format stays `space`
(human-first, matches ls long-iso / git iso, sortable); --time-format makes that a
soft choice (rfc3339 is one flag, or one .xffrc line, away). TODO.md updated.
Tests: fields_test (a bare {mtime} honors time_format=epoch, falls back to "space"
with none, and an explicit {mtime:%Y} qualifier wins), run_test (end to end,
--time-format=epoch --template={mtime} renders all-digit Unix seconds via
ElementsAre). Green in both configs; clang-format + em-dash clean.
helly25
enabled auto-merge (squash)
June 23, 2026 23:44
helly25
added a commit
that referenced
this pull request
Jul 6, 2026
…280) * docs(TODO): give #109, smart-case, and #84 their own TODO.md entries These three were tracked only in the session task list / memory with no TODO.md home. Add roadmap-tail bullets so TODO.md is complete: - Hash-verification workflow (#109) [DISCUSS] - -eval matcher + read-into-var + --summary tallies; the hashing primitives already shipped (#105). - Smart-case matching (--smart-case) [DISCUSS] - rg/fd convention; sequence before the flavor feature-map help row. - Sharded-file support (#84) TBD - needs a design pass. Fold in a correction: the old 'Per-file content hashes' bullet was stale - the {hash} field + -hash action shipped in #105 (fields.cc, registry.cc); its only still-open aspect (verify/match) is now the #109 entry. * docs(TODO): promote the --sort/-j CLI bashtest to its own bullet It was a sub-clause buried in the (shipped) #43 parallel-traversal bullet, so it had no findable standalone location. Give it its own roadmap-tail bullet and point the #43 record at it, so every tracked item maps to its own line.
helly25
added a commit
that referenced
this pull request
Aug 9, 2026
Add the `-verify EXPECTED` predicate: TRUE when the file's computed digest
equals EXPECTED, a {field} template rendered per entry - the manifest-
verification companion of -hash. So:
xff . -type f -verify {def.SUMS} # list files matching their manifest
xff . -type f ! -verify {def.SUMS} # list drift / corruption
`-verify=ALGO[/ENCODING]` shares the -hash spec grammar (sha256/hex default;
sha1/sha512/md5, hex/base64); hex comparison folds case (sha256sum lowercases,
SRI-style tools upper-case) while base64 stays case-sensitive. Style::kXff, so
the find style rejects it; a bad spec is a pre-walk usage error.
Wiring mirrors -cmp (arity-1 field-template target) + -hash (kHash binding);
the parser's kHash =SPEC branch now consumes the descriptor's arity operands
so `-verify=sha256 EXPECTED` parses. ValidateHashArgs covers -verify too.
Tests: xff/cli/verify_test.sh (match/mismatch, {def.X} source, hex case-fold,
ALGO/ENCODING selectors, `! -verify` drift, bad-spec + find-style errors).
Regenerated XFF.md; CHANGELOG + TODO updated. --summary tallies deferred to a
follow-up slice.
helly25
added a commit
that referenced
this pull request
Aug 9, 2026
* feat(#109): --summary=hash dedup grouping mode Add `--summary=hash` as a first-class summary mode: groups matches by file digest, so identical files collapse into one bucket and the count column reads as a dedup histogram. Reuses the {hash} field renderer (default sha256/hex), so it cannot drift from the field value - the same pattern as --summary=mime/user/group. Equivalent to the already-working --summary={hash} template, now named and documented. Tests: summary_test.sh asserts two identical files share one digest bucket (count 2) via --format=jsonl. Regenerated XFF.md; CHANGELOG + TODO updated. * chore: drop issue-number references from CHANGELOG CHANGELOG is user-facing release notes; internal issue numbers (#NNN) are noise there. Remove them from the 0.2.0 entries.
helly25
added a commit
that referenced
this pull request
Aug 9, 2026
helly25
added a commit
that referenced
this pull request
Aug 9, 2026
* docs(#109): park the single-pass verify tally as a deferred refinement The -hasheq matcher and --summary=hash dedup grouping cover the practical hash-verification workflow. A one-pass verified/failed tally needs the per-entry verdict threaded thread-safely through the reduction feed (parallel walk / tsan); parked with that note until a concrete need appears. * docs(#109): mark hash-verification workflow done
helly25
added a commit
that referenced
this pull request
Aug 9, 2026
* docs(#109): park the single-pass verify tally as a deferred refinement The -hasheq matcher and --summary=hash dedup grouping cover the practical hash-verification workflow. A one-pass verified/failed tally needs the per-entry verdict threaded thread-safely through the reduction feed (parallel walk / tsan); parked with that note until a concrete need appears. * docs(#109): mark hash-verification workflow done * feat(#169): MemorySanitizer via an instrumented libc++, Linux CI cell MSan catches reads of uninitialized memory that asan does not. The one real prerequisite is an instrumented C++ standard library: MSan false-positives on anything it did not instrument, and while every other dep builds from source under bazel (so -fsanitize=memory reaches it), libc++ ships prebuilt inside the hermetic LLVM. - tools/build_msan_libcxx.sh builds libc++/libc++abi/libunwind from the LLVM source release matching bazelmod/llvm.MODULE.bazel's llvm_version, with -DLLVM_USE_SANITIZER=MemoryWithOrigins and the hermetic clang as compiler, into .msan-libcxx/ (gitignored). It stamps the prefix with version+script hash so a cached tree is reused, and skips cleanly on non-Linux. - .bazelrc --config=msan mirrors asan/tsan and swaps the runtime in via -nostdinc++ -isystem .../include/c++/v1 and -nostdlib++ -L... -Wl,-rpath,... - CI gains one ubuntu `msan` cell (never macOS: MSan has no macOS support) with the instrumented libc++ cached on the LLVM version + script hash. It starts continue-on-error while first findings are triaged - the same introduction path the clang-tidy cell took - then becomes a hard gate. Also folds the ratified archive control surface into the docs so nothing is left open before that work starts: --archive[=none|roots|all] + -z/-z+/-z- with find -> none and the xff family -> roots, dual container identity, --archive-depth=1, sniff-gating, and the pre-implementation "not yet implemented" guard. Rewrites the stale smart-case entry (it shipped as --case=smart/-s, not a boolean), and resolves the remaining design.md TBDs (PCRE2 spelling is --regextype=PCRE2; the VFS seam is built, remote backends stay post-v1). * fix(#169): runtimes build needs llvm-lit off / present The first msan CI run failed at cmake configure: the runtimes CMakeLists add_subdirectory()s llvm/utils/llvm-lit for its check targets, which the partial source extraction did not include. Turn the test machinery off (-DLLVM_INCLUDE_TESTS=OFF; we only want the libraries) and extract llvm/utils as well so the path exists either way. * fix(#169): extract the whole LLVM source release for the runtimes build Second configure/compile failure from the hand-picked extraction: libcxx's from_chars_floating_point.h includes shared/fp_bits.h, which lives under libc/, just as the earlier failure needed llvm/utils/llvm-lit. Picking directories is a losing game - each attempt only surfaces the next missing one - so extract the whole source release. It costs seconds, the tree is discarded afterwards, and what CI caches is the INSTALLED runtimes, not the sources. * fix(#169): wire msan into the done gate The done job asserts that EVERY declared workflow job is listed in its needs - a guard against adding a job that silently is not gated - and adding msan without wiring it tripped exactly that check. msan belongs in needs like the rest: the gate step only inspects the needs KEY SET, never the results, and a continue-on-error job cannot fail the run. So listing it restores the completeness invariant while a red msan still cannot block a merge, which is the whole point of introducing it report-only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Config phase D4b:
--time-format+ #71 resolvedAdds
--time-format=NAME, the companion to--timezone: it sets the default format for a time field rendered without an explicit{:qualifier}. Respected in every style - it is a global, so it never reaches the find-style filter (per the "find stays loose" call).What
RenderContext/EvalContextcarrytime_format; the four time-field renderers ({atime}/{mtime}/{ctime}/{btime}) use it when the field has no qualifier. An explicit{mtime:iso}qualifier always wins.run.ccresolves the last--time-format(last wins; any value is accepted verbatim - an unknown name renders literally, like printf, so nothing to reject) and threads it to the implicit-print template and the three-exec/-execdir/-capturefield contexts.Resolves #71 (default time format)
Per discussion, the modern default stays
space(2026-06-22 14:30:00 +0100): human-first (matches GNUls --time-style=long-isoandgit log --date=iso), ISO-ordered so it sorts, and parseable back byParseTimeString.--time-formatmakes this a soft choice -rfc3339is one flag (--time-format=rfc3339) or one.xffrcline away, and machine consumers use--format=jsonl. TODO.md updated to record the resolution.Test
fields_test: a bare{mtime}renders withtime_format=epoch, falls back tospacewhen unset, and an explicit{mtime:%Y}qualifier wins over the default.run_test: end to end,--time-format=epoch --template={mtime}renders all-digit Unix seconds (asserted viaElementsAre(Not(HasSubstr("-")))- one matcher folds the count + content).bazel test //...green in both--config=clangand--config=clang --config=asan. clang-format + em-dash clean.