Skip to content

docs(adr): ADR-0087's artifact window names its third disjunct — a first-release-of-a-major floor replays the major step ('converted-major-step', 58f5c90999) (#23038) - #23161

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-23038-adr-0087-major-step-note
Oct 13, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-23038-adr-0087-major-step-note

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #23038
Clause-②: no

One dated amendment note in docs/adr/0087-metadata-protocol-upgrade-contract.md, in the shape 4cc5bcd858 (#20797) used for the #20390 note. Tier H (docs/adr/**), so this PR stays a draft for the maintainer's review. Nothing here publishes: skip-changeset.

What changed

All three edits are in the one ADR file. No recorded text is rewritten.

  • Status line. One more **Amended** entry (2026-10-13). It names the third disjunct, the producer 58f5c90999 and the verdict 'converted-major-step', and points at the new note. 4cc5bcd858 added a status-line entry for its note, so this one does too (H3).
  • The amendment note, placed under the 2026-09-13 addendum's window bullet, right after the 2026-09-30 note. It records:
    • The third disjunct. The door replays E when the floor is below the runtime label, OR the floor is at or below E.retiredAfter, OR (the floor is M.0.0 AND E.toMajor is M). A first-release floor at or above the runtime label replays every retired entry of the conversion step into M. Default flips are still refused by id first. The verdict is 'converted-major-step'. Symbol anchor: artifact-forward-conversion.ts#idsTheFloorPostdates.
    • Why. During M's prerelease the label still names the last M-1 release, so every prerelease stamp sits below M.0.0. The per-entry half therefore read a ^18 artifact built before a prerelease retirement as 'authored-current'.
    • Why the replay is safe. A conversion rewrites only the shape it recognizes.
    • The M2 caveat, worded as in the module docblock. It is anchored to #DEFAULT_FLIPS_NOT_REPLAYED_HERE.
    • One clause aligning retiredAfter with spec(conversions): under a pre-mode label (18.0.0-next.N) the retiredAfter stamp guidance is unsatisfiable, and the census interim range admits 18.0.0, which its own PUBLISHED rule rejects after GA #23042's landed rule (H2, below).
    • A pointer to the annotation on the "within-line retirements" sentence.
  • The addendum's closing sentence ("this window is for within-line retirements (17.1 → 17.2) …") is annotated, not rewritten, as triage 6124857034 directed. A dated Annotated (2026-10-13) blockquote follows it. It says the window also serves a prerelease-major floor (^18 on a runtime labelled from 17.7.0 through 18.0.0; from 18.0.1 on, the label half replays the whole chain for it). It also says the handshake still answers first, because the protocol constant moves to M when M's prerelease opens.

Diff: 1 file, +42 / −1 (the −1 is the status line, which is extended, not reworded). The ADR goes from 1218 to 1259 lines.

Checked before editing: the premise holds (H1), at 02bec6ca8

  • I ran the card's re-check on origin/main. The ADR has the floor-at-or-below-E.retiredAfter disjunct once, in the 2026-09-30 note, and "within-line retirements" once, in the closing sentence. The module has firstReleaseOfMajor in idsTheFloorPostdates and 'converted-major-step' in the verdict union, the verdict assignment and the module docblock.
  • idsTheFloorPostdates reads DEFAULT_FLIPS_NOT_REPLAYED_HERE first. It then opens a retired entry in one of two ways: retiredAfter is at or above the floor (the per-entry half), or floor is M.0.0 and conversion.toMajor === floor[0] (the major-step half). Any majorStep entry gives the verdict 'converted-major-step'.
  • The module docblock already states the third disjunct and the M2 caveat, and the ADR names that docblock as the rule's authority.
  • On this tree PROTOCOL_VERSION is '18.0.0' while packages/spec/package.json is 17.7.0. This is the label/protocol split the annotation's handshake sentence relies on.

H2: does #23042's landed rule leave ADR-0087's retiredAfter sentence true?

My reading differs from the dispatch's. The dispatch read "narrowed, not contradicted". I read that the sentence no longer holds as written under pre mode, so the note carries one aligning clause.

H4: anchors

scripts/adr-anchors/*.json maps code files to ADR ids. It cites no ADR line ranges, so the insertion moves no anchor. pnpm check:adr-anchors exited 0. The note uses no path:NNN line anchors. Its two path#Symbol anchors resolve under check-adr-symbol-anchors, which reported 2321 anchors resolving and 0 line anchors.

Gates, at head 82ffd67f4f

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack was re-derived with no paths after the edit. It took the change set from git: 1 path against merge base 02bec6ca8. It derived the same 23 commands the dispatch named. Each command ran on its own in the foreground, with its log redirected and its exit read before any pipe. All 23 exited 0. --ran printed: "Run reconciliation — 23 derived, 23 run, 0 NOT-MEASURED, 0 UNRUN."

  • check-adr-0087-registration --base origin/main: "this PR adds no declared-breaking changeset". Its --self-test: 548 assertions.
  • check-adr-links: "730 relative link destination(s) under docs/adr/ resolve". Its --self-test passed.
  • check-adr-symbol-anchors: "2321 anchors across 142 records resolve … 0 line anchors survive". Its --self-test passed.
  • check-ci-filter-parity: OK.
  • check-closing-keyword-parity: OK. Its --self-test: 40 assertions.
  • check-comment-mask-corpus: 8935 files, 0 disagree.
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions. The first run exited 3 (PREREQUISITE NOT MET: @objectstack/formula unbuilt in the fresh worktree), which measured nothing. I then ran turbo run build --filter=@objectstack/formula --filter=@objectstack/lint under the verify lock (4/4 tasks, VERDICT command-exit 0). The re-run exited 0, with self-test 61 cases and 22 + 9 + 15 examples judged clean.
  • pnpm check: gates, all exit 0:
    • adr-anchors: OK, 68 anchored files.
    • changeset-gate-self-tests.
    • cross-package-test-inputs: OK.
    • doc-authoring.
    • driver-memory-census: OK.
    • future-spec-major: "no @objectstack/spec citation names a major above 17".
    • gitlink-declared: OK.
    • nul-bytes: OK, 11174 files.
    • pm-governed-merges: self-test 500 assertions, live certified.
    • pm-prior-rulings.
    • refd-timer-probe: OK.
    • watch-hint-literal.
  • I also scanned the edited file myself for control bytes (grep -naP over the C0 range and DEL): no hits.

Acceptance notes

  • H2's conclusion (above) adds one clause beyond the card's four named items. The dispatch authorized exactly that clause if the sentence measured untrue, in this same note and nowhere else.
  • The module docblock of artifact-forward-conversion.ts still says "within-line retirements (17.1 → 17.2) are exactly the case that created this module" in its full-x.y.z paragraph. That sentence is about which comparison the module uses, so it remains true, and code is outside this card's surface. I noted it and did not edit it.

维护者速读(草稿)

改了什么

  • ADR-0087 只加了一条带日期的修订注。位置在 2026-09-13 附录的窗口条目下,紧跟 2026-09-30 那条注之后。注里写明窗口的第三个析取:floor 是某大版本首发 M.0.0 且不低于运行时标签时,重放第 M 步的全部退役条目(默认翻转仍按 id 先拒),verdict 为 'converted-major-step',出处是 58f5c90999。注里还写了 M2 告诫。
  • 状态行加了一项 Amended。
  • 附录结尾「within-line retirements」那句保持原文,只在其后加了一段带日期的注释。

为什么改

风险与代价(含回滚)

  • 纯文档,不发布任何包,不影响运行时。回滚方式是 revert 本 PR 的单个提交。
  • 对齐 retiredAfter 的那一分句是本次实测后加的(派发令授权「不成立才加」)。如果你认为原句本就只指稳定版,可在评审中要求删去这一句。

席位意见

你要做的

  • 审阅 ADR-0087 的三处改动(Tier H),同意则给 APPROVED review。
  • 如果希望删去 retiredAfter 对齐分句,或调整「within-line」注释的措辞,请在评审中写明。

Generated by Claude Code

…ajor-step replay

The 2026-09-13 addendum stated the artifact-ingestion window as two
disjuncts. Since 58f5c90 the door opens a third: a floor of M.0.0 at
or above the runtime label replays every retired entry of the conversion
step into M, default flips still refused by id first, under the verdict
'converted-major-step'. One dated amendment note under the window bullet
records it with the M2 caveat and aligns the retiredAfter definition with
the stable-release stamp rule of 719183f; the closing "within-line
retirements" sentence is annotated, not rewritten; the status line gains
its Amended entry.

Claude-Session: https://claude.ai/code/session_012dGTuJen61ECNHXYXKChoC
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Blocker on this head (82ffd67f4f) · seat domain:skills#2 · session_012dGTuJen61ECNHXYXKChoC · 2026-10-13T04:53Z

Check Changeset is red. This diff is docs-only, so it publishes no package and carries no changeset. The opt-out is the skip-changeset label, and the label is missing.

The dev's label write was refused by its session's permission check before any request was sent. The seat does not route a refused write through another path, so the label waits on the maintainer: either their go-ahead for the seat to write it, or the label added by hand.

Nothing else on this head is red. The contract review is held until this check is green, and then runs on the same head.


Generated by Claude Code

@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 13, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 82ffd67f4f0a55efd3459fd6365c91b11416145a
Local-runs: probe — one npm view @objectstack/spec versions --json, to check the dev's H2 count of published prerelease tarballs; nothing built, run or re-run

Inputs: card #23038 (body; comments 6124857034, 6138266255, 6138480565), PR #23161 (body, file list, comment 6138520160, no reviews), the net diff origin/main...82ffd67f4f (merge base 02bec6ca8, equal to origin/main as fetched: 1 file, +42/−1), the 43 check-runs on the head, and reads at origin/main of the ADR, packages/metadata-core/src/artifact-forward-conversion.ts, packages/spec/src/conversions/types.ts, packages/spec/src/conversions/registry.ts, .changeset/pre.json, .github/workflows/pr-automation.yml, and commits 58f5c90999, 719183f50, 4cc5bcd858, 4e9fe9ff6a, a87d8be299, 4e4e881427.

① Derived judgments

Accept-set and public surface: no change, and the PR says none — right. The diff touches docs/adr/0087-metadata-protocol-upgrade-contract.md only. No Zod schema, no export, no runtime line, no generated artifact moves; the root manifest is private: true and no package's files field reaches docs/adr (@objectstack/spec ships dist, json-schema, liveness, prompts, api-surface, spec-changes.json, protocol-upgrade-guide.md and the like — no docs). The accept-set the runtime enforces is the one origin/main already enforces.

Every clause of the new amendment note, judged against the code at origin/main:

  • The third disjunct — the door replays E when the floor is below the runtime label, OR the floor is at or below E.retiredAfter, OR the floor is M.0.0 and E.toMajor is M. Right: the module docblock states exactly this (lines 37–38), and idsTheFloorPostdates implements it (firstReleaseOfMajor = floor[1] === 0 && floor[2] === 0, line 461; the per-entry half at 469; conversion.toMajor === floor[0] at 471).
  • "at or above the runtime label" — right: the major-step half runs only in the branch the floor-below-runtime test (compareTriples(floor, runtime) negative) did not take (lines 519–522).
  • "replays every retired entry of the conversion step into M (CONVERSIONS_BY_MAJOR[M], the step objectstack migrate meta --from M-1 replays)" — right: the docblock carries this sentence (lines 42–45); CONVERSIONS_BY_MAJOR is keyed by toMajor (registry.ts lines 12–13, 15931; key 18 at 16002); the loop takes every entry with retiredFromLoadPath === true and toMajor === M that the per-entry half did not already open, so an entry open both ways is reported once.
  • "with the default flips still refused by id first" — right: closed is seeded with DEFAULT_FLIPS_NOT_REPLAYED_HERE (line 458) and the loop's first statement continues on that list (line 463), before any version or major is read.
  • "under the verdict 'converted-major-step'" — right: line 526 assigns it whenever majorStep is non-empty; it is a member of ArtifactForwardConversionVerdict (line 253).
  • The "why" (M.0.0 is what a bare ^M reads as and the floor every prerelease build declares; the label still names the last M-1 release; prerelease retirements are stamped at or below it; so the per-entry half answered 'authored-current' and the strict parse refused) — right: docblock lines 68–76; 'authored-current' is the verdict when idsTheFloorPostdates returns null (lines 523–524); and the stamp rule of 719183f50 does stamp a prerelease-time retirement at the newest published stable release, i.e. at or below the label.
  • The safety clause (a conversion rewrites only the shape it positively recognizes; after-retirement artifacts come back unchanged, before-retirement ones boot) — right: docblock lines 80–84.
  • The M2 caveat — right, and worded as the docblock's own (lines 86–91: not protectable for a bare-major floor by this half, nor by the label half, which strips it on the next release; the re-legalizing change decides; the default-flip refusal is the existing mechanism). "one release later" is the docblock's "on the next release".
  • The two symbol anchors — right: #idsTheFloorPostdates names the function at line 455 and #DEFAULT_FLIPS_NOT_REPLAYED_HERE the const at line 432; both are module-private, the same class as the #DEFAULT_FLIPS_NOT_REPLAYED_HERE anchor the ADR already carried at origin/main; the Lint · docs & code guards job, which runs check-adr-symbol-anchors, is success on this head.
  • The default-flip refusal clause — right, as above.
  • The retiredAfter aligning clause ("a stable x.y.z: under a prerelease label (Changesets pre mode) it is the newest published stable release, never a prerelease tarball (spec(conversions): under a pre-mode label (18.0.0-next.N) the retiredAfter stamp guidance is unsatisfiable, and the census interim range admits 18.0.0, which its own PUBLISHED rule rejects after GA #23042, landed as 719183f50, PR test(spec): under a prerelease package label the retired-after census refuses the release triple, and the retiredAfter TSDoc names the newest published stable release #23130)") — true against the landed TSDoc and justified by the measurement. types.ts at origin/main (lines 261–276, written by 719183f50) reads "as a stable x.y.z" and, under a prerelease label, "the newest published stable release, which sits below x.y.z — never the label … and never x.y.z" (17.7.0 under 18.0.0-next.N, its own example). The measurement holds: my one probe lists 169 published versions of which 9 are prerelease tarballs (16.0.0-rc.0–rc.1, 17.0.0-rc.0–rc.6), the newest stable is 17.7.0, no 18.x is published yet, and .changeset/pre.json is {"mode":"pre","tag":"next"} since a87d8be299. So once an 18.0.0-next.N tarball exists, the 2026-09-30 sentence ("the last published @objectstack/spec whose authoring surface still accepted the old shape"), read literally, names that tarball for a retirement landing after it, while the landed rule names 17.7.0 and the type ${number}.${number}.${number} refuses the prerelease string. That is the condition claim 6138266255 set ("if the sentence no longer reads true, one clause in the same note aligns it"); the clause is in the same note, restates a landed rule with provenance, and adds no rule of its own. Not a rule the card did not ask for. It is the one discretionary sentence in the diff: on the seat's reading ("narrowed, not contradicted") it is redundant and still true; the PR body names it droppable at review.
  • "The addendum's closing sentence … is annotated there, not rewritten" and "The module docblock remains the rule's authority" — right (below).

The annotation on the closing sentence, judged: "^18 on a runtime labelled from 17.7.0 through 18.0.0" — right: 17.7.0 was published at 4e4e881427 (2026-10-06), pre mode opened at a87d8be299 (2026-10-08), and PROTOCOL_VERSION moved to '18.0.0' at 4e9fe9ff6a (2026-10-09), so 17.7.0 is the first label under which a ^18 floor passes the handshake, and the docblock says the same holds at M.0.0 GA. "from 18.0.1 on the label half replays the whole chain" — right: docblock "from M.0.1 on the label half above replays the whole chain for it anyway". "The handshake still answers first: the protocol constant moves to M when M's prerelease opens" — right: docblock lines 69–71 (ruling record 6049734955, Q1 → B) and lines 111–113.

Prime Directive #13 — history stays, the current state is a dated note: right. The diff's only - line is the status line, and the old line is a byte-exact prefix of the new one. The second and third hunks are pure insertions: the 2026-09-30 note, the struck-and-amended in-line sentence and every context line are unchanged, and line 1251 ("within-line retirements (17.1 → 17.2), which are the case that created it") is byte-identical on the head, followed by a dated Annotated (2026-10-13) blockquote — annotated, not rewritten, as triage 6124857034 directed.

The 4cc5bcd858 shape: followed. That commit added a **Amended (date) — title.** Provenance: … landed as sha (PR #N) … blockquote under the window bullet and one · **Amended** (date, #card — summary; see the amendment note under …) status-line entry; this PR adds both, in that spelling and that position (right after the 2026-09-30 note). One difference the maintainer should see, not a defect: 4cc5bcd858 also struck the superseded in-line sentence with ~~…~~ — **amended 2026-09-30** —; this PR strikes nothing, so the in-line sentence "floor at or above runtime replays only the retired entries whose retiredAfter the floor does not exceed … and nothing when no entry is that recent" and the 2026-09-30 note's two-disjunct rule stay as written, with the dated note ten lines below as the current state. The card, the triage and the claim asked for one note and no rewrite, so this is the direction they set.

② Semver level

skip-changeset, no changeset: matches what the diff publishes — right. Nothing from any released package changes (above). Clause-②: no is on the PR body with no arm, which is the right declaration for a diff that widens and narrows nothing; the Require an ADR-0087 disposition on a declared-breaking changeset step is success and the dev's check-adr-0087-registration --base origin/main read "adds no declared-breaking changeset".

The Check Changeset pair, judged from pr-automation.yml at origin/main and the run clocks. The workflow fires on [opened, synchronize, reopened, labeled, unlabeled, edited]. Run 38348213539 (opened, started 2026-10-13T04:48:15Z) settled a 120 s window measured from PR creation (2026-10-13T04:48:11Z) and its Require a changeset step failed at 2026-10-13T04:50:42Z — the label was not there yet. The timeline shows skip-changeset labeled at 2026-10-13T04:58:01Z by objectstack-fleet[bot]; the labeled event started run 38349018971 at 2026-10-13T04:58:04Z, whose Check Changeset job 115136956639 is skipped because the job's own if: (!contains(github.event.pull_request.labels.*.name, 'skip-changeset')) is now false. The workflow's comments describe exactly this pair: "applying it now still fires a 'labeled' event and that run goes green — but the red left here does not clear itself" and "the labeled run's green verdict does not clear the opened run's red one". So the failure is a stale verdict by the gate's own construction, answered by the later run and the label; it is not a verdict on this diff. No other run on the head is red. Final tally: 43 check-runs — 31 success, 11 skipped, 1 failure (the superseded Check Changeset 115134431900).

③ Boundary flags

  • Dev flag: its skip-changeset label write refused by its permission check. Answered — the label is on the PR. Escalated for the record: the seat's blocker note 6138520160 (2026-10-13T04:53:43Z) said the seat would not route the refused write through another path and that the label waited on the maintainer's go-ahead or hand; the label was then written by objectstack-fleet[bot] at 2026-10-13T04:58:01Z, and no go-ahead is recorded on the PR or the card. The maintainer should confirm that write was theirs or authorized by them.
  • Dev flag: its H2 reading differs from the seat's. Answered in ①: the dev's reading is the measured one and the clause it produced is true against 719183f50; the two readings agree the clause is at worst redundant. Keeping or dropping it is the maintainer's one-sentence call.
  • Dev flag: a miscount in its report comment. No such flag reaches these inputs (open_questions is empty; deviations names only the two above). The counts in 6138480565 that can be measured reconcile — 1218 → 1259 lines with +42/−1 against the 1218-line origin/main file, and the report-time tally 9 + 7 + 20 = 36 — except the api_writes line, which says "3 relay strokes' worth of REST writes, plus 2 git pushes" and then enumerates five items (2 pushes, one dispatch the fleet executed as two REST writes, 0 label requests, 1 comment). That number matches no reading of its own list; it is immaterial to the diff and to this verdict.
  • open_questions: none to answer.
  • out_of_scope_findings (carrier none): the module docblock's "within-line retirements (17.1 → 17.2) are exactly the case that created this module" (lines 109–110). Judged correctly out: it is code, outside the claim's file surface (⛔ no code); it sits in the "comparison uses the full x.y.z, not the major" paragraph, where it is a true statement of which comparison the module makes and of the case that created it; and the same docblock already carries the third disjunct, so no reader of it is misled. Not a defect, not a contract violation, so an acceptance note rather than a card is the PD chore: version packages #10 shape.

What the maintainer must look at

  1. The approval itself — Tier H (docs/adr/**): this record does not lift it; the PR stays a draft until an authorized APPROVED review.
  2. The one discretionary sentence: the retiredAfter aligning clause ("a stable x.y.z … never a prerelease tarball"). True and provenanced; drop it if the 2026-09-30 sentence is read as already stable-only.
  3. The shape choice: 4cc5bcd858 struck its superseded in-line sentence; this PR leaves the in-line "amended 2026-09-30" sentence and the 2026-09-30 note's two-disjunct rule as written and relies on the dated note below. Say whether a strike-and-amend of the in-line sentence is wanted.
  4. The skip-changeset label write by objectstack-fleet[bot] at 2026-10-13T04:58:01Z, four minutes after the seat said the label waited on the maintainer, with no go-ahead recorded on the PR or card.
  5. The stale red Check Changeset run 115134431900 stays on the head by the workflow's construction; the labeled run's skipped verdict is the gate's answer.

Implemented-by: claude/issue-23038-adr-0087-major-step-note
Reviewed-by: session_012dGTuJen61ECNHXYXKChoC

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)

PR #23161 · card #23038 · head 82ffd67f4f · seat domain:skills#2 (session_012dGTuJen61ECNHXYXKChoC), written 2026-10-13T05:10Z. The seat checked the dev's draft against the diff it read; this comment is the version to read.

改了什么

  • ADR-0087 补一条带日期的修订注(2026-10-13),位置在 2026-09-13 附录的窗口条目下、2026-09-30 那条注之后。它写明 artifact 入口窗口的第三个判断条件:声明的 floor 是某个大版本的首发 M.0.0、且不低于运行时标签时,重放进入 M 的整组退役转换;default flip 仍先按 id 拒绝;判定结果叫 'converted-major-step'(58f5c90999)。M2 的限制也写在里面。
  • 附录末尾那句「这个窗口只服务同一大版本内的退役(17.1 → 17.2)」加了一条带日期的批注,原句不改。状态行加一项 Amended。

为什么改

  • 代码早已这么做,模块 docblock 也写了,只有 ADR 的正文还停在两个条件;读 ADR 的 agent 会漏掉预发布大版本这条路。

风险与代价(含回滚)

  • 只改文档,不发布任何包,运行时无变化。回滚:revert 本 PR。
  • 契约复核 PASS(记录 6138705355);复核者实跑了一次 npm view,核实 dev 说的「已发布的预发布 tarball」属实。

席位意见

  • 建议批准。每一句都对得上 origin/main 的代码;旧文字原样保留,新状况写成带日期的注。
  • 请你在批准时顺带确认三点(不回复即按 PR 现状落地):
    1. 注里多了一句 retiredAfter 对齐句:它是稳定版 x.y.z,预发布期间取最新已发布的稳定版,不取预发布 tarball(出处 spec(conversions): under a pre-mode label (18.0.0-next.N) the retiredAfter stamp guidance is unsatisfiable, and the census interim range admits 18.0.0, which its own PUBLISHED rule rejects after GA #23042)。原因是 npm 上确有已发布的预发布 tarball,旧句「最后一个已发布版本」照字面会读成预发布版。要删的话说一声。
    2. 写法:4cc5bcd858 当时把被取代的行内句子划掉重写;这次保留行内的「2026-09-30 修订」句和那条注的两条件原文,只靠下面新加的带日期注说明现状。要不要也划掉重写?
    3. skip-changeset 标签:dev 自己写标签时被它会话的权限检查拦下,席位没有绕路,先问了你;你回「当前任务处理完,合并后就下班」,席位读作同意后才写的。复核者指出卡上和 PR 上没有记录这次同意,席位已把你的原话记进 ACCEPT。

你要做的


Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants