chore(release): 8.0.5 — declare the agent-interface peer as a caret range - #138
Conversation
…ange Interface 1.0.0 publishes the surface of 0.56.0 unchanged and states a compatibility promise, so a caret range reads it. The peer held >=0.56.0 <0.57.0, a window that needed a release here for every interface minor and that no consumer on a different generation could satisfy. verify-package compared a cohort dependency by string equality against the resolved version. A caret range is a different string, so the check refused the declaration it exists to accept. It now compares by admission: a caret range on the same major with a floor at or below the installed version. The one-installed-copy assertion it guards is unchanged.
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — c5ae43a9
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-16T12:43:52Z
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — c5ae43a9
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-16T12:44:05Z
tangletools
left a comment
There was a problem hiding this comment.
🟡 Value Audit — sound-with-nits
| Verdict | sound-with-nits |
| Coverage | 2 of 2 lenses (value, usefulness) |
| Concerns | 2 (1 medium-concern, 1 weak-concern) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 173.8s (2 bridge agents) |
| Total | 173.8s |
💰 Value — sound-with-nits
Replaces a one-generation Interface peer window with ^1.0.0 and rewrites the packaging check to compare cohort ranges by admission — the right response to proven release churn, but it migrated only one of the two scripts that encode the peer contract, leaving the publish gate red.
- What it does: Release 8.0.5. Widens the peer on @tangle-network/agent-interface from the single-minor window >=0.56.0 <0.57.0 to ^1.0.0 (package.json:83), floors agent-eval at 0.145.21 (package.json:82), and repins the dev cohort to interface 1.0.0 / eval 0.145.21 (package.json:89-90). In scripts/verify-package.mjs the expected Interface peer is now derived with caretPeerRange (line 71, 287-289), and the agent-
- Goals it achieves: Ends the cadence where every Interface minor forces a release of this package: the CHANGELOG records four such alignment releases (8.0.1 through 8.0.4) in the two days before this PR, each just bumping the cohort — pure churn with no code delta. A caret on Interface 1.0.0 (which the registry confirms exists and whose semver promise the PR cites) lets future additive minors satisfy the peer without
- Assessment: Good change, well-evidenced and in the grain of the codebase. The dev pins stay exact so verification still tests one known cohort; only the peer widens, and deliberately only for Interface — eval keeps the explicit minor window because a caret on 0.145.x is semantically the same window (npm treats ^0.145.21 as >=0.145.21 <0.146.0), so nothing was left on the table there. assertCaretAdmits is fail
- Better / existing approach: Searched for existing capability to reuse: grep for PeerRange|satisfies|caret across the repo finds range logic only in the two verify scripts (verify-package.mjs:280-313, verify-official-optimizers.mjs:21-37); no shared semver utility exists and semver is not a direct dependency, so the hand-rolled admission check is proportionate. none for the peer-widening itself — but the sibling script miss (
- Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 2
- Bridge warning: opencode/kimi-for-coding/k2p7: opencode: opencode error
🎯 Usefulness — sound
Retires the one-generation peer window on agent-interface in favor of a caret on the new 1.0.0 stable major, and fixes the release-verification script that hard-coded the window being retired; both the new cohort manifests on npm and the repo's own alignment-release churn confirm the change does its
- Integration: Fully wired and immediately exercised. The verify-package.mjs change sits on the release path itself: package.json:74 defines verify:package, run by .github/workflows/ci.yml:40 and .github/workflows/publish.yml:43 — the old string-equality check (dependencies?.[agentInterfacePackage] !== version) would throw on the new cohort, which declares '^1.0.0' where '1.0.0' is resolved, so without the scrip
- Fit with existing patterns: Fits and retires an established anti-pattern with receipts. Git log shows 7 of the last 12 commits are 'align Knowledge with Interface/Eval X' releases (8ee086c, 2128bb2, 173d230, fd0eaa7...) — exactly the per-minor release churn the PR body claims and the caret eliminates. The disjoint-set claim verified exactly: agent-runtime peer '>=0.53.0 <0.54.0' (and it depends on agent-knowledge 8.0.1), age
- Real-world viability: Checked the new admission logic by executing it against the real cohort values and edge cases: ('^1.0.0','1.0.0') admits for both eval and core (the actual published manifests), floor-above-installed ('^1.2.3' vs '1.2.2') rejects, wrong-major rejects, non-caret ranges ('>=1.0.0 <2.0.0') reject, and the arithmetic comparison (minor*1e6+patch) is order-correct. Hand-rolled comparison instead of a se
- Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 1
💰 Value Audit
🟠 Contract migrated in one of two scripts; verify-official-optimizers still enforces the retired window and will fail CI and publish [maintenance] ``
scripts/verify-official-optimizers.mjs:31-37 rebuilds the expected Interface peer as the exact single-generation window (>=1.0.0 <1.1.0) and throws on mismatch — with the new ^1.0.0 declaration it fails at line 33 before doing any work. That script is a required gate in .github/workflows/ci.yml:63 and .github/workflows/publish.yml:46, so both go red on merge. The PR body correctly diagnosed that verify-package.mjs 'encoded the shape being retired' but missed that the sibling script encodes the i
🟡 assertCaretAdmits accepts only the literal ^X.Y.Z form [better-architecture] ``
scripts/verify-package.mjs:295 rejects semantically equivalent declarations (e.g. ^1.0, >=1.0.0 <2.0.0). This is acceptable strictness — the cohort packages are internal Tangle packages whose tooling emits ^X.Y.Z, and refusing unknown shapes is the file's fail-loud convention — but if a cohort ever switches range syntax the check will need a visitor, not a regex. Note for the reviewer only; does not gate shipping.
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.
✅ No Blockers —
|
| opencode GLM 5.2 | opencode DeepSeek v4 Pro | opencode DeepSeek v4 Flash | aggregate | |
|---|---|---|---|---|
| Readiness | 83 | 86 | 80 | 80 |
| Confidence | 80 | 80 | 80 | 80 |
| Correctness | 83 | 86 | 80 | 80 |
| Security | 83 | 86 | 80 | 80 |
| Testing | 83 | 86 | 80 | 80 |
| Architecture | 83 | 86 | 80 | 80 |
Reviewer score is advisory once the run is complete and the verdict has no blockers.
Full multi-shot audit completed 4/4 planned shots over 4 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 4/4 planned shots over 4 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 4/4 planned shots over 4 changed files. Global verifier still owns final merge decision.
🟡 LOW Open-ended caret peer range on a high-velocity dependency — package.json
peerDependencies declares '@tangle-network/agent-interface': '^1.0.0' (>=1.0.0 <2.0.0) while agent-eval keeps a narrow band '>=0.145.21 <0.146.0' (line 82). npm publish timestamps show agent-interface released 0.54.0, 0.55.0, 0.56.0, and 1.0.0 within ~8 hours on 2026-08-16 — a cadence where range-relevant releases land daily. The narrow eval band exists precisely because this family ships breaking changes in minor bumps; trusting unbounded 1.x acceptance on a package that just demonstrated that cadence risks silently pulling a breaking 1.x minor into consumer installs (the repo's minimumReleaseAge gate explicitly exempts @tangle-network/*, so no age delay protects it). Fix: c
🟡 LOW Peer dependency major swap shipped as a patch version bump — package.json
version goes 8.0.4→8.0.5 while peerDependencies replaces '@tangle-network/agent-interface': '>=0.56.0 <0.57.0' with '^1.0.0' (line 83). A consumer pinned to agent-interface 0.56.x who upgrades knowledge to ^8.0.5 now hits a peer conflict — an install-graph breaking change delivered as a patch. All 0.145.x eval floors that require interface 0.56 are simultaneously excluded by the raised floor, so consumers must move both deps in lockstep. Impact is contained because agent-eval 0.145.21+ requires interface 1.x anyway and typecheck confirms API compatibility. Fix: none required pre-merge; consider a minor bump (8.1.0) instead of 8.0.5 to signal the install-graph change, or note
🟡 LOW Peer range style inconsistency between the two @tangle-network peers — package.json
agent-eval is declared
>=0.145.21 <0.146.0(pre-1.0 bounded style) while agent-interface is now^1.0.0(caret). Both are semantically bounded at their next major, so no functional problem, and the lockfile resolves a single interface@1.0.0 for the whole tree. This is cosmetic; leaving as-is is fine, or normalize both to caret for consistency in a later release.
🟡 LOW Peer-range exclusion of interface 0.56.x shipped as a patch bump — package.json
Peer range changes from
>=0.56.0 <0.57.0to^1.0.0(line 83), which invalidates previously-valid consumer dependency trees on agent-interface 0.56.x; pnpm 10 strict peer resolution would make a consumer on 0.56.x fail to install this patch release. Strict semver would class this as a minor/major change, not a patch. Mitigation evidence: the source code did not change, and any consumer of this package must already resolve agent-eval >=0.145.21 (peer floor at line 82), whose dependency on agent-interface 1.0.0 (confirmed in pnpm-lock.yaml) forces installed int
🟡 LOW New admission helpers have no direct unit test — scripts/verify-package.mjs
caretPeerRange and assertCaretAdmits are new logic with several negative branches (non-caret declared range, wrong major, floor-above-installed, and the 0.x edge) but the script only self-verifies the happy path at runtime. assertEdgeUnsafeStaticImportMatcher (line 393) shows the file's own convention of inline self-tests; the new helpers would benefit from an equivalent negative-case check so the 0.x defect above is caught in-repo rather than by luck of the current version.
🟡 LOW New matcher has no self-test while the file's pattern self-tests its other custom matcher — scripts/verify-package.mjs
The file self-tests its other hand-rolled matcher via assertEdgeUnsafeStaticImportMatcher (line 393) with admit/reject cases run before any network work, but assertCaretAdmits — newly added, pure, and exactly the kind of logic that drifts from semver (see 0.x finding) — has no equivalent. Its only execution path is the expensive pack/install flow, so a regression in admission logic surfaces as a confusing late failure or, worse, a silent over-permissive gate. Add an assertCaretAdmitsMatcher() with cases (^1.0.0 vs 1.0.0 admit, ^1.0.0 vs 2.0.0 reject, ^1.2.3 vs 1.2.2 reject, '1.0.0' reject-not-caret) called alongside [line 75](https://github.com/tangle-network/a
🟡 LOW No self-test coverage for caretPeerRange/assertCaretAdmits — scripts/verify-package.mjs
The file already ships a self-test for its other non-trivial matching logic (assertEdgeUnsafeStaticImportMatcher, lines 393-408). The new admission logic has no embedded negative-path coverage, so a regression in the major/floor comparison would only surface at CI verify time, gating a release rather than a commit. Low. Fix: mirror the matcher self-test pattern with cases for different-major, floor-above, non-caret, and undefined inputs.
🟡 LOW Peer range ^1.0.0 promises compatibility with the full 1.x generation, verified only against 1.0.0 — scripts/verify-package.mjs
The new peer '^1.0.0' (>=1.0.0 <2.0.0) admits interface minors the script never exercises; only the pinned 1.0.0 is installed and smoke-tested (import + CLI + re-pack). This is the intended broadening per the commit message (interface 1.0.0 republishes 0.56.0's surface with a compatibility promise) and the single-copy + import-run checks still validate the pinned cohort end-to-end, so it is a documented trust shift rather than a defect. No action required beyond awareness that admission-based checks cannot detect an agent-eval caret floor set below the interface version it actually needs.
🟡 LOW assertCaretAdmits diverges from npm caret semantics for 0.x majors — scripts/verify-package.mjs
npm semver bounds
^0.56.0to>=0.56.0 <0.57.0, but this implementation compares only major equality plus a floor, so it judges^0.56.0as admitting0.57.0(verified by probe: 'admits'). Unreachable today: agent-interface is 1.0.0, the version argument is always the dev pin (enforced^\d+\.\d+\.\d+$by exactDevelopmentPin and equality-locked at line 160), and a major can never go backward in a registry. Also backstopped by assertSingleInstalledAgentStack, where npm itself would nest a second copy for a non-admitting range. Latent only. Fix is one line:if (declaredMajor === 0 && declaredMinor !== minor) throwbefore the floor comparison. Related hard
🟡 LOW assertCaretAdmits mis-handles 0.x caret majors — scripts/verify-package.mjs
Caret semantics for a 0.x version are >=0.b.c <0.(b+1).0 (the minor is locked), but this helper only checks same-major + declared-floor<=installed. I reproduced that assertCaretAdmits('^0.56.0','0.57.0') passes, when real semver rejects it (upper bound 0.57.0 is exclusive). Not triggered today: agent-interface moved to 1.0.0, and a cohort declaring a different major is caught by declaredMajor!==major. But if Interface ever returns to 0.x or a cohort declares ^0.x, this guard silently accepts a non-admitted version and defers entirely to assertSingleInstalledAgentStack. Fix: when declaredMajor===0, also require declaredMinor===minor before the floor comparison.
🟡 LOW assertCaretAdmits models caret as 'same major + floor', which diverges from npm caret semantics on 0.x — scripts/verify-package.mjs
The admission rule requires only same-major plus declaredFloor <= installed. That is exactly caret semantics for major>=1 (>=X.Y.Z <X+1.0.0) but NOT for 0.x: node-semver '^0.55.0' means >=0.55.0 <0.56.0, yet this check admits installed 0.56.0 (harness-verified). If the cohort ever pins a 0.x interface, this check would pass a declared range npm itself cannot resolve to the installed version; the error would then surface only later via assertSingleInstalledAgentStack (npm would nest a second copy). Unreachable today because interface is 1.0.0 and the rule actually matches the stated 'minor is additive' policy, hence low. Fix if desired: compare (minor,patch) pairwise against declaredFloor using <0.(minor+1).0 upper bound, or document the 0.x caveat in the comment.
🟡 LOW version.split('.') is unvalidated; a prerelease string would silently pass — scripts/verify-package.mjs
const [major, minor, patch] = version.split('.').map(Number) — a prerelease like '1.0.0-beta.1' yields NaN minor/patch, so both comparisons (declaredMajor !== major is false, declaredFloor > installed is false since NaN comparisons are false) admit the version, and the regex floor check on the declared range does not cover the installed side. Unreachable today: the only caller passes agentInterfaceVersion, which exactDevelopmentPin validates as ^\d+.\d+.\d+$. Low. Fix: validate version against /^\d+.\d+.\d+$/ (or reuse the split length) at the top of assertCaretAdmits.
tangletools · 2026-08-16T12:54:16Z · trace
tangletools
left a comment
There was a problem hiding this comment.
✅ Approved — 12 non-blocking findings — c5ae43a9
Full multi-shot audit completed 4/4 planned shots over 4 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 4/4 planned shots over 4 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 4/4 planned shots over 4 changed files. Global verifier still owns final merge decision.
Full immutable report for this review: trace
Summary comment for this run: full summary
tangletools · 2026-08-16T12:54:16Z · immutable trace
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — c0f9f928
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-16T13:03:32Z
Problem
The Interface peer was
>=0.56.0 <0.57.0— a window exactly one generation wide. Two consequences, both measured:>=0.56.0whileagent-runtime,sandbox-ui,agent-appandagent-profile-materializeall capped below 0.54. The two sets are disjoint, sonpm installof this package beside those could not resolve at all.Change
@tangle-network/agent-interface>=0.56.0 <0.57.0^1.0.0@tangle-network/agent-eval>=0.145.18 <0.146.0>=0.145.21 <0.146.0@tangle-network/agent-interface0.56.01.0.0@tangle-network/agent-eval0.145.180.145.21Interface 1.0.0 publishes the surface of 0.56.0 unchanged and states the promise the caret needs: a minor is additive, a patch is a fix, and only a major removes or narrows. Eval 0.145.21 is the release that declares that caret range itself.
The verification script encoded the shape being retired
scripts/verify-package.mjsbuilt its expected peer withexactMinorPeerRange(version)— literally>=X.Y.0 <X.(Y+1).0, the single-generation window this release exists to retire. It also compared a cohort package's declared dependency against the resolved version by string equality:Eval now declares
^1.0.0and resolves1.0.0. Those are different strings, so the check would refuse the exact declaration the wave is adopting. Both are fixed:caretPeerRange, so it tracks the lowest version this package actually uses.semveris not a dependency here and one was not added; the check parses the caret form directly. Eight cases, all correct:^1.0.0^1.0.0^1.0.5^1.4.0^1.4.0^2.0.01.0.0>=1.0.0The one-installed-copy assertion this guards is unchanged and still enforced.
Proof on this head
The last line is the one that matters: