Skip to content

docs: technical memory architecture + landing page clarity - #32

Closed
UfukNode wants to merge 1 commit into
NousResearch:mainfrom
UfukNode:docs/technical-memory-architecture
Closed

docs: technical memory architecture + landing page clarity#32
UfukNode wants to merge 1 commit into
NousResearch:mainfrom
UfukNode:docs/technical-memory-architecture

Conversation

@UfukNode

Copy link
Copy Markdown

No description provided.

@UfukNode UfukNode closed this Feb 26, 2026
@UfukNode
UfukNode deleted the docs/technical-memory-architecture branch February 26, 2026 03:11
h4x3rotab pushed a commit to Clawdi-AI/hermes-agent that referenced this pull request Apr 10, 2026
…ch#32)

- Render ContextBar in chat screen (was imported but never placed)
- Pass sessionId to context-usage API for accurate token data
- Count all tokens (cached + uncached) for real context window usage
- Model-aware max tokens (200k for Claude, 128k for GPT)
- Return model name in context-usage response
- Remove header border-b (context bar replaces separator)
- Remove context bar own border-b for clean look
- Change dev server port from 3000 to 3002

Co-authored-by: outsourc-e <eric@outsourc.e>
maiixu added a commit to maiixu/hermes-agent that referenced this pull request Apr 13, 2026
…h#32)

Parses ACTION directives from agent responses and executes PR/issue
actions via Claude Code headless sessions with bot identity.
claude-bot-maiixu Bot added a commit to maiixu/hermes-agent that referenced this pull request Apr 13, 2026
feat(webhook): NousResearch#32 headless CC invocation + routing fixes
ashneil12 referenced this pull request in ashneil12/vanilla-hermes-agent May 18, 2026
)

When the WebUI's model picker sets the active provider to
"venice" (or "crof", "bankr", "cometapi"), the agent's
resolve_provider_client() looked up the slug in
PROVIDER_REGISTRY, failed to find it, and raised:

  "Provider 'venice' is set in config.yaml but no API key
   was found. Set the VENICE_API_KEY environment variable..."

VENICE_API_KEY WAS set in env — the failure was because
the agent had no idea which env var or base URL to use for
"venice" as a slug. PROVIDER_REGISTRY entries for the other
OpenAI-compatible aggregators (Z.AI, MiniMax, Mistral, etc.)
already existed; Venice/CrofAI/Bankr/CometAPI just hadn't
been added in the upstream code.

Adds four api_key-auth entries mirroring the existing
OpenAI-compat ones:
- venice → https://api.venice.ai/api/v1 + VENICE_API_KEY
- crof → https://crof.ai/v1 + CROF_API_KEY
- bankr → https://gateway.bankr.bot/v1 + BANKR_API_KEY
- cometapi → https://api.cometapi.com/v1 + COMETAPI_API_KEY

