Consumers need to be told, in this project's own documentation, not to log per access-check call. Without it the obvious integration is also the one that destroys the chain's usefulness.

Carried over from mcp_sentinel #3613759 ("Publish the dedup guidance below for consumers"), which was the plan issue for extracting this module. The guidance was written there; it has not been published here, and here is where consumers will actually arrive.

GitHub mirror: https://github.com/Wilkes-Liberty/audit_chain/issues/3

The guidance

Consumers must not log per access-check call. A field-access hook fires per field, per entity, per render — naive logging floods the chain and makes it unreadable, which defeats the purpose. Deduplicate per request and flush once at kernel.terminate.

Why this is not merely a nice-to-have

The driver that motivated extracting this module in the first place was a module recording reads of access-controlled fields. That is the single worst case for naive logging: hook_entity_field_access can fire dozens of times for one page render, so a per-call log() turns one human action into dozens of chain entries. A tamper-evident log nobody can read is not evidence, and the damage is not reversible after the fact — you cannot un-flood a hash chain without breaking it.

So the first consumer likely to exist is the one most likely to get this wrong, and the project ships no warning.

Remaining tasks

* Add a "Writing to the chain" / consumer-integration section to README.md with the dedup rule and the kernel.terminate flush pattern.
* Mirror it on the drupal.org project page — that is what an evaluator reads before installing.
* Consider whether the module should make the safe path the easy one: a request-scoped collector service that dedupes and flushes on terminate, so a consumer gets it right by calling the obvious thing rather than by having read the docs.

The third item is the real fix. Documentation that says "do not do the obvious thing" is weaker than an API where the obvious thing is correct.

Comments

jmcerda created an issue. See original summary.

jmcerda’s picture

Status: Active » Fixed

Fixed on the 1.x branch.

The guidance is published in the README, but the substantive part is the API. `audit_chain.collector` buffers entries per request, deduplicates them, and writes once at `kernel.terminate` — so a consumer logging from a per-field access hook gets the safe behaviour by calling the obvious thing, rather than by having read a warning.

Deduplication is by channel, operation and the promoted entity keys, overridable per call. First occurrence wins and metadata is **not** merged: forty reads of one node is still one read, and a union of forty payloads would describe an action nobody took.

Writing after the response also keeps the chain's append lock off the request's critical path — it serialises across the whole site, so holding it mid-request makes concurrent requests wait on work none of them needs.

Covered by seven tests, including one asserting that deferred entries still form a chain `verify()` accepts: deferring the write must not weaken the guarantee the module exists for.

Still to do, and not part of this fix: mirroring the guidance onto this project page, which is where an evaluator reads before installing.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

jmcerda’s picture

Version: 1.0.1 » 1.1.0

Fixed in 1.1.0 (GitHub #3). Request-scoped collector (audit_chain.collector) dedupes and writes once at kernel.terminate so the obvious integration is safe.

jmcerda’s picture

Status: Fixed » Closed (fixed)

Shipped in 1.1.0. Closing after release.