There is a gap that opens between two events that feel like one event and are not: the client accepting a deliverable, and you billing for it.
Acceptance is a thing the client does. Invoicing is a thing you do. Nothing in the world connects them. If the second one does not happen, nothing breaks, nothing turns red, and nobody complains — least of all the client, who has what they asked for and no outstanding request for money.
Think about where a finished-and-accepted deliverable sits in a tracker built around outstanding work.
It is not overdue, so it does not appear in anything that filters on a date passing. It is not in progress, so it is absent from your active work. It is not a task, because you completed the task — the note, if you keep one, is ticked. It is done, and a view built to surface outstanding work stops at done.
That is the whole problem. The gap is invisible not because it is hidden but because a view built to track unfinished work cannot show a finished thing — and this thing is finished. Seeing it takes a different question: what is complete, and unpaid?
You cannot query a distinction you have not recorded. So the first move is not a query, it is a decision about states.
A single done state merges three different situations: you finished it, you sent it, and the client agreed it was what they wanted. Those have different consequences. A deliverable you have finished and the client has not accepted is not revenue — it is risk sitting on your side of the table.
So drop done and use states that keep the events apart:
not_started → in_progress → submitted → accepted (or rejected)
Then record the two dates separately — submitted_date and accepted_date — and keep one more field, invoice, which is either a link to the invoice or empty.
That last field is the entire mechanism. status: accepted with an empty invoice is work you have delivered and never billed for. It is now a condition you can write down, which means it is a condition a machine can look for.
Once the states and the invoice field exist, finding the gap takes one query. In Obsidian, with the Dataview plugin:
TABLE WITHOUT ID file.link AS Deliverable, engagement AS Engagement, accepted_date AS Accepted, value AS Value
WHERE type = "deliverable" AND status = "accepted" AND !invoice
SORT accepted_date ASC
!invoice is the load-bearing part: it matches notes where the field is empty. Sorting by accepted_date puts the oldest first, which is the order in which they stopped being visible.
Run it against a vault with a few months of history in it. The result is either an empty table, which is a genuinely useful thing to know, or it is not.
The same modelling gives you another view for free — everything submitted and not yet accepted, with a count of how long it has been waiting:
TABLE WITHOUT ID file.link AS Deliverable, engagement AS Engagement, submitted_date AS Submitted, (date(today) - date(submitted_date)).days AS "Days waiting"
WHERE type = "deliverable" AND status = "submitted"
SORT submitted_date ASC
This one watches the other end of the same pipe. Work sitting in submitted is work you have done that has not yet become billable, and a number of days next to it is harder to ignore than a feeling that something is taking a while.
One habit makes all of the above work, and without it the accepted state becomes guesswork: write the acceptance criteria before the work begins, and write them so a third party could check them.
"Covers all four product lines with a recommendation and a sensitivity range for each" is a criterion. "Is useful" is not. If you cannot say what accepted means, the deliverable is not scoped, and you are about to do work whose completion is somebody else's opinion.
own publisher under that publisher's own terms.
licensed, which is what runs the queries above. You install it yourself from Obsidian's community plugin browser, from its own author, under its own licence. No plugin code is bundled by us.
Without Dataview, a query block renders as an inert code block and every note is still plain readable markdown. Nothing is locked up in a format you cannot read.
The deliverable template, the meeting note, the engagement record and the tracker containing both queries above are published as a free, MIT-licensed repository:
https://github.com/engagementdesk/obsidian-consulting-components
Copy templates/ and dashboards/ into your vault, enable Dataview, and open dashboards/deliverable-tracker.md. The components are complete and usable on their own.
More guides on running client engagements in Obsidian: all guides.
---
Engagement Desk is not affiliated with, endorsed by, or supported by Obsidian or by the author of Dataview. Those are separate products from separate publishers, distributed under their own terms.