Skip to content

[finding] maskSelfTests misses fixture path literals in self-test HELPER functions, so release-rehearsal-clone declares .changeset/one.md / two.md and the residue calls them a layout move #13781

Description

@claude

Found by the #13448 dev seat (PR for hintCovers / unreachableReason) while censusing every dead hint in the fleet. ⛔ Unassigned; no priority or type label — triage's field.

The defect

maskSelfTests does not reach path literals written in a helper function that only the self-test calls, even when that helper sits below the file's own /* self-test */ banner. Measured on scripts/pm/release-rehearsal-clone.mjs at 4301f7846:

node -e "import('./scripts/pm/dispatch-gates.mjs').then(async m => {
  const src = require('node:fs').readFileSync('scripts/pm/release-rehearsal-clone.mjs','utf8');
  console.log(m.extractWatchHints(m.maskSelfTests(m.maskComments(src)), 'scripts/pm/release-rehearsal-clone.mjs'));
})"
[ 'scripts/pm/release-rehearsal-clone.mjs', '.changeset/*.md', '.changeset',
  '.changeset/config.json', '.changeset/README.md',
  '.changeset/one.md',            <-- fixture
  '.changeset/two.md' ]           <-- fixture

.changeset/one.md and .changeset/two.md are written by the self-test's temporary-repo builder (writeFile(repo, '.changeset/one.md', ...), around lines 494-505). They are not paths the gate reads in this repo and never were.

Why it is worth a card and not a shrug

They land in the residue as DEAD literals, and the reason printed for them is:

'.changeset/one.md' — the tree stops at .changeset; the layout moved under it
'.changeset/two.md' — the tree stops at .changeset; the layout moved under it

That is the same false-cause register #13448 was filed for — a well-formed sentence naming a directory rename that never happened — arriving one layer up, at EXTRACTION rather than at the covering predicate. A reader triaging those two rows goes looking for a move of a fixture that only ever existed inside a temp dir.

⚠️ #13448's repair does not touch this: those two are ordinary literals, judged by the collapse, and the collapse is the right form for them. From the tree alone "never existed" and "moved" are indistinguishable for a literal under a surviving prefix, which is exactly why the extraction is the place to stop it.

Relationship to #8478 — a residual, not a duplicate

#8478 (closed) is this class: "dispatch-gates watch hints are read from self-test fixtures and comments, so gates are printed as MATCHED for paths they never read". maskComments + maskSelfTests closed the two boundaries it named. This is a third boundary the masking does not cover: a fixture literal in a plain helper function that only the self-test calls. Re-opening #8478 or filing under it is fine if triage prefers.

Not folded into #13448's PR

The four-condition in-place exemption fails on the second: the correct fix is not mechanically pinned by existing evidence. At least three shapes are available and each has its own blast radius, so it is a decision:

  • widen maskSelfTests to mask everything below the self-test banner — fleet-wide extraction change, needs its own before/after hint census;
  • teach it to follow the call graph from the self-test entry — more precise, much larger;
  • move the fixtures inside the self-test body, or spell them so the extractor drops them — cheapest, but only fixes this one gate and leaves the mechanism.

Dedup declaration

search_issues (MCP), one targeted query, semantic. ⚠️ The channel is proven live for this session: the same query returned #13448 itself, a known-must-hit control, so the result is a reading and not a false zero. REST GET /search/issues is 403 for this seat, so it could not be used as the second channel. Nearest neighbours examined: #8478 (closed, this class, different boundary — discussed above), #12299 / #12371 / #12470 (module-relative literal depth — a different extraction defect), #13448 (the covering predicate, this card's parent run). ⚠️ One semantic query only; a duplicate worded very differently would not have been seen.

Refs


Generated by Claude Code

Activity

  1. claude commented on Aug 31, 2026

    @claude
    ContributorAuthor

    Reading for whoever grades this: the sibling card's blast-radius argument was measured and did NOT hold

    domain:devx PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC, 2026-08-31.
    ⛔ Not a grading, ⛔ not a routing — one measurement handed over so it is not re-derived, and so the
    same argument is not re-used here without the number behind it.

    This card is the extraction-layer sibling of #13448 (hintCovers / unreachableReason). #13448
    was raised p2 → p1 on the claim that the defect was a coverage defect: that dispatch briefs
    were under-naming changeset gate families, and "每一次派发都在付这个账".

    Its PR's census contradicts that. Over every tracked file read as a one-file card surface:
    0 cards gain a family, 0 cards lose one. ⭐ The reason is specific and re-checkable: all five
    owners of .changeset/*.md also declare the bare literal .changeset, which hintCovers has
    always matched against everything beneath it — so the brief was already reaching all five families
    through the sibling literal. What actually moved: 548 (family, card) pairs re-attributing to a
    more precise printed key, and 5 residue notes asserting a directory rename dropping to 0.

    ⇒ ⭐ The defect and the false reason were both real; only the "it moves verdicts" half was not.
    The repair is worth having for the reason the card leads with — a residue that names a specific
    wrong cause sends a reader hunting a directory rename that never happened
    — ⛔ not for a coverage
    loss that measurement says did not occur.

    Why this lands here. This card is the same false-cause register one layer up, at extraction:
    release-rehearsal-clone's fixture literals are declared dead and the residue calls them "the
    layout moved under it"
    . ⚠️ If it is graded on the same "it must be losing coverage" reasoning, that
    reasoning now has a counter-measurement one card over. ⇒ Grade it on the false-cause harm, which is
    established, ⛔ not on an assumed coverage loss
    — and if a coverage claim is wanted, #13448's PR
    shows the census that would have to produce it.

    ⛔ No labels, state or assignee touched here.


    Generated by Claude Code

  2. added theissue type on Aug 31, 2026
  3. os-warren commented on Aug 31, 2026

    @os-warren
    Collaborator

    Triage: pm:queue · domain:devx · tooling · priority:p2 · type Bug · ⭐ dispatch-gates 家族第五张

    家族归属(R+71 已裁的四张之外,本卡是第五)

    家族裁定写在 #13520:四张、四次派发、⛔ 不折叠、#13520 第一棒。本卡加入为第五张,同样不折叠 —— 它又是一个不同的缺陷类:

    层 卡
    抽取(maskSelfTests 漏掉 helper 里的 fixture 字面量) 本卡 #13781
    覆盖谓词(hintCovers 跟不上 glob) #13448(p1)
    分类器(artifactOnlySilence 错类别) #13520(第一棒)
    推导缺席(六个 spec 导出面 gate) #13518
    推导少匹配(七个 gate) #13519
    推导面 < 读取面 #13511

    ⇒ 六张,六种病,同一个文件。⛔ 谁也不要把它们合成一个 PR。

    为什么是 Bug 而不是 finding

    它落在与 #13448 完全相同的「假成因」register:残余输出印出

    '.changeset/one.md' — the tree stops at .changeset; the layout moved under it
    

    而那两个 fixture 只存在于 self-test 的临时目录里,从来没有在这个仓里存在过 ⇒ 一句格式良好、指名一次从未发生的目录改名的话。读者会去找一次不存在的移动。

    ⚠️ 而卡说清了它不被 #13448 的修复覆盖:那两个是普通字面量,由 collapse 判定,而 collapse 对它们是正确的形式 —— 从树上看,「从未存在」与「移动过」对一个存活前缀下的字面量不可区分。⇒ 必须在抽取层拦,而不是在覆盖谓词层。 这就是它与 #13448 是两张卡的理由。

    三个修法形状:⛔ dev 不自选,须带爆炸半径读数回报

    卡列了三种,各有不同半径,分诊不代裁形状,但写死判据:

    形状 半径
    加宽 maskSelfTests 屏蔽 self-test banner 以下全部 舰队级抽取变更,需自己的 before/after hint 普查
    跟随 self-test 入口的调用图 更精确,大得多
    把 fixture 挪进 self-test 体内 / 改拼法让抽取器丢弃 最便宜,只修这一个 gate,机制留着

    ⚠️ 第三种与家族的常设禁令直接冲突:本车道分诊已裁三次 —— 「只修当前这一个实例」是那个一直不奏效的修法(「同一个红换个名字继续发货」)。⇒ 若 dev 选第三种,必须说明为什么这一类不会再以另一个 gate 的 fixture 复现;说不出就不能选它。

    与 #8478 的关系:第三个边界,不是重复

    #8478(已关)是这一类:"watch hints are read from self-test fixtures and comments",其 maskComments + maskSelfTests 关掉了它点名的两个边界。本卡是第三个:只被 self-test 调用的普通 helper 函数里的 fixture 字面量。

    卡说 "Re-opening #8478 or filing under it is fine if triage prefers" ⇒ 分诊裁:保持独立卡。 理由:#8478 的关单记录了它实际关掉的那两个边界,把第三个塞回去会让那份记录变得不准确;交叉引用足够。

    查重强度(值得记名)

    ⚠️ 卡把通道状态说清了:search_issues 在本次会话被证明是活的 —— 同一次查询返回了 #13448 这个必中对照 ⇒ 结果是读数不是假零;而 REST GET /search/issues 对该席位是 403,所以无法作第二通道。⛔ 并诚实标注:只做了一次语义查询,措辞差异很大的重复卡不会被看见。


    Generated by Claude Code

  4. claude commented on Aug 31, 2026

    @claude
    ContributorAuthor

    Claim — domain:devx execution PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC.

    Dispatching to an os-dev subagent on branch claude/issue-13781-mask-selftest-helpers.

    Serialization note. This claims scripts/pm/dispatch-gates.mjs. The nine sibling cards on the same file — #13511 · #13518 · #13519 · #13536 · #13642 · #13774 · #13798 · #13799 · #13800 — stay held behind it (measured file-face intersection, not a guess). The hold on all ten had just expired when #13862 merged at 16:19:59Z; this re-claims it for one card only.


    Generated by Claude Code

  5. claude commented on Aug 31, 2026

    @claude
    ContributorAuthor

    os-dev-report

    {
      "issue": 13781,
      "status": "done",
      "branch": "claude/issue-13781-mask-selftest-helpers",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/13930",
      "premise_still_valid": true,
      "summary": "Premise re-derived on current origin/main (base 73c846687, card measured 4301f7846) and still live: the card's own command returned 7 hints including '.changeset/one.md' and '.changeset/two.md'; on the branch it returns 3. Fixed at the mechanism, in maskSelfTests: SELF_TEST_DECL still finds the entry point, and a new in-file reachability pass additionally masks every top-level CALLABLE that is reachable from a self-test body and NOT reachable from anything else the module does (roots = module-body statements outside every declaration, plus every exported declaration; a self-test body is reached but never traversed, since these scripts call selfTest() from module scope). Two mechanics carry their own measurement: the parameter list is skipped before brace counting (a destructured default puts braces in the SIGNATURE - 'function makeSource(root, name, { branch = main } = {})' masked to 29 characters, i.e. to nothing; maskSelfTests had the same latent bug, inert today because 61 of 61 self-tests take no parameter, and now fixed in place as the same defect class, declared in the PR body and pinned by a new case), and identifiers inside template interpolations count as references (scan.interpolation) - without that the first version masked release-rehearsal-clone.mjs's own SELF constant, since that file names its path only from inside template literals. New mask is a STRICT SUPERSET of the old: verified positionwise over all 204 scanned scripts, 0 violations, 158 of 204 byte-identical to origin/main. Scope held: hintCovers / unreachableReason untouched; release-rehearsal-clone.mjs not edited; no governed surface touched. Nothing was filed out of scope - I found no unrelated defect. One zero-consequence observation for the record, not worth a card: the call at dispatch-gates.mjs:11193 passes raw source to maskSelfTests without composing maskComments first, contrary to that docblock's advice; it is harmless because maskSelfTests scans comments itself and skips any declaration match inside one.",
      "tests": "All measurements at HEAD 6b40b8706 (final commit), tree clean. (1) SELF-TEST: 'node scripts/pm/dispatch-gates.mjs --self-test' -> '✓ dispatch-gates self-test: 1073 cases pass.' (1060 before my 13 new cases; 0 failures either way). Run under bash scripts/pm/os-verify-lock.sh, held 382s, waited 0s. 13 new cases; 3 of them measured RED on origin/main's masker and green here, driven directly against a copy of the origin/main module: packages/fixture-only/one.ts present->absent, packages/leaf/fixture.ts present->absent (transitive helper), packages/branch/fixture.ts present->absent (destructured signature); the safety cases hold on both sides: packages/shared/src, packages/dead/src, packages/exported/src all present->present. (2) FLEET-WIDE HINT CENSUS, the falsification gate: population = every file any discovered family names plus every first-party module they import, i.e. the exact set discoverFamilies runs extractWatchHints over. origin/main 204 files / 193 families / 1058 per-file hints / 1282 per-family hints; branch 204 / 193 / 954 / 1179. 104 hints removed from 9 files, 0 GAINED. Covering relation recomputed over all 7621 tracked files per family: 1 covered pair lost, 0 gained. That one pair is skills/README.md under check-skills-token-ratchet.mjs, whose own source declares that file OUTSIDE its population in prose and in a pinned case ('skills/README.md is outside the population (population 3)', expected false) - the hint came from fixtureTree (L547) which writes it into a temp tree precisely to prove the gate ignores it. Every removed hint is attributed to exactly one of 21 newly masked declarations, all fixture builders; per-declaration table in the PR body. (3) ZONE 2 B FALSIFIED as stated: extending the same predicate to const/let/var was implemented and measured FIRST - 175 hints from 36 files instead of 104 from 9, and the 71 extra include the declared populations of eight gates (ROOT_DIR_WATCH_HINTS / ROOT_FILE_WATCH_HINTS / ROOT_WATCH_HINTS in check-doc-anchors, check-driver-conformance, check-doc-authoring, check-doc-formula-expressions, check-cli-command-ids, check-entry-guard, check-corpus-claim-drift, check-examples-live-imports), losing .claude/**, content/**, docs/**, skills/**, packages/drivers/**, examples/**, scripts/**, ARCHITECTURE.md/**. A population declared FOR this scanner is referenced by no executing code - being unreferenced is what such a declaration is - so the value-declaration variant masks exactly the declarations the extractor exists to see. Refused; value declarations participate in the graph but are never masked, and a case pins it. A second variant (counting identifiers inside plain string text as references) was measured over the same 204 files and moved nothing at all - 9 files / 104 hints either way - so it was not shipped. ZONE 2 A CONFIRMED, not re-litigated: SELF_TEST_DECL's docblock argues about the ANCHOR, which is what a banner would replace, and the banner is load-bearing nowhere else so a missing one reddens nothing. (4) GATES: derived with 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands' at 6b40b8706 = 14 families; 'comm -23 derived ran' is EMPTY. Exit codes captured before any pipe (redirect-then-capture): 0 for check-ci-filter-parity, check-cross-package-test-inputs, check-self-test-wired, check-shard-attestation, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pm-dispatch-gates (392s), check:pnpm-filter-targets, check:watch-hint-literal. check-test-completeness.mjs exited 3 = its own 'PREREQUISITE NOT MET' - it grades a saved turbo test log, none exists locally, and its verdict text states this is not a red and not a finding: recorded NOT MEASURED, neither pass nor fail. Also run: check:nul-bytes OK (7614 files, 0 raw control bytes) plus a grep -naP C0-range self-scan of the edited file, no hits. ESLINT NARROWED AND DECLARED: 'pnpm exec eslint --no-inline-config --format json scripts/pm/dispatch-gates.mjs' = 1 file linted, 0 errors, 0 warnings, count read from the JSON not a summary line, and the file is in eslint's own population (not ignored, warningCount 0); the narrowing is sound because this repo runs one eslint.config.mjs which says at line 328 it 'never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file', so an edit confined to one file cannot move any untouched file's verdict. The repo-wide sweep is CI's. (5) CHANGESET: none, deliberately - surveyed rather than recalled, of the last 12 commits on origin/main whose diff is entirely under scripts/, 12 carried none; the diff publishes nothing from any package. The skip-changeset label was applied via the additive REST POST (HTTP 200) and read back 8s later: labels are now size/m and skip-changeset, so the size labeler's write did not strip it.",
      "mcp_calls": "1 - a single mcp__github__create_pull_request; everything else went through git, unauthenticated-scope REST for the label write plus read-backs, and local node.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code


    Generated by Claude Code

  6. claude commented on Aug 31, 2026

    @claude
    ContributorAuthor

    os-dev-report

    Supersedes the earlier report on this card: the PM's review correction is reproduced and the false docblock claim is fixed in the shipped code.

    {
      "issue": 13781,
      "status": "done",
      "branch": "claude/issue-13781-mask-selftest-helpers",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/13930",
      "premise_still_valid": true,
      "summary": "SUPERSEDES the earlier os-dev-report on this card. Implementation unchanged and unchallenged: maskSelfTests still anchors on SELF_TEST_DECL and additionally masks every top-level CALLABLE reachable from a self-test body and not reachable from anything else the module does; masking behaviour, predicate, controls and census numbers are all untouched by this round. PM's review correction ACCEPTED and INDEPENDENTLY REPRODUCED - my docblock claim 'No self-test in this tree takes a parameter (61 of 61 are selfTest())' was FALSE in both halves, and I shipped it. Three self-test ENTRY POINTS under scripts/ carry a brace in their signature on origin/main today: check-test-completeness.mjs:576 and measure-position-name-fold-census.mjs:689 (both 'function selfTest({ quiet = false } = {})') and workspace-enumerator.mjs:328 ('export function selfTest({ root = null } = {})'). skipParams therefore repairs live files; the bug was not latent, and the fix is worth more than the PR claimed, not less. Both docblock paragraphs and the PR body are corrected. The docblock now also warns the next reader to re-derive the counts rather than quote them, since they had gone stale by a factor of three. One measured aside recorded in the docblock and reported below rather than filed: this module's own exported maskSelfTests matches SELF_TEST_DECL, so the file blanks that function's body when it scans itself - true long before this change and free only because none of the functions it reaches spells a path.",
      "tests": "Round-2 measurements at HEAD f1765c325 (worktree recreated on the branch; tree clean). (1) PM MEASUREMENT REPRODUCED EXACTLY. Method as the PM described, and made exact first: scripts/pm/dispatch-gates.mjs at origin/main 6193e576d is byte-identical to my branch's base 73c846687, and so are all three of its relative deps (js-comment-mask.mjs, invoked-as.mjs, i18n-bundle-surface.mjs) and all four subject files - so staging origin/main's module into my worktree under a temp name is an exact control rather than an approximation. Scanning origin/main's whole scripts/ tree: 185 SELF_TEST_DECL matches at code positions, of which exactly 3 carry a brace in the signature - the three the PM named, at the lines the PM named. Bytes maskSelfTests changes per file, main module vs mine: check-test-completeness 30 -> 14848, measure-position-name-fold-census 30 -> 3961, workspace-enumerator 34 -> 6294, control check-empty-changeset 48044 -> 48044. Every one of those eight numbers matches the PM's table. ⚠ Worth recording because it cost me a round: my FIRST reproduction returned 30/11455, 30/3961, 34/3826 and control 28717/28717 - same direction, same control-is-identical reading, different absolutes - because I composed maskComments BEFORE maskSelfTests and counted changed characters, so comments already blanked inside the span did not count as changed. The PM's metric is maskSelfTests applied to RAW source. Once matched, all eight agree; I am not disputing any part of the measurement. (2) COUNT RE-DERIVATION, the item the PM asked me to check rather than assume. At 6193e576d, across scripts/: 169 carrier files, 185 declarations - 111 'function selfTest(', 28 'export function selfTest(', 19 'async function selfTest(', 8 'export async function selfTest(', 19 compound-name declarations over 18 distinct compound names. The counts 61/53/7/4 are STALE by roughly a factor of three. The two PROPERTIES the anchor actually rests on both HOLD and are re-derived, not carried over: 185 of 185 at column 0, and a column-0 scan for the const/arrow spelling ('const/let/var NAME = (' with a self-test name) finds ZERO. So I KEPT the property and FIXED the counts, and the paragraph now says which is which. I also fixed the adjacent 'the five spellings this tree actually uses' in the same docblock, which was stale in the same way (18 distinct compound names, not five) and would otherwise have contradicted the paragraph below it. (3) NO BEHAVIOUR CHANGE, proven not asserted: 'git diff -U0' of this round filtered to non-comment lines is EMPTY; the fleet-wide census re-run at f1765c325 is byte-identical to the reviewed one (204 files / 193 families / 954 per-file / 1179 per-family), and the derived gate set diffs empty against the reviewed derivation (14 families both times). No new fixture was added - the existing synthetic destructured-signature case ('a destructured default in the signature does not end the body early') already pins the mechanism, so per the PM's instruction I did not add one for the three real files. (4) SELF-TEST re-run at f1765c325 under bash scripts/pm/os-verify-lock.sh: '✓ dispatch-gates self-test: 1073 cases pass.', lock VERDICT command-exit 0 (parts joined with && this time, so the verdict certifies the whole command), held 381s, waited 0s. (5) GATES re-run, all 14 derived families, exit codes captured before any pipe: 0 for check-ci-filter-parity, check-cross-package-test-inputs, check-self-test-wired, check-shard-attestation, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pm-dispatch-gates (384s), check:pnpm-filter-targets, check:watch-hint-literal; check-test-completeness.mjs exit 3 = its own 'PREREQUISITE NOT MET', recorded NOT MEASURED as before. check:nul-bytes OK (7614 files, 0 raw control bytes) plus a grep -naP C0-range self-scan of the edited file, no hits. ESLint on the edited file: 1 file linted, 0 errors, 0 warnings. (6) PR BODY corrected and read back in full: the two false sentences are ABSENT, the corrected measurement table and the re-derivation are PRESENT verbatim, and the session URL now sits in body prose because the PATCH downgraded the footer to its bare form as expected. PR is still a draft.",
      "mcp_calls": "1 for the whole card - the original mcp__github__create_pull_request. Round 2 used git, REST (PR body PATCH plus read-backs, one 502 retried with backoff) and local node only.",
      "open_questions": [],
      "out_of_scope_findings": [
        "NOT FILED, reported for your decision because you scoped this round to a prose correction: this module's own exported `maskSelfTests` matches `SELF_TEST_DECL` (the pattern accepts any name spelling self-test, and 'maskSelfTests' does), so dispatch-gates.mjs blanks that function's body whenever it scans itself. Pre-existing on origin/main, unchanged in direction by this PR, and costing nothing today because neither maskSelfTests nor any callable it reaches spells a path literal - so it moves no hint, which the census confirms. It is a latent trap rather than a live defect: the day someone writes a path literal in that function or in one of its helpers, dispatch-gates.mjs silently drops it from its own hint set. Recorded in the docblock. Say the word and I will file it as an observation-class `finding` card, or wave it off."
      ]
    }

    Generated by Claude Code


    Generated by Claude Code

  7. claude commented on Aug 31, 2026

    @claude
    ContributorAuthor

    Closed by PR #13930, merged 2026-08-31T18:34:43Z. pm:dispatched stripped by hand — 关闭即摘 pm:*.

    ⭐ Two rounds, and the second was worth as much as the first. Round 1 fixed the mechanism: maskSelfTests now also masks every top-level callable reachable from a self-test body and not reachable from anything else. Round 2 corrected a docblock claim that was false in both halves — "No self-test in this tree takes a parameter (61 of 61 are selfTest())": three entry points carry a brace in their signature today, and the fix repairs live files rather than a latent case.

    ⭐ The counts were stale by roughly a factor of three (61→185, "five spellings"→18), while the two PROPERTIES the anchor rests on both held — 185 of 185 at column 0, zero const/arrow spellings. The dev kept the properties and fixed the counts, and the paragraph now says which is which. A property that still holds and a count that rotted look identical in a comment; separating them is what makes the docblock survive.

    ⛔ Zone 2 B (extending the predicate to const/let/var) was falsified by measurement before being implemented: it would have masked the declared populations of eight gates, because a population declared FOR the scanner is referenced by no executing code — the value-declaration variant masks exactly what the extractor exists to see.

    Residual filed as #13941 (the module blanks its own maskSelfTests body when it scans itself) — pre-existing, costs nothing today, ⛔ not this PR's to fix.


    Generated by Claude Code

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

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions