Skip to content

feat(toolbox): reconcile by the age of the last one, not the hour - #12

Merged
jshvn merged 1 commit into
mainfrom
josh/reconcile-by-age
Sep 23, 2026
Merged

jshvn merged 1 commit into
mainfrom
josh/reconcile-by-age

Conversation

@jshvn

@jshvn jshvn commented Sep 23, 2026

Copy link
Copy Markdown
Member

Why

reconcile was due only in the run that started in hour 03 UTC. The schedule lives in katoptra/dispatch and moves. tlnet's slot left 03:30 on 2026-09-09, and every run since has logged Task "reconcile" is up to date. The last sweep was a manual RECONCILE=true on 09-09.

What

  • The toolbox owns the rule.
    • due pulls .state/reconciled through the engine's pull. The key holds the start epoch of the run that last completed a reconcile.
    • It leaves .run/reconcile once that time is RECONCILE_HOURS old (default 24; a mirror overrides it in root vars), or when none is on record.
    • The mark is half an hour short: a daily run starts seconds either side of 24 h after the last, and a strict mark would reconcile every other day.
    • RECONCILE=true forces a reconcile and false skips one.
    • Any other RECONCILE, and any hour count that is not a whole number from 1, stops the run. A leading zero would be read as octal.
  • reconciled records the run's start through push.
  • clock writes only the epoch and clears a stale .run/reconcile. Nothing can key on the hour any more.
  • The rsync engine:
    • runs due after clock;
    • gates reconcile on the flag;
    • holds the reconcile while batches still wait, because delete would hold the orphans back and the chained run that lands the last batch should sweep;
    • records the reconcile as its last step.

The next minor release, v2.2.0. The first run on each rsync mirror after the tag moves reconciles, because no marker exists yet. ctan's takes about 7 minutes.

Test plan

  • examples/rsync: task check and task run -- task offline, from a clean .run. New cases:
    • auto with no marker, at 23 h 50 min and at under 3 h;
    • RECONCILE_HOURS=2;
    • true and false;
    • refusals for RECONCILE=yes and RECONCILE_HOURS=abc and 08, each checked by its message.
  • examples/proton: task check and task run -- task offline
  • ctan, tlnet, github and dropbox render.txt previewed against this branch; each has a follow-up PR.

A reconcile was due only in the run that started in hour 03 UTC. The
schedule lives in katoptra/dispatch and moved: tlnet left 03:30 on
2026-09-09 and had not reconciled since.

The toolbox now owns the rule. `due` reads the start epoch of the run
that last completed a reconcile from .state/reconciled, through the
engine's pull, and leaves .run/reconcile once it is RECONCILE_HOURS
(24, a mirror's root var) old, less half an hour so a daily run's
start-time jitter cannot skip every other day. `reconciled` records it
through push. RECONCILE=true and false still force either way; any
other value, and an hour count that is not a whole number from 1,
stops the run.

The rsync engine runs `due` after `clock`, gates `reconcile` on the
flag, holds it while batches wait (delete would hold the orphans
back), and records the reconcile last. `clock` writes the epoch alone
and clears a stale flag. The rsync example's offline check covers the
rule, and CLAUDE.md records that task runs every command under set -e.
@jshvn
jshvn merged commit fe81623 into main Sep 23, 2026
2 checks passed
jshvn added a commit to katoptra/ctan that referenced this pull request Sep 23, 2026
## Why

lib v2.2.0 (katoptra/lib#12) decides a reconcile by the age of the last
one instead of the hour a run starts. tlnet's slot left 03:30 on
2026-09-09, and it had not swept its bucket since.

## What

- `render.txt` changes:
  - `clock` writes the epoch alone and clears `.run/reconcile`;
  - `due` runs after it;
- `reconcile` ends with `reconciled`, which pushes `.state/reconciled`.
- The docs drop hour 03 (and tlnet's 03:30 dispatch) for the age rule:
CLAUDE.md, the Taskfile comment that names `RECONCILE` as the toolbox's,
and for tlnet the README.

The first run on v2.2.0 reconciles, because no marker exists yet.

## Test plan

- [x] `render.txt` rendered against the lib branch before release. The
`check` job re-renders it against the released `v2`.
jshvn added a commit to katoptra/tlnet that referenced this pull request Sep 23, 2026
## Why

lib v2.2.0 (katoptra/lib#12) decides a reconcile by the age of the last
one instead of the hour a run starts. tlnet's slot left 03:30 on
2026-09-09, and it had not swept its bucket since.

## What

- `render.txt` changes:
  - `clock` writes the epoch alone and clears `.run/reconcile`;
  - `due` runs after it;
- `reconcile` ends with `reconciled`, which pushes `.state/reconciled`.
- The docs drop hour 03 (and tlnet's 03:30 dispatch) for the age rule:
CLAUDE.md, the Taskfile comment that names `RECONCILE` as the toolbox's,
and for tlnet the README.

The first run on v2.2.0 reconciles, because no marker exists yet.

## Test plan

- [x] `render.txt` rendered against the lib branch before release. The
`check` job re-renders it against the released `v2`.
@jshvn
jshvn deleted the josh/reconcile-by-age branch September 23, 2026 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant