Both ReadProjectionProgressAsync overloads hardcode LastHeartbeat and AgentStatus to null, and neither selects the columns — so the targeted per-cell progression read returns NULL for exactly the two fields a monitor would call it for, even with EnableExtendedProgressionTracking on and the columns populated.
src/Marten/Storage/MartenDatabase.EventStorage.cs:
// :419 SQL is only "select name, last_seq_id from ... where name like ..."
// :450
return best is null ? null : new ProjectionProgressRow(projectionName, tenantId, bestSequence, null, null);
// :480 SQL is only "select last_seq_id from ... where name = ..."
// :490
return new ProjectionProgressRow(name.Name, name.TenantId, sequence, null, null);
The rationale is stale
The XML docs assert a world that no longer exists — :402-403:
ProjectionProgressRow.AgentStatus and ProjectionProgressRow.LastHeartbeat are always null: Marten models the columns but no daemon path writes them (#519).
and :465-466 repeats it. ProjectionProgressRow's own doc in JasperFx (src/JasperFx.Events/ProjectionProgressRow.cs:21-25) says the same.
That was true when #519 was written. Since #537 the daemon does write them — ExtendedProgressionWriter → WriteExtendedProgressionAsync populates heartbeat and agent_status on every flush, and AllProjectionProgress reads them back correctly via ProjectionProgressStatement + ShardStateSelector. Only this read path was never updated.
Why it matters
#435 added ReadProjectionProgressAsync(projectionName, tenantId, …) specifically as a targeted per-cell read for monitoring — the alternative to pulling every row through AllProjectionProgress. A caller who takes that supported path to ask "is this shard's agent alive" gets NULL, with no indication the answer is a placeholder rather than a fact. The row-scan path they were meant to avoid returns the real value.
Fix
Add the two columns to both queries when EnableExtendedProgressionTracking is on, hydrate them into the record, and drop the stale comments in both repos. The like query at :419 already reads name for ShardName.TryParse, so it's a column-list change.
Note ProjectionProgressRow has no field for pause_reason, running_on_node, or the failure_* columns — worth deciding whether this read should carry those too, or stay minimal and point monitors at AllProjectionProgress.
Found while auditing #5167. See also the companion issues on the never-written *_behind_threshold columns and the never-written high-water heartbeat.
Both
ReadProjectionProgressAsyncoverloads hardcodeLastHeartbeatandAgentStatustonull, and neither selects the columns — so the targeted per-cell progression read returns NULL for exactly the two fields a monitor would call it for, even withEnableExtendedProgressionTrackingon and the columns populated.src/Marten/Storage/MartenDatabase.EventStorage.cs:The rationale is stale
The XML docs assert a world that no longer exists —
:402-403:and
:465-466repeats it.ProjectionProgressRow's own doc in JasperFx (src/JasperFx.Events/ProjectionProgressRow.cs:21-25) says the same.That was true when #519 was written. Since #537 the daemon does write them —
ExtendedProgressionWriter→WriteExtendedProgressionAsyncpopulatesheartbeatandagent_statuson every flush, andAllProjectionProgressreads them back correctly viaProjectionProgressStatement+ShardStateSelector. Only this read path was never updated.Why it matters
#435 added
ReadProjectionProgressAsync(projectionName, tenantId, …)specifically as a targeted per-cell read for monitoring — the alternative to pulling every row throughAllProjectionProgress. A caller who takes that supported path to ask "is this shard's agent alive" gets NULL, with no indication the answer is a placeholder rather than a fact. The row-scan path they were meant to avoid returns the real value.Fix
Add the two columns to both queries when
EnableExtendedProgressionTrackingis on, hydrate them into the record, and drop the stale comments in both repos. Thelikequery at:419already readsnameforShardName.TryParse, so it's a column-list change.Note
ProjectionProgressRowhas no field forpause_reason,running_on_node, or thefailure_*columns — worth deciding whether this read should carry those too, or stay minimal and point monitors atAllProjectionProgress.Found while auditing #5167. See also the companion issues on the never-written
*_behind_thresholdcolumns and the never-written high-water heartbeat.