Skip to content

Report no substrate time when there was no substrate reading - #635

Merged
xmap merged 1 commit into
mainfrom
worktree-observer-no-clock
Aug 10, 2026
Merged

Report no substrate time when there was no substrate reading#635
xmap merged 1 commit into
mainfrom
worktree-observer-no-clock

Conversation

@xmap

@xmap xmap commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Found by a four-lens gate review of the next slice's design. All four reviewers
reported it independently, from different starting points, before any of them
saw another's findings.

ControlPortEnclosureObserver._unknown stamped clock.now() onto the
synthesized observation it emits on a PV disconnect or clean stream end. That is
a CORA time wearing a substrate label — the same defect removed from the caproto
adapter one layer up, in the very commit that wrote the rule it breaks:

An adapter with no substrate time MUST answer None rather than supply its own
clock, because a synthesized time is indistinguishable from a reported one once
it is written down.
enclosure_observer.EnclosureObservation, added in #631

Writing a rule into a docstring does not enforce it. The absent-stamp pin added
alongside that rule (test_absent_timestamp_mapping.py) covers only the four
ControlPort adapters and structurally cannot see EnclosureObserver implementors.

Why it matters now

Harmless today only because the seam discards the field. The next slice stops
discarding it.

At 2-BM the inversion would be total rather than occasional. Both PSS permit PVs
report an undefined EPICS stamp, so every real reading already yields None
there, while the monitor re-subscribes every 5 seconds and each cycle's
stream-end would carry a real-looking time. The substrate-time column would be
populated exactly when the substrate said nothing, and NULL exactly when it spoke.

Changes

  • _unknown reports None. This makes the clock dependency dead, so it goes,
    along with clock=deps.clock at the composition root. When CORA learned of the
    disconnect is still recorded, on the event's occurred_at.
  • AlwaysPermittedEnclosureObserver had the same shape in sentinel form, a fixed
    1970 date chosen for determinism. None is equally deterministic and cannot be
    mistaken for a reading.
  • That stub's docstring claimed a "first-boot no observer wired" code path. Grep
    finds no such wiring, so the claim is corrected rather than preserved.

Tests

Two pinned the old behaviour and were correct when written; they now pin absence
with the reasoning attached. Two are added for the gap that let this through: no
test anywhere drove a reading with no substrate time through the bridge. They are
paired, absent and present, so neither direction can regress into a constant.

Verified: 30561 unit + architecture pass, pyright clean.

🤖 Generated with Claude Code

`ControlPortEnclosureObserver._unknown` stamped `clock.now()` onto the
synthesized observation it emits on a PV disconnect or a clean stream
end. That is a CORA time wearing a substrate label, and it is the same
defect removed from the caproto adapter one layer up, in the commit
that also wrote the rule it breaks:

  enclosure_observer.py, EnclosureObservation
  "An adapter with no substrate time MUST answer None rather than
   supply its own clock, because a synthesized time is
   indistinguishable from a reported one once it is written down."

Writing a rule into a docstring does not enforce it. The absent-stamp
pin added alongside that rule covers only the four ControlPort
adapters and structurally cannot see EnclosureObserver implementors.

Harmless today only because the seam discards the field: the next
slice stops discarding it. At 2-BM the inversion would be total rather
than occasional. Both PSS permit PVs report an undefined EPICS stamp,
so every REAL reading already yields None there, while the monitor
re-subscribes every 5 seconds and each cycle's stream-end would carry
a real-looking time. The substrate-time column would be populated
exactly when the substrate said nothing, and NULL exactly when it
spoke.

Removing the stamp makes the `clock` dependency dead, so it goes too,
along with `clock=deps.clock` at the composition root. When CORA
learned of the disconnect is still recorded: the event's `occurred_at`
carries it.

`AlwaysPermittedEnclosureObserver` had the same shape in sentinel
form, a fixed 1970 date chosen for determinism across timezones. None
is equally deterministic and cannot be mistaken for a reading. Its
docstring also claimed a "first-boot no observer wired" code path;
grep finds no such wiring, so that claim is corrected rather than
preserved.

Two tests pinned the old behaviour and were correct when written.
They now pin absence, with the reasoning attached. Two more are added
for the gap that let this through: no test anywhere drove a reading
with no substrate time through the bridge. They are paired, absent and
present, so neither direction can regress into a constant.

Found by a four-lens gate review of the next slice's design. All four
reviewers reported it independently, from different starting points,
before any of them saw another's findings.

Verified: 30561 unit + architecture pass, pyright clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  apps/api/src/cora/api
  _enclosure_permit_observer.py
  main.py
  apps/api/src/cora/enclosure/ports
  enclosure_observer.py
Project Total  

This report was generated by python-coverage-comment-action

@xmap
xmap merged commit 8e36634 into main Aug 10, 2026
19 checks passed
@xmap
xmap deleted the worktree-observer-no-clock branch August 10, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant