fix(packaging): verify the kirocrew entry-point after venv install + self-heal a half-built venv - #8413
Conversation
78cee55 to
4389d17
Compare
|
Pushed
Local gate green: 129 tests pass across Note: the shard-3 |
4389d17 to
5b965b2
Compare
5b965b2 to
b5eed14
Compare
Design Review (Fable 5, fork) — 🟡 CONCERNSDesign-level review of Design-Verdict: CONCERNS Sound self-heal with well-argued fail-closed ownership, but the background pip has no mutual exclusion with other installers and its failure remedy points at a broken command. Watch
[DESIGN-REVIEWED] d359401 |
First Principles Review (Fable 5, fork) — 🟡 CONCERNSPremise-level review of All claims verified against the base. First-Principles-Verdict: CONCERNS The change's own "PYTHONPATH cannot mask a half-built install" rationale is not applied to the aiohttp probe three lines above, inside the same record gate. What this change shipsIntent: make an interrupted editable install detectable and self-healing so cloud-crew connect stops dying with an opaque exit 127 — a FIX.
WatchThe description says the SubtractionsMerge the two probes: replace the unisolated aiohttp check at install.sh:506 and the new [FIRST-PRINCIPLES-REVIEWED] d359401 |
GPT 5.6 Review (fork) — ✅ no blocking findingsReviewed Review detailsNo findings. |
Opus 4.8 Review (fork) — ✅ no blocking findingsReviewed |
b97b00d to
eb09d7e
Compare
|
|
|
|
eb09d7e to
df2d2c0
Compare
|
|
|
df2d2c0 to
d76a7c4
Compare
|
Verify the expected platform console script and package import after editable installs, repair missing wrappers without delaying gateway socket readiness, and keep locked Windows wrappers on dependency-only sync. Fixes kirodotdev#8409
d76a7c4 to
d359401
Compare
|
bolichen97
left a comment
There was a problem hiding this comment.
Tech Lead review — approved.
Self-heal safety. The repair is an in-place pip install -e .; nothing is deleted, moved, or swapped, so there is no path to user-data loss. The ownership bypass that lets the reinstall proceed with no installed package is narrow on four independent conditions: the opt-in allow_missing_package_repair flag (set only by the internal --repair-missing-package CLI), origin is None, exact normcase/abspath equality with <repo>/.venv's platform interpreter, and a runnable interpreter. _is_owned_project_venv_target additionally refuses a symlinked or junction-like .venv or bin/Scripts, and fails closed on OSError — so lexical equality cannot be turned into authority over another tree. Path.is_junction is reached through getattr, so the 3.10/3.11 shards are safe.
No masking of a real failure. This is the inverse: the change replaces proxy signals with artifact postconditions. install.sh and sync_or_reinstall both require an executable console script and an isolated (-I) import kiro_crew through the target interpreter before declaring success, so pip returning 0 on a half-built venv now returns 1. The gateway path never heals into a broken state silently — failure, timeout, and SandboxUnavailableError each print a named reason plus the manual kirocrew update fallback and log redacted detail. The Windows locked-wrapper dependency-only branch still returns before the full-reinstall postconditions, so the substitute path is not asked to rewrite a wrapper it deliberately leaves alone.
Cross-platform. Consistent with AGENTS.md's platform_compat rule: start_new_session=platform_compat.IS_POSIX, process-tree teardown routed through platform_compat.kill_process_tree_async (process-group signal on POSIX, taskkill /T on Windows, so the Windows child is still reaped without a session), and both console_script_path and project_venv_python split on sys.platform rather than assuming the POSIX bin/ layout — the correct fix for a module that exists for the Windows Scripts\kirocrew.exe case.
Lifecycle. Scheduling after the API socket binds keeps READY off the pip budget, and the dedicated _console_script_repair_task handle (cancelled and awaited in _shutdown, distinct from the GC-retention _background_tasks set) is what actually prevents pip outliving the gateway — the general set would not have.
Scope. 4 source files / ~340 added lines, all on the reported exit-127 chain; the token_mint.py diagnostics are the surface that produced the opaque failure in #8409, not adjacent cleanup. Single commit, 897 tests across the affected files with four mutation proofs.
Signals. All 60 check-runs success / 6 skipped / 0 failure on d359401d; GPT 5.6 and Opus 4.8 report no blocking findings against this exact SHA (comments updated 03:52–03:55, after the 03:40:48 head), Design and First Principles are 🟡 CONCERNS which are advisory by the lanes' own contract; readiness: passed applied 04:25:32, postdating the head. No unresolved blocking findings and no CHANGES_REQUESTED.
One accepted trade-off, not a blocker: mode="strict" hides credential dirs while pip runs, so an operator whose index auth lives in ~/.netrc rather than PIP_INDEX_URL may see the repair fail rather than succeed. That degrades to the explicit "run manually" message, which is the right direction for an untrusted-interpreter child.
…self-heal a half-built venv (#8413) Enforce artifact postconditions instead of proxy signals on the install and update paths: install.sh and dep_sync.sync_or_reinstall now require an executable kirocrew console script and an isolated (-I) kiro_crew import through the target interpreter before a full editable reinstall counts as success. Adds a narrowly scoped in-place repair for an interrupted rebuild that left a working interpreter with no entry point, gated on exact <repo>/.venv ownership with redirected .venv or bin/Scripts refused and filesystem-inspection errors failing closed. The gateway runs the repair as a directly owned sandboxed child after the API socket binds, with the task cancelled and awaited during shutdown. token_mint emits bounded per-candidate diagnostics before exit 127. Fixes #8409 (cherry picked from commit febfe08)
Problem / Motivation
An interrupted editable install (
pip install -e .) can leave a crew's venv with a working Python interpreter but no usablekirocrewconsole entry point. Nothing previously detected or repaired this state, so a later cloud-crew connect could fail when the remote auth step exited 127 withkirocrew binary not found.Reported by @timwukp in #8409. This is the same failure class previously documented in #3220, which was resolved independently; this change is limited to the venv entry-point incident tracked in #8409.
Why it matters
A recoverable mid-install interruption can become an opaque "crew unreachable" outage: a launcher symlink can point at a missing target, the service can fail on restart, and the operator sees only code 127 without a diagnosis of which candidate was absent, dangling, or non-executable.
What changed (motivation → approach → change)
The install and update paths treated a successful subprocess or dependency import as sufficient even when the actual console entry point or target-venv package was unusable. An atomic
.venv.newswap was considered and rejected because the update path has no independent interpreter to build from and Windows cannot rename the running executable this code already protects. The fix therefore enforces explicit in-place postconditions and repairs only a narrowly verified interrupted state:install.sh— afterpip install -e .and before recording.install-method=pip, require thekirocrewscript to be executable and requirekiro_crewto import through the venv interpreter in isolated mode (python -I), so an inheritedPYTHONPATHcannot mask a half-built install.dep_sync.sync_or_reinstall— after every full editable reinstall, require the platform-correct console script and run the package import through the existing isolated interpreter probe (-I, neutral cwd, inheritedPYTHONPATHignored). The intentional Windows locked-wrapper dependency-only branch still returns before these full-reinstall postconditions.<repo>/.venvplatform interpreter. Reject symlinked or junction-like.venvandbin/Scriptsdirectories, fail closed on filesystem-inspection errors, require a runnable interpreter, and allow only the final interpreter symlink used by normal POSIX venvs. Foreign paths and foreign origins remain refused.slack/gateway.py— run the potentially long repair through a directly owned asyncdep_sync.py --repair-missing-packagesubprocess only after the dashboard/API socket has bound. Timeout and cancellation kill the child process tree and bounded-reap it. A dedicated single-flight repair-task handle is cancelled and awaited during graceful shutdown, preventing pip from surviving the gateway that started it.instances/token_mint.py— before exit 127, emit bounded per-candidate diagnostics for absent paths, dangling symlinks, and present-but-non-executable candidates, including venv interpreter and entry-point sentinels. Existing transports redact and carry stderr to the operator.Tests
test/test_installer_python_floor.pypins the executable/import gates before.install-methodis recorded, including the isolated-Ispelling.test/test_dep_sync.pycovers missing/non-executable entry points, isolated import failure and timeout, locked-wrapper behavior, exact managed-venv ownership, redirected.venvand scripts directories, a normal final interpreter symlink, foreign/unrunnable targets, and the narrow internal repair CLI.test/test_slack_gateway.pycovers platform-correct script paths, explicit repair intent, post-bind scheduling, single-flight task ownership, child-tree kill/reap on timeout or cancellation, and shutdown cancellation/join through the real repair path.test/test_bootstrap.pyandtest/test_cli_server_more_coverage.pyexercise the isolated post-install import contract through bootstrap and update callers.test/test_instances.pycovers the ordered remote candidate diagnostics.On exact published commit
df2d2c0b2e21312e350e961cfbb8f6899174c5c0, the seven affected test files collected 897 tests: 893 passed, 4 skipped. Four targeted mutation proofs each failed in pytest call phase when installer isolation, redirected-directory refusal, cancellation tree-kill, or shutdown task ownership was removed.Manual verification
An earlier live t4g.xlarge reproduction established the half-built-venv failure shape, installer failure behavior, and remote dangling-symlink diagnostics without changing crew data. The exact final candidate then passed repository-wide isort, flake8, mypy (1,305 source files), pinned Black
26.3.1plus its baseline ratchet, subprocess-encoding, async-I/O, Agent SDK boundary, and lockdown gates,git diff --check, the single-commit push guard, and the complete affected-file matrix above. Focused GPT and Opus reviews of the exact SHA both passed after the shutdown-owned repair task regression was added.Screenshots / video
Why no screenshot: packaging, gateway lifecycle, and CLI diagnostics only; no rendered UI surface changes.
Related Issues
Fixes #8409
Pattern harvest
Rule candidate: review-prompt
Pattern: flag install/build steps that verify a proxy signal instead of the artifact produced; require isolated probes, explicit filesystem ownership boundaries, and cancellation ownership for repair subprocesses.
Checklist
feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)Contribution License Agreement