Commit Graph
5 Commits
Author SHA1 Message Date
timothy 75139bbf31 fix(603): close four defects found in adversarial review of the stale-after fields
1. `date.fromisoformat` is not a YYYY-MM-DD validator. On Python >= 3.11 it also
   accepts ISO basic format ("20270101") and week dates ("2027-W01-1"), so a
   malformed-looking value passed the blocking check — and which forms parse
   depends on the interpreter, meaning the same corpus could validate differently
   on a dev machine and on the runner (pr-checks.yml pins only python-version
   '3.x'). Knock-on: the catalog's Review-due section sorts on the raw STRING, so
   an accepted "20270101" sorted AFTER "2027-01-15" ('-' < '0'), contradicting the
   section's own "sorted soonest-first" text. Gate on ^\d{4}-\d{2}-\d{2}$ first,
   which fixes both — a fixed-width zero-padded form makes string sort == date sort.

2. A present-but-empty `stale-after:` was collapsed to None by `or None` in the
   parser and then skipped by a truthiness guard in the validator, so it passed as
   "absent" — a field that silently never fires, which is the exact failure mode
   the blocking check exists to prevent. Keep "" distinct from None and test with
   `is not None`.

3. `test_catalog_is_date_independent` was partly vacuous: with no date in either
   render, both sides were trivially equal after the .replace(). It did still catch
   an injected clock-derived marker, but it passed with the feature deleted. Assert
   the dates are present.

4. The malformed-date check ran only over the active set, exempting archive
   records. Staleness is moot there, but a typo is still a typo — check both wings.

Adds regression tests for each, plus a Review-due row for a topic-file record
(pinning the `../decisions.md` vs bare-filename link forms).
2026-07-25 15:22:50 +02:00
timothy 0ad02db651 feat(603): adopt OKF's optional stale-after and Sources decision-record metadata
Evaluated the Open Knowledge Format (GoogleCloudPlatform/knowledge-catalog okf
v0.2, scaccogatto/okf-skills) as a replacement for our decision-record system and
rejected it: its conformance rules are deliberately permissive exactly where ours
are strict (broken links, unknown types and missing fields must all be tolerated;
`deprecated` points at no successor), and its stable identity is the file path,
which the breadcrumb rule tells agents not to trust.

Adopted two of its optional families instead, additively:

- `stale-after: YYYY-MM-DD` on the metadata line — marks a record asserting an
  outside-world fact as due for re-confirmation. Absolute date, no TTL.
- `**Sources:**` in the metadata block — the evidence a record rests on, as
  distinct from `Signals:` (recall keywords).

Neither is required; absence is never an error. A malformed `stale-after` is
blocking (it would silently never fire), but a past-due record is only a
non-blocking `::notice::` — going stale is the passage of time, not a defect in
whatever commit is under test. The catalog's new "Review due" section renders the
date only and never a clock-derived verdict, so it cannot drift `--check` red on a
calendar boundary with no commit touching the corpus.

No backfill: no existing record adopts either field here.

fixes #603
2026-07-25 15:22:50 +02:00
timothyandClaude Opus 4.8 f93458c76c fix(521): whole-branch review — correct Gitea anchors, guard archive+demotion, reciprocal links, stale append-only refs, budget warning [decisions-edit]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 03:00:15 +02:00
timothyandClaude Opus 4.8 458ab2111f fix(521): catalog _anchor collapses punctuation runs; single trailing newline
_anchor() mapped each space/hyphen to its own '-' without collapsing runs,
so the standard heading separator " — " (space, em-dash, space) produced a
double hyphen in every generated anchor. Since nearly every real decision
record heading uses that separator, this made the catalog emit a dead link
for essentially every row. Fix: after building the char list, collapse
consecutive '-' into one and strip leading/trailing '-' via re.sub, matching
how Goldmark/GitHub/Gitea sluggers behave.

Also fixed main() writing an extra trailing newline (want already ends in
"\n", then "+ \n" appended a second one) so docs/decisions/README.md now
ends with exactly one trailing newline; --check still compares via .strip().

Added test_anchor_collapses_em_dash_and_keeps_underscore to pin the anchor
behavior against the reported iptv.base_url case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 02:58:58 +02:00
timothyandClaude Opus 4.8 67619b2bf6 feat(521): active-catalog generator
Adds scripts/build_decisions_catalog.py, which renders docs/decisions/README.md
as a compact table of only 'active' decision records (sorted by key), and its
test scripts/tests/test_build_catalog.py. Supports --check for CI drift
detection. No decision records are migrated yet, so the generated catalog is
currently empty (banner + header only) — expected at this stage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 02:58:58 +02:00