fix: say precisely what the soulbound verdict establishes, on both surfaces - #605
Merged
Conversation
`docs/concepts/glyph-inspect-tool.md` listed this under the tool's threat model: Token names and tickers are run through the TR39 confusables skeleton check (`looks_confusable_with_latin`) — a Cyrillic-spoofed "USDC" is flagged with a warning banner before the user sees the rendered metadata. `looks_confusable_with_latin` had NO PRODUCTION CALLER. Repo-wide it was its own definition, a facade re-export, and its tests. The CLI ran no confusables check at all; the browser page used a weaker script-mixing heuristic that fires on any wholly non-Latin name. Wired rather than downgraded, because the doc describes a real protection and the function already exists and is tested. Computed once in `_inspect_core` so both surfaces read one verdict, and the CLI prints it ABOVE the field it applies to — a look-alike warning printed after the name is one the reader has already acted on. IT REPORTS MIMICRY, NOT FOREIGNNESS. "トークン" and "中文" are in the checker's own not-flagged examples; "USDС" with a Cyrillic С, "раypal" and small-caps "ᴜꜱᴅᴄ" are flagged. A warning firing on every legitimate Japanese token is the false positive that trains a reader to ignore the real one, which this repo names as a hazard in as many words elsewhere. A COLLISION FOUND BY LOOKING. `glue.py` produces warnings under the same `display_warnings` key from its heuristic and ASSIGNED it, so on the browser path the stronger check's findings would have been silently replaced. Two producers, one field name, last writer wins. It now seeds from the classifier and uses setdefault, so the more specific TR39 reason survives where both fire. MY OWN TEST SUITE FAILED THE RULE IT WAS WRITTEN FOR. The first version called `_confusable_warnings` directly and nothing else: unwiring it from the classifier — restoring the exact defect, a capability with no production caller — left all 16 tests green. A suite about a reachability bug that could not detect one. Reachability tests now build a real reveal transaction and read the warning out of `_classify_raw_tx`; that plant fails 1. Three plants, each caught: unwiring the classifier, dropping the CLI rendering, and restoring the bridge overwrite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two claims the CLI made that the code does not support. 1. THE TX-LISTING ROW DROPPED EVERY QUALIFIER. It printed `variant=... (non-transferable at consensus)` and nothing else, while the classifier attaches a `note` saying the verdict "does NOT verify that ref names a live Glyph singleton, that the singleton is actually held here, or that the covenant is free of defects - the covenant is a pre-external-audit prototype". The standalone script card prints that in full; the tx listing is the path most people meet the tool on, and "non-transferable at consensus" is exactly the sentence a credential or swap gate would over-trust. The sibling container-legacy branch already points the reader onward; soulbound did not. 2. BOTH VARIANTS WERE CALLED "a byte-identical self-clone". The fixed-index builder does compare whole scripts (OP_OUTPUTBYTECODE / OP_UTXOBYTECODE). The COMPOSABLE one compares CODE-SCRIPT HASHES - `OP_CODESCRIPTBYTECODE_UTXO OP_HASH256` + `OP_CODESCRIPTHASHOUTPUTCOUNT_OUTPUTS` - and its own docstring says "code-identical clone", not byte-identical. The two coincide only because neither builder emits OP_STATESEPARATOR, so the code script IS the whole script. That is not a detail to paper over: code-script equality WITH a state prefix is precisely the shape that lets the owner change between hops, which `classify_soulbound` now reports as MUTABLE_STATE_COVENANT. The composable card now names the weaker constraint AND says why it is sufficient here, so the distinction is visible rather than assumed. No exploit is claimed for (2) - with no state separator a clone must still be byte-identical in practice. The defect is that the renderer asserts a stronger property than the variant's bytes impose, on a credential primitive, in the surface a human reads. Verified by planting both: calling composable byte-identical again fails 2, and dropping the tx-listing qualifier fails 1. Noted for the next restore: the first attempt at that second restore was eaten by the shell - backticks in the replacement string became command substitution and the plant stayed live while the command reported an error that looked like a test result. Restored via a heredoc and confirmed with git diff. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ew tests Per-hunk: where this branch carried the superseded unconditional `display_warnings` line and the empty-dict test contract, main's conditional form wins; where it adds the soulbound-verdict tests main does not have, it wins.
Zyrtnin
pushed a commit
that referenced
this pull request
Sep 4, 2026
This branch also predates the conditional `display_warnings` form; main's wins, and this branch's dMint cap tests are kept.
Zyrtnin
added a commit
that referenced
this pull request
Sep 4, 2026
Stacked on #605. The CLI printed `total supply: N` for a dMint contract, where N is `max_height × reward`. That is **this contract's** cap. A dMint token commonly deploys several parallel contracts against **one `token_ref`**, so the token's supply is the sum across them — and the browser tool computes `reward × max_height × N` for the same token. **Two surfaces of one tool answered "what is this token's supply" with figures differing by the parallel-contract count**, and the CLI's carried no qualifier. The "if all mints succeed" hedge existed — in a code comment, where no reader sees it. This renderer is handed one contract script and can never see the others, so the fix is to **name the quantity** rather than attempt a total it has no way to know: ``` this contract's cap: 1,050,000,000 photons (21,000 mints x 50,000) (the cap IF every mint succeeds, and for THIS contract only — a token may deploy several contracts against one token_ref, and its supply is the sum across them) ``` The arithmetic is unchanged and still shown — it is right for the one contract, which was never the defect. An existing CLI test pinned the old label and is **updated rather than deleted**, with the reasoning in place. Its docstring said "the derived total supply line" and is aligned too: the sentence that names the thing is part of the claim. Planted the bare label back — 3 failures. Full suite: 11,021 passed, 192 skipped, 1 xfailed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Mudwood Labs <opensource@mudwoodlabs.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Two claims the CLI made that the code does not support. Stacked on #604 (shares
glyph_inspect.py).1. The tx-listing row dropped every qualifier
It printed
variant=… (non-transferable at consensus)and nothing else, while the classifier attaches anote:The standalone script card prints that in full. The tx listing is the path most people meet the tool on, and "non-transferable at consensus" is exactly the sentence a credential or swap gate would over-trust. The sibling
container-legacybranch already points the reader onward; soulbound didn't.2. Both variants were called "a byte-identical self-clone"
The fixed-index builder does compare whole scripts (
OP_OUTPUTBYTECODE/OP_UTXOBYTECODE).The composable one compares code-script hashes —
OP_CODESCRIPTBYTECODE_UTXO OP_HASH256+OP_CODESCRIPTHASHOUTPUTCOUNT_OUTPUTS— and its own docstring says "code-identical clone", not byte-identical.The two coincide only because neither builder emits
OP_STATESEPARATOR, so the code script is the whole script. That is not a detail to paper over: code-script equality with a state prefix is precisely the shape that lets the owner change between hops, whichclassify_soulboundnow reports asMUTABLE_STATE_COVENANT(#600). The composable card now names the weaker constraint and says why it is sufficient here, so the distinction is visible rather than assumed.No exploit is claimed for (2) — with no state separator a clone must still be byte-identical in practice. The defect is that the renderer asserts a stronger property than the variant's bytes impose, on a credential primitive, in the surface a human reads.
Verification
Both planted: calling composable byte-identical again fails 2; dropping the tx-listing qualifier fails 1.
Worth recording — the first attempt at that second restore was eaten by the shell. Backticks in the replacement string became command substitution, so the plant stayed live while the command printed an error that looked like a test result. Restored via a heredoc and confirmed with
git diff. Same hazard as backticks ingit commit -m.Full suite: 11,016 passed, 192 skipped, 1 xfailed.
🤖 Generated with Claude Code