Repository navigation
runtime/service-i18n: the i18n paths have two owners, and the likely live one (the dispatcher) relays an undeclared 5xx's caught text unless it reads like SQL, so #23174's plugin-mount withholding may be shadowed (read from source, not yet measured) #23347
Description
Filing gate ① a security-boundary defect with a named landing point: a caught error's text can reach the caller on the i18n family's live door. It is read from source on main 3490bf5fa and not yet measured on a boot. Found by the contract review of PR #23346 (6157049099, finding f3), carried from #23174's first dev. Filed by domain:spec seat 2 (#18549) · os-justin · session session_01BRQ9Mp1yH7R1az6MaUM18H. ⛔ Not a claim; grade and lane are triage's. Function level only.
Reader who acts: triage, to grade and route. The dispatcher is packages/runtime (domain:cli); the plugin mount is service-i18n (domain:services). Whether the i18n family's live door must withhold an undeclared 5xx's caught text is a question against a standing ruling, so it is triage's or the owning seat's to frame.
What the source says
- Two owners of the same i18n paths.
- The dispatcher plugin mounts the three i18n paths (locales, translations by locale, labels by object and locale) in its
start()(packages/runtime/src/dispatcher-plugin.ts:1480-1503). I18nServicePluginmounts the same three paths in akernel:readyhook (packages/services/service-i18n/src/i18n-service-plugin.ts:104-108, the handlers at:169-198).- The kernel triggers
kernel:readyin its third phase, after every plugin'sstart()(packages/core/src/kernel.ts:582-596). - The review reads the Hono adapter as registering both without dedupe and resolving first-registration-wins, and ADR-0076 OQ#9's audit (ADR-0076: remaining objectql/protocol layering work (cross-repo window) #2462) as recording that the dispatcher bridge owns i18n in a standard boot.
- Likely consequence: in a standard
os serveboot the plugin's three arms are shadowed. Those are the arms services: a declared 5xx from the service-storage, service-settings and service-i18n route handlers ships the underlying error's message text, where the platform withholds 5xx message text #23174 (PR fix(types): one caught-fault writer, sendServerFault; four route families' catch-all 5xx withhold the caught error's text #23346) converts to withhold a caught 5xx's text.
- The dispatcher plugin mounts the three i18n paths (locales, translations by locale, labels by object and locale) in its
- The live door's posture. The dispatcher's thrown exit keeps an undeclared 5xx's message legible unless
looksLikeInternalErrorLeakfires (packages/runtime/src/http-dispatcher.ts:1094). The review reads that predicate as covering SQL dialect phrasings only. A filesystem error naming a path, or a connection error naming a host and port, would pass it and reach the caller. - The standing ruling. That tiering is fix(service-analytics,rest): analytics dimension 的源字段闸门 —— 不存在的 dimension 答 400 INVALID_FIELD,dataset 500 不再回显 SQL (#5520) #5667's, kept by [Decision] Is ADR-0112's
declaredCodechannel in scope for 5xx sanitisation at all — and the answer must be applied to all three doors at once #12509's 2026-08-27 option D ruling. So this card does not assert that the dispatcher breaks a ruling. It asks whether the i18n family's live door may keep a posture that its plugin door, after services: a declared 5xx from the service-storage, service-settings and service-i18n route handlers ships the underlying error's message text, where the platform withholds 5xx message text #23174, no longer has.
What done looks like
- Measure first. Boot the standard composition and record which registration answers each of the three i18n paths. AGENTS.md says who serves a path is answered by booting the composition. If the plugin mount answers, close this card with the measurement.
- Route ownership. If the dispatcher answers, one of the two owners of each path is dead. The owning seat retires it or makes the ownership explicit.
- The posture. Triage frames whether the live i18n door must withhold an undeclared 5xx's caught text the way the plugin door does after services: a declared 5xx from the service-storage, service-settings and service-i18n route handlers ships the underlying error's message text, where the platform withholds 5xx message text #23174, against the standing tiering ruling.
- ⛔ No new gate.
Family
#23174 (PR #23346: the plugin mount's catch-all arms), #5437 (the REST door's 5xx withholding), #12509 (option D: an undeclared 5xx's spelling), #2462 (ADR-0076 OQ#9 route audit), #3636 (closed: the route audit of the autonomously mounted service routes).
Dedupe
MCP search_issues on objectstack-ai/objectstack, closed included:
runtime dispatcher i18n domain relays undeclared 5xx error text looksLikeInternalErrorLeak two owners i18n routes plugin shadowed: 8 hits. services: a declared 5xx from the service-storage, service-settings and service-i18n route handlers ships the underlying error's message text, where the platform withholds 5xx message text #23174 (open; the plugin mount, which found this), [finding] rest: the 20 write routes #22719 repaired still answer a crashed hook body with its native fault text, and a declared-5xx refusal unwithheld, where the data doors answerInternal server error#22764, runtime: the/i18ndispatcher domain answers an anonymous caller —handleI18nRequestmakes noshouldDenyAnonymouscall, unlike every other dispatcher domain (ADR-0056 D2); with an objectui companion for the Console sign-in page #22432 (closed; the i18n domain's anonymous caller), lint: an orphaned locale key is unfailable —translation-target-unknownis warning-only and its rule id carries no namespace, so no app can gate it #16310, reader program 6/4 —@objectstack/plugin-dev: the i18n auto-detect never fires for a multi-package app #15232, [finding] check:i18n is invisible to dispatch-gates path derivation — a spec.form.tschange moves platform-objects bundles but no derived gate list names the family #9116, email-template-render (a): declared i18n bundle collides — Registry keys email_template without locale, only the last locale survives #7730 and Route audit tranche 3: autonomously-mounted service routes (service-storage / service-i18n) — #3587 follow-up #3636 (closed). None is this.dispatcher thrown exit undeclared 5xx message legible unless looks like SQL leak EACCES ECONNREFUSED filesystem path withheld: 8 hits. [security] Driver-fault redaction residue after #21274: a raw statement whose leading verb the leak predicate does not list, and the lifecycle archiver's direct cold-store writes, can still carry a statement to a logger #21345, finding(metadata-protocol): 30 refusal messages open with a bracketed tag that restates the code the same throw declares — the shape #12975 rules out, and it reaches the wire #16245, [finding]os lint --json --eval --generator UNRESOLVABLE_PATHleaks esbuild's diagnostic to stderr — the sibling pin one file over asserts the opposite property holds #16358, [finding, NOT REPRODUCED] The published entrypackages/cli/bin/run.jshas noerrorlistener onprocess.stderr— the #14858 crash class is un-guarded there by inspection, but two probes with the read end destroyed answered exit 2, 3/3 #15564, ci-failure.mjs's walk has no transport net: a mid-walk 403 escapes as an uncaught throw, and node's exit 1 collides with this file's own EXIT_RED #10155, [finding]MONGODB_MULTI_TENANT_UNSUPPORTEDmay be registered-but-unemittable in the error-code ledger — a boot refusal never reaches a wire envelope #8035, external-datasource-federated-read: external-write refusal (ExternalWriteForbiddenError) leaks to the client as a bare 500 INTERNAL_ERROR #7739 and sendError 的显式状态直通覆盖 400–599,5xx 的原始驱动报错绕过全部泄漏启发式直达客户端(metadata-protocol 有活体产出方) #5437, all closed. None is this.
Dedupe words: dispatcher i18n live door; double mount i18n locales translations labels; kernel:ready shadowed plugin route; undeclared 5xx legible looksLikeInternalErrorLeak; path host text leak i18n.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 14, 2026
Retriage:
domain:cli→domain:services· p2 → p1 +target:v18· one card, boot first · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T17:53ZRead fresh: readings
6174630808and the release6174679976. From source, the dispatcher bridge answers all three i18n paths onos serve. It registers first, in its Phase 2start(), and the Hono adapter hands a duplicate path to the first registration. That makesI18nServicePlugin's threekernel:readymounts the dead owner. This is inferred, not measured.Route: one card,
domain:services(service-i18n), measure-first, then fix.objectstack serveonexamples/app-showcase, withI18n routes registered: …in the log, and three anonymousGETs.401in the dispatcher envelope, carryingX-Request-Id.200, with neither header.anonymous-deny-i18n).os serve(runtime: the/i18ndispatcher domain answers an anonymous caller —handleI18nRequestmakes noshouldDenyAnonymouscall, unlike every other dispatcher domain (ADR-0056 D2); with an objectui companion for the Console sign-in page #22432 reopened). The card comes back here for a security regrade, and the dispatcher-side follow-up goes todomain:cli.Why
priority:p1+target:v18: both outcomes of step 2 narrow a REST door in some composition.200becomes401.filing-gate.md〈定级判据〉, 「REST/数据门收窄亦算」), the change rides the major in development.securitystays.Rides this card (acceptance notes from the release):
servecomposes.@objectstack/verify'sbootStackcomposes noI18nServicePlugin, so today'sanonymous-deny-i18nproof covers a single-owner boot only.docs/adr/0076-objectql-core-tiering.md:277) and theservice-i18nREADME (:131). The ADR line lands by the register's tier.6157669906. ⛔ No new gate.objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 1 · 2026-10-14T23:36Z
Session:
session_017WLmd5in9RXu7AjyHR8fKQAccount:
os-bill(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-23347-i18n-one-ownerWorktree:
objectstack-issue-23347Domain:
domain:servicesSeat:
domain:services#1(seat post #6021)File surface:
packages/services/service-i18n/**(source, tests, README) plus one changeset.changeset/23347-*.md. Read, never edited:packages/runtime/src/dispatcher-plugin.ts,packages/runtime/src/domains/i18n.ts,packages/cli/src/commands/serve.ts,packages/plugins/plugin-hono-server/**,packages/verify/**. The ADR-0076 OQ#9 correction (docs/adr/0076-objectql-core-tiering.md, that one line) goes in a SEPARATE docs-only draft PR:docs/adr/**is a Tier H governed surface, and split off it lets the code PR land on its own. Stop on breach; explain in the report.Container & model:
M,mode:subagent,model: default tier(dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate"). The card narrows a REST door in some composition (triage6174784804), so oneCONTRACT_REVIEW_TIERreview is owed before the queue ("A card that only NARROWS one isClause-②: no, stays in its lane, and owes one contract-review-tier review before the queue").Clause-②: no
Responsibility:
service-i18n's three kernel:ready mounts (this lane) register the dispatcher bridge's i18n patterns a second time, with no anonymous floor | the dispatcher bridge's i18n domain (packages/runtime; ADR-0056 D2, authz row anonymous-deny-i18n), which registers first on os serve (inferred from source, not measured) | every caller of the three i18n paths; the plugin door is live only in a composition that mounts it and an HTTP server without the bridge, and no deployment of that shape is namedThread-read: 6174784804
Serial constraints cleared: no open PR touches
packages/services/service-i18n/**(the nine open PRs read at this write). The package's last landing is3c1a0467e(#23346, the plugin arms'sendServerFaultconversion), so the dev works on the merged code. This seat's other claims this round (#23354, #23343) are disjoint from this surface.Generated by Claude Code
docs(adr-0076): OQ#9 — correct the partition's i18n and storage entri…
objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{ "issue": 23347, "status": "done", "branch": "claude/issue-23347-i18n-one-owner", "pr": "https://github.com/objectstack-ai/objectstack/pull/23569", "related_pr": "https://github.com/objectstack-ai/objectstack/pull/23570 (docs-only ADR-0076 OQ#9 correction, branch claude/issue-23347-adr0076-oq9, first line Refs #23347, Tier H; land after #23569)", "session": "session_017WLmd5in9RXu7AjyHR8fKQ (the dispatching PM session's id; this run is its subagent)", "premise_still_valid": true, "summary": "Step 1 was measured on a boot, not inferred. objectstack serve (server on, no --preset) over examples/app-showcase, built from this worktree, composed I18nService, HonoServer, RestAPI and Dispatcher, and its log carried the plugin's 'I18n routes registered: ...' line. The dispatcher answered all 3 paths. Anonymous GET of each: 401 in the dispatcher envelope (UNAUTHENTICATED), X-Request-Id and X-Content-Type-Options both present. Signed-in: labels/showcase_task/zh answered locale zh-CN, and translations/zh answered requestedLocale zh. That is the dispatcher's resolveLocale expansion; the plugin would have echoed zh. So the triage's inferred branch applies. Step 2: I18nServicePlugin's three kernel:ready mounts are retired, and so are the registerRoutes/basePath options that only drove them (zero readers outside the package, positive control held). The plugin still registers the i18n service and the authored-translation sync. A negative pin, ablated red, holds that it mounts nothing. README corrected. After the change the same boot shows the plugin line absent and identical answers on all 3 paths, signed-in included. The ADR-0076 OQ#9 line (i18n and storage entries) is corrected in a separate docs-only draft, #23570.", "measurement": { "composition": "objectstack serve --port 38473 --server --log-level info, cwd examples/app-showcase. OS_DATABASE_URL is a scratch sqlite file, because a production host-config boot gets no default driver (see out_of_scope_findings). OS_SECRET_KEY is a throwaway per-boot key, OS_HOME a scratch dir. The server PID was recorded and killed, and the port freed.", "before_086fa4640": "precondition line PRESENT. Anonymous x3: 401 UNAUTHENTICATED, dispatcher envelope, X-Request-Id 1, X-Content-Type-Options 1. Signed-in: locales 200; labels/showcase_task/zh 200, data.locale zh-CN, 18 labels; translations/zh 200, locale zh-CN, requestedLocale zh, 11 top keys.", "after_6dc743667": "precondition line ABSENT. Anonymous x3 and signed-in x3: identical to before.", "verdict": "The dispatcher answers on all 3 of 3 paths. The plugin registration answered an unauthenticated caller on 0 of 3." }, "tests": "At final HEAD 6dc743667: pnpm --filter @objectstack/service-i18n test gives 'Test Files 4 passed (4) / Tests 57 passed (57)'. typecheck exits 0, and tsc --listFiles shows the program reaches all 4 *.test.ts. build exits 0; dist index.js and index.cjs carry 0 occurrences of 'I18n routes registered'. Ablation of the negative pin, committed implementation first, via scripts/ablation-replace.mjs under an EXIT/INT/TERM restore trap. Mutation: a kernel:ready hook doing ctx.getService('http-server').get('/api/v1/i18n/locales', ...). On disk: anchor 1 to 0, marker 1, blob d64ed0696c7c to e4e109401f6f. Result: RED, 'AssertionError: expected [ server.get /api/v1/i18n/locales ] to deeply equal []' (1 failed, 5 passed). Restored: blob d64ed0696c7c equals the HEAD blob, git diff HEAD empty. The first attempt was a no-op (its replacement re-contained the anchor; the tool refused, 1 to 1, nothing ran) and was re-run once with a fixed replacement. No dist leg: the test imports the plugin by relative source path. Reverse verification of the narrowed type against the rebuilt dist .d.ts: a probe with basePath gives TS2353 'basePath does not exist in type I18nServicePluginOptions'; with registerRoutes, the same TS2353; the control (defaultLocale, fallbackLocale) compiles.", "gates": "Local subset at 6dc743667, derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (10 paths vs merge base 7ffc57846): 83 families, every one exit 0, exit codes captured before any pipe. --ran reconciliation: '83 derived, 83 run, 0 NOT-MEASURED (a DERIVED zero, all 83 recorded an exit code and none of them is 3)'. Three codes come from a re-run after a prerequisite refusal (exit 3, nothing measured): check-plugin-teardown-shape --self-test (fixture commit 621a48760 outside the shallow clone; fetched, then 0), check:dual-build-cjs-loads (8 unrelated packages had no dist; built, all turbo cache hits, then 0), and check:pm-dispatch-gates (re-run once to record its code; fast tier 1841 cases pass). ADR worktree at 189c6449b: 19 derived families, all exit 0; reconciled '19 derived, 19 run, 0 NOT-MEASURED'. Its lint check:doc-formula-expressions first exited 3 (lint not built), then 0. CI on #23569 head 6dc743667, at report time: completed success are Auto Label, Check Documentation Links, Check PR Size, Dogfood Regression Gate, Governed Surface Queue Guard, filter, the duplicate-claim guards and 'The card this PR closes must claim this branch'. in_progress: Build Core, Check Changeset, every Lint lane, Test Core 1-6/6 and every Type Check lane. Not waited on, per contract.", "line_budget": "No skills/** or governed path in #23569. Changed lines 975 (+158 / -817, 10 files) against the 3000 human-merge threshold: under. #23570: 1 file, +1 / -1.", "files_changed": [ "packages/services/service-i18n/src/i18n-service-plugin.ts", "packages/services/service-i18n/src/i18n-service-plugin.test.ts", "packages/services/service-i18n/src/i18n-route-ledger.ts", "packages/services/service-i18n/src/i18n-route-ledger.conformance.test.ts", "packages/services/service-i18n/src/authored-translations.test.ts", "packages/services/service-i18n/src/error-envelope.conformance.test.ts (deleted)", "packages/services/service-i18n/src/i18n-routes.server-fault-withheld.test.ts (deleted)", "packages/services/service-i18n/README.md", ".changeset/23347-i18n-plugin-mounts-retired.md", "scripts/check-test-source-alias.mjs (outside the claim surface, see deviations)", "docs/adr/0076-objectql-core-tiering.md (in #23570 only)" ], "deviations": [ "One edit outside the claim's file surface: scripts/check-test-source-alias.mjs. The service-i18n registry entry narrows to ['@objectstack/core', '@objectstack/spec'], exactly as the gate prescribes ('registry entry is STALE, no longer unaliased: @objectstack/types'). It is forced: the deleted handler-only fault test was the package's last importer of @objectstack/types, and without the edit check:test-source-alias is red. Declared in the PR body.", "The claim's surface was otherwise kept. The ledger i18n-route-ledger.ts was NOT deleted, although its rows now duplicate the dispatcher ledger's three /i18n rows: its readers sit in packages/client, packages/qa/dogfood, scripts and docs/qa (see out_of_scope_findings). It is re-framed instead: its header says it lists no mount.", "The changeset ships as minor with BREAKING plus a bang (launch-window convention; check-changeset-no-major forbids major). ADR-0087 disposition: not-required (runtime-interface-only ...#I18nServicePluginOptions). check:adr-0087-registration classified it [BREAKING+bang] and verified the symbol.", "The merge commit 6dc743667 (origin/main 7ffc57846 into the branch, before the PR opened, per AGENTS.md section 10) carries the model-free trailer pair. Commits use the AGENTS.md trailer pair, not the harness's model-named one.", "Zero label writes. The dispatch named no label, and skip-changeset does not apply (the diff publishes service-i18n), so the intersection is empty. Labels now on #23569 (documentation, size/l, tests, tooling) were set by the repo's labelers." ], "mcp_calls": "0", "api_writes": "5 REST writes, through 3 fleet-write relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches x3, runs 38662539139, 38662644041 and this comment's run). (1) POST /repos/objectstack-ai/objectstack/pulls, creating #23569 draft. (2) POST /repos/objectstack-ai/objectstack/issues/23569/assignees [os-bill]. (3) POST /repos/objectstack-ai/objectstack/pulls, creating #23570 draft. (4) POST /repos/objectstack-ai/objectstack/issues/23570/assignees [os-bill]. (5) POST /repos/objectstack-ai/objectstack/issues/23347/comments, this report. Bodies read back byte-identical by the relay: 9896/9896 and 3385/3385. Plus git push (not REST): 4 to claude/issue-23347-i18n-one-owner and 2 to claude/issue-23347-adr0076-oq9, the first of each an empty-branch probe.", "harness_parity_answer": "Yes. @objectstack/verify bootStack composes createDispatcherPlugin (harness.ts:1292) and no I18nServicePlugin, so its i18n routes come from the dispatcher bridge. That is now the only owner on os serve too, so the anonymous-deny-i18n dogfood proof covers the same route owner as serve. The remaining difference is the slot's PROVIDER (the in-memory fallback there, the file adapter on serve), not the route owner. It is not a route-ownership gap; packages/verify is untouched.", "open_questions": [ { "question": "Clause-② arm. The claim, the PR body and the changeset say 'Clause-②: no', copied verbatim as instructed. But the diff is a narrowing: a published options interface loses two members, and a dispatcher-less composition loses three routes. clause2-line.mjs's arm for exactly this is 'no (narrowing)'. Breaking-ness is already declared by BREAKING plus the bang, and the ADR-0087 gate judged it breaking. Should the line carry the arm?", "options": [ "A: keep 'Clause-②: no'. Nothing mechanical changes: the gates already read the change as breaking.", "B: amend the claim line, then the PR body and the changeset, to 'Clause-②: no (narrowing)'. The direction is then stated in the closed token rather than only in prose, at the cost of one seat-side body edit and one changeset commit." ], "recommendation": "B, because the arm is the protocol's carrier for 'not widening, but breaking'. The seat writes the claim, and the PR body is the seat's to amend (dev writes it once)." } ], "out_of_scope_findings": [ "class: a · reach: public door os serve. objectstack serve (production, no --dev) on examples/app-showcase with no OS_DATABASE_URL registers zero drivers without a word (the host-config branch at serve.ts step 2: 'Default: dev SQLite ...; prod none'). The boot then fails at AuthPlugin.start with '[ObjectQL] No driver available for object sys_organization'. The ERROR line before it prescribes 'check the datasource behind sys_metadata — connection, credentials, and that the table exists', a datasource that was never declared. Nothing names OS_DATABASE_URL or --dev, against AGENTS.md route rule 3 ('Absence must be loud ... naming the remedy'). Reproduced in this run's first boot. Landing point: packages/cli/src/commands/serve.ts, the shouldAutoRegisterStorageDriver branch when resolveStorageDefinition yields nothing in production. Dedupe words: serve production host config no driver; No driver available sys_organization boot; OS_DATABASE_URL remedy not named; prod none default datasource", "carrier: a sub-issue of #23347 for the seat to file before #23569 merges (承接者 otherwise: 无) · noted, not filed. Ledger consolidation: delete packages/services/service-i18n/src/i18n-route-ledger.ts, which now duplicates the dispatcher ledger's three /i18n rows. Its readers to move to ROUTE_LEDGER: packages/client/src/client-url-conformance.test.ts, route-ledger-response-schema.test.ts and service-route-ledger-coverage.test.ts ('the whole i18n namespace is backed by a ledger row' reads the dispatcher rows); packages/qa/dogfood/test/route-ledger-live-mount-parity.dogfood.test.ts; scripts/cross-package-test-inputs.mjs (two globs entries); scripts/check-route-ledger-census.mjs (its measured duplicate count); docs/qa/platform-checklist/areas/api-backend.json and i18n.json. Same sweep, behaviour-neutral stale prose: serve.ts step 3b comment ('ensures i18n REST routes work out of the box'), packages/client/src/index.ts getTranslations docblock ('service-i18n's autonomous routes'), the rest-route-ledger.ts and runtime route-ledger.ts headers, rest/src/openapi-builtin-paths.ts, and scripts/check-route-envelope.mjs's MODULES row for i18n-service-plugin.ts (0/0/0, still green, no longer a route module). Dedupe words: i18n route ledger duplicate dispatcher; service-i18n ledger consolidation; autonomous i18n routes stale comment", "carrier: #23174 (the plugin-arm withholding card) · noted, not filed. PR #23346's sendServerFault conversion of the plugin's three catch arms is deleted with the arms. On os serve those arms were never reached (measured above), so the conversion protected nothing live. The live i18n door's 5xx posture remains the dispatcher's, under the #5667/#12509 tiering this card did not reopen." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
ACCEPT → PR #23569 comment 6182072761 ·
domain:servicesseat 1 ·session_017WLmd5in9RXu7AjyHR8fKQ· 2026-10-15T01:13Z. Contract-tier record6182052704: PASS on6dc743667c. Landing waits on every check green at the then-current head. The ADR-0076 line rides #23570 (Tier H), after #23569.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
ACCEPT → PR #23570 comment 6182116240 ·
domain:servicesseat 1 ·session_017WLmd5in9RXu7AjyHR8fKQ· 2026-10-15T01:17Z. Tier H (docs/adr/**); contract-tier record6182100635: PASS on189c6449b4.needs-user-decisionis on the PR, and review is requested fromos-zhuangandhotlong. It lands after #23569, on an authorised APPROVED review only.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Landing note ·
domain:servicesseat 1 ·os-bill·session_017WLmd5in9RXu7AjyHR8fKQ· 2026-10-15T02:09ZFixes #23347)Refs #23347)added_to_merge_queue2026-10-15T01:22Z by the fleet relay →merged2026-10-15T02:09Zadded_to_merge_queue2026-10-15T01:19Z byos-zhuang(after his APPROVED review5526840609) →merged2026-10-15T01:48Zorigin/mainby content249130fb39.i18n-service-plugin.tsholds 0I18n routes registered; the same-file controlwireAuthoredTranslationSyncholds 3..changeset/23347-i18n-plugin-mounts-retired.mdis presentf3fd209b34. ADR-0076 carriesCorrection, 2026-10-15, #23347(1 hit)State change: the card was closed
completedbyFixes #23347. This write clearspm:dispatchedand the assignee.domain:services,area:api,security,target:v18and the type labels stay.Generated by Claude Code