I keep stopping on the same merge request comment. The author says the tests already passed somewhere else. I ask which pipeline recorded that exact result.
The thread often goes quiet, and nobody pastes a link. Have you watched a review stall on that gap? A busy side session can feel like proof.
It is still not a receipt GitLab stored. I want the pipeline row GitLab actually kept.
The claims I keep hearing
These lines show up in review threads often. They sound helpful, and they skip the record. I want these claims retired from review notes.
- A zero exit on my server means the pipeline is green.
- Cloning the default branch means I tested the merge head.
- A pasted log means the failure cause is already known.
- A temporary free server is safe enough for job tokens.
- A commit hash in chat means that job already finished.
Which of these have you accepted too quickly?
Why I started asking for ids
Speed is not the same thing as evidence. I can still respect a fast careful rehearsal. I still need a stored row before I approve.
Myth 1: A side pass is a pipeline
You ran a suite, and the shell returned zero. That event happened outside GitLab's own pipeline table. A pipeline row has an id, a status, and a sha.
Your scrollback has none of those stored fields. I call the side run a rehearsal, not evidence. I will not cite it as a green check.
Where is the job URL for this head? I will not invent one from terminal memory.
What I accept instead
I accept a pipeline id that I can open. I accept a job status from that same pipeline. I accept a web_url pasted into the thread.
Myth 2: Default clone means this head
The server cloned whatever branch the remote offered. Often that branch is the default, not your head. A merge request head can differ after a rebase.
Did your rehearsal fetch the exact sha under review? A branch name match is not a commit match. I compare the checked out commit with the merge head.
If those hashes differ, stop the claim there. You tested another snapshot, not this review. Why argue about logs from the wrong tree?
A local equality check
Run this before you describe the rehearsal. It fails closed when the local checkout drifted.
: "${MR_HEAD_SHA:?sha from the merge request}"
test "$(git rev-parse HEAD)" = "${MR_HEAD_SHA}"
echo "checkout matches ${MR_HEAD_SHA}"
That test proves your worktree, not a pipeline. Keep that limit in the sentence you post. A matching checkout is still only a rehearsal.
Myth 3: A pasted log is the trace
A colleague pastes forty lines into the model chat. The reply then names a confident root cause. I still cannot see a job id in that paste.
A trace belongs to one job in one project. A paste can be trimmed, stale, or mislabeled. Which job URL produced those exact log lines?
Does that job's sha match the merge request head? If you cannot answer, you do not have the trace. Guessing a cause from a snippet wastes the next hour.
Questions I ask before debugging
- Which project hosted the job that failed?
- Which job id emitted the lines you pasted?
- Which sha did that job actually build?
- Is that sha still the merge request head?
- Did anyone trim the trace before the paste?
If one answer is missing, I stop the diagnosis. I go fetch the job instead of theorizing. The trace page beats another confident chat paragraph.
Myth 4: Temporary means safe for tokens
A free hosted shell will still execute what you type. Free access does not create a trust boundary. A short lifetime is not an access policy.
Would you type a job token on a laptop you do not administer? Protected variables belong on protected runners and refs. A side shell sits outside that fence entirely.
Keep production secrets on machines you already control. Masked variables are not safe just because chat feels private. A pasted token can outlive the session that received it.
Myth 5: A typed SHA means the job finished
The chat can mention a full commit hash. Typing a hash only proves someone typed it. It does not prove a pipeline reached success.
I ask the API for pipelines with that sha. I want the status, ref, source, and web_url. If the list is empty, the claim is unfinished.
The same hash on another ref is still different. A branch pipeline is not a tag pipeline. A merge-result pipeline is a third distinct case.
Fields I refuse to infer
I do not infer status from a cheerful summary. I do not infer ref from a branch nickname. I do not infer source from the words about pushing.
The model I keep instead
I keep three layers apart when I review. Mixing them is how weak green claims survive.
The claim is whatever the author or model said. The rehearsal is whatever a side shell ran. The receipt is whatever GitLab stored for that sha.
Only the receipt belongs in the approval note. The other layers can shape your next question. They cannot close the review on their own.
Claim map
Use this map before you trust a comment. Weak answers stay in the rehearsal column only.
| Question | Weak answer | Receipt field |
|---|---|---|
| Was it green? | "I ran it" | pipeline status
|
| Which commit? | a hash in chat | pipeline sha
|
| Which branch context? | a nickname | pipeline ref
|
| Which job? | a YAML snippet | job name and status
|
| Where is the log? | pasted lines | job web_url
|
| Did secrets work? | a token in shell | do not export it |
A receipt check you can copy
The script below is a proposal, not a benchmark. I am not reporting timings or sample counts. Run the authenticated calls where your token already lives.
#!/usr/bin/env bash
set -euo pipefail
: "${GITLAB_HOST:?set your GitLab host}"
: "${GITLAB_TOKEN:?read_api token}"
: "${PROJECT_ID:?numeric project id}"
: "${SHA:?merge request head sha}"
api() {
curl -fsS --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
"${GITLAB_HOST}/api/v4/projects/${PROJECT_ID}${1}"
}
echo "commit"
api "/repository/commits/${SHA}" | jq '{id, short_id, title}'
echo "pipelines"
api "/pipelines?sha=${SHA}&per_page=20" \
| jq '.[] | {id, status, ref, source, sha, web_url}'
Pick a pipeline id from that first list. Then fetch the pipeline row and its jobs.
: "${PIPELINE_ID:?id from the list above}"
api "/pipelines/${PIPELINE_ID}" \
| jq '{id, status, sha, ref, source, web_url}'
api "/pipelines/${PIPELINE_ID}/jobs?per_page=100" \
| jq '.[] | {id, name, status, stage, allow_failure, web_url}'
Compare these points before you write the review.
- Confirm the sha equals the merge request head.
- Confirm status is success, not a chat summary.
- Confirm the job name matches the YAML you read.
- Paste web_url into the thread, not shell history.
- Treat a missing job as an absent receipt.
No pipeline for that sha means you only rehearsed. Say that plainly when you reply in review. Do not promote a rehearsal into a receipt.
Those paths follow the Pipelines API and the Jobs API. Confirm them in the current GitLab docs for your host.
Read the flags, not just the color
A green badge can still be a soft pass. Look at allow_failure on the job you care about. Look at source so you know why the pipeline exists.
A scheduled pipeline is not your merge pipeline. A trigger pipeline may carry different variables entirely. Name the source in your note when it matters.
Where drafting help fits
MonkeyCode provides free model access and a free server option. Disclosure: This article was prepared as part of MonkeyCode's product outreach.
I treat both as drafting aids, not as runners. Neither one writes a row in your pipeline table. Removing them would leave this receipt habit intact.
Ask the model to list the receipt fields you need. Ask it to flag comments that lack a job URL. Do not ask it to approve the merge request.
Use the free server to syntax-check a local fixture. Point that session only at fake sample JSON. Run real curl calls on your own credentialed machine.
mkdir -p fixtures
cat > fixtures/pipelines.json <<'EOF'
[
{
"id": 101,
"status": "success",
"ref": "feature/receipt",
"source": "push",
"sha": "abc123deadbeef",
"web_url": "https://example.invalid/pipelines/101"
}
]
EOF
jq '.[] | {id, status, sha, ref, web_url}' fixtures/pipelines.json
bash -n check-receipt.sh
The model may draft that fixture for you. The server may run jq against the file. Neither step created a pipeline in your project.
Do you see the gap between rehearsal and receipt? If the model invents a job name, discard it. Your YAML and the jobs API remain the source.
A fluent paragraph is not an API field. I throw those inventions out of the note.
What I will not claim about those options
I am not stating quotas, hardware, or duration. I am not naming models or ranking them. Check the current product docs before you rely on availability.
Limits I will not smooth over
This check stays read-only on purpose for reviewers. It does not retry jobs or explain flakes. It does not prove coverage or deploy health.
A success status can still hide allow_failure jobs. Read that flag before you relax your review. A green pipeline can also skip your target job.
Use a read_api token for this glance, not a maintainer token. Rotate any secret you pasted into a side session. A vanished server does not unpaste a leaked token.
Free model text can be stale or simply wrong. Free server files can disappear when the session ends.
Plan on rerunning the authenticated check after every push. Treat yesterday's pasted log as expired context now.
GitLab.com and self-managed hosts are not the same. Set GITLAB_HOST to the site you actually use. I am not choosing a default for your company.
Parent-child pipelines need a second API request too. Bridge jobs do not inline every downstream job. Follow the bridges endpoint when you see a trigger.
Confirm these paths against current GitLab API docs. I am describing a habit, not pinning an API version. Your admin may also expose a different API prefix.
Who should skip this approach
Skip this if you already open the job log yourself. You do not need a script just to click web_url.
Skip this when the decision is a release approval. A pipeline id is not your release process. Keep that checklist with the release owners.
Skip this if personal tokens are forbidden on the project. Use the access path your maintainers already approved. Do not bypass policy through a side server.
Skip this after the merge request head moves. Recheck pipelines for the new head sha only. An older green row describes a different commit.
Skip this if you cannot see pipelines in the project. A hidden pipeline is not something to reconstruct from chat. Ask a maintainer for the recorded status instead.
The note I actually leave
I post one question, and then I stop pushing. A short question beats a lecture every time.
Which pipeline id matches this current head sha? Paste the job URL, not the shell history.
Need a drafter for that checklist, not a verdict? Use the free model to phrase the questions only. Keep the token on the machine you control.
Claim, rehearsal, receipt: I merge on the last one. I let the first two stay as questions only.
Top comments (0)