Skip to content

feat(interface): define activation outcomes#63

Merged
drewstone merged 2 commits into
mainfrom
feat/activation-result
Jul 17, 2026
Merged

feat(interface): define activation outcomes#63
drewstone merged 2 commits into
mainfrom
feat/activation-result

Conversation

@drewstone

Copy link
Copy Markdown
Contributor

Problem

Activation authority had no expiry or restore intent, and the public contract could not distinguish success, replay, stale state, unsupported targets, known failure, or uncertain commit state.

Solution

  • bind apply versus restore and expiry into the authorization
  • add one compact, idempotent transaction result with seven outcomes
  • keep cross-record and exact candidate checks in agent-runtime

Checks

  • pnpm --dir packages/agent-interface test (141 tests)
  • pnpm --dir packages/agent-interface check-types
  • pnpm --dir packages/agent-interface build
  • fresh tarball install and public import

Advances tangle-network/agent-runtime#561 Track B and release check 8.

@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 — a3ce15ac

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.

tangletools · auto-approval · reason: drewstone_author · 2026-07-17T22:00:17Z

@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

Verdict sound
Concerns 2 (2 weak-concern)
Heuristic 0.0s
Duplication 0.0s
Interrogation 114.7s (2 bridge agents)
Total 114.7s

💰 Value — sound

Extends the activation authority with intent + expiry and adds a matching idempotent, transaction-wide, seven-state outcome receipt — clean, in-grain, no existing equivalent to reuse.

  • What it does: Two deltas to @tangle-network/agent-interface's agent-improvement-activation contract. (1) The existing AgentImprovementActivation authority gains intent: "activate-candidate" | "restore-baseline" (binds rollback into the same shape) and expiresAt (authority TTL, superRefine-enforced to be > authorizedAt). The previously-duplicated inline target object literal is extracted into one shared `imp
  • Goals it achieves: Let the public contract distinguish the seven terminal states a transaction-wide activation can end in — success, replay, stale-base, expired authority, unsupported target, proven-no-write failure, and unknown-commit — so callers can retry idempotently or reconcile without re-issuing the LLM call. Bind restore/rollback into the same authority machinery instead of a parallel path. Give the authorit
  • Assessment: Good change, built in the grain of the codebase. It completes the Promotion pipeline (Proposal -> Review -> Activation -> ActivationResult) symmetrically, all using the shared canonicalCandidateDigest / isCanonicalJsonValue / sha256DigestSchema / \u0000-joined surface+identity uniqueness machinery already established in agent-candidate-schema-common.ts and the sibling schemas. The Zod idioms are e
  • Better / existing approach: none — this is the right approach. Considered three alternatives, none materially better: (1) collapsing unsupported/failed/indeterminate into one variant with a status enum — rejected because the discriminated-union form gives exhaustive TS narrowing at call sites, which is the point of modeling them separately and matches agentImprovementReviewSchema's pattern; (2) merging already-applied + conf
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 2
  • Bridge warning: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content

🎯 Usefulness — sound

Extends an already-consumed activation authority (perpetual → bounded lifetime with restore intent) and adds the missing idempotent transaction-result type, both following the package's exact established document pattern with a real named cross-repo consumer.

  • Integration: Both new and extended symbols are public: agentImprovementActivationSchema/agentImprovementActivationResultSchema are export const (agent-candidate-promotion-schema.ts:886,994) and ride the existing export * at index.ts:826; the TS interfaces are exported via the sibling export * from "./agent-candidate.js" (index.ts:824). The activation schema is NOT hypothetical — agent-runtime already
  • Fit with existing patterns: Fits the grain precisely. Every promotion document in this package (proposal, review, measured-comparison, activation) uses the same recipe: kind literal + digest + superRefine invariants + isCanonicalJsonValue check + a parallel TS interface in agent-candidate.ts. The new result schema follows that recipe exactly (agent-candidate-promotion-schema.ts:994-1027 mirrors the others), and the `
  • Real-world viability: Holds up off the happy path. The seven-way outcome union covers the realistic transaction states an idempotent activator actually hits: success with atomic transitions, no-op replay, base-state drift, lapsed authority, unsupported target, proven-failed write, and unknown-commit (the spec-grade failed vs indeterminate distinction at agent-candidate.ts:1000 is the right call). `idempotencyKey =
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 1

💰 Value Audit

🟡 Three error-variant bodies are textually identical [duplication] ``

unsupported/failed/indeterminate each repeat the same z.object({ code: z.string().min(1).max(100), message: z.string().min(1).max(2_000) }).strict() literal (agent-candidate-promotion-schema.ts:971-991). A shared improvementActivationErrorBodySchema const would DRY this and the matching type narrowing is unaffected since the discriminated status still tags each variant. Minor — 3 duplicated lines, does not gate shipping.

🎯 Usefulness Audit

🟡 Breaking addition to an already-consumed schema; runtime caller will throw until #561 Track B lands [integration] ``

Adding required intent and expiresAt to agentImprovementActivationSchema (agent-candidate-promotion-schema.ts:893,900) makes the existing createAgentImprovementActivation in agent-runtime fail its own agentImprovementActivationSchema.parse(...) call (/home/drew/code/agent-runtime/src/intelligence/improvement-cycle.ts:412-423) because it does not yet pass either field. This is coordinated and tracked (#561 Track B, called out in the PR body), so it is expected staged work — but confirm


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 · 20260717T220447Z

@tangletools

Copy link
Copy Markdown

✅ No Blockers — a3ce15ac

Review health 100/100 · Reviewer score 83/100 · Confidence 70/100 · 4 findings (4 low)

glm: Correctness 83 · Security 83 · Testing 83 · Architecture 83

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

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

🟡 LOW Duplicate-target negative test covers only already-applied; applied transition dedup is uncovered — packages/agent-interface/src/agent-candidate-promotion-schema.test.ts

The dedup refine (agent-candidate-promotion-schema.ts:1012) runs generically over result.outcome.targets for any status that carries targets, including the applied transition-target variant. The only duplicate-target rejection test (test:127) uses already-applied state targets. A regression scoped to transition-target dedup would not be caught. Mirror the negative test with a duplicated applied transition target for symmetry.

🟡 LOW Trailing blank line before EOF in test file — packages/agent-interface/src/agent-candidate-promotion-schema.test.ts

Line 149 is an empty line between the closing }); of the last it and the EOF, introduced by the diff. Cosmetic; remove to match surrounding file style.

🟡 LOW restore-baseline intent value is never exercised by any test — packages/agent-interface/src/agent-candidate-promotion-schema.test.ts

The intent field is an enum accepting activate-candidate | restore-baseline (agent-candidate-promotion-schema.ts:893, agent-candidate.ts:947), but the activation() helper hardcodes intent: "activate-candidate" (test:17) and every test reuses it. The restore-baseline path is never parsed. Today the schema treats both intents identically (no status-specific refinement), so this is a coverage gap, not a bug — but any future intent-specific invariant will land untested. Add at least one it("accepts a restore-baseline authority", ...) parsing restore-baseline.

🟡 LOW Adding required intent + expiresAt to AgentImprovementActivation is a source+wire breaking change for any existing producer/serialized doc — packages/agent-interface/src/agent-candidate.ts

Both fields are new REQUIRED members of a pre-existing interface (agent-candidate.ts:958,963) and the schema (agent-candidate-promotion-schema.ts:893,900) now requires them. Any previously-serialized agent-improvement-activation document lacking these fields will now FAIL agentImprovementActivationSchema.parse, and any external producer's object literal will fail typecheck. The changeset (.changeset/clean-plums-activate.md) declares minor, which is the correct breaking channel for a 0.x package per changesets/semver convention, so this is informational — but the global verifier should confirm no persisted activations exist in live systems that would no longer reparse.


tangletools · 2026-07-17T22:06: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 — 4 non-blocking findings — a3ce15ac

Full multi-shot audit completed 2/2 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-07-17T22:06:26Z · immutable 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.

✅ Auto-approved drewstone PR — 55bc6b4a

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.

tangletools · auto-approval · reason: drewstone_author · 2026-07-17T22:27:42Z

@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

Verdict sound
Concerns 0 (none)
Heuristic 0.0s
Duplication 0.0s
Interrogation 87.6s (2 bridge agents)
Total 87.6s

💰 Value — sound

Extends the activation authority with intent + expiry and adds a typed idempotent transaction-result record whose seven-status discriminated union correctly separates replay, conflict, expiry, and known-clean vs. unknown-commit failures — in-grain, correctly placed, no existing equivalent to reuse.

  • What it does: Two deltas in packages/agent-interface. (1) The existing AgentImprovementActivation authority receipt gains intent: 'activate-candidate' | 'restore-baseline' (apply vs. rollback) and a mandatory expiresAt with a superRefine enforcing expiry strictly follows authorizedAt (agent-candidate-promotion-schema.ts:900, :915). (2) A new AgentImprovementActivationResult record (agent-candidate.ts:1007,
  • Goals it achieves: (a) Make the authority bounded in time so a signed write permission cannot be held forever. (b) Let the same authority shape drive both forward activation and restore-to-baseline rollback. (c) Give callers a typed, replay-safe receipt so a retry can distinguish 'I just applied it', 'someone already applied it', 'the base moved under me', 'the authority is dead', 'this target has no adapter', 'it f
  • Assessment: Squarely in the grain of the file. The surrounding 1000 lines are a uniform idiom: zod object schemas, .strict(), sha256DigestSchema, isCanonicalJsonValue canonicalization check, superRefine for cross-field invariants, and the ${surface}\u0000${identity} uniqueness idiom (used identically here at :906 and :1013). The new record follows every one of those conventions, and the small DRY extraction
  • Better / existing approach: Searched for any pre-existing primitive to extend rather than reinvent: rg idempotency|Idempotency finds only agent-core/src/retry's generateIdempotencyKey() helper (a retry utility, not a record schema) and a plain idempotencyKey?: string field on agent-core's storage write interface (no outcome union). rg restore|rollback|baseline-restore in the interface package finds nothing — this capab
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 2
  • Bridge warning: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content

🎯 Usefulness — sound

Coherent contract-layer addition (expiring apply/restore authority + seven-state idempotent activation result) that extends the existing candidate-lineage pattern and will be consumed by the named cross-repo caller in agent-runtime.

  • Integration: Public surface is wired and reachable: agent-candidate.ts and agent-candidate-promotion-schema.ts are both re-exported via export * in packages/agent-interface/src/index.ts:824,826, so the new AgentImprovementActivationIntent/Outcome/Result types and the agentImprovementActivationResultSchema are part of the package's published API. No in-repo caller exists, but this is the @tangle-network/agent
  • Fit with existing patterns: Follows the established candidate-improvement lineage exactly: AgentImprovementReview (agent-candidate.ts:928) -> AgentImprovementActivation (952) -> AgentImprovementActivationResult (1007), each a content-addressed record with kind/digest/superRefine + isCanonicalJsonValue. The discriminated-union outcome is idiomatic Zod and matches how this file models other state spaces; the split between impr
  • Real-world viability: The seven outcomes form a notably complete enumeration of transactional-write state space, including the routinely-forgotten indeterminate (commit state unknown -> reconcile) and already-applied (idempotent retry). idempotencyKey = activation digest is the correct retry-safe key. Boundary operators are chosen correctly: expiresAt uses <= against authorizedAt (closes the zero-duration hole),
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 1

No concerns — sound change, no better or existing approach found. ✅


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 · 20260717T222928Z

@drewstone
drewstone merged commit d8227eb into main Jul 17, 2026
1 check passed
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