phase: 154_sync_status_freshness
All 4 task files exist in `complete/`, and only `00_phase.md` remains in `todo/`. This is the final verification pass. I'll read through the task files and check the current state of the code.
This commit is contained in:
@@ -164,8 +164,11 @@ tests/unit/test_frontend_sync_upload.py's node check).
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from collections.abc import Callable, Iterator, Sequence
|
||||
@@ -198,6 +201,8 @@ RETIRED_ID = "-".join(("sync", "result")) # built at runtime: 3.12+ folds
|
||||
# adjacent/"+" constant strings at compile time, which would leave the
|
||||
# retired name in the .pyc — the phase gate greps even the bytecode.
|
||||
|
||||
HAVE_NODE = shutil.which("node") is not None
|
||||
|
||||
|
||||
def _text(path: Path) -> str:
|
||||
assert path.is_file(), f"missing frontend file: {path}"
|
||||
@@ -563,6 +568,10 @@ def test_sources_js_terminal_states() -> None:
|
||||
|
||||
success = _body(js, "applySyncSuccess")
|
||||
assert '"Synced"' in success and "fmtSyncTime(status.finished_at)" in success
|
||||
assert 'settleSyncButton(time ? `Synced ${time}` : "Synced")' in success, (
|
||||
"the settle string — phase 154: the qualified stamp rides the SAME"
|
||||
" shape (the qualifier lives inside the formatter)"
|
||||
)
|
||||
|
||||
failure = _body(js, "applySyncFailure")
|
||||
assert 'settleSyncButton("Sync sources")' in failure # retry-ready
|
||||
@@ -578,6 +587,313 @@ def test_sources_js_terminal_states() -> None:
|
||||
|
||||
time = _body(js, "fmtSyncTime")
|
||||
assert "getHours()" in time and "getMinutes()" in time, "local HH:MM of finished_at"
|
||||
assert 'if (Number.isNaN(d.getTime())) return "";' in time, (
|
||||
"the parse guard is UNCHANGED — unparseable ISO → "" (the bare"
|
||||
" 'Synced' settle)"
|
||||
)
|
||||
# Phase 154 (task 01): the DATE-QUALIFIER (A1 rule — the LOCAL
|
||||
# calendar dates, the page's clock; the table dates' family).
|
||||
assert "const now = new Date();" in time, "'now' is the page's clock"
|
||||
assert (
|
||||
"d.getFullYear() === now.getFullYear() &&" in time
|
||||
and "d.getMonth() === now.getMonth()" in time
|
||||
and "d.getDate() === now.getDate()" in time
|
||||
), "same local calendar day as now → HH:MM (byte-identical to pre-phase)"
|
||||
assert "d.getHours() % 12 || 12" in time, (
|
||||
"12-hour WITHOUT leading zero on the hour (the 12 o'clock edge)"
|
||||
)
|
||||
assert '"AM"' in time and '"PM"' in time, "the AM/PM family"
|
||||
assert "pad(d.getMinutes())" in time, "MM zero-padded in every form"
|
||||
assert "`${d.getMonth() + 1}/${d.getDate()}`" in time, (
|
||||
"M/D, no leading zeros (same year, different day)"
|
||||
)
|
||||
assert "`${d.getMonth() + 1}/${d.getDate()}/${d.getFullYear()}`" in time, (
|
||||
"M/D/YYYY across years"
|
||||
)
|
||||
|
||||
|
||||
# Phase 154 (task 01) — the date-qualifier's boundary set, behavioral
|
||||
# under node with a FIXED clock. The test body never calls `new
|
||||
# Date()` for its own timing: the fake clock is installed in the
|
||||
# driver (global Date patched BEFORE the call — `new Date()` → the
|
||||
# fixed now, `new Date(iso)` → the real parse), and every ISO is
|
||||
# designator-less (local) so the comparison is timezone-independent.
|
||||
# The fixed now is Oct 3, 2026, 18:30 LOCAL.
|
||||
|
||||
_STAMP_NOW_JS = "new RealDate(2026, 9, 3, 18, 30, 0)"
|
||||
|
||||
|
||||
def _stamp_driver(fn_src: str, expr: str) -> str:
|
||||
"""Run `expr` under node with the REAL sources.js function + the
|
||||
fake clock (the idiom: the Date patch precedes the call)."""
|
||||
driver = (
|
||||
f"{fn_src}\n"
|
||||
"const RealDate = Date;\n"
|
||||
f"const NOW = {_STAMP_NOW_JS};\n"
|
||||
"globalThis.Date = function (...args) {\n"
|
||||
" return args.length === 0 ? NOW : new RealDate(...args);\n"
|
||||
"};\n"
|
||||
f"{expr}\n"
|
||||
)
|
||||
proc = subprocess.run(
|
||||
["node", "-e", driver], capture_output=True, text=True, timeout=60
|
||||
)
|
||||
assert proc.returncode == 0, f"node failed: {proc.stderr}"
|
||||
return proc.stdout
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAVE_NODE, reason="node not available")
|
||||
def test_sources_js_fmt_sync_time_qualifier_boundaries_fixed_clock() -> None:
|
||||
"""The REAL sources.js ``fmtSyncTime`` under node (fake clock, the
|
||||
fixed now Oct 3 2026 18:30 local) — the A1 boundary set:
|
||||
same-day → ``HH:MM`` (byte-identical to the pre-phase output —
|
||||
the audit's own ``16:06`` case, plus the midnight / end-of-day
|
||||
edges); yesterday (same year) → ``M/D, h:MM AM/PM`` (no leading
|
||||
zero on the hour — ``3:14 PM``; the ``12:05 AM`` / ``12:07 PM``
|
||||
o'clock edges); last-year same M/D → ``M/D/YYYY, h:MM AM/PM``;
|
||||
garbage / missing ISO → ``""`` (the guard unchanged).
|
||||
The ``null`` edge (``new Date(null)`` IS the epoch — parseable,
|
||||
the guard unchanged) is pinned TZ-independently: ``null`` and the
|
||||
epoch ISO render identically (same instant), in the dated + year
|
||||
form (1969 ≠ the fixed 2026). The wall clock never appears in an
|
||||
assertion."""
|
||||
fn = _body(_text(SOURCES_JS), "fmtSyncTime")
|
||||
# (iso, expected) — the expected strings are the pins.
|
||||
cases = [
|
||||
("2026-10-03T16:06:00", "16:06"), # same day — the audit case
|
||||
("2026-10-03T00:05:00", "00:05"), # same day, midnight edge
|
||||
("2026-10-03T23:59:00", "23:59"), # same day, end-of-day edge
|
||||
("2026-10-02T15:14:00", "10/2, 3:14 PM"), # yesterday, no zero hour
|
||||
("2026-10-02T00:05:00", "10/2, 12:05 AM"), # yesterday, 12:05 AM edge
|
||||
("2026-10-02T12:07:00", "10/2, 12:07 PM"), # yesterday, noon edge
|
||||
("2026-10-02T23:58:00", "10/2, 11:58 PM"), # yesterday, PM minutes
|
||||
("2025-10-03T21:12:00", "10/3/2025, 9:12 PM"), # last year, same M/D
|
||||
("2025-01-03T09:12:00", "1/3/2025, 9:12 AM"), # last year, month 1
|
||||
("garbage", ""), # unparseable → the pre-phase fallback
|
||||
("", ""), # empty → the pre-phase fallback
|
||||
("undefined", ""), # missing ISO (the app-restart case) → ""
|
||||
]
|
||||
iso_literals = []
|
||||
for iso, _ in cases:
|
||||
if iso == "undefined":
|
||||
iso_literals.append("undefined")
|
||||
else:
|
||||
iso_literals.append(f'"{iso}"')
|
||||
driver_expr = (
|
||||
"const CASES = [" + ", ".join(iso_literals) + "];\n"
|
||||
"const STAMPS = CASES.map((c) => fmtSyncTime(c));\n"
|
||||
"const EPOCH = [fmtSyncTime(null), fmtSyncTime(new RealDate(0).toISOString())];\n"
|
||||
"console.log(JSON.stringify({ STAMPS, EPOCH }));"
|
||||
)
|
||||
out = json.loads(_stamp_driver(fn, driver_expr))
|
||||
assert out["STAMPS"] == [expected for _, expected in cases], out
|
||||
assert out["EPOCH"][0] == out["EPOCH"][1], (
|
||||
"null and the epoch ISO render identically (the same instant —"
|
||||
" the guard is unchanged: new Date(null) IS the epoch)"
|
||||
)
|
||||
assert re.fullmatch(
|
||||
r"\d{1,2}/\d{1,2}/\d{4}, \d{1,2}:\d{2} (AM|PM)", out["EPOCH"][0]
|
||||
), "the epoch takes the M/D/YYYY, h:MM AM/PM form (1969 ≠ the fixed year)"
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAVE_NODE, reason="node not available")
|
||||
def test_sources_js_synced_settle_string_qualifies_the_stamp() -> None:
|
||||
"""The ``applySyncSuccess`` settle string (the pinned shape
|
||||
``time ? `Synced ${time}` : "Synced"`` — the qualifier lives
|
||||
INSIDE the formatter, the shape is unchanged) under node with the
|
||||
fixed clock: a same-day ``finished_at`` settles as
|
||||
``Synced 16:06`` (byte-identical to pre-phase), a non-same-day
|
||||
one settles as ``Synced 10/2, 3:14 PM`` (the date-qualified
|
||||
badge — the phase's ask), and an unparseable/missing ISO settles
|
||||
as the bare ``Synced`` (the existing fallback). The ``null`` edge
|
||||
pins identically to the boundary test (the epoch — the pre-phase
|
||||
rendered ``Synced 00:00`` there)."""
|
||||
fn = _body(_text(SOURCES_JS), "fmtSyncTime")
|
||||
settle = (
|
||||
"const settle = (iso) => {\n"
|
||||
" const t = fmtSyncTime(iso);\n"
|
||||
" return t ? `Synced ${t}` : \"Synced\";\n"
|
||||
"};\n"
|
||||
)
|
||||
iso_literals = [
|
||||
'"2026-10-03T16:06:00"', # same day
|
||||
'"2026-10-02T15:14:00"', # yesterday
|
||||
'"2025-10-03T21:12:00"', # last year
|
||||
'"garbage"', # unparseable
|
||||
"undefined", # missing ISO
|
||||
]
|
||||
driver_expr = (
|
||||
settle
|
||||
+ "const CASES = [" + ", ".join(iso_literals) + "];\n"
|
||||
+ "const SETTLES = CASES.map(settle);\n"
|
||||
+ "const EPOCH = [settle(null), settle(new RealDate(0).toISOString())];\n"
|
||||
+ "console.log(JSON.stringify({ SETTLES, EPOCH }));"
|
||||
)
|
||||
out = json.loads(_stamp_driver(fn, driver_expr))
|
||||
assert out["SETTLES"] == [
|
||||
"Synced 16:06", # same day — byte-identical to pre-phase
|
||||
"Synced 10/2, 3:14 PM", # yesterday — date-qualified
|
||||
"Synced 10/3/2025, 9:12 PM", # last year — date + year
|
||||
"Synced", # garbage — the bare fallback
|
||||
"Synced", # missing ISO — the bare fallback
|
||||
], out
|
||||
assert out["EPOCH"][0] == out["EPOCH"][1], (
|
||||
"settle(null) and the epoch ISO settle identically (the guard"
|
||||
" unchanged)"
|
||||
)
|
||||
assert out["EPOCH"][0].startswith("Synced "), (
|
||||
"the epoch settles with a stamp (new Date(null) is parseable"
|
||||
" — the pre-phase rendered 'Synced 00:00' there)"
|
||||
)
|
||||
|
||||
|
||||
# Phase 154 (task 03) — the qualifier's BYTE-IDENTITY: the pre-phase
|
||||
# fmtSyncTime, pinned VERBATIM from git history (the phase-154
|
||||
# pre-state — the time-only formatter). Only the function NAME is
|
||||
# renamed (so the real + the reference run side by side under node);
|
||||
# the body is the old code byte-for-byte — the old strings (the
|
||||
# `HH:MM` return + the `""` guard) live in this constant, so the
|
||||
# byte-identity below is assertable, not assumed. The reference is
|
||||
# clock-free (it reads no `now` — only the ISO's local time), but
|
||||
# the same fixed-clock driver (the task-01 boundary set's clock) is
|
||||
# used, so the real function's same-day comparison runs on the fixed
|
||||
# now exactly as in the boundary test.
|
||||
PRE_PHASE_FMT_SYNC_TIME_JS = """
|
||||
function prePhaseSyncTime(iso) {
|
||||
const d = new Date(iso);
|
||||
if (Number.isNaN(d.getTime())) return "";
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
return `${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAVE_NODE, reason="node not available")
|
||||
def test_sources_js_fmt_sync_time_same_day_is_byte_identical_to_pre_phase() -> None:
|
||||
"""Phase 154 (task 03): the REAL sources.js ``fmtSyncTime`` and
|
||||
the VERBATIM pre-phase formatter (pinned above) run side by side
|
||||
under node with the fixed clock (Oct 3 2026 18:30 local — the
|
||||
task-01 boundary set's clock):
|
||||
|
||||
* the pinned reference's own output is asserted against the
|
||||
verbatim old strings FIRST (a self-check on the constant — a
|
||||
typo in the pinned function fails here, not silently);
|
||||
* EVERY same-day ISO renders BYTE-IDENTICALLY to the pre-phase
|
||||
output (the old ``HH:MM`` — the audit's ``16:06`` case, the
|
||||
midnight / end-of-day edges), and its settle string is
|
||||
byte-identical to the pre-phase settle (``"Synced " + HH:MM``
|
||||
— a same-day badge never moved);
|
||||
* EVERY unparseable/missing ISO (``garbage`` / ``""`` /
|
||||
``undefined``) renders byte-identically to the pre-phase
|
||||
``""`` (the guard unchanged);
|
||||
* the NON-same-day ISOs (yesterday + last year + the
|
||||
``null``/epoch edge — the epoch's local time is a different
|
||||
day AND a different year, so the qualified form applies; its
|
||||
value is TZ-dependent, so it is pinned by SHAPE: the
|
||||
``M/D/YYYY, h:MM AM/PM`` family vs the old ``HH:MM``) are the
|
||||
pinned DIVERGENT set — the qualified form is byte-different
|
||||
from the pre-phase time-only string (the phase's change lives
|
||||
exactly there).
|
||||
|
||||
The wall clock never appears in an assertion."""
|
||||
# Source-level self-check: the pinned constant carries the old
|
||||
# strings verbatim (the `HH:MM` return + the parse guard).
|
||||
assert (
|
||||
"return `${pad(d.getHours())}:${pad(d.getMinutes())}`;"
|
||||
in PRE_PHASE_FMT_SYNC_TIME_JS
|
||||
), "the old HH:MM return is pinned verbatim"
|
||||
assert (
|
||||
'if (Number.isNaN(d.getTime())) return "";' in PRE_PHASE_FMT_SYNC_TIME_JS
|
||||
), "the old parse guard is pinned verbatim"
|
||||
|
||||
fn = _body(_text(SOURCES_JS), "fmtSyncTime")
|
||||
# (js literal, category) — category: same / fallback / diverge.
|
||||
cases = [
|
||||
('"2026-10-03T16:06:00"', "same"), # the audit case
|
||||
('"2026-10-03T00:05:00"', "same"), # midnight edge
|
||||
('"2026-10-03T23:59:00"', "same"), # end-of-day edge
|
||||
('"garbage"', "fallback"),
|
||||
('""', "fallback"), # empty ISO
|
||||
("undefined", "fallback"), # missing ISO (the app-restart case)
|
||||
("null", "diverge"), # the epoch edge — shape-pinned (TZ-dependent)
|
||||
('"2026-10-02T15:14:00"', "diverge"), # yesterday
|
||||
('"2026-10-02T00:05:00"', "diverge"),
|
||||
('"2026-10-02T12:07:00"', "diverge"),
|
||||
('"2026-10-02T23:58:00"', "diverge"),
|
||||
('"2025-10-03T21:12:00"', "diverge"), # last year
|
||||
('"2025-01-03T09:12:00"', "diverge"),
|
||||
]
|
||||
# The verbatim old strings (the pre-phase output — pinned here so
|
||||
# the identity is assertable); the null/epoch value is
|
||||
# TZ-dependent, so its old string is pinned by shape, not value.
|
||||
old = {
|
||||
'"2026-10-03T16:06:00"': "16:06",
|
||||
'"2026-10-03T00:05:00"': "00:05",
|
||||
'"2026-10-03T23:59:00"': "23:59",
|
||||
'"garbage"': "",
|
||||
'""': "",
|
||||
"undefined": "",
|
||||
}
|
||||
driver_expr = (
|
||||
"const CASES = [" + ", ".join(lit for lit, _ in cases) + "];\n"
|
||||
"const PRE = CASES.map((c) => prePhaseSyncTime(c));\n"
|
||||
"const REAL = CASES.map((c) => fmtSyncTime(c));\n"
|
||||
"const settle = (f) => (iso) => {\n"
|
||||
" const t = f(iso);\n"
|
||||
" return t ? `Synced ${t}` : \"Synced\";\n"
|
||||
"};\n"
|
||||
"const PRE_SETTLE = CASES.map((c) => settle(prePhaseSyncTime)(c));\n"
|
||||
"const REAL_SETTLE = CASES.map((c) => settle(fmtSyncTime)(c));\n"
|
||||
"console.log(JSON.stringify({ PRE, REAL, PRE_SETTLE, REAL_SETTLE }));"
|
||||
)
|
||||
out = json.loads(
|
||||
_stamp_driver(fn + "\n" + PRE_PHASE_FMT_SYNC_TIME_JS, driver_expr)
|
||||
)
|
||||
# 1. the pinned reference reproduces the verbatim old strings
|
||||
# (self-check on the constant — assertable, not assumed).
|
||||
for i, (lit, _cat) in enumerate(cases):
|
||||
if lit in old:
|
||||
assert out["PRE"][i] == old[lit], (
|
||||
f"the pre-phase reference for {lit} must be the verbatim old"
|
||||
f" string {old[lit]!r} — got {out['PRE'][i]!r} (a typo in the"
|
||||
" pinned constant?"
|
||||
)
|
||||
null_i = [lit for lit, _ in cases].index("null")
|
||||
assert re.fullmatch(r"\d{2}:\d{2}", out["PRE"][null_i]), (
|
||||
"the null/epoch edge takes the old HH:MM shape on the reference"
|
||||
" side (the pre-phase is time-only — the value is TZ-dependent,"
|
||||
" the shape is not)"
|
||||
)
|
||||
assert out["PRE_SETTLE"][null_i] == "Synced " + out["PRE"][null_i] # old settle
|
||||
assert re.fullmatch(
|
||||
r"\d{1,2}/\d{1,2}/\d{4}, \d{1,2}:\d{2} (AM|PM)", out["REAL"][null_i]
|
||||
), (
|
||||
"the null/epoch edge takes the M/D/YYYY, h:MM AM/PM shape on the"
|
||||
" real side (the epoch is a different day + year — the qualified"
|
||||
" form; the value is TZ-dependent, the shape is not)"
|
||||
)
|
||||
assert out["REAL_SETTLE"][null_i].startswith("Synced ")
|
||||
# 2. the audit case's settle is byte-identical to pre-phase.
|
||||
audit_i = [lit for lit, _ in cases].index('"2026-10-03T16:06:00"')
|
||||
assert out["REAL_SETTLE"][audit_i] == "Synced 16:06", (
|
||||
"the same-day settle is byte-identical to the pre-phase string"
|
||||
)
|
||||
# 3. same-day + fallbacks: byte-identical to the reference, settle
|
||||
# included; the divergent set: byte-different (the qualified form).
|
||||
for i, (lit, cat) in enumerate(cases):
|
||||
if cat == "diverge":
|
||||
assert out["REAL"][i] != out["PRE"][i], (
|
||||
f"{lit} must DIFFER from the pre-phase form (the qualified"
|
||||
f" branch) — got {out['REAL'][i]!r} == {out['PRE'][i]!r}"
|
||||
)
|
||||
assert out["REAL_SETTLE"][i] != out["PRE_SETTLE"][i]
|
||||
else:
|
||||
assert out["REAL"][i] == out["PRE"][i], (
|
||||
f"{lit} must be byte-identical to the pre-phase output"
|
||||
f" (category {cat}) — got {out['REAL'][i]!r} vs"
|
||||
f" {out['PRE'][i]!r}"
|
||||
)
|
||||
assert out["REAL_SETTLE"][i] == out["PRE_SETTLE"][i]
|
||||
|
||||
|
||||
def test_sources_js_failed_error_is_sanitized() -> None:
|
||||
|
||||
Reference in New Issue
Block a user