Problem
The attention view cannot tell "nothing needs you" apart from "everything was thrown away".
buildAttentionModel drops records for several ordinary reasons and records each one as a diagnostic: unknown_host when a record names a host that is neither M5 nor M1, and the freshness suppressions stale_source, stale_companion, and clock_skew. The reader drops records earlier for unreadable, invalid_json, schema_invalid, repository_mismatch, workspace_mismatch, and id_mismatch. In all of those cases the source still reports status: ok with partial: false and truncated: false, because the read succeeded — it was the records that did not survive.
PR #150 drives its incompleteness signal off the source flags (partial or truncated) plus the payload-level diagnostics_truncated kind. That is deliberate: the earlier rule fired on any diagnostic at all, which made a permanently-on banner, and a client-side list of "which kinds mean data loss" is a copy of the model's vocabulary that will drift the first time a kind is added.
The consequence of the correct rule is this gap: when every card is suppressed, the view renders 0 actions need Justin and the decided empty state, with no indication that six records were read and discarded. The failure is quiet and it asserts something false.
It is worst in combination with #160. On any machine whose records name a host other than M5 or M1, every card is suppressed, so the view is not merely inert — it actively reports that there is nothing to do.
Proposed fix
Put the signal on the server, where the vocabulary lives, rather than in a client-side kind list.
Give each source entry a count of records that were read but did not become cards — for example suppressed_count, alongside the existing partial and truncated. The model already knows this number: it emits one diagnostic per suppression. Then the client's existing rule covers it with no new vocabulary: a source with suppressed_count > 0 is a source whose data is incomplete, and the notice can say how many records were suppressed rather than how many diagnostics exist.
Two details worth deciding together:
- Whether
suppressed_count should distinguish reader-level drops (malformed or foreign records) from model-level suppressions (unknown host, stale). One number is simpler and probably enough for a banner; two numbers let the view say something more useful about which is which.
- Whether a suppressed-only payload should show the empty state at all. "0 actions need Justin, 6 records suppressed" is honest; "0 actions need Justin" alone is not.
The client change is small once the field exists, and it is additive to the payload, so it does not break the existing guard.
Evidence
The server-side-signal approach was suggested by the lane worker while implementing that correction, and it is the right shape: the client should not learn the model's vocabulary.
Problem
The attention view cannot tell "nothing needs you" apart from "everything was thrown away".
buildAttentionModeldrops records for several ordinary reasons and records each one as a diagnostic:unknown_hostwhen a record names a host that is neitherM5norM1, and the freshness suppressionsstale_source,stale_companion, andclock_skew. The reader drops records earlier forunreadable,invalid_json,schema_invalid,repository_mismatch,workspace_mismatch, andid_mismatch. In all of those cases the source still reportsstatus: okwithpartial: falseandtruncated: false, because the read succeeded — it was the records that did not survive.PR #150 drives its incompleteness signal off the source flags (
partialortruncated) plus the payload-leveldiagnostics_truncatedkind. That is deliberate: the earlier rule fired on any diagnostic at all, which made a permanently-on banner, and a client-side list of "which kinds mean data loss" is a copy of the model's vocabulary that will drift the first time a kind is added.The consequence of the correct rule is this gap: when every card is suppressed, the view renders
0 actions need Justinand the decided empty state, with no indication that six records were read and discarded. The failure is quiet and it asserts something false.It is worst in combination with #160. On any machine whose records name a host other than
M5orM1, every card is suppressed, so the view is not merely inert — it actively reports that there is nothing to do.Proposed fix
Put the signal on the server, where the vocabulary lives, rather than in a client-side kind list.
Give each source entry a count of records that were read but did not become cards — for example
suppressed_count, alongside the existingpartialandtruncated. The model already knows this number: it emits one diagnostic per suppression. Then the client's existing rule covers it with no new vocabulary: a source withsuppressed_count > 0is a source whose data is incomplete, and the notice can say how many records were suppressed rather than how many diagnostics exist.Two details worth deciding together:
suppressed_countshould distinguish reader-level drops (malformed or foreign records) from model-level suppressions (unknown host, stale). One number is simpler and probably enough for a banner; two numbers let the view say something more useful about which is which.The client change is small once the field exists, and it is additive to the payload, so it does not break the existing guard.
Evidence
src/server/attention/buildAttentionModel.ts— theunknown_hostsuppression path andfreshnessSuppressions, eachcontinue-ing past card construction after pushing a diagnostic.src/server/attention/readAttentionRecords.ts— the typed reader outcomes that drop a record before the model sees it.src/client/attention/AttentionView.tsxat PR Add the Human Attention view with numbered cards, degraded states, and visibility-aware polling #150 head0c44dbe6—findDegradationtriggers onsource.partial || source.truncatedor thediagnostics_truncatedkind.main6bdf70726f7accc4ad31e19cda51e56a903fe21dwhile correcting PR Add the Human Attention view with numbered cards, degraded states, and visibility-aware polling #150's incompleteness rule.The server-side-signal approach was suggested by the lane worker while implementing that correction, and it is the right shape: the client should not learn the model's vocabulary.