Skip to content

v0.23.0

Choose a tag to compare

@github-actions github-actions released this 13 Nov 17:59
· 138 commits to main since this release

Changed

  • npm run release now accepts a package up to 35 MB (was 20 MB): the Go port made the four native binaries about 15 MB each, so the 0.23.0 package is 28.3 MB; the refusal reads published package must be under 35 MB (B605)
  • block close runs in Go for late and cap rows whose file, finding or open id is an object or array (Node's [object Object] and joined text, or Node's arg.replaceAll is not a function error for a file it cannot quote) and for plain-text or Codex transcripts with JavaScript-only whitespace (NBSP, U+2028, BOM); before, these closes handed over to Node (close-gates-format, close-transcript-format). A routine close under a close:routine grant now prints Node's opened before warning once per gate load and joins every routine failure into the close-not-routine reason, byte-equal to Node (B590)
  • block close runs in Go when a changed file matches review.exclude or the default lock-file list: the file leaves the review set, gets a gate.review_excluded row and a not reviewed line, and an npm lock gets Node's lock check and lockfile blocker; before, every such close handed over to Node (close-excluded-file). A lock shape Go cannot judge like Node hands over with the new reason close-lockfile-format (B587)
  • block close runs in Go for a transcript that is not valid UTF-8 (decoded as Node does, each bad byte run one U+FFFD), a Claude Code log with an escaped surrogate pair, and agent waiver and reopen rows whose fields hold objects or arrays (--json prints them in the ledger line's key order); before, these closes handed over to Node (close-transcript-format, close-gates-format) (B583)
  • Go reads the Node version when it runs (node --version once per process, CODE_FORGE_NODE else node on PATH), not the build machine's: error-log rows, the gate reuse stamp and the logs report Node line match the node that runs; logs report no longer hands over when no Node version is known and prints unknown (B585)
  • facts with a Codex (openai) step in the levels.L0 ladder (first, as a fallback, or from a top-level provider: openai) now runs in Go byte-equal to Node instead of handing over: the read-only codex exec call in the snapshot, the packet on stdin, the OpenAI-strict schema file, the -o answer, the fallback moves on usage limit, 401, 503, timeout and exit, the answer checks, the sheet and the ledger rows; review.allow_open_book_codex does not change it, as in Node (B582)
  • A fix-loop recheck with a block base runs in Go byte-equal to Node's packet builder for every peer case: one peer, several peers (named and imported kept, the rest dropped), a moved-code hint alone, a moved hint plus cross-file evidence, over the budget (the cut line, or no evidence), no peers and no base; worker --run <id> serves such a recheck of a .js file end to end with no hand-over row (B564)
  • block ready no longer hands over to Node when the workspace path holds secret-like text such as eyJ, AKIA, AIza or sk- (a random temp folder name did this once on CI); like Node, it masks only the run's signer key, and output that would show that key still runs in Node (B565)
  • Go no longer needs a node on PATH for context pack and cloud-coder: with no Node, the pack's ## code-forge line names the install's bin/code-forge launcher instead of refusing (with Node found, the pack bytes are unchanged), and cloud-coder runs review-file and ledger add coder in this Go binary instead of the Node router (B572)
  • The Go binary is required: bin/code-forge no longer falls back to Node. With no binary for the platform and arch, a missing file or one without execute permission (and for setup, a binary that crashes), it prints one stderr message with <platform>-<arch>, the expected path and the fix (sh <package>/scripts/install.sh, then npm i -g @codedology/code-forge if that fails) and exits 69, a code no verb uses; CODE_FORGE_NATIVE=0 still runs the Node router. New scripts/install.sh (POSIX sh, shipped) checks the binary for this OS and processor, restores a lost execute bit, runs --version and internal version, compares the version with package.json and prints OK or the problem and one fix: line (exit 0 / 1); no network, no sudo, no postinstall (B569)
  • npm run release runs no Node on the laptop: it builds the four native release targets with go build from Go (same targets, flags, temp name, mode and printed lines as scripts/build-native.mjs; the Node version stamp comes from node --version when a node is usable and stays unknown otherwise), and in place of the local gen-config-doc --check, gen-commands-doc --check, npm test and npm run typecheck it requires the latest CI run for HEAD to be completed with success, refusing before any write with one line naming HEAD and the run state; npm pack --dry-run, npm ls --json and claude plugin validate . still run; the --no-checks warning names the new list and the notes usage line names sh scripts/cf-release.sh release notes (B580)
  • The Node release scripts are gone: scripts/release.mjs, release-site.mjs, docs-block.mjs and changelog.mjs and their Node tests are deleted, after every case those tests checked was ported to the Go tool's goldens (74 new multi-step cases recorded from Node); the GitHub release workflow sets up Go and writes the notes with sh scripts/cf-release.sh release notes (same bytes), and scripts/gen-site-data.mjs reads CHANGELOG sections itself with the same output; nothing changes in the npm package (B574)
  • The maintainer release tools run in Go: npm run release, npm run release:site, npm run docs-block and npm run changelog build and run native/cmd/cf-release through scripts/cf-release.sh, with the same arguments, output, exit codes, file edits and git commands as the Node scripts, checked against goldens recorded from Node; the Node scripts stay because tests, the site data generator and the release workflow still use them, and nothing new ships in the npm package (B570)
  • The native daemon's status no longer starts a Node helper: a block id outside printable ASCII is answered in Go when it is the one listed block or sits on a closed or stopped block (also for status and native-status); with two or more such listed blocks the daemon answers status-unreadable, as it did with no Node, and the status command computes the status itself (B576)
  • The native rebuild in gates run and block rebase runs go build in Go instead of node scripts/build-native.mjs --host: same env, ldflags, <binary>.<pid>.tmp temp name, mode 755, rename and native-rebuild-failed text; it works with no Node on PATH, and then leaves the binary's Node version at unknown (B575)
  • facts checks more glob path claims in Go, like Node's path.matchesGlob: braces ({a,b}, {1..3}), backslashes, [:ascii:] and [:xdigit:], extglob openers with no ) and non-ASCII text with Node's case folding. A Unicode POSIX class, an extglob that can close, a case-insensitive suffix with a sigma, a Codex L0 step (B551 is not on this base) and the gate's non-ISO dates (Node reads them in the local time zone) still hand over before any write (B577)
  • block rebase that hands a narrow state to Node no longer prints an autopilot expiry warning twice: a failed grant expiry or an approval not restored yet is reported once, by Node's own check; a key or file read error in such a warning names no path, as Node's (B584)
  • block rebase no longer starts a Node child: active and due autopilot approvals, run records with no orphans list, an odd sibling block or an unreadable config snapshot, falsy or invalid rebase_check values and a missing HOME run in Go with Node's output, run record and ledger rows; the few states Go cannot read hand over with a narrow named rebase-* reason before any write (B578)
  • The Go worker, the daemon (internal serve) and every Go verb (review, block close, block land, gates, status, proof export and the rest) record each child they start in the run root's pid registry like Node's exec: pids/<pid>.json while it runs, the owner pid, start time and run id in its environment, the lazy root released at exit; stdout and exit codes do not change (B573)
  • block open serves its former Node fallbacks in Go, byte-equal to Node: an empty proof.worktree.dir or base, --after statuses that are not text, claim rows whose path is not text, the signer key and ledger checks with no --level, brief loop, name-too-long and read errors, acceptance and pipeline YAML errors, pipeline and outcome read errors, no HOME and block ids such as __proto__; YAML forms Go does not reproduce, AJV schema wording, a torn ledger line, a failed home lookup and an unresolvable brief path hand over before any write under the new reasons open-acceptance-yaml, open-pipeline-form, open-outcome-form, open-level-ledger, open-home-lookup and open-brief-cwd; Go's ELOOP and ENAMETOOLONG texts are libuv's, as Node prints them (B581)
  • CI on Linux is green again: the tools and init rows follow a platform seam, so the init wizard test replays its Mac golden (Homebrew hints, Solo.app) on Linux too; the block close fake reviewer writes its result file then renames it, like the worker, so close never reads a half-written result; the Jev triage test waits for its fake server before it reads the requests (the race detector caught the bare read); the 25 ms Go hand-over check reports its number on CI runners instead of failing, because the same binary measured 10 to 63 ms there, and local runs keep the gate (B560).
  • A Go worker that hands its run to Node keeps the queue served while Node starts: it leaves a hand-over announcement that review-file --wait reads as live and Node's boot prunes, so a waiting review no longer ends worker_down during the hand-over (B561)
  • Go doctor records each child it starts (CLI probes, pings and probe sessions, git and op read) in the run root's pid registry like Node, and Go init takes the temp root from the config at process start as Node does, so a tmp.root found from a subfolder still holds after init writes its own .code-forge.yml (B567)
  • code-forge review of several files or of a test-like file runs in Go, byte-equal to Node, instead of handing the whole run to Node (review-worker-handoff is no longer used): the B561 hand-over announcement closed the race that made a waiting review read worker_down (B561b)
  • Go tools, tools install and the init tool installs record each child in the run root's pid registry like Node (pids/<pid>.json with pid, start time and command while it runs, removed when it ends), so a later sweep can stop an orphan; a registry that cannot be written never stops the probe or install (B563)
  • Go logs report records each npm and gh child in its run root's pid registry like Node (pids/<pid>.json with pid, start time and command while the child runs, removed when it ends), so a later sweep can stop an orphan; a registry that cannot be written never stops the child (B559)
  • Tests give the same result on every machine: the doctor and tools rows no longer read this machine's /Applications (a seam the tests point at an empty folder), the no-config doctor test seals PATH, the init wizard golden compares copied skill files with the repo's skill/ folder instead of a frozen copy, the B489 fake reviewer waits for its pid entry, and the Node gates tests expect gates detect and gates scope to run in Go (since B459); no product change (B552)
  • facts builds the facts sheet in Go, byte-equal to Node: the claim tokens, the read-only snapshot at HEAD with in-project --sources, the L0 facts session on anthropic or xai, the answer checks and downgrade lines, the sheet, the ledger rows, the breadcrumb and error log, and --run; spawn --role facts --cwd runs in Go too. A Codex L0 step, a glob path claim, a non-UTF-8 brief, a run root inside a git work tree and a --sources path outside the project keep narrow hand-overs decided before any write (B556)
  • facts serves in Go, byte-equal to Node, the cases B556 handed over: glob path claims, a non-UTF-8 --brief, a run root inside a git work tree, --sources outside the project, and Node's crash for a config with no levels.L0 (same stderr, exit 1 and error-log row); the gate's Date.parse cases now hand over before any write. A Codex L0 step still hands over until B551 is on main (B568)
  • facts refuses in Go, like Node, before its session starts: a missing, unreadable or too-new .code-forge.yml, an unreadable --brief or --sources path, a bad --timeout and a bad --run id give Node's stderr, exit 2, breadcrumb and error-log row with nothing written; a call that passes these checks still builds the sheet in Node (facts-session), and a YAML syntax error hands over as facts-config (B555)
  • logs report --no-ai with matching errors runs in Go, byte-equal to Node: the npm version check, the built-in scrub, the secret check, the preview and --dry-run, the gh search, comment and create with the label retry, and the prefilled link with the saved report when gh is missing or fails; the AI scrub, --with-doctor, a known-fixes table, an unknown system and a terminal prompt still hand over to Node with named reasons (B554)
  • author, s2 and jev ask run in Go, byte-equal to Node: author and s2 on anthropic and xai levels (prompt, provider argv, schema check, draft or answer, ledger rows, refusals), jev ask with --rules and with Jev (request, retries, failure lines, decision bands, decision row, refusals) using the env or file-store key; an openai (Codex) level, the keychain or 1Password key, YAML syntax errors and inputs Node words differently hand over before any session or write, each with its own reason (B550)
  • review of one file runs in Go, byte-equal to Node: config, --acceptance/--intent, --run reuse, run start, the review block, the ticket and its wait, block stop, run end, the worker reap, the fix list, totals, --json, exit codes and signals. Several files or a test-like file, and state Go cannot read like Node, keep narrow named hand-overs decided before anything is written (B553)
  • Go tests no longer fail on a loaded machine where they waited on a short fixed clock: the block close fake reviewer waits until close returns (30 s safety bound) instead of 2 s, and the run start worker-stop, file lock FIFO, test slot admission and leaked-pipe gate waits get long bounds that still end as soon as the awaited event happens; no product change (B539)
  • The Go worker reviews light blocks (the batch round), Markdown files section by section, dual lenses with the L3 judge and consensus review, and recovers the recheck session (second level, its ladder, the L2 ladder retry, routes) like Node, byte-equal, instead of handing the ticket to Node; an L2 ladder entry with no provider routes like Node; a judge with no levels.L3, a light round after the cap with peer files, a surrogate-cutting Markdown heading and an adaptive pick of a no-provider entry still hand over with nothing written (B545)
  • init runs its steps after the write in Go, byte-equal to Node: the Jev key from CODE_FORGE_KEY_JEV or the file key store (with the 24 h expiry cap and expired-entry removal), --tools recommended and --yes-tool installs, --refresh-models, and the quick doctor (its rows, JSON summary and exit 1 on a FAIL). The keychain key path stays on Node with the new narrow reason init-jev-keychain, and a doctor that would hand over makes init hand over before it writes anything (B548)
  • spawn --role coder, --role facts and --background run in Go, byte-equal to Node: the coder prompt with --block and the run's block brief and acceptance lines, the sentinel result field, the --run coder.sandbox check, the facts session and the detached background start with its logs and pid files; a Codex step, facts with --cwd, a run record Go cannot read like Node and a background CLI that is not found still hand over with their own reasons (B549)
  • The skill's forge <verb> shim now runs the package's bin/code-forge sh launcher (Go binary first, Node router with CODE_FORGE_NATIVE=0 or no Go binary) instead of always the Node router bin/code-forge.mjs, so skill verbs ported to Go run in Go; CODE_FORGE_BIN naming the launcher, or a code-forge.mjs with the launcher next to it, also goes through the launcher, while other CODE_FORGE_BIN files and old installs with only bin/code-forge.mjs keep running in Node (B547)
  • Codex (openai) sessions run in Go where review.allow_open_book_codex: true lets them: spawn reviewer, judge, s2 and author steps and the worker's ticket review on an openai level, with Node's codex exec argv, stdin packet, OpenAI-strict schema file, -o answer file, usage and cost rows, null drop and passed coerce, error events (usage limit retries, login expired, at capacity), timeout and exit codes, byte-equal to Node; an effort the codex builder refuses or a schema strict mode changes stays with Node, and doctor's Codex pings, isolation and path-deny still hand over (B551)
  • spawn --role coder on an openai (Codex) step runs in Go, foreground and --background, byte-equal to Node: Node's codex exec -s workspace-write argv, a fresh CODEX_HOME per session under the run root's codex-homes/, the answer and sentinel read from the -o file and outPath in pid.json; the facts role on openai runs in Go too. Only a Codex coder step with coder.sandbox set still goes to Node (spawn-codex-sandbox) (B551r)
  • doctor with a valid config finishes the probes' I/O errors in Go like Node instead of handing over after the probes started: an unwritable temp root gives Node's probes: no temp root row, a session that cannot start gives Node's error(<code>) rows, an unwritable prompt file, temp repo or canary ends with Node's verb "doctor" failed line and exit 1, and an errno Node has no name for prints Node's Unknown system error -<n> instead of UNKNOWN (B535)
  • init at a terminal runs its wizard in Go: every prompt with its text, default, choices, keys and re-ask on a bad answer, the summary, the gates and proof choice and the apply confirm, then the B527 setup; terminal output, files, the init log and exit codes (cancel 1, end of input 13 with Node's warning) are byte-equal to Node in a pseudo-terminal; a terminal Go does not draw like Node, --yes-tool, the Jev key store, the doctor and preset shapes the wizard shows differently hand over before the first prompt (B528)
  • The Go worker builds the whole review packet itself, byte-equal to Node: related files and definitions with the import-header context, the deletion note, the test-quality hint and moved-code hints with peer files (also in Markdown sections, the dual-lens judge packet and a light round after the cap); a recheck under review.recheck_scope: file and a recheck with moved-code hints and cross-file evidence from the block's other changed files run in Go too, so these tickets no longer hand over to Node (B537)
  • doctor with a valid config runs in Go, text and --json, byte-equal to Node: the Jev live call, the provider CLI rows, the role pings, isolation, path deny, Codex rules and the worker and signer probe join the local rows; every case Go cannot serve is decided before the first probe, so a hand-over writes nothing. A worker registry Go cannot judge hands over after the probe cleans up, an errno outside Go's table prints UNKNOWN like Node, and one pid registry writer serves sessions and the doctor (B525)
  • The Go worker serves runs with a Jev key: it resolves the key at boot like Node (env variable, file store, 1Password cache) instead of handing the whole worker to Node, and the review asks System 1 (Jev) like Node, byte-equal: defect triage in full rounds and on late findings, resolved closing open findings before the recheck session, the request, retries, timeouts, failure kinds, the review.triage rows with source, p and band, and the s1_fallback warning; a key in the OS keychain, a store Go cannot read back or a live 1Password read, and a bad key reference still hand over with their own reasons (worker-jev-keychain, worker-jev-key-store, worker-jev-key-ref) (B533)
  • The Go worker runs the commit watch (review.file_loop: watch) instead of handing the whole worker to Node: the 15 s quiet wait and 120 s burst limit, one ticket per owned changed file hashed from git objects, the watch.skipped/watch.held rows, superseded markers and the watch cursor, byte-equal to Node; a watch shape Go cannot reproduce stops the Go worker before that tick writes (worker-watch-shape) (B534)
  • autopilot ask runs the delegate session in Go when the grant lets the question through, and autopilot approve writes the .code-forge.yml change, reloads the run and signs the autopilot.approve row in Go, byte-equal to Node; a due approval of an active run is put back and reloaded in Go too. Shapes Go does not reproduce keep a narrow hand-over decided before any write (B536)
  • The Go worker's review recovers like Node instead of handing the ticket to Node: the levels.L2 fallback ladder, review.routes recovery and review.second_levels, with Node's rows, warnings and session configs byte-equal, and the timeout fallback picks among ladder, second-level and route entries like Node; malformed shapes and the recheck session's recovery still hand over (B538)
  • init --no-interaction (and init with no terminal) sets the project up in Go, byte-equal to Node: gate and proof detection, the settings summary, the merge with an existing .code-forge.yml, the config checks, the .code-forge.yml write with the yaml package's exact bytes, skill links and installs.json, the user config, the engine stop text, the init log and the agent JSON line; a Jev key read, a 1Password item, --tools recommended, --refresh-models, the doctor, links Go cannot place, configs Go cannot rebuild or check and an unreadable user config hand over before any write, each with its own reason (B527)
  • Tests can no longer stop a process of the person running them: every signal to a pid from the process table or a run record (the run start/sweep process sweep, run end and the launched-worker stop, the Go worker's orphan sweep, the gates' and sessions' leftover group members) goes through one guard that, inside go test, in a binary a test builds, or with CODE_FORGE_TEST_SIGNAL_ROOT set, sends a real signal only to descendants of the test and answers EPERM otherwise; without them nothing changes. doctor counts a .nan level value as unset, as Node does (B529)
  • The doctor's worker and signer probe has a Go part, not wired into the full run yet: the throwaway run and repository, the signer key, worker and signer rows byte-equal to Node (worker announced and stopped on SIGTERM, a worker that never announces, one that ignores SIGTERM, a failed sign/verify round trip, a git or config copy failure), and the run, key, lock, pid entry and temp root removed afterwards; run start shares its record and locked create with it (B524)
  • init serves in Go, byte-equal to Node, every usage error, no HOME, a .code-forge.yml that cannot be loaded (read-error, migrate-error, a root that is not a mapping) and the draft-PR refusal without --coder-may-push yes, with the init log, the agent JSON line, the breadcrumb and the error log; the rest of the wizard hands over before Go writes anything, each with its own reason (init-interactive, init-setup, init-jev-link, init-arg-encoding, init-config-syntax, init-answers, init-output) (B502)
  • Plain run start and run start --add-worker launch this binary's Go worker (code-forge worker --run <id>) and pin its pid, so they no longer need Node or hand over when no Node is found; a run the Go worker does not serve still becomes the Node worker in the same process, and the process sweep now also stops a Go worker of a finished run (B511)
  • The hand-over reason list (the handoverReason constants and the handoverReasons array) moved unchanged from handover_log.go to its own file native/cmd/code-forge-native/handover_reasons.go, and .gitattributes now marks only that file merge=union, so a union merge can no longer garble the hand-over functions; a Go test checks every reason has one non-empty, unique code (B513)
  • native-status, the private daemon helper, runs in Go with the same status lines, line splitting, router error line, exit 1, breadcrumb and error log as Node, and --help/-h print its usage; no HOME, a terminal stderr with no agent, and a line Go cannot read exactly like Node (a non-ASCII block id to sort, an Infinity number, a lone surrogate, bytes that are not UTF-8) still hand over to Node with their own reason (B501)
  • The native daemon answers status in Go where it used to start Node's native-status helper: a run record or ledger row Node cannot read gives status-unreadable, and a spend that overflows is null, with the same gate timeout and flaky details; only a block id outside printable ASCII still uses the helper (B503)
  • Go has the doctor's Jev client (Node's request, retries, 30 s attempts and failure kinds), its jev row and the provider CLI cli/flags rows; the full doctor run still hands over to Node as doctor-live-probes until the model-call, isolation, path-deny, Codex rules and worker probes run in Go (B505)
  • The full doctor run with no .code-forge.yml runs in Go (text and --json) with Node's rows, exit code, summary and error log: tools, ledger, locks and worker registry, tmp roots, the read-only process sweep and memory rows, review state, review concurrency, probes skipped, signer, native binary and native daemon; Go functions for the gate command, coder sandbox and darwin worktree-indexing rows match Node's; a config that loads but fails validation (doctor-full-invalid-config), a live project worker (doctor-full-live-worker), a worker registry Go cannot judge, another native binary and an unreadable review-state record still hand over to Node with their own reasons (B504)
  • Go has the doctor's model-call probes with Node's rows: the role pings (facts, coder, reviewer, s2, delegate) on anthropic and xai with the same argv, budget, timeout, schemas and rate-limit retries, and the isolation, path-deny and Codex rules probes; Codex sessions and config shapes Go does not reproduce stay with Node, and the full doctor run still hands over as doctor-live-probes until the doctor calls them (B523)

Added

  • block accept-hit, block amend-acceptance, block unwaive, block ack-waivers and block attempt run in Go with Node's terminal question, refusals, signed ledger rows, registry changes and text or JSON output; block waive at a terminal asks and signs the human waiver in Go; the --yes judge and block reopen at a terminal still hand over to Node (B453)
  • block close runs in Go for an ack digest in Node's Latin localeCompare order, an object or array decision (Node's key order), V8 Date.parse rollover and 2-digit date forms, and late or cap rows whose file is empty, a number or false or whose finding is missing or not text; on a shared terminal its stderr lines (auto-claim, WARN, refusal summary) come before the stdout result as in Node, and --auto-claim claims before a later transcript or --worker-pid refusal as Node does; non-Latin ack digests, object or array late/cap values and out-of-range legacy dates still hand over (B498)
  • block close --auto-claim runs in Go on a run with an autopilot record and with close.require_human at a terminal (same prompt text and answers; a cancel records nothing); a transcript that runs the hooks.on_block_end command is Node's rule_break in Go block ready and block close (Go close skipped this check before and closed where Node refuses); late findings with no file, legacy toUTCString/toString review dates and non-ASCII ack digests run in Go; an object decision, an unknown date form and an order-dependent ack digest still hand over to Node with their own reason (B493)
  • block close refuses a malformed, missing, not-a-directory, other-branch or foreign block worktree and one without the run's workspace directory in Go with Node's messages, reads ledger null and scalar rows and an unreadable rotated ledger file like Node, and reads the ledger before the run-ended check; block open --brief prints Node's realpath and read errors; block stop with a daemon socket runs in Go and its done file takes the serving daemon's rows; block land prints Node's read error for a run file it cannot read (B470).
  • keys list, keys set --cache-hours, keys test and keys remove (file key store), report --slug (text, --json, --export, all 18 sections) and doctor --help run in Go with the same output, exit codes and files as Node; 1Password and keychain writes, a typed keys set, every doctor check run and ledger rows whose bytes depend on JavaScript coercion still hand over to Node (B456)
  • ledger calibration, ledger outcome (--pr/--ci and --scan-git), ledger add coder and ledger outside-review run in Go with Node's output, exit codes, signed rows and error-log entries; logs clear (no log, --yes, no-terminal refusal), logs report with nothing to report, and logs help, unknown subcommands and usage errors run in Go; the clear prompt on a terminal and a report that would file an issue hand over to Node with their own reasons (B457)
  • Go review plays a needs_file answer (the file round with attached files), a schema miss (the signed review.schema_invalid row with its diagnosis) and a second same-model timeout (the ledger-confirmed fallback reviewer) like Node instead of recording them as unavailable (B514)
  • The Go worker plays the recheck and patch-check rounds and reopens a cap stop or a split stop when the config is raised, like Node, instead of handing the ticket over (B517)
  • Go worker --run <id> serves the queue: boot, registry, heartbeat, run root, ticket reviews, orphan sweep, idle exit and a clean stop on SIGINT/SIGTERM, with --once; it gives the whole worker to Node for a Jev key, the commit watch, no config snapshot and on the first ticket Go cannot review, so no ticket is lost or reviewed twice (B489)
  • Go worker serves the other worktree codes, Node's one config-read retry and the worker-error result for an I/O error (with the routing detail) byte-equal to Node, so those tickets no longer go to Node (B507)
  • Go worker.TicketRunner.RunTicket now reviews a ticket end to end when a dry pass finds every part ported (rules risk, block kind, acceptance facts, rules digest or context-unreadable, owned/changed/test files, paired test context, one fix-loop round with one L2 session): rows, review state, signed result, timings and done marker (now with open_findings) are byte-equal to Node on the same repo and fake reviewer CLI; anything else stays unsupported with nothing written and worker still hands over (B497)
  • Go worker.FixLoopRound wraps one fix-loop round like Node's fixLoopRound (block lock, once-per-block review.budget row, state load with tampered / lost / restored / legacy move, L3 rung, hash-moved approval check, crash saved as retry, outcomes approval-not-written, findings-open, no-fix-hunks), byte-equal to Node goldens; tickets needing reopen rows, extra rounds, rechecks or patch checks stay unsupported with nothing written, and the worker does not call it yet (B496)
  • Go review.RunRound, review.BudgetRows/review.RulesRisk and worker.SaveState port the worker's full fix-loop round, block budget rows and signed review state byte-equal to Node (golden tests over Node's own output); tests pin pickReviewer exploration and strict date parsing to Node; the worker does not call them yet and still returns unsupported for review sessions (B495)
  • Go worker.TicketRunner.RunTicket routes a ticket like Node (review.routes, adaptive L2 routing from the ledger, signed review.route rows, route-invalid and route-row) and serves the engine's first refusals (review.exclude, unreadable run record, unknown block, missing base, malformed worktree, amended acceptance), byte-equal to Node; tickets that need a review session still return unsupported with nothing written, and worker still hands over (B492)
  • Go native/worker runs one ticket's refusal outcomes (TicketRunner.RunTicket): bad ticket, bad path, other run, stale or missing file, worktree mismatch, unreadable file, gone or malformed worktree, unreadable run record and missing config snapshot, with Node's file lock, signed result, ticket timings, done marker, signed review.result row and poison rule, byte-equal to Node; tickets that need a review (routing, risk and facts, fix loop) return unsupported with nothing written, and worker still hands over (B488)
  • Go package native/worker holds the review worker's boot and ticket pool (boot lock, registry admission, pins and the signed worker.reattach row, announce and heartbeat files byte-equal to Node, clean stop, queue order, Node's ticket claim lock, parallel_tickets, provider_parallel and fair_share); the per-ticket review is not ported yet, so worker still hands the queue over to Node (B485)
  • spawn --run <id> runs in Go for the roles Go serves without --run: the run's temp root, then the run-pinned budget.usd and autopilot category gate before each step (Go package native/session), with the same refusals, stderr, exit 3, budget.refused, budget.warning and signed autopilot.pause rows, saved pause and error-log warning as Node; --run with the coder role and --background still hand over (B482)
  • spawn runs a foreground closed-book session in Go (Go package native/session: argv, fallback ladder, rate-limit retries, hard and silence timeouts, pid registry, answer and usage parsing, the ledger row) for the reviewer, judge, s2, author and delegate roles on anthropic and xai steps with no schema or the finding schema, and --print-argv, with Node's stdout, stderr, exit code and row; --run, --background, the coder and facts roles and other schemas still hand over to Node; review.Deps.Spawn can now run on this session (B477)
  • Go can review one ticket on the single-reviewer path (native/review: packet, one L2 session through a spawn seam with the same-model timeout retry, the stub guard, the review.plan, review.unavailable and review.session_timeout rows and Node's result object), equal to Node on 25 tickets; a case it does not cover is refused before a session starts, or stops with a gap error when it shows only after the session (needs_file, a second same-model timeout, a schema miss with a ledger), and the review verb still hands over to Node until B477 wires it (B476)
  • worker, spawn and review run in Go for help, usage errors, unknown flags and the refusals Node makes before work starts (a bad or ended run for worker; config, --timeout, --schema, run id, level and role for spawn; no repository, a bad base or --files path for review), and review with nothing left to review runs fully in Go (text and --json, with the skipped-file notes); serving the queue, the session and a review run with files still hand over to Node with their own reasons (B460)
  • autopilot binnacle, autopilot log, autopilot round, autopilot level, the start prompt at a terminal without --yes, and autopilot status and autopilot stop for a grant with no link (the binnacle files) run in Go with the same output, exit codes, files and signed autopilot.extra_round and autopilot.level rows as Node; ask, waive, approve and runs with active approvals still hand over to Node with their own reason (B478)
  • A due autopilot approval of an ended run now puts the old value back in .code-forge.yml in Go, with the same bytes the yaml package writes (comments, blank lines, quoting, flow and block lists, document markers, CRLF), the file's mode kept and Node's WARN lines for a parent that is not a mapping or a failed write; YAML shapes Go does not write byte for byte still hand over to Node (B494)
  • autopilot approve at a terminal (the owner's prompt with clack's wrapping, the cancel text, a failed prompt and the refusals that come after the answer without a config change) and a due approval that needs no .code-forge.yml write or run reload (a pending signed row, a value changed by hand, an ended run that already holds the old value, a missing or unreadable config) run in Go with the same output, exit codes, records and signed rows as Node; an approve that changes the config, a due approval of an active run or one that writes the old value back, and config text Go reads differently still hand over to Node with their own reason (B490)
  • autopilot ask (every refusal before the delegate session, in text and --json, with the signed autopilot.expire row of an expired grant), autopilot approve (every input check and the no-terminal refusal) and runs with active approvals that are not due run in Go with the same output, exit codes, records and rows as Node; ask with a grant that lets the question through, approve at a terminal, a due approval (autopilot-restore) and waive still hand over to Node (B484)
  • autopilot binnacle, autopilot log, autopilot round, autopilot level, the start prompt at a terminal without --yes, and autopilot status and autopilot stop for a grant with no link (the binnacle files) run in Go with the same output, exit codes, files and signed autopilot.extra_round and autopilot.level rows as Node, and mask the run's signer key in output and binnacle files at the same points as Node; ask, waive, approve and runs with active approvals still hand over to Node with their own reason (B478)
  • autopilot status, autopilot stop and autopilot start (with --yes or with no terminal) run in Go with the same output, exit codes, run record and signed autopilot.grant, autopilot.stop and autopilot.expire rows as Node, as do autopilot help, usage errors, unknown flags and the approve --yes refusal; the start prompt at a terminal, ask, waive, round, level, approve, binnacle, log and grants with no link still hand over to Node with their own reason (B461)
  • proof red-green runs in Go with the same output, exit codes, export tree, lock, journal and signed export and red-green rows as Node, and proof counts every project config rule in Go, including proof.runners, review.routes under multimodel and coder.sandbox.add_dirs, and loads the config without the merge-gate check as Node does; a red-green that uses a proof.runners entry or the Pest default, has a snapshot Go cannot read, or meets another error before the export still hands over to Node with its own reason (proof-runner, proof-snapshot, proof-red-green) (B481)
  • proof lock, unlock, restore, export (also --remove) and proof tier with a project config run in Go with the same output, exit codes, run record, lock, journal, export tree and signed ledger rows as Node; proof red-green and the config rules Go does not check yet (review.routes under multimodel, coder.sandbox.add_dirs, proof.runners, a schema merge gate) still hand over to Node with their own reason (B462)
  • help, version and the --help/-h, usage errors and unknown flags of init, native-status, facts, author, s2, jev and proof run in Go with the same output, exit codes, breadcrumb and error log as Node, as do proof baseline, proof tier without a project config and the jev ask and proof argument checks; model sessions, the init wizard, native-status, jev ask past --state, proof tier with a config and the proof run work still hand over to Node with their own reason (B458)
  • gates detect, gates secret-scan, gates safe-edit, gates scope, gates acceptance and gates transcript-grep run in Go with the same output, exit codes, error rows and breadcrumbs as Node, as do gates help and usage errors; gates run --help now prints the usage instead of running the gates; the cases Go cannot match exactly hand over to Node with their own named reason; gates detect treats a prettier dependency set to 0 as absent, as Node does (B459)
  • code-forge sweep runs in Go: help, usage errors, the dry run (text and --json, idle workers included) and --apply give Node's output, exit codes, logs and signals; no HOME, an unreadable temp base and an idle check Go cannot judge still hand over to Node (B486)
  • run start stops in Go what Node's process sweep stops (a worker of a finished run, an orphan whose owner is gone, a registered child of a dead temp root) with Node's checks and signals, and run start and run reload report a duplicate key or an unresolved tag in .code-forge.yml in Go with Node's text; a run reload of a config that loads, other YAML syntax errors and run start without Node keep the Node hand-over (B472)
  • A plain run start (config snapshot and hash, run record, key, mirror, signed rows, dead temp root removal, worker launch and pin), run start --add-worker and the run reload refusals run in Go with Node's output, exit codes, files and rows; a process sweep that would stop a process, a YAML syntax error and a run reload of a config that loads still hand over to Node (B468)
  • run status, run end and run start --reattach (with or without --worker-pid) run in Go with the same output, exit codes, run record, mirror and signed ledger rows as Node, as do run help, usage errors and unknown flags; a plain run start, run start --add-worker and run reload still hand over to Node with their own reason (B454)
  • block close and block ready read Codex exec --json transcripts and decide the code-forge-reviews-write rule in Go with Node's hits, an unreadable --transcript prints Node's error and exits 1 in Go, and review dates in every ECMAScript date-time form are read like V8; hand-made late/cap rows with no file, object decisions, non-ASCII ack digests and the open, claim, stop and land edge cases still hand over to Node (B466)
  • The full doctor run still hands over to Node, but its hand-over now says why: doctor-live-probes for a valid config (live Jev call, provider model probes, worker start and stop), doctor-full-no-config when no valid config loads (the process sweep, tmp-root and worker-registry checks are not in Go yet), and doctor-full-run only for a config Go cannot judge (B487)
  • doctor --quick now refreshes the cached Jev key in Go like Node: an expired file-store entry is deleted with its index row, an entry kept longer than keys.cache_hours is cut (entry and index row rewritten), and an op:// reference is read with op read (one retry after a first-call timeout, logged as an op_retry warning) and cached with its index row, with Node's 1Password reasons; only an index Go cannot read exactly like Node still hands over (doctor-key-refresh), and the full run stays in Node (doctor-full-run) (B483)
  • doctor --quick runs in Go with Node's text, --json, masking and exit codes: config, harness links, Jev key (env or file store) and reviewer rows; doctor help, usage errors and unknown flags too; the full run, the keychain store, a key refresh or 1Password read, schema errors, secret-shaped values, sandbox dirs and ledger rows Go cannot read exactly still hand over to Node with their own reasons (B474)
  • run reload of a config that loads runs in Go with Node's output, exit codes, run record, mirror, ticket pins and signed run.reload row under the run lock, inside the one run router; YAML syntax errors, schema errors, secret-shaped values, sandbox dirs, !! tags and odd record shapes keep their own named hand-overs (B473, landed by B491)
  • plan check (facts, slug, config caps and budget, ledger lanes, claims, overlaps, cycles, imports) and upgrade re-pointing recorded installs run in Go with Node's output, exit codes and installs file; odd cases keep their own named hand-overs (B475)
  • validate and signing a passing outcome record run in Go with Node's output, exit codes and signed row; plan check, sweep and upgrade answer help, usage errors and bad files in Go, while the plan check itself, the process scan and re-pointing installs still hand over to Node with their own reasons; schema errors, secret-shaped values and sandbox dirs in validate hand over too (B471)
  • resolve, models, list, remove, pipeline status|next, outcome seal|check (and the check part of outcome record) and tools [install] run in Go with Node's output, exit codes and files, including help, usage errors and unknown flags; YAML syntax errors, schema errors, files Go cannot write, signing a passing outcome record and the tools install yes prompt still hand over to Node; validate, plan check, sweep and upgrade still run in Node (B455)
  • Go prints the router's once-a-day error-log hint on a terminal (and keeps ~/.code-forge/logs/hints.json) for the verbs it serves, so ledger no longer hands a failure over for it; logs clear asks its confirm prompt in Go; pipeline status|next reports outcome files it cannot read (for example a folder) in Go; a hint state Go cannot judge hands over as router-hint-state (B500)

Fixed

  • The worker's daemon (internal serve) no longer leaves its proc-<pid>-<ms> temp root behind when it gets two stop signals: a stop of the worker's process group sends one and the worker's daemon stop a second, which killed the daemon after its first signal handler ended and before it removed the root (seen on Linux CI, where the daemon socket path fits); the daemon now keeps SIGTERM and SIGINT handled until it exits and stops without listening when a signal comes during its start (B602)
  • logs report --no-ai with a long folder path in an error message (such as a temp scratchpad path) gives the same result in Go and Node: both refuse it as a high-entropy string at the same report line, exit 1, unless the cleaning turns the whole long part into ~ or <project>; the earlier report of Node refusing while Go printed came from two different error logs, not from the code (B588)
  • Issue #36: block rebase diffs merges on main against their first parent only, so a feature branch cut before main changed an owned file no longer reports that file as upstream_owned (or, with --accept-changed, as a false owned-conflict); a batch block land merge gate now links gates.merge_gate_links, runs gates.merge_gate_setup and honours --copy-links; a retry of a closed block under active autopilot approvals stays in Go instead of Node's block is closed, not open; native/README.md names the internal block-rebase-landed helper with its prefix (B589)
  • Go doctor hands a worker registry it cannot judge to Node only after its probe worker is gone: the strict launch now waits (at most 2 s, like Node's stop after SIGKILL) until the killed worker is reaped, so no live or zombie worker pid is left behind on a loaded machine (B593)
  • block land and review-file --wait-block no longer stop at the join with "reviews did not finish" on a busy machine: a git helper that exited 0 counted as failed when its output pipes were read more than 50 ms after it exited (exec.ErrWaitDelay); the pipe grace is now 2 s. The doctor golden tests read a sealed process table, so a zombie of another program on the machine no longer changes their sweep row (B544)
  • CI fixes for the red main runs: the Go job installs the npm packages (npm ci, Node 24, npm cache) so the Go parity tests can run the Node reference, and 12 Node tests now expect what moved to Go (--version, logs clear/empty logs report/no HOME, ledger calibration/outcome/add/outside-review, an unreadable land transcript), copy every native package the config imports into their fixtures, measure the hand-over budget on a verb that still hands over, and size the npm package for the host binary only (B541)
  • code-forge setup (also npm run setup and the npm postinstall) checks the Go binary for this OS and processor: restores lost execute bits, compares internal version with the package version, prints one OK line or the problem plus one fix: line (exit 1); the postinstall form only warns and exits 0 (B463)
  • A Go panic in a goroutine a command starts (the gates block land runs next to its review wait, gates run's gate wait and output copies, the daemon, signal forwarders) follows the main-goroutine rules: a read-only command goes to Node with a go-panic row, any other command prints one line, writes a go-panic-stopped row and exits 1, never exit 2 with a stack trace; the panic line also reaches the terminal for gates, block land and block rebase, whose stderr is copied through the heal pipe (B509)
  • A Go panic no longer looks like a usage error (exit 2 with a stack trace): a read-only command (setup, status, run status, queue status, heal list/show, decisions list, docs path, logs, logs summary/path/handovers, ledger tail) goes to Node with a go-panic hand-over row; any other command is not re-run, prints one line naming the command and code site (never the panic text or arguments), writes a go-panic-stopped row and exits 1; a panic in a background goroutine still exits 2 (B508)
  • code-forge setup (also npm run setup) checks the Go binary for this OS and processor: restores lost execute bits, compares the binary's version with the package version, prints one OK line or the problem plus one fix: line (exit 1); the Go binary serves it, and the entry hands it to Node's scripts/setup.mjs when the binary is missing, not executable or crashes; npm runs no install script (no postinstall), so after npm install -g @codedology/code-forge run code-forge setup (B463)

npm: https://www.npmjs.com/package/@codedology/code-forge/v/0.23.0
Full changelog: https://github.com/ricardov03/code-forge/blob/v0.23.0/CHANGELOG.md