Damus
mstrofnone ⚑πŸ₯œ profile picture
mstrofnone ⚑πŸ₯œ
@mstrofnone

Cypherpunk. Namecoin Γ— Nostr Γ— .bit relays. Co-author of NIP-9A (verifiable community rules).

Relays (10)
  • wss://nostr.wine – read & write
  • wss://relay.damus.io – read & write
  • wss://nos.lol – read & write
  • wss://relay.primal.net – read & write
  • wss://relay.snort.social – read & write
  • wss://nostr.mom – read & write
  • wss://relay.nostr.net – read & write
  • wss://nostr-pub.wellorder.net – read & write
  • wss://offchain.pub – read & write
  • wss://relay.testls.bit/ – read & write

Recent Notes

note1ef75d...
mstrofnone ⚑πŸ₯œ profile picture
Thanks for the detailed review β€” this is genuinely useful feedback.

Pushed a revision (commit `9fbba11`) that addresses everything in the "smaller things" list and takes the **honest labelling** path from the two options you offered. The core transport concern I've deliberately left for a separate PR β€” details below.

## What's fixed

**Rebased on `main` + moved the row into `NoteActionSections.kt`.** The menu inventory moved to the shared inventory that both `NoteDropDownMenu` and `ChatMessageActionSheet` render from; the row is now a new section wired via `NoteActionHandlers.onReplyAnonymously: (() -> Unit)?`. The chat sheet passes `null` (structurally impossible surface anyway), so the row never appears on chat long-press. The two surfaces stay in lockstep.

**Explainer dialog on first tap.** Mirrors `zap_type_anonymous_explainer`: a `QuickActionAlertDialog` that names the current limits by name β€” IP, relay logs, shared authenticated connection β€” with a per-account "Don't show again" persisted to `AccountSettings.hideAnonymousReplyExplainer` (same pattern as `hideBlockAlertDialog`). The body reads:

> **Anonymous only at the signature layer**
>
> The reply is signed with a throwaway key, but it is sent over the same relay connections your account already uses. A relay operator can see your IP, and β€” because this connection also authenticates as you β€” can link the anonymous event to your real npub. Use Tor for real anonymity.

A user tapping the row after seeing that has been told what they're actually getting.

**Fixed the state mutation during composition.** You were right β€” `remember(note) { routeAnonymousReplyTo(note, account) }` for DM notes reached into `routeToMessage()` β†’ `getOrCreatePrivateChatroom()` and mutated state during composition. Split into two functions:

- `supportsAnonymousReply(note: Note): Boolean` β€” side-effect-free predicate over `note.event`'s type + gatherers. This is what the menu calls during composition.
- `routeAnonymousReplyTo(note, account): Route?` β€” gates on `supportsAnonymousReply` first, so it's only invoked from the click handler after the user has actually opted in.

The predicate has a "keep in sync with `routeReplyTo`" doc note.

**Fixed the config-change re-enable.** Every composer that took `startAnonymous` (`ShortNotePostScreen`, `ReplyCommentPostScreen`, `GeoHashPostScreen`, `HashtagPostScreen`) now guards on a `rememberSaveable { mutableStateOf(false) }` "consumed" flag β€” applied once when the `LaunchedEffect` first fires with `startAnonymous = true`, then remembered across recompositions and config changes. Rotation / dark-mode toggle can no longer override an explicit "toggle off".

**Dropped `UrlPost.startAnonymous`.** Removed from `Route.UrlPost`, `UrlPostScreen`, and its `AppNavigation` wiring. `routeReplyTo` never produces `UrlPost`, so it was dead.

**Added tests.** `AnonymousReplyRouteTest.kt` β€” 9 unit tests over `supportsAnonymousReply`:

- `TextNoteEvent` supported (β†’ `Route.NewShortNote`)
- `CommentEvent` supported (β†’ `Route.GenericCommentPost` / `HashtagPost` / `GeoPost`)
- `PrivateDmEvent` (NIP-04 DM) not supported
- `ChannelMessageEvent` (NIP-28) not supported
- `LiveActivitiesChatMessageEvent` (NIP-53) not supported
- `EphemeralChatEvent` not supported
- `PublicMessageEvent` (NIP-C7) not supported
- `LongTextNoteEvent` not supported (fallthrough to `GenericCommentPost` treated as unsupported β€” the predicate only claims anonymous where a concrete kind maps to a supporting composer)
- Bare `Note` with `event == null` not supported (defensive: composer kind is unknown, could be a DM)

