python -m guard.review --base … --head … --defs --memory --gate --agent run
coverage (deterministic): ok, 32881 of 32881 changed lines and 85 of 85 files are in a bubble
Review the change, not the diff.
Molly shows a GitLab merge request file by file, splits it into changes, proves the links between them in the code and shows every changed line. A GitLab Duo agent explains each change; code checks what it says.
Code checks that every changed line and file is in a change, before and after the agent writes; the job fails if one is missing. On !18, 32,881 of 32,881 changed lines shown. coverage: ok
Hover a proven name in the diff and a peek shows its definition and the link code proved. README
Click a proven name and the code it points to unfolds in place, inside the diff, so you never leave the change you are reading. README
Plan proposes a stack of smaller merge requests from the proven links, bottom layer first. Stack dims the files of the other merge requests in a GitLab stack, and Mine shows a reviewer only their slice. README
The GitLab Duo agent groups, explains and ranks the changes (30 explained on !18). CI refuses a note that names a change code did not build. note on !18
GitLab Orbit gives the callers outside the diff and each file’s past merge requests, reverts and incidents. A file changed by a merge request that was later reverted with an incident marks the new one review-lens::history-risk.
memory.pySemgrep SAST and secret-detection findings are placed on the change they touch, so a finding sits next to the code it is about. semgrep on !18
On dbt merge requests CI builds the data at base and head and diffs it. On !13 Board Revenue for one month fell, and the guard said so first. guard note on !13
When a dashboard number moves, the merge request waits for a data owner who is not its author. On !13 the author’s approval was refused and another owner’s was recorded. the recorded approval
The release gate holds main until every data change has a safe floor or a recorded decision; it logged “release: yes” and shipped data-release-61, and a deploy job ships the dashboard to Cloud Run.
data-release-61The data watch reconciles production on main. After !2 merged it found 74 orders missing (25 October run), failed, and nothing was packaged.
prod_buildpipelineThe incident flow opened Incident #3 with what the guard had predicted and prepared the revert; a person merged it eleven minutes after the merge. Incident #3
Press a feature to see it; the tour plays when none is open.
$ numbers from the merge request pipeline of !18
- 32,881of 32,881 changed lines showncoverage: ok
- 400links proven in the codejob
17486070469 - 85of 85 files, split into 1,033 changes
review_lens - 11of 11 pipeline jobs passedpipeline
2991927333 - 538unit tests passed in CI
unit_tests
What the review page shows.
Molly’s review page, rendered from the review model CI built for a merge request. Code finds the changes, proves the links and checks that every line is there; the GitLab Duo agent only adds text.
files changedFiles changed, split into changes
The diff stays file by file; each change is marked in its file, with the proven names underlined.

hover peekHover a proven name
A peek shows the definition and the link code proved. A click unfolds it in place.

plan lensThe Plan lens
A big merge request split into smaller ones that land bottom up; every change carries its layer.

history riskHistory risk, from GitLab Orbit
On !13, a high history-risk finding, the data guard’s verdict and the file’s history above its diff.

Every changed line, with its proof.
Reviewing a big merge request today means going back and forth through a long diff. Molly keeps the diff file by file and adds what it lacks: code finds the changes, proves the links between them and checks that every line is there, and the agent explains.
Every changed line shown
python -m guard.review --base … --head … --defs --memory --gate --agent run review lens ff44e08e..5164d377 (!18 Add the review lens: a connected map of a merge request) 85 files, 1888 hunks, 1033 bubbles, +32863 -18 lines links: 400 (file 5, method 395) memory: ok, 11 calls in 6.2 s coverage (deterministic): ok, 32881 of 32881 changed lines and 85 of 85 files are in a bubble history risk: none (every changed file's history was read), review-lens::history-risk not added started flow session 10092479 (status created) merged the review-lens note: 0 problem(s) coverage (after-agent): ok, 32881 of 32881 changed lines and 85 of 85 files are in a bubble
Duo explains, code checks it

- Files, split into changes.
On !18 code split 85 files into 1,033 changes, each marked in its file’s diff. job
17486070469 - Links are proven.
400 links proven in the code (the job log); a proven name is underlined, peeks on hover and unfolds on click. The agent adds none. README
- Coverage is a gate.
On !18, 32,881 of 32,881 changed lines shown, in 85 of 85 files. The job fails if one changed line or file is in no change, checked before and after the agent writes.
coverage: ok - The agent only adds text.
Duo groups, explains and ranks findings (30 changes explained on !18); CI refuses a note that names a change code did not build. note on !18
It remembers what the diff can’t show.
The review lens asks GitLab Orbit, GitLab’s knowledge graph, what the diff cannot show: who calls the changed code, each file’s past merge requests, reverts and incidents, and who has reviewed it. Suggested reviewers come from that evidence, never the author or a service account.
review lens 32e66498..4c39a1f0 (!22 Draft: Demo: history risk on fct_orders.sql (do not merge)) memory: ok, 7 calls in 2.1 s history risk: analytics/models/marts/fct_orders.sql (b1): !2 reverted by !3 (Incident #2); !8 reverted by !9 (Incident #3) coverage (deterministic): ok, 1 of 1 changed lines and 1 of 1 files are in a bubble wrote review_lens.env: REVIEW_LENS_HISTORY=risk history risk on 1 change(s): labelled review-lens::history-risk
python -m guard.owner_decision --diff guard_out/data_diff.json !22: history risk: review-lens::history-risk: waiting until a project member who is not the author replies "@ai-review-lens-gitlab-ai-hackathon approve" or removes review-lens::history-risk with a note saying why ERROR: Job failed: exit code 1
- Callers outside the diff.
On !18,
guard.release_gate.runhas 14 unchanged callers that no diff would show you.memory: ok - History risk.
A file changed before by a merge request that was later reverted with an incident marks the new one
review-lens::history-risk.history_risk.py - Held until a person clears it.
On Draft !22,
owner_decisionwaited for a project member who is not the author. job17489142968 - Not yet seen live.
The gate moving a merge request to Draft and a person clearing it are covered by unit tests only.
docs/stages.md
A person decides when a number moves.
On dbt merge requests CI builds the data at base and head and diffs it. When a dashboard number moves, the merge request waits for a data owner who is not its author, and the release gate holds main until one decides.
@@ -3,6 +3,7 @@33 with payments as (44 select order_id, sum(amount) as amount_paid55 from {{ ref('stg_payments') }}6+ where payment_method != 'gift_card' -- gift cards are booked as revenue when sold67 group by order_id78 )
| Dashboard | Month | Base | Head | Change |
|---|---|---|---|---|
| Board Revenue | 2026-09 | 141,799.15 | 116,581.82 | −17.78% |
17465300021). Shop data is synthetic.@codebreaker23author repliedapprove
@bhawnanautiyaldata owner repliedapprove
- The number first.
Board Revenue for 2026-09 falls from 141,799.15 to 116,581.82. guard note
- The author’s approval is refused.
11:17:26 UTC: an author cannot approve their own change.
note_4089803004 - Another owner’s is recorded.
11:34:03 UTC, and the label turns
data-guard::approved.note_4089912878 - Released as approved.
Merged at 13:11:29;
release_gatelogged “release: yes” and shipped it as data-release-61.data-release-61
A broken number opens an incident.
!8 changed one join. The guard warned that orders with no payment would vanish, and it was merged anyway. The production watch found 73 orders missing, the incident flow opened Incident #3 and prepared the revert, and a person merged it eleven minutes after the merge.
26 October 2026, UTC
- The guard says needs_humanFloor safe, but the inner join drops unpaid orders; !8 goes to Draft.
- The watch finds 73 orders missingdata_watch on main fails reconciliation; nothing is packaged.
- Incident #3: “Was this predicted? Yes”Opened from CI, quoting the guard's warning on !8.
- Revert !9 mergedThe one-line revert the incident flow prepared; it closes #3.
- main released againrelease_gate held main, then released it after !10.
@@ -14,4 +14,4 @@ select1414 coalesce(p.amount_paid, 0) as amount_paid,1515 case when o.status = 'completed' then coalesce(p.amount_paid, 0) else 0 end as revenue1616 from {{ ref('stg_orders') }} as o17−left join payments as p on p.order_id = o.order_id17+inner join payments as p on p.order_id = o.order_id



Nine stages, each with a real run.
Every stage of the DevSecOps loop is touched by a job in this project, and every row links to the run. The unit tests run on every pipeline: on !18, 538 passed, 1 skipped.
| Stage | What runs it | Evidence |
|---|---|---|
| PlanThe incident flow, started from CI, opens an Incident with the impact, the evidence and “Was this predicted?” | The incident flow, started from CI, opens an Incident with the impact, the evidence and “Was this predicted?” | Incident #3, session 10036890 |
| CreateThe review-lens flow writes one note per merge request; the incident flow prepares the revert | The review-lens flow writes one note per merge request; the incident flow prepares the revert | note on !18, revert !9 |
| VerifyThe review lens fails the job if a changed line is in no change; dbt builds base and head and diffs the data | The review lens fails the job if a changed line is in no change; dbt builds base and head and diffs the data | job 17486070469, 538 passed |
| PackageThe dashboard image goes to the container registry after the release gate, then container scanning | The dashboard image goes to the container registry after the release gate, then container scanning | package_image, container_scanning |
| SecureSAST and secret detection; the review lens places their findings on the change they touch | SAST and secret detection; the review lens places their findings on the change they touch | semgrep-sast on !18, findings on !18 |
| Releaserelease_gate holds main until every data change is safe or approved; GitLab Pages and Cloud Run deploy after it | release_gate holds main until every data change is safe or approved; GitLab Pages and Cloud Run deploy after it | held, data-release-61 |
| ConfigureThree flows as code in .gitlab/duo/flows, linted on every pipeline and published to the AI Catalog | Three flows as code in .gitlab/duo/flows, linted on every pipeline and published to the AI Catalog | flows_lint on !18, flows_config |
| MonitorA production data watch on every main pipeline and daily at 06:00 UTC; a failed check starts the incident flow | A production data watch on every main pipeline and daily at 06:00 UTC; a failed check starts the incident flow | 73 missing, passing |
| GovernHistory-risk gate from GitLab Orbit's memory; an owner who is not the author decides; a floor the agent cannot lower | History-risk gate from GitLab Orbit's memory; an owner who is not the author decides; a floor the agent cannot lower | held on !22, refusal on !13 |
11 of 11 jobs passed
dbt_build_headbuild1m 02sdbt_build_basebuild1m 02ssemgrep-sasttest0m 39ssecret_detectiontest0m 14sunit_teststest1m 32sflows_lintconfigure0m 51sdata_diffguard0m 55srehearse_watchmonitor0m 59sguard_handoffhandoff0m 52sowner_decisionhandoff0m 50sreview_lenshandoff3m 28s
data-release-612026-10-26 13:15 UTC
Every data change from ccb93ec1 to e54672ef has a safe floor or a recorded decision.
| Merge request | Floor | Decision |
|---|---|---|
!13 Exclude gift card payments from order revenue | needs_human | release approved by a data owner who is not its author |
Dashboard image dashboard:e54672ef
python -m guard.release_gate counting from ccb93ec1 (last release) to e54672ef !13 release approved by a data owner who is not its author (Exclude gift card payments from order revenue) release: yes
gitlab_release) and the gate’s log.Run it on your laptop.
The tests and the dbt build run on your machine against the synthetic shop data. The setup guide covers the GitLab side: the three flows, the service accounts, the Mention trigger and the daily schedule.
git clone https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/22678466/showcase.git cd showcase && uv venv && . .venv/bin/activate && uv pip install -r requirements.txt pytest && cd analytics && DUCKDB_PATH=../warehouse/dev.duckdb dbt build --profiles-dir . 538 passed, 1 skipped (on !18’s pipeline)