AI Implementation feature(1086): Posted-Anniversary Dedup Store (#5)
This commit was merged in pull request #5.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
---
|
||||
type: architecture
|
||||
title: Anniversary Matching
|
||||
description: Rules and file boundaries used to discover Jekyll posts whose publication anniversary is exactly ten years before the current date.
|
||||
tags: [matching, jekyll, anniversary, posts]
|
||||
timestamp: 2026-08-04T18:35:00Z
|
||||
---
|
||||
|
||||
# Purpose
|
||||
|
||||
`tenbackward.matching` scans the synchronized blog at
|
||||
`<blog_dir>/_posts/blog` and returns posts whose date is exactly ten years
|
||||
before the current date. The current date is evaluated in the configured
|
||||
IANA timezone, defaulting to `Europe/Berlin` in the matcher.
|
||||
|
||||
# Discovery Rules
|
||||
|
||||
1. Walk every Markdown file below the configured post root recursively.
|
||||
2. Parse YAML front matter when present.
|
||||
3. Require a filename stem shaped as `YYYY-MM-DD-slug` with a valid calendar
|
||||
date and non-empty slug.
|
||||
4. Prefer a valid front matter `date`; otherwise use the date in the filename.
|
||||
5. Match the post year to `today.year - 10` and the month/day to today.
|
||||
6. Skip posts with `published: false`.
|
||||
7. Return a `MatchedPost` containing the relative path, title, date, and
|
||||
canonical site URL. If front matter has no title, use the filename slug.
|
||||
|
||||
# Leap-Day Behavior
|
||||
|
||||
A February 29 post matches February 29 when the current year is a leap year.
|
||||
In a non-leap year it matches March 1, preserving one anniversary event for
|
||||
leap-day posts.
|
||||
|
||||
# Output and Integration
|
||||
|
||||
`find_anniversary_matches()` returns `MatchedPost` values for callers that
|
||||
need metadata. `iter_anniversary_paths()` yields only relative paths; the
|
||||
pipeline uses those paths as deduplication identifiers in the
|
||||
[system state store](/architecture/system-overview.md) and persists new IDs in
|
||||
`posted.json`.
|
||||
|
||||
Unreadable files, malformed front matter, invalid filenames, unpublished
|
||||
posts, and unexpected per-file errors are skipped with structured warning
|
||||
events rather than aborting the full scan.
|
||||
|
||||
# Key Files
|
||||
|
||||
| Path | Responsibility |
|
||||
|---|---|
|
||||
| `/repo/src/tenbackward/matching.py` | Date parsing, Jekyll front matter handling, anniversary rules, URL construction, and recursive scanning. |
|
||||
| `/repo/src/tenbackward/main.py` | Supplies the blog post root and site URL, then applies state deduplication. |
|
||||
| `/repo/tests/test_matching.py` | Covers filename/front matter parsing, date matching, unpublished posts, malformed files, URL output, and leap-day behavior. |
|
||||
| `/repo/src/tenbackward/blog.py` | Ensures the source repository is cloned or fast-forwarded before matching. |
|
||||
|
||||
# Examples
|
||||
|
||||
## Matching post
|
||||
|
||||
On 2026-08-04, a file named
|
||||
`_posts/blog/2016/2016-08-04-release.md` is eligible. Its identifier is
|
||||
`2016/2016-08-04-release.md` and its generated URL is:
|
||||
|
||||
```text
|
||||
https://example.com/2016/08/04/release/
|
||||
```
|
||||
|
||||
## Skipped post
|
||||
|
||||
A file with `published: false`, an invalid date, or a non-matching
|
||||
month/day is not yielded and does not enter `posted.json`.
|
||||
|
||||
# Related
|
||||
|
||||
* [Pipeline Runner](/architecture/pipeline-runner.md)
|
||||
* [System Architecture](/architecture/system-overview.md)
|
||||
* [Daily Run Guide](/guides/daily-run.md)
|
||||
Reference in New Issue
Block a user