NAME

App::karr::Cmd::Repair - Migrate an old board off double-encoded UTF-8 and off impossible start stamps

VERSION

version 0.500

SYNOPSIS

karr repair              # report what would change
karr repair --yes        # rewrite the affected refs
karr repair --json

DESCRIPTION

Two migrations of old board data, reported and applied together but kept apart in the output, because a board can need either one without the other.

Neither of them touches updated: a migration is not an edit, and bumping the stamp on every card it rewrites would destroy the very history it is repairing.

Double-encoded UTF-8

karr up to and including 0.402 handed YAML::XS::Dump output — UTF-8 octets — around as if it were characters, so every board written by those versions carries UTF-8 encoded twice in its task frontmatter, its board config, and its activity log. Task bodies are not affected: they were concatenated onto the Markdown document verbatim and are correctly encoded.

Such a board is still read correctly, because refs/karr/meta/encoding is absent and everything that loads board state undoes the second encoding on the way in (see "repair_mojibake" in App::karr::Encoding). This command makes that permanent: it rewrites the affected refs once and stamps the marker, after which nothing guesses at the board's bytes again.

It is safe to run on any board:

  • a board already at the current version is left completely alone;

  • a ref whose payload is pure ASCII is skipped, so an ASCII-only board comes out bit-identical apart from the new marker ref;

  • running it twice changes nothing the second time.

Start stamps that precede their own card

karr wrote started as a bare YYYY-MM-DD date until ticket #68 made it a full timestamp. A bare date reads as midnight UTC, so every card filed and picked up on the same day carries a started that is earlier than its own created — by up to a day. On karr's own board that is 75 of 116 finished cards. Nothing can be measured from such a stamp: counted, its cycle time exceeds its lead time, which is why App::karr::Cmd::Metrics leaves those cards out of the averages entirely.

This command raises started to the card's own created — the only defensible value, since the work cannot have begun before the card existed.

What that costs, stated because it is not recoverable afterwards:

  • A clamped card asserts that the work began the instant the card was filed, i.e. zero queue time. For a card filed in the morning and picked up at night that is false, and the true start is not recorded anywhere else — the activity log does not cover the boards whose history is oldest.

  • After the clamp nothing on the card marks the stamp as having been day-granular. A migrated card is indistinguishable from one that really was started the second it was created, so the migration cannot be undone or audited from the data.

  • Those cards become measurable for karr metrics, with a cycle time equal to their lead time and a flow efficiency of 100%. That is arithmetic on the clamped value, not a finding about how the work ran.

  • The same old karr wrote completed day-granular too, and this command does not touch it. Where such a completed falls before the card's own created, raising started to created steps over it, and the card's cycle time reads negative afterwards where before it was merely absent. That is 42 of the 75 clamped cards on karr's own board. They are counted on a line of their own in the report and in started_clamped_over_completed under --json, because the clamp creates that state rather than inheriting it (ticket #139).

The criterion is deliberately narrow. A card is clamped only when its started is a bare YYYY-MM-DD date and its created is a full YYYY-MM-DDTHH:MM:SSZ stamp of karr's own writing and midnight of that date really does precede that created. A started that precedes created in any other shape is a different, unknown fault — a hand edit, a clock skew, an import from another tool — and clamping it blind would erase the evidence for it, so it is reported and left alone.

Stamps this command does not repair

Every card is checked for the other orderings that cannot be true either (completed before started, completed before created, updated before created), and for stamps in a shape karr cannot compare at all. Those are counted and reported, never rewritten: this command clamps started and nothing else (ticket #138), and a repair that quietly normalised the rest would be the same mistake in a larger size. The counts describe the board as the run leaves it, so a dry run shows what --yes would produce rather than what is there now. completed is the one with a ticket of its own (#139): karr wrote it day-granular before #68 as well, on more cards than started, and unlike started it has no single defensible value to be raised to.

OPTIONS

  • --yes

    Actually rewrite the refs. Without it the command only reports what it would change.

  • --json

    Emit the report as JSON instead of text. up_to_date answers for the encoding migration alone, as it always has, so it is not on its own an answer to "does this board need repairing" — read started_clamped beside it. applied distinguishes a dry run's repaired/started_clamped ("would") from a --yes run's ("did"). stamp_anomalies carries the findings above, and its lists are never acted on.

SEE ALSO

karr, App::karr, App::karr::Encoding, App::karr::Cmd::Backup, App::karr::Cmd::Import, App::karr::Cmd::Metrics, App::karr::Task

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/karr/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.