Skip to content

Promote dev → staging - #1262

Closed
harrymove-ctrl wants to merge 103 commits into
stagingfrom
dev
Closed

harrymove-ctrl wants to merge 103 commits into
stagingfrom
dev

Conversation

@harrymove-ctrl

Copy link
Copy Markdown
Collaborator

Summary

Promotes dev into staging. As of opening, dev is at d914af57.

GitHub counts 96 commits because earlier promotions were squash-merged (#1182, #1239). Most of those commits are already in the staging tree. Against the current staging tree (f41df1ac), the diff is 18 files, +776/−109, and 4 merged PRs are new since #1239 (frozen at 256ac7f0).

Merge #1257 into dev first. It cuts SDK 0.1.9 and Python 0.1.12. Until it lands, this PR still carries SDK 0.1.8 and Python 0.1.11, and staging keeps publishing 0.1.8-rc.N / 0.1.11rcN. Those sort below the released versions.

Changes

CI / release

Python SDK

Chatbot / security

Once #1257 is merged

Publishing on merge to staging

  • SDK: @mysten-incubation/memwal@0.1.9-rc.N on the rc dist-tag. latest stays 0.1.8.
  • Python: memwal 0.1.12rcN. pip install memwal stays on 0.1.11.
  • release-mcp.yml and release-oc-memwal.yml changed in fix(ci): retry a prerelease publish that hits a staged version #1237, so both workflows run on staging and publish the next rc of their current versions (MCP 0.0.14-rc.N).

Migrations

  • None. services/server/migrations has no changes between staging and dev.

Not in this promotion

Test plan

  • chore(sdk): cut TypeScript 0.1.9 and Python 0.1.12 #1257 merged into dev and included in this PR's head
  • CI green on this PR
  • Release SDK on staging publishes 0.1.9-rc.0 with the rc tag; latest unchanged
  • Release Python SDK on staging publishes 0.1.12rc0
  • Staging chatbot: a vote or tool approval against another user's chat is refused

HoangDucBach and others added 30 commits September 11, 2026 11:17
The TypeScript gap already shipped in 0.1.6. Agent docs still listed the old RecallOptions, which is how GH #708 concluded recency ranking was unreachable.
Agents reading only this file still could not see the weight fields.
Recall is similarity-ranked and limit-bounded, so a write can't be
confirmed and a namespace can't be counted. listMemories() wraps the
existing GET /v1/owners/{owner}/memories and reuses resolveOwner().
Metadata only: no blob fetch, no decrypt.

The relayer has no namespace filter, so the optional namespace is
applied client-side; a filtered page can be empty while has_more is
true. Tombstone fields default for relayers older than WALM-363.
…y reached (WALM-670)

A same-key POST on a paid job always answered 202 `uploaded`, even when it
lost the recovery claim. And the claim fenced `failed` rows for 60s, so a
recovery that had just failed (the wallet job, or an enqueue error that
returned before the publish) left a lease behind. The next retry enqueued
nothing, still said `uploaded`, and GET kept saying `failed`: the
poisoned-key shape for a blob that already exists.

The claim now publishes `uploaded` in the same statement. A `failed` row is
claimable at once, and only an `uploaded` row keeps the 60s fence. Two
racing retries therefore enqueue one recovery, and the loser reports the
row's real status. If enqueue fails, the claim is released back to
`failed` with the lease cleared, so the next retry takes it immediately.
…d (WALM-670)

The timeout message said "retry with the same idempotency key" and that
remember_and_wait / rememberAndWait does this for you. Neither is reliably
true. `remember` drops its key as soon as the POST is accepted, and an
explicit idempotencyKey is never stored, so following the advice minted a
new key and a second paid write while the first job was still running.

A wait only times out on a job that is still pending, running or uploaded
(a failed job raises), so the advice is now to call waitForRememberJob /
wait_for_remember_job on the job id again, and to pass an explicit key
again on any retry. Python also stores the redacted server_error on the
exception attribute, not just in the message.
* fix(sdk): reject bad mock page sizes and honor recent recall

MemWalMock.listNamespaces treated limit 0 as an endless page and a negative
limit as slice's drop-the-tail. Bulk writes skipped the client's empty-batch
check, idempotency keys were ignored, and sort recent stayed oldest-first.
Positional recall(query, options, namespace) also dropped the namespace on
both the mock and MemWal.

Fixes #1144, #1145, #1146, #1147, #1124, #1038

* test(sdk): cover the mock limit, idempotency, and recent-recall edges

The first tests matched the issue repros. These also lock the branches a
tie-break-only sort, a 50-row window cap, a byte-length key, and a mutated
options object would have left green.
…us polls (#1168)

* fix(sdk): treat a remember options object as options and fix job status polls

remember(text, { idempotencyKey }) and rememberAndWait used to send that object as the namespace. Empty job ids no longer hit GET /api/remember/. Duplicate ids in waitForRememberJobs settle in every slot. Bulk status returns namespace, status polls skip the SEAL session, batches over 20 are rejected before signing, and a destroyed client throws instead of reading a zeroed key or probing /version.

#1142 #1087 #1121 #1084 #1104 #1135 #1136 #1090

* fix(sdk): reject a destroyed key still in flight and merge remember options

An in-flight getPublicKeyHex resolved to the zeroed cache, and a key
derived after destroy was the well-known key of the wiped seed. A third
options argument was also dropped when the namespace slot was an object.
…1134)

* fix: reject blank text, treat [::1] as local, and pin weekday dates

Whitespace-only remember, analyze, and embed text is rejected before a job is created (#1129). The TypeScript client treats bracketed ::1 as loopback (#1128). Fact extraction copies a server-built weekday calendar (#1131). AUTH_REJECTED names a pasted wallet address without changing the 401 (#1132).

* refactor: one weekday table, inline the loopback host check

The English weekday names lived in a match and again in the calendar loop. One Sunday-first array covers both, indexed by num_days_from_sunday. The IPv6 bracket strip stays inside normalizeServerUrl.
search_similar kept every vector_entries row, so a remember retry or restore could surface the same Walrus blob twice with identical scores.
Duplicate index rows were eating the ANN LIMIT window. Over-fetch by the dropped count, then unique and truncate. Ranker docs no longer narrate WALM-594.
limit + dropped only added the unique shortfall, so a 2x index crawled many HNSW round-trips. Widen by dropped rows in the current window and stop at limit * 4.
…all-returns-duplicate-records-for-the-same

fix(server): return each blob once in recall (WALM-594)
…161)

recall(query, namespace) was silently treated as options and ran against the default namespace. Fail loudly instead of dropping the intended scope.
recallManual has no object-first overload, so hinting
method({ query, namespace }) sent callers to query.trim() failure.
…itional-overload-silently-accepts-string-as

fix(sdk): throw when positional recall gets a namespace string (WALM-161)
…ixes #1143, #1040, WALM-721)

- Declare "default" fallback condition across all exported subpaths (".", "./account", "./manual", "./ai") so bundlers (Next.js/Turbopack) and Node 22 require(esm) resolve cleanly instead of throwing ERR_PACKAGE_PATH_NOT_EXPORTED
- Place "types" condition first for TypeScript nodenext/bundler resolution
- Add exports-map regression tests asserting types-first ordering and default fallback
* fix(mcp): re-check the bridge before signing connect consent (#368)

POST /preflight on load already rejects a phishing link. Two pieces of
that fix were still missing: a wallet that connects after the consent
screen is showing starts add_delegate_key without a click, and the page
does not ask the bridge again immediately before the signature. Gate
auto-continue on an explicit click, refuse to sign if the bridge no
longer confirms the request, and warn when the relayer is not the default.

* test(app): a connected wallet does not sign connect consent on its own

The consent screen must stay up until the user clicks, even when a wallet
is already connected.
…on-to-list-stored-blobs-writes-are-unauditable-and

feat(sdk): listMemories() pages every memory without a query (WALM-388)
fix(relayer,sdk): stop a slow remember job reading as a dead key (WALM-670)
… budget (Fixes #1103, WALM-756)

- In applyTokenBudget, select candidates by ascending distance under high-relevance-only strategy rather than array order
- Preserve the caller's requested order (e.g. sort: recent) for the retained lowest-distance hits
- Break distance ties stably by original index
- Update TruncationStrategy documentation and recall client commentary
- Add regression test reproducing the two-hit recency order bug and multi-hit order preservation
…budget-relevance

fix(sdk): retain lowest-distance hits under high-relevance-only token budget (Fixes #1103, WALM-756)
fix(sdk): add default condition to exports map and place types first (Fixes #1143, #1040, WALM-721)
…eck (#1081)

- In waitForRememberJob and waitForRememberJobs, clamp the polling sleep delay to Math.max(0, deadline - Date.now()) so the client never sleeps past the wait budget.
- Refactor the polling loop so that if the remaining budget expires during sleep, a boundary poll is performed rather than exiting immediately without a status check.
- Update pollDeadlineMs to supply a usable minimum timeout (1000ms, clamped to requestTimeoutMs) at or past the boundary so the final check does not immediately abort with a 1ms timeout.
- Add regression tests verifying that a job settling before the deadline resolves instead of timing out, and that wait loops do not sleep past the deadline.
…781)

- Scope unique partial index on remember_jobs to (owner, namespace, idempotency_key)
- Add migration 025 to drop legacy uq_remember_jobs_owner_idempotency_key index
- Update conflict handling and idempotency lookups in server routes/remember.rs and routes/analyze.rs
- Scope TypeScript MemWalMock idempotency map to namespace + key and document in JSDoc
- Add tests covering cross-namespace key re-use and intra-namespace deduplication

Fixes WALM-781, #1170
harrymove-ctrl and others added 12 commits October 16, 2026 14:25
* fix(sdk): reject an object passed as remember text

remember, rememberAsync, and rememberAndWait throw TypeError before signing when text is not a string.

* review: reject an object remember text in the mock

MemWal throws TypeError. The mock used to fall through to "text cannot be empty".
* fix(sdk): turn an empty or non-JSON 2xx body into an SDK error

health() and signed requests called res.json() on success and leaked
a raw SyntaxError. Callers now get an error that names the HTTP status.

Fixes #1201

* fix(sdk): name empty JSON bodies in MemWalManual and MCP

The same 2xx parse guard from MemWal now covers manual restore, compatibility, embed, Walrus upload, and the MCP relayer check.

* fix(sdk): give an unreadable 2xx body its HTTP status

A remember wait treated a status-less parse error as HTTP 0 and polled until timeout.

* review: await the restore body and test the empty JSON path

Without await, the deadline disposed before text() finished, so a stalled body became a TypeError. The empty-202 tests now stub the SEAL session and hit /api/remember.
#1235)

A cached storage price below the live price makes reserve_space abort in balance::split. The durable path only rebuilt the client on destroy_zero, so every wallet attempt reused the same snapshot.
The credential assignment regex covered password and secret_key but not
db_pass or encryption_key, so those values were stored verbatim.

Fixes #1052
HEX_LABEL_AFTER could consume "my" from mypass and then match pass,
so a commit SHA or blob id in front of that word was redacted.
…8) (#1244)

* fix(chatbot): scope tool-approval updates to the caller chat (WALM-798)

* test(chatbot): cover tool-approval updates through the chat route
* fix(chatbot): reject a vote for a message outside the chat

PATCH checked that the caller owns the chat, then voted on any message id.
A missing row and a message from another chat now both return not_found:vote,
and voteMessage is not called.

* test(chatbot): keep vote route mocks in beforeEach only

clearAllMocks does not reset implementations, so the module-scope
defaults never ran. beforeEach is the only copy.
* fix(python-sdk): forward recall scoring weights and sort

RecallParams can carry scoring_weights and sort, and recall sends them on POST /api/recall.

* review: honor mock recall sort and clear the Python lint

sort=recent was still returning relevance order. The README table now lists scoring_weights and sort, and the capture signature fits the line limit.

* review: keep recent recall inside the semantic window

sort=recent was reordering the whole namespace, so a newer memory outside the window could win. It now matches the TypeScript mock: semantic top max(min(limit * 5, 50), limit), then write time.

* review: note that the mock recall ignores scoring_weights

* review: mock recall docstring no longer claims distance order for sort=recent
* fix(ci): retry a prerelease publish that hits a staged version

Version & Publish computed 0.1.8-dev.25 while that version was already staged, so npm returned 409 and the promote check failed. A 409 now bumps the number and retries.

* fix(ci): read the prerelease number without the pipefail double -1

Under pipefail, `npm view | node || echo -1` appended a second -1 when npm
view failed, so the version math published `*-channel.-1` or republished the
current max. Capture npm view on its own and check its status separately:
E404 (never published) means none yet, any other failure aborts before
publishing. Parse the output in a separate node step, refuse non-JSON, take
only numeric suffixes, and accept the result only if it matches ^-?[0-9]+$.

Add node:test coverage with npm and pnpm stubbed on PATH (failure, E404,
garbage, multi-line output, staged-version retry). Run it with
`node --test .github/scripts/publish-prerelease.test.mjs`.
fix(mcp): redact db_pass and encryption_key assignments (#1052)
* chore(sdk): cut TypeScript 0.1.9 and Python 0.1.12

The 18 Oct promote to main already had these SDK fixes, but the version
strings were still 0.1.8 and 0.1.11, so both release jobs skipped publish.

* docs(sdk): fill 0.1.9 and 0.1.12 changelog notes

The package changelogs and the docs pages had drifted, and several
fixes since the last published SDK were still under Unreleased or missing.

* docs(sdk): name rememberBulkAsync and #1080 in the 0.1.9 summary

---------

Co-authored-by: harrymove-ctrl <harry.phan@commandoss.com>
@ducnmm
ducnmm deployed to benchmark-dev October 21, 2026 05:56 — with GitHub Actions Active
@railway-app
railway-app Bot temporarily deployed to Walrus Memory / dev October 21, 2026 05:56 Inactive
@ducnmm
ducnmm deployed to benchmark-dev October 21, 2026 05:57 — with GitHub Actions Active
@ducnmm ducnmm mentioned this pull request Oct 21, 2026
10 of 15 tasks
@ducnmm

ducnmm commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator

Superseded by #1273.

This PR's head is dev, so the four changelog conflicts cannot be resolved here without merging staging into dev. #1273 is staging plus that merge. The tree matches dev e49853e1. Please close this one and review #1273 with a merge commit, not a squash.

@railway-app
railway-app Bot temporarily deployed to Walrus Memory / dev October 21, 2026 06:14 Inactive
@harrymove-ctrl

Copy link
Copy Markdown
Collaborator Author

Superseded by #1273.

1 similar comment
@harrymove-ctrl

Copy link
Copy Markdown
Collaborator Author

Superseded by #1273.

@ducnmm ducnmm mentioned this pull request Oct 21, 2026
4 of 7 tasks

This branch was successfully deployed

1 active and 1 inactive deployments
Walrus Memory / dev — 7dc91ba3 Deployed Oct 21, 2026 by railway-app[bot]
benchmark-dev — 7dc91ba3 Deployed Oct 21, 2026 by harrymove-ctrl via Memory API Latency #466
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.

5 participants