Composer: toggle type badges, edit-mode media adding, inline URL adder, 📦 Things rename - #496
Conversation
…inline URL adder, 📦 Things rename - Post-type badges are now additive toggles: Text is the always-on base; Photos, Marketplace, and Things each switch their field group on top without deselecting the others (clicking Text switches them all off). The stored crystal type is derived from the live toggles (things > marketplace > photos-with-visual-media > text), so the server vocabulary is unchanged. The media panel only shows when Photos is on. - Edit mode mounts the live upload panel again: PATCH /api/v1/things attachmentIds is upgraded from a pure-permutation reorder to a sync — the full desired display order that must cover every bound id (removals still rejected) and may append newly uploaded ready drafts, which are bound with the same owner/purpose fences create-time binding uses (plus an owner-fenced post-family target check so an edit can never deface another owner's thread). - The linked-image URL adder moves below the upload grid as a single inline input with an Add button: each valid URL becomes a grid tile and the field clears for the next one (Enter works, multi-URL paste splits). - 🌀 Thingtime badge renamed to 📦 Things (POST_TYPE_META, composer eyebrows, feed filter chips follow). Verified: attachments + things unit suites green (planAttachmentSync + sync-kind tests added), Vite client build green, live browser pass on the worktree dev stack at desktop + 375px mobile (toggle combos, URL adder, create, edit-add-linked-image, Things sheet). Upload binding on edit is unit-tested; local stack has no S3, so the upload-complete-then-save flow needs a preview/prod pass per TESTING.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🧹 Develop S3 preview removedThe PR-specific alias and every workflow-created develop deployment were removed when this PR closed. The ordinary generated Vercel Preview remains available on the shared development runtime. |
Lopu repository reviewLopu reviewed this PR against develop as Thingtime's principal PR and repository manager. Using Claude Opus 5. Lopu found no justified local change to publish from this review pass. The model did not leave a detailed report; inspect this workflow run for the Lopu session log. |
…ding, inline URL adder, 📦 Things rename
…ding, inline URL adder, 📦 Things rename
…-visible pending; hidden-tolerant PATCH sync Round 2 of the composer overhaul (owner QA feedback on PR #496): - URL media now mints real linked-attachment things (POST /api/v1/attachments/link): attachmentLinked root marker, linked/<id> object key, zero object bytes, url-bearing crystal with a DECLARED render hint, ready at mint, moderation stamped 'skipped'. Accounting treats the shape as a closed variant (partial/forged combinations fail closed); only doc bytes hit quota; the server never fetches the URL. Duplicate URLs are deliberately allowed. Rate-limit row, import-map entry, and apiDocs entry (docs registry = Nitro registration + capability feature) included. - Lifecycle: cleanupClaimedDoc takes a lazy S3 getter and short-circuits linked docs straight to the transactional remove+refund, so delete/cancel/ reap/cascade/session-sweep work without S3; the content endpoint 302s linked ids to their external URL as a renderer fallback; the analyzer skips linked docs. - Composer: the add-by-URL input lives INSIDE the Media & files panel below the grid (Add button; clears per add; probe demotes extensionless URLs to file when they fail to load as images); linked entries share the uploads list so reorder/snapshot/markCommitted/remove behave identically; the panel stays usable before upload approval. Legacy crystal.images seed as local linked tiles on edit and migrate to linked attachments on save; new posts never write crystal.images. LinkedImageGallery removed from the composer. - Renderers (card gallery, lightbox, media page, reorder gallery, layout canvas) use crystal.url directly for linked media; linked file rows and downloads open the original URL in a new tab. - Moderation fixes for the vanished-image + edit-409 report: owners now see their own PENDING attachments (pending: true → "Checking…" badge; blocked stays hidden for all), and planAttachmentSync exempts moderation-hidden bound ids from the cover requirement, re-stamping them after the requested order inside the bind transaction. Verified: full test:unit green (new suites: linked crystal canonicalization, closed-union accounting, ownerView pending, hidden-tolerant sync, extension table client/server pin), build:client green, live E2E on the worktree stack (duplicates, pdf file-row + download, probe path, post render from external URLs, edit-add-URL save via PATCH sync, legacy 4-image migration, linked mint/delete with no S3 configured, desktop + 375px mobile). Detailed note in PRs/496-claude-post-editor-media-badges-7b2acd--*.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round 2 — URL media unified into attachments + the edit-save/vanishing-image fixes (a6409b8)All five QA items from testing are addressed: 1. URL media now IS the media/attachments system. Adding a URL mints a real linked attachment ( 2. Duplicate URLs are allowed. Every Add mints its own attachment — same URL twice = two tiles (verified live). 3. The edit/save failure is fixed — root cause found. Uploaded images get a 4. …that same hiding is why your uploaded picture “disappeared”. Now: you always see your own pending media with a small “Checking…” badge (card, file rows, edit composer); other viewers see it once analysis clears. The save path additionally tolerates moderation-hidden bound ids, so that 409 can’t recur even from a stale tab. 5. Image-vs-file detection with working download. File-extension URLs ( Bonus: editing an old post that still has legacy URL-images migrates them into linked attachments on save — everything renders through one gallery from then on. Verified: full 🤖 Generated with Claude Code |
…ding, inline URL adder, 📦 Things rename
…atomic S3 failure, name round-trip, mint compensation, seed cap) Confirmed by the 12-agent adversarial review of a6409b8: - The content endpoint now 404s linked attachment ids instead of 302ing to crystal.url — the redirect made the first-party content URL an open redirect to attacker-chosen origins (CWE-601). Renderers always use crystal.url directly, so nothing needed the fallback. - cleanupClaimedDoc resolves S3 BEFORE the destructive deleting claim for non-linked docs (attachmentLinked is immutable, so the pre-claim doc is authoritative): an unconfigured/broken S3 fails atomically again instead of half-deleting a mixed linked+uploaded cascade and stranding uploaded docs in an endless deleting retry loop. Linked docs still need no S3. - linkedAttachmentNameForUrl re-validates after the 255-char slice (trim, control chars, well-formed unicode; falls back hostname → 'linked-media') so exotic basenames can no longer produce a non-canonical crystal that fails the mint. Round-trip pin test added. - A linked mint whose tile was removed mid-flight now fires a compensating delete instead of orphaning the draft until the 24h reap. - Legacy image seeds cap at the remaining attachment slots so a >25-media legacy post cannot 400-loop on every save. Accepted-by-design (documented in the PR note): linked mints skip the beta upload-approval gate and byte moderation — exact parity with the legacy crystal.images flow they replace; pre-hygiene URLs that fail today's canonicalizer drop on edit-save exactly as the old composer's client filter already did. Verified: test:attachments 134/134 green, lint green, build:client green, live check — content?id=<linked> now 404s while the card keeps rendering from the external URL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adversarial review round (post-push hardening, 1bec66c)Ran a 12-agent adversarial review workflow over the linked-media commit; 9 findings, 8 confirmed. Fixed immediately:
Two accepted-by-design items flagged for your call (detailed in 134/134 attachment tests, full unit suite, lint and client build all green. 🤖 Generated with Claude Code |
…ding, inline URL adder, 📦 Things rename
🤖 Lopu live PR updateStatus: ↪️ Resolver finished; a newer conflict remains Current phase: The next detector event will own the current branch state Estimated completion: Done — no further active-work ETA. Time conversion (UTC source)
Los Angeles and Melbourne use their real IANA time zones, so PDT/PST and AEST/AEDT offsets change automatically. Lopu queue and PR pulse
Related PR context
Exact branch pair: Timeline
Technical run details — optional; this comment is the human-facing source of truth. |
🤖 Lopu live PR updateStatus: 🛠️ Lopu is actively working Current phase: Merging the target branch into the PR branch Estimated completion: around 12:50 UTC (~14 minutes; adjusted as work moves). Next automatic check-in: within 10 minutes, or sooner when the phase changes. You can stay on this PR; there is no need to find the Actions run. Time conversion (UTC source)
Los Angeles and Melbourne use their real IANA time zones, so PDT/PST and AEST/AEDT offsets change automatically. Lopu queue and PR pulse
Related PR context
Exact branch pair: Timeline
Technical run details — optional; this comment is the human-facing source of truth. |
…ding, inline URL adder, 📦 Things rename
…ding, inline URL adder, 📦 Things rename
…ding, inline URL adder, 📦 Things rename
|
🤖 Lopu is resolving this PR — work started at 12:24 UTC. Expected to finish around 12:32 UTC (most updates still land in 3-8 minutes; the hosted-runner ceiling is 360). On success the target branch is merged into this PR branch, Graphify is rebuilt, and this status comment updates with the result — no manual action is needed meanwhile. |
…gallery-search # Conflicts: # remix/CHANGELOG.md # remix/app/components/Feed/PostComposer.tsx
|
✅ Promoted to An earlier run stood aside on this PR; that verdict no longer applies. |
|
✅ Promotion #517 has verified source lineage at current |
|
🚀 Promotion PR for |
…e media adding, inline URL adder, 📦 Things rename (#496)
…e media adding, inline URL adder, 📦 Things rename (#496)
…e media adding, inline URL adder, 📦 Things rename (#496)
…e media adding, inline URL adder, 📦 Things rename (#496)
…e media adding, inline URL adder, 📦 Things rename (#496)
…e media adding, inline URL adder, 📦 Things rename (#496)
…e media adding, inline URL adder, 📦 Things rename (#496)
…-badges-7b2acd--to-main [Promote] Composer: toggle type badges, edit-mode media adding, inline URL adder, 📦 Things rename (#496)
|
🤖 Promotion conflict resolution was queued automatically for Conflicted source paths: The trusted worker will reconstruct, verify, publish, and attest the review branch; no manual branch update is needed.
|
|
🔄 Promotion state moved or could not be revalidated while this run was active; the promoter is replanning safely. Branch: No pause was recorded because develop, the base, or the reserved branch no longer matches this transient run snapshot. A fresh promoter run was requested to re-derive authority and continue. Review the run. |
|
🤖 Promotion conflict resolution was queued automatically for Conflicted source paths: The trusted worker will reconstruct, verify, publish, and attest the review branch; no manual branch update is needed.
|
|
🤖 Promotion conflict resolution was queued automatically for Conflicted source paths: The trusted worker will reconstruct, verify, publish, and attest the review branch; no manual branch update is needed.
|
|
🤖 Promotion conflict resolution was queued automatically for Conflicted source paths: The trusted worker will reconstruct, verify, publish, and attest the review branch; no manual branch update is needed.
|
Composer: toggle type badges, edit-mode media adding, inline URL adder, 📦 Things
Four owner requests in one composer pass:
1. Media is addable when editing a post again
Edit mode previously replaced the upload panel with a read-only reorder gallery because binding was create-only. Now:
PATCH /api/v1/things { id, attachmentIds }is upgraded from a pure-permutation reorder to a sync: the list is the full desired display order. It must still include every bound id (removals stay a delete operation and get the 409), and it may append newly uploaded ready drafts, which are bound into the post via the existingbindReadyAttachmentsForPurposefences (owner-only, ready, purpose-matched, unexpired) inside a home-Mongo transaction. A new owner-fenced post-family target check means an edit can never bind the editor's media onto someone else's thread. Pure permutations keep the old non-transactional idempotent stamp path.planAttachmentSyncinattachmentCore.ts(+ unit tests),syncBoundTargetAttachmentsinattachmentStore.ts,syncReadyAttachmentsForTargetservice wrapper, PATCH route wired beforeupdateThingso the returned projection andboundAttachmentPresencecrystal validation both see the new media.commentdrafts (composer mints the matching purpose fromeditPost.thingtime).AttachmentComposernext to the reorder gallery; Save sendsattachmentIds = [reordered bound set, …new uploads]whenever either changed, andmarkCommittednow runs for edits too so unmount cleanup can't delete just-bound media.2. Type badges are additive toggles
Text is the always-on base. Photos, Marketplace, and Things each switch their field group on top without deselecting the others; clicking Text switches every extra group off. The stored crystal
typeis derived (things > marketplace > photos-with-visual-media > text), so the server vocabulary and feed rendering are unchanged — a files-only or empty media panel still saves as a valid text post. Text-only posts no longer show the media panel until Photos is toggled on. The old Thingtime-tab inner Photos/Marketplace buttons are gone; the top badges now control those groups everywhere.3. 🌀 Thingtime → 📦 Things
POST_TYPE_METArename, so the composer badges, feed filter chips, and algorithm interest labels all follow; composer eyebrows updated to match.4. URL adder below the upload grid, with an Add button
LinkedImageGallerygains aninlinevariant used by the composer: a single always-visible URL input + Add button below the media grid. Each valid URL becomes a preview tile and the field clears for the next one; Enter adds too, and pasting several whitespace-separated URLs adds them all. Other gallery usages keep the existing disclosure/textarea flow.Docs / tests
apiDocs.tsPATCH + attachments-completion entries updated for the sync contract.TESTING.md: toggle-badge, URL-adder, and edit-add-media checklist items; stale "no upload panel on edit" item rewritten.planAttachmentSyncsuite,postCreatesync-kind tests.test:attachments(125) andtest:things(20) green.Verification
build:clientgreen; targeted ESLint green (full-project tsc has known pre-existing failures).image), edit → add a 4th linked image → save → card shows 4, Things bottom-sheet opens/closes, no horizontal overflow.🤖 Generated with Claude Code