refactor(929): drop redundant YAML re-parse in db::ops::move_item_stage
Every stage transition was reading the content body's YAML front matter to derive name/agent/blocked/depends_on, then writing those values straight back into the CRDT registers — but the CRDT was already the source of truth for all of these fields. The reparse was at best a no-op and at worst could regress the CRDT to stale YAML values during transitions on items whose YAML was out of date. Now move_item_stage: - writes the new stage to the CRDT with None for every other field, so write_item leaves existing registers untouched. - reads name/agent/blocked/depends_on back from the CRDT view when mirroring the row into the SQLite shadow table (still needed because the shadow stores a denormalised snapshot for read-side queries). The yaml_legacy::parse_front_matter import is gone from db/ops.rs; the only path still using it on the production side is ItemMeta::from_yaml, which is a caller convenience (mostly used in test fixtures). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-25
@@ -132,24 +132,10 @@ pub fn move_item_stage(
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let (name, agent, _ignored_retry_count, blocked, depends_on) = content
|
||||
.as_deref()
|
||||
.or(current_content.as_deref())
|
||||
.and_then(|c| parse_front_matter(c).ok())
|
||||
.map(|meta| {
|
||||
(
|
||||
meta.name,
|
||||
meta.agent,
|
||||
meta.retry_count.map(|r| r as i64),
|
||||
meta.blocked,
|
||||
meta.depends_on
|
||||
.as_ref()
|
||||
.and_then(|d| serde_json::to_string(d).ok()),
|
||||
)
|
||||
})
|
||||
.unwrap_or((None, None, None, None, None));
|
||||
|
||||
// CRDT stage transition.
|
||||
// Story 929: metadata (name/agent/blocked/depends_on) is owned by the
|
||||
// CRDT typed registers — no need to re-derive it from the content body's
|
||||
// YAML front matter on every stage transition. Pass `None` for those
|
||||
// fields so write_item leaves the existing registers untouched.
|
||||
let merged_at_ts = if crate::pipeline_state::Stage::from_dir(new_stage)
|
||||
.is_some_and(|s| matches!(s, crate::pipeline_state::Stage::Done { .. }))
|
||||
{
|
||||
@@ -160,11 +146,11 @@ pub fn move_item_stage(
|
||||
crate::crdt_state::write_item(
|
||||
story_id,
|
||||
new_stage,
|
||||
name.as_deref(),
|
||||
agent.as_deref(),
|
||||
None,
|
||||
blocked,
|
||||
depends_on.as_deref(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
merged_at_ts,
|
||||
@@ -176,15 +162,24 @@ pub fn move_item_stage(
|
||||
// transitions.
|
||||
crate::crdt_state::set_retry_count(story_id, 0);
|
||||
|
||||
// Shadow table — always reset retry_count to 0 on stage transition.
|
||||
let retry_count: Option<i64> = Some(0);
|
||||
// Shadow table — read current metadata from the CRDT so the SQLite
|
||||
// mirror stays in sync. Always reset retry_count to 0 on stage transition.
|
||||
if let Some(db) = PIPELINE_DB.get() {
|
||||
let view = crate::crdt_state::read_item(story_id);
|
||||
let name = view.as_ref().and_then(|v| v.name().map(str::to_string));
|
||||
let agent = view.as_ref().and_then(|v| v.agent().map(str::to_string));
|
||||
let blocked = view.as_ref().map(|v| v.blocked());
|
||||
let depends_on = view
|
||||
.as_ref()
|
||||
.map(|v| v.depends_on())
|
||||
.filter(|d| !d.is_empty())
|
||||
.and_then(|d| serde_json::to_string(d).ok());
|
||||
let msg = PipelineWriteMsg {
|
||||
story_id: story_id.to_string(),
|
||||
stage: new_stage.to_string(),
|
||||
name,
|
||||
agent,
|
||||
retry_count,
|
||||
retry_count: Some(0),
|
||||
blocked,
|
||||
depends_on,
|
||||
content,
|
||||
|
||||
Reference in New Issue
Block a user