Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,19 @@ repos:
pass_filenames: true
stages: [pre-commit]

# OMN-13023 (retro B-11): UTC timestamp discipline in handoff/evidence docs.
# Rejects Z-suffixed clock times cited next to file-mtime markers (ls -l,
# mtime, Finder, last modified) — local mtimes relabeled as UTC manufactured
# a false outage narrative on 2026-06-11 (PROCESS_FAILURE_RETRO.md §5.1).
# Hard fail — no warn-only (CLAUDE.md Rule #5). Escape: 'utc-ok: <reason>'.
- id: check-utc-timestamp-discipline
name: Reject Z-suffixed times adjacent to mtime citations (OMN-13023)
entry: .pre-commit-hooks/check-utc-timestamp-discipline.sh
language: script
types: [markdown]
pass_filenames: true
stages: [pre-commit]

# OMN-9730: DGM-Phase4 — mechanical block on skip-deploy-gate bypass tokens.
# Rejects any staged file containing [skip-deploy-gate:] without an explicit
# approval receipt (# skip-token-allowed: <receipt-id>).
Expand Down
82 changes: 82 additions & 0 deletions .pre-commit-hooks/check-utc-timestamp-discipline.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc.
# SPDX-License-Identifier: MIT
#
# OMN-13023 (retro B-11): Reject Z-suffixed timestamps adjacent to file-mtime
# citations in handoff/evidence documents.
#
# Failure class this prevents (PROCESS_FAILURE_RETRO.md §5.1, 2026-06-11):
# an evening handoff transcribed local-EDT `ls -l` mtimes with a `Z` suffix,
# manufacturing a false "16:00Z mass worker death / 4h undetected" outage
# narrative that a later investigation consumed as fact. UTC timestamps must
# come from `date -u` or epoch conversion — never from local-time file
# listings relabeled as UTC.
#
# Matches files:
# docs/handoffs/**/*.md
# docs/evidence/**/*.md
#
# Fires when a single line contains BOTH:
# (a) an mtime-citation marker: `ls -l`, `ls -la`, `mtime`, `Finder`,
# `last modified`, `modified at`, `modification time`
# (b) a Z-suffixed clock time (e.g. `16:00Z`, `2026-06-11T16:00:12Z`)
#
# Escape hatch (same line): `utc-ok: <reason>` — use ONLY when the timestamp
# was independently produced by `date -u`/epoch conversion and the mtime
# marker is incidental prose. Cite the conversion.
#
# Fails with:
# UTC_MTIME_MISLABEL: <file>:<line> — Z-suffixed time cited next to an mtime
#
# CLAUDE.md Rule #5 (enforcement, not detection). No warn-only mode.

set -euo pipefail

TICKET_REF="OMN-13023"
MTIME_MARKER='(ls -la?|mtime|Finder|last modified|modified at|modification time)'
Z_TIME='[0-9]{2}:[0-9]{2}(:[0-9]{2})?(\.[0-9]+)?Z'
ESCAPE='utc-ok:'

FOUND_VIOLATION=0

for file in "$@"; do
case "$file" in
*.md) ;;
*) continue ;;
esac

