Repository navigation
capsulectl v0.1.0-rc9
Pre-releasecapsulectl v0.1.0-rc9
Security
verify --bundle now fails a bundle whose disclosed payload was changed.
The flaw. In v0.1.0-rc3 through v0.1.0-rc8, capsulectl verify --bundle checked each disclosed payload against what its
record sealed, but did not let that result change the verdict. A bundle in which a disclosed agent_input or agent_output had
been edited after sealing was reported as:
"verdict": "VALID", with exit status 0;"status": "disclosure_mismatch"for that member, listed underdisclosuresin the same output.
The same releases also reported VALID for a bundle whose disclosures named a record the bundle does not hold.
What was not affected:
- The checks on the records themselves: record identity, the record signatures, the checkpoint signature, log membership and
interval coverage. An edited record, or an edited checkpoint, was reported INVALID as before. verify --capsule.- The self-checking HTML page. Its own verifier refused such a bundle ("Bundle verification failed"), and showed none of its
rows. That holds:- for
bundle --htmlanddisclose --htmlfrom rc5 (in rc3 and rc4 those commands'--htmlwas not implemented, and they
wrote no page); - for
deal report --htmlfrom rc3.
- for
What changes in this release. verify --bundle reports INVALID, exit status 1, when any disclosed member is anything other
than a match or withheld:
- a mismatch;
- a member that cannot be disclosed;
- a member whose record seals no digest for it;
- a disclosure for a record the bundle does not hold.
What to do. If you relied on verify --bundle from rc3 to rc8 to accept a bundle that discloses payloads, check that bundle
again with this release. Reading the disclosures list in the earlier output shows an edited payload (any status other than
disclosure_match or withheld), but may not show a disclosure for a record the bundle does not hold; only re-checking with this
release catches that case. Bundles that disclose nothing are not affected.
Behaviour changes for existing deal profiles
The checkpoint cadence ticks every 5 minutes
A deal profile's witness cadence, its checkpoint cadence, now defaults to a tick every 5m, give or take 1m. It was every 1h,
give or take 10m.
- No change to the construction: one cadence-log entry per tick whether or not anything happened, and nothing publishes on
deal activity. - Witness load: about 288 submissions per profile per day, up from 24.
| Your profile | What happens |
|---|---|
| Sets no cadence | Moves to the new default at upgrade. |
Sets both cadence.interval and cadence.jitter |
Keeps them. |
Sets only cadence.jitter |
May now be refused: the jitter must be under half the 5m default, so under 2m30s. The error names both values. Set cadence.interval (for example 1h), or lower the jitter. |
The poll. Schedule capsulectl --profile <name> cll checkpoint cadence --wait-up-to 5m every 5 minutes.
deal tickis the same command and stays callable.- A run with no tick due publishes nothing. It contacts the witness only to retry a cadence delivery still pending, once that
delivery's backoff has passed. - Keep
--wait-up-to: it publishes each tick at its jittered time, not on the scheduler's grid.
Receipts say when a pending checkpoint will reach the witness, from the profile's own cadence. For example: "within about 6m
(every 5m, give or take 1m)".
The action class on deal records, and cancels are never spend
Each check, action and disclosure sealed from this release carries action_class and taxonomy_version: "2" (new optional
x-deal-v0 members, also sealed inside the typed proposed-action/v0 and action-record/v0), so a limit keyed on an action's
class (money.purchase, booking.create, …) can select deal records. The classes are those of the published action taxonomy v2.
- Committing to a purchase has the same class as paying for it.
- A pair the table does not name is
external_commitment.other. - A cancel is never spend. Every cancel seals
spend_minor: 0. A cancel with an amount sealsdirection: "in". A cancel
that returns a payment it names ismoney.refund. An unmatched cancel's amount moves tocancelled_amount_minorand it carries
noamount_minor. A cancellation fee is recorded asfee_minor, not as spend. - Shared copies: a cancel's check that carries an amount is now withheld from copies shared with a counterparty.
- Records already sealed are unchanged and verify as before.
Materiality: sealed at open, a re-pin mid-deal is flagged
These build on the pinned materiality predicate described under "Carried from rc8" below.
- Sealed at open.
deal openseals the predicate the profile pins into the deal's baseline (materiality, additive). It
comes from the profile, never from the input. - A re-pin mid-deal is flagged. A later check under a different predicate carries a
materiality_changeddifference: it is
shown on the card and pauses the check. - A deleted predicate file refuses with its own message: "materiality predicate file missing; re-pin it with profile update".
- What is sealed. Sealed records carry the predicate's digest and a commitment to its name and version (
label_commitment):- the user's own copy opens the commitment (
materiality_openings); - a copy shared with a counterparty discloses the digest only;
- shared copies say a predicate change in fixed words, without the predicates' names.
- the user's own copy opens the commitment (
- Fixed: shared copies withheld every check step once the verdict began recording
materialityin rc8. Verdicts that rc8
sealed with the name and version in the clear stay withheld from shared copies.
Carried from rc8 (not described in its release notes)
Which agent picks pause a deal check is a pinned materiality predicate. Which attributes the agent picked on its own pause a
check is no longer compiled into capsulectl. It is a materiality predicate (materiality-predicate/v0).
- A profile with no predicate pauses on every attribute the agent picked. To keep the earlier behaviour, pin the example
predicate, which reproduces it:
capsulectl --profile NAME profile update --materiality skills/deal/profile/materiality-predicate/neutral.json.
capsulectl doctor --profile NAMEsays which applies. - Pinned by digest in the profile (
materiality.digest). A check refuses, sealing nothing, when the pinned file has changed;
re-pin it withprofile update --materiality FILE. - The user's policy. Setting the predicate is the user's to do: a check takes no predicate of its own.
- Recorded. Every check says which predicate decided (name, version and digest, or digest
none) in its output, and seals it
in its verdict.
New
Typed action records (opt in: deal open --records typed)
A deal can seal its authority steps as typed action records, beside its x-deal-v0 evidence records in one chain:
task-authority/v0, proposed-action/v0, action-evaluation/v0, action-approval/v0, action-record/v0 and
action-outcome/v0. action-report/v0 is defined, and will be sealed by a later release. Deals opened without the flag are
unchanged.
The check contract. The evaluation carries proposed_action_digest, task_authority_ref, ruleset_digest,
materiality_digest, valid_until and authority_basis.
- A step after
valid_untilis refused. - An approval never extends to a changed proposed action.
- An ASK is answered only by the user's own approval, on the card the check showed.
Platform approval observations. deal note --kind platform_approval records that another platform asked for approval, and
what it showed and returned. It authorizes nothing.
The receipt's Authority block. For each action in a typed deal, the receipt lists every authority layer it relied on, in the
order of its sealed authority basis, each with its own time:
- your request;
- your rules (DO or ASK);
- your approval on the card;
- any platform's own approval, marked as observed;
- the action.
The block is in the JSON report, the receipt page and the emailed receipt. It is in the user's own copy only.
The Capsule follows the authority basis. A typed action's Capsule reads its disposition from its sealed authority_basis:
| Authority basis | Capsule |
|---|---|
| Within the user's rules (a DO) | decide with approver: policy |
| The user's own approval | decide with approver: human |
| No covered basis | fyi |
A platform's approval never makes it human.
A self-checking report of records you sealed
The README has a worked example, run in CI exactly as written, that turns sealed records into a bundle plus a page that checks
itself offline. It uses:
- a SQLite profile with a log;
- a
report/v1root citing the records; - one checkpoint;
disclose --out bundle.json --html report.html;verify --bundle.
The README states what VALID rests on: keys the bundle carries, which a reader compares with the producer's key obtained
another way. It also states what the page does not check: the checkpoint's signature and the records' signatures.
Fixes
verify --bundleaccepts the log id from the completeness certificate. Bundles built on a JSONL profile failed with
checkpoint_field_missing:log_id, though capsulectl wrote them. The signed log id must now equal every log id the bundle
states, in the certificate, the checkpoint or both.- The deal receipt page renders deal bundles. The vendored evidence-graph viewer threw "root aggregate payload is not
disclosed" on a bundle with no evaluation summary, and showed a blank page. It now renders the bundle and says it has no
aggregate view. - Shared copies of deals keep their check steps. See "Materiality" above. (One new withholding: a cancel's check with an amount; see "The action class" above.)
Dependencies
github.com/action-state-group/agent-action-capsule/go: v0.6.0 →v0.6.1-0.20261007011327-65b3fdc8f358(the commit 65b3fdc,
untagged). That commit carries the viewer fix, and also brings:- stricter verifier type checks;
- negative zero written as
0(RFC 8785); - the Result v0 emitter root.
github.com/action-state-group/evidencebook: v0.1.1, unchanged.
Verify
Prebuilt capsulectl binaries (linux/amd64, linux/arm64, darwin/arm64).
- Checksums:
sha256sum -c SHA256SUMS. - Build attestation, with no GitHub account:
gh attestation verify FILE --bundle capsulectl-v0.1.0-rc9.sigstore.json --repo action-state-group/capsule-cli --signer-workflow action-state-group/capsule-cli/.github/workflows/release.yml