Repository navigation
feat(L171): journal commits made where no vault is mounted - #77
Merged
Merged
Conversation
The reconciler walks history and describes repositories it only points at, so the two places that assume "the commit is HEAD" and "the folder is where I am" have to take those as arguments instead. - extract CommitSaver::from_commit, so a row can be built for any commit rather than only the one HEAD points at - take the branch as an argument: a commit made months ago has no branch of its own to report, so the caller has to say - split append_row_to_diary out of append_entry_to_diary, so the FOLDER column can come from the repository rather than from the process - no behaviour change: the hook path still reads HEAD and still reports the current directory, and the existing suite covers it unchanged Co-Authored-By: Vulcan <chess7th@pm.me>
The hook resolves a note path and makes sure the file exists, inline in run_commit_saver. The reconciler needs exactly those two steps, so they become named functions rather than a second copy. - add CommitSaver::diary_path_for, which resolves the absolute note path from the COMMIT'S timestamp rather than the clock - add ensure_diary_file, which creates the note from the template only when it is missing and reports whether it did - run_commit_saver calls both instead of open-coding them - no behaviour change: same path, same template, same append, and the existing suite covers it unchanged Co-Authored-By: Vulcan <chess7th@pm.me>
D-98 ruled two paths to the journal and this is the second one: a pass that reads a repository's history and appends whatever row the day note is missing. It needs no broker and no network, so it works on the day the wire is down and on the day the wire does not exist yet. - add reconcile_repo, walking HEAD's history oldest commit first - identity is the row's COMMIT HASH column, so a row the hook already wrote is recognised and never written twice - the dedup rule D-98 named as the thing that must be exactly right - read the hash from the LAST cell, so an escaped pipe in the commit message cannot be mistaken for a column boundary - only ever append: existing bytes in a note are never rewritten, reordered or reformatted - a row lands in the note for the COMMIT'S own date, never today's, so a backfill cannot collapse a month of history into one note - honour the exclude list, which until now bound only the hook path - add reconcile_all, which reports a repository it cannot open and carries on to the next rather than abandoning the run - read each day note once per pass, however many rows it gains Twelve tests, one per claim above, including the two-pass proof that the second run appends nothing and leaves the note byte-identical. Co-Authored-By: Vulcan <chess7th@pm.me>
The reconciler existed and nothing could reach it. This is the entry point: a flag that turns the same binary into the backstop pass, so the vault box can run it on a schedule. - add --reconcile <PATH>, repeatable, naming the repositories to walk - add --since <YYYY-MM-DD>, so a nightly pass need not re-read history a first backfill already covered - the flag opts IN: with no --reconcile the binary behaves exactly as every installed post-commit hook already expects - a --since the tool cannot read stops the run and names both the shape it wanted and the value it got, rather than silently backfilling years from a typo in a timer unit - one stdout line per repository, because an unattended pass that appended nothing must look different from one that never ran Proven end to end through the real binary: a commit made in a repository the run is not standing in reaches the vault, and the repository the run IS standing in is left alone. Co-Authored-By: Vulcan <chess7th@pm.me>
- describe --reconcile: what it is for, how to run it, what its output means on a scheduled run - state its four guarantees where a user will look for them: append only, the commit's own date, hash identity, and the exclude list - add a build-and-test section, and record that `devenv shell` needs a checkout at $HOME/devenv_shared that the repository does not carry, while `nix develop` needs nothing outside it - warn that the flake shell's rustfmt defaults to a different style edition, so formatting there without --style-edition=2024 reflows files it should not touch Co-Authored-By: Vulcan <chess7th@pm.me>
The gate returned green with seven non-blocking findings. Four are closed here; the fifth is documented rather than fixed, and two are left as they are with the reason recorded. - looks_like_object_id had a ceiling of 40. That reads as correct against SHA-1 and is a trap: a SHA-256 repository writes 64-character ids, none of them would match, and every pass would stop recognising its own rows and append duplicates for ever - the one outcome the dedup rule exists to prevent. The floor alone already excludes the header and the rule line, which is all the ceiling ever did. Test added for a 64-character id. - the note-set lookup used expect() on a key it had just inserted. The entry API says the same thing without a panic path, and removes the second lookup. - prepare_commit_entry_as_string was widened to pub(crate) for a caller that never materialised. Private again. - run_commit_saver took its vault root by value and no longer consumes it, so it takes &Path. That was the last warning this lane added: clippy::pedantic is now down to the five that predate it. - the docs said the pass reads "a repository's history" when it reads what HEAD can reach. That gap bites in exactly this fleet's workflow - a commit on an unmerged lane branch is not journalled, and a squash-merge makes it unreachable for good. Swept in all five places that said it: the module doc, reconcile_repo's doc, the crate doc, the README feature line and the README section. NOT taken, and why: widening the walk to every local branch changes what belongs in the journal rather than fixing a defect, so it is a decision and not mine to make here. An unborn HEAD reported as an unopenable repository, and --since ignored without --reconcile, are both real and both cosmetic; they go to the follow-up rather than growing this lane after its gate. Co-Authored-By: Vulcan <chess7th@pm.me> Verify-Round: 1 Verify-Class: docs claiming the pass sees more than HEAD reaches - swept in all five places
Round 2 was red, and correctly: the previous commit asserted the claim had been swept in five places and left three standing, one of them in src/. Closing a documentation-honesty finding with an overstatement about its own scope is the same defect wearing the fix's clothes. The three the round named: - run_reconcile's doc still said "it reads history", the sixth site and the one the count missed - the README's opening sentence still said "a repository's history". The last commit appended a corrective blockquote below it instead of editing it, so the section asserted the claim and contradicted itself four lines later - the example comment said "every commit ever made in these repositories", three lines under the blockquote denying it Two more the round did not name, found by sweeping for the idea rather than for the sentence it quoted: - --reconcile's own --help text said the binary "does not touch HEAD", which is the opposite of true: the reconcile path reads each named repository's HEAD. It meant "does not journal the repository it was started in", and now says that - a test comment carried the same "every commit ever made" And one claim of a different kind, corrected because the round measured it: looks_like_object_id's comment said a SHA-256 repository would make the pass append duplicates for ever. The git2 this crate builds against refuses to open such a repository at all, so that harm is not reachable today. Removing the ceiling is still right - it protected nothing the floor does not - but the comment now says what was measured rather than what sounded convincing. Co-Authored-By: Vulcan <chess7th@pm.me> Verify-Round: 2 Verify-Class: docs and help text claiming coverage wider than HEAD-reachable - swept by idea, not by quoted string
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
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.
Lane L171. D-98 ruled two paths to the commit journal; the hook was the first
and this is the second.
Why
The post-commit hook can only write the journal on a machine that mounts the
vault. Everywhere else the row is lost — and once the config was copied onto
those machines it started being lost silently, which is worse: a journal that
quietly stops looks exactly like a quiet week.
What
--reconcile <PATH>turns the same binary into a backstop pass. It reads thehistory each named checkout's
HEADcan reach and appends whatever row the daynote is missing. No broker, no network — so it works on the day the wire is
down, and on the day the wire does not exist yet.
What it guarantees
reformatted.
the months it actually happened in.
row the hook already wrote is recognised. A second pass appends nothing and
leaves every note byte-identical.
[exclude]list applies here too — it previously bound only the hookpath.
does not stop the others catching up.
What it does not do
It sees only what
HEADreaches. A commit on an unmerged branch is notjournalled, and a squash-merge makes it unreachable for good. Widening the walk
to every local branch changes what belongs in the journal rather than fixing a
defect, so it is left as a decision rather than taken here. Documented in the
README and in the module docs.
Scope
No broker or wire code — that half was split to its own lanes.
Cargo.tomlandCargo.lockare untouched;clapwas already a dependency.The first two commits are pure refactors with no behaviour change, verified line
by line: they take the commit and the folder as arguments so a row can be built
for a commit that is not
HEAD, from a directory that is not the process's.Verification
Three independent blind review rounds. Round 1 green with non-blocking findings;
round 2 red on documentation and fixed; round 3 green. The gate —
cargo test(171),
cargo clippy -W pedantic,cargo build --release,cargo fmt --check,nix fmt -- --ci— is clean, and the lane adds no clippy warning of its own.🤖 Generated with Claude Code
https://claude.ai/code/session_01XMq7vQufRBhJqD2yBJoR54