| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
| |
A Phone section of the side menu leads to it, on the Android application
only; Settings no longer holds it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
| |
A month folder named 08 alone read like an album number.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Signing in on a desktop links this machine's node to the account, but never
over a key already linked (that would cut off the user's other machine) nor a
node set up for another account. On a real install both left the node reading
"Running" while the hub refused it in a loop, and nothing said why. And the
only way to unlink was the linked machine's own Node page, of no use once
that machine is gone.
- The Node page works out, from the node and the hub each time it looks,
whether this node can serve the signed-in account (nodeLinkProblem), and
says why not: "Link this node instead" (asked first) puts this node's key
on the account; "Use this node for my account" switches a node set up for
another account through node:start, which takeOver now lets past a node
that answers "running". The first version went through node:start for
both, and clicking it on a real install did nothing: a node signed in
before the account was linked elsewhere answers "running".
- The Profile page unlinks the account's node (DELETE /v1/users/me/node_key),
from any machine.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A test-signed install of the MSIX build, in the WindowsApps folder a Store
install uses, showed that every script-made piece of the NSIS model breaks
there, because each names the install folder and every update deletes it:
the firewall rules went stale, the PATH entries piled up pointing at deleted
folders, and the Startup-folder .vbs was refused ("Permission denied") right
after sign-in. The network capabilities the manifest declared covered
nothing: they make rules for sandboxed apps only, and a listener in the
package still got the Windows firewall prompt. The package's own startup
task was on by default, started the node whatever mode the Node page said,
and ran the console executable, whose window stopped the node when closed.
The package now declares what Windows then creates at install, carries
across updates and removes with the app, all without an administrator
prompt (each measured on the real install, through an update and a reboot):
- firewall rules for the node, in a custom manifest template, since only a
package-level element can hold them;
- the startup task, off by default, running meshbay-nodew.exe, a new build
of the daemon without a console;
- an execution alias for meshbay-node.exe, so the app adds no PATH entry.
The node's CLI switches the startup task (platform.startup_task, ctypes over
the WinRT ABI): Windows gives the package's identity to the executables in
it, not to a powershell.exe the app starts, which got "Element not found".
`meshbay-node autostart install | remove | status` therefore works in the
Store package from the app and a terminal alike; the app caches the answer,
since the Node page polls. Starting at boot stays the .exe installer's: the
Store package offers no service mode, and the CLI refuses `service install`
there. Process listings count both image names.
The Node page's status poll cleared the message of a refused action within
five seconds; the two errors are kept apart now (all Windows builds).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Android application sends the photos taken on the phone to one folder of
one group chosen by the member (docs/MESHBAY_DESIGN.md §9.12). The phone lists
MediaStore, keeps a ledger of what was sent and hands each photo's bytes to the
page by an opaque token on the packaged origin; the page decides when a run is
due and uploads through the existing path, one photo at a time under a slot.
- Once a day from the last finished run, on an unmetered network only;
"Back up now" asks first on mobile data. Leaving Wi-Fi stops after the file
in flight.
- Photos already on the phone are sent by default, newest first, under
<folder>/YYYY/MM; edits are sent beside the original as -edited-<date>.
- Additive by construction: nothing is ever deleted, renamed or replaced on
the node, and a photo deleted on the node is not sent again.
- A confirmation names the group, owner, members, folder and size when the
destination or starting point changes; a lasting refusal (disk full, folder
read-only or gone, no longer a member) is said once and retried a day later.
- No ACCESS_MEDIA_LOCATION, so the platform redacts photo locations.
- A dataSync foreground service keeps a run going with the screen off.
HEIC/HEIF photos are sent but not shown in Photos yet (§15.2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Nothing on the upload path knew about ENOSPC: a write that found no room
raised out of the handler, the catch-all answered "Request failed", and the
.part stayed behind holding the space that had run out. The node now refuses
with `disk_full` at chunk 0 when the announced size would leave less than
1 GiB free, and at any write that fails with ENOSPC/EDQUOT, dropping the
partial. The client carries the code on the error and the transfers panel
says "The node's disk is full" in every catalogue.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The page asked for the notification list at sign-in and at a token renewal,
and at no other time. A notification created after the application started,
such as a chat line the hub wrote 20 ms after the message, stayed unseen until
the next launch.
The hub has no channel to the page and is not polled on a timer, so the list
is asked for again on a gesture: the application returning to the foreground
(an Android phone included) and the home page, where the list is shown. Two
requests less than 30 s apart count as one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Signed chat_purge from the Chat settings deletes every stored message;
epoch keys and attachments stay. The ack is broadcast so open chat
panels empty.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The phone fetches what is new every fifteen minutes with a poll secret
(POST /v1/push/poll) that reads notification lines and nothing else. When a
UnifiedPush distributor is already installed, the hub also pushes at once,
encrypted to the phone (RFC 8291); losing the distributor falls back to
fetching.
The hub now honours "disable all notifications" itself: create_notification
creates nothing for that account, as it already did for a muted group, so
neither switch lets anything reach a phone. The interface used to be the only
reader of the account-wide switch.
Push endpoints are member-supplied URLs: a send refuses non-public
addresses, connects to the address it checked, and follows no redirect.
Android build untested here (no SDK on this machine).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
A member invited after the roster was read showed "key changed" on each
message until a reload. Read it again once per account and device on the
connection, shared by concurrent messages, and pin only the final verdict.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Found by the first Windows beta tester, then reproduced on a clean install.
After a service-mode install nothing set the node up for the account that
signed in: the boot task started a node that quit ("hub.username not set"),
and the sidebar showed Node / Create group only once the hub held a node key.
The only way to the wizard that provisions was the home page's welcome card,
which an account already in a group never sees. The way out was
`meshbay-node init` and the key pasted on the profile page -- which is also
what PACKAGING-GUIDE.md told people to do.
- main.js `node:ensure`, called by app.js at sign-in: provisions, starts and
links the node this build ships (Windows, bundled node only). A node set up
for another account, or an account linked to another node, is left alone.
node:start waits for it, so the two never race.
- The sidebar shows the Node section when a node exists on this machine.
- The Node page's status is the node's: its control API and the process
list, not the service task's state (a node started from a terminal ran
while the page said Stopped). Stop says Stopped only once no
meshbay-node.exe is left, and stays offered for a process that answers
nothing.
- CLI stop kills the pid that answered when a graceful stop does not finish,
and fails with the reason when a node process is still there.
- The daemon ends its process 3s after _shutdown(): Python's exit waited for a
busy indexer thread, with the control API already closed. Armed by main()
only, never by a daemon run inside a test.
- node.toml is read as utf-8-sig (PowerShell 5.1 writes a BOM), and a config
that cannot be read is logged instead of dying silently in service mode.
- "Pair this browser" queues the code for the next group of this node to
open instead of saying "Paired successfully"; no banner before a group.
- test_e2e_windows_app.py (opt-in, MESHBAY_WIN_E2E=1) drives the installed
app against a throwaway hub: fresh account to linked node, Stop, Start,
Restart, checked against the real processes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
A node busy indexing could miss the single 3 s check after a root was
added, and the button stayed hidden until a reload. Ask up to four times
before deciding there is no node on this machine.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Chunks sent while the reconnect's connect() runs throw at once, and six
retries 1.5 s apart ran out before the reconnect landed. Wait for it, up
to two minutes, without spending retries. Follow-ups parked in §15.3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
9269374 let the transfers header wrap, which broke the one-line header
test_layout_measured enforces. The button now sits beside what it clears,
and the header is title and summary only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
The header (title, summary, clear button) overflowed the 330 px panel in
French. Let it wrap, with a gap, and hide horizontal overflow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
An iPhone has no MediaSource; every film was refused as an
unsupported codec. A browser with neither now says so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The line sat above the results for as long as the page was open. It is now
said once a cross-group pass is over, for five seconds, in the same passing
note as "Link copied" — moved out of copy-link.js into note.js (`say(text,
ms)`), one note at a time for the whole page. The `.search-unreachable` rule
goes with the line it styled.
The copy-link probe now also checks in Chrome that the note goes by itself.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
and Search
"Copy link" puts the address group-link.js resolves on the clipboard, on the
hub's origin rather than the page's, so a link copied in the desktop
application is not app://meshbay. Files offers it for one row, from the
right-click menu or the toolbar with one row ticked (a phone's way in);
Music on one track's menu, whose dots a phone has; Photos on a right-clicked
tile and in the lightbox's bar. The video player and the file preview carry
a link button next to Download.
Applications get a `linkFor(entry | folderPath)` prop (MESHBAY_DESIGN.md
§9.2) and offer the action only when it names a link. The group page builds
it from the hub's row; Search from each result's own group and its path
before the merged views prefixed it, and names no link for a folder of the
merged tree, which a group name alone does not identify.
harness/copy_link_probe.py mounts the three applications in Chrome and reads
what reached the clipboard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A group can now be reached by the handle shown under its name, and a path
after it points inside the group: #/name@owner/root/dir/file downloads the
file and opens Files on its folder; a folder opens Files there. The handle
is resolved in the client against the account's own /v1/groups/mine, so no
hub route answers for a name and nobody can probe for one. While a group is
open the address shows the handle (replace, no history entry); a linked path
is taken out of the address once acted on, so a reload does not download
twice.
Signing in no longer sends everyone home: the form stood in for the page the
address named, and that is where a link opened signed out was going.
group-link.js holds the parsing and lookups, executed whole by
test_group_link.py; harness/group_link_probe.py drives the router in Chrome.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Members list showed the hub's membership, which an account gains when it
accepts the invitation or redeems a link, before it has presented its code to
the node. The node's roster is the authority (MESHBAY_DESIGN.md §3.4), so
the list now crosses the hub's members with the sealed group roster the node
already sends every connected member. An account the node has not admitted
yet is shown to the owner alone, as waiting for its code, with the Remove
button; other members do not see it. When the roster cannot be read, the
hub's list is shown as before.
groupRoster() takes { fresh: true } so the page sees who joined since the
connection opened.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
The hub address is where the person's account lives, so it sits with the
account: on the Profile page, after Sessions and before deleting the account.
Settings keeps "Keys on this device", which describes the machine.
The hint now says what the setting is: the hub this application connects
to, and that changing it signs you out while the account stays on that hub.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
docs/MESHBAY_HTTP_API.md lists every route of the hub (by domain, with the
authentication each requires) and of the node's loopback control API. It is
written by docs/generate_http_api.py from the routes and their docstrings;
test_http_api_doc.py fails when the file drifts from the code or when a
route has no docstring, so a new route must say what it does.
79 routes had no docstring and get a one-line description; a few whose first
line did not describe the route get a summary line.
The login page's developer docs gain an API link next to Design and
Protocol, in every language. README, MESHBAY_DESIGN.md (§0.1, §6.7, §7) and
CLAUDE.md point to the listing; README also points to examples/.
The examples scripts with a shebang become executable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
The first-run "Which hub?" field now starts filled with meshbay.org; it is
still asked, so the client can be pointed at another hub. The note under the
form, which explained there was no default, is removed with its catalogue key.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
node:op only knew the daemon's token once a page had called detect(), and
kept it after the daemon replaced it on restart: the index dock stayed empty
on a node machine until the Node page was opened, every operation answered
401 after a node restart, and on a machine without a node each 30 s poll was
a rejected IPC call Electron printed to the terminal ("Node not detected").
node:op now reads the config and token from disk on every call, and the dock
asks detect() before its first operation and after any failure.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The protocol layer is LGPL-3.0-or-later in every language it exists in, so
any client may use it whatever its own licence: meshbay-common, and the files
marked with an SPDX line — keyderive.js, crypto.js, playlist-crypto.js,
transport*.js; keyring.js, transcripts.js and argon2-wasm.js on the desktop;
Kdf.kt, Keyring.kt and Transcripts.kt on Android. Everything else is
AGPL-3.0-or-later, which the RPM specs and package.json already declared
without a licence file to back them.
Two AGPL section 7 permissions:
- group applications may be under any licence when they use the interface
only through a named surface (static/licenses/APPLICATION-EXCEPTION.txt);
the reference application is 0BSD so that copying it brings no AGPL code;
- the Android application may be conveyed linked with Google Play services.
Third-party code is accounted for: THIRD-PARTY-NOTICES.txt is generated from
what a build ships (packaging/third_party_notices.py) for the deb/rpm venv and
the frozen Windows node — PyAV's wheel grafts in libx264 and libx265, which its
BSD licence does not mention — and the vendored browser libraries get their
licence texts and htm-preact.js its provenance. Wheels carry SPDX metadata,
RPMs %license, debs a DEP-5 copyright file, every Windows target LICENSE.txt.
test_licensing.py holds the line: the LGPL layer imports nothing under the
AGPL, the reference application nothing outside the application interface,
and every SPDX line is one of the known ones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A cast button in Music's toolbar and in the music bar. With a television
chosen, each decrypted track goes to the relay with its cover — found as the
album card finds it — and plays there as music with its title, artist and
album; the bar's play, pause, seek, previous and next drive the receiver, its
clock is the receiver's, and the end of a track there moves the queue on.
A film or a photo taking the television pauses the bar; stopping the cast
carries the track on locally.
Photos and tracks now share one path: a whole file sent to the relay in
pieces (binary frames on Android, written to disk there), served at /file
with byte ranges and its cover at /cover, and loaded as what the relay says
it is. cast:image is gone; cast:chromecast:seek is new.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
A cast button in Videos' toolbar, at the top of Photos, in an album's bar and
in the lightbox, in a group and in Search alike. A television chosen there is
kept for the session: a film opened plays on it with the player as its remote
from the start, and a photo opened in the lightbox is shown on it, scaled to
1920x1080, upright, as JPEG. The lightbox gains a slideshow.
The relay serves one photo at /image behind the stream's token, on the desktop
and on Android; the shell, not the page, decides that the receiver loads it as
a picture.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Held while a track plays or loads and released 5 s late, so skipping a
bad file with the screen off no longer drops the Android foreground
service, which cannot be taken back from the background.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
While a track plays, the page asks the shell to stay awake
(playback:keep-alive): on Android the cast's foreground service and
visible WebView, with a notification; on desktop a power save blocker.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
A transport failure while the page is hidden, or within 30 s of waking,
keeps the track and its spinner and retries once the page or the
connection is back, instead of skipping it with an error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
refusals
WebView now allows play() after the track fetch; a NotAllowedError leaves
the track waiting for the play button instead of raising an error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
Skip buttons with circular arrows, filled scrubber, large play/pause,
device header; the remote is its own component.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
Shows the receiver's position with play/pause, ±30 s and a scrubber;
a seek restarts the relay where asked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
The player's remote mode reads where the television is instead of the
local playhead, which drifts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
It keeps playing to pace the relay, so it doubled the television's sound.
The viewer's mute setting comes back when the cast ends.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
They are the new stream, header first. Dropped, a cast relay restarted at the
landing got no ftyp/moov and the receiver gave up; they are now replayed in
order once reinitAt/resumeAt is done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
pipelinedDownload kept every chunk's resolved promise until the end; a 2 GB
download held 2 GB in the page. Each is released once read.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
Gated on capabilities.nodeAdmin rather than on any bridge, so a phone with no
groups sees its invitations and the join link.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
node_status, node_settings_set, roster_read, denylist_read, denylist_clear,
node_reload and the signed gek_rotate, member_unpin, transfer_limits,
group_detach leave MNP 6.0; the Node page and the CLI do this work over
loopback. Their ops keep their tests, moved to the ops level.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
Removes confirmFolder (addRoot, attachGroup) and the writable confirmation
added in e4f6177, with their two catalogue keys.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
| |
root_add, root_update and group_attach leave MNP: adding a directory and
switching writable/removable go through the loopback API (native dialog in
the desktop app) or the CLI. The operator's Settings tab still lists the
roots from any browser, read-only. The desktop app refuses to sign those
ops; a loopback flag change now reaches open pages (publish_roots).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
The scan still runs six seconds, but the picker polls what it has found
and shows each receiver immediately. A rescan no longer has its timer
cut short by the scan it replaced.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
Rotation narrows rather than widens: members still connected receive the
new key, and nothing already shared changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
The folder chosen in the native picker is the consent; the dialog that
followed on every group creation asked the same thing twice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
A cell starting with = + - @ (or a tab or carriage return) gets a leading
apostrophe; the export carries text members chose (F-29).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
static/webrtc-test.html posted a raw password to /login from the hub's own
origin; meshbay_common/keyderive.py derived keys from a password and nothing
called it (F-32).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Transitional. The Argon2 run that makes M makes A, the key MBK2 bundles were
sealed under; a session keeps it as a decrypt-only key (IndexedDB in a browser,
the key storage in the desktop app). A client meeting an MBK2 bundle opens it —
or its recovery copy — and stores the same identity as MBK3 once connected; the
desktop app reseals or withdraws it as browser access says. A session without
A asks for the passphrase once. Older formats stay refused by name. Replaces
the unpin-and-reinvite step the 0.17 flag day required on every node.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
The desktop app writes the Mark-of-the-Web on each file it saves on Windows, as
a browser does. Bidirectional controls are reserved characters in a saved name
(portable-name.js and paths.sanitize_for_download, and again in the main
process), so a name cannot display one extension and carry another. The node
refuses uploads of files Windows Explorer acts on by itself: desktop.ini,
.lnk, .url, .scf, .library-ms, .searchConnector-ms (F-19).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
A sign-in from a browser that presented no token is answered with one
(known_browser, kept hashed, twenty per account); a later sign-in presenting it
counts failures on its own row, which nobody else can spend. Passphrase checks
inside an open session (change, e-mail, deletion, device, pepper) count on the
account's own row, so a locked name no longer stops its owner there either; /me
reports that row. Reset and erasure forget the browsers (F-15).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Over 128 characters was a 500 on PostgreSQL; line breaks, C0/C1 controls and
bidi overrides are refused (joiners stay, for emoji). The creation form caps
the field at 128 (F-13, what remains of it).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|