Skip to content

chore(sync): merge sanitized upstream through v1.0.3 (Helm) - #20

Merged
zeeshanhaque21 merged 189 commits into
mainfrom
sync/upstream-1.0.3-sanitize
Oct 12, 2026
Merged

zeeshanhaque21 merged 189 commits into
mainfrom
sync/upstream-1.0.3-sanitize

Conversation

@zeeshanhaque21

@zeeshanhaque21 zeeshanhaque21 commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Sync upstream nanoMuse v1.0.3 (Helm) into the fork (sanitized)

Merges the published upstream release v1.0.3 into the fork without losing any fork-only
feature, and keeps every .cn cloud-backend reference out of the shipped tree.

Provenance

Upstream repository (read-only) nano-muse/nanoMuse
Upstream tip merged 189621240d7efd6a99debc45a4cc1a55edb6b141 (upstream/main)
Published upstream releases discovered v1.0.3 (Helm) — the only release newer than the fork's previous integration point
Upstream release commit 34a950c82977f20006d19d87d2241fe1f7071e7c (refs/tags/v1.0.3) — an ancestor of upstream/main, 67 commits behind it, so no separate release-commit integration was needed
Fork baseline before this run f3237f9b697e0fd6c988c1fafcd2bfce830d54fc (fork/main)
Previous merge base 5379e97a5e6d8c68c6f1fc4da3b4649692b94f82
Commits integrated 180 (git rev-list --count fork/main..upstream/main)
Content head (all code) cc4b552a040c53d78d05e57ef88c75c63fb0827d
Tested head the branch tip — every commit after the content head changes only maintenance-evidence/run-2026-10-11/, so tip and content head have identical code
Diff (fork/main..cc4b552a04, content only) 334 files changed, 12,087 insertions(+), 2,301 deletions(−)

Five content commits sit on fork/main, each with a DCO Signed-off-by line. Everything
after cc4b552a04 is evidence-only, touching nothing but maintenance-evidence/run-2026-10-11/:

c7bd659949 chore(sync): merge sanitized upstream through v1.0.3 (Helm)
df23dbb031 build(web): regenerate committed static from the merged source (Node 22)
f38a067f85 test(sync): keep the fork's expectations on two tests upstream 1.0.3 rewrote
204633f988 style(sync): apply ruff format to the three files an earlier sanitization left unformatted
cc4b552a04 fix(docs): restore the sentence period the mirror-clause removal ate, and guard it

The full runtime suite was re-run at the branch tip as well as at the content head, so the
numbers below describe the code that would merge rather than an earlier revision. Because
each further evidence edit moves the tip without touching code, the exact tip SHA at merge
time is recorded in maintenance-evidence/run-2026-10-11/completion.md instead of here.

Releases are discovered independently of whether upstream/main moved. Fork releases
already present (v1.0.0-fork.1, v1.0.1-fork.1, v1.0.2-fork.1, v0.1.41-fork.1, …)
were deduplicated by upstream tag; v1.0.3-fork.1 did not exist.

Sanitization — the scan of record

Post-merge, the canonical scan (this exact command is the evidence of record in
maintenance/RUNBOOK.md):

git grep -l 'nanomuse\.cn' -- . \
  ':(exclude)CHANGELOG.md' ':(exclude)docs/releases/**' ':(exclude)cloud/deploy/**' \
  ':(exclude)demo/**' ':(exclude)docs/privacy.md' ':(exclude)docs/roadmap.md' \
  ':(exclude)docs/readme/**' ':(exclude)site/README.md' \
  ':(exclude)docs/release-notes-template.md' ':(exclude)nanomuse/server/static/**'

Remainder — 19 files, every one classified, none a new active reference:

cloud/README.md                              1   the deploy artifact name cloud.nanomuse.cn.caddy
docs/zh/cloud.md                             3   attribution prose for upstream's public relay
docs/zh/every-device.md                           and upstream's showcase site
docs/zh/privacy.md                                legal text (in the sanitization test's ALLOWED set)
maintenance/RUNBOOK.md                       1   the runbook's own literal scan commands
tests/test_fork_relay_defaults.py            3   absence assertions
tests/test_fork_upstream_037_sanitization.py
tests/test_nudges_runtime.py
maintenance-evidence/run-2026-10-05/*        5   immutable prior-run evidence
maintenance-evidence/run-2026-10-10/*        5   immutable prior-run evidence
maintenance-evidence/run-2026-10-11/pr-body.md 1 this run's PR body — it quotes the scan command

(The runbook's "as of the 0.1.41 sync" list is 13 files; the extra six are prior runs'
evidence files plus this run's own, which necessarily quote nanomuse\.cn. This run's
completion.md will be a 20th once the run finishes.)

Active-surface scan of the areas the command does not exclude is empty:

git grep -nI 'nanomuse\.cn\|demo\.nanomuse\.dev\|nano-muse\.github\.io' -- \
  nanomuse web/src cloud/nanomuse_cloud harness desktop android/src \
  ':(exclude)nanomuse/server/static/**'                        # no hits
grep -rl 'nanomuse\.cn' nanomuse/server/static/                # empty

Contract held

  • NANOMUSE_CLOUD_BASE_URL / cloud.base_url is still the only relay seam.
  • cloud/nanomuse_cloud/config.py: invite_url, own_key_docs, privacy_url, repo_url
    all default to ""; openrouter_url keeps its documented third-party default.
  • Empty relay still raises relay_unconfigured before any network I/O
    (nanomuse/cloud.py), and the Android path still calls requireBaseUrl(context) before
    building a request (NanoMuseCloud.kt:1129).
  • Upstream's 1.0.3 rewording turned the Chinese docs' relay mentions into bare hostnames
    (在 \cloud.nanomuse.cn` 上). The fork's "upstream's public relay" attribution was re-applied so the text never reads as this fork's own relay, matching fork/main`.

Historical and attribution material

Untouched relative to upstream/main — no active reference was removed from them:

  • CHANGELOG.md — byte-identical to upstream/main
  • docs/releases/** — relative to fork/main upstream added only its own
    docs/releases/v1.0.3.md; the directory carries no fork edit
  • docs/privacy.md, site/README.md — byte-identical to upstream/main

Edited relative to upstream/main only to rename the repository, drop the hosted-demo
and download-mirror references, and bump the version. Their history and their upstream
attribution are kept, not rewritten:

  • docs/readme/README_*.md (all ten), docs/release-notes-template.md, docs/roadmap.md
  • cloud/deploy/nanomuse-hk/deploy.sh
  • demo/showcase/** (gateway/showcase_gateway/{config,logs,webpage}.py, mirror/traffic.py)

Unrelated third-party .cn citations are untouched: open.bigmodel.cn, api.moonshot.cn,
api.siliconflow.cn, open.feishu.cn, iat-api.xfyun.cn, pypi.tuna.tsinghua.edu.cn,
goproxy.cn, and the rest.

Generated assets

nanomuse/server/static/** is never merged by hand. Commit c7bd659949 takes upstream's
tree unchanged; commit df23dbb031 replaces it with the output of the merged source built
on Node 22 (vite.config.ts writes outDir: "../nanomuse/server/static",
emptyOutDir: true). CI's web app build job re-runs npm run build and fails if the
committed bundle is stale — it is green.

Fork-only features preserved

Feature Where State
Google Calendar over OAuth nanomuse/calendar/feeds.py fork's _refresh_feeds / _refresh_google split kept and upstream's _error_text URL redaction taken (private feed links are secrets)
relay_unconfigured before network I/O NanoMuseCloud.kt requireBaseUrl(context) kept inside upstream's refactored request()
Configurable relay hosting / signed-out relay editing nanomuse/server/*, web/src/** kept
Bundled desktop Playwright/Chromium scripts/desktop-app/*, harness/desktop kept
Update check: GitHub only, mirror opt-in nanomuse/server/update.py INDEX_URL = os.environ.get("NANOMUSE_UPDATE_INDEX_URL", ""), no default, no fallback
source: 'github' | 'mirror' | 'none' harness/dsh-nanomuse/src/desk.ts kept
Fork badge (no upstream repo ref in the READMEs) README.md, docs/readme/** kept — see the test note below

No file present at fork/main is missing from this branch except regenerated
nanomuse/server/static/assets/* bundles; zero non-static files were dropped.

Three upstream tests needed a fork-aware expectation

These arrive with 1.0.3 and fail against the fork's configuration rather than against the
merged code. They are fixed, not papered over:

  • tests/test_readme_contributors.py asserted the badge is
    hits.sh/github.com/nano-muse/nanoMuse.svg?. That URL embeds an upstream repository
    reference, which tests/test_fork_docs_sanitization.py forbids; the ten READMEs carry
    the fork's komarev badge. The fork's assertion (already present at fork/main) is
    restored.
  • tests/test_endpoints_api.py is new to the fork and posts
    settings.cloud.base_url + "/v1" as a custom endpoint, expecting the "it is the
    account, not an endpoint"
    refusal. With the fork's empty relay default that address is
    the relative /v1, refused earlier as malformed. The test now asserts the fork's
    behaviour for an unconfigured relay, then sets a relay on the live Settings and keeps
    upstream's coverage of the account guard.
  • tests/test_fork_docs_sanitization.py grows a regression test for the sentence-gluing
    scar described under Review below.

Checks actually run

Local

Check Result
pytest -q -m "not live" (runtime, py3.12 CI venv) 955 passed, 5 skipped, 1 deselected, 0 failed
Same command at the fork/main baseline (/tmp/nm_base, f3237f9b69) 854 passed, 5 skipped, 1 deselected, 0 failed
Fork contract tests (3 files) 144 passed
cloud/ ruff check . && ruff format --check . && pytest -q clean; 178 passed
demo ruff check && ruff format --check; gateway pytest -q clean; 44 passed
ruff check nanomuse tests scripts / ruff format --check nanomuse tests scripts clean / 229 formatted
mypy (py3.12 venv, [tool.mypy] files = ["nanomuse"]) Success: no issues found in 140 source files
python -m compileall -q demo cloud nanomuse scripts clean
web npm run check (lint + tsc + vitest) exit 0, 105 vitest tests passed
harness/dsh-nanomuse build + typecheck + test 313 tests pass, 0 fail
harness/desktop typecheck + test 59 tests pass, 0 fail
node scripts/connectors-json.mjs --check / providers-json.mjs --check clean

The merge adds 101 passing runtime tests and no new failure (the count rose from 854 at
fork/main to 955 here; the last one is the regression test for the scar below).

CI

The first pushed head (f38a067f85) had two red jobs, both ruff format --check
failures the fork's own earlier sanitization had left behind and which the local commands
in AGENTS.md do not cover (demo/ and cloud/ are checked by their own jobs):

  • gateway tests — demo/showcase/mirror/traffic.py
  • relay · ruff and pytest — cloud/nanomuse_cloud/config.py:493,
    cloud/tests/test_cloud.py:694 (an indentation scar and two expressions laid out for
    upstream's longer URLs)

ruff format --check demo cloud reported 11 unformatted files at fork/main and 3
here — the merge already took upstream's formatted versions of the other eight. Commit
204633f988 applies the repository's own formatter to the remaining three; both jobs are
now green at the current head, as are Signed-off-by on every commit, web app build,
build · test · pack and build · test (Windows).

End-to-end smoke proof (before any expensive build)

nanomuse serve v1.0.3 booted on 127.0.0.1:8791 from the merged tree:

  • /api/state with the Bearer token → HTTP 200, version: "1.0.3"
  • /api/state without a token → HTTP 401 invalid or missing token
  • all 7 content-hashed assets referenced by index.html → HTTP 200, including the
    entry chunk assets/index-tYqPtwPX.js produced by the regenerated bundle
  • a real browser (chrome-headless-shell, Chrome for Testing 153.0.8010.12) navigated
    http://127.0.0.1:8791/#token=…: the SPA mounted into <div id="root"> and rendered the
    onboarding copy ("nanoMuse · Skip setup · Meet your nanoMuse …"). The only stderr line
    is the known non-GUI-session CVDisplayLinkCreateWithCGDisplay failed noise.

Review

A separate fresh-context read-only subagent reviewed the diff, independently re-ran the
backend scan and both pytest suites, re-checked the baseline comparison, audited credential
handling and release provenance, and fact-checked this body. Verdict: safe to merge, no
blockers.

Its findings, all corrected before the merge:

  1. A real scar — the mirror-clause removal swallowed a sentence's . and the joining
    ; in README.md and five translated readmes, gluing two sentences together. Fixed in
    cc4b552a04, with a regression test. (Review listed four readmes; README_ru.md had
    the same scar and is fixed too.)
  2. This body's counts were wrong — the remainder is 19 files, not 18, and this run's
    evidence directory held one file, not three. Corrected above.
  3. The stated tested head was stale and had two red CI jobs. Corrected above.
  4. "Preserved, not rewritten" was overstated — several listed paths are edited
    relative to upstream/main. The section above now separates what is genuinely
    untouched from what was edited, and says why.
  5. The diff stat and tested head were stale. Both corrected.

Not verified here

  • Windows and Linux desktop installers, the iOS build, and the Android release APK are CI
    and release-time artifacts, not verified in this PR.
  • The committed static bundle was structurally checked (every index.html asset reference
    exists on disk, no .cn strings, no upstream repo refs) and CI rebuilds it, but it was
    not byte-compared against a fresh build in this session.
  • The adversarial reviewer did not reproduce the end-to-end smoke proof itself; it verified
    the surrounding evidence instead.

Vela and others added 30 commits October 10, 2026 13:52
The home bottom bar is now a centered floating pill instead of a
full-width strip. It blurs whatever is behind it with Haze, carries a
hairline edge, and keeps the icons-only design: the current tab shows a
filled glyph on a soft indicator pill that springs in, the others stay
outlined. Adds the Haze blur dependencies.

Signed-off-by: Vela <vela@local>
Debug builds now carry the applicationIdSuffix .debug
(io.github.nanomuse.app.debug), so a CI debug APK installs alongside the
release nanoMuse instead of replacing it. The manifest already uses the
applicationId placeholder everywhere; the launcher shortcuts get a debug
source-set copy pointing at the debug package.

Signed-off-by: Vela <vela@local>
Haze 2.x (and 1.7.x) need compileSdk 37 and the module is on 36, which
failed checkDebugAarMetadata in CI. 1.6.10 carries no compileSdk floor
and the same backdrop-blur API the bar uses.

Signed-off-by: Vela <vela@local>
- hazeEffect's block is not a @composable scope in 1.x, so hoist the
  MaterialTheme surface lookup above it.
- Name tints explicitly: HazeStyle has a twin constructor taking
  tint: HazeTint?, which made the call ambiguous.

Signed-off-by: Vela <vela@local>
Draw modifiers paint in chain order: with hazeEffect() before clip(),
the blurred rect was drawn unclipped and the frost stuck out past the
pill's rounded ends, making the sides look rectangular. Clipping first
masks the blur to the pill shape.

Signed-off-by: Vela <vela@local>
Every CI runner mints its own throwaway debug key, so consecutive CI
APKs carried different signatures and Android refused to install one
over the other ('update incompatible'). The committed ci-debug.keystore
uses the stock public debug credentials and is debug-only.

Signed-off-by: Vela <vela@local>
M3E: floating frosted-glass pill bottom bar
MinisMenu's container was surfaceContainerHigh grey; now it's the chat
canvas (pure black in dark, white in light) with a slightly stronger
hairline.

Cherry-picked from m3e/chat-meta-ai-polish for upstream.

Signed-off-by: Vela <vela@local>
Pure black canvas, large agent-name header, uppercase section labels,
quiet monochrome pills for selected rows, circular settings/search/new
chat buttons.

Cherry-picked from m3e/chat-meta-ai-polish for upstream.

Signed-off-by: Vela <vela@local>
…ranch

These are sent as separate upstream PRs (upstream/menu-polish,
upstream/drawer-polish). This branch keeps only the pill nav and
Meta AI chat polish.

Signed-off-by: Vela <vela@local>
Brings the branch up to 1.0.2 so the CHANGELOG lines and the Android
sources merge against what is on main today. No conflicts.

Signed-off-by: lgy0404 <2528379691@qq.com>
Takes back a5a20d2 (debug builds under io.github.nanomuse.app.debug) and
c02ca42 (a committed debug keystore for CI): the signing config, the
debug build type, ci-debug.keystore, the debug copy of shortcuts.xml and
the CHANGELOG line. A debug build keeps installing over the release app,
the way it has, and the repository carries no key, not even a public one;
how test APKs get a stable signature is a separate conversation from the
look.

For nano-muse#329

Signed-off-by: lgy0404 <2528379691@qq.com>
…s and the Chinese page

CHANGELOG.md had a leftover `<<<<<<< HEAD` marker and the new line
inside the released 1.0.0 block; the marker is gone and the line sits
under Unreleased, Android, now also naming the menus' canvas and the
author. THIRD_PARTY_NOTICES.md lists Haze (Apache-2.0) among the Gradle
dependencies, docs/zh/every-device.md says what docs/every-device.md
says about the bar, and four new code comments read without em dashes.

For nano-muse#329

Signed-off-by: lgy0404 <2528379691@qq.com>
Brings the branch up to main with nano-muse#329 merged, so the drawer commit is
the only change left. No conflicts.

Signed-off-by: lgy0404 <2528379691@qq.com>
…t for now

The drawer commit also removed the content's bottom inset and passed a
`nmBottomOverlay` to the chat screen that nothing on main defines, so the
branch did not compile. Those two hunks belong to the chat polish (nano-muse#331)
and come back with it; this PR is the drawer. Also a CHANGELOG line under
Unreleased, Android, and two code comments without em dashes.

For nano-muse#330

Signed-off-by: lgy0404 <2528379691@qq.com>
The five tabs sit in a centred Capsule 12 pt above the bottom safe
area, icons only: .ultraThinMaterial under the shell's surface tone at
55 percent, a 1 pt hairline edge, 60 by 46 pt tap boxes. The current
tab shows its filled symbol on an indicator capsule in the new
NanoMuseTones.tabIndicator tone (Android's primaryContainer, light and
dark) that springs to the tab tapped next through matchedGeometryEffect;
the others stay outlined in the secondary colour. The full-width strip
and its hairline on top are gone. The SF symbols, the accessibility
labels and the selected trait are the ones from before, so no string
changes.

Layout: the pill lies over the rooms and the chat in a ZStack aligned
to the bottom. The chat keeps the 0.1.40 rule (plain layout, never an
inset of the NavigationStack's ancestor) as bottom padding of the bar's
height, so the composer sits above the pill. The rooms are plain
SwiftUI scroll views and take the same height as a safeAreaInset, so
their content scrolls under the pill and the glass has something to
blur. The bar still leaves while the keyboard or the voice panel is up.

Follows nano-muse#329 by @Ichiro786 (Android's MuseBottomBar).

Signed-off-by: lgy0404 <2528379691@qq.com>
The five tabs sit in a rounded pill 12 px above the bottom edge, over the
safe area, icons only and no labels, the same bar the Android app draws
since nano-muse#329: the pill is surface-2 at 55 percent over a backdrop blur with a
hairline ring of the border colour at 50 percent; the current tab shows its
filled glyph on a soft blue indicator (a new accent-soft pair, light
#e5f0ff with #012f80 ink, dark #1a2b4a with #e5f0ff ink), the others stay
outlined in muted. The background colour eases over 300 ms.

The bar floats over the screen column instead of taking a row of it; the
nav lets taps through and only the pill takes them. The screens keep clear
of the pill through one place, a tabbar-room utility on <main> that pads
the bottom by the pill's footprint (74 px plus the safe area), given back
with wide:pb-0 when the sidebar shows; the chat's composer sits above it,
and the toast rises by the safe area so it clears the pill on a phone with
a home indicator. Lite keeps the bar at any width, as before.

Docs: app.md, design.md and their Chinese twins describe the pill;
CHANGELOG under Unreleased, Web. The built app under
nanomuse/server/static is regenerated.

Follows nano-muse#329 by @Ichiro786.

Signed-off-by: lgy0404 <2528379691@qq.com>
feat(android):  restyle chats drawer in Muse's visual language
Signed-off-by: lgy0404 <2528379691@qq.com>
Brings in nano-muse#329 and nano-muse#330 so docs/every-device.md can describe every client in one row.

Signed-off-by: lgy0404 <2528379691@qq.com>
The row for Feed, Ideas, Goals and Library names the floating pill at phone
width on the web and on iOS, and the sidebar on a wide window and in the
desktop app, in English and in Chinese.

Signed-off-by: lgy0404 <2528379691@qq.com>
feat(web): the phone layout's tab bar is a floating frosted-glass pill
… only

AnthropicProvider.resolveSystemPrompt read
ClaudeOAuthManager.ANTHROPIC_OAUTH_IDENTIFIER_PROMPT before checking
isOAuth. The getter throws when BuildConfig leaves the value empty, which
is the case on the public build (provider-customization.properties is not
shipped), so every send and stream through an own Anthropic API key failed
with "ANTHROPIC_OAUTH_IDENTIFIER_PROMPT is not configured" before any HTTP
request. The read now sits inside the OAuth branch; the API-key path never
needed it.

The 30 API-key cases of the upstream AnthropicProviderTest pass again. Its
one OAuth case needs a non-empty identifier, so it now runs under an Assume
on the BuildConfig value and is skipped, not failed, where the value is
empty. A regression test in io.github.nanomuse.models, the package the CI
filter runs, sends through MockWebServer with a null and with a normal
system prompt and checks one request, no or one `system` block.

For nano-muse#333

Signed-off-by: lgy0404 <2528379691@qq.com>
…tput

TerminalSanitizer.foldCarriageReturns kept only the last non-empty segment
of a line split on \r, so "AAAA\rBB" became "BB" and a progress line
followed by a shorter final line handed the model a truncated result. A \r
now resets the write column to 0 and the next segment overwrites from
there; shorter text keeps the old tail, which is what a terminal shows.
"AAAA\rBB" is "BBAA", "10%\r50%\r100%" is "100%", "\r\n" stays a line
break. The final trim of sanitize() stays as it was.

The two data-loss cases of the upstream TerminalSanitizerTest pass. Its two
whitespace expectations ("complete   ", " 100%[=========>]") only failed
because of that deliberate trim and now expect the trimmed text, with a
comment. A test class under io.github.nanomuse.sandbox covers the four
shapes above plus a longer rewrite, so the CI filter runs them.

For nano-muse#334

Signed-off-by: lgy0404 <2528379691@qq.com>
…test

ExecutionCoordinatorInstrumentedTest still read ExecutionCoordinator.mountedSessionId,
a field the coordinator dropped when it moved to one PersistentShell and one Mutex per
session. compileDebugAndroidTestKotlin failed with eight unresolved references, which
also kept io.github.nanomuse.reach.ReachHubInstrumentedTest from ever running on a device.

The eight assertions now check the command result and whether the session's shell is
registered, through one small internal accessor on the coordinator (hasShell). The
reflection reset of the old field is replaced by sessionDidTerminate for every test
session. The assertion that sessionDidTerminate empties the kernel's bind mount table is
dropped: the coordinator only stops and drops the shell today.

The Android workflow compiles the instrumentation sources right after the unit tests, so
the source set stays compilable. The tests themselves still need a device.

For nano-muse#332

Signed-off-by: lgy0404 <2528379691@qq.com>
…pects

OpenAIProvider.sendMessageClamped always issues a streaming request and folds the deltas
into one LLMResponse, because some gateways reject stream=false; a plain JSON body yields
no chunk and failOnSilentEmptyCompletion raises LLMError.TransientError. Fourteen cases
still enqueued non-streaming ChatCompletions bodies and failed with that error.

The test gains an sse() helper and a one-delta sseReply(); the fourteen fixtures are SSE
streams whose last chunk carries finish_reason and usage, then [DONE]. The request
assertion expects stream=true and stream_options.include_usage=true. The empty-choices
case expects the documented TransientError. The cached-tokens case follows
parseChatCompletionsUsage, which reports the fresh prompt tokens in inputTokens and the
full prompt in latestContextTokens.

The CI filter is unchanged; the class joins it once the sibling Anthropic fix has landed.

For nano-muse#335

Signed-off-by: lgy0404 <2528379691@qq.com>
lgy0404 and others added 29 commits October 12, 2026 03:40
fix(cloud): one hub device per console tab, consistent backups, a mail that rounds like the SMS
The new Windows job hung for half an hour in the shell's tests: the helper
test reads the token file's mode bits back (0600, 0700), Windows has none,
the assertion failed before stop() and the fake helper's HTTP server kept
the test process alive. The mode check is now skipped on win32, every fake
server is closed in after() so a failed assertion cannot hang the run again,
and both harness jobs carry a 30 minute limit.

Signed-off-by: lgy0404 <2528379691@qq.com>
Signed-off-by: lgy0404 <2528379691@qq.com>
…ipts

Signed-off-by: lgy0404 <2528379691@qq.com>
The relay still sends both: `password_wrong` when the current password given
while changing or removing one is not the one set (service.py set_password,
clear_password), `password_weak` for a new password with fewer than three
different characters or equal to the address. The audit's commit folded the
first into the sign-in sentence and the second into the eight-characters
rule; each gets its own line again, the second a new one in nine languages.

Signed-off-by: lgy0404 <2528379691@qq.com>
…ders every page

Eleven spots on docs/zh/{desktop-muse,every-device,ios,parity}.md closed a
bold or italic run right after a Chinese colon, a full stop or a closing
bracket and went on with a character, which CommonMark does not read as a
closer; the site showed the asterisks (checked with markdown-it-py and the
built site). The design page's dragon row says the error state has a still
only, as web/src/avatars.ts has it. CONTRIBUTING.md states the rule and
tests/test_docs_markup.py renders README.md and every page under docs/ and
fails on a literal marker.

Signed-off-by: lgy0404 <2528379691@qq.com>
fix(ios): password refusals, the Cloud row, the relay key, Reduce Motion, three translations
The translocation and defaultHelperPath tests built or compared macOS
paths through node:path's join, which uses the backslash on Windows; the
first joins with "/" on purpose and the second compares with the
separators normalised, so the Windows job runs the shell's 59 tests green.

Signed-off-by: lgy0404 <2528379691@qq.com>
# Conflicts:
#	docs/app.md
#	docs/configuration.md
#	docs/zh/app.md
#	docs/zh/configuration.md
Signed-off-by: lgy0404 <2528379691@qq.com>
…ipts

Signed-off-by: lgy0404 <2528379691@qq.com>
docs: bring the docs up to the code after the docs audit
…writes

A page without the past-releases table, or with the version's row already
there, refused the run after CHANGELOG.md, the READMEs and the issue forms
had been rewritten. The rows are now computed right after the arguments are
checked and written in their old place, so a refusal leaves every file as it
was; the test covers it.

Signed-off-by: lgy0404 <2528379691@qq.com>
ci: label web pull requests right, test the desktop on Windows, trim the Docker contexts
…ipts

chore(release): release-docs.py writes the roadmap rows; release-apk.sh checks the iOS version
The admin page's funnel line said how many people had made a code,
brought someone and come through one, and nothing more; the relay has
held who signed up with whose code since invites began, but no view
showed it.

A new Invites view (GET /v1/admin/invites) ranks the inviters by the
accounts their code brought, with how many of those ever made a
request, how many were seen from one of the inviter's own addresses,
what they spent, what the inviter earned from them and when the first
and the last signed up; a row unfolds to the newest of the people it
brought. An account's page names its inviter by identifier with a link
and lists everyone it brought with when they joined, whether they used
anything and from where; the accounts table marks an inviter with the
count and can sort by it. English and 简体中文; the route is in the
api docstring, cloud/README.md and docs/cloud.md with its twin.

The invitee list is ordered newest first with the row id as the tie
break, so two sign-ups in one second keep a stable order.

Signed-off-by: lgy0404 <2528379691@qq.com>
feat(relay): show who invited whom on the admin page
Integrate nano-muse/nanoMuse main (1896212,
180 commits past the fork's previous merge base 5379e97) into the fork. This
covers the published upstream release v1.0.3 (34a950c,
an ancestor of upstream/main, so no separate release-commit integration was needed).

Fork-only features preserved across the merge: Google Calendar over OAuth
(nanomuse/calendar/feeds.py keeps the _refresh_feeds/_refresh_google split and
takes upstream's _error_text URL redaction, since private feed links are
secrets), the Android requireBaseUrl/relay_unconfigured guard, configurable
relay hosting, signed-out relay editing, and bundled desktop Playwright/Chromium.

Sanitization: no active nanomuse.cn / demo.nanomuse.dev / upstream-repo
references remain outside the historical and attribution paths the contract
preserves. The Chinese docs re-add the "upstream's public relay" attribution
that upstream's 1.0.3 rewording dropped. Generated assets
(nanomuse/server/static) are taken from upstream's tree and regenerated from the
merged source in the following commit.

Historical and attribution references are preserved as-is: CHANGELOG.md,
docs/releases/**, docs/privacy.md, docs/roadmap.md, docs/readme/**,
site/README.md, cloud/deploy/nanomuse-hk/**, demo/showcase/**, and unrelated
third-party .cn citations (bigmodel.cn, moonshot.cn, siliconflow.cn, tuna mirrors).

Signed-off-by: Zeeshan Haque <zhaque.mail@gmail.com>
`nanomuse/server/static/**` is a committed build artifact, so it is never merged
by hand: the previous commit took upstream's tree and this one replaces it with
the output of the merged source.

    cd web && PATH=/opt/homebrew/opt/node@22/bin:$PATH npm ci && npm run build

vite.config.ts writes `outDir: "../nanomuse/server/static"` with
`emptyOutDir: true`. Node 22 is required; the default node on this machine is
v26. `grep -rl 'nanomuse\.cn' nanomuse/server/static/` is empty.

Signed-off-by: Zeeshan Haque <zhaque.mail@gmail.com>
…rewrote

Both files arrive from upstream 1.0.3 with assertions that assume upstream's own
configuration, so they fail against the fork's sanitization contract rather than
against the merged code:

- `tests/test_readme_contributors.py` asserts the badge is
  `hits.sh/github.com/nano-muse/nanoMuse.svg?`. That URL embeds an upstream repo
  reference, which `tests/test_fork_docs_sanitization.py` forbids, so the ten
  READMEs carry the fork's komarev badge. Restores the fork's assertion (it was
  already this way at `fork/main` and the merge overwrote it).
- `tests/test_endpoints_api.py` is new to the fork and adds
  `settings.cloud.base_url + "/v1"` as a custom endpoint, expecting the "it is the
  account, not an endpoint" refusal. With the fork's empty relay default that
  address is the relative `/v1`, refused earlier as malformed. The test now asserts
  the fork's behaviour for an unconfigured relay and then sets a relay on the live
  `Settings` to keep upstream's coverage of the account guard.

Signed-off-by: Zeeshan Haque <zhaque.mail@gmail.com>
The PR body for the v1.0.3 (Helm) sanitized sync: provenance, the canonical
backend scan and its 18-file classified remainder, the fork-only features the
merge had to preserve, the two upstream tests that needed a fork-aware
expectation, and every check actually run.

Signed-off-by: Zeeshan Haque <zhaque.mail@gmail.com>
…tion left unformatted

CI runs `ruff format --check` over more of the tree than the local commands in
`AGENTS.md` do (`demo/` and `cloud/` are checked by their own jobs, with the
repository's own ruff). Three files fail that gate, all of them fork-caused:

- `cloud/nanomuse_cloud/config.py`: the comment above the emptied `invite_url`
  default lost its indentation when the default became `""`, so it sits at column
  0 inside the class body.
- `cloud/tests/test_cloud.py`: the same damage on one dict entry, plus two
  expressions that were laid out for upstream's longer `nanomuse.cn` URLs and no
  longer need the wrapping now that the example host is `relay.test` and
  `own_key_docs` was added.
- `demo/showcase/mirror/traffic.py`: `OWN_HOSTS` kept the multi-line comprehension
  upstream needed for its long `TRAFFIC_HOSTS` default; with the sanitized empty
  default the formatter joins it to one line.

Measured before this commit: `ruff format --check demo cloud` reported 11 files at
`fork/main` and 3 here (the merge already took upstream's formatted versions of
the other 8). After: 0, with `ruff check` and both pytest suites unchanged
(178 relay, 44 gateway). No behaviour changes — whitespace and indentation only.

Signed-off-by: Zeeshan Haque <zhaque.mail@gmail.com>
… and guard it

Review found a real scar from this run's sanitization: dropping upstream's
download-mirror clause also swallowed the joining `;` and the sentence's own `.`,
so six READMEs read ".../releases/latest) Open the app" with the two sentences
glued together. `README.md:65` plus `docs/readme/README_{es,fr,id,ru,vi}.md:63`
now end the sentence properly, matching the wording already on `fork/main`
(`README_fr.md` also had a double space). The zh, zh-TW, ja and ko readmes were
never affected: the CJK ones have no space after `)` and the ja/ko ones continue
with a particle.

`tests/test_fork_docs_sanitization.py` grows a regression test for the whole
class: a `releases/latest)` link followed by whitespace and a word is the
signature, which no correct README produces.

Signed-off-by: Zeeshan Haque <zhaque.mail@gmail.com>
…vation claims

The adversarial review fact-checked the body and found five wrong or overstated
claims: the sanitization remainder is 19 files not 18, this run's evidence
directory held one file not three, the stated tested head was stale and had two
red CI jobs, and "preserved, not rewritten" was asserted over several paths that
are in fact edited relative to upstream/main.

Separate what is genuinely byte-identical to upstream from what was edited and
why, restate the counts from a fresh scan, and record the review's findings.

Signed-off-by: Zeeshan Haque <zhaque.mail@gmail.com>
…resh runs

The suite is 955 passed at the current head, not 954 -- the 954 reading predates
the regression test added in cc4b552 -- so the delta against the fork/main
baseline (854) is 101, not 100. The branch also carries seven commits, not five:
an evidence commit sat between the ruff-format and README fixes.

Pin the diff stat to the content head so it cannot drift as evidence is edited,
and record the merge-time tip SHA in completion.md rather than here.

Signed-off-by: Zeeshan Haque <zhaque.mail@gmail.com>
A list of commits cannot contain the commit that writes it, so enumerating the
evidence commits made the list stale on every edit. List the five content
commits, which are fixed, and describe the evidence commits without counting
them.

Signed-off-by: Zeeshan Haque <zhaque.mail@gmail.com>
@zeeshanhaque21
zeeshanhaque21 merged commit 51dfee7 into main Oct 12, 2026
18 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.

3 participants