-
Notifications
You must be signed in to change notification settings - Fork 0
ci: add semantic-data-portal hourly review-repair caller #1343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+284
−0
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
57207a7
ci: add semantic-data-portal hourly review-repair caller
seonghobae 4189e6a
fix: tighten semantic portal caller contracts
seonghobae cd3e1c2
fix: move semantic portal hourly caller to reserved slot
seonghobae ce402a4
Merge branch 'main' into feat/semantic-data-portal-hourly-loop
seonghobae 419ebef
docs(semantic-portal): clarify hourly heartbeat timing
seonghobae b296a00
Merge branch 'main' into feat/semantic-data-portal-hourly-loop
opencode-agent[bot] 6be8660
Merge branch 'main' into feat/semantic-data-portal-hourly-loop
seonghobae 18724c9
Merge branch 'main' into feat/semantic-data-portal-hourly-loop
opencode-agent[bot] 08dea3f
Merge branch 'main' into feat/semantic-data-portal-hourly-loop
opencode-agent[bot] 40f3ba6
Merge branch 'main' into feat/semantic-data-portal-hourly-loop
opencode-agent[bot] cfcf899
Merge branch 'main' into feat/semantic-data-portal-hourly-loop
opencode-agent[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
.github/workflows/semantic-data-portal-hourly-review-repair.yml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| name: Semantic Data Portal Hourly Review Repair | ||
|
|
||
| on: | ||
| schedule: | ||
| # Minute 59 is reserved for semantic-data-portal in the organization | ||
| # caller ledger and is unique among product heartbeats. GitHub may delay | ||
| # scheduled runs, so this is a heartbeat rather than a minute-zero surge | ||
| # avoidance guarantee. | ||
| - cron: "59 * * * *" | ||
|
seonghobae marked this conversation as resolved.
|
||
|
|
||
| concurrency: | ||
| group: semantic-data-portal-hourly-review-repair | ||
| # The queue scan is bounded and the worker has its own exact-head lease. Do not | ||
| # discard an in-flight RCA merely because the next hourly heartbeat arrives. | ||
| cancel-in-progress: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| dispatch-review-repair: | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| uses: ./.github/workflows/pr-review-fix-scheduler.yml | ||
| with: | ||
| target_repository: ContextualWisdomLab/semantic-data-portal | ||
| base_branch: main | ||
| max_prs: "50" | ||
| max_dispatches: "1" | ||
| # Central OpenCode/NVIDIA NIM work can legitimately approach two hours. | ||
| # A two-hour same-head floor avoids duplicate writers without freezing the | ||
| # next eligible PR or confusing provider latency with a source-code defect. | ||
| retry_hours: "2" | ||
| secrets: | ||
| PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} | ||
| OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} | ||
133 changes: 133 additions & 0 deletions
133
docs/doctoring/semantic-data-portal-hourly-review-caller.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| # Semantic Data Portal hourly review-repair caller | ||
|
|
||
| ## Decision | ||
|
|
||
| ContextualWisdomLab operates one protected hourly caller for | ||
| `ContextualWisdomLab/semantic-data-portal`. The caller runs at minute 59, | ||
| delegates to the product-neutral central review-fix scheduler, inspects at most | ||
| 50 open pull requests, and dispatches at most one bounded repair per heartbeat. | ||
| The minute is reserved for semantic-data-portal in the organization caller | ||
| ledger and is unique among the product caller slots. GitHub may delay scheduled | ||
| runs, so the cron is a heartbeat and does not promise avoidance of the | ||
| minute-zero runner surge. | ||
|
|
||
| The caller does not implement review or mutation logic itself. It keeps the | ||
| portal independently operable while centralizing privileged automation in | ||
| `ContextualWisdomLab/.github`. The reusable worker performs exact-head | ||
| root-cause analysis, tests remediation feasibility, and edits only when one | ||
| small reversible action can change the diagnosed cause inside its sealed | ||
| writer authority. | ||
|
|
||
| ## Root-cause analysis and remediation feasibility | ||
|
|
||
| The portal queue is dependency-ordered: the shared-base cryptography unlock | ||
| merges before the security lock, Keyverse claim aliases, the SQL gate pair, | ||
| and then the catalog-plane stack. An hourly redispatch of an unchanged head | ||
| does not accelerate that order; it duplicates writer pressure. The worker | ||
| therefore enforces these transitions: | ||
|
|
||
| 1. Refetch the exact live head, base, reviews, checks, changed paths, and | ||
| writer state. | ||
| 2. Establish the causal chain rather than repeat the terminal symptom. | ||
| 3. Enumerate materially distinct minimal remedies. | ||
| 4. Reject remedies that lack writer authority, cross sealed paths, require | ||
| unavailable credentials or protected-setting changes, violate stack order, | ||
| cannot be verified, or do not alter the diagnosed cause. | ||
| 5. Dispatch at most one feasible repair. Otherwise leave the tree unchanged so | ||
| another eligible pull request can be considered by a later heartbeat. | ||
|
|
||
| A queued or pending check remains a merge blocker but is not itself a code | ||
| finding. The independent non-author approval remains an external authorization | ||
| gate and is never synthesized by the repair worker. Product-gap development | ||
| that a heartbeat cannot safely automate (for example the Data Management | ||
| Evidence Console) stays with the repository's own issue-driven loop; the caller | ||
| never fabricates UI evidence to fill it. | ||
|
|
||
| ## Cadence and concurrency | ||
|
|
||
| The caller uses a single concurrency group and `cancel-in-progress: false`. | ||
| This preserves an in-flight bounded RCA instead of discarding its evidence when | ||
| the next hourly heartbeat arrives. The reusable scheduler cancels only its own | ||
| superseded short queue scan; the separately dispatched per-PR repair worker and | ||
| this product caller remain non-cancelling. The central scheduler and per-PR | ||
| worker also retain exact-head leases and mutation limits. | ||
|
|
||
| The caller sets a **two-hour same-head retry floor**. Central OpenCode and | ||
| NVIDIA NIM work can legitimately approach two hours, so an hourly redispatch of | ||
| the same unchanged head would create duplicate writer pressure rather than | ||
| faster remediation. A later hourly scan can still select another eligible pull | ||
| request. | ||
|
|
||
| GitHub scheduled workflows can be delayed under load and execute only from the | ||
| default branch. Consequently, the cron expression is a heartbeat rather than a | ||
| real-time service-level promise. Exact-head state, not elapsed wall-clock time, | ||
| controls every mutation and merge decision. | ||
|
|
||
| ## Credential and model boundary | ||
|
|
||
| The queue-scanning caller has only `contents: read`. It maps only the | ||
| established `PR_REVIEW_MERGE_TOKEN` and `OPENCODE_APPROVE_TOKEN` scheduler | ||
| credentials and does not use `secrets: inherit`. | ||
|
|
||
| Model execution remains inside the central worker. The model credential is the | ||
| GitHub Secret `NVIDIA_NIM_API_KEY`; the caller does not receive or forward it. | ||
| `COPILOT_GITHUB_TOKEN` is prohibited. GitHub tokens and GitHub Models are not | ||
| model credentials for this write-capable path. The independent review-agent | ||
| credential contract is unchanged. | ||
|
|
||
| ## Security, standalone operation, and modularity | ||
|
|
||
| The caller adds no portal runtime dependency, database object, network | ||
| endpoint, tenant authority, or product credential. The semantic-data-portal | ||
| continues to run as a standalone FastAPI application and as a module beside | ||
| naruon, Keyverse, DiskSage, fast-mlsirm, TEPP, LineageWeave, RankWeave, and | ||
| contextual-orchestrator without weakening its local validation, | ||
| protected-branch, exact-head, approval, or security gates. Authority boundaries | ||
| stay fixed: identity belongs to Keyverse, policy truth to GRC, capability | ||
| targets to enterprise-architecture-core, document-KG writes to naruon, lineage | ||
| reconstruction to LineageWeave, and central governance to this repository. | ||
|
|
||
| The reusable workflow source is bound to the called workflow repository, SHA, | ||
| ref, and file path before privileged scheduler logic runs. The worker cannot | ||
| approve, merge, release, weaken checks, change reviewer identities, or modify | ||
| protected settings. Queued, pending, absent, failed, cancelled, skipped-required, | ||
| neutral-required, stale-head, or synthetic-merge evidence is not success. | ||
|
|
||
| ## Verification and rollback | ||
|
|
||
| Repository contracts require the exact cron, target repository, one-dispatch | ||
| budget, two-hour retry floor, non-cancelling single-flight policy, read-only | ||
| workflow token, explicit secret mapping, and absence of both | ||
| `NVIDIA_NIM_API_KEY` and `COPILOT_GITHUB_TOKEN` from the caller. | ||
|
|
||
| Rollback is a reviewed source change. Do not disable exact-head binding, reduce | ||
| the independent approval requirement, increase dispatch volume, use inherited | ||
| secrets, or convert provider latency into a fabricated code edit. If the | ||
| heartbeat becomes too frequent or too slow, change only the caller cadence and | ||
| retry floor after examining observed run duration and queue throughput; preserve | ||
| the central RCA, feasibility, lease, and credential contracts. | ||
|
|
||
| ## APA 7th references | ||
|
|
||
| GitHub. (n.d.). *Control the concurrency of workflows and jobs*. Retrieved | ||
| August 25, 2026, from | ||
| https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency | ||
|
|
||
| GitHub. (n.d.). *Events that trigger workflows: Schedule*. Retrieved August 25, | ||
| 2026, from | ||
| https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#schedule | ||
|
|
||
| GitHub. (n.d.). *Reuse workflows*. Retrieved August 25, 2026, from | ||
| https://docs.github.com/en/actions/how-tos/sharing-automations/reusing-workflows | ||
|
|
||
| NVIDIA. (n.d.). *NVIDIA NIM for large language models documentation*. Retrieved | ||
| August 25, 2026, from | ||
| https://docs.nvidia.com/nim/large-language-models/latest/ | ||
|
|
||
| OpenCode. (n.d.). *OpenCode documentation*. Retrieved August 25, 2026, from | ||
| https://opencode.ai/docs/ | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| Souppaya, M., Scarfone, K., & Dodson, D. (2022). *Secure software development | ||
| framework (SSDF) version 1.1: Recommendations for mitigating the risk of | ||
| software vulnerabilities* (NIST Special Publication 800-218). National | ||
| Institute of Standards and Technology. https://doi.org/10.6028/NIST.SP.800-218 | ||
114 changes: 114 additions & 0 deletions
114
tests/test_semantic_data_portal_hourly_review_caller.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| """Contract tests for the semantic-data-portal bounded hourly review-repair caller.""" | ||
|
|
||
| import re | ||
| from pathlib import Path | ||
|
|
||
|
|
||
| CALLER = Path(".github/workflows/semantic-data-portal-hourly-review-repair.yml") | ||
| DOCTORING = Path("docs/doctoring/semantic-data-portal-hourly-review-caller.md") | ||
|
|
||
|
|
||
| def _read(path: Path) -> str: | ||
| """Return one repository contract file as UTF-8 text.""" | ||
| return path.read_text(encoding="utf-8") | ||
|
|
||
|
|
||
| def _permission_map(caller: str, header: str) -> dict[str, str]: | ||
| """Parse one exact YAML permission block without widening test dependencies.""" | ||
| lines = caller.splitlines() | ||
| header_index = lines.index(header) | ||
| entry_indent = len(header) - len(header.lstrip()) + 2 | ||
| permissions: dict[str, str] = {} | ||
| for line in lines[header_index + 1 :]: | ||
| if not line.strip(): | ||
| continue | ||
| indent = len(line) - len(line.lstrip()) | ||
| if indent < entry_indent: | ||
| break | ||
| if indent != entry_indent: | ||
| continue | ||
| key, separator, value = line.strip().partition(":") | ||
| assert separator, f"malformed permission entry: {line!r}" | ||
| permissions[key] = value.strip() | ||
| return permissions | ||
|
|
||
|
|
||
| def test_semantic_data_portal_caller_is_hourly_bounded_and_non_cancelling() -> None: | ||
| """The portal receives one realistic repair opportunity without overlap cancellation.""" | ||
| caller = _read(CALLER) | ||
|
|
||
| assert 'cron: "59 * * * *"' in caller | ||
| assert "group: semantic-data-portal-hourly-review-repair" in caller | ||
| assert "cancel-in-progress: false" in caller | ||
| assert "uses: ./.github/workflows/pr-review-fix-scheduler.yml" in caller | ||
| assert "target_repository: ContextualWisdomLab/semantic-data-portal" in caller | ||
| assert "base_branch: main" in caller | ||
| assert 'max_prs: "50"' in caller | ||
| assert 'max_dispatches: "1"' in caller | ||
| assert 'retry_hours: "2"' in caller | ||
|
|
||
|
|
||
| def test_semantic_data_portal_caller_preserves_credentials_and_read_only_token_scope() -> None: | ||
| """The queue scanner maps established credentials without exposing model secrets.""" | ||
| caller = _read(CALLER) | ||
| workflow_scope, jobs_scope = caller.split("\njobs:\n", maxsplit=1) | ||
|
|
||
| assert _permission_map(workflow_scope, "permissions:") == {"contents": "read"} | ||
| assert _permission_map(jobs_scope, " permissions:") == { | ||
| "contents": "read", | ||
| "id-token": "write", | ||
| } | ||
| assert "PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }}" in caller | ||
| assert "OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }}" in caller | ||
| assert "secrets: inherit" not in caller | ||
| assert "NVIDIA_NIM_API_KEY" not in caller | ||
| assert "COPILOT_GITHUB_TOKEN" not in caller | ||
| for forbidden in ( | ||
| "actions: write", | ||
| "contents: write", | ||
| "issues: write", | ||
| "pull-requests: write", | ||
| "statuses: write", | ||
| ): | ||
| assert forbidden not in caller | ||
|
|
||
|
|
||
| def test_semantic_data_portal_caller_cron_avoids_other_callers() -> None: | ||
| """Minute 59 does not collide with any other product caller heartbeat.""" | ||
| caller = _read(CALLER) | ||
| assert '- cron: "59 * * * *"' in caller | ||
| other_minutes = { | ||
| minute | ||
| for path in Path(".github/workflows").glob("*hourly-review-repair.yml") | ||
| if path != CALLER | ||
| for minute in re.findall(r'cron:\s*["\'](\d+) \* \* \* \*["\']', _read(path)) | ||
| } | ||
| assert "59" not in other_minutes | ||
|
|
||
|
|
||
| def test_semantic_data_portal_caller_doctoring_records_rca_feasibility_and_latency() -> None: | ||
| """Operators retain the exact rationale for the bounded two-hour retry policy.""" | ||
| doctoring = _read(DOCTORING) | ||
|
|
||
| for phrase in ( | ||
| "root-cause analysis", | ||
| "remediation feasibility", | ||
| "two-hour same-head retry floor", | ||
| "exact-head", | ||
| "cancel-in-progress: false", | ||
| "NVIDIA_NIM_API_KEY", | ||
| "COPILOT_GITHUB_TOKEN", | ||
| "PR_REVIEW_MERGE_TOKEN", | ||
| "OPENCODE_APPROVE_TOKEN", | ||
| "ContextualWisdomLab/semantic-data-portal", | ||
| "minute 59", | ||
| ): | ||
| assert phrase in doctoring, phrase | ||
|
|
||
| for reference in ( | ||
| "https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency", | ||
| "https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#schedule", | ||
| "https://docs.github.com/en/actions/how-tos/sharing-automations/reusing-workflows", | ||
| "https://doi.org/10.6028/NIST.SP.800-218", | ||
| ): | ||
| assert reference in doctoring, reference |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.