@caupulican/pi-adaptative 0.81.9 → 0.81.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +152 -0
- package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +128 -0
- package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +201 -0
- package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +141 -0
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +5 -0
- package/dist/cli/list-models.js.map +1 -1
- package/dist/core/agent-session.d.ts +46 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +394 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/delegation/worker-actions.d.ts +2 -1
- package/dist/core/delegation/worker-actions.d.ts.map +1 -1
- package/dist/core/delegation/worker-actions.js +34 -2
- package/dist/core/delegation/worker-actions.js.map +1 -1
- package/dist/core/extensions/types.d.ts +3 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/failure-corpus.d.ts +27 -1
- package/dist/core/failure-corpus.d.ts.map +1 -1
- package/dist/core/failure-corpus.js +33 -11
- package/dist/core/failure-corpus.js.map +1 -1
- package/dist/core/model-registry.d.ts +3 -2
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +12 -4
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/models/adaptation-store.d.ts +79 -0
- package/dist/core/models/adaptation-store.d.ts.map +1 -0
- package/dist/core/models/adaptation-store.js +196 -0
- package/dist/core/models/adaptation-store.js.map +1 -0
- package/dist/core/session-analytics.d.ts +24 -1
- package/dist/core/session-analytics.d.ts.map +1 -1
- package/dist/core/session-analytics.js +75 -0
- package/dist/core/session-analytics.js.map +1 -1
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +10 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt-builder.d.ts +4 -0
- package/dist/core/system-prompt-builder.d.ts.map +1 -1
- package/dist/core/system-prompt-builder.js +8 -0
- package/dist/core/system-prompt-builder.js.map +1 -1
- package/dist/core/tool-repair-health.d.ts +3 -0
- package/dist/core/tool-repair-health.d.ts.map +1 -0
- package/dist/core/tool-repair-health.js +63 -0
- package/dist/core/tool-repair-health.js.map +1 -0
- package/dist/core/tool-repair-settings.d.ts +11 -0
- package/dist/core/tool-repair-settings.d.ts.map +1 -0
- package/dist/core/tool-repair-settings.js +18 -0
- package/dist/core/tool-repair-settings.js.map +1 -0
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +0 -9
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +10 -7
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +15 -9
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +7 -3
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +21 -4
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +5 -3
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +61 -7
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +16 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +47 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/index.md +1 -0
- package/docs/models.md +5 -1
- package/docs/rpc.md +75 -0
- package/docs/settings.md +22 -0
- package/docs/tool-repair.md +83 -0
- package/docs/usage.md +3 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +6 -4
- package/docs/bug-ledger.md +0 -134
package/docs/bug-ledger.md
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# Bug Ledger — pi-adaptative (SHARED · Claude + agy + codex)
|
|
2
|
-
|
|
3
|
-
**Standing rule (Cau, mandatory):** while reviewing, building, or hunting ANYTHING, if you find a bug —
|
|
4
|
-
**even one unrelated to the task at hand or to what was asked** — you MUST log it here. Never discard it,
|
|
5
|
-
never stay silent, never "fix-and-forget" without recording it. Drive-by discoveries count. Unrelated
|
|
6
|
-
counts. If unsure whether it's a bug, log it as `suspected`.
|
|
7
|
-
|
|
8
|
-
Unversioned (`.git/info/exclude`) working doc. One row per bug. Keep it append-only except for status
|
|
9
|
-
updates. Sign the "Found by" column.
|
|
10
|
-
|
|
11
|
-
## Severity
|
|
12
|
-
- **critical** — data loss, crash/hang, security, or breaks a core flow (boot, shutdown, send/receive).
|
|
13
|
-
- **high** — wrong behavior on a common path; silent incorrect results.
|
|
14
|
-
- **medium** — wrong behavior on an edge/uncommon path; degraded UX.
|
|
15
|
-
- **low** — cosmetic, minor, or theoretical.
|
|
16
|
-
|
|
17
|
-
## Status
|
|
18
|
-
`open` · `investigating` · `fix-proposed` · `fixed` · `wontfix (with reason)` · `not-a-bug (with reason)`
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Ledger
|
|
23
|
-
|
|
24
|
-
| # | Severity | Area | Location (file:line) | Description | Found by | Status |
|
|
25
|
-
|---|---|---|---|---|---|---|
|
|
26
|
-
| 1 | critical | lifecycle / idle-watcher | `/home/caudev/GitHub/mine/CaupulicanDev/AIConfigs/pi/extensions/idle-watcher/index.ts:321-332`, `:334-347`, `:638-642`, `:690-692`, `:783-787` | Root cause of boot + manual-close bug: (1) `effectiveIdleMs()` converted a no-message branch (`raw == null`) into `sinceReset` (which evaluated to `Date.now() - resetEpochMs`). This defeated the first-message escape (`idleMs == null`), making fresh/re-initialized empty sessions eligible for handoff. The handoff generator built an empty transcript, causing `"No conversation to summarise"`. (2) In-flight async paths (confirm picker/model restore) in `handleSessionStartHandoff` could finish and write/inject against a disposed/stale session after manual close. Fix: Return `null` when `raw == null`, set `disposed = true` on `session_shutdown`, and abort in-flight async flows if `disposed` is set. | Cau / codex / agy | **verified (agy, codex)** — `effectiveIdleMs` now preserves `null` for message-less sessions before applying the reset floor, preventing boot/post-close handoff on empty history. |
|
|
27
|
-
| 2 | high | lifecycle / continuous-learning | `/home/caudev/GitHub/mine/CaupulicanDev/AIConfigs/pi/extensions/continuous-learning/index.ts:4535-4555`; `packages/coding-agent/src/modes/interactive/interactive-mode.ts:5732-5740` | External `continuous-learning` extension still registers `session_start` scheduling and `agent_end` triggers even when native reflection is enabled. The core gate only disables the built-in/interactive auto-learn path, not this installed extension, so boot and turns can still start legacy learning alongside native reflection. Minimal fix: make the extension honor `PI_NATIVE_REFLECTION` or expose a core disable signal so the external scheduler does not start when native reflection owns learning. | codex / claude | **verified (agy, codex)** — `session_start` skips `schedule()` and `agent_end` skips `maybeTriggerAutoLearn()` when `PI_NATIVE_REFLECTION !== "0"`; legacy learning requires explicit `PI_NATIVE_REFLECTION=0`. |
|
|
28
|
-
| 3 | high | lifecycle / continuous-learning | `/home/caudev/GitHub/mine/CaupulicanDev/AIConfigs/pi/extensions/continuous-learning/index.ts:4091-4152`, `:4561-4568` | Suspected shutdown bug: `session_shutdown` clears timers/status but does not cancel or await an active `runRound`; `runRound` only checks `runtimeActive` before starting. A manual close during a learning round can let file/memory writes continue against a stale session context after shutdown. Minimal fix: use an `AbortController`/generation token for active rounds, abort it on `session_shutdown`, and check it before each phase/write. | codex / claude | **open — verification failed (codex)**: `roundGeneration` is bumped and checked before the learning executor and `persistLearningOutcome`, but not before every phase/write (`writeHermesComparison`, provider sweep/indexing, skill audit, and run-log writes happen before the first abort check). The round is mostly synchronous, so an in-flight round also cannot observe `session_shutdown` until it yields. Root fix still needs per-phase/write abort checks and/or cancellable async phases. |
|
|
29
|
-
| 4 | medium | lifecycle / idle-watcher | `/home/caudev/GitHub/mine/CaupulicanDev/AIConfigs/pi/extensions/idle-watcher/index.ts:755-759`, `:772-774`; `packages/coding-agent/src/core/agent-session.ts:1023-1025` | Suspected stale-context race: `session_start` launches `handleSessionStartHandoff()` fire-and-forget, while `session_shutdown` only stops status UI. If the session is manually closed while the async picker/injection path is pending, the task can continue using a stale extension context after `AgentSession.dispose()` invalidates it. Minimal fix: track a per-session generation/abort flag, cancel it on `session_shutdown`, and re-check before UI calls, `pi.sendMessage`, or `pi.appendEntry`. | codex / claude | **verified (agy, codex)** — `disposed` is reset on `session_start`, set on `session_shutdown`, and checked after the model-restore await and after the confirm/picker await before `injectHandoff`/`pi.appendEntry`. |
|
|
30
|
-
|
|
31
|
-
| 5 | high | native reflection / cost accounting | `packages/coding-agent/src/modes/interactive/interactive-mode.ts:5783-5791`; `packages/agent/src/types.ts:309`; `packages/ai/src/types.ts:281-299` | Native reflection duplicate-cost dedupe is still ineffective on the real host path. `maybeRunNativeReflection()` derives `reportId` from `(messages[messages.length - 1] as { id?: string })?.id`, but `AgentMessage` is `Message | CustomAgentMessages[...]` and user/assistant messages have timestamps but no top-level `id`. In normal turns `reportId` is therefore `undefined`, so duplicate scheduling/retry can double-count reflection cost despite `runReflectionPass` supporting idempotence. Minimal fix: derive the report id from a real session entry id after persistence (e.g. latest branch entry id) or a stable turn digest, and add an integration test that calls `maybeRunNativeReflection` twice for one turn and asserts one `spawned_usage` report. | codex | **fixed (pending commit)** — derives `reportId` from a stable digest of role/timestamp/plain-text turn content; duplicate normal turns produce the same reflection report id without reading a non-guaranteed `AgentMessage.id`. |
|
|
32
|
-
| 6 | low | lifecycle / continuous-learning | `/home/caudev/GitHub/mine/CaupulicanDev/AIConfigs/pi/extensions/continuous-learning/index.ts:4550-4563` | Suspected residual native-mode side effect: even when `PI_NATIVE_REFLECTION !== "0"`, `session_start` still initializes continuous-learning state, writes the Hermes comparison artifact, registers the active session, and updates status before returning. This no longer starts the scheduler (#2 fixed), but it is not a true no-op/yield while native reflection owns learning. Minimal fix: move the native-reflection gate to the top of `session_start` before state/artifact writes unless those side effects are explicitly still desired. | codex | open — W11.2 is out-of-repo in AIConfigs; intentionally not fixed in pi-adaptative. |
|
|
33
|
-
| 7 | high | context-gc / memory subsystem | `packages/coding-agent/src/core/context-gc.ts:236-243`; `packages/coding-agent/src/core/agent-session.ts:1497-1502` | `<memory_context` recall pages are prepended to history as `"user"` messages. However, `ContextGc.ts` only applies semantic memory GC markers (like `<memory_context`) to `"custom"` or `"toolResult"` messages. It does NOT scan `"user"` or `"assistant"` messages. As a result, every cross-session recall page fetched during a session accumulates permanently in active memory and gets persisted in transcript files, completely bypassing Context GC and leading to context window bloat over long sessions. | agy | **fixed (claude)** — recall injected as a GC-managed `custom` message (role custom, customType memory_context) so semantic-memory context-GC packs stale recall pages instead of accumulating forever. |
|
|
34
|
-
| 8 | high | memory subsystem / prompt injection | `packages/coding-agent/src/core/memory/providers/transcript-recall.ts:74-75`, `:134-157`; `packages/coding-agent/src/core/agent-session.ts:1497-1502` | Transcript recall interpolates raw past user/assistant text inside an XML-ish `<memory_context>` block and then injects that block as a `user` message. A prior transcript can contain `</memory_context>` or direct instructions, break out of the wrapper, and be replayed as current-turn user content. Minimal fix: treat snippets as untrusted data (escape/fence delimiters or encode), strengthen the wrapper instruction, and add a regression with a closing-tag/instruction payload. | codex | **fixed (claude)** — recall snippets fenced via the untrusted-content boundary (Hermes-aligned: recall = data, not instructions). |
|
|
35
|
-
| 9 | high | memory subsystem / corpus bounds | `packages/coding-agent/src/core/memory/providers/transcript-recall.ts:94-128`; `packages/coding-agent/src/core/session-manager.ts:489-553` | R3 corpus caps are applied only after `loadEntriesFromFile()` has synchronously read and parsed an entire selected JSONL session into memory. A huge or long-lived transcript can block the first recalled turn and allocate far beyond `MAX_DOC_CHARS` / `MAX_TOTAL_CHARS`, violating the bounded-ms-local contract. Minimal fix: stream-extract only user/assistant text with byte/entry/session caps, skip overlarge files before parse, and test a large transcript path. | codex | **fixed (claude)** — skip transcript files > MAX_FILE_BYTES (8MB) before parse so a huge log can't block/bloat the first recalled turn. |
|
|
36
|
-
| 10 | high | memory subsystem / double injection | `packages/coding-agent/src/core/agent-session.ts:1497-1502`; `packages/agent/src/agent-loop.ts:111-114`; `packages/agent/src/agent.ts:519-522`; `packages/coding-agent/src/core/agent-session.ts:773-790`; `packages/coding-agent/src/core/memory/providers/transcript-recall.ts:134-157` | Recall pages are real persisted `user` messages, and future transcript indexing concatenates every `user`/`assistant` message without excluding `<memory_context source="transcript-recall">`. That recirculates recalled snippets into later sessions, duplicates stale data, and can amplify injected transcript content. Minimal fix: make recall context non-persistent or a filtered custom/context-only message, and/or make `extractSessionText()` skip transcript-recall pages; add a regression proving recalled pages are not re-indexed. | codex | **reinforced (claude)** — recall is now a `custom` message which the transcript index (user/assistant only) never re-reads. |
|
|
37
|
-
| 11 | medium | memory subsystem / cwd privacy | `packages/coding-agent/src/core/memory/providers/transcript-recall.ts:120-126`; `packages/coding-agent/src/core/session-manager.ts:574-596` | Suspected hardening gap: recall relies on the cwd-derived session directory but does not verify that each session header's `cwd` matches the active cwd before indexing. Normal writes are per-cwd, but a misplaced/copied JSONL in that directory can be recalled across cwd boundaries; session resume already performs header-cwd matching. Minimal fix: skip headers whose `cwd` is present and does not resolve to `ctx.cwd`, and test a mismatched-header file. | codex | **fixed (claude)** — skip session headers whose cwd does not resolve to the active cwd (no cross-project recall). |
|
|
38
|
-
<!-- Append new rows below. Renumber sequentially. Include file:line whenever known. -->
|
|
39
|
-
|
|
40
|
-
| 5 | high | reflection cost dedup | interactive-mode.ts maybeRunNativeReflection | reportId derived from messages[last].id which doesn't exist on the real path (messages carry only timestamps) -> reportId always undefined -> reflection-cost dedup ineffective (flagged by codex R1+R2 round-2, re-surfaced by agy). | codex / agy | **fixed (claude)** — derive turnKey from last message timestamp + turn size (present on every real turn, stable across retry, distinct per turn). |
|
|
41
|
-
| 12 | high | security / untrusted boundary | `packages/coding-agent/src/core/security/untrusted-boundary.ts:50-53` | Case and spacing variations in boundary tags bypass escaping: `wrapUntrustedText` uses case-sensitive exact-match `replaceAll` to escape boundary tags. This allows an attacker/untrusted content to bypass the boundary by using case variations (e.g. `</UNTRUSTED_CONTENT>`) or spacing variations (e.g. `</untrusted_content >`), which LLMs often interpret as closing the boundary tag. | agy | **fixed (claude)** — case/whitespace-tolerant fence neutralization regex. |
|
|
42
|
-
| 13 | high | security / untrusted boundary | `packages/coding-agent/src/core/security/untrusted-boundary.ts:16-35` | Under-classification of untrusted tools: `UNTRUSTED_NAME_RE` is too narrow and misses generic terms like `download`, `exec`, or `execute` for third-party extensions. If an extension retrieves remote content or runs untrusted scripts under a different name, its output is classified as `trusted` by default and escapes wrapping. | agy | **fixed (claude)** — widened UNTRUSTED_NAME_RE (download/scrape/exec/execute/run-script/shell/curl/wget/request/api). |
|
|
43
|
-
| 14 | high | memory subsystem / effectiveness | `packages/coding-agent/src/core/memory/effectiveness-tracker.ts:48-58` | Fraction-based distinctive recall usage metric false-negative bias: (1) It divides hits by the entire `distinctive.length`, heavily penalizing longer recall snippets since concise assistant responses only repeat a few key tokens, driving the rolling EMA below the 0.15 gate threshold. (2) If a query perfectly overlaps with a recall page, `distinctive.length` becomes 0, returning a score of 0 (useless) for a perfect keyword match. | agy | **fixed (claude)** — saturate denominator at a few key tokens (no length penalty) + no-signal sentinel when recall adds nothing (skip sample), per Hermes reference-data framing. |
|
|
44
|
-
| 15 | high | memory subsystem / file-store | `packages/coding-agent/src/core/memory/providers/file-store.ts:15-34` | R5 `supersedeNearDuplicateLine` lacks Markdown structural protection: it split-checks all non-empty lines, allowing a new fact to overwrite section headers (e.g. `## User profile`) if the Jaccard similarity is >= 0.6, corrupting the file structure. It can also overwrite negative rules (e.g. `Do not use curl`) with generic positive assertions (e.g. `Use wget`), silently deleting critical safety instructions. | agy | **fixed (claude)** — supersede skips Markdown header lines (never overwrites structure). |
|
|
45
|
-
| 16 | medium | settings / profiles | `packages/coding-agent/src/core/settings-manager.ts:891-902` | Multi-profile soul concatenation: souls from all active profiles are concatenated via `join("\n\n")` instead of following specificity-based override rules. This can inject contradictory soul instructions (e.g., combining a project soul with a global soul) and confuse the model. | agy | **fixed (claude)** — getActiveProfileSoul uses first-wins precedence (no concatenation of contradictory souls). |
|
|
46
|
-
| 17 | high | gateways | `packages/coding-agent/src/core/gateways/channel-provider.ts:70-78` | Resource leak on gateway/scheduler re-registration: registering a channel or scheduler with a name that is already in the map overwrites the entry but does not call `.stop()` on the old provider if the registry is active (`started === true`), leaving background listeners/sockets dangling. | agy | **fixed (claude)** — registerChannel/Scheduler stop the same-named provider being replaced. |
|
|
47
|
-
| 18 | medium | catalog-manager | `packages/coding-agent/src/core/catalog-manager.ts:74-77`, `:94-100` | Partial copy corruption on failure: `install()` and `backup()` use `cpSync()` directly without rollback. If the copy fails halfway (e.g., disk full, permissions), it leaves a corrupt, partially copied resource at the destination which can cause startup crash-loops or runtime loader errors. | agy | **fixed (claude)** — install/backup copy to a temp then atomic-swap (no partial tree at dest). |
|
|
48
|
-
| 19 | high | catalog-manager / hashPath | `packages/coding-agent/src/core/catalog-manager.ts:108-137` | Infinite recursion stack overflow crash: `hashPath` walks directories using `statSync`, which follows symlinks. If a catalog resource contains a circular symlink (pointing back to a parent directory), it causes infinite recursion and crashes the agent process on startup/reload with `RangeError: Maximum call stack size exceeded`. | agy | **fixed (claude)** — hashPath tracks visited realpaths + depth cap (breaks circular symlinks). |
|
|
49
|
-
| 20 | medium | lifecycle / memory leak | `packages/coding-agent/src/core/agent-session.ts:1033-1044` | Deactivated session hooks leak: `AgentSession.dispose()` does not clear hooks (`beforeToolCall`, `afterToolCall`, `contextTransform`, `turnRefresh`) that it registers directly on the shared `this.agent` instance. If the `agent` instance is reused or outlives the session (e.g. in IDE/daemon integrations), the captured closure variables keep the entire deactivated `AgentSession` instance (including all its history and maps) alive in memory. | agy | **fixed (claude)** — dispose() clears agent.afterToolCall + transformContext so the closures stop pinning the session. |
|
|
50
|
-
| 21 | high | lifecycle / reflection | `packages/coding-agent/src/modes/interactive/interactive-mode.ts:5809-5820`; `packages/coding-agent/src/core/agent-session.ts:1033-1044` | In-flight reflection pass leak/corruption: In-flight native reflection passes are not tracked or cancelled on session shutdown/dispose. If a user quits, reloads, or switches sessions while a background reflection pass is in-flight, the completion request will continue to run, wasting tokens/budget and executing memory writes (`_applyReflectionWrite` / `_promoteReflectionSkill`) on the file system against the stale session context. | agy | **fixed (claude)** — _disposed flag + _reflectionAbort signal: runReflectionPass bails pre/post-completion and aborts the in-flight call on dispose (no writes to a dead session). |
|
|
51
|
-
| 22 | high | performance / memory subsystem | `packages/coding-agent/src/core/agent-session.ts:4029-4066`; `packages/coding-agent/src/modes/interactive/components/footer.ts:188` | O(N) spawned usage scan on TUI loop: `getSpawnedUsage` performs an `O(N)` scan of all session entries (and filters `this.fileEntries`) to compute cost. Since this is called by the interactive footer component on every single keystroke/render frame, in long sessions with thousands of entries, this synchronous scan causes severe interface lag and CPU spikes. Similarly, `addSpawnedUsage` performs an `O(N)` scan to check for duplicate report IDs. | agy | **fixed (claude)** — getSpawnedUsage cached by entry count (O(1) per render frame; recompute only when entries change). |
|
|
52
|
-
| 23 | critical | agent loop / runaway loop | `packages/agent/src/agent-loop.ts:174-254` | **(Token/Cost)** No turn limit or iteration cap is enforced in the core `runLoop`. If a model gets stuck in a tool execution loop (repeatedly calling tools due to errors or confusion), it executes infinitely. Since history grows quadratically, this can consume hundreds of thousands of tokens and cost $50+ on premium models in a single run. *Cost Impact:* High/Unbounded. *Minimal Fix:* Add a default turn cap (e.g., max 25 turns) in `AgentLoopConfig` or `Agent`. | agy | **verified + fixed (claude)** — confirmed real (`while(true)` core loop, no backstop). NOT fixed with a blunt turn cap (that would kill legitimate long agentic work = feature-removal, banned). Root-cause fix: progress-based runaway backstop — `maxStallTurns` (default 12) in `AgentLoopConfig`; `runLoop` keys a sliding window on exact tool-call signature (name+args) and stops gracefully (+`onRunawayStop` hook) only when ONE signature recurs ≥limit within the window. Varied/long work never trips it. Tests: `packages/agent/test/runaway-loop.test.ts`. **Review (agy):** AGREE that progress-based backstop is superior to a blunt cap. However, (1) Legit polling tasks (e.g. waiting for a build to finish via repeated command calls) will false-positive after 12 iterations. (2) Gaped: Any period P >= 3 loop (e.g. sequence A->B->C->A->B->C...) will completely bypass the detector because the sliding window of size 2 * L can contain at most 2 * L / P < L occurrences of any single signature. E.g. for L=12 and P=3, maximum repeats count is 8, allowing the runaway loop to execute infinitely. (3) Non-deterministic arguments (like changing timestamps) also completely bypass the detector. Filed Bug #28. |
|
|
53
|
-
| 24 | high | memory subsystem / file-store | `packages/coding-agent/src/core/memory/providers/file-store.ts:99-128` | **(Context Bloat)** `systemPromptBlock` reads the entire contents of `MEMORY.md` and `USER.md` verbatim into the system prompt on every turn with no size limit or warning. If these memory files grow large (e.g. from repeated reflection promotions), they will permanently bloat every turn's context window. *Cost Impact:* High permanent token cost per turn (up to $0.50+ extra/turn for 15KB memory). *Minimal Fix:* Cap the injected memory block length (e.g., max 12,000 characters total) or warn when files exceed a threshold. | agy | **verified (mostly invalid) + hardened (claude)** — claim "no size limit" is wrong: the `memory` tool already hard-caps every WRITE at `BUDGET_MEMORY=2200`/`BUDGET_USER=1375` chars (file-store.ts:165,225), and reflection promotions go through that same budgeted tool — so an agent can never bloat memory past ~3.5KB. The 15KB/"$0.50/turn" scenario can't occur via any agent path. Residual gap (external/manual edits bypassing the tool): added a read-time cap in `systemPromptBlock` so the injected view is bounded to the same budgets with a truncation note (file on disk untouched). Tests: `packages/coding-agent/test/file-store-budget.test.ts`. **Review (agy):** AGREE. While the memory tool caps writes, the read-time cap is a critical hardening fix for out-of-band/manual edits. Tested and correct. |
|
|
54
|
-
| 25 | medium | lifecycle / reflection | `packages/coding-agent/src/modes/interactive/interactive-mode.ts:5772-5820` | **(Redundant Calls)** Background native reflection runs unconditionally at the end of any turn that meets the tool call threshold or contains correction keywords. In a multi-turn troubleshooting session where the user repeatedly corrects the agent, this spams back-to-back/overlapping background reflection reasoning passes for the same task. *Cost Impact:* Medium ($1.00 - $3.00/session in wasted background model calls). *Minimal Fix:* Add a time-based debounce or turn-based cooldown (e.g. do not reflect more than once every 3 turns). | agy | **verified + fixed (claude)** — confirmed: `maybeRunNativeReflection` fires per eligible turn; the reportId only dedups retries of the *same* turn, not consecutive distinct corrective turns. Fix: debounce in `InteractiveMode` — `_nativeReflectionInFlight` blocks overlapping passes, `_lastNativeReflectionAt` + `NATIVE_REFLECTION_MIN_INTERVAL_MS` (45s) enforces a minimum gap. Not feature-removal: skipped corrections are still reflected on the next eligible pass over the accumulated turn text. **Review (agy):** DISAGREE with "Not feature-removal". Since reflection only analyzes `event.messages` (the current turn's messages) rather than the whole history, skipped turns are completely lost and never reflected on, causing learning loss. Filed Bug #29. |
|
|
55
|
-
| 26 | high | context-gc / recall | `packages/coding-agent/src/core/context-gc.ts:236-243` | **(Context Bloat)** `semanticMessageHasMarker` in `context-gc.ts` only scans `toolResult` and semantic `custom` messages. However, `TranscriptRecallProvider` memory context pages are injected as `role: "user"` messages. Thus, recall pages completely bypass GC and accumulate verbatim forever, causing significant context window token bloat over long sessions. *Cost Impact:* Medium/High token accumulation over long sessions. *Minimal Fix:* Update `semanticMessageHasMarker` to also scan messages with `role: "user"`. | agy | **invalid — already fixed by #7 (claude)** — STALE finding (reviewed pre-batch-3 code). Recall pages are NO LONGER `role:"user"`: batch-3 #7 changed injection to `createCustomMessage("memory_context", …)` → `role:"custom"`, customType contains "memory" so `isSemanticMemoryCustomMessage` matches, and `<memory_context` is in the default GC markers. Recall pages ARE GC-managed now. Agy's suggested fix (scan `role:"user"`) is also wrong — it would sweep genuine user input into GC. No change. **Review (agy):** AGREE. Recall pages are indeed custom messages now, and are correctly garbage collected. Stale finding verified invalid. |
|
|
56
|
-
| 27 | high | compaction / settings | `packages/coding-agent/src/core/compaction/compaction.ts:219-230` | **(Token/Cost)** Auto-compaction trigger is based on the absolute model context window (`contextWindow - reserveTokens`). For large-context models (e.g. 200k for Claude 3.5 Sonnet, 128k for GPT-4o), auto-compaction will not trigger until 110k-180k tokens are reached, resulting in extremely expensive inputs ($0.30 - $0.50+ per turn) for ordinary chat. *Cost Impact:* Very High ($2.00 - $10.00+ per long session). *Minimal Fix:* Cap the default compaction trigger threshold at a hard maximum ceiling (e.g. 32k or 48k tokens) on large-context models. | agy | **rejected as framed (claude)** — `shouldCompact` ALREADY accepts a configurable `triggerTokens` (Math.min with the window-based default), so the threshold is tunable per deployment. A hard 32–48k ceiling on a 200k model is NOT a root-cause fix: it would force frequent *lossy* compaction, discarding cheaply-cached context and forcing re-derivation/re-reads — that raises cost and degrades quality (the opposite of the goal). Compaction is a quality/cost tradeoff knob that already exists; hardcoding a low ceiling removes headroom users paid for. Open for a possible *opt-in* default cap setting later, but no blunt hardcode. **Review (agy):** AGREE. Compaction triggers are already tunable, and a hard ceiling could degrade performance on expensive cached context windows. An opt-in ceiling is a better approach than a blunt hardcode. |
|
|
57
|
-
| 28 | high | agent loop / runaway loop | `packages/agent/src/agent-loop.ts:227-238` | Evasion of runaway loop detector via period >= 3 oscillations (e.g. A->B->C->A->B->C). Since window size is capped at 2 * L, the count of any single signature in a periodic sequence is at most 2 * L / P, which is less than L. Thus, the detector never triggers and period >= 3 loops run infinitely. | agy | **fixed (claude)** — two root-cause changes in `agent-loop.ts`: (1) signatures are normalized (`normalizeToolSignature`) to mask volatile arg tokens — UUIDs, ISO timestamps, ≥10-digit epochs, ≥16-char hashes — so a model retrying the same call with a fresh timestamp/nonce each turn collapses to one signature and IS detected (gap 3). Short numbers (`file2`, `line 42`) are deliberately NOT masked, so distinct numbered calls aren't falsely merged. (2) window widened from `stallLimit*2` to `stallLimit*STALL_WINDOW_PERIODS` (×4): a period-P cycle repeats each signature ~window/P times, so the count-based trip now catches oscillation up to period 4 (gap 2), not just back-to-back repeats. Tests: `runaway-loop.test.ts` (volatile-timestamp + period-3 cases). Residual (accepted/documented): exact cycles of period ≥5 and legit identical-poll loops still trip — `onRunawayStop` stops gracefully (recoverable) and `maxStallTurns` is tunable/0-disables per deployment (gap 1). Also (agy round-2): a loop that legitimately shows ≥`stallLimit` full ≥16-char commit hashes (40-char SHAs) would over-mask to one signature and false-positive — accepted as the safer default (masking prevents UNBOUNDED nonce-evasion runaways; the false-positive is a graceful recoverable stop). Narrow in practice: git short hashes (7–12 chars) are below the ≥16 threshold and stay distinct, so only full-SHA loops are affected. **Review (agy):** AGREE. The fix is robust and complete. (1) Widening the window to 4 * L successfully catches period P <= 4 oscillations, as each signature will occur at least 4 * L / P >= L times. (2) Normalization correctly filters volatile parameters (UUIDs, timestamps, large digits, large hashes). One minor over-masking edge case remains: git commit hashes of length >= 16 are collapsed, meaning a legitimate loop of showing >= L commits will false-positive. (3) Handled gracefully via onRunawayStop and custom maxStallTurns settings. |
|
|
58
|
-
| 29 | high | lifecycle / reflection | `packages/coding-agent/src/modes/interactive/interactive-mode.ts:5780-5790` | Native reflection debounce skips learning inputs on skipped turns. Since reflection only analyzes the current turn's messages, corrective feedback from turns skipped due to the 45-second gap is permanently lost. | agy | **fixed (claude)** — agy is correct: reflection only sees the current turn's `event.messages`, so dropping a debounced turn lost its learning (making my debounce a feature-removal). Fix: the debounce now DEFERS instead of dropping — an eligible-but-debounced turn's text is buffered (`_bufferPendingReflection`, bounded to `PENDING_REFLECTION_MAX_CHARS=12000`, oldest-dropped) and folded into the next pass's `recentTurnText` via `_drainPendingReflection`. Eligibility (trigger) is now computed BEFORE the debounce check so corrective turns are buffered, not skipped silently. No corrective feedback is lost; it's batched. **Review (agy):** AGREE. The fix is robust and correct. Buffering debounced turns preserves corrective inputs, folding them into the next pass without loss of learning. The FIFO drop-oldest buffer bounds memory growth safely, and the ordering is preserved correctly. |
|
|
59
|
-
| 30 | high | compaction / cost | `packages/coding-agent/src/core/compaction/compaction.ts:123,226`; `packages/coding-agent/src/core/agent-session.ts:2243-2252` | **(Token/Cost — found during Hermes parity review)** Long-session compaction is doubly expensive vs Hermes: (1) default trigger is `contextWindow - reserveTokens` (reserveTokens=16384), i.e. it waits until the context is NEARLY FULL — on a 200k model every turn before compaction pays ~184k input tokens; Hermes compacts at **50% of the window** (capping per-turn input far lower on sustained sessions). (2) the summary is generated with `this.model` (the MAIN/expensive model), whereas Hermes summarizes with a **cheap auxiliary model** (Gemini Flash) and skips compaction if the last 2 passes each saved <10% (anti-thrashing). This is the nuanced, defensible form of the earlier #27 (rejected as a blunt hardcoded ceiling): the real fix is a configurable **percentage-based trigger default** + an optional **cheap auxiliary summarizer model** + anti-thrashing. *Cost Impact:* High on long sessions. | claude (Hermes review) | **fix-proposed (shipped v0.80.75, agy impl-review: AGREE)** — `shouldCompact` adds a fractional trigger (`triggerPercent` default 0.7, lower-of with reserve) + stateless anti-thrashing gate (skip early compaction when projected savings <12%, hard near-full trigger never gated); `_resolveCompactionModel` summarizes with the cheapest authed model meeting a 64k context floor and strictly cheaper than the session model, else the session model. Tests: `compaction.test.ts`. **Review (agy):** AGREE. The stateless anti-thrash projected savings calculation is mathematically sound and superior to a turn counter. The hard near-full trigger is evaluated first, guaranteeing no context overflow. Model selection is appropriately bounded by the 64k capability floor and strictly-cheaper pricing checks. |
|
|
60
|
-
| 31 | medium | security / threat scanning | `packages/coding-agent/src/core/resource-loader.ts:112-130` | **(Security — found during Hermes parity review)** `scanContextFileThreats` has only **3 regex patterns** (instruction-override, secret-exfil, hidden-instruction) and does **not** detect invisible/bidirectional Unicode (zero-width `-`, directional isolates `-`, embeddings/overrides `-`) — a known prompt-injection vector that can hide instructions in context files/memory. Hermes scans 17 such codepoints plus scoped (all/context/strict) pattern sets incl. exfil/C2/role-hijack. Our nonce-fenced untrusted boundary is stronger than Hermes's static fence, but our pre-injection content scanner is much thinner. Minimal fix: add an invisible/bidi-Unicode detector to the scanner and broaden the pattern set (esp. for memory-write `strict` scope). | claude (Hermes review) | **fix-proposed (shipped v0.80.75, agy impl-review: AGREE)** — added `hasInvisibleUnicode`/`stripInvisibleUnicode` (zero-width, bidi overrides/isolates, BOM) + scoped `THREAT_PATTERNS` (`context` vs strict superset incl. exfil/ssh-backdoor/secret-read). Layered per agy: context-file + memory READS strip+continue; memory WRITES scanned `strict` and rejected (incl. hidden chars). Tests: `threat-scanner.test.ts`. **Review (agy):** AGREE. Threat patterns are correctly scoped and memory writes are appropriately blocked. However, identified a significant internationalization bug: `INVISIBLE_UNICODE_RE` includes standard RTL/Indic formatting characters (ZWNJ `\u200C`, ZWJ `\u200D`, LRM `\u200E`, RLM `\u200F`), meaning reading legitimate Arabic, Hebrew, Persian, or Hindi text will strip these characters, corrupting ligatures and word boundaries. Logged as Bug #35. |
|
|
61
|
-
| 32 | medium | learning / skill lifecycle | `packages/coding-agent/src/core/agent-session.ts:4287-4306` (`_promoteReflectionSkill`) | **(Cost/Bloat — found during Hermes parity review)** R7 promotes recurring lessons into `<agentDir>/skills/<name>/SKILL.md`, but there is **no curator**: promoted skills are never usage-tracked, archived when stale, or consolidated when overlapping. Over time this grows the skills corpus unboundedly → tool/context bloat → higher per-turn cost and degraded routing. Hermes has a curator (usage sidecar; STALE >30d, ARCHIVED >90d to restorable `.archive/`; idle-triggered consolidation). Minimal fix: track promoted-skill usage and add an idle/threshold-triggered archive+consolidate pass (restorable, non-destructive). | claude (Hermes review) | **fix-proposed (agy impl-review: AGREE)** — new `skill-curator.ts`: promoted skills carry frontmatter `promoted: true`; `_expandSkillCommand` bumps a usage sidecar on invocation; `computeCurationProposals` (pure) flags stale-unused for archival + overlapping pairs for consolidation; `SkillCurator` archives/restores non-destructively to `skills/.archive/`. PROPOSE-ONLY per agy — surfaced via the new `/curate` command (`/curate archive|restore <name>`); never auto-archives/merges, never touches hand-authored skills. Tests: `skill-curator.test.ts`. **Review (agy):** AGREE. The curator implementation correctly maintains the propose-only invariant. The `createdMs` grace logic guards new skills successfully. Moving skills to `.archive` and restoring works atomically, preventing any concurrency races. **Default-on AUTO-ARCHIVE (Cau, post-review):** at Cau's request the curator now auto-archives stale promoted skills at session start by default (`curator.autoArchive` default true), reversing the propose-only default. agy sanity-checked the safety design and AGREED it's safe enough given the safeguards, flagging a concurrent-session race → mitigated: `autoArchiveStale` runs the batch under a `proper-lockfile` lock on the skills dir, archival is restorable + promoted-only + ANNOUNCED at startup (`Curator: auto-archived N stale skill(s) … restore with /curate restore`). Consolidation stays propose-only. Tests: `skill-curator.test.ts` (autoArchiveStale). |
|
|
62
|
-
| 33 | low | learning / reflection cost | `packages/coding-agent/src/core/agent-session.ts` (`runIsolatedCompletion`/`runReflectionPass`) | **(Cost optimization — found during Hermes parity review)** Our in-process reflection uses a FRESH Context (`tools:[]`, `cacheRetention:"none"`, no sessionId), so the reflection LLM call gets NO prompt-cache hit and pays full input cost. Hermes reuses the parent's cached system prompt for its background-review fork for a measured ~26% cost reduction. **Plan decision (agy):** do NOT inherit the session prompt (it's packed with tool/extension defs → dilutes reflection quality + inflates tokens). Instead make the dedicated reflection prompt a STATIC structure so it hits prompt-cache naturally across passes. | claude (Hermes review) | **fix-proposed (agy impl-review: AGREE)** — `REFLECTION_SYSTEM_PROMPT` is now a static module constant (no per-call interpolation); existing-memory + turn transcript moved into the USER prompt. `runIsolatedCompletion` gained an optional `cacheRetention` (default "none"); reflection passes "short" so the static prefix is provider-cached. Tests: native-reflection/reflection-skill-promotion still green. **Review (agy):** AGREE. Restructuring `REFLECTION_SYSTEM_PROMPT` to be fully static while passing variables in the user prompt is correct. It successfully enables prompt caching with `cacheRetention: "short"` without quality dilution. |
|
|
63
|
-
| 34 | medium | cost / billing guard | `packages/coding-agent/src/core/agent-session.ts` (pre-submit path) | **(Cost/Token — superiority item proposed by agy in the parity plan)** Neither Hermes nor we have a PROACTIVE per-turn cost ceiling. Add a token cost guard: estimate the dollar cost of the pending prompt before submission (input size × model input price + expected max output), and if it exceeds a user-defined threshold (e.g. $1.50/turn) either warn interactively or auto-downgrade reasoning effort (high→low/off) to prevent runaway billing spikes. Beats Hermes (it only compresses reactively; this caps cost proactively). | agy (Hermes parity plan) | **fix-proposed (agy impl-review: AGREE)** — new pure `cost-guard.ts` (`estimateTurnCostUsd`, `evaluateCostGuard`, `downgradeReasoning`) + `costGuard` settings (`maxTurnUsd` default 0 = disabled, `action` warn|downgrade). Wired in `transformContext` via `_applyCostGuard`: estimates the imminent turn's USD, records a decision (`getLastCostGuardDecision()` for the UI), and on `downgrade` steps reasoning down once per over-threshold episode. Tests: `cost-guard.test.ts`. **Review (agy):** AGREE. Integration in `transformContext` runs at the right chokepoint before submission. The one-shot downgrade latch successfully steps reasoning down once per episode without cascading to "off" immediately, and the try-catch wrapper ensures it never disrupts a turn. **Default-on (Cau, post-review):** flipped to ON in WARN-only mode — `maxTurnUsd` default 0→2.5, `action` default "warn" — and wired the decision into the footer (`⚠$X/turn` indicator) so it's actually visible. Auto-downgrade stays opt-in. |
|
|
64
|
-
| 35 | medium | threat-scanner / internationalization | `packages/coding-agent/src/core/resource-loader.ts:177` | **(Internationalization)** The threat scanner's `INVISIBLE_UNICODE_RE` includes standard RTL/Indic formatting characters (ZWNJ `\u200C`, ZWJ `\u200D`, LRM `\u200E`, RLM `\u200F`). Stripping these from read-context files corrupts spelling, joined glyph rendering, and punctuation alignment in Persian, Arabic, Hebrew, and Hindi. | agy | **fixed (claude)** — narrowed `INVISIBLE_UNICODE_RE` to genuinely-dangerous controls only (U+200B, U+202A–202E, U+2060–2064, U+2066–206F, U+FEFF); the legitimate joiners/marks U+200C ZWNJ, U+200D ZWJ, U+200E LRM, U+200F RLM are now PRESERVED (load-bearing in Persian/Arabic/Hebrew/Hindi shaping + emoji ZWJ sequences). The Trojan-Source reorder attack relies on the embeddings/overrides/isolates, which are still stripped. Test: `threat-scanner.test.ts` (i18n-preservation case). |
|
|
65
|
-
| 36 | medium | resource profiles / extension filtering | `packages/coding-agent/src/core/resource-loader.ts` (`getDiscoverableExtensionPaths` vs reload extension discovery) | **(Found in live testing)** External-resource-root extensions (`<root>/extensions/<name>`) are LOADED at reload (`filterPathsByProfile(externalExtensions, "extensions")`) but were ABSENT from `getDiscoverableExtensionPaths()`, which only read `packageManager.resolve()` + CLI paths. The profile-resource editor builds its "available extensions" universe from `getDiscoverableExtensionPaths()`, so external-root extensions (e.g. Cau's private automata-memory-graph/skill-tool-router/etc.) were active but INVISIBLE to the editor — it showed "(none available)" while ~60 ran, and they couldn't be blocked per-profile. | claude (live testing) | **fixed (claude)** — extracted the external-extension directory scan into one shared `discoverExternalExtensionPaths()` used by BOTH the load path and `getDiscoverableExtensionPaths()`, so the editor's universe always matches the loaded set. External extensions now appear in the profile editor and are blockable per-profile. Test: `resource-loader.test.ts` ("getDiscoverableExtensionPaths includes external-root extensions"). |
|
|
66
|
-
| 37 | high | ai / cost accounting | `packages/ai/src/models.ts:44; packages/ai/src/providers/anthropic.ts:550` | W1.1 Anthropic streamed usage.cost.total freezes at input-only value after message_start, under-reporting output cost. | 2026-07-05 harness bug hunt | fixed |
|
|
67
|
-
| 38 | high | ai / json parsing | `packages/ai/src/utils/json-parse.ts:3` | W1.2 repairJson treats invalid \u escapes as valid, causing tool-call JSON parsing to fall back to empty args. | 2026-07-05 harness bug hunt | fixed |
|
|
68
|
-
| 39 | high | coding-agent / model router | `packages/coding-agent/src/core/model-router-controller.ts:715` | W1.3 Executor speculative retry truncates live history but leaves discarded first attempt in router session buffer, persisting ghost turns. | 2026-07-05 harness bug hunt | fixed |
|
|
69
|
-
| 40 | high | coding-agent / bash fast path | `packages/coding-agent/src/core/tools/bash.ts` | W1.4 grep/rg fast path uses literal substring matching for regex patterns, yielding silent false negatives. | 2026-07-05 harness bug hunt | fixed |
|
|
70
|
-
| 41 | high | coding-agent / bash fast path | `packages/coding-agent/src/core/tools/bash.ts` | W1.5 find fast path follows symlinked directories without cycle/escape guard, diverging from real find and risking hangs. | 2026-07-05 harness bug hunt | fixed |
|
|
71
|
-
| 42 | high | coding-agent / html export | `packages/coding-agent/src/core/export-html/index.ts:164` | W1.6 HTML export asset injection uses String.replace values directly, corrupting $ sequences in JS/vendor assets. | 2026-07-05 harness bug hunt | fixed |
|
|
72
|
-
| 43 | high | coding-agent / goals | `packages/coding-agent/src/core/slash-commands.ts` | W2.1 /goal has no user-facing producer; goal consumer stack remains unreachable unless model volunteers goal tool calls. | 2026-07-05 harness bug hunt | fixed |
|
|
73
|
-
| 44 | high | agent / retry kernel | `packages/agent/src/reliability/retry-controller.ts:116` | W3.1 Turn retry controller ignores parsed retryAfterMs when computing backoff. | 2026-07-05 harness bug hunt | fixed |
|
|
74
|
-
| 45 | high | coding-agent / failure corpus | `packages/coding-agent/src/core/agent-session.ts:3639; packages/coding-agent/src/core/billing-failover-controller.ts:73` | W3.2 Failure corpus recording is side-effectful in retry predicate and billing failover, duplicating one failure and possibly disagreeing on classification. | 2026-07-05 harness bug hunt | fixed: de7409ca |
|
|
75
|
-
| 46 | medium | agent / classifier | `packages/agent/src/reliability/classifier.ts:53` | W3.3 Numeric status regexes match inside longer numbers, misclassifying token counts and IDs as rate/server errors. | 2026-07-05 harness bug hunt | fixed: 553fa60f |
|
|
76
|
-
| 47 | medium | agent / compaction loop | `packages/agent/src/compaction/loop.ts:227` | W3.4 Compaction-loop failure mapping treats any aborted substring as user abort, suppressing retries for ECONNABORTED-style provider errors. | 2026-07-05 harness bug hunt | fixed: pending |
|
|
77
|
-
| 48 | medium | ai+agent / streams | `packages/ai/src/utils/event-stream.ts:38; packages/agent/src/proxy.ts:213` | W3.5 Streams ending without terminal event can leave result() unresolved after watchdog disarms. | 2026-07-05 harness bug hunt | fixed: pending |
|
|
78
|
-
| 49 | low | ai / oauth | `packages/ai/src/utils/oauth/openai-codex.ts:150` | W3.6 Codex OAuth token expiry lacks the 5-minute early-refresh buffer used by sibling providers. | 2026-07-05 harness bug hunt | fixed: pending |
|
|
79
|
-
| 50 | high | agent / compaction loop | `packages/agent/src/compaction/loop.ts:63` | W4.1 effect-not-restored retry path is unreachable after apply appends a compaction entry; tests mask real branch mutation. | 2026-07-05 harness bug hunt | fixed: ea6737fa |
|
|
80
|
-
| 51 | medium | agent / compaction verification | `packages/agent/src/compaction/extraction.ts:24` | W4.2 Cancelled-work extraction over-matches everyday phrasing and creates unsatisfiable verification gates. | 2026-07-05 harness bug hunt | fixed: e459899d |
|
|
81
|
-
| 52 | medium | agent / compaction verification | `packages/agent/src/compaction/verification.ts:87` | W4.3 actions-overlap Jaccard penalizes faithful Done carry-over on update compactions. | 2026-07-05 harness bug hunt | fixed: e459899d |
|
|
82
|
-
| 53 | low | agent / compaction tokens | `packages/agent/src/compaction/compaction.ts:294` | W4.4 Token estimator comment is directionally wrong and chunk sizing uses 100% of input bound with no headroom. | 2026-07-05 harness bug hunt | fixed: pending |
|
|
83
|
-
| 54 | low | agent / branch summarization | `packages/agent/src/compaction/branch-summarization.ts:324` | W4.5 Branch summarization bypasses wrapped stream/retry/watchdog path. | 2026-07-05 harness bug hunt | fixed: pending |
|
|
84
|
-
| 55 | medium | coding-agent / interactive rendering | `packages/coding-agent/src/modes/interactive/interactive-mode.ts:2465` | W5.1 renderSessionContext is not reentrancy-safe; overlapping rebuilds can orphan chat containers. | 2026-07-05 harness bug hunt | fixed (claude) |
|
|
85
|
-
| 56 | medium | coding-agent / extensions UI | `packages/coding-agent/src/modes/interactive/interactive-mode.ts:656` | W5.2 extensions-changed UI subscription is not rebound after session switch. | 2026-07-05 harness bug hunt | fixed: pending |
|
|
86
|
-
| 57 | medium | coding-agent / extensions loader | `packages/coding-agent/src/core/resource-loader.ts:912` | W5.3 Failed /reload can leak event-bus subscriptions from new and partial extension generations. | 2026-07-05 harness bug hunt | fixed: pending |
|
|
87
|
-
| 58 | medium | coding-agent / extensions runner | `packages/coding-agent/src/core/extensions/runner.ts:878` | W5.4 emitToolCall lacked per-handler error isolation, skipping later handlers and diagnostics on throw. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — wraps each `tool_call` handler, emits `ExtensionError`, continues dispatch, then rethrows the first handler error to preserve fail-closed semantics. |
|
|
88
|
-
| 59 | medium | tui / input | `packages/tui/src/keys.ts:1375` | W6.1 Kitty PUA functional keys decoded as printable invisible text. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — rejects unnormalized Kitty functional PUA codepoints while preserving keypad printable aliases. |
|
|
89
|
-
| 60 | medium | tui / measurement | `packages/tui/src/utils.ts:295` | W6.2 extractAnsiCode CSI terminator set was too narrow and could swallow visible text after non-SGR CSI. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — CSI extraction now stops at any valid CSI final byte (`0x40`-`0x7e`), with regression coverage for `?25l`, cursor-forward, and clear-screen sequences. |
|
|
90
|
-
| 61 | low | tui / stdin buffer | `packages/tui/src/stdin-buffer.ts:315` | W6.3 Bracketed paste without end marker could leave pasteMode set forever. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — arms a paste-mode timeout that emits unterminated paste content literally, exits paste mode, and lets subsequent keys process normally. |
|
|
91
|
-
| 62 | high | coding-agent / startup migrations | `packages/coding-agent/src/migrations.ts:147` | W7.1 Malformed models.json hard-crashes startup migrations; trust-manager parse has similar unguarded path. | 2026-07-05 harness bug hunt | fixed: pending |
|
|
92
|
-
| 63 | medium | coding-agent / settings | `packages/coding-agent/src/core/settings-manager.ts:427` | W7.2 deepMergeSettings documented recursive merge but only merged one level. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — nested object overlays now recurse, preserving sibling leaves while arrays remain replacement values. |
|
|
93
|
-
| 64 | low | coding-agent / migrations | `packages/coding-agent/src/migrations.ts:252` | W7.3 Windows session migration basename extraction silently no-opped. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — session migration now extracts file names with a separator regex that handles both POSIX and Windows-style paths. |
|
|
94
|
-
| 65 | medium | coding-agent / scout | `packages/coding-agent/src/core/scout-controller.ts:103` | W8.1 Scout budget counted total tokens against an output-token cap, causing premature truncation. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — accumulates `usage.output` for the output-token cap and covers high-input/low-output scout turns. |
|
|
95
|
-
| 66 | low | coding-agent / reflection | `packages/coding-agent/src/core/learning/reflection-engine.ts:177` | W8.2 Reflection JSON parse failure returned empty usage, zeroing real spend. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — completed reflection calls retain provider usage when JSON parsing or validation fails. |
|
|
96
|
-
| 67 | low | coding-agent / research lane | `packages/coding-agent/src/core/background-lane-controller.ts:452` | W8.3 Research-lane budget gate compared unclamped estimate against clamped envelope limit. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — computes one clamped lane budget from settings and foreground envelope, then passes it to both the research envelope and runner limit. |
|
|
97
|
-
| 68 | low | agent / public loop API | `packages/agent/src/agent-loop.ts:41` | W9.1 agentLoop public API had a detached promise with no catch. Reproduction confirmed with a throwing `convertToLlm`: the stream never completed and Vitest reported an unhandled rejection. Continuation array mutation was not reproduced in this row's regression. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — public `agentLoop`/`agentLoopContinue` wrappers catch detached loop failures, emit `agent_end`, and resolve the stream result with an error assistant message. |
|
|
98
|
-
| 69 | low | agent / shell output | `packages/agent/src/utils/shell-output.ts` | W9.2 sanitizeBinaryOutput preserved lone surrogates, DEL, and C1 controls despite comment. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — filters lone surrogate code units plus DEL/C1 controls while preserving valid surrogate pairs. |
|
|
99
|
-
| 70 | low | ai / anthropic | `packages/ai/src/providers/anthropic.ts:1259` | W9.3 Anthropic stop-reason mapping default threw on future `stop_reason` values instead of graceful stop. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — unknown Anthropic stop reasons now warn and map to `stop`; unit and SSE fixture coverage added. |
|
|
100
|
-
| 71 | low | coding-agent / failure corpus | `packages/coding-agent/src/core/failure-corpus.ts:83` | W9.4 redactSecrets missed separator-bearing sk-proj/sk-ant key formats. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — redacts `sk-proj-` and `sk-ant-` keys containing separators. |
|
|
101
|
-
| 72 | low | coding-agent / exec | `packages/coding-agent/src/core/exec.ts:135` | W9.5 exec decoded per chunk with data.toString(), splitting multibyte characters. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — uses UTF-8 `StringDecoder` per stream and flushes pending bytes at process settlement. |
|
|
102
|
-
| 73 | low | coding-agent / bash execution | `packages/coding-agent/src/core/bash-execution-controller.ts:39` | W9.6 Overlapping executeBash calls clobbered the shared abort controller. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — tracks all active bash abort controllers and aborts/removes each independently. |
|
|
103
|
-
| 74 | low | coding-agent / tools manager | `packages/coding-agent/src/utils/tools-manager.ts:312` | W9.7 Concurrent same-tool first-run downloads raced on one archive path. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — same-tool installs now share one in-flight download promise and clear it after settlement. |
|
|
104
|
-
| 75 | low | coding-agent / interactive mode | `packages/coding-agent/src/modes/interactive/interactive-mode.ts` | W9.8 Interactive-mode small leaks: current-scope session selector lacked seq guard; custom editor replacement did not dispose previous editor. | 2026-07-05 harness bug hunt | **fixed (pending commit)** — current/all session loads each have sequence guards and `setEditor` disposes replaced non-default editors. |
|
|
105
|
-
| 76 | low | ai / mistral streaming | `packages/ai/src/providers/mistral.ts:397` | W9.9 Investigation: Mistral streaming tool-call assembly may fragment if ids are absent from later deltas. | 2026-07-05 harness bug hunt | **not reproduced / no code change** — attempted fixture-gated investigation: repo has Mistral e2e tests gated on `MISTRAL_API_KEY`, but no key is available in this environment, so no SDK-executed streaming tool-call chunk fixture could be captured. Static search found no existing recorded Mistral streaming tool-call fixture to prove absent-id deltas. Per W9.9, left provider code unchanged because fragmentation was not demonstrated. |
|
|
106
|
-
| 77 | high | coding-agent / local models | `packages/coding-agent/src/core/models/local-registration.ts:81` | W10.1 Local model context windows are registered as a guess (8192 default); no num_ctx/served-window awareness anywhere, so over-window prompts are silently truncated by the server. | 2026-07-06 compaction incident | fixed: 15eb7c69 |
|
|
107
|
-
| 78 | high | coding-agent / compaction | `packages/coding-agent/src/core/compaction-support.ts:132` | W10.2 Summarizer selection was capacity-blind: router-cheap local model chosen for spans its window cannot hold, producing recall-empty checkpoints. | 2026-07-06 compaction incident | fixed: ebcc1137 |
|
|
108
|
-
| 79 | high | agent / compaction | `packages/agent/src/compaction/compaction.ts` | W10.3 Verification demands scale with span size while the summary budget was fixed at 1500 tokens; length-stopped summaries were gated as complete; truncation deleted the gate-checked Files/Done sections. | 2026-07-06 compaction incident | fixed: ebcc1137 |
|
|
109
|
-
| 80 | high | agent+coding-agent / compaction | `packages/coding-agent/src/core/context-pipeline.ts:388` | W10.4 Pre-digest feeds the summarizer a lossy digest while facts are extracted from the raw span; active-task text did not ride in the facts block, making the gate unsatisfiable. | 2026-07-06 compaction incident | fixed: ebcc1137 |
|
|
110
|
-
| 81 | medium | coding-agent / compaction | `packages/coding-agent/src/core/agent-session.ts:2784` | W10.5 Manual /compact is single-shot on the cheap summarizer with no escalation ladder or deterministic fallback; surfaces raw gate internals. | 2026-07-06 compaction incident | fixed: 77d22ee1 |
|
|
111
|
-
| 82 | low | agent / compaction extraction | `packages/agent/src/compaction/extraction.ts:23` | W10.6 Prohibition extraction captured a mid-sentence fragment as a mandatory rule in the incident trace; needs fixture with W4.2. | 2026-07-06 compaction incident | **fixed (pending commit)** — sentence splitting no longer breaks version-number sentences into mid-clause prohibition fragments; incident fixture added. |
|
|
112
|
-
| 83 | low | coding-agent / red-team tests | `packages/coding-agent/test/red-team/provider-limits.test.ts:158` | Pre-existing failure on main: d444e991 added _failureCorpus.record inside _compactWithRetry but the red-team CompactWithRetryHarness was never updated, so the quota-mid-compaction row failed with a TypeError. | 2026-07-06 compaction incident (drive-by) | fixed: ebcc1137 |
|
|
113
|
-
| 84 | high | ai / openai responses | `packages/ai/src/providers/openai-responses-shared.ts:349` | Regression in c81848ec (W1.1): providerSuppliedTotal flag dereferences response.usage.cost outside the usage guard, crashing finalizeResponse on usage-less streams; caught by the full sweep. | 2026-07-06 compaction incident (drive-by) | fixed: 4325cc7e |
|
|
114
|
-
| 85 | high | agent / compaction verification | `packages/agent/src/compaction/verification.ts:92` | Resumed-session incident 2026-07-06: actions gate used symmetric Jaccard against the whole ## Done section while the update prompt mandates carrying prior Done items, so every 2nd+ compaction (all resumed sessions that compact) trended to deterministic gate failure; capacity fix in 0.81.4 could not address this. Gate now measures recall of new-span actions; update prompt bounds Done carry-over; reversal trigger narrowed; fact paths excluded from cancelled-leakage. | 2026-07-06 compaction incident round 2 | fixed: e459899d |
|
|
115
|
-
| 86 | low | coding-agent / tests | `packages/coding-agent/test/bash-edit-write-race.test.ts:28` | Flaky under full parallel sweep load: mutation-barrier ordering assertion observed [bash, file-start, file-end] once during ./test.sh while passing 5/5 in isolation; timing-sensitive microtask ordering. | 2026-07-06 compaction incident round 2 (drive-by) | **fixed (pending commit)** — verdict: test setup race, not a barrier ordering bug; replaced fixed sleeps with explicit wait-until scheduling gates while preserving the exact ordering assertions. |
|
|
116
|
-
| 87 | high | agent / compaction extraction | `packages/agent/src/compaction/extraction.ts` | Field incident 2026-07-06 (round 3, on v0.81.5): prohibition extraction harvested 13 "never/do not" fragment rules from one pasted instruction document, making mandatory-rules-recall demand the checkpoint reproduce the document; harvest now skips user messages >1500 chars and caps rules at the 8 most recent. Same trace: /goal seeded no requirement when the model skipped decomposition (now seeded deterministically), and gate-failure warnings now name the summarizer selection + input estimate for the still-open estimator question (rows 77/85 lineage). | 2026-07-06 compaction incident round 3 | fix-proposed |
|
|
117
|
-
| 88 | high | coding-agent / git filter | `packages/coding-agent/src/core/tools/git-filter.ts:423` | R1 git log filtering discarded user arguments whenever no explicit limit or pretty format was present, so author/path/range filters silently returned the latest repository commits. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — default log limiting now appends to preserved user arguments, and compact output is computed from the filtered result. |
|
|
118
|
-
| 89 | high | coding-agent / edit tool | `packages/coding-agent/src/core/tools/edit-diff.ts:209` | R2 fuzzy edit matching rewrote the whole file through normalized text and generated a normalized-vs-normalized diff, hiding unrelated byte changes. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — fuzzy matching now maps normalized spans back to original content and splices only the matched region, so diffs compare original content with the actual final file. |
|
|
119
|
-
| 90 | medium | coding-agent / edit tool | `packages/coding-agent/src/core/tools/edit-diff.ts:141` | R7 duplicate detection counted exact matches in fuzzy-normalized space, rejecting a unique raw match when a fuzzy-equivalent line existed elsewhere. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — exact matches count raw occurrences, while fuzzy matches still count normalized occurrences and reject ambiguity. |
|
|
120
|
-
| 91 | high | tui / editor | `packages/tui/src/components/editor.ts:156` | R3 editor word wrapping recursed forever when a single grapheme was wider than the layout width, crashing width-1 CJK/emoji renders with a stack overflow. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — single overwide graphemes now emit one visual overflow chunk, while multi-grapheme atomic segments still split visually. |
|
|
121
|
-
| 92 | high | coding-agent / rpc | `packages/coding-agent/src/modes/rpc/rpc-mode.ts:705` | R4 RPC mode accepted parsed non-object JSON such as null as a command, then threw while handling and reporting it, risking process termination from an unhandled rejection. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — stdin JSON is validated as a non-array object with string type before dispatch, and command errors use validated id/type values. |
|
|
122
|
-
| 93 | high | ai / anthropic | `packages/ai/src/providers/anthropic.ts:658` | R5 Anthropic-compatible streams that sent populated tool input in `content_block_start` and no `input_json_delta` lost arguments at block stop because finalization reparsed an empty partial buffer as `{}`. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — tool-call finalization only reparses streamed JSON when deltas arrived, otherwise preserving seeded arguments; delta streams still take precedence. |
|
|
123
|
-
| 94 | medium | coding-agent / read tool | `packages/coding-agent/src/core/tools/read.ts:108` | R6 `read` tail mode counted the phantom empty string from newline-terminated files as a content line, returning N-1 real lines plus a blank and inflating total-line accounting. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — whole-file and streamed line paths now drop only the terminal phantom line while preserving real blank lines and files without trailing newlines. |
|
|
124
|
-
| 95 | medium | coding-agent / cli | `packages/coding-agent/src/cli/initial-message.ts:22` | R8 initial prompt construction concatenated distinct stdin, `@file`, and CLI message sources without separators, producing merged text such as `codeexplain this`. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — prompt parts now trim trailing source-boundary newlines and join with a blank line while single-source prompts stay unchanged. |
|
|
125
|
-
| 96 | medium | agent / session migration | `packages/agent/src/session/session-manager.ts:232` | R9 v1-to-v2 session migration never added newly generated entry IDs to its collision set, so duplicate 8-hex IDs could be assigned and corrupt parent chains. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — migration now records each generated ID before generating the next, so collisions retry and parent chains remain complete. |
|
|
126
|
-
| 97 | low | agent / session resume | `packages/agent/src/session/session-manager.ts:584` | R24 `findMostRecentSession` aborted the whole recent-session scan when one candidate vanished before `statSync`, returning null instead of the most recent remaining session. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — per-file stat failures are skipped while the scan continues over remaining candidates. |
|
|
127
|
-
| 98 | medium | coding-agent / worker delegation | `packages/coding-agent/src/core/delegation/worker-actions.ts:85` | R10 worker edit actions used string replacement, so `$` replacement patterns such as `$$`, `$&`, `$\``, and `$'` in model-proposed text were interpreted and corrupted on disk. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — worker edits now use a function replacement so replacement text is inserted literally. |
|
|
128
|
-
| 99 | medium | coding-agent / model router | `packages/coding-agent/src/core/model-router/tool-escalation.ts:86` | R11 cheap-tier shell escalation split only on `&&`, so commands like `git log | patch -p1` or `ls || ./run.sh` could be classified by their first read-only segment and bypass escalation. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — shell commands now split on `&&`, `||`, `;`, pipes, and newlines, and every non-empty segment must classify read-only. |
|
|
129
|
-
| 100 | medium | coding-agent / model resolver | `packages/coding-agent/src/core/model-resolver.ts:424` | R12 bare CLI model-id resolution used the first provider-order match, ignoring ambiguity and the single authenticated provider that could actually serve the requested id. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — bare exact-id matches now collect all candidates, prefer a single authenticated match, and otherwise return an ambiguity error listing provider/id references. |
|
|
130
|
-
| 101 | medium | ai / oauth | `packages/ai/src/utils/oauth/index.ts:135` | R13 concurrent expired-token callers each refreshed the same OAuth provider independently, racing one-use rotating refresh tokens and risking spurious failures or orphaned credentials. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — OAuth refreshes are memoized per provider while in flight, shared by concurrent callers, and cleared on settle so failures retry later. |
|
|
131
|
-
| 102 | medium | ai / openai-codex | `packages/ai/src/providers/openai-codex-responses.ts:245` | R14 OpenAI Codex SSE and WebSocket paths emitted successful `done` events even when terminal response status mapped to `error`/`aborted`, producing out-of-contract done reasons for cancelled or failed responses. | 2026-07-06 roadmap sweep | **fixed (pending commit)** — terminal Codex responses with error/aborted stop reasons now throw into the provider error path, emitting `error` events instead of `done`. |
|
|
132
|
-
| 103 | high | agent / compaction extraction | `packages/agent/src/compaction/extraction.ts` | C6 checkpoint v2 extraction needed the content contract to preserve where work is, open failures, and working set while dropping resolved/transient errors and avoiding duplicate file appendices. | 2026-07-06 compaction reliability Phase 0 | **fixed (pending commit)** — extraction now emits recency-ordered working-set facts, open error facts with supersession, deterministic fallback parity, and compaction summaries rely on the facts block instead of a post-gate file appendix. |
|
|
133
|
-
| 104 | high | agent / compaction verification | `packages/agent/src/compaction/verification.ts` | C7 checkpoint v2 prompts and gates needed to make the extraction content contract enforceable: working-set files and open errors had no dedicated recall gates, and prompt sections still carried the old Blocked/Open shape. | 2026-07-06 compaction reliability Phase 0 | **fixed (pending commit)** — prompts now use Working Set/Open Problems sections with drop instructions, verification gates working-set and open-error recall, deterministic fallback passes its own gate, and a facts-transcription invariant covers gate satisfiability. |
|
|
134
|
-
| 105 | high | agent / compaction update path | `packages/agent/src/compaction/compaction.ts:519` | C8 checkpoint v2 update prompts needed explicit merge rules so stale Working Set entries and prior Open Problems resolved by new turns do not persist across checkpoints. | 2026-07-06 compaction reliability Phase 0 | **fixed (pending commit)** — update prompts now carry explicit Open Problems resolution and Working Set refresh instructions, with regression coverage asserting the previous checkpoint and new facts reach the update request. |
|