From 2b68acb2d55fee3e4d99a96ac607acb8ed8bcd12 Mon Sep 17 00:00:00 2001 From: garrytan Date: Mon, 26 Oct 2026 03:01:29 +0000 Subject: [PATCH] fix(context-bill): --exact resolves a billed path one link at a time, so a shared deep chain keeps its measurements Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- lib/context-bill.ts | 17 ++++++++++++++++- test/context-bill.test.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/context-bill.ts b/lib/context-bill.ts index c7f8863d2..e13270961 100644 --- a/lib/context-bill.ts +++ b/lib/context-bill.ts @@ -243,6 +243,21 @@ function entryKind(p: string, e: fs.Dirent): "file" | "dir" | null { * followed directory symlink that contains the tree being walked (`..`, `/`, * `$HOME`) would climb out of that tree, so walkers refuse it. */ +/** + * The realpath of `p`, resolved one component at a time the way the walk + * reads directories, so a lexical path that crosses more links than the + * kernel's limit still resolves. + */ +function realpathStepwise(p: string): string { + const abs = path.resolve(p); + const { root } = path.parse(abs); + let real = fs.realpathSync(root); + for (const segment of abs.slice(root.length).split(path.sep)) { + if (segment) real = fs.realpathSync(path.join(real, segment)); + } + return real; +} + function encloses(outer: string, inner: string): boolean { const rel = path.relative(outer, inner); return rel === "" || (rel !== ".." && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel)); @@ -1019,7 +1034,7 @@ export async function measureExactTokens( const isFm = key.endsWith(fmSuffix); let real: string; try { - real = fs.realpathSync(isFm ? key.slice(0, -fmSuffix.length) : key); + real = realpathStepwise(isFm ? key.slice(0, -fmSuffix.length) : key); } catch { return undefined; } diff --git a/test/context-bill.test.ts b/test/context-bill.test.ts index c4f023b85..7856175ea 100644 --- a/test/context-bill.test.ts +++ b/test/context-bill.test.ts @@ -1406,6 +1406,33 @@ describe("--exact (opt-in measurement; offline here via an injected fetch)", () expect(rows).toBe(depth + 1); }); + it("prices a second skill's links into a chain deeper than the kernel's limit from the one measurement", async () => { + if (process.platform === "win32") return; + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "context-bill-exact-shared-deep-")); + const levels = path.join(tmp, "levels"); + const depth = 50; + for (let i = 0; i < depth; i++) { + fs.mkdirSync(path.join(levels, `L${i}`), { recursive: true }); + fs.writeFileSync(path.join(levels, `L${i}`, `f${i}.md`), `F${i}-${"x".repeat(30)}`); + } + for (let i = 0; i < depth - 1; i++) fs.symlinkSync(path.join(levels, `L${i + 1}`), path.join(levels, `L${i}`, "next")); + markCheckout(levels); + const root = path.join(tmp, "skills"); + for (const name of ["qa", "qb"]) { + fs.mkdirSync(path.join(root, name), { recursive: true }); + fs.writeFileSync(path.join(root, name, "SKILL.md"), `---\nname: ${name}\ndescription: d\n---\n# ${name}\n`); + fs.symlinkSync(path.join(levels, "L0"), path.join(root, name, "next")); + } + fs.symlinkSync(levels, path.join(root, "gstack")); + const measured = await measureExactTokens(root, { model: "m", apiKey: "sk-test", fetchImpl: fakeFetch(), egressHome }); + const bill = buildBill(root, { tokensOf: measured.tokensOf, tokenSource: measured.tokenSource }); + fs.rmSync(tmp, { recursive: true, force: true }); + expect([...measured.missedKeys]).toEqual([]); + const [qa, qb] = ["qa", "qb"].map((n) => bill.skills.find((s) => s.name === n)!); + expect(qb.totalMdBytes).toBe(qa.totalMdBytes); + expect(qb.totalMdTokens).toBe(qa.totalMdTokens); + }); + it("names a missing tree, without a raw ENOENT or any request", async () => { const parent = fs.mkdtempSync(path.join(os.tmpdir(), "context-bill-missing-")); const out = capture();