Skip to content

feat: anchor fingerprint and typed diagnostics events#131

Merged
tkhquang merged 2 commits into
mainfrom
feat/anchor-fingerprint-diagnostics-events
Jun 14, 2026
Merged

feat: anchor fingerprint and typed diagnostics events#131
tkhquang merged 2 commits into
mainfrom
feat/anchor-fingerprint-diagnostics-events

Conversation

@tkhquang

@tkhquang tkhquang commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Summary

Adds two self-heal / diagnostics ergonomics features.

  • Anchors::anchor_fingerprint(const Anchor&): an address-independent FNV-1a hash of an anchor's resolution evidence, so a future manifest diff can tell "same evidence, new address" from "new evidence path".
  • A process-wide diagnostic event bus (Diagnostics::scanner_faults() / hook_lifecycle()) that surfaces scanner skipped-region faults and hook create/enable/disable/remove transitions as typed events, plus Diagnostics::collect() snapshotting leak counters, hook counts, anchor quality, and drift into one struct.

Event emission is best-effort and never affects hook or scan behavior; lifecycle events represent completed transitions only (failures and idempotent no-ops emit nothing).

Summary by CodeRabbit

  • New Features
    • Anchor fingerprinting: New API to compute deterministic, address-independent hashes of anchor resolution evidence for drift analysis across versions.
    • Diagnostic event buses: Added process-wide typed event dispatchers for monitoring scanner faults and hook lifecycle transitions (create, enable, disable, remove).
    • Diagnostics snapshot aggregation: New API to collect comprehensive runtime diagnostics including leak counters, hook population counts, anchor quality assessment, and drift summaries.

Add Anchors::anchor_fingerprint for address-independent manifest diffing. Add a process-wide diagnostic event bus for scanner-fault and hook-lifecycle transitions plus a Diagnostics::collect snapshot aggregator. Emission is best-effort and never perturbs hook or scan behavior; lifecycle events represent completed transitions only. Includes tests and docs.
@tkhquang tkhquang self-assigned this Jun 14, 2026
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@tkhquang, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 41 minutes and 16 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c4d95d95-b185-4303-8e4b-62126382677c

📥 Commits

Reviewing files that changed from the base of the PR and between c9a2edb and 614b8d7.

📒 Files selected for processing (6)
  • include/DetourModKit/anchors.hpp
  • src/anchors.cpp
  • tests/test_anchors.cpp
  • tests/test_diagnostics.cpp
  • tests/test_hook_manager.cpp
  • tests/test_scanner.cpp
📝 Walkthrough

Walkthrough

Adds Anchors::anchor_fingerprint(), a deterministic address-independent 64-bit FNV-1a hash of an anchor's declarative resolution evidence, and extends the diagnostics module with typed process-wide EventDispatcher instances for scanner faults and hook lifecycle transitions, a Diagnostics::Snapshot struct, and a collect() aggregator. Hook lifecycle emissions are wired into all HookManager mutators and the scanner fault path.

Changes

Anchor Evidence Fingerprinting

Layer / File(s) Summary
anchor_fingerprint public API declaration and docs
include/DetourModKit/anchors.hpp, docs/misc/anchors.md, README.md, AGENTS.md
Declares [[nodiscard]] anchor_fingerprint(const Anchor&) noexcept with documentation of per-kind evidence inputs, drift interpretation, Quorum order-independent combination, null sub-anchor sentinel, and CallArgHome kind-only hashing.
FNV-1a hashing implementation
src/anchors.cpp
Adds <cstdint>/<type_traits> headers, anonymous-namespace FNV-1a helpers with length-prefixed folding, kind-specific evidence hash functions for each AnchorKind, and the exported anchor_fingerprint function with sorted Quorum sub-fingerprints and match/tolerance incorporation.
AnchorFingerprintTest suite
tests/test_anchors.cpp, AGENTS.md
Tests determinism, cosmetic-field exclusion (label), evidence-field inclusion per kind, same-evidence/different-address invariant, quorum order independence, match/tolerance evidence, null sub-anchor, CallArgHome kind-only, and candidate-boundary non-aliasing.

Diagnostics Event Bus, Snapshot Aggregator, and Hook/Scanner Wiring

Layer / File(s) Summary
Diagnostics event types, dispatcher declarations, and Snapshot contract
include/DetourModKit/diagnostics.hpp, include/DetourModKit/diagnostics_dump.hpp
Defines ScannerFaultEvent, HookKind/HookTransition enums, HookLifecycleEvent, and scanner_faults()/hook_lifecycle() dispatcher accessors. Introduces Snapshot struct (per-subsystem leak totals, hook active/disabled/total, anchor quality, drift healed/failed) and declares collect() with optional anchor and drift spans.
Event dispatcher singletons and collect() implementation
src/diagnostics.cpp, src/diagnostics_dump.cpp
Implements scanner_faults() and hook_lifecycle() as function-local static EventDispatcher singletons. Implements collect() iterating LeakSubsystem values, summing HookStatus counts, invoking Anchors::assess_quality, and tallying DriftEntry::ok.
Hook lifecycle and scanner fault emission wiring
src/hook_manager.cpp, src/scanner.cpp
Adds HookType-to-HookKind mapping and exception-swallowing emit_hook_lifecycle helper; wires Created/Removed after hook creation/removal and transition-guarded Enabled/Disabled in enable_hook/disable_hook. Scanner emits scanner_faults() event when faulted_regions > 0, wrapped in try/catch.
Central header wiring and documentation
include/DetourModKit.hpp, README.md, AGENTS.md
Adds diagnostics_dump.hpp to the central DetourModKit.hpp include set; updates README Features table and adds Diagnostics details section; updates AGENTS.md header descriptions.
Event bus, dump, hook-manager, and scanner tests
tests/test_diagnostics.cpp, tests/test_diagnostics_dump.cpp, tests/test_hook_manager.cpp, tests/test_scanner.cpp
DiagnosticsEventBusTest covers singleton stability, payload delivery, and RAII unsubscription. DiagnosticsDumpTest covers zero-input snapshot, leak/hook/anchor/drift aggregation. Hook-manager tests verify kind/transition/order across inline/mid/vmt operations including no-op and failure negatives. Scanner test validates ScannerFaultEvent fields during concurrent decommit sweep.

Sequence Diagram(s)

sequenceDiagram
  participant Consumer
  participant HookManager
  participant emit_hook_lifecycle
  participant hook_lifecycle_dispatcher
  participant Subscriber

  rect rgba(70, 130, 180, 0.5)
    note over Consumer,HookManager: Hook creation / removal / state change
    Consumer->>HookManager: create_inline_hook(name, ...)
    HookManager->>HookManager: insert hook (locked)
    HookManager->>emit_hook_lifecycle: (name, Inline, Created)
    emit_hook_lifecycle->>hook_lifecycle_dispatcher: emit_safe(HookLifecycleEvent)
    hook_lifecycle_dispatcher->>Subscriber: deliver event
  end

  rect rgba(60, 179, 113, 0.5)
    note over Consumer,HookManager: Enable / disable with transition guard
    Consumer->>HookManager: enable_hook(name)
    HookManager->>HookManager: detect Disabled→Active transition
    HookManager->>emit_hook_lifecycle: (name, Inline, Enabled) only if transitioned
    emit_hook_lifecycle->>hook_lifecycle_dispatcher: emit_safe(HookLifecycleEvent)
    hook_lifecycle_dispatcher->>Subscriber: deliver event
  end

  rect rgba(205, 92, 92, 0.5)
    note over Consumer,Subscriber: Snapshot aggregation
    Consumer->>Diagnostics_collect: collect(hooks, anchor_report, drift_report)
    Diagnostics_collect->>HookManager: query hook counts by HookStatus
    Diagnostics_collect->>Anchors_assess_quality: assess_quality(anchor_report)
    Diagnostics_collect->>Diagnostics_collect: tally DriftEntry::ok healed/failed
    Diagnostics_collect-->>Consumer: Snapshot
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • tkhquang/DetourModKit#48: Adds VMT hook support and related HookManager VMT APIs (create_vmt_hook/remove_vmt_hook) which this PR wires Created/Removed lifecycle emissions into.
  • tkhquang/DetourModKit#70: Modifies the EventDispatcher lock-free atomic-snapshot implementation that the new scanner_faults() and hook_lifecycle() dispatchers in this PR depend on for emit_safe() and RAII subscription behavior.
  • tkhquang/DetourModKit#113: Changes guarded TOCTOU/SEH skip logic in the scanner's faulted-region path, the same code site where this PR adds Diagnostics::scanner_faults().emit_safe(...) emission.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main additions: anchor fingerprinting and typed diagnostics events. Both features are core changes reflected throughout the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/test_hook_manager.cpp (1)

3071-3072: ⚡ Quick win

Use explicit captures for subscribed callbacks.

These lambdas are stored by subscribe, so broad [&] capture should be narrowed to explicit references (e.g., &events, &count) to avoid accidental lifetime/capture expansion.

Suggested change
-    auto sub =
-        Diagnostics::hook_lifecycle().subscribe([&](const Diagnostics::HookLifecycleEvent &e)
+    auto sub =
+        Diagnostics::hook_lifecycle().subscribe([&events](const Diagnostics::HookLifecycleEvent &e)
                                                 { events.push_back({std::string(e.name), e.kind, e.transition}); });

-    auto sub = Diagnostics::hook_lifecycle().subscribe([&](const Diagnostics::HookLifecycleEvent &) { ++count; });
+    auto sub = Diagnostics::hook_lifecycle().subscribe([&count](const Diagnostics::HookLifecycleEvent &) { ++count; });

As per coding guidelines: "use explicit capture lists ([this, &var1, &var2]) for lambdas passed to threads or stored."

Also applies to: 3102-3103, 3118-3118, 3132-3133, 3151-3152

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_hook_manager.cpp` around lines 3071 - 3072, The lambda expressions
passed to Diagnostics::hook_lifecycle().subscribe() use broad [&] captures,
which is unsafe for stored callbacks because variables' lifetimes may not extend
as long as the stored lambda. Replace the [&] capture with explicit captures of
only the variables actually used: at tests/test_hook_manager.cpp lines 3071-3072
change [&] to [&events] (capturing only the events variable used in the lambda
body), at lines 3102-3103 apply the same pattern with explicit captures for
variables used, at line 3118 apply explicit captures for variables used, at
lines 3132-3133 apply explicit captures for variables used, and at lines
3151-3152 apply explicit captures for variables used. For each lambda, only
include references to variables that are actually accessed within the lambda
body.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/anchors.cpp`:
- Around line 199-213: The fnv1a_cascade function currently hashes the raw
candidate.pattern text, which means semantically equivalent patterns with
different formatting (spacing, case variations, etc.) will produce different
hashes and be incorrectly classified as different evidence. Instead of hashing
the raw pattern field directly, canonicalize or normalize the pattern to its
parsed byte representation (or an equivalent normalized form) before passing it
to the hashing function so the fingerprint reflects the actual resolution
evidence rather than textual formatting variations.

---

Nitpick comments:
In `@tests/test_hook_manager.cpp`:
- Around line 3071-3072: The lambda expressions passed to
Diagnostics::hook_lifecycle().subscribe() use broad [&] captures, which is
unsafe for stored callbacks because variables' lifetimes may not extend as long
as the stored lambda. Replace the [&] capture with explicit captures of only the
variables actually used: at tests/test_hook_manager.cpp lines 3071-3072 change
[&] to [&events] (capturing only the events variable used in the lambda body),
at lines 3102-3103 apply the same pattern with explicit captures for variables
used, at line 3118 apply explicit captures for variables used, at lines
3132-3133 apply explicit captures for variables used, and at lines 3151-3152
apply explicit captures for variables used. For each lambda, only include
references to variables that are actually accessed within the lambda body.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 97768fc0-7336-40ec-8c18-aeb79c77a0d0

📥 Commits

Reviewing files that changed from the base of the PR and between 83369f9 and c9a2edb.

📒 Files selected for processing (17)
  • AGENTS.md
  • README.md
  • docs/misc/anchors.md
  • include/DetourModKit.hpp
  • include/DetourModKit/anchors.hpp
  • include/DetourModKit/diagnostics.hpp
  • include/DetourModKit/diagnostics_dump.hpp
  • src/anchors.cpp
  • src/diagnostics.cpp
  • src/diagnostics_dump.cpp
  • src/hook_manager.cpp
  • src/scanner.cpp
  • tests/test_anchors.cpp
  • tests/test_diagnostics.cpp
  • tests/test_diagnostics_dump.cpp
  • tests/test_hook_manager.cpp
  • tests/test_scanner.cpp

Comment thread src/anchors.cpp Outdated
Reword the doc and comment (the cascade pattern is hashed as authored, not re-parsed to canonical bytes) and pin it with a test. Switch the diagnostic-bus test subscribe lambdas to explicit captures per the stored-lambda convention.
@tkhquang tkhquang merged commit a31789e into main Jun 14, 2026
4 checks passed
@tkhquang tkhquang deleted the feat/anchor-fingerprint-diagnostics-events branch June 14, 2026 20:09
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