Skip to content

chore(interface): release 1.0.0 with a stated compatibility promise - #195

Merged
drewstone merged 3 commits into
mainfrom
chore/interface-1-0
Aug 16, 2026
Merged

chore(interface): release 1.0.0 with a stated compatibility promise#195
drewstone merged 3 commits into
mainfrom
chore/interface-1-0

Conversation

@drewstone

@drewstone drewstone commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Closes the version-scheme half of #190.

What this is

@tangle-network/agent-interface 1.0.0. The published surface equals 0.56.0 exactly — this branch touches no file under packages/agent-interface/src. Only the number changes, plus the promise that explains what the number now means.

Why

#190 measured the mechanism. A 0.x minor has the force of a major under npm range rules, so every consumer declared a single-generation window (>=X.Y.0 <X.(Y+1).0) and every interface minor started a coordinated release across five repositories. The measured publish cadence was eleven minors in 9.9 days, median gap 20.4h, minimum 24 minutes. An adoption wave is slower than that, so the fleet could not converge by chasing.

The evidence that 1.0 is honest, from #190:

  • Ten transitions 0.45.0 → 0.55.0 audited from unpacked tarballs. Exports grew 748 → 823. Zero removals.
  • Every non-comment .d.ts deletion audited across the same window. One breaking generation in ten (0.53.0 → 0.54.0: RequestedInteractions narrowed to Readonly<Record<...>>, ZodObjectZodRecord).
  • Every changeset in this repository's history that names the interface: 0 major, 53 minor, 14 patch. The team already applies 1.x semantics to a 0.x number.

Under ^1.0.0, nine of those ten transitions would have resolved with no consumer release at all.

The promise, stated in the CHANGELOG

  • A minor release is additive. A new export, a new optional field, and a new member on an exported union are minor.
  • A patch release is a fix.
  • A major release removes or narrows. A deleted export, a removed member, a narrowed type, and a new required field are major.

Two limits are stated with it, because a caret range makes them reachable:

  • Write a default branch in every switch over an exported union. An exhaustiveness check that assigns the remaining case to never fails when a minor adds a member, and the promise does not cover it.
  • Set the caret floor to the lowest minor you actually use. A package reading a 1.4.0 export declares ^1.4.0, because ^1.0.0 lets a resolver keep 1.0.0.

All of it also lands in packages/agent-interface/README.md under Versioning, so a consumer author reads it without opening a CHANGELOG.

Contents

file change
.changeset/interface-1-0.md major bump for agent-interface, carrying the promise into the CHANGELOG
packages/agent-interface/README.md Versioning section
scripts/check-package-artifacts.mjs an internal runtime dependency range must admit the workspace version and stop below the next major
package.json, pnpm-lock.yaml semver dev dependency for that check

The artifact check previously required an exact match, which is the rule that forced the exact pin this release exists to retire. Admitting the version keeps the same safety — a packed tarball can never name a version the workspace will not publish — while allowing ^1.0.0. The next-major bound was added after an adversarial pass showed that admission alone lets >=0.56.0 through, which would admit a future major the package never compiled against.

Verified by table: 1.0.0 and ^1.0.0 pass, >=0.55.0 and * are refused, and 0.9.4 / ^0.9.4 still pass on a 0.x package.

Proof

Run in this branch's worktree:

pnpm install --frozen-lockfile   Done
pnpm build                        10/10 packages Done
pnpm check-types                  exit 0, 10/10 packages Done
pnpm test                         exit 0
pnpm check:package-artifacts      Checked 9 isolated packages, 28 exports, and 56 export targets.   exit 0
pnpm check:control-artifacts      7 files / 131 tests passed   exit 0

A second pass in a different model family, prompted to refute, returned 3 findings and 2 clean answers. All three are fixed in 9885308 — see the review comment below.

package test files tests
agent-interface 35 passed (35) 438 passed (438)
agent-core 22 passed (22) 505 passed (505)
agent-trace-contract 4 passed (4) 182 passed (182)
agent-provider-cli-bridge 8 passed (8) 144 passed (144)
agent-provider-tangle 9 passed (9) 138 passed (138)
agent-provider-testkit 3 passed (3) 24 passed (24)
agent-provider-e2b 2 passed (2) 2 passed (2)
agent-provider-daytona 2 passed (2) 2 passed (2)
agent-provider-computesdk 2 passed (2) 2 passed (2)
total 87 1437 passed, 0 failed

pnpm changeset version was run locally to confirm the outcome, then reverted: interface 0.56.01.0.0, agent-core → 0.9.4, six providers → patch. Substituting ^1.0.0 for the exact pins on top of that versioned state and rerunning pnpm check:package-artifacts also exits 0, which is the proof that the follow-up in this workspace lands cleanly.

What follows

  1. This merges, the Version Packages PR publishes 1.0.0.
  2. This workspace's seven packages move from the exact interface pin to ^1.0.0 (agent-core, agent-provider-{cli-bridge,computesdk,daytona,e2b,tangle,testkit}).
  3. Every other first-party declaration moves to ^1.0.0 — 5 peer ranges (agent-runtime, agent-app, agent-knowledge, agent-profile-materialize, sandbox-ui) and 3 exact deps (sandbox, sandbox-cli, agent-eval).

The in-flight single-generation PRs — tangle-network/agent-runtime#878 and tangle-network/sandbox-ui#254 — are redirected to ^1.0.0 rather than landing another window. This is intended as the last adoption wave.

@drewstone

Copy link
Copy Markdown
Contributor Author

@tangletools review now

tangletools
tangletools previously approved these changes Aug 16, 2026

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-approved drewstone PR — c62c45b3

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-16T10:52:10Z

tangletools
tangletools previously approved these changes Aug 16, 2026

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-approved drewstone PR — c62c45b3

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-16T10:52:19Z

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Value Audit did not run — no verdict

This is not an approval and not a clean bill of health. Neither interrogation lens returned a judgment, so this PR has no value-audit evidence for or against it.

Status audit-incomplete (could not run)
Why value: cli-bridge admission rejected (queue saturated); usefulness: cli-bridge admission rejected (queue saturated)
Lenses answered 0 of 2
What to do re-run once the CLI bridge has capacity: pr-reviewerctl trigger <repo>#<pr> --force

💰 Value — error

value agent never ran: the CLI bridge refused admission (no model was started).

  • Model: opencode/deepseek/deepseek-v4-pro
  • Bridge attempts: 4
  • Bridge error: opencode/kimi-for-coding/k2p7: Bridge returned 503: bridge at capacity (queue_timeout, lane=reserved): active=20/20 queued=6/48 — no model was started

🎯 Usefulness — error

usefulness agent never ran: the CLI bridge refused admission (no model was started).

  • Model: opencode/deepseek/deepseek-v4-pro
  • Bridge attempts: 4
  • Bridge error: opencode/zai-coding-plan/glm-5.2: Bridge returned 503: bridge at capacity (queue_timeout, lane=reserved): active=20/20 queued=5/48 — no model was started

No concerns are listed because nothing examined the change — absence of findings here is absence of evidence, not a pass.


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.

value-audit · 20260816T105622Z

@tangletools
tangletools dismissed stale reviews from themself August 16, 2026 10:56

Value audit could not run (value: cli-bridge admission rejected (queue saturated); usefulness: cli-bridge admission rejected (queue saturated)). This approval was provisional on that audit running, so it is dismissed. Re-run the reviewer once the CLI bridge has capacity.

The published surface of 1.0.0 equals the published surface of 0.56.0.
No file under packages/agent-interface/src changes. The version number
changes so a caret range can read the promise the package already keeps.

A 0.x minor has the force of a major under npm range rules, so every
consumer declared a single-generation window and every interface minor
started a coordinated release across five repositories.

The artifact check now requires an internal runtime dependency range to
admit the workspace version rather than equal it, so a package can hold
one installed copy across additive minors.
@drewstone
drewstone force-pushed the chore/interface-1-0 branch from c62c45b to bfcb293 Compare August 16, 2026 10:59
@drewstone

Copy link
Copy Markdown
Contributor Author

@tangletools review now

tangletools
tangletools previously approved these changes Aug 16, 2026

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-approved drewstone PR — bfcb293b

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-16T11:02:31Z

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Value Audit did not run — no verdict

This is not an approval and not a clean bill of health. Neither interrogation lens returned a judgment, so this PR has no value-audit evidence for or against it.

Status audit-incomplete (could not run)
Why value: cli-bridge admission rejected (queue saturated); usefulness: cli-bridge admission rejected (queue saturated)
Lenses answered 0 of 2
What to do re-run once the CLI bridge has capacity: pr-reviewerctl trigger <repo>#<pr> --force

💰 Value — error

value agent never ran: the CLI bridge refused admission (no model was started).

  • Model: opencode/deepseek/deepseek-v4-pro
  • Bridge attempts: 6
  • Bridge error: opencode/kimi-for-coding/k2p7: opencode: opencode error; opencode/zai-coding-plan/glm-5.2: Bridge returned 503: bridge at capacity (queue_timeout, lane=reserved): active=20/20 queued=12/48 — no model was started

🎯 Usefulness — error

usefulness agent never ran: the CLI bridge refused admission (no model was started).

  • Model: opencode/deepseek/deepseek-v4-pro
  • Bridge attempts: 4
  • Bridge error: opencode/zai-coding-plan/glm-5.2: Bridge returned 503: bridge at capacity (queue_timeout, lane=reserved): active=20/20 queued=5/48 — no model was started

No concerns are listed because nothing examined the change — absence of findings here is absence of evidence, not a pass.


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.

value-audit · 20260816T111315Z

@tangletools
tangletools dismissed their stale review August 16, 2026 11:13

Value audit could not run (value: cli-bridge admission rejected (queue saturated); usefulness: cli-bridge admission rejected (queue saturated)). This approval was provisional on that audit running, so it is dismissed. Re-run the reviewer once the CLI bridge has capacity.

…limits

An adversarial review of the 1.0.0 cut found two gaps.

The relaxed artifact check accepted any range that contains the workspace
version, so ">=0.9.0" passed and admits a future major whose removals the
package never compiled against. The check now also requires the range to
stop below the next major.

The promise said a widened union is minor without naming what that costs.
An exhaustive switch that assigns the remaining case to `never` fails when
a minor adds a member, and a caret floor of ^1.0.0 lets a resolver keep
1.0.0 for a package that reads a later export. Both limits are now stated
in the changeset and the README.
@drewstone

Copy link
Copy Markdown
Contributor Author

Independent adversarial review — codex CLI, high effort, prompted to REFUTE

The tangletools value audit could not run on either head. Both attempts returned value_audit_unavailable_capacity: the cli-bridge is at active=20/20, oldestHeldMs 5.1h, which matches the router outage that started this morning. pr-reviewerctl health lists the two incidents at 20260816T105624Z and 20260816T111315Z. The auto-approvals from tangletools at 10:52 and 11:02 are the trusted-author stamp, not a verdict.

So the second pass was run in a different model family instead. It was asked five questions and told to refute, not to help. Result: 3 findings, 2 clean.

# question finding
1 does satisfies remove a safety property that exact equality had? YES — an open range such as >=0.56.0 passed while the workspace publishes 1.1.0, so a consumer lockfile could keep 0.56.0 and hit a missing export
2 does changeset version really produce 1.0.0 from a 0.x major? cleanpnpm changeset status reports newVersion: "1.0.0"; fixed and linked are empty
3 is semver resolvable under pnpm's isolated node_modules? clean — root devDependencies with a root importer entry in pnpm-lock.yaml; CI installs before the script runs
4 does anything still assume the interface is 0.x? clean — no active regex, fixture, doc rule, or workflow; only the seven exact pins that changeset version rewrites
5 anything else that breaks a consumer? two: the caret is not adopted internally by this PR alone, and "a widened union is minor" breaks an exhaustive switch

All three are fixed in 9885308:

  • Open range. The check now requires the declared range to admit the workspace version and to stop below the next major. Verified: 1.0.0/^1.0.0 pass, >=0.55.0 and * are refused, 0.9.4/^0.9.4 pass on a 0.x package.
  • Exhaustive switch. The promise now states the limit rather than implying it: write a default branch in every switch over an exported union; an exhaustiveness check that assigns the remaining case to never is not covered.
  • Caret floor. The promise now says to set the floor to the lowest minor actually used — ^1.4.0 for a package reading a 1.4.0 export — because ^1.0.0 lets a resolver keep 1.0.0.

The internal caret adoption is deliberate sequencing, not an omission: ^1.0.0 cannot satisfy a workspace still at 0.56.0, so the seven packages here move on the Version Packages branch, after changeset version sets the interface to 1.0.0. That was proven locally — versioning this branch, substituting ^1.0.0 for the seven exact pins, and rerunning pnpm check:package-artifacts exits 0.

Not merged

This PR is not being merged on the auto-approval alone. It waits for a real tangletools verdict once the bridge has capacity: pr-reviewerctl trigger tangle-network/agent-sdk#195 --force.

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-approved drewstone PR — 98853088

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-16T11:17:38Z

@tangletools

Copy link
Copy Markdown

⚠️ Review Interrupted — 98853088

The review runner stopped before publishing a final verdict: webhook_restarted.

State Detail
Interrupted webhook restarted

No review verdict was produced for this run. Trigger a fresh review on the current PR head if the PR is still open.

tangletools · #195 · model: kimi-for-coding · updated 2026-08-16T11:24:05Z

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-approved drewstone PR — 98853088

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-16T11:35:07Z

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Value Audit — sound-with-nits

Verdict sound-with-nits
Coverage 2 of 2 lenses (value, usefulness)
Concerns 3 (3 weak-concern)
Heuristic 0.0s
Duplication 0.0s
Interrogation 251.6s (2 bridge agents)
Total 251.6s

💰 Value — sound-with-nits

Releases agent-interface as 1.0.0 with a documented semver promise and rewrites the repo's packaging guard from exact-pin equality to a bounded-range rule so internal consumers may adopt caret ranges — coherent, in-grain, and correctly sequenced; only transitional looseness in the guard is worth a n

  • What it does: Three coordinated pieces. (1) A major changeset (.changeset/interface-1-0.md) bumps @tangle-network/agent-interface 0.56.0 → 1.0.0 with the published surface unchanged, plus a stated promise: minor = additive, patch = fix, major = removes/narrows, with two consumer limits (default branch in switches over exported unions; caret floor set to the lowest minor actually used). The same promise is docum
  • Goals it achieves: Breaks the coordinated-release coupling measured in #190. Under 0.x, npm range rules gave every minor the force of a major, so all internal consumers exact-pinned (all seven still pin 0.56.0 — grep across packages/*/package.json) and external consumers needed single-generation windows, forcing a five-repo release on every interface minor. Once the promise is stated at 1.0.0, additive minors become
  • Assessment: Good on its merits and in the grain of the codebase. The repo already centralizes publish hygiene in one hand-rolled guard (no workspace: specifiers at check-package-artifacts.mjs:341-345, no prepare scripts at :372-377, packed-tarball manifest equality at :296-325); extending that same guard is exactly where this policy belongs, and it runs in both CI and release workflows. Policy and enforcement
  • Better / existing approach: none — this is the right approach. I searched for existing semver-range validation to reuse (grep for manypkg, syncpack, dependency-cruiser, and semver imports across .json/.mjs/*.ts excluding node_modules): nothing exists; this is the first and only semver import. The standard pnpm alternative — declaring 'workspace:^' and letting pnpm substitute at publish — is explicitly rejected by this repo
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 2
  • Bridge warning: opencode/kimi-for-coding/k2p7: opencode: opencode error

🎯 Usefulness — sound-with-nits

A coherent, self-consistent policy change: it releases agent-interface 1.0.0 via a changeset whose published surface is unchanged, states the compatibility promise where consumers read it, and rewrites the existing CI/release gate to enforce the new caret-range rule instead of fighting it — immediat

  • Integration: Fully wired and reachable now, not hypothetical. The relaxed rule lives in scripts/check-package-artifacts.mjs:346-369, which runs on the critical path in .github/workflows/ci.yml:22, .github/workflows/release.yml:56 (immediately before changesets/action publishes at line 58), and scripts/upstream-check.mjs:246 (UP-11). Its subjects are the 7 workspace packages that depend on @tangle-network/agent
  • Fit with existing patterns: Fits the grain. It edits the established enforcement point in place — same loop, same error-message shape — rather than adding a competing checker; check-control-contract-artifacts.mjs is a different domain and untouched. Using the semver package (root devDependency, lockfile updated in the diff) matches how the surrounding ecosystem (npm, changesets) reasons about ranges, and replaces string eq
  • Real-world viability: Holds up beyond the happy path, with one latent gap. Verified numerically against the installed semver 7.8.5: exact pins pass (current state), '^1.0.0' on a 1.0.0 workspace passes, open ranges like '>=0.9.0' are refused, and prerelease/unreadable versions are handled (inc returns null is guarded, check-package-artifacts.mjs:356-358). Gap: for a 0.x internal dependency, npm gives a minor the force
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 1

🎯 Usefulness Audit

🟡 ? [robustness] ``

scripts/check-package-artifacts.mjs:355 uses inc(version, 'major') as the excluded ceiling. Under npm semantics a 0.x MINOR carries the force of a major, so for a 0.x internal dep the checker admits ranges like '>=0.56.0 <1.0.0' that can resolve to a breaking next minor — verified with the installed semver: satisfies('0.57.0', '>=0.56.0 <1.0.0') is true. Not reachable in today's tree (the only internal dependency edge is agent-interface, promoted to 1.0.0 by this same PR), but new packages in th

💰 Value Audit

🟡 Guard permits the single-generation window the promise retires [maintenance] ``

The changeset and README (packages/agent-interface/README.md:174-175) say the '>=X.Y.0 <X.(Y+1).0' window 'is retired and must not be reintroduced', but the new check passes it: verified with node-semver, satisfies('1.5.0', '>=1.4.0 <1.5.0') fails the next-major stop test nowhere — '>=1.4.0 <1.5.0' admits 1.4.0 and excludes 2.0.0, so it PASSES. Likewise a multi-major OR whose lower arm predates the workspace major (e.g. '^0.9.0 || ^1.4.0') passes. The looseness is currently necessary — every int

🟡 The relaxed rule is dormant until a follow-up converts internal manifests [maintenance] ``

No manifest in this PR uses a range: all internal consumers of @tangle-network/agent-interface still declare exact '0.56.0' (packages/agent-core/package.json:200, agent-provider-tangle:103, daytona:47, testkit:71, cli-bridge:67, computesdk:47, e2b:47), and the changeset bump will rewrite them to exact '1.0.0', which the old equality rule would also have accepted. So the permissive branch of the new check exercises nothing until a deliberate conversion PR switches these to '^1.0.0'. The ordering


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.

value-audit · 20260816T113956Z

@tangletools

Copy link
Copy Markdown

✅ No Blockers — 98853088

Review health 100/100 · Reviewer score 76/100 · Confidence 85/100 · 9 findings (1 medium, 8 low)

opencode GLM 5.2 opencode DeepSeek v4 Pro opencode DeepSeek v4 Flash aggregate
Readiness 76 92 83 76
Confidence 85 85 85 85
Correctness 76 92 83 76
Security 76 92 83 76
Testing 76 92 83 76
Architecture 76 92 83 76

Reviewer score is advisory once the run is complete and the verdict has no blockers.

Full multi-shot audit completed 5/5 planned shots over 5 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 5/5 planned shots over 5 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 5/5 planned shots over 5 changed files. Global verifier still owns final merge decision.

🟠 MEDIUM inc(version,'major') on a prerelease returns same-major stable, falsely rejecting correct caret ranges — scripts/check-package-artifacts.mjs

const nextMajor = inc(version, 'major'). For a prerelease workspace version, node-semver returns the same-major stable: inc('1.0.0-rc.1','major') === '1.0.0' (verified against the repo's semver 7.8.5), not '2.0.0'. Then satisfies('1.0.0', '^1.0.0-rc.1') is true, so the check at line 364 throws 'must stop below 1.0.0' for the canonical correct range. Any dependent declaring ^X.Y.Z-rc.N while the workspace holds a prerelease (the standard 'changeset pre' workflow) fails CI with a misleading error. Latent today (all committed versions are stable), fail-closed direction. Fix: parse with new SemVer(version) and construct ${semver.major + 1}.0.0 instead of inc()

🟡 LOW Single-generation window ban is stated but not enforceable by the shipped check — .changeset/interface-1-0.md

The changeset ends with 'The single-generation window >=X.Y.0 <X.(Y+1).0 is retired and must not be reintroduced.' The companion check in scripts/check-package-artifacts.mjs (same PR) only verifies satisfies(workspaceVersion, specifier) and !satisfies(nextMajor, specifier); a window such as '>=1.4.0 <1.5.0' satisfies both (admits 1.4.0, excludes 2.0.0), so the ban relies solely on review discipline. Impact: a future PR could reintroduce the window shape without CI failing, silently eroding the caret-range promise this release is built on. Fix: add a range-shape check (e.g. require the specifier to be an exact pin or a caret range parsed via semver.validRange plus a prefix test) or accept it as a documented convention. Not a release blocker; the 1.0.0 bump itself is unaffected.

🟡 LOW Surface-equality claim is asserted but not enforced at release time — .changeset/interface-1-0.md

Lines 7-8 assert 'The published surface of 1.0.0 equals the published surface of 0.56.0. No export is added, removed, or narrowed by this release.' This is true today because this PR touches no file under packages/agent-interface/src. However, the release happens later when changeset version runs (baseBranch main), and changesets only knows about changesets. A source change to packages/agent-interface landed before that version bump — with its own changeset — would be folded into the same 1.0.0 release, silently voiding the claim this promise is founded on. Nothing in this PR gates 1.0.0 on surface equality (e.g., a diff of the built dist/d.ts or exports of 0.56.

🟡 LOW README states semver-from-1.0.0 before the version actually is 1.0.0 — packages/agent-interface/README.md

The section opens 'This package follows semantic versioning from 1.0.0', but at this HEAD packages/agent-interface/package.json still declares version 0.56.0 (verified via git show at the head commit). The 1.0.0 promise only becomes true if the .changeset/interface-1-0.md major changeset is applied and the package is actually published as 1.0.0. If that release does not ship with this doc, the README overstates the current published contract. Impact: misleading consumer guidance on a published README (it is part of the npm files list in publishConfig, so it ships to registry). Fix: ship the 1.0.0 release in the same PR/cycle, or gate the section wording on the release landing.

🟡 LOW Disjunctive ranges bypass the 'stop at next major' gate — scripts/check-package-artifacts.mjs

The gate probes a single point (nextMajor) rather than bounding the whole range. For version 1.0.0 and specifier '^1.0.0 || ^3.0.0', satisfies('2.0.0', specifier) === false so the gate passes, yet the range admits 3.0.0 — a future major the package 'has never compiled against', contradicting the rationale stated in the comment at lines 348-353. Rare in practice (an internal dep would have to be hand-written as a disjunction), but if the intent is 'must stop below the next major', the check should verify the range's own upper bound rather than one probe version. Not blocking.

🟡 LOW False positive: prerelease of a fresh major rejects its own caret range — scripts/check-package-artifacts.mjs

semver.inc(version,'major') for a version with minor=patch=0 and a prerelease does NOT bump the major (verified with semver@7.8.5: inc('1.0.0-beta.0','major') === '1.0.0'). Then the next-major probe at line 364 runs satisfies('1.0.0', '^1.0.0-beta.0') === true and throws 'must stop below 1.0.0', even though ^1.0.0-beta.0 caps at <2.0.0-0 and admits no future major. Consequence: publishing any X.0.0-beta.y while internal deps use the natural ^X.0.0-beta.y range fails the guard; deps would be forced to exact pins or hand-written upper bounds. Not triggered today (all internal pins are exact, version 0.56.0) but this PR's release cadence makes a major prereleas

🟡 LOW Next-major ceiling is looser than pre-1.0 semver breaking boundary — scripts/check-package-artifacts.mjs

inc('0.56.0','major') yields '1.0.0', so the check 'must stop below next major' accepts a range such as '>=0.56.0 <1.0.0' (satisfies('1.0.0', ...) is false). Under semver convention, pre-1.0 packages break on minor bumps, so such a range would admit a breaking 0.57+. This matches the comment's stated next-major contract, so it is intentional, and no current manifest uses such a range (all internal deps are exact '0.56.0'). Non-blocking; only matters if a future pre-1.0 range is introduced.

🟡 LOW Next-major guard only tests the immediate major; compound ranges admitting later majors pass — scripts/check-package-artifacts.mjs

satisfies(nextMajor, specifier) rejects a range admitting major+1 but not major+2 and beyond: '^1.0.0 || ^3.0.0' with workspace version 1.x passes (verified: satisfies('2.0.0') false, satisfies('3.0.0') true), even though the comment at lines 348-353 claims open ranges are refused because they 'admit a future major whose removals this package has never compiled against' — major 3 is exactly that. Contrived input for a CI guard, but the enforced invariant is weaker than the documented one. Fix: additionally reject if satisfies a high sentinel (e.g. '999999.0.0') or inspect the parsed Range's maximum.

🟡 LOW Unparseable specifier reported as 'must admit workspace version' instead of invalid range — scripts/check-package-artifacts.mjs

satisfies() returns false (does not throw) for unparseable ranges such as 'latest', 'not-a-range', git URLs, or npm: aliases, so the failure surfaces as 'must admit workspace version 1.2.0, received latest', masking the real cause. Still fail-closed, but the message misleads. Fix: validate with new Range(specifier) in a try/catch first and report 'invalid range' distinctly.


tangletools · 2026-08-16T11:52:26Z · trace

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Approved — 9 non-blocking findings — 98853088

Full multi-shot audit completed 5/5 planned shots over 5 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 5/5 planned shots over 5 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 5/5 planned shots over 5 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-16T11:52:26Z · immutable trace

…very later major

semver inc() returns the same-major stable release for a prerelease, so
inc("1.0.0-rc.1", "major") is "1.0.0". The artifact check used that value as
the ceiling, so a prerelease workspace refused its own caret range.

The ceiling now comes from the parsed major. The check also probes majors
above the next one, because a disjunction such as "^1.0.0 || ^3.0.0" excludes
2.0.0 and still admits a major the package has never compiled against. An
unparseable specifier now reports an invalid range instead of a missing
workspace version.
@drewstone

Copy link
Copy Markdown
Contributor Author

Fixed the MEDIUM and four of the LOW findings — 8eb5d913

The multi-shot verdict on 98853088 was No Blockers, but the MEDIUM is a real defect in the guard the whole adoption wave depends on, so it is fixed rather than carried.

I reproduced both root causes against the repo's pinned semver@7.8.5 before changing anything:

1.0.0-rc.1   -> inc major: 1.0.0   | correct next major: 2.0.0
1.0.0-beta.0 -> inc major: 1.0.0   | correct next major: 2.0.0
satisfies('1.0.0','^1.0.0-rc.1')      = true    <- false rejection
satisfies('3.0.0','^1.0.0 || ^3.0.0') = true    <- bypass

Two changes:

  • The ceiling is built from the parsed major (parsed.major + 1), not inc(version,'major'). A prerelease workspace no longer refuses its own caret range.
  • The gate probes major+1, major+2 and a high sentinel instead of a single point, so a disjunction that skips the next major but admits a later one is refused. An unparseable specifier is now reported as an invalid range rather than as a missing workspace version.

Ten cases, all correct:

version range result
1.0.0 ^1.0.0 accept
1.0.0 1.0.0 accept
1.0.0-rc.1 ^1.0.0-rc.1 accept (was a false reject)
1.0.0-beta.0 ^1.0.0-beta.0 accept (was a false reject)
1.4.0 ^1.0.0 accept
1.0.0 >=1.0.0 <2.0.0 accept
1.0.0 ^1.0.0 || ^3.0.0 refuse (was a bypass)
1.0.0 >=1.0.0 refuse
1.0.0 latest refuse as invalid range
0.56.0 ^1.0.0 refuse

The last row is the release mechanic, not a curiosity: ^1.0.0 cannot land on this PR because the workspace still publishes 0.56.0. The seven internal ranges move on the Version Packages branch, where the workspace already reads 1.0.0, which also saves a second agent-core and six-provider release round.

Negative control on the real repo, not only the harness:

$ pnpm check:package-artifacts     # after setting agent-core's range to >=0.56.0
Error: @tangle-network/agent-core dependencies.@tangle-network/agent-interface
       must stop below 1.0.0, received >=0.56.0
exit=1

Suite re-run by me on this head, not relayed:

build          exit 0
check-types    exit 0
test           1437 passed  (interface 438, core 505, cli-bridge 144, tangle 138,
                             trace-contract 182, testkit 24, computesdk/daytona/e2b 2 each)
check:package-artifacts   exit 0   (9 packages, 28 exports, 56 export targets)
check:control-artifacts   131 passed

The remaining LOW findings are accepted as stated: the surface-equality and window-shape claims are review conventions, and the README wording becomes true when this release ships.

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-approved drewstone PR — 8eb5d913

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-16T11:57:34Z

@tangletools tangletools left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Value Audit — sound-with-nits

Verdict sound-with-nits
Coverage 2 of 2 lenses (value, usefulness)
Concerns 2 (2 weak-concern)
Heuristic 0.0s
Duplication 0.0s
Interrogation 160.5s (2 bridge agents)
Total 160.5s

💰 Value — sound-with-nits

Releases agent-interface as 1.0.0 with a documented additive-minor compatibility promise, and relaxes the repo's manifest guard from 'internal deps must exactly equal the workspace version' to 'valid range that admits the workspace version and stops below the next major' — coherent, in-grain, and th

  • What it does: Three pieces: (1) a major changeset bumping @tangle-network/agent-interface to 1.0.0 with an explicit promise (minor=additive, patch=fix, major=removal/narrowing) plus two stated limits (default branch in switches over exported unions; caret floor set to the lowest minor used) — .changeset/interface-1-0.md:1; (2) the same policy mirrored into packages/agent-interface/README.md:161 under 'Versionin
  • Goals it achieves: Let the seven in-workspace consumers of agent-interface (agent-core, provider-cli-bridge, provider-computesdk, provider-daytona, provider-e2b, provider-tangle, provider-testkit — all currently exact-pinned at 0.56.0) migrate to ^1.x so an additive interface minor no longer forces a coordinated patch release of every dependent: with updateInternalDependencies:'patch' plus exact pins (.changeset/con
  • Assessment: Good change, well matched to its goal and the codebase's grain. The repo concentrates all publish-manifest invariants in this one guard script (no workspace: specifiers, no prepare script, pack/repack export checks), and extending that script — rather than adding syncpack/manypkg or a new lint pass — is exactly the established pattern. The README 'Versioning' section follows an existing precedent
  • Better / existing approach: No existing equivalent found — searched for other semver/range linting (rg 'semver|check-package-artifacts' across .github/workflows, package.json, scripts/): the only manifest guard is this script, and the repo deliberately bans workspace: specifiers in publishable fields (scripts/check-package-artifacts.mjs:341), so pnpm's workspace:^ protocol is not an option here. One simpler-and-complete refi
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 2
  • Bridge warning: opencode/kimi-for-coding/k2p7: opencode: opencode error

🎯 Usefulness — sound-with-nits

A coherent, correctly-sequenced 1.0.0 release: the changeset rides the existing changesets flow, the promise is documented where consumers read it, and the artifact-check relaxation is the mechanically necessary enabler for caret-range adoption, wired into both CI and the release pipeline.

  • Integration: Fully wired and reachable. The modified check runs on every PR (ci.yml:22, after install at :18) and before every publish (release.yml:33). The changeset (.changeset/interface-1-0.md) is consumed by the existing changeset:version/changeset:publish flow (root package.json:8-9) and will produce 1.0.0 from 0.56.0. The checker relaxation is ahead of its caller by necessity, not by neglect: all six
  • Fit with existing patterns: Fits the codebase grain. It modifies the established artifact-guard in place (scripts/check-package-artifacts.mjs:347-388) rather than adding a competing mechanism, and the two new conditions map exactly onto real workspace mechanics: satisfies(wsVersion, range) is the condition under which pnpm still links the workspace copy instead of fetching a registry copy, and later-major exclusion is the
  • Real-world viability: Held up under direct verification with the installed semver 7.8.5: open ranges (*, >=0.9.0) are refused, the disjunction ^1.0.0 || ^3.0.0 is caught by the major+2 probe, ~/1.x/>=1.0.0 <2.0.0 behave as the comments claim, and the prerelease ceiling pitfall (documented at scripts/check-package-artifacts.mjs:361-364) is real and correctly avoided by building nextMajor from the parsed majo
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 1

🎯 Usefulness Audit

🟡 Relaxed guard admits the single-generation window it exists to retire [problem-fit] ``

The changeset states the window >=X.Y.0 <X.(Y+1).0 'is retired and must not be reintroduced', but I verified with the repo's semver that >=1.4.0 <1.5.0 and <=1.9.0 at workspace 1.4.0 both pass the new logic (satisfies the floor, excludes all later majors). The check's stated scope — one installed copy, no uncompiled major — is exactly enforced, so this is a deliberate floor, but an internal window declaration would quietly re-impose the coordinated-release tax this PR is retiring. A cheap

💰 Value Audit

🟡 Ceiling enforcement samples three versions instead of reading the range's max bound [better-architecture] ``

scripts/check-package-artifacts.mjs:378-387 probes satisfies() at (major+1).0.0, (major+2).0.0, and 999999.0.0, but a range admitting a later major at a non-probed point slips through: I verified satisfies('2.5.0', '>=1.0.0 <2.0.0 || >=2.5.0 <3.0.0') === true while all three probes return false, so the invariant 'must stop below the next major' the comment claims is not fully enforced. A structural check — iterate range.set and reject any comparator set whose max is '*' or whose max version's ma


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.

value-audit · 20260816T120119Z

@drewstone
drewstone merged commit ca3901d into main Aug 16, 2026
1 check passed
@drewstone drewstone mentioned this pull request Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants