Skip to content

Sign v2 action tuples for dev.24 reactors; drives get as a tree - #2

Merged
liberuum merged 4 commits into
mainfrom
feat/v2-action-signatures
Sep 25, 2026
Merged

liberuum merged 4 commits into
mainfrom
feat/v2-action-signatures

Conversation

@liberuum

Copy link
Copy Markdown
Owner

Why

A 6.2.3-dev.24 reactor creates every document v2-required and refuses the CLI's legacy signature, so every signed write to a new document failed:

[SCHEME_BELOW_POLICY]: action … carries a legacy tuple but … requires v2 signatures

What changed

  • fix(sign) — signs with the reactor's v2 scheme: "v2:" + base64url(sha256(canonicalJson([...]))) over the document, branch, scope, type, action id, timestamp, input and signer. canonicalJson matches safe-stable-stringify (keys sorted by UTF-16 code unit, numbers written as JavaScript writes them). Relationships are signed against their sourceId. The message layout is unchanged, so older Switchboards accept v2 tuples too; the CLI always signs v2.
  • feat(drives) — drives get shows a plain folder/document tree, one line per document (📄 name type id) instead of a table per folder. 701 → 349 lines on a 325-document drive.
  • fix(release) — the release job now bumps the crate's entry in Cargo.lock along with Cargo.toml; the committed lock had been trailing by one release.
  • chore — syncs Cargo.lock to 1.0.37.

Verification

  • 13 hash vectors generated from the reactor's own hashActionV2 (@powerhousedao/shared@6.2.3-dev.24) pin the preimage and hash byte for byte; a naive serde_json port fails them.
  • Live against a dev.24 reactor: docs apply, docs link and docs mutate all succeed, stored with a v2 tuple under the caller's key.
  • dev.20's own verifyOperationSignature accepts a stored v2 tuple and rejects a tampered one.
  • cargo metadata --locked accepts the lock the new release step produces and refuses the old one.
  • fmt, clippy -D warnings, 73 unit tests and 34/34 integration tests pass; the release checks pass on a fresh clone.

🤖 Generated with Claude Code

liberuum and others added 4 commits September 25, 2026 12:06
… documents

A 6.2.3-dev.24 reactor creates every document v2-required and refuses the
legacy tuple the CLI signed:

  [SCHEME_BELOW_POLICY]: action … carries a legacy tuple but … requires v2 signatures

The v2 hash is "v2:" + base64url(sha256(canonicalJson([...]))) over the
document, branch, scope, type, action id, timestamp, input and signer, as
@powerhousedao/shared's hashActionV2 builds it. canonicalJson sorts keys by
UTF-16 code unit and writes numbers as JavaScript does (2.0 is 2, 1e21 is
1e+21, -0 is 0); serde_json does neither. sign_action now takes the job's
document and branch: a relationship is signed against its sourceId, other
document-scope actions against input.documentId.

The message layout is unchanged, so a Switchboard older than dev.24, which
checks only the ECDSA over the tuple, accepts a v2 tuple too. Checked with
dev.20's own verifyOperationSignature, so the CLI always signs v2.

The hash is pinned by 13 vectors generated from the reactor's hashActionV2
(tests/fixtures/, with the script that regenerates them). `docs apply` now
refuses to sign when the document id does not resolve, rather than sign the
raw fallback the reactor would reject.

Removes the legacy action_hash, compact_json and sign, which this replaces.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The default view nested a table under every folder, two lines per document
plus borders, so a large drive ran to hundreds of lines and came apart when
a row wrapped. It is now a plain folder/document tree, `📄 name  type  id`,
with the type and id dimmed and the id kept whole and last.
My Personal Vault goes from 701 lines to 349.

Columns are not padded: document names run to ~100 characters, and aligning
on them would make a folder wider than the table this replaces.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The release job bumps Cargo.toml but not Cargo.lock, which still named
1.0.36. Nothing builds with --locked, so this never failed a build.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The release job rewrote the version in Cargo.toml and committed only that,
so the committed lock trailed by a release (1.0.36 against 1.0.37). It now
bumps the crate's own entry in Cargo.lock too — only the line after
`name = "switchboard-cli"`, since the lock holds a `version =` line for
every one of its 358 packages — and commits both files. A plain sed, so the
release job still needs no Rust toolchain or network.

Checked with `cargo metadata --locked`: it accepts the lock this produces,
and refuses the one the old step left behind.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@liberuum
liberuum merged commit 1552222 into main Sep 25, 2026
3 checks passed
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