The operator: "I think I want creation and update dates on the booths now too." UPDATE was already there — `landed_at`, the newest mtime among CONTENT excluding our own machinery, which the Desk already sorts "new since you looked" by. CREATION had no honest source. `.booth.json` carries a declared `created`, but only for booths posted through the CLI since U5 — TWELVE OF THIRTY live booths had none. Every alternative was a guess wearing a fact's clothes: oldest content mtime is wrong the moment an agent copies files with timestamps preserved; directory mtime is just "last thing added", which is landed_at renamed; and stamping a first-seen marker on read is the same write-on-read shape that spent an hour of today aging the booth it cached. ext4 records a real birth time. CPython does not expose st_birthtime on Linux, so booth/birthtime.py reads it through statx(2) — a fact the disk already holds rather than one we invent. Verified against stat(1) on live booths, 6 of 6 exact, including every booth with no manifest. ONE rule for all thirty, which is what invariant 6 asks of anything statable in a line. None when the filesystem cannot say (tmpfs, NFS, an old kernel), and None renders as nothing — the honest output when nobody knows. Never raises: list_booths calls it once per booth on every index load, so a read that can raise is a service-wide outage wearing a single-booth bug's clothes. ALSO TWO REAL TEST-HARNESS DEFECTS, found chasing a flake and fixed on their merits rather than because they were proven to be the cause: - The keyboard-flag browser test fired ArrowRight and `f` back to back, assuming the first had finished — and focus() does a scrollIntoView, so under load `f` could arrive with no cursor and flag nothing. It now waits for the cursor to land. - BOTH browser fixtures did bind -> getsockname -> CLOSE -> hand uvicorn the port NUMBER, leaving a window for the kernel to give that port to somebody else. This suite runs two browser files that each start a server per test, so the competitor is right there. The bound socket is now handed over directly. ⚠ THE FLAKE IS NOT PROVEN FIXED. Two different browser tests failed once each across full-suite runs while passing 3/3 and 5/5 in isolation; since the fixes, one failure in three runs. n=3 cannot distinguish that from the prior rate and this commit does not claim it does. 770 green on a clean run.
74 lines
2.9 KiB
Python
74 lines
2.9 KiB
Python
"""The filesystem's own record of when a directory was created.
|
|
|
|
The operator asked for creation dates on booths. Only 18 of 30 live booths had
|
|
one: `.booth.json` carries a declared `created`, but that file only exists for
|
|
booths posted through the CLI since U5, and the twelve older ones had nothing.
|
|
|
|
The tempting answers were all guesses wearing a fact's clothes — the oldest
|
|
content mtime (wrong whenever an agent copies files with timestamps preserved),
|
|
or the directory mtime (which is just "last time something was added"). Writing
|
|
a first-seen stamp on read was worse still: this service spent an hour today
|
|
fixing a cache that aged the booth it cached.
|
|
|
|
ext4 records a real birth time. CPython 3.13 does not expose `st_birthtime` on
|
|
Linux, but `statx(2)` does and glibc has wrapped it since 2.28 — so this reads
|
|
a FACT the disk already holds rather than inventing one.
|
|
|
|
DEGRADES TO None, always: an old kernel, a filesystem that does not record
|
|
btime (tmpfs, NFS, some overlayfs), a missing glibc symbol, or anything else
|
|
unexpected. A caller that gets None shows nothing, which is the honest output
|
|
when nobody knows.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import ctypes
|
|
import ctypes.util
|
|
import os
|
|
from pathlib import Path
|
|
|
|
_AT_FDCWD = -100
|
|
_STATX_BTIME = 0x00000800
|
|
# struct statx: stx_btime is the SECOND statx_timestamp, and the four that
|
|
# precede it occupy a fixed 64-byte head (mask, blksize, attributes, nlink,
|
|
# uid, gid, mode, spare, ino, size, blocks, attributes_mask), then atime.
|
|
_BTIME_SEC_OFFSET = 80
|
|
_STATX_BUF_SIZE = 256
|
|
|
|
|
|
def _load():
|
|
try:
|
|
libc = ctypes.CDLL(ctypes.util.find_library("c") or "libc.so.6", use_errno=True)
|
|
return libc.statx
|
|
except (OSError, AttributeError):
|
|
return None
|
|
|
|
|
|
_statx = _load()
|
|
|
|
|
|
def birth_time(path: Path) -> float | None:
|
|
"""When the filesystem says this path was created, or None if it cannot say.
|
|
|
|
NEVER RAISES. `list_booths` calls this once per booth on every index load,
|
|
so a read that can raise is a service-wide outage wearing a single-booth
|
|
bug's clothes — the posture `read_manifest` already states, applied before
|
|
the same mistake rather than after it.
|
|
"""
|
|
if _statx is None:
|
|
return None
|
|
try:
|
|
buf = ctypes.create_string_buffer(_STATX_BUF_SIZE)
|
|
rc = _statx(ctypes.c_int(_AT_FDCWD), os.fsencode(str(path)),
|
|
ctypes.c_int(0), ctypes.c_uint(_STATX_BTIME), buf)
|
|
if rc != 0:
|
|
return None
|
|
mask = int.from_bytes(buf.raw[0:4], "little")
|
|
if not mask & _STATX_BTIME:
|
|
return None # the filesystem does not record it
|
|
sec = int.from_bytes(buf.raw[_BTIME_SEC_OFFSET:_BTIME_SEC_OFFSET + 8],
|
|
"little", signed=True)
|
|
return float(sec) if sec > 0 else None
|
|
except Exception: # noqa: BLE001 — see the docstring; nothing here is worth a 500
|
|
return None
|