Skip to content

automation: New similar on a flow with a live override answers 403 NOT_OVERRIDABLE, because the copy keeps the source's overrides block #29650

Closed

Description

@objectstack-fleet

epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848

Filing gate: ④ child of epic #28236, filed on the maintainer's word in direct chat with the epic PM seat, 2026-11-03: 「发记录并立卡」 and 「相关卡 p1, 让车道处理」. ⛔ Not a claim.
QA-source: #29648 · automation.package-flow-override · off-clause
Part of #28236 · governs: ADR-0146 D2, D4, D9
Reader: domain:server (the clone door in packages/runtime).
Dedupe (open and closed): clone override, New similar, NOT_OVERRIDABLE clone. #28567 and #28149 built the door, and both predate a live override as the clone's source. New.
reach: any packaged flow customized in Studio. Studio and the API both meet it.
type: Bug

Business reason. An administrator who customized a flow and wants a second variant presses New similar and gets an English sentence about a declaration they never wrote. The only way forward in the product today is to delete their customization first.

What happens

Measured on main at 322cf9068f, twice in Studio and once over the API.

source state POST /api/v1/automation/showcase_budget_approval/clone
no override 200, status obsolete, packageId com.example.showcase.custom
published override 403 NOT_OVERRIDABLE: "'flow/showcase_budget_approval_copy' declares an override of 'com.example.showcase', which ships no flow named 'showcase_budget_approval_copy'. Remove overrides to keep it as 'com.example.showcase.custom''s own item, or correct the name (ADR-0146 D2)."

The Studio dialog (auto-new-similar-dialog) shows that sentence and stays open. No flow is written.

Reproduce

  1. Publish an override of showcase_budget_approval (Customize, edit a node label, Publish).
  2. POST /api/v1/automation/showcase_budget_approval/clone with {name:'showcase_budget_approval_copy', label:'x'}. Expected: a switched-off copy in the pair (ADR-0146 D4). Actual: the 403 above.
  3. Restore package original, and repeat step 2: 200.

Why (read from source, the dev confirms)

cloneFlowDefinition (packages/runtime/src/flow-clone.ts:255) copies the whole definition and removes only FLOW_CLONE_DROPPED_KEYS (:159), which do not include overrides. So the copy declares it overrides the base under a name the base does not ship, and the write gate is right to refuse that.

Wanted

  • The copy never carries the source's overrides block: it is the pair's own item, under a new name (D2, D4).
  • It copies what the source serves: with a live override, the override's definition. The dev states this in the PR, and asks if the code says otherwise.
  • A pin at the clone door with a live override as the source, and a clause added to automation.package-flow-override, whose steps today clone only after the restore, so they cannot see this.

Links back: #29648, #28567, #28149, #28236, ADR-0146 D4.

Activity

  1. added
    bugSomething isn't working
    priority:p1High: required for production / M2
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Nov 2, 2026
  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

    Claim: PM loop round 1 · 2026-11-03T00:26Z
    Session: session_01JQwxbZUR3xvHyDPCjNL5P4 (the seat); the dev is the card thread session_01JQwxbYmYA3GtqMUGHGQkR8
    Account: os-warren
    Branch: claude/project-thread-yzu3d4 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own
    Domain: domain:server (sub-issue of epic #28236, domain inherited; handed to the lane by the epic PM's filing line)
    Seat: domain:server#5
    Ruling-ref: none on the card. Governing: ADR-0146 D2 and D4.
    File surface: packages/runtime/src/flow-clone.ts (FLOW_CLONE_DROPPED_KEYS, cloneFlowDefinition) and the clone door's tests; the dogfood/QA case automation.package-flow-override (a clause that clones while the override is live); one .changeset/29650-*.md. ⛔ No packages/spec/**; ⛔ no packages/metadata-protocol/src/protocol.ts unless measured necessary (then stop and report).
    Container & model: M, mode:thread, model: default (--tier: no path mandate), effort: high (p1)
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the code is the flow clone door's copy · New similar on a customized packaged flow answers 403 and writes nothing · every administrator who customized a packaged flow in Studio, or the API
    Thread-read: none
    Premise: holds (read on origin/main b391feb1: FLOW_CLONE_DROPPED_KEYS does not name overrides; the dev reproduces red first)
    Serial constraints cleared: no other in-flight claim on packages/runtime/src/flow-clone.ts (seat 4's #29649 is in domains/packages.ts).

  3. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-warren · session_01JQwxbYmYA3GtqMUGHGQkR8
    os-dev-report

    {
      "issue": 29650,
      "status": "done",
      "branch": "claude/project-thread-yzu3d4",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29689",
      "session": "session_01JQwxbYmYA3GtqMUGHGQkR8",
      "premise_still_valid": true,
      "summary": "Premise held: cloneFlowDefinition dropped only the read decorations, the protection envelope and protection, so with a live override the copy kept the source's overrides block under its new name and the save gate answered 403 NOT_OVERRIDABLE. FLOW_CLONE_DROPPED_KEYS now also derives Object.keys(OverrideDeclarationFields) from @objectstack/spec/kernel, so the copy is the pair's own item. The door's source is automationService.getFlow(name), the engine map entry, which with a published override is the override's body (ADR-0146 D9 item 1), so the copy carries the override's definition; the PR states this and asks a reviewer to say if they read it differently. QA case automation.package-flow-override goes to revision 3 with step 10 and acceptance[6] (clone while the override is live), appended so existing indices do not move; one runtime patch changeset.",
      "tests": "Red first at db4ce28f (pin only): new describe in packages/runtime/src/domains/automation-flow-clone-custom-package.test.ts (real better-sqlite3 + ObjectQL + ObjectStackProtocolImplementation; override saved into the pair declaring overrides, armed in the engine map; POST /automation/:name/clone through HttpDispatcher) -> 2 failed / 17 passed, AssertionError 403 NOT_OVERRIDABLE with the card's sentence; the no-override control cases in the same file stayed 200. After the fix: both clone suites Test Files 2 passed, Tests 38 passed. Ablation via scripts/ablation-replace.mjs --delete of the OverrideDeclarationFields spread (anchor 1 to 0, blob 9864c4f16874 to 60975c62ef63): 2 failed / 17 passed; restored, blob == HEAD and git diff HEAD empty. The suite imports flow-clone.ts from src, so there is no dist leg. Runtime pnpm test at head 14f1ec09: Test Files 529 passed, Tests 8514 passed, 19 skipped; typecheck exit 0.",
      "gates": "Local at 14f1ec09: dispatch-gates --commands derived 63 families; 62 exit 0. check-plugin-teardown-shape --self-test exited 3 on the shallow clone, then 0 after git fetch --unshallow origin main. NOT MEASURED: pnpm check:dual-build-cjs-loads, PREREQUISITE NOT MET (reads every package's dist; only the runtime closure was built), left to CI. --ran reconciliation: 63 derived, 62 run, 1 NOT-MEASURED, 0 UNRUN. Outside the derivation: runtime test exit 0, runtime typecheck exit 0, pnpm lint exit 0. CI check-runs: in_progress when this was written, not awaited.",
      "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2: POST pulls via the fleet-write relay pr_create (#29689, 6814 bytes sent and stored, identical); this os-dev-report comment via post-stamped.mjs. git push is not a REST write.",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": []
    }

    Clause-②: no and Metadata-protocol: none, confirmed from the diff (no packages/spec, no packages/metadata-protocol). No packages/metadata-protocol/src/protocol.ts change was needed. Report written after local verification, before CI converged.


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

    Landed · 2026-11-03T02:14Z

    Probe Reading
    PR #29689 MERGED 2026-11-03T02:13Z, merge commit c9636f1e50, through the merge queue
    #29650 closed completed by Fixes #29650

    Seat records: claim 6592058258, ACCEPT 6593411405 on head 14f1ec09 (TIER_DEFAULT, not governed). pm:dispatched comes off in the same round. Follow-ups: none.

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

Metadata

Metadata

Assignees

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions