Repository navigation
feat(managed-agent): enforce workspace actor roles across the bound-Session surface - #13545
Conversation
Slice B of #13535 (storage only, behavior-invisible): - V48 migration replaces managed_workspace_access.can_read/can_create with a single role column (READER/OPERATOR/OWNER, CHECK-enforced), backfilling can_create -> OPERATOR and can_read-only -> READER, and adds managed_agent_session.owner_actor_key backfilled from creator_actor_key. - WorkspaceAccess becomes NONE/READER/OPERATOR/OWNER (ordered, with an atLeast helper); NONE remains the no-row decision, never storable. - Every grant reader (canRead, findReadable, listReadable, readableDefault, resolveForCreation, authorizePassiveAttachment, the cwd-change registry-facts join, the listSessions EXISTS filter) keeps its current truth table, re-derived from role. - insertSession writes owner_actor_key = creator on both bound and legacy creation paths; anonymous legacy creation leaves both NULL. - Test fixtures move to the role column; revocations that previously zeroed booleans now delete the grant row (the honest no-access equivalent under the CHECK); a (FALSE,TRUE) fixture state that role ordering makes unrepresentable becomes a grant-row deletion. - New tests: V47->V48 migration shape (backfill, owner:=creator, CHECK rejects NONE/invalid, post-V48 store-path creation writes owner) and session-owner store test (bound/legacy owner write, anonymous NULL). The full managed-agent-server suite differs from baseline only in the new tests; ManagedSessionStoreIntegrationTest#holdsRestorePages InsideThePerPageByteBudget errors identically on unmodified HEAD (verified in a clean worktree at ac497ae).
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
âĶn admission gate Slice A of #13535 (D5/D6): SurfaceRegistry over today's rules for all 78 mounted handler methods (32 public + 24 WebShell + 22 internal), the Spring-scanned correspondence gate that fails a route without a registry entry or a stale entry, and the parametrized acceptance walk that pins today's per-rule-class refusals on both surfaces plus both arms of the internal writer credential. Purely additive; no production edits. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
âĶackfill A (can_read=FALSE) row grants nothing under the booleans, but the role relabel would have given it READER (or OPERATOR with can_create). Dropping such rows keeps the migration a pure relabel for every reachable grant; pins the drop for (FALSE,TRUE) and (FALSE,FALSE) shapes in the migration test. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
âĶession surface Closes #13535. Turn submit/cancel/rename, cwd change and Action respond now admit any caller holding the OPERATOR role on the bound Workspace (Action respond additionally keeps the Session-owner arm), so a second operator can answer a pending approval â the blocked handoff of R1. Lifecycle (close, archive, unarchive, delete) admits the Session's recorded owner (owner_actor_key, with the pre-V40 creator fallback) holding a read grant: exactly today's caller set. The submitter family's readable-but-below-OPERATOR refusal normalizes from 409 workspace_unavailable to 403 session_operation_forbidden; all other refusal vocabularies are unchanged and the shape gates (deployment files opt-in, ACTIVE qwen-code Session, frozen execution profile) keep their domain 409 for an admitted OPERATOR. The SurfaceRegistry flips SESSION_CWD_CHANGE and ACTION_RESPOND from OWNER to OPERATOR on both surfaces, the D6 probes pin the post-flip matrix with a non-owner OPERATOR admitted on every OPERATOR-family route, and the WebShell workspaceTurns capability is computed from the caller's role instead of creator identity. Contract v1.34 records the role vocabulary, the refusal normalization and the capability rule; the generated WebShell types are refreshed with it.
|
â Qwen Triage finished â view run. See the stage comments in this thread for the result. â Qwen Triage å·ēåŪæ ââ æĨįčŋčĄãįŧæč§æŽįšŋįĻäļįåéķæŪĩčŊčŪšã |
|
Thanks for the PR! Template looks good â â every required heading is present and filled in, including the Tested-on matrix and the Risk & Scope bullets. Problem: real and named, not theoretical. #13535 is open and states the block concretely: every bound-Session operation merged so far admits its creator only, so a Hosted approval can only be answered by the Session's creator and a second operator on the same Workspace cannot unblock a Turn that is waiting on it. That is an observed product gap with a tracker, plus #12380 naming actor/tenant isolation as a production-enablement requirement. Not a "could theoretically" PR. Direction: aligned. #12867 §10 already fixed the vocabulary (reader/operator/owner, 404-below-read, 403-below-operate); this enforces that existing contract per route rather than inventing a parallel one, and it lands under the surface registry + build gate so a newly added route cannot silently skip the check. Enforcing a contract the repo already agreed to is the right shape for this. Size: 3,162 changed lines, broken down:
You have admin on this repo, so the two-tier core gate in AGENTS.md does not apply to a maintainer-authored PR â recording the 836 production lines for the trail rather than as an escalation. Worth knowing though: 574 of those 836 are Approach â one thing that needs correcting before review. The description says "this branch is based on
Because #13544's branch does not contain #13543, this PR re-adds all of #13543 â 2,695 of its 2,985 additions (90%). The actual enforcement slice is 290 additions / 177 deletions. Two consequences: a reviewer following the description will review the wrong 10%, and since four of the six files diverge, whichever of #13543/#13545 merges second hits an add/add conflict on files that already exist on Risk: no elevated Stage 1e signals â none of the changed files match the revert-correlated path list. The real risk is evidentiary and I have left the detail in the code-review comment: Flagging the stack ordering and the CI gap for discussion; the enforcement code itself is in the next comment. ð äļæčŊīææč°ĒčīĄįŪïž æĻĄæŋåŪæī â ââ ææåŋ åĄŦå°čé―åĻäļå·ēåĄŦåïžå æŽæĩčŊåđģå°įĐéĩäļãéĢéĐäļčåīãã éŪéĒïžįåŪäļå·ēįđåïžäļæŊįčŪšæ§įã #13535 åĪäš open įķæïžåđķå ·ä―čŊīæäšéŧåĄįđïžčŋäŧæŊäļŠįŧåŪ Session æä―åŠåå Ĩå ķååŧšč ïžå æĪ Hosted åŪĄæđåŠč―įą Session ååŧšč åįïžåäļ Workspace äļįįŽŽäšäļŠ operator æ æģč§ĢéĪčĒŦåŪĄæđéŧåĄį TurnãčŋæŊæ tracker įå·ēč§æĩäš§åįžšåĢïžå äļ #12380 æ actor/tenant éįĶŧįđåäļšįäš§åŊįĻčĶäŧķãäļæŊãįčŪšäļåŊč―ãį PRã æđåïžåŊđé―ã #12867 įŽŽ 10 čå·ēéäļčŊčĄĻïžreader/operator/ownerïžä―äščŊŧč 404ãä―äšæä―č 403ïžïžæŽ PR æŊéč·Ŋįąåžšåķæ§čĄčŋäŧ―äŧåšå·ēįŧčŪĪåŊįæĒæåĨįšĶïžčäļæŊåĶé äļåĨïžåđķäļč―åĻ surface æģĻåčĄĻ + æåŧšéĻįĶäđäļïžä―ŋæ°åĒč·Ŋįąæ æģééŧč·ģčŋæ ĄéŠã č§æĻĄïž å
ą 3,162 čĄåæīïžæååĶäļïžįäš§éŧčūïžmain Javaïž836 čĄãæĩčŊ 1,535 čĄãåĨįšĶäļįææäŧķïž ä― åĻæŽäŧåšæ admin æéïžå æĪ AGENTS.md įäļĪįš§æ ļåŋéĻįĶäļéįĻäšįŧīæĪč
æŽäššæäšĪį PR ââ čŋéčŪ°å― 836 čĄįäš§äŧĢį åŠæŊįįïžäļæŊåįš§åĪįãäļčŋéčĶįĨéïžčŋ 836 čĄéæ 574 čĄæŊ æđæĄ ââ æäļåĪéčĶå
æīæĢåčŊåŪĄã æčŋ°éåãæŽåæŊåšäš å äļš #13544 įåæŊäļåŦ #13543ïžæŽ PR æ #13543 æīäļŠéæ°å äšäļé ââ 2,985 čĄæ°åĒéæ 2,695 čĄïž90%ïžæĨčŠ #13543ïžįæĢįåžšåķæ§čĄåįæŊ 290 čĄæ°åĒ / 177 čĄå éĪãäļĪäļŠåæïžææčŋ°čŊåŪĄįäššäžįééĢ 10%ïžčäļå
äļŠæäŧķéæåäļŠå
åŪđååïž#13543 äļ #13545 äļåååđķįéĢäļŠäžåĻ éĢéĐïž Stage 1e æ åįš§äŋĄå· ââ åæīæäŧķé―äļå―äļäļåæŧįļå
ģįč·Ŋåūæļ
åãįæĢįéĢéĐåĻčŊæŪåąéĒïžįŧčįåĻäŧĢį åŪĄæĨčŊčŪšéïž å å 饚åšäļ CI įžšåĢå æåšæĨčŪĻčŪšïžåžšåķæ§čĄéĻåįäŧĢį åŪĄæĨč§äļäļæĄčŊčŪšã ð â Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
Code reviewMy independent read first. Given only the title and #13535's R1, I would have: put the role on the Workspace binding (a Session-keyed role table multiplies rows and needs a fan-out insert per creation), collapse the two grant booleans into one ordered column, funnel every bound-Session mutation through one shared "resolve caller role â compare to the family's minimum" helper so a new route cannot skip it, keep The enforcement slice holds up. I checked the parts that would be easy to get wrong:
One consistency note, not a blocker. The OPERATOR threshold is now expressed twice: as Coverage gap against your own validation plan. Design §7 promises slice-C targeted tests for "second-operator answers a pending approval on both surfaces, OPERATOR submits/cancels/renames/changes cwd". What lands:
The role check is clearly reached (403 became 404/403/409 in the right places) and The probe matrix itself is the strong part: Docs defect. Section 2's table is malformed in both language versions (EN lines 50â54, zh-CN lines 28â32). The cell carrying Refusal vocabulary as implemented
This matches contract v1.34's changelog sentence and the Files changed (15 of 15 shown â grouped by which slice they belong to)#13543's slice, re-added here because the base branch does not contain it (2,695 additions, 0 deletions):
The enforcement slice this PR is actually about (290 additions, 177 deletions):
TestingThis comment carries no independent test evidence, and none is obtainable while the base is a feature branch. Both The JDK 21 / Maven 3.9.11 / H2 results in the PR description, including the
No red checks to triage; the absence of the two build lanes is the finding, not noise. Retargeting this PR onto Sandboxed verification would settle this: äļæčŊīæäŧĢį åŪĄæĨ å čŊīæčŠå·ąįįŽįŦæđæĄïžåŠįæ éĒäļ #13535 į R1ïžæäžæč§čēæūåĻ Workspace įŧåŪäļïžSession įš§č§čēčĄĻäžæååĒå čĄåđķåĻæŊæŽĄååŧšæķæå ĨäļæđæåĄįŦŊæ æģæäļūį actorïžïžæäļĪäļŠææåļå°ååđķäļšäļäļŠæåšåïžčŪĐæŊäļŠįŧåŪ Session åæīé―čĩ°åäļäļŠãč§Ģæč°įĻæđč§čē â äļčŊĨææä―čĶæąæŊčūãįå ąäšŦčū åĐæđæģäŧĨå æ°č·ŊįąæžæĢïžčŪĐ owner äļ creator åįĶŧåđķäļš V40 äđåįčĄįåéïžåđķæãč·Ŋįą â č§čēãįĐéĩéåĻåļĶæåŧšéĻįĶįæģĻåčĄĻéãčŋåĨå å åįæĢæŊčŋäšïžčäļãæģĻåčĄĻ + éĻįĶãįæĄåŪæŊæįãäļäļŠå ąäšŦčū åĐæđæģãæīåĨ― ââ åŪčŪĐæäļūæŽčšŦæäļščĒŦæĩåŊđ蹥ïžčäļæŊäŋĄäŧŧæŊäļŠč°įĻįđãæįäļåšæīįŪįč·Ŋåūã åžšåķæ§čĄåįæŊįŦåūä―įãææ ļåŊđäšåŪđæåšéįå åĪïž äļåĪäļčīæ§æéïžäļæŊéŧåĄéĄđã OPERATOR éåžį°åĻčĒŦčĄĻčūūäšäļĪæŽĄïžservice/agent-store č·Ŋåūäļį įļåŊđä― čŠå·ąéŠčŊčŪĄåįčĶįįžšåĢã čŪūčŪĄææĄĢ Â§7 æŋčŊšåį C įåŪåæĩčŊå
åŦãįŽŽäšäļŠ operator åĻäļĪäļŠéĒäļåįåū
įåŪĄæđãOPERATOR æäšĪ/åæķ/æđå/æđ cwdããåŪé
č―å°ïžAction åįææĢåč§čŊïž æĒéįĐéĩæŽčšŦæŊææåįéĻåïž ææĄĢįžšé·ã įŽŽ 2 čįčĄĻæ žåĻäļčąäļĪįé―æŊåįïžčąæ 50â54 čĄïžäļæ 28â32 čĄïžãåį æĩčŊ æŽæĄčŊčŪšäļæšåļĶäŧŧä―įŽįŦæĩčŊčŊæŪïžčäļåĻ base æŊįđæ§åæŊæéīäđæ æģč·åūã PR æčŋ°éį JDK 21 / Maven 3.9.11 / H2 įŧæïžåŦ CI čĄĻč§äļæđčąæéĻåįæšåĻåŊčŊŧåšåïžčĄĻæ žäļéåĪįŋŧčŊïžãæēĄæįšĒæĢæĨéčĶå―å ïžįžšåĪąįäļĪæĄæåŧšééæŽčšŦå°ąæŊįŧčŪšïžäļæŊåŠéģãį #13543 äļ #13544 č―å°åææŽ PR į base æđå æēįŪąéŠčŊåŊäŧĨåŪæĄïž â Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
|
Confidence: 3/5 â the enforcement code is good and I would not change its shape, but I cannot verify a line of it runs, and the PR cannot merge as filed. Going back to the proposal I wrote before reading the diff: this exceeds it. I would have reached for one shared admission helper and trusted each call site to call it; the registry-plus-build-gate framing makes the enumeration itself the thing under test, so a route added next quarter cannot quietly skip the check. That is the better design and it is the part I would most want to keep. The refusal vocabulary is coherent â 404 below read, 403 below operate, 409 only for a shape gate an admitted OPERATOR hits â and it is applied consistently enough that I could reconstruct the whole matrix from the code and have it match contract v1.34 and the So the reservations are not about the code's shape. Three things stop me approving: I have no way to verify it, and that is structural rather than a timing accident. The diff does not match the description, and that misdirection is load-bearing. "The diff shows only the enforcement slice" and "design docs land with #13543" are both false as filed: 2,695 of 2,985 additions are #13543's six files, four of them divergent copies. I reviewed the 290/177 enforcement slice on its merits and it stands up â but a maintainer who trusts the description would spend their attention on the wrong 10%, and the add/add conflict waiting on whichever of #13543/#13545 merges second is a real cost, not a tidiness complaint. This is the part I would fix first, because it also fixes the CI problem: once #13543 and #13544 land and this retargets One arm of your own validation plan did not arrive. §7 promises targeted tests that an OPERATOR submits, cancels, renames and changes cwd. cwd has a genuine admitted-and-succeeded witness ( Also worth fixing while you are in the file: §2's table is malformed in both language versions â the raw pipes in the Am I being a pushover, or the reverse? The pull here is real â it is a maintainer's own PR, the code is clean, and "LGTM" is free. But an approval would be attesting to a suite result that does not exist, on a PR that cannot merge until two others land first. That is not a judgement I should make on the author's behalf by waving it through, and I found no code defect that would justify requesting changes either. So: deferring, not rejecting. Asks, in the order I would do them:
One open question from design §9 that I do not have the context to answer and that a human should: lifecycle stays Session-owner-only, so a workspace-OWNER grant does not admit lifecycle on Sessions bound to that workspace. That is a defensible line, but it means an OWNER can be locked out of deleting a Session in their own workspace â worth confirming that is the intended admin model before v1.34 is treated as settled, since flipping it later is a client-visible change. On the escalation mention: the deterministic resolver could not produce one. äļæčŊīæäŋĄåŋïž3/5 ââ åžšåķæ§čĄéĻåįäŧĢį æŊåĨ―įïžæäļäžåŧæđåŪįå―Ēæïžä―ææ æģéŠčŊå ķäļäŧŧä―äļčĄč·åūčĩ·æĨïžčäļæŽ PR æå―åæäšĪæđåžæ æģååđķã åå°æåĻčŊŧ diff äđååäļįæđæĄïžæŽ PR čķ
åšäšåŪãææŽæĨäžéäļäļŠå
ąäšŦįåå
Ĩčū
åĐæđæģïžåđķäŋĄäŧŧæŊäļŠč°įĻįđåŧč°įĻåŪïžčãæģĻåčĄĻ + æåŧšéĻįĶãįæĄåŪčŪĐæäļūæŽčšŦæäļščĒŦæĩåŊđ蹥ïžäļäļŠåĢåšĶæ°åĒįč·Ŋįąæ æģééŧč·ģčŋæ ĄéŠãčŋæŊæīåĨ―įčŪūčŪĄïžäđæŊæææģäŋįįéĻåãæįŧčŊčĄĻæŊčŠæī―į ââ ä―äščŊŧææ 404ãä―äšæä―ææ 403ãåŠæå·ēåå
Ĩį OPERATOR æäļå―ĒæéĻæ 409 ââ čäļåšįĻåūčķģåĪäļčīïžäŧĨčģäšæč―äŧäŧĢį åæĻåšæīåž įĐéĩïžåđķäļåĨįšĶ v1.34 å æäŧĨæįäŋįæč§äļåĻäŧĢį å―ĒæäļãæäļäŧķäščŪĐæäļæđåïž ææēĄæåæģéŠčŊåŪïžčäļčŋæŊįŧææ§įïžäļæŊæķåšäļįåķįķã diff äļæčŋ°äļįŽĶïžččŋäļŠčŊŊåŊžæŊæŋéįã ãdiff åŠåŦåžšåķæ§čĄåįãäļãčŪūčŪĄææĄĢé #13543 č―å°ãæå―åæäšĪæđåžé―äļæįŦïž2,985 čĄæ°åĒéæ 2,695 čĄæŊ #13543 įå
äļŠæäŧķïžå
ķäļåäļŠæŊåååŊæŽãææå
ķåŪčīĻåŪĄäšéĢ 290/177 čĄįåžšåķæ§čĄåįïžåŪįŦåūä― ââ ä―äļä―äŋĄäŧŧæčŋ°įįŧīæĪč
äžææģĻæåčąéåĻéĢ 10% äļïžč #13543 äļ #13545 äļåååđķč
å°æäļį add/add åēįŠæŊåŪé
äŧĢäŧ·ïžäļæŊæīæīæ§éŪéĒãčŋéĻåæäžæå
äŋŪïžå äļšåŪåæķäđäŋŪåĨ―äš CI éŪéĒïžį #13543 äļ #13544 č―å°ãæŽ PR æđ base å° ä― čŠå·ąéŠčŊčŪĄåéįäļčæēĄæå°ä―ã §7 æŋčŊšæåŪåæĩčŊčĶį OPERATOR æäšĪãåæķãæđåäļæđ cwdãcwd æįæĢįãåå
Ĩäļæåãč§čŊïž éĄšæäđåžåūäŋŪïžÂ§2 įčĄĻæ žåĻäļčąäļĪįé―æŊåį ââ ææŊåĻå―åĨ―åĨ―å įïžčŋæŊįļåïžčŋéįæåæŊįåŪį ââ čŋæŊįŧīæĪč æŽäššį PRïžäŧĢį åđēåïžčãLGTMãæŊå čīđįãä―äļæŽĄæđåå°æŊåŊđäļäļŠåđķäļååĻįåĨäŧķįŧæä―äŋïžčäļæŊåĻäļäļŠåŋ éĄŧįåĶåĪäļĪäļŠ PR å č―å°æč―ååđķį PR äļãčŋäļæŊæčŊĨæŋä―č æĨææūčĄįåĪæïžåæķæäđæēĄæåį°čķģäŧĨæŊæãčŊ·æąåæīãįäŧĢį įžšé·ãæäŧĨïžæĻčŋïžčéåĶåģã åŧščŪŪäšéĄđïžææäžæ§čĄį饚åšïž
čŪūčŪĄææĄĢ Â§9 éæäļäļŠææēĄæäļäļæåįãéčĶäššæĨåŪįåžæūéŪéĒïžįå―åĻæäŋæäŧ Session ownerïžå æĪ workspace äļį OWNER ææäļåå ĨčŊĨ workspace äļ Session įįå―åĻææä―ãčŋæĄįšŋæŊåŊäŧĨčūĐæĪįïžä―åŪæåģįäļäļŠ OWNER åŊč―čĒŦæĄåĻå éĪčŠå·ą workspace å Session äđåĪ ââ åžåūåĻ v1.34 čĒŦå―ä―åŪæĄäđåįĄŪčŪĪčŋæŊéĒæįįŪĄįæĻĄåïžå äļšå°æĨįŋŧč―ŽåŪæŊåŪĒæ·įŦŊåŊč§įåæīã å
ģäšåįš§ @ æåïžįĄŪåŪæ§č§ĢæåĻįŧäļåšäššéã â Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
âĶstry javadoc The RuleClass summary said a caller below OPERATOR everywhere answers 403, dropping the qualifier the per-class entries carry: below the read grant every Session route answers 404 session_not_found, and only a readable actor below OPERATOR gets the normalized 403 â the #12867 split the sentence claims to summarize. Review finding F4 on PR #13545. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
âĶ's own language The Chinese section-10 note sent readers to D4's English 'Rule today' column; the Chinese table calls it 'äŧåĪĐ'. Review finding F2 on PR #13545.
qwen-code-review-bot
left a comment
There was a problem hiding this comment.
Partially reviewed â gaps disclosed.
Not reviewed: end-to-end integration layer â HostedPublicWorkspaceIT and the two MySQL ITs compile but were never executed in this review (the failsafe profile needs MySQL plus a bundled dist/cli.js), so the findings that rest on their fixtures were traced, not measured.
Not reviewed: web-shell client unit tests â the vitest suite was never run (no node_modules in the review worktree); the one changed web-shell file is generated and its regeneration gate was reproduced byte-identical, so the changed file is covered, but no client behaviour was executed.
Not explored to full depth (tool budget reached): "agent reverse-audit (round 2)": could not execute a GFM/Prettier render of docs/design/2026-10-07-managed-agent-actor-roles.md lines 49-53 â no node_modules in this worktree (no prettier binarâĶ; "agent reverse-audit (round 1)": byte-exact regeneration check â openapi-typescript is not installed in the review worktree (no node_modules ), so managed-agent-api.test.ts 's toBe(await râĶ; "agent reverse-audit (round 3)": did not execute the managed-agent-server suite, so section 7 Slice C's "updated probes and contract tests pin the new matrix" stays unverified for ManagedAgentâĶ; "agent reverse-audit (round 2)": section 8's "Full managed-agent-server suite green on H2" â I test-compiled the module clean offline ( mvn -o -q test-compile , exit 0) but could not establish âĶ.
Not reviewed: reverse audit â stopped before round 4 by the review time budget.
[Critical] Re-check of a blocker already filed on this PR by the earlier triage round (comments 6027112673 and 6027112927) - STILL STANDS at 215999c. The base is still feat/13535-role-storage and the diff still re-adds all six files that #13543 also adds: git diff --name-status 7a6c52bd..HEAD reports A for both design docs, api/SurfaceRegistry.java, SurfaceAdmissionAcceptanceTest.java, SurfaceRegistryGateTest.java and SurfaceRegistryGateNegativeTest.java. Only two commits landed since that triage (aab53c1 a zh-CN matrix note, 215999c a registry javadoc qualifier), both documentation-only, so nothing about the stacking changed. Whichever of #13543 and #13545 merges second meets an add/add conflict on all six, and the description's 'this branch is based on feat/13535-role-storage so the diff shows only the enforcement slice' together with 'Design docs (EN/zh-CN) land with #13543' still describe a rebase that has not happened.
[Critical] Re-check of the same triage round's second blocker - STILL STANDS structurally at 215999c. .github/workflows/ci.yml filters pull_request on branches [main, release/, omni-experiment] and .github/workflows/sdk-java.yml on [main, release/], so with this base neither lane fires; the pre-submission check sees 3 checks and none of them is the Java test lane. The evidentiary half of that blocker is discharged by this review rather than by CI: the module was built and tested at this commit (mvn test -> Tests run: 1208, Failures: 0, Errors: 1, and the single error was measured identical at the merge base 7a6c52b, so it is pre-existing in a file this diff does not touch). What remains open is that the PR itself carries no CI signal, and HostedPublicWorkspaceIT plus the two MySQL ITs were never executed in this review because the failsafe profile needs MySQL and a bundled dist/cli.js.
äļæčŊīæ
äŧ åŪæéĻååŪĄæĨïžåŪĄæĨįžšåĢå·ēæŦéēã
æŠåŪĄæĨïžåæäļščąæïžïžend-to-end integration layer â HostedPublicWorkspaceIT and the two MySQL ITs compile but were never executed in this review (the failsafe profile needs MySQL plus a bundled dist/cli.js), so the findings that rest on their fixtures were traced, not measured.
æŠåŪĄæĨïžåæäļščąæïžïžweb-shell client unit tests â the vitest suite was never run (no node_modules in the review worktree); the one changed web-shell file is generated and its regeneration gate was reproduced byte-identical, so the changed file is covered, but no client behaviour was executed.
æŠæĒįīĒå°å
ĻéĻæ·ąåšĶïžčūūå°å·Ĩå
·č°įĻéĒįŪïžïž"agent reverse-audit (round 2)"ïžcould not execute a GFM/Prettier render of docs/design/2026-10-07-managed-agent-actor-roles.md lines 49-53 â no node_modules in this worktree (no prettier binarâĶïž"agent reverse-audit (round 1)"ïžbyte-exact regeneration check â openapi-typescript is not installed in the review worktree (no node_modules ), so managed-agent-api.test.ts 's toBe(await râĶïž"agent reverse-audit (round 3)"ïždid not execute the managed-agent-server suite, so section 7 Slice C's "updated probes and contract tests pin the new matrix" stays unverified for ManagedAgentâĶïž"agent reverse-audit (round 2)"ïžsection 8's "Full managed-agent-server suite green on H2" â I test-compiled the module clean offline ( mvn -o -q test-compile , exit 0) but could not establish âĶã
æŠåŪĄæĨïžåååŪĄčŪĄââčŊåŪĄæķéīéĒįŪäļčķģïžæŠč―åžå§įŽŽ 4 č―Ūã
[Critical] Re-check of a blocker already filed on this PR by the earlier triage round (comments 6027112673 and 6027112927) - STILL STANDS at 215999c. The base is still feat/13535-role-storage and the diff still re-adds all six files that #13543 also adds: git diff --name-status 7a6c52bd..HEAD reports A for both design docs, api/SurfaceRegistry.java, SurfaceAdmissionAcceptanceTest.java, SurfaceRegistryGateTest.java and SurfaceRegistryGateNegativeTest.java. Only two commits landed since that triage (aab53c1 a zh-CN matrix note, 215999c a registry javadoc qualifier), both documentation-only, so nothing about the stacking changed. Whichever of #13543 and #13545 merges second meets an add/add conflict on all six, and the description's 'this branch is based on feat/13535-role-storage so the diff shows only the enforcement slice' together with 'Design docs (EN/zh-CN) land with #13543' still describe a rebase that has not happened.
[Critical] Re-check of the same triage round's second blocker - STILL STANDS structurally at 215999c. .github/workflows/ci.yml filters pull_request on branches [main, release/, omni-experiment] and .github/workflows/sdk-java.yml on [main, release/], so with this base neither lane fires; the pre-submission check sees 3 checks and none of them is the Java test lane. The evidentiary half of that blocker is discharged by this review rather than by CI: the module was built and tested at this commit (mvn test -> Tests run: 1208, Failures: 0, Errors: 1, and the single error was measured identical at the merge base 7a6c52b, so it is pre-existing in a file this diff does not touch). What remains open is that the PR itself carries no CI signal, and HostedPublicWorkspaceIT plus the two MySQL ITs were never executed in this review because the failsafe profile needs MySQL and a bundled dist/cli.js.
â qwen3.8-max via Qwen Code /review (v0.25.0)
âĶyed execution facts The widened OPERATOR admission of the submitter family certified runs the execution authority still keys on the create-command actor, so a demoted creator meant an accepted 202 that could only fail. Admission now also requires the creator-keyed execution facts (registry ACTIVE and backing the binding, create-command actor keeps OPERATOR or above), synchronously from the service and the WebShell advertisement, and the cwd contract names the recorded actor at admission and settlement. Actor-scoped idempotency replays now run before any mutable role check on every family, so a role revoked after admission still resolves a retry to the callers own operation. The v1.34 contract and design docs state the new matrix truthfully, and the follow-up gaps are tracked: #13617 handover, #13618 legacy hardening, #13619 command-key actor scope.
Local verification â PR #13545 (Workspace actor roles enforcement, contract v1.34)Verdict:
äļææčĶįŧčŪš:
æ°æäšĪčŊäđæ ļåŪ: A/B įŧčŪš:åå åĨäŧķ head 1215 č·ã0 éįŊåĒåĪąčīĨ;base 1041;äļäļŠéčŊŊäļĪæ éåčåå(#13542 äļæŽæš ToolPublication æķåš)ãIT åŊđį §:base äļ reader æäšĪ 409â403ãoperator2 åŪĄæđåšį 403(åĄæŧ)ãoperator2 åįŧ Turn æäšĪ 409ââå ĻéĻåĻ head åįŧŋã æŠčĶį:Linux/Windows č ŋ(äļĪå°čŋįĻæšåĻ SSH å ŽéĨå§įŧæŠææ);MySQL failsafe profile;durableClose(macOS č·ģčŋ,Linux-only);runtime-broker å ĻéåĨäŧķ(æĻĄåæŠčĒŦč§Ķįǰ,åĒééå å·ēæ ļåŪäļšįĐš)ã Round-1 findings carried forward (re-measured at
|
| # | item (from triage stage-3 / round 1) | status at b9f90ebb |
|---|---|---|
| 1 | Land #13543/#13544, retarget to main |
stands, and grew: #13544 still open; trial merge now shows 7 conflicts (5 add/add from merged #13543 + 2 content conflicts in ManagedActionStore/ManagedAgentStore from main's #13260, #13174) |
| 2 | Show the acceptance/approval arms fail without the role checks | done â mutation matrix below (M1âē, M2, M4 etc.) |
| 3 | Missing positive witness: non-owner OPERATOR submit succeeds | fixed by author â committed IT arms (operator2-later/hold/cancel/rename â 202) now exist; independently pre-proven by my round-1 scratch arm (kept in artifacts) |
| 4 | Escape the §2 table pipes in both design docs | stands â still malformed at b9f90ebb (EN line 54, zh-CN line 30; mechanical scan, both files) |
| 5 | Consider one home for the OPERATOR threshold | stands â atLeast(OPERATOR) in service/store vs role IN ('OPERATOR','OWNER') in ManagedActionStore unchanged by the fix commit |
Central claim and A/B proof
Central claim (as amended by b9f90ebb): on the bound-Session surface, Turn submit/cancel/rename and cwd change admit any Workspace OPERATOR and certify the creator-keyed execution facts (registry ACTIVE and backing the binding, create-command actor still OPERATOR+); Action respond admits the recorded owner or any OPERATOR; lifecycle admits the recorded owner; actor-scoped idempotency replays precede the mutable role checks; refusal vocabulary 404/403/409 per v1.34.
Unit suite (managed-agent-server, mvn -B test, isolated .m2repo per tree)
| cell | tests | outcome |
|---|---|---|
head b9f90ebb |
1215 | 0 failures, 3 errors â all three byte-identical to base's pre-existing environmental failures |
base 7a6c52bd |
1041 | 0 failures, 3 errors (same three names) |
round-1 head 215999c8 |
1208 | same 3 + 1 load flake (HarnessCoordinatorTestâĶ[2], green 33/33 on isolated rerun; unrelated to this PR) |
Pre-existing error names on both trees: holdsRestorePagesInsideThePerPageByteBudget (the PR-declared #13542 break), ToolPublicationStoreTest.streamsLargeOutputAndReadsItsTailAfterStoreReplacement(Path), âĶrenewsTheOriginalClaimWhileScanningSlowObjectBytes (known macOS-local timing failures).
Witness suites at head, all green: SurfaceAdmissionAcceptanceTest 164/164 (the v1.34 refusal matrix), ManagedCwdChangeOperationTest 34/34 (incl. the new demotion/replay arms), Issue13181QueryBudgetTest 30/30 (role-advertised workspaceTurns, one fewer page query), SurfaceRegistryGateTest 3/3 + âĶNegativeTest 2/2 + âĶUnconstrainedTest 1/1 (the build gate), ManagedWorkspaceRolesMigrationTest 1/1 (V48 invariants). Web Shell: the two touched suites 84/84 green; generate:managed-agent-api produces zero drift; prettier clean.
HostedPublicWorkspaceIT â real signed HTTP, spawned CLI + server, H2
| test | HEAD (committed) | HEAD + one-line fix | BASE (same tests) |
|---|---|---|---|
ownerAnswersHostedApprovalsThroughBothSurfaces |
PASS (9.0s) | PASS | ERROR â operator2 respond 403 on base â Turn stuck RUNNING |
workspaceCwdChangeSettlesThroughBothSurfaces |
PASS | PASS | PASS |
publicCreationRunsFilesThroughProductionWorkspaceBinding |
ERROR (64.5s) â test bug F1 | PASS (9.3s) | FAIL â READER later-submit 409â403 flip |
durableCloseStopsOriginalWorkersAndRetainsHistoryAndFiles |
SKIP (macOS) | SKIP | SKIP |
Captures: 01-r2-suite-and-it.png (three-column cells), 04-r2-testbug-fix.png (the bug and its measured fix).
Mutation matrix @ b9f90ebb (single-point mutants, head tree)
| mut | guard removed | result | killed by |
|---|---|---|---|
| M1 | requireOwner workspace-role arm |
survived â method has no callers (F5) | â |
| M1âē | admit(): the live respond-gate role arm |
KILLED | secondOperatorAnswersPendingApprovalsOnBothSurfaces 202â403 |
| M2 | maySubmitWorkspaceTurn admission â false |
KILLED | 2 ManagedWorkspaceAdmissionTest rename tests (owner path) |
| M6 | = M2, driven through the committed full-stack IT | KILLED | operator2 later-Turn 202 arms |
| M7 | creator-keyed facts conjunct dropped | KILLED | the IT's demoted-creator arm: expected 409, got 202 (mut2-m7b.log; the first M7 run was masked by the F1 test bug, so it was re-run against the fixed IT â evidence discipline) |
| M3 | requireCwdChangeActor OPERATOR gate |
KILLED | ManagedCwdChangeOperationTest Ã3 |
| M4 | isSessionOwner lifecycle gate |
KILLED | refusal matrix, 8 probes flip 403â409 |
| M5 | CONTROL: corrupt the 409 code string | KILLED | 5 acceptance probes (harness liveness) |
Tree state after the matrix: production sources byte-identical to b9f90ebb. Capture: 02-r2-mutation-matrix.png.
Findings
F1 â the committed full-stack test cannot pass: operator2-cancel arm targets the wrong Turn (test bug, deterministic). In HostedPublicWorkspaceIT.runFiles, the cancel body is built once at L581 with turn_id = heldTurn â the owner's hold-turn, already cancelled and settled at L587â590. The new operator2 arm (L671â683) submits a second held turn (heldByOperator) but sends the stale map: the cancel lands on the already-CANCELLED owner turn (a no-op replay, 202), while the awaited heldByOperator stays RUNNING until the 35s awaitility cap (state dump at timeout: status=RUNNING, epoch/dispatch lease present â nothing ever requested its cancellation). Both callers hang identically (owner-cancel control run: same 64â68s ERROR), so it is the variable, not the role path. Untouched by environment: reproduces with zero concurrency. This means the PR's own "operator cancels a running later Turn" witness has never executed anywhere. Measured fix (kept as fix-operator2-cancel.patch):
Map<String, Object> cancelHeldByOperator = Map.of("type",
"agent.session.cancel", "turn_id", heldByOperator);
request("POST", "/v1/agents/sessions/" + session + "/events",
cancelHeldByOperator, "operator2-cancel-" + workspace, "operator2", 202);With exactly this change: single method PASS in 12.1s; whole IT class 4/4 green, BUILD SUCCESS (it-head-fixed.log). Zero collateral â no other arm's expectations move.
F2 â merge as filed is blocked (process, mechanically confirmed). Base branch feat/13535-role-storage is open PR #13544; the filed diff still carries the stacked slices (2,932 of 3,755 additions are the six #13543-overlapping files). Trial merge onto current main: 7 conflicts â 5 add/add (both design docs, SurfaceAdmissionAcceptanceTest, both gate tests; all from the merged #13543) + 2 content conflicts in ManagedActionStore.java and ManagedAgentStore.java (main moved under the base via #13260 and #13174). Post-resolution hazard: #13543 merged a test-tree api/SurfaceRegistry.java; this PR adds the main-tree class with the same FQN â the conflict resolution must delete the test-tree copy or the gate tests compile against a shadow. Neither ci.yml nor sdk-java.yml fires on this base (pull_request filters main/release/** only â confirmed in YAML and in the PR's check list). Capture: 03-r2-merge-tree.png.
F3 â ManagedActionStore.requireOwner is dead code at this head (nit). The fix commit moved respond admission into admit() (owner arms â replay â role arm) and left requireOwner with zero callers anywhere in packages/sdk-java (only two stale javadoc references in ManagedAgentApiContractTest comments). Its javadoc still claims it is "The responder gate". My M1 mutant removed its role arm and the full probe suite stayed green â nothing observes it. Delete it or re-point the comment.
F4 â design-doc §2 table still malformed in both languages (nit, carried). âĶactor-roles.md L54 and âĶzh-CN.md L30: the close | archive | unarchive cell's raw pipes render 6 cells against a 4-column header (mechanical pipe-count scan, both files).
Confirmed intent, not a defect: lifecycle stays Session-owner-only â a workspace-OWNER who is not the Session owner gets 403 (M4's kill proves enforcement). The stage-3 open question (can an OWNER be locked out of deleting a Session in their own workspace?) is a product call for v1.34, not an implementation bug.
Not covered
- Linux/Windows legs: the two offered LAN machines (192.168.0.54/.75) rejected the verifier's SSH key for the whole session (publickey denied), so macOS is the only execution leg; the Linux-only
durableCloseâĶarm was skipped everywhere it ran. - MySQL failsafe profiles (
hosted-harness-mysqlagainst real MySQL): not run; H2 MySQL-mode, matching the author's stated local setup. runtime-brokerfull suite: the module's input closure is untouched by the PR (re-verified empty atb9f90ebb); round-1 checkstyle/spotbugs gates on it were green and carry forward on that basis.- Per-commit attribution (verified as the aggregate
base..headdiff); the trial-merge tree (un-compilable until the 7 conflicts resolve); web-shell runtime UI behavior (types/latch logic covered by its vitest suites, no browser drive).
Methodology
Two detached worktrees at the metadata OIDs, isolated per-tree Maven repositories (clonefile-seeded). Round 2 re-measured every round-1 cell at the new head. The full-stack IT runs the real server in-JVM plus a spawned Node CLI harness and a loopback model server; the base cell ran the head version of the test file (its assertions are the post-v1.34 matrix, so base reds are the expected-failure control cells); the same dist/cli.js (built from head) served both arms â the PR touches no CLI production code. Mutations are single-point source edits applied/restored by script with per-cell targeted suites; M5 is the can-fail control. The test-bug diagnosis used three independent cuts: an owner-caller control (same hang â not actor-specific), a state dump at timeout (target turn never left RUNNING, no cancel requested against it), and the measured one-line fix. All raw logs, both mutation scripts, the probe test source, frozen failsafe XMLs (head committed / head+fix / base), and the fix patch are under tmp/pr13545-verify-20261007-224357/.
Evidence captures
-
01-r2-suite-and-it.pngâ A/B cells: unit suite, witness suites, HostedPublicWorkspaceIT (HEAD / HEAD+fix / BASE):
â unit-suite counts, witness suites, and the three-column IT table (HEAD / HEAD+fix / BASE). -
02-r2-mutation-matrix.pngâ Mutation matrix: every live guard pinned; the dead requireOwner exposed:
â eight mutation cells, incl. the dead-requireOwnerexposure and the M1âM1âē correction. -
03-r2-merge-tree.pngâ Trial merge onto main: 5 add/add + 2 content conflicts: -
04-r2-testbug-fix.pngâ F1: the wrong-turn_id cancel bug, timeout dump, measured one-line fix:
â F1's wrong-variable bug, the timeout state dump, and the measured fix.
Local maintainer verification requested by @wenshao. Round-1 head 215999c8 evidence is retained in the same artifact dir; every number above was re-measured at b9f90ebb. Nothing here approves or blocks the merge â the four findings are the actionable set.
qwen-code-review-bot
left a comment
There was a problem hiding this comment.
Partially reviewed â gaps disclosed.
Unresolved, please confirm:
- [Critical] Issue-level triage comment 6027112416 - the context render cut this body at the section budget and it was not fetched within this round's remaining time budget, so whether it asserts a blocker beyond the two triage blockers re-checked aboveâĶ
Not reviewed: build-and-test â the MySQL-backed integration lane never ran: hosted-harness-mysql (HostedPublicWorkspaceIT and the V48 migration ITs) needs a MySQL 8.4 service plus a bundled dist/cli.js, and no CI lane fires at all on this feature-branch base, so those findings are traced, not measured.
Not explored to full depth (tool budget reached): "agent reverse-audit (round 1)": dynamic execution of the three new SurfaceRegistryGate*Test classes and the rewritten boundWebShellPageBatchesTheRoleSubmitCapability â not run; mvn -o tesâĶ; "agent reverse-audit (round 1)": did not compile or run packages/sdk-java/managed-agent-server (Maven dependency resolution offline unverified), so every conclusion above is from source readiâĶ; "agent reverse-audit (round 2)": the zh-CN section-2 claim "įąåäļŠ Spring controller åŪį°" â my controller-count probe resolved a path outside the api package and returned 0; the per-surface routeâĶ; "agent reverse-audit (round 2)": did not open SurfaceAdmissionAcceptanceTest / the SSE-revocation test to confirm §7 Slice C's named probes ("second-operator answers a pending approval on botâĶ; "agent reverse-audit (round 1)": did not execute ManagedWorkspaceRolesMigrationTest or any Java suite â the V48 backfill, the CHECK-constraint rejections and the narrowed responder fall-throuâĶ, and 4 more.
Not reviewed: reverse audit â stopped before round 3 by the review time budget.
Not reviewed: "agent verify" â pointed at diff lines it never opened: it made tool calls, but none of them read the diff.
Deferred under the convergence posture (round 2, not a blocker) â recorded, not requested in this round:
docs/design/2026-10-07-managed-agent-actor-roles.md:87 â [probe] D1 defines the Workspace OWNER rank as "OPERATOR plusâĶdocs/design/2026-10-07-managed-agent-actor-roles.md:235 â [review] The RuleClass.OWNER arm of the acceptance walk fires noâĶdocs/design/2026-10-07-managed-agent-actor-roles.md:316 â [review] Section 6's deferral and open question 3 (line 374) bothâĶdocs/design/2026-10-07-managed-agent-actor-roles.zh-CN.md:18 â [review] §2 names the identity contract AuthenticatedActor , aâĶpackages/sdk-java/managed-agent-server/src/main/java/com/alibaba/qwen/code/managedagent/store/ManagedWorkspaceRegistry.java:70 â [review] This PR writes the "recorded Session owner" resolutionâĶpackages/sdk-java/managed-agent-server/src/test/java/com/alibaba/qwen/code/managedagent/SurfaceAdmissionAcceptanceTest.java:83 â [review] The class javadoc states the walk probes theâĶpackages/sdk-java/managed-agent-server/src/test/java/com/alibaba/qwen/code/managedagent/SurfaceAdmissionAcceptanceTest.java:1072 â [review] bodyFor ignores the probe actor, so the WebShellâĶpackages/sdk-java/managed-agent-server/src/test/java/com/alibaba/qwen/code/managedagent/api/SurfaceRegistryGateNegativeTest.java:11 â [review] TestConfiguration (line 11) and Bean (line 13) areâĶ
Mechanism health: this round did not close cleanly, so it withholds the incremental anchor â and the round it recovered had no anchor this round could use either â none at all, one with no certifier, one certified by an identity other than the one this round runs under, or one this round's fetch refused or resolved to the head â so the next review re-reads the whole diff unless recovery grafts an earlier own anchor that the round running it can use onto the complete work list this round leaves behind, and keeps doing so until a round's marker carries an anchor again or a graft lands that the round running it can use. (Stated, not acted on â this changes nothing about what the round posts.)
[Critical] Re-check of the blocker filed by the earlier triage round (comments 6027112673 / 6027112927) and re-asserted by round 1 - STILL STANDS at b9f90eb. The base is still feat/13535-role-storage and git diff --name-status 7a6c52bd..HEAD still reports A for all seven paths PR 13543 also added (both design docs, api/SurfaceRegistry.java, SurfaceAdmissionAcceptanceTest.java and the three SurfaceRegistryGate* classes). PR 13543 has since MERGED to main, and four of those paths now differ from origin/main while two are absent from it, so this branch merges second into an add/add conflict. The description half of the round-1 blocker is fixed - the body no longer promises a rebase that has not happened; it now states 13543 merged and that this PR retargets to main once 13544 lands. What remains open is that the retarget has not happened, so the conflict is still live at this head.
[Critical] Re-check of the same triage round's second blocker - STILL STANDS at b9f90eb. .github/workflows/ci.yml filters pull_request on branches [main, release/, omni-experiment] and .github/workflows/sdk-java.yml on [main, release/], so with a feature-branch base neither lane fires: gh pr checks 13545 lists only the review/assign/label/authorize jobs and no Java test lane, and gh run list --commit b9f90ebb shows five runs, all pull_request_target. The description now discloses this and names the retarget as what restores the lanes. The evidentiary half is discharged by this review rather than by CI: the module was built and tested at this commit (web-shell 412 files / 10900 tests green; managed-agent-server surefire 1214 tests with one error measured identical at the merge base, so pre-existing). What remains open is that the PR itself carries no CI signal, and HostedPublicWorkspaceIT plus the MySQL ITs were never executed here.
äļæčŊīæ
äŧ åŪæéĻååŪĄæĨïžåŪĄæĨįžšåĢå·ēæŦéēã
æŠåģïžčŊ·įĄŪčŪĪïžå ą 1 æĄïžåææŠįŋŧčŊïžåčĄĻč§äļæđčąæéĻåïžã
æŠåŪĄæĨïžåæäļščąæïžïžbuild-and-test â the MySQL-backed integration lane never ran: hosted-harness-mysql (HostedPublicWorkspaceIT and the V48 migration ITs) needs a MySQL 8.4 service plus a bundled dist/cli.js, and no CI lane fires at all on this feature-branch base, so those findings are traced, not measured.
æŠæĒįīĒå°å
ĻéĻæ·ąåšĶïžčūūå°å·Ĩå
·č°įĻéĒįŪïžïž"agent reverse-audit (round 1)"ïždynamic execution of the three new SurfaceRegistryGate*Test classes and the rewritten boundWebShellPageBatchesTheRoleSubmitCapability â not run; mvn -o tesâĶïž"agent reverse-audit (round 1)"ïždid not compile or run packages/sdk-java/managed-agent-server (Maven dependency resolution offline unverified), so every conclusion above is from source readiâĶïž"agent reverse-audit (round 2)"ïžthe zh-CN section-2 claim "įąåäļŠ Spring controller åŪį°" â my controller-count probe resolved a path outside the api package and returned 0; the per-surface routeâĶïž"agent reverse-audit (round 2)"ïždid not open SurfaceAdmissionAcceptanceTest / the SSE-revocation test to confirm §7 Slice C's named probes ("second-operator answers a pending approval on botâĶïž"agent reverse-audit (round 1)"ïždid not execute ManagedWorkspaceRolesMigrationTest or any Java suite â the V48 backfill, the CHECK-constraint rejections and the narrowed responder fall-throuâĶïžåĶæ 4 æĄã
æŠåŪĄæĨïžåååŪĄčŪĄââčŊåŪĄæķéīéĒįŪäļčķģïžæŠč―åžå§įŽŽ 3 č―Ūã
æŠåŪĄæĨïž"agent verify"ââåŊåĻ prompt äļšåŪæåŪäš diff äļįčĄïžä―åŪäŧæŠæåžïžæå·Ĩå
·č°įĻïžåīæēĄæäļæŽĄčŊŧå diffã
æķæå§ŋæäļåŧķåïžįŽŽ 2 č―Ūïžééŧæïžââå·ēčŪ°å―ïžæŽč―ŪäļčĶæąäŋŪæđïžå ą 8 æĄïžåææŠįŋŧčŊïžåčĄĻč§äļæđčąæéĻåïžã
æšåķåĨåš·ïžæŽč―ŪæŠč―åđēåæķå°ūïžå čæĢįäšåĒééįđïžčåŪæĒåĪå°įéĢäļč―ŪäđæēĄæįäļæŽč―ŪåŊįĻįéįđââčĶäđåŪå ĻæēĄæãčĶäđæēĄæčŪĪčŊč ãčĶäđįąæŽč―ŪčŋčĄčšŦäŧ―äđåĪįčšŦäŧ―čŪĪčŊãčĶäđčĒŦæŽč―Ūįč·åæįŧæč§ĢæäļšåĪīæäšĪââå æĪäļäļæŽĄčŊåŪĄå°éčŊŧæīäļŠ diffïžéĪéæĒåĪæĩįĻææŽč―Ūč―ä―ŋįĻįæīæĐčŠæéįđåŦæĨå°æŽč―ŪįäļįåŪæīå·Ĩä―æļ åäļïžåđķäžäļįīåĶæĪïžįīå°æäļč―Ūįæ čŪ°éæ°åļĶäļéįđïžæč―å°įåŦæĨč―čĒŦčŋčĄčŊĨč―ŪįčŊåŪĄä―ŋįĻãïžäŧ éčŋ°ïžäļæŪæĪčĄåĻââčŋäļæđåæŽč―Ūååļįäŧŧä―å åŪđãïž
[Critical] Re-check of the blocker filed by the earlier triage round (comments 6027112673 / 6027112927) and re-asserted by round 1 - STILL STANDS at b9f90eb. The base is still feat/13535-role-storage and git diff --name-status 7a6c52bd..HEAD still reports A for all seven paths PR 13543 also added (both design docs, api/SurfaceRegistry.java, SurfaceAdmissionAcceptanceTest.java and the three SurfaceRegistryGate* classes). PR 13543 has since MERGED to main, and four of those paths now differ from origin/main while two are absent from it, so this branch merges second into an add/add conflict. The description half of the round-1 blocker is fixed - the body no longer promises a rebase that has not happened; it now states 13543 merged and that this PR retargets to main once 13544 lands. What remains open is that the retarget has not happened, so the conflict is still live at this head.
[Critical] Re-check of the same triage round's second blocker - STILL STANDS at b9f90eb. .github/workflows/ci.yml filters pull_request on branches [main, release/, omni-experiment] and .github/workflows/sdk-java.yml on [main, release/], so with a feature-branch base neither lane fires: gh pr checks 13545 lists only the review/assign/label/authorize jobs and no Java test lane, and gh run list --commit b9f90ebb shows five runs, all pull_request_target. The description now discloses this and names the retarget as what restores the lanes. The evidentiary half is discharged by this review rather than by CI: the module was built and tested at this commit (web-shell 412 files / 10900 tests green; managed-agent-server surefire 1214 tests with one error measured identical at the merge base, so pre-existing). What remains open is that the PR itself carries no CI signal, and HostedPublicWorkspaceIT plus the MySQL ITs were never executed here.
â qwen3.8-max via Qwen Code /review (v0.25.0)
|
@qwen-code /resolve |
wenshao
left a comment
There was a problem hiding this comment.
åĒéåĪéŠåŪæïžåšäšææ° head ffd7b2255902096c593a9ebc413cfe95930acfcbïžåšįšŋ 4a3b8f3c084a1aa82af6cd75684f26123cdc64beïžã
äļč―Ū P2 å·ēäŋŪåĪïžæŽč―Ūæ°åĒå·ŪåžæŠåį°æ°įåŊæĨåéŪéĒã a3022f13 æĒåĪį generation čŠåĻæĨįŪĄäļ rename čŊīæãSurfaceRegistry čŊīæãbig-output å W1c čŋį§ŧæŪĩč―åäļå―ååšįšŋéåäļčīãåå
âåŋ
éĄŧéåŊ JavaâįéčŊŊčŊīæå·ēå éĪïžäŋŪåĪæēĄæčĒŦåįŧååđķčĶįã
æŽč―ŪéįđåĪæĨäšäļŧåđēååđķåįåŪæīæ§ïžč§čēįäš§éŧčūį PR å·Ūåžåŧķįŧäļč―ŪåŪį°ïžactor-key čŋį§ŧč°æīäļš V56ïžäŋįäļŧåđē V55 channel čŋį§ŧïžåĨįšĶæīæ°äļš v1.37ïžåŪæīäŋįäļŧåđē 58 æĄ OpenAPI č·Ŋåūãå ĻéĻ schema åå·ēæ changelogãįæ TypeScript äļåĨįšĶäļčīã
éŠčŊįŧæïž
- æļ įæ§æåŧšäš§įĐåæ§čĄ Java åŪåæĩčŊïž325 éĄđéčŋïž0 åĪąčīĨ/éčŊŊ/č·ģčŋãčĶįæéįĐéĩãcwd åčĩ·č æĪæãWorkspace admissionãåĨįšĶ/č·Ŋįą gateãæĨčŊĒéĒįŪãæ°ååđķį channel service/contractïžäŧĨå generation æĨįŪĄæĩčŊãH2 æĨåŋįĄŪčŪĪ V55 channel â V56 actor-key åæååšįĻã
- WebShell éĄĩéĒãåŪĄæđ hookãAPI įąŧåįææĩčŊïž89 éĄđéčŋã
- Flyway 鿿̿Ĩïž56 äļŠčŋį§ŧįžå·ååŊäļïž
git diff --checkéčŋã
æŽč―ŪæēĄæåĻæŽå°éč· MySQL/Hosted čŋįĻįŦŊå°įŦŊïžäđæŠčŋčĄå ĻäŧæĩčŊãååļåïžCI į JavaãMariaDBãWebShell E2E įå·ēåŪææĢæĨåæ åĪąčīĨïžHosted process fault gates / MySQL 8.4 / Java 21 äŧåĻčŋčĄãPR äŧäļš OPENã
yiliang114
left a comment
There was a problem hiding this comment.
Reviewed head ffd7b2255902096c593a9ebc413cfe95930acfcb (base 4a3b8f3c084a1aa82af6cd75684f26123cdc64be) â the enforcement slice of #13535, now reconciled over current main (H4b #13550, H5b/H5c #13572, replay-floor #13621). No merge blocker found; approving.
What I re-verified on this head:
- The out-of-enum role read is now fail-closed:
accessOf,resolveForCreation,initiatorKeepsOperateandWorkspaceExecutionStoreall add therole IN ('READER','OPERATOR','OWNER')filter, with a settlement witness (settlementFailsClosedWhenTheInitiatorsStoredRoleIsOutOfEnum) and an admission witness. That closes the note from the previous round. - The actor-key migration is renumbered to V56 (V54 is #13550's lineage, V55 is #13572's channel instance binding), and the Flyway uniqueness check passes against main. Note for the merge window: V56 is co-claimed by seven other open PRs (#13526 #13530 #13554 #13598 #13642 #13654 #13682), so if one of them lands first this needs the same renumber dance the storage slice went through (V48ââĶâV53). Not a blocker here.
isSessionOwnerprecedence (owner_actor_keyâ create-command actor âcreator_actor_key) matches the design's owner-of-record resolution and the H4b child cases; the registry, design doc and contract now agree at v1.37 (openapiversion1.37.0; design acceptance says "Contract v1.37").- All 75 review threads are resolved; CI on this head is green apart from
delay-automatic-reviewstill pending.
Three non-blocking notes: the ownerRow null-contract nit is inline; SurfaceAdmissionAcceptanceTest still omits the positive-admission arm (expectAdmitted), so its walk catches a registration stronger than its handler but not a whole family declared weaker; and the PR body still says "contract v1.36" / "openapi version 1.36.0", while the head artifact is v1.37.0 (main's replay-floor took v1.36) â worth refreshing the body so the test plan matches the tree. None of these blocks merge.
| // back execution, so a demoted creator moves an answer to 409 | ||
| // rather than letting it be queued where the arbiter can never | ||
| // reach â whichever arm admitted the caller. | ||
| if (ownerRow.workspaceId() != null |
There was a problem hiding this comment.
Same non-blocking note as the previous round: the two admits helpers just above tolerate a null OwnerRow (session == null ? null : ..., session != null && ...), but this gate dereferences ownerRow.workspaceId() unconditionally. It is safe today because the FOR UPDATE existence probe earlier in this method throws when the Session row is gone, so ownerRow cannot be null here â ownerRow != null && ownerRow.workspaceId() != null && ... would just keep the gate self-consistent with the arms above.
qqqys
left a comment
There was a problem hiding this comment.
Critical-only pass at head ffd7b2255902096c593a9ebc413cfe95930acfcb. Comment, not approval: the two most load-bearing historical Criticals are verifiably fixed at this head, but five further round-2 Criticals and both round-1 Criticals could not be confirmed inside this run's budget, so the approve gate is not met.
Verified fixed at this head, in source
R2-1 â the submitter-family role gate moved behind the idempotency replay. This was the security-critical finding: if the mutable role check ran after the actor-unscoped replay, a revoked actor could still collect a recorded answer. It does not run after it. In ManagedAgentService.java, submit orders:
297: validateIdempotencyKey(idempotencyKey);
300: requireSubmitterRole(session, actorId);
304: Admission replay = replay(tenantId, SUBMIT, idempotencyKey, ...
306: if (replay != null) { dispatch(...); return response(replay); }
311: requireSubmitterFacts(session, actorId);
requireSubmitterRole (:959-967) tests the caller's live rank â workspaces.accessOf(...).atLeast(WorkspaceAccess.OPERATOR) â and precedes the replay, so a below-OPERATOR caller never reaches a recorded key. requireSubmitterFacts (:969-975) follows the replay, and the comment at :954-958 states the split deliberately: the facts gate "certifies new work only, so a recorded completed outcome always answers â a Workspace re-registration, a DRAINING row or a creator demotion must not retire it." Cancel keeps its own narrower rule in requireCanceller (:980-988), which requires OPERATOR plus the executable shape and re-checks no grants, consistent with the W2 semantics. The ordering is correct and the reason for it is documented at the site.
R1-30 â the "wrong" publication token was byte-identical to the real one, which made the refusal probes unable to fail. At this head SurfaceAdmissionAcceptanceTest.java:123-124 declares WRONG_TOKEN = "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", a fixed literal appearing once in the file, while the admitted token is issued per test at :954 by credentials.issue(tenant, "ws", session). The probes now pair genuinely distinct values â :966, :996, :1031 and :1241 send WRONG_TOKEN, :989 and :1006 send the issued token â so an issued HMAC and a 32-character q literal cannot collide and the refusal arm asserts something.
The V56 migration is safe. V56__managed_operation_actor_key.sql adds one nullable column and nothing else:
ALTER TABLE managed_agent_operation
ADD COLUMN actor_key VARBINARY(2048) NULL;with the header comment recording that pre-V56 rows stay NULL and settle on the creator-keyed facts alone. No backfill, no rewrite of existing rows, no data-loss path. I also checked the version namespace rather than trusting it: main currently tops out at V55__managed_channel_instance_binding.sql, and this head carries exactly one V56, so the renumbering the author describes did preserve main's V55. Flyway migration version uniqueness is green. One forward-looking note, not a finding against this PR: #13598 is open and also claims V56 (V56__managed_automation_ledger.sql), so whichever of the two merges second will need to renumber â the uniqueness gate runs against each PR's own merge base and cannot see the other branch today.
Not confirmed at this head
Five round-2 Criticals and both round-1 Criticals remain unruled by me:
- R2-4 â widening cwd-change admission from
requireWorkspaceCreatorto "any OPERATOR". This is the other authorization-widening question on the PR and I did not reach it: the cwd path is not inManagedAgentService.java, so tracing it needs the store and contract together. - R2-2, R2-5, R1-2 â the published responder contract for a bound Session with no owner record, the
changeSessionCwd"Errors in pipeline order" sentence, and the v1.34 contract sentence describing who cwd change admits. These are the mis-certification class: contract prose that does not match what the handler does. The contract is now v1.37 and the author reports main's 58 paths and all schemas preserved, but I did not read the sentences against the handlers. - R2-3 â the README cwd paragraph promising behaviour around "the initâĶ". Not read.
- R2-6 â the operator-cancel probe at
HostedPublicWorkspaceIT.java:675reusing thecancelpayload declared at:581, which can make the probe assert on the wrong request. Not read. - R1-1 â turn submit/cancel/rename admission certifying on the caller's OPERATOR role. R2-1's ordering verification covers the submit arm's role gate directly; I did not separately rule the cancel and rename arms.
I stopped on the short-circuit rule once unconfirmed blocking findings remained, rather than enumerating equivalent evidence for the two I had already closed.
Scope
Of ~2,000 added lines across 30 files I read the submit/cancel admission path and its two predicates, the wrong-token probes, the migration, and the version namespace. ManagedActionStore, ManagedAgentStore, ManagedWorkspaceRegistry, the web-shell ManagedSessionsPage and use-managed-actions changes, and the generated TypeScript client are unexamined by this pass. That is a scope statement, not a clean ruling on those areas. The prior approving pass at ba1e8d7e reports all review threads resolved and both bot CHANGES_REQUESTED verdicts sitting on superseded heads; resolved threads are not code, so I did not treat that as discharging the findings above.
CI at this head
Green: 23 checks succeeded â Test (ubuntu-latest, Node 22.x), Lint & Static, Integration Tests, both desktop shells, all four Java lanes, Hosted process fault gates / MySQL 8.4 / Java 21, Runtime Broker and Managed Agent MariaDB / Java 21, Real daemon E2E / Java 11, Flyway migration version uniqueness and the web-shell lanes â with only delay-automatic-review queued and no failures. Note the author's report at this head said the MySQL fault-gate lane was still running; it has since landed green.
Next step
Point at per-finding rulings for R2-2, R2-3, R2-4, R2-5, R2-6, R1-1 and R1-2 at this head â R2-4 above all, since it is the remaining authorization-widening question â or re-request review so they can be read against a settled commit. The two fixes I verified and the migration are good as they stand.
|
Verdict:
äļæįįŧčŪšïž
F6 įŧčïž
qqqys čŊåŪĄæŠč―įĄŪčŪĪį 7 æĄ CriticalïžæŽč―ŪįĻåŪæĩčĢåģïž
äđååį°įįķæïž
įŊåĒčŊīæïž Previous-finding status (re-measured at
|
| item | ruling | evidence |
|---|---|---|
| R2-4 | holds | cwd widened to OPERATOR, bounded by the creator facts and the V56 initiator re-check |
| R1-1 | holds | the cancel and rename arms |
| R2-5 | holds | the six pipeline orderings each answer in the contract's order (probe Q) |
| R1-2 | holds | the v1.37 cwd sentence matches the measured behaviour |
| R2-3 | holds | the README cwd paragraph matches the measured behaviour |
| R2-6 | fixed | the operator-cancel probe now targets its own Turns |
| R2-2 | stands | this is F6, above |
What changed since round 2, and what was re-measured
P = a3022f1, H = ffd7b22. The history between them:
- two merges of
main(feat(managed-agent): H5b/H5c channel runtime for the email reference adapter #13572 channel runtime, feat(managed-agent): add opt-in production replay-floor advancement for Session event retention (#12380) #13621 replay floor, and others); 84f3669.
git show --remerge-diff isolates the hand-written parts:
- contract version/changelog, docs, the V56 rename, and test text;
- 3 Java comment lines.
So the PR's own production logic is unchanged since b8f004f. main's production code under it moved, so the whole matrix was re-run, together with the upgrade from current main and the trial merge.
Follow-ups for main:
- F6, with the candidate above.
- F4: add
candidate-expect-admitted.patch. It still applies cleanly and still kills the R3 mutant. - yiliang114's
ownerRownull-safety nit. - V56 is now taken on
main. Seven open PRs that claimed it (fix(managed-agent): reconcile approval delivery and concurrent session titles #13682, feat(managed-agent): verify tool publications asynchronously #13654, feat(runtime-broker): add bounded retention for terminal JDBC history #13642, feat(managed-agent): H6b/H6c automation runtime for persistent definitions #13598, feat(managed-agent): Collect retired stream-capture tool outputs (#13534) #13554, feat(managed-agent): execute pinned AgentDefinition revisions #13530, fix(managed-agent): close the critical R2 review findings on #12692 #13325) must renumber, and ci(sdk-java): re-check open PRs for Flyway version collisions as main moves #13770's re-check will flag them.
Environment, not counted as a failure: ManagedAgentMySqlIT.admitsHookExecutionsWithoutReadingTheirHistoryOnMySql timed out at about 60.1 s ("writer grant is stale") at host load 30â80. main f20ed55 fails identically back to back, and CI's MariaDB lane runs it green.
Not covered:
- Windows.
- A live H4b child cascade. F6 uses a lineage-shaped row written the way
insertChildSessionCommandwrites one, not a relay-created child. - Fresh UI captures: the managed-panel code is unchanged since round 2.
Assets: pr13545/r3, with the ledger, raw cells, logs, rig and patches.
Main's #13545 moved cwd admission from creator identity to atLeast(OPERATOR) while this branch was in review. The capability predicate now mirrors exactly that: one role grant read covers the workspaces of the cwd- and Turn-shaped candidate union, the execution-facts read covers the union of both id sets, and the facts batch is skipped when the caller holds no OPERATOR grant â the same zero-query shape the submit path has. The OpenAPI entry becomes v1.38 (main took v1.37 for the roles slice). Capability tests move to the role vocabulary: a non-creator OPERATOR now sees cwdChange while a READER does not, and the no-facts-read cases run under a READER-only caller. Design docs record the convergence.
Textual auto-merge with #13545 concatenated this branch's fail-closed default methods with main's abstract declarations of the same two AgentStateStore methods, breaking compilation. Main's abstract declarations win: ManagedAgentStore is the only implementation and overrides both. The design docs' fail-closed-default note goes with the removed methods.
âĶmodel The field description still said the caller must be the Session creator, contradicting the role-based predicate shipped in the same diff; the WebShell design docs still recorded #13545 as open with a pre-rebase baseline. Both now match the converged role model, and the generated client is refreshed. The composeSignals fallback test also pins the hook-lifetime half of the composition, not just the caller signal. R1-2, R1-3, R1-22.
Main's #13545 moved cwd admission from creator identity to atLeast(OPERATOR) while this branch was in review. The capability predicate now mirrors exactly that: one role grant read covers the workspaces of the cwd- and Turn-shaped candidate union, the execution-facts read covers the union of both id sets, and the facts batch is skipped when the caller holds no OPERATOR grant â the same zero-query shape the submit path has. The OpenAPI entry becomes v1.38 (main took v1.37 for the roles slice). Capability tests move to the role vocabulary: a non-creator OPERATOR now sees cwdChange while a READER does not, and the no-facts-read cases run under a READER-only caller. Design docs record the convergence.
Textual auto-merge with #13545 concatenated this branch's fail-closed default methods with main's abstract declarations of the same two AgentStateStore methods, breaking compilation. Main's abstract declarations win: ManagedAgentStore is the only implementation and overrides both. The design docs' fail-closed-default note goes with the removed methods.
âĶmodel The field description still said the caller must be the Session creator, contradicting the role-based predicate shipped in the same diff; the WebShell design docs still recorded #13545 as open with a pre-rebase baseline. Both now match the converged role model, and the generated client is refreshed. The composeSignals fallback test also pins the hook-lifetime half of the composition, not just the caller signal. R1-2, R1-3, R1-22.
#13325) Merge origin/main's role/facts actor model (#13545) and re-express the replay-after-delete machinery on it: the visibility fence moves below the replay while the role gate (whose 404 arm is the read grant) stays above, and the creator half gates the replay arm on key presence, before the digest comparison can leak a live key to a non-creator. Renumber the created_at list index to V58 (main spent V56/V57) and extend the MariaDB upgrade canary to match. Case-fold the lock-order canary's SQL matching and pin the store's turn-row population exactly, with synthetic witnesses for a lowercase lock and a turn-only writer. Fold C0 controls and DEL to spaces in the WebShell titleFor and the channel bindRoute title derivation, so the server's control-character rejection no longer breaks either shipped caller.
Main's #13545 moved cwd admission from creator identity to atLeast(OPERATOR) while this branch was in review. The capability predicate now mirrors exactly that: one role grant read covers the workspaces of the cwd- and Turn-shaped candidate union, the execution-facts read covers the union of both id sets, and the facts batch is skipped when the caller holds no OPERATOR grant â the same zero-query shape the submit path has. The OpenAPI entry becomes v1.38 (main took v1.37 for the roles slice). Capability tests move to the role vocabulary: a non-creator OPERATOR now sees cwdChange while a READER does not, and the no-facts-read cases run under a READER-only caller. Design docs record the convergence.
Textual auto-merge with #13545 concatenated this branch's fail-closed default methods with main's abstract declarations of the same two AgentStateStore methods, breaking compilation. Main's abstract declarations win: ManagedAgentStore is the only implementation and overrides both. The design docs' fail-closed-default note goes with the removed methods.
âĶmodel The field description still said the caller must be the Session creator, contradicting the role-based predicate shipped in the same diff; the WebShell design docs still recorded #13545 as open with a pre-rebase baseline. Both now match the converged role model, and the generated client is refreshed. The composeSignals fallback test also pins the hook-lifetime half of the composition, not just the caller signal. R1-2, R1-3, R1-22.
* feat(web-shell): support managed session cwd changes Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * feat(managed-agent): advertise WebShell cwd change capability Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * chore(managed-agent): consolidate W2 WebShell delivery Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(web-shell): compose abort signals without AbortSignal.any below Chrome 116 refreshSummary composed the caller signal with the hook lifetime via an unconditional AbortSignal.any, which is Chrome 116 / Safari 17.4 while the package floor is Chrome 111 / Safari 16.4. On those browsers a successful cwd change threw TypeError on the completion readback, was booked as unconfirmed, and left the composer locked for the lifetime of the tab. Mirror the composeAbortSignals feature-detect from acpTransportUtils and rebase onto main: the cwdChange capability becomes OpenAPI v1.36 (v1.34 is reserved for actor roles, v1.35 landed first). * refactor(managed-agent): address triage nits - managed.cwd.unconfirmedForbidden now tells the user sending stays blocked until the server settles the operation or a new tab is opened. - cwdShaped collects to HashSet explicitly since retainAll mutates it; Collectors.toSet makes no mutability promise. - Drop the never-read cwd field from ManagedSessionCwdControl basis state. * fix(web-shell): repair CI after rebase Prettier rejected the conflict-resolved OpenAPI JSON (the closing brace stayed glued to the description line), and the transcript entry grew past its byte ceiling: main measures 1,320,579 and this branch 1,323,120 against a 1,323,000 gate. The growth is the cwd slice's shared i18n strings; no interactive cwd code enters the transcript graph. Raise the ceiling to 1,324,000 with the measurements recorded, matching the gate's documented ratchet practice. * chore(managed-agent): renumber cwd capability to OpenAPI v1.37 Main took v1.36 for the replay-floor pass (QwenLM#13621) while this branch was in review, so the cwdChange capability moves to v1.37 and the design docs follow. Also drop the pre-rebase SHA from the size-gate docblock; the measurement is unchanged at 1,323,120 on the rebased branch. * feat(managed-agent): converge cwd capability on the QwenLM#13545 role model Main's QwenLM#13545 moved cwd admission from creator identity to atLeast(OPERATOR) while this branch was in review. The capability predicate now mirrors exactly that: one role grant read covers the workspaces of the cwd- and Turn-shaped candidate union, the execution-facts read covers the union of both id sets, and the facts batch is skipped when the caller holds no OPERATOR grant â the same zero-query shape the submit path has. The OpenAPI entry becomes v1.38 (main took v1.37 for the roles slice). Capability tests move to the role vocabulary: a non-creator OPERATOR now sees cwdChange while a READER does not, and the no-facts-read cases run under a READER-only caller. Design docs record the convergence. * fix(managed-agent): drop duplicate registry-facts interface declarations Textual auto-merge with QwenLM#13545 concatenated this branch's fail-closed default methods with main's abstract declarations of the same two AgentStateStore methods, breaking compilation. Main's abstract declarations win: ManagedAgentStore is the only implementation and overrides both. The design docs' fail-closed-default note goes with the removed methods. * fix(web-shell): release a parked cwd intent on definitive replay refusals A lost-ACK intent has no operationId, so Confirm is the only way out â but definitive was gated on initialSubmission, so a confirm replay could never classify a refusal as final and the composer stayed locked for the tab's lifetime. The store's actor-scoped idempotency lookup runs before the role, revision and busy gates, so a 4xx behind it proves the original submit was never recorded. Drop the initialSubmission conjunct and release with the real refusal code; 401 and the pre-lookup read-visibility 404 stay non-definitive (they prove nothing about recording), as do transient 408/429. The query path starts accepted=true, so transient mid-poll refusals still retain an admitted operation's intent. R1-12. * docs(managed-agent): align the cwdChange contract text with the role model The field description still said the caller must be the Session creator, contradicting the role-based predicate shipped in the same diff; the WebShell design docs still recorded QwenLM#13545 as open with a pre-rebase baseline. Both now match the converged role model, and the generated client is refreshed. The composeSignals fallback test also pins the hook-lifetime half of the composition, not just the caller signal. R1-2, R1-3, R1-22. * chore(managed-agent): renumber cwd capability to OpenAPI v1.39 Main took v1.38 for the automation runtime (QwenLM#13598); the cwdChange entry moves to v1.39 and the design docs follow. Transcript entry measures 1,323,162 against the 1,324,000 gate on the rebased branch. * codex: address PR review feedback (QwenLM#13760) * codex: address PR review feedback (QwenLM#13760) --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
Released in v0.25.1. |






What this PR does
Enforces the Workspace actor roles across the bound-Session surface (contract v1.36), advancing #13535. On top of the registry slice and the role-storage slice, the three former creator checks become role/owner checks: Turn submit, cancel, rename and cwd change now admit any caller holding OPERATOR on the bound Workspace â under the unchanged shape gates and while the Session's creator-keyed execution facts hold (the Registry still backs the binding and stays ACTIVE, and the actor recorded by the Workspace create command keeps OPERATOR or above), because the admitted work executes under the creator's grants; crossing that line answers the family's domain 409
workspace_unavailablesynchronously at admission instead of returning a 202 for a Turn that could only fail asynchronously. Approval (Action) respond admits the Session's recorded owner or any OPERATOR, under no shape gate â so a second operator on the same Workspace can now answer a pending approval that blocks a Turn, the product behaviour the issue names as blocked. Close/archive/unarchive/delete admit the Session's recorded owner (owner_actor_key, with the pre-V40 creator/create-command fallback). The refusal vocabulary normalises to the #12867 contract: below the read grant answers 404 (session_not_found, invisible as before); a readable actor below OPERATOR answers 403session_operation_forbiddenon the submitter family (was 409), 403action_forbiddenon respond. The WebShellworkspaceTurnscapability mirrors server admission exactly: caller OPERATOR plus the same creator-keyed facts; the page's former create-command batch read becomes a creator-facts batch read, so the page stays a constant number of queries (pinned byIssue13181QueryBudgetTest). The surface registry flips cwd and Action respond OWNERâOPERATOR with the enforcement, its probes pin the new matrix on both surfaces, the contract changelog records v1.36, and the generated TypeScript types are regenerated.Deliberately preserved: legacy (unbound) Sessions stay tenant-wide; execution (
authorizePassiveAttachment) and cwd settlement still re-verify the recorded creator's grant set â execution authority semantics are unchanged, and admission now certifies the same facts synchronously on every family that runs under them; a cwd operation admitted before its initiator's own demotion still commits (the operation row storesactor_digest, not the actor key â the W2 revocation sentence is scoped to the recorded actor, documented in contract text and the design); legacy open-mode Action answering stays tenant-owned for unbound Sessions only; internal writer routes are untouched.Why it's needed
#13535's R1: every bound-Session operation admitted only its creator, so a Hosted approval could only be answered by the Session's creator (a second operator could not unblock a Turn) and nothing could express an owner distinct from the creator. #12867 section 10 fixed the vocabulary (reader/operator/owner, 404-below-read/403-below-operate); this PR enforces it per route and flips the registry it landed on, under the build gate that makes future routes unable to skip the check.
R1 review round (this push)
The round-1 review's two Criticals and 32 Suggestions are resolved; each thread carries a reply naming the code/test that addresses it. Headline changes since the reviewed head:
hasExecutionRegistryFacts/ batchedsessionsWithExecutionRegistryFacts), so a demoted creator means a synchronous 409 rather than an accepted Turn that asynchronously dies in the execution authority.HostedPublicWorkspaceITpins the IT acceptance (second OPERATOR: 409, no PENDING row, no model request, no tool execution) and the headline widening end to end (a non-creator OPERATOR submits a later Turn and it executes, cancels, and renames).ManagedCwdChangeOperationTest.settlementKeepsAnAdmittedChangeWhenOnlyTheInitiatorDroppedand the design's D4 note).aDemotedOperatorStillReplaysTheirAdmittedChange;requireOwnersplit into identity/role arms with the role arm after the replay).publicationTokenDecidesThroughTheStoredGrantComparisonand receipts/commit 403; unconditional null-actor probes; method-agnostic@RequestMappingfails the gate (SurfaceRegistryGateUnconstrainedTest); the dual-purpose events route's ordinal-first capability;operatorAnswered.hasSize(2)in the approvals IT; the WebShell forbidden latch now survives Session navigation but re-probes on retry, with EN/zh strings matching the server's rule.Deferred deliberately, now tracked: #13617 (Session handover command), #13618 (legacy-Session hardening), #13619 (submitter-family command idempotency actor scope).
Reviewer Test Plan
How to verify
With JDK 21 and Maven 3.9+:
mvn -q -DskipTests installinpackages/sdk-java/runtime-broker, thenmvn -B testinpackages/sdk-java/managed-agent-server. Key witnesses: (1)SurfaceAdmissionAcceptanceTestâ the full post-v1.36 matrix including OWNER-rank arms and null-actor probes, plussecondOperatorAnswersPendingApprovalsOnBothSurfaces; (2)ManagedCwdChangeOperationTestâ creator-only demotion â 409 at admission, initiator demotion â committed settlement, demoted-operator replays; (3)HostedPublicWorkspaceIT(real signed HTTP) â non-creator OPERATOR executes a later Turn, 409 when only the creator is demoted,operatorAnswered.hasSize(2); (4)Issue13181QueryBudgetTestâ constant page queries with the new facts batch; (5)SurfaceRegistryGateTest+âĶNegativeTest+âĶUnconstrainedTestâ the gate fails close on unregistered, handler-less, and method-agnostic routes; (6)ManagedWorkspaceAdmissionTest.aPreV40BoundSessionFallsBackToTheCreateCommandOwner. Cross-check the contract: openapiversion1.36.0 with the v1.36 changelog sentence;packages/web-shellnpm run generate:managed-agent-apiproduces no drift;use-managed-actions.test.tsxcovers the retry re-probe.Evidence (Before & After)
Before: submitter family readable non-creator â 409
workspace_unavailable; approval respond limited to the creator (403action_forbidden); cwd limited to the creator (403). After: any OPERATOR admitted on all three families while the creator-keyed facts hold; readable-below-OPERATOR â 403 on all three; owner keeps lifecycle exactly as the creator had it; a demoted creator stops the widened family synchronously with 409 instead of an async failure. The acceptance-probe diff in this PR is the human-readable before/after matrix.Tested on
Environment (optional)
JDK 21 (Zulu 21.0.11), Maven 3.9.11, H2 MySQL-mode; suites: runtime-broker green; managed-agent-server full suite green â 1404 passed, 0 failures (1 pre-existing skip).
mvn checkstyle:check spotbugs:checkgreen on both modules. Hosted MySQL failsafe profiles left to CI (the local harness environment cannot warm a runtime â the IT aborts atruntime_warmbefore the first Turn, independent of this diff).Risk & Scope
actor_manager), MySQL profiles locally.rolecolumn whose hardened backfill relabelscan_read/can_createunder the single-version doctrine); this PR adds only V56 (managed_agent_operation.actor_key, NULL grandfathering pre-V54 rows); contract v1.36 refusal-code normalisation above.Linked Issues
Refs #13535 â this PR delivers the vocabulary enforcement it names (second-operator approval handoff through the role column, plus route-level role checks and owner records driving every former creator check); the two behaviours it defers land as #13617 (Session handover command) and #13618 (legacy-Session hardening). Also resolves #12867's roles follow-up vocabulary enforcement (Q4 answered in the design doc). The submitter-family command idempotency gap the review surfaced is tracked as #13619.
Stacked delivery for #13535: #13543 (surface registry + gate, R2, merged) and #13544 (V53 role storage, merged) precede this PR; with #13544 merged this PR is retargeted to
mainand the CI lanes run again (the feature-branch base had matched nopull_requestbranch filter). Design docs:docs/design/2026-10-07-managed-agent-actor-roles.{md,zh-CN.md}.äļæčŊīæ
æŽ PR åäŧäđ
åĻįŧåŪ Session éĒäļåžšåķæ§čĄ Workspace actor č§čēïžåĨįšĶ v1.36ïžïžæĻčŋ #13535ãåĻæģĻåčĄĻåįäļč§čēååĻåįäđäļïžäļäļŠåååŧšč æ ĄéŠåäļšč§čē/owner æ ĄéŠïžTurn æäšĪãåæķãæđåäļ cwd åæīį°åĻåå Ĩäŧŧä―åĻčŊĨ Workspace ææ OPERATOR įč°įĻæđ ââ å―ĒæéĻäļåïžäļ Session įååŧšč éŪæ§čĄäšåŪåŋ éĄŧæįŦïžRegistry äŧæŊæčŊĨįŧåŪåđķåĪäš ACTIVEïžWorkspace ååŧšå―äŧĪčŪ°å―į actor äŋæ OPERATOR åäŧĨäļïžïžå äļščĒŦåå Ĩįå·Ĩä―äŧĨååŧšč įæææ§čĄïžčķčŋčŋæĄįšŋåĻåå ĨæķåæĨåįæįååįš§ 409
workspace_unavailableïžčäļæŊįŧäļäļŠåŠäžåžæĨåĪąčīĨį Turn čŋå 202ãåŪĄæđïžActionïžåįåå Ĩé Session įå·ēčŪ°å― owner æäŧŧä― OPERATORïžäļæå―ĒæéĻ ââ åäļ Workspace äļįįŽŽäšäļŠ operator į°åĻč―åįéŧåĄ Turn įåū įåŪĄæđïžåģ issue įđåčĒŦéŧåĄįäš§åčĄäļšãclose/archive/unarchive/delete åå Ĩ Session įå·ēčŪ°å― ownerïžowner_actor_keyïžåļĶ V40 äđåį creator/create-command åéïžãæįŧčŊčĄĻå―äļå° #12867 åĨįšĶïžä―äščŊŧææåį 404ïžsession_not_foundïžäļåŊč§æ§äļåïžïžåŊčŊŧä―ä―äš OPERATOR į actor åĻ submitter æåį 403session_operation_forbiddenïžåäļš 409ïžïžåĻåįč·Ŋįąäļš 403action_forbiddenãWebShellworkspaceTurnsč―åįēūįĄŪéåæåĄįŦŊåå Ĩïžč°įĻæđ OPERATOR å äļåæ ·įååŧšč éŪäšåŪïžéĄĩéĒåæĨį create-command æđéčŊŧåæĒæååŧšč äšåŪæđéčŊŧåïžæĨčŊĒæ°äŋæåļļéïžIssue13181QueryBudgetTestéä―ïžãsurface æģĻåčĄĻéæ§čĄæ cwd äļ Action respond äŧ OWNER įŋŧå° OPERATORïžæĒéåĻäļĪäļŠéĒäļéä―æ°įĐéĩïžåĨįšĶ changelog čŪ°å― v1.36ïžįæį TypeScript įąŧåå·ēéæ°įæãåŧæäŋæäļåïžlegacyïžæŠįŧåŪïžSession äŋæį§æ·įš§ïžæ§čĄïž
authorizePassiveAttachmentïžäļ cwd įŧįŪäŧåĪæ ļå·ēčŪ°å―ååŧšč įææéå ââ æ§čĄæčŊäđäļåïžčåå Ĩį°åĻåĻæŊæĄäŧĨčŊĨæææ§čĄįæäļåæĨæ äŋåäļįŧäšåŪïžåčĩ·č æŽäššåå ĨåčĒŦéįš§į cwd æä―äŧäžæäšĪïžæä―čĄåŠåactor_digestââ W2 æĪéåĨįéįĻčåīéåŪäļščŊĨčŪ°å― actorïžåĨįšĶææŽäļčŪūčŪĄåå·ēåæïžïžlegacy åžæūæĻĄåžį Action åįäŧ åŊđæŠįŧåŪ Session äŋæį§æ·å ąæïžå éĻ writer č·ŊįąäļåĻãäļšäŧäđéčĶ
#13535 į R1ïžčŋäŧäļšæĒæŊäļŠįŧåŪ Session æä―åŠåå Ĩååŧšč ïžå æĪ Hosted åŪĄæđåŠč―įą Session ååŧšč åįïžįŽŽäšäļŠ operator æ æģč§ĢéĪéŧåĄį TurnïžïžäđæēĄæäŧŧä―äļčĨŋč―čĄĻčūūäļååŧšč äļåį ownerã#12867 įŽŽ 10 čéäļäščŊčĄĻïžreader/operator/ownerïžä―äščŊŧč 404ãä―äšæä―č 403ïžïžæŽ PR éč·Ŋįąåžšåķæ§čĄåŪïžåđķįŋŧč―Žå ķč―å°įæģĻåčĄĻïžį―Ūäšä―ŋæŠæĨč·Ŋįąæ æģįŧčŋæ ĄéŠįæåŧšéĻįĶäđäļã
R1 čŊåŪĄč―ŪïžæŽæŽĄæĻéïž
įŽŽäļč―ŪčŊåŪĄį 2 æĄ Critical äļ 32 æĄ Suggestion å·ēåĪį―ŪïžéæĄ thread æååĪčŊīææŋč――įäŧĢį /æĩčŊãįļåŊđčĒŦčŊåŪĄåĪīįåĪīæĄååïž
hasExecutionRegistryFactsäļæđésessionsWithExecutionRegistryFactsïžïžååŧšč čĒŦéįš§åģåæĨ 409ïžäļååšį°čĒŦæĨååīæģĻåŪåĻæ§čĄææåĪåžæĨæŧæį TurnãHostedPublicWorkspaceITéä― IT éŠæķïžįŽŽäšäļŠ OPERATORïž409ãæ PENDING čĄãæ æĻĄåčŊ·æąãæ å·Ĩå ·æ§čĄïžäļåĪīæĄæūåŪ―įįŦŊå°įŦŊïžéååŧšč OPERATOR æäšĪåįŧ Turn åđķįæĢæ§čĄïžéååæķäļæđåïžãManagedCwdChangeOperationTest.settlementKeepsAnAdmittedChangeWhenOnlyTheInitiatorDroppedäļčŪūčŪĄ D4 æģĻéä―ïžãaDemotedOperatorStillReplaysTheirAdmittedChangeïžrequireOwneræäļščšŦäŧ―č/č§čēčïžč§čēčåĻéæūäđåïžãpublicationTokenDecidesThroughTheStoredGrantComparisonäļ receipts/commit 403ïžæ actor įå ĻįĻæĒéïžæđæģæ å ģ@RequestMappingä―ŋéĻįĶåĪąčīĨïžSurfaceRegistryGateUnconstrainedTestïžïžåįĻé events č·ŊįąįéĶäļŠ capability æčĻïžapprovals IT įoperatorAnswered.hasSize(2)ïžWebShell æįŧ latch č·Ļ Session åŊžčŠäŋæãæūåž retry æķéæĒïžEN/zh ææĄäļæåĄåĻč§åäļčīãææåŧķååđķå·ēįŦéĄđïž#13617ïžSession į§ŧäšĪå―äŧĪïžã#13618ïžlegacy Session æķįī§ïžã#13619ïžsubmitter æå―äŧĪåđįéŪį actor åïžã
čŊåŪĄæĩčŊčŪĄå
åĶä―éŠčŊ
JDK 21 äļ Maven 3.9+ïžåĻ
packages/sdk-java/runtime-brokeræ§čĄmvn -q -DskipTests installïžįķååĻpackages/sdk-java/managed-agent-serveræ§čĄmvn -B testãå ģéŪč§čŊïžïž1ïžSurfaceAdmissionAcceptanceTestââ v1.36 åå ĻįĐéĩïžOWNER įš§č§čēčãæ actor æĒéïžåsecondOperatorAnswersPendingApprovalsOnBothSurfacesïžïž2ïžManagedCwdChangeOperationTestââ äŧ ååŧšč éįš§ â åå Ĩ 409ïžåčĩ·č éįš§ â įŧįŪäŧæäšĪïžéįš§ operator įéæūïžïž3ïžHostedPublicWorkspaceITïžįåŪįūå HTTPïžââ éååŧšč OPERATOR æ§čĄåįŧ Turnïžäŧ ååŧšč éįš§æķ 409ïžoperatorAnswered.hasSize(2)ïžïž4ïžIssue13181QueryBudgetTestââ æ°äšåŪæđæŽĄäļéĄĩéĒæĨčŊĒæ°åļļéïžïž5ïžSurfaceRegistryGateTest+âĶNegativeTest+âĶUnconstrainedTestââ æŠæģĻåãæ handlerãæđæģæ å ģč·ŊįąäļčååĪąčīĨå ģéïžïž6ïžManagedWorkspaceAdmissionTest.aPreV40BoundSessionFallsBackToTheCreateCommandOwnerãæ ļåŊđåĨįšĶïžopenapiversionäļš 1.36.0 äļåļĶ v1.36 changelog åĨïžpackages/web-shellįnpm run generate:managed-agent-apiæ æžį§ŧïžuse-managed-actions.test.tsxčĶį retry éæĒãčŊæŪïžåååŊđį §ïž
äđåïžsubmitter æåŊčŊŧéååŧšč â 409
workspace_unavailableïžåŪĄæđåįäŧ éååŧšč ïž403action_forbiddenïžïžcwd äŧ éååŧšč ïž403ïžãäđåïžååŧšč éŪäšåŪæįŦæéīäļäļŠæé―åå Ĩäŧŧä― OPERATORïžåŊčŊŧä―ä―äš OPERATOR â äļäļŠæé― 403ïžowner åæ ·äŋæååŧšč æūæįįå―åĻæïžååŧšč čĒŦéįš§ä―ŋæūåŪ―åįæåæĨ 409 čäļæŊåžæĨåĪąčīĨãæŽ PR äļéŠæķæĒéį diff å°ąæŊåŊčŊŧįååįĐéĩãæĩčŊåđģå°
macOS â ïžWindowsâ ïļ ïžLinux â ïļ ã
įŊåĒïžåŊéïž
JDK 21ïžZulu 21.0.11ïžïžMaven 3.9.11ïžMySQL æĻĄåž H2ïžåĨäŧķïžruntime-broker įŧŋïžmanaged-agent-server å ĻåĨįŧŋ ââ 1404 éčŋã0 åĪąčīĨïž1 äļŠæĒæč·ģčŋïžã
mvn checkstyle:check spotbugs:checkäļĪæĻĄåįŧŋãHosted MySQL failsafe profile äšĪįŧ CIïžæŽæš harness įŊåĒæ æģéĒį runtime ââ IT åĻéĶäļŠ Turn åįruntime_warmåĪäļæĒïžäļæŽ diff æ å ģïžãéĢéĐäļčåī
actor_managerïžãæŽæš MySQL profileãroleåïžįĄŽåååĄŦåĻåįæŽįšŠåūäļæķįžcan_read/can_createïžïžæŽ PR åŠæ°åĒ V56ïžmanaged_agent_operation.actor_keyïžNULL åéčĄį §æ§įŧįŪïžïžäļčŋ°åĨįšĶ v1.36 æįŧį å―äļãå ģč issue
Refs #13535 ââ æŽ PR äšĪäŧå ķäļįđåįčŊčĄĻåžšåķæ§čĄïžįŧč§čēååŪį°įįŽŽäš operator åŪĄæđäšĪæĨïžäŧĨåéč·Ŋįąįč§čēæ ĄéŠäļéĐąåĻæŊäļŠåååŧšč æ ĄéŠį owner čŪ°å―ïžïžåŪåŧķåįäļĪéĄđčĄäļšååŦč―å°äļš #13617ïžSession į§ŧäšĪå―äŧĪïžäļ #13618ïžlegacy Session æķįī§ïžãåæķč§Ģåģ #12867 įč§čēåįŧčŊčĄĻåžšåķæ§čĄïžQ4 å·ēåĻčŪūčŪĄææĄĢåįïžãčŊåŪĄæīéēį submitter æå―äŧĪåđįįžšåĢč·čŋäļš #13619ã
#13535 įå å äšĪäŧïž#13543ïžsurface æģĻåčĄĻ + éĻįĶïžR2ïžå·ēåå Ĩïžäļ #13544ïžV53 č§čēååĻïžå·ēåå Ĩïžå čĄïž#13544 åå ĨåæŽ PR å·ēéåŪåå°
mainïžCI ééå·ēæĒåĪïžæĪåįđæ§åæŊ base äļåđé äŧŧä―pull_requeståæŊčŋæŧĪïžãčŪūčŪĄææĄĢïždocs/design/2026-10-07-managed-agent-actor-roles.{md,zh-CN.md}ãReview disposition and post-merge audit (2026-10-09)
R1 (34 threads) was dispositioned at
b9f90eb; R2 (38 threads) is fully dispositioned across8c1db10,3c646ffand the audit-pass commitsbf93110âba1e8d7: every thread carries an inline reply naming its fix and its witness, and all 72 threads are resolved. Themainmerge had silently dropped five pre-existingManagedCwdChangeOperationTestarms (retained-runtime Ã2, migration fence Ã2, confirmed-release) â restored in5f117dewith the full class at 46 green. A multi-round audit of the whole PR (unbiased production and test reads, adversarial probes on auth ladders, replay ordering, merge double-adds, doc parity and contract wording) then landed: the respond creator-facts gate now covers every bound admission (the identity arm had the same 202-into-a-dead-arbiter hole; pinned by a two-armed witness plus its!admitted &&mutation witness), a superseded dead session-mutation replay probe is removed, theworkspaceTurnsfield, the contract changelog and both design languages no longer bundle cancellation into the facts conjunct (cancel admits on role and shape alone; every bound respond certifies the facts), and the README no longer tells a public caller to gate on a WebShell-only field. Final state:mvn teston managed-agent-server is 1404 green with zero failures atba1e8d7; hosted MySQL profiles stay with CI per the environment note. Contract story after the next CI cycles: main's merged H5b/H5c channel runtime (#13572) took v1.35, so this slice finalises the contract at v1.36 and the actor-key migration as V56 (V54 is #13550's lineage; V55 is #13572's channel instance binding); #13545 is rebased over both without code overlap.čŊåŪĄåĪį―ŪäļååđķååŪĄčŪĄïž2026-10-09ïž
R1ïž34 æĄïžåĻ
b9f90ebåĪį―ŪåŪæŊïžR2ïž38 æĄïžįŧ8c1db10ã3c646ffäļåŪĄčŪĄč―ŪæäšĪbf93110âba1e8d7å ĻéĻåĪį―ŪïžæŊæĄ thread é―æææäŋŪåĪäļč§čŊįčĄå ååĪïž72 æĄå ĻéĻ resolvedãmainååđķæūééŧäļĒæ 5 äļŠæĒæįManagedCwdChangeOperationTestčïžretained-runtime Ã2ãčŋį§ŧæ æ Ã2ãįĄŪčŪĪéæūïžââ å·ēåĻ5f117deæĒåĪïžæīäļŠįąŧ 46 įŧŋãéååŊđæī PR įåĪč―ŪåŪĄčŪĄïžįäš§äļæĩčŊ diff įæ æđåéčŊŧãææéķæĒŊ/éæūæŽĄåš/merge åå /ææĄĢåčŊ/åĨįšĶæŠčūįåŊđææĒéïžč―å°ïžrespond įååŧšč éŪäšåŪéļį°åĻčĶįæŊæĄįŧåŪåå Ĩïžidentity čæūåæ ·æ 202 čŋå ĨäļåŊčūūåĪåŪč įæīïžåčč§čŊå!admitted &&ååžč§čŊéæŧïžïžå éĪäščĒŦäļĪįš§ååäŧĢįæŧ replay æĒéïžworkspaceTurnsåæŪĩãåĨįšĶ changelog äļåčŊčŪūčŪĄäļåæåæķåđķå ĨäšåŪååïžåæķåŠéč§čēäļå―ĒæïžæŊäļŠįŧåŪ respond é―æ äŋäšåŪïžïžREADME äļåæåžå Žåžč°įĻæđåŧįäļäļŠäŧ WebShell ææįåæŪĩãįŧæïžba1e8d7äļ managed-agent-servermvn test1404 įŧŋã0 åĪąčīĨïžhosted MySQL profile æįŊåĒčŊīæäšĪ CIã åĨįšĶåįŧįįđïžmain å·ēåå Ĩį H5b/H5c ééčŋčĄæķïž#13572ïžå äš v1.35ïžæŽåįįåĨįšĶå æĪæķå°ūäļš v1.36ãactor_key čŋį§ŧæđå· V56ïžV54 å― #13550 į lineageïžV55 å― #13572 į channel instance bindingïžïž#13545 å·ēč·ĻčŋäļĪæŽĄäļŧåđēåčŋäļäŧĢį éĒéķéå ã