fix(types): ship the lock option types a consumer must resolve - #150
Conversation
The published surface exposes LockOptions['retries'], so a consumer that typechecks against it needs those declarations at runtime install time.
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 0ce7ca14
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
This approval is provisional. It rests on the audit running. If the audit cannot run — for example the CLI bridge rejects it — this approval is dismissed rather than left standing, so an unrun check never reads as a passing one.
tangletools · auto-approval · reason: drewstone_author · 2026-08-17T04:11:54Z
|
Merging with CI is green (ci, official-optimizers) and the multi-shot reviewer completed its shots without publishing a verdict — the reviewer bridge has been dropping verdicts intermittently all night. Branch protection wants an APPROVED state and only the provisional auto-approval exists. The whole change is one dependency move plus the version bump: It fixes a live break: 8.0.7's published Verified on this head: |
tangletools
left a comment
There was a problem hiding this comment.
🟢 Value Audit — sound
| Verdict | sound |
| Coverage | 2 of 2 lenses (value, usefulness) |
| Concerns | 1 (1 weak-concern) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 442.6s (2 bridge agents) |
| Total | 442.6s |
💰 Value — sound
Moves @types/proper-lockfile to dependencies (8.0.7→8.0.8) so the published d.ts's import { LockOptions } from "proper-lockfile" resolves for every consumer — correct, minimal, canonical fix for a real reproduced regression; ship.
- What it does: A one-file package.json change: @types/proper-lockfile@4.1.4 moves from devDependencies to dependencies, plus a patch version bump to 8.0.8. No code changes. Effect: every npm/pnpm install of this package now also installs proper-lockfile's type declarations (with @types/retry pulled transitively via its "*" dependency), so the emitted dist/index.d.ts — which imports LockOptions from 'proper-lockf
- Goals it achieves: Restores the 8.0.6 consumer contract: typecheck-against-this-package works with zero extra installs. I verified the regression end-to-end: the real published 8.0.6 tarball emits
import "proper-lockfile";(side-effect only) at dist/index.d.ts:9, while the current source (src/mutation-lock.ts:4,:79,:301 — publicretries?: LockOptions['retries']) emits a named type import at dist/index.d.ts:9. A - Assessment: Good on its merits and in the codebase's grain. This is the TypeScript-documented standard remedy when published declarations import from a types-less package, applied at exactly the right level: source didn't regress (the public type surface legitimately exposes LockOptions and has since the lazy-lock refactor f455a68/#97), so the fix belongs in packaging, not code. The repo's history shows the s
- Better / existing approach: none — this is the right approach. Alternatives considered and rejected with evidence: (1) inline the retries type in src/mutation-lock.ts — decouples the d.ts from proper-lockfile but hand-copies @types/retry's OperationOptions shape and invites drift from the pass-through target, for no consumer-visible gain; (2) change tsdown dts config to inline external type imports — more build moving parts
- Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 2
- Bridge warning: opencode/kimi-for-coding/k2p7: opencode: opencode error
🎯 Usefulness — sound
Moves @types/proper-lockfile to dependencies (8.0.7 → 8.0.8) so the published dist/index.d.ts's import { LockOptions } from "proper-lockfile" resolves for consumers — empirically verified under both npm and pnpm layouts; minimal, standard, and correctly targeted at the real regression.
- Integration: Verified end-to-end, not just claimed. The chain is real: src/mutation-lock.ts:4 imports the type and exposes
retries?: LockOptions['retries']at src/mutation-lock.ts:79 and :301; src/index.ts:34-44 re-exports those interfaces from the root entrypoint; my fresh build emitsimport { LockOptions } from "proper-lockfile";at dist/index.d.ts:9; proper-lockfile@4.1.2 ships no types (no types/typing - Fit with existing patterns: Moving a @types package referenced by emitted declarations from devDependencies to dependencies is the standard, documented remedy for exactly this failure, and matches how the package already treats runtime types: zod ships its own types, and proper-lockfile was the only untyped runtime dependency leaking into the public d.ts. The alternative — inlining the
LockOptions['retries']shape into thi - Real-world viability: Proven beyond the happy path: the fix holds under pnpm's strict isolated node_modules (the layout most likely to break transitive type resolution), not just npm's flat hoisting. @types/proper-lockfile is types-only, so zero runtime/install cost beyond one small package; its own transitive @types/retry resolves cleanly. One bounded caveat confirmed during testing: the emitted declarations also refe
- Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 1
🎯 Usefulness Audit
🟡 Emitted d.ts still ambiently depends on @types/node (same error class, ubiquitous dependency) [robustness] ``
While reproducing the TS7016, a strict consumer without @types/node also fails on Buffer/NodeJS references in dist/index.d.ts (lines ~1716, 2020-2029). This is the same class of 'published declarations need ambient types' but @types/node is present in effectively every Node consumer, so it is conventionally left a devDependency — unlike @types/proper-lockfile, which no consumer would have by accident. Informational only; no action needed for this PR. If the team ever wants declarations fully sel
What this audit checks
It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.
| Pass | What it asks |
|---|---|
| Heuristic | Vague title? Whitespace-only or cruft-bearing diff? (content signals only) |
| Duplication | Do added function/class names already exist elsewhere in the repo? |
| Value Audit | What does it do? What goal does it achieve? Is it good? Better architecture or already-exists? |
| Usefulness Audit | Does it integrate and fit? Will it hold up in real use and actually get used? |
Findings are concerns, not blocks — the human reviewer decides what to do with them.
8.0.7's published
dist/index.d.tsimports a type from a package that ships no declarations:@types/proper-lockfilewas a devDependency, so any consumer that typechecks against this package fails:This is a regression against 8.0.6, which emitted only the side-effect form
import "proper-lockfile";and therefore needed nothing from the consumer. The public surface began exposingretries?: LockOptions['retries'](src/mutation-lock.ts:79, :301), which pulls the declaration into the emitted types.Caught by agent-runtime's packed-cohort gate, which typechecks a real consumer against the packed archives — it failed the moment the cohort ref moved to 8.0.7, and it blocks agent-runtime#887.
Fix:
@types/proper-lockfilemoves todependencies, the standard remedy when a published.d.tsreferences a types-less package. Version 8.0.8.Verified locally:
pnpm install,pnpm typecheck,pnpm build,pnpm verify:package— all exit 0.