Skip to content

fix(deps): update dependencies - #115

Open
tannevaled wants to merge 1 commit into
mainfrom
renovate/deps
Open

fix(deps): update dependencies#115
tannevaled wants to merge 1 commit into
mainfrom
renovate/deps

Conversation

@tannevaled

@tannevaled tannevaled commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
github.com/go-crdt/collab v0.37.0v0.39.0 age confidence
github.com/go-crdt/crdt v0.39.0v0.42.0 age confidence
github.com/go-opentype/fonts v0.8.0v0.9.0 age confidence
github.com/go-richdoc/latex v0.2.0v0.3.0 age confidence
github.com/go-richdoc/markdown v0.2.0v0.7.0 age confidence
github.com/go-richdoc/richdoc v0.2.0v0.3.0 age confidence
github.com/go-tex/engine v0.204.0v0.207.0 age confidence
github.com/go-widgets/mvvm v0.7.0v0.9.0 age confidence
github.com/go-widgets/painter v0.11.0v0.12.0 age confidence
github.com/go-widgets/toolkit v0.294.0v0.301.0 age confidence

Release Notes

go-crdt/collab (github.com/go-crdt/collab)

v0.39.0

Compare Source

Every transport now carries the advertisement, not only gRPC.

Pipe, WebSocket and BroadcastChannel send what a peer understands, so a participant on any of them gets a snapshot instead of the history it was being sent for want of saying anything — 9.9× smaller on a document of two hundred sentences.

Why the wait ended

The room went out in v0.38.0 and nothing wrote into it: a peer built before it reads a join and a welcome to the end and refuses anything after them, so an advertisement had nowhere to go until enough peers had somewhere to put it.

What settled it is a fact rather than a calendar — there are no production servers on this project, so the peer that would have been broken does not exist. Waiting for it to disappear was waiting for nothing.

A peer with nothing to say still writes nothing, so the wire keeps one way of saying nothing rather than two.

v0.38.1

Compare Source

The server now introduces itself too.

v0.38.0 had a participant say what it understands and the server say nothing back — while the field for its half was already on the wire in both encodings, defined and carried and always empty.

That is worse than not having it: an empty field reads as supported and says nothing, so a later peer trusts it and gets silence.

Nothing reads it yet — a participant sends only operations, which carry no format version. The reader is crdt#80, where whether to send an operation kind is a decision each side has to make about the other. Given the choice between a wire field that lies for a release and a value nothing uses yet, the unused value is the one that cannot mislead.

v0.38.0: — a peer says what it understands

Compare Source

Nothing on this wire said what a peer could read. A participant joined, the
server sent a snapshot in whatever format its crdt writes, and the participant
either read it or did not — no negotiation, and nothing to negotiate with. A
federated link is the same code path, which made it the worse case: two
servers upgraded independently, each able to send the other a whole document it
cannot read.

crdt v0.38.0 made that
concrete, and the answer was a sentence in its release notes. A documented
procedure standing in for a protocol.

Capabilities, with versions

type Capabilities map[Capability][]byte
func Mine() Capabilities
func (c Capabilities) Accepts(name Capability, version byte) bool

Named rather than numbered, so a peer meeting a capability it has never heard of
keeps it, answers not accepted about it, and carries on — extensible without a
registry everyone must agree on first.

A version set, not a highest version. crdt reserves version 7 of a text and
refuses it, so a build reads 1–6 and 8. Told "up to 8", a peer would send a 7 and
be refused by the thing that told it.

Not one number for the snapshot format, because the next thing to negotiate
is already known — crdt#80 adds an operation kind a peer refuses if it does not
know it — and a mechanism stretched to fit that afterwards is how a protocol ends
up with two of everything.

What the server does with it

A snapshot is the cheap way to hand over a whole document, and the only thing
here whose format a peer may not be able to read. Operations carry no version
number and always work. So the snapshot is the fast path, unlocked by saying
so
:

the participant gets
says it reads what we write a snapshot
says nothing the history
says it reads an older text the history
says something unreadable the history

Silence is not acceptance. The participant that says nothing is exactly the
older build this protects.

It costs something, and here is what
snapshot     11507 bytes
history     113666 bytes  (9.88x)

on a document of two hundred sentences. A participant that says nothing pays
9.9× on its first join — instead of failing — and stops paying it by saying
one sentence about itself.

One narrow window loses: a build that reads format 8 but predates this and cannot
say so. It works today and pays 9.9× until it upgrades. Nothing distinguishes it
from a build that genuinely cannot read a snapshot, and a second round trip to
find out would cost more than it saves.

Where it works

gRPC carries it today — protobuf ignores a field it does not know, which is
why the transport's own rules beat inventing one. The hand-rolled wires (Pipe,
WebSocket, BroadcastChannel) have the room as of this release and will send it
once peers that refuse trailing bytes are gone; that will be a change to one
encoder.

Needs crdt v0.40.0, which added Reads, Writes and Formats so a build can
be asked what it understands.

go-crdt/crdt (github.com/go-crdt/crdt)

v0.42.0: — stop reading formats nobody holds

Compare Source

⚠️ Breaking for a stored snapshot. One written by a build older than roughly v0.30 can no longer be opened. There are no production servers on this project, this module has never promised format stability, and since v0.40.0 a caller can ask what a build reads (Reads) rather than find out.

Text versions 1–6, list version 1 and map version 1 are no longer read. This build writes text 8 for a document that has not purged and 9 for one that has, and reads those two. Version 7 stays reserved and refused.

What actually went

718 lines net, and the line count is not the point. Removing the numbers made whole reading modes dead, and they went rather than being left always-true:

  • sameStream and readColumns — the entire pre-columnar reading mode
  • readCharacter / reader.character
  • steppedID's stepped parameter
  • readRun's version parameter, with its conditional clock addition and two conditional step encodings
  • column.plain and both its branches

Every one of those was a place a format change had to be thought about twice — and three tests were found this week passing while testing nothing, two of them confused by exactly this kind of version-conditional reading.

Bytes unchanged

Same document, same trace: version 8, 259 890 bytes, same sha256 as v0.41.0.

What deletion revealed

Nine rejections were reachable only through the version 1 fixture, and all of them guard live code: a site listed twice, two runs claiming one identity, runs in an impossible order, five duplicate-deletion refusals. Deleting a reader deletes the only route to checks that still matter — they were ported to the run builder rather than dropped with the fixture that reached them.

Five fuzz seeds stamped in removed versions were refused at the version byte and reached none of the loader. They are gone, and the four still-live seeds stay.

v0.41.0: — Doc.Purge

Compare Source

Doc.Purge() discards the characters of runs every character of which is
deleted. The run keeps its identity, its length, its origin and the operations
that deleted it; only the characters go. Nothing is re-pointed and nothing moves
— which is the whole difference between this and the collection withdrawn in
v0.35.0, where a survivor that named one of those characters could no longer find
it.

the automerge-paper trace, purged −24.7% (259 890 → 195 669 bytes)
a revised document, purged −33.1% (22 899 → 15 326)

It costs nothing to anyone who does not call it

Snapshot format version 9, written only by a document that has actually
purged
. Everything else writes version 8 and produces byte-identical
snapshots to v0.40.0 — same length, same sha256, verified by running the same
document through both builds rather than by reasoning about it. A Purge() that
finds nothing to take leaves the floor at zero and changes nothing.

Refusing a peer it can no longer serve

Doc.CanServe and Composite.CanServe report the new ErrPurged for a
version that needs characters a purge discarded.

Both, not one: Composite.Text hands out the *Doc, so anything holding a
composite can purge one of its texts — and a safety on the part with none on
the whole is one somebody reaches around without meaning to.

Writing that consumer first is what found that the predicate it was meant to use
answered the wrong question. "Nothing purged was still visible at v" is the
condition for reading the past, and it accepts the worst peer there is: a version
that never saw a purged run at all. Measured — it accepted the empty version
vector, which would have been sent 798 operations and read "" where the
document held eight hundred characters.

Sound without a stability condition

Checked rather than argued, and against the reference: Yjs replaces a deleted
item's content and keeps the item, needs no such condition, and this does the
same thing. Tested against Yjs 13.6.32 over 200 random histories, five peers,
out-of-order delivery, gc: true — all converge, including the case that broke
the withdrawn collection.

No reference implementation computes a safety condition for this. Loro, the only
one that removes records outright, declares the limitation instead.

v0.40.0

Compare Source

Reads, Writes and Formats — this build can now be asked what it understands.

func Reads(f Format) []byte  // the versions of a format this build can load
func Writes(f Format) byte   // the one it produces
func Formats() []Format      // text, list, map, composite

A snapshot travels — a joining participant loads one the server sends, a federated link adopts one from the server it follows — and neither side can negotiate: a reader knows the version byte or refuses the bytes. The only way to avoid sending something unreadable is to have been told what the other side reads, and until now there was nothing to tell with.

A set, not a range

Version 7 of a text is reserved for the purge and refused here, so this build reads 1–6 and 8. A peer told "up to 8" would send a 7 and be refused by the very thing that told it. The first draft of this returned a highest version and its test failed on its first run.

One list, two readers

The accepted versions are a single list, used by Load and by Reads. A second list was the obvious way to write it and the wrong one: a number that has drifted from the loader is worse than no number, because it is believed.

The test tries every version from 1 to 255 against every loader, in both directions: nothing claimed may be refused for its version, and nothing unclaimed may be accepted.

Who calls it

Nothing here. The caller is collab#106 — a peer says this at a join so the other side can send operations rather than a snapshot it cannot read, which replaces the upgrade-order note in v0.38.0's release with something the protocol enforces.

go-opentype/fonts (github.com/go-opentype/fonts)

v0.9.0: — Tinos, and a licence that lives elsewhere

Compare Source

Tinos is the metric-compatible stand-in for Times, as Arimo is for Helvetica and Cousine for Courier. Two of the three were bundled and the third was not.

It was skipped because its google/fonts directory ships no OFL.txt, though its METADATA.pb names the licence and the text sits in the upstream project. A seed may now say where the real text is — the rule is untouched: no licence, no bundle.

48 families.

go-richdoc/latex (github.com/go-richdoc/latex)

v0.3.0: — typeset it, not just write it

Compare Source

latex/pdf typesets a richdoc document into a PDF:

data, err := pdf.Write(doc, pdf.Options{})

Every converter in this organisation reaches richdoc, and none of them could reach a PDF. The pieces were all there — this module emits LaTeX, and go-tex/engine is a pure-Go TeX engine that runs the genuine LaTeX classes. What was missing was somewhere to put the composition. So Markdown, reStructuredText and LaTeX all reach a PDF now, because they all reach richdoc.

It typesets nothing itself. What comes back is a page TeX laid out, with TeX's line breaking.

A package rather than a module, and not part of the parent. The engine is a six-megabyte TeX implementation; this module already names it, but only from a test, so importing latex does not link it. Putting this beside Write would link it into every consumer that only wanted LaTeX text. Go links by package, so a package costs neither that nor another repository to keep in step.

What survives is measured by poppler rather than by ourselves: a document carrying a heading, emphasis, bold, a bulleted list, a code block and accented text goes through the whole chain and is read back out of the finished PDF with pdftotext. All of it arrives.

100% statement coverage, go vet clean, -race clean, CGO-free.

go-richdoc/markdown (github.com/go-richdoc/markdown)

v0.7.0

Compare Source

v0.6.0

Compare Source

v0.5.0

Compare Source

v0.4.0

Compare Source

v0.3.0

Compare Source

go-richdoc/richdoc (github.com/go-richdoc/richdoc)

v0.3.0

Compare Source

go-tex/engine (github.com/go-tex/engine)

v0.207.0

Compare Source

v0.206.0

Compare Source

v0.205.0

Compare Source

go-widgets/mvvm (github.com/go-widgets/mvvm)

v0.9.0

Compare Source

v0.8.0

Compare Source

go-widgets/painter (github.com/go-widgets/painter)

v0.12.0

Compare Source

go-widgets/toolkit (github.com/go-widgets/toolkit)

v0.301.0

Compare Source

v0.300.0

Compare Source

v0.299.0

Compare Source

v0.298.0

Compare Source

v0.297.0

Compare Source

v0.296.0

Compare Source

v0.295.0

Compare Source


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Enabled.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate CLI.

@tannevaled

tannevaled commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

ℹ️ Artifact update notice

File name: playground/go.mod

In order to perform the update(s) described in the table above, Renovate ran the go get command, which resulted in the following additional change(s):

  • 3 additional dependencies were updated

Details:

Package Change
github.com/go-gfx/gfx v0.18.0 -> v0.19.0
github.com/go-images/images v0.0.0-20260815210351-4a50ef5ab734 -> v0.0.0-20260831115433-23d959d868e3
github.com/go-tex/math v0.19.0 -> v0.21.0

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