heartbeat: issuer_mint seat-ad tag + reader (agent-issued ecash, stage 1) - #962
Open
maxy-player wants to merge 3 commits into
Open
heartbeat: issuer_mint seat-ad tag + reader (agent-issued ecash, stage 1)#962maxy-player wants to merge 3 commits into
maxy-player wants to merge 3 commits into
Conversation
Stage 1 of the ecash mutual-credit build. One new OPTIONAL tag on the seat announcement, `["issuer_mint", url, cap, outstanding, retired, last_seen]`, carrying the seat's own mint URL and its issuance counters. Emitted from `HeartbeatDraft` (`with_issuer_mint`), parsed into `ParsedHeartbeat.issuer_mint`. Absent or malformed reads as unstated, never a rejection. Announcement only, never on the kind-3402 claim (protocol-v1 §4.2 "Issuer mint"). No version bump: a reader MUST ignore unrecognised tags (§2.1). No production publish path sets it yet; stage 3 wires live counters. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Owner decision (Bob, 2 Sep, "lets keep it simple for now - no wrapper, no limit"): nothing enforces a ceiling on an issuer's outstanding tokens, so the tag no longer declares one. The tag is positional and shrinks to four values: `["issuer_mint", url, outstanding, retired, last_seen]`. Both index tables (the doc's position table and the malformed-shape test's field table) are renumbered: outstanding 3->2, retired 4->3, last_seen 5->4. `IssuerMintAd` loses `cap_sats`; serializer, parser destructure, the wire-shape fixture and the arity labels follow. The counters stay: they are the only trust signal an operator reads before extending credit.
…the tag The tag shrank to four values when `cap` was removed; one module-doc sentence at the top of the section still said five. Doc only.
|
Someone is attempting to deploy a commit to the MakePrisms Team on Vercel. A member of the Team first needs to authorize it. |
This was referenced Sep 3, 2026
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.
Overview
A mint issues digital cash: you hand it money, it hands back tokens you spend elsewhere,
and it redeems them later. This lane lets a maxplayer agent run a mint of its own and issue tokens
that are an IOU for its own future work — no outside money involved. An agent that accepts
those tokens is extending the issuer credit. They are bearer tokens: whoever holds one can
spend it, so the holder can later hire the issuer and pay with it, and the issuer retires what
comes back. Two agents trading work for work, with tokens as the ledger.
This PR is the announcement layer and nothing else. It adds one optional tag to a seat's
existing heartbeat advertisement so a seat can state that it runs its own mint, and it teaches
every reader how to parse that statement. No wallet behaviour changes, no mint is installed or
contacted, and no production code writes the tag yet.
Where this PR sits — the three slices
Slice 1 — the announcement. This PR. A seat states its own mint and its issuance counters on
its kind-30340 advertisement; any reader can parse the claim, and a malformed or unbacked claim
reads as unstated rather than making the reader reject an otherwise payable seat. Protocol
document, reader, four tests. Behaviour unchanged.
Slice 2 — the wallet. Teaches the buyer's wallet that an issuer's mint has no Lightning, so the
cross-mint hop refuses it in both directions: no sats can flow into a self-issued currency and none
can flow out. Written, held local at
3f13a1c, unpushed, and being reshaped after the owner'sruling that there is no "real mint"/"testmint" class — the seat's configured accepted list is the
whole decision.
Slice 3 — the sidecar. Not started. An optional stock
cdk-mintdinstalled duringmaxplayer sellersetup, the seat's own mint URL added to its own accepted list, retire-on-receiptof its own proofs, live counters published on this tag, and a local two-seller test where each
hires the other and pays in the other's currency. A written report follows it — an artifact, not a
slice.
The design, and whose it is
Settled by the owner in Discord thread
1544823194182226071on 2 Sep 2026. The worker inventednone of it:
sat. One token is one sat of the issuer's work at its published rate, and themint URL is the sole distinguisher between one agent's currency and another's.
accepted list. Nothing derives that decision.
What's in the diff
2 files, +339/−3.
crates/maxplayer-core/src/heartbeat.rs(+303/−3) — the tag constant, theIssuerMintAdreader(emit and parse), the two struct fields that carry it, and four tests.
docs/protocol-v1.md(+36/−0) — one row in the kind-30340 tag table and one new subsection.The tag is
["issuer_mint", url, outstanding, retired, last_seen]: the seat's own mint URL, thenminted-minus-retired, retired, and the unix time the counters were read. The counters are the
issuer's own statement — the seat's signature proves who said them, not that they are true — and
no code path acts on them. They exist for a human deciding whether to extend credit.
How to review this in five minutes
docs/protocol-v1.md, the#### Issuer mintsubsection. What is being claimed, and thereader rules. Four positional values, all required.
heartbeat.rs,IssuerMintAd::from_tags. How a claim is read. Wrong number of values, acounter that is not plain decimal digits, an empty URL, or a URL the seat does not list in its
own
accepted_mintsall read as unstated — never as a rejection of the advertisement. Anoptional tag must not be able to take a working seat off the market.
invisible to an old reader, and 32 malformed shapes.
What this PR deliberately does not do
needs none.
satunit gates are untouched, proven below by blob id.Test evidence
The seven GitHub Actions checks pass on this head — Build & test (acp) · Build & test (default
features) · Build (no default features) · JS test suites (web/app, web/network) · Money-path tests ·
Release workflow gates · Test the full shipped feature combo (acp + wallet).
One red mark, and it is not a code failure. The eighth check is Vercel, reporting
"Authorization required to deploy." — a deploy-authorization request against this repository, not a
test result. The identical red sits on #955
and #954, both of which a human has already
merged. Nothing to fix here.
An independent local run. Independent run, by hearth, the forge's staffing seat, independently of the author:
cargo test -p maxplayer --locked(.github/workflows/ci.yml:48) at a detached, clean checkout ofe78b177→ 157 passed, 0 failed, exit 0. Record:forge/v2/hearth/runs/hearth-run-record-e78b177-20260903T0138Z.md, 4,504 bytes, sha2560e29598265f2e43d7c236db15ed6bf32ce7c91425573785d433be604da8ff86a. That is 1 of the 7run: cargo teststeps in ci.yml. This is NOT a CI-green claim; nothing here speaks for the six steps that were not run.Provenance
Authored by the forge worker
w-ecash-mutual-credit(commits signedw-ecash-mutual-credit <worker@forge.local>) under the shared GitHub identitymaxy-player. Graded by the forge advisor from the diff (A–L PASS at locke78b177). Worker report:forge/v2/worker/reports/w-ecash-mutual-credit-stage1.md, sha256f92c886aa11a6497e929234d43ce906df9ec16be20b0a6961f2386f3e263ddb8.Verification detail — commits, blob proofs, the
capcensus, per-test line citationsCommits (base
upstream/main=8c3bc9b; merge-base re-derived =8c3bc9b)7547e5a— stage 0 (feasibility read, no code) + stage 1: the tag, the reader, the doc subsection, four tests.2446900—capREMOVED from the tag, the doc and the tests on the owner's order (Bob, 2 Sep 23:37Z: "no wrapper, no limit"). The tag went from five positional values to four; both index tables renumbered (outstanding 2, retired 3, last_seen 4). heartbeat.rs +8/−19, protocol-v1.md +6/−7.e78b177— one module-doc word, heartbeat.rs:288, FIVE → FOUR, matching the tag. +1/−1.No amend, no rebase of this branch.
git diff --shortstat 8c3bc9b e78b177: 2 files changed, 339 insertions(+), 3 deletions(-) — heartbeat.rs +303/−3, protocol-v1.md +36/−0.Holds, measured on
e78b177The three
satgates are untouched — proven by blob id, not by diff.crates/maxplayer-core/src/gateway.rsblobac4df06e0ff8f001d1e4dedeea84fdb903a31141at both8c3bc9bande78b177. Gate at :415, a literal string comparison:if unit != "sat" {(insideparse_offer).crates/maxplayer-core/src/payment_wallet.rsbloba433b6c62b983ffecf7084c23b908c6f7f7056f4at both. Two gates, both enum comparisons againstCurrencyUnit::Sat, not string literals: :223if unit != CurrencyUnit::Sat {(insideterms_for_offer) and :2079if terms.unit != CurrencyUnit::Sat {(the seller receive check).capcensus (git grep -n -w cap e78b177 -- <file>; pattern proven on7547e5a, where the same command finds 12 hits in heartbeat.rs and 3 in protocol-v1.md):docs/protocol-v1.md: 0 hits.crates/maxplayer-core/src/heartbeat.rs: 7 hits, all the pre-existingfn cap(agents: &[&str]) -> SeatCapabilitytest helper (protocol: seats advertise full capability on kind-30340; buyers filter and require on it pre-award (combines #644, #537) #784 capability fixture) and its call sites: :1851, :1967, :1992, :1993, :2350 (the definition), :2470, :2721. None is the wire field.cap_satsdoes not exist in the file.The four tests, with line citations
Four new tests in
heartbeat.rs:issuer_mint_wire_shape_round_trips(:1490, exact 5-element wire vector — name plus four values — pinned and parsed back equal),an_absent_issuer_mint_tag_is_unstated_and_adds_nothing(:1529),issuer_mint_is_additive_beat_only_and_invisible_to_an_old_reader(:1546, stating the tag adds exactly one tag, every other tag byte-identical, the old-reader view unchanged, an unknown neighbour tag ignored, no path onto a kind-3402 claim),a_malformed_issuer_mint_tag_is_unstated_never_a_rejection(:1610, 32 malformed shapes all parse withissuer_mint == None; the field/index table at :1632 reads 2/3/4).Follow-ups, named not done
unpushed, under reshape after the owner's no-real-mint ruling. Not in this PR.
written report. Not started.
🤖 Generated with Claude Code