Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/fm-helm-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ fm_helm_backlog_parse_program() {
since:metadata_word($m.rest; "since"), merged:metadata_word($m.rest; "merged"),
reported:metadata_word($m.rest; "reported"), done:metadata_word($m.rest; "done"),
blocked_by_ids:blocked_by_ids($m.rest),
pr_url:(([$m.rest | scan(url_pattern)] | map(select(test("/pull/[0-9]+"))) | .[0]) // null),
pr_url:(([$m.rest | scan(url_pattern)] | map(select(test("/pull/[1-9][0-9]*$") or test("/-/merge_requests/[1-9][0-9]*$"))) | .[0]) // null),
report_path:cap($m.rest; ".*(?<v>data/[^[:space:])]+/report\\.md).*"),
body_lines:[]}]
elif ($line | test("^[[:space:]]+")) and (.records | length) > 0 and .records[-1].structured then
Expand Down
20 changes: 20 additions & 0 deletions docs/bugs/2026-09-14-helm-sync-multi-host-pr-link.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Helm sync dropped non-GitHub PR links
description: Helm sync now preserves GitHub pull-request and GitLab merge-request URLs in card Facts sections.
---

## Symptom

Helm cards showed a `PR:` Facts line for GitHub pull-request URLs, but omitted the line for GitLab merge-request URLs even when `fm-helm-pr-check` had recorded the link in the backlog.

## Root cause

The backlog parser selected a PR URL only when it matched the GitHub-specific `/pull/<number>` path. GitLab's `/-/merge_requests/<number>` path therefore passed through as an ordinary backlog URL and was removed from the rendered card title without being retained for the Facts section.

## Fix

The parser now recognizes the canonical PR and MR URL shapes documented in [Helm board sync configuration](../configuration.md#helm-board-sync-confighelmjson). The existing card renderer continues to place a retained link in the Facts section.

## Prevention

`tests/fm-helm-sync.test.sh` creates cards from backlog rows containing both GitHub and GitLab links and asserts that each appears as a `PR:` Facts line. Keep new provider-specific URL shapes in this allowlist rather than accepting every URL from task notes.
1 change: 1 addition & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ An external interruption, including the watcher's check timeout, can end without
A `--force` run that reaches the partial path leaves `state/.helm-sync-resume` so the next run is forced too, which keeps the captain's board edits on the cards it never reached on the reconciliation path instead of the backlog-wins path.

Field authority: `data/backlog.md` in the owning home is authoritative for a card's title, body, kind, repository, priority, and lifecycle status.
When a backlog row contains a GitHub `/pull/<positive number>` or GitLab `/-/merge_requests/<positive number>` URL, the card body includes it as a `PR` fact.
The board is authoritative only for the captain's own edits, only for Priority, Status, and card text, and only on an explicit `bin/fm-helm-sync.sh --force` read.
On `--force` a captain edit to a card's Priority is written back into the owning backlog row; a move into the dispatch status raises one durable dispatch `check` wake for ordinary firstmate intake; and a move to Done on a live task, a move backwards, a title or body edit, a new captain card, or a deleted card each raise one `check` wake and change no backlog task mechanically.
The sync compares Status, Priority, title, and body with their own recorded board baselines.
Expand Down
4 changes: 4 additions & 0 deletions docs/documentation-audiences.json
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,10 @@
"path": "docs/bugs/2026-09-13-helm-sync-deadline-lost-progress.md",
"audience": "maintainer-architecture"
},
{
"path": "docs/bugs/2026-09-14-helm-sync-multi-host-pr-link.md",
"audience": "maintainer-architecture"
},
{
"path": "docs/calm-mode-feasibility.md",
"audience": "maintainer-verification"
Expand Down
47 changes: 47 additions & 0 deletions tests/fm-helm-sync.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,53 @@ run_watch() { # <case-dir> <fakebin>
"$WATCH"
}

# ---------------------------------------------------------------------------
# PR links: card Facts retain canonical GitHub and GitLab link shapes.
# ---------------------------------------------------------------------------
case_dir="$TMP_ROOT/pr-link-shapes"
mkdir -p "$case_dir/home/config" "$case_dir/home/data" "$case_dir/home/state"
fb=$(install_fakes "$case_dir")
printf '{"owner":"geojitsu","number":2}\n' > "$case_dir/home/config/helm.json"
cat > "$case_dir/home/data/backlog.md" <<'EOF'
# Backlog

## Queued
- [ ] github-pr-task - GitHub PR task (repo: firstmate) (kind: ship) (since: 2026-09-05) https://github.com/geojitsu/firstmate/pull/123
- [ ] gitlab-mr-task - GitLab MR task (repo: nocout) (kind: ship) (since: 2026-09-05) https://gitlab.com/dc-noc/nocout/-/merge_requests/123
- [ ] gitlab-bare-mr-task - GitLab bare MR task (repo: nocout) (kind: ship) (since: 2026-09-05) https://gitlab.com/dc-noc/nocout/merge_requests/456
- [ ] gitlab-zero-mr-task - GitLab zero MR task (repo: nocout) (kind: ship) (since: 2026-09-05) https://gitlab.com/dc-noc/nocout/-/merge_requests/0
- [ ] gitlab-suffixed-mr-task - GitLab suffixed MR task (repo: nocout) (kind: ship) (since: 2026-09-05) https://gitlab.com/dc-noc/nocout/-/merge_requests/12x
## Done
EOF
board_json '[]' > "$case_dir/board.json"
run_sync "$case_dir" "$fb" >/dev/null 2>&1 || fail "PR-link shape sync failed"
jq -e --arg url 'https://github.com/geojitsu/firstmate/pull/123' '
[.data.user.projectV2.items.nodes[].content.body]
| any(.[]; contains("- **PR:** " + $url))
' "$case_dir/board-state.json" >/dev/null \
|| fail "a GitHub pull-request URL did not render in the Facts section"
jq -e --arg url 'https://gitlab.com/dc-noc/nocout/-/merge_requests/123' '
[.data.user.projectV2.items.nodes[].content.body]
| any(.[]; contains("- **PR:** " + $url))
' "$case_dir/board-state.json" >/dev/null \
|| fail "a GitLab merge-request URL did not render in the Facts section"
jq -e --arg url 'https://gitlab.com/dc-noc/nocout/merge_requests/456' '
[.data.user.projectV2.items.nodes[].content.body]
| all(.[]; contains("- **PR:** " + $url) | not)
' "$case_dir/board-state.json" >/dev/null \
|| fail "a bare GitLab merge-request URL rendered in the Facts section"
jq -e --arg url 'https://gitlab.com/dc-noc/nocout/-/merge_requests/0' '
[.data.user.projectV2.items.nodes[].content.body]
| all(.[]; contains("- **PR:** " + $url) | not)
' "$case_dir/board-state.json" >/dev/null \
|| fail "a zero GitLab merge-request URL rendered in the Facts section"
jq -e --arg url 'https://gitlab.com/dc-noc/nocout/-/merge_requests/12x' '
[.data.user.projectV2.items.nodes[].content.body]
| all(.[]; contains("- **PR:** " + $url) | not)
' "$case_dir/board-state.json" >/dev/null \
|| fail "a suffixed GitLab merge-request URL rendered in the Facts section"
pass "canonical GitHub and GitLab PR links render in card Facts"

# ---------------------------------------------------------------------------
# Two-home union: close-missing only fires for a card in no home's backlog.
# ---------------------------------------------------------------------------
Expand Down
Loading