From 808172a45fded19cf3108e087c540f24acae75fe Mon Sep 17 00:00:00 2001 From: choiyounggi <74581798+choiyounggi@users.noreply.github.com> Date: Fri, 7 Aug 2026 23:01:39 +0900 Subject: [PATCH] knowledge: ingest 1 verified insight (uv exact-sync prunes undeclared packages) --- .dev-loop/INGEST_REPORT.md | 147 ++++++++++++------ log.md | 2 + wiki/platforms/index.md | 1 + .../processes/background-services.md | 2 +- ...ment-resync-removes-undeclared-packages.md | 77 +++++++++ .../toolchains/version-management.md | 2 +- 6 files changed, 185 insertions(+), 46 deletions(-) create mode 100644 wiki/platforms/toolchains/environment-resync-removes-undeclared-packages.md diff --git a/.dev-loop/INGEST_REPORT.md b/.dev-loop/INGEST_REPORT.md index 55ccfd1..0eaf78e 100644 --- a/.dev-loop/INGEST_REPORT.md +++ b/.dev-loop/INGEST_REPORT.md @@ -1,53 +1,112 @@ -# Knowledge consolidation — 15 open PRs (#17–#40) → one reconciled state - -The 15 open `knowledge/*` PRs (created 2026-08-04 → 2026-08-05, before the -harvest processed-store dedupe fix in #41) contained 123 file-versions of ~75 -unique pages, with the same insight landing at up to 3 different paths across -up to 8 PRs. Per-PR review would re-import those duplicates, so — as with the -#6–#13 consolidation — this branch carries the reconciled end-state and the 15 -PRs are closed in its favor. +# Knowledge flush — 3 candidate(s): 1 ingested, 2 dropped ## Verified best-practice -Every adopted page's sources were carried from its originating PR's flush, where -they were live-verified at flush time; no new URLs were introduced during -consolidation (checked mechanically: every `http(s)` URL in every merged page -appears in a source PR's diff; every added body line in amended pages traces to -a source PR hunk — orphan-line verification). Confidence fields were kept as the -originating flushes set them, except client-side-rate-limiting where the union -of provider-doc citations (Okta, Auth0, GitHub, OpenAI, RFC 6585) supports -`verified` for the load-bearing claims. One subagent's fabricated content (12 -files matching neither main nor any PR, with invented source URLs) was detected -by the same verification and replaced with true PR content. +### 1. A dependency command that resyncs the environment deletes undeclared packages — `confidence: verified` + +**Candidate as harvested:** "run `uv add`/`uv remove` only after background jobs +finish; register dev tools like pytest/ruff in a dependency-group instead of +`uv pip install`, so they survive a sync." + +**Sources checked (live this session):** + +- https://docs.astral.sh/uv/concepts/projects/sync/ — "`uv sync` performs 'exact' + syncing by default, which means it will remove any packages that are not present + in the lockfile"; `--inexact` retains them; "`uv run` uses 'inexact' syncing by + default, ensuring that all required packages are installed but not removing + extraneous packages." +- https://docs.astral.sh/uv/concepts/projects/dependencies/ — PEP 735 + `[dependency-groups]`; "the `dev` group is synced by default." +- https://docs.astral.sh/uv/reference/cli/ — `uv add`: "The lockfile and project + environment will be updated to reflect the added dependencies." +- https://peps.python.org/pep-0735/ — dependency groups as a standard manifest field. + +**How it was verified — local reproduction, uv 0.11.5 (aarch64-apple-darwin), +throwaway project:** + +1. Declared `packaging`, then installed `iniconfig` ad-hoc with `uv pip install` + (undeclared, absent from `uv.lock`). +2. `uv add typing-extensions` → `iniconfig` **survived**. +3. `uv remove packaging` → `iniconfig` **deleted** along with the intended package. + Repeated a second time with the same result. +4. `uv remove packaging --no-sync` → `iniconfig` **preserved**. +5. Flag inventory via `uv {add,remove,sync,run} --help`: only `uv sync` exposes + `--inexact`, only `uv run` exposes `--exact`; `uv add` and `uv remove` expose + neither. `uv remove --no-sync`: "Avoid syncing the virtual environment after + re-locking the project." +6. Delayed-failure mechanism: a background process that had imported `iniconfig` + before the resync kept running and still resolved the cached module, while a + later `import tomli_w` in that same process raised `ModuleNotFoundError`. + +**Correction applied to the candidate.** The candidate treats `uv add` and +`uv remove` as symmetric ("uv add/remove re-syncs the whole environment"). The +reproduction refutes that: `add` is inexact and harmless to undeclared packages, +`remove` is exact and has no `--inexact` escape hatch. The ingested page carries +the measured per-command exactness table rather than the symmetric claim, so the +"wait for the job" directive is scoped to the commands that actually prune. + +### 2 & 3. Dropped — see Open-PR check + +No independent verification was performed on the two orchestration candidates +because both are pending duplicates; neither is being promoted to a page here. ## Existing-layer check -- Merged-main near-dup scan before consolidation: pairwise Jaccard over - title + "When this applies" across all 141 merged pages → **0 flagged pairs**; - previously merged content carries no duplication. -- Cross-PR dedup during consolidation: 10 duplicate clusters collapsed to one - canonical page each (rate limiting 8→1, call-site enumeration 7→folded into - the canonical merged in #20, stderr/exit-0 diagnostics 4→1, sysroot 2→1, - env-off-switch 2→1, completion predicates 2→1, robots.txt 2→1, - harness-mediated results 2→1, leaked artifacts 2→1, orchestration category - naming unified). Three near-pairs kept distinct after trigger comparison, - with mutual `related:` links (differential setup vs interpretation; expansion - semantics vs off-switch design; import-time tactics vs level choice). -- 24 existing pages received union-merged amendments; additions already present - in main (from #16/#20) were skipped, and all non-canonical `related:` ids - were remapped to canonical page ids (post-merge broken-link scan: 0). +Routed via `INDEX.md` → `platforms` ("toolchain version pinning", "background +services") rather than the harvested `infrastructure` hint, whose seeded scope is +CI/CD, containers, rollout, observability, path-valued config and multi-agent +orchestration — none of which covers a local package manager mutating a project +virtualenv. Then read the `platforms` domain index and every toolchains/processes +page whose "load when" line overlaps. + +Pages read: platforms-toolchains-version-management, platforms-toolchains-compiler-sysroot-on-macos, platforms-processes-background-services, infrastructure-agent-orchestration-pane-delivery-confirmation, infrastructure-agent-orchestration-worktree-isolated-workers + +**Overlaps found.** `platforms-toolchains-version-management` was the only merged +page mentioning uv at all (`uv sync --frozen`, `.python-version`). Its trigger is +*version drift across machines* and its directives are about pinning and +committing lockfiles — it never covers a sync deleting packages, nor the timing +hazard of mutating dependencies mid-run. Different trigger → new page, not a +merge (a merge would have forced two cases onto one page, against the one-case +rule). + +**Conflicts flagged:** none. Nothing in the merged wiki asserts the opposite +behavior; `version-management`'s "install from lockfiles (`npm ci`, `uv sync +--frozen`)" line is consistent with the new page and is not modified. + +**Created:** `wiki/platforms/toolchains/environment-resync-removes-undeclared-packages.md` +(63 body lines, within the 120 limit; positive-guidance form; the two prohibitions +appear only as paired `Instead of` rows). + +**Related links added, both ways:** +`platforms-toolchains-version-management` ↔ new page (lockfile/reproducibility +adjacency), and `platforms-processes-background-services` ↔ new page (the timing +hazard is against a job running in the background). + +**Plumbing:** `wiki/platforms/index.md` toolchains table gains a routing row; +`log.md` gains the dated ingest entry. + +## Open-PR check + +Listed with `gh pr list --repo choiyounggi/dev-loop --state open --search "head:knowledge/"` — +10 open heads: #61, #58, #57, #56, #55, #52, #51, #50, #49, #47. Each head was +fetched and diffed against `origin/main` under `wiki/`. + +| Candidate | Overlapping open head | Verdict | +|-----------|----------------------|---------| +| uv / environment resync deletes undeclared packages | none — grepping every one of the 10 heads' `wiki/` diffs for `uv (add\|remove\|sync\|pip)` and `site-packages` returned 0 hits on all 10 | **new** | +| dev-loop `worktree_escape` guardrail escalates read-only cross-worktree access | **#51** — its `infrastructure-agent-orchestration-worktree-isolated-workers` already carries this case, and its local reproduction is *more* accurate than the candidate: reads alone (`grep`, `awk`, `cat`, `git -C … status`) pass; the escalation fires only when a main-root mention survives the strip **and** a write verb or absolute-path redirect also matches | **drop** | +| dev-loop Orca dispatch binding taxonomy (busy pane, `runtime_unavailable` vs `agent_unconfigured`, `--terminal` with `--worktree`) | **#51** — its `infrastructure-agent-orchestration-pane-delivery-confirmation` carries the idle-prompt-before-binding rule and the three-stage field observation verbatim | **drop** | + +Both dropped candidates are **recurring re-emissions**, not un-retired rows: they +already appear in `~/.dev-loop/queue/.processed.jsonl` 15× and 10× respectively, +and PRs #56, #57 and #58 each recorded dropping the same pair as in-flight +duplicates of #51. They will keep re-entering the queue from live orchestration +sessions until #51 merges; retiring them again here is correct and cheap. ## Routing decision -- New categories: `infrastructure/agent-orchestration` (5 pages; unified the - competing `orchestration`/`agent-orchestration` names), `databases/data-survey` - (1), `qa/deliverables` (1). All other pages route into existing categories. -- Canonical-path decisions: rate limiting → `backend/common/reliability/` - (sits beside timeouts-and-retries; 6 of 8 variants chose it); stderr - diagnostics → `platforms/processes/` (concern spans beyond shells); leaked - artifacts → `testing/data/artifact-leakage-from-a-suite`; call-site - enumeration → the existing `backend/common/change-impact/` page. -- All 38 new pages listed in their domain indexes (nearest-index rule; backend - routes via its python sub-index for bytecode-cache-staleness); INDEX.md domain - summaries updated for infrastructure/qa/databases. Full-wiki lint: frontmatter, - ids, related-links, index coverage, size, qualifiers, staleness → 0 findings. +| Insight | Domain / category / page | New category? | +|---------|--------------------------|---------------| +| A dependency command resyncing the environment deletes packages absent from the lockfile | `platforms` / `toolchains` / `environment-resync-removes-undeclared-packages` (new page) | No — `toolchains` already owns package/version tooling behavior (`version-management`, `compiler-sysroot-on-macos`). The harvested `infrastructure` hint was re-routed: `infrastructure`'s seeded scope is pipelines, containers, rollout, observability and orchestration, none of which covers a local package manager pruning a project virtualenv. | +| `worktree_escape` guardrail read-vs-write | already at `infrastructure/agent-orchestration/worktree-isolated-workers` in open PR #51 | Not ingested (drop) | +| Orca dispatch binding taxonomy | already at `infrastructure/agent-orchestration/pane-delivery-confirmation` in open PR #51 | Not ingested (drop) | diff --git a/log.md b/log.md index c930fc2..2098676 100644 --- a/log.md +++ b/log.md @@ -43,3 +43,5 @@ Append-only. Format: `## [YYYY-MM-DD] --no-sync`, or `--frozen` to skip re-locking too) and run + `uv sync` once the job is done. +4. To repair an environment a resync stripped, run `uv sync` to restore the declared + set, then re-declare what was ad-hoc (`uv add --dev `) instead of + re-running `uv pip install`. For a single package that is present but broken, + `uv sync --reinstall-package `. +5. For a tool you invoke as a CLI and never import, install it outside the project + environment with `uv tool install `, so no project resync can reach it. + +## Edge cases + +| Case | Then | +|------|------| +| A process was already running when the resync stripped the package, and it keeps working | Its already-imported modules live in the interpreter's module cache, so the running job survives while any *new* import in that same process raises `ModuleNotFoundError` — the breakage surfaces whenever that import line is first reached, not at the moment of the resync | +| The failure looks like a code regression (22 tests fail to collect, nothing was edited) | Check the environment before the diff: list installed packages and compare against the manifest; a collection-time `ModuleNotFoundError` across unrelated test files is an environment symptom, not a source one | +| You need the dependency dropped now and cannot pause the job | `uv remove --no-sync` — the manifest and lockfile update, the environment is left alone until you sync deliberately | +| The removed package is a transitive dependency of something still declared | The exact sync keeps it; only packages absent from the resolved lockfile are removed | +| Another manager (pip, poetry, npm) is in play | The same question applies but the answer differs per tool — `pip install` never prunes, `npm ci` deletes and rebuilds `node_modules` wholesale; check the command's own docs for whether it prunes before running it near live work | + +## Instead of + +| If you are about to | Do this instead | Why | +|---------------------|-----------------|-----| +| `uv pip install pytest` to get the suite running in a project env | `uv add --dev pytest` | An ad-hoc install is extraneous to the lockfile; the next exact sync deletes it, and the deletion is triggered by an unrelated command | +| Treat `uv add` and `uv remove` as symmetric and run either one mid-job | Run the exactness table above, and gate only the exact commands on the job finishing | Measured: `uv add` left an undeclared package in place, `uv remove` deleted it in the same environment | +| Re-run `uv pip install ` each time the tool disappears | Declare it once in a dependency group | The `dev` group is synced by default, so the command that removed the ad-hoc copy is the one that restores the declared one | + +## Sources + +- https://docs.astral.sh/uv/concepts/projects/sync/ — "`uv sync` performs 'exact' syncing by default, which means it will remove any packages that are not present in the lockfile"; `--inexact` retains them; "`uv run` uses 'inexact' syncing by default" +- https://docs.astral.sh/uv/concepts/projects/dependencies/ — PEP 735 `[dependency-groups]`; "the `dev` group is synced by default" +- https://docs.astral.sh/uv/reference/cli/ — `uv add`: "The lockfile and project environment will be updated to reflect the added dependencies"; `--no-sync` on `uv remove`: "Avoid syncing the virtual environment after re-locking the project" +- https://peps.python.org/pep-0735/ — dependency groups as a standard manifest field +- Local reproduction 2026-08-07, uv 0.11.5 (aarch64-apple-darwin), throwaway project: with `iniconfig` installed via `uv pip install` (undeclared), `uv add typing-extensions` left it installed, while `uv remove packaging` deleted it — twice, and `uv remove packaging --no-sync` preserved it. A background process that had imported `iniconfig` before the resync kept running and still resolved the cached module, while a later `import tomli_w` in that same process raised `ModuleNotFoundError`. Flag presence confirmed with `uv {add,remove,sync,run} --help`: only `sync` exposes `--inexact` and only `run` exposes `--exact`. diff --git a/wiki/platforms/toolchains/version-management.md b/wiki/platforms/toolchains/version-management.md index a9fccec..b925512 100644 --- a/wiki/platforms/toolchains/version-management.md +++ b/wiki/platforms/toolchains/version-management.md @@ -10,7 +10,7 @@ sources: - https://mise.jdx.dev/configuration.html - https://docs.npmjs.com/cli/v11/configuring-npm/package-json last_verified: 2026-07-10 -related: [platforms-processes-background-services, platforms-shells-portable-shell-scripts, platforms-toolchains-compiler-sysroot-on-macos] +related: [platforms-processes-background-services, platforms-shells-portable-shell-scripts, platforms-toolchains-compiler-sysroot-on-macos, platforms-toolchains-environment-resync-removes-undeclared-packages] --- # Pinning Tool Versions So Every Machine Runs the Same Toolchain