|
| 1 | +name: Glossary Monitor |
| 2 | + |
| 3 | +# Runs every Monday at 09:00 UTC and can be triggered manually. |
| 4 | +# On each run it scans all labs64.io-* repositories for documentation, |
| 5 | +# uses an LLM via OpenRouter to propose glossary updates, and opens a PR |
| 6 | +# only when the glossary content actually changes. |
| 7 | + |
| 8 | +# ----------------------------------------------------------------------- |
| 9 | +# ARCHITECTURE NOTE — why everything goes through PRs, never direct push |
| 10 | +# ----------------------------------------------------------------------- |
| 11 | +# The default branch is assumed to be protected (required PR reviews, |
| 12 | +# status checks, etc.). Direct `git push` to it would either be blocked |
| 13 | +# or silently bypass those rules depending on the token used. |
| 14 | +# All commits from this workflow — glossary updates AND the encrypted |
| 15 | +# state file — are therefore proposed via peter-evans/create-pull-request, |
| 16 | +# which targets a separate branch and opens/updates a PR. |
| 17 | +# Do not replace these steps with a bare `git commit && git push`. |
| 18 | +# ----------------------------------------------------------------------- |
| 19 | + |
| 20 | +# ----------------------------------------------------------------------- |
| 21 | +# ARCHITECTURE NOTE — when to advance the state baseline (state_changed) |
| 22 | +# ----------------------------------------------------------------------- |
| 23 | +# The state file records the HEAD SHA of each repo after a run so the |
| 24 | +# next run skips commits already evaluated. |
| 25 | +# |
| 26 | +# It only needs to be updated when the LLM was actually invoked — i.e. |
| 27 | +# when changed or removed doc files were found. Re-examining commits that |
| 28 | +# contain no doc files costs only a few GitHub API calls (cheap), so |
| 29 | +# there is no benefit to recording those commits in state. |
| 30 | +# |
| 31 | +# This collapses state_changed to the same condition as "did we call |
| 32 | +# the LLM", which equals "were there any changed or removed doc files". |
| 33 | +# If no doc files changed, state is left untouched and those commits are |
| 34 | +# re-scanned next run at negligible cost. Do not widen state_changed to |
| 35 | +# fire on every run — it would open noisy PRs with no meaningful payload. |
| 36 | +# ----------------------------------------------------------------------- |
| 37 | + |
| 38 | +on: |
| 39 | + schedule: |
| 40 | + - cron: '0 9 * * 1' # Every Monday 09:00 UTC |
| 41 | + workflow_dispatch: # Manual trigger from the Actions tab |
| 42 | + |
| 43 | +permissions: |
| 44 | + contents: write |
| 45 | + pull-requests: write |
| 46 | + |
| 47 | +jobs: |
| 48 | + update-glossary: |
| 49 | + name: Scan repos and update GLOSSARY.md |
| 50 | + runs-on: ubuntu-latest |
| 51 | + timeout-minutes: 15 |
| 52 | + |
| 53 | + steps: |
| 54 | + - name: Checkout labs64.io-docs |
| 55 | + uses: actions/checkout@v4 |
| 56 | + |
| 57 | + # The state file contains private repository names and HEAD SHAs. |
| 58 | + # It is stored encrypted in the repo (scripts/.glossary-state.json.enc) |
| 59 | + # so the plaintext never appears in the public git history. |
| 60 | + # Decrypt with STATE_ENCRYPTION_KEY (a repository secret: any strong |
| 61 | + # passphrase, e.g. `openssl rand -hex 32`). |
| 62 | + - name: Decrypt state file |
| 63 | + env: |
| 64 | + STATE_ENCRYPTION_KEY: ${{ secrets.STATE_ENCRYPTION_KEY }} |
| 65 | + run: | |
| 66 | + if [ -f scripts/.glossary-state.json.enc ]; then |
| 67 | + openssl enc -aes-256-cbc -d -pbkdf2 \ |
| 68 | + -pass env:STATE_ENCRYPTION_KEY \ |
| 69 | + -in scripts/.glossary-state.json.enc \ |
| 70 | + -out scripts/.glossary-state.json |
| 71 | + fi |
| 72 | +
|
| 73 | + - name: Set up Python 3.12 |
| 74 | + uses: actions/setup-python@v5 |
| 75 | + with: |
| 76 | + python-version: '3.12' |
| 77 | + cache: pip |
| 78 | + cache-dependency-path: scripts/requirements.txt |
| 79 | + |
| 80 | + - name: Install dependencies |
| 81 | + run: pip install -r scripts/requirements.txt |
| 82 | + |
| 83 | + - name: Run glossary monitor |
| 84 | + id: monitor |
| 85 | + env: |
| 86 | + # GH_TOKEN must have read access to all labs64.io-* repos (public + private). |
| 87 | + # Use a classic PAT or a fine-grained token with "Contents: Read" on all target repos. |
| 88 | + # Store it as a repository secret named GH_TOKEN. |
| 89 | + GH_TOKEN: ${{ secrets.GH_TOKEN }} |
| 90 | + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} |
| 91 | + run: python scripts/glossary_monitor.py |
| 92 | + |
| 93 | + # Re-encrypt the updated state so it is ready for either PR step below. |
| 94 | + # The .enc file is safe to store publicly — without STATE_ENCRYPTION_KEY |
| 95 | + # it reveals nothing about private repo names or commit SHAs. |
| 96 | + - name: Encrypt state file |
| 97 | + if: steps.monitor.outputs.state_changed == 'true' |
| 98 | + env: |
| 99 | + STATE_ENCRYPTION_KEY: ${{ secrets.STATE_ENCRYPTION_KEY }} |
| 100 | + run: | |
| 101 | + openssl enc -aes-256-cbc -pbkdf2 \ |
| 102 | + -pass env:STATE_ENCRYPTION_KEY \ |
| 103 | + -in scripts/.glossary-state.json \ |
| 104 | + -out scripts/.glossary-state.json.enc |
| 105 | +
|
| 106 | + # When the glossary changed, the state travels in the same PR so both |
| 107 | + # land on the default branch together when the PR is merged. |
| 108 | + - name: Open glossary PR |
| 109 | + if: steps.monitor.outputs.glossary_changed == 'true' |
| 110 | + uses: peter-evans/create-pull-request@v6 |
| 111 | + with: |
| 112 | + token: ${{ secrets.GH_TOKEN }} |
| 113 | + branch: glossary/auto-update |
| 114 | + base: master |
| 115 | + title: "docs: glossary update from weekly repository scan" |
| 116 | + body: | |
| 117 | + This PR was opened automatically by the **Glossary Monitor** workflow. |
| 118 | +
|
| 119 | + ### What changed |
| 120 | + The job scanned all `labs64.io-*` repositories and used an LLM via OpenRouter to: |
| 121 | + - Add terms present in documentation but missing from the glossary |
| 122 | + - Improve definitions that were incomplete or outdated |
| 123 | + - Expand the *Context* column for terms that appear in additional modules |
| 124 | +
|
| 125 | + ### Review checklist |
| 126 | + - [ ] New terms are accurate and belong in a human-readable glossary |
| 127 | + - [ ] Definitions are concise and free of code symbols |
| 128 | + - [ ] Context column lists the correct module(s) |
| 129 | + - [ ] Alphabetical order is preserved |
| 130 | +
|
| 131 | + > Generated by [`scripts/glossary_monitor.py`](../blob/master/scripts/glossary_monitor.py) |
| 132 | + commit-message: "docs: auto-update GLOSSARY.md via glossary-monitor" |
| 133 | + labels: | |
| 134 | + documentation |
| 135 | + automated |
| 136 | + # Re-use the same branch so repeated runs update the existing PR |
| 137 | + # instead of opening a new one each time. |
| 138 | + delete-branch: false |
| 139 | + add-paths: | |
| 140 | + GLOSSARY.md |
| 141 | + scripts/.glossary-auto.md |
| 142 | + scripts/.glossary-state.json.enc |
| 143 | +
|
| 144 | + # When docs were scanned but the glossary needed no changes, open a |
| 145 | + # minimal PR to advance the state baseline so the next run does not |
| 146 | + # re-examine the same commits. Reuses the same branch across weeks so |
| 147 | + # a lingering unmerged PR is updated in place rather than duplicated. |
| 148 | + - name: Open state-only PR |
| 149 | + if: >- |
| 150 | + steps.monitor.outputs.state_changed == 'true' && |
| 151 | + steps.monitor.outputs.glossary_changed != 'true' |
| 152 | + uses: peter-evans/create-pull-request@v6 |
| 153 | + with: |
| 154 | + token: ${{ secrets.GH_TOKEN }} |
| 155 | + branch: glossary/state-update |
| 156 | + base: master |
| 157 | + title: "chore: advance glossary monitor state baseline" |
| 158 | + body: | |
| 159 | + The **Glossary Monitor** ran this week and scanned new commits across |
| 160 | + `labs64.io-*` repositories, but found no glossary changes to propose. |
| 161 | +
|
| 162 | + This PR advances the encrypted state baseline so the next weekly run |
| 163 | + does not re-examine the same commits. Safe to merge without review. |
| 164 | + commit-message: "chore: update glossary monitor state [skip ci]" |
| 165 | + labels: | |
| 166 | + automated |
| 167 | + delete-branch: false |
| 168 | + add-paths: | |
| 169 | + scripts/.glossary-state.json.enc |
0 commit comments