@@ -307,7 +307,7 @@ export async function materializeExecutionDataForDisplayWithBlockOutputs(
307307 'traceStore.blockOutputRunProvenance'
308308 )
309309 const provenanceFaults = new Map < string , StoredDisplayProvenanceFault > ( )
310- if ( isResolvedSecretTraceProvenanceV1 ( runProvenance ) && ! runProvenance . complete ) {
310+ if ( isIncompleteStoredEnvelope ( runProvenance ) ) {
311311 provenanceFaults . set ( 'run' , 'incomplete' )
312312 }
313313 const blockOutputs = new Map < string , unknown > ( )
@@ -318,11 +318,11 @@ export async function materializeExecutionDataForDisplayWithBlockOutputs(
318318 if ( ! blockState || blockState . output === undefined ) continue
319319
320320 const hasExactProvenance = Object . hasOwn ( blockState , RESOLVED_SECRET_PROVENANCE_KEY )
321- if ( hasExactProvenance ) {
322- const blockProvenance = blockState [ RESOLVED_SECRET_PROVENANCE_KEY ]
323- if ( isResolvedSecretTraceProvenanceV1 ( blockProvenance ) && ! blockProvenance . complete ) {
324- provenanceFaults . set ( `blockOutput: ${ blockId } ` , 'incomplete' )
325- }
321+ if (
322+ hasExactProvenance &&
323+ isIncompleteStoredEnvelope ( blockState [ RESOLVED_SECRET_PROVENANCE_KEY ] )
324+ ) {
325+ provenanceFaults . set ( `blockOutput: ${ blockId } ` , 'incomplete' )
326326 }
327327 const registry = hasExactProvenance
328328 ? await importResolvedSecretTraceRegistry (
@@ -377,17 +377,27 @@ async function importResolvedSecretTraceRegistry(
377377
378378type StoredDisplayProvenanceFault = 'incomplete' | 'malformed'
379379
380+ /** True for a stored envelope that parses but cannot vouch for the value it accompanies. */
381+ function isIncompleteStoredEnvelope ( value : unknown ) : boolean {
382+ return isResolvedSecretTraceProvenanceV1 ( value ) && ! value . complete
383+ }
384+
380385const MAX_REPORTED_PROVENANCE_FAULT_PARTS = 20
381386
382387/**
383- * One attributed line per display materialization, in place of one registry summary per envelope
384- * per view.
388+ * One attributed line per display function per materialization, in place of one registry summary
389+ * per envelope per view.
385390 *
386391 * The registry summaries these replace carried counts and a workspace but no execution id, so a
387392 * reader repeatedly materializing the same stored rows produced an unattributable stream — the
388393 * lines could not say which executions to go look at. Incomplete stays at warn (a stored state
389394 * being re-read); malformed stays at error (a stored envelope that cannot be parsed is a fault
390395 * wherever it is met, matching the level its registry reason carries elsewhere).
396+ *
397+ * A block-outputs read runs the display projection first, so an incomplete run envelope appears
398+ * once under each site — `traceSpans` guarding the span projection, `run` as the block fallback.
399+ * Two sites reading the same envelope are two facts about the view; collapsing them would couple
400+ * the display functions to share reporting state for one line less.
391401 */
392402function reportStoredDisplayProvenanceFaults (
393403 site : string ,
@@ -489,7 +499,7 @@ export async function projectExecutionDataForDisplay(
489499 const projectionStore = createReadOnlyProjectionStore ( context )
490500
491501 const provenanceFaults = new Map < string , StoredDisplayProvenanceFault > ( )
492- if ( isResolvedSecretTraceProvenanceV1 ( provenance ) && ! provenance . complete ) {
502+ if ( isIncompleteStoredEnvelope ( provenance ) ) {
493503 provenanceFaults . set ( 'traceSpans' , 'incomplete' )
494504 }
495505
0 commit comments