From b530783d09a656fe4ddc324243dd15de193eee86 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 22:50:43 +0900 Subject: [PATCH 1/6] test(autofix): require ConceptWeave target enrollment --- .../test_conceptweave_review_repair_target.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/test_conceptweave_review_repair_target.py 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() From a84da81b6a7e822923f3414379db9072a4c41fde Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 22:50:57 +0900 Subject: [PATCH 2/6] fix(autofix): register ConceptWeave dispatch target --- scripts/ci/opencode_repository_dispatch_targets.json | 1 + 1 file changed, 1 insertion(+) 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", From 18109ca0b84a554caafe1e72f18cf52e74a0c3cf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 22:51:48 +0900 Subject: [PATCH 3/6] fix(autofix): enroll ConceptWeave in central recovery caller --- .github/workflows/hourly-review-repair.yml | 38 +++++++++------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/.github/workflows/hourly-review-repair.yml b/.github/workflows/hourly-review-repair.yml index 0b45c7fd37..1fca821aa3 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 @@ -234,12 +232,10 @@ jobs: permissions: contents: read id-token: write - # Each repository keeps the independent, non-cancelling concurrency group - # its own former dedicated file used (e.g. `afipc-hourly-review-repair`), - # so all 18 (17 distinct-minute) schedules still run independently of - # each other and a later heartbeat never cancels this repository's - # in-flight RCA. `matrix.*` is available to a job-level `concurrency:` - # expression because the matrix is resolved before the job starts. + # Each repository keeps an independent, non-cancelling concurrency group, + # so a shared recovery trigger cannot cancel another repository's in-flight + # RCA. `matrix.*` is available to a job-level `concurrency:` expression + # because the matrix is resolved before the job starts. concurrency: group: ${{ matrix.concurrency_group }} cancel-in-progress: false @@ -248,21 +244,17 @@ jobs: target_repository: ${{ matrix.target_repository }} base_branch: ${{ matrix.base_branch }} # The reusable scheduler's own default (also "50") is too low for a - # queue this size: this repository alone (one of the 20 targets below) - # had 117 open PRs as of 2026-09-03, and BandScope independently hit - # 136 (see the now-superseded #1397, whose fix predates this file and - # never reached main before its target file was consolidated away). - # An oldest-first scan capped at 50 never reaches a repository's newer - # non-draft work once its queue exceeds that bound. 200 mirrors #1397's - # own chosen bound. + # queue this size: some organization repositories exceed that bound. + # An oldest-first scan capped at 50 can otherwise starve newer non-draft + # work. 200 preserves the existing bounded broad scan. max_prs: "200" max_dispatches: "1" scan_window_size: "50" rotation_seed: ${{ format('{0}', github.run_number) }} retry_hours: ${{ matrix.retry_hours }} # Explicit for every target: the reusable workflow's own default is - # already `true`, so this is behaviorally identical to the 17 original - # files that omitted the key and the 1 (github) that set it explicitly. + # already `true`, so this remains behaviorally identical to the former + # dedicated callers. resolve_unreviewed_conflicts: true secrets: PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} From 2e9b7dd47e054fe2b84f07cf4d56310f60041551 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 22:52:41 +0900 Subject: [PATCH 4/6] test(autofix): cover ConceptWeave central target --- tests/test_hourly_review_repair_callers.py | 7 +++++++ 1 file changed, 7 insertions(+) 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", + }, ], } From 796adc4393b6e83553ad330afc38e52a3b1544dd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 22:53:39 +0900 Subject: [PATCH 5/6] chore(autofix): minimize ConceptWeave caller delta --- .github/workflows/hourly-review-repair.yml | 26 +++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/hourly-review-repair.yml b/.github/workflows/hourly-review-repair.yml index 1fca821aa3..f79befd55c 100644 --- a/.github/workflows/hourly-review-repair.yml +++ b/.github/workflows/hourly-review-repair.yml @@ -232,10 +232,12 @@ jobs: permissions: contents: read id-token: write - # Each repository keeps an independent, non-cancelling concurrency group, - # so a shared recovery trigger cannot cancel another repository's in-flight - # RCA. `matrix.*` is available to a job-level `concurrency:` expression - # because the matrix is resolved before the job starts. + # Each repository keeps the independent, non-cancelling concurrency group + # its own former dedicated file used (e.g. `afipc-hourly-review-repair`), + # so all 18 (17 distinct-minute) schedules still run independently of + # each other and a later heartbeat never cancels this repository's + # in-flight RCA. `matrix.*` is available to a job-level `concurrency:` + # expression because the matrix is resolved before the job starts. concurrency: group: ${{ matrix.concurrency_group }} cancel-in-progress: false @@ -244,18 +246,22 @@ jobs: target_repository: ${{ matrix.target_repository }} base_branch: ${{ matrix.base_branch }} # The reusable scheduler's own default (also "50") is too low for a - # queue this size: some organization repositories exceed that bound. - # An oldest-first scan capped at 50 can otherwise starve newer non-draft - # work. 200 preserves the existing bounded broad scan. + # queue this size: this repository alone (one of the 20 targets below) + # had 117 open PRs as of 2026-09-03, and BandScope independently hit + # 136 (see the now-superseded #1397, whose fix predates this file and + # never reached main before its target file was consolidated away). + # An oldest-first scan capped at 50 never reaches a repository's newer + # non-draft work once its queue exceeds that bound. 200 mirrors #1397's + # own chosen bound. max_prs: "200" max_dispatches: "1" scan_window_size: "50" rotation_seed: ${{ format('{0}', github.run_number) }} retry_hours: ${{ matrix.retry_hours }} # Explicit for every target: the reusable workflow's own default is - # already `true`, so this remains behaviorally identical to the former - # dedicated callers. + # already `true`, so this is behaviorally identical to the 17 original + # files that omitted the key and the 1 (github) that set it explicitly. 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 From 309a59daa4413c593b93ce625901471a0ca701dc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 22:54:13 +0900 Subject: [PATCH 6/6] docs(autofix): trace ConceptWeave target enrollment --- ...ptweave-review-repair-target-enrollment.md | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 docs/doctoring/conceptweave-review-repair-target-enrollment.md 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.