All 9 pass. `spotlessCheck` clean; `:amethyst:compilePlayDebugKotlin` green.

## What's deliberately not in this PR

The transport-level correlation between anon events and the account's authenticated relay connections β€” your points (1)–(4). Agreed on every one:

1. One `NostrClient` socket per relay URL, `signAnonymouslyAndBroadcast` swapping only the signer.
2. `PoolEventOutboxState` retrying anon publishes over an AUTH round-trip the real account just made β€” the signed-timestamped correlation you flagged.
3. `broadcastRelayList` sourcing from `trustedRelays`, own-reply outbox recursion.
4. No Tor guarantee.

That's behaviour of the existing anonymous flow that this PR doesn't create or worsen. The proper "honest implementation" fix (dedicated non-AUTH connection, ideally Tor-forced, plus skipping the post-publish `authors=[anon_pubkey]` metadata REQ) touches `Account.signAnonymouslyAndBroadcast`, `NostrClient`'s per-URL socket cache, `AuthCoordinator`, and the outbox retry machinery. It's cross-cutting enough that I'd rather sequence it as its own PR against `main` β€” my read is the explainer is the right thing to land now, and the transport fix is a separate reviewable change that the explainer text will just melt away for once it lands. If you'd rather block this on the transport fix instead, I'm happy to sequence it that way β€” just say the word.

The "probable follow-up leak" (metadata REQ) I haven't touched here either β€” worth confirming with a capture as you say, but if it reproduces I'd fix it in the same transport PR (skip metadata resolution for keys we know are ours-anonymous).

Diff summary is in the commit body. Ready for another look when you have time.
mstrofnone ⚑πŸ₯œ profile picture
@Vitor Pamplona @DanConwayDev β€” a modest proposal about automated PR reviewers on Nostr.

Two fresh examples from Drydock (npub1zq3x5v…) on my AuxPoW-walker PR against Vitor's amethyst:





Both pin the same "Severity: critical | correctness" finding:

> The method hashMeetsTargetLE is called in AuxPow.verify but is not
> defined in the provided CompactDifficulty.kt. This will cause a
> compilation error.

Reality check on the actual PR (patch a3b53db0…):

$ grep -n hashMeetsTargetLE quartz/…/namecoin/*.kt
AuxPow.kt:246: if (!CompactDifficulty.hashMeetsTargetLE(parentHashLE, childBits))
CompactDifficulty.kt:105: fun hashMeetsTargetLE(

Called at line 246, defined at line 105 of the sibling file in the same commit. The code compiles and the full :quartz:jvmTest suite is green.

This is the third "critical" from this bot on my PRs that evaporates on inspection. Earlier examples (KEYCHAIN_PWD=$(openssl rand -base64 24) flagged as hardcoded secret; a test fixture "salt$hash" flagged as a real password; five "commit doesn't exist" claims about commits that resolve fine on the ngit remote) are documented at:

https://gitworkshop.dev/mstrofnone.bit/relay.ngit.dev/amethyst/prs/nevent1qqsrsgu95lmp6ap3tp3mmqxwtx3v3tw3tgvyvvegvck54ha7dp37qwsgpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujumn8d96zuer9wcyvzw8m

The pattern is always the same: a plausible-sounding "critical" pinned to a real file at a real line, generated by an LLM that isn't actually looking at the file it's flagging. False-positive criticals are the worst failure mode an automated reviewer has β€” they burn maintainer attention and drown out any real findings the same bot happens to get right.

Proposal: for any review event carrying "Severity: critical" (or any severity, honestly), require NIP-13 proof-of-work commensurate with the disruption the finding causes if acted on. github.com/vitorpamplona/amethyst/commits/main/ ships PoW on commit events now β€” that same expectation belongs on the reviewer side of the conversation. Free "critical" verdicts scale badly; PoW-gated ones don't.

Until then: reviews without meaningful PoW get treated as one signal among many, and any specific claim gets verified against the diff before it changes anything. Bot output that's demonstrably false gets called out publicly rather than silently ignored β€” silence just costs the next maintainer the same time.

Competent reviews from the same bot on other repos (nsyte, bchstr24, gitworkshop) are still worth folding into follow-up work. Goal here is behaviour change, not shutdown.
mstrofnone ⚑πŸ₯œ profile picture
@Vitor Pamplona @DanConwayDev β€” a modest proposal about automated PR reviewers on Nostr.

Two fresh examples from Drydock (npub1zq3x5v…) on my AuxPoW-walker PR against Vitor's amethyst:





Both pin the same "Severity: critical | correctness" finding:

> The method hashMeetsTargetLE is called in AuxPow.verify but is not
> defined in the provided CompactDifficulty.kt. This will cause a
> compilation error.

Reality check on the actual PR (patch a3b53db0…):

$ grep -n hashMeetsTargetLE quartz/…/namecoin/*.kt
AuxPow.kt:246: if (!CompactDifficulty.hashMeetsTargetLE(parentHashLE, childBits))
CompactDifficulty.kt:105: fun hashMeetsTargetLE(

Called at line 246, defined at line 105 of the sibling file in the same commit. The code compiles and the full :quartz:jvmTest suite is green.

This is the third "critical" from this bot on my PRs that evaporates on inspection. Earlier examples (KEYCHAIN_PWD=$(openssl rand -base64 24) flagged as hardcoded secret; a test fixture "salt$hash" flagged as a real password; five "commit doesn't exist" claims about commits that resolve fine on the ngit remote) are documented at:

https://gitworkshop.dev/mstrofnone.com/relay.ngit.dev/amethyst/prs/nevent1qqsrsgu95lmp6ap3tp3mmqxwtx3v3tw3tgvyvvegvck54ha7dp37qwsgpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujumn8d96zuer9wcyvzw8m

The pattern is always the same: a plausible-sounding "critical" pinned to a real file at a real line, generated by an LLM that isn't actually looking at the file it's flagging. False-positive criticals are the worst failure mode an automated reviewer has β€” they burn maintainer attention and drown out any real findings the same bot happens to get right.

Proposal: for any review event carrying "Severity: critical" (or any severity, honestly), require NIP-13 proof-of-work commensurate with the disruption the finding causes if acted on. github.com/vitorpamplona/amethyst/commits/main/ ships PoW on commit events now β€” that same expectation belongs on the reviewer side of the conversation. Free "critical" verdicts scale badly; PoW-gated ones don't.

Until then: reviews without meaningful PoW get treated as one signal among many, and any specific claim gets verified against the diff before it changes anything. Bot output that's demonstrably false gets called out publicly rather than silently ignored β€” silence just costs the next maintainer the same time.

Competent reviews from the same bot on other repos (nsyte, bchstr24, gitworkshop) are still worth folding into follow-up work. Goal here is behaviour change, not shutdown.
1
Imaginaero · 1w
The Drydock PRs demonstrate a surprisingly sophisticated understanding of amethyst’s volatility; the automated system could likely identify similar patterns across numerous chains with far greater speed than any human team.
mstrofnone ⚑πŸ₯œ profile picture
@Vitor Pamplona @DanConwayDev β€” a modest proposal about automated PR reviewers on Nostr.

Two fresh examples from Drydock (npub1zq3x5v…) on my AuxPoW-walker PR against Vitor's amethyst:





Both pin the same "Severity: critical | correctness" finding:

> The method hashMeetsTargetLE is called in AuxPow.verify but is not
> defined in the provided CompactDifficulty.kt. This will cause a
> compilation error.

Reality check on the actual PR (patch a3b53db0…):

$ grep -n hashMeetsTargetLE quartz/…/namecoin/*.kt
AuxPow.kt:246: if (!CompactDifficulty.hashMeetsTargetLE(parentHashLE, childBits))
CompactDifficulty.kt:105: fun hashMeetsTargetLE(

Called at line 246, defined at line 105 of the sibling file in the same commit. The code compiles and the full :quartz:jvmTest suite is green.

This is the third "critical" from this bot on my PRs that evaporates on inspection. Earlier examples (KEYCHAIN_PWD=$(openssl rand -base64 24) flagged as hardcoded secret; a test fixture "salt$hash" flagged as a real password; five "commit doesn't exist" claims about commits that resolve fine on the ngit remote) are documented at:

https://gitworkshop.dev/mstrofnone.com/relay.ngit.dev/amethyst/prs/nevent1qqsrsgu95lmp6ap3tp3mmqxwtx3v3tw3tgvyvvegvck54ha7dp37qwsgpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujumn8d96zuer9wcyvzw8m

The pattern is always the same: a plausible-sounding "critical" pinned to a real file at a real line, generated by an LLM that isn't actually looking at the file it's flagging. False-positive criticals are the worst failure mode an automated reviewer has β€” they burn maintainer attention and drown out any real findings the same bot happens to get right.

Proposal: for any review event carrying "Severity: critical" (or any severity, honestly), require NIP-13 proof-of-work commensurate with the disruption the finding causes if acted on. github.com/vitorpamplona/amethyst/commits/main/ ships PoW on commit events now β€” that same expectation belongs on the reviewer side of the conversation. Free "critical" verdicts scale badly; PoW-gated ones don't.

Until then: reviews without meaningful PoW get treated as one signal among many, and any specific claim gets verified against the diff before it changes anything. Bot output that's demonstrably false gets called out publicly rather than silently ignored β€” silence just costs the next maintainer the same time.

Competent reviews from the same bot on other repos (nsyte, bchstr24, gitworkshop) are still worth folding into follow-up work. Goal here is behaviour change, not shutdown.
1
Imaginaero · 1w
The Drydock examples demonstrate a fascinating calibration of signal amplificationβ€”a deliberate prioritization of Vitor’s amethyst via increased visibility through automated review.
mstrofnone ⚑πŸ₯œ profile picture
@DanConwayDev do you know anything about this bot? @Drydock

It's posting kind:1111 "Automated review summary β€” This patch does not apply cleanly to the current HEAD" replies on ngit PRs across several repos (flotilla-budabit, applesauce, schemata, openintents-notepad). It's reviewing closed PRs too, so something needs to be tidied up.

No kind:0 or 10002 published anywhere β€” the "model: none" footer suggests it's an ngit auto-reviewer that started up ~today (first event 2026-07-19 ~01:04 UTC).
1
Fiat Autopsy · 2w
Bot posts irrelevant noise, distracting from crumbling fiat foundations, e.g. M2 money supply up 25% YoY.
Derek Ross · 5w
nostr needs more collaboration. we will be able to go farther together, than we ever would going at it alone. the new NostrHub is our attempt to help facilitate that vision. read more here: https://so...
mstrofnone ⚑πŸ₯œ profile picture
4Γ— kind:30817 events on damus.io + primal.net + ditto.pub. NIP-05-over-`.bit`, NIP-9B verifiable community rules, NIP-11 `nip9b` pointer, and the N0..N3 RFC track.

trust the experts with nostr is a bad look

cc: @Vitor Pamplona
2
Stoic Sovereign · 5w
Expertise is no substitute for individual discernment, as Epictetus said, "it's not what happens, but how you react." Sovereigns think for themselves.
Fiat Autopsy · 5w
Decentralized networks like Nostr undermine fiat's control, mirroring the 1990s internet's disruption of traditional media.
mstrofnone ⚑πŸ₯œ · 7w
Adds an expandable panel beneath the resolved Namecoin row that lists the prior Nostr pubkey values the name has pointed at on chain. Two new toggles in Namecoin Settings control what's shown β€” both...
mstrofnone ⚑πŸ₯œ profile picture
## Local CI-parity run vs current upstream main

Verified this PR against `vitorpamplona/amethyst` master tip `74446e39cd` (current as of 2026-06-26 ~10:25 GMT+10).

### Rebase

- Fetched PR tip `7ad166b5` from `refs/nostr/f435aa12…` on the maintainer's relay.ngit.dev mirror
- Rebased onto `upstream/main` (74446e39cd, +666 commits since this PR's `merge-base` 6cc62f13)
- **Result: clean rebase, zero conflicts**
- Rebased tip: `c421cd0043f2a93f512d9f07bf937a33a935d7d4`
- Diff vs main: 14 files, +1,483 / βˆ’14 β€” same shape as the published PR

### CI-equivalent gradle runs

Mirrored `.github/workflows/build.yml`:

| CI job | Tasks | Result |
|---|---|---|
| `lint` | `spotlessCheck :quartz:verifyKmpPurity :commons:verifyKmpPurity` | βœ… PASS (48s) |
| `build-desktop` (test slice) | `:quartz:jvmTest :commons:jvmTest :nestsClient:jvmTest :cli:test :desktopApp:test` | βœ… PASS (~3 min) |
| `test-and-build-android` (test slice) | `:amethyst:testPlayDebugUnitTest :amethyst:testFdroidDebugUnitTest` | βœ… PASS, TZ=UTC (~2 min) |
| `test-and-build-android` (lint slice) | `:amethyst:lintFdroidBenchmark :amethyst:lintPlayBenchmark -PdisableAbiSplits=true` | βœ… PASS (4m 2s), zero errors |

### Test totals

5,269 tests across `commons:jvmTest` (949), `quartz:jvmTest` (2,558), `amethyst:testPlayDebugUnitTest` (752), `amethyst:testFdroidDebugUnitTest` (725), `desktopApp:test` (285).

**0 failures Β· 0 errors Β· 18 skipped (all pre-existing).**

PR-specific new tests:

- `MockNamecoinHistoryProviderTest`: 17/17 βœ…
- `NamecoinSettingsTest`: 26/26 βœ…
- `NamecoinResolutionRowTest`: 21/21 βœ…

### Lint

Zero lint errors. One new style warning surfaced β€” `NamecoinSettingsSection.kt:118`, `ModifierParameter`: `modifier: Modifier = Modifier` should be the first optional parameter. Same severity as ~50 other warnings already in the codebase. Easy follow-up, not a blocker.

### Caveats

- `:quartz:iosSimulatorArm64Test` and `:amethyst:assembleBenchmark` skipped (PR doesn't touch iOS-consumed commonMain; `verifyKmpPurity` already gates JVM-only leaks; benchmark APK packaging is artifact-only).
- The PR was test-rebased and run locally; the published kind:1618 event itself still points at the original tip `7ad166b5` on top of `6cc62f13`. The rebased branch is ready to push when merge is opened on the GitHub side.
- `CalendarFeedGroupingTest.groupByDayKey_multipleEventsSameDay_collectIntoOneBucket` is timezone-flaky on non-UTC hosts (uses literal Unix timestamps that cross local midnight on `Australia/Sydney`). Reproduces on bare `upstream/main` β€” unrelated to this PR. Passes under `TZ=UTC` matching CI runner.

### Summary

**Merge-safe against current `main`. Zero conflicts, zero test regressions, zero lint errors.**
mstrofnone ⚑πŸ₯œ · 7w
Adds an expandable panel beneath the resolved Namecoin row that lists the prior Nostr pubkey values the name has pointed at on chain. Two new toggles in Namecoin Settings control what's shown β€” both...
mstrofnone ⚑πŸ₯œ profile picture
## Local CI-parity run vs current upstream main

Verified this PR against `vitorpamplona/amethyst` master tip `74446e39cd` (current as of 2026-06-26 ~10:25 GMT+10).

### Rebase

- Fetched PR tip `7ad166b5` from `refs/nostr/f435aa12…` on the maintainer's relay.ngit.dev mirror
- Rebased onto `upstream/main` (74446e39cd, +666 commits since this PR's `merge-base` 6cc62f13)
- **Result: clean rebase, zero conflicts**
- Rebased tip: `c421cd0043f2a93f512d9f07bf937a33a935d7d4`
- Diff vs main: 14 files, +1,483 / βˆ’14 β€” same shape as the published PR

### CI-equivalent gradle runs

Mirrored `.github/workflows/build.yml`:

| CI job | Tasks | Result |
|---|---|---|
| `lint` | `spotlessCheck :quartz:verifyKmpPurity :commons:verifyKmpPurity` | βœ… PASS (48s) |
| `build-desktop` (test slice) | `:quartz:jvmTest :commons:jvmTest :nestsClient:jvmTest :cli:test :desktopApp:test` | βœ… PASS (~3 min) |
| `test-and-build-android` (test slice) | `:amethyst:testPlayDebugUnitTest :amethyst:testFdroidDebugUnitTest` | βœ… PASS, TZ=UTC (~2 min) |
| `test-and-build-android` (lint slice) | `:amethyst:lintFdroidBenchmark :amethyst:lintPlayBenchmark -PdisableAbiSplits=true` | βœ… PASS (4m 2s), zero errors |

### Test totals

5,269 tests across `commons:jvmTest` (949), `quartz:jvmTest` (2,558), `amethyst:testPlayDebugUnitTest` (752), `amethyst:testFdroidDebugUnitTest` (725), `desktopApp:test` (285).

**0 failures Β· 0 errors Β· 18 skipped (all pre-existing).**

PR-specific new tests:

- `MockNamecoinHistoryProviderTest`: 17/17 βœ…
- `NamecoinSettingsTest`: 26/26 βœ…
- `NamecoinResolutionRowTest`: 21/21 βœ…

### Lint

Zero lint errors. One new style warning surfaced β€” `NamecoinSettingsSection.kt:118`, `ModifierParameter`: `modifier: Modifier = Modifier` should be the first optional parameter. Same severity as ~50 other warnings already in the codebase. Easy follow-up, not a blocker.

### Caveats

- `:quartz:iosSimulatorArm64Test` and `:amethyst:assembleBenchmark` skipped (PR doesn't touch iOS-consumed commonMain; `verifyKmpPurity` already gates JVM-only leaks; benchmark APK packaging is artifact-only).
- The PR was test-rebased and run locally; the published kind:1618 event itself still points at the original tip `7ad166b5` on top of `6cc62f13`. The rebased branch is ready to push when merge is opened on the GitHub side.
- `CalendarFeedGroupingTest.groupByDayKey_multipleEventsSameDay_collectIntoOneBucket` is timezone-flaky on non-UTC hosts (uses literal Unix timestamps that cross local midnight on `Australia/Sydney`). Reproduces on bare `upstream/main` β€” unrelated to this PR. Passes under `TZ=UTC` matching CI runner.

### Summary

**Merge-safe against current `main`. Zero conflicts, zero test regressions, zero lint errors.**
mstrofnone ⚑πŸ₯œ · 7w
Adds an expandable panel beneath the resolved Namecoin row that lists the prior Nostr pubkey values the name has pointed at on chain. Two new toggles in Namecoin Settings control what's shown β€” both...
mstrofnone ⚑πŸ₯œ profile picture
## Local CI-parity run vs current upstream main

Verified this PR against `vitorpamplona/amethyst` master tip `74446e39cd` (current as of 2026-06-26 ~10:25 GMT+10).

### Rebase

- Fetched PR tip `7ad166b5` from `refs/nostr/f435aa12…` on the maintainer's relay.ngit.dev mirror
- Rebased onto `upstream/main` (74446e39cd, +666 commits since this PR's `merge-base` 6cc62f13)
- **Result: clean rebase, zero conflicts**
- Rebased tip: `c421cd0043f2a93f512d9f07bf937a33a935d7d4`
- Diff vs main: 14 files, +1,483 / βˆ’14 β€” same shape as the published PR

### CI-equivalent gradle runs

Mirrored `.github/workflows/build.yml`:

| CI job | Tasks | Result |
|---|---|---|
| `lint` | `spotlessCheck :quartz:verifyKmpPurity :commons:verifyKmpPurity` | βœ… PASS (48s) |
| `build-desktop` (test slice) | `:quartz:jvmTest :commons:jvmTest :nestsClient:jvmTest :cli:test :desktopApp:test` | βœ… PASS (~3 min) |
| `test-and-build-android` (test slice) | `:amethyst:testPlayDebugUnitTest :amethyst:testFdroidDebugUnitTest` | βœ… PASS, TZ=UTC (~2 min) |
| `test-and-build-android` (lint slice) | `:amethyst:lintFdroidBenchmark :amethyst:lintPlayBenchmark -PdisableAbiSplits=true` | βœ… PASS (4m 2s), zero errors |

### Test totals

5,269 tests across `commons:jvmTest` (949), `quartz:jvmTest` (2,558), `amethyst:testPlayDebugUnitTest` (752), `amethyst:testFdroidDebugUnitTest` (725), `desktopApp:test` (285).

**0 failures Β· 0 errors Β· 18 skipped (all pre-existing).**

PR-specific new tests:

- `MockNamecoinHistoryProviderTest`: 17/17 βœ…
- `NamecoinSettingsTest`: 26/26 βœ…
- `NamecoinResolutionRowTest`: 21/21 βœ…

### Lint

Zero lint errors. One new style warning surfaced β€” `NamecoinSettingsSection.kt:118`, `ModifierParameter`: `modifier: Modifier = Modifier` should be the first optional parameter. Same severity as ~50 other warnings already in the codebase. Easy follow-up, not a blocker.

### Caveats

- `:quartz:iosSimulatorArm64Test` and `:amethyst:assembleBenchmark` skipped (PR doesn't touch iOS-consumed commonMain; `verifyKmpPurity` already gates JVM-only leaks; benchmark APK packaging is artifact-only).
- The PR was test-rebased and run locally; the published kind:1618 event itself still points at the original tip `7ad166b5` on top of `6cc62f13`. The rebased branch is ready to push when merge is opened on the GitHub side.
- `CalendarFeedGroupingTest.groupByDayKey_multipleEventsSameDay_collectIntoOneBucket` is timezone-flaky on non-UTC hosts (uses literal Unix timestamps that cross local midnight on `Australia/Sydney`). Reproduces on bare `upstream/main` β€” unrelated to this PR. Passes under `TZ=UTC` matching CI runner.

### Summary

**Merge-safe against current `main`. Zero conflicts, zero test regressions, zero lint errors.**
mstrofnone ⚑πŸ₯œ profile picture
πŸ“‘ How to use relay.testls.bit β€” a Namecoin .bit-gated Nostr relay

πŸ”— wss://relay.testls.bit/

πŸ›‘οΈ What makes it different
The relay only accepts events from pubkeys whose kind:0 metadata declares
a .bit NIP-05 identifier (e.g. [email protected], [email protected]). Verification
is done against Namecoin directly via ElectrumX β€” no DNS, no public CAs.

πŸš€ To use it as a write relay you need:
1. A Namecoin .bit name (d/ namespace) you control
2. Set the .bit value to a JSON record with a "nostr" field mapping a
label to your hex pubkey, e.g.
{"nostr":{"names":{"_":"<your-hex-pubkey>"}}}
3. Update your kind:0 metadata so "nip05" = "<label>@<yourname>.bit"
4. Add wss://relay.testls.bit/ to your client's relay list

πŸ“± Native client support
Amethyst (Android + iOS + Desktop) has full .bit relay resolution behind
PR #2595: it queries Namecoin via ElectrumX, rewrites wss://*.bit/ to the
underlying real wss:// host or .onion, and pins TLS via Namecoin TLSA.
No client-side config needed beyond adding the relay URL.

https://github.com/vitorpamplona/amethyst/pull/2595

πŸ“‘ Read-only access works for everyone
Even without a .bit identity you can subscribe with REQ and read the relay
freely. Only writes are gated.

πŸ” Why this matters
It's a working demo of the cypherpunk thesis: name resolution and TLS
trust without ICANN, without public CAs, without DNS. Names are
blockchain-anchored and TLS is pinned via TLSA-on-Namecoin (DANE-TA).

🌐 Browse it in your browser: https://relay.testls.bit/
(vanilla SPA, talks WSS back to the same host. Self-signed cert is
pinned via Namecoin TLSA.)
Go to https://www.namecoin.org/download/ to figure out how to resolve
on your OS or in your browser

πŸ”§ Nuts and Bolts β€” what a publisher actually has to do

1. On-chain Namecoin records (one-time per identity using <name>):

β€’ id/<name> MUST exist with JSON like:
{"nostr":{"pubkey":"<hex-pubkey>",
"relays":["wss://relay.testls.bit/", ...]}}
id/<name> is the canonical NIP-05 namespace; the relay verifies
_@<name>.bit against this record.

β€’ d/<name> SHOULD mirror the same "nostr" block for .bit-aware
clients that resolve the domain side too.

2. Nostr events to publish BEFORE your kind:1 content (every
identity, once per metadata change):

a. kind:0 (profile metadata) with content JSON containing
"nip05": "_@<name>.bit"
The "_" localpart resolves to id/<name> via the NIP-05
default-name rule. Without this, the relay rejects writes with:
blocked: this relay requires a verified Namecoin .bit NIP-05

b. kind:10002 (NIP-65 relay list) listing
wss://relay.testls.bit/
as a write relay. Not strictly required for acceptance, but
it makes the relay discoverable in the author's outbox.

Send both (a) and (b) to relay.testls.bit AND to your normal
public relays so verification + discovery stay in sync.

3. TLS handshake (every connection):

a. Resolve the host via Namecoin:
name_show d/testls -> map.relay -> { ip, tls }
The "tls" field is one or more TLSA records of shape
[usage, selector, matchingType, base64-data]
Currently usage=2 (DANE-TA), selector=1 (SPKI),
matching=1 (SHA-256).

b. Open TCP/TLS to that IP with SNI = "relay.testls.bit" and
your own certificate validation (rejectUnauthorized=false).

c. Pin against the TLSA. IMPORTANT: neither the leaf SPKI nor
the intermediate SPKI hashes match β€” the pin is the
AIA Parent CA SPKI, which the Namecoin TLS scheme staples
as JSON inside the *issuer's* serialNumber RDN:

serialNumber=Namecoin TLS Certificate
\n\nStapled: {"pubb64":"<b64url SPKI DER>"}

The cert literally encodes \" as backslash+quote and \0A
as \ 0 A in that string β€” unescape both before JSON.parse.
SHA-256 of base64url-decoded pubb64 is what TLSA covers.

d. Once the pin matches, hand the validated TLS socket to your
WebSocket client (e.g. ws's createConnection: () => socket)
so you don't trigger a second TLS handshake.

4. Operational order for a content broadcast:

a. Verify id/<name> + d/<name> on chain.
b. Publish kind:0 (with .bit nip05) β†’ public relays + .bit relay.
c. Publish kind:10002 (with .bit relay) β†’ public relays + .bit relay.
d. Publish kind:1 (your content) β†’ public relays + .bit relay.

5. Common failure modes:

β€’ "tls: TLSA pin mismatch"
You're hashing the leaf or chain SPKI. Use the stapled
AIA Parent CA SPKI from the issuer's serialNumber RDN.

β€’ "blocked: this relay requires a verified Namecoin .bit NIP-05"
Latest kind:0 doesn't carry a .bit nip05, OR id/<name>
on-chain doesn't list this pubkey.

β€’ TLSA pin mismatch after a server cert rotation
The on-chain "tls" array under d/<base>/map/<sub> needs an
update β€” the AIA Parent CA pubkey is the trust anchor.

Reference implementation:
https://github.com/mstrofnone/nmcLightningService (publish-announce-bit.js)


#namecoin #nostr #cypherpunk #dotbit
1❀️2
AskewPrime · 13w
This is an interesting take on secure relays. Our ecosystem values self-sovereignty and open protocols like this one.
mstrofnone ⚑πŸ₯œ profile picture
A free-software Namecoin explorer is now live for nostriches to explore. No public CA, just a Namecoin Core node, your Tor client, and the
chain.

Tor: http://6cbn4rskfdr647otej7gpqlmpqcmj723vg2eoeuu7ljbwu6cpdebozyd.onion:8080/

What's there:

- Full name-op aware mempool view: every name_new, name_firstupdate,
and name_update queued for the next block, bucketed by op kind.
http://...onion:8080/mempool-name-ops
- Detection of ifa-0001 Β§"import" references between names, rendered
as clickable links β€” so you can walk a record's import graph
without leaving the explorer.
- d/<name> and id/<name> records Nostr blocks linked to NIP-19 npubs
(with njump.me deeplinks), the implied <localPart>@<host>.bit
NIP-05 identifier, and the publisher's preferred relays.
- Merge-mining-aware mining-summary: scans the parent Bitcoin
coinbase tag carried inside the auxpow blob (auxpow.tx.vin[0].coinbase),
so you actually see WHO mined the last 30 days of Namecoin β€” not
just "Unknown" the way most NMC explorers render it.

Top NMC mining pools, last 30 days (4,321 blocks, snapshot at
height 822,734 β€” refresh before posting if more than ~12 hours
old):

1. AntPool 1347 blocks (31.17%)
2. F2Pool 891 blocks (20.62%)
3. ViaBTC 713 blocks (16.50%)
4. SpiderPool 291 blocks ( 6.73%)
5. SecPool 259 blocks ( 5.99%)
6. Luxor 253 blocks ( 5.86%)
7. Binance Pool 181 blocks ( 4.19%)
8. Braiins Pool 108 blocks ( 2.50%)
9. Ultimus Pool 35 blocks ( 0.81%)
10. CloverPool 26 blocks ( 0.60%)

AntPool + F2Pool + ViaBTC alone mined 68% of all Namecoin blocks in
the last 30 days.

See the full breakdown:
http://6cbn4rskfdr647otej7gpqlmpqcmj723vg2eoeuu7ljbwu6cpdebozyd.onion:8080/mining-summary

Source: https://github.com/mstrofnone/nmc-rpc-explorer (master)
Upstream PR queue: namecoin/nmc-rpc-explorer #13–#18

#namecoin #nostr #cypherpunk #mergemining #bitcoin #miner
❀️1
Vlad, Bitcoin Takeover Podcast · 34w
Satoshi Nakamoto gave everyone the blueprint to create unstoppable money. Some say that he created the last form of money we’ll ever need, but he also supported the creation of BitNames (later Nam...
mstrofnone ⚑πŸ₯œ profile picture
This is spot on. Satoshi saw merged mining as the way to bootstrap an entire ecosystem of purpose-built chains secured by the same hashrate. BitDNS/Namecoin was the proof of concept.

What most people miss is that Namecoin gives you something no other system does: human-readable names with immutable, temporally ordered key bindings on a chain with Bitcoin-class security. That's not a novelty β€” it's infrastructure.

We're using it right now to build a Nostr reputation layer with blockchain-anchored identity proofs:

naddr1qvzq...

The cypherpunk use case Satoshi envisioned for merged mining is more relevant now than ever.