Skip to content

feat(spec): optional caller on IAutomationService.toggleFlow - #26545

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-x54rab
Oct 27, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-x54rab

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Yibo Wang · project thread

Fixes #26506

Clause-②: yes (widening)
Metadata-protocol: none

维护者速读

  • 改了什么:IAutomationService.toggleFlow 增加可选的第三个参数 caller,只携带 userId,用来告诉服务是谁开关了这个打包流程。
  • 为什么改:管理员关掉打包流程时,激活台账行与审计行的操作人都是空,审计无法说明是哪位管理员做的;服务端修复 (automation: switching off a packaged flow or a packaged action writes the activation-ledger row and its audit row with a null actor, so nothing records which admin did it #26474) 需要契约先有这个通道。
  • 风险与回滚:参数可选,现有实现与调用方原样编译,运行时行为零变化;回滚即还原这一行签名。
  • 先看:packages/spec/src/contracts/automation-service.ts(toggleFlow 签名与 TSDoc),packages/spec/src/contracts/automation-toggle-flow-caller.pin.test.ts。
  • 两分钟验证:pnpm --filter @objectstack/spec exec vitest run src/contracts/automation-toggle-flow-caller.pin.test.ts,预期 2 个用例通过。
  • 需要你做的:无,席位落地。

What changes

IAutomationService.toggleFlow?(name, enabled) gains an optional third parameter, caller, typed as Pick over AutomationContext narrowed to the single key 'userId'. A door that serves a person passes that person's id, so the sys_metadata_activation row the switch writes, and its sys_audit_log row, can name the admin instead of a null actor. The method's TSDoc now says what the channel carries, that it is attribution only (it grants nothing, and an implementation neither refuses nor widens the switch on it), and that an absent caller, or one with no userId, means an unattributed write.

The parameter is optional, so every current implementer (AutomationEngine.toggleFlow in @objectstack/service-automation) and every caller (the runtime's POST /api/v1/automation/:name/toggle door and its test doubles) compiles unchanged. This is the contract half only: the door passing the caller and the engine writing with it are the server half, #26474.

Why this shape

The order was to follow execute(flowName, context?: AutomationContext) in the same contract, reusing AutomationContext or a narrow subset of it. I took the subset, one key:

  • userId is the key the write records. The engine stamps created_by / updated_by from the context's user, and the audit writer reads user_id from it. AutomationContext.userId is already the contract's spelling for "the acting user", so execute and toggleFlow name the person the same way.
  • No positions, permissions or posture. toggleFlow is no authority gate: ADR-0126 §5 gates the switch at the door that receives the request, and the ledger write runs elevated. A channel carrying grants would invite a second gate inside the service whose rules could drift from the door's.
  • No tenant. The activation ledger is deployment state with no organization column (ADR-0126 as amended by ADR-0131 D6), so a tenant id would carry nothing the write reads.
  • Not the whole AutomationContext. Most of its keys (record, params, runAs, flowName, flowRunId, callerParamKeys) describe a run and mean nothing for a switch. Taking the whole type would leave each implementer to decide which to ignore. With the narrow type, a caller literal carrying positions or record does not compile (pinned).
  • Not ExecutionContext. Several store contracts take the caller as ExecutionContext | undefined (IAIConversationService, ISharingService). That would hand the service the caller's whole principal, grants included, which is the second-gate risk above. The order also pointed at the AutomationContext precedent in this contract.

Widening later is additive: another key can join the Pick if a reader ever needs it.

Tests

packages/spec/src/contracts/automation-toggle-flow-caller.pin.test.ts, compiled by check:test-typecheck under tsconfig.test.json and run by vitest:

  • type level: the third parameter is exactly the narrowed Pick or undefined; the arity is 2 or 3; name and enabled keep their types and places;
  • additive: a two-parameter implementation (a function and a class) still satisfies the contract, and a two-argument call still compiles;
  • narrow: a caller literal with positions, or with record, is a compile error (@ts-expect-error, which itself fails if the line ever compiles);
  • runtime: an implementation reads caller?.userId without a cast, and reads it as absent when not passed; a two-parameter implementation runs when a caller is passed.

Reverse verification (one-off, not kept): the signature reverted to the two-parameter form via scripts/ablation-replace.mjs (anchor 1 to 0, blob 8fc1e1cc to 201b1e11), then tsc --noEmit -p tsconfig.test.json. The pin file turned red with 9 errors (TS2344 on both identity asserts, TS2554 on each three-argument call, TS2493 and TS7006 where the third parameter vanished). Restored: blob equals HEAD and git diff HEAD is empty.

Acceptance notes

Verification

All readings at head f3ce50a7, in the objectstack-issue-26506 worktree based on origin/main 3fcafcd3.

  • pnpm --filter @objectstack/spec build under the verify lock: VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec check:generated: exit 0, all 14 generated artifacts up to date, and git status clean afterwards, so no generated artifact moved (api-surface/contracts.json records IAutomationService by name only).
  • pnpm --filter @objectstack/spec typecheck (tsc, scripts typecheck, check:test-typecheck) and vitest on the new pin, automation-service.test.ts and automation-context-caller-param-keys.pin.test.ts: VERDICT command-exit 0, Test Files 3 passed, Tests 22 passed.
  • pnpm exec eslint --no-inline-config on both changed .ts files: exit 0.
Derived gates: 79 derived, 75 run with exit 0, 4 NOT MEASURED

node scripts/pm/dispatch-gates.mjs --commands derived 79 families from the three changed paths; all were run serially and reconciled with --ran (79 accounted, 0 unrun). Four exited 3, PREREQUISITE NOT MET, because this container has a shallow clone and no full build. They read nothing this diff touches, and CI runs them:

  • node scripts/check-plugin-teardown-shape.mjs --self-test (needs an unshallowed main)
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions (needs built packages)
  • pnpm check:dual-build-cjs-loads (needs every package's dist)
  • pnpm check:lean-entry-closure (needs @objectstack/objectql built)

Not run locally: the full dogfood battery (the title has no ! and the declaration has no (narrowing) arm), test:repo and the repo-wide lint, which are CI's.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WGufzgdxgk35nWqLB6EMzg


Generated by Claude Code

toggleFlow(name, enabled, caller?: Pick<AutomationContext, 'userId'>)
lets a door hand down who switched a packaged flow, so the activation
ledger row and its audit row can name that user. Optional, so every
current implementer and caller compiles unchanged. Type-level pin and a
patch changeset for @objectstack/spec.

Claude-Session: https://claude.ai/code/session_01WGufzgdxgk35nWqLB6EMzg
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 4 documentable anchor(s).

26 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 416d9ddd3d54a0a957941a765b60ff06076984ad.

⛔ 6 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • the SDK route bridge reached 55 of 207 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 146 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 416d9ddd3d54a0a957941a765b60ff06076984ad → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 8b3bc378720b16e736d3f74e4f4653afc91b55dc — the merge of head f3ce50a7cc2bb55ce12807ae1181253966ac26e2 into base 416d9ddd3d54a0a957941a765b60ff06076984ad, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 8b3bc378720b16e736d3f74e4f4653afc91b55dc && git checkout 8b3bc378720b16e736d3f74e4f4653afc91b55dc
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 416d9ddd3d54a0a957941a765b60ff06076984ad f3ce50a7cc2bb55ce12807ae1181253966ac26e2 && git checkout -B drift-repro 416d9ddd3d54a0a957941a765b60ff06076984ad && git merge --no-ff f3ce50a7cc2bb55ce12807ae1181253966ac26e2

node scripts/docs-audit/affected-docs.mjs --json 416d9ddd3d54a0a957941a765b60ff06076984ad

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 416d9ddd3d54a0a957941a765b60ff06076984ad → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: f3ce50a7cc2bb55ce12807ae1181253966ac26e2
Local-runs: none
Scope: packages/spec/src/contracts/automation-service.ts + packages/spec/src/contracts/automation-toggle-flow-caller.pin.test.ts, .changeset/26506-toggle-flow-caller.md, packages/services/service-automation/src/engine.ts (:2552 implements IAutomationService, :5281-5323 toggleFlow), packages/services/service-automation/src/flow-definitions.ts:472, packages/runtime/src/domains/automation.ts (:1258 Partial host, :3010-3079 the toggle door), packages/runtime/src/http-dispatcher.test.ts:456, the eight runtime door tests that pin the call (activation-gate-positions-name-authority, automation-activation-posture-gate, automation-body-validation, automation-packaged-base-lock, automation-toggle-deny-message, automation-toggle-unknown-flow, automation-write-capability-gate, http-dispatcher), packages/core/src/utils/metadata-activation-store.ts (SYSTEM_CTX, setActive), packages/platform-objects/src/system/sys-metadata-activation.object.ts (systemFields: { tenant: false }), packages/objectql/src/engine.ts:21513 (userId stamps created_by/updated_by), packages/spec/api-surface/contracts.json, packages/spec/src/api/automation-api.zod.ts:814, packages/spec/src/contracts/automation-service.test.ts, packages/spec/tsconfig.test.json, docs/adr/0126-packaged-metadata-customization-model.md §5 and §7.2, docs/adr/0131-total-organization-ownership-no-null-organization-id.md D6.

Inputs read: card #26506 body and both comments (claim 6435538904, os-dev report 6436156952); #26474 body and its four comments (triage 6434156905, claim 6434820232, seat ruling 6434876664 letter A, amended claim 6434884699); PR #26545 body, file list (3 paths) and the net diff of f3ce50a7 against merge-base 3fcafcd3 (+120 -1, the same 3 paths); the head's check-runs, read twice (07:25:03Z and 07:29:07Z).

① Derived judgments

  1. The widening holds at the type level, for every implementer and caller shape the brief names. toggleFlow?(name: string, enabled: boolean) becomes toggleFlow?(name, enabled, caller?: Pick of AutomationContext at 'userId'). The member is method-shorthand on an interface, so parameter comparison is bivariant, and TypeScript treats optional and required parameters as interchangeable when comparing signatures. Therefore: (i) the only class implementer, AutomationEngine implements IAutomationService (engine.ts:2552), whose toggleFlow(name, enabled) declares two parameters, is assignable (fewer parameters is always assignable); (ii) every object literal typed IAutomationService or Pick of IAutomationService in the spec's own tests (automation-service.test.ts:87, :224, two-parameter arrows) and the runtime door's Partial of IAutomationService host (domains/automation.ts:1258, :3078 passes two arguments) compile unchanged; (iii) a hypothetical implementation with a non-optional third parameter caller: Pick of AutomationContext at 'userId' is also assignable to the optional-parameter target, so the contract does not force an implementer to spell ?; (iv) engine.test.ts:922 (const service: IAutomationService = engine) still holds. The pin file proves (i), (ii) and the two-argument call by compiling them (twoParameterToggle, TwoParameterService, twoArgumentCall) and pins the arity as 2 | 3 and the third parameter as exactly the narrowed type | undefined. Nothing on main reads Parameters of toggleFlow with a two-tuple pin, so no existing type pin reds.

  2. The pin is compiled, not a phantom. packages/spec/tsconfig.test.json includes src/**/*, the package's typecheck script runs check:test-typecheck --project tsconfig.test.json, and the new file is absent from the shrink-only test-typecheck-debt.json, so its two @ts-expect-error lines evaluate. The reverse verification in the PR body (signature reverted, 9 tsc errors in the pin, restored) is consistent with that; I did not re-run it.

  3. The shape is right for an install-wide ledger. sys_metadata_activation declares systemFields: { tenant: false } (the object file's own comment: no tenant column on this table), ADR-0131 D6 names it the tenant-less activation ledger "without D3's reserved organization column", and ADR-0126 §5 keeps the authority gate at the door with the write operator-gated there. The data engine stamps created_by / updated_by from the context's userId (objectql engine.ts:21513), and the runtime's buildAutomationContext derives AutomationContext.userId from ExecutionContext.userId (domains/automation.ts:200), so the one picked key is exactly what the write records and the same spelling execute(flowName, context?) already uses. A tenantId would carry nothing the write reads; positions / permissions would invite the second gate the engine's own docblock refuses. The TSDoc says what an absent caller means ("an absent caller, or one without a userId, means an unattributed write ... never the answer for a door that has one") and that the channel is attribution only. The two ADR citations in the TSDoc read as cited.

  4. Nothing published moves. The diff touches three paths and no generated artifact. packages/spec/api-surface/contracts.json records IAutomationService (interface) and AutomationContext (interface) by name only (the api-surface baseline records existence, not resolution); no file under api-surface/, authorable-surface/ or the JSON-schema manifest names toggleFlow; no file under content/ names it. The wire schema automation-api.zod.ts:814 (POST /api/v1/automation/:name/toggle, ToggleFlowRequestSchema) is unchanged, so no authorable or request shape changes. The dev's check:generated reading (14/14 up to date, tree clean) is consistent with what the head's tree shows; the CI Spec property liveness, Check Changeset and Governed Surface Queue Guard runs are green.

  5. The TSDoc and ADR-0126 agree on where the gate is. The engine's toggleFlow docblock (engine.ts:5286-5294) says the §5 gate lives at the toggle route because it needs the caller; the new contract TSDoc says the same and adds that an implementation "neither refuses nor widens the switch" on the caller. That matches the seat ruling on automation: switching off a packaged flow or a packaged action writes the activation-ledger row and its audit row with a null actor, so nothing records which admin did it #26474 (letter A, item 1: doors hand { ...callerContext, isSystem: true } down and the core store writes with it instead of SYSTEM_CTX). The spec half leaves ObjectStoreMetadataActivationStore.setActive(row) (no context parameter) untouched, which is correct for this card's file surface.

  6. File surface held exactly as claimed (claim 6435538904: the signature and TSDoc in automation-service.ts, one pin test beside it, one changeset): no edit to service-automation, core, runtime or the doors. The branch is the harness-pinned claude/project-thread-x54rab, as the claim recorded.

Head check-runs: read at 2026-10-27T07:29:07Z, 46 runs: 24 success, 8 skipped (opt-in and path-filtered jobs), 14 in progress, 0 failure. Green already: all six Lint · jobs including ESLint, Type Check · source gates, Build UI Deps, Spec property liveness, Check Changeset, Governed Surface Queue Guard, the three claim guards, Check PR Size, Dogfood Regression Gate, Plan Test Core shards. Still in progress at that read: Build Core, Build & E2E UI, Type Check UI, Type Check · workspace, Type Check · debt ledger, Type Check · consumer gates, Test Core (1-8/8). Their conclusions are the gate verdicts; the landing waits for every check green.

② Semver level

Clause-②: yes (widening) is right: an optional third parameter on an optional interface method widens what a caller may pass and what an implementer may read, and narrows nothing (judgment 1). Metadata-protocol: none is right: no authorable key, accepted value, metadata type, meaning or default changes (judgment 4; the wire schema is untouched). Under the Post-Task Checklist rule a non-protocol widening ships patch, and the changeset .changeset/26506-toggle-flow-caller.md declares '@objectstack/spec': patch with both declaration lines line-initial, matching the PR body. No BREAKING banner and no ADR-0087 disposition marker are owed. feat(spec): as the changeset's title prefix with a patch level is consistent with the rule (the level follows the kind, not the prefix).

③ Boundary flags

  1. Carry to automation: switching off a packaged flow or a packaged action writes the activation-ledger row and its audit row with a null actor, so nothing records which admin did it #26474, widening the dev's note. The os-dev report (6436156952) and the PR's Acceptance notes name two runtime test files whose pins (toHaveBeenCalledWith(FLOW, false)) will need the caller argument once the door passes it. The head's tree has eight runtime test files with such pins, eighteen assertions in all: activation-gate-positions-name-authority.test.ts:259; automation-activation-posture-gate.test.ts:159,168,226; automation-body-validation.test.ts:132,139; automation-packaged-base-lock.test.ts:368,399; automation-toggle-deny-message.test.ts:301,305 (toHaveBeenLastCalledWith); automation-toggle-unknown-flow.test.ts:115,120,126,174; automation-write-capability-gate.test.ts:322,326,355; http-dispatcher.test.ts:456. Vitest's toHaveBeenCalledWith matches the argument list exactly, so each reds when a third argument arrives. The server half should budget for all eight, not two. Noted for automation: switching off a packaged flow or a packaged action writes the activation-ledger row and its audit row with a null actor, so nothing records which admin did it #26474's dev; nothing for this PR.

  2. Carry to automation: switching off a packaged flow or a packaged action writes the activation-ledger row and its audit row with a null actor, so nothing records which admin did it #26474: a docblock on the server side goes stale at this head. AutomationEngine.toggleFlow's docblock (engine.ts:5288-5294) says the contract has "no caller channel and no room to grow one on this line". After feat(spec): optional caller on IAutomationService.toggleFlow #26545 lands that sentence is false; it is the server half's to rewrite when the engine starts reading the caller (the dev's file surface rightly excluded engine.ts). Also flow-activation-store.ts:68 and flow-definitions.ts:472 describe the two-argument shape; same owner.

  3. The non-human caller note needs no carrying. AutomationContext declares no actor label; a service principal or agent on this channel names a userId or nothing. The seat ruling's item 1 hands { ...callerContext, isSystem: true } down on the sibling doors, so that is already the server half's shape and no reader asks for a label today. Agreed: carrier none.

  4. Boundary held. No packages/spec path was touched by the server lane (its red line), and no server path by this spec card. The claim's Container & model: S, mode:thread, model: TIER_DEFAULT is the dispatch's; the PR carries no governed path (docs/adr/**, .claude/**, workflows) and the Governed Surface Queue Guard run is green, so this record is at-tier for the schema face only.

Implemented-by: claude/project-thread-x54rab
Reviewed-by: session_01WGufzfhobWEgUUrjz4rrbh

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · domain:spec seat 1 (#6017) · session session_01WGufzfhobWEgUUrjz4rrbh · 2026-10-27T07:53Z

Head f3ce50a7cc2bb55ce12807ae1181253966ac26e2. Card #26506 (spec half of #26474, seat ruling letter A), claim 6435538904, dev report 6436156952.

  • Contract review: owed at CONTRACT_REVIEW_TIER, because packages/spec/src/contracts/automation-service.ts is touched. PASS 6436279001 names this head. toggleFlow?(name, enabled, caller?: Pick<AutomationContext, 'userId'>) is a true widening. The two-parameter class implementer, the Partial door host, two-argument callers and a required-third-parameter implementer all still type-check, and the pin test is compiled. The shape fits the install-wide, tenant-less activation ledger. The TSDoc says an absent caller means an unattributed write. No published baseline moves.
  • Carried to automation: switching off a packaged flow or a packaged action writes the activation-ledger row and its audit row with a null actor, so nothing records which admin did it #26474: the server half must update 18 exact-argument door-test pins across 8 runtime test files, plus the stale "no caller channel" prose in service-automation (6436285999).
  • Shape: Fixes #26506, 3 files. '@objectstack/spec': patch, Clause-②: yes (widening), Metadata-protocol: none on the body, the changeset and the claim. check-governed-merges --pr 26545: NOT governed, 121 changed lines.
  • Gates: check-runs on the head are 40 success, 8 skipped and 0 red. mergeable_state is clean.
  • Landing: Tier S. pr_ready + automerge_enable in this act.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 27, 2026 07:54
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 27, 2026 07:54
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit d9bf777 Oct 27, 2026
49 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-x54rab branch October 27, 2026 08:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec(automation): IAutomationService.toggleFlow has no caller channel, so a flow switch-off cannot record which admin did it (the spec half of #26474)

2 participants