Skip to content

lody: an image staged on the landing attaches on a box — seam patch 12 closes seam patch 8's declared gap - #163

Merged
pythonlearner1025 merged 4 commits into
mainfrom
lody-landing-image-fix
Sep 1, 2026
Merged

lody: an image staged on the landing attaches on a box — seam patch 12 closes seam patch 8's declared gap#163
pythonlearner1025 merged 4 commits into
mainfrom
lody-landing-image-fix

Conversation

@pythonlearner1025

Copy link
Copy Markdown
Member

The defect

Seam patch 8 (#156) fixed attachments on a box by putting the local transport in
front of the cloud-token guard. It named the one entry point it could not fix
that way: hooks/use-chat-landing-image-draft.ts had no local handoff and no
degrade-to-file fallback, so there was nothing to move.

So on a box today:

Staged On the landing Inside a session
a file works works
an image fails — "Missing workspace or auth token" works (becomes a file)

An image on the landing is the one remaining combination.

The mechanism, and why this one

The behaviour that closes it is upstream's own, one surface away.
session-chat-input-area.tsx:1004-1066 turns an image it cannot upload into a
pending FILE attachment over the local transport, with the toast
sessions.imageStoredAsLocalFile. In-session that is one component holding both
state machines, so the image moves from pendingImages to pendingFiles in
place.

On the landing the same two state machines are two sibling hooks that
chat-landing.tsx mounts side by side and that already share one reserved
session id. So the degrade is the same move across that seam: the image hook
hands the raw File to the file hook's own addFiles.

That choice does three things a copied transport would not:

  1. The bytes take seam patch 8's fix rather than a second copy of it. Nothing
    about sendSessionFileToLocalRuntime is restated in the image hook.
  2. The degraded item gets the file draft's size and count limits, its chip, its
    status, and its Retry.
  3. Availability is asked, not re-derived. The file draft already computes
    canSendFileLocally; it now returns it. The alternative was a third copy of
    localMachineId === machineId && canUseElectronLocalFileSend().

The change

Seam patch 12, declared in vendor/lody/BLITZ-PATCHES.md. Five hunks in three
files, of which two files were already diverged by seam patches 7 and 8.

File Hunks Effect
hooks/use-chat-landing-image-draft.ts 3 an optional degradeToFileAttachments, a hoisted label, and the degrade inserted ABOVE the unchanged guard
hooks/use-chat-landing-file-draft.ts 1 returns the canSendFileLocally it already computes
components/chat/chat-landing.tsx 1 declares the file draft first and wires the two together

plans/evidence/lody-landing-image-degrade-pr.md holds the upstream PR sketch.
Drop the seam patch when upstream merges the fix.

Safety when a cloud token IS present

The same argument seam patch 8 made, and by construction rather than by
inspection.

The inserted block's condition leads with !authToken. With a token set it is
false, so startUpload runs the same statements in the same order as before —
the cloud upload, its telemetry and its catch are untouched. The guard below it
keeps its exact text and still owns the case where there is no token and no local
transport, which still fails with the same message.

The other three hunks add a parameter, a label and a returned field, and change
no existing expression. The reordered hook calls are independent: the file draft
has never read anything from the image draft.

The degrade is also deliberately NOT extended to a genuine upload failure,
although the in-session path degrades on any failure. Widening it that far would
change what a token holder sees, so this patch keeps to the tokenless case.

Tests

packages/webapp/test/lody-attachment-guard.test.tsx gains the landing-image
half, over the same three cases and the same stub window.ipc seam patch 8 used:

  1. no token, bridge present → the handoff runs and a transport:'local' FILE
    block reaches the outgoing message (this is the fix)
  2. no token, no bridge → still fails with "Missing workspace or auth token"
  3. token AND bridge → no handoff, the image stays the image draft's

It mounts BOTH real vendored hooks the way chat-landing.tsx does, because the
mechanism IS the move across them: a harness that mounted the image hook over a
hand-written callback would prove nothing about where the bytes go.

Verified against the pre-fix vendor tree with the new test in place: case 1
fails (expected [] to deeply equal [ { workspaceId: 'lw_guard', … } ]), cases 2
and 3 pass there unchanged.

Gates

  • npm run typecheck — clean.
  • npm run lint:gate — passed; 74 anti-slop findings, all at baseline.
  • BLITZDEV_MANAGED=1 npm test — 0 assertion failures.

The full run reported 8 failed tests in 5 daemon-backed webapp files, every one
of them lody_daemon_unavailable or a boot timeout: the known port-17789
environment issue. Re-run alone, that workspace reports 828 passed, 12 skipped,
0 failed tests
. One file still fails at the SUITE level —
test/lody-sharing-relay.test.ts, a beforeAll that times out waiting for a
joined frame from a real relay, with its 6 tests skipped. No assertion in the
tree fails, and nothing this change touches is reachable from either suite.

A note for the merge queue

Seam patch 12 was free at this branch's base. Another change may claim the same
number for the archive page; whichever lands second renumbers to 13. Nothing
else in the patch depends on the number.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN

pythonlearner1025 and others added 4 commits September 1, 2026 22:48
…llback

Seam patch 8 named the one attachment entry point it could not fix by moving
the guard: `use-chat-landing-image-draft.ts` had no local handoff and no
degrade-to-file fallback to move in front of it. So on a box a file attaches
from the landing, an image attaches from inside a session, and an image on the
LANDING is the single combination that still fails.

The behaviour that closes it is upstream's own, one surface away:
`session-chat-input-area.tsx` turns an image it cannot upload into a pending
file attachment over the local transport. Declare that mirror before making it,
and record the upstream PR sketch that lets us drop the patch again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
…token

Seam patch 12, five hunks in three files.

With no cloud token there is no image upload to attempt, but the landing's
sibling FILE draft can still hand the bytes to the machine over its local
transport. So the image hook drops the pending image and stages the raw `File`
on that draft — the same degrade `session-chat-input-area.tsx` performs when
both state machines live in one component, with the same toast.

The move re-uses the file draft's own entry point rather than restating
`sendSessionFileToLocalRuntime`, so the bytes take seam patch 8's fix, the file
draft's limits, its chip and its Retry. Availability is asked of that draft
(it already computes `canSendFileLocally`) instead of derived a third time.

The inserted block leads with `!authToken`, so with a token set it is skipped
and `startUpload` runs the same statements in the same order as before. The
cloud-credential guard's text is unchanged and still owns the case where there
is no local transport either.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
Extends the seam patch 8 suite with the landing-image half, over the same
three cases and the same stub `window.ipc`: no token with the bridge (the
fix), no token without it (the same refusal, from the unchanged guard), and a
token WITH the bridge (the cloud path, untouched).

It mounts BOTH real vendored hooks the way `chat-landing.tsx` does, because
the mechanism IS the move across them — a harness that mounted the image hook
over a hand-written callback would prove nothing about where the bytes go.
Verified: the first case fails against the pre-fix vendor tree, and the other
two pass there unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
The hunk tables list five; the opening line said four.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhdxNAYjV97JTv2pddcJiN
@pythonlearner1025
pythonlearner1025 merged commit fe94a92 into main Sep 1, 2026
10 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.

1 participant