os-sdlc: reload a timestamp column after stamping it with the DB clock #557

Open
opened 2026-09-11 15:46:41 +00:00 by jared · 0 comments
Owner

Context

ADR-0165 stamps lifecycle columns with Sequel::CURRENT_TIMESTAMP. Sequel does not reload a row after update, so the in-memory row keeps the Sequel::SQL::Constant object instead of a time. Model#refresh reloads the row but the associations plugin clears the association cache first, which drops the in-memory ADR-0171 commit record. During #552 this crashed DispatchSummary.seconds_between with undefined method 'to_time' for an instance of Sequel::SQL::Constant, and the interim fix reads a fresh row in Implementation#summary. Verified against sequel 5.108.0 source; vault note user-guide/sequel-model-transaction-and-multi-db-gotchas.md section 3.

Observed

Implementation#complete!, fail!, escalate! and the dispatch stamping methods leave the constant in memory. Implementation#summary works around it with Summary.for(Models.for(db).implementation[id]).

Reproduce

In a test, open an implementation, call complete!(position: "start"), then inspect completed_at on the same object: it is a Sequel::SQL::Constant.

Expected

One helper in the lifecycle module stamps a column with the DB clock and then reloads only that column (for example via this.get(column) assigned into values), keeping the association cache. All <event>_at writes use it. Implementation#summary goes back to Summary.for(self). ADR-0165 stays intact; the DB clock is still the writer. Replacing the constant with Time.now was rejected because ADR-0165 chose the DB clock so every writing process shares one clock.

Tasks

  • Add the stamp-and-reload helper; route every CURRENT_TIMESTAMP lifecycle write through it.
  • Revert Implementation#summary to Summary.for(self).
  • Test: after complete!, completed_at is a Time on the same object and commit_record survives.

Origin

Session: 5fdd0aa3-8a9c-4c31-a5b3-d575d8e709ab
Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/5fdd0aa3-8a9c-4c31-a5b3-d575d8e709ab.jsonl
Where: plugins/os-sdlc/lib/os_sdlc/runner/lifecycle.rb; plugins/os-sdlc/lib/os_sdlc/runner/implementation.rb
Filed by: agent, from the user's question on 2026-09-11 about replacing CURRENT_TIMESTAMP with Time.now. Parent: #552.

## Context ADR-0165 stamps lifecycle columns with `Sequel::CURRENT_TIMESTAMP`. Sequel does not reload a row after `update`, so the in-memory row keeps the `Sequel::SQL::Constant` object instead of a time. `Model#refresh` reloads the row but the associations plugin clears the association cache first, which drops the in-memory ADR-0171 commit record. During #552 this crashed `DispatchSummary.seconds_between` with `undefined method 'to_time' for an instance of Sequel::SQL::Constant`, and the interim fix reads a fresh row in `Implementation#summary`. Verified against sequel 5.108.0 source; vault note `user-guide/sequel-model-transaction-and-multi-db-gotchas.md` section 3. ## Observed `Implementation#complete!`, `fail!`, `escalate!` and the dispatch stamping methods leave the constant in memory. `Implementation#summary` works around it with `Summary.for(Models.for(db).implementation[id])`. ## Reproduce In a test, open an implementation, call `complete!(position: "start")`, then inspect `completed_at` on the same object: it is a `Sequel::SQL::Constant`. ## Expected One helper in the lifecycle module stamps a column with the DB clock and then reloads only that column (for example via `this.get(column)` assigned into `values`), keeping the association cache. All `<event>_at` writes use it. `Implementation#summary` goes back to `Summary.for(self)`. ADR-0165 stays intact; the DB clock is still the writer. Replacing the constant with `Time.now` was rejected because ADR-0165 chose the DB clock so every writing process shares one clock. ## Tasks - [ ] Add the stamp-and-reload helper; route every CURRENT_TIMESTAMP lifecycle write through it. - [ ] Revert `Implementation#summary` to `Summary.for(self)`. - [ ] Test: after `complete!`, `completed_at` is a Time on the same object and `commit_record` survives. ## Origin Session: 5fdd0aa3-8a9c-4c31-a5b3-d575d8e709ab Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/5fdd0aa3-8a9c-4c31-a5b3-d575d8e709ab.jsonl Where: plugins/os-sdlc/lib/os_sdlc/runner/lifecycle.rb; plugins/os-sdlc/lib/os_sdlc/runner/implementation.rb Filed by: agent, from the user's question on 2026-09-11 about replacing CURRENT_TIMESTAMP with Time.now. Parent: #552.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#557
No description provided.