Zapis decyzji 0004Przyjęta
Dates carry month precision, not day precision
Ta strona nie została jeszcze przetłumaczona — czytasz angielski oryginał.
Context
Every period in the corpus — project timelines, employment — is naturally known to the month. Nobody remembers the day a project started, and no consumer of this data needs it. Modelling these as full dates forces an invented day, and that invented day then gets rendered, indexed, and cited as if it were a fact.
Decision
Periods use a YYYY-MM string in frontmatter, validated by a regex in Zod and
parsed into a YearMonth readonly record struct in C#.
YearMonth implements IParsable<YearMonth> and IComparable<YearMonth>, has
comparison operators, and serializes to and from its canonical string form
through a JsonConverter. TypeScript keeps it as a validated string, which
compares correctly with localeCompare precisely because the format is
zero-padded and fixed-width.
period.end is optional; its absence means “current”, and Period.IsCurrent
exposes that rather than making every consumer re-derive it.
Consequences
- No invented precision reaches JSON-LD, the profile dump, or a RAG answer.
- Sorting is lexicographic on the wire and structural in C#; both agree.
ToDateOnly()exists for the rare consumer that genuinely needs aDateOnly, and the widening to the first of the month is explicit at the call site.- A future need for day precision is a schema-version bump, not a silent change.
Alternatives rejected
z.coerce.date() / DateOnly. Fabricates a day and invites time-zone bugs
in a value that has no time-zone meaning.
Free-text period strings (“Jan 2024 – present”). Unsortable, unlocalizable, and unparseable by the machine surface.