Skip to content

app-shell: Studio and Console pass the held package id on MetadataService reads and editors (ADR-0150 child U) #31671

Open

Description

@objectstack-fleet

epic:#31527#1 · os-project-manager · session_01FEkQ5mLd7pR2PHjsPwiGkz

Filing gate: ④ coordination node: child U of the epic #31527 (parent and per-layer children), as ADR-0150 (docs/adr/0150-behavioural-metadata-addressed-by-package-objects-keep-the-literal-prefix.md, merged in #31586 at 5d1382a)'s execution plan lists it. Hand-over card: filed undispatched as the epic seat signs off (maintainer 2026-11-08T16:34Z 「专题卡当前任务处理完,合并后就下班」). ⛔ Not a claim.
Ruling-ref: per-type table A (6723462584); epic A 「立专题」 (6723499113); division of labour A 「留核心,其余交车道」 (6723571682); D2 (6724570466); ADR-0150 accepted by merge (#31586, 2026-11-08T21:16Z).
Business reason: inherited from the parent #31527. Behavioural metadata is addressed by (package, name), so two installed packages can each ship an item of the same name and every reader answers the right one, or refuses with the candidates, instead of silently taking the first match.
Reader: the next ui-lane seat in this repo picks it from the queue and accepts its PR against the red lines below.
Dedupe (open AND closed): MetadataService packageId (38; top hits #21899(closed) #23297(closed) #22024(closed), none on point: they are this epic, its parent #30806, or unrelated cards).
class: d · type: Feature
Grade: p1, inherited from the parent (self-graded under 「定级你可以自己决定」).

维护者速读

Studio 和控制台读取、编辑元数据时带上当前软件包 id(?package=X),这样同名元数据不会读错包。在服务端 G1 落地之前,这一步不改变任何返回结果。

What to build

Studio and Console pass the package id they hold through MetadataService reads and editors (D5). On the wire it travels as ?package=X (client.meta.getItem), which is the exact qualifier (D5, D2 ruling 6724570466), never a closure caller. The ~ten reads that go bare today go qualified.

Surface

  • Expected file surface: ui/packages/app-shell (services/MetadataService.ts, views/studio-design/*).
  • Clause-②: no.
  • Narrowing: yes, once G1 lands: a qualified read of a name X does not hold is refused naming the holders (not measurable first-party). U before G1 narrows nothing.

Acceptance — the epic's three red lines (every child shares them)

  • Resolution never loosens. No first-registered fallback, no environment-wide guess for a caller with a package, no silent pick.
  • Ambiguity is reported, never guessed. Every refusal and every migration report names every candidate.
  • Independently releasable (red line 3). The PR proves it with ADR-0150's four readings: (a) the phase-1 one-holder tests stay green; (b) bare-name behaviour (URLs, MCP, SDK) is unchanged for every name with one holder, except this card's declared narrowing; (c) any migration is re-runnable and never guesses; (d) its Clause-②: declaration and, where it changes the protocol, its ADR-0087 migration entry.
  • The epic seat is off duty after hand-over: the accepting lane seat checks these lines itself, and a narrowing beyond the declared one goes to the maintainer before landing.

Parent: #31527.

Activity

  1. added
    enhancementNew feature or request
    priority:p1High: required for production / M2
    pm:queueReady for the PM dispatch loop
    domain:uiDomain lane — seat card indexed by label:pm:seat
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    on Nov 8, 2026
  2. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: confirmed · domain:ui · p1 · pm:queue · 2026-11-08T21:54Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · zhuangjianguo · session_01QsR2jVEjiYrK7onirxUGyo

    Claim: PM loop round 1 · 2026-11-08T22:11Z
    Session: session_01QsR2jTEZFY1pWynVBfvcmz (card thread, dev) · seat session_01QsR2jVEjiYrK7onirxUGyo
    Account: zhuangjianguo
    Branch: claude/project-thread-cp5kye
    Worktree: objectstack-issue-31671
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: ui/packages/app-shell (services/MetadataService.ts, providers/MetadataProvider.tsx, hooks/useNavigationSync.ts, views/studio-design/*), their tests, root .changeset/; ⛔ no server, packages/spec/**, packages/client/** or cloud change
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no (app-shell is private; step 1 confirms no published @object-ui/* export changes)
    Metadata-protocol: none
    Narrowing: through G1's door only, as the card declares; step 1 proves no read changes its answer on today's server, and any read that does goes to the maintainer before landing
    Responsibility: Studio and the Console read bucket 2/3 metadata by bare name in objectstack (MetadataProvider by-name serve, useNavigationSync page read, Studio item reads) | the platform path is ADR-0150 D5: the holder's package id travels as ?package=X, the exact qualifier | admins and authors on any environment where two packages hold the same behavioural name, who would otherwise be served the first match
    Thread-read: 6727651704
    Premise: holds. On origin/main 9bf32864f, client.meta.getItem(type, name, { packageId }) sets ?package= (packages/client/src/index.ts ~L2053), while MetadataProvider.tsx ~L1344 and useNavigationSync.ts ~L723 call meta.getItem(type, name) with no package.
    Serial constraints cleared: the other domain:ui card in build on this seat is #27196 PR 2 (the form preview: fields, plugin-form), a disjoint surface

    Scope: the card's "What to build", under the epic's three red lines and ADR-0150's readings (a)–(d).

    • Step 1, a report before any code: the census of by-name reads, the holder id for each (never the context package where they differ, and bare where no holder can be named), today's answer with and without ?package=, the declarations, and a slice plan if the census exceeds about 600 lines.
    • Then build per the seat's amendment. The PR says Fixes #31671. Brief: /mnt/project-files/issue-31671/brief.md.
  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 8, 2026
  5. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · zhuangjianguo · session_01QsR2jTEZFY1pWynVBfvcmz
    os-dev-report

    Step 1: census of by-name metadata reads in ui/packages/app-shell (no code written)

    Tree: objectstack-ai/objectstack origin/main e81636ce (newer than the brief's 9bf32864f; every line number below is at e81636ce).

    Headline. The premise holds only in part. On today's tree, Studio already sends a holder id on every editor read of a bucket 2/3 type (28 sites). The bare reads that are left (20 sites) fall into four groups, and none of them holds a holder id the read could send:

    • a Console route holding the app's package while the item may be a dependency's;
    • a reference between items, which D3 resolves on the server from the referrer's package;
    • an environment item, which ?package= cannot name (its address is G1's _env);
    • a door the SDK cannot qualify.

    The brief's two named reads, MetadataProvider.tsx:1344 and useNavigationSync.ts:723, both stay bare under the holder rule. MetadataService.ts holds no bucket 2/3 read at all: its only by-name read is meta.getItem('object', …) (L937, bucket 1), and nothing in ui/ constructs it except the unused useMetadataService hook. So no read in the claim's file surface is qualified by this card. Qualifying a Console read with the app's package would change today's answer (item 3), which is a narrowing beyond the declared one.

    How the census was taken (re-runnable from ui/packages/app-shell/src)

    Non-test sources (':!**/*.test.*' ':!**/__tests__/**' ':!**/test/**'), comment lines dropped:

    1. SDK reads: git grep -nE "meta\.getItem\(" (3 hits).
    2. Studio and metadata-admin client (@object-ui/data-objectstack MetadataClient): git grep -nE "\.(get|getDraft|layered|history|diff|references|audit)GENERIC\(\s*('[a-z_]+'|[a-zA-Z_.?]+)\s*," (49 hits, before dropping Reflect.get, searchParams and storage).
    3. Its wrappers: git grep -nE "(readDraftForSave|readAuthoredDraft|fetchItemBody|fetchItemRead)GENERIC\(".
    4. Provider by-name readers: git grep -nE "useMetadataItem\(|readItemsByName\(|readItemPreferLocal\(|getItem\('(page|action)'".
    5. Raw fetches: git grep -nE "/meta/".

    GENERIC stands for an optional TypeScript type argument, spelled out here so the comment survives: a less-than sign, any run of characters other than an opening parenthesis, a greater-than sign, the whole group optional.

    Then I dropped the bucket 1 and bucket 4 types: object, view, object_extension and datasource. Their reads are listed at the end.

    A. Qualified today: the holder id is already sent (28 sites, nothing to do)

    Holder sources:

    • rail: the Studio rail's package. The rail lists that package's own items through ?package=, so the rail package is the holder.
    • addedIn: a contributed item's adding package.
    • pair: the ADR-0146 .custom package, which holds the draft and the declared override of a base item.
    • ledger: the _drafts row's packageId.
    • URL: ?package= on the edit page, set by the list row's link. The read goes bare when the URL names none.
    Site Type Holder sent
    views/studio-design/StudioDesignSurface.tsx:968 publish failure's type pair, else rail (draftScope)
    StudioDesignSurface.tsx:2680 app (layers) rail
    StudioDesignSurface.tsx:2681, :2709 app (draft) pair, else rail (navReadAt)
    StudioDesignSurface.tsx:3027, :3057 leaf type (draft) addedIn, else pair, else rail (readAt, L3026)
    StudioDesignSurface.tsx:3080, :3174 leaf type (layers) addedIn, else rail
    StudioDesignSurface.tsx:7963, :8249 flow (draft) the package the draft was saved at; pair, else rail (L8247-8248)
    views/studio-design/StudioCustomizeControls.tsx:191 / :197 customizable type pair (draft) / base (layers)
    views/studio-design/StudioNavItemInspector.tsx:822 nav target type rail
    views/studio-design/StudioBundleItemEditor.tsx:313, :334, :350 bundled type pair when read-only, else rail
    views/studio-design/translationTable.ts:314 listed type the scoped list's package
    views/studio-design/ObjectHooksPanel.tsx:243 hook rail
    views/studio-design/pairObjectActions.ts:180 action pair
    views/item-tools/StudioItemTools.tsx:118 item type (layers) the tool's packageId when held
    preview/DraftChangesPanel.tsx:281 (callers :1115, :1116, :1563, :1586) draft row's type ledger
    views/metadata-admin/ResourceEditPage.tsx:1362, :1366, :2044, :2045, :2267, :2314, :2315, :2405 item type URL
    views/metadata-admin/PermissionMatrixEditor.tsx:987, :992, :1563, :1572, :1620, :1650 permission prop, else route package
    views/metadata-admin/EmbeddedItemEditor.tsx:158 parent type (layers) URL (readParentOwnerPackage)

    B. Bare today (20 sites): why each one stays bare

    # Site Type Package the surface holds Holder Verdict
    B1 providers/MetadataProvider.tsx:1344 (preview leg :1341) any non-object none: getItem(type, name) and its byName cache are keyed by name only the callers' (B2-B6) bare: the seam has no holder to send
    B2 console/AppContent.tsx:494, layout/AppHeader.tsx:738, views/PageView.tsx:344 (readItemPreferLocal) page activeApp._packageId, the context package unknown before the read: the client accepts the answer only when answer._packageId === owner, and otherwise picks prefer-local from the list (hooks/useObjectPresence.ts:190-212), so a dependency's page is a legal answer bare (item 3: the app's id changes today's answer)
    B3 hooks/useNavTargetLabel.ts:236 dashboard app a nav item's reference bare (D3 reference)
    B4 hooks/useRecentItemLabel.ts:126 / :132 page / report none: RecentNamedItem stores no package (context/RecentItemsProvider.tsx:79) unknown bare
    B5 hooks/useActionModal.tsx:216 page none a modal target's reference bare (D3 reference)
    B6 hooks/useNavActionDispatch.ts:68 action none ActionNavItem.actionDef.actionName, a reference bare (D3 reference)
    B7 hooks/useNavigationSync.ts:723 page none the environment: its only caller passing no body is usePublishAllDrafts.ts:178, for package-less (orphans) first publishes bare (environment)
    B8 preview/usePublishAllDrafts.ts:205 page / dashboard (layers) none the environment: package-less drafts only (L82, L126) bare (environment)
    B9 views/runtime-metadata-persistence.ts:383 (via views/RuntimeDraftBar.tsx:109) view, report, dashboard, page (draft) none the environment: the matching saves are package-less too (L258, L367) bare (environment)
    B10 views/studio-design/StudioDesignSurface.tsx:2458 app rail unknown by construction: this read discovers the app's owner from _packageId (StudioRailCustomizations.tsx:436-438) bare
    B11 views/ReportView.tsx:131 dataset none the report's dataset reference bare (D3 reference)
    B12 views/metadata-admin/PositionPermissionSetsSection.tsx:83 permission none a position's permissionSets reference; positions are environment-wide (D7) bare (D3 reference)
    B13 views/metadata-admin/previews/useDatasetCatalog.ts:282 dataset none a reference bare (D3 reference)
    B14 views/metadata-admin/EmbeddedItemEditor.tsx:139 (its save at :188 too) parent type (draft) URL known: the same URL id the editor's :158 layers read sends holder known, but outside the claim's surface, and today's answer is not proven unchanged (item 3)
    B15 views/item-tools/AuditPanel.tsx:133, ReferencesPanel.tsx:69, ResourceHistoryPage.tsx:210 item type StudioItemTools' packageId known in Studio SDK gap: MetadataClient.audit / references / history (ui/packages/data-objectstack/src/metadata-client.ts:2092, :1881, :2070) and packages/client getAudit / getReferences / getHistory (index.ts:2494, :2445, :2199) take no package. Per the brief I stop here and report it
    B16 views/metadata-admin/previews/BookPreview.tsx:171 book (/tree) URL known an href, not a read the app makes; outside the surface

    Excluded as bucket 1/4: services/MetadataService.ts:937; StudioDesignSurface.tsx:5959, :5960, :6069, :6070, :6390; PackageOwdOverviewPanel.tsx:108-109; ObjectListViewInspector.tsx:587, :653, :674, :719, :721; useFormViewDraft.ts:165, :178, :190; ListViewBulkActionsSection.tsx:206; translationTable.ts:333; ResourceEditPage.tsx:1218; anchors.ts:221; useDatasetFields.ts:332, :346; useObjectFields.ts:158; external-object.tsx:69 (datasource); PermissionMatrixEditor.tsx:247; InterfaceListPage.tsx:413 and objectViewTabs.ts:322 (views); and the object fetches in PagePreview, AiChatPage, ExcelImportBar and external/api.ts.

    2. Which id is the right one (the cases the brief names)

    • Customize pair. Studio reads the base's layers at the base and the draft or declared override at the pair (StudioCustomizeControls.tsx:191/197; readAt/navReadAt above). ⚠ This is a G1 dependency, not U's. After G1, ?package=PAIR on a base-held name is a read of a name whose code holder is the base. G1's exact-qualifier arm ("X's item with its bound overlay") must count the pair's declared override, and the pair's added member, as held by the pair. Otherwise these Studio reads, which work today, are refused. I am naming the sites so that G1's card can pin them.
    • An app page or dashboard shipped by a dependency. The Console holds the app's package, not the holder (B2, B3). Today readItemPreferLocal prefers the app's own item and accepts a dependency's. Sending the app's id would refuse the dependency's page after G1, and changes the answer today (item 3). Stays bare.
    • The environment package (B7, B8, B9) has no id to send. ?package= cannot name it; its qualified address is G1's _env. Stays bare.
    • A Console route that holds an app's package while the item comes from another package: B2, as above. The holder is knowable only from the answer (_packageId) or from the list row.

    3. Today's answer, before G1 (packages/metadata-protocol/src/protocol-meta-item-reads.ts at e81636ce)

    A read naming package X differs from the bare read at three points:

    • L213: no package-less draft address;
    • L237 and L246: no package-less binding, and the content package is X;
    • L341: findServedOverlayRow with X, whose candidates are "the package's own row then the package-less row (never another package's…)" (protocol-environment-rows.ts:118).

    The registry tier is the same for both reads: the bare slot (registry.ts:8188), then X's composite (:8193), then the first composite (:8199).

    • X = the one holder H (every Studio read in table A): the bare read's content package is packagelessContentPackage's "exactly one code package ships it: that package" (protocol-environment-rows.ts:224), which is H. So both reads take the same stored row and the same registry item. No change, which is reading (b).
    • X = the context package C, with holder H a dependency (what qualifying B2 or B3 would send): the bare read serves H's bound stored row (content package H). The C-qualified read skips it (C's own row, else the package-less row) and falls to the registry's first composite. The answer changes today whenever H has a bound stored row (a saved edit, or a declared override). That is why B2 and B3 stay bare.
    • X = C, with an environment-only item: same answer today (package-less row, then the bare slot). G1 refuses it (D3 (a)). Stays bare.
    • B14 at its URL owner: the bare draft read uses strictDraftReadAddress (L213-214), the qualified one uses O's row then the package-less one. These agree when O is the package-less address, and are not proven equal otherwise. Following the brief (⛔ never guess), I make no claim of "no change".

    Conclusion: no read this card would qualify changes its answer today, because the census leaves no in-surface read to qualify. The one read that would change today (B2/B3 with the app's id) is not qualified.

    4. Declarations

    • Clause-②: no. @object-ui/app-shell is "private": true (ui/packages/app-shell/package.json:4). With no code change, no published @object-ui/* export moves.
    • Metadata-protocol: none.
    • Narrowing: none today. Nothing beyond G1's door is declared, and nothing goes to the maintainer.

    5. Slice plan and recommendation (four axes)

    The census needs no slices: the in-surface diff is 0 lines.

    • A (recommended): no code PR. The seat closes app-shell: Studio and Console pass the held package id on MetadataService reads and editors (ADR-0150 child U) #31671 with this census as the record, with premise_still_valid: false for the build half. Studio already sends the holder; every bare read lacks one.
      • Real need: first-party two-holder names measure 0 (ADR-0150, HotCRM 0/297), and no reader is wrong today.
      • Long-term: the holder rule is kept exactly.
      • Anti-AI-error: no context-id read that G1 would turn into silent refusals.
      • Startup: no surface without pull.
    • B: pins only. Add pins that table A's reads send their holder, and that B1-B13 stay bare, into the existing harness files. Costs about 150 lines of tests that guard no behaviour change. Not recommended: the existing ADR-0048 comments already sit beside pins at most table A sites.
    • C: qualify with the context package. Rejected: it changes today's answer (item 3) and refuses dependency items after G1. That is a narrowing beyond the declared one.

    Carriers, not filed by me:

    • (i) The SDK gap B15: packages/client getHistory / getReferences / getAudit / diffItem and data-objectstack MetadataClient. Carrier: G3, plus a ui follow-up.
    • (ii) The pair-addressed Studio reads: G1 must keep answering them. Carrier: G1's card.
    • (iii) B14: the EmbeddedItemEditor draft read and save addressed bare beside an owner-addressed layers read. That is an address mismatch inside one editor, and a candidate ui card. Dedupe words: EmbeddedItemEditor getDraft package, embedded parent draft address.
    • (iv) After G1/E8, a bare Console read of a two-holder name answers 409 with candidates. B1's ANSWERED_REFUSAL_CODES path should then show the candidates rather than a failed read. That is a ui card when G1 lands.
    {
      "issue": 31671,
      "status": "reading",
      "branch": "claude/project-thread-cp5kye",
      "pr": null,
      "session": "session_01QsR2jTEZFY1pWynVBfvcmz",
      "head": "e81636ce (origin/main; no commit on the branch)",
      "premise_still_valid": false,
      "summary": "Census of by-name bucket 2/3 reads in ui/packages/app-shell at e81636ce: 28 sites already send the holder's package id (Studio rail/addedIn/pair, ledger rows, edit-page URL); 20 stay bare because no holder can be named there (Console context package with possible dependency holder, D3 references, environment items, SDK gap on history/references/audit). No read in the claim's surface is qualified; MetadataService has no bucket 2/3 read. Qualifying Console reads with the app's package would change today's answer (dependency holder's bound stored row skipped), so they stay bare.",
      "declarations": "Clause-②: no · Metadata-protocol: none · Narrowing: none today (no code)",
      "files_changed": [],
      "line_budget": "0 changed lines",
      "deviations": "none; no worktree created, nothing written to the repo",
      "gates": "NOT MEASURED: no diff",
      "tests": "NOT MEASURED: no diff",
      "dogfood_battery": "n/a — no code",
      "mcp_calls": "3 — mcp__github__issue_read (get, get_comments x2) on #31671; no MCP writes",
      "api_writes": "1 — this os-dev-report comment via post-stamped",
      "open_questions": [
        {
          "question": "With no in-surface read to qualify, how does #31671 close?",
          "options": ["A close on this census, no PR", "B pins-only PR (holder sent / control bare), about 150 test lines", "C qualify with the context package (rejected: changes today's answer)"],
          "recommendation": "A, because every remaining bare read lacks a nameable holder and table A already sends one; B guards no behaviour change"
        }
      ],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: G3 (client SDK) · history/references/audit/diff take no package (packages/client index.ts:2199/2445/2494/2598; data-objectstack metadata-client.ts:2070/1881/2092/2049) · noted, not filed",
        "carrier: G1 · Studio reads at the customize pair for a base-held name (StudioCustomizeControls.tsx:191, StudioDesignSurface.tsx:2681/3027/8249, StudioBundleItemEditor.tsx:313/334, pairObjectActions.ts:180) must stay answered by the exact-qualifier arm · noted, not filed",
        "carrier: none · EmbeddedItemEditor.tsx:139/188 draft read and save go bare beside the owner-addressed layers read at :158 (an address mismatch inside one editor, not measured as a wrong answer) · noted, not filed · dedupe: EmbeddedItemEditor getDraft package; embedded parent draft address"
      ]
    }
  6. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · zhuangjianguo · session_01QsR2jVEjiYrK7onirxUGyo

    席位核对 · step 1 accepted · close not planned · 2026-11-08T22:24Z

    Seat domain:ui#3 read the dev's step-1 report 6727959027 (premise_still_valid: false, pr: null) for its claim 6727842128, and spot-checked it against origin/main e81636ce.

    Ruling: option A. The census is the record of this card, and no PR follows. #31671 closes not_planned. Reopening is free, and the maintainer can veto.

    1. What the census found. There are 48 by-name reads of bucket 2/3 types in ui/packages/app-shell.
      • 28 already send the holder's id (table A of the report). The holder comes from the Studio rail, from addedIn, from the ADR-0146 pair, from the _drafts ledger row, or from the edit page's ?package=.
      • 20 stay bare (table B), because no holder can be named at that point:
        • Console routes that hold only the app's package;
        • D3 references;
        • environment items, which ?package= cannot name (their address is G1's _env);
        • doors the SDK cannot qualify.
      • MetadataService.ts holds no bucket 2/3 read; its only by-name read is object, at ~L937. So the card's "~ten bare reads" have no holder to send.
    2. Why the context package is refused (option C). The seat checked this.
      • readItemPreferLocal (hooks/useObjectPresence.ts ~L190–212) accepts a by-name answer only when _packageId equals the app's package. Otherwise it picks prefer-local from the list, so a dependency's page is a legal answer today.
      • A read naming package X serves "the package's own row then the package-less row (never another package's)" (findServedOverlayRow, protocol-environment-rows.ts ~L118). So qualifying a Console read with the app's id changes today's answer whenever a dependency holder has a bound stored row.
      • After G1, the same read is refused. That is a narrowing beyond the declared one, so it is not taken.
      • The MetadataProvider.tsx ~L1344 seam is keyed by name only (byName). It has no holder to send either.
    3. Red lines and readings.
      • Resolution never loosens: no read changes, so nothing loosens.
      • Ambiguity is never guessed: a read with no nameable holder stays bare.
      • Readings (a) and (b) hold trivially, because there is no diff. (c): no migration. (d): Clause-②: no, Metadata-protocol: none, and no narrowing today.
    4. Findings (one line each):

    Epic pointer posted on #31527.

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, iteratedomain:uiDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpm:dispatchedDispatched to a dev agent by /pm-dispatchpriority: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