1+ # Generated by labkit (python -m labkit gen). Do not edit by hand.
2+ # Edit labs/<lab>/publish.config.json and regenerate; drift fails `labkit doctor`.
3+ # Install into operatorstack/value-map at .github/workflows/sync-upstream.yml (bootstrap step).
14name : Sync from Intelligence Flow
25
36on :
47 schedule :
5- - cron : " 23 */6 * * *"
8+ - cron : " 9 */6 * * *"
69 workflow_dispatch :
710 inputs :
811 source_commit :
9- description : Exact Intelligence Flow commit dispatched by Operator Stack Publisher
12+ description : Exact Intelligence Flow commit to project (defaults to main)
1013 required : false
1114 type : string
1215
@@ -23,69 +26,96 @@ jobs:
2326 runs-on : ubuntu-latest
2427 steps :
2528 - name : Create Operator Stack Publisher token
26- id : publisher -token
29+ id : app -token
2730 uses : actions/create-github-app-token@v3
2831 with :
2932 client-id : ${{ vars.OPERATOR_STACK_PUBLISHER_APP_CLIENT_ID || vars.BOATSTACK_APP_CLIENT_ID }}
3033 private-key : ${{ secrets.OPERATOR_STACK_PUBLISHER_APP_PRIVATE_KEY || secrets.BOATSTACK_APP_PRIVATE_KEY }}
3134 owner : operatorstack
32- repositories : value-map
33- permission-contents : read
35+ repositories : |
36+ intelligence-flow
37+ value-map
38+ permission-contents : write
3439 permission-pull-requests : write
3540 - name : Check out Value Map
3641 uses : actions/checkout@v4
3742 with :
38- path : value-map-repo
43+ path : public-repo
44+ token : ${{ steps.app-token.outputs.token }}
3945 - name : Check out Intelligence Flow
4046 uses : actions/checkout@v4
4147 with :
4248 repository : operatorstack/intelligence-flow
4349 ref : ${{ inputs.source_commit || 'main' }}
44- path : intelligence-flow
4550 fetch-depth : 0
46- - name : Project canonical skill
47- id : project
51+ path : intelligence-flow
52+ token : ${{ steps.app-token.outputs.token }}
53+ - name : Set up Python
54+ uses : actions/setup-python@v5
55+ with :
56+ python-version : " 3.12"
57+ - name : Install labkit
58+ shell : bash
59+ run : python3 -m pip install --quiet ./intelligence-flow/labkit
60+ - name : Generate projection
61+ id : generate
4862 shell : bash
4963 run : |
50- if [[ -n "${{ inputs.source_commit }}" ]]; then
51- source_commit="$(git -C intelligence-flow rev-parse HEAD)"
52- else
53- source_commit="$(git -C intelligence-flow log -1 --format=%H -- labs/14-product-value-projection)"
64+ source_commit="$(git -C intelligence-flow log -1 --format=%H -- labs/14-product-value-projection)"
65+ current_commit="$(jq -r '.source.commit // empty' public-repo/UPSTREAM.json 2>/dev/null || echo '')"
66+ if [[ -n "$current_commit" ]] &&
67+ ! git -C intelligence-flow merge-base --is-ancestor "$current_commit" "$source_commit"; then
68+ echo "Ignoring stale request; Value Map already records $current_commit."
69+ echo "stale=true" >> "$GITHUB_OUTPUT"
70+ exit 0
5471 fi
55- python3 value-map-repo/scripts/project_upstream.py \
56- --source intelligence-flow \
57- --repo value-map -repo \
58- --commit "$source_commit" \
72+ python3 -m labkit project \
73+ --config intelligence-flow/labs/14-product-value-projection/publish.config.json \
74+ --repo public -repo \
75+ --source- commit "$source_commit" \
5976 --write
6077 echo "source_commit=$source_commit" >> "$GITHUB_OUTPUT"
78+ echo "stale=false" >> "$GITHUB_OUTPUT"
6179 - name : Open generated pull request
80+ if : steps.generate.outputs.stale != 'true'
6281 env :
63- GH_TOKEN : ${{ steps.publisher -token.outputs.token }}
64- SOURCE_COMMIT : ${{ steps.project .outputs.source_commit }}
82+ GH_TOKEN : ${{ steps.app -token.outputs.token }}
83+ SOURCE_COMMIT : ${{ steps.generate .outputs.source_commit }}
6584 shell : bash
6685 run : |
67- cd value-map -repo
86+ cd public -repo
6887 if [[ -z "$(git status --porcelain)" ]]; then
6988 echo "Value Map already matches Intelligence Flow."
7089 exit 0
7190 fi
91+ git add -A
92+ body_file="$(mktemp)"
93+ {
94+ echo "## Projection provenance"; echo
95+ echo "Generated from \`operatorstack/intelligence-flow@$SOURCE_COMMIT\`."
96+ echo "Review the operator contract, provenance, and compatibility before merging."
97+ } > "$body_file"
7298 short="${SOURCE_COMMIT:0:12}"
7399 branch="sync/intelligence-flow-$short"
74100 existing="$(gh pr list --head "$branch" --state open --json url --jq '.[0].url')"
75- if [[ -n "$existing" ]]; then
76- echo "Upstream PR already open: $existing"
77- gh pr merge "$existing" --auto --squash
78- exit 0
79- fi
80- git config user.name "github-actions[bot]"
81- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
82- git checkout -B "$branch"
83- git add value-map/SKILL.md UPSTREAM.json
84- git commit -m "Sync Value Map from Intelligence Flow $short"
101+ git config user.name "${{ steps.app-token.outputs.app-slug }}[bot]"
102+ git config user.email "${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com"
103+ git switch -c "$branch"
104+ git commit -m "Sync Value Map from Intelligence Flow @ $short"
85105 git push --force --set-upstream origin "$branch"
86- pr_url="$(gh pr create \
87- --base main \
88- --head "$branch" \
89- --title "Sync Value Map from Intelligence Flow $short" \
90- --body "Generated from operatorstack/intelligence-flow@$SOURCE_COMMIT. Review the operator contract, provenance, and compatibility checks before merging.")"
106+ if [[ -z "$existing" ]]; then
107+ pr_url="$(gh pr create --base main --head "$branch" \
108+ --title "Sync Value Map from Intelligence Flow @ $short" \
109+ --body-file "$body_file")"
110+ echo "Opened generated PR: $pr_url"
111+ else
112+ pr_url="$existing"
113+ echo "Updated existing PR: $existing"
114+ fi
115+ required_checks="$(gh api "repos/operatorstack/value-map/branches/main/protection/required_status_checks" --jq '(.contexts // []) + ([.checks[]?.context] // []) | unique | length')"
116+ if [[ "$required_checks" -lt 1 ]]; then
117+ echo "BLOCKED: main has no required status checks; refusing unsafe auto-merge." >&2
118+ exit 1
119+ fi
91120 gh pr merge "$pr_url" --auto --squash
121+ echo "Native auto-merge requested; branch protection owns merge eligibility."
0 commit comments