How it works
Lookback is a set of steps that run on GitLab after a benefits appeal is won. The steps are the same every time, and every step leaves something you can click.
Lookback is a GitLab Duo flow GitLab Duo flowWhat it is. A multi-step AI workflow defined in YAML and run by GitLab. Lookback's flow has three agents, triage, reproduce and fix, each with the smallest set of tools it needs.Why it matters. The flow writes the test and the fix. It never touches money and cannot merge. plus a CI pipeline. The flow does the reasoning (triage, test, fix). The pipeline does everything that must be exact and repeatable (replay, money, ledgers, releases). Agents never compute amounts and cannot merge.
Follow the real run
This is the thread of work item #2, in order. Each row links to the live artifact.
| # | What happened | Evidence |
|---|---|---|
| 1 | A hearing officer wrote up the decision as a work item and mentioned the Lookback account.Work item created with label appeal::overturned; a mention of @ai-lookback-appeal-to-fix-gitlab-ai-hackathon fired the flow trigger within one second. | Work item #2 |
| 2 | Triage read the decision and the code, and said: the software is wrong, here is the rule, here is the right amount.Agent triage returned JSON: verdict software_error, rule area excess_medical_deduction, citation 7 CFR 273.9(d)(3), facts, recorded $23, correct $42. | Flow session on the work item |
| 3 | Reproduce wrote a test with the appellant's numbers and showed the current code fails it.Agent reproduce created tests/regression/test_appeal_2.py, asserting 4200 cents, and ran it: AssertionError, actual 2300. | The test |
| 4 | Fix changed one line and opened a merge request explaining who might be affected.Agent fix: min(expenses, threshold) became max(0, expenses - threshold) with the citation in a comment; branch fix/appeal-2; MR labeled lookback::remediate. | Merge request !1 |
| 5 | The merge request's checks all passed, and it was merged.MR pipeline: unit and property tests, replayability gate, SAST, secret detection, container build and scan. The agent cannot merge; a human or auto-merge does. | MR pipeline |
| 6 | The fixed engine was deployed.Image pushed to Artifact Registry and deployed to Cloud Run Cloud RunWhat it is. Google Cloud's service for running containers. Each release of the rules engine becomes a tagged revision.Why it matters. Old revisions stay addressable, so a past decision can be re-run against the exact code that made it. Deployed by the GitLab pipeline with no stored keys. as a tagged revision, with no stored keys (Workload Identity Federation). | Pipeline |
| 7 | Lookback found when the bug started: it tried the new test on each past release.Bisect BisectWhat it is. A search over past releases to find the first one where the appeal's test fails.Why it matters. It tells you exactly when the harm started, so you know which decisions to replay. over the engine's git history: 3 releases, 3 probes, first bad commit 08c5a271. | Job lookback-replay |
| 8 | It replayed every decision the broken code had made and compared.Replay ReplayWhat it is. Re-running past decisions through the fixed code, with the same inputs, and comparing outcomes.Why it matters. It is how Lookback finds everyone a bug harmed, instead of waiting for them to complain. of 10,656 ledger records through the fix; 410 re-run on the engine that made them, all matched. Differences: OVERPAID 9, UNDERPAID 410, WRONGLY_DENIED 3. | Job artifact summary.json |
| 9 | It worked out what each family was owed and restored it. Overpayments went to a person.Remedy under 7 CFR 273.17: $25,861 to 413 households, $0 lost to the 12-month limit, 9 adverse findings held, 422 correction records appended to the ledger Decision ledgerWhat it is. An append-only log of every decision the system made, with its inputs, outputs, and the exact code version that made it. Each record is chained to the previous one by a hash.Why it matters. You can replay any past decision exactly, and nobody can quietly edit or delete one. Anyone can run the verify command.. | Release |
| 10 | A summary was posted back on the original work item.Release description and work item note rendered from summary.json. | Work item #2 |
Read what the agents actually said
Every session's trace is exported unedited (secrets redacted) into the repository, so the agent's reasoning is readable even when the platform is slow.
- Appeal #2: triage finds the wrong line, reproduce writes the test, fix opens the MR
- Appeal #12: a wrongful denial, the size-minus-one lookup found unaided
- Appeal #12 re-run in the Python 3.12 agent image: the real test passes, so nothing changes
- Appeal #12, first attempt: no hearing text yet, so triage says "unclear" and nothing happens
- Flow B: nine overpayments become nine review work items for a caseworker
What the ledger looks like
Every decision is written down with the exact version of the code that made it. A fix never rewrites history; it adds a new line that says what the old one should have been.
Records are canonical JSON, hash-chained, with the engine commit and image digest. Corrections and adverse findings are appended and reference the record they concern.
Ask it anything, and it cannot lie about the numbers
A caseworker can ask GitLab Duo: "why does this household get $42?" or "what did the last remediation do?". The agent is not allowed to work the sum out itself; it has to ask the rules engine and quote the answer, regulation included. It cannot change anything. Today that works from GitLab's Duo CLI; the Duo Chat panel on GitLab.com cannot reach a project's own tool server yet, and there the agent declines rather than guesses.
The decider exposes an MCP server MCP serverWhat it is. Model Context Protocol, a standard way for an AI assistant to call tools on another system. Lookback's server offers six tools, and every one only reads.Why it matters. An assistant that explains a benefit should get the number from the rules engine, not make it up. There is no tool that writes, so there is nothing an attacker could trick the assistant into changing. (Streamable HTTP, protocol 2025-11-25) with six tools, every one annotated readOnlyHint: true: decide_household, explain_decision, list_remediations, get_remediation, verify_ledger, lookback_guarantees. .gitlab/duo/mcp.json registers it for the project; agents/ask_lookback.yaml is the chat agent in the AI Catalog whose system prompt forbids computing an amount without a tool call. 12 transport conformance tests in tests/test_mcp.py; scripts/mcp_probe.py passes 14 checks against the live server. Proven on the platform's own client: the GitLab Duo CLI, run from this repository, loaded mcp.json, called explain_decision and quoted $42.00 with thirteen regulation steps (session 9261760). One platform limit, recorded as found: web sessions on GitLab.com (the chat panel and custom flows) cannot reach a project MCP server yet. A flow that declared the tools anyway (session 9237114) answered that it would not compute the amount without them, which is the guarantee holding under a missing tool.
And before any future change
Every proposed code change is tested against the last 90 days of real decisions. If any real household's result would change, the change is blocked unless it comes from an appeal or a change in the law.
The replay gate Replay gateWhat it is. Before any change merges, the last 90 days of real decisions are replayed through the proposed code.Why it matters. If any real household's outcome would change, the merge is blocked unless the change references an appeal or a policy change. runs on every merge request that touches rules/. It fetches the ledger, verifies the hash chain, replays the window, and fails on unexplained flips. Explained flips are those whose MR references an appeal or a policy change.
A pure refactor
Renamed a variable. 14,205 decisions replayed, none changed.
Merge request !2A quiet rule change
Changed > to >= at the income limit, which would deny a household exactly at the limit. Caught by the unit tests. The replay gate passed, because no real household in the window sits exactly on the limit, which is why both layers exist.
The parts
rules/ pure rules engine, integer cents, every step cites its regulation
ledger/ append-only hash-chained ledger; python -m ledger.cli verify
gates/ replayability gate (no clock, randomness, I/O, floats); replay gate
replay/ release builds, bisect, replay, cascade
remedy/ 7 CFR 273.17: 12-month limit, asymmetric autonomy
lookback/ the post-merge stage: git history, record, stage, publish
decider/ HTTP service, one image per release; MCP server with six read-only tools
agents/ Ask Lookback, a Duo Chat agent that must call a tool before quoting an amount
.gitlab/duo/ Flow A (three agents), Flow B (two agents), Flow C (negative control), mcp.json, one-host sandbox configThe code is open, MIT licensed, and the README explains each part. See the repository.