D365 keeps no dedicated actor column for the actions that matter most to an auditor. If your usage-evidence plan assumes "the ERP surely logs who posted," it is built on a column that does not exist.

The column you expect is not there

Across one client's entire D365 Finance and Supply Chain schema, exactly 1 table carried a `PostedBy` column, 4 carried `CancelledBy`, and 18 carried `ApprovedBy`. Set that against 2,229 tables carrying `ModifiedBy` and the picture is clear: D365 does not model "who performed this verb" as a first-class fact. It models document state.

Posting, cancellation, approval, confirmation, and firming are not stored as "user X did verb V at time T." They are stored as a status enum on the record (`Posted`, `WorkStatus = Cancelled`, and similar) plus whatever `ModifiedBy` happened to be stamped when the status flipped. There is no separate identity field waiting to be read.

Why "the ERP logs who posted" is false

The intuition comes from smaller systems where a posting routine writes an audit row naming the user. D365 does not work that way for its highest-stakes operations. When a journal is posted, the header's `ModifiedBy` is bumped, blended together with every other edit that record ever received. The person who posted is indistinguishable from the person who changed a description, reopened the journal, or corrected a dimension an hour earlier.

So the header cannot answer "did this user post this journal?" The `ModifiedBy` value on the header is the last writer of any kind, not the poster. Reading it as a posting signal produces confident, wrong attribution.

Where the signal actually lives

The reliable answer is downstream. Posting a document creates rows on a terminal transaction table that exist only as a consequence of the post. Those rows carry `CreatedBy`, and that stamp is the human (outside batch, covered separately). So:

The pattern is consistent: read `records_created` on the terminal table, never `records_modified` on the header. `CreatedBy` on a terminal row means that row did not exist until this action ran, so the create stamp is the actor. `ModifiedBy` on a header means someone touched a record that already existed, which is a much weaker claim.

Why this reshapes the write-evidence strategy

If you start from the header, you get three failures at once. You attribute the post to the wrong person (the last modifier). You cannot separate the preparer from the poster, which is exactly the segregation-of-duties question an auditor cares about. And you miss the writes entirely when the terminal table, not the header, is where the action left its mark.

Starting from the terminal table fixes all three. The create stamp names the actor, the preparer never appears on the terminal table because they never triggered the post, and the evidence is the write that actually happened.

This also means the evidence is indirect by design, not by accident. You are never going to point at a `PostedBy` column, because the platform does not maintain one. The honest version of the claim is "this user created the posted output of this action," and that is a stronger claim than any header field could support.

What this costs you, and what it does not

It is tempting to want a dedicated `records_cancelled` or `records_posted` extraction column. The schema evidence says it is not worth building. The verb-actor columns that do exist number roughly 34 tables across the whole schema, and none of them intersect the privileges that drive license cost. You would build a special extraction path to populate columns that almost no table has and that never touch the decisions you are trying to make.

For cancellation and approval specifically, the evidence lives in the status enum plus `ModifiedBy`, which is weaker than the terminal-table create signal available for posting. Treat those as "rules out a drop" evidence, not as positive confirmation that a named user performed the verb.

Bottom line

D365 answers "who posted this?" only indirectly, through `records_created` on the downstream terminal table, and never through an actor column on the document header. Any usage-evidence model that reads the header `ModifiedBy` as a posting signal is attributing the action to the last editor, not the poster. Build the write-evidence strategy on terminal-table create stamps from the start, and treat the absence of verb-actor columns as a permanent property of the platform rather than a gap to be patched.

Frequently asked questions

Does this mean there is no audit trail for posting at all?

No. The posting leaves a durable trail on the terminal transaction table, and those rows carry a create stamp. The point is that the trail is downstream of the document, not a labeled field on the document.

Can we just turn on the D365 Database Log to capture who posted?

The Database Log and audit-trail features track field changes on configured tables and carry their own performance and scope tradeoffs. They do not retroactively add a `PostedBy` column to the standard schema, and they are not the per-table create-stamp aggregate this method relies on. Scope and licensing of those features should be checked against Microsoft Learn before you plan around them.

Why not just read `ModifiedBy` on the journal header?

Because it names the last person to touch the record for any reason, which blends the poster with every other editor and defeats the preparer-versus-poster distinction.