Skip to content

Flow clone door → "new similar": the copy lands in a writable target package, by default the paired <base>.custom, never package-less #28149

Closed

Description

@objectstack-fleet

epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848

Filing gate: ④ child of epic #28236 — re-scoped from ADR-0146 child 2c on the maintainer's rulings of 2026-10-30, verbatim: 「方向定为包级覆盖:代码和 Studio 用同一机制,定制都进 .custom。」 · 「等我拍板的 8 个问题,全部同意」 (Q6: clone is kept only as "new similar", landing in <base>.custom). The original body (2c, optional packageId, <base>.customize) is in this card's edit history. ⛔ Not a claim.

Blocked-by: #28407

Part of #28236 (P2, child N-21) · governs: ADR-0146 as rewritten by N-01, ADR-0070 D5/D6 · lane: domain:server · size: S–M.

Why it waits. The door's default target is the paired <base>.custom package, created on demand by the .custom ensure door (epic child N-13, #28407 — itself waiting on N-08 #28404 for the pair constants). ⛔ A dev dispatched while no ensure door exists reports premise_still_valid: false instead of building a second creation path.

Business reason. Cloning a packaged flow today writes a copy that belongs to no package — the scope ADR-0070 D5/D6 retired — and, because the original keeps running, a record change fires both (measured 2026-10-30 on showcase: showcase_urgent_task_alert and its _copy both ran). The customer's work sits outside every package Studio can open and outside every export. Under the ruled direction, a "new flow like this one" is a new item of the paired .custom package.

Measured (d6c0a75f1a).

  • packages/runtime/src/flow-clone.ts strips the ADR-0010 envelope (_packageId, _packageVersion, _provenance: 'package', _lock) and sets no package, so the copy is package-less.
  • POST /automation/<name>/clone takes a mandatory new name and nothing else; PackagedAutomationPage.tsx is its only caller.

Wanted.

  1. The door takes a target package. Given: it must be an installed, writable package inside whose dependency closure the flow's objects lie (else a worded refusal in the DUPLICATE_SOURCE_NOT_A_BASE family). Omitted: the target is the source package's <base>.custom, ensured through N-13's door.
  2. ⛔ No package-less clone after this card: the omission no longer writes a package-less row.
  3. The copy is written inactive (definition status draft), so a clone never double-runs beside its original; the response says so in the server's words.
  4. Contract: request schema in packages/spec (Zod first), the route ledger's requestSchema, the SDK client and the OpenAPI output regenerated; Clause-② / Metadata-protocol lines filled honestly on the PR.
  5. Tests: default lands in <base>.custom with no base envelope; explicit writable target lands there; read-only, unknown and out-of-closure targets refused; the copy is inactive.

Not here. Creating .custom (N-13); the Studio "new similar" button (N-22); overriding a flow in place (N-11 / N-18); clone lineage (ADR-0126 §9 second bullet).

Dedupe. objectui#13270 (clone result offers, console side); objectui#11553 (package-less scope). No other card changes the clone door's target.

Links back: #28236, #28130 (superseded), ADR-0146, ADR-0070 D3/D5/D6, ADR-0010.


Generated by Claude Code

Activity

  1. added
    enhancementNew feature or request
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Oct 30, 2026
  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848

    Recorded 2026-10-30T15:21Z (desktop session 040dfd80-c4c9-411b-895c-698e785a6848).

    Label transition: pm:queue → pm:epic (one replace write, read back: enhancement,priority:p2,pm:epic,area:studio,domain:server); linked as a sub-issue of #28130.

    Instruction — the maintainer, in a direct desktop session, verbatim: 「相关的issue 你都应该标记 epic,避免被车队认领」. The card is reserved to the epic subtree; no domain seat takes it.

    Why it waits: in the same session the maintainer ruled the package-level override direction — 「方向定为包级覆盖:代码和 Studio 用同一机制,定制都进 .custom。」 — and, on the follow-up questions, 「等我拍板的 8 个问题,全部同意」, which includes keeping clone only as a "new flow like this one" that lands in the paired <base>.custom package. This card is re-scoped (or replaced) in the epic's re-plan; nothing is claimed until then.

    The label write and the sub-issue link above were made with the maintainer's own account (hotlong) from the desktop session before this seat switched to the fleet write tools; this record is the provenance the transition owes.

  3. changed the title [-]Flow clone door takes a target `packageId` (a writable package) so a clone of a packaged flow no longer lands in the retired package-less scope (ADR-0146 D3, ADR-0070 D5; #28130 child 2c)[/-] [+]Flow clone door → "new similar": the copy lands in a writable target package, by default the paired <base>.custom, never package-less[/+] on Oct 30, 2026
  4. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848

    Recorded 2026-10-30T18:38Z (desktop session 040dfd80-c4c9-411b-895c-698e785a6848).

    Re-scoped as N-21 and parked behind the ADR rewrite.

  5. 11 remaining items

  6. added
    priority:p1High: required for production / M2
    and removed on Oct 31, 2026
  7. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
    2026-11-01T06:08Z

    Notify: rider · #28149 (N-21) · Setup's "Open the clone in Studio" link

    Found by the P2 drafting review (epic #28236). ui/packages/app-shell/src/views/setup/PackagedAutomationPage.tsx:573–578 draws "Open the clone in Studio" with studioOrgScopePath({ type: 'flow', name }), which is the package-less scope. After this card the copy lives in the target package (Wanted 1–2), so that link lands nowhere.

    Asked of this card, in the same PR: the clone response names the package the copy landed in, and that one link reads it. The link opens the copy in Studio's automations surface of that package, in the shape the dev settles. A release cut right after this card must not ship a dead link. N-22 (#28567, Studio "New similar") only checks the link and re-points it only if this PR did not. This is a rider on the card's own scope (its console surface), not a new card; it is one ui/ line declared beside the card's domain:server lane.

  8. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
    2026-11-01T06:51Z

    Unblocked · p1 · pm:queue (epic stall patrol)

    ⛔ Not a claim.

  9. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

    Claim: PM loop round 4 · card thread · 2026-11-01T07:21Z
    Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5pRVPsxnFxPBAQLUMh
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-sdqbrt (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#2
    Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. Also the maintainer, 2026-11-01T06:40Z: 「任务很多啊 is:issue state:open label:pm:queue label:domain:server」. Epic #28236 direction, the maintainer 2026-10-30T15:21Z (quoted on this card): 「方向定为包级覆盖:代码和 Studio 用同一机制,定制都进 .custom。」 · 「等我拍板的 8 个问题,全部同意」 (Q6: clone kept only as "new similar", landing in <base>.custom). Unblock 6554634959: the dev builds on N-13's door on main as the only way to create <base>.custom; ⛔ no second creation path. Rider 6554259755 rides in the same PR.
    File surface: packages/runtime/src/flow-clone.ts and the POST /automation/<name>/clone handler and route-ledger entry; a request schema in packages/spec; the SDK client method in packages/client; regenerated OpenAPI; the rider's link in ui/packages/app-shell/src/views/setup/PackagedAutomationPage.tsx; tests and changesets. Calls N-13's ensureCustomizationPackage (packages/metadata-protocol) without re-implementing it.
    Container & model: M, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: high
    Clause-②: yes (widening — the clone door gains an optional target package and its response names the landed package; the default target moves from package-less to <base>.custom and bad targets are refused, so the dev declares a narrowing arm too if CLAUSE2_ARMS reads it that way; a contract review is owed before the queue, at CONTRACT_REVIEW_TIER since a spec schema moves)
    Metadata-protocol: none (expected; the dev measures and declares)
    Responsibility: the code is the flow clone door · the platform path is ADR-0146 D3's paired .custom package via N-13's ensure door, under ADR-0070 D5/D6 (no package-less scope) · reached by an administrator cloning a packaged flow from Setup's packaged automation page
    Thread-read: none
    Premise: holds (read 2026-11-01T07:21Z at origin/main: flow-clone.ts strips the ADR-0010 envelope and sets no package; N-13's ensure door is on main since #28407 closed)
    Serial constraints cleared: #28407 (N-13) closed as completed; open PR #28554 (#28410) edits packages/metadata-protocol/src/protocol.ts and protocol-packaged-base-refusal.ts, so the dev reads its diff first, does not edit its hunks, and merges origin/main once if it lands first
    Resume-from: none — fresh from origin/main

    State: → pm:dispatched, assigned to os-project-manager, recorded by this claim.


    Generated by Claude Code

  10. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
    os-dev-report
    {
    "issue": 28149,
    "status": "done",
    "branch": "claude/project-thread-sdqbrt",
    "pr": "#28621",
    "session": "session_01FEkQ5pRVPsxnFxPBAQLUMh",
    "premise_still_valid": true,
    "summary": "POST /automation/:name/clone is now ADR-0146 D4's "new similar". The copy lands in a writable package: by default the source's paired .custom, ensured in process through N-13's ensureCustomizationPackage (no second creation path), or the package named by the new optional package member. It is written switched off (status 'obsolete', because 'draft' arms like 'active' in the engine), with a first-write pin so an existing row is never overwritten, and the answer is { flow, packageId, notice }. The target rule (installed 422 / writable 422 WRITABLE_PACKAGE_REQUIRED / dependency closure 409 RESOURCE_CONFLICT) lives in runtime domains/new-similar-target.ts, shared with #28563. Also in this PR: CloneFlowRequestSchema/CloneFlowResponseSchema in spec, client.automation.clone, the route-ledger row moved to sdk, the Setup 'Open the clone in Studio' link reading data.packageId (rider 6554259755), and the metadata-lifecycle docs row.",
    "tests": "Head 71dca74 (main merged at de3fafc, regenerated from the merged tree). New runtime/src/domains/automation-flow-clone-custom-package.test.ts runs on the real protocol + ObjectQL + sqlite sys_metadata; red-first on base sources gave 11 red / 2 green (packageId undefined, 'draft' not 'obsolete', package refused unknown_field, a local clone 200 package-less). At 8a0ba37, under os-verify-lock: runtime vitest run --project local --project repo: Test Files 506 passed (506), Tests 9121 passed | 19 skipped, VERDICT command-exit 0. Client: tsc -p tsconfig.test.json clean; Test Files 53 passed (53), Tests 690 passed. ui: PackagedAutomationPage.test.tsx 32/32. app-shell type-check cannot resolve sibling @object-ui/* in this container (no ui build), so it is left to CI Type Check UI; no error names a touched file. Ablation via scripts/ablation-replace.mjs (committed first, restore verified against the HEAD blob): ensure call -> target = owner; gives 5 red; FLOW_CLONE_STATUS 'obsolete' -> 'draft' gives 4 red. Scoped eslint over the touched files: exit 0, 0 errors (one existing react-hooks/set-state-in-effect warning on PackagedAutomationPage.tsx:333, not a changed line).",
    "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 8a0ba37: 140 gates, each run with its exit code captured before any pipe; all 140 exit 0. --ran reconciliation: '140 derived famil(ies) accounted for — 140 run, 0 NOT-MEASURED'. The first pass at c3369fd found real reds, all fixed: api-surface, export-origins, strictness-ledger and check:docs stale (regenerated); spec-parsed-alias (added CloneFlowRequestParsed); test-source-alias (aliased /^@objectstack\/lint\/runtime$/ in runtime vitest.config.ts); doc-authoring (dropped an issue id from the route-ledger note string); route-envelope (new-similar-target.ts declared handBuilt 0, byte-identical to #28563's lines). The last commit, 71dca74, touches only two dogfood test files. Declared narrowing: at that head I re-ran only the 15 test-reading gates (cross-package-test-inputs, query-options-erasure, objectql-double-limit, test-source-alias, where-matcher, doc-authoring, issue-citations, nul-bytes, engine-double-contract, registry-log-declared, rest-log-spy-declared, refd-timer-probe, closed-ceremony-text, role-word, org-identifier), all exit 0. PR check-runs were not read yet: CI was still starting at report time.",
    "dogfood_battery": "8a0ba3770f · pnpm --filter @objectstack/dogfood test after pnpm --filter '@objectstack/dogfood^...' build, under the lock · VERDICT command-exit 1 · Test Files 3 failed | 362 passed | 3 skipped (368) · Tests 3 failed | 2936 passed | 28 skipped (2967). Failures: (1) flow-credential-channel 6: the env-flow control clone answered 400, the intended narrowing; fixed in 71dca74 to create a writable package and name it. (2) flow-provenance-server-held 'a clone of a shipped flow…': the copy now lands in com.example.showcase.custom and its meta read carries the pair's _packageId (the measured META_BOUND shape); fixed in 71dca74 to assert the pair, and that the round-trip PUT saves 200. Re-run of those two files plus automation-flow-clone-door at 71dca74: Test Files 3 passed (3), Tests 29 passed, VERDICT command-exit 0. (3) route-ledger-live-mount-parity: 'GET /packages/:id/customizations — LEDGERED BUT NOT MOUNTED'. That is main's, from #28595 (handler in domains/packages.ts and the ledger row, but no mountPackagesRoute in dispatcher-plugin.ts). Not caused by this diff and not fixed here; see out_of_scope_findings.",
    "mcp_calls": "3: mcp__github__list_pull_requests ×1, mcp__github__pull_request_read (get_files) ×2. All reads, no write tool.",
    "api_writes": "Write budget spent: 2 git push (the PR head was conflicted after #28595 landed, so main was merged and pushed again), 1 relay pr_create (fleet-write run 41290018382 success, read-back 8531/8531 bytes identical, assignees none), and this report comment through post-stamped. No REST proxy writes; 1 gh api GET (claim comment 6554908823).",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: public door + wrong answer — GET /api/v1/packages/:id/customizations answers 404 on a live stack · evidence: dogfood route-ledger-live-mount-parity at 8a0ba37, 'LEDGERED BUT NOT MOUNTED'. #28595 added the domain arm (packages.ts) and the route-ledger row, but packages/runtime/src/dispatcher-plugin.ts has no mountPackagesRoute('get', '/:id/customizations', …) beside '/:id/ensure-customization' (line ~1613). Dogfood skips PR CI, so main is red on that pin · dedupe words: customizations route not mounted, mountPackagesRoute, #28411",
    "carrier: seat 2 (hand-back message) · noted, not filed"
    ]
    }


    Generated by Claude Code

  11. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

    Landing record · #28149 · PR #28621

    domain:server seat 2 · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-11-01T11:37Z

    Reading Probe Result
    Merged PR #28621 state merged, merge commit f23e0512
    On main git merge-base --is-ancestor f23e0512 origin/main yes
    Queue refs git ls-remote origin refs/heads/gh-readonly-queue/* matching 28621 0
    Content git grep -c CloneFlowRequestSchema origin/main -- packages/spec/src/api/automation-api.zod.ts 4

    Release: claim 6554908823 (session_01FEkQ5pRVPsxnFxPBAQLUMh, branch claude/project-thread-sdqbrt) · landed.

    • State: pm:dispatched removed; assignee cleared; the card closed on merge.
    • Resume-from: none.

    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:studioChanging a running app without code — authoring, publish, docs and the portaldomain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority: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