Enablement fails quietly: everything ships, everyone is happy, and six months later every change still arrives as a ticket addressed to you. The fix is to make transfer a number that is visible from week one.
Your share of the work starts near total and falls to near nothing; theirs rises to meet it. The crossover is the deliverable. Put the curve in the statement of work with numbers, because a curve that stays a metaphor never gets measured.
Sixteen weeks, with the signal that tells you the week actually happened
Week
Your share of merged PRs
What the team owns
Signal
1–2
~90%
nothing yet — reading, then workshop 1
the layer contract is committed, by them
3–5
~70%
one silver table end to end
the first PR you did not have to touch
6–8
~45%
two gold tables and the CI job
they review each other before you see it
9
~30% — crossover
the alert rota
you come off the rota and nothing changes
10–12
~15%
all pipelines, all runbooks
an incident resolved without you
13–16
≤10%
everything; you review by exception
game day survived; your name on no runbook
The percentages are not targets to hit exactly — the shape is. And it is measurable on the platform, not only in the repository, because what matters is who operates the warehouse rather than who types. Measure it as two lanes — consultant and team — and never as a ranked list of named people. The falling consultant share is the entire signal; identifying individuals adds nothing to it and adds a legal problem, which is the callout under the query.
Why
This prevents a warehouse that works and a team that cannot change it. The defect is invisible during the project, because during the project you are there. It surfaces the first time silver.customer needs a new attribute and nobody but you has ever opened src/dwh/common/scd2.py.
The second reason is commercial and works in your favour: a falling line is the only honest evidence a sponsor has that they bought capability rather than headcount. A line still flat in week 12 means staff augmentation at consultant rates, and eventually someone notices. Two numbers a week carry that argument completely — which is worth remembering when someone asks for the per-person breakdown, because the breakdown adds no evidence and converts a status note into monitoring data.
How
sqlConsultant share of write actions, by week. Run it weekly; paste the two numbers into the status note.
-- Action names differ per service. List yours first:
-- SELECT DISTINCT service_name, action_name FROM system.access.audit
-- WHERE event_date >= current_date() - INTERVAL 7 DAYS;
-- The lane map is the only thing you edit. Keep it in the repo next to the
-- engagement plan, so the measurement survives you leaving.
WITH lane AS (
SELECT * FROM VALUES
('you@partner.example', 'consultant'),
('maria@client.example', 'team'),
('jonas@client.example', 'team'),
('priya@client.example', 'team')
AS t(email, lane)
),
weekly AS (
SELECT date_trunc('WEEK', a.event_date) AS week,
coalesce(l.lane, 'other') AS lane,
count(*) AS write_actions
FROM system.access.audit a
LEFT JOIN lane l ON l.email = a.user_identity.email
WHERE a.event_date >= current_date() - INTERVAL 90 DAYS
AND a.service_name IN ('unityCatalog', 'jobs')
-- ANCHORED, and deliberately without 'run'. Unanchored, the alternation
-- binds the whole pattern and 'run' also matches runNow, runTriggered,
-- runSucceeded and runFailed: system-emitted job lifecycle events, one set
-- per scheduled run of every job, carrying the run-as identity. Ranked by
-- count they bury the human signal this is supposed to measure.
AND a.action_name RLIKE '^(create|update|delete)'
-- Platform-emitted events.
AND a.user_identity.email <> 'System-User'
-- Service principals: the identity is an application-id UUID, not an
-- address. A job's run-as principal is not a person learning anything.
AND a.user_identity.email LIKE '%@%'
GROUP BY ALL
)
SELECT week,
lane,
write_actions,
round(100 * write_actions
/ sum(write_actions) OVER (PARTITION BY week), 1) AS pct_of_week
FROM weekly
ORDER BY week, lane;
One prerequisite, in week 1: system.access is enabled per metastore and is not on by default — databricks system-schemas enable <metastore-id> access. Whether enabling backfills earlier events is not documented either way, so enable it before you need the first data point rather than at the moment you want to draw the curve.
Doing it
Put the curve and its measurement in the statement of work, with the week-9 crossover namedWrite down there that it is measured by lane, not by person.
Run the two-lane query every Friday and publish both numbersThat includes the weeks the consultant lane moves the wrong way.
Before measuring anything per named person in a client's workspace, get it cleared with the works council in writingThe lane aggregate needs no clearance; a named ranking does, and asking afterwards is how the whole measurement gets switched off.
From week 5, stop taking tickets that touch goldReview them instead; the queue slowing down is the point.
Leave the alert rota in week 9, not in the final week — standby for a fortnight, then off
Embedding it
In week 3 ask which two tables they will own end to endThen refuse to merge anything on those under your name.
When asked to do something you already taught, answer with the file path, not the fix
Have them present the architecture to their own stakeholders in week 8You sit at the back and say nothing.
In week 10 ask each engineer which part they would not want to be on call forThat names the gap while it is still cheap.
Move the lane map and the weekly query into the repo in week 3 and let a team member run itA measurement only you can produce stops the day you leave, and this is the one number the sponsor still wants in month six.
Defaults
Numbers in the statement of work, measured weekly, visible to the sponsor
Two lanes, never namesNothing the sponsor needs from this metric requires identifying an employee.
Off the alert rota by week 9 at the latest
One named human owner per gold table by week 6, written into the table COMMENT
The final quarter is theirs; you review by exception and write nothing
Gotchas
The line that never falls — you are faster, so you do it, so they never doIt does not show in the standup mood — it shows in the merged-PR count, which is why you count.
Publishing a per-person ranking of write actionsIt reads as a productivity leaderboard whatever you call it, it is Leistungskontrolle under §87(1)6 BetrVG, and a works council can have the entire measurement suspended — the lane aggregate with it. A metric that gets the monitoring practice switched off is worse than no metric, and you are doing this inside someone else's company.
Leaving the RLIKE unanchored'(?i)create|update|delete|run' matches runNow, runTriggered, runSucceeded and runFailed — one set per scheduled run of every job, emitted by the platform under the run-as identity. Ordered by count, the top of the result is service principals and System-User, and the curve you are trying to read is below the fold.
Reaching the crossover by removing yourself rather than raising themIt measures as success and arrives as a 3am incident nobody can resolve. Tell them apart by asking who wrote the last three runbooks.
Holiday as the real testIf the daily load cannot survive a week without you, week 9 did not happen whatever the chart says. Take that week off deliberately, in week 11.
A plateau presented as ownership — every non-trivial PR still waits on your approvalThey say they own it while you remain the gate. If you are a required reviewer everywhere, you are still the bottleneck under a new title.
One a week from week 2. Ninety minutes by default, two hours for modelling, six people maximum. The proportion is the argument: four on architecture and modelling, one and a half on testing, the rest on governance and operations. Teams ask for more tooling sessions because tooling feels productive — but a wrong CI configuration costs a day, and a wrong fact grain costs a rebuild of every report beneath it.
The eight, with the artefact each must produce
#
Week · length
Subject
Artefact — merged, or it did not happen
1
2 · 90 min
The layer contract
the contract table, filled in by them, committed to the repo
2
3 · 120 min
Grain and the star
gold.fct_order_line DDL with a grain COMMENT, merged
3
4 · 120 min
Keys and SCD2
the boundary table, plus two-changes-in-one-day written as a test
4
5 · 90 min
Ingestion decision table
all four sources placed, each with a written reason
5
6 · 90 min
Testing I — the pure function
one transform extracted to src/dwh/pipelines/transforms/silver_sales_order.py, with a test
6
7 · 90 min
Testing II — SQL assertions, then CI
three .sql assertions from RULES 1–7, running in the bundle test target
7
8 · 90 min
Governed tags, ABAC, PII
gold.dim_customer.email tagged; a column mask proven from two accounts
8
9 · 90 min
Runbooks and the re-run question
one runbook per pipeline, written by whoever gets woken
Workshop 7 used to spend its first half on preview caveats and a documented fallback. It no longer needs to: ABAC row filter and column mask policies, governed tags and automated data classification are all generally available, so the ninety minutes are entirely hands on gold.dim_customer. Every session runs the same six-segment sheet, and the segment that gets cut when you run late is the one that must not be:
Why
A workshop that ends in a slide is entertainment. The named failure is a team fluent in bronze/silver/gold that cannot say what one row of gold.fct_order_line is — discovered in month four, when the first aggregate double-counts and nobody can explain it.
The break it segment exists because the happy path teaches nothing durable. Ten minutes watching their own design fail a plausible business question beats an hour of correct explanation, and it is the part that survives into production instincts.
How
textRun sheet — workshop 2, the exemplar for all eight
WORKSHOP 2 — Grain and the star week 3 · 120 min · max 6 people
PREREQ everyone has run 'databricks bundle validate' and can query dwh_dev.silver
ARTEFACT gold.fct_order_line DDL merged to main, with a grain COMMENT
00:00 frame One sentence on the whiteboard: "one row per order line."
Nothing else may be written until everyone agrees it.
00:10 hands Team draws the star. Consultant holds the pen for zero minutes.
00:40 break it "Sales wants revenue per delivery, not per order line."
New fact, or does that change this grain?
01:10 build Write the DDL together. CLUSTER BY (customer_sk, order_ts).
01:40 commit PR opened by a team member, reviewed by a second team member.
Consultant comments; consultant does not approve.
02:00 close Each person names the one thing they would still get wrong.
The other seven sheets are this one with two substitutions: the artefact from the table above, and the provocation that drives break it. Those are the only two parts worth preparing — the six clock positions never change, which is why nobody has to think about the format. The provocations, in workshop order:
Layer contract — 'a dashboard needs a column that only exists in bronze. Where does it go, and what does the contract say?'
Grain and the star — 'Sales wants revenue per delivery, not per order line.'
Keys and SCD2 — 'the same customer changes customer_segment twice on one day. How many versions, and what are the interval bounds?'
Ingestion — 'bronze.sap_kna1 arrives with no change timestamp. How do you know which customers changed?'
Testing I — 'the transform needs today's date. Where does the clock come from, and how do you test yesterday?'
Testing II — 'your assertion returns zero rows against an empty table. Did it pass, or did it not run?'
Governed tags and ABAC — 'the analyst is excluded by the column mask. Can they still CLONE the table or TIME TRAVEL past it?'
Runbooks — 'the load failed at 02:00 and nobody knows why. Is it safe to re-run blind?'
Doing it
Publish all eight dates and artefacts before week 2That way the calendar is defensible when delivery pressure arrives.
Check the prerequisite the day beforeA room where half the people cannot connect loses forty minutes and its credibility.
Cap attendance at sixThe seventh person turns a workshop into a presentation.
Keep your hands off the keyboard during the hands and build segments, without exception
Embedding it
Hand facilitation over from workshop 5A team member runs the run sheet; you take notes and speak twice.
Have each artefact reviewed by someone who was not in the roomThat tests understanding rather than a shared mood.
At week 10, ask which workshop should be repeatedThe one they name did not land, and repeating it is cheap.
Let them write workshop 8's runbooks badly, then run an incident against what they wrote
Defaults
Weekly cadence, never a two-day bootcampHands need a week between them.
Ninety minutes default, 120 for modelling, six people, one merged artefact each
The same six-segment run sheet every time, so nobody spends attention on the format
Four sessions on architecture and modellingProtect that proportion when the schedule is squeezed.
Gotchas
The two-day kickoff bootcampRetention is near zero because nothing is applied between sessions; you re-teach SCD2 in week 7 and the client concludes their team is slow.
Workshops that drift into demosThe tell is the consultant being the only person typing for more than ten minutes. Say it out loud and hand over the keyboard.
Cutting break-it to finish on timeThey then learn only the happy path and meet the edge case in production, at the worst hour, without you.
Inviting the department for visibilityAbove six people nobody types, it becomes a status update, and the artefact is not built.
Teaching workshop 7 as a preview briefingGoverned tags, ABAC policies and classification went GA in May 2026; the old fallback wastes the session and installs a workaround the team keeps for years.