Crosshire
← Handbook
EngagementIntake · feasibility · tickets

19Requirements

This route decides how a sentence spoken in a meeting becomes a table in gold — and how it gets refused when it cannot. Three artefacts do the work: an intake short enough that people actually fill it in, five feasibility questions asked in a fixed order, and a link between the requirement and the object that satisfies it that survives both of them leaving the company.

Stand 29.07.2026

Intake

The request arrives as one sentence in a meeting. Everything expensive that follows is decided by how much of the rest gets written down in the next twenty minutes.

#The seven-field intake

What
Seven fields, one screen, filled in during the meeting. It is deliberately shorter than the template the client already has, because a form nobody completes is not a control — it is a folder.
The intake, with a worked request (REQ-118)
FieldWhat it must containREQ-118
1 · Requester + ownertwo names; the owner is whoever signs the number offrequester: Head of Sales DE. Owner: Finance Controlling.
2 · The questionone sentence, worded as the report title would beMonthly revenue by customer segment and country, DE / AT / CH / NL.
3 · Decision it changeswhat somebody does differently depending on the answerthe quarterly segment-discount review, run today off a spreadsheet.
4 · Grain, slices, as-ofone row per what, sliced by what, and as of whenone row per month × customer_segment × country; segment as of the order date, not today.
5 · Measure definitionthe arithmetic and the edge cases, citing the business ruleSUM(amount_eur) excluding status = 'CANCELLED' (rule 1); amount_eur already converted at the order-date rate (rule 2).
6 · Source + freshnesswhich objects, and how late is too lategold.fct_order_line + gold.dim_customer; loaded daily by 07:00 CET; month closes on working day 3.
7 · Acceptance testa query, a number, and who runs itthe query below; the June 2026 total agreed with Finance to the cent; the requester runs it.
Field four does most of the work, and field seven is the one that turns the rest into something checkable. Write the acceptance query during intake, against whatever exists today, even if it returns nothing:
sql
REQ-118 acceptance test — agreed before build, run by the requester
-- Rule 1: revenue excludes CANCELLED.
-- Field 4: customer_segment AS OF the order date.
SELECT
  DATE_TRUNC('MONTH', f.order_ts)   AS month,
  c.customer_segment,
  c.country,
  ROUND(SUM(f.amount_eur), 2)       AS revenue_eur,
  COUNT(DISTINCT f.order_id)        AS order_count
FROM gold.fct_order_line f
JOIN gold.dim_customer   c
  ON  c.customer_sk = f.customer_sk
  AND f.order_ts   >= c._tech_valid_from
  AND (c._tech_valid_to IS NULL OR f.order_ts < c._tech_valid_to)
WHERE f.status <> 'CANCELLED'
  AND f.order_ts >= TIMESTAMP '2026-06-01'
  AND f.order_ts <  TIMESTAMP '2026-07-01'
GROUP BY ALL
ORDER BY month, customer_segment, country;

-- The other reading of the same sentence -- segment as of TODAY -- is
--   ON c.customer_sk = f.customer_sk AND c._tech_is_current
-- and returns a different number. Field 4 exists so that choice is made once,
-- by the owner, and not by whoever writes the join.
Why here
Intake is not paperwork. It is the only moment when a definition problem costs nothing to fix. Most the numbers do not match incidents in a warehouse are not bugs — they are one measure defined twice, once in the pipeline and once in someone's head, and both definitions are defensible.
Field three is the one that kills work, which is why it earns a place on a seven-field form. A request with no decision behind it becomes a report that is opened twice, maintained for four years, and included in every migration because nobody can prove it is unused.
Doing it
  • Fill the form in the meeting, out loud, with the requester watching your screen. Emailing the template gets it back in three weeks with fields four and five empty.
  • Write and run the acceptance query during intake, even against an empty gold — running it proves the objects and the join are agreed.
  • Force the as-of decision explicitly whenever the request touches an SCD2 dimension, and record which reading was chosen.
  • Restate the measure in your own words and wait. There is always a correction, and it is always cheaper now.
  • Issue the requirement ID before anyone leaves the room; every branch, PR and table tag downstream references that string.
Embedding it
  • Have an engineer run the next intake with you in the room and silent unless asked. They run the one after alone.
  • Back the team the first time they refuse an incomplete intake, in front of the requester. Whether the form is real is decided that afternoon, once, permanently.
  • Ask 'what gets decided differently?' in refinement until somebody else asks it before you do.
  • Have the team keep the list of requests that died at field three. At the next steering meeting it is a stronger argument for the process than any slide you could write.
Defaults
  • Seven fields, one screen, completed in the meeting — not sent as homework.
  • The acceptance test is a query and a number, agreed before a line of build.
  • Measure definitions cite the business rule number instead of restating prose per ticket.
  • Every requirement has one named human owner. 'The business' is not a name.
Gotchas
  • 'Segment as of today' versus 'segment as of the order date'. Both joins are correct SQL and they return different revenue. The divergence grows silently as customers move segment, and it surfaces months later as a trend chart that restates itself — which reads exactly like the business changing.
  • An acceptance test written after the build. It is then written against what was built, passes by construction, and proves only that the code does what the code does.
  • Field five answered with 'revenue, the usual'. Rule 1 (exclude CANCELLED) and rule 2 (the rounding in amount_eur) are precisely the 'usual' on which finance and sales differ by a few percent — enough for the report to be disbelieved once and then never trusted again.
  • Skipping field six because latency 'is a technical detail'. A daily 07:00 load against a request that assumed intraday is discovered in UAT, by the requester, in front of their own stakeholders.

Feasibility, in order

Five questions, cheapest first. The order is the technique: three of the five can kill a request outright, and asking them out of order is how a sprint gets spent building something the data-protection officer was always going to veto.

#The five questions

What
Each question has an owner, a cost, and a meaning when the answer is no. None of them is 'is it hard?' — difficulty is an estimate, not a feasibility gate.
Asked in this order, every time
#QuestionAnswered byCostWhat 'no' means
1Does the data exist in any source system at all?the source owner, in a messageminutesthis is a source project, not a warehouse project — it leaves your backlog today
2Does it reach us at the grain and latency the request needs?the bronze table and the job schedulean houra new feed or a cadence change: costed, scheduled, and dependent on someone else
3Does the source carry the history the question needs?the extract's specification — not its contentsa morningfrequently fatal, always a surprise; see bronze.sap_kna1 below
4Do the keys survive conformance across sources?profiling the joina daythe answer stays per-source until someone makes an identity decision
5Is anyone allowed to see it?the classification and the access policya week — it involves people outside the teama masked or aggregated version of the request, or nothing
Cheapest disqualifier first, with one exception: if the request names a column classified as personal data — dim_customer.email, .phone, .street — ask question five first. It is the only one of the five whose answer is not yours to give, and the only one that can be reversed by someone who was not in the room.
Why here
The expensive mistake is symmetrical. Refusing something feasible sends the work to a spreadsheet you will never see again; accepting something infeasible spends a sprint and then costs the credibility you needed for the next three.
A fixed order makes 'no' a position in a sequence rather than an opinion. Question three failed, here is the probe I ran, here is what the source does not record. That is a sentence a junior engineer can say to a stakeholder; 'I don't think we can' is not.
Doing it
  • Run the five in order, out loud, with the requester present. The sequence is the argument.
  • Timebox each: question one is a message, question five is a meeting. Two days into question three IS the answer — the history is not there.
  • Record which question failed on the requirement itself. In six months nobody remembers whether it was a source problem or a governance one, and the request comes back.
  • Jump straight to question five whenever email, phone or street appears in the request.
Embedding it
  • The team runs the five; you hold the clock. Any question that overruns its box is itself a finding worth discussing.
  • Make them ask question one of the source owner directly rather than routing it through you — that relationship is part of the handover, and it does not transfer at the end.
  • Walk one feasible request through all five so the team sees the sequence when the answer is yes. A team that only ever sees it applied to refusals learns it as a rejection ritual and quietly drops it.
  • When they reach question five, hand the conversation to the data-protection owner in front of them. The lesson is that this answer has an owner, and it is not an engineer.
Defaults
  • Fixed order, cheapest first; anything naming personal data jumps to question five.
  • Every failed question is recorded with its evidence, not summarised as 'not feasible'.
  • Feasibility ends in three options, never in a verdict.
  • Question three is asked about semantics, question four about data — do not swap them.
Gotchas
  • Answering question one by looking in the warehouse. The warehouse shows only what was already ingested, so you get a 'no' that actually means 'not yet' and a viable request dies of a lookup.
  • Profiling data to answer question three. A snapshot source looks history-rich — many rows per customer — while the thing being asked for, when and why it changed, is not in there at any row count.
  • Question five answered by an engineer. 'We can mask it' is true and is not the same statement as 'you may have it'. The engineer's yes gets quoted back six weeks later by someone who never spoke to the data-protection owner.
  • Treating question four as a modelling task instead of a feasibility one. If SAP customers and webshop customers share no resolvable key, no amount of dimension design produces conformed revenue — and that is a finding for the intake, not a ticket for the sprint.

#Question three failing: bronze.sap_kna1

What
REQ-118's field four already asked for segment as of the order date, and the owner's follow-up makes the dependency explicit: show me when customers moved between segments, and how many moved last year. Both readings need the same thing — a history of segment changes — and both are bounded by the same source. That source is bronze.sap_kna1, the SAP customer master as a daily full extract with no change timestamp. Nothing in the file says a change happened; the change is the difference between two files.
  • Answerable: that a customer's segment differs between two extracts we hold — to a resolution of one day, forward from the first snapshot retained.
  • Not answerable: anything before that first retained snapshot. No engineering recovers it, at any budget. The information was never sent.
  • Not answerable: a change that happened and reversed between two extracts. A → B → A over a weekend is, to this source, no change at all.
  • Silently misdated: a change on a day whose extract never arrived is dated to the next extract we hold, and nothing marks it as approximate.
Before promising anything, run the probe. It reads _tech_extract_date — the fourth technical column this source carries beyond the standard three, the extract's business date parsed from the filename by the Ingestion job. It takes a minute and it converts the estimate from a hope into a date:
sql
The feasibility probe — run during intake, not during build
-- How far back can this source answer 'when did it change'?
-- _tech_extract_date is the extract's BUSINESS date, taken from the filename.
-- _tech_loaded_at would answer a different question -- when we loaded it --
-- and would move every answer on the day the extracts are re-run.
SELECT
  MIN(_tech_extract_date)                       AS earliest_snapshot,
  MAX(_tech_extract_date)                       AS latest_snapshot,
  COUNT(DISTINCT _tech_extract_date)            AS snapshots_held,
  DATEDIFF(MAX(_tech_extract_date), MIN(_tech_extract_date)) + 1
    - COUNT(DISTINCT _tech_extract_date)        AS missing_days
FROM bronze.sap_kna1;
earliest_snapshot is the honest start of the answer. missing_days is the honest caveat: each missing day is a day on which a real change gets stamped with the wrong date, invisibly. If the probe returns 2026-03-14 and four missing days, the sentence you owe the requester is 'from 14.03.2026, to the day, except across four days where the date may be late' — not 'partially'.
Building it, once an option is chosen, is the snapshot-comparison pattern in the Ingestion route. This route only decides what may be promised.
Why here
This question gets skipped because the table looks rich: a year of rows, one per customer per day. Grain is not history. A year of states and a year of changes are different things, and the request lives exactly in the gap between them.
Skipping it does not cost a sprint — it costs the engagement's credibility. You promise a churn number, build the pipeline correctly, and deliver a chart that starts in March to a business that asked about last year. Everything you did was right and the deliverable is still wrong.
Doing it
  • Ask the source team for the extract's specification, not a sample. A sample cannot tell you whether a change timestamp exists.
  • Run the probe before the estimate. Quoting a history start date you have not queried is how the March boundary becomes a surprise in the demo.
  • State the limitation as a date and a count, in the requirement, in the requester's language.
  • Record intra-extract reversal as a known limitation — it is invisible by construction, so it will never be found later by testing.
Embedding it
  • Hand the team the probe and the request and let them find the March date themselves. Being told the source has no history is forgettable; watching MIN() return a date three months ago is not.
  • Have the team member who found the limitation write the sentence to the requester. Delivering a limitation is the skill being transferred, and you cannot transfer it by doing it for them.
  • Ask 'what does this source not know?' at every new-feed refinement until somebody answers before you finish the question.
  • Ask the same question of bronze.sap_vbak and let them find that there is nothing to probe: CDC carries a change timestamp per record, so question three is settled from the extract's specification in a minute. Contrast is what makes the distinction stick — one source needs a query to find its limit, the other has none to find.
Defaults
  • Interrogate the source's semantics before its contents.
  • Every promise about history cites a queried date, never an adjective.
  • Limitations that follow from the source live on the requirement and later in the table COMMENT.
  • Snapshot sources make bronze retention a correctness requirement, not a storage preference — say so at intake, because it is a cost.
Gotchas
  • 'We have a year of data' offered as the feasibility answer. It is a year of states. The request wanted changes, and the two coincide only where the source records a change event — which this one does not.
  • Deriving the change date from _tech_loaded_at instead of the extract's business date. Re-running last month's extracts on a Friday stamps every change that Friday, the report shows one enormous migration day, and every job was green.
  • Promising a backfill from the source archive before anyone has opened it. Archives are routinely incomplete, differently formatted, or kept for thirty days — all of which you discover after the commitment, not before.
  • Treating missing_days as an operations problem to fix later. For this request it is a correctness caveat owed to the business now, because the misdating is silent and no downstream test can detect it.

#Never a flat no

What
'Not possible' ends the conversation and moves the decision to whoever says yes next — usually a spreadsheet. Replace it with three options: what we can do now, what we could do with someone else's help, and what it would take to answer the question properly. Each carries a cost, a dependency, and the part people omit: what it still does not answer.
REQ-118's history problem, as three options
What you getCostDepends onStill not answered
A · compare snapshots forwardsegment changes to the day, from the first retained extract~2 days, this sprintnothing outside the teamanything before that date; reversals inside one extract interval
B · request change documents from SAPtrue change dates including history, back to SAP's own retention1 day our side, 4–8 weeks lead timethe SAP team's backlognothing — if it arrives, and it arrives later than anyone plans for
C · reconstruct from the extract archivepossibly several extra months of history1 sprint, quality unknown until it is openedthe archive existing and being completewhatever the archive lacks — and you find that out at the end
Present all three, name your recommendation, let the owner choose, and write the choice into the requirement including the two that were rejected. In month nine somebody asks why the history starts in March, and the answer has to be a decision with a name and a date on it.
Why here
A flat refusal is heard as the platform cannot do this. It does not stop the report from being built — it stops the report being built where you can govern it, test it, or find it during the next audit.
Three options also move the trade-off to the person who owns it. Whether four weeks of waiting is worth a year of history is a business decision, and every time an engineer makes it silently the business later discovers it was made and resents both the choice and the process.
Doing it
  • Never present fewer than three, and never pad to three with an option you would not take. A straw option is spotted instantly and it costs you the credibility of the other two.
  • Cost in days and dependencies, not in t-shirt sizes. 'Large' is not a number anyone can plan against.
  • State what each option still does not answer. That is the sentence people quote back to you, correctly, in six months.
  • Recommend one. Three options with no recommendation is abdication wearing the costume of neutrality.
  • Write the decision, the date, the decider and the rejected options into the requirement before the meeting ends.
Embedding it
  • The engineer who found the limitation presents the three options, with you in the room and quiet. Whoever finds the problem should carry the conversation.
  • Rehearse five minutes before: ask what option C costs. If they cannot say, the option is not real yet and the meeting will expose that.
  • Ban 'not possible' from stand-up. The replacement phrase is 'not from this source — three options', and the team will start using it on each other first.
  • When the business picks the cheap option against your recommendation, write it down and move on visibly. The team is watching to learn whether disagreeing with a stakeholder is survivable here.
Defaults
  • Three real options, honest costs, one stated recommendation, one written decision.
  • Every option names what it still leaves unanswered.
  • Rejected options stay on the requirement — they are the answer when the same question returns next year.
  • Anything depending on a third party is quoted as a lead time, never as an estimate.
Gotchas
  • The straw option. Padding to three with something obviously unserious teaches the room that the exercise is theatre, and the next set of options gets read as sales material.
  • Costing option B at one day because your part is one day. The SAP team's queue is the schedule; a plan that quietly assumes otherwise slips in public, and it slips at the demo.
  • Options with no recommendation. The business picks the cheapest, hits its limitation, and feels misled — correctly, because you already knew which limitation they were choosing.
  • Letting the chosen option live only in a slide. The chart's history starts in March forever, and whoever inherits it treats March as a bug and re-investigates the whole thing from scratch.

From requirement to table

Two objects with different lifetimes, and one link that has to survive a backlog migration, a table rename, and both original humans leaving.

Straight to the documentation

The generic platform material lives in the official docs and is not restated here. These are the pages worth having open while you work through this route.

  • Attribute-based access control in Unity Catalogfeasibility question five — what a tag-driven policy can actually do, before you promise it at intake
  • ALTER TABLEexact SET TAGS syntax, so the requirement link is deployable DDL rather than a click
  • Information schemathe column names behind the orphan sweep — tables and table_tags differ in how they name catalog and schema
  • Lineage system tables referencethe two retention regimes that decide whether a historical audit question is answerable at all
  • System tablescheck the platform-side question — who read it, what it cost — is answerable before you accept a request that assumes it
Platform facts on this page verified 29.07.2026 against the official documentation. Volatile claims are anchored to the currency register.