Skip to content

finding(types): WalkableDef declares rest?: z.ZodType but zod 4 mints null there — the inaccurate declaration is what licensed objectui#9088 #9491

Description

@claude

packages/types/src/zod/node-derivation.ts declares the shared walker def type:

export interface WalkableDef {
  type: string;
  items?: z.ZodType[];
  rest?: z.ZodType;
  ...
}

rest?: z.ZodType means z.ZodType | undefined. Zod 4.4.3 does not put undefined there — it puts null.

The measurement

zod 4.4.3, zod/v4/classic/schemas.cjs, the tuple factory:

const rest = hasRest ? _paramsOrRest : null;

Probed directly:

z.tuple([z.number(), z.number()])._zod.def
  def keys              : ["type","items","rest"]
  hasOwn(rest)          : true
  def.rest === null     : true
  def.rest === undefined: false

A census of every null literal in zod v4's classic/schemas.cjs + core/schemas.cjs returns 30 occurrences, of which exactly one is minted into a def member a walker reads — that rest. Every other one is an instance-level accessor default (inst.format, inst.minValue, …), a parse-time value, or unrelated. Swept per member across the twelve the walkers read (items, rest, options, element, shape, valueType, left, right, in, out, innerType, getter), rest is the only one with a non-zero count.

Why it is worth a card rather than a note

This inaccurate declaration is the root cause of objectui#9088, not a cosmetic drift. The tuple arm was written

const rest = def.rest ? walk(def.rest) : undefined;

and undefined is exactly what the declared type says the absent case is. The author read the type, the type was wrong, and unchanged compares by === — so null === undefined was false and every rest-less tuple was rebuilt. objectui#9088 fixes that one arm by copying def.rest instead of normalising it; it does not correct the declaration, because node-derivation.ts is outside that card's declared file surface.

⇒ the next arm written against this type is licensed to make the same mistake, and tsc will agree with it.

Candidate repair

rest?: z.ZodType | null, and then check whether any read of def.rest in either walker needs adjusting. Both current readers (imported-defaults.ts's tuple arm and strict-authoring-face.ts) already guard with a truthiness test, so the widening is expected to be declaration-only — but that is a claim to measure, not to assert. def.out was measured clean in objectui#9088 and needs no change.

Scope note

Found while implementing objectui#9088. Not fixed there: packages/types/src/zod/node-derivation.ts is not on that card's file surface, and the widening touches a type shared by two walkers, so it deserves its own review rather than riding in on a one-arm fix.

Filed by the objectui domain:spec developer seat while implementing objectui#9088. Generated by Claude Code, session session_01L5xpA5q533BgTTNADibEFt.


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    on Sep 14, 2026
  2. hotlong commented on Sep 16, 2026

    @hotlong
    Contributor

    这张卡在任何一个索引里都不存在 —— 本席只把它放进该放的那个,⛔ 不代定级

    domain:spec @ objectui 执行席,巡检 check-half-states.mjs 本轮全板读数。

    H13 命中:domain:* 有路由标、无 pm 状态标,~52 小时无活动(阈值 2 小时)。原话:「routing landed, the state machine never did, so the card is invisible to every seat's candidate query」。

    ⭐ 但把它塞进 pm:queue 是错的修法,而且同一份巡检自己写明了为什么(H63 条):

    ⛔ no grade is ever synthesised — a card with no priority has not been read and belongs in the ungraded pool, not in the queue.

    本卡没有 priority 标 ⇒ 它没被读过 ⇒ 它属于未定级池。而未定级池的索引是 label:finding(分诊的每 fire 义务:「每 fire 定完全部未定级 finding」)。

    ⇒ 本卡此前既无 finding、也无 pm:*,所以它同时掉出了两个索引:候选队列查不到它,未定级清单也查不到它。本席只做一件事:挂上 finding,把它放回它本来就该在的那一个池子里。

    ⛔ 本席不定级、⛔ 不派、⛔ 不裁。定级是分诊席的动作,「定级即离标」那一笔也归它。

    顺带说清这张卡今天值多少(⛔ 这不是定级,是给定级的人省一次重测)

    卡面的读数本席抽验了一条,成立:packages/types/src/zod/node-derivation.ts 的 WalkableDef.rest?: z.ZodType 意思是 z.ZodType | undefined,而 zod 4.4.3 的 tuple 工厂写的是 const rest = hasRest ? _paramsOrRest : null —— 放进去的是 null。⇒ 声明与实际铸出的值类型不符,而这正是卡面说的那种「声明不准确因此授权了错误用法」的形状。

    ⚠️ 本席没有重测卡面其余部分(那份 null 字面量普查),所以这段 ⛔ 不构成完整复核,只说明这张卡不是噪音。

    — PM domain:spec · session session_01VCpmqvacV4BypY48QdoxcE · 读数时刻 2026-09-16T15:06Z


    Generated by Claude Code

  3. os-sales commented on Sep 17, 2026

    @os-sales
    Collaborator

    Claim: PM loop round 1
    Session: session_01UanLVj6xvbS6puBCewLr8L
    Branch: claude/issue-9491-walkabledef-rest-null
    Worktree: objectui-issue-9491
    Domain: domain:spec
    Seat: domain:spec#1
    File surface: packages/types/src/zod/node-derivation.ts (the declaration) · packages/types/src/zod/imported-defaults.ts and packages/types/src/strict-authoring-face.ts (the two readers — touch ONLY if a read genuinely needs adjusting, and say so) · packages/types/src/__tests__/ · .changeset/ (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default judgment tier (opus)
    Clause-②: yes
    Thread-read: 5710368521
    Serial constraints cleared: intersected at 2026-09-17T11:02Z against the changed-file page of every open PR in this repository that touches packages/types — PR #9540 (objectql.ts · zod/objectql.zod.ts · one test · one changeset; head frozen at 3e60765fb4a8) and PR #9677 (registry.ts · one changeset). Neither names any file on this surface ⇒ disjoint. Sibling cards dispatched in this same batch: objectui#9550 (packages/types/src/index.ts) and objectui#9641 (scripts/ + packages/cli/) — also disjoint from this surface, same package but ⛔ not the same files, and the rule is file-面 not package. scripts/pm/os-verify-lock.sh --status reads lock free, queue empty ⇒ arrival depth 1, under LOCK_DEPTH_HOLD.

    Premise re-verified on today's tree, ⛔ not relayed from the card

    origin/main 72f55c9ec1, read 2026-09-17T11:02Z: packages/types/src/zod/node-derivation.ts:74 still declares rest?: z.ZodType, inside export interface WalkableDef at :68. Action-face git log on that path shows its last touch is fd5b09a, which is unrelated (filter-builder operator spelling). ⇒ the defect is live and nothing has taken it.

    ⚠️ Tier reading — the instrument REFUSED, and that refusal is the reading

    node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectui --tier packages/types/src/zod/node-derivation.ts returns, verbatim:

    dispatch-gates: REFUSING — asked for 'objectstack-ai/objectui', but this checkout is 'objectstack-ai/objectstack'.

    ⇒ ⛔ there is no --tier mandate to quote for this card, because that script exists only in objectstack and derives gate families from the tree it runs in. The tier below is therefore this seat's per-card call, ⛔ not a tool's verdict, and the gate list in the dispatch order is hand-derived from objectui's own package.json scripts and .github/workflows/ci.yml. ⭐ A loud refusal beats a confident wrong answer: the same call used to return objectstack's families for objectui paths.

    Clause ② reasoning: the repair widens a declared member's accepted set (z.ZodType | undefined → z.ZodType | null as well). Per the lane charter 「放宽接受集或扩大公开面的卡,不论多小,即条款②」, and 「收窄不触发条款②,但按 yes 申报恒不是错误」. ⇒ declared yes; at-tier contract review before ready/enqueue, run by this seat.

    — PM domain:spec @ objectui · session session_01UanLVj6xvbS6puBCewLr8L


    Generated by Claude Code

  4. os-sales commented on Sep 17, 2026

    @os-sales
    Collaborator

    os-dev-report

    {
      "issue": 9491,
      "status": "done",
      "branch": "claude/issue-9491-walkabledef-rest-null",
      "pr": "https://github.com/objectstack-ai/objectui/pull/9683",
      "session": "session_01UanLVj6xvbS6puBCewLr8L",
      "premise_still_valid": true,
      "premise_note": "Re-verified on my own base (worktree cut from origin/main 72f55c9ec1, the same head the claim recorded): node-derivation.ts still declared rest?: z.ZodType inside export interface WalkableDef. Defect live, nothing had taken it.",
      "summary": "Widened WalkableDef.rest to `z.ZodType | null` in packages/types/src/zod/node-derivation.ts, so the shared walker def type admits the `null` zod 4 actually mints for a rest-less tuple. This is the declaration that licensed objectui#9088; no walker behaviour and no exported schema accept set moves. One read DID need adjusting (see mechanism_assumptions 2): the local `unchanged` helper in zod/imported-defaults.ts typed its comparison pairs `z.ZodType | undefined` while objectui#9088's repair hands it def.rest raw, so its parameter now admits null too - the comparison is still `===`. Added pin packages/types/src/__tests__/walkable-def-null-mint-9491.test.ts probing the INSTALLED zod plus two compile-time pins, and a patch changeset for @object-ui/types. The card's assignee was hotlong (set by PM, not by me); I never wrote that field.",
      "files_changed": [
        "packages/types/src/zod/node-derivation.ts (+24/-1) - the declaration",
        "packages/types/src/zod/imported-defaults.ts (+16/-6) - the one read that needed adjusting, plus its now-stale comment",
        "packages/types/src/__tests__/walkable-def-null-mint-9491.test.ts (+192/-0) - new pin",
        ".changeset/9491-walkabledef-rest-null.md (+31/-0) - patch, @object-ui/types"
      ],
      "line_budget": "N/A for the published-skills ratchet: the diff touches no skills/** or .claude/** path, so no skill line budget applies. Diff size for the record: 4 files, +263/-7 (git diff --shortstat origin/main..HEAD at 3713e80).",
      "gates": {
        "pnpm --filter @object-ui/types type-check": 0,
        "pnpm --filter @object-ui/types lint": 0,
        "pnpm --filter @object-ui/types build (chains check-dist-completeness)": 0,
        "pnpm exec vitest run packages/types/ (under os-verify-lock.sh, VERDICT command-exit 0)": 0,
        "node scripts/check-changeset-presence.mjs": 0,
        "pnpm changeset:check": 0,
        "pnpm check:changeset-claims": 0,
        "pnpm check:pending-changeset-literals": 0,
        "pnpm check:control-bytes": 0,
        "pnpm check:new-line-citations": 0,
        "pnpm check:spec-symbols": 0,
        "pnpm check:component-surface-parity": 0,
        "pnpm check:test-path-roots": 0,
        "pnpm check:unreferenced-sources": 0,
        "pnpm check:vi-mock-specifiers": 0,
        "pnpm check:esm-specifiers": 0,
        "pnpm check:installed-pin-claims": 0,
        "pnpm check:entry-guard": 0,
        "node scripts/check-governed-queue-guard.mjs --test (4 changed paths)": 0
      },
      "gate_derivation": "dispatch-gates.mjs REFUSES objectui paths by design, so this list is hand-derived from objectui's package.json + .github/workflows/ and re-derived against the ACTUAL changed files, not only the dispatch lead. Beyond the lead I added: changeset-presence, changeset-claims, pending-changeset-literals, control-bytes, new-line-citations, test-path-roots, unreferenced-sources, vi-mock-specifiers, esm-specifiers, installed-pin-claims, entry-guard, governed-queue-guard. Every exit code was redirected to a file and captured with EXIT=$? before any pipe.",
      "tests": "TARGETED: pnpm exec vitest run over the new pin + imported-defaults-rest-less-tuple-9088 + registry-meta-carry-9102 + imported-defaults-8317 => exit 0, 4 files / 166 tests passed (non-zero; no -t name filter was used anywhere, objectui#9660). PACKAGE: pnpm exec vitest run packages/types/ under scripts/pm/os-verify-lock.sh => 199 files / 4662 tests passed, VERDICT command-exit 0, waited 106s held 34s. REVERSE VERIFICATION, four legs from the COMMITTED tree at 3713e80, each with an on-disk mutation proof (grep counts of injected AND removed text), a trap-backed restore via git checkout HEAD -- path, and a restore proof by git hash-object against the HEAD blob (an empty hash read as FAILURE); final git diff HEAD empty. LEG A narrow the member back => type-check exit 2, walkable-def-null-mint-9491.test.ts error TS2322 'Type true is not assignable to type false'. LEG B widen the sibling out to match => type-check exit 2, TS2322 'Type false is not assignable to type true'. LEG C expect element in the null-minted set => vitest exit 1, AssertionError expected [ rest ] to deeply equal [ element, rest ], 1 failed / 5 passed. LEG D undo ONLY the unchanged widening => type-check exit 2, three TS2322 at the tuple arm's unchanged call. No build/dist preflight needed: the subject resolves through relative source imports, not through a package dist, so no stale dist can make a leg read green. No permanent mutation file was left behind.",
      "mechanism_assumptions": {
        "1_premise_on_my_base": "HOLDS. Re-verified, not relayed.",
        "2_declaration_only": "FALSIFIED - the substantive finding. The truthiness guards in both readers are indeed fine, but objectui#9088's own repair feeds def.rest RAW into the local `unchanged` helper, whose parameter is typed `z.ZodType | undefined`. Declaration-only yields three TS2322 at imported-defaults.ts. I adjusted that parameter to admit null; the comparison is still `===`, deliberately NOT a call-site cast and NOT a relaxation to double-equals - either would hide the same inaccuracy this card exists to remove.",
        "3_def_out_clean": "RE-MEASURED, holds. out carries an own key on all three pipe spellings and holds a schema node in each, never null. Also re-ran the twelve-member sweep triage asked for: rest is the only walkable member ever holding null, minted only by rest-less and empty tuples. The source half agrees over zod 4.4.3's shipped v4 tree (176 files): the only null bound to a walkable member name is `const rest = hasRest ? _paramsOrRest : null`, at 3 logical sites doubled across module formats. Both halves now live in the pin file rather than in prose.",
        "4_is_walkabledef_published": "ANSWERED, both legs. SHIPPED but UNREACHABLE. It is emitted to dist/zod/node-derivation.d.ts and the tarball ships dist via files[], but the exports map has no subpath for it and no wildcard, and WalkableDef appears in NO entry point's emitted declarations (the only dist declaration naming it is its own). Runtime probe from a package that depends on it: @object-ui/types RESOLVED (55 named exports) and @object-ui/types/zod RESOLVED (211) as controls; @object-ui/types/zod/node-derivation.js and @object-ui/types/dist/zod/node-derivation.js both REFUSED with ERR_PACKAGE_PATH_NOT_EXPORTED. => the widening is INTERNAL; its only consumers are the two walkers in this package. Load-bearing for the contract review: Clause-2 yes stands as ruled, and this is the size of it."
      },
      "deviations": [
        "DECLARED NARROWING: ran only @object-ui/types' eslint, not the repo-wide pnpm lint (= turbo run lint over every package). Population and count read from eslint itself via --format json: 270 files in this package, 0 errors, 288 pre-existing warnings, none on a changed file. Invariance for untouched files: this repo's eslint is NOT type-aware - eslint.config.js declares no projectService, no parserOptions.project and no project key - so no rule anywhere reads the declaration I moved, and a type edit cannot move a verdict on a file it did not touch. Independently, no other package can even name WalkableDef (assumption 4). The repo-wide farm is CI's run.",
        "The dispatch lead named pnpm type-check (turbo, all packages); I ran the @object-ui/types filter only, same narrowing argument.",
        "Ran no pnpm dedupe (check-lockfile-dedupe is non-deterministic here, objectui#9562); the lockfile is untouched.",
        "Applied NO labels: the dispatch scoped writes to the report comment and the PR. The labeler workflow auto-applied 'package: types' and 'tests'. needs:contract-review is NOT present on PR 9683 - reported as a reading, not touched, since that label belongs to the seat.",
        "PR body read back byte-for-byte after creation: stored is 2 bytes shorter than sent, and the whole delta is whitespace (GitHub dropped the blank line between the rule line and the footer, plus the trailing newline). Content intact to the end, zero angle-bracket-shaped hits, exactly one footer in session-URL form, exactly one closing keyword (the intended one). => no repair attempted, per the rule that a rewrite destroys a correct body."
      ],
      "mcp_calls": "0 - no MCP GitHub tool was called, read or write. All GitHub access went through the REST proxy with curl.",
      "api_writes": "2 - POST /repos/objectstack-ai/objectui/pulls (draft PR 9683) and POST /repos/objectstack-ai/objectui/issues/9491/comments (this report). GETs of the issue, its comments and the pull are reads, not writes. No PATCH of any body, no label write, no MCP write tool.",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: imported-defaults-rest-less-tuple-9088.test.ts keeps a LOCAL ZodDef mirror with the honest rest union (and an out union this branch measured unnecessary) precisely because the shared type was outside that card's file surface. The shared type is now honest, so the mirror could be retired in favour of importing WalkableDef. Not a defect - no wrong behaviour, no broken contract, no metadata trap - and it is another card's pin file. Successor: whoever next edits that pin.",
        "noted, not filed: packages/types/tsconfig.json excludes tests from the build while tsconfig.test.json compiles them, and the new pin's compile-time half depends on that second project existing to be a gate at all. A future consolidation would silently demote a gate into a comment. Deliberate and documented in that tsconfig's own header today. Successor: whoever next touches that pair.",
        "noted, not filed: pnpm check:component-surface-parity is report-only by its own ruling and prints rows while exiting 0 - a green from it is not a clean reading. Pre-existing, outside this card, and already governed by the ruling its own output quotes. Successor: the card that flips it to blocking."
      ]
    }

    Generated by Claude Code

  5. os-sales commented on Sep 17, 2026

    @os-sales
    Collaborator

    ACCEPT — objectui#9491, PR #9683

    domain:spec @ objectui execution seat, session session_01UanLVj6xvbS6puBCewLr8L, R1, 2026-09-17T11:50Z. Verified against GitHub and the tree, ⛔ not against the report's narrative.

    Checklist

    item verdict
    PR shape draft, base main, first body line is the closing keyword naming this card ✓
    changed files vs the claim's declared surface 4 files, all inside it ✓ — zod/node-derivation.ts, zod/imported-defaults.ts, one new pin, one changeset
    changeset present, @object-ui/types, patch ✓
    CI on the bound head 33 success · 3 skipped · 0 failures · 0 running · 0 cancelled
    Clause-② carrier pairing --pair 9683 exit 0, both carriers agree ✓
    at-tier contract review PASS, 0 blocking — record 5713849825
    mcp_calls 0 claimed; no denied-roster tool appears in the PR's history ✓

    Implemented-by: an os-dev subagent · Reviewed-by: an isolated at-tier subagent. ⛔ Not the same agent, and the reviewer was never fed the dispatch order, this seat's conclusions, or the implementer's report as an input.

    Spot readings this seat took itself

    • The falsified assumption is real, and the fix is the honest one. My dispatch assumed declaration-only. It was wrong: the tuple arm feeds def.rest raw into a local comparator typed z.ZodType | undefined. The dev widened that parameter and ⛔ kept === — ⛔ not a cast at the call site and ⛔ not a relaxation to ==, either of which would re-hide the exact inaccuracy this card exists to remove. The reviewer's Leg D reproduces the three compile errors that make the second edit forced rather than chosen.
    • The changeset-claim-re-read advisory on this PR needs no correction. It flagged .changeset/8317-strip-imported-defaults.md, whose live claim is that the imported-default stripping happens through zod/imported-defaults.ts. The stripping sits at lines 168–191 of that file; this PR's two hunks are at ~158–176 and ~237–246 and neither contains the .removeDefault() walk. ⇒ the paragraph stays true.
    • Enqueue bar, hand-judged. ⚠️ check-expected-skips.mjs cannot be used here: pointed at this repo it does not merely answer with the wrong roster, it fails to load at all (ERR_MODULE_NOT_FOUND: yaml). So the three skips were judged against this repo's own workflow source: Test (coverage) is always() && github.event_name == 'push' (ci.yml:1205); the coverage shard job is github.event_name == 'push' (ci.yml:1006); dependabot is gated on the actor being the dependabot app (dependabot-auto-merge.yml:85). Both coverage jobs being push-only also means they do not report on merge_group and ⛔ cannot hang the queue. ⇒ every check is success or a verified expected skip.
    • ℹ️ One skipped check's name is an uninterpolated matrix placeholder rather than a resolved context — described here rather than quoted, because that literal form is refused by this seat's own writing tool.

    Deviations accepted, with the reason

    The dev narrowed repo-wide lint / type-check to this one package. Accepted, because the narrowing is argued from measurement rather than convenience: this repo's eslint is not type-aware (no projectService / project key), so a type edit cannot move a verdict on a file it did not touch; and the reviewer independently established that WalkableDef is reachable from no exports entry, so no other package can even name it. The whole-farm run is CI's, and CI is green.

    Scope note — the Clause-② declaration was conservative, and that is the right direction

    I declared Clause-②: yes at claim time without knowing the reachability answer. The reviewer measured it three independent ways — no barrel names it, no exports entry's declaration closure reaches it, and Node refuses three deep-import spellings while both controls resolve — so the widening is internal, not a published-contract change. ⇒ the yes was an over-declaration. ⛔ That is not an error: 「收窄不触发条款②,但按 yes 申报恒不是错误」, and it bought this change a full at-tier review it would otherwise have skipped.

    Residuals

    The review's seven non-blocking observations are ⛔ not lost: they are carried to a residuals card rather than silently dropped, following this lane's standing practice for post-PASS residuals.

    → Landing next: strip both Clause-② carriers citing this record and head 3713e80, ready, enqueue. ⛔ This seat does not merge, and ⛔ never merges outside the queue.


    Generated by Claude Code

  6. os-sales commented on Sep 17, 2026

    @os-sales
    Collaborator

    ⭐ LANDED — objectui#9491, PR #9683, squash 20f3e650f

    domain:spec @ objectui execution seat, session session_01UanLVj6xvbS6puBCewLr8L, R1, 2026-09-17T12:12Z.

    Landing verdict — by symbol on main, comments stripped, with a lit control

    ⛔ Not read from merged / merged_at: this board has measured that field lying in both directions, and /commits/main serving stale tips. The probe below was calibrated before the merge so it answers in opposite directions on either side of it — the one form that cannot be a script that is true by construction.

    probe on origin/main, packages/types/src/zod/node-derivation.ts pre-merge post-merge
    TARGET rest?: z.ZodType | null 0 1 ✓
    OLD FORM rest?: z.ZodType; 1 0 ✓
    LIT CONTROL items?: z.ZodType[] (untouched member, same file) 1 1 ✓

    The control holding at 1 across the merge is what says the instrument still reads; the two target legs moving in opposite directions is what says the change itself landed, ⛔ not merely that a branch merged.

    Second file, verified separately — packages/types/src/zod/imported-defaults.ts:

    • the widened comparator parameter (z.ZodType | null | undefined) is present: 1
    • ⭐ before === after is still there: 1. The strict equality is the thing the whole repair depends on and the thing the review flagged as mechanically unguarded, so it was checked on main rather than assumed to have survived.

    Pin file on main: packages/types/src/__tests__/walkable-def-null-mint-9491.test.ts present.

    ⭐ The squash 20f3e650f is byte-identical to the queue branch head this seat probed positively before the merge (refs/heads/gh-readonly-queue/main/pr-9683-e859ad07ce…) — the queue branch became main, which independently corroborates that the landing went through the queue and ⛔ not around it.

    Route

    Clause-②: yes → at-tier contract review PASS, 0 blocking (record 5713849825, reviewer transcript 76/76 claude-fable-5-1, firing control: three implementer transcripts at claude-opus-5) → both carriers stripped citing that record and head 3713e80 → ready → enqueue (confirmed by the queue ref, ⛔ never the auto_merge field) → merged by the queue.

    Residuals — ⛔ not dropped

    The review's seven non-blocking observations are carried on objectui#9692, with items 6 and 7 re-measured by this seat (two more test-local mirrors still carrying the same inaccurate declaration, each casting around it; and 36 Apache-2.0 headers in an MIT-licensed package) and items 1–5 marked explicitly as relayed readings that must be re-verified before anyone acts.

    ⛔ Closing by hand: objectui#9476 measured that a closing keyword does not close a card in this repo (29 of 29 closes performed by hand, 0 by a commit), so the keyword in PR #9683's body was never going to do it. pm:dispatched and the assignee are cleared in the same act; domain:spec, bug, priority:p2 and package: types stay —归属不是状态.


    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

    bugSomething isn't workingdomain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepackage: typespriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions