← All white papersBuild plan · September 2026

The Cited Answer on Microsoft 365

An assistant over your own documents is the easy half and you may already have it. The half that makes it safe to rely on is the part nobody ships by default.

10 min read·Free to implement·Published by AI Pathway

Used by

  • AI Officer
  • Business Systems Analyst
  • Compliance Officer
  • Quality Manager

This is the build plan most likely to be read by somebody who believes they have already done it, because the tenant comes with an assistant and the assistant answers questions about documents. The distance between that and this standard is the distance between a citation and a dated clause, and it is the whole distance.

In short

  • What this is

    A build plan for the cited answer standard on Microsoft 365. A library, four lists, three flows, five measures, and whichever assistant you already pay for on top.

  • The core rule

    Retrieval runs over clauses with effective dates. A superseded clause cannot produce a live answer, and no general document assistant knows that on its own.

  • What it does not do

    It never certifies, never issues or forecloses a certificate, and never resolves a conflict between two live instruments.

  • The hard part

    Finding every answer that relied on an instrument that just changed, which is only possible if the cards were stored on the answers.

Take the spec to Claude, ChatGPT or Copilot. The sentence to paste is one click away.

Want the whole thing by email?

This paper, plus the rest of the library. One click to stop them.

1. Before you start, and the thing to get straight

Read the cited answer build standard first. Shared conventions are in building the standards on Microsoft 365.

Pointing a document assistant at a folder of standards does not implement this. A document-grounded assistant tells you which file an answer came from. This standard is about a clause, its edition, its jurisdiction and the date it was live, and about a retired clause being unable to answer at all. No general assistant has a concept of a superseded clause, because nothing in a document tells it one.

So the assistant is the part you already have. The clause library, the source cards and the change feed are the build, and they sit underneath whichever model you are paying for.

2. The lists, with their columns

For your developer. Show the fields
Site: Knowledge

LIBRARY  Instruments        the documents as issued
  InstrumentId    Text            indexed
  Title           Text
  IssuingBody     Text
  Jurisdiction    Choice          the states you operate in
  Edition         Text
  EffectiveFrom   DateTime
  EffectiveTo     DateTime        blank means live
  RetrievedAt     DateTime

LIST  Clauses               retrieval runs over THIS
  ClauseId        Text            indexed
  Instrument      Text            lookup to Instruments
  ClauseRef       Text
  Text            Note
  Supersedes      Text            a ClauseId, or blank

LIST  SourceCards
  Clause          Text            indexed. lookup to Clauses
  Edition         Text
  Jurisdiction    Choice          the states you operate in
  EffectiveFrom   DateTime
  AcceptedBy      Person          REQUIRED
  AcceptedOn      DateTime        REQUIRED
  RetiredOn       DateTime        blank means live

LIST  Answers
  Question        Note
  AskedOn         DateTime
  AskedAboutDate  DateTime        defaults to AskedOn, often is not
  Jurisdiction    Choice          the states you operate in
  Audience        Choice          internal | public
  Body            Note
  SourceCardIds   Text            indexed. STORED. Not looked up later.
  Queue           Choice          answered | declined | conflict
                                  | change_pending

LIST  ChangeDeltas
  Instrument      Text            indexed. lookup to Instruments
  DetectedOn      DateTime
  Summary         Note
  Status          Choice          pending | accepted | rejected
  DecidedBy       Person
  DecidedOn       DateTime
  AffectedAnswers Text

An Answer with Queue = answered and no SourceCardIds should not
be representable. Enforce it in the flow, not in a review.

SourceCardIds is stored as a value on the answer rather than derived when somebody looks. That is the entire mechanism by which you can later list every answer that relied on an instrument that has just changed.

3. Every check, and what enforces it

The checkEnforced byHow
Retrieve clauses, not documentsClauses listThe library holds instruments; the list holds clauses with their text. Retrieval runs over the list. A citation that says which document is not a citation.
Only clauses live on the asked-about date reach an answerAnswer flowThe retrieval filter includes EffectiveFrom and EffectiveTo against the date in question, not today by default, because people ask about the past.
Every answer carries a source cardAnswer flowThe card is written with the answer and stored on it. Looking the citation up again later is not the same thing, because the clause may have moved.
No clause means decline, not the nearest answerAnswer flowAn empty retrieval is a terminating branch that writes a declined answer and names a person. It is not a fallback prompt.
A change is accepted by a named person before it is liveChange flowA detected change writes a pending ChangeDelta, marks affected cards, and pushes answers into change_pending. Acceptance is an approval with a name and a date.
Public and internal are different policiesAnswer flowAudience is a field that selects the policy branch, not a sentence in a prompt that a clever question can talk around.

4. The three flows

For your developer. Show the fields
FLOW 1  Answer
  trigger  a question arrives, from wherever you accept them
  logic    1 establish jurisdiction and AskedAboutDate FIRST
           2 retrieve Clauses filtered to that jurisdiction and
             live on that date
           3 if nothing retrieved -> write Queue = declined,
             name a person, STOP. Do not call the model.
           4 if two live instruments disagree -> Queue = conflict,
             route to a person, STOP.
           5 compose from the retrieved clause text only
           6 write SourceCardIds onto the Answer
           7 apply the Audience policy branch
  never    let the model answer from its own memory of a standard.
           Step 3 is a branch, not an instruction in a prompt.

FLOW 2  Change feed
  trigger  scheduled, weekly
  logic    check each instrument at its source
           on a change: ChangeDelta status = pending
                        mark the instrument's cards change pending
                        move answers relying on them to
                        Queue = change_pending
  note     from here those questions decline until accepted.

FLOW 3  Accept a change
  trigger  a pending ChangeDelta
  logic    request approval from the certifier group
           on accept: write DecidedBy and DecidedOn, retire the
             superseded cards, create the new ones
           on reject: record that too, with the reason
  never    auto-accept. The interpretation is the professional
           judgement and it is the reason this flow exists.

Flow 1 step 3 is the line between this standard and a chatbot. A decline is a branch taken before the model is asked for anything, which is why it cannot be talked around.

5. The Power BI model and its measures

For your developer. Show the fields
Answers Cited =
CALCULATE ( COUNTROWS ( Answers ), Answers[Queue] = "answered" )

Uncited Answers =                        -- must be zero
CALCULATE (
    COUNTROWS ( Answers ),
    Answers[Queue] = "answered",
    ISBLANK ( Answers[SourceCardIds] )
)

Decline Rate =
DIVIDE (
    CALCULATE ( COUNTROWS ( Answers ), Answers[Queue] = "declined" ),
    COUNTROWS ( Answers )
)

Serving Retired Cards =                  -- must be zero
CALCULATE (
    COUNTROWS ( SourceCards ),
    NOT ISBLANK ( SourceCards[RetiredOn] ),
    SourceCards[RetiredOn] < TODAY ()
)

Change Acceptance Days =
AVERAGEX (
    FILTER ( ChangeDeltas, ChangeDeltas[Status] = "accepted" ),
    DATEDIFF ( ChangeDeltas[DetectedOn], ChangeDeltas[DecidedOn], DAY )
)

Do not treat a falling Decline Rate as progress. It falls when the library genuinely improves and also when somebody loosens the retrieval filter, and those are opposite events. Read it against Uncited Answers, which must stay at zero.

6. The order to build it in

  1. Create the library and lists. Index ClauseId.
  2. Load one instrument and split it into clauses. One instrument is enough to prove the shape and small enough to check by hand.
  3. Create source cards for those clauses, with a real accepting person. If nobody will accept them, stop: that is the finding.
  4. Build Flow 1 up to step 3 and no further. Prove it declines before teaching it to answer.
  5. Add steps 4 to 7. Confirm SourceCardIds is written on the answer.
  6. Retire a clause and run the pass test.
  7. Build Flows 2 and 3.
  8. Connect Power BI. Uncited Answers on the front page, at zero.

7. Four traps specific to this build

Assuming Copilot over SharePoint satisfies this

It does not, and this is the most important line on the page. A document-grounded assistant cites the file it drew on. This standard is about a clause, an edition, a jurisdiction and an effective date, and about a superseded clause being unable to produce a live answer. Nothing in a general document assistant knows that a clause was retired. The clause library and the card layer are yours to build whichever assistant sits on top.

The instrument library as the only store

Dropping PDFs in a library and pointing retrieval at it gives you document-level answers and no way to retire a clause. Split them: the library keeps the instrument as issued, the list keeps the clauses with their dates.

Declining implemented as a prompt instruction

Telling a model to say it does not know is a request, not a gate. The decline must be the branch taken when retrieval returns nothing, decided in the flow before the model is asked to write anything.

No link from an instrument to the answers that relied on it

When an instrument moves you need the list of answers already given from it. That requires storing the card ids on the answer at the time. Reconstructing it later is exactly the work you will not do in the week it matters.

8. Where the automation stops

  • Accepting a change to an instrument, and deciding what it does to existing cards.
  • Resolving a conflict between two live instruments.
  • Any certificate, sign-off or statement of compliance.
  • Any answer where being wrong is somebody's safety rather than somebody's afternoon.
  • Deciding a question is outside the body of rules you hold, and saying so to the person who asked.

The pass test. Retire one clause your assistant answers from: set its EffectiveTo and load the replacement with a later EffectiveFrom, then ask the same question again. The answer must either change and cite the new clause, or decline into change_pending until somebody accepts the delta. Then ask something adjacent that your library genuinely does not cover: it must decline and name a person, with no body text composed. A few minutes on your own material. If the first still answers from the retired clause, retrieval is not filtering on the date. If the second produces a plausible paragraph, the model is answering from memory and you have a chatbot with a citation field.

Related reading