Commit Graph

5 Commits

Author SHA1 Message Date
Teknium 8f1ef66b1f refactor(adapters/p2p_group): 12752->8794; buzz/photon/a2a/raft dedupe (sidecar paths unified in photon package, JSON-RPC helpers, Nostr event builders), dead a2a security getters + stream_message removed 2026-09-02 14:06:36 -07:00
Teknium 6b81590c55 test: prune low-value tests suite-wide (wave 1) — 46,820 → 28,106 test functions
Systematic prune per AGENTS.md test policy, one pass over every major
test tree (gateway, hermes_cli, tools, agent, run_agent, plugins, cli,
cron, tui_gateway, honcho/openviking, root-level):

- DELETE: source-reading tests (read_text/getsource on prod files),
  change-detector tests (exact catalog counts, model-name snapshots,
  config version literals), mock-echo tests (assert a mock returns what
  it was told), assertion-free/trivial tests, near-duplicate
  parametrizations (boundaries + one representative kept), async/sync
  twin duplicates, cosmetic within-file variations.
- KEEP (mandatory): security/redaction/approval guards, message-role
  alternation invariants, prompt-caching/deterministic-call-id
  invariants, issue-number regression tests (deduped), E2E tests.
- 6 test files deleted outright (script-style/no-assert or fully
  redundant); conftest.py, fakes/, fixtures/ untouched.
- tests/acp/conftest.py added: autouse fixture stubs the live
  models.dev/GitHub/Copilot/Anthropic inventory fetches that ACP server
  tests performed on every session create — test_server.py 147s → 3.4s,
  and the tests are now genuinely hermetic.
- Sleep-based slowness shrunk where safe (codex_ttfb_watchdog,
  compression_concurrent_fork, etc.); no wall-clock assertion tightened.

Verification: full hermetic suite via scripts/run_tests.sh —
2439 files, 31,130 tests passed, 0 failed, 0 flaky retries, 315s wall
(baseline: 583s wall, 13,564s subprocess CPU).
2026-07-29 13:10:23 -07:00
Shannon Sands 0dfd5546fc fix(photon): support immutable install trees for the sidecar (NS-606)
The Photon iMessage sidecar needs node_modules under
plugins/platforms/photon/sidecar/, but hosted/managed images keep the
whole install tree under an immutable /opt/hermes — every install and
self-heal path (setup CLI, stale-deps reinstall, cold install) died on
EROFS, and hosted users have no shell to work around it.

Three-layer fix, mirroring the WhatsApp bridge resolver pattern:

1. Bake the deps into the image. The Dockerfile now runs npm ci for the
   sidecar in the layer-cached dependency stage (deterministic installs
   from the committed lockfile; the postinstall spectrum-ts patch runs
   at build time). Hosted happy path needs no runtime install at all.

2. New sidecar_paths.resolve_sidecar_dir() decides where the sidecar
   runs from: PHOTON_SIDECAR_DIR override > writable source dir (dev
   installs, unchanged) > read-only dir with baked fresh deps (managed
   image) > mirror to $HERMES_HOME/photon/sidecar (writable data
   volume) when deps are missing or stale in a read-only tree. The
   mirror refreshes changed source files on image updates while
   keeping node_modules, so the existing lockfile-staleness self-heal
   works there.

3. connect() can now cold-install: _start_sidecar() runs the bounded
   npm ci bootstrap when node_modules is missing instead of raising
   immediately, and check_requirements() reports available when a
   self-install is possible (npm present + writable resolved dir) so
   the gateway actually creates the adapter on hosted instances. A
   failed bootstrap still raises the actionable error, which connect()
   surfaces as the retryable SIDECAR_FAILED fatal state on the
   dashboard.

Tests: resolver decision table (env override, in-place, mirror,
refresh, fail-open), cold-install lifecycle paths, and a Dockerfile
contract test guarding the baked-deps + no-chown invariants.

Fixes NS-606.
2026-07-28 22:41:32 -07:00
joaomarcos 9cf2046081 fix(photon): unify sidecar-deps check, harden log unlink and truncation
Addresses teknium1 review on #50983:

- cli.py's `hermes photon status` and adapter.py's _start_sidecar() still
  used the old node_modules/-existence check while check_requirements()
  had moved to a spectrum-ts content check. Extracted the check into a
  shared sidecar_deps_installed(), used by all three, so an
  empty/partial node_modules/ (aborted npm install) is rejected
  consistently instead of only in check_requirements().
- _install_sidecar()'s success-path _NPM_ERROR_LOG.unlink() only caught
  FileNotFoundError, so a PermissionError/OSError on a locked file would
  propagate. Broadened to OSError.
- npm stderr was truncated only when read back in check_requirements();
  an unbounded stderr was written to disk on every failed install. Now
  truncated to _NPM_ERROR_LOG_MAX_CHARS before write_text().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 18:20:06 -07:00
joaomarcos de5c39c033 fix(photon): surface npm install failures in check_requirements() diagnostic chain
Problema
--------
Quando o npm install do sidecar Photon falhava, o Hermes descartava toda
evidencia e continuava normalmente - deixando o adapter de iMessage
silenciosamente ausente, sem nenhuma mensagem de erro acionavel.

Tres falhas independentes formavam o caminho de falha silenciosa:

1. check_requirements() sem logging
   Cada branch de return False retornava sem emitir nenhum log. O core em
   platform_registry.py so consome o bool de check_fn() e loga uma mensagem
   generica com o install_hint - sem acesso ao motivo real da falha.

     if not HTTPX_AVAILABLE:     return False  # sem log
     if not shutil.which(node):  return False  # sem log
     if not node_modules.exists: return False  # sem log

2. node_modules/ parcialmente criado passava o guard (Risk 2)
   npm cria node_modules/ antes de abortar em ENOSPC, timeout de rede ou
   EACCES. O diretorio existia, check_requirements() retornava True (falso
   positivo), o adapter era registrado, e o crash acontecia em runtime com
   um erro de modulo ausente aparentemente nao relacionado ao setup.

3. stderr do npm descartado (Risk 3)
   subprocess.run sem stderr=PIPE. O output de erro aparecia no terminal
   durante o setup e sumia depois - diagnostico impossivel em CI/CD, Docker,
   VPS headless, e qualquer reinstalacao posterior.

Correcoes
---------
adapter.py - check_requirements() agora loga por branch:
  - httpx ausente       -> logger.warning com nome do pacote
  - node nao no PATH    -> logger.warning com nome do binario e env var
  - spectrum-ts ausente -> logger.debug com path do sidecar + ultimo erro npm
    (DEBUG nao WARNING: estado normal pre-setup; check_fn() e chamado de
    5 hot paths do core incluindo polling do /api/status)

adapter.py - content check em vez de existence check (Risk 2):
  antes:  if not (_SIDECAR_DIR / node_modules).exists()
  depois: if not (_SIDECAR_DIR / node_modules / spectrum-ts).exists()
  spectrum-ts e a unica dependencia do package.json. Checar sua presenca
  garante que instalacao parcial/abortada e detectada no boot do gateway,
  nao na primeira mensagem recebida via gRPC.

cli.py - stderr capturado e persistido (Risk 3):
  subprocess.run passa agora stderr=subprocess.PIPE, text=True em ambas as
  chamadas (npm ci e npm install fallback). O stderr capturado e:
    - impresso em sys.stderr imediatamente (output visivel no terminal)
    - persistido em _NPM_ERROR_LOG = sidecar/.photon-npm-error.log se
      returncode != 0, limitado a 300 chars
    - apagado de _NPM_ERROR_LOG se returncode == 0 (evita erro stale)
  check_requirements() le _NPM_ERROR_LOG quando spectrum-ts esta ausente e
  inclui o conteudo no DEBUG log - o erro do npm sobrevive ao terminal, ao
  restart do gateway e a reinicializacao da maquina.

sidecar/.gitignore - adicionado node_modules/ e .photon-npm-error.log.

Isolamento - sem impacto no core:
  - check_fn() continua retornando apenas bool; core nao e modificado
  - Logging usa namespace plugins.platforms.photon.adapter, isolado de
    gateway.* e hermes_cli.*
  - Cada plugin tem seu proprio check_requirements() independente
  - OSError no write/read de _NPM_ERROR_LOG e silenciado - nunca propaga

Testes - 24/24 passando:
  test_check_requirements_risks.py (7 testes):
    WARNING emitido quando httpx ausente
    WARNING emitido quando node nao no PATH
    DEBUG emitido (nao WARNING) quando spectrum-ts ausente, com path
    node_modules/ vazio agora retorna False (Risk 2 resolvido)
    _NPM_ERROR_LOG escrito no stderr do npm em falha
    _NPM_ERROR_LOG apagado apos npm bem-sucedido
    erro npm aparece no DEBUG log quando node_modules ausente

  test_npm_error_log_regression.py (9 testes - vetores de falha da solucao):
    return code contrato intacto (0 em sucesso, nao-zero em falha)
    OSError no write do log silenciado, exit code ainda propagado
    OSError no read do log silenciado, check_requirements() retorna False
    stderr vazio nao cria arquivo de log
    proc.stderr=None nao lanca AttributeError
    log stale apagado apos reinstall bem-sucedido
    DEBUG emitido mesmo sem log de erro (setup pela primeira vez)

Closes #50981

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-28 18:20:06 -07:00