null (never now()) as the absent-recency sentinel for lastModifiedAt
Date: 2026-06-08 Status: Accepted Decision: hl-26y Deciders: Sean Brandt
Context
Section titled “Context”When a file’s last-commit date cannot be determined — scan disabled, scan failed, file predates the --shallow-since window, or an incremental re-index lacks a head-commit timestamp — the lastModifiedAt chunk payload field must carry some value. The sentinel choice determines how every downstream consumer (analyzer context formatter, reviewer demotion logic, prompt annotations) interprets missing data.
Decision
Section titled “Decision”All code paths that cannot determine a file’s last-commit date write lastModifiedAt: null. Consumers treat null and field-absent identically as “age unknown”: no annotation, no demotion. One rule: null ≡ window-cutoff ≡ scan-disabled ≡ scan-failure ≡ incremental-index-without-head-commit. Freshness is never fabricated with now().
Rationale
Section titled “Rationale”- Fabricating freshness (
now()) would make scan failures silently corrupt the recency signal — stale docs would appear fresh, defeating the feature. - Treating unknown as maximally stale (epoch) would incorrectly demote all pre-existing chunks on first deploy, before any re-index.
- A single null rule covers four distinct “unknown” causes uniformly, so consumers need no per-cause branching — one null-check suffices.
Alternatives Considered
Section titled “Alternatives Considered”null/ absent ≡ “age unknown” (chosen): unambiguous; never false-fresh, never false-stale. Requires an explicit null-check in every consumer.Date.now()/ current timestamp: no null-check, but fabricates freshness for unknown-age files.- Epoch (1970-01-01): always present and clearly “old”, but treats unknown as maximally stale — wrong for all pre-existing data.
Consequences
Section titled “Consequences”- Positive: pre-existing chunks are neutral until re-indexed; scan failures are safe (index completes, age features inert); future consumers implement correct behavior with a single null-check.
- Negative: repos never re-indexed after deploy never gain age annotations — operators must trigger a re-index to backfill; webhook re-indexes without a head-commit timestamp stay null-dated.
- Neutral: Qdrant payloads are schemaless — null and absent are treated identically by the JS client; the rule unifies both.