Show loop-to-loop discussion on the board (#273) - #274
Conversation
A post's kind decides its quota; it was also being read as whether there is anything in it to read. Every `node send` carries the sender's full text and mirrors as a record, so the board folded away exactly the traffic it exists to show (#273). `wasWritten` rides beside the kind rather than becoming a third case of it, so an older build meets no raw value it cannot decode. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gz9hh5iq8MNpr9QSCjkbnt
The rail split the board on `kind`, and `kind` is a budget: every `node send` mirrors as a `.record` so mirrored traffic prunes on its own quota, and every `.record` was folded into a rollup that neither counted toward the badge nor remembered it had been opened. The effect was that two loops correcting each other's diagnosis held the conversation in the one place on the board a supervisor never reads (#273). `wasWritten` splits the two axes. A `node send`, a template or script edge, and a handoff carrying a payload all put words there that somebody chose; a payload-less edge or handoff is the board noticing that something fired. Written posts take a row and count toward `N NEW` — which stays clearable, because leaving the workspace advances the pointer over exactly what was drawn. Receipts keep the rollup, which now persists its open state and offers the older ones instead of only counting them. The record budget is untouched: a graph that merely talks still cannot evict a note. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gz9hh5iq8MNpr9QSCjkbnt
Defaulting a legacy record to "receipt" would have left every conversation already on a board exactly as buried as #273 found it — a fix that only helps graphs created after it shipped. This project's own board has 73 posts, most of them the loop-to-loop traffic the issue is about. There is no other signal left on those posts, so the two lines the mirror generates for itself are read back out of the body and everything else is taken as somebody talking. Narrow on purpose: the failure it can make is leaving a written message folded, which is where it already was. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gz9hh5iq8MNpr9QSCjkbnt
Review of #274 (high effort, adversarial)Reviewed The core logic is sound. Five findings, one of which should block.
1 — Receipts evict written messages (
|
|
Hold on to this one |
Review of #274, findings 1-4. 1. Receipts had the record budget to themselves as much as messages did, and a `.none`-transform edge on a cycle mirrors a fresh one every pass. Fifty passes would have evicted the discussion this section exists to show and left "50 delivery receipts" in its place — invisible before, because both halves were hidden, and so a regression the change introduced into its own feature. Three pools now, each pruned alone. 2. The two lines the mirror generates were written in GraphcodeKit and matched in ArtifactoryKit, with nothing tying them together: reword either and every legacy receipt silently reclassifies as written, with no compile error. They are ArtifactoryKit's constants now, and a test asserts the mirror's own output against the reader rather than against a copy of the string. 3. The rollup sits at the top of a bottom-anchored box, so "show all" grew its result off the top of the viewport and looked inert — the very failure the line was added to remove. It scrolls itself back under the eye. 4. Nothing set the expansion back, contradicting its own doc comment. Closing the rollup resets it and there is a "show fewer". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gz9hh5iq8MNpr9QSCjkbnt
Closes #273.
The problem
The rail split the Artifactory on
ArtifactoryPost.Kind, and that field is a budget: mirrored traffic is written as.recordso a talkative graph prunes on its own quota instead of evicting notes. It was also being read as "is there anything in here to read", which it never was — anode sendcarries every word its sender typed and mirrors as a.recordall the same. So the rail hid it, theN NEWbadge skipped it, and the rollup forgot it had ever been opened.Measured on this repo's own board while the issue was filed: the two posts carrying the actual technical substance (a root-cause correction and its acceptance) were the two least visible.
The fix
ArtifactoryPost.wasWrittensplits the axes.wasWrittennode send.message/.handoffedge with a template or script payload"Author finished.")Direction (3) + (2) from the issue, with one deliberate departure: the issue proposes making a written message a
.note. That would putnode sendtraffic in the note budget and reinstate the regressionKind's own doc comment records — two hundred sends evicting every note on the board. A thirdKindcase would fix the budget but hand an older build a raw value it cannot decode, andloadGraphreturningnilcosts a project its whole graph. A flag beside the kind keeps both properties, and old boards decode with their records still folded — exactly where they are today.Also in here, per the issue's other two directions:
@Stateto@AppStorage, beside the section's own fold.N earliercutoff opens. It was a line that named something and did nothing; it is nowN earlier — show all. The scroll box already clamps its own height, so opening the rest costs the rail nothing.extension, buying back thetype_body_lengthlines this change spends. Pure move, no logic.Verification
From
worktrees/fix-273-visible-messages, per theworktree-build-checkskill:xcodebuild -scheme graphcode buildxcodebuild -scheme graphcode test-scheme graphcode-cli/-scheme graphcodedbuildswiftlint lintswift format lint --strictSeven new tests, each confirmed present in the run: the written/receipt split at all three mirror sites, that written messages still prune on the record budget, that a pre-split board decodes its records as receipts, and that the badge both counts a written message and is cleared by leaving the workspace — the property the section's doc comment insists on.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Gz9hh5iq8MNpr9QSCjkbnt