Vocabulary Temporal-Binding Consumer Hardening - Status

Unit ID: temporal-binding-consumer-hardening Status: Implemented (2026-09-25), at the human’s direction (“proceed with the attached plan”), which is treated as confirmation of Finding 1’s Option B (the plan’s own “Human Input” line already recorded this agreement). Not yet executed in this sandbox — no rdflib here (network-restricted); statically verified (py_compile, a direct AST-level mutation probe for Finding 4) and handed off for mise run check:vocabulary / python -m unittest surface.test_surface -v. Last updated: 2026-09-25 Trigger: Closure cross-reference of vocabulary-temporal-binding against docs/architecture/rdf-sparql-patterns-guide.md Plan: temporal-binding-consumer-hardening.md Predecessor: vocabulary-temporal-binding (closed)

Current position

All four findings are implemented, in slice order (1, 2, then 3, then 4 per the plan’s dependency: 4 needed 3’s resolution-instant decision).

Slice 1 — Finding 3 (documentation)

ontology/vocabulary/shapes/constraints.ttl’s header and vvp:resolvedAt’s rdfs:comment, tools/vocabulary/README.md’s “What this package deliberately does not check”, and the validation pack’s VTB-13 row now state explicitly that vvp:resolvedAt is a valid-time “as-of” query point (the same axis as fnd:validFrom/fnd:validTo and resolve()’s at parameter), not a transaction-time “recorded when” timestamp, and name the guide’s recordedAt/occurredAt convention as the naming precedent a real consuming property should follow instead. No shape, resolver, or test change.

Slice 2 — Finding 4 (test)

New tools/vocabulary/tests/test_architecture.py: no module under tools/vocabulary/src/vocabulary/ may call datetime.now()/time.time()/ datetime.utcnow(), or import the time module at all. Exemption list starts empty (unlike persistence’s HLC carve-out — nothing here needs one). Mutation-probed in this session: a temporary datetime.now() call added to resolver.py made the test fail with the exact offending module/call named; reverting made it pass again. Both runs executed directly against the package’s stdlib-only AST-scanning logic (no rdflib needed for this test).

Slice 3 — Finding 1, Option B

Slice 4 — Finding 2

New tests added (statically verified, not yet executed)

In tools/surface/src/surface/test_surface.py:

All four were checked by hand against the fixture’s actual IRIs (ex:north-binding, ex:region-north under https://example.org/lattice/surface/employment-scoped#) and by tracing enumerate_population/resolve()’s logic manually, since this sandbox cannot execute them.

What was verified in this sandbox (no rdflib available)

Decisions made during implementation (flagged for review)

Human validation gate

Not yet performed. Before closing this unit:

  1. Run mise run check:vocabulary (Finding 3/4’s package) and python -m unittest surface.test_surface -v (Findings 1/2’s new cases) and report the result.
  2. Confirm Finding 1’s Option B is accepted as implemented (the plan’s own “Human Input” line already recorded this, carried through unchanged).
  3. Decide whether command_parity --shared-corpus needs the same guard in a follow-on unit, or stays a documented non-coverage.

Blockers

None recorded against this unit’s four findings — all are implemented. Execution of the new/changed tests in an environment with rdflib installed is the only remaining step before full closure.