Companion to the WebUI side (PRs #26/#27/#29/#30/#32/#33)
which made these providers discoverable in the model picker
with their live /v1/models catalogs.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
rafe-walker referenced this pull request in rafe-walker/kora May 20, 2026
…ink MCP call — closes D-kr3-st2

Fourth + final mechanical follow-on swap unlocked by K-10 + 0083
(IsoKron PM #32). Same pattern as KR-7 (chain-emit) and KR-8
(scratchpad-write): create_relationlink body replaces `raise
RelationLinkWriteNotAvailableError()` with
`await mcp_client.invoke('kora__create_relationlink', {...})`,
returning the substrate-assigned link_id. ~30 LOC across
relationlink.py + tools/iso_link.py + tests + docs.

All three KR-3 ST2 substrate blockers are now resolved substrate-side:
* actor_kind CHECK extended to include 'kora' via 0083 (prod-applied)
* public.kora_create_relationlink SECDEF function exists
* kora.relationlink.created event literal in event_log_event_type_check
  (300th literal in the set post-0083)
* kora__create_relationlink Sea MCP tool registered

Production-test posture per IsoKron PM #27:
* K-10's kora__create_relationlink handler is a notImplementedHandler
  stub on substrate main; substrate-team's dispatch tier (task NousResearch#395)
  un-stubs + bridges Layer-A wsk_* auth → Layer-B actor_kind='kora'.
* KR-9 code shape is sound; mock tests verify correctness.
* Production deploys wait on dispatch tier landing — identical
  posture to KR-7 / KR-7b / KR-8.

Verify-at-first-live-emit per spec § 3:
* event_log row with event_type = 'kora.relationlink.created'
* event_log.actor_id = 0076-seeded canonical Kora actor (NOT
  token-UUIDv5)
* relationlink row with chain_event_id matching the emitted event +
  created_by_actor_kind = 'kora'

relationlink.py:
* create_relationlink body: live call to mcp_client.invoke. K-10
  contract output: {'link_id': '<uuid>', 'chain_event_id': '<uuid>'}
  — projected to a plain str link_id return.
* mcp_client param now required (was Optional with deferred-error
  default).
* New rationale_block_id + evidence_block_ids params match K-10's
  input schema. Legacy `rationale` parameter preserved for one-
  release back-compat (silently dropped — superseded by
  rationale_block_id).
* Defensive: None mcp_client → ValueError; unexpected response shape
  → RuntimeError (mirrors KR-7/KR-8 pattern).
* RelationLinkWriteNotAvailableError class kept exported tagged
  [kora.isokron.deprecated] for one release. Original three-blocker
  message preserved inside the message body for grep stability.

tools/iso_link.py:_handle_iso_link_create:
* Dropped the deferred-envelope path. Success →
  {"ok": True, "link_id": <substrate-uuid>}. Substrate failure →
  {"ok": False, "substrate_error": True, "tool_name", "message"} —
  same structured signal shape as KR-8's iso_node_create.
* Fetches IsoKronMCPClient via get_mcp_client(); MCP-client-
  unavailable returns {"ok": False, "error": ...} envelope.
* Removed unused RelationLinkWriteNotAvailableError import.

Tests (7 new + 2 updated):
* test_iso_link_tools.py:
  - test_create_relationlink_raises_deferred_write_error →
    test_create_relationlink_invokes_kora__create_relationlink:
    happy path asserts spec-pinned arg shape (workspace_id,
    from/to entity_id + kind, link_type, evidence_block_ids=[]).
  - New test_create_relationlink_propagates_mcp_invocation_error
    (substrate active-edge uniqueness violation surfaces).
  - New test_create_relationlink_rejects_none_mcp_client.
  - New test_create_relationlink_rejects_unexpected_response_shape.
  - New test_create_relationlink_passes_rationale_block_id_when_present
    (optional args pass-through).
  - New test_relationlink_write_not_available_error_still_importable_post_kr9
    (deprecation runway).
  - test_iso_link_create_handler_returns_deferred_envelope →
    _returns_ok_envelope_with_substrate_link_id: success-envelope
    + verifies spec-pinned tool name in invoke recording.
  - New test_iso_link_create_handler_surfaces_substrate_error_envelope:
    IsoKronMCPInvocationError flips to structured envelope.
  - _FakeMcpClient routes by tool_name (returns link-N for
    kora__create_relationlink). _FakeProviderConnection gains
    get_mcp_client().

BUILD_DEVIATIONS:
* D-kr3-st2-no-relationlink-write-mcp-tool moved Open → Closed with
  Rule-5 spec-quote, call-site refactor inventory, production-test
  posture, all-three-blockers-resolved-substrate-side note,
  deprecation-runway note, verify-at-first-live-emit step.

README "Operator pitfalls":
* "Deferred-surface summary" table replaced with
  "All BUILD_DEVIATIONS closed code-side as of KR-9 (parallel-merged
  with KR-7b + KR-8)" note. All 5 deferral closures listed under
  Recently closed.
* Individual "iso_link_create writes are blocked" pitfall rewritten
  as "RelationLink writes route via kora__create_relationlink (KR-9)"
  with success/failure envelope shapes + operator grep pointer.

Parallel-mergeability note: KR-7b + KR-8 + KR-9 modify disjoint files
(KR-7b: capability_matrix_mirror.py + provider.initialize; KR-8:
scratchpad.py + provider sync_turn/on_memory_write; KR-9:
relationlink.py + tools/iso_link.py). Merge interleaves; each PR
narrows its E2E assertions to its own surface so test fixture
counts don't fight. PM handles README + BUILD_DEVIATIONS final
reconciliation on merge order.

Local gates:
* ty check — 7,337 diagnostics, zero-delta vs KR-7 baseline.
* pytest tests/plugins/memory/ — 357/357 passing.
* Full suite via xdist (-n auto): 24,629 / 181 failed / 12 errors /
  129 skipped. Same tests/tools/* xdist isolation noise as documented
  across prior PRs; none touch isokron.

After KR-9 + KR-7b + KR-8 merge, all four BUILD_DEVIATIONS are
closed code-side. Standing-by state becomes dispatch-tier-gated
(waiting on substrate-team task NousResearch#395 + service-token mint for
production deploys).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dizhaky referenced this pull request in dizhaky/hermes-agent Jun 4, 2026
- path-to-regexp: 0.1.12 → 0.1.13 (CVE-2026-4867, GHSA-37ch-88jc-xwx2)
- picomatch: 2.3.1 → 2.3.2 (CVE-2026-33671, GHSA-c2c7-rcm5-vvqj)
- undici: 7.23.0 → 7.27.1 (CVE-2026-1526/CVE-2026-2229/CVE-2026-1528)
- serialize-javascript: 6.0.2 → 7.0.3 (GHSA-5c6j-r48x-rmvq, via overrides)

Fixes Dependabot alerts #37, #34, #33, #32, #29, #27
jarvis-stark-ops pushed a commit to 1Team-Engineering/hermes-agent that referenced this pull request Jun 10, 2026
Adds two new completion gates that fire alongside the Part 1/2 gates.

Closes hermes-jarvis#63 (PR-existence verification)
Closes hermes-jarvis#32 (doc-drift check)
Context: hermes-jarvis#61 (bootstrap-paradox case study)

## NousResearch#63 — verify_pr_urls_exist

When a verdict result or summary contains a GitHub PR URL pattern,
the dispatcher runs `gh pr view <url> --json number` to verify each
URL resolves. Phantom URLs (404 with "Not Found" / "Could not
resolve" / "no pull request" in stderr) reject the completion.

Indeterminate cases (gh missing, network error, unauthenticated) fall
open — workers can still complete in offline / broken-gh envs without
being trapped.

Catches the 2026-06-09 Tchalla case (hermes-jarvis#61): release-gate
reviewer blocked with "cannot run gh pr diff 42" on PR NousResearch#42 that
didn't exist. With this gate, his completion would have surfaced the
phantom URL specifically, prompting him to surface the real cause.

Opt-out: `metadata.x_phantom_pr_ok` with ≥20-char string reason.

## NousResearch#32 — verify_doc_drift

For tasks whose tenant slug encodes a version
(`marvel-swarm-vN-N-test`), the gate scans `README.md` / `README` in
the workspace for older `vX.Y` mentions outside a history-style
heading (`## History`, `## Older versions`, `## Previous versions`,
`## Archive`). Stale mentions reject the completion.

CHANGELOG.md is intentionally skipped — older versions are expected
there by definition.

Catches the 2026-06-09 agent-dashboard PR #1 case (hermes-jarvis#61):
README still said "v6.2 Marvel swarm test target" while the chain
was v6.6. No reviewer flagged it.

Opt-out: `metadata.x_doc_drift_ok` with ≥20-char string reason.

## Tests

19 new tests added to `test_kanban_completion_gates.py`:
- TestPRExistence (8) — no PR URL skipped, real passes, phantom
  rejects, mixed real+phantom flags only phantom, indeterminate falls
  open, summary scanned, dedup, opt-out
- TestDocDrift (10) — non-versioned tenant skips, no README skips,
  stale README rejects, current README passes, History section
  excused, CHANGELOG file excused, higher version not stale, scratch
  skipped, opt-out

83 passed in test_kanban_completion_gates.py (up from 64). Zero
regressions on adjacent paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jarvis-stark-ops added a commit to 1Team-Engineering/hermes-agent that referenced this pull request Jun 10, 2026
…earch#32)

- `verify_pr_urls_exist` (closes hermes-jarvis#63) — scans verdict
  text + summary for GitHub PR URLs and runs `gh pr view` per URL.
  Phantom URLs (404) reject; indeterminate (gh missing / network)
  falls open. Strict 404 classification excludes DNS/network token
  patterns so "could not resolve host" stays indeterminate.
- `verify_doc_drift` (closes hermes-jarvis#32) — for tasks whose
  tenant slug encodes a version (marvel-swarm-vN-N-test), scans
  README.md/README for older vX.Y mentions outside a history section.
  Depth-aware section-tracking so `## History\n### v6.2 details`
  correctly excuses the subsection.

Opt-outs: x_phantom_pr_ok / x_doc_drift_ok (≥20-char string reasons).

Context: hermes-jarvis#61.

90 tests pass after two self-review passes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jleechan2015 added a commit to jleechanorg/hermes-agent that referenced this pull request Jun 29, 2026
…te (NousResearch#32)

* fix(gateway): add OutboundGuard to prevent cross-channel Slack misroute

Production incident (2026-06-19 11:20:58–11:22:32 UTC):
  Inbound from C0AH3RY3DK6 (WorldArchitect) at 11:20:58.
  Orphan reply 1781868147.039389 posted to C0AJQ5M0A0Y (home channel)
  at 11:22:27 — 5 seconds BEFORE the correct reply to C0AH3RY3DK6.
  No thread_ts on the orphan because the inbound had no parent in C0AJQ5M0A0Y.

Root cause class: the gateway's outbound path used a chat_id that was
NOT derived from the inbound that triggered the response.

This change adds OutboundGuard (gateway/outbound_guard.py) — a
task-local contextvar that pins the inbound chat_id for the lifetime
of _handle_message_with_agent. Any adapter.send call whose chat_id
mismatches the active inbound is logged as a WARNING and recorded in
violations for the regression test.

Wiring:
  - Pin source.chat_id at handler entry (gateway/run.py:6943).
  - Reset in the existing finally block (gateway/run.py:7953) so the
    next handler's verify_send() checks are not contaminated.

Regression test (tests/hermes_cli/test_outbound_guard.py):
  - 8 tests cover pin/verify round-trip, exact incident repro pattern
    (pin A, send to B, send to A → exactly one violation), task-local
    isolation across concurrent asyncio tasks, allowed_extra_destinations
    opt-out for home-channel startup/shutdown notifications, and the
    unrestricted case where no chat_id is pinned.
  - All 8 tests pass.

* fix(gateway): wire OutboundGuard into real send paths; per-instance ContextVar; None-block

- outbound_guard.py: move _active_chat_id ContextVar into __post_init__
  so each OutboundGuard instance has its own per-instance ContextVar
  (regression for CR major on the dataclass mutable-default smell).
  Treat verify_send(None) while inbound is pinned as a violation
  rather than a silent bypass (regression for codex-connector P1 and
  CR major). Add module-level singleton _global_guard with
  pin_inbound/unpin_inbound/verify_outbound helpers so production call
  sites that don't hold a guard reference still see the handler's pin.
- run.py: route the per-handler pin through both the per-instance guard
  AND the module-level singleton; unpin both in the finally block.
- platforms/slack.py: SlackAdapter.send calls verify_outbound(chat_id)
  before chat_postMessage; returns a failed SendResult when misaligned.
- delivery.py: DeliveryRouter._deliver_to_platform calls
  verify_outbound(target.chat_id) before adapter.send; raises
  ValueError on misalignment (cron deliveries outside a handler still
  pass through because the guard has no pinned inbound).
- stream_consumer.py: replace every self.adapter.send call with a new
  _guarded_send helper that wraps verify_outbound around the send;
  on violation returns a fake failed SendResult without invoking the
  underlying adapter.
- tests/hermes_cli/test_outbound_guard.py: add test_none_chat_id_while_inbound_pinned_records_violation,
  test_module_level_singleton_pins_and_verifies,
  test_per_instance_contextvar_is_not_shared_between_guards,
  test_real_slack_send_with_aligned_chat_id_succeeds, and
  test_real_slack_send_with_misaligned_chat_id_is_refused.
  Apply the CR nitpicks: f-string assertion keys + shared guard
  instance in the task-locality test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(gateway): sentinel for no-active-inbound; guard all slack write paths

Three CR Major findings on the previous commit (234aafe6b1) addressed:

1. chat_id=None was bypassing the guard while inbound was pinned. The
   guard had no way to distinguish 'no handler active' from 'handler
   active with missing inbound chat_id' — both states collapsed to
   None via the Optional[str] ContextVar. Introduced _NO_ACTIVE_INBOUND
   sentinel object so verify_send can refuse sends through a handler
   that has no idea what channel to target (incident class includes
   no-destination sends when upstream code forgot to thread
   source.chat_id through).

2. The CR Major asked to extract the verify_outbound guard logic
   into a reusable helper and call it from every Slack write path.
   Added module-level _slack_guard_check() in slack.py and wired it
   into all 11 write methods: send, send_private_notice, _upload_file,
   send_multiple_images, send_image_file, send_image, send_voice,
   send_video, send_document, send_exec_approval, send_slash_confirm.

3. _send_draft_frame in stream_consumer.py uses adapter.send_draft
   (not adapter.send), so it slipped through the previous _guarded_send
   wiring. Added verify_outbound check at the top of _send_draft_frame
   that disables draft streaming on a misroute.

Tests: 13 existing tests pass + 3 new tests covering the sentinel:
  - test_pin_none_marks_handler_active_and_refuses_sends
  - test_pin_none_also_blocks_via_module_singleton
  - test_active_chat_id_distinguishes_inactive_from_pin_none

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(gateway): bound OutboundGuard.violations retention with deque(maxlen)

CR Major (review 4546711137) flagged the violations list as growing
unbounded for the lifetime of the _global_guard singleton — a
misbehaving handler spinning in a loop could exhaust process memory.

Replaced List[dict] with collections.deque(maxlen=MAX_VIOLATION_HISTORY=256).
Retains the most recent 256 violations for diagnostics while bounding
memory at a fixed cost. Added violation_count property for clean
test assertions (avoids deque/list equality noise).

Added 2 regression tests:
- test_violations_list_is_bounded — verifies retention cap
- test_violations_clear_works_with_bounded_deque — verifies clear_violations

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
whichguy added a commit to whichguy/hermes-agent-1 that referenced this pull request Jul 4, 2026
…ion preflight + cost-aware gate (build stage, gate pending)

ATTEMPTED:
- NousResearch#32 first-order candidate source: pipeline.firstorder_questions (one naive raw_chat asking for
  the K best clarifying questions, numbered-parse -> tagged family="First-order semantics",
  lens="firstorder"); infogain.run() round-1 merge gated on the families-block key "firstorder"
  (default "off"); --firstorder / INFOGAIN_FIRSTORDER plumbing + families_cfg(firstorder=...);
  dry-run STAGE 1c. Scored by the normal pipeline; formula frozen.
- NousResearch#33 discrimination preflight (audit A7): validate_evsi.discrimination_preflight -- 8 static
  forced-choice fixtures (one-token semantic flips + cosmetic rewording), score <6/8 -> exit 2;
  --strict-preflight flag on validate_evsi + outcome_eval (default off, 8 calls/model).
- Cost-aware gate instrumentation (Part 0b): outcome_eval.analyze() prints per-arm mean
  wall/tokens/calls (missing usage -> "--"); zeroshot/prompt-evsi arms now carry meta.usage;
  new gate arms nbq-firstorder / nbq-firstorder-behavior.
- Bank +6 agentic tasks (AGENTIC 8->14, gate n 28->34), each combining a first-order + a
  lens-class ambiguity, reference-passes/misreading-fails verified.
- New docs-only nbq-improve skill (the self-improving REVIEW->RESEARCH->PLAN->BUILD->EVALUATE->
  JOURNAL->LOOP protocol) with preregistration template, verdict rubric (incl. this
  commit-message contract), and a research-populated backlog; next-best-questions README
  §5 meta-lessons + §7 + SKILL/evals cross-links.

WHY:
- P4 gap hypothesis (from the NousResearch#28 verdict): the residual gap over the zeroshot arm is generation
  altitude, not the value judge -- so expose first-order semantic unknowns AT GENERATION and let
  the frozen formula dispose. Institutionalize the research -> pre-registered experiment ->
  mechanical verdict -> journal loop as a documented skill, now cost-aware (Δtokens/Δwall
  measured alongside Δresult).
- NousResearch#33: today's emptiness preflight passes a model that answers but judges randomly; verify actual
  better-vs-worse discrimination before trusting realized-value judgments.

RESULT:
- NousResearch#32: build stage, gate pending. Offline: 206 tests green (inert-by-default pin holds -- a cfg
  from DEFAULTS makes no firstorder call and emits no firstorder lens). Live smoke (rate-limiting
  prompt, --firstorder on): 3 firstorder-lens candidates scored through the pipeline, 2 surviving
  at value ~0.69. Pre-registered gate (arms baseline/nbq/nbq-firstorder/nbq-firstorder-behavior/
  zeroshot, both banks n=34, K=3, all-deepseek, --strict-preflight) + ADOPT rule to run next;
  verdict commit to follow.
- NousResearch#33: PASS -- discrimination_preflight scores fast 8/8, deepseek 8/8 (both eval-duty models
  discriminate perfectly on the fixtures). Instrument adopted; no elicitation change, so no gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
whichguy added a commit to whichguy/hermes-agent-1 that referenced this pull request Jul 4, 2026
…h#33 adopted; journal + v1.3.4

ATTEMPTED:
- Ran the pre-registered NousResearch#32 gate (objective outcome harness, n=34 = 20 micro + 14 agentic, K=3,
  all-deepseek, --max-rounds 1, --strict-preflight; 170 cells / 52 min; raw
  ~/.hermes/outcome_eval_32.json) and applied the ADOPT rule mechanically. Journaled the verdict
  both ways across README §6, design-decisions (§First-order candidate source NousResearch#32 + §Discrimination
  preflight NousResearch#33), evsi-validation-findings (pre-registered rule quoted verbatim, incl. the efficiency
  ceiling), and the nbq-improve backlog. Bumped nbq 1.3.3 -> 1.3.4 (negative result, no default flip).

WHY:
- NousResearch#32 tested the NousResearch#28 successor hypothesis: the residual P4 gap over the naive zeroshot arm is
  generation altitude, not the value judge. First cost-aware gate: efficiency (wall/tokens/calls)
  measured alongside Δresult, with a pre-registered 10%-added-wall ceiling that vetoes even a result win.

RESULT:
- NousResearch#32: NO ADOPT. Per-arm pass vs baseline 0.460 -- nbq +0.083 (9W/4L, un 74%, 25.0s/20221tok/38.3c);
  nbq-firstorder +0.132 (7W/3L, un 78%, 29.2s/23944tok/45.4c); zeroshot +0.274 (15W/1L, p=0.0005,
  un 31%, 5.9s/154tok/1c). Paired nbq-firstorder vs nbq: Δ+0.049 > 0 but 6W/6L/22-tie (broad-win
  guard fails); unanswerable 77% (>50%); lens-payoff regression (log-clean 0.67->0.33); +16.8% wall
  (>10% ceiling). All four adopt conditions fail. Altitude has signal (mean beat plain nbq) but did
  NOT close the gap -- zeroshot still dominates at ~1/5 wall, ~1/150 tokens; the residual gap is
  ANSWERABILITY. firstorder stays built, off-by-default. NousResearch#30 answerability weighting re-opened
  (its condition, unanswerable >50%, is now met).
- NousResearch#33: PASS/adopted as opt-in instrument -- discrimination_preflight fast 8/8, deepseek 8/8.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
whichguy added a commit to whichguy/hermes-agent-1 that referenced this pull request Jul 4, 2026
…retro probe

ATTEMPTED: First real use of the nbq-improve protocol (iteration two) — a conditional
full lap. Built a zero-model-call retro probe (evals/probe_answerability.py + 5 tests)
to gate whether to build NousResearch#30 answerability weighting, testing NousResearch#30's premise against the
existing objective corpus (outcome_eval_32.json: per-question EVSI meta.q_values,
answerability qa[].revealed, outcome frac).

WHY: NousResearch#32 pinned the residual P4 gap on answerability (unanswerable 77% > 50%), re-opening
NousResearch#30. Rather than build first, probe the premise for free: do kept high-EVSI *unanswerable*
questions cause objective failure? The cheapest falsifying test uses data we already have
— zero new model calls.

RESULT: PARK (premise NOT supported, n=34). top1_unans x fail r=+0.052, SE=0.177, does not
clear SE (no association); any_unans x fail r=-0.112, base rate 0.971 => DEGENERATE
(near-universal unanswerability => no answerable-question contrast to steer toward) +
wrong-direction; tertiary n_unans x frac r=-0.219 (weak whiff only). Delta-result: none
(no NousResearch#30 build; conditional gate honored in commit order). Delta-cost: zero (probe is
offline). Verdict per the pre-registered rule (quoted verbatim in
evsi-validation-findings.md): PARK. NousResearch#30 re-open now requires a higher-contrast corpus
(candidate 2/3) plus a non-self-rated mechanism (batched strict-simulator answer/refuse
probe, designed + parked in prereg-iteration-two.md item B, unbuilt). Methodology banked:
cost is multi-dimensional — verdict-rubric.md now requires a per-axis ceiling (wall,
tokens, calls), any bust vetoing a result win. Suite 206 -> 211 green.
next-best-questions 1.3.4 -> 1.3.5; nbq-improve 1.0.0 -> 1.0.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Soju06 added a commit to Soju06/hermes-agent that referenced this pull request Jul 16, 2026
JZKK720 added a commit to JZKK720/hermes-agent that referenced this pull request Jul 30, 2026
Upstream TS 6 migration (3bfbb3f) introduced unresolved type errors
in web/src/ (ChatSidebar, PairingPage, PluginsPage, etc.) that cause
tsc -b to fail with exit code 2.  vite build uses esbuild and does
not type-check, so the production bundle is unaffected.

This unblocks the GHCR fork build (runs NousResearch#31/NousResearch#32 both failed).
ethenotethan added a commit to ethenotethan/harness that referenced this pull request Aug 4, 2026
…y (§1) (NousResearch#32)

* fix(artifact-actions): confirmation prompt leads with trusted intent name; codify entity-ref rule (§0)

Two pre-merge security fixes identified in the V2 spec review (§0):

§0.1 — _build_confirmation_prompt now leads with the server-resolved intent
name rather than the artifact-authored label. A declaration labelled "Refresh"
bound to artifact.entity.tombstone previously produced a dialog the user could
confirm thinking they were refreshing; it now reads "artifact.entity.tombstone
— ..." so the real operation is unambiguous. Artifact label appears as
secondary text when it differs. Two tests assert the invariant: one that the
first line starts with the intent name, one that a mismatched label ("Refresh"
→ tombstone) still appears downstream.

§0.2 — Module docstring now codifies the entity-ref resolution rule: handlers
must treat entity_ref as a lookup key into pinned artifact content and must
extract external IDs from stored entity fields, never from the raw client
string. Wrong-vs-right example included. Built-in handlers already conform;
the rule is now the stated contract for plugin authors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(artifacts): plugin action loader — ~/.hermes/plugins/actions/*.py (§1)

Adds a plugin system for Tier-1 artifact action handlers so per-deployment
integrations (e.g. linear.issue.delete) don't require forking core.

Design:
- Plugins live in ~/.hermes/plugins/actions/*.py. Each file calls
  register_handler("name", fn) at load time.
- Authorship/activation split: the loader resolves the real path and
  hard-fails (not warns) if the plugins dir sits under any registered
  agent workspace root. This makes the reload trigger safe to expose
  publicly — agent tools/CLI/RPC can trigger reload, but only the human
  can author what activates.
- Reload is explicit only (actions.reload RPC). No file-watching; silent
  auto-reload would turn agent file-write tools into a code-injection path
  if the workspace-root check were ever misconfigured.
- Staged swap: all plugin files execute against a staging registry; any
  parse/exec error aborts the swap and leaves the last-good handlers live.
  The traceback is returned to the caller.
- Registry diff (added/changed/removed) logged on every reload with file
  list. Pairs with the invocation ledger (§2) to answer "what code ran".
- Built-in handlers (artifact.refresh, artifact.entity.tombstone) survive
  reload; a plugin can deliberately override a built-in by name.
- initial_load() called at gateway startup before gateway.ready fires.

New:
  tui_gateway/artifact_plugin_loader.py — loader, staged swap, diff
  tests/gateway/test_artifact_plugin_loader.py — 11 tests

Modified:
  tui_gateway/server.py — actions.reload RPC (error 5218);
                          artifact.action.reload in gateway.capabilities
  tui_gateway/entry.py  — initial_load() at startup

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
ethenotethan added a commit to ethenotethan/harness that referenced this pull request Aug 4, 2026
…ference (NousResearch#34)

Fulfills the docs follow-up from NousResearch#32 (§1 plugin loader) — the module
docstring in artifact_actions.py already points at docs/plugins/actions.md
for the entity-ref wrong-vs-right example; this adds the file.

Covers:
- Where plugins live, handler signature, register_handler contract
- Explicit reload (RPC / chat / startup), staged swap semantics,
  registry diff + ledger pairing
- The authorship/activation split and why reload is never file-watched
- The mandatory entity-ref resolution rule with wrong-vs-right code
- Destructive role declaration and the challenge flow
- Full reference plugin: linear.issue.delete — lookup from pinned
  content, linear_id from stored row fields, env-var credential,
  GraphQL error surfacing
- Artifact binding declaration + inline HTML marker wiring
- Iteration loop and built-in override behavior

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Meraniya pushed a commit to Meraniya/hermes-agent that referenced this pull request Aug 6, 2026
mansonyu2000 pushed a commit to mansonyu2000/hermes-agent that referenced this pull request Aug 10, 2026
… Sprint NousResearch#30

evidence: none
verified:
- zentao story list --product=11 → 4 stories (NousResearch#117-120)
- zentao task list --execution=30 → 13 tasks (NousResearch#45-57)
- http://pm.test.com/zentao/story-browse-117.html

Changed:
- .zentao/mapping.json: winpeek#6 → peeka数字机器人NousResearch#11, SCRUM NousResearch#29, Sprint NousResearch#30
- tasks/mim-chat-v1-*: updated zentao IDs NousResearch#32-44 → NousResearch#45-57
- tasks/README.md + CLAUDE-module.md: zentao URLs/commands

Co-Authored-By: Claude <noreply@anthropic.com>
ethernet8023 added a commit that referenced this pull request Aug 14, 2026
Dep-inventory items #26/#27/#32: three copies of the same
uv - pip - ensurepip strategy grew independently, and lazy_deps'
docstring admitted being a mirror of tools_config's. Copies drift:
the lazy copy had learned that a uv resolver failure must be final
(falling to pip discards exclude-newer and can install a quarantined
release) while the setup-hook copy still fell through, and only one
of them hid console windows on Windows.

installation/pip_ladder.py now owns the mechanics, stdlib-only under
the same run-dont-parse audit as the rest of the package (the ladder
exists precisely for venvs that are missing pip). The policy choices
that used to be baked into each copy are arguments:

* uv_bin - the caller decides what acquiring uv is worth. Setup hooks
  pass ensure_uv() (downloading uv is in scope during setup); lazy
  installs pass resolve_uv() (a download as a side effect of an
  optional import is not).
* uv_resolver_failure_is_final - the lazy policy above. Availability
  failures (binary vanished, could not exec) always fall through:
  uv never evaluated the requirements, so pip is not a second opinion.
* target/constraints - the durable overlay mode sealed installs use.

tools_config._pip_install and lazy_deps._venv_pip_install are now thin
policy wrappers; agent/lsp/install.py already delegated to the former,
so the third copy collapses transitively. A structural test walks both
wrappers' AST (code, not docstrings) and fails if either regrows a
private ladder.

The 5 failing tests in test_lazy_deps.py fail identically without
this change (verified by stash round-trip): pre-existing on the
branch, not introduced here.
ethernet8023 added a commit that referenced this pull request Aug 15, 2026
Dep-inventory items #26/#27/#32: three copies of the same
uv - pip - ensurepip strategy grew independently, and lazy_deps'
docstring admitted being a mirror of tools_config's. Copies drift:
the lazy copy had learned that a uv resolver failure must be final
(falling to pip discards exclude-newer and can install a quarantined
release) while the setup-hook copy still fell through, and only one
of them hid console windows on Windows.

installation/pip_ladder.py now owns the mechanics, stdlib-only under
the same run-dont-parse audit as the rest of the package (the ladder
exists precisely for venvs that are missing pip). The policy choices
that used to be baked into each copy are arguments:

* uv_bin - the caller decides what acquiring uv is worth. Setup hooks
  pass ensure_uv() (downloading uv is in scope during setup); lazy
  installs pass resolve_uv() (a download as a side effect of an
  optional import is not).
* uv_resolver_failure_is_final - the lazy policy above. Availability
  failures (binary vanished, could not exec) always fall through:
  uv never evaluated the requirements, so pip is not a second opinion.
* target/constraints - the durable overlay mode sealed installs use.

tools_config._pip_install and lazy_deps._venv_pip_install are now thin
policy wrappers; agent/lsp/install.py already delegated to the former,
so the third copy collapses transitively. A structural test walks both
wrappers' AST (code, not docstrings) and fails if either regrows a
private ladder.

The 5 failing tests in test_lazy_deps.py fail identically without
this change (verified by stash round-trip): pre-existing on the
branch, not introduced here.
ethernet8023 added a commit that referenced this pull request Aug 19, 2026
Dep-inventory items #26/#27/#32: three copies of the same
uv - pip - ensurepip strategy grew independently, and lazy_deps'
docstring admitted being a mirror of tools_config's. Copies drift:
the lazy copy had learned that a uv resolver failure must be final
(falling to pip discards exclude-newer and can install a quarantined
release) while the setup-hook copy still fell through, and only one
of them hid console windows on Windows.

installation/pip_ladder.py now owns the mechanics, stdlib-only under
the same run-dont-parse audit as the rest of the package (the ladder
exists precisely for venvs that are missing pip). The policy choices
that used to be baked into each copy are arguments:

* uv_bin - the caller decides what acquiring uv is worth. Setup hooks
  pass ensure_uv() (downloading uv is in scope during setup); lazy
  installs pass resolve_uv() (a download as a side effect of an
  optional import is not).
* uv_resolver_failure_is_final - the lazy policy above. Availability
  failures (binary vanished, could not exec) always fall through:
  uv never evaluated the requirements, so pip is not a second opinion.
* target/constraints - the durable overlay mode sealed installs use.

tools_config._pip_install and lazy_deps._venv_pip_install are now thin
policy wrappers; agent/lsp/install.py already delegated to the former,
so the third copy collapses transitively. A structural test walks both
wrappers' AST (code, not docstrings) and fails if either regrows a
private ladder.

The 5 failing tests in test_lazy_deps.py fail identically without
this change (verified by stash round-trip): pre-existing on the
branch, not introduced here.
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