Skip to content

Roadmap item 6: Add inactive GitLab forge normalizer payload - #239

Merged
yihanzhu merged 7 commits into
mainfrom
ystack/roadmap-6/gitlab-forge-normalizer-v1
Sep 6, 2026
Merged

Roadmap item 6: Add inactive GitLab forge normalizer payload#239
yihanzhu merged 7 commits into
mainfrom
ystack/roadmap-6/gitlab-forge-normalizer-v1

Conversation

@yihanzhu

@yihanzhu yihanzhu commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • Roadmap item 6, first alternative forge. adapters/gitlab-forge/v1/normalize.jq validates one untrusted GitLab merge-request snapshot against caller-supplied project, merge-request iid, head, base, bot-user, time, instruction, and config bindings and returns the same canonical generic observation the GitHub forge returns (open-ready, open-blocked, closed-unmerged, merged, stale, inconclusive) with the same output keys, effect boundary, and stale-binding shape, so a profile can swap one forge for the other.
  • GitLab vocabulary stays at the edge: a locked request and a checking or unchecked merge status are inconclusive; a merged request is never also closed; a closed or merged request carries no merge status; the acting identity is the bot user the integration runs as (GitLab has no app id). Provider metadata stays opaque. GitHub-shaped states, mergeability values, and trust contexts are refused.
  • This lands only the immutable payload and its test. Manifest and profile wiring, and the eval seed cases that prove it against the same safety evals, follow in their own units.
  • Branches from main directly; not stacked on the item 5 eval stack.

Same contract as the GitHub forge

The test normalizes a GitHub and a GitLab baseline side by side and requires identical output keys, identical adapter keys, and identical non-provider content (state, stale bindings, authority, qualification, effects). The six generic states appear in both payloads by name.

Inactive boundary

Pure jq, offline, unqualified: no GitLab or CLI call, credential, project or merge-request change, authority, qualification, or profile activation. The test greps the payload for any network, shell, or provider-host reference.

Exact candidate

  • Head: 25667e9
  • Base: main at a637451
  • Roadmap: item 6, Alternative adapters, unit 1 (alternative forge payload; the alternative harness and the eval wiring follow)
  • Owned paths (4): adapters/gitlab-forge/v1/normalize.jq (new), scripts/test/default-gitlab-forge-adapter.test.sh (new), README.md, ci/required-files.txt

Current-head local proof

  • bash scripts/test/default-gitlab-forge-adapter.test.sh — 54/54 checks passed
  • ShellCheck 0.11.0 — clean
  • Schema activation guard and rename gate — clean on the committed tree

Fresh CI and a fresh independent review are required for this head.

First alternative forge. adapters/gitlab-forge/v1/normalize.jq validates
one untrusted GitLab merge-request snapshot against caller-supplied
project, merge-request iid, head, base, bot-user, time, instruction, and
config bindings and returns the same canonical generic observation the
GitHub forge returns: open-ready, open-blocked, closed-unmerged, merged,
stale, or inconclusive, with the same output keys, effect boundary, and
stale-binding shape, so a profile can swap one forge for the other.

GitLab vocabulary stays at the edge: a locked request and a checking or
unchecked merge status are inconclusive, a merged request is never also
closed, a closed or merged request carries no merge status, and the
acting identity is the bot user the integration runs as, since GitLab
has no app id. Provider metadata stays opaque data; GitHub-shaped
states, mergeability values, and trust contexts are refused.

Pure jq, offline, unqualified: no GitLab or CLI call, credential,
project or merge-request change, authority, qualification, or profile
activation. The test proves the contract equals the GitHub forge's
output contract key for key.

Proof: scripts/test/default-gitlab-forge-adapter.test.sh 54/54,
shellcheck 0.11.0 clean, rename gate clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 5, 2026

Copy link
Copy Markdown

Deploying ystack with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2c61065
Status: ✅  Deploy successful!
Preview URL: https://c70464c8.fabrica-6yx.pages.dev
Branch Preview URL: https://ystack-roadmap-6-gitlab-forg.fabrica-6yx.pages.dev

View logs

The test imports the public schema module to check reference shapes, the
same way the GitHub forge test does, so it joins that closed allowlist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@yihanzhu

yihanzhu commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Codex reviewer (cross-vendor, read-only)

Reviewed-head: ade23b7
Reviewed-base: a637451
reviewer: gpt-5.5 @ high

Posted verbatim by codex-review.sh (codex exec review --json --base refs/codex-review/239-69470/base in an isolated temp worktree, sandbox forced read-only). Comments only — Codex never pushes, approves, or merges.

The new GitLab normalizer rejects common GitLab merge-request API status values, so it will fail for ordinary mergeable or blocked GitLab MRs. The issue is localized but blocks the adapter's main purpose.

Review comment:

  • [P2] Accept GitLab's real merge_status values — /private/var/folders/rm/bkx4f4b91vqfn79vk02pcd140000gn/T/tmp.hxJqRQeBfU/adapters/gitlab-forge/v1/normalize.jq:145-145
    When the snapshot comes from GitLab's merge-request API, merge_status is reported with values such as can_be_merged and cannot_be_merged, not mergeable, conflict, or blocked. As written, a standard mergeable MR with merge_status: "can_be_merged" is rejected as gitlab-forge.invalid-snapshot instead of normalizing to open-ready, so this adapter cannot handle ordinary GitLab snapshots unless an undocumented pre-normalization step rewrites the provider field.

Review finding on the previous head: the snapshot used an invented
merge-status vocabulary, so an ordinary GitLab merge request could not
be normalized.

The snapshot now carries detailed_merge_status with GitLab's documented
values. mergeable is open-ready; the fourteen blocking values are
open-blocked; the four transitional values are inconclusive
(gitlab.merge-status-unsettled); not_open belongs only to a closed or
merged request. An invented value, the legacy merge_status field, a
GitHub-shaped value, or not_open on an open request is refused.

scripts/test/default-gitlab-forge-adapter.test.sh 71/71, shellcheck
0.11.0 clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@yihanzhu

yihanzhu commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Codex reviewer (cross-vendor, read-only)

Reviewed-head: fea2ff9
Reviewed-base: a637451
reviewer: gpt-5.5 @ high

Posted verbatim by codex-review.sh (codex exec review --json --base refs/codex-review/239-4239/base in an isolated temp worktree, sandbox forced read-only). Comments only — Codex never pushes, approves, or merges.

The new GitLab normalizer rejects a valid documented merge status, so it will fail for security-policy-blocked merge requests despite the intended GitLab API coverage.

Review comment:

  • [P2] Handle GitLab security-policy merge blocks — /var/folders/rm/bkx4f4b91vqfn79vk02pcd140000gn/T/tmp.06v3QcOOzm/adapters/gitlab-forge/v1/normalize.jq:104-108
    When an open GitLab merge request reports detailed_merge_status: "security_policy_violations", which is a documented GitLab API value for security-policy approval blocks, this allowlist rejects the whole snapshot as gitlab-forge.invalid-snapshot instead of normalizing it to open-blocked. That makes valid snapshots unusable for projects with security policies enabled; include this status in the blocking set and cover it in the tests.

Review finding on the previous head: security_policy_violations, a
documented GitLab detailed_merge_status value, was refused as an invalid
snapshot. The blocking set now carries all twenty documented blocking
values, including security_policy_violations, status_checks_must_pass,
merge_request_blocked, merge_time, locked_paths, and locked_lfs_files;
each normalizes an open request to open-blocked.

scripts/test/default-gitlab-forge-adapter.test.sh 76/76, shellcheck
0.11.0 clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@yihanzhu

yihanzhu commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Codex reviewer (cross-vendor, read-only)

Reviewed-head: 4b7365d
Reviewed-base: a637451
reviewer: gpt-5.5 @ high

Posted verbatim by codex-review.sh (codex exec review --json --base refs/codex-review/239-25130/base in an isolated temp worktree, sandbox forced read-only). Comments only — Codex never pushes, approves, or merges.

The GitLab normalizer misclassifies a transient CI-running merge status as a blocked merge request. This can produce incorrect forge observations once the adapter is wired in.

Review comment:

  • [P2] Treat running CI as inconclusive — /var/folders/rm/bkx4f4b91vqfn79vk02pcd140000gn/T/tmp.0JuY16nnil/adapters/gitlab-forge/v1/normalize.jq:105-105
    When GitLab reports detailed_merge_status: "ci_still_running" for an otherwise open merge request, this code normalizes it to open-blocked. That status is a temporary provider state that can become mergeable without any action, like checking or preparing, so later orchestration would be told the request is blocked instead of waiting for a settled observation.

Review finding on the previous head: ci_still_running was normalized to
open-blocked, but it settles on its own once the pipeline finishes, like
checking or preparing. It is now transitional and normalizes to
inconclusive (gitlab.merge-status-unsettled); ci_must_pass stays
blocking because it names a failed requirement.

scripts/test/default-gitlab-forge-adapter.test.sh 76/76, shellcheck
0.11.0 clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@yihanzhu

yihanzhu commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Codex reviewer (cross-vendor, read-only)

Reviewed-head: 633603a
Reviewed-base: a637451
reviewer: gpt-5.5 @ high

Posted verbatim by codex-review.sh (codex exec review --json --base refs/codex-review/239-29224/base in an isolated temp worktree, sandbox forced read-only). Comments only — Codex never pushes, approves, or merges.

No actionable correctness issues were found in the added GitLab forge normalizer, tests, or manifest updates.

@yihanzhu

yihanzhu commented Sep 6, 2026

Copy link
Copy Markdown
Owner Author

Codex reviewer (cross-vendor, read-only)

Reviewed-head: ccf060c
Reviewed-base: 69ded23
reviewer: gpt-5.5 @ high

Posted verbatim by codex-review.sh (codex exec review --json --base refs/codex-review/239-77825/base in an isolated temp worktree, sandbox forced read-only). Comments only — Codex never pushes, approves, or merges.

The GitLab normalizer otherwise follows the existing adapter shape, but it accepts a contradictory unknown/not_open state combination that should be rejected as malformed provider facts.

Review comment:

  • [P2] Reject not_open for unknown GitLab states — /var/folders/rm/bkx4f4b91vqfn79vk02pcd140000gn/T/tmp.VMsjDzJWZs/adapters/gitlab-forge/v1/normalize.jq:130-132
    When a snapshot has state:"unknown" with detailed_merge_status:"not_open", this branch accepts it, so snapshot_ok emits an inconclusive observation instead of rejecting the malformed state facts. The normalizer already treats not_open as belonging only to closed or merged requests, where the closed/merged booleans and timestamps are required, so this lets an invalid closed/merged snapshot bypass validation by labeling the state unknown.

Review finding: an unknown state accepted detailed_merge_status
not_open, although that value belongs only to a closed or merged request.
The unknown branch now refuses it, like the opened and locked branches.
Regression added. default-gitlab-forge-adapter 77/77, shellcheck 0.11.0
clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@yihanzhu

yihanzhu commented Sep 6, 2026

Copy link
Copy Markdown
Owner Author

Codex reviewer (cross-vendor, read-only)

Reviewed-head: 2c61065
Reviewed-base: 69ded23
reviewer: gpt-5.5 @ high

Posted verbatim by codex-review.sh (codex exec review --json --base refs/codex-review/239-78967/base in an isolated temp worktree, sandbox forced read-only). Comments only — Codex never pushes, approves, or merges.

I found no discrete correctness issues in the added inactive GitLab forge normalizer, its manifest entry, or the accompanying tests/docs.

@yihanzhu
yihanzhu merged commit a670fbc into main Sep 6, 2026
2 checks passed
@yihanzhu
yihanzhu deleted the ystack/roadmap-6/gitlab-forge-normalizer-v1 branch September 6, 2026 02:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant