diff --git a/.github/workflows/hourly-review-repair.yml b/.github/workflows/hourly-review-repair.yml index 0b45c7fd37..f79befd55c 100644 --- a/.github/workflows/hourly-review-repair.yml +++ b/.github/workflows/hourly-review-repair.yml @@ -114,11 +114,10 @@ on: # central merge scheduler to consume the queue. # -- Orgmetra (formerly orgmetra-hourly-review-repair.yml) - cron: "58 15 * * *" - # 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. - # -- semantic-data-portal (formerly semantic-data-portal-hourly-review-repair.yml) + # Minute 59 remains a single daily semantic-plane recovery trigger. It + # fans out to semantic-data-portal and ConceptWeave through independent + # per-repository concurrency groups; neither product owns the other's work. + # -- semantic-data-portal + ConceptWeave - cron: "59 16 * * *" # Coalesce admissions before resolve-target needs a runner. @@ -213,9 +212,8 @@ jobs: TARGETS='[{"name":"orgmetra","target_repository":"ContextualWisdomLab/Orgmetra","base_branch":"develop","retry_hours":"2","concurrency_group":"orgmetra-hourly-review-repair"}]' ;; "59 16 * * *") - # 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. - TARGETS='[{"name":"semantic-data-portal","target_repository":"ContextualWisdomLab/semantic-data-portal","base_branch":"main","retry_hours":"2","concurrency_group":"semantic-data-portal-hourly-review-repair"}]' + # Keep the ontology owner and catalog/governance consumer in separate leases. + TARGETS='[{"name":"semantic-data-portal","target_repository":"ContextualWisdomLab/semantic-data-portal","base_branch":"main","retry_hours":"2","concurrency_group":"semantic-data-portal-hourly-review-repair"},{"name":"conceptweave","target_repository":"ContextualWisdomLab/ConceptWeave","base_branch":"main","retry_hours":"2","concurrency_group":"conceptweave-hourly-review-repair"}]' ;; *) echo "::error::Unrecognized schedule '$SCHEDULE'; no target repository is configured for it." >&2 @@ -266,4 +264,4 @@ jobs: resolve_unreviewed_conflicts: true secrets: PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} + OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} \ No newline at end of file diff --git a/docs/doctoring/conceptweave-review-repair-target-enrollment.md b/docs/doctoring/conceptweave-review-repair-target-enrollment.md new file mode 100644 index 0000000000..2f15ed2126 --- /dev/null +++ b/docs/doctoring/conceptweave-review-repair-target-enrollment.md @@ -0,0 +1,43 @@ +# ConceptWeave bounded review-repair target enrollment + +Date: 2026-09-20 + +## Problem + +`ContextualWisdomLab/ConceptWeave` has valid exact-head review findings but was absent from the protected central `hourly-review-repair.yml` target lookup and from the source-controlled mirror of `OPENCODE_REPOSITORY_DISPATCH_TARGETS`. Mention-triggered OpenCode is review-only, so an `@opencode-agent` comment is not a source-writer handoff. The edit-capable owner remains the central `pr_review_fix_scheduler.py -> pr-review-autofix.yml` path. + +ConceptWeave PR #46 exact `974972e2885baa956af9b728fee158b1782704d1` is the concrete consumer case: its executable relation-kind/index-ownership RED needs a bounded same-head writer, not a second product-local workflow. + +## Decision + +Enroll ConceptWeave in the existing consolidated central recovery caller instead of creating a repository-local caller or widening review-agent permissions. + +The existing `59 16 * * *` daily missed-event recovery is shared with `semantic-data-portal`. The matrix keeps separate `target_repository` and `concurrency_group` values, so sharing the trigger does not merge product ownership or cancellation leases. ConceptWeave uses protected base `main`, `retry_hours = 2`, `max_dispatches = 1`, and the existing central scheduler/autofix implementation. + +The source-controlled dispatch-target mirror also includes the exact `ContextualWisdomLab/ConceptWeave` repository name. The live repository variable remains a separate deployment prerequisite because source control cannot mutate that configuration by itself. + +## RED -> repair trace + +- Protected base: `.github/main@e6334e229581a918e2f22de18733b76fa65d7e71`. +- RED commit: `b530783d09a656fe4ddc324243dd15de193eee86` adds `tests/test_conceptweave_review_repair_target.py`; protected source contains neither the caller target nor mirror entry, so the contract is unsatisfied before enrollment. +- Mirror repair: `a84da81b6a7e822923f3414379db9072a4c41fde`. +- Consolidated caller repair: `18109ca0b84a554caafe1e72f18cf52e74a0c3cf`, minimized by ordinary-forward successor `796adc4393b6e83553ad330afc38e52a3b1544dd`. +- Existing consolidated-caller contract is extended on the same branch so schedule resolution and the dispatch-target mirror remain one acceptance surface. + +No product-local `conceptweave-hourly-review-repair.yml` is introduced. No provider/model/group override, paid fallback, workflow-token write grant, approval, merge, release, protection mutation, or source-neutral wake is added. + +## Acceptance and rollout boundary + +Source acceptance requires the focused caller contracts and repository workflow validation to pass on the exact PR head. Runtime acceptance additionally requires all of the following after protected integration: + +1. `OPENCODE_REPOSITORY_DISPATCH_TARGETS` in `ContextualWisdomLab/.github` contains the exact `ContextualWisdomLab/ConceptWeave` entry and is re-read after mutation. +2. An unchanged-head ConceptWeave canary with an autofixable file-scoped review finding produces a central `PR Review Autofix ContextualWisdomLab/ConceptWeave#...@` worker. +3. The worker revalidates the live PR/head/base before model work and before publication, writes only sealed reviewed paths, and ordinary-forwards the same head branch. +4. A stale-head canary fails closed before publication. Queued, cancelled, or failed checks are never normalized into success. +5. ConceptWeave contains no duplicate local review-repair workflow. + +Until those conditions are observed, enrollment is Proposed rather than operationally Accepted. Source GREEN cannot substitute for the live repository-variable update or canary evidence. + +## Rollback + +If the central caller causes target-specific admission or isolation regressions, remove only the ConceptWeave matrix entry and mirror entry, restore the previous exact target set, and leave the product repository unchanged. Do not replace the rollback with a local writer. If the live allowlist variable was updated, remove the same exact ConceptWeave entry there in the same rollback and re-read the variable before declaring rollback complete. diff --git a/scripts/ci/opencode_repository_dispatch_targets.json b/scripts/ci/opencode_repository_dispatch_targets.json index dd82dd1fd0..6e9e053c1e 100644 --- a/scripts/ci/opencode_repository_dispatch_targets.json +++ b/scripts/ci/opencode_repository_dispatch_targets.json @@ -2,6 +2,7 @@ "$comment": "Mirrors the live ContextualWisdomLab/.github repository variable OPENCODE_REPOSITORY_DISPATCH_TARGETS, which gates ALLOWED_TARGET_REPOSITORIES in pr-review-merge-scheduler.yml/pr-review-fix-scheduler.yml and the agent-mention dispatch allowlist. There is no API to commit an org/repo variable's value to source control, so this file is a hand-maintained mirror -- update it AND run `gh variable set OPENCODE_REPOSITORY_DISPATCH_TARGETS --repo ContextualWisdomLab/.github` in the same PR whenever a repository is added. tests/test_hourly_review_repair_callers.py::test_every_hourly_caller_target_is_in_the_dispatch_targets_mirror locks every repository hourly-review-repair.yml dispatches to as a subset of this list -- see docs/doctoring/scheduler-target-list-drift-20260902.md for the incident history (governance-risk-compliance, nonnest2, quarantine-sandbox-runtime all silently failed their hourly heartbeat because this sync was missed) that this file and test exist to catch before it recurs.", "targets": [ "ContextualWisdomLab/.github", + "ContextualWisdomLab/ConceptWeave", "ContextualWisdomLab/ContextualWisdomLab.github.io", "ContextualWisdomLab/DiagramWeave", "ContextualWisdomLab/EgressWeave", diff --git a/tests/test_conceptweave_review_repair_target.py b/tests/test_conceptweave_review_repair_target.py new file mode 100644 index 0000000000..7a4556a915 --- /dev/null +++ b/tests/test_conceptweave_review_repair_target.py @@ -0,0 +1,32 @@ +"""Coverage contract for ConceptWeave's canonical bounded review-repair target.""" + +from __future__ import annotations + +import json +import re +from pathlib import Path + + +_CALLER = Path(".github/workflows/hourly-review-repair.yml") +_DISPATCH_TARGETS_MIRROR = Path("scripts/ci/opencode_repository_dispatch_targets.json") +_TARGET = "ContextualWisdomLab/ConceptWeave" + + +def test_conceptweave_has_exactly_one_canonical_review_repair_target() -> None: + """ConceptWeave resolves once through the central caller and dispatch allowlist mirror.""" + caller = _CALLER.read_text(encoding="utf-8") + matches = re.findall( + r'\{"name":"conceptweave","target_repository":"ContextualWisdomLab/ConceptWeave",' + r'"base_branch":"main","retry_hours":"2",' + r'"concurrency_group":"conceptweave-hourly-review-repair"\}', + caller, + ) + assert len(matches) == 1 + + mirror = json.loads(_DISPATCH_TARGETS_MIRROR.read_text(encoding="utf-8")) + assert mirror["targets"].count(_TARGET) == 1 + + +def test_conceptweave_target_uses_shared_caller_without_a_duplicate_workflow() -> None: + """Enrollment stays in the consolidated central caller rather than a new thin workflow.""" + assert not Path(".github/workflows/conceptweave-hourly-review-repair.yml").exists() diff --git a/tests/test_hourly_review_repair_callers.py b/tests/test_hourly_review_repair_callers.py index 0b9a049771..5d62961db0 100644 --- a/tests/test_hourly_review_repair_callers.py +++ b/tests/test_hourly_review_repair_callers.py @@ -215,6 +215,13 @@ "retry_hours": "2", "concurrency_group": "semantic-data-portal-hourly-review-repair", }, + { + "name": "conceptweave", + "target_repository": "ContextualWisdomLab/ConceptWeave", + "base_branch": "main", + "retry_hours": "2", + "concurrency_group": "conceptweave-hourly-review-repair", + }, ], }