You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by "ARE404 (via GitHub)" <gi...@apache.org> on 2026/09/01 06:40:55 UTC
[PR] feat(workhub): add direct stop coordination [maka]
ARE404 opened a new pull request, #4439:
URL: https://github.com/apache/maka/pull/4439
## Summary
Add WorkHub Slice 5D: direct stop for one explicitly named, active durable delegation.
- require a direct named imperative and fail closed for pronouns, pause/wait language, negation, malformed literals, or ambiguous/multiple active delegations
- persist `delegation_stop_requested` and `delegation_stop_resolved` facts and project their outcomes into WorkHub
- cancel a still-pending delegated Message with same-claim crash replay
- stop only an exact Message-owned root Turn; preserve shared/user-owned Turns as `not_owned`
- bind owning-root Stop provenance to the WorkHub action identity so restart recovery cannot mistake a manual Stop for WorkHub delivery
- serialize stop against replacement, rename, target removal, and active-delegation-set races
- surface neutral UI copy (`asked to stop`) without claiming execution completion
## Verification
- Biome check and `git diff --check`
- typecheck: Core, Storage, Runtime, Runtime Host, Desktop
- build: Core, Storage, Runtime, Runtime Host, UI, Desktop main
- Core WorkHub tests: 11 passed
- SQLite metadata and WorkHub assignment tests: 82 passed
- Runtime Stop provenance tests: 3 passed
- Runtime Host WorkHub suites: 51 passed
- owning-root provenance regressions: 4 passed
- Root authority invalid-provenance zero-side-effect regression: 1 passed
- Desktop WorkHub suites: 104 passed
- independent adversarial Spec and Standards reviews: GO, no remaining P1/P2
## Review focus
The destructive authority remains delegation- and Message-centered. The renderer proposes only `stopsActionId`; Session, Message, Turn, and Run identities are resolved and verified by Host-owned durable state. Pending cancellation and owning-root Stop each retain action-bound durable provenance across the request/resolution crash seam.
This PR also advances the Runtime Host compatibility epoch to 87. Epoch 86 remains assigned to Client Capability admission evidence from current `main`; epoch 87 covers the new closed WorkHub direct-stop protocol shapes.
## AI use
Select exactly one:
- [ ] No generative tool made a substantive contribution
- [x] Generative tooling made a substantive contribution
Tool(s) and scope: Codex implemented, tested, documented, rebased, and adversarially reviewed the change. Claude Opus was consulted during design planning.
## Checklist
- [x] Tests cover the change and fail without it
- [x] Lint, format, typecheck and the affected suites pass locally
Does this PR entail a change in behavior?
- [x] Yes — described under Summary above
- [ ] No
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "ARE404 (via GitHub)" <gi...@apache.org>.
ARE404 commented on code in PR #4439:
URL: https://github.com/apache/maka/pull/4439#discussion_r3904492644
##########
packages/runtime-host/src/server/workhub-coordination-action-gate.ts:
##########
@@ -343,6 +506,12 @@ export class WorkHubCoordinationActionGate {
return this.#replace(prepared, context);
}
const replacement = await this.#replacementAssignment(input, replaced);
+ await this.#claimAction(
Review Comment:
Fixed in d45ed15d6. Prepared replacement replay now durably claims and verifies the persisted replace operation, fingerprint, and source delegation before entering #replace. Added a restart/migration regression with an empty legacy claim table plus a conflicting post-upgrade claim; it rejects with action_conflict and records zero retirements and zero assignments. Runtime Host build, Biome, and the action-gate suite (37/37) pass.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "ARE404 (via GitHub)" <gi...@apache.org>.
ARE404 commented on PR #4439:
URL: https://github.com/apache/maka/pull/4439#issuecomment-5505942381
@likun666661 Agreed on both points.
I will treat the shared `SessionResolver` port as part of this PR's architectural boundary, with the current exact-name behavior behind a temporary deterministic implementation. That makes it replaceable without coupling the durable stop protocol to display-name grammar. The follow-up removal criteria are: all target-bearing WorkHub actions use the shared port, the replacement resolver passes the common evaluation, and rollout retains a tested rollback path.
I also agree that `create_new` is not a Session-retrieval result. The Resolver should return ranked existing Sessions, `none`, or ambiguity. The per-action policy decides whether explicit creation is allowed, whether an existing target is sufficient, or whether to clarify/reject. An unambiguous must-create request may bypass retrieval; otherwise creation combines trusted explicit intent with the absence of a suitable existing Session. Any created Work remains explicitly announced to the user.
I added a proposed design document that records the original experiment branches and R2.4/R3 plan, the production slices already delivered, the new pipeline and contracts, the reframed experiment arms, and the remaining PR-sized work:
[`docs/architecture/workhub-action-resolution-design.md`](https://github.com/ARE404/maka-agent/blob/feat/workhub-direct-stop/docs/architecture/workhub-action-resolution-design.md)
The WorkHub domain language now also names `Action Intent`, `Session Resolver`, `Action Policy`, and `Action Proposal`, and marks exact-name stop syntax as a temporary implementation rather than the long-term product contract. I have also synchronized a concise architecture update back to Discussion #3286.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
Astro-Han commented on code in PR #4439:
URL: https://github.com/apache/maka/pull/4439#discussion_r3921577048
##########
packages/runtime-host/src/server/workhub-coordination-action-gate.ts:
##########
@@ -269,18 +345,101 @@ export class WorkHubCoordinationActionGate {
}
if (proposal.disposition === 'answer_here') {
const turnId = coordinationTurnId(input.actionId, 'answer');
+ await this.#claimAction(input.actionId, 'answer_here', fingerprint, turnId);
await this.#effects.answer({ turnId, text: input.userText }, context);
return { disposition: 'answer_here', coordinationTurnId: turnId };
}
if (proposal.disposition === 'clarify') {
const turnId = coordinationTurnId(input.actionId, 'clarify');
+ await this.#claimAction(input.actionId, 'clarify', fingerprint, turnId);
await this.#effects.clarify({
turnId,
userText: input.userText,
assistantText: proposal.assistantText,
});
return { disposition: 'clarify', coordinationTurnId: turnId };
}
+ if (proposal.disposition === 'stop_work') {
+ if (input.confirmation?.kind !== 'user_stop' || !requestIntent.stop.imperative) {
+ throw new WorkHubActionGateFailure(
+ 'action_conflict',
+ 'WorkHub stop requires an explicit named command in trusted user text',
+ );
+ }
+ const source = await this.#stopSource(input.actionId, proposal.expects.targetSessionId);
+ const stopFingerprint = stopActionFingerprint(input, source);
+ await this.#claimAction(input.actionId, 'stop', stopFingerprint, source.delegationId);
+ const existing = await this.#effects.readStopRequest(source.delegationId);
+ if (existing) {
+ if (existing.actionId !== input.actionId) {
+ // `not_owned` deliberately leaves the delegation active, so the user
+ // can and will try again with a fresh request. That later attempt has
+ // its own identity and must converge on the immutable non-destructive
+ // outcome instead of colliding with the first attempt's stop claim.
+ const resolved = await this.#effects.readStopResolution(source.delegationId);
+ if (resolved?.outcome === 'not_owned') return stopResult(resolved);
+ }
+ assertStopReplay(existing, input, source, stopFingerprint);
+ return this.#stop(existing, source);
+ }
+ const [sessions, activeAssignments] = await Promise.all([
+ this.#effects.listSessions(),
+ this.#effects.listActiveAssignments(),
+ ]);
+ const sessionNameById = new Map(sessions.map((session) => [session.id, session.name]));
+ // Only this delegation's target has to be visible. A delegation whose
+ // Session the user deleted stays in the active set forever — nothing
+ // retires it — so proving visibility over the whole set would let one
+ // deleted Session block every stop in the system from then on.
+ const currentTargetName = sessionNameById.get(source.targetSessionId);
+ if (!currentTargetName) {
+ throw new WorkHubActionGateFailure('action_conflict', 'WorkHub stop target is unavailable');
+ }
+ // Authority is the opaque delegation identity, never the display name the
+ // Resolver recalled it by. This is the advisory read; the coordinator
+ // reproves it from durable state under the admission lease.
+ //
+ // A delegation link ends only by supersession or a resolved stop, so a
+ // delegation whose work already finished is still linked. It is not a
+ // competing stop target though — there is nothing left in it to stop —
+ // and counting it would make a Session that was delegated to twice
+ // permanently unstoppable once the first delegation completed.
+ if (!activeAssignments.some((assignment) => assignment.actionId === source.actionId)) {
Review Comment:
P2. `#stopSource` derived `source` from `listActiveAssignments()` moments ago using this same rule, and the replay branch returns at `:380` before reaching here, so on every path that reaches this line the check has just been made. `#prepareStop` makes it a third time under the lease, which is the copy that decides. Dropping this and the `#hasCompetingWork` call below it removes one full scan of the coordination transcript per stop and one of the two places the retirement rule lives; `listSessions()`/`currentTargetName` and the supersession/replacement reads above still earn their place.
##########
packages/runtime-host/src/server/workhub-coordination-action-gate.ts:
##########
@@ -371,6 +542,160 @@ export class WorkHubCoordinationActionGate {
);
}
+ /**
+ * The delegation a stop names, by the only two keys that can name it.
+ *
+ * A stop carries its target Session and its own action identity; it never
+ * carries the delegation, because a client cannot prove which link is live.
+ *
+ * Replay reads the claim first. A resolved stop takes its delegation out of
+ * the active set, so re-deriving after one succeeded would find nothing and
+ * turn a converging replay into a conflict. The claim records the delegation
+ * this exact action already bound itself to, and it is written before any
+ * effect, so whatever the first attempt reached is reachable again.
+ *
+ * A first attempt has no claim and resolves from the active links: exactly
+ * one delegation on that Session must still hold work a stop could reach.
+ * Zero or several is the same refusal admission has always made, from the
+ * same durable state, rather than a client's guess about either.
+ */
+ async #stopSource(
+ actionId: string,
+ targetSessionId: string,
+ ): Promise<WorkHubDelegationAssignedMessage> {
+ const claim = await this.#effects.readActionClaim(actionId);
+ if (claim?.operation === 'stop') {
+ // The request records which delegation this action bound itself to. It is
+ // written after the claim, so a crash between the two leaves a claim with
+ // nothing to converge on — and nothing destructive happened either, so
+ // that case resolves from the active links below like a first attempt.
Review Comment:
P3. This holds only while the single active link on that Session is unchanged. If that delegation leaves the active set and another takes its place before the retry, the fallback below re-derives the new one, `stopActionFingerprint` changes with it, and `claimAction` returns `conflict`, permanently, since claims are never deleted. Nothing destructive happened and a fresh message gets a fresh action id, so it costs one refused attempt rather than anything worse. Either narrow the sentence, or compare the re-derived delegation against `claim.subject` and return the stable refusal.
##########
packages/runtime-host/src/server/execution-composition.ts:
##########
@@ -1990,6 +1999,74 @@ export async function createExecutionRuntimeHostComposition(
}
}
+/**
+ * Confirmed direct stop. The action-derived abort source is written onto the
+ * exact root Turn so a retry after a crash can tell WorkHub's own delivery
+ * apart from an earlier or concurrent manual Stop.
+ */
+export async function stopOwnedWorkHubRoot(
+ coordinator: Pick<RootTurnCoordinator, 'readRootState' | 'read' | 'stopRoot'>,
+ identity: { readonly sessionId: string; readonly turnId: string; readonly runId: string },
+ actionId: string,
+): Promise<{
+ readonly outcome: 'stop_delivered' | 'already_terminal' | 'recovering';
+ readonly targetTurnId: string;
+}> {
+ if (isActiveWorkHubRoot(coordinator, identity)) {
+ await coordinator.stopRoot(identity, {
+ source: 'workhub_direct_stop',
+ workHubActionId: actionId,
+ });
+ }
+ const terminal = await coordinator.read(identity);
+ if (
+ terminal.status === 'cancelled' &&
+ terminal.abortSource === workHubDirectStopAbortSource(actionId)
+ ) {
+ return { outcome: 'stop_delivered', targetTurnId: identity.turnId };
+ }
+ // Registration is in-memory, so between Host restart and execution recovery
+ // this root looks inactive while it is still running. `already_terminal` is
+ // committed as an immutable fact, so only a durably terminal snapshot may
+ // claim it; anything else is still resolving.
+ return isHostedExecutionTerminal(terminal)
+ ? { outcome: 'already_terminal', targetTurnId: identity.turnId }
+ : { outcome: 'recovering', targetTurnId: identity.turnId };
+}
+
+/**
+ * Route correction retiring the root it is replacing. It carries its own
+ * cancellation claim, but it is not a direct stop: recording direct-stop
+ * provenance here would let replay mistake a correction for one, so the
+ * retirement keeps the neutral Stop source ordinary supersession has always
+ * used.
+ */
+export async function stopReplacedWorkHubRoot(
+ coordinator: Pick<RootTurnCoordinator, 'readRootState' | 'read' | 'stopRoot'>,
+ identity: { readonly sessionId: string; readonly turnId: string; readonly runId: string },
+): Promise<{
+ readonly outcome: 'stop_delivered' | 'already_terminal';
+ readonly targetTurnId: string;
+}> {
+ if (!isActiveWorkHubRoot(coordinator, identity)) {
Review Comment:
P3. The last reader in this file that treats missing in-memory registration as proof the work ended, the same restart window `readDelegationRetirement` names in its own comment, and the one `stopOwnedWorkHubRoot` now guards. It preserves what `main` did on the replacement path, so not a regression here; threading a `recovering` outcome through replacement is its own change and reads like a follow-up.
##########
packages/runtime-host/src/server/workhub-coordination-coordinator.ts:
##########
@@ -214,12 +255,143 @@ export class HostWorkHubCoordinationCoordinator {
});
}
+ async #prepareStop(
+ input: Parameters<WorkHubActionGateEffects['prepareStop']>[0],
+ ): Promise<WorkHubDelegationStopRequestedMessage> {
+ const initiallyActive = await this.#listActiveAssignments();
+ const admittedTargetSessionIds = new Set(
+ initiallyActive.map((assignment) => assignment.targetSessionId),
+ );
+ const suffix = workHubDestructiveClaimIdentitySuffix(input.stopsDelegationId);
+ return this.#commitCoordinationFact({
+ admissionSessionIds: [WORKHUB_COORDINATION_SESSION_ID, ...admittedTargetSessionIds],
+ read: () => this.#stores.readWorkHubStopRequest(input.stopsDelegationId),
+ build: (existing) => ({
+ type: 'workhub_coordination',
+ id: `whq_${suffix}`,
+ turnId: input.actionId,
+ ts: existing?.ts ?? Date.now(),
+ schemaVersion: WORKHUB_COORDINATION_STOP_SCHEMA_VERSION,
+ kind: 'delegation_stop_requested',
+ actionId: input.actionId,
+ actionFingerprint: input.actionFingerprint,
+ coordinationTurnId: input.actionId,
+ stopsActionId: input.stopsActionId,
+ stopsDelegationId: input.stopsDelegationId,
+ targetSessionId: input.targetSessionId,
+ targetMessageId: input.targetMessageId,
+ targetSessionName: input.targetSessionName,
+ userText: input.userText,
+ }),
+ conflictMessage: 'WorkHub delegation already has a different stop claim',
+ beforeAppend: async () => {
+ const [replacement, supersession, headers, messages] = await Promise.all([
+ this.#stores.readWorkHubReplacement(input.stopsDelegationId),
+ this.#stores.readWorkHubSupersession(input.stopsDelegationId),
+ this.#stores.listHeaders(),
+ this.#stores.readMessagesSnapshot(WORKHUB_COORDINATION_SESSION_ID),
+ ]);
+ if (replacement || supersession) {
+ throw new WorkHubActionGateFailure(
+ 'action_conflict',
+ 'WorkHub delegation is already being replaced',
+ );
+ }
+ const visibleSessionIds = new Set(headers.map((header) => header.id));
+ const activeAssignments = activeWorkHubAssignments(messages);
+ if (
Review Comment:
P2. This whole-set comparison is what forces `admissionSessionIds` to cover every Session with an active delegation, so admitting one stop serializes delegation traffic system-wide, and a delegation created concurrently to an unrelated Session refuses this stop. The scoped proof below (target Session visible, `source` found in `targetActive`, every competitor retired) is what actually establishes the one-target property, and it needs only the target Session lane plus the coordination Session. It fails closed and is retryable, so not a blocker.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "ARE404 (via GitHub)" <gi...@apache.org>.
ARE404 commented on PR #4439:
URL: https://github.com/apache/maka/pull/4439#issuecomment-5504360678
@likun666661 I agree with this boundary. The direction I propose is:
```text
user input
-> Action Intent: identify the action type, without resolving its target
-> shared Session Resolver: return existing Session candidate(s), create_new, none, or ambiguous
-> per-action policy: decide whether that resolution is sufficient and allowed for this action
-> typed Action Proposal: stable IDs plus expected-state preconditions
-> Action Gate: revalidate authority, ownership, current state, and idempotency
-> persist and execute on the owning Host
```
The Resolver is shared by continue, inspect, stop, resume, delegation, and future control actions. It may combine structured references, visible Session metadata, focus/recency/state signals, and later lexical retrieval such as BM25. It only proposes identities; it never grants execution authority.
`create_new` is an explicit resolution outcome, not a routing side effect. Each action policy decides whether creation is legal: delegation may allow it and must tell the user that a new Work was created, while stop would normally reject or clarify instead.
For this PR, the durable half remains valuable and should stay: action identity, exact ownership, cancellation, owning-root Stop, replay, and stop/replacement arbitration. The current direct-stop parser and exact-name lookup should be treated as a compatibility adapter, not the canonical architecture. Follow-up work can introduce the shared Resolver contract first, move stop onto it, then add deterministic retrieval/BM25 behind the same contract.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "likun666661 (via GitHub)" <gi...@apache.org>.
likun666661 commented on PR #4439:
URL: https://github.com/apache/maka/pull/4439#issuecomment-5505628571
Thanks, I think we are aligned on the long-term boundary.
My preference is to do the shared Session Resolver properly rather than knowingly establish a second target-resolution path. If delivery timing requires this PR to keep the deterministic regex/exact-name behavior temporarily, I think the minimum acceptable shape is to introduce the shared `SessionResolver` contract now and put that behavior behind it as the first replaceable implementation:
```text
Action Intent
-> SessionResolver
-> ExactNameSessionResolver // temporary deterministic baseline
-> BM25 / ranked resolver // follow-up implementation
-> per-action policy
-> typed Action Proposal
-> Action Gate
```
Without that port, the current code is not really a compatibility adapter: there is no previous direct-stop contract to preserve. It becomes the canonical implementation by construction, and its regex, display-name matching, clarification behavior, tests, and domain language will all become migration constraints for the future Resolver.
Putting the boundary in place now would let this PR retain its valuable durable stop execution work while making the temporary resolver visibly replaceable. I would also avoid documenting the exact-name grammar as a long-term product contract, and link a concrete follow-up with removal criteria for the temporary resolver.
One smaller modeling question: I think a Session Resolver should probably return ranked existing Sessions, `none`, or `ambiguous`. `create_new` is not a recalled Session; it appears to be a per-action policy decision based on explicit creation intent plus the absence of a suitable existing Session. Keeping that decision outside retrieval would make the shared resolver easier to reuse for stop, inspect, resume, and delegation.
If there is no timing constraint, I would rather introduce the real shared Resolver path in this change. If there is one, the interface plus temporary implementation seems like the smallest step that does not harden the wrong boundary.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "likun666661 (via GitHub)" <gi...@apache.org>.
likun666661 commented on PR #4439:
URL: https://github.com/apache/maka/pull/4439#issuecomment-5496214312
## Architecture discussion: resolve Sessions, not stop syntax
This is a first-principles / Occam pass, not a claim that I already have the final design.
I think direct stop belongs in WorkHub. At this point WorkHub is naturally becoming both a coordination control plane and a navigation layer. My concern is narrower: the current change makes target resolution a stop-specific text grammar.
The current path is roughly:
```text
user text
-> DIRECT_STOP_REQUEST / DIRECT_CHINESE_STOP_REQUEST
-> exact Session display-name match
-> require exactly one active delegation
-> stop_work
```
That gives Stop its own target resolver in `workhub-creation-intent.ts` and `workhub-route-policy.ts`, ahead of the ordinary routing/candidate path. I do not think regex plus exact display-name matching is a viable permanent boundary for a conversational control plane. It also couples destructive authority to presentation metadata and makes every future control verb likely to grow another resolver.
Starting from the underlying model:
1. A Session is effectively one agent loop plus its execution/permission/concurrency authority.
2. WorkHub is a coordinator that discovers those loops, routes work to them, and issues typed control actions.
3. Therefore, phrases such as “stop the work that was handling payment timeouts” are primarily a **Session relevance retrieval** problem. Raw messages are retrieval evidence; the Session is the recalled, ranked, and ultimately controlled entity.
A possible direction to discuss is:
```text
user input
-> classify control intent (continue / inspect / stop / resume / ...)
-> retrieve relevant visible Sessions
-> rank or clarify
-> produce an opaque Session/delegation candidate
-> Action Gate revalidates authority
-> target Session executes the typed control action
```
For an initial deterministic baseline, Session retrieval could use BM25 over permitted raw-message chunks and Session metadata, aggregate message hits by `sessionId`, and then rank Sessions using a small number of observable signals such as lexical relevance, title match, current WorkHub focus, recency, active/running state, and active delegation presence. This is not a proposal to inject cross-Session raw text into execution context. Retrieval proposes bounded candidates; it never grants Stop authority. The Action Gate and target Message authority remain responsible for existence, Host scope, ownership, active delegation identity, and the actual cancellation/Stop.
Visibility also fits this model cleanly. Hidden, archived, or logically deleted Sessions can be excluded from the recall projection according to explicit policy while their underlying records follow the existing retention/recovery contract. The search index remains rebuildable rather than becoming lifecycle authority.
From this perspective, the valuable part of this PR is the latter half: durable action identity, exact Message ownership, pending cancellation, owning-root Stop, crash replay, and stop/replacement arbitration. The questionable part is permanently binding that control protocol to a bespoke direct-stop parser and exact Session-name uniqueness proof.
My current Occam conclusion is:
> WorkHub needs one shared `user reference -> ranked Session candidates` capability that can serve continue, inspect, stop, and resume. Stop should consume the resolved stable identity, not own a separate natural-language resolver.
BM25 is only one plausible first baseline, not the final answer. I would like to discuss whether there are repository or product constraints that rule out Session-level relevance recall, and whether this PR can keep the durable stop execution work while avoiding the regex/exact-name path becoming the canonical target-resolution contract.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "hqhq1025 (via GitHub)" <gi...@apache.org>.
hqhq1025 commented on code in PR #4439:
URL: https://github.com/apache/maka/pull/4439#discussion_r3904074671
##########
packages/runtime-host/src/server/workhub-coordination-action-gate.ts:
##########
@@ -343,6 +506,12 @@ export class WorkHubCoordinationActionGate {
return this.#replace(prepared, context);
}
const replacement = await this.#replacementAssignment(input, replaced);
+ await this.#claimAction(
Review Comment:
**P1:** This claim runs only for a newly constructed replacement. The `prepared` branch above returns through `#replace` without first claiming the action ID. Migration 38 creates an empty `workhub_action_claims` table and does not backfill schema-36 `delegation_replacement_requested` records, so after upgrade another operation can claim the same ID. Replaying the old prepared replacement then reaches `retireDelegation` before `#assign` finally detects the conflict. I reproduced this with a migrated-prepared probe: replay rejected with `action_conflict`, but only after one source retirement had already been recorded. Please claim and verify the prepared replacement's `replace` operation, fingerprint, and source delegation before entering `#replace`, and add a migration/restart regression asserting that a conflicting claim causes zero retirement.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
Astro-Han merged PR #4439:
URL: https://github.com/apache/maka/pull/4439
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
Astro-Han commented on code in PR #4439:
URL: https://github.com/apache/maka/pull/4439#discussion_r3913437155
##########
packages/runtime-host/src/server/workhub-coordination-action-gate.ts:
##########
@@ -269,18 +334,115 @@ export class WorkHubCoordinationActionGate {
}
if (proposal.disposition === 'answer_here') {
const turnId = coordinationTurnId(input.actionId, 'answer');
+ await this.#claimAction(input.actionId, 'answer_here', fingerprint, turnId);
await this.#effects.answer({ turnId, text: input.userText }, context);
return { disposition: 'answer_here', coordinationTurnId: turnId };
}
if (proposal.disposition === 'clarify') {
const turnId = coordinationTurnId(input.actionId, 'clarify');
+ await this.#claimAction(input.actionId, 'clarify', fingerprint, turnId);
await this.#effects.clarify({
turnId,
userText: input.userText,
assistantText: proposal.assistantText,
});
return { disposition: 'clarify', coordinationTurnId: turnId };
}
+ if (proposal.disposition === 'stop_work') {
+ if (input.confirmation?.kind !== 'user_stop' || !requestIntent.stop.imperative) {
+ throw new WorkHubActionGateFailure(
+ 'action_conflict',
+ 'WorkHub stop requires an explicit named command in trusted user text',
+ );
+ }
+ const source = await this.#effects.readAssignment(proposal.stopsActionId);
+ if (!source || source.targetSessionId !== proposal.expects.targetSessionId) {
+ throw new WorkHubActionGateFailure(
+ 'action_conflict',
+ 'WorkHub can stop only the resolved durable delegation it owns',
+ );
+ }
+ const stopFingerprint = stopActionFingerprint(input, source);
+ await this.#claimAction(input.actionId, 'stop', stopFingerprint, source.delegationId);
+ const existing = await this.#effects.readStopRequest(source.delegationId);
+ if (existing) {
+ if (existing.actionId !== input.actionId) {
+ // `not_owned` deliberately leaves the delegation active, so the user
+ // can and will try again with a fresh request. That later attempt has
+ // its own identity and must converge on the immutable non-destructive
+ // outcome instead of colliding with the first attempt's stop claim.
+ const resolved = await this.#effects.readStopResolution(source.delegationId);
+ if (resolved?.outcome === 'not_owned') return stopResult(resolved);
+ }
+ assertStopReplay(existing, input, source, stopFingerprint);
+ return this.#stop(existing, source);
+ }
+ const [sessions, activeAssignments] = await Promise.all([
+ this.#effects.listSessions(),
+ this.#effects.listActiveAssignments(),
+ ]);
+ const sessionNameById = new Map(sessions.map((session) => [session.id, session.name]));
+ if (
+ activeAssignments.some((assignment) => !sessionNameById.has(assignment.targetSessionId))
Review Comment:
P1. This rejects on *any* active assignment whose target is gone, and nothing retires such an assignment: no completion fact, Session deletion writes nothing here, and a stop or correction aimed at it is refused by this same check. One deleted target Session bricks direct stop globally. Scope the proof to `source.targetSessionId` (the `currentTargetName` check below already does) and drop this and the coordinator twin.
##########
apps/desktop/src/renderer/workhub-route-policy.ts:
##########
@@ -101,15 +140,74 @@ const MAX_RELATED_CLARIFICATION_OPTIONS = 4;
* It owns only transient inference context. Session identity, transcript,
* execution state, and recovery continue to come from the Session port.
*/
-export function createWorkHubRoutePolicy(): WorkHubRoutePolicy {
- return createWorkHubRoutePolicyVisit();
+export function createWorkHubRoutePolicy(
+ sessionResolver: WorkHubSessionResolver = createExactNameSessionResolver(),
+): WorkHubRoutePolicy {
+ return createWorkHubRoutePolicyVisit(sessionResolver);
}
-function createWorkHubRoutePolicyVisit(): WorkHubRoutePolicy {
+function createWorkHubRoutePolicyVisit(
+ sessionResolver: WorkHubSessionResolver,
+): WorkHubRoutePolicy {
let currentFocus: WorkHubRouteTarget | undefined;
let previousFocus: WorkHubRouteTarget | undefined;
return {
+ // The stop Action Policy. Action Intent says only that the user issued a
+ // stop imperative and what work it refers to; the shared Session Resolver
+ // recalls which visible Sessions that reference names; this policy decides
+ // whether the resolution is sufficient for a destructive action.
+ //
+ // Direct stop is a narrow claim over WorkHub's own active delegations, not
+ // a filter over every sentence that begins with "stop". A reference that
+ // recalls no WorkHub identity — "Stop using the deprecated API" — is
+ // ordinary work and falls through to routing; an unsafe or anaphoric
+ // reference still fails closed, and a resolved Session that is not uniquely
+ // stoppable says why.
+ resolveStop({ text, sessions }) {
+ const intent = readWorkHubRequestIntent(text);
+ if (!intent.stop.cue) return { kind: 'not_requested' };
+ const reference = intent.stop.imperative ? intent.stop.target : undefined;
+ if (!reference) {
+ return { kind: 'clarification', reason: 'stop_target_required' };
+ }
+ const sessionByRef = new Map(
+ sessions.map((session) => [session.target.sessionId, session]),
+ );
+ const resolution = sessionResolver.resolve({
+ reference: { text: reference },
+ sessions: sessions.map((session) => ({
+ ref: session.target.sessionId,
+ sessionName: session.sessionName,
+ projectName: session.projectName,
+ updatedAt: session.updatedAt,
+ })),
+ });
+ if (resolution.kind === 'none') return { kind: 'not_requested' };
+ if (resolution.kind === 'ambiguous') {
+ return { kind: 'clarification', reason: 'stop_target_ambiguous' };
+ }
+ // Stop admits one candidate only. A ranked resolver may return several;
+ // this action never picks a winner from a ranking it cannot justify.
+ if (resolution.candidates.length > 1) {
+ return { kind: 'clarification', reason: 'stop_target_ambiguous' };
+ }
+ const resolved = sessionByRef.get(resolution.candidates[0].ref);
+ if (!resolved) return { kind: 'not_requested' };
+ const [stopsActionId, ...furtherActive] = resolved.activeActionIds;
+ if (!stopsActionId) {
+ return { kind: 'clarification', reason: 'stop_target_not_active' };
Review Comment:
P2. Both stop clarifications are decided from the renderer's active-delegation mirror and never reach the Host. A second window or a reload before the coordination stream refills answers with a zero-option clarification that contradicts Host state. Submit and let the Gate's conflict reason drive the copy, or read the Host first.
##########
packages/core/src/workhub-creation-intent.ts:
##########
@@ -292,9 +307,28 @@ export function readWorkHubRequestIntent(value: string): WorkHubRequestIntent {
cue: correctionCue,
...(existingTarget ? { existingTarget } : {}),
},
+ stop: {
+ cue: stopCue,
+ imperative: Boolean(stopTarget),
+ ...(stopTarget ? { target: stopTarget } : {}),
+ },
};
}
+/**
+ * Whether trusted reference text names exactly this Session.
+ *
+ * This is the matching rule behind the temporary exact-name Session Resolver.
+ * It answers a retrieval question only: naming a Session grants no authority
+ * over it, and the Action Gate revalidates the resolved opaque identity.
+ */
+export function workHubSessionReferenceNamesSession(
+ reference: string,
+ sessionName: string,
+): boolean {
+ return stopTargetMatchesSession(reference, sessionName);
Review Comment:
P2. The port's only implementation delegates to `stopTargetMatchesSession`, while `correctionTargetMatchesSession` at `:397` is a second copy of the same rule and `resolve()` in route-policy still runs its own ranking, so the port is a third path, not the shared one. Either bring `resolve()` and correction onto the resolver in this PR, or drop the port and fold the two matchers into one strict core with per-action tails (−394 lines on a scratch branch, all tests green). Not the half-way state.
##########
packages/runtime-host/src/server/execution-composition.ts:
##########
@@ -1967,6 +1971,65 @@ export async function createExecutionRuntimeHostComposition(
}
}
+/**
+ * Confirmed direct stop. The action-derived abort source is written onto the
+ * exact root Turn so a retry after a crash can tell WorkHub's own delivery
+ * apart from an earlier or concurrent manual Stop.
+ */
+export async function stopOwnedWorkHubRoot(
+ coordinator: Pick<RootTurnCoordinator, 'readRootState' | 'read' | 'stopRoot'>,
+ identity: { readonly sessionId: string; readonly turnId: string; readonly runId: string },
+ actionId: string,
+): Promise<{
+ readonly outcome: 'stop_delivered' | 'already_terminal';
+ readonly targetTurnId: string;
+}> {
+ if (isActiveWorkHubRoot(coordinator, identity)) {
+ await coordinator.stopRoot(identity, {
+ source: 'workhub_direct_stop',
+ workHubActionId: actionId,
+ });
+ }
+ const terminal = await coordinator.read(identity);
+ return terminal.status === 'cancelled' &&
+ terminal.abortSource === workHubDirectStopAbortSource(actionId)
Review Comment:
P2. `isActiveWorkHubRoot` reads in-memory root state. After a Host restart, before recovery re-registers the execution, this skips `stopRoot`, reads a snapshot that may still be `running`, and returns `already_terminal`, which `#stop` commits as an immutable resolution. Use `isHostedExecutionTerminal` and return `recovering` when nothing was delivered and the snapshot is not terminal.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org
Re: [PR] feat(workhub): add direct stop coordination [maka]
Posted by "Astro-Han (via GitHub)" <gi...@apache.org>.
Astro-Han commented on PR #4439:
URL: https://github.com/apache/maka/pull/4439#issuecomment-5508750835
@ARE404 Two things outside this PR that surfaced on the scratch branch, in case you want to file them:
1. On `main`, `Create a new Session called "Payments"` resolves as `non_executable` because the literal mask strips the quoted title and nothing is left as an action object; unquoted titles are the only way to name a Session today. Same for `请创建一个新会话名为"支付任务"`.
2. Several paths in the series have no producer or consumer any more (the ordinary-Session transcript projection in the session port, the `workHub.answer` / `createSession` / `listWithCoverage` bridge surface, the Gate's in-memory replay map next to durable `delegation_assigned`, `WorkHubCoordinationCandidateState` as a copy of `SessionStatus`); removing them keeps the suites green.
Happy to share the branches if you open something for either.
<details><summary>简体中文</summary>
两件本 PR 之外的事,供你决定要不要开 issue:main 上带引号的命名请求会被判不可执行;系列里有几条已无生产者或消费者的路径,删掉后测试全绿。需要的话我把实验分支给你。
</details>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org