@senpi/runtime 3.0.9-dev.feat-strategy-compos.20260722213012 → 3.0.9-dev.feat-strategy-compos.20260723050017

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.
@@ -37,22 +37,28 @@ anything.
37
37
 
38
38
  from __future__ import annotations
39
39
 
40
+ import json
40
41
  from dataclasses import dataclass, field
41
42
  from pathlib import Path
42
43
  from typing import Callable, Optional
43
44
 
44
45
  from . import _box
45
46
  from ._box import McpFn, default_mcp_call
46
- from ._layout import canonical_graph_path
47
+ from ._layout import ARCHIVES_DIR, canonical_graph_path
47
48
  from ._live import LiveState
49
+ from ._target import TargetError
48
50
  from .portfolio import _effective_install, _resolve_wallet, enumerate_strategies
49
51
  from .status import run_status
52
+ from composer.validator.errors import Location, TeachingError
50
53
 
51
54
  # The named sources every figure is attributed to (printed so an operator always knows the producer).
52
55
  SRC_HISTORY = "backend trade history" # discovery_get_trader_history (onchain closed ledger)
53
56
  SRC_EVENTS = "box event log" # the runtime's on-disk event ring (dsl/position/order/…)
54
57
 
55
58
  CLOSED_HISTORY_PULL = 100 # closed positions to pull per wallet (review.py parity)
59
+ EVENTS_PULL = 500 # recent-ring window per runtime (review.py's `-l 500`;
60
+ # mirrors composer-live-read.ts EVENTS_PULL_DEFAULT so the
61
+ # ARCHIVED cold path enriches over the SAME depth as live)
56
62
 
57
63
  # EXIT attribution — the exit events a closed trade is matched against (references/event-log.md shapes).
58
64
  _EXIT_EVENT_NAMES = ("dsl.closed", "position.closed")
@@ -722,3 +728,276 @@ def run_review(
722
728
  result.strategies.append(
723
729
  _review_one(str(state_dir), strategy, runtime_id, wallet, history_fn, events_section))
724
730
  return result
731
+
732
+
733
+ # =========================================================================== K7: ARCHIVED cold path
734
+ #
735
+ # The live review reads the HOT event ring served in-process by the rim (no cold-boot subprocess).
736
+ # But `runtime delete` (close / update teardown) ARCHIVES the whole per-runtime state dir to
737
+ # `<base>/archives/<runtimeId>-<wallet>-<ts>/` (src/runtime/state-layout.ts::archiveStateDir), moving
738
+ # the on-disk event ring with it (`<archive>/strategies/<wallet>/events/events.jsonl` +
739
+ # `events.1.jsonl`, src/telemetry/event-store.ts). A CLOSED / torn-down strategy's exit-attribution
740
+ # data SURVIVES teardown — it is just no longer on the live rim. So `composer review --archived
741
+ # <wallet|runtime>` does an OFFLINE FILE READ of that archived ring (NOT a subprocess, NOT a cold
742
+ # boot — the sanctioned exception the module header carves out) and feeds the rows through the SAME
743
+ # enrichment/render the live path uses. Dev-test #7 F3: the model called a closed strategy's exits
744
+ # "unknowable (event ring gone)" while the ground-truth DSL trail sat in the archive — this reaches it.
745
+
746
+
747
+ def _parse_archive_dir_name(name: str) -> Optional[tuple[str, str, int]]:
748
+ """Parse an archive dir name ``<runtimeId>-<wallet>-<ts>`` into ``(runtimeId, wallet, ts_ms)``.
749
+ Mirrors TS ``listArchives`` (state-layout.ts): the trailing token is the epoch-ms timestamp, the
750
+ token before it is the wallet (0x… — no dashes), and everything before that is the runtime id
751
+ (which DOES carry dashes, e.g. ``<strategy>-<hash8>``). None when the name doesn't fit / no ts."""
752
+ parts = name.rsplit("-", 2)
753
+ if len(parts) < 3:
754
+ return None
755
+ runtime_id, wallet, ts_str = parts[0], parts[1], parts[2]
756
+ if not runtime_id or not wallet:
757
+ return None
758
+ try:
759
+ ts = int(ts_str)
760
+ except ValueError:
761
+ return None
762
+ if ts <= 0:
763
+ return None
764
+ return runtime_id, wallet, ts
765
+
766
+
767
+ def _archives_root(base_state_dir: str) -> Path:
768
+ return Path(base_state_dir) / ARCHIVES_DIR
769
+
770
+
771
+ def _list_archive_dirs(base_state_dir: str) -> list[tuple[str, str, str, int, Path]]:
772
+ """Every parseable archive under ``<base>/archives`` as ``(name, runtimeId, wallet, ts, path)``,
773
+ newest ts first. Unparseable / non-dir entries are skipped (they are not composer's shape)."""
774
+ root = _archives_root(base_state_dir)
775
+ if not root.is_dir():
776
+ return []
777
+ out: list[tuple[str, str, str, int, Path]] = []
778
+ for child in sorted(root.iterdir()):
779
+ if not child.is_dir():
780
+ continue
781
+ parsed = _parse_archive_dir_name(child.name)
782
+ if parsed is None:
783
+ continue
784
+ runtime_id, wallet, ts = parsed
785
+ out.append((child.name, runtime_id, wallet, ts, child))
786
+ out.sort(key=lambda t: t[3], reverse=True)
787
+ return out
788
+
789
+
790
+ def _resolve_archive(base_state_dir: str, target: str) -> tuple[str, str, int, Path]:
791
+ """Resolve the NEWEST archive dir matching ``target`` (a wallet OR a runtime id OR a substring of
792
+ the dir name). Returns ``(runtimeId, wallet, ts, path)``. Fail-loud: raises :class:`TargetError`
793
+ (CMP256 — the existing "target could not be resolved" class, reused per the _target.py precedent)
794
+ ENUMERATING the archive dirs that DO exist, mirroring ``_target.available_strategies_hint``."""
795
+ archives = _list_archive_dirs(base_state_dir)
796
+ tl = target.strip().lower()
797
+ matches = [
798
+ a for a in archives
799
+ if a[2].lower() == tl # wallet (case-insensitive)
800
+ or a[1] == target.strip() # runtime id (exact)
801
+ or tl in a[0].lower() # substring of the dir name (strategy-name / partial)
802
+ ]
803
+ if matches:
804
+ best = matches[0] # already newest-first
805
+ _name, runtime_id, wallet, ts, path = best
806
+ return runtime_id, wallet, ts, path
807
+
808
+ root = _archives_root(base_state_dir)
809
+ if archives:
810
+ shown = ", ".join(a[0] for a in archives[:20]) + (", …" if len(archives) > 20 else "")
811
+ hint = (f"Archive dirs under {root} (newest first): {shown}. Pass a wallet (0x…) or a "
812
+ f"runtime id that appears in one of those names.")
813
+ else:
814
+ hint = (f"No archived runtime state dirs exist under {root} — nothing has been closed / "
815
+ f"torn down on this box (archives are written by `runtime delete`, i.e. `composer "
816
+ f"close` / `composer update`). For a LIVE strategy, run `composer review <strategy>` "
817
+ f"(no --archived).")
818
+ raise TargetError(TeachingError(
819
+ "CMP256",
820
+ f"no archived event ring matched {target!r} under {root} — it is not the wallet or runtime "
821
+ f"id of any archived (closed / torn-down) runtime on this box.",
822
+ hint,
823
+ Location(),
824
+ ))
825
+
826
+
827
+ def _find_archived_events_dir(archive_dir: Path, wallet: str) -> Optional[Path]:
828
+ """The events dir inside an archive: ``<archive>/strategies/<wallet>/events`` (the on-disk ring
829
+ layout, event-store.ts::eventsDir, keyed by the LOWERCASED wallet). Falls back to the first
830
+ ``strategies/*/events`` dir if the exact lowercased wallet subdir isn't there (a case/normalize
831
+ drift). None when the archive carries no events tree at all."""
832
+ strategies = archive_dir / "strategies"
833
+ if not strategies.is_dir():
834
+ return None
835
+ exact = strategies / wallet.strip().lower() / "events"
836
+ if exact.is_dir():
837
+ return exact
838
+ for sub in sorted(strategies.iterdir()):
839
+ ev = sub / "events"
840
+ if sub.is_dir() and ev.is_dir():
841
+ return ev
842
+ return None
843
+
844
+
845
+ def _read_archived_ring(events_dir: Optional[Path]) -> tuple[list[dict], int]:
846
+ """Read the archived 2-file ring OFFLINE: ``events.1.jsonl`` (older rotation) THEN ``events.jsonl``
847
+ (newer), chronological — the SAME order the runtime's ``readEvents`` uses. Each line is one JSONL
848
+ row (``{ts,name,body,level,attrs}``). Corrupt / non-dict rows are SKIPPED and COUNTED (never a
849
+ crash, never silently dropped). Applies the ``EVENTS_PULL`` recency cap (newest tail by ts).
850
+ Returns ``(rows, skipped_count)``; rows is ``[]`` for a genuinely empty / absent ring."""
851
+ rows: list[dict] = []
852
+ skipped = 0
853
+ if events_dir is None:
854
+ return rows, skipped
855
+ for fname in ("events.1.jsonl", "events.jsonl"): # archive (older) then current (newer)
856
+ fpath = events_dir / fname
857
+ if not fpath.is_file():
858
+ continue
859
+ try:
860
+ text = fpath.read_text(encoding="utf-8")
861
+ except OSError:
862
+ continue
863
+ for line in text.splitlines():
864
+ if not line.strip():
865
+ continue
866
+ try:
867
+ obj = json.loads(line)
868
+ except (json.JSONDecodeError, ValueError):
869
+ skipped += 1 # a torn / partial JSONL row — count, skip
870
+ continue
871
+ if isinstance(obj, dict):
872
+ rows.append(obj)
873
+ else:
874
+ skipped += 1 # a well-formed-but-non-object row
875
+ # Recency cap (EVENTS_PULL) — keep the newest tail by ts, matching the live per-runtime pull.
876
+ if len(rows) > EVENTS_PULL:
877
+ rows.sort(key=lambda r: _num(r.get("ts")) or 0)
878
+ rows = rows[-EVENTS_PULL:]
879
+ return rows, skipped
880
+
881
+
882
+ @dataclass
883
+ class ArchivedReviewResult:
884
+ """A CLOSED / torn-down strategy's retrospective review, read from its ARCHIVED on-disk event ring
885
+ (K7). Wraps ONE :class:`StrategyReview` (built through the SAME enrichment/render as live) with the
886
+ archive provenance banner: which archive dir, when it was archived, the runtime id, and the ring's
887
+ read/skip counts. Exit reasons + leaks come from the archived ring; realized PnL / win rate from the
888
+ backend trade history (wired from the wallet parsed out of the archive name)."""
889
+
890
+ base_state_dir: str
891
+ target: str
892
+ archive_name: str
893
+ archive_dir: str
894
+ archive_ts: int
895
+ runtime_id: str
896
+ wallet: str
897
+ strategy: str
898
+ review: StrategyReview
899
+ events_total: int = 0
900
+ rows_skipped: int = 0
901
+
902
+ @property
903
+ def ring_empty(self) -> bool:
904
+ return self.events_total == 0
905
+
906
+ def _archived_at(self) -> str:
907
+ """The archive timestamp as an ISO-8601 UTC string (the ts is epoch MILLISECONDS)."""
908
+ import datetime as _dt
909
+ try:
910
+ return _dt.datetime.fromtimestamp(self.archive_ts / 1000.0,
911
+ tz=_dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
912
+ except (OverflowError, OSError, ValueError):
913
+ return "unknown"
914
+
915
+ def to_json(self) -> dict:
916
+ return {
917
+ "verb": "review",
918
+ "scope": "archived",
919
+ "state_dir": self.base_state_dir,
920
+ "target": self.target,
921
+ "archived": {
922
+ "archive_name": self.archive_name,
923
+ "archive_dir": self.archive_dir,
924
+ "archived_at_ms": self.archive_ts,
925
+ "archived_at": self._archived_at(),
926
+ "runtime_id": self.runtime_id,
927
+ "wallet": self.wallet,
928
+ "strategy": self.strategy,
929
+ "ring_events_read": self.events_total,
930
+ "ring_rows_skipped": self.rows_skipped,
931
+ "ring_empty": self.ring_empty,
932
+ },
933
+ "sources": {"history": SRC_HISTORY, "events": f"{SRC_EVENTS} (ARCHIVED)"},
934
+ "strategy": self.review.to_json(),
935
+ }
936
+
937
+ def render(self) -> str:
938
+ lines = [
939
+ f"trade review — ARCHIVED (state: {self.base_state_dir})",
940
+ f"reading the NEWEST archived event ring for target {self.target!r}: this strategy is "
941
+ f"CLOSED / torn down — its live runtime + event ring were ARCHIVED on `runtime delete` "
942
+ f"(`composer close` / `composer update`). Exit reasons + leaks below are from that "
943
+ f"archived ring [{SRC_EVENTS}]; realized PnL + win rate from {SRC_HISTORY}.",
944
+ f" archive : {self.archive_name} (archived {self._archived_at()})",
945
+ f" archive dir: {self.archive_dir}",
946
+ f" runtime : {self.runtime_id}",
947
+ ]
948
+ if self.ring_empty:
949
+ lines.append(" ring : archived ring is empty — no events were recorded "
950
+ "(the ring WAS read; it simply held nothing — this is not an "
951
+ "unavailable/undetermined telemetry state)")
952
+ else:
953
+ skip = f" [{self.rows_skipped} unreadable row(s) skipped]" if self.rows_skipped else ""
954
+ lines.append(f" ring : {self.events_total} event(s) read from the archived "
955
+ f"ring{skip} [{SRC_EVENTS} (ARCHIVED)]")
956
+ lines.append("")
957
+ lines.append("strategy (closed / torn down):")
958
+ lines.extend(self.review.render())
959
+ return "\n".join(lines) + "\n"
960
+
961
+
962
+ def run_archived_review(
963
+ base_state_dir: str,
964
+ target: str,
965
+ *,
966
+ history_fn: HistoryFn = default_closed_history,
967
+ ) -> ArchivedReviewResult:
968
+ """`composer review --archived <wallet|runtime>` — review a CLOSED / torn-down strategy from its
969
+ ARCHIVED on-disk event ring (K7). Resolves the NEWEST archive dir under ``<base>/archives`` matching
970
+ the target (wallet / runtime id / dir-name substring; :class:`TargetError` CMP256 enumerating what
971
+ DOES exist when nothing matches), reads the archived ring OFFLINE (``events.1.jsonl`` then
972
+ ``events.jsonl``, EVENTS_PULL-capped, corrupt rows skipped + counted), and feeds the rows through
973
+ the SAME exit-reason enrichment + leak scan + render the LIVE path uses — banner-labelled ARCHIVED.
974
+ Closed-trade history is wired from the wallet parsed out of the archive name (an honest "unavailable
975
+ (reason)" degrades that side only). Never a subprocess, never a cold boot — a sanctioned file read."""
976
+ runtime_id, wallet, ts, archive_dir = _resolve_archive(base_state_dir, target)
977
+
978
+ events_dir = _find_archived_events_dir(archive_dir, wallet)
979
+ rows, skipped = _read_archived_ring(events_dir)
980
+
981
+ # Derive the strategy NAME from the runtime id (``<strategy>-<hash8>``) so the render labels it and
982
+ # a still-present composer/<strategy>/graph.yaml thesis is quoted (torn-down runtime, but the
983
+ # composer record graph often survives). Falls back to the raw runtime id when there is no dash.
984
+ strategy = runtime_id.rsplit("-", 1)[0] if "-" in runtime_id else runtime_id
985
+
986
+ # Feed the archived rows through the SAME machinery as live by presenting them as the resolved
987
+ # runtime's slice of an events section — _review_one + StrategyReview.render() are reused verbatim.
988
+ events_section = {"ok": True, "by_runtime": {runtime_id: rows}}
989
+ sr = _review_one(base_state_dir, strategy, runtime_id, wallet, history_fn, events_section)
990
+
991
+ return ArchivedReviewResult(
992
+ base_state_dir=str(Path(base_state_dir)),
993
+ target=target,
994
+ archive_name=archive_dir.name,
995
+ archive_dir=str(archive_dir),
996
+ archive_ts=ts,
997
+ runtime_id=runtime_id,
998
+ wallet=wallet,
999
+ strategy=strategy,
1000
+ review=sr,
1001
+ events_total=len(rows),
1002
+ rows_skipped=skipped,
1003
+ )
@@ -78,8 +78,27 @@ from ._layout import (
78
78
  resolve_wallet_json,
79
79
  runtime_state_dir,
80
80
  )
81
+ from ._target import TargetError, available_strategies_hint
81
82
  from .check import run_check
82
83
  from .install import INSTALL_JSON, REGISTRY_FILENAME, compute_hash8
84
+ from composer.validator.errors import Location, TeachingError
85
+
86
+
87
+ def _status_read(path: Path, base_state_dir=None) -> str:
88
+ """Read a user-supplied status target, wrapping any OSError (a permissions/IO fault, a vanished
89
+ file) as a CMP256 teaching error instead of letting a raw ``[Errno N]`` escape to the backstop
90
+ (K4). ``status`` shares the graph verbs' target vocabulary — a read fault teaches the same way."""
91
+ try:
92
+ return path.read_text(encoding="utf-8")
93
+ except OSError as exc:
94
+ detail = exc.strerror or str(exc)
95
+ raise TargetError(TeachingError(
96
+ "CMP256",
97
+ f"the status target {str(path)!r} could not be read: {detail}.",
98
+ "Pass the path to an existing, readable graph .yaml, a strategy directory, or a strategy "
99
+ "name. " + available_strategies_hint(base_state_dir),
100
+ Location(),
101
+ )) from exc
83
102
 
84
103
  ABSENT = "absent"
85
104
  INVALID = "invalid"
@@ -429,7 +448,7 @@ def _resolve(target, out_dir, base_state_dir=None) -> tuple[Optional[str], str,
429
448
  if p.is_dir():
430
449
  manifest = p / "manifest.json"
431
450
  if manifest.is_file():
432
- man = json.loads(manifest.read_text(encoding="utf-8"))
451
+ man = json.loads(_status_read(manifest, base_state_dir))
433
452
  strategy = str(man.get("strategy", p.name))
434
453
  # G8b: the top-level graph SNAPSHOT is the record; fall back to the in-unit copy, then
435
454
  # the flat legacy location for older stagings.
@@ -439,7 +458,7 @@ def _resolve(target, out_dir, base_state_dir=None) -> tuple[Optional[str], str,
439
458
  if c.is_file()),
440
459
  p / "main" / graph_name,
441
460
  )
442
- text = gpath.read_text(encoding="utf-8") if gpath.is_file() else None
461
+ text = _status_read(gpath, base_state_dir) if gpath.is_file() else None
443
462
  return text, str(gpath if gpath.is_file() else p), p, strategy
444
463
  return None, str(p), None, p.name
445
464
  if not p.is_file():
@@ -449,11 +468,11 @@ def _resolve(target, out_dir, base_state_dir=None) -> tuple[Optional[str], str,
449
468
  cstaged = canonical_staged_dir(base_state_dir, target)
450
469
  staged = cstaged if (cstaged / "manifest.json").is_file() else None
451
470
  if cgraph.is_file():
452
- return cgraph.read_text(encoding="utf-8"), str(cgraph), staged, target
471
+ return _status_read(cgraph, base_state_dir), str(cgraph), staged, target
453
472
  if staged is not None:
454
473
  return None, str(cgraph), staged, target
455
474
  return None, str(p), None, p.name.replace(".graph.yaml", "")
456
- text = p.read_text(encoding="utf-8")
475
+ text = _status_read(p, base_state_dir)
457
476
  strategy = _strategy_name(text, p.stem)
458
477
  staged = None
459
478
  if out_dir is not None:
@@ -687,7 +706,9 @@ def _build_manual_status(label: str, strategy: str, state_dir: Path,
687
706
  if wj_path is not None:
688
707
  try:
689
708
  rec = json.loads(wj_path.read_text(encoding="utf-8"))
690
- wallet = str(rec.get("wallet")) if rec.get("wallet") else None
709
+ # K3 follow-up: tolerant address read (hand-authored markers use the MCP key spellings).
710
+ from .fund import _rec_wallet
711
+ wallet = _rec_wallet(rec) or None
691
712
  strategy_id = rec.get("strategyId")
692
713
  except (OSError, json.JSONDecodeError):
693
714
  pass
@@ -70,7 +70,7 @@ from ._layout import (
70
70
  )
71
71
  from ._unit_diff import UnitDiff, diff_unit_dirs
72
72
  from .check import render_unit_summary
73
- from .fund import _read_wallet_json
73
+ from .fund import _read_wallet_json, _rec_wallet
74
74
  from .install import (
75
75
  ALREADY_INSTALLED,
76
76
  INSTALL_JSON,
@@ -368,11 +368,15 @@ def run_update(
368
368
  # corrupt staging can never strand a live wallet.
369
369
  staged = _resolve_staged(target, out_dir, base_state_dir)
370
370
  if staged is None:
371
+ # K4: share the graph verbs' target vocabulary — a target that resolves to nothing names the
372
+ # strategies that DO exist under the state root, so the model corrects to a real one.
373
+ from ._target import available_strategies_hint
371
374
  return _refused(target, TeachingError(
372
375
  "CMP200", "the update target is not a staged unit (no manifest.json found).",
373
376
  "Point `composer update` at a `composer deploy` staging dir (the one containing "
374
- "manifest.json + main/), or pass the graph file plus `-o <staging-dir>`. Run "
375
- "`composer deploy <graph> -o <dir>` first.",
377
+ "manifest.json + main/), a graph file plus `-o <staging-dir>`, or a strategy NAME whose "
378
+ "canonical staged/ exists. Run `composer deploy <graph>` first. "
379
+ + available_strategies_hint(base_state_dir),
376
380
  Location(),
377
381
  ))
378
382
  try:
@@ -416,7 +420,13 @@ def run_update(
416
420
  if not wallet:
417
421
  wj, _layout = resolve_wallet_json(base_state_dir, strategy)
418
422
  rec = _read_wallet_json(wj) if wj is not None else None
419
- rec_wallet = str((rec or {}).get("wallet") or "").strip()
423
+ # K4 (CMP240 fix): read the wallet ADDRESS with the SAME tolerant reader `composer fund` uses
424
+ # (K3 `_rec_wallet`) — a hand-authored / MCP-shaped / adopt-flow wallet.json records the
425
+ # address under `address` / `walletAddress` / `strategyWalletAddress`, NOT the canonical
426
+ # `wallet` key. Pre-K4 update read `rec.get("wallet")` raw and REFUSED CMP240 on such a
427
+ # marker (dev-test #7: a wallet.json with strategyId + address) though fund/install resolved
428
+ # it fine — the exact fund/update divergence this unifies.
429
+ rec_wallet = _rec_wallet(rec or {}).strip()
420
430
  if not rec_wallet:
421
431
  return _refused(target, TeachingError(
422
432
  "CMP240", f"no wallet to update — `--wallet` was omitted and no funded "
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -36,6 +36,7 @@ import { resolvePackageName } from "./runtime/auto-update/resolve-package-name.j
36
36
  import { runOpenClawPluginsUpdate } from "./runtime/auto-update/run-update-command.js";
37
37
  import { registerSpanHooks } from "./telemetry/spans/index.js";
38
38
  import { registerComposerWriteAnnotationHook } from "./runtime/composer-managed-write.js";
39
+ import { registerNoReplyScopingOverlayHook } from "./runtime/no-reply-scoping-overlay.js";
39
40
  import { initDefaultPiiRedactor } from "./telemetry/spans/redact-pii.js";
40
41
  import { initOtelSdk, shutdownOtelSdk } from "./telemetry/otel-sdk.js";
41
42
  import { getLogLevel, getLogLevelSource, parseLogLevel, setErrorNotifier, setLogLevel, } from "./utils/logger.js";
@@ -333,6 +334,21 @@ const senpiRuntimePlugin = {
333
334
  err: err instanceof Error ? err.message : String(err),
334
335
  });
335
336
  }
337
+ // K9 — NO_REPLY scoping overlay. openclaw core teaches an unscoped "Silent
338
+ // Replies" rule (entire reply = NO_REPLY); a model that considers its
339
+ // tool-side work "already communicated" then goes silent after real work
340
+ // (dev-test #7 F6: silence after a successful composer update). The fleet
341
+ // pins openclaw, so the deployable lever is plugin-side: append a scoping
342
+ // correction to the cached system prompt via before_prompt_build. Additive
343
+ // and defensive — never blocks a turn or takes the plugin down.
344
+ try {
345
+ registerNoReplyScopingOverlayHook({ api, logger: pluginLogger });
346
+ }
347
+ catch (err) {
348
+ pluginLogger.warn("[senpi-runtime] failed to register NO_REPLY scoping overlay hook", {
349
+ err: err instanceof Error ? err.message : String(err),
350
+ });
351
+ }
336
352
  const runtimeHandles = new Map();
337
353
  let apiHandle;
338
354
  // Supervised scanner state — module-scoped so stop() can reach them.