refactor(improvement): consolidate training validation and execution lifecycle - #1300
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 39a546fd
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-09-19T04:19:59Z
|
| 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 · #1300 · model: kimi-for-coding · updated 2026-09-19T05:33:33Z
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 39a546fd
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-09-19T05:47:15Z
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 | 3 (1 low, 2 weak-concern) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 153.5s (2 bridge agents) |
| Total | 153.5s |
💰 Value — sound-with-nits
A follow-up consolidation to #1287 that fixes a real admission hole (async validators silently ignored), de-duplicates three divergent validator implementations into one, and replaces hand-rolled process teardown, deadline timers, and abort plumbing in the trainer with the runtime's existing primiti
- What it does: Four concrete deltas. (1) New src/improvement/candidate-validation.ts:25 exports assertCandidateValidator/validateProfileCandidate and is now the single validator admission path for method execution (src/improvement/method-execution.ts:391,420), training (src/improvement/training.ts:425), and the bound harness (src/improvement/profile-improvement-harness.ts:91,107,116); a validator that returns a
- Goals it achieves: Correctness and composability of the training path landed one commit earlier (6a419ea, #1287): every candidate admission goes through the same synchronous-void-or-throw contract regardless of entry point; a training child gets graceful shutdown and confirmed teardown identical to the coding harnesses; long-running training jobs are supported without a timer-overflow workaround cap; and an ImproveT
- Assessment: Good on its merits. It is precisely the kind of second pass a codebase wants after a large feature lands: the feature commit shipped three divergent copies of validator logic (one of which — method execution — lacked the async guard training had), a raw setTimeout with an arbitrary cap, manual AbortController listener management, and kill-only teardown. This PR converges all of them onto primitive
- Better / existing approach: none — this is the right approach. Searches run:
rg 'process\.kill\(' src/shows the only remaining hand-rolled group kill is src/runtime/isolated-checker.ts:177, which is an intentionally immediate-SIGKILL policy for a throwaway bwrap sandbox check (no grace desired, status via fd 3) — different semantics, not a missed consolidation target for this change; tangle-sandbox-exact-process-provider. - Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 2
- Bridge warning: opencode/kimi-for-coding/k2p7: opencode: opencode error event without a message: {"type":"error","timestamp":1789798077186,"sessionID":"ses_f47b8ae95ffekj0I990X5qwMu3","error":{"name":"UnknownError","data":{"message":"Unexpected server error. Check server logs for details.","ref":"err_d65bdc6b"}}}
🎯 Usefulness — sound
A coherent consolidation that replaces three bespoke validator copies and a raw-setTimeout/SIGKILL trainer lifecycle with the codebase's established deadline, abort, and process-group-teardown primitives, removing arbitrary ceilings that blocked realistic training runs — all reachable through the pu
- Integration: Fully wired.
improve(profile, {mode:'training'})andcreateCommandProfileTrainerare exported from src/index.ts:107 and documented as canonical in docs/canonical-api.md:196; the capability landed in the immediately preceding commit 6a419ea (#1287) and this PR is its consolidation follow-up, so callers exist now.scripts/verify-package-exports.mjs:307-320(CI-gated) exercises the new frozen-p - Fit with existing patterns: Fits the grain precisely — this PR is deletion of competing patterns in favor of established ones. Old trainer used a raw
setTimeoutwith a 7-day ceiling (main:training.ts:419,378); now usesarmDeadlineTimerfrom src/runtime/supervise/deadline.ts:12, the chunked-timer utility already used across ~12 supervise modules, whose header comment (deadline.ts:4) documents exactly the native-timer clam - Real-world viability: Holds up beyond the happy path. I ran the four touched test files: 104/104 pass, including new boundary tests for no-implicit-deadline when timeoutMs is omitted, deadlines beyond native timer range, cancellation during input persistence and checkpoint fsync, adapters that ignore cancellation, committed profiles not retracted by late cancellation, and retrained-checkpoint model-reference rebinding
- Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 1
🔎 Heuristic Signals
🟡 Cruft: magic number added tests/profile-training-boundaries.test.ts
- const day = 24 * 60 * 60 * 1000
💰 Value Audit
🟡 Process-group teardown extraction stops one caller short [duplication] ``
src/runtime/isolated-checker.ts:173-181 still hand-rolls
process.kill(-child.pid, 'SIGKILL')with fallback to child.kill, the same shape the extraction removed from training.ts. It is defensible to leave it: the checker wants immediate kill with no grace and has no group-exit-confirmation requirement, so forcing it through terminateProcessTreeAndConfirm would change its policy. A future pass could still give it the shared exit-confirmation loop if evidence shows sandbox checks leaking descenda
🟡 Shared helper retains a caller-specific default context label [maintenance] ``
terminateProcessTreeAndConfirm in its new generic home src/runtime/process-tree.ts:27 still defaults
context = 'runLocalHarness'. All three current call sites either pass an explicit context (training.ts:269 passes 'createCommandProfileTrainer', worktree-harness.ts:826 passes 'defaultRunCommand') or rely on the default (local-harness.ts:742,1128). Preserving it was deliberate per the PR's 'preserve existing policy' stance, and error messages are unchanged for existing callers; a later cleanup
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 —
|
tangletools
left a comment
There was a problem hiding this comment.
✅ Approved — 12 non-blocking findings — 39a546fd
Full multi-shot audit completed 8/8 planned shots over 23 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-09-19T06:37:39Z · immutable trace
…olidation waves (#1304) * refactor(improvement): one owner per rule after the training and consolidation waves #1287 and #1300 landed hours apart and each added its own spelling of rules the other already had. Collapse them without changing a public export or behavior: - executionRef was checked three ways: a hand-rolled regex in the harness, a safeParse in method execution, and a bare schema parse in training that threw a ZodError instead of a ConfigError. candidate-validation now owns the rule. - method-execution imported agent-interface's canonicalCandidateDigest under the alias interfaceCandidateDigest while also importing the runtime's own, which is the same sha256Bytes(canonicalCandidateBytes(value)). Use one name. - copyProvenance was an alias for immutableCandidateValue. - Both candidate admission points prepared the surface and shaped the validator input separately; one helper does it, and the redundant caller-side Object.freeze is gone because validateProfileCandidate already freezes. check() also deep-copied a profile the materializer had already detached. - profile-surface had a private validateProfileCandidate(candidate, surface) with the same name as candidate-validation's exported validateProfileCandidate(validator, input) and a different job. It parses a materialized candidate, so it is now parseMaterializedProfile. - improve.ts re-listed by hand every type improve-types and training export, so each new option type was a three-file edit. `export type *` from the owning modules keeps the identical surface. The meta-harness case added by #1300 repeated an assertion the preceding case already made; its new half is folded into that case. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(improvement): resolve the training output root the fixture hands training runProfileTraining realpaths its output directory before syncing it, so on macOS, where tmpdir() is a symlink to /private/var, the synced path never equals the path the fixture passed and "publishes the durable receipt before the profile through the shared writer" fails locally while CI stays green. Resolve the fixture root once so both paths are the same string. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(deps): take agent-profile-materialize 0.20.1 and agent-core 0.9.7 Both are the newest published versions and need no code change: Materialize 0.20.1 peers on agent-interface ^2.6.1, which the catalog already pins at ^2.10.0, and Core 0.9.7 is inside the range the catalog already declares. agent-eval 0.183.0 is left out. agent-knowledge@17.0.2, the newest published, peers on `@tangle-network/agent-eval` `>=0.182.0 <0.183.0`, so under this workspace's strictPeerDependencies the install fails: [ERR_PNPM_PEER_DEP_ISSUES] Unmet peer dependencies ">=0.182.0 <0.183.0": @tangle-network/agent-knowledge@17.0.2 Runtime uses none of the /rl exports 0.183.0 changes; only bench/src/corpus.ts imports a type from that entry point. The bump needs an agent-knowledge release that admits 0.183, not a change here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(candidate-execution): take Materialize 0.20's generated-file marker agent-profile-materialize 0.20 puts a provenance comment on line 1 of every context file it generates from prompt.instructions, so the next materialization can prove which bytes it is about to replace. Files whose bytes are the caller's own — an explicit profile resource, a system-prompt replacement — stay verbatim, which is why only the agent-root AGENTS.md in these cases moves and the workspace one does not. Three expectations pinned the unmarked bytes. They now build the expected file through tests/helpers/materialized-context.ts so the marker's shape is stated once rather than in each test, matching how the subagent marker is already spelled in candidate-execution-prepare.test.ts. The checked-in improvement-proposal fixtures are regenerated: they carry both runtimeVersion and the profile plan digest, and both moved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(deps): keep the pre-1.0 window range for agent-core `pnpm update @tangle-network/agent-core --recursive` rewrote the catalog entry from `>=0.9.6 <0.10.0` to `^0.9.7`, and the packed-consumer gate refused it: Error: packed consumer must load exactly one @tangle-network/agent-core@^0.9.7; found 1 installed path(s) - 0.9.7 at agent-core That refusal is correct. `caretAdmits` in scripts/lib/packed-package-test.mjs returns false for any caret below 1.0, because a pre-1.0 package makes no promise that a minor is additive — the repo's shape for one is the `>=X.Y.Z <X.Y+1.0` window `currentMinorPeerRange` builds. Restore the window. The declared range already admitted 0.9.7, so only the lockfile moves and the consumer-visible specifier is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(api): carry the 0.245.0 version into the generated catalog and prose The docs gate regenerates docs/api and then refuses any curated page whose stated version does not match package.json, so the version bump this PR pays for the manifest change with left both stale. `pnpm run docs:api` rewrites exactly one line of docs/api/primitive-catalog.md — the version in its GENERATED banner. Nothing else in the generated reference moves, which is the same result check:api-surface reports: replacing improve.ts's hand-written re-export list with `export type *` changed no exported symbol. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Status
Non-draft; all four required final-head CI checks pass on
39a546fd87e32186774e4e514c3a70ec8ec4ca23.https://github.com/tangle-network/agent-runtime/actions/runs/35420987353
Passed:
ci,agent-bench,official-optimizers, andpacked-cohort. One product commit on main6a419eac84bbf3ec80760d61385cd316395ea93b. No required check or protection was bypassed.tangletoolscurrently shows its explicitly provisional auto-approval; that is not presented as a completed independent audit. The separate Codex reviewer reports exhausted review quota.Purpose
Follow up on merged #1287 by consolidating execution infrastructure and removing training-only restrictions. One Runtime PR; no new dependency or parallel optimizer, dataset exporter, scheduler, provider, or deployment client.
Changes
improveand bound harnesses. Retraining updates auxiliary references to the old receipted checkpoint while preserving unrelated model choices. Interface's existing schema owns ancestry bounds; no duplicate literal limit.The change adds 72 net production TypeScript lines, including the extracted shared helper. Most additions are regression tests; the remaining changes document behavior and regenerate release metadata. Dependency versions, frozen lockfile, and exact cohort are unchanged.
Compatibility
Validators accept synchronously by returning
undefined, or reject by throwing. Optimization previously ignored promises and other return values; it now rejects them, matching training. Use block bodies for side effects and perform asynchronous preparation outside this synchronous validation contract. This behavior change and the widened profile/deadline API are documented in Runtime 0.243.0. Bench 0.13.5 follows the Runtime dependency; benchmark APIs and grading do not change.Verification
Boundaries
The 35-day deadline test uses virtual time; it is not a claim of observed month-long uptime. Process-group cleanup covers the owned POSIX group, not separately detached sessions or an OS sandbox. Managed adapters still own remote cancellation/reconciliation. Byte checks, serving identity, receipt ancestry, disjoint task partitions, and receipt-before-profile publication are retained. Training does not itself establish model improvement or authorize promotion. No merge, publication, deployment, or paid training/inference performed.