Skip to content

docs: message edit/delete, AI assistant bridge, push decision matrix, contract function how-to - #680

Merged
codebestia merged 1 commit into
codebestia:devfrom
Themancalledpg:docs-batch
Oct 22, 2026
Merged

codebestia merged 1 commit into
codebestia:devfrom
Themancalledpg:docs-batch

Conversation

@Themancalledpg

Copy link
Copy Markdown
Contributor

closes #618
closes #619
closes #622
closes #635

Four documentation issues, each traced against the current source rather than written from the issue description alone.

apps/backend/docs/concepts-message-edit-delete.md (#618)

edit_message inserts a new linked message rather than mutating the original. Found while tracing it: editsMessageId always points at the root message, not the previous edit in a chain, so an edit chain is not literally the backward linked list the read-side comment on supersededRows describes it as. delete_message nulls ciphertext, hard-deletes every message_envelopes row, and conditionally soft-deletes an attached file only if no other live message still references it.

Covers: the sender-only authorization rule for both; that a deleted message's envelope can never reach a device via /sync (both because the envelopes are already gone and because of an explicit isNull(messages.deletedAt) filter); that an edit's sibling-device requirement runs through the exact same findMissingSiblingDeviceIds send_message uses; the honest limit that delete cannot un-reveal plaintext a recipient already decrypted.

A real finding, not assumed from the existing code comments: delete_message double-emits message_deleted to two different room names, and every connected socket joins both at connect time, so a client receives the event twice per delete, not once. Documented, with the recommendation that a client dedupe on messageId.

apps/backend/docs/concepts-ai-assistant-bridge.md (#619)

Traces the full path: client event, rate-limit bucket, the hardcoded http://localhost:8000/chat call, the reply persisted and fanned out through the same message_envelope pipeline as any other message.

States plainly that the reply is stored unencrypted (the column is named ciphertext, but what's in it is plaintext) and that the user's message leaves Clicked's infrastructure entirely and reaches OpenAI, per the AI agent's own api-chat.md. Documents the single try/catch collapsing every distinct failure mode (connection refused, non-2xx, malformed JSON, DB error) into one generic error with no way for a client to tell them apart.

apps/backend/docs/concepts-push-decision-matrix.md (#622)

The full filter chain in pushFilter.ts as a decision table. Confirmed from presence.ts's isOnline that online status is checked per-user via a single presence hash, not per-device, so one online device suppresses push to every other device that user owns, before the separate per-device isDeviceConnected check even runs.

Layers in the 2-second coalescing window and 30-second per-device rate limit both push paths share via queueCoalescedPush, confirms the push payload carries no message content, and notes a real asymmetry: dispatchOfflinePush always passes an explicit recipientDeviceIds list but sendPushForMessage never does, so that filter stage is a no-op for the file-message path today.

contracts/docs/howto-add-contract-function.md (#635)

Worked example of a read-only function (is_initialized) and a state-changing one (set_paused, which also gates transfer and emits a new event) on token_transfer, chosen specifically because it's the one contract with an in-place upgrade path. Both examples were actually compiled against the real contract and its existing test suite (8/8 passing, verified locally and reverted before committing, not written from reading the code alone).

Documents regenerating test_snapshots/ and that the CI check that fails if it's forgotten is simply cargo test's own storage-footprint mismatch detection, not a separate check. Covers the frontend side (building, simulating, signing, submitting via soroban.ts's existing transferToken pattern) and when the backend's Stellar listener (#331) needs its topic filter and decode logic extended for a new event, linking the events reference (#351).

Also

Added index entries for all four docs in docs/README.md, matching the existing per-doc one-line-description convention.

…on matrix, contract function how-to (codebestia#618, codebestia#619, codebestia#622, codebestia#635)

concepts-message-edit-delete.md (codebestia#618): edit_message inserts a new
linked message rather than mutating the original (editsMessageId
always points at the root, not the previous edit in a chain, not a
literal backward linked list despite how the read-side comment on
supersededRows describes it); delete_message nulls ciphertext, hard
deletes every message_envelopes row, and conditionally soft-deletes
an attached file only if no other live message still references it.
Documents the sender-only authorization rule for both; that a
deleted message's envelope can never reach a device via /sync (both
because the envelopes are already gone and because of an explicit
isNull(messages.deletedAt) filter); that an edit's sibling-device
requirement runs through the exact same findMissingSiblingDeviceIds
send_message uses; the honest limit that delete cannot un-reveal
plaintext a recipient already decrypted; and that delete_message
actually double-emits message_deleted to two different room names
every connected socket joins, so a client receives it twice, not
once, a real finding from tracing the two io.to() calls against
index.ts's connection setup, not something I assumed from the
existing code comments alone.

concepts-ai-assistant-bridge.md (codebestia#619): traces client event to
rate-limit bucket to the hardcoded http://localhost:8000/chat call to
the reply being persisted and fanned out through the same
message_envelope pipeline as any other message. States plainly that
the reply is stored unencrypted (same storage column named
ciphertext, actually plaintext) and that the user's message leaves
Clicked's infrastructure entirely and reaches OpenAI, per the AI
agent's own api-chat.md. Documents the single try/catch collapsing
every distinct failure mode, connection refused, non-2xx, malformed
JSON, DB error, into one generic error with no way for a client to
tell them apart.

concepts-push-decision-matrix.md (codebestia#622): the full filter chain in
pushFilter.ts as a table, confirming from presence.ts's isOnline that
online status is checked per user via a single presence hash, not per
device, so one online device suppresses push to every other device
that user owns, before the separate per device isDeviceConnected
check even runs. Layers in the 2 second coalescing window and 30
second per-device rate limit both push paths share via
queueCoalescedPush, confirms the push payload carries no message
content, and notes a real asymmetry: dispatchOfflinePush always
passes an explicit recipientDeviceIds list but sendPushForMessage
never does, so that filter stage is a no-op for the file-message
path today.

howto-add-contract-function.md (codebestia#635): worked example of a read-only
function (is_initialized) and a state-changing one (set_paused, which
also gates transfer and emits a new event) on token_transfer, chosen
specifically because it is the one contract with an in-place upgrade
path; both examples were actually compiled against the real contract
and its existing test suite (8/8 passing) before being written up,
not written from reading the code alone. Documents regenerating
test_snapshots/ and that the CI check that fails if it's forgotten is
simply cargo test's own storage-footprint mismatch detection, not a
separate check. Covers the frontend side (building, simulating,
signing, submitting via soroban.ts's existing transferToken pattern)
and when the backend's Stellar listener (codebestia#331) needs its topic filter
and decode logic extended for a new event, linking the events
reference (codebestia#351).

Added index entries for all four docs in docs/README.md, matching the
existing per-doc one-line-description convention.
@drips-wave

drips-wave Bot commented Oct 21, 2026

Copy link
Copy Markdown

@Themancalledpg Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@codebestia
codebestia merged commit 3846027 into codebestia:dev Oct 22, 2026
7 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants