Summarise every token with view --summary - #19
Draft
bajtos wants to merge 1 commit into
Draft
Conversation
Reading the audience out of a pasted proof took one `ucantool view -i` per entry, with no way to learn the entry count except walking the index until it errored, and a jq path carrying the UCAN spec version. A script comparing audiences against a configured DID broke silently when the version moved, because `jq -r` on a missing key prints `null`. `--summary` decodes every token in the input and reports its command, audience and issuer as a table, or the full field set as JSON under keys this tool fixes rather than borrowing from the encoded tag. An entry that decodes as no known token kind reports its index and an error, so the remaining entries stay readable. A single delegation summarises the same way as a container. The container branch now reads its entries straight out of the input. It used to decode the container and re-encode it as raw, which sorts the entries and drops the ones that decode as no known token kind, so indices and entry count could disagree with the file. Stripping the transport encoding locally duplicates about twenty lines that `container.Decode` keeps unexported; the duplication goes away once ucantone exports that step. Assisted-by: Claude:claude-opus-5[1m] Signed-off-by: Miroslav Bajtoš <oss@bajtos.net>
This was referenced Aug 28, 2026
bajtos
added a commit
to fil-forge/ucantone
that referenced
this pull request
Aug 28, 2026
_Written by Claude._ `container.Decode` is the only way to read a container, and it is lossy. It returns a `*Container` of decoded tokens, so three properties of the input are gone by the time it returns: `decodeTokens` skips any entry that decodes as none of delegation, receipt or invocation, the tokens are split into three slices by kind, and `encodeTokens` sorts bytewise on the way back out, so a `Decode` then `Encode(Raw, …)` roundtrip does not reproduce the input's entry order either. A tool that inspects containers rather than executing them needs the entries as they appear in the file: same order, same count, undecodable ones included, so it can report an index that matches what a person or a script counts. Today the only way to get them is to reimplement the transport step outside the package, which duplicates about twenty lines of `Decode` and will drift from it. `ucantool view --summary` carries that copy now - see fil-forge/ucantool#19. I'd like to rework that pull request to use the new API added by this change. ## What this changes `DecodeTransport(input []byte) (byte, []byte, error)` strips the transport encoding and returns the codec byte and the CBOR of the container model. The body of `Decode` moves into it unchanged up to the `UnmarshalCBOR` call, error strings included, so what counts as a decodable container cannot diverge between the two. `Decode` is now a wrapper over it. A caller reaches the raw entries through the already-exported datamodel: ```go codec, cborBytes, err := container.DecodeTransport(input) model := datamodel.ContainerModel{} err = model.UnmarshalCBOR(bytes.NewReader(cborBytes)) // model.Ctn1 is the entries, in file order ``` Returning the codec byte saves the caller re-reading `input[0]`; `FormatCodec` turns it into a name. Nothing about `Decode`'s signature or behaviour changes, and the existing `TestContainer` passes untouched. That is the evidence the split is behaviour-preserving. ## Follow-up worth its own issue `decodeTokens` swallowing undecodable entries and returning a nil error is a real defect: a caller cannot tell a container of three tokens from a container of three tokens plus two it could not read. Fixing it means deciding whether `Decode` should fail or whether `Container` should carry the unreadable entries, and that decision touches every consumer, so it is left alone here. ## Testing `GOWORK=off make ci` passes except `examples.TestServer`, which cannot bind a TCP port in this sandbox.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Written by Claude.
Reading the audience out of a pasted proof takes one
ucantool view -iper entry today:There is no way to learn the entry count except walking
-iuntil it errors, every entry costs a process, and the jq path carries the spec version. A script comparing audiences against a configured DID breaks silently when UCAN moves past1.0.0-rc.1, becausejq -ron a missing key printsnull, which a naive comparison reads as "audience does not match".--summarydecodes every token in the input and reports its fields:The JSON keys (
index,tag,cmd,iss,aud,sub,exp) are fixed by this tool rather than borrowed from the encoded tag, so.[].audkeeps resolving across UCAN versions. The tag is reported as a value for callers that care. An entry that decodes as no known token kind reports its index and an error, leaving the other entries readable. A single delegation summarises the same way as a container.-jwithout--summaryis untouched: it still emits DAG-JSON of the container with entries as opaque bytes.One behaviour change worth review
The container branch now reads its entries straight out of the input. It used to decode the container and re-encode it as raw to get the entry list, and that roundtrip sorts the entries bytewise and silently drops the ones
decodeTokenscannot read, so indices and entry count could disagree with the file. The plainviewtable on a container therefore now shows the file's real entries in file order, and for a container whose entries were not already sorted, the displayed root CID changes. Containers this tool produces are already sorted, so nothing moves on the happy path.Stripping the transport encoding (codec byte, base64, gzip) locally duplicates about twenty lines that
container.Decodekeeps unexported. We can remove that duplication after fil-forge/ucantone#55 is landed.Tests
cmd/view_test.godrivesrootCmdthe waycmd/delegate_test.godoes, building fixtures withucantool delegaterather than committing any. It pins that every entry of a three-command container appears with its audience, that the JSON keys carry no spec version, that a bare delegation summarises, that an undecodable entry reports its index without hiding the others, and that-i <n>and--summaryagree on the audience of entryn. Both paths go through onedecodeTokenhelper, so they cannot drift on what counts as a delegation.