Skip to content

fix(sources): profile-qualify Hermes verification-ledger session identity#3227

Merged
Sinity merged 1 commit into
masterfrom
fix/hermes/verification-profile-qualified-identity
Jul 20, 2026
Merged

fix(sources): profile-qualify Hermes verification-ledger session identity#3227
Sinity merged 1 commit into
masterfrom
fix/hermes/verification-profile-qualified-identity

Conversation

@Sinity

@Sinity Sinity commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Summary

hermes_verification.py retained the exact unqualified observer-id collapse
pattern that PR #3224 fixed for ATIF/ATOF (hermes_spans.py). This PR
mirrors that fix for the Hermes verification-ledger importer.

Problem

Two Hermes installs (profiles) can legitimately reuse the same raw session
id. hermes_verification.observer_session_provider_id /
hermes_verification_session_id_for built a bare verification:<raw_id>
identity and stripped any @profile-<key> qualifier when mapping back from
a conversational session id, so two installs' verification-ledger evidence
(lint/typecheck/build/test command outcomes) silently collapsed onto one
archive session.

Solution

  • observer_session_provider_id(hermes_session_id, profile_key=None) and
    hermes_verification_session_id_for now thread an optional profile key
    through hermes_identity.qualified_session_id /
    split_qualified_session_id -- the exact shared helper hermes_spans.py
    and hermes_state.py already use. The verification: family prefix stays
    distinct from ATIF/ATOF's observer: family even when both qualify the
    same raw id against the same profile.
  • parse_verification_evidence_db / parse_verification_evidence_db_payload
    accept profile_root: Path | None, compute a profile key when known, and
    assert parent_session_provider_id back to the state-db conversational
    session only when the profile root is known (fail-closed: no edge is
    safer than a wrong one).
  • Added a parent_session_link fidelity capability, aggregated across
    sessions, mirroring hermes_spans._parent_session_link_capability.
  • Wired profile_root=Path(spec.source_path).parent (or path.parent) at
    every verification-evidence call site: dispatch.py, import_explain.py,
    source_parsing.py, live/batch.py.
  • Left revision_backfill.py's existing call untouched per scope (it already
    fails closed with profile_root defaulting to None).
  • Did not touch hermes_spans.py / hermes_identity.py (consumed
    read-only) or the ATIF/ATOF call sites -- those are owned by another
    active lane.

Verification

  • devtools test tests/unit/sources/parsers/test_hermes_verification.py tests/unit/sources/test_dispatch_payloads.py tests/unit/sources/test_hermes_import_explain.py tests/unit/sources/test_hermes_source_freshness_integration.py tests/unit/insights/test_hermes_verification_coverage.py tests/unit/sources/test_live_watcher_catchup_order.py tests/unit/core/test_sampling.py tests/unit/sources/test_parsers_local_agent.py -> 103 passed
  • mypy --strict on the 5 touched production modules -> Success: no issues found in 5 source files
  • devtools verify --quick -> exit_code: 0
  • Anti-vacuity: temporarily reverted the profile-key qualification in
    observer_session_provider_id (collapsed back to unconditional
    verification:<raw_id>) and re-ran the new collapse/family-prefix/
    dispatch-wiring tests -- all 3 failed with the expected unqualified-id
    assertion mismatches. Restored the fix; tests green again.

Ref polylogue-y9zx

…tity

Problem: PR #3224 fixed the unqualified observer-id collapse pattern for
ATIF/ATOF (hermes_spans.py) but hermes_verification.py retained the exact
pre-fix pattern -- observer_session_provider_id/
hermes_verification_session_id_for built bare `verification:<raw_id>`
identities and stripped the `@profile-<key>` qualifier. Two Hermes installs
(profiles) sharing a raw session id collapse their verification-ledger
evidence onto one archive session.

Solution: mirror #3224. observer_session_provider_id and
hermes_verification_session_id_for now thread an optional profile_key
through hermes_identity.qualified_session_id/split_qualified_session_id, the
same shared helper hermes_spans.py/hermes_state.py use.
parse_verification_evidence_db/parse_verification_evidence_db_payload accept
profile_root: Path | None, compute a profile key when known, and assert
parent_session_provider_id back to the state-db conversational session only
when the profile is known (fail-closed -- no edge is safer than a wrong
one). The `verification:` family prefix stays distinct from ATIF/ATOF's
`observer:` family. Wired profile_root=Path(spec.source_path).parent at
every verification-evidence call site: dispatch.py, import_explain.py,
source_parsing.py, live/batch.py. Left revision_backfill.py's existing call
untouched (owned surface, and it already fails closed with profile_root
defaulting to None). Did not touch hermes_spans.py/hermes_identity.py
(consumed read-only) or the ATIF/ATOF call sites, which are owned by another
active lane.

Verification:
- devtools test tests/unit/sources/parsers/test_hermes_verification.py
  tests/unit/sources/test_dispatch_payloads.py
  tests/unit/sources/test_hermes_import_explain.py
  tests/unit/sources/test_hermes_source_freshness_integration.py
  tests/unit/insights/test_hermes_verification_coverage.py
  tests/unit/sources/test_live_watcher_catchup_order.py
  tests/unit/core/test_sampling.py tests/unit/sources/test_parsers_local_agent.py
  -> "103 passed"
- mypy --strict on the 5 touched modules -> "Success: no issues found in 5 source files"
- devtools verify --quick -> exit_code 0 (format/lint/mypy/render/topology/
  layering/manifests/doc-commands/docs-coverage/clock-hygiene/etc all ok)
- Anti-vacuity: reverted observer_session_provider_id's profile-key
  qualification (collapsed back to unconditional `verification:<raw_id>`)
  and re-ran the new collapse/family-prefix/dispatch-wiring tests -- all 3
  failed with the expected unqualified-id assertion mismatches, confirming
  they exercise the real production mutation. Restored the fix; tests green
  again.

Ref polylogue-y9zx

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

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Sinity, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6db6dfee-ecbf-4499-8af1-05b743a9557b

📥 Commits

Reviewing files that changed from the base of the PR and between 9a58a43 and 68ebaee.

📒 Files selected for processing (6)
  • polylogue/sources/dispatch.py
  • polylogue/sources/import_explain.py
  • polylogue/sources/live/batch.py
  • polylogue/sources/parsers/hermes_verification.py
  • polylogue/sources/source_parsing.py
  • tests/unit/sources/parsers/test_hermes_verification.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/hermes/verification-profile-qualified-identity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 68ebaeed2c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

path: Path,
*,
fallback_id: str | None = None,
profile_root: Path | None = None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Thread the profile root through retained-raw replay

When revision backfill or a derived-tier rebuild reparses a retained Hermes verification database, revision_backfill._parse_one still calls parse_verification_evidence_db(sqlite_path, fallback_id=...) without the available Path(source_path).parent. Because the new default here produces an unqualified verification:<raw_id> session with no parent edge, the same raw evidence has qualified identity during live ingest but unqualified identity during rebuild; multiple profiles can collapse again and verification coverage no longer resolves to the qualified conversational session. Update that replay call just as the state-db branch immediately above it already does.

Useful? React with 👍 / 👎.

@Sinity

Sinity commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

Coordinator review stand-in (CodeRabbit rate-limited — no findings produced).

Read the full diff. Mirrors merged #3224 exactly: profile_key threaded through the shared hermes_identity helpers; verification: family prefix stays distinguishable from observer:atif|atof; hermes_verification_session_id_for now preserves (split-and-rethreads) the conversational id's qualifier instead of stripping it — the collapse-and-strip pattern the bead names; parent link asserted fail-closed only when profile_root is known. Extending profile_root to all four real call sites (dispatch, import_explain, source_parsing, live/batch) rather than dispatch alone is the right call — the bug existed at each; revision_backfill.py correctly left untouched (excluded surface) and now fails closed there. Anti-vacuity proven by reverting the qualification (3 tests fail as expected).

Same semantic-reparse note as #3225's P1 applies: already-materialized verification-ledger observer sessions carry old unqualified ids; covered by the coordinator's post-promote targeted Hermes reprocess bead (posted separately). 103 focused tests, mypy --strict, quick-gate green. Merging.

@Sinity
Sinity merged commit 8adacda into master Jul 20, 2026
2 of 3 checks passed
@Sinity
Sinity deleted the fix/hermes/verification-profile-qualified-identity branch July 20, 2026 20:17
Sinity added a commit that referenced this pull request Jul 20, 2026
…rmes-reprocess + provider-usage-500 beads

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QUsH3Rhq6oAZpYPWcsZqnZ
Sinity added a commit that referenced this pull request Jul 20, 2026
Problem: master gained #3226 (objective-posture insight, new module +
topology regen) and #3227 (hermes_verification.py profile-qualified
identity: verification:<id>[@PROfile-<key>], hermes_verification_session_id_for
now PRESERVES the qualifier instead of stripping it) since this branch's
last rebase. Rebasing surfaced one real conflict and one silent cross-file
break the rebase's textual merge did not flag:

- polylogue/sources/parsers/hermes_verification.py: conflicting docstring
  edits (both #3227 and this branch's earlier commit touched the same
  observer_session_provider_id/hermes_verification_session_id_for
  docstrings) -- resolved to describe the composed state: profile-qualified
  AND correctly referencing hermes_spans's renamed
  atif_session_provider_id/atof_session_provider_id (this branch) instead
  of the retired shared observer_session_provider_id.
- tests/unit/sources/parsers/test_hermes_verification.py (added by #3227,
  never touched by this branch's commits, so the rebase reported no
  conflict): test_verification_family_prefix_stays_distinguishable_from_atif_atof_observer_family
  imported hermes_spans.observer_session_provider_id, a name this branch
  retired in favor of atif_session_provider_id/atof_session_provider_id --
  an ImportError, not a merge conflict, so it only surfaced by actually
  running the suite. Fixed to import and assert against both renamed
  functions (verification: stays distinguishable from BOTH observer:atif:
  and observer:atof:, not just the old single observer: family).

Semantic composition check (per coordinator request): hermes_topology_projection.py
never hardcodes a session-id shape itself -- callers resolve each artifact's
session_id (see HermesArtifactInput docstring) via
hermes_spans.atif_session_provider_id/atof_session_provider_id or
hermes_verification.hermes_verification_session_id_for -- so the module is
scheme-agnostic by construction and needed no code change. Added
test_composes_with_profile_qualified_verification_ids_like_atif_and_atof in
tests/unit/insights/test_hermes_topology_projection.py, which drives the
REAL hermes_verification_session_id_for/hermes_identity helpers (not a
hand-typed "verification:<id>" string) from a profile-qualified
conversational session id and proves: the resolved verification id
preserves the qualifier (not stripped, matching #3227's fix), and two
different profiles resolve to two distinct, non-colliding verification
session ids for the same raw Hermes session id -- exactly the guarantee
ATIF/ATOF already have.

docs/hermes-operators.md: "Session identity" section and item 1 updated --
previously (written before #3227 merged) claimed hermes_verification's
helper "still strips" the profile qualifier and was "explicitly left out of
this fix's scope"; now correctly describes it as fixed separately
(polylogue-y9zx, PR #3227) using the same shared hermes_identity.py scheme.

docs/plans/topology-target.yaml, docs/topology-status.md: regenerated
(devtools render topology-projection && render topology-status) to reflect
#3226's new objective-posture insight module -- no textual conflict during
rebase, but genuinely stale without regen.

Verification:
- devtools test tests/unit/insights/test_hermes_topology_projection.py
  tests/unit/sources/parsers/test_hermes_spans.py
  tests/unit/sources/test_dispatch_payloads.py
  tests/unit/sources/test_live_watcher.py
  tests/unit/sources/parsers/test_hermes_verification.py -- 151 passed.
- devtools verify --quick -- exit 0.

Ref polylogue-fs1.14

Co-Authored-By: Claude <noreply@anthropic.com>
Sinity added a commit that referenced this pull request Jul 20, 2026
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.

1 participant