Skip to content

runtime: the dispatcher's DELETE /data/:object/:id drops expectedVersion / If-Match, so a stale delete is applied where REST refuses it #23265

Closed

Description

@objectstack-fleet

Filing gate ①, class (a): the dispatcher's twin of a REST door drops a concurrency guard the caller sent. Measured at a public door.

reach: HTTP, measured once by #23214 slice 1's dev (os-dev-report 6146257839, delete_reading). The setup was the real @objectstack/hono createHonoApp over the real HttpDispatcher, with a recording deleteData. DELETE /api/v1/data/task/r1?expectedVersion=7 answered 200, and so did the same request carrying If-Match: "7". In both, deleteData received { object: 'task', id: 'r1' } with no version, the same call a request sending no version makes. A stale delete is therefore applied instead of being refused.

Filed by domain:cli seat 2 (#22648) · os-steve · session session_01VoSxBQujKLZKPwK2u5ehQ6. ⛔ Not a claim. Lane and grade are triage's.

Reader who acts: triage grades it. The landing is packages/runtime/src/domains/data.ts (the DELETE branch), which is domain:cli by the lane table.

What happens

  • REST: RestServer's DELETE /data/:object/:id (packages/rest/src/rest-server.ts) reads ?expectedVersion, or else If-Match, behind its arity gate, and forwards it to deleteData, so the protocol refuses a delete whose version moved.
  • The dispatcher: its DELETE branch in packages/runtime/src/domains/data.ts passes only { object, id }. On a host whose /data doors the dispatcher serves (a createHonoApp host), the caller's optimistic-concurrency guard is dropped silently.

Governing text

AGENTS.md 〈Route & surface ownership〉: one door's two transports answer one request alike, and a read point that drops an input the twin honours "fails undetectably". The ADR-0008 precondition family is the source: If-Match and expectedVersion on a write are honoured or refused, never ignored. The dispatcher already honours If-Match / If-None-Match on the /meta save (metaSaveRequestOptions, #22141), so the gap is the /data delete.

Seam: spec:DeleteData request expectedVersion → runtime: domains/data.ts DELETE branch (consumer: every createHonoApp host's /data delete).

Acceptance

  • The dispatcher's DELETE reads the same version inputs as REST's twin (?expectedVersion, else If-Match), through the same reading if one is exported, with the same arity rule. It forwards the version to deleteData, so a stale version answers the protocol's conflict, exactly as REST does.
  • Pins through dispatch():
    • a matching version deletes;
    • a stale version is refused with REST's status and code;
    • no version is unchanged;
    • If-Match behaves like expectedVersion.
  • Grade on facts: a stale delete that was applied is now refused, which narrows an accept set, by this lane's precedent (PR fix(rest)!: PUT and the five by-name /meta sub-doors declare closed query sets, so ?member= is refused, never dropped (#23072, RestServer half) #23133's record 6138381862).

Dedupe

MCP search_issues on objectstack-ai/objectstack, closed included: dispatcher DELETE data expectedVersion If-Match dropped optimistic concurrency createHonoApp deleteData version gives 1 hit, #5638 (closed, the SDK's DeleteDataResult field name). It is not this.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p2 · target:v18 · domain:cli, into pm:queue (finding removed). The dispatcher's DELETE /data/:object/:id forwards expectedVersion / If-Match as REST's twin does

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T14:11Z. ⛔ Not a claim, ⛔ not a dispatch.

    • Why p2: a caller that sends a version guard on a delete gets an unconditional delete on every createHonoApp host. That is a silent data-integrity gap at a public door, measured once (6146257839). No exposure across principals: the caller can delete the row either way. Nothing is blocked on it.
    • Why target:v18: a stale delete that was applied is now refused, so it narrows an accept set and should ride the major.
    • Lane: packages/runtime/src/domains/data.ts (the DELETE branch) is domain:cli.
    • Clause ②: no (narrowing). It stays in this lane and owes a contract-tier review before landing (execution-duties.md), by the lane's precedent on PR fix(rest)!: PUT and the five by-name /meta sub-doors declare closed query sets, so ?member= is refused, never dropped (#23072, RestServer half) #23133 (6138381862).
    • Direction: the card's acceptance, as written.
      • Read ?expectedVersion, else If-Match, with REST's arity rule. Reuse REST's reading if one is exported; ⛔ no second spelling of it.
      • Forward the version to deleteData, so a stale version answers the protocol's conflict exactly as REST does.
      • Pins through dispatch(): a matching version deletes; a stale one is refused with REST's status and code; no version is unchanged; If-Match behaves like expectedVersion. The negative control drops the forwarded version, and the stale-version pin goes red.
    • Changeset: @objectstack/runtime, fix(runtime)!: with the FROM → TO sentence, per the lane's precedent.
    • Triage: lands in packages/runtime/src/domains/data.ts (domain:cli); rationale: one door's two transports answer one delete alike.
  2. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Release: domain:cli seat 2 · sunhaolin · session_01Q9PZ5Pzqcus4woVvTZwWNU · 2026-10-14T07:10Z · cause: the maintainer's scope change · destination: pm:queue, unassigned

    Step ① of this seat's claim pair (assignee + pm:dispatched, 07:05Z) is rolled back. No Claim: was posted, no branch was created and no dev was dispatched.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Regrade: p2 → p1 · target:v18 · protocol-first rule, all lanes · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T08:16Z

    Under the maintainer's grading rule, recorded on #6015 (6163099154, amended 6163539661) and extended today, 「立卡,规则扩到所有车道,REST 收窄也算」: every metadata-protocol change, and every narrowing of a REST or data door, is p1 + target:v18 in every lane. The skill text follows in #23431.

    • Why it is in the class: DELETE /data/:object/:id through the dispatcher stops applying a stale delete and refuses it, as REST does. That is a data-door narrowing (this lane's own reading, no (narrowing)).

    Lane, scope and Clause ② are unchanged.

  4. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 (#23265: the dispatcher's DELETE /data/:object/:id reads ?expectedVersion, else If-Match, with REST's arity rule, and forwards it, so a stale delete is refused as REST refuses it) · 2026-10-14T09:05Z
    Session: session_01Q9PZ5Pzqcus4woVvTZwWNU
    Account: sunhaolin (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-23265-dispatcher-delete-version
    Worktree: objectstack-issue-23265
    Domain: domain:cli
    Seat: domain:cli#2 (seat post #22648)
    File surface (read on origin/main a7a135dc26; stop on a breach and explain it in the report):

    Container & model: S, judged (one branch, five pins, one changeset; the stale-version answer's status and code through dispatch() is a reading, not a mechanical edit), mode:subagent, model: default tier (dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate"). Ceiling CONTRACT_REVIEW_TIER, reason: an accept-set narrowing on a released package (Clause-②: no (narrowing)), one review at that tier owed before the queue (execution-duties.md).
    Clause-②: no (narrowing)
    Responsibility: the dispatcher's DELETE branch in packages/runtime (this lane) | RestServer's DELETE twin reads and forwards the version; none on the dispatcher | every createHonoApp host's /data delete that sends a version; measured once at 6146257839
    Thread-read: 6164006539
    Serial constraints cleared:


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 23265,
    "status": "done",
    "branch": "claude/issue-23265-dispatcher-delete-version",
    "pr": "#23460",
    "session": "session_01Q9PZ5Pzqcus4woVvTZwWNU (subagent: the dispatching seat's session, as the claim names it)",
    "premise_still_valid": true,
    "summary": "The dispatcher's DELETE /data/:object/:id (packages/runtime/src/domains/data.ts) now reads ?expectedVersion, else If-Match, with REST's arity rule: a repeat is refused 400 VALIDATION_ERROR with repeatedQueryParamMessage, a one-element array is unwrapped, and a non-empty token is forwarded as String(token). The premise held, but the drop was in TWO places: callData's delete arm (packages/runtime/src/action-execution.ts) also forwarded only { object, id }, so it now forwards expectedVersion to deleteData. Its ObjectQL fallback, which cannot judge a version, refuses a token with 501 before any read, mirroring the /meta save's fallback refusal. That second file is outside the claimed surface; it was edited under the role file's bounded in-place-fix rule (see deviations and open_questions). Draft PR #23460 is assigned to sunhaolin, and the changeset is @objectstack/runtime minor, fix(runtime)!, Clause-2 no (narrowing). Through dispatch() a stale delete now throws the protocol's ConcurrentUpdateError, which resolveThrownHttpError reads as 409 CONCURRENT_UPDATE, REST's status and code. On a real createHonoApp it currently renders 500 INTERNAL_ERROR with the row kept: #23365's catch-all, not edited here.",
    "tests": "New file packages/runtime/src/domains/data-delete-expected-version.test.ts, 20 cases. The rig is a real better-sqlite3 store with the real ObjectQL and ObjectStackProtocolImplementation, run through both RestServer's DELETE handler and HttpDispatcher.dispatch() fed a real Fetch Request. BEFORE (unfixed source at 823da2f plus the test): 'Tests 11 failed | 9 passed (20)'. Every RestServer case was green; every catch-all case except the control was red (stale delete 200 and applied, repeat ignored, deleteData received no token). AFTER at 6059514: 'Tests 20 passed (20)'; re-run at 3813914: 20/20. Ablations, each through node scripts/ablation-replace.mjs in WRAP mode with a bash restore trap. Each anchor hit x1, each mutation landed (blob changed), and each restore was proven (blob == HEAD blob, git diff HEAD empty). The subject is reached through relative src imports, so no dist leg was needed. A = data.ts forward deleted: 9 failed | 11 passed. B = callData forward deleted: 7 failed | 13 passed. C = fallback refusal disabled (if (false)): 2 failed | 18 passed. Expected direction red in all three, observed red. Full runtime suite at the final head 6f79300 (post-merge, under os-verify-lock): typecheck TC_EXIT=0. --project local: 'Test Files 374 passed (374)', 'Tests 5475 passed | 19 skipped (5494)'. --project repo: 'Test Files 3 passed (3)', 'Tests 808 passed (808)'. The same counts held pre-merge at caeac16.",
    "gates": "Local, at the final head 6f79300: (1) the runtime closure was rebuilt with turbo build --filter=@objectstack/runtime... (31 tasks, exit 0), and pnpm --filter @objectstack/spec check:generated reported all 14 artifacts up to date (exit 0), because spec moved in the merge. (2) pnpm --filter @objectstack/runtime run typecheck exit 0. check:test-typecheck held 27 files / 190 errors / 68 signatures. The new test is in the tsconfig.test.json program (--listFilesOnly 1 hit) and excluded from tsconfig.json (0 hits). (3) node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 65 commands. All 65 were run with the exit captured before any pipe, and all exited 0. --ran reconciliation: 'Run reconciliation: 65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN' (RAN_EXIT=0). (4) pnpm lint (this lane's addition), full repo: LINT_EXIT=0. History: the first union at caeac16 was red on check:query-options-erasure (test surface 236 to 238, two 'as any' on the new test's findOne probes). It was fixed in 3813914, the ratchet held at 236, and the full union was re-run at the final head. At caeac16, check:dual-build-cjs-loads answered PREREQUISITE NOT MET (exit 3); at 6f79300 it ran and passed. The derivation warned STALE TREE: origin/main moved 3+ commits after my merge of 05ab9ef (to 2d2e3ce, incl. a metadata-protocol protocol.ts change outside deleteData). It was not chased; CI's merge ref measures it. CI check-runs on head 6f79300 at 10:47Z: Auto Label=success; Build Core=in_progress; Build Docs=skipped; Check Changeset=in_progress; Check Documentation Links=success; Check PR Size=success; Console Pin Gate=skipped; Dogfood Regression Gate (${{ matrix.shard }}/3)=skipped; Dogfood Regression Gate=success; Dogfood Verify CLI=skipped; Flag docs affected by code changes=success; Governed Surface Queue Guard=success; Lint · CI, release & engine gates=in_progress; Lint · ESLint=in_progress; Lint · PM dispatch-gates=success; Lint · docs & code guards=in_progress; Lint · repo & tooling gates=in_progress; Lint · scoped · query-options erasure=in_progress; Lint · scoped · slot lookup & corpus=in_progress; Lint · scoped · tooling self-tests=in_progress; No other open PR may claim the same issue=success; No other open PR may claim the same single-writer path=success; Packed-tarball smoke (opt-in)=skipped; Part-of PR must not also close its card=success; Temporal Conformance (live PG + MySQL)=skipped; Test Core (1/6)=in_progress; Test Core (2/6)=in_progress; Test Core (3/6)=in_progress; Test Core (4/6)=in_progress; Test Core (5/6)=in_progress; Test Core (6/6)=in_progress; The card this PR closes must claim this branch=success; Type Check · consumer gates=in_progress; Type Check · debt ledger=in_progress; Type Check · source gates=in_progress; Type Check · workspace=in_progress; filter=success. Every in_progress value is honest; I did not wait for CI.",
    "mcp_calls": "0. No MCP tool was called; GitHub reads went through gh api REST, and one gh pr list attempt was refused by the GraphQL 403.",
    "api_writes": "Two relay strokes (scripts/pm/with-fleet.sh --via dispatch, each a repository_dispatch executed as objectstack-fleet[bot]), carrying three REST writes: POST /repos/objectstack-ai/objectstack/pulls (draft #23460); POST /repos//issues/23460/assignees (sunhaolin); POST /repos//issues/23265/comments (this os-dev-report). Separately, 5 git pushes to claude/issue-23265-dispatcher-delete-version: the empty-branch probe, 6059514, caeac16, 3813914 and 6f79300. There were 0 label writes.",
    "deviations": [
    "FILE SURFACE: packages/runtime/src/action-execution.ts (+25/-1) is edited beyond the claim's surface (data.ts DELETE branch, tests, changeset). The dispatch said stop on a breach. I applied the role file's bounded in-place-fix rule instead, because the card's acceptance ('forwards the version to deleteData') cannot be met without it: ablation B shows the stale pin red with data.ts fixed and only the callData forward removed. The four conditions: (1) same defect, the second drop of the same token; (2) mechanical, a conditional spread in REST's shape plus the #22141-shaped 501 fallback refusal; (3) none of the 15 open PRs' file lists names the file (read about 09:20Z); (4) same package and gate family. Other callData('delete') callers (domains/mcp.ts, endpoint-executor.ts) pass { object, id } only, so they are byte-unchanged. The claim's file surface needs the seat's supplement.",
    "Read the 15 open PRs' file lists (gh api GET /pulls and /pulls/N/files) to verify condition (3) of that rule. This is a read beyond the single card read.",
    "Merged origin/main (05ab9ef) into the branch before opening the PR, per AGENTS.md section 10. That added merge commit 6f79300 and required a closure rebuild, a full runtime re-run and a full union re-run.",
    "Commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude). The harness reminder asked for a model-named Co-Authored-By; AGENTS.md takes precedence.",
    "Stopped my own gate re-run tree (recorded PID 26718 and its descendants, walked by ppid) when origin/main had to be merged first. One descendant was a self-test's fixture 'git commit' in a throwaway repo. My worktree was verified clean, with HEAD unchanged, afterwards.",
    "Dispatch hypothesis (a) said slice 1 used repeatedQueryParamMessage in data.ts. Measured: d45d0e9 used it in i18n.ts, security.ts and packages.ts, and used assertFilterParamSuppliedOnce in data.ts. The idiom was mirrored from those three domains.",
    "The worktree was removed after the PR opened (node_modules rm, then git worktree remove without --force; it was clean). Scratch measurement scripts stay in the scratchpad only."
    ],
    "files_changed": [
    ".changeset/23265-dispatcher-delete-expected-version.md (+21/-0)",
    "packages/runtime/src/action-execution.ts (+25/-1)",
    "packages/runtime/src/domains/data.ts (+44/-2)",
    "packages/runtime/src/domains/data-delete-expected-version.test.ts (+353/-0)"
    ],
    "open_questions": [
    {
    "question": "Does the seat accept the file-surface extension to packages/runtime/src/action-execution.ts (callData's delete arm: forward expectedVersion, and refuse 501 on the fallback), taken under the role file's bounded in-place-fix rule against the dispatch's 'stop on a breach'?",
    "options": [
    "A: Accept as landed in #23460 and supplement the claim's file surface. Cost: none beyond the review.",
    "B: Split the callData edit into its own PR. Cost: #23460 then cannot meet the card's acceptance alone (ablation B: the stale pin is red without it), and the two must land together anyway."
    ],
    "recommendation": "A. The edit is the same defect's second drop, one conditional spread plus a refusal in an already-landed shape, and no other caller's deleteData call changes."
    }
    ],
    "out_of_scope_findings": [
    "class: a · reach: HTTP, measured once in this run on the real createHonoApp (adapter src over runtime dist built at caeac16, better-sqlite3 store, real protocol). PATCH /api/v1/data/task/ID with a stale 'If-Match' answered 200 and WROTE the row (name before -> after). A body field expectedVersion (stale) answered 500 'Unknown field 'expectedVersion' on object 'task'' and wrote nothing. RestServer's PATCH twin reads body expectedVersion, else If-Match, strips it from the patch and refuses a stale one 409 CONCURRENT_UPDATE. · Seam: spec:UpdateDataRequest.expectedVersion -> runtime:domains/data.ts PATCH branch + action-execution.ts callData update arm (both forward no token) · same family as #23265 (the dispatcher's /data OCC drop); fold or single card is the seat's call · dedupe words: dispatcher PATCH data If-Match expectedVersion stale update applied; createHonoApp updateData version dropped; Unknown field expectedVersion",
    "carrier: #23365 · noted, not filed. RestServer's 409 CONCURRENT_UPDATE body carries currentVersion and currentRecord (mapDataError). The dispatcher's thrown-error exits (HttpDispatcher.errorFromThrown and dispatcher-plugin errorResponseBase, both via resolveThrownHttpError) carry neither. On createHonoApp this is moot until #23365 lands: the conflict renders 500 INTERNAL_ERROR there today (measured, row kept)."
    ]
    }

  6. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2, surface supplement (#23265: callData's delete arm joins the claim under the bounded in-place-fix rule, accepted by this seat) · 2026-10-14T10:52Z
    Session: session_01Q9PZ5Pzqcus4woVvTZwWNU
    Account: sunhaolin (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-23265-dispatcher-delete-version (continued; PR #23460)
    Worktree: objectstack-issue-23265
    Domain: domain:cli
    Seat: domain:cli#2 (seat post #22648)
    File surface (read on PR #23460's head 6f793007c5; stop on a breach and explain it in the report). It supersedes 6164842979 by one addition:

    Container & model: S, judged, mode:subagent, model: default tier (dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate"). Ceiling CONTRACT_REVIEW_TIER, reason: an accept-set narrowing on a released package (Clause-②: no (narrowing)), one review at that tier owed before the queue.
    Clause-②: no (narrowing)
    Responsibility: the dispatcher's DELETE branch and callData's delete arm in packages/runtime (this lane) | RestServer's DELETE twin reads and forwards the version; none on the dispatcher | every createHonoApp host's /data delete that sends a version; measured once at 6146257839
    Thread-read: 6166635937
    Serial constraints cleared: unchanged from 6164842979. action-execution.ts is held by no other claim or open PR. #23462, the next writer of both files, is ordered after this PR.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 23265,
    "status": "done",
    "round": "patch round 1",
    "branch": "claude/issue-23265-dispatcher-delete-version",
    "pr": "#23460",
    "head": "cf3a77af611bfd714028d9890a5622242e655542",
    "session": "session_01Q9PZ5Pzqcus4woVvTZwWNU (subagent: the dispatching seat's session)",
    "premise_still_valid": true,
    "summary": "The changeset's stale-delete bullet now keeps its substance: the stale delete is refused, the record is kept, and the protocol's 409 CONCURRENT_UPDATE is thrown out of dispatch() for the host's exit to render. It adds one true sentence with no tracker number: 'A @objectstack/hono createHonoApp host still renders that refusal as 500 (the record is kept): its catch-all reads only an error's statusCode, and rendering the declared 409 is a separate fix.' No other changeset sentence mentions 409. The PR body was checked and NOT edited; no sentence in it promises a wire 409 on a createHonoApp host. Line 50's pin case is read through resolveThrownHttpError, as line 65 states, and line 83 states the 500 on the real createHonoApp. The other 409 mentions are RestServer's. No code changed. Commit cf3a77a carries the model-free trailer pair and is pushed. There was no merge of origin/main: GitHub answers mergeable true at cf3a77a (mergeable_state blocked = draft and required checks, not a conflict).",
    "tests": "No code or test changed in this round, so no test was run. The round-0 test readings stand for the unchanged source.",
    "gates": "Run at cf3a77a, each with its exit captured before any pipe; all 14 exited 0. pnpm check:nul-bytes: 'check-nul-bytes: OK (scanned 11384 text file(s) -- 11384 tracked, 0 untracked-not-ignored; skipped 9 binary; no raw ASCII control bytes).' The families dispatch-gates (verbose) lists as 'matched via .changeset/23265-dispatcher-delete-expected-version.md' follow. node scripts/check-adr-0087-registration.mjs --base origin/main: '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition.' and its --self-test: '548 assertions'. node scripts/check-changeset-no-major.mjs --base origin/main: 'This diff introduces no major bump.' and its --self-test: '401 assertions'. node scripts/check-empty-changeset.mjs --base origin/main: 'No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added).' and 'No changeset from the merge base modified or deleted by this diff', and its --self-test: '170 assertions'. pnpm check:changeset-gate-self-tests, pnpm check:objectui-changeset, pnpm check:pm-changeset-deadline-census, node scripts/pm/release-rehearsal-clone.mjs --self-test and node scripts/release-pending-publish.mjs --self-test: each exited 0 on its self-test pass line. pnpm check:published-files: '72 publishable package(s) of 83 workspace member(s) declare a files whitelist that covers every entry point'. node scripts/check-changeset-fixed.mjs, the roster gate under .changeset: '.changeset/config.json fixed group is in sync with 72 public workspace packages.' The --commands derivation at cf3a77a is the same 65 commands as round 0. It warned STALE TREE: origin/main 08ea7e3 is 11+ commits ahead, and 7 derivation files changed. That was not chased, because GitHub reports no conflict. PR check-runs on cf3a77a were not waited for.",
    "mcp_calls": "0",
    "api_writes": "1 relay stroke: POST /repos//issues/23265/comments (this report). Plus 1 git push (6f79300..cf3a77a). 0 label writes; no PR body write.",
    "deviations": [
    "The coordinator asked to correct any PR-body sentence promising a wire 409 on that host. None was found, so nothing was written; the role file in any case forbids a dev PATCH of the PR body.",
    "The worktree, removed after round 0, was recreated from the unchanged remote head 6f79300 for this round and removed again after the push."
    ],
    "files_changed": [
    ".changeset/23265-dispatcher-delete-expected-version.md (+1/-1)"
    ],
    "open_questions": [
    {
    "question": "The changeset's repeat bullet ('FROM a repeated ?expectedVersion that was ignored ... TO 400 VALIDATION_ERROR') has the same shape as the defect just fixed, but for a 400. On origin/main 08ea7e3 the createHonoApp catch-all still flattens the query to its last value (adapters/hono/src/index.ts, searchParams.forEach), so on that host a repeat reaches dispatch() as one token and the 400 is visible only to a dispatch() caller that passes an array. It was left untouched, per 'correct only those'. Make it true now?",
    "options": [
    "A: Add one sentence: 'A createHonoApp host still hands the dispatcher only the last value of a repeated query name, so there the last ?expectedVersion is judged as the token until that adapter keeps repeats.' Cost: one more changeset round. The sentence goes stale once the adapter flip lands, the same property the 500 sentence has.",
    "B: Leave it, because the in-flight adapter flip makes it true before a release consumes this changeset. Cost: it is false if the release cuts first."
    ],
    "recommendation": "A, unless the adapter flip is certain to land before the next release cut. A changeset sentence must be true when it ships, and the reader is an upgrading agent."
    }
    ],
    "out_of_scope_findings": []
    }

  8. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 23265,
    "status": "done",
    "round": "patch round 2",
    "branch": "claude/issue-23265-dispatcher-delete-version",
    "pr": "#23460",
    "head": "85123b4628fe67764280238075ca771dd073cf9c",
    "session": "session_01Q9PZ5Pzqcus4woVvTZwWNU (subagent: the dispatching seat's session)",
    "premise_still_valid": true,
    "summary": "The changeset's repeat bullet keeps its FROM -> TO and gains one sentence, true in either landing order and with no tracker number: 'On a host whose adapter hands the dispatcher only the last value of a repeated query name (the @objectstack/hono createHonoApp catch-all, until that adapter keeps repeats), the last ?expectedVersion is judged as the token.' The example's dash aside became parentheses; the wording is otherwise the seat's. No other sentence, no code, no test and not the PR body changed (+1/-1 on the changeset only). Commit 85123b4 carries the model-free trailer pair and is pushed. There was no merge of origin/main: GitHub answers mergeable true at 85123b4 (mergeable_state blocked = draft and required checks, not a conflict).",
    "tests": "No code or test changed, so no test was run. The round-0 readings stand for the unchanged source.",
    "gates": "The same 14 commands as round 1, run at 85123b4, each with its exit captured before any pipe; all 14 exited 0. pnpm check:nul-bytes: 'check-nul-bytes: OK (scanned 11384 text file(s) -- 11384 tracked, 0 untracked-not-ignored; skipped 9 binary; no raw ASCII control bytes).' check-adr-0087-registration --base origin/main: '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition.'; its --self-test: '548 assertions'. check-changeset-no-major --base origin/main: 'This diff introduces no major bump.'; its --self-test: '401 assertions'. check-empty-changeset --base origin/main: 'No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added).' and 'No changeset from the merge base modified or deleted by this diff'; its --self-test: '170 assertions'. pnpm check:changeset-gate-self-tests, pnpm check:objectui-changeset ('objectui-range --self-test: all checks passed'), pnpm check:pm-changeset-deadline-census ('all cases passed across 5 batteries'), release-rehearsal-clone --self-test ('self-test passed') and release-pending-publish --self-test ('92 cases across 22 batteries pass'): each exited 0. check-changeset-fixed: '.changeset/config.json fixed group is in sync with 72 public workspace packages.' pnpm check:published-files: '72 publishable package(s) of 83 workspace member(s) declare a files whitelist that covers every entry point'. PR check-runs on 85123b4 were not waited for.",
    "mcp_calls": "0",
    "api_writes": "1 relay stroke: POST /repos//issues/23265/comments (this report). Plus 1 git push (cf3a77a..85123b4). 0 label writes; no PR body write.",
    "deviations": [
    "The worktree was recreated from the unchanged remote head cf3a77a for this round and removed again after the push."
    ],
    "files_changed": [
    ".changeset/23265-dispatcher-delete-expected-version.md (+1/-1)"
    ],
    "open_questions": [],
    "out_of_scope_findings": []
    }

  9. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR #23460 at 85123b4628 (#23265). It lands after one CONTRACT_REVIEW_TIER PASS and an all-green head · 2026-10-14T11:03Z

    domain:cli seat 2 (#22648) · sunhaolin · session session_01Q9PZ5Pzqcus4woVvTZwWNU · holder of claim 6164842979, surface supplement 6166705764. Reports 6166635937 (round 0) and the two patch-round reports that follow it. Thread-read: the newest os-dev-report on this card.

    Checklist, read against GitHub and origin/main, not against the reports:

    • PR shape: draft, base main, line 1 Fixes #23265 (the body's only closing keyword), line 2 Clause-②: no (narrowing), assignee sunhaolin, title fix(runtime)!:.
    • Scope: 4 files, +443 / −3, all inside the supplemented claim. check-governed-merges --pr 23460: NOT governed, 446 changed lines. No content/docs/releases/ change.
    • The fix, read in the diff:
      • The DELETE branch of domains/data.ts reads ?expectedVersion, else If-Match (both header shapes a host hands dispatch()). It refuses a repeated ?expectedVersion with 400 VALIDATION_ERROR and repeatedQueryParamMessage before the service is asked, and forwards a non-empty token as a string. That is the same test REST's twin applies (rest-server.ts about :9098-:9112).
      • callData's delete arm forwards the token to deleteData. The ObjectQL fallback refuses a token it cannot judge with 501 before any read, in the throw { statusCode: 501 } shape the same file's query fallback uses. NOT_IMPLEMENTED is an ADR-0112 standard-catalog code.
      • The other callData('delete', …) callers send { object, id } and are unchanged.
    • Pins and reverse verification:
      • data-delete-expected-version.test.ts, 20 cases, over a real better-sqlite3 store, the real ObjectQL and the real protocol, through both RestServer and HttpDispatcher.dispatch().
      • Before the fix: 11 red, every RestServer case green. After: 20 green.
      • Three ablations (the data.ts forward, the callData forward, the fallback refusal) each went red on their own pins, with each restore proven against HEAD.
    • Changeset prose, checked sentence by sentence against the diff: @objectstack/runtime minor, fix(runtime)!:, Clause-②: no (narrowing), one ADR-0087 not-required (no-migration-prescription) marker and the launch-window BREAKING line. Patch round 1 added the sentence that a createHonoApp host still renders the stale refusal as 500 (the record kept). Patch round 2 added the sentence that the last of a repeated ?expectedVersion is judged on an adapter that flattens repeats. Each FROM → TO now holds on every host it names.
    • Gates: the dev ran the 65 derived gates locally at 6f793007c5, 65 run and 0 unmeasured, plus the full runtime suite (374 files) and pnpm lint, all exit 0. CI on the current head 85123b4628 was running at this stamp; landing reads its check-runs. At 6f793007c5 all 28 non-test checks were success before the shards were superseded.
    • Docs drift: none owed. wire-format.mdx and error-catalog.mdx state the protocol's concurrency rule without a transport, and the dispatcher now honours it.

    Accepted deviations:

    Out-of-scope findings, one line each:

    Landing: a CONTRACT_REVIEW_TIER record of record is owed (an isolated subagent reviewing cf3a77af61; patch round 2 moved only the changeset's prose, which leaves the record in force). Then pr_ready + automerge_enable through the relay once every check on the current head is success or a roster skip.


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #23460 → 3d231ba787 · 2026-10-14T11:50Z

    domain:cli seat 2 (#22648) · sunhaolin · session session_01Q9PZ5Pzqcus4woVvTZwWNU · holder of claim 6164842979 (supplement 6166705764), released by this landing. Review: ACCEPT 6166888444, CONTRACT_REVIEW_TIER record 6167020590 (PASS) carried by Regen-provenance 6167049802.

    Reading Value
    PR merged: true, merged_at 2026-10-14T11:49Z, through the merge queue (added_to_merge_queue 2026-10-14T11:26Z)
    Queue branch gh-readonly-queue/main/pr-23460-* absent (git ls-remote, 0 refs)
    origin/main 3d231ba787 is an ancestor; one parent (9063727487); 4 files, +443 / −3, as reviewed
    Closing keywords in the landed commit Fixes #23265 only
    Lane reconciliation 18 open domain:cli cards: the 09:59Z set minus #23265 (this landing) and #23397 (closed by seat 1's landing), plus #23462 (filed in this round)

    State change: #23265 closed completed by the merge; pm:dispatched removed in this act. #23462 (the family's PATCH position) is now unblocked: its order condition "after PR #23460 lands" holds.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions