You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2026/09/14 14:49:56 UTC
(skywalking-ai-sessionizer) branch main updated: Prepare the 0.3.0 candidate and open 0.4.0 (#8)
This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-ai-sessionizer.git
The following commit(s) were added to refs/heads/main by this push:
new 9f3666e Prepare the 0.3.0 candidate and open 0.4.0 (#8)
9f3666e is described below
commit 9f3666efb7c5700de80a28ae441d1947f23689c9
Author: 吴晟 Wu Sheng <wu...@foxmail.com>
AuthorDate: Mon Sep 14 22:49:51 2026 +0800
Prepare the 0.3.0 candidate and open 0.4.0 (#8)
* Prepare the 0.3.0 candidate
The changelog of 0.3.0 loses its in-development note and keeps its
path, docs/en/changes/changes.md, which the menu and the welcome page
link. The tag goes on this commit, as the candidate for the vote.
* Open 0.4.0
The changelog of 0.3.0 moves from changes.md to its own page,
changes-0.3.0.md, and the version is listed under Changelog, right
after Current Version. changes.md is the changelog of 0.4.0 from here.
Current Version and the welcome page still link changes.md.
---
docs/en/changes/{changes.md => changes-0.3.0.md} | 2 -
docs/en/changes/changes.md | 446 +----------------------
docs/menu.yml | 2 +
3 files changed, 4 insertions(+), 446 deletions(-)
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes-0.3.0.md
similarity index 99%
copy from docs/en/changes/changes.md
copy to docs/en/changes/changes-0.3.0.md
index 3276eaf..bd176e9 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes-0.3.0.md
@@ -1,7 +1,5 @@
# Changes in 0.3.0
-> In development, not yet released. `tools/release.sh prepare 0.3.0` removes this note.
-
## Reliability
- A round is published only after its temporary file is complete, read-only and synced. An
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index 3276eaf..9d41cee 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -1,445 +1,3 @@
-# Changes in 0.3.0
+# Changes in 0.4.0
-> In development, not yet released. `tools/release.sh prepare 0.3.0` removes this note.
-
-## Reliability
-
-- A round is published only after its temporary file is complete, read-only and synced. An
- interrupted write no longer leaves a truncated `.sf` file that stops every later parse. A
- storage root on exFAT on macOS, which has neither an exclusive rename nor hard links, still
- publishes rounds and receipts. An empty file a crash leaves there under a round's or a receipt's
- name is not counted, and is replaced once it is a minute old. The conversation list skips a conversation whose only round
- file is the temporary file of an interrupted write.
-- `asz repack` refuses a populated destination before writing. Its session reservation and
- file publication also refuse existing data, so repeating a repack cannot invalidate a chain.
-- `asz show` locates the current `.sd` files through the shared filename parser.
-- Named adapters inherit their own defaults, while explicit `false` and empty exclusions stay
- as written. Omitting `enabled` no longer disables a local adapter by mistake. An adapter entry
- without `exclude` now inherits `/private/tmp/**`, so it no longer collects those sessions.
-- Token derivation follows calls across any number of landed files and leaves unfinished calls
- eligible for later completion. Deferred sessions are retried while other sessions keep growing.
- Immutable receipts keep requests and their accounting together across an interrupted progress
- save, even when new fragments arrive before retry. The retry applies those receipts before it
- derives a file that waited for its grace, and a receipt only moves a series forward, so no two
- windows of a series overlap. A session the first pass did not finish, because a file waited for
- its grace or an error stopped it, retains that pass's look-back.
-- The Claude Code plugin applies roots, exclusions and content limits to subagent edits and their
- manifest updates. Its `readonly-v2` policy scans executable wrappers and writing command modes
- that the earlier policy skipped, so concurrent writes retain their actual tool windows. A
- variable assignment before a command scans too, unless it only sets locale or display output.
-- Local tar packaging disables AppleDouble metadata. Source and binary archive checks reject
- `._*`, `.DS_Store` and `__MACOSX` entries, including the entries macOS tar hides by default.
-
-## Collection
-
-- A landed record keeps the provider model a call ran on, as `model`, the name the runtime wrote
- on the record. It is what a token count is reported under, so a metric per model can be
- produced from the landed data alone. Records landed before this carry none, and the glossary
- says where the runtime writes it.
-- A parse takes the conversation's lock before it reads the session's index. A parser that read
- the index first could hold an old one while a scenario removal took the session away, and then
- publish a round over evidence that is gone. A parse of a session with no landed files and no
- chain creates nothing.
-- An `unknown` part that `claude-code-local` or `claude-code-changes` lands keeps every byte the
- dialect could not describe, as the Session Data page always said. A JSON string cannot hold
- bytes that are not valid UTF-8. Go's JSON encoder wrote U+FFFD in their place, so such a byte was
- lost while the part still said `available`. When any byte is not valid UTF-8, the part now keeps
- all of its bytes in standard base64, and carries a new key, `encoding`, set to `base64`. Valid
- UTF-8 is written as before, as one JSON string with no `encoding`, so every file landed before
- reads as it did. The schema stays `sd/1`, because a key was only added. `Part.Raw` in
- `pkg/sessiondata` reads both forms, and `Part.SetRaw` writes them. Both adapters now build the
- part with `Part.SetRaw`. The plugin's adapter, `claude-code-changes`, passed the line to the JSON
- encoder as a string, and lost such bytes the same way. Claude Code and the plugin write UTF-8,
- but such bytes can still reach an adapter. A write cut short and joined to the next line is one
- way, and a workflow script saved in another encoding is another. Measured on 2026-09-11 on one
- machine's storage root of 60 sessions, none of its 151 `unknown` parts had lost a byte. That root
- held no change records of the plugin, so the measurement covers `claude-code-local` only.
-- Source JSON in a part's `data` now keeps its bytes, apart from whitespace between tokens. The
- writer inserts it after `json.Compact` instead of re-encoding it. Earlier writers changed `<`,
- `>` and `&` to `\u003c`, `\u003e` and `\u0026`, and U+2028 and U+2029 to `\u2028` and `\u2029`.
- Turning HTML escaping off alone still changes the last two under Go 1.27's JSON v2 engine.
- Inserting the compact JSON keeps `data` the same under both Go JSON engines. Unknown strings,
- derived change records and plugin lines keep their own encodings. Whitespace between tokens
- is still removed without a warning. [What data holds](../formats/session-data.md#what-data-holds)
- describes the exact boundary. On a 2026-09-12 sample of 6,377 source files from 85 sessions, all
- 229,341 source JSON parts landed byte for byte, compared with 144,464 (62.99%) before. Both Go
- JSON engines gave the same result. The schema stays `sd/1`; old files and their digests stay intact.
- A data-only step can therefore show escapes from an old file and literal characters from a new
- one. The example `asz-view-example.yaml` is regenerated with the new writer. OAP's copies need
- a paired follow-up: regenerate both fixture scenarios and their example documents from the same
- asz commit, then replace their landed files and expected documents together.
-- The new `parts_keep_source_bytes` scenario property compares source JSON and unknown bytes
- with landed parts and checks source digests. It runs on `claude-code` scenarios only, including
- the new `source-bytes.yaml`; it does not monitor real sources. Scenario writers now preserve
- literal `<`, `>`, `&`, U+2028 and U+2029. Workflow names produce valid run ids even when they
- start with punctuation, and a build refuses names that produce the same run id, ignoring letter
- case.
-- A source Claude Code pruned now has its cursor set to `source_gone`, as the documentation said.
- A pass visits only the files discovery lists. So before, only a file that went while a pass read
- it was marked, and a pruned file's cursor said `active` forever. Measured on 2026-09-11 on one
- machine's storage root of 60 sessions, not one of 6,080 cursors said `source_gone`, while
- discovery no longer found 8 of the sessions, with 415 cursors between them, and 1 file of
- another. Now, after a session's sources, a pass sets `source_gone` on each other cursor of the
- session whose file does not exist. A session discovery no longer finds is checked the same way.
- Either way the pass holds the session's lock, and it leaves alone a session the adapter's
- `include` and `exclude` keep out. A collector checks a session discovery no longer finds until
- one check completes, and again only after discovery has found it in between. Claude Code prunes
- by age, so without that a pass would read more cursors every week. Discovery reports a project
- directory it cannot read, and a pass that met one does not check the sessions discovery did not
- find, because an unreadable directory hides files the way pruning does. Discovery does not
- report a directory it cannot read inside a session, such as `subagents/`, so such a directory
- does not stop the check. A cursor moves only when its file does not exist, so the cursor of a
- file in such a directory stays as it was. Only an `active` cursor is set to `source_gone`, and a
- `conflict` stays. A cursor that names a path this adapter does not produce, as the cursors of a
- scenario `sd` build do, is left alone. When discovery lists a file whose cursor says
- `source_gone`, restored from a backup for instance, the pass sets the cursor back to `active`
- before it reads the file. So an older copy of a transcript or a journal, shorter than what was
- read, becomes a `conflict` in that same pass. A copy that still holds every byte that was read
- is collected from where reading stopped. A file in a session that `include` and `exclude` keep
- out is not read, so its cursor stays `source_gone`. The landed files stay in every case. The
- plugin's change records are not Claude Code's files, and their cursors are still marked only
- when a file goes while a pass reads it.
- [Pruned sources](../formats/storage-root.md#pruned-sources) has the details.
-- A new scenario property, `pruned_sources_gone`, checks this in every scenario in the
- `claude-code` format. On a copy of the finished root it deletes the session's main transcript,
- then every other file of the session that the Claude Code adapter finds, and then puts them all
- back with the bytes they had. After each step, one pass of `claude-code-local` and
- `claude-code-changes` runs, as a newly started process would. After a deletion, each deleted
- file's active cursor must say `source_gone`, and every other cursor must say what it said before,
- with no cursor added or removed. A cursor that already said `conflict` stays that way. After the
- files come back, every cursor must say again what it said before. No pass may land anything,
- meet a new conflict or an error, or change a landed file. A parse must write no round, and
- `asz verify` must count as many problems as it counted before. The scenario guide describes the
- property under [Check](../guides/scenario.md#check).
-
-## Commands
-
-- `asz collect` is the whole pipeline. One pass lands what is new, parses every session that
- moved, and sends what `export.otlp` asks for, in that order, so a pass ships the rounds it has
- just written. It reads every enabled local adapter in the same pass, where before it ran them
- one after another and a watching source kept the others from ever running.
-- `asz server` is new: the pipeline and the page in one process, which is what a person runs to
- watch their own conversations locally.
-- `asz view` only reads now. It serves a storage root that already holds conversations and never
- collects, parses or sends, which is what a root copied from another machine, or filled by the
- receiver, needs. Use `asz server` to collect and serve together.
-- `asz push` makes one pass and exits. A root that keeps growing is sent by `asz collect`. This
- command is for a root that is already there. `export.otlp.interval` is gone with the loop it
- drove, and the collector's `interval` is the one period.
-- The `claude-code-otlp` receiver listens under `asz collect` and `asz server`, the two commands
- that write for as long as they run. It no longer listens under `asz view`.
-- `asz verify` holds the first record of each stream to line 1 and byte 0. Where the stream has an
- append cursor, its records must also reach the line and the byte the cursor says the collector
- read to. Before, the check started from whatever the first record said and never read the
- cursor. So a lost first or last landed file passed unless a round had consumed it, and in a root
- never parsed, or one whose rounds were removed, nothing reported it. Now, in a stream with an
- append cursor, such a loss shows whether or not a round consumed the file. A lost first file
- shows as an `ord gap` and a `byte gap`. Records that stop short of the cursor show on a new
- `end gap` line, with the cursor's position and theirs. A stream with an append cursor whose every
- landed file is lost is checked from its cursor too. A snapshot cursor, or no cursor, is not
- compared. There are two exceptions, and in both only a round that consumed the file shows the
- loss. A lost file leaves no gap when another landed file holds the same records, as after an
- interrupted pass. A cursor never travels, so in a root rebuilt from a push the check stops at
- the last landed record, and a lost last file leaves no gap there. Which streams have an append
- cursor depends on what landed them. `claude-code-local` gives one to a transcript and a workflow
- journal, and `claude-code-changes` to the plugin's change records. `claude-code-local` reads a
- child agent's sidecar, a workflow manifest and a workflow script whole, with a snapshot cursor.
- So in a root it collected, a lost file of one of them is found only by the round chain, and a
- root with no rounds does not show it. A scenario `sd` build gives each of them an append cursor
- that counts records, so there such a loss is an end gap too. A cursor behind the records is what
- an interrupted pass leaves, and is not a problem. The cursor is read before the files are
- listed, so a collector running beside the check cannot make it look ahead. Measured on
- 2026-09-11 on one machine's storage root of 60 sessions, all 6,080 streams began at line 1 and
- byte 0, and none of the 2,995 append cursors was ahead of its records. So on that root, neither
- rule reported a problem that was not there. The new `tests/scenarios/lost-ends.yaml` loses the
- first and then the last landed file of a stream. `tests/scenarios/lost-file.expect.yaml` now
- counts two problems where it counted one. The second is the end gap of the helper stream whose
- file it loses.
-- `asz scenario build` keeps building with `--every D`: one whole session, then that long on the
- wall clock, then the next. It takes more than one scenario file, and a directory contributes
- every `.yaml` in it, with `--pick cycle` or `--pick random` and `--seed` to repeat an order.
- Each session is stamped so its last record lands when it was written, and carries an id no
- earlier session has. It is a mock client to run beside `asz server` or `asz collect`.
-- `asz scenario build --remove` says when a pipeline may remove each session a `claude-code` build
- writes: `immediately`, the default, or a duration such as `24h` or `7d` after the session's last
- record. The build writes a marker for each session after every other file of it, naming the
- policy and every file it wrote for the session with its size and SHA-256. `asz collect` and
- `asz server` remove a marked session at the end of a pass, once every landed file, round and
- metrics request of it is recorded as sent to the receiver they send to and none was rejected.
- They remove its source files, its landed files, its chain, its spool files, its lines in the state
- files, and last the marker. The session directory and its chain directory are each renamed into
- `_removed/` in one call before they are deleted, so a crash never leaves half a session for a
- parse to read. Only a pipeline whose storage root is the build's `--out` removes. It holds
- `_scenario/.lock` there, and a second one waits. When the configuration keeps every marked
- session, the `scenario :` line at the start says why. Removal is a policy of the scenario, never
- of the product. The configuration has no removal setting, and a session no build marked, which
- is every real Claude Code session, is never removed.
-- A workflow in a scenario starts its children as one batch, and they run at the same time, as the
- runtime's do. Before, each child started only after the one before it had ended, so a review by
- four agents was drawn as four reviews in a row. The parent's next step waits for the last child.
- The `push_follows_the_wire` check now compares record times as times rather than as text, which
- the overlapping children showed it needed.
-
-## Read
-
-- The conversation list shows what a conversation did, not how it is built: talks, model calls,
- subagents, Bash runs, and changes with the lines those records added and removed. Steps, streams
- and segments leave the table. This follows Horizon's own conversation list, so the two read the
- same. The list folds each conversation to draw its row, and keeps the fold until the head round
- on disk moves. Talks and the time span are read from the fold. Model calls, subagents, Bash runs
- and changes are the counts in the head round's header, and a count the head round does not carry
- shows a dash: a round cut before that count existed does not know the answer, and a zero would be
- a claim it never made. Measured on 2026-09-11 on one machine's storage root of 60 conversations,
- the first list took 2.75 seconds, and a later one with no new round took 43 milliseconds.
-- The conversation page is drawn by Horizon's conversation renderer,
- `@skywalking-horizon-ui/conversation-view`, embedded from a pinned Horizon commit with Horizon's
- themes and fonts, so `asz view` and the SkyWalking UI draw a conversation identically and the
- page needs nothing from the network. The pin now names Horizon `22e2f869`, which draws a tool
- call's input and result as fields rather than one escaped string, reads an edit as a line diff,
- puts a changes mark on a step that changed files with the files and their diffs behind it, adds a
- Changes tab to the inspector carrying where each record came from, and pops the inspector out
- over the page. The hand-written viewer is gone with the API routes only it read. The page reads
- the `asz.view` document, the glossary, and the landed record behind a step.
- `tools/conversation-view.sh` rebuilds the copy from the pin, and CI fails when it differs.
-
-## Release
-
-- `tools/release.sh` runs the Apache release in three commands, each started by hand. `prepare`
- tags the candidate, pushes the tag and opens the pull request. Its tag message, its commit and
- its pull request no longer call the candidate a release, and it checks for the tools it uses
- first. CI on the tag push creates the GitHub prerelease with the binaries, and the release
- manager waits for it by hand. `candidate` downloads the verified CI binaries from that
- prerelease, archives the tagged source locally, signs every package, verifies them against KEYS,
- uploads them to the dev area of dist.apache.org, attaches the source package and every signature
- to the prerelease, and writes the vote mail. After the vote, `publish`, run by a PMC member,
- verifies the signatures, moves the voted packages to the release directory, promotes the same
- GitHub prerelease, and writes the announcement, the website entries and the install manifests.
- The release manager counts the votes and writes the result mail by hand.
- [How to Release](../guides/how-to-release.md) walks through each command and the svn commands it
- runs.
-- `candidate` refuses a signing key that is not RSA of at least 2048 bits, as the ASF requires,
- or that has no apache.org user ID, and a source package that would hold a font file, since
- fonts are Category B works the ASF keeps out of source releases. The vote mail names the signing
- key and tells voters what the committed conversation renderer is. `--no-upload` writes its mail
- to `vote-preview.txt` and refuses once a candidate is uploaded.
-- `candidate` also refuses a signing key that has expired or is revoked in KEYS, the primary key
- or the subkey that signs. gpg reads a key's expiry from KEYS, not from the signer's machine, so
- a key extended there but not in KEYS passed before, and every voter's gpg would warn about it.
- Every signature, of the scratch file before the build and of each package after it, must now be
- a good signature by the checked key that gpg does not report as expired or revoked. gpg exits 0
- and writes `VALIDSIG` for such a key too, so neither was enough. A revoked key is now named as
- revoked, where before it was refused as having no apache.org user ID. An expired user ID no
- longer counts as that address. Reading the KEYS listing no longer stops `candidate` when more
- than a pipe buffer of it follows the signing key. The voters' check list and
- [Install](../setup/install.md) say what gpg must not print.
-- `--dry-run` is described as it behaves. `candidate` and `publish` read the tag to
- make their plan, so a dry run fetches `v$VERSION` from origin when the local repository does not
- have it, as a real run does. They fetch that one tag and no other, and say so. A `candidate`
- dry run signs its scratch file and reads KEYS in a temporary directory, which it removes.
-- `tools/package-smoke.sh` checks one binary package the way a person uses it. It verifies the
- package's sha512, unpacks it, checks that every file is there, and then runs `asz` and the plugin
- from the unpacked files: four scenarios through `asz scenario check`, the list page and one
- conversation page from `asz view`, and one shell command through the plugin's hooks. A new CI
- job, `packages`, runs it on all six packages, each on a GitHub runner of its own platform. The
- `binaries` job cross-compiles every platform on one Linux runner, and a binary that was never
- started proves nothing about its platform. The voters' check list asks each voter to run it on
- the package for their own platform.
-- `candidate` runs the package for the release manager's machine with the tag's
- `tools/package-smoke.sh`, after it verifies the candidate and before the upload. When the check
- fails, nothing is uploaded and no vote mail is written. On a machine no package is built for, it
- runs none and says so.
-- `tools/package-smoke.sh` reads the plugin's own record, `output/<session-id>/main.jsonl`, and
- needs it to name the file the shell command created. Before, it searched the plugin's whole data
- directory, where files of the plugin's scan name that file before the record is written, so a
- plugin that wrote no record passed. It compares the package's sha512 with the one in its
- `.sha512` itself. That file must hold exactly one line that is not blank, and that line must be
- a sha512 followed by this package's name. `sha512sum -c` checks whichever file the line names,
- and the BSD `sha512sum` on macOS passed an empty file. On Windows it hands the two paths to
- `Expand-Archive` in the environment, so an apostrophe in a path no longer stops the unpack. Each
- page request now has a time limit, and `asz view` has 20 seconds to answer.
-- CI builds and tests the source package as a voter does. A new required job, `source-package`,
- makes it with `git archive`, unpacks it outside the checkout, where there is no `.git` and no
- font, and runs `go build` and `go test` there. The unit tests of the `build` job now also run
- the tests of the command and of the plugin, the plugin's hook from end to end included, on
- Linux, macOS and Windows. No CI job ran those tests before.
-- The release guide shows the result mail, which lists every vote, +0 and non-binding -1 included,
- and links the vote thread. Only binding votes decide.
-- `publish` also holds each local signature to the voted one, dates the website entries by the day
- of the move, and refuses `--remove-old` in the run that moves: older versions leave the release
- directory in a later run, once the website links them from the archive. The announcement is
- titled `[ANNOUNCE]`, and the website entries link the packages through closer.lua.
-- The notes of the GitHub release name the Apache release, the downloads page, the signatures and
- KEYS. They no longer point at a git checkout or the container image.
-- The changelog has the layout of Apache SkyWalking and SkyWalking SWCK. On `main`,
- `docs/en/changes/changes.md` is the changelog of the version in development, and Current Version
- in the menu always points at it. In the commit it tags, `prepare` only removes the
- in-development note, so the tag and the source package hold the finished changelog where the
- menu and the welcome page of the tag link it. The website publishes the docs of each version
- from its tag. In the next commit, `prepare` moves the page to `changes-VERSION.md`, lists the
- version under Changelog, and writes a new `changes.md` for the next version. The vote mail, the
- announcement, the GitHub release and the winget manifest link the tag's `changes.md`. `publish`
- builds the text of the GitHub release from that page when it runs, in place of the
- `release-notes-VERSION.md` file `prepare` used to store.
- [How to Release](../guides/how-to-release.md#the-changelog) describes the layout, which the root
- `CHANGES.md` used to describe.
-- On the push of a release tag, CI creates the GitHub prerelease and attaches the six binary
- archives and their checksums, only after all checks pass. It reuses an empty prerelease an
- earlier attempt of the run created, and refuses any other. The local download verifies the tag,
- CI run, release identity and asset checksums. The readiness marker carries a fingerprint of the
- assets CI verified. `candidate` accepts only the run of the tag push, and only binaries that
- `github-actions[bot]` uploaded during it. A replacement candidate requires explicitly removing
- the rejected prerelease and its tag first.
-- `candidate` attaches the source package, its checksum and every signature to the prerelease
- after the SVN upload, and never replaces a file there. If that stops, running `candidate` again
- from the same checkout finishes it without signing or uploading again.
-- `publish` checks the GitHub release before anything moves, verifies every signature against
- KEYS, and after the move checks each file of the release against the release directory and
- promotes it. A KEYS entry that gpg cannot import does not stop it, as it never stopped
- `candidate`; each package still needs a valid signature from an imported key. Existing GitHub
- binaries and checksums must match and are never uploaded again. It attaches only missing source
- files and signatures, verifies the full asset set, and promotes the prerelease. A run after the
- move resumes there without the original CI artifacts or a local `dist` directory.
-- Windows on ARM 64 joins the platforms, so a version ships six binary packages beside the source
- package.
-- `tools/install-manifests.sh` writes a Homebrew formula, a Scoop manifest and the winget
- manifests from the voted binary packages, and `publish` runs it. They are conveniences,
- submitted after the release and after the PMC agrees to each channel. The Homebrew formula
- installs the voted binary package for macOS or Linux, on ARM 64 or x86-64. It builds nothing, so
- it needs no Go, and the `asz` it installs serves the page with the renderer's fonts. It
- downloads from the GitHub release, with archive.apache.org as its mirror, and goes to a tap,
- because homebrew-core does not take a formula that installs a binary built for each platform.
- The winget manifests download from the GitHub release too, because the archive slows down and
- bans heavy use. Each package must match the voted `.sha512` beside it.
- [Install](../setup/install.md) lists every way to get asz.
-- `make release` delegates to `candidate --no-upload`, preparing signed files locally from the
- verified GitHub binaries and tagged source. `GPG_USER` picks the signing key. Local binaries
- from `make binaries` are for diagnostics; candidate staging never falls back to them.
-- Binary builds use `GOWORK=off` and `GOFLAGS=-mod=readonly`, so local workspace settings cannot
- change their dependencies. `candidate` checks the source archive for compiled files by content
- type and extension, including static libraries, Go objects, Java archives and Python byte code.
- The voters' checklist checks them too.
-- `make checksums` stops at the first package it cannot checksum, removes that `.sha512`, and
- checks each `.sha512` right after writing it. Before, a failed checksum left an empty
- `.sha512`, and `make release` went on to sign every package.
-- The source package holds no font file. The two fonts of the conversation renderer are under the
- SIL Open Font License, which the ASF puts in Category B, and the ASF does not allow a Category B
- work in a source release. `.gitattributes` marks them `export-ignore`, so `git archive` leaves
- them out, and candidate preparation refuses a source package that holds a font file anyway.
- The binaries in the binary packages embed the fonts, and `dist-material/LICENSE` names them. A
- build from the source package draws the page with system fonts.
-- `make conversation-view-check` passes in an unpacked source package. That package leaves out
- the renderer's two fonts, so there the check leaves them out of its comparison, names them, and
- compares every other file. Before, it failed in every source package and told the voter to
- commit an update. In a clone of the tag it still compares the fonts, and the vote mail says
- which files it compares.
-- The `LICENSE` and `licenses/` of a binary package name only the modules built into `asz` and
- the plugin. `github.com/kr/text` and `github.com/rogpeppe/go-internal`, which only the tests of
- `gopkg.in/yaml.v3` need, are gone from them, because the ASF asks the `LICENSE` of a package to
- account for exactly what it holds. `make dep-licenses` and `make dep-licenses-check` take the
- modules for the `LICENSE` and the `NOTICE` alike from `go list -deps` of both binaries, on every
- platform in `PLATFORMS`.
-- Two builds of one tag give the same binary packages, byte for byte, when they use the same Go,
- the same tar and the same gzip. Go records the tag in each binary as the module's version, so a
- build of the commit before it was tagged differs. Every file has the commit's time, its owner
- and group are 0, and the entries are sorted. No package records who built it or when. GNU tar
- and bsdtar write their headers differently, and GNU gzip and Apple's gzip compress differently,
- so a CI build, made with GNU tar and GNU gzip, and a macOS build, made with bsdtar and Apple's
- gzip, differ.
-- The compiled `collectorcheck` and `otlpdump` helpers, committed at the repository root by
- mistake, are removed, and `.gitignore` keeps them out. Their sources stay under `tools/`.
-- Creating the GitHub release publishes the container image under the version the tag names, and
- under `latest` when it is the newest version, and nothing looser. The `major.minor` line tag,
- `0.2` beside `0.2.0`, is no longer published: a reader who pulled it could not tell which release
- answered. The `0.2` tag that 0.2.0 published stays on the registry and points at the same image
- as `0.2.0`.
-
-## Workspace changes
-
-- Which files a tool call changed is shown beside the step. Two producers write one shape,
- `changes/1`, defined by `pkg/changes`, whose id is the tool-use id and whose `captured_by` says
- which producer observed it: the Claude Code adapter copies the runtime's own patch from every
- `Edit` and `Write` result on the main stream into a second `data` part beside the raw result,
- and the new asz Claude Code plugin, `plugins/claude-code/`, records shell commands, and edits
- inside subagents, into its own data directory. The plugin runs inside Claude Code's hooks, one
- short process per event, needs nothing from asz, classifies read-only commands to skip their
- scans, excludes every known language's build output by a frozen rule set, names overlapping
- windows on the same root, and keeps its output for 30 days. The new `claude-code-changes`
- adapter, on by default, tails the plugin's files and lands each line as a record of kind
- `changes` under the stream the tool ran in, with the session's own lock and sequence, and the
- pipeline refreshes both sources in one pass. Session Data and Session Flow are unchanged:
- `changes` is a new kind, assembly emits no node for it, and a session folds to the same nodes
- with and without the records.
-- `asz.view` gains `workspace_changes`, every record joined to its step. A tool step names its
- records under `changes`, and `summary.changes` counts them. The version stays 1.0: no official
- release carries the format yet, so the keys are added rather than a version raised.
-- The plugin ships in every binary package under `claude-code-plugin/`, and `make build` builds it
- beside `asz`.
-- The plugin's hooks give Claude Code the binary as the command and `hook` as its one argument, in
- the hook's `args`. Claude Code's hooks reference says Claude Code then starts the command
- directly, with no shell, and that no shell splits the command into words on any platform.
- Claude Code 2.1.260 on macOS ran the hooks in this form, and the plugin's record named the file a
- shell command created. The command line the hooks gave before went to a shell. The hooks
- reference says that on Windows without Git Bash, that shell is PowerShell. On macOS, PowerShell
- 7.5.3 refused that line, a quoted path followed by a word, and the binary did not start. Claude
- Code has not run either form on Windows. With no argument and its event on standard input, the
- binary now runs as `hook`, so a Claude Code that drops the argument does not block a tool with
- the usage text's exit status 2.
- [The hook command](../setup/claude-code-plugin.md#the-hook-command) describes the form, and
- [What was verified](../setup/claude-code-plugin.md#what-was-verified) says what is still unknown
- on Windows.
-
-## Metrics
-
-- `claude-code-local` with `metrics: true` derives a reconstructed subset of the runtime's own
- metric family from the landed files. Phase one derives `claude_code.token.usage`, under the name
- Claude Code's OpenTelemetry exporter uses. The usage of a call is its last fragment's in line
- order, and only a finished call counts. Points are per minute, by type, model, query source and
- session. The exporter's account, speed, effort and attribution labels and its auxiliary calls
- are not reconstructed, and the export page states the difference. The points wait in the
- storage root's `_metrics/` spool. They are sent over the metrics service, under asz's identity,
- with the same budget and once-only rule as the files, at the end of each pass of `asz collect`
- and `asz server`, and by `asz push`. `metrics_lookback`, 24 hours unless set, bounds the first
- derivation over a root with history, and so does the newest request the receiver landed, so a
- switch of source counts nothing twice. A pass is deterministic, names its requests after their
- landed files and saves its state once, so a pass cut short is run again to the same bytes.
- Every scenario checks the points on the wire against its plan, and the Collector job verifies
- the tokens that arrive from both sources.
-- A receiver's partial success is a success the protocol says not to retry: the rejected records
- or points are counted on the pass line as `rejected`, and the files are marked sent.
-- A capture of what Claude Code 2.1.260 itself sent to the receiver, with every identifying value
- replaced, is the parity fixture: a test holds the derived token metric to it, the same name,
- unit, description, kind, value encoding and token types, the same session, model, query source
- and type labels, and a difference that is exactly the labels and metrics the export page lists
- as not derived. The derivation now writes doubles and a point for every type, zero included, as
- the exporter does. `tools/otlpdump` prints a spooled request as the protocol's JSON.
-- `claude-code-otlp` is a second adapter for the runtime: an OpenTelemetry receiver its own
- exporter is pointed at, gRPC and HTTP with protobuf on one `listen` port. Phase one lands the
- metrics requests it receives in the same spool, bytes as received, and they are sent from there
- as the derived points are. Logs and traces are accepted and dropped, counted in the status. It
- runs beside the local adapter under `asz collect` and `asz server`, and not with `-once`.
- `metrics` may be on for one adapter, never both, and the configuration refuses to load
- otherwise, so the same tokens are never counted twice. A receiver takes `listen` and `metrics`
- only. Collector settings on it are refused, since it polls nothing.
-- `export.otlp.logs` and `export.otlp.metrics` switch the two things a push sends, the landed
- files and rounds as logs and the metrics spool as metrics, each on its own, both on unless set
- off. `asz push` says which it is sending, and a configuration with both off is refused.
-
-## Export
-
-- `push.state` names the receiver its files were sent to, on an `endpoint` line, and each file a
- receiver rejected records of, on a `rejected` line. Both lines are kept on every save. A
- `push.state` written before this names no receiver. It is read as sent to an unknown receiver, so
- a scenario root that holds one removes nothing.
-- Over HTTP, a 2xx answer counts as sent only when its body is empty or protobuf, and a redirect is
- not followed. Before, an HTML page answered with 200, or a redirect to a login page, left files
- recorded as sent that no receiver stored.
-
-## Documentation
-
-- `design-notes/` is removed. What its three notes described that has landed is now documented in
- these pages, checked against the code rather than copied from the notes, which were older than
- the code. The notes remain in the git history. The documentation is the one reference.
-- Conversation Assembly now gives the size of the index that
- `design-notes/02-parse-and-assembly.md` measured: 47 MB of index for 1.0 GB of landed payload,
- about 21 times smaller. The note, as the tag `v0.2.0` holds it, said about 12 times for the same
- two numbers.
+> In development, not yet released. `tools/release.sh prepare 0.4.0` removes this note.
diff --git a/docs/menu.yml b/docs/menu.yml
index 2931855..8f4c447 100644
--- a/docs/menu.yml
+++ b/docs/menu.yml
@@ -72,6 +72,8 @@ catalog:
catalog:
- name: Current Version
path: /en/changes/changes
+ - name: 0.3.0
+ path: /en/changes/changes-0.3.0
- name: 0.2.0
path: /en/changes/changes-0.2.0
- name: 0.1.0