fix(goals): prevent profile goal contract drift - #6899
ticketclosed-wontfix wants to merge 3 commits into
Conversation
|
| Filename | Overview |
|---|---|
| api/goals.py | Adds capability-gated native profile delegation, guaranteed context cleanup, scoped native rollback, and a compatible legacy fallback without an identified blocking defect. |
| tests/test_goal_command_webui.py | Adds focused regression coverage for the five-field judge contract, native wait behavior, concurrent profile isolation, fallback selection, snapshot restoration, and exception cleanup. |
| ARCHITECTURE.md | Documents the native ownership boundary, capability probe, context lifecycle, rollback behavior, and compatibility fallback introduced by the implementation. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Profile-scoped goal operation] --> B{Context-local home API available?}
B -- No --> L[Legacy explicit-DB GoalManager]
B -- Yes --> C[Bind profile home]
C --> D{Default DB resolves to profile/state.db?}
D -- No --> E[Reset context]
E --> L
D -- Yes --> F[Reset probe context]
F --> N[Construct native GoalManager under scoped profile home]
N --> O[Run native operation or snapshot restore]
O --> R[Reset profile context in finally]
L --> P[(Profile state.db)]
O --> P
Reviews (4): Last reviewed commit: "fix(goals): gate native profile persiste..." | Re-trigger Greptile
| from hermes_constants import reset_hermes_home_override, set_hermes_home_override | ||
| except Exception: # pragma: no cover - depends on installed hermes-agent | ||
| return None | ||
| return set_hermes_home_override, reset_hermes_home_override |
There was a problem hiding this comment.
Document profile goal delegation
The new context-local native-manager path, legacy compatibility fallback, and scoped rollback behavior change the documented runtime architecture, but no subsystem documentation describes the new ownership and compatibility boundary. This leaves future maintenance guidance based on the obsolete explicit-DB-only model.
Context Used: AGENTS.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
a5c307e to
c4ff6d2
Compare
nesquena-hermes
left a comment
There was a problem hiding this comment.
Thanks @ticketclosed-won — the goal-contract-drift concern is real and the fix direction is right, but the gate reproduced a profile-isolation hole in the version gating that needs tightening first:
Must-fix (CORE, reproduced) — cross-profile goal overwrite on an intermediate Agent range
api/goals.py:309. On Hermes Agent v2026.5.28–v2026.7.20, the native _ProfileGoalManager is selected because the context-override API is present — but on those versions SessionDB() still resolves to the frozen import-time DEFAULT_DB_PATH, so all profile goal mutations target the same state.db and one profile overwrites another's goal. Reproduced: two profiles with the same session id both ended up reading goal-b (the explicit-DB fallback correctly kept goal-a/goal-b isolated).
Fix: gate selection of _ProfileGoalManager on both (a) context-home support and (b) call-time SessionDB path resolution — if either is missing, fall back to _LegacyProfileGoalManager. Add a regression with a frozen DEFAULT_DB_PATH proving identical session IDs stay isolated across two profiles (the current 76 tests pass but don't exercise this intermediate-version contract).
Re-push with the capability gate tightened and I'll re-gate.
Use Hermes' context-local home override to run profile-scoped goal operations through the native GoalManager, preserving current judge, wait, and failure semantics while retaining the explicit-DB legacy fallback.
c4ff6d2 to
bb8b10d
Compare
|
Addressed the reproduced intermediate-Agent profile-isolation hole.
Rebased onto current |
…not installed) #6899's native-contract tests imported hermes_cli unconditionally, failing CI with ModuleNotFoundError. Match the repo's established importorskip pattern so they skip cleanly when the agent isn't installed and run when it is. Co-authored-by: ticketclosed-wontfix
|
Re-gate at head bb8b10d: SAFE TO SHIP — Codex verified the capability gate now requires both context-home resolution AND call-time DB-path selection, the affected agent tags (v2026.5.28, v2026.7.20) correctly select the legacy manager so profiles keep separate goals, and newer builds use native delegation correctly (32 goal tests pass). One CI-only fix I folded into the release: the new |
…-webui entry point (#6742) (#7108) * fix(goals): delegate profile evaluation to native manager Use Hermes' context-local home override to run profile-scoped goal operations through the native GoalManager, preserving current judge, wait, and failure semantics while retaining the explicit-DB legacy fallback. * docs(goals): describe profile ownership boundary * fix(goals): gate native profile persistence capability * feat(cli): add packaged hermes-webui CLI entry point (#6739) * fix(cli): route hermes-webui entry through bootstrap:main for wheel install (#6742) * docs(changelog): note #6899 profile goal isolation + #6742 hermes-webui entry point * test(goals): guard hermes_cli import with importorskip for CI (agent not installed) #6899's native-contract tests imported hermes_cli unconditionally, failing CI with ModuleNotFoundError. Match the repo's established importorskip pattern so they skip cleanly when the agent isn't installed and run when it is. Co-authored-by: ticketclosed-wontfix --------- Co-authored-by: Nick <202622897+ticketclosed-wontfix@users.noreply.github.com> Co-authored-by: webtecnica <webtecnica@gmail.com> Co-authored-by: n <a@n>
|
Shipped in experimental release exp-v0.52.237. Native profile-goal persistence is now gated on the agent supporting both context-home resolution and call-time DB-path selection (else it falls back to the legacy per-profile manager), so profiles stay isolated on the affected builds. Thanks @ticketclosed-won! (I folded in a small CI-only test guard — see the comment above.) |
…+ hermes-webui entry point (nesquena#6742) (nesquena#7108) * fix(goals): delegate profile evaluation to native manager Use Hermes' context-local home override to run profile-scoped goal operations through the native GoalManager, preserving current judge, wait, and failure semantics while retaining the explicit-DB legacy fallback. * docs(goals): describe profile ownership boundary * fix(goals): gate native profile persistence capability * feat(cli): add packaged hermes-webui CLI entry point (nesquena#6739) * fix(cli): route hermes-webui entry through bootstrap:main for wheel install (nesquena#6742) * docs(changelog): note nesquena#6899 profile goal isolation + nesquena#6742 hermes-webui entry point * test(goals): guard hermes_cli import with importorskip for CI (agent not installed) nesquena#6899's native-contract tests imported hermes_cli unconditionally, failing CI with ModuleNotFoundError. Match the repo's established importorskip pattern so they skip cleanly when the agent isn't installed and run when it is. Co-authored-by: ticketclosed-wontfix --------- Co-authored-by: Nick <202622897+ticketclosed-wontfix@users.noreply.github.com> Co-authored-by: webtecnica <webtecnica@gmail.com> Co-authored-by: n <a@n>
Thinking Path
GoalManager.evaluate_after_turn()rather than the native Hermes implementation.verdict,reason, parse failure, wait directive, transport failure), while the WebUI copy still unpacked two.ValueErrorwas caught by the WebUI goal hook and converted to a non-continuing error decision, leaving the goal active but idle.What Changed
GoalManagerunder a context-local profile home.finallyafter every delegated operation.SessionDBpath resolution; otherwise use the explicit-DB fallback.WAITstate and persistence;DEFAULT_DB_PATHcompatibility range;Why It Matters
An incomplete goal turn no longer silently stops because WebUI's profile adapter drifted from Hermes' native goal contract. Delegating to the native manager also keeps newer wait, parse-failure, transport-failure, contract, and subgoal semantics from drifting independently in WebUI.
Verification
test_profile_goal_evaluation_supports_native_judge_contractfailed withdecision["verdict"] == "error"instead of"continue".test_profile_goal_falls_back_when_session_db_path_is_frozenreproduced profile A readinggoal-bafter profile B wrote the same session ID through a frozen default DB path../scripts/test.sh tests/test_goal_command_webui.py tests/test_stage326_pending_goal_continuation_race.py tests/test_issue_1932_goal_hook_unrelated_turns.py tests/test_webui_gateway_chat_backend.py -q77 passedv2026.7.20compatibility canary:_LegacyProfileGoalManagerselected and two profiles with the same session ID retained separategoal-a/goal-bstate.git diff --check: pass.8,441 passedbefore 22 unrelatedtest_jump_to_answer_scroll_settle.pyfailures and a 60-second pytest-timeout internal error; that entire file then passed independently (26 passed). CI remains the authoritative full-matrix check.Contract Routing
Task type: narrow runtime compatibility bug fix.
Touched areas:
api/goals.pyprofile-scoped goal persistence/evaluation adapterRelevant public docs:
AGENTS.mdCONTRIBUTING.mddocs/CONTRACTS.mddocs/rfcs/hermes-run-adapter-contract.mdState owner and invariant:
GoalManagerremains the authoritative goal-state owner.HERMES_HOMEselection is task-local and is restored on every exit.This restores documented behavior; it does not intentionally change the persistent-goal contract.
Risks / Follow-ups
WAITbarrier is outside this focused repair and remains part of broader continuation scheduling work.Release-note wording: Profile-scoped persistent goals no longer stop silently when WebUI runs with current Hermes goal-judge semantics.
Model Used
OpenAI Codex provider,
gpt-5.6-sol, with Hermes tool orchestration, isolated worktrees, TDD, and an independent reviewer subagent.