MCP playbook

The fix-and-verify loop, from VS Code

A gap says an engine recommended someone else. The loop is: read what the engines cited, read what they searched, write a fix from that evidence and nothing else, let the guard check it, hand it to a person to approve, and re-measure after the indexing delay. This recording runs the read and check steps for real on our own top gap, and shows the guard rejecting a source the engines never cited.

Recorded 4 September 2026 on the Linkeddit connector, project 441e8df6 (linkeddit.com), gap 557a8732. Read and check calls are live; the three write calls are quoted from their tool contracts and marked as not executed.

The transcript

  1. 1

    You ask: Open the top gap with its evidence.

    Tool call: answer_gap_get

    { "gap_id": "557a8732-…", "mode": "evidence" }

    Response, abridged

    {
      "title": "Not represented for: 'What is the best competitor monitoring software for tracking pricing changes and product launches?'",
      "summary": "'Linkeddit' was neither mentioned nor cited in 4 successful answer samples for this prompt.",
      "rank": 1, "confidence": 0.7, "status": "open",
      "observed": [ { "fact": "'Linkeddit' was not mentioned or cited in any of 4 successful answer samples" } ],
      "hypotheses": [],
      "recommended_actions": [ { "action": "Publish a source-backed page answering 'What is the best competitor monitoring software for tracking pricing changes and product launches?'" } ],
      "citations": [
        { "domain": "price2spy.com", "count": 3 }, { "domain": "thunderbit.com", "count": 3 },
        { "domain": "visualping.io", "count": 3 }, { "domain": "shopvision.ai", "count": 2 },
        { "domain": "aimultiple.com", "count": 1 }, { "domain": "blog.hubspot.com", "count": 1 },
        { "domain": "prisync.com", "count": 1 }, { "domain": "reddit.com", "count": 1 }, "… 9 more"
      ]
    }

    Observed, hypotheses and recommended actions arrive as separate arrays. Here the hypotheses array is empty, which is the tool declining to guess. The citations are the pages the engines read when they answered without us.

  2. 2

    You ask: What did the engines search for before answering this question?

    Tool call: answer_fanout_get

    { "project_id": "441e8df6-…", "run_id": "19910a90-…" }

    Response, abridged

    {
      "prompt_texts": ["What is the best competitor monitoring software for tracking pricing changes and product launches?"],
      "segments": [
        { "segment": { "engine": "Claude", "instrument": "e9e2ca40" },
          "queries": ["best competitor monitoring software pricing product launches"] },
        { "segment": { "engine": "Gemini", "instrument": "1674df18" },
          "queries": ["best competitor monitoring software pricing changes product launches 2025 2026",
                      "competitor price tracking product launch monitoring tools"] },
        { "segment": { "engine": "ChatGPT", "instrument": "f155ac25" },
          "queries": ["Competiflow product launch monitoring pricing changes",
                      "Price2Spy product launch monitoring features",
                      "Prisync competitor price monitoring product launch alerts features",
                      "Veilleo pricing product launch monitoring competitor intelligence",
                      "best competitor price tracking software product launch monitoring 2026"] },
        { "segment": { "engine": "Perplexity", "instrument": "d17097c8" }, "queries": [] }
      ],
      "measurement_note": "These are the search queries the provider reported issuing while answering this prompt, as recorded at run time. A provider may issue searches it does not report …"
    }

    ChatGPT searched for four named vendors by name before writing a list. That is the retrieval layer the page has to enter: a comparison that names those vendors is a page the engine can find for those searches. Perplexity reports related topics, not searches, so its segment is empty with a reason rather than a plausible list.

  3. 3

    You ask: I have written a draft. Does it cite only what the run recorded?

    Tool call: answer_fix_check

    {
      "gap_id": "557a8732-…",
      "content": "Draft: a comparison page for competitor monitoring software that tracks pricing changes and product launches. Sources the engines actually read include https://www.price2spy.com/ and https://visualping.io/ . It would also cite https://linkeddit.com/competitor-intelligence as our own page."
    }

    Response, abridged

    {
      "faithful": false,
      "checked": { "urls": 3, "citation_ids": 0 },
      "sources": [
        { "url": "https://www.price2spy.com/", "supported": true, "matched_by": "domain",
          "citation_ids": ["13ba6cb0-…", "5d39246a-…", "46e79a3b-…"] },
        { "url": "https://visualping.io/", "supported": true, "matched_by": "domain",
          "citation_ids": ["b367d697-…", "6ce221da-…", "ec193b3c-…"] },
        { "url": "https://linkeddit.com/competitor-intelligence", "supported": false, "matched_by": null }
      ],
      "unsupported": { "urls": ["https://linkeddit.com/competitor-intelligence"] },
      "available_evidence": { "citation_count": 24,
        "domains": ["aimultiple.com","softwarereviews.com","thunderbit.com","pricinghunter.com","blog.hubspot.com",
                    "withorb.com","visualping.io","price2spy.com","pagecrawl.io","getapp.com","shopvision.ai",
                    "qubit.capital","prisync.com","guideflow.com","reddit.com","competiflow.com","veilleo.com"] },
      "disclosure": { "notes": ["This is a structural check on sources …",
        "matched_by='url' means the run recorded that exact page; matched_by='domain' means the run cited that site but not that page.",
        "Only measured evidence counts. A source that is real and public but was never returned in an answer we sampled is still unsupported here."] }
    }

    The guard did its job. Two sources are supported by domain, meaning the run cited those sites but not those exact pages. Our own competitor intelligence page is unsupported: it is real and public, but no engine cited it when answering this question, so a fix may not present it as evidence the engines used. The response lists the 17 domains that are available so the draft can be rewritten against them.

  4. 4

    Tool call: answer_fix_draft (not executed in this recording)

    { "gap_id": "557a8732-…", "type": "brief" }

    Response, abridged

    Contract, from the live tool description:
    "Build the evidence skeleton for a fix (brief, article, or response): the gap's summary, the facts
    observed during measurement, and the recommended actions, assembled deterministically from the run's
    recorded evidence and saved as a fix artifact. No model is involved and no prose is generated -- you
    write the words, this gives you the evidence to write them from."

    We did not run the write steps in this recording because each creates a row on the account. In a real loop, draft first, then write, then check, then update.

  5. 5

    Tool call: answer_fix_update, then answer_fix_save (not executed)

    { "fix_id": "…", "content": "<your rewritten draft>", "source_citation_ids": ["13ba6cb0-…", "b367d697-…"] }

    Response, abridged

    Contract, from the live tool descriptions:
    update: "Any change to the body or the cited sources is re-checked against the measured evidence for the
    fix's gap … an edit that cites a source the run never recorded is rejected and nothing is written …
    'approved' and 'published' cannot be set here: approval is a human action in the Linkeddit workspace."
    save: "Save a fix you have drafted into the Linkeddit review workspace, where a human approves or edits
    it, and get back the deep link to that page. This is the governed step."

    The update tool applies the same check the check tool reported, so a draft the check passed will save, and a draft it flagged will be refused with nothing written. Approval happens in the Fixes page, by a person.

  6. 6

    Tool call: answer_verify_start (not executed)

    { "gap_id": "557a8732-…", "fix_id": "…" }

    Response, abridged

    Contract, from the live tool description:
    "Register a re-verification of a recommendation gap: re-measure the same prompts with the same
    configuration after an indexing delay, then report what moved. This starts NO run now -- the delay is the
    point, because content published today is not retrievable today … The result is always an OBSERVED
    DELTA, never evidence that your change caused it."

    After publishing the approved fix, register the re-verification and poll answer_verify_get after followup_due_at, 168 hours later by default. The report is null until then, which means not measured yet, never no change.

The three rules the loop enforces

Each one is a refusal the tools make, not a guideline.

Evidence before words

The draft tool assembles observed facts and recorded citations and writes no prose. Your client writes the words. The measurement layer is never the author, which is the doctrine on the methodology page.

Only measured sources

A URL is supported when the run cited that page, or at least that domain. A page that exists but was never cited is unsupported, and an update citing it is refused with nothing written. The check tool reports; the update tool rejects; both use one definition.

A delta, not a cause

Re-verification pairs baseline and follow-up on the same instrument, applies a minimum change and a resolution floor, uses control prompts, and reports movement. There is no field for a cause and no confidence value. The help article lists the six outcomes.

Frequently asked questions

Why did you not run the write steps for the recording?

Because they create rows on a real account, and a playbook should not leave artifacts behind to look complete. The read and check steps are real and recorded; the write steps are quoted from their live tool descriptions, which is what the tools will do when you run them.

Why is our own page unsupported? It exists.

Existing is not the test. The faithfulness guard accepts only sources the run recorded as cited, so a fix cannot claim the engines relied on a page they never read. To make our page citable evidence, it has to be cited in a future run, which is the whole point of the fix.

What does VS Code need?

An MCP extension that accepts a remote HTTP server and can complete OAuth in a browser, or the mcp-remote bridge. The connect guide covers both. The transcript is identical from Cursor, Claude Code or Claude Desktop.

Run the loop on your own gap

Answer Radar is included with Compete. Every tool in this playbook is available to any MCP client on the Linkeddit connector.