Skip to content

Replace IPC busy-loop polling with async fs.watch#6

Closed
gavrielc wants to merge 1 commit intomainfrom
claude/async-file-watcher-szF5V
Closed

Replace IPC busy-loop polling with async fs.watch#6
gavrielc wants to merge 1 commit intomainfrom
claude/async-file-watcher-szF5V

Conversation

@gavrielc
Copy link
Copy Markdown
Collaborator

@gavrielc gavrielc commented Feb 1, 2026

  • Use fs.watch for event-driven file watching instead of setTimeout polling
  • Replace synchronous fs calls (readdirSync, readFileSync, unlinkSync, renameSync)
    with async fs.promises equivalents to avoid blocking the event loop
  • Add simple coalescing via pending flags to prevent redundant processing
  • Remove unused IPC_POLL_INTERVAL config constant

https://claude.ai/code/session_01Lccp65bZyEMMbDdF7d9E4j

- Use fs.watch for event-driven file watching instead of setTimeout polling
- Replace synchronous fs calls (readdirSync, readFileSync, unlinkSync, renameSync)
  with async fs.promises equivalents to avoid blocking the event loop
- Add simple coalescing via pending flags to prevent redundant processing
- Remove unused IPC_POLL_INTERVAL config constant

https://claude.ai/code/session_01Lccp65bZyEMMbDdF7d9E4j
@gavrielc
Copy link
Copy Markdown
Collaborator Author

gavrielc commented Feb 1, 2026

Incompatible with PR #3's per-group IPC directory structure. fs.watch would need to be redesigned to watch multiple group directories. Closing for now.

@gavrielc gavrielc closed this Feb 1, 2026
Rlin1027 referenced this pull request in Rlin1027/NanoGemClaw Feb 6, 2026
New Module: memory-summarizer.ts
- needsSummarization(): Check if conversation exceeds thresholds
- summarizeConversation(): Generate summary via Gemini CLI
- getMemoryContext(): Get formatted summary for injection

Config (config.ts):
- MEMORY.SUMMARIZE_THRESHOLD_CHARS: 50K chars trigger
- MEMORY.MAX_CONTEXT_MESSAGES: 100 messages max
- MEMORY.SUMMARY_PROMPT: Customizable summary template

Database (db.ts):
- memory_summaries table with upsert support
- getGroupMessageStats() for threshold checking
- getMessagesForSummary() for batch retrieval
- deleteOldMessages() for archival

Integration:
- ContainerInput.memoryContext field added
- agent-runner injects memory before prompt
- index.ts imports getMemoryContext for each execution

This enables automatic conversation compression when context
grows too large, preserving important information while reducing
token usage.
@TomGranot TomGranot deleted the claude/async-file-watcher-szF5V branch February 12, 2026 15:51
asantopietro added a commit to asantopietro/nanoclaw that referenced this pull request Mar 1, 2026
Closes qwibitai#6, relates to qwibitai#4

## Changes

### `container/build.sh`
- Default (no args) builds with `git rev-parse --short HEAD` SHA tag **and** re-tags as `latest`
- Optional `REGISTRY` env var: push both SHA tag and `latest` to a registry after build
- Explicit tag argument still works for one-off builds; skips `latest` re-tag in that case
- Build output now prints both tags and includes rollback instructions

### `setup/container.ts`
- Derives SHA tag via `git rev-parse --short HEAD` at build time (falls back to `'unknown'` in non-git environments)
- Builds with SHA tag, then re-tags as `latest`
- Adds `SHA_TAG` field to all `emitStatus` calls — setup output now records which exact commit was built
- Test run uses the SHA-tagged image

## Verification

After merge, `./container/build.sh` will produce:
```
nanoclaw-agent:<sha>   ← immutable, traceable
nanoclaw-agent:latest  ← always current
```

To confirm a running container's commit:
```bash
docker inspect nanoclaw-agent:latest --format '{{.Config.Labels}}'
# or compare the SHA tag against git log
```

To roll back:
```bash
docker tag nanoclaw-agent:<previous-sha> nanoclaw-agent:latest
```

Co-authored-by: Tony Santopietro <asantopietro@gmail.com>
Reviewed-on: https://gitea.cluster.lab1.lan/asantopietro/nanoclaw/pulls/7
Co-authored-by: nanoclaw-bot <nanoclaw@nowhere.net>
Co-committed-by: nanoclaw-bot <nanoclaw@nowhere.net>
dptts added a commit to dptts/nanoclaw that referenced this pull request Mar 7, 2026
Implements token optimization via RTK with clean enable/disable via config.

- Added `RTK_ENABLED` (default: true) - Install RTK in containers
- Added `RTK_AUTO_HOOK` (default: false) - Auto-intercept Bash commands
- Both configurable via environment variables

- Install RTK from GitHub releases (rtk-linux-x86_64)
- Controlled by RTK_ENABLED build arg (default: true)
- RTK auto-hook initialization controlled by RTK_AUTO_HOOK build arg
- Build script passes config as build args

- Added comprehensive RTK usage guide
- Manual prefix mode examples (default)
- Auto-hook mode explanation (experimental)
- Token savings analytics with `rtk gain`
- When to use/not use RTK

- Added 6 RTK configuration tests
- Test RTK_ENABLED defaults and behavior
- Test RTK_AUTO_HOOK defaults and behavior
- All 48 tests passing

**Default (RTK enabled, manual prefix):**
```bash
./container/build.sh
```

Agents use `rtk git status`, `rtk npm test`, etc. for 60-90% token savings.

**Disable RTK:**
```bash
RTK_ENABLED=false ./container/build.sh
```

**Enable auto-hook (experimental):**
```bash
RTK_AUTO_HOOK=true ./container/build.sh
```

All Bash commands transparently become `rtk <command>`.

Use built-in RTK analytics (zero code):
```bash
rtk gain              # Last 7 days savings
rtk gain --days 30    # Last 30 days
rtk gain --json       # Machine-readable
```

1. Default: RTK enabled with manual prefix (this PR)
2. Test: Run 1-2 weeks, check `rtk gain` for actual savings
3. Evaluate: Review token consumption metrics
4. Decision: Enable `RTK_AUTO_HOOK=true` if results are good

Closes qwibitai#6

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
agent-fleet-bot Bot referenced this pull request in bryantb2/nanoclaw Mar 30, 2026
…security

Proposal #4 — Pre-Implementation Ticket Check (REQUIRED)
Adds mandatory comment read before any implementation. Blocks start if
comments contain "don't implement", "wait for", "architecture only", etc.
Evidence: KRE-196 was implemented despite a comment saying architecture
plan only — causing rework and mid-session user notification (2026-03-30).

Proposal #5 — QA Delegation Enforcement
Adds explicit FORBIDDEN clause: running lint/typecheck/tests via Bash
does NOT satisfy the QA gate. Creating and immediately deleting a QA
team does NOT satisfy the gate. Only a named QA subagent reporting
PASS or FAIL counts. Evidence: 3rd consecutive session (2026-03-26,
2026-03-27, 2026-03-30) where PM bypassed QA subagent with shell commands.

Proposal #6 — Token Security: No Literal Tokens in Task Prompts
Adds rule to use GH_TOKEN=$(~/github-credential-helper.sh) instead of
embedding resolved ghs_... values in SendMessage content. Evidence: 81
hardcoded token occurrences in session f497c6f8 JSONL transcript.

Approved by Blake (operator) via Slack on 2026-03-30.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
luisherranz pushed a commit to luisherranz/nanoclaw that referenced this pull request Mar 31, 2026
Critical bugs:
- Bug qwibitai#4: Remove sequence from content hash to prevent duplicates on
  repeated PreCompact calls. Hash is now sha256(session_id:role:content).
- Bug qwibitai#5: storeMessages() now returns count of newly inserted messages.
  PreCompact only creates leaf summaries for newly inserted messages,
  preventing re-summarization of already-stored content.

Should-fix:
- #1/qwibitai#10: Add dbInitialized flag to skip redundant schema setup on
  repeated initLcmDatabase() calls (fast path for MCP tool calls).
- qwibitai#6: Depth-capped condensation now attempts API summarization first,
  falls back to truncated concatenation with 10K token cap instead of
  unbounded blob.
- qwibitai#7: Skip API call entirely when neither ANTHROPIC_API_KEY nor
  ANTHROPIC_AUTH_TOKEN is set, go straight to deterministic fallback.

Nice-to-have:
- qwibitai#3: Remove duplicate LcmMessage/LcmSummary from src/types.ts.
  Single source of truth is container/agent-runner/src/lcm-store.ts.
@Nate-Vish Nate-Vish mentioned this pull request Mar 31, 2026
5 tasks
morrowgarrett added a commit to morrowgarrett/nanoclaw that referenced this pull request Apr 1, 2026
…ation

qwibitai#5 Warm container: Already supported via 30min IDLE_TIMEOUT + IPC piping.
   Docker startup is only 0.4s; Claude Code init is the real bottleneck.
   Full elimination requires embedded SDK (future).

qwibitai#6 Frozen memory snapshot + prompt caching:
- Query memU once at container start for relevant context
- Inject as immutable system prompt prefix
- Enables Anthropic's automatic prefix caching (50-75% token savings)
- Memory context frozen for session duration (no mid-turn re-queries)

qwibitai#7 Smart model routing: Skipped — Agent SDK doesn't expose model selection
   in query options. Would require SDK changes or CLI wrapper.

qwibitai#8 FTS5 session search:
- Added FTS5 virtual table on messages for full-text cross-session search
- Auto-synced via INSERT/DELETE triggers
- searchMessages() function for keyword-based message recall
- Complements memU's semantic search with fast keyword search

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
morrowgarrett added a commit to morrowgarrett/nanoclaw that referenced this pull request Apr 2, 2026
All 7 container features re-applied after confirming the earlier hang
was caused by API rate limiting, not code issues. SDK v0.2.76 confirmed
to support abortController.

#1  AbortController idle timeout (5min, configurable)
qwibitai#3  Per-group .mcp.json config (auto-discovered servers + tools)
qwibitai#6  Frozen memU memory snapshot (query once at start, hybrid RAG)
qwibitai#11 Skill-as-markdown auto-loading from /workspace/group/skills/
qwibitai#12 Structured compaction summary (last-compaction-summary.md)
qwibitai#13 Peer channel MCP tools (peer_send, peer_status via SSH)
qwibitai#14 Recall MCP tool (FTS5 cross-session message search)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gkarolyi pushed a commit to gkarolyi/nanoclaw that referenced this pull request Apr 7, 2026
niels-emmer added a commit to niels-emmer/nanoclaw that referenced this pull request Apr 9, 2026
- Read HTTP Content-Type header from audio download response instead of
  hardcoding audio/ogg; falls back to Matrix event info.mimetype
- Map MIME type to correct file extension for OpenAI Whisper (webm, ogg,
  wav, flac, mp3, mp4) — fixes 400 errors from Chrome-based Element Web
  which sends audio/webm;codecs=opus
- Add HTTP response status check before attempting transcription
- Docs: add issues qwibitai#5 (container image loss) and qwibitai#6 (voice transcription
  MIME mismatch) to DEBUG_CHECKLIST.md with diagnosis commands
- Docs: add Linux systemd commands to Service Management section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Quirds added a commit to thankyourobot/tyr-aios that referenced this pull request Apr 9, 2026
Two issues exposed when the new "nanoclaw using OneCLI" assertion (qwibitai#6
from the adversarial review) was deployed alongside the still-stale
"credential proxy listening" check from section 6.

Bug 1 — SIGPIPE under pipefail:
  journalctl ... | grep -q "Credential layer..." worked when run by
  hand but FAILed inside dr-test.sh under set -uo pipefail. Root cause:
  grep -q exits on first match, closing the pipe; journalctl gets
  SIGPIPE on its next write and exits 141; pipefail surfaces 141 as
  the pipeline exit code; the && branch doesn't fire and the || prints
  FAIL even though the line was present.

  Fix: capture journalctl output into a variable first, then grep
  against the variable. No pipeline → no SIGPIPE.

Bug 2 — stale section 6 check in OneCLI mode:
  "credential proxy listening" greps ss -tln for :3001. With OneCLI
  active, credential-proxy.ts is not started, so the check always
  reports FAIL — a false positive. The dr report from #aios-alerts
  has been "FAILED — N check(s) need attention" since the Phase 2 flag
  flip and the section 7 nanoclaw-using-OneCLI check exposed it.

  Fix: skip the port 3001 check when ONECLI_API_KEY is set in
  /opt/nanoclaw/.env, reporting "skipped — OneCLI mode" as detail.
  Phase 3 will delete both this check and credential-proxy.ts entirely.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
luisherranz pushed a commit to luisherranz/nanoclaw that referenced this pull request Apr 10, 2026
Critical bugs:
- Bug qwibitai#4: Remove sequence from content hash to prevent duplicates on
  repeated PreCompact calls. Hash is now sha256(session_id:role:content).
- Bug qwibitai#5: storeMessages() now returns count of newly inserted messages.
  PreCompact only creates leaf summaries for newly inserted messages,
  preventing re-summarization of already-stored content.

Should-fix:
- #1/qwibitai#10: Add dbInitialized flag to skip redundant schema setup on
  repeated initLcmDatabase() calls (fast path for MCP tool calls).
- qwibitai#6: Depth-capped condensation now attempts API summarization first,
  falls back to truncated concatenation with 10K token cap instead of
  unbounded blob.
- qwibitai#7: Skip API call entirely when neither ANTHROPIC_API_KEY nor
  ANTHROPIC_AUTH_TOKEN is set, go straight to deterministic fallback.

Nice-to-have:
- qwibitai#3: Remove duplicate LcmMessage/LcmSummary from src/types.ts.
  Single source of truth is container/agent-runner/src/lcm-store.ts.
foxsky added a commit to foxsky/nanoclaw that referenced this pull request Apr 12, 2026
Three parallel subagent reviews (correctness, tests, template/bot-flow)
of 6e33f39 + f859aa6 flagged three material gaps. All addressed here.

TEMPLATE — recoverable-error retry loop (Agent 3 finding qwibitai#4)

The existing success:false handler at L567 said "If error exists,
present it in {{LANGUAGE}}" — which degrades into "sorry, registration
failed" when the engine rejects register_person with the new missing-
fields error. The bot would just show the error to the user instead of
parsing which fields are missing and asking for them. Added a new
"Recoverable-error retry loop" bullet right after the generic handler
that teaches the bot to:
  1. Parse the missing-field list from the error text
  2. Ask the user in ONE concise question for only those specific fields
  3. Retry the SAME register_person call with the complete payload
  4. Only degrade to "sorry, failed" if the user refuses or retry errors

This is a two-turn conversation, not a failure.

TEMPLATE — Cross-Board Assignee Guard 4-field reminder (Agent 3 qwibitai#6)

M8 already cross-referenced the offer_register branch for handling
cross-board reassignment rejects, but didn't inline the 4-field rule.
Added an explicit note on the offer_register diagnose step so a reader
landing there directly understands the hierarchy-board requirement
without chasing the cross-reference to L545.

TESTS — 3 new cases closing Agent 2 coverage gaps

container/agent-runner/src/taskflow-engine.test.ts:

  1. Hierarchy board missing ALL three fields (phone + group_name +
     group_folder) → error message lists all three. Guards the dynamic
     `missing.join(', ')` output so the bot can ask for everything in
     one prompt instead of discovering the fields one by one across
     multiple retries.

  2. Legacy board with max_depth = NULL → canDelegateDown() returns
     false, so the validation does NOT fire and a 3-field register_person
     call succeeds. Pre-hierarchy installs (before the hierarchy schema
     was added) still have max_depth NULL in the boards table; this
     regression guard prevents my validation from breaking them.

  3. offer_register on a LEAF board → message does NOT include the
     division/sigla ask. Counterpart to the existing assertion that
     the sigla IS present on the hierarchy fixture. Locks down the
     canDelegateDown() branch in buildOfferRegisterError.

218 container engine tests pass (up from 214).

DEFERRED (pre-existing, out of scope): Agent 3 qwibitai#2 suggested injecting
a pre-resolved {{IS_HIERARCHY_BOARD}} boolean into the generator
instead of using literal {{HIERARCHY_LEVEL}} < {{MAX_DEPTH}} comparisons
that render as "3 < 3" in rendered group prompts. The current pattern
is functional — LLMs read "3 < 3 = false" correctly — but it's
cognitively more expensive than a pre-resolved flag. Changing this
would require generator refactoring and touches L293, L294, L534, L545
and other places that use the same pattern. Out of scope for the
Edilson fix; worth a separate refactor commit later.

REGEN

11 groups/*/CLAUDE.md re-rendered to pick up the L545 retry-loop and
cross-board 4-field additions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
foxsky added a commit to foxsky/nanoclaw that referenced this pull request Apr 12, 2026
…index

Three parallel review agents (reuse, quality, efficiency) flagged
actionable items on Phase 2:

1. TYPE SAFETY (Agent 1 qwibitai#5, Agent 2 qwibitai#4): The pending_approval response
   field was not declared in UpdateResult, and new AdminResult fields
   (offer_register, merged, source_archived, notes_added) were only
   returned via 'as any' casts. Fixed:
   - UpdateResult extended with pending_approval: { request_id,
     target_chat_jid, message, parent_board_id }
   - AdminResult extended with offer_register, merged, source_archived,
     notes_added (used by merge_project and handle_subtask_approval)
   - All 4 'as any' casts in the Phase 2 code removed
   - Also cleaned up `parentBoard?.group_jid ?? null` dead fallback
     (the null case was already made unreachable by the earlier
     fail-fast guard)

2. UNUSED INDEX (Agent 3 qwibitai#6): idx_subtask_requests_status on
   (status, target_board_id) was never queried — the dominant query
   is the PK lookup on request_id (O(1)). Removed the index and the
   drift-guard test that asserted its existence. Added a comment
   explaining the decision so a future scan-by-pending query can
   reinstate it.

Deferred (acceptable at current scale):
- subtask_requests grows unbounded: zero boards have opted into
  approval mode, so no current users. Revisit when adoption warrants.
- N+1 insert in approve loop: typical batches < 10 subtasks,
  better-sqlite3 caches prepared statements.
- decision field conflates handle_subtask_approval + process_minutes_
  decision: matches existing codebase pattern.
- Reject/approve notification duplication: only 2 sites with small
  variation, helper extraction would save ~2 lines.

236 engine / 365 skill tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
johnhojohn969 pushed a commit to johnhojohn969/nanoclaw that referenced this pull request Apr 14, 2026
Risk/execution overhaul — makes the bot safe to run on real money and
replaces per-coin tuning with a universal volatility-normalized formula.

Fix qwibitai#3 — Exchange-side SL/TP (real-money safety net):
- Entry market orders now include attachAlgoOrds with ATR-derived
  slTriggerPx + tpTriggerPx, so positions are protected on the exchange
  even if the bot goes offline between cron cycles.
- Main bot: new syncExchangeSl() amends the live conditional algo
  (cancel-and-recreate fallback via orders-algo-pending) whenever the
  local trailing-SL tier advances, keeping exchange SL in lockstep.
- Store slAlgoClOrdId + currentExchangeSlPrice in state.openData.

Fix qwibitai#4 — Session rules actually enforced:
- New getCurrentSession() (UTC: asian<8, london<13, ny).
- Entry logic now applies session_rules[session].max_leverage and
  size_multiplier instead of only passing them to Claude for logging.

Fix #5a — OI divergence with real previous OI:
- OKX has no public per-instrument historical OI endpoint, so roll a
  state.oiHistory cache: pushOiSample() writes current OI each cycle,
  pickOiPrev() returns the oldest sample inside a 2–8h window.
- analyzeMarket() signature extended with oiPrev; both call sites
  (hold loop + scan loop) pass it through.
- Kills the `analyzeOIDivergence(oiCurrent, oiCurrent, ...)` no-op that
  silently disabled 4 OI signal weights.

Fix #5b — Funding-rate trap F&G fusion:
- analyzeFundingTrap() now receives the real fg object instead of
  hardcoded {value: 50}; `combined_with_fear/greed` flags finally fire.

Fix qwibitai#6 — Risk dialed down:
- risk_per_trade_main: 0.08 → 0.01 (8x reduction; 1% per trade)
- hard_limits.max_risk_per_trade: 0.08 → 0.02 (ceiling for selfEvolve)
- max_positions_main: 2 → 4 (room for ETH/SOL/XRP/DOGE/SUI scan)
- max_drawdown_main: 0.20 → 0.15 (tighter DD circuit-breaker)
- Added risk_per_trade_lab 0.005, max_positions_lab 4, max_leverage_lab 5
- instruments[] now matches WATCHLIST (ETH/SOL/XRP/DOGE/SUI)
- Params version bump 0 → 1 with update_reason=atr_universal_fix_v1

Universal per-instrument formula (replaces hardcoded per-coin tuning):
- New atr(rawCandles, 14) helper computes True Range on 1H candles.
- New getInstrumentProfile() returns {atr, atrPct, sizeMult, maxLev,
  k_sl=1.5, k_tp=3.0}. sizeMult is log-normalized from 24h USD volume
  ($10M→0.4, $1B→1.0). maxLev is volatility-capped: ~0.12/atrPct.
- analyzeMarket() now computes and returns the profile per instrument.
- Entry sizing replaces equity*risk*lev*sizeM/ctUsdVal with:
    riskUsd  = equity × risk% × session × liquidity × signal
    notional = riskUsd × (price / (k_sl × ATR))
    sz       = notional / ctUsdVal
  So SUI/DOGE get smaller positions automatically (higher ATR%) while
  keeping the same USD risk as ETH. No per-coin tuning required.
- Initial SL/TP prices derive from ATR: SL = entry ± 1.5×ATR, TP =
  entry ± 3.0×ATR (1:2 R:R), passed both to attachAlgoOrds and stored
  in state.openData for the tier-ladder override below.

Trailing-SL ladder (main bot):
- At t0 (hwm below t1 threshold), prefer the stored ATR-derived
  atrSlUplRatio over the fixed -7% margin-% default, so the initial
  stop scales with the coin's natural volatility.
- Tiers t1..t5 unchanged; still drive exchange-SL sync on advance.

Lab bot (okx-trader-lab.js):
- Same helpers/fixes (ATR, profile, session rules, OI cache, FR fix,
  attachAlgoOrds at entry).
- Skips exchange-side SL tier sync because lab's pnlPct is
  equity-scale rather than uplRatio-scale — initial attach SL/TP
  still provides the safety net.
mludoml added a commit to mludoml/nanoclaw that referenced this pull request Apr 16, 2026
…ons, DB schema changes

- registered_groups: PK is now (jid, session_group), not global
- sessions: PK is (group_folder, session_group), adds last_node tracking
- messages: bot responses now stored (is_bot_message=1)
- New env vars: SESSION_GROUP, CLAUDE_MODEL documented in all .env examples
- Syncthing: added nanoclaw-main-sessions and nanoclaw-trading-sessions folders
- Dev workflow: updated copy command to include db.ts, index.ts, task-scheduler.ts
- New customizations: qwibitai#6 SESSION_GROUP isolation, qwibitai#7 CLAUDE_MODEL

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
carstenf pushed a commit to carstenf/nanoclaw that referenced this pull request Apr 20, 2026
…ASR upgrade

Urgent insertion after Phase 05 Plan 05-03 Task 5 live verification surfaced
3 unfixable-in-wave defects: qwibitai#4 retry-args, qwibitai#5 attempt_no hardcoded, qwibitai#6
persona handoff broken after amd_result=human. See 05-03-TASK5-DEFECTS.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
carstenf pushed a commit to carstenf/nanoclaw that referenced this pull request Apr 21, 2026
… missing in sideband.ts

Adds 5 new failing tests covering defect qwibitai#6 Layer 1 root cause:
- Test A: session.update MUST include session.type='realtime'
- Test B: extraSession merges with type:'realtime' preserving both
- Test C: regression guard — no session.update ever lacks session.type
- Test D: WS error event logs session_update_rejected with code/message/param/event_id
- Test E: non-error WS messages do NOT trigger session_update_rejected (negative control)

RED status: 4 tests fail (A, B, C, D) because sideband.ts:619 omits session.type
and the WS onmessage handler has no 'error' case. Test E passes trivially (acceptable
negative control — the handler is absent so no spurious log.error calls occur).

Defect root cause per RESEARCH §2.4: OpenAI Realtime GA 2026 rejects session.update
without session.type='realtime' with invalid_request_error, causing the post-AMD
CASE2_OUTBOUND_PERSONA swap to silently fail (Plan 05-03 Task 5 live defect).
carstenf pushed a commit to carstenf/nanoclaw that referenced this pull request Apr 21, 2026
…n sideband.ts (defect qwibitai#6 L1 + Pitfall 2)

Layer-1 fix: add type:'realtime' discriminator to session.update payload at
sideband.ts:619. OpenAI Realtime GA 2026 requires this field on every session.update.
Placed FIRST in the object literal so extraSession spread can still override
if a future caller explicitly needs a 'transcription' session (no production
caller currently does). See 05.1-RESEARCH.md §2.4 + §6.1.

Observability (Pitfall 2): add explicit 'error' case to the WS onmessage
handler. Logs event='session_update_rejected' at ERROR level with code,
message, param, error_type, openai_event_id. This closes the observability
gap that let defect qwibitai#6 remain invisible during Plan 05-03 Task 5 live calls.
Explicit return after log matches existing handler conventions.

All Wave 3 prior work preserved (amd-classifier.ts, persona.ts, pre-greet.ts,
cost-farewell path — unchanged). Full voice-bridge suite: 365 passed /
4 skipped. Sideband tests: 28/28 pass. TypeScript strict build clean.

Closes defect qwibitai#6 Layer 1 (persona-swap silent failure). Layer 2 (synthetic
user-directive injection in webhook.ts onHuman) follows in Task 3.
carstenf pushed a commit to carstenf/nanoclaw that referenced this pull request Apr 21, 2026
…on in onHuman (breaks AMD context contamination)

Layer-2 defense-in-depth for defect qwibitai#6: between updateInstructions(persona) and
setTimeout→requestResponse in webhook.ts onHuman closure, inject a
conversation.item.create with role=user containing a bracketed system-hint
directive. This breaks the conversational context the model inherited from
CASE2_AMD_CLASSIFIER_PROMPT so it cannot mis-read the callee's opening
greeting ('Restaurant Bellavista') as evidence it should continue in
AMD-helper mode.

Text verbatim per RESEARCH §2.5 with ASCII umlauts (Phase 2 CASE6B_PERSONA
convention): 'Beginne bitte mit der Begruessung gemaess deiner neuen
Anweisungen'. Hardcoded literal, not derived from counterpart input —
safe under T-05.1-01-04 (counterpart cannot prompt-inject).

Pitfall 5: conversation.item.create does NOT itself trigger a response.create
(VAD only scopes audio-derived items). The explicit setTimeout→requestResponse
is preserved unchanged.

Tests added (RED before, GREEN after this commit):
- Test F: asserts send order session.update → conversation.item.create →
  (after GREET_TRIGGER_DELAY_OUTBOUND_MS) response.create
- Test G: asserts verbatim directive text with ASCII umlauts, no unicode
- Test H (regression, inside F): persona-swap trigger from Wave 3 still fires

Also adds dispatch.getAmdClassifier() test-only accessor so the tests can
drive classifier.onAmdResult('human') end-to-end through the /accept flow.

Full voice-bridge suite: 367 passed / 4 skipped. Build clean. Both defect qwibitai#6
layers now shipped (L1 session.type discriminator, L2 synthetic directive).
carstenf pushed a commit to carstenf/nanoclaw that referenced this pull request Apr 21, 2026
…ign plan

SUMMARY records:
- Layer 1 fix: session.type='realtime' at sideband layer (sideband.ts:619)
- Layer 1 observability: session_update_rejected error-event handler (Pitfall 2)
- Layer 2 defense-in-depth: synthetic conversation.item.create in onHuman (webhook.ts)
- Test-only accessor: dispatch.getAmdClassifier() for end-to-end onHuman assertion
- 7 new tests (A-E sideband + F,G accept); 367/367 passed, TypeScript strict clean
- Wave 3 preserved: amd-classifier.ts, persona.ts, VAD thresholds, §201 audit invariant
- Risk A1 live verification deferred to Plan 05.1-05 Scenario HAPPY

Three atomic commits landed: 88df156 (RED), 8012c06 (L1 GREEN), 838c451 (L2 GREEN).
NV-xiaoyongs pushed a commit to NV-xiaoyongs/nanoclaw that referenced this pull request Apr 22, 2026
Dashboard sends decision="Approve" (capital A) but the response handler
compared against lowercase 'approve'. Every approval was silently treated
as a rejection.

Co-authored-by: haaggarwal <haaggarwal@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@alecburrett alecburrett mentioned this pull request Apr 23, 2026
carstenf pushed a commit to carstenf/nanoclaw that referenced this pull request Apr 24, 2026
…ocked

All 4 D-4 questions answered at HIGH confidence from OpenAI docs verbatim.
Checkpoint auto-approved (workflow.auto_advance=true).

Deliverable: idle-timeout-finding.md (368 lines) — read_first for Plans 05.3-05a/05b.

Locked decisions for Wave 4:
- SESSION_CONFIG.audio.input.turn_detection.idle_timeout_ms = 8000 (env-clamped 5000..30000)
- silence-monitor.ts verdict: SHRINK-TO-HARD-SAFETY-STUB (~30 LOC; or full-delete if cost/gate.ts
  catatonic-call coverage confirmed in 05.3-05b audit)
- sideband.ts: single new handler for input_audio_buffer.timeout_triggered (~10 LOC)
- §201 StGB zero-audio-leak invariant preserved under native-idle-timeout path
- GREET_TRIGGER_DELAY_MS (1000ms) stays Pattern B (sync requestResponse) — API min 5000ms
  disallows idle_timeout replacement for initial greet

Empirical probe skipped — docs (developers.openai.com server-events reference) sufficed.
Probe fallback pattern documented in finding §"Open caveats qwibitai#6" if later reviewers disagree.
carstenf pushed a commit to carstenf/nanoclaw that referenced this pull request Apr 24, 2026
…13 Plan-XX refs)

- Aggressive sweep: 79 inline Plan-XX breadcrumbs reduced to 13 invariant-
  anchor refs across 18 voice-bridge/src/*.ts files.
- Far exceeds ROADMAP success criterion qwibitai#6 (≤30).
- 13 retained anchors map 1:1 to CONTEXT D-5 retention criteria a-f
  (§201 zero-audio-leak, D-8 wait-for-speech, event-driver contracts, AMD
  VAD-fallback, idempotency-key contract, atomic session.update Q7).
- webhook.ts setTimeout-adjacent 05.3-05a blocks left byte-identical per
  PLAN STEP 3 scope-boundary.
- Zero runtime changes; tsc clean; vitest 42 files / 431 passed / 5 skipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
carstenf pushed a commit to carstenf/nanoclaw that referenced this pull request Apr 24, 2026
- 7/8 PASS: qwibitai#2 setTimeout, qwibitai#3 idle_timeout_ms, qwibitai#4 CASE6B_PERSONA gone, qwibitai#5 tsc strict, qwibitai#6 Plan-XX refs (13 ≤ 30), qwibitai#7 suite green + D-6 byte-identical, qwibitai#8 finding file
- 1 PARTIAL: #1 LOC delta — CONTEXT baseline 7021 measure shows -274 (LOC INCREASED), but git pre-plan baseline (7529) shows +234 reduction (78% of 300 target). CONTEXT baseline was captured pre-Phase-05.2-final-merge; cross-check is the honest measurement.
- D-6 evidence: accept.test.ts:285-311 byte-identical pre/post phase
- §201 invariant tests green (audio-guard + ghost-scan + amd-classifier 3/3 files / 25 tests)
- Plan 05.2-03 D-8 invariant test green (sideband-wait-for-speech 4/4)
- silence-monitor.ts: 227 LOC VAD ladder → 49 LOC hard-safety stub (-176 LOC, biggest delta)
- persona.ts: -86 LOC (CASE6B_PERSONA deleted, dead exports retired)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
carstenf pushed a commit to carstenf/nanoclaw that referenced this pull request Apr 25, 2026
…4 warnings

Plan-checker revision round 2 fixes for Phase 05.6:

BLOCKER #1 — REQ-DIR-17 real NanoClaw-side gateway (Plan 06-01):
- Added Task 4 to Plan 06-01: ships src/voice-mid-call-gateway.ts +
  src/voice-mid-call-gateway.test.ts. Module exports checkMidCallMutation,
  registerActiveCall, deregisterActiveCall, isCallActive. Active-call
  set lifecycle bound to voice_triggers_init (register on entry) and
  voice-finalize-call-cost (deregister on completion).
- Modified ToolRegistry in src/mcp-tools/index.ts to be metadata-aware:
  register(name, handler, meta) accepts { mutating: true } and the
  invoke() dispatch path calls checkMidCallMutation BEFORE the handler
  runs. Mutating tools registered with { mutating: true } at registration
  time. 11 mutating tools enumerated.
- Updated must_haves.truths in Plan 06-01 to reflect 3-tier defense
  (agent prompt + dispatch gateway + handler-boundary sentinel) and the
  active-call set lifecycle.
- Updated success_criteria + frontmatter (files_modified, artifacts,
  key_links) to add the new gateway module + its integration points.

BLOCKER qwibitai#2 — FAIL-recovery wording (Plan 06-02 + 06-03):
- Plan 06-02 <objective> now contains an explicit FAIL-recovery policy:
  diagnose, land fix in separate plan/hot-patch (NOT in 05.6 plans),
  re-run synthetic smoke, re-execute failed step from beginning,
  three-strike escalation to ASK FOR CHAT. Policy applied to Task 2
  (synth FAIL), Task 4 (inbound FAIL), Task 6 (outbound FAIL). §201
  BREACH does NOT follow generic recovery — audit-level investigation
  required.
- Plan 06-03 Task 3 already had `git revert HEAD` recovery; now also
  notes the runtime-ENV revert window REOPENS after revert.

WARNING qwibitai#3 — Runtime-revert truth qualification (Plan 06-03):
- must_haves.truth qualified to "Step 1→Step 2 ONLY; after Step 2 the
  emergency revert path becomes `git revert <Step-2-cleanup-SHA>` per
  D-30." Same qualification added to <objective>, the Step 1 commit
  message, the Step 2 commit message, success_criteria, and the
  briefing template.

WARNING qwibitai#4 — Wrong WireGuard IP (Plan 06-02 + 06-03):
- Replaced hardcoded http://10.0.0.2:3201/ with http://127.0.0.1:3201/
  in: Plan 06-02 Task 1 step 2 (.env append + curl /health verification);
  Plan 06-03 Task 2 step 7 (.env.example update); the briefing template
  in Plan 06-03 Task 5; verification + acceptance_criteria across both
  plans. NanoClaw + voice-bridge are co-located on Lenovo1 per
  /opt/server-docs/MASTER.md + project_nanoclaw_infra memory — local
  loopback. 10.0.0.x is the WireGuard subnet, not a NanoClaw transport
  address. Both plans now also instruct: if container deploy changes
  the host, ASK Carsten for the lenovo1-internal address — do NOT
  guess; do NOT use 10.0.0.x.

WARNING qwibitai#5 — §201 audio-leak jq query (Plan 06-02):
- Aligned the jq selector with tracing-contract.md: contract specifies
  `delta` is STRIPPED and replaced with `delta_bytes` integer. Task 4
  step 4 now (a) verifies every response.audio.delta event has
  delta_bytes integer (redaction integrity), AND (b) asserts no
  response.audio.delta event retains a non-empty .delta payload (BREACH
  on any leak). Same query applied in Task 6 step 3 for the outbound
  trace.

WARNING qwibitai#6 — Du/Sie negative check missing (Plan 06-02):
- Task 4 step 6 (inbound, Du-axis) and Task 6 step 3.d (outbound,
  Sie-axis) now BOTH run a negative check: PLACEHOLDER_LEAK=$(jq -r
  '...instructions...' | grep -c '{{[a-z_]\+}}'); test
  "$PLACEHOLDER_LEAK" -eq 0 — BREACH on any unsubstituted {{...}}
  token. Positive Du/Sie token check stays as before; negative
  placeholder-leak check added on top.

Files modified:
- .planning/phases/05.6-container-agent-integration-cutover/05.6-01-PLAN.md
- .planning/phases/05.6-container-agent-integration-cutover/05.6-02-PLAN.md
- .planning/phases/05.6-container-agent-integration-cutover/05.6-03-PLAN.md

Phase scope unchanged — fixes are corrective, not additive scope. The
new src/voice-mid-call-gateway.ts file is NEW SOURCE CODE that the
executor (later /gsd-execute-phase) writes; the planner only updates
the PLAN.md task spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jmcstone added a commit to jmcstone/nanoclaw that referenced this pull request Apr 25, 2026
…sona refresh

- lode/architecture/madison-pipeline.md (NEW): mirror data model (RFC-822
  identity, message_labels, message_folder_uids, label_catalog, label_map),
  session-hash invalidation pattern, hydration phases + self-audit invariants,
  live migration results, Mermaid data-flow diagram, locked Decisions table
  summary. Graduate of findings.md 2026-04-22 design session.

- lode/infrastructure/mailroom-mirror.md (NEW): Gmail history.list incremental
  sync + 404 recovery, Proton IMAP IDLE + CONDSTORE MODSEQ polling, nightly
  reconcile two-phase correctness, migration orchestrator + dry-run, startup
  wiring diagram (Mermaid), apply-path diagram (Mermaid), operational notes
  (env-vault, both-containers rebuild, btrfs snapshots).

- lode/infrastructure/mailroom-rules.md: add explicit env-vault prefix
  requirement section with correct command; links to lessons.md incident.

- lode/practices.md: add Mailroom deploy checklist (10-step), Counter-note
  pattern (AC-P3), Cross-workstream API contracts pointer, Migration self-audit
  pointer.

- lode/lode-map.md: add Architecture section entry for madison-pipeline.md;
  add mailroom-mirror.md entry under Infrastructure.

- lode/summary.md: extend email pipeline description to mention full upstream
  mirror + sync worker; link new lode files.

- lode/plans/active/2026-04-madison-read-power/findings.md: add Graduated
  content pointer section noting what moved to which lode files; diagnostic
  record retained as historical context.

Madison CLAUDE.md updated directly (outside git repo):
- Added mcp__inbox__query section: signature, 5 example patterns with tool
  calls, when to use query vs search/recent/thread.
- Documented default filter behavior (direction=received + deleted_at IS NULL;
  include_sent/include_deleted opt-outs; thread direction-agnostic).
- Added session-stale instruction (stop + acknowledge + ask Jeff to clear
  session + resume fresh; manual sqlite3 command included).
- Extended Truthful action reporting with verify-before-quoting-a-mem rule
  (rule qwibitai#6; cite date when quoting; "verify before acting" hedge pattern).
- Added query tool to Tools section.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants