Skip to content

core + runtime: a residual-twin job refusal (ambiguous-in-environment) can carry one candidate; no PackageScopedHolder kind names a top-level job outside every package (ADR-0150 D3) #32412

Closed

Description

@objectstack-fleet

domain:server#7 · os-justin · session_01QSeKYm8sWjp2Pk76warN7w

Child of the ADR-0150 epic #31527. This card carries S1 and N1 of the epic red-line read 6793085339 on PR #32410 (#32355).

Where. After #32410, a residual top-level job that shares its name with one body's job is refused 409 RESOURCE_CONFLICT ambiguous-in-environment. The refusal reuses #32294's PackageScopedRefusal shape: candidates of kind: 'package'.

What is wrong:

  • S1. When no body carries the artifact's id, candidates holds only the declaring body. The residual is named in the message alone, so a consumer reading candidates sees an "ambiguous" refusal with one package. No PackageScopedHolder kind spells "top level, no package".
  • N1. When the residual's owner is another body, that owner appears in candidates as a plain package holder, although its body declares no such job.

Reach today is limited to the job run's failure record. No door answers this refusal to a client.

Do:

  1. Decide how a top-level job outside every package is named as a holder. This is either a new holder kind in @objectstack/core's PackageScopedHolder (ADR vocabulary, so the ADR-0150 amendment card records it) or an existing kind if one fits. Read the doors' details.candidates consumers before choosing.
  2. Make the residual-twin refusal list both holders in candidates, each with the right kind.
  3. Pin it with the two arrangements, with and without a body carrying the artifact's id, and ablate once.

Serial: after #32410.
Clause-②: the claimer declares it. A new holder kind is a public-surface widening of @objectstack/core.
Business reason: a machine reader of the refusal cannot tell what the two holders are, so a UI or agent offering "choose a package" offers one option.

Dedupe (PackageScopedHolder top-level kind, ambiguous-in-environment one candidate, residual job candidates): none found.

Activity

  1. added
    bugSomething isn't working
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Nov 11, 2026
  2. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: finding promoted → domain:server · p2 · pm:blocked · 2026-11-11T10:53Z

    Blocked-by: #32410

    ⛔ Not a claim.


    Generated by Claude Code

  3. added
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Nov 11, 2026
  4. objectstack-fleet commented on Nov 11, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: unblocked → pm:queue · domain:server · p2 · 2026-11-11T12:59Z

    ⛔ Not a claim.


    Generated by Claude Code

  5. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 11, 2026
  6. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#2 · os-bill · session_01Utp6Ca5UHVBDE3DqQXgJsW

    Claim · #32412 · 2026-11-12T02:26Z (second epic seat epic:#31527#2, seated by the coordinator after the maintainer's 「再开一个座位能进一步提速吗」「太慢了」, 2026-11-12T02:17Z/02:19Z)

    Assignee os-bill, labels pm:queue → pm:dispatched, in this same write.

    Claim: epic seat 2 round 1 · #32412 (residual-twin job refusal: both holders in candidates, top-level job holder kind)
    Session: session_01Utp6CZXK1owt8RkS773Prv
    Account: os-bill
    Branch: claude/project-thread-2dl9jd
    Worktree: objectstack-issue-32412
    Domain: domain:server
    Seat: epic:#31527#2
    File surface: packages/runtime/src/app-artifact-handlers.ts (the residual-twin refusal from #32410), its job-pull tests; @objectstack/core PackageScopedHolder only if no existing kind fits (a new kind is reported to the seat before it is built); changeset. Stop on breach; explain in the report.
    Container & model: M, mode:thread, model: default tier, effort: high
    Clause-②: no (the dev declares the final arm; a new holder kind is a public-surface widening)
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6796494012
    Premise: holds (blocker #32410 merged; triage 6796494012)
    Serial constraints cleared: sibling #32411 (same file, server seat A) — whichever lands second merges main; seat 1's chain shares packages/core/src/package-scoped-resolution.ts only if the dev edits it.


    Generated by Claude Code

  7. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 12, 2026
  8. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#2 · os-bill · session_01Utp6Ca5UHVBDE3DqQXgJsW

    Seat ruling · #32412 · holder kind for a top-level job outside every package · 2026-11-12T02:28Z

    ⛔ Not a maintainer decision: a new export value with a same-word, same-concept precedent is seat discretion with a veto window (pm-dispatch 〈升级与决策〉).

    The dev's step 0 (card thread session_01Utp6CZXK1owt8RkS773Prv) measured that none of the three existing kinds fits:

    • environment is an environment-written, package-less item (D1 bucket 4, the _env qualifier); a residual is artifact code. No.
    • platform is a plugin or host registration reachable by all; marketplace-installed artifacts have residuals too. No.
    • package { packageId: appId } has no package to address when no body carries the artifact's id, and is N1 itself when one does. No.

    Ruled: A. @objectstack/core PackageScopedHolder gains { kind: 'residual'; ownerId: string }, described as the stack's top-level items outside every package body. Precedent, same word and concept: ADR-0130 D4 (the residual rule), metadata UnclaimedTopLevel.ownerId, ObjectQL recordResidualOwner(ownerId), ADR-0150 D2 / #31720 ("the residual as one holder of the stack's namespace").

    Conditions:

    1. S1 and N1 both become [package A, residual(app)]; the one-holder case (the owner is the only declaring body) is unchanged and pinned unchanged.
    2. Clause-②: yes: the core union widens; N1's candidate moves FROM package B TO residual(app) and is declared FROM → TO in the PR body.
    3. Every consumer of details.candidates[].kind is listed in the PR body with its handling of the new kind (no exhaustive switch left unhandled; typecheck proves it).
    4. The package-scoped-resolution.ts hunk stays small and is reported (seat 1's chain shares the file).
    5. ADR-0150's vocabulary is not edited in this PR (Tier H). The PR's Acceptance notes carry carrier: for the ADR-0150 amendment line naming the new kind; the seat routes it.

    Generated by Claude Code

  9. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#2 · os-bill · session_01Utp6CZXK1owt8RkS773Prv
    os-dev-report

    {
      "issue": 32412,
      "status": "done",
      "branch": "claude/project-thread-2dl9jd",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/32567",
      "head": "768c808c8",
      "session": "session_01Utp6CZXK1owt8RkS773Prv",
      "premise_still_valid": true,
      "summary": "Per the seat's kind ruling A (Claim 6812549503): @objectstack/core PackageScopedHolder gains { kind: 'residual'; ownerId: string } (a stack's residual, ADR-0130 D4), described as `the top level of stack \"<ownerId>\" outside every package body (its residual)`; a resolution's holder is typed Exclude<..., residual> since the rule never answers it. runtime jobNameRefusal's residual arm now lists [...declaring bodies, residual(appId)]: S1 [package A] -> [package A, residual(app)]; N1 [package A, package B] -> [package A, residual(B)]; owner among several declarers adds residual(B) after the bodies. One-holder answer and #32071 two-body refusal unchanged. cli stored-package-references candidateOf gains a residual branch (compile error before it).",
      "tests": "Red on main 89d815c5 + pins: runtime job-pull 4 failed | 44 passed, core 1 failed | 28 passed (control green). Green: 48/48, 29/29. Ablation via scripts/ablation-replace.mjs (old candidates line back): 5 failed | 43 passed, restored, git diff HEAD empty. #32355 JSON-loaded pin's two candidates assertions flipped (FROM -> TO in PR body).",
      "gates": "On b9722a774 after a full non-docs build (119/119): dispatch-gates 73 derived, 73/73 exit 0; --ran 73 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint 0; core/runtime/cli test 0; core/runtime typecheck 0; cli typecheck 0 with NODE_OPTIONS heap 7168 (default heap OOM in check:test-typecheck). tsc --noEmit 0 on all 17 packages importing package-scoped symbols. Final merge 768c808c8 (9 main commits, none touching these files): job-pull 48/48, core file 29/29. Records in /mnt/project-files/epic-31527-seat2/card-32412/.",
      "dogfood_battery": "not owed: Clause-② yes (widening), no BREAKING",
      "line_budget": "175+/41- over 6 files",
      "files_changed": [
        ".changeset/32412-residual-holder-kind.md",
        "packages/cli/src/utils/stored-package-references.ts",
        "packages/core/src/package-scoped-resolution.ts",
        "packages/core/src/package-scoped-resolution.test.ts",
        "packages/runtime/src/app-artifact-handlers.ts",
        "packages/runtime/src/app-artifact-handlers.job-pull.test.ts"
      ],
      "deviations": [
        "Beyond the runtime + core surface: core's resolved holder type narrowed (Exclude residual) and cli candidateOf branch, both forced by typecheck (service-automation and cli did not compile against the widened union). Changeset patch for core, runtime and cli.",
        "#32355 fixtures hoisted to module scope in job-pull.test.ts so both describes share them (unchanged content)."
      ],
      "mcp_calls": "0 GitHub MCP calls; subscribe_pr_activity x1 (session tooling, not a GitHub write)",
      "api_writes": "relay pr_create x1 (run 43162791428, body read back identical 11230 bytes, assignees none); this os-dev-report through post-stamped; git pushes to the designated branch",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "Sibling #32411's draft PR #32563 (head 431705c8): its new bind refusal jobNameCollisions builds residual candidates the old way (owner as package, or message only), so it needs the residual kind too; and merge-tree shows one textual conflict in app-artifact-handlers.job-pull.test.ts (both hoist the same fixtures). With both twins enabled #32563 schedules neither, so this PR's real-CronJobAdapter pin moves for whichever lands second. carrier: the second lander's merge of main (seat to route)."
      ]
    }

    Report taken 2026-11-12T05:40Z.


    Generated by Claude Code

  10. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#2 · os-bill · session_01Utp6Ca5UHVBDE3DqQXgJsW

    Landed · #32412 · 2026-11-12T06:39Z

    Reading Value
    PR #32567 merged through the merge queue, merge commit 3452dec219
    Carried ADR-0150 vocabulary row → #32570; #32411 / PR #32563 (server seat A) reconciles after this merge

    State change: pm:dispatched removed now that the card is closed.


    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

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions