--- phase: 27-hermes-adapter verified: 2026-04-02T16:30:35Z status: gaps_found score: 3/4 must-haves verified re_verification: false gaps: - truth: "AGENT_ADAPTER_TYPES has no duplicate entries" status: failed reason: "packages/shared/src/constants.ts still contains two gemini_local entries (lines 29 and 35). The SUMMARY claimed this was 'already clean on this branch' but the file has not been deduplicated. Commit 79b61059 ([nexus] feat(20-01)) added gemini_local after hermes_local, creating the duplicate, and no subsequent commit removed it." artifacts: - path: "packages/shared/src/constants.ts" issue: "gemini_local appears twice: line 29 (first occurrence, correct) and line 35 (second occurrence after hermes_local, duplicate to remove)" missing: - "Remove the second 'gemini_local' entry (line 35) from AGENT_ADAPTER_TYPES in packages/shared/src/constants.ts" --- # Phase 27: Hermes Adapter Verification Report **Phase Goal:** Users can create a Hermes agent in Nexus, configure it, and have it execute heartbeats that spawn `hermes chat -q`, return a result, and persist the session across runs **Verified:** 2026-04-02T16:30:35Z **Status:** gaps_found — 1 gap blocking full compliance **Re-verification:** No — initial verification ## Goal Achievement ### Observable Truths | # | Truth | Status | Evidence | |----|----------------------------------------------------------------------------------------|-------------|----------------------------------------------------------------------------------------------| | 1 | hermes_local is treated as a sessioned local adapter for orphan-process liveness checks | VERIFIED | `heartbeat.ts` line 75: `"hermes_local"` in `SESSIONED_LOCAL_ADAPTERS` set; consumed at line 1759 via `isTrackedLocalChildProcessAdapter` in orphan-reaping logic | | 2 | Toolsets field does not corrupt extraArgs when creating a new Hermes agent | VERIFIED | `config-fields.tsx` lines 70–119: Toolsets `` is inside `{!isCreate && (<> ... )}` guard; no `extraArgs` reference anywhere in the file | | 3 | Hermes session codec round-trip is tested (serialize, deserialize, getDisplayId, legacy key) | VERIFIED | `adapter-session-codecs.test.ts` lines 16, 109–132: hermesSessionCodec imported from `hermes-paperclip-adapter/server`; 2 hermes test cases pass; all 11 adapter-session-codecs tests pass | | 4 | AGENT_ADAPTER_TYPES has no duplicate entries | FAILED | `constants.ts` line 29 and line 35 both contain `"gemini_local"` — duplicate not removed | **Score:** 3/4 truths verified ### Required Artifacts | Artifact | Expected | Status | Details | |-------------------------------------------------------|-------------------------------------------------|------------|-----------------------------------------------------------------------------------------------------------| | `server/src/services/heartbeat.ts` | hermes_local in SESSIONED_LOCAL_ADAPTERS set | VERIFIED | Line 75: `"hermes_local"` present in set; function `isTrackedLocalChildProcessAdapter` wraps set at line 655–657, called at line 1759 | | `packages/shared/src/constants.ts` | Deduplicated AGENT_ADAPTER_TYPES array | FAILED | File exists and contains hermes_local (line 34), but gemini_local is duplicated (lines 29 and 35); deduplication task was not completed | | `ui/src/adapters/hermes-local/config-fields.tsx` | Toolsets field hidden in create mode | VERIFIED | File created (123 lines); Toolsets inside `{!isCreate && ...}` at line 70; no extraArgs references; no stubs | | `server/src/__tests__/adapter-session-codecs.test.ts` | Hermes session codec test block | VERIFIED | Lines 16 (import), 109–132 (2 test cases); all 11 tests pass in vitest run | ### Key Link Verification | From | To | Via | Status | Details | |---------------------------------------------------|------------------------------------------|----------------------------------------------|----------|------------------------------------------------------------------------------------------------------| | `server/src/services/heartbeat.ts` | `server/src/adapters/registry.ts` | SESSIONED_LOCAL_ADAPTERS set membership check | WIRED | `isTrackedLocalChildProcessAdapter` defined line 655, called line 1759 in orphan-reaping loop | | `server/src/__tests__/adapter-session-codecs.test.ts` | `hermes-paperclip-adapter/server` | import sessionCodec | WIRED | Line 16: `import { sessionCodec as hermesSessionCodec } from "hermes-paperclip-adapter/server"`; tests pass | ### Data-Flow Trace (Level 4) Not applicable — this phase modifies backend constants, a heartbeat set, test coverage, and a UI config form. No new data-rendering components were introduced that require data-flow tracing. ### Behavioral Spot-Checks | Behavior | Command | Result | Status | |---------------------------------------------------|-------------------------------------------------------------------------------------------------------|-----------------------------|---------| | All session codec tests pass (incl. hermes) | `pnpm --filter server exec vitest run src/__tests__/adapter-session-codecs.test.ts` | 11/11 tests pass | PASS | | Hermes dual-source tests pass (regression check) | `pnpm --filter server exec vitest run src/__tests__/hermes-dual-source.test.ts` | 7/7 tests pass | PASS | | UI TypeScript compiles cleanly | `pnpm --filter ui exec tsc --noEmit` | Exit 0, no errors | PASS | | Server TypeScript (excluding pre-existing errors) | `pnpm --filter server exec tsc --noEmit` | Only plugin-sdk errors (pre-existing, unrelated to this phase) | PASS (scoped) | | Toolsets field has no extraArgs reference | `grep -n "extraArgs" ui/src/adapters/hermes-local/config-fields.tsx` | No output (no matches) | PASS | | constants.ts gemini_local count | `grep -c "gemini_local" packages/shared/src/constants.ts` | 2 (should be 1) | FAIL | ### Requirements Coverage | Requirement | Source Plan | Description | Status | Evidence | |-------------|-------------|-----------------------------------------------------------------------------------------------------------|----------------|--------------------------------------------------------------------------------------------------------| | HERM-01 | 27-01-PLAN | Hermes adapter installed, enabled, appears in "Add Agent" dropdown | SATISFIED | Pre-existing: `ui/src/components/NewAgentDialog.tsx` lists hermes_local; `ui/src/components/AgentConfigForm.tsx` includes hermes_local in ENABLED_ADAPTER_TYPES | | HERM-02 | 27-01-PLAN | User can create a Hermes agent with config options (model selection, tool permissions) | SATISFIED | `config-fields.tsx` has Model field in both modes; Toolsets properly guarded to edit-only, preventing extraArgs corruption | | HERM-03 | 27-01-PLAN | Heartbeat execution spawns `hermes chat -q`, processes task, returns result | SATISFIED | `hermes_local` in SESSIONED_LOCAL_ADAPTERS enables correct orphan-process liveness checks; adapter wiring pre-exists from prior phase; 7 hermes-dual-source tests pass | | HERM-04 | 27-01-PLAN | Session persistence works across heartbeats via `--resume` flag | SATISFIED | Hermes session codec tests pass: serialize/deserialize round-trip and legacy session_id key both verified | **Note:** HERM-01 through HERM-04 are marked complete in REQUIREMENTS.md. The one failing truth (duplicate constant) is a cleanup item that supports HERM-01 type compliance but does not directly block any of the 4 HERM requirements from functioning at runtime. However, the PLAN explicitly listed it as a must-have truth, so it is recorded as a gap. ### Anti-Patterns Found | File | Line | Pattern | Severity | Impact | |------------------------------------|-------|----------------------------------------------|-----------|-------------------------------------------------------------------------------------------------| | `packages/shared/src/constants.ts` | 35 | `"gemini_local"` — duplicate array entry | Warning | TypeScript `as const` array has duplicate. No runtime breakage (TypeScript union types deduplicate), but it is incorrect and the plan explicitly required removal. | The server TS errors (`plugin-sdk` module not found) are pre-existing and unrelated to this phase — they exist on the branch prior to any phase-27 commits and are not introduced by this phase. ### Human Verification Required None — all critical behaviors are verifiable programmatically for this phase. ### Gaps Summary One gap blocks full must-have compliance: **Duplicate `gemini_local` in `AGENT_ADAPTER_TYPES` (constants.ts)** — The plan task required removing the second `"gemini_local"` entry from `AGENT_ADAPTER_TYPES` in `packages/shared/src/constants.ts`. The SUMMARY noted "already clean on this branch," but the actual file has the duplicate at lines 29 and 35. Commit `79b61059` (from an earlier phase) added `gemini_local` after `hermes_local`, and no subsequent commit in phase 27 removed it. The fix is a single-line deletion. The three other must-haves are fully implemented and tested: - `hermes_local` is correctly in `SESSIONED_LOCAL_ADAPTERS` and the orphan-reaping logic uses it - `config-fields.tsx` correctly guards the Toolsets field behind `{!isCreate && ...}` with no extraArgs corruption - Hermes session codec has 2 passing tests (standard sessionId + legacy session_id key) --- _Verified: 2026-04-02T16:30:35Z_ _Verifier: Claude (gsd-verifier)_