Source code for trader.persistence.deployed_versions
"""Repository for `deployed_versions` (issue #30).
A sparse deploy-event log, not a per-invocation timestamp — see
`DeployedVersion`'s docstring for why. `record_if_changed` is the only write;
`latest`/`version_at` are the two reads a future consumer (`tools/
roi_investigation.py`, `trader/replay/`) would use to attribute a historical
row to the code that produced it.
"""
from datetime import datetime
from sqlalchemy import select
from sqlalchemy.orm import Session, sessionmaker
from trader.persistence.models import DeployedVersion
__all__ = ["DeployedVersionRepository"]
[docs]
class DeployedVersionRepository:
"""Writes and reads `deployed_versions`."""
def __init__(self, session_factory: sessionmaker[Session]) -> None:
self._session_factory = session_factory
[docs]
def latest(self) -> DeployedVersion | None:
"""The most recently detected version, or `None` if never recorded."""
statement = (
select(DeployedVersion)
.order_by(DeployedVersion.detected_at.desc(), DeployedVersion.id.desc())
.limit(1)
)
with self._session_factory() as session:
return session.scalars(statement).first()
[docs]
def record_if_changed(
self, git_sha: str, git_ref: str | None, *, now: datetime
) -> bool:
"""Insert a new row iff `git_sha` differs from the most recent one.
Returns whether it inserted. A process running unchanged code across
many cycles or invocations must not grow this table on every one of
them — only an actual version change is an event worth recording.
"""
current = self.latest()
if current is not None and current.git_sha == git_sha:
return False
row = DeployedVersion(git_sha=git_sha, git_ref=git_ref, detected_at=now)
with self._session_factory() as session:
session.add(row)
session.commit()
return True
[docs]
def version_at(self, instant: datetime) -> DeployedVersion | None:
"""The version in effect at `instant`, or `None` if unrecorded.
The row with the greatest `detected_at <= instant` — `None` when
`instant` predates every recorded version, which must read as
unknown rather than defaulting to the earliest row on file.
"""
statement = (
select(DeployedVersion)
.where(DeployedVersion.detected_at <= instant)
.order_by(DeployedVersion.detected_at.desc(), DeployedVersion.id.desc())
.limit(1)
)
with self._session_factory() as session:
return session.scalars(statement).first()