# Only handoff/evidence documents
case "$file" in
docs/handoffs/*.md|docs/evidence/*.md|\
docs/handoffs/*/*.md|docs/evidence/*/*.md|\
*/docs/handoffs/*.md|*/docs/evidence/*.md|\
*/docs/handoffs/*/*.md|*/docs/evidence/*/*.md) ;;
*) continue ;;
esac

# Read from staged index when available; fall back to working tree for self-test
if git cat-file -e ":$file" 2>/dev/null; then
content="$(git show ":$file")"
elif [[ -f "$file" ]]; then
content="$(cat "$file")"
else
continue
fi

lineno=0
while IFS= read -r line; do
lineno=$((lineno + 1))
if grep -qE "$ESCAPE" <<<"$line"; then
continue
fi
if grep -qiE "$MTIME_MARKER" <<<"$line" && grep -qE "$Z_TIME" <<<"$line"; then
echo "UTC_MTIME_MISLABEL: ${file}:${lineno} — Z-suffixed time cited next to an mtime marker (${TICKET_REF})" >&2
echo " ${line}" >&2
echo " Local file mtimes are NOT UTC. Source the timestamp from 'date -u' or epoch conversion," >&2
echo " or drop the Z suffix and label the timezone explicitly. Escape hatch: 'utc-ok: <reason>'." >&2
FOUND_VIOLATION=1
fi
done <<<"$content"
done

exit "$FOUND_VIOLATION"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Evening handoff

## Infra Health

All lanes nominal.

## Timeline

Worker death detected: file mtime 16:00Z per ls -l of the workflow directory.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Evening handoff

## Infra Health

All lanes nominal.

## Timeline

Worker death boundary: 2026-06-11T20:00:12Z (sourced from `date -u` against wf_*.json epoch records).
The workflow directory listing was taken separately; mtimes recorded as local EDT without a Z suffix.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Evening handoff

## Infra Health

All lanes nominal.

## Timeline

Checkpoint at 20:05:00Z near the mtime boundary (utc-ok: timestamp from epoch conversion of wf_1234.json, mtime mention is incidental).
112 changes: 112 additions & 0 deletions tests/hooks/test_check_utc_timestamp_discipline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc.
# SPDX-License-Identifier: MIT
"""Tests for check-utc-timestamp-discipline.sh — OMN-13023 (retro B-11).

Verifies that handoff/evidence documents citing Z-suffixed clock times adjacent
to file-mtime markers are rejected, that date-u-sourced timestamps pass, that
the ``utc-ok:`` escape hatch works, and that non-handoff/evidence docs are
ignored. Failure class: PROCESS_FAILURE_RETRO.md §5.1 (local-EDT mtimes
relabeled as UTC manufactured a false outage narrative on 2026-06-11).
"""

import os
import shutil
import subprocess
import tempfile
from pathlib import Path

import pytest

HOOK = (
Path(__file__).parent.parent.parent
/ ".pre-commit-hooks"
/ "check-utc-timestamp-discipline.sh"
)
FIXTURES = Path(__file__).parent / "fixtures" / "utc_timestamp_discipline"


def run_hook(fixture_file: Path, fake_path: str) -> tuple[int, str]:
"""Run the hook against a fixture file at a spoofed repo-relative path."""
tmp_dir = tempfile.mkdtemp()
try:
spoof_path = Path(tmp_dir) / fake_path
spoof_path.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(fixture_file, spoof_path)
result = subprocess.run(
["bash", str(HOOK), str(spoof_path)],
capture_output=True,
check=False,
text=True,
env={**os.environ, "GIT_DIR": "/dev/null"},
)
return result.returncode, result.stderr
finally:
shutil.rmtree(tmp_dir, ignore_errors=True)


@pytest.mark.unit
def test_rejects_z_suffix_adjacent_to_mtime_in_handoff() -> None:
"""A Z-suffixed time on the same line as an mtime marker must be rejected."""
rc, stderr = run_hook(
FIXTURES / "invalid_mtime_z_suffix.md",
fake_path="docs/handoffs/2026-06-11-evening-handoff.md",
)
assert rc != 0, "Expected hook to reject Z-suffixed time next to mtime citation"
assert "UTC_MTIME_MISLABEL" in stderr


@pytest.mark.unit
def test_rejects_same_content_in_evidence_dir() -> None:
"""The same violation under docs/evidence/ must also be rejected."""
rc, stderr = run_hook(
FIXTURES / "invalid_mtime_z_suffix.md",
fake_path="docs/evidence/2026-06-11-incident/timeline.md",
)
assert rc != 0
assert "UTC_MTIME_MISLABEL" in stderr


@pytest.mark.unit
def test_passes_date_u_sourced_timestamps() -> None:
"""Z-suffixed times sourced from date -u with no same-line mtime marker pass."""
rc, stderr = run_hook(
FIXTURES / "valid_date_u_sourced.md",
fake_path="docs/handoffs/2026-06-11-evening-handoff.md",
)
assert rc == 0, f"Expected pass, got stderr: {stderr}"


@pytest.mark.unit
def test_escape_hatch_utc_ok_suppresses_finding() -> None:
"""A line carrying 'utc-ok: <reason>' is exempt."""
rc, stderr = run_hook(
FIXTURES / "valid_escape_hatch.md",
fake_path="docs/handoffs/2026-06-11-evening-handoff.md",
)
assert rc == 0, f"Expected escape hatch to pass, got stderr: {stderr}"


@pytest.mark.unit
def test_ignores_non_handoff_non_evidence_docs() -> None:
"""Docs outside docs/handoffs/ and docs/evidence/ are not in scope."""
rc, stderr = run_hook(
FIXTURES / "invalid_mtime_z_suffix.md",
fake_path="docs/architecture/some-design.md",
)
assert rc == 0, f"Expected out-of-scope doc to pass, got stderr: {stderr}"


@pytest.mark.unit
def test_ignores_non_markdown_files() -> None:
"""Non-markdown files are ignored even under docs/handoffs/."""
rc, _ = run_hook(
FIXTURES / "invalid_mtime_z_suffix.md",
fake_path="docs/handoffs/notes.txt",
)
assert rc == 0


@pytest.mark.unit
def test_hook_is_executable() -> None:
"""The hook script must carry the executable bit (pre-commit language: script)."""
assert os.access(HOOK, os.X_OK), f"{HOOK} is not executable"
Loading