Repository navigation
Port did.fun.timestamp, leap-second datestamp clamp, and SQLite BUSY/READONLY retry - #90
Merged
stevevanhooser merged 1 commit intoOct 23, 2026
Conversation
…USY/READONLY retry
Brings the three entries bin/check_bridge_coverage.py reported against
DID-matlab main back in sync.
timestamp (new, DID-matlab bb29861): did.fun.timestamp(raw=None) returns
the current UTC time as 'yyyy-mm-ddTHH:MM:SS.fffZ' and clamps a ':60'
leap second (with or without a fraction or trailing Z) to ':59.999' with
MATLAB's regex.
document (bb29861): Document stamps base.datestamp with
did.fun.timestamp(). The private _utc_timestamp it replaces had a looser
clamp (':60.123' -> ':59.999123'), so it is removed.
sqlitedb (decd155, da83fa3): 30 s busy timeout on open; do_run_sql_query
retries BUSY/READONLY with MATLAB's backoff schedule, reopening the
connection first for READONLY (poisoned handle / DBMOVED); exhausted
retries print the filesystem diagnostics. Because SQLiteDB groups writes
into transactions where mksqlite autocommits, the statement retry runs
only with no transaction open, and COMMIT is retried (never reopened)
through a new _commit(). Deviations are recorded in the bridge entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Dn4gCNCU2jUGdmfPVCAGK
stevevanhooser
pushed a commit
that referenced
this pull request
Oct 23, 2026
#91's bridge coverage job reports the same three drift problems #90 fixes. Merging that branch here makes this PR's check meaningful now; the merge is a no-op once #90 lands on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Dn4gCNCU2jUGdmfPVCAGK
stevevanhooser
deleted the
claude/port-timestamp-leapsecond-sqlite-readonly
branch
October 23, 2026 22:41
This was referenced Oct 23, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the three problems
bin/check_bridge_coverage.pyreports against DID-matlabmain, which make the "Bridge coverage vs DID-matlab" check fail on every PR. After this change the check reports 0 problem(s).What was ported
1.
did.fun.timestamp(new; DID-matlab bb29861)did.fun.timestamp(raw=None). It returns the current UTC time asyyyy-mm-ddTHH:MM:SS.fffZ. It clamps a:60leap second to:59.999using MATLAB's regex, with or without a fraction and with or without a trailingZ.status: ported) indid_matlab_python_bridge_util.yaml. Python'sdatetimecan't represent a leap second, so on the default path the clamp never fires. It only changes arawstring that is passed in, such as one MATLAB wrote.2.
document(c95b4f2 → bb29861)Document.__init__now setsbase.datestampwithdid.fun.timestamp(), as MATLAB's constructor now does.document._utc_timestamp. Its clamp was a plain:60.→:59.999substitution, which would have turned:60.123into:59.999123.3.
sqlitedb(8bea92c → da83fa3; decd155 + da83fa3)_open_dbconnects withtimeout=30.0, the same setting as MATLAB'spragma busy_timeout=30000. The previous Python default was 5 s.do_run_sql_queryretries BUSY/READONLY errors with MATLAB's backoff schedule (0.1, 0.2, 0.5, 1, 2, 4 s). For READONLY it reopens the connection before each retry, which is what clears a poisoned handle (DBMOVED)._is_retryable_sql_error,_is_readonly_errorand_collect_readonly_diagnosticsmirror the three new protected MATLAB helpers.Deviations (recorded in the entry's
sync_notes)SQLiteDBruns each add, remove or branch operation as one transaction. Rolling back or reopening partway through would drop the statements already pending, so the statement retry only runs when no transaction is open. Inside a transaction the error is reported and raised, and the caller's existing rollback runs._commit(), which retries a BUSY/READONLY commit while the transaction is still open. It never reopens, because that would lose the transaction. A truly poisoned handle at COMMIT is therefore raised rather than recovered. Replaying the whole operation was not attempted because_do_add_docalso copies ingested files, so a replay is not obviously safe.sqlite_errorcodewould be exact but needs Python 3.11+, and this package supports 3.10. Unlike MATLAB, onlysqlite3.Errorinstances count.Tests
tests/test_timestamp.pymirrors MATLAB'sTestTimestamp. It checks timestamps against Python's validator and thatDocumentstamps through the helper.tests/test_sqlitedb_transient_errors.pyuses real sqlite3 failures: a second connection holding the lock, and a handle swapped for a read-only one. Onlytime.sleepis faked. It covers the 30 s timeout, error classification, BUSY retry without reopen, READONLY reopen, retries running out, no retry inside a transaction, the COMMIT retry (including throughadd_branch), and the diagnostics.Local runs:
black --check,ruff check(pinned 0.16.5),pytest(766 passed), andcheck_bridge_coverage.pyagainst a full DID-matlab clone (0 problems).Found, not fixed here
_outside_bracketsand_strip_commentinbin/check_bridge_coverage.pyread a MATLAB transpose as the start of a string, for example the'inreshape(varargin,[],numRows)'; catch, endinsiderun_sql_noOpen. Everything after that line insqlitedb.mdrops out of the member checks. That includes themethods (Static, Access=public)block, whose 8 public static methods have no bridge entry. Fixing the parser turns those 8 into reported problems, so that belongs in its own PR.Generated by Claude Code