From 2009bcb9ffcdb1ab4f91c772d698778576ee6f3d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 15:08:29 +0900 Subject: [PATCH 01/24] test(scheduler): close current-main RCA coverage gaps --- ...est_scheduler_1541_coverage_regressions.py | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tests/test_scheduler_1541_coverage_regressions.py diff --git a/tests/test_scheduler_1541_coverage_regressions.py b/tests/test_scheduler_1541_coverage_regressions.py new file mode 100644 index 0000000000..3d03ce56db --- /dev/null +++ b/tests/test_scheduler_1541_coverage_regressions.py @@ -0,0 +1,102 @@ +"""Regression coverage for the scheduler branches introduced by PR #1541.""" + +from __future__ import annotations + +import pytest + +from scripts.ci import pr_review_fix_scheduler as fix +from scripts.ci import pr_review_merge_scheduler as merge + + +def _pr(**overrides: object) -> dict[str, object]: + """Return a minimal same-repository pull-request fixture.""" + value: dict[str, object] = { + "number": 7, + "isDraft": False, + "baseRefName": "main", + "baseRefOid": "b" * 40, + "headRefName": "feature", + "headRefOid": "a" * 40, + "headRepository": {"nameWithOwner": "owner/repo"}, + "mergeStateStatus": "CLEAN", + "reviews": {"nodes": []}, + "reviewThreads": {"nodes": []}, + } + value.update(overrides) + return value + + +def test_conflicted_draft_skips_before_repair_authority() -> None: + """A conflicted draft remains a draft skip rather than an RCA dispatch.""" + args = fix.parse_args(["--repo", "owner/repo", "--base-branch", "main"]) + + assert fix.inspect_pr( + "owner/repo", + _pr(isDraft=True, mergeStateStatus="DIRTY"), + args, + ) == ("skip", ("draft PR",)) + + +def test_conflicted_unapproved_pr_fails_closed_without_repair_authority() -> None: + """A conflict without explicit unreviewed-repair authority stays closed.""" + args = fix.parse_args(["--repo", "owner/repo", "--base-branch", "main"]) + + assert fix.inspect_pr( + "owner/repo", + _pr(mergeStateStatus="DIRTY"), + args, + ) == ("skip", ("merge conflict is not authorized for repair",)) + + +def test_workflow_name_rest_fallback_paginates_and_filters_rows( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Workflow identity pagination keeps only rows with usable names.""" + page_one = [{"check_suite_id": index, "name": f"workflow-{index}"} for index in range(99)] + page_one.append({"check_suite_id": 99, "name": ""}) + calls: list[str] = [] + + def fake_api(path: str) -> dict[str, object]: + calls.append(path) + if path.endswith("page=1"): + return {"workflow_runs": page_one} + return {"workflow_runs": [{"check_suite_id": 100, "name": "opencode-review"}]} + + monkeypatch.setattr(merge, "gh_api_json", fake_api) + + names = merge.fetch_workflow_names_by_check_suite_rest("owner/repo", "a" * 40) + + assert names[0] == "workflow-0" + assert 99 not in names + assert names[100] == "opencode-review" + assert calls == [ + f"repos/owner/repo/actions/runs?head_sha={'a' * 40}&per_page=100&page=1", + f"repos/owner/repo/actions/runs?head_sha={'a' * 40}&per_page=100&page=2", + ] + + +def test_workflow_name_rest_fallback_treats_permission_denial_as_unknown( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """An inaccessible Actions inventory returns an empty fail-closed map.""" + + def fake_api(_path: str) -> dict[str, object]: + raise RuntimeError("Resource not accessible by integration") + + monkeypatch.setattr(merge, "gh_api_json", fake_api) + + assert merge.fetch_workflow_names_by_check_suite_rest("owner/repo", "a" * 40) == {} + + +def test_workflow_name_rest_fallback_propagates_unrelated_failures( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Transport failures other than permission denial remain visible.""" + + def fake_api(_path: str) -> dict[str, object]: + raise RuntimeError("gh: HTTP 502 (exhausted retries)") + + monkeypatch.setattr(merge, "gh_api_json", fake_api) + + with pytest.raises(RuntimeError, match="HTTP 502"): + merge.fetch_workflow_names_by_check_suite_rest("owner/repo", "a" * 40) From 563a766c5be935a8cdba7afc0cc9684af741e72e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 15:46:35 +0900 Subject: [PATCH 02/24] test(scheduler): close remaining current-main coverage gaps --- tests/test_pr_review_fix_scheduler.py | 86 +++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/tests/test_pr_review_fix_scheduler.py b/tests/test_pr_review_fix_scheduler.py index 9860eeaec7..daeefae573 100644 --- a/tests/test_pr_review_fix_scheduler.py +++ b/tests/test_pr_review_fix_scheduler.py @@ -177,6 +177,92 @@ def test_prepare_autofix_slot_preserves_new_head_workers_after_head_advance(monk workflow_repository=fix.DEFAULT_AUTOFIX_REPOSITORY, dry_run=False, ) is None + + +def test_prepare_autofix_slot_returns_same_head_with_no_stale_workers(monkeypatch): + """No stale workers means the cancellation branch is never entered.""" + head = "a" * 40 + monkeypatch.setattr( + fix, + "run_json", + lambda _args: { + "workflow_runs": [ + { + "id": 1, + "status": "in_progress", + "display_title": f"PR Review Autofix owner/repo#7@{head}", + } + ] + }, + ) + monkeypatch.setattr( + fix, + "force_cancel_workflow_runs", + lambda *_args: pytest.fail("there is no stale worker to cancel"), + ) + monkeypatch.setattr( + fix, + "live_head_matches", + lambda *_args: pytest.fail( + "staleness is only ever checked when a stale worker exists" + ), + ) + + assert fix.prepare_autofix_slot( + "owner/repo", + make_pr(headRefOid=head), + workflow=fix.DEFAULT_AUTOFIX_WORKFLOW, + workflow_repository=fix.DEFAULT_AUTOFIX_REPOSITORY, + dry_run=False, + ) + + +def test_live_head_matches_compares_the_live_head_to_the_cached_snapshot(monkeypatch): + """The real head-matching implementation reads GitHub's current PR head. + + Every other test in this module monkeypatches ``live_head_matches`` away, + so its own body (the ``gh api`` read, the payload-shape guard, and the + case-insensitive comparison) was never exercised by the suite at all. + """ + pr = make_pr(headRefOid="a" * 40) + + monkeypatch.setattr(fix, "run_json", lambda _args: {"head": {"sha": "A" * 40}}) + assert fix.live_head_matches("owner/repo", pr) + + monkeypatch.setattr(fix, "run_json", lambda _args: {"head": {"sha": "b" * 40}}) + assert not fix.live_head_matches("owner/repo", pr) + + monkeypatch.setattr(fix, "run_json", lambda _args: {"head": {"sha": "short"}}) + assert not fix.live_head_matches("owner/repo", pr) + + monkeypatch.setattr(fix, "run_json", lambda _args: {"head": {"sha": None}}) + assert not fix.live_head_matches("owner/repo", pr) + + monkeypatch.setattr(fix, "run_json", lambda _args: {"head": "not-a-dict"}) + assert not fix.live_head_matches("owner/repo", pr) + + monkeypatch.setattr(fix, "run_json", lambda _args: "not-a-dict") + assert not fix.live_head_matches("owner/repo", pr) + + +def test_inspect_pr_reports_active_autofix_worker_without_dispatch(monkeypatch): + """An already-running current-head worker waits instead of re-dispatching.""" + args = fix.parse_args(["--repo", "owner/repo", "--base-branch", "main"]) + monkeypatch.setattr(fix, "needs_autofix", lambda _pr: (True, ("review",))) + monkeypatch.setattr(fix, "issue_comments", lambda _repo, _number: []) + monkeypatch.setattr(fix, "prepare_autofix_slot", lambda *_args, **_kwargs: True) + monkeypatch.setattr( + fix, + "dispatch_autofix", + lambda *_args, **_kwargs: pytest.fail("an active worker must not be redispatched"), + ) + + assert fix.inspect_pr("owner/repo", make_pr(), args) == ( + "wait", + ("current-head autofix run is already queued or running",), + ) + + def test_terminal_failed_check_triggers_rca_without_prior_opencode_review(): """Exact-head check evidence can start RCA without a circular review prerequisite.""" pr = make_pr( From 8b26dab2f8743a286f430a9cdb96a51fa8dd2305 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 15:48:50 +0900 Subject: [PATCH 03/24] fix(agent-mention): stack safe OpenCode slash aliases --- .github/workflows/agent-mention-router.yml | 2 + .../review-agent-comment-invocation.md | 4 +- scripts/ci/agent_mention_router.py | 38 ++++- tests/test_agent_mention_router.py | 154 ++++++++++++++++++ 4 files changed, 195 insertions(+), 3 deletions(-) diff --git a/.github/workflows/agent-mention-router.yml b/.github/workflows/agent-mention-router.yml index 43fb163975..a109c8a97c 100644 --- a/.github/workflows/agent-mention-router.yml +++ b/.github/workflows/agent-mention-router.yml @@ -23,6 +23,8 @@ jobs: && ( contains(github.event.comment.body, '@cwl-noema-review') || contains(github.event.comment.body, '@opencode-agent') + || contains(github.event.comment.body, '/opencode') + || contains(github.event.comment.body, '/oc') ) concurrency: group: review-agent-mention-router-local-${{ github.repository }} diff --git a/docs/automation/review-agent-comment-invocation.md b/docs/automation/review-agent-comment-invocation.md index a886caa967..926249b563 100644 --- a/docs/automation/review-agent-comment-invocation.md +++ b/docs/automation/review-agent-comment-invocation.md @@ -1,13 +1,13 @@ # Review-agent comment invocation -Updated: 2026-08-22 +Updated: 2026-09-01 ## Purpose Trusted ContextualWisdomLab maintainers can invoke the existing review planes from a pull-request conversation: - `@cwl-noema-review` requests the independent Noema review. -- `@opencode-agent` requests a bounded current-head OpenCode review only; the invocation itself disables branch updates, automatic merge, and direct merge. +- `@opencode-agent` (or upstream OpenCode's own `/opencode`/`/oc` comment triggers, accepted as aliases of the same request) requests a bounded current-head OpenCode review only; the invocation itself disables branch updates, automatic merge, and direct merge. The router never checks out or executes pull-request-controlled code. It reads live PR metadata, binds the request to the current head SHA and base branch, and dispatches the already deployed central workflows in `ContextualWisdomLab/.github`. diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index ee9232ebd5..498b885c27 100755 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -15,13 +15,49 @@ CENTRAL_AUTOMATION_REPOSITORY = "ContextualWisdomLab/.github" TRUSTED_ASSOCIATIONS = frozenset({"OWNER", "MEMBER", "COLLABORATOR"}) +# "opencode-agent" also accepts /opencode and /oc: upstream OpenCode's own +# GitHub Action documents those as its trigger phrases +# (https://open-code.ai/en/docs/github), and this repo's dispatch pipeline +# accepts them as aliases of the same @opencode-agent request rather than +# forcing commenters to learn a locally-invented mention instead. +# +# None of the three alternatives below may be preceded by a bare "/": a +# preceding slash almost always means the match is embedded in a URL path +# (e.g. https://opencode.ai/docs, https://youtube.com/@opencode-agent) or an +# ordinary path segment (docs/@opencode-agent), not a deliberate trigger. The +# one deliberate exception is a maintainer separating both supported agent +# requests with a bare slash and no space (@cwl-noema-review/@opencode-agent). +# That case is matched as one combined literal — "@cwl-noema-review/@opencode-agent" +# — guarded by the same left-boundary exclusion as the standalone +# "@opencode-agent" alternative. A boundary check on the trailing slash alone +# is not enough: it would still fire for invalid pasted text where +# "@cwl-noema-review" is itself embedded in a larger token (e.g. +# foo@cwl-noema-review/@opencode-agent, docs/@cwl-noema-review/@opencode-agent) +# without checking that the Noema mention has a valid left boundary of its own. +# The bare /opencode and /oc forms additionally exclude a preceding "=": a +# URL query string (?next=/opencode, ?redirect=/oc) shares the same "not +# preceded by a word character" shape as a deliberate standalone command. +# +# The shared trailing boundary after any of the three alternatives also +# excludes a following "/": without it, a root-relative path continuation +# right after the alias (/oc/config, /opencode/docs, @opencode-agent/config, +# @cwl-noema-review/@opencode-agent/foo) still matched, since the alias text +# itself is a complete, valid match and nothing in the original trailing +# lookahead treated "/" as a word character. This mirrors the +# leading-boundary "/" exclusion already applied above and closes the same +# false-positive class from the trailing side, for every alternative rather +# than only the bare /opencode and /oc forms. MENTION_PATTERNS = { "cwl-noema-review": re.compile( r"(? None: assert module.exact_mentions("@opencode-agent-evil @cwl-noema-review2") == () +@pytest.mark.parametrize( + "body", + [ + "/opencode please re-review", + "/oc please re-review", + "kicking off /oc", + "/OC", + "/OpenCode", + ], +) +def test_exact_mentions_accepts_slash_opencode_aliases(body: str) -> None: + """Upstream OpenCode's own /opencode and /oc trigger phrases also dispatch.""" + + module = load_module() + assert module.exact_mentions(body) == ("opencode-agent",) + + +def test_exact_mentions_accepts_at_mention_after_a_slash_separator() -> None: + """A slash used to separate two agent requests must not swallow the @mention. + + Devin/owner review regression on #1537, across three rounds: + + 1. Excluding a preceding ``/`` from the lookbehind to reject + documentation-link false positives (see + ``test_exact_mentions_rejects_slash_opencode_substrings``) was + originally applied to the whole ``@opencode-agent|/opencode|/oc`` + alternation, so a maintainer separating both requested agents with a + bare slash and no space (``@cwl-noema-review/@opencode-agent``) + silently lost the OpenCode request. + 2. Simply exempting the ``@`` form from the slash exclusion reopened the + same false-positive class for ``/@opencode-agent`` embedded in an + arbitrary URL or path segment. + 3. Recognizing ``/@opencode-agent`` only when the slash is immediately + preceded by the other pattern's exact literal mention text + (``@cwl-noema-review``) checked only the boundary of the trailing + slash, not whether that ``@cwl-noema-review`` occurrence itself has a + valid left boundary, so invalid pasted text such as + ``foo@cwl-noema-review/@opencode-agent`` still dispatched OpenCode + (see ``test_exact_mentions_rejects_invalid_separator_prefixes``). + + The final pattern matches the whole separator form + (``@cwl-noema-review/@opencode-agent``) as one literal, guarded by the + same left-boundary exclusion as the standalone ``@opencode-agent`` + alternative. + """ + + module = load_module() + assert module.exact_mentions("@cwl-noema-review/@opencode-agent") == ( + "cwl-noema-review", + "opencode-agent", + ) + + +@pytest.mark.parametrize( + "body", + [ + "foo@cwl-noema-review/@opencode-agent", + "docs/@cwl-noema-review/@opencode-agent", + "user.name@cwl-noema-review/@opencode-agent", + ], +) +def test_exact_mentions_rejects_invalid_separator_prefixes(body: str) -> None: + """The combined separator literal must not fire when embedded in a larger token. + + Fifth-round finding on #1537, reported directly by the repository owner + (not a review bot): the separator alternative + ``(?<=@cwl-noema-review)/@opencode-agent`` only checked the literal text + immediately before the slash, not whether that ``@cwl-noema-review`` + occurrence itself has a valid left boundary. Pasted text embedding the + Noema mention inside a larger token — a preceding word + (``foo@cwl-noema-review/@opencode-agent``), a path segment + (``docs/@cwl-noema-review/@opencode-agent``), or an email-like local part + (``user.name@cwl-noema-review/@opencode-agent``) — still dispatched an + unintended OpenCode review. The fix matches the whole + ``@cwl-noema-review/@opencode-agent`` literal with the same left-boundary + exclusion as the standalone ``@opencode-agent`` alternative, so it no + longer fires unless the combined mention itself starts at a valid + boundary. Some of these inputs still independently match the unrelated, + pre-existing ``cwl-noema-review`` pattern (e.g. a preceding ``/`` is not + excluded there); that pattern predates this PR and is out of scope for + this fix, so only the OpenCode dispatch is asserted here. + """ + + module = load_module() + assert "opencode-agent" not in module.exact_mentions(body) + + +@pytest.mark.parametrize( + "body", + [ + "the /occupied seat", + "visit /oceanography for more", + "see /opencode-docs for the guide", + "check out https://opencode.ai/docs for more info", + "see http://open-code.ai/en/docs/github", + "share this: https://youtube.com/@opencode-agent", + "see docs/@opencode-agent for the config file", + "visit https://example.com/?next=/opencode for the redirect", + "visit https://example.com/?next=/oc for the redirect", + ], +) +def test_exact_mentions_rejects_slash_opencode_substrings(body: str) -> None: + """A longer token merely starting with /oc or /opencode is not a mention. + + Includes a URL whose path component happens to embed ``/opencode`` right + after the scheme's own ``//`` (Devin review finding on #1537): the prior + lookbehind excluded a preceding letter/digit/underscore/hyphen but not a + preceding ``/``, so a documentation link like ``https://opencode.ai`` + satisfied it and could launch an unintended review. Also includes a + second-round Devin finding on the same PR: restoring plain recognition of + ``@opencode-agent`` after a bare slash (so a maintainer could write + ``@cwl-noema-review/@opencode-agent`` with no space) reopened the same + class of false positive for ``/@opencode-agent`` embedded in an arbitrary + URL or path segment, since both share the exact same "word char, then + slash, then the mention" shape as the deliberate separator case. A third + finding (CodeRabbit, same PR) noted the slash-preceded exclusion for the + bare ``/opencode``/``/oc`` forms did not also exclude a preceding ``=``, + so a URL query string such as ``?next=/opencode`` or ``?next=/oc`` still + matched. + """ + + module = load_module() + assert module.exact_mentions(body) == () + + +@pytest.mark.parametrize( + "body", + [ + "/oc/config", + "/opencode/docs", + "@opencode-agent/config", + "@cwl-noema-review/@opencode-agent/foo", + ], +) +def test_exact_mentions_rejects_trailing_path_continuation(body: str) -> None: + """A root-relative path continuation right after the alias is not a mention. + + Sixth-round finding on #1537's successor PR (Devin): the shared trailing + boundary after all three ``opencode-agent`` alternatives excluded a + following letter, digit, underscore, or hyphen but not a following + ``/``, so a root-relative path glued directly onto the alias — ``/oc`` + followed by ``/config``, ``/opencode`` followed by ``/docs``, or even + ``@opencode-agent`` or the ``@cwl-noema-review/@opencode-agent`` + separator followed by ``/config`` or ``/foo`` — still matched as a + complete, valid mention, since nothing treated the alias text itself as + incomplete just because a slash continued right after it. The fix adds + ``/`` to the shared trailing exclusion, mirroring the leading-boundary + ``/`` exclusion already applied to each alternative from the other side. + """ + + module = load_module() + assert "opencode-agent" not in module.exact_mentions(body) + + @pytest.mark.parametrize( "payload", [ From cd6a98618f504b1c5ab46ace65c4cc831e062fa6 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 06:53:19 +0000 Subject: [PATCH 04/24] fix(agent-mention): exclude a trailing query string from the opencode-agent boundary The shared trailing lookahead excluded a following letter, digit, underscore, hyphen, or slash, but not a following "?", so a query string glued directly onto the alias with no separator (/oc?mode=docs, /opencode?next=x) still matched as a complete mention. Reported by CodeRabbit on this feature's predecessor PR (#1558, now closed in favor of this clean stack on #1554). Reproduced first, then added "?" to the same shared trailing exclusion, verified against the full existing accept/reject matrix plus the new query-string cases before applying. Full suite: 2278 passed, 1 skipped, 21 subtests passed. 100% coverage and 100% docstrings maintained. --- scripts/ci/agent_mention_router.py | 8 ++++++-- tests/test_agent_mention_router.py | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index 498b885c27..da2f257826 100755 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -46,7 +46,11 @@ # lookahead treated "/" as a word character. This mirrors the # leading-boundary "/" exclusion already applied above and closes the same # false-positive class from the trailing side, for every alternative rather -# than only the bare /opencode and /oc forms. +# than only the bare /opencode and /oc forms. It also excludes a following +# "?": a query string glued directly onto the alias with no separator +# (/oc?mode=docs, /opencode?next=x) is a URL path with a query component, +# not a standalone command, and shares the exact same "alias text is a +# complete match, but something non-word continues right after it" shape. MENTION_PATTERNS = { "cwl-noema-review": re.compile( r"(? None: assert "opencode-agent" not in module.exact_mentions(body) +@pytest.mark.parametrize( + "body", + [ + "/oc?mode=docs", + "/opencode?next=x", + ], +) +def test_exact_mentions_rejects_trailing_query_string(body: str) -> None: + """A query string glued directly onto the alias is not a mention. + + Seventh-round finding on #1537's successor PR (CodeRabbit): the shared + trailing boundary excluded a following letter, digit, underscore, + hyphen, or slash, but not a following ``?``, so a query string with no + separator (``/oc?mode=docs``, ``/opencode?next=x``) still matched as a + complete mention — the same "alias text is a complete match, but + something non-word continues right after it" shape as the sixth-round + trailing-slash finding, just with ``?`` instead of ``/``. The fix adds + ``?`` to the same shared trailing exclusion. + """ + + module = load_module() + assert "opencode-agent" not in module.exact_mentions(body) + + @pytest.mark.parametrize( "payload", [ From de821dff291883789c1c77e5f5b8075d68eda53f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 07:04:13 +0000 Subject: [PATCH 05/24] fix(agent-mention): give each mention alternative its own boundary, fix a regression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two real findings on this exact head (both Devin): 1. (New bug) The bare /opencode and /oc forms' boundary excluded neither a preceding "#" (a URL fragment identifier: https://example.com/#/oc) nor a following "." (a dotted filename continuation: /oc.json), and the trailing boundary used a plain ASCII character class, so a following non-ASCII word character was never excluded (/océan, where "é" is a Unicode letter outside [A-Za-z0-9_/?-]). 2. (Regression, introduced by the immediately preceding commit) Adding "?" to the shared trailing lookahead affected all three opencode-agent alternatives, not just the bare-slash forms it was meant for, so "@opencode-agent?" and "@cwl-noema-review/@opencode-agent?" — ordinary sentence punctuation, not a URL query string — stopped dispatching. Root cause of both: a single trailing lookahead shared across the whole alternation can't express "exclude ? only for these two alternatives, exclude . and # only for these two, but not those." Fixed by giving each alternative its own leading and trailing lookaround instead of one shared lookahead outside the group, and switching every boundary in this module from an ASCII-only character class to Python's Unicode-aware `\w` (which also closes the same class of gap for the @-mention forms, e.g. "café@opencode-agent", not just the reported bare-slash cases). While redesigning, also closed a previously-flagged, out-of-scope gap: `cwl-noema-review`'s own pattern didn't exclude a preceding "/", so "docs/@cwl-noema-review/@opencode-agent" still fired Noema (flagged but not fixed in an earlier round on this same PR chain, since fixing it then would have needed exactly this per-alternative-boundary work to avoid breaking the "@cwl-noema-review/@opencode-agent" separator's own recognition of the Noema mention preceding it). Verified with a from-scratch script against all ~35 accumulated accept/ reject cases from every prior round on this file before touching source, catching two design mistakes (a leftover shared trailing "/" that broke the separator form, and a dropped hyphen exclusion) before they ever reached the test suite. Full suite: 2285 passed, 1 skipped, 21 subtests passed. 100% coverage and 100% docstrings maintained. git diff --check clean. --- scripts/ci/agent_mention_router.py | 79 +++++++++++++++------------ tests/test_agent_mention_router.py | 88 ++++++++++++++++++++++++++---- 2 files changed, 123 insertions(+), 44 deletions(-) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index da2f257826..0fbcadff2d 100755 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -21,47 +21,58 @@ # accepts them as aliases of the same @opencode-agent request rather than # forcing commenters to learn a locally-invented mention instead. # -# None of the three alternatives below may be preceded by a bare "/": a -# preceding slash almost always means the match is embedded in a URL path -# (e.g. https://opencode.ai/docs, https://youtube.com/@opencode-agent) or an -# ordinary path segment (docs/@opencode-agent), not a deliberate trigger. The -# one deliberate exception is a maintainer separating both supported agent -# requests with a bare slash and no space (@cwl-noema-review/@opencode-agent). -# That case is matched as one combined literal — "@cwl-noema-review/@opencode-agent" -# — guarded by the same left-boundary exclusion as the standalone -# "@opencode-agent" alternative. A boundary check on the trailing slash alone -# is not enough: it would still fire for invalid pasted text where -# "@cwl-noema-review" is itself embedded in a larger token (e.g. -# foo@cwl-noema-review/@opencode-agent, docs/@cwl-noema-review/@opencode-agent) -# without checking that the Noema mention has a valid left boundary of its own. -# The bare /opencode and /oc forms additionally exclude a preceding "=": a -# URL query string (?next=/opencode, ?redirect=/oc) shares the same "not -# preceded by a word character" shape as a deliberate standalone command. +# Boundary model (each alternative below carries its own leading and +# trailing lookaround, not a lookahead shared across the alternation, so +# each form's exclusions can differ where the false-positive classes +# differ): # -# The shared trailing boundary after any of the three alternatives also -# excludes a following "/": without it, a root-relative path continuation -# right after the alias (/oc/config, /opencode/docs, @opencode-agent/config, -# @cwl-noema-review/@opencode-agent/foo) still matched, since the alias text -# itself is a complete, valid match and nothing in the original trailing -# lookahead treated "/" as a word character. This mirrors the -# leading-boundary "/" exclusion already applied above and closes the same -# false-positive class from the trailing side, for every alternative rather -# than only the bare /opencode and /oc forms. It also excludes a following -# "?": a query string glued directly onto the alias with no separator -# (/oc?mode=docs, /opencode?next=x) is a URL path with a query component, -# not a standalone command, and shares the exact same "alias text is a -# complete match, but something non-word continues right after it" shape. +# - "@opencode-agent" and the combined "@cwl-noema-review/@opencode-agent" +# separator each exclude a preceding/following Unicode word character +# (\w — this also covers accented and other non-ASCII letters, not just +# ASCII), hyphen, or slash. The leading "/" exclusion rejects URL/path +# embedding (https://youtube.com/@opencode-agent, docs/@opencode-agent); +# the trailing "/" exclusion rejects a root-relative path glued directly +# onto the alias (@opencode-agent/config, +# @cwl-noema-review/@opencode-agent/foo). Ordinary sentence punctuation +# (a trailing "?", ".", "!") is deliberately NOT excluded here: a +# maintainer ending a sentence with "@opencode-agent?" is a legitimate +# request, not a URL continuation — rejecting it (an early version of +# this exclusion did, by mistake, when a query-string fix below was +# applied to every alternative instead of only the one it targeted) is a +# worse failure mode than never seeing the rare literal "@opencode-agent" +# immediately followed by junk with no separating space. +# - The "@cwl-noema-review/@opencode-agent" separator's own left boundary +# is on the combined literal as a whole, not just the trailing slash: a +# boundary check on the slash alone would still fire for invalid pasted +# text where "@cwl-noema-review" is itself embedded in a larger token +# (foo@cwl-noema-review/@opencode-agent, +# docs/@cwl-noema-review/@opencode-agent) without checking that the +# Noema mention has a valid left boundary of its own. +# - The bare "/opencode"/"/oc" forms are the most URL/path-context-prone, +# so both sides exclude the full set of characters that continue a +# URL/path/filename token: a Unicode word character, ".", "/", "?", "=", +# "#", or "-". This rejects, on the leading side, a query string +# (?next=/opencode) and a URL fragment identifier +# (https://example.com/#/oc); and on the trailing side, a root-relative +# path (/oc/config), a dotted filename continuation (/oc.json), a query +# string glued on with no separator (/oc?mode=docs), and a Unicode word +# continuation (/océan) that a plain ASCII character class would miss. +# - "@cwl-noema-review" on its own additionally excludes a preceding "/" +# (closing the same URL/path-embedding class as "@opencode-agent" above) +# but deliberately NOT a trailing "/": that would break recognition of +# its own mention inside the "@cwl-noema-review/@opencode-agent" +# separator, where a "/" legitimately follows it. MENTION_PATTERNS = { "cwl-noema-review": re.compile( - r"(? None: ], ) def test_exact_mentions_rejects_trailing_query_string(body: str) -> None: - """A query string glued directly onto the alias is not a mention. - - Seventh-round finding on #1537's successor PR (CodeRabbit): the shared - trailing boundary excluded a following letter, digit, underscore, - hyphen, or slash, but not a following ``?``, so a query string with no - separator (``/oc?mode=docs``, ``/opencode?next=x``) still matched as a - complete mention — the same "alias text is a complete match, but - something non-word continues right after it" shape as the sixth-round - trailing-slash finding, just with ``?`` instead of ``/``. The fix adds - ``?`` to the same shared trailing exclusion. + """A query string glued directly onto the bare slash alias is not a mention. + + Seventh-round finding on #1537's successor PR (CodeRabbit): the bare + ``/opencode``/``/oc`` forms' trailing boundary excluded a following + letter, digit, underscore, hyphen, or slash, but not a following ``?``, + so a query string with no separator (``/oc?mode=docs``, + ``/opencode?next=x``) still matched as a complete mention. The fix adds + ``?`` to that alternative's own trailing exclusion only — see + ``test_exact_mentions_accepts_ordinary_punctuation_after_at_mentions`` + for why this must NOT be shared with the ``@``-mention alternatives. """ module = load_module() assert "opencode-agent" not in module.exact_mentions(body) +def test_exact_mentions_accepts_ordinary_punctuation_after_at_mentions() -> None: + """A trailing "?" after an @-mention is ordinary punctuation, not a mention. + + Ninth-round finding on #1537's successor PR (Devin), a regression from + the eighth-round fix above: excluding a trailing ``?`` was applied to + the whole ``opencode-agent`` alternation instead of scoped to only the + bare-slash forms it was meant for, so a maintainer ending a sentence + with ``@opencode-agent?`` (or the ``@cwl-noema-review/@opencode-agent`` + separator followed by ``?``) silently stopped dispatching. Each + alternative now carries its own trailing lookahead instead of one + shared across the alternation, so the bare-slash forms' ``?`` exclusion + no longer leaks onto the ``@``-mention forms. + """ + + module = load_module() + assert module.exact_mentions("@opencode-agent?") == ("opencode-agent",) + assert module.exact_mentions("@cwl-noema-review/@opencode-agent?") == ( + "cwl-noema-review", + "opencode-agent", + ) + + +@pytest.mark.parametrize( + "body", + [ + "https://example.com/#/oc", + "https://example.com/#/opencode", + "/oc.json", + "/opencode.json", + "/océan", + ], +) +def test_exact_mentions_rejects_fragment_dotted_and_unicode_continuations( + body: str, +) -> None: + """A URL fragment, dotted filename, or Unicode word continuation is not a mention. + + Eighth-round finding on #1537's successor PR (Devin): the bare + ``/opencode``/``/oc`` forms' boundary excluded neither a preceding + ``#`` (a URL fragment identifier, ``https://example.com/#/oc``) nor a + following ``.`` (a dotted filename continuation, ``/oc.json``), and + used a plain ASCII character class for the trailing boundary, which + does not exclude a following non-ASCII word character (``/océan``, + where ``é`` is a Unicode letter but not in ``[A-Za-z0-9_/?-]``). The fix + adds ``#`` and ``.`` to that alternative's own leading/trailing + exclusion set and switches every boundary in this module from an + ASCII-only character class to Python's Unicode-aware ``\\w``. + """ + + module = load_module() + assert "opencode-agent" not in module.exact_mentions(body) + + +def test_exact_mentions_rejects_unicode_embedded_at_mentions() -> None: + """A Unicode word character directly touching an @-mention is not a mention. + + Companion case to the eighth-round Unicode finding above, for the + ``@``-mention alternatives rather than the bare-slash forms: switching + their boundaries to Unicode-aware ``\\w`` closes the same class of gap + (a preceding or following accented letter that a plain ASCII character + class would not have excluded). + """ + + module = load_module() + assert module.exact_mentions("café@opencode-agent") == () + assert module.exact_mentions("@opencode-agenté") == () + + @pytest.mark.parametrize( "payload", [ From f26b3bdbd6128ef3dae53bedf0f39c305a9b0144 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 07:13:20 +0000 Subject: [PATCH 06/24] fix(agent-mention): exclude a percent-encoded path or URI scheme separator The bare /opencode and /oc forms' boundary excluded neither a following "%" (a percent-encoded path continuation: /oc%2Fconfig) nor a preceding ":" (a URI scheme separator: scheme:/oc, app:/opencode), so both still matched as complete, standalone mentions. Reported by Devin on this PR's current head. Reproduced first, then added "%" and ":" to that alternative's own leading/trailing exclusion set alongside the ".", "/", "?", "=", and "#" already excluded there. Verified against the full accumulated accept/reject matrix (41 cases from every prior round on this file) before applying. Full suite: 2289 passed, 1 skipped, 21 subtests passed. 100% coverage and 100% docstrings maintained. --- scripts/ci/agent_mention_router.py | 16 +++++++++------- tests/test_agent_mention_router.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index 0fbcadff2d..590e55ff68 100755 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -51,12 +51,14 @@ # - The bare "/opencode"/"/oc" forms are the most URL/path-context-prone, # so both sides exclude the full set of characters that continue a # URL/path/filename token: a Unicode word character, ".", "/", "?", "=", -# "#", or "-". This rejects, on the leading side, a query string -# (?next=/opencode) and a URL fragment identifier -# (https://example.com/#/oc); and on the trailing side, a root-relative -# path (/oc/config), a dotted filename continuation (/oc.json), a query -# string glued on with no separator (/oc?mode=docs), and a Unicode word -# continuation (/océan) that a plain ASCII character class would miss. +# "#", "%", ":", or "-". This rejects, on the leading side, a query +# string (?next=/opencode), a URL fragment identifier +# (https://example.com/#/oc), and a URI scheme separator (scheme:/oc, +# app:/opencode); and on the trailing side, a root-relative path +# (/oc/config), a dotted filename continuation (/oc.json), a query +# string glued on with no separator (/oc?mode=docs), a percent-encoded +# path continuation (/oc%2Fconfig), and a Unicode word continuation +# (/océan) that a plain ASCII character class would miss. # - "@cwl-noema-review" on its own additionally excludes a preceding "/" # (closing the same URL/path-embedding class as "@opencode-agent" above) # but deliberately NOT a trailing "/": that would break recognition of @@ -71,7 +73,7 @@ r"(?:" r"(? None: + """A percent-encoded path or URI-scheme-separated alias is not a mention. + + Tenth-round finding on #1537's successor PR (Devin): the bare + ``/opencode``/``/oc`` forms' boundary excluded neither a following + ``%`` (a percent-encoded path continuation, ``/oc%2Fconfig``) nor a + preceding ``:`` (a URI scheme separator, ``scheme:/oc``, ``app:/oc``), + so both still matched as complete, standalone mentions. The fix adds + ``%`` and ``:`` to that alternative's own leading/trailing exclusion + set, alongside the ``.``, ``/``, ``?``, ``=``, and ``#`` already + excluded there. + """ + + module = load_module() + assert "opencode-agent" not in module.exact_mentions(body) + + @pytest.mark.parametrize( "payload", [ From db106d50f2134ece147bc5318e389aeb124d198c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 07:21:06 +0000 Subject: [PATCH 07/24] test(ci): close main's post-#1546 scheduler coverage regression Protected main regressed to 99% scripts/ci coverage after #1546 added live_head_matches, a no-active/no-stale fall-through in prepare_autofix_slot, and an "already queued or running" wait branch to pr_review_fix_scheduler.py without covering them, while the pre-existing inspect_pr conflicted-draft/conflicted-unauthorized returns and pr_review_merge_scheduler.py's fetch_workflow_names_by_check_suite_rest pagination/filtering/ permission-denied paths stayed untested. Every PR rebasing onto main inherits this via the coverage-evidence required check regardless of its own diff. Test-only change; no production code touched. --- CHANGELOG.md | 9 +++ tests/test_pr_review_fix_scheduler.py | 49 ++++++++++++++ ...ew_fix_scheduler_rest_workflow_identity.py | 67 +++++++++++++++++++ 3 files changed, 125 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5810d5308..1c46c64657 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ this file. The format follows Keep a Changelog, and versioned releases follow Semantic Versioning where the repository publishes a release. ## [Unreleased] +- Close a 99% `scripts/ci` coverage regression on protected main: merged #1546 added an + uncovered `live_head_matches` helper, an uncovered no-active/no-stale-runs fall-through in + `prepare_autofix_slot`, and an uncovered "current-head autofix run is already queued or + running" wait path in `pr_review_fix_scheduler.py::inspect_pr`, while the pre-existing + conflicted-draft and conflicted-unauthorized `inspect_pr` returns and the REST + `fetch_workflow_names_by_check_suite_rest` pagination/name-filtering/permission-denied paths + in `pr_review_merge_scheduler.py` remained untested. Every PR rebasing onto main inherited + this failure via the `coverage-evidence` required check regardless of its own diff; this adds + test-only coverage for all of the above with no production code change. - Avoid redundant merge-scheduler wakes when the trusted receipt predicate already finds a substantive exact-head OpenCode verdict. Missing, stale, or fallback-only evidence still dispatches review work, while receipt lookup or diff --git a/tests/test_pr_review_fix_scheduler.py b/tests/test_pr_review_fix_scheduler.py index 9860eeaec7..f6abd64b0f 100644 --- a/tests/test_pr_review_fix_scheduler.py +++ b/tests/test_pr_review_fix_scheduler.py @@ -177,6 +177,40 @@ def test_prepare_autofix_slot_preserves_new_head_workers_after_head_advance(monk workflow_repository=fix.DEFAULT_AUTOFIX_REPOSITORY, dry_run=False, ) is None + + +def test_prepare_autofix_slot_returns_directly_with_no_active_or_stale_runs(monkeypatch): + """An empty Actions run list needs no reconciliation and skips cancellation.""" + monkeypatch.setattr(fix, "run_json", lambda _args: {"workflow_runs": []}) + monkeypatch.setattr( + fix, + "force_cancel_workflow_runs", + lambda *_args: pytest.fail("no stale runs must not attempt cancellation"), + ) + + assert fix.prepare_autofix_slot( + "owner/repo", + make_pr(), + workflow=fix.DEFAULT_AUTOFIX_WORKFLOW, + workflow_repository=fix.DEFAULT_AUTOFIX_REPOSITORY, + dry_run=False, + ) is False + + +def test_live_head_matches_compares_case_insensitively_and_fails_closed(monkeypatch): + """Live head lookup normalizes case and rejects malformed or mismatched payloads.""" + head = "a" * 40 + + monkeypatch.setattr(fix, "run_json", lambda _args: {"head": {"sha": head.upper()}}) + assert fix.live_head_matches("owner/repo", make_pr(headRefOid=head)) + + monkeypatch.setattr(fix, "run_json", lambda _args: {"head": {"sha": "b" * 40}}) + assert not fix.live_head_matches("owner/repo", make_pr(headRefOid=head)) + + monkeypatch.setattr(fix, "run_json", lambda _args: {"nothead": {}}) + assert not fix.live_head_matches("owner/repo", make_pr(headRefOid=head)) + + def test_terminal_failed_check_triggers_rca_without_prior_opencode_review(): """Exact-head check evidence can start RCA without a circular review prerequisite.""" pr = make_pr( @@ -1329,6 +1363,21 @@ def test_fix_inspect_skip_wait_and_error_paths(monkeypatch): monkeypatch.setattr(fix, "issue_comments", lambda repo, number: [{"body": f"{fix.FIX_MARKER} head_sha={'a' * 40} epoch={int(time.time())} -->"}]) assert fix.inspect_pr("owner/repo", make_pr(), args) == ("wait", ("recent autofix marker exists for this head",)) + assert fix.inspect_pr( + "owner/repo", make_pr(mergeStateStatus="DIRTY", isDraft=True), args + ) == ("skip", ("draft PR",)) + assert fix.inspect_pr("owner/repo", make_pr(mergeStateStatus="DIRTY"), args) == ( + "skip", + ("merge conflict is not authorized for repair",), + ) + + monkeypatch.setattr(fix, "issue_comments", lambda repo, number: []) + monkeypatch.setattr(fix, "prepare_autofix_slot", lambda *_args, **_kwargs: True) + assert fix.inspect_pr("owner/repo", make_pr(), args) == ( + "wait", + ("current-head autofix run is already queued or running",), + ) + pr1 = make_pr(number=1) pr2 = make_pr(number=2) monkeypatch.setattr(fix, "fetch_open_prs", lambda repo, max_prs: [pr1, pr2]) diff --git a/tests/test_pr_review_fix_scheduler_rest_workflow_identity.py b/tests/test_pr_review_fix_scheduler_rest_workflow_identity.py index c24cfb05f9..f261ce5beb 100644 --- a/tests/test_pr_review_fix_scheduler_rest_workflow_identity.py +++ b/tests/test_pr_review_fix_scheduler_rest_workflow_identity.py @@ -154,3 +154,70 @@ def fake_api(path: str) -> Any: assert merge.is_strix_context(context) assert merge.strix_evidence_state(pr) == expected_state assert fix.current_head_failed_checks(pr) == () + + +def test_fetch_workflow_names_by_check_suite_rest_paginates_past_100( + monkeypatch: Any, +) -> None: + """A first page of exactly 100 runs must fetch a second page and merge both.""" + head_sha = "e" * 40 + page1 = [ + {"check_suite_id": i, "name": f"workflow-{i}"} for i in range(100) + ] + page2 = [{"check_suite_id": 100, "name": "workflow-100"}] + calls: list[str] = [] + + def fake_api(path: str) -> Any: + calls.append(path) + if path.endswith("page=1"): + return {"workflow_runs": page1} + if path.endswith("page=2"): + return {"workflow_runs": page2} + raise AssertionError(f"unexpected path {path}") + + monkeypatch.setattr(merge, "gh_api_json", fake_api) + + names = merge.fetch_workflow_names_by_check_suite_rest("owner/repo", head_sha) + + assert names == {i: f"workflow-{i}" for i in range(101)} + assert calls == [ + f"repos/owner/repo/actions/runs?head_sha={head_sha}&per_page=100&page=1", + f"repos/owner/repo/actions/runs?head_sha={head_sha}&per_page=100&page=2", + ] + + +def test_fetch_workflow_names_by_check_suite_rest_skips_entries_missing_suite_id_or_name( + monkeypatch: Any, +) -> None: + """A run with no check-suite id or a blank name must not populate the map.""" + head_sha = "f" * 40 + + def fake_api(path: str) -> Any: + return { + "workflow_runs": [ + {"check_suite_id": None, "name": "orphaned run"}, + {"check_suite_id": 900, "name": ""}, + {"check_suite_id": 901, "name": "kept run"}, + ] + } + + monkeypatch.setattr(merge, "gh_api_json", fake_api) + + names = merge.fetch_workflow_names_by_check_suite_rest("owner/repo", head_sha) + + assert names == {901: "kept run"} + + +def test_fetch_workflow_names_by_check_suite_rest_propagates_non_access_errors( + monkeypatch: Any, +) -> None: + """A page-fetch failure unrelated to integration access must fail closed.""" + head_sha = "0" * 40 + + def fake_api(path: str) -> Any: + raise RuntimeError("gh: HTTP 502 (exhausted retries)") + + monkeypatch.setattr(merge, "gh_api_json", fake_api) + + with pytest.raises(RuntimeError, match="HTTP 502"): + merge.fetch_workflow_names_by_check_suite_rest("owner/repo", head_sha) From c46445b02a04a76cf6a3d72d8ab6e00d7025bc6c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 07:22:52 +0000 Subject: [PATCH 08/24] fix(agent-mention): make % and : boundary exclusions direction-specific MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tenth-round fix added both "%" and ":" to the SAME leading-and-trailing exclusion set for the bare /opencode and /oc forms, but each character is only ever a URL/path continuation indicator from the direction it actually appears in a URL: - "%" starts a percent-encoding escape (%2F), which only ever continues a path FORWARD (/oc%2Fconfig) — a preceding "%" (100%/oc) is not a URL-encoding pattern. - ":" separates a URI scheme from its path (scheme:/oc), which only ever precedes the alias — a following ":" (/oc:) is not a scheme separator. Excluding "%" on the leading side and ":" on the trailing side too had no motivating false-positive case and instead rejected ordinary usage (reported by Devin on this PR's current head): "/oc:" (colon as a label separator after the command) and "100%/oc" (a percentage immediately before a command, no space). Fixed by splitting the shared set into direction-specific leading (".", "/", "?", "=", "#", ":", plus \w and "-") and trailing (".", "/", "?", "=", "#", "%", plus \w and "-") exclusion sets. Verified against the full accumulated accept/reject matrix (43 cases from every prior round on this file) before applying. Also fixes an unrelated, pre-existing test-harness flake this branch inherited: tests/test_opencode_required_verdict_regression.py's fake `gh` script didn't drain stdin before exiting on the dispatches branch, so the upstream `jq -cn | gh api --input -` pipe intermittently received SIGPIPE under `set -o pipefail` (exit 141) — a timing race, not a production bug (the real `gh api --input -` does read its stdin). Root-caused and fixed the same way as the already-diagnosed instance of this flake elsewhere in this PR chain: `cat >/dev/null` before recording the dispatch. Verified with 20 consecutive clean runs of the previously-flaky test after the fix. Full suite: 2293 passed, 1 skipped, 21 subtests passed. 100% coverage and 100% docstrings maintained. --- scripts/ci/agent_mention_router.py | 32 +++++++++----- tests/test_agent_mention_router.py | 44 +++++++++++++++++-- ...st_opencode_required_verdict_regression.py | 1 + 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index 590e55ff68..c19a4c1342 100755 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -49,16 +49,28 @@ # docs/@cwl-noema-review/@opencode-agent) without checking that the # Noema mention has a valid left boundary of its own. # - The bare "/opencode"/"/oc" forms are the most URL/path-context-prone, -# so both sides exclude the full set of characters that continue a -# URL/path/filename token: a Unicode word character, ".", "/", "?", "=", -# "#", "%", ":", or "-". This rejects, on the leading side, a query -# string (?next=/opencode), a URL fragment identifier +# so both sides exclude the characters that continue a URL/path/filename +# token, but NOT the same set on both sides — each excluded character is +# only ever a continuation indicator from the direction it actually +# appears in a URL. Leading exclusion: a Unicode word character, ".", +# "/", "?", "=", "#", ":", or "-". This rejects a query string +# (?next=/opencode), a URL fragment identifier # (https://example.com/#/oc), and a URI scheme separator (scheme:/oc, -# app:/opencode); and on the trailing side, a root-relative path -# (/oc/config), a dotted filename continuation (/oc.json), a query -# string glued on with no separator (/oc?mode=docs), a percent-encoded -# path continuation (/oc%2Fconfig), and a Unicode word continuation -# (/océan) that a plain ASCII character class would miss. +# app:/opencode) — but NOT a preceding "%", since percent-encoding syntax +# is "%" followed by hex digits, never followed by a literal "/", so a +# leading "%" before "/oc" (100%/oc) is not a URL-encoding pattern and +# was, in an earlier version of this exclusion, wrongly rejected as one. +# Trailing exclusion: a Unicode word character, ".", "/", "?", "=", "#", +# "%", or "-". This rejects a root-relative path (/oc/config), a dotted +# filename continuation (/oc.json), a query string glued on with no +# separator (/oc?mode=docs), a percent-encoded path continuation +# (/oc%2Fconfig), and a Unicode word continuation (/océan) that a plain +# ASCII character class would miss — but NOT a trailing ":", since a +# colon is not itself a path/URL continuation character in this +# direction (unlike the scheme-separator case, which is a *preceding* +# colon), so excluding it on the trailing side too, in an earlier +# version, wrongly rejected ordinary usage like "/oc:" (a colon used as +# a label separator after the command, not as part of a URL). # - "@cwl-noema-review" on its own additionally excludes a preceding "/" # (closing the same URL/path-embedding class as "@opencode-agent" above) # but deliberately NOT a trailing "/": that would break recognition of @@ -73,7 +85,7 @@ r"(?:" r"(? None: + """A colon after, or a percent sign before, the alias is not a URL indicator. + + Eleventh-round finding on #1537's successor PR (Devin), a regression + from the tenth-round fix above: that fix added both ``%`` and ``:`` to + the *same* leading-and-trailing exclusion set, but each character is + only ever a URL/path continuation indicator from the direction it + actually appears in a URL — a percent sign starts percent-encoding + escapes (``%2F``), so it only matters as a *trailing* character + (``/oc%2Fconfig``); a colon separates a URI scheme from its path, so it + only matters as a *leading* character (``scheme:/oc``). Excluding "%" + on the leading side and ":" on the trailing side too had no motivating + false-positive case and instead rejected ordinary usage: ``/oc:`` (a + colon used as a label separator after the command) and ``100%/oc`` (a + percentage immediately before a command, no space). The fix splits the + two into direction-specific exclusion sets instead of one shared set + applied to both boundaries. + """ + + module = load_module() + assert module.exact_mentions(body) == ("opencode-agent",) + + @pytest.mark.parametrize( "payload", [ diff --git a/tests/test_opencode_required_verdict_regression.py b/tests/test_opencode_required_verdict_regression.py index 8f8047ff10..0e5d30805b 100644 --- a/tests/test_opencode_required_verdict_regression.py +++ b/tests/test_opencode_required_verdict_regression.py @@ -173,6 +173,7 @@ def test_scheduler_wake_reuses_trusted_receipt_predicate( elif [[ "$*" == *"/pulls/7/reviews"* ]]; then printf '[%s]' "$FAKE_REVIEWS" elif [[ "$*" == *"repos/ContextualWisdomLab/.github/dispatches"* ]]; then + cat >/dev/null printf 'dispatch\n' >>"$DISPATCH_CALLS" fi """, From 6920f07f1a3f451b20dde5dfd2e211c39fa73abf Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 07:30:01 +0000 Subject: [PATCH 09/24] fix(agent-mention): reject colon- and percent-delimited path segments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Distinguishing "/oc:" (accept: a colon used as a label separator, at end of string or before a space) from "/oc:config" (reject: a colon-delimited path segment) needs more context than a single trailing character can express — both have ":" as the character immediately after the alias. Likewise "100%/oc" (accept: a percentage before a command) from "docs/%/oc" (reject: a literal "%" path segment) both have "%" as the character immediately before the alias. Reported by Devin on this PR's current head. Reproduced first (/oc:config and docs/%/oc both matched before the fix). Fixed by adding two fixed-width two-character lookarounds on top of the existing single-character exclusion sets, rather than widening those sets (which cannot distinguish the accept case from the reject case sharing the same immediate character): - `(? None: + """A colon-delimited or percent-delimited path segment is not a mention. + + Twelfth-round finding on #1537's successor PR (Devin): distinguishing + ``/oc:`` (accept) from ``/oc:config`` (reject), and ``100%/oc`` (accept) + from ``docs/%/oc`` (reject), needs more context than a single + leading/trailing character can express — in both accept cases the + punctuation sits at a natural boundary (end of string, or preceded by + an ordinary word/digit); in both reject cases the SAME punctuation + character is itself part of a path/URI structure (a colon immediately + followed by more path text, forming a colon-delimited segment; a + percent sign immediately preceded by a path separator, forming a + literal "%" path segment). The fix adds two fixed-width two-character + lookarounds — ``(? Date: Tue, 1 Sep 2026 07:38:38 +0000 Subject: [PATCH 10/24] docs(gap-baseline): record post-#1546 scheduler coverage regression Adds a dated traceability entry for the coverage gap this PR closes: root cause (#1546's uncovered additions plus the older #1547/#1551/ #1554 gap, neither of which merged or transfers evidence here), the fix and its verification, the resolved Devin false-positive on sub-clause coverage, and the known pre-existing SIGPIPE test flake left unremediated as out of scope. --- docs/product-technical-gap-baseline.md | 48 ++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 76d85b949b..812f068e34 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -2344,6 +2344,54 @@ contract assertion, and `docs/adr/0003-contextual-orchestrator-vendored-free-zdr "today" reference. Landed in the same PR (`#1463`) as the streaming revert, not split out, since the revert is unsafe without it. +## 2026-09-01 post-#1546 `scripts/ci` coverage regression on protected main: root-caused and closed + +**Context**: `#1546` (merged, exact head `5686de41660d51a7a7f22b8840dfa6ccfe5ff3f1`) reconciled +unbounded exact-head review agents and, as part of a 90-line expansion of +`scripts/ci/pr_review_fix_scheduler.py`, added a `live_head_matches` helper, a no-active/no-stale +fall-through branch in `prepare_autofix_slot`, and an "already queued or running" wait branch in +`inspect_pr` — none of which any test exercised directly. This compounded a narrower, older gap in +the same file (`inspect_pr`'s conflicted-draft and conflicted-unauthorized returns) and in +`scripts/ci/pr_review_merge_scheduler.py::fetch_workflow_names_by_check_suite_rest` (pagination, +missing-suite-id/blank-name filtering, non-access-error propagation), first found and attempted in +now-closed, unmerged `#1547`/`#1551`/`#1554` — none of whose evidence or diffs transferred here; +this pass re-derived the current gap from a clean `origin/main` clone rather than assuming those +predecessors were still accurate against `#1546`'s shifted line numbers and new branches. Verified +directly: `coverage report --show-missing` on unmodified `main` showed +`scripts/ci/pr_review_fix_scheduler.py` at 97% (missing 116-121, 459->466, 495, 503, 546) and +`scripts/ci/pr_review_merge_scheduler.py` at 99% (missing 1003, 1008->1005, 1012) — total repo-wide +99%, below the `pyproject.toml` `fail_under = 100` gate. Because `opencode-review-dispatch.yml`'s +`coverage-evidence` job measures the **merged** PR tree (base + head) and hard-fails below 100%, +every PR rebasing onto main inherited this failure regardless of its own diff — org-wide impact, +not scoped to one PR. + +**Fix**: `#1567` (test-only, no production code) adds direct unit coverage for `live_head_matches` +(case-insensitive match, mismatch, malformed-payload paths), `prepare_autofix_slot`'s empty-run +fall-through, the `inspect_pr` conflicted-draft/conflicted-unauthorized/already-queued cases, and +the `fetch_workflow_names_by_check_suite_rest` pagination/filtering/error-propagation paths. +Verified on the fix commit (`db106d50f2134ece147bc5318e389aeb124d198c`): `coverage run -m pytest +tests -q` (2251 passed, 1 skipped, 21 subtests), `coverage report` (repo-wide 100%, both files +individually 100% statement and 100% branch), `interrogate` (100.0%). + +**Devin Review raised a false positive on the fix itself**, claiming +`test_live_head_matches_compares_case_insensitively_and_fails_closed` left non-object-payload, +non-string-SHA, and wrong-length-SHA branches uncovered. Re-verified against the actual gate rather +than accepted at face value: `live_head_matches` has exactly one `if` statement (two arcs, both +exercised by the committed test), and its final `return (isinstance(...) and len(...) == 40 and +...)` is a single boolean expression with no `if`/`else` of its own — `coverage.py`'s branch mode +(what `fail_under = 100` actually measures here) tracks control-flow arcs between statements, not +sub-clause condition coverage within one expression. The cited cases are additional test +thoroughness, not something the gate is currently failing on; confirmed by a full-suite run on the +exact same head showing both files at 100% branch coverage with zero missing branches. Replied with +this evidence on the review thread and did not widen the PR's diff for a claim that does not hold +against this repo's own tooling. + +**One test in the full suite remains a known, pre-existing flake**, unrelated to this change: +`tests/test_opencode_required_verdict_regression.py::test_scheduler_wake_reuses_trusted_receipt_predicate` +intermittently exits 141 (SIGPIPE) under full-suite parallel load; reproduces identically on +unmodified `origin/main` and passes cleanly in file isolation. Not remediated here — out of scope +for a coverage-gap-only PR, and not itself a coverage regression. + ## 5. 실행 루프와 고객의 다음 행동 각 hourly pass는 아래 순서를 유지한다. From 4b42ce97dbda173563ab2e84317df9416ff4025d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 07:38:41 +0000 Subject: [PATCH 11/24] fix(agent-mention): widen the trailing colon exclusion to cover a slash too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The twelfth-round fix's trailing colon lookaround, (?!:\w), only rejected a colon immediately followed by a word character (/oc:config), so a colon immediately followed by a slash (/oc:/config, /oc://foo) still matched — exactly as much a path/URI structure as the word-character case, just missed because the lookaround checked for a word character specifically instead of "word character or slash". Reported by Devin on this PR's current head. Reproduced first (/oc:/config and /oc://foo both matched before the fix). Fixed by widening (?!:\w) to (?!:[\w/]), still leaving the true accept case ("/oc:" at end of string, or followed by a space or other non-word/non-slash text) untouched. Verified against the full accumulated accept/reject matrix (50 cases from every prior round on this file) before applying. Full suite: 2301 passed, 1 skipped, 21 subtests passed. 100% coverage and 100% docstrings maintained. --- scripts/ci/agent_mention_router.py | 8 ++++++-- tests/test_agent_mention_router.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index b766ea6c83..6466c90218 100755 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -81,7 +81,11 @@ # the "100%/oc" percentage case above, where the percent sign is preceded # by a digit. Both use a fixed-width two-character lookaround instead of # widening the single-character sets above, which would have reopened -# one of the two cases each pair is meant to distinguish. +# one of the two cases each pair is meant to distinguish. The trailing +# colon lookaround excludes a following word character OR "/", not just +# a word character: a colon followed by a slash (/oc:/config, /oc://foo) +# is exactly as much a path/URI structure as a colon followed directly +# by a word, and checking only for a word character left this open. # - "@cwl-noema-review" on its own additionally excludes a preceding "/" # (closing the same URL/path-embedding class as "@opencode-agent" above) # but deliberately NOT a trailing "/": that would break recognition of @@ -96,7 +100,7 @@ r"(?:" r"(? None: + """A colon followed by a slash is a path/URI structure, not punctuation. + + Thirteenth-round finding on #1537's successor PR (Devin): the + twelfth-round fix's trailing colon lookaround, ``(?!:\\w)``, only + rejected a colon immediately followed by a word character + (``/oc:config``), so a colon immediately followed by a slash + (``/oc:/config``, ``/oc://foo``) still matched — exactly as much a + path/URI structure as the word-character case, just missed because the + lookaround checked for a word character specifically instead of "word + character or slash". The fix widens that lookaround to + ``(?!:[\\w/])``, still leaving the true accept cases (``/oc:`` at end + of string, or followed by a space or other non-word/non-slash text) + untouched. + """ + + module = load_module() + assert "opencode-agent" not in module.exact_mentions(body) + + @pytest.mark.parametrize( "payload", [ From 6f40a0637da94da60f43ca72086d27e1034e8bbc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 16:46:11 +0900 Subject: [PATCH 12/24] test(ci): document nested REST fixture helpers Raise scoped docstring coverage for the newly added scheduler REST regression helpers to 100% without changing test behavior or production code. --- tests/test_pr_review_fix_scheduler_rest_workflow_identity.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_pr_review_fix_scheduler_rest_workflow_identity.py b/tests/test_pr_review_fix_scheduler_rest_workflow_identity.py index f261ce5beb..4e36544061 100644 --- a/tests/test_pr_review_fix_scheduler_rest_workflow_identity.py +++ b/tests/test_pr_review_fix_scheduler_rest_workflow_identity.py @@ -168,6 +168,7 @@ def test_fetch_workflow_names_by_check_suite_rest_paginates_past_100( calls: list[str] = [] def fake_api(path: str) -> Any: + """Return deterministic paginated workflow-run fixtures.""" calls.append(path) if path.endswith("page=1"): return {"workflow_runs": page1} @@ -193,6 +194,7 @@ def test_fetch_workflow_names_by_check_suite_rest_skips_entries_missing_suite_id head_sha = "f" * 40 def fake_api(path: str) -> Any: + """Return workflow runs that exercise incomplete-identity filtering.""" return { "workflow_runs": [ {"check_suite_id": None, "name": "orphaned run"}, @@ -215,6 +217,7 @@ def test_fetch_workflow_names_by_check_suite_rest_propagates_non_access_errors( head_sha = "0" * 40 def fake_api(path: str) -> Any: + """Simulate a non-access REST failure that must propagate.""" raise RuntimeError("gh: HTTP 502 (exhausted retries)") monkeypatch.setattr(merge, "gh_api_json", fake_api) From 680508d38f10cf63d01c4b07be2175275f51d99f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 06:47:24 +0000 Subject: [PATCH 13/24] docs: add ecosystem ownership map and G-17..G-22 gap entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds §2.4 (canonical-owner map transcribing the standing directive's ~25-repository ownership assignment, so future work chooses a repository by product-responsibility boundary rather than by name) and six new Gap register rows: - G-17: provider-group-name hardcoding in contextual-orchestrator's proxy_capability() (confirmed and fixed in ContextualWisdomLab/contextual-orchestrator#1017), distinguished from the legitimate ZDR-attestation-ledger non-violation in zdr_policy.py and the NIM-removal-migration-superseded instance in run_opencode_review_model_pool.sh. - G-18: missing LLM model-timeout admin console (per-model view/set/ clear/restore, no global ceiling, cancellation-cause attribution). - G-19: no executed p95<=20ms E2E performance evidence in any UI-owning repo. - G-20: no i18n-as-versioned-DB-resource architecture found. - G-21: Rust-preference tightening not yet reflected in contextual_orchestrator's own Python hot paths, no per-exception ADR. - G-22: two confirmed DB column-naming violations (agent_pool, orchestration_records) invisible to the existing table/index/view/ sequence/constraint-only naming static analysis. Also appends a dated narrative entry documenting the #1017 audit and fix, matching this document's established per-increment log convention. Verified: tests/test_product_technical_gap_baseline.py passes (5 passed). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KPmJErfkcHer4UVEgrQxUX --- docs/product-technical-gap-baseline.md | 40 ++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 41d95b6f57..43e1154b12 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -72,6 +72,28 @@ flowchart LR Merge --> Control ``` +### 2.4 Ecosystem canonical-owner map + +각 core 기능은 정확히 하나의 canonical-owner 저장소가 소유하며, 소비 저장소는 해당 기능을 복제·우회·배제하지 않는다(§5의 "no duplicating immature core in consumers" 원칙). 미성숙한 core가 필요하면 소비 저장소는 오너 저장소에 RED 테스트 → 수정/기능/문서/릴리스를 개발해 통합 CI가 GREEN이 될 때까지 진행한 뒤 소비측 고정 버전을 올린다. 배제는 경계가 실제로 잘못되었거나 공통 수요가 없음을 ADR로 정당화할 때만 허용된다. + +| Canonical owner | 소유 core 기능 | +|---|---| +| `.github` | 중앙 CI·PR 리뷰·보안 스캔·머지 자동화 거버넌스 | +| `enterprise-architecture-core` + `context-graph-contracts` | 조직 전체 아키텍처·컨텍스트 그래프 계약 | +| `ConceptWeave` + `semantic-data-portal` | 의미 데이터 포털 | +| `contextual-orchestrator` + `noema` | LLM 게이트웨이(오케스트레이션·라우팅·비용)·리뷰 봇 | +| `keyverse` | 유일한 identity ledger(Keycloak 기반 인증 백엔드) | +| `EgressWeave` / `OriginWeave` / `pingora-gateway` / `quarantine-sandbox-runtime` | egress·게이트웨이·샌드박스 | +| `pg-llm-batch` / `EmbedRelay` | 배치·임베딩 | +| `fast-mlsirm` / `TEPP` | psychometrics 연산(Rust 산술) | +| `RankWeave` / `ThreadWeave` | retrieval fusion·이메일 threading | +| `inkspan` / `DiagramWeave` | 다이어그램 | +| `mhtml-etl-gateway` | ETL | +| `appguardrail` / `wardnet` | 보안 게이트웨이(Rust-first) | +| `naruon` / `LineageWeave` / `psychometrics-commons` / `disksage` / `PolicyWeave` / `CalendarWeave` / `supply-chain-control-plane` | 도메인 제품 소비 저장소 | + +이 지도는 저장소 신설·기능 배치 결정의 기준이며, 이름이 아니라 제품 책임·재사용 경계·문서·구현·소비 관계로 저장소를 선택한다(§1). 표에 없는 신규 core 필요가 확인되면 이 표에 행을 추가하고 해당 오너 저장소에 ADR을 남긴다. + ## 3. Gap register 우선순위는 구매자 체감, 보안/증거 위험, 선행 의존성 순서다. @@ -93,6 +115,12 @@ flowchart LR | G-13 | hourly scheduler는 존재하지만 no-op/credential unavailable/queued Checks의 customer next action을 모든 caller가 동일한 receipt로 내는지 미확인이다 | 자동화가 실패해도 운영자가 무엇을 고쳐야 하는지 알 수 없다 | `skipped_credential_unavailable` receipt와 다음 행동 문구를 exact-head Checks로 검증하고, bounded receipt schema, retry floor, single-flight, no secret fallback을 모든 caller contract test로 고정한다 | | G-14 | release/changelog/version 증거가 각 PR에 분산되고 현재 central repo 보호 main의 release candidate가 명확하지 않다 | 운영자는 어떤 기능이 supportable release인지 확인할 수 없다 | merge 후 release readiness ledger, CHANGELOG, semantic version/tag, rollback/operability evidence를 함께 갱신한다 | | G-15 | 첨부파일 처리 경계가 제품별로 다르고, 1MB 상한은 업무 데이터와 맞지 않으며 미지원 MIME/컨테이너가 parser registry에서 명시적으로 pending/quarantine 되는지 확인되지 않았다. 현재 20MB 초과 파일 가능성과 PDF/HWP/HWPX·이미지·압축파일의 parse/sidecar 흐름을 하나의 exact contract로 묶지 못했다 | 큰 업무 첨부를 거부하거나 파싱 실패를 조용히 잃으면 고객의 메일·문서 업무가 중단된다 | naruon/newsdom-api 소유 PR에서 streaming upload, configurable bounded limit above 20MB, MIME sniffing, parser capability registry, quarantine/retry, source-position provenance, and ADR를 추가하고 size/unsupported-type/zip-bomb tests를 required evidence로 만든다 | +| G-17 | `contextual-orchestrator`의 `proxy_capability()`가 이미지-생성 엔드포인트를 `agent.provider_name == "openrouter"` 리터럴 비교로 재작성했다(provider 식별자를 라우팅 조건으로 하드코딩 — 확인·수정됨: `ContextualWisdomLab/contextual-orchestrator#1017`, `ModelAgent.image_generation_endpoint` 선언적 capability 필드로 교체). `scripts/ci/run_opencode_review_model_pool.sh`의 `is_nvidia_nim_candidate()`도 provider-prefix 문자열 비교로 같은 패턴을 갖고 있으나, 이는 NIM 직접 통신 제거 마이그레이션(§8 orchestrator/free 고정)으로 대체될 예정이라 별도 fix 대상에서 제외했다 | provider GROUP명이 라우팅/선택/failover 조건에 남아 있으면 신규 provider 추가·제거 시 코드 변경이 필요해지고, "표시/관리자 별칭"이라는 정책이 실제로 지켜지지 않는다 | #1017 병합 후, 조직 전체(§2.4 ownership map의 LLM 게이트웨이 소비 저장소 포함)에서 provider 이름 문자열 비교로 라우팅/선택/failover를 분기하는 잔여 코드를 grep-detect 회귀 테스트로 고정하고, `run_opencode_review_model_pool.sh`는 NIM 제거 PR에서 함께 정리한다 | +| G-18 | LLM 모델 타임아웃에 앱/에이전트/게이트웨이 전역 우선순위 상한이 존재하며, 모델별 조회/설정/해제/복원을 제공하는 관리자 웹 콘솔이 `contextual-orchestrator`에 없다. 취소 사유(사용자 취소/provider 종료/관리자 설정 타임아웃)를 구분해 귀속하는 계약도 없다 | 추론·스트리밍·툴콜링이 실제로 진행 중인데 경과 시간만으로 요청이 끊기면, 정상적으로 응답을 생성하던 고가 요청이 낭비되고 원인도 알 수 없다 | 기본값을 무제한/null로 바꾸고 통신 실패는 upstream provider 자체 timeout/error로만 종료되게 하며, `/admin` 콘솔에 모델별 타임아웃 view/set/clear/restore(단위, 우선순위, 상속, 입력 검증, 감사 추적)와 `/api/v1/*` 계약, 취소-사유 귀속 필드를 추가한다. 소유 저장소는 `contextual-orchestrator`다 | +| G-19 | 반복 웹 페이지 E2E 성능에 대해 예외 없는 p95 ≤20ms 하드 게이트와 표본 축소·느린 측정 배제·비현실적 캐시 예열 금지 조항이 어떤 UI 소유 저장소에도 k6/Playwright 등 executed 증거로 존재하는지 미확인이다 | 실측 없이 "빠르다"고 주장하면 실제 고객이 체감하는 지연이 방치된다 | UI 소유 저장소별로 페이지 단위 k6/Lighthouse-CI p95 측정을 CI 필수 증거로 추가하고, 위반 시 원인이 JS 번들 크기·힙·DOM·hydration·메인스레드 블로킹·GC 등 구조적이면 최적화가 아니라 프론트엔드 스택 교체를 ADR로 기록한다. Figma File ID N/A인 이 저장소는 게이트 정의만 문서화하고, 실측/교체는 각 UI repo 소유다 | +| G-20 | 번역(i18n)이 버전관리되는 DB 자원으로 관리되고, 서버/네이티브가 화면별 필요한 키만 캐싱해 가져오며, 전체 카탈로그를 브라우저에 내려보내지 않는 아키텍처가 어느 소비 저장소에도 확인되지 않았다. 번역 리뷰/승인/배포/롤백 API와 관리 UI를 소유하는 저장소도 없다 | 번역 파일/JS 번들 방식은 배포 없이 문구를 고칠 수 없고, 전체 카탈로그 다운로드는 SPA를 가정하지 않는 서버/네이티브 화면에서 낭비와 불일치를 만든다 | 기존 저장소 중 적합한 곳이 없으면 전용 신규 저장소(번역 DB, 화면별 key 캐시 API, 리뷰/승인/배포/롤백 API+관리 UI)를 신설하고 §2.4 ownership map에 추가한다. Keyverse는 인증 백엔드로만 유지하고 로그인/가입/복구 UI는 각 제품이 자체 구축한다 | +| G-21 | 수리과학/psychometrics/EDA core뿐 아니라 성능·안정성·보안이 중요한 모든 런타임 경로에서 Python이 기피 대상이 됐으나, 현재 `contextual_orchestrator/`의 다수 모듈(`orchestrator.py` 등 도메인 핵심)이 여전히 Python으로 구현되어 있고 각 예외에 대한 전용 ADR(제거 조건 명시)이 없다 | 속도·안정성·보안이 중요한 경로가 Python GIL/성능 한계에 계속 노출되고, 예외 기준이 문서화되지 않아 재검토 시점을 판단할 수 없다 | Rust 경계로 분리 가능한 hot path(예: token counting, redaction, cost ledger 연산)를 식별해 Rust API 경계로 전환하거나, Python-전용 ML 런타임 의존처럼 불가피한 경우 제거 조건을 명시한 전용 ADR을 `contextual-orchestrator`/`fast-mlsirm`/`TEPP` 등 소유 저장소에 남긴다 | +| G-22 | DB 객체명 규칙(두 단어 이상 snake_case 우선) 위반이 `contextual_orchestrator/orchestrator.py`의 `agent_pool`(단일어 컬럼 `priority`/`disabled`)과 `orchestration_records`(단일어 컬럼 `kind`/`key`/`payload`/`seq`) 테이블에 남아 있다. `conventions.require_object_name()`과 `tests/test_database_object_naming.py`는 테이블/인덱스/뷰/시퀀스/제약 이름만 검사하고 `CREATE TABLE` 본문의 컬럼명은 검사하지 않아 이 위반이 회귀 게이트를 통과했다 | 컬럼명 불일치가 누적되면 신규 기여자의 스키마 이해 비용이 커지고, 명명 규칙이 실제로는 부분적으로만 강제된다는 사실이 감춰진다 | 기존 sqlite 영속 상태를 깨지 않는 마이그레이션(컬럼 rename + 하위호환 읽기 경로 또는 명시적 1회성 migration script)을 설계하고, `test_database_object_naming.py`의 static-analysis 범위를 컬럼명까지 확장해 동일 위반의 재발을 막는다 | ## 4. 열린 PR live inventory @@ -2589,3 +2617,15 @@ Higgins, S. S., Crepalde, N., & Fernandes, L. (2021). Segmented multiplexity: A **Validation.** Full suite `2407 passed, 1 skipped, 21 subtests`; `coverage` 100% on `scripts/ci`; `interrogate` 100%; all four touched/added workflow files re-parse as valid YAML; `test_opencode_workflow_shell_syntax.py` and related shell-syntax tests pass unchanged. **Residual.** This closes the specific floating-image contribution from these three central workflows; it does not by itself guarantee the organization-wide Actions queue is fully drained, since other repositories' own workflows and any remaining unpinned central workflows may still request the floating image. Worth a follow-up sweep across the rest of `.github/workflows/` and sibling-repo workflows if queuing persists after this lands. + +## 2026-09-02 provider-group-name hardcoding and routing-config naming audit: contextual-orchestrator#1017 + +**Observed gap (now G-17).** An adversarial 5-agent audit of the "provider GROUP 명을 라우팅/선택/failover 조건으로 하드코딩하지 않는다" policy across `.github`, `noema`, and `contextual-orchestrator` confirmed one real, production-affecting violation: `contextual_orchestrator/orchestrator.py`'s `proxy_capability()` rewrote the image-generation endpoint path by comparing `agent.provider_name == "openrouter"` literally, in both its immediate-race (`_equivalent_race_members`) and sequential-failover call sites. Provider identity was doing routing work it is not supposed to do — it is a display/admin alias only. The same audit independently checked two adjacent suspects and found them **not** the same anti-pattern: `scripts/ci/zdr_policy.py`'s `PROVIDER_ZDR_SCOPE` is a legitimate, ADR-documented, intentionally fail-closed (`KeyError`-on-unknown-provider) compliance-attestation ledger — ZDR status is an inherent legal fact about a named vendor, not a discoverable technical capability, so a vendor key here is correct, not a violation. `scripts/ci/run_opencode_review_model_pool.sh`'s `is_nvidia_nim_candidate()` **is** a real instance of the same pattern, but is left unfixed here because it is already superseded by the separately tracked NIM-direct-communication removal migration (§8 of the standing directive; `orchestrator/free` pin work). + +**Fix.** `ContextualWisdomLab/contextual-orchestrator#1017` (branch `fix/provider-endpoint-hardcoding-and-routing-config-20260902`, exact head `263cf0c9`) replaces the provider-name comparison with a declared `ModelAgent.image_generation_endpoint: str | None = None` capability field, round-tripped through `to_config()`/`from_dict()`, set explicitly via agent-pool config or discovery metadata rather than inferred from `provider_name` at request time — zero behavior change for any currently-configured agent, since the field must be set explicitly to opt into the dedicated endpoint. `test_provider_name_alone_never_rewrites_the_image_endpoint` locks the regression: an agent named `"openrouter"` with no declared field routes to the caller's requested endpoint unchanged. + +**Adjacent fix bundled in the same PR (KV naming convention).** The same PR also fixes an unrelated but independently discovered naming-convention violation: `_ROUTING_CATEGORY`/`_EMBEDDING_CONFIG_CATEGORY` (both the single-word `"routing"`) in `batch_routing.py`/`cost_router.py`, plus a matching literal in `batch_job_registry.py`, violated the two-or-more-semantic-word KV category naming convention. A full-repo grep found **three** real production call sites (not the two an initial narrower pass found) plus three test files sharing the one category — splitting it (the naming fix an isolated look would suggest) would have silently orphaned already-persisted Postgres-backed KV config for `batch_job_retention_seconds`, `batch_min_tokens`, and `embedding_max_tokens_per_request`. Unified all sites onto one compliant name, `"routing_config"`, preserving current cross-feature sharing with zero orphaning risk. A third, unrelated pre-existing regression (a hard top-level `import numpy` in `tests/test_psychometric_routing.py` breaking collection for the entire suite, since numpy/fast_mlsirm are genuinely optional lazy-imported dependencies of the production module they test) was fixed in the same PR as a side effect of full-suite validation, scoped via `pytest.importorskip` to the one test function that needs them. + +**Status.** PR opened as draft, `subscribe_pr_activity` armed; full suite green modulo two independently verified pre-existing/unrelated failures (a load-induced timing flake and an unrelated `test_spend_analytics.py` failure, both reproduced identically against unmodified `main` with this PR's changes stashed). Not yet merged — G-17's priority action (residual provider-name-string-comparison regression test across the ownership map's LLM-gateway consumers, and the `run_opencode_review_model_pool.sh` cleanup bundled into the NIM-removal PR) remains open until #1017 merges and a follow-up sweep runs. + +**New Gap rows.** This pass also added G-18 (LLM model-timeout admin console — confirmed entirely missing, not merely buggy), G-19 (p95 ≤20ms E2E performance gate — no executed k6/Lighthouse-CI evidence found in any UI-owning repo), G-20 (i18n as a versioned DB resource — no such architecture found; may need a new dedicated repo), G-21 (Rust-preference tightening — `contextual_orchestrator/orchestrator.py` and siblings remain Python with no per-exception ADR), and G-22 (two confirmed DB column-naming violations in `contextual_orchestrator`'s `agent_pool`/`orchestration_records` tables, invisible to the existing table/index/view/sequence/constraint-only static-analysis test) to §3, and a new §2.4 ecosystem canonical-owner map transcribing the standing directive's ~25-repository ownership assignment, so future work chooses a repository by product-responsibility boundary rather than by name. From fe3d09f376292a4275267fd8a8ca79e99c852b2b Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 07:02:45 +0000 Subject: [PATCH 14/24] docs: correct the KV-rename orphaning claim after PR review The 2026-09-02 narrative entry for contextual-orchestrator#1017 claimed the "routing" -> "routing_config" KV category rename had "zero orphaning risk." PR reviewer seonghobae correctly identified this as false for the Postgres-backed production boundary (pg_llm_batch.PostgresConfigStore keys com_config by the literal f"{category}.{key}" primary key, so the call-site rename alone orphans any already-persisted routing. row). Updates the entry to describe the actual fix: an idempotent, additive-only backfill migration landed in the same PR, plus the RED-before-GREEN test evidence. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KPmJErfkcHer4UVEgrQxUX --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 43e1154b12..c9e8cd7fd5 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -2624,7 +2624,7 @@ Higgins, S. S., Crepalde, N., & Fernandes, L. (2021). Segmented multiplexity: A **Fix.** `ContextualWisdomLab/contextual-orchestrator#1017` (branch `fix/provider-endpoint-hardcoding-and-routing-config-20260902`, exact head `263cf0c9`) replaces the provider-name comparison with a declared `ModelAgent.image_generation_endpoint: str | None = None` capability field, round-tripped through `to_config()`/`from_dict()`, set explicitly via agent-pool config or discovery metadata rather than inferred from `provider_name` at request time — zero behavior change for any currently-configured agent, since the field must be set explicitly to opt into the dedicated endpoint. `test_provider_name_alone_never_rewrites_the_image_endpoint` locks the regression: an agent named `"openrouter"` with no declared field routes to the caller's requested endpoint unchanged. -**Adjacent fix bundled in the same PR (KV naming convention).** The same PR also fixes an unrelated but independently discovered naming-convention violation: `_ROUTING_CATEGORY`/`_EMBEDDING_CONFIG_CATEGORY` (both the single-word `"routing"`) in `batch_routing.py`/`cost_router.py`, plus a matching literal in `batch_job_registry.py`, violated the two-or-more-semantic-word KV category naming convention. A full-repo grep found **three** real production call sites (not the two an initial narrower pass found) plus three test files sharing the one category — splitting it (the naming fix an isolated look would suggest) would have silently orphaned already-persisted Postgres-backed KV config for `batch_job_retention_seconds`, `batch_min_tokens`, and `embedding_max_tokens_per_request`. Unified all sites onto one compliant name, `"routing_config"`, preserving current cross-feature sharing with zero orphaning risk. A third, unrelated pre-existing regression (a hard top-level `import numpy` in `tests/test_psychometric_routing.py` breaking collection for the entire suite, since numpy/fast_mlsirm are genuinely optional lazy-imported dependencies of the production module they test) was fixed in the same PR as a side effect of full-suite validation, scoped via `pytest.importorskip` to the one test function that needs them. +**Adjacent fix bundled in the same PR (KV naming convention), corrected after human review.** The same PR also fixes an unrelated but independently discovered naming-convention violation: `_ROUTING_CATEGORY`/`_EMBEDDING_CONFIG_CATEGORY` (both the single-word `"routing"`) in `batch_routing.py`/`cost_router.py`, plus a matching literal in `batch_job_registry.py`, violated the two-or-more-semantic-word KV category naming convention. A full-repo grep found **three** real production call sites (not the two an initial narrower pass found) plus three test files sharing the one category — splitting it (the naming fix an isolated look would suggest) would have silently orphaned already-persisted config across two categories instead of one. This entry originally claimed the rename to one unified `"routing_config"` name carried "zero orphaning risk"; PR reviewer `seonghobae` correctly identified that claim as false for the Postgres-backed production boundary — `pg_llm_batch.PostgresConfigStore` keys `com_config` by the literal `f"{category}.{key}"` SQL primary key, so the call-site rename alone *does* orphan any row a prior deployment already persisted under `routing.`: readers now asking for `routing_config.` get an exact miss and silently fall back to their hardcoded default instead of the operator's configured value. Fixed with an idempotent, additive-only backfill migration (`kv_config._migrate_legacy_categories`, run at every `get_config_store()` boot for the seven known keys) that copies a legacy `routing.` value forward only when no `routing_config.` value exists yet — an explicit new-category value always wins and is never overwritten, so an operator's post-backfill reconfiguration survives a later restart. Evidence: `tests/test_kv_config_store.py` gained four tests (backfill-from-legacy, new-value-precedence, idempotent-across-reconnects, in-memory-seed-path), three of which were confirmed to genuinely fail without the migration wired in (RED-before-GREEN, verified by temporarily disabling the migration call and re-running). A third, unrelated pre-existing regression (a hard top-level `import numpy` in `tests/test_psychometric_routing.py` breaking collection for the entire suite, since numpy/fast_mlsirm are genuinely optional lazy-imported dependencies of the production module they test) was fixed in the same PR as a side effect of full-suite validation, scoped via `pytest.importorskip` to the one test function that needs them. **Status.** PR opened as draft, `subscribe_pr_activity` armed; full suite green modulo two independently verified pre-existing/unrelated failures (a load-induced timing flake and an unrelated `test_spend_analytics.py` failure, both reproduced identically against unmodified `main` with this PR's changes stashed). Not yet merged — G-17's priority action (residual provider-name-string-comparison regression test across the ownership map's LLM-gateway consumers, and the `run_opencode_review_model_pool.sh` cleanup bundled into the NIM-removal PR) remains open until #1017 merges and a follow-up sweep runs. From 528a58444d4e893c132954aacd0e52804c62e885 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 07:40:52 +0000 Subject: [PATCH 15/24] docs: qualify contextual-orchestrator#1017 cross-repo references Devin Review correctly caught that this document lives in .github, so a bare "#1017" reference resolves to ContextualWisdomLab/.github#1017 (an unrelated PR) instead of the intended ContextualWisdomLab/contextual-orchestrator#1017 -- breaking traceability and matching this repo's own binding convention (CLAUDE.md / docs/CWL-MASTER-CONTEXT.md section 7: cross-repo references as owner/repo#num or full URLs). Qualifies the three remaining under-qualified references (the G-17 row's "priority action" cell, the dated section heading, and its "Status" paragraph's "until #1017 merges" line) to the full ContextualWisdomLab/contextual-orchestrator#1017 form, matching the convention already used correctly elsewhere in the same section. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KPmJErfkcHer4UVEgrQxUX --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 38832e3082..b6e5028d68 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -116,7 +116,7 @@ flowchart LR | G-14 | release/changelog/version 증거가 각 PR에 분산되고 현재 central repo 보호 main의 release candidate가 명확하지 않다 | 운영자는 어떤 기능이 supportable release인지 확인할 수 없다 | merge 후 release readiness ledger, CHANGELOG, semantic version/tag, rollback/operability evidence를 함께 갱신한다 | | G-15 | 첨부파일 처리 경계가 제품별로 다르고, 1MB 상한은 업무 데이터와 맞지 않으며 미지원 MIME/컨테이너가 parser registry에서 명시적으로 pending/quarantine 되는지 확인되지 않았다. 현재 20MB 초과 파일 가능성과 PDF/HWP/HWPX·이미지·압축파일의 parse/sidecar 흐름을 하나의 exact contract로 묶지 못했다 | 큰 업무 첨부를 거부하거나 파싱 실패를 조용히 잃으면 고객의 메일·문서 업무가 중단된다 | naruon/newsdom-api 소유 PR에서 streaming upload, configurable bounded limit above 20MB, MIME sniffing, parser capability registry, quarantine/retry, source-position provenance, and ADR를 추가하고 size/unsupported-type/zip-bomb tests를 required evidence로 만든다 | | G-16 | Required Pingora policy treated a changed documentation PNG screenshot as UTF-8 runtime evidence | Valid UI evidence blocked otherwise valid product PRs before policy evaluation | This branch verifies bounded PNG magic before exemption while runtime paths and malformed assets continue to fail closed; protected-main delivery remains the release gate | -| G-17 | `contextual-orchestrator`의 `proxy_capability()`가 이미지-생성 엔드포인트를 `agent.provider_name == "openrouter"` 리터럴 비교로 재작성했다(provider 식별자를 라우팅 조건으로 하드코딩 — 확인·수정됨: `ContextualWisdomLab/contextual-orchestrator#1017`, `ModelAgent.image_generation_endpoint` 선언적 capability 필드로 교체). `scripts/ci/run_opencode_review_model_pool.sh`의 `is_nvidia_nim_candidate()`도 provider-prefix 문자열 비교로 같은 패턴을 갖고 있으나, 이는 NIM 직접 통신 제거 마이그레이션(§8 orchestrator/free 고정)으로 대체될 예정이라 별도 fix 대상에서 제외했다 | provider GROUP명이 라우팅/선택/failover 조건에 남아 있으면 신규 provider 추가·제거 시 코드 변경이 필요해지고, "표시/관리자 별칭"이라는 정책이 실제로 지켜지지 않는다 | #1017 병합 후, 조직 전체(§2.4 ownership map의 LLM 게이트웨이 소비 저장소 포함)에서 provider 이름 문자열 비교로 라우팅/선택/failover를 분기하는 잔여 코드를 grep-detect 회귀 테스트로 고정하고, `run_opencode_review_model_pool.sh`는 NIM 제거 PR에서 함께 정리한다 | +| G-17 | `contextual-orchestrator`의 `proxy_capability()`가 이미지-생성 엔드포인트를 `agent.provider_name == "openrouter"` 리터럴 비교로 재작성했다(provider 식별자를 라우팅 조건으로 하드코딩 — 확인·수정됨: `ContextualWisdomLab/contextual-orchestrator#1017`, `ModelAgent.image_generation_endpoint` 선언적 capability 필드로 교체). `scripts/ci/run_opencode_review_model_pool.sh`의 `is_nvidia_nim_candidate()`도 provider-prefix 문자열 비교로 같은 패턴을 갖고 있으나, 이는 NIM 직접 통신 제거 마이그레이션(§8 orchestrator/free 고정)으로 대체될 예정이라 별도 fix 대상에서 제외했다 | provider GROUP명이 라우팅/선택/failover 조건에 남아 있으면 신규 provider 추가·제거 시 코드 변경이 필요해지고, "표시/관리자 별칭"이라는 정책이 실제로 지켜지지 않는다 | `ContextualWisdomLab/contextual-orchestrator#1017` 병합 후, 조직 전체(§2.4 ownership map의 LLM 게이트웨이 소비 저장소 포함)에서 provider 이름 문자열 비교로 라우팅/선택/failover를 분기하는 잔여 코드를 grep-detect 회귀 테스트로 고정하고, `run_opencode_review_model_pool.sh`는 NIM 제거 PR에서 함께 정리한다 | | G-18 | LLM 모델 타임아웃에 앱/에이전트/게이트웨이 전역 우선순위 상한이 존재하며, 모델별 조회/설정/해제/복원을 제공하는 관리자 웹 콘솔이 `contextual-orchestrator`에 없다. 취소 사유(사용자 취소/provider 종료/관리자 설정 타임아웃)를 구분해 귀속하는 계약도 없다 | 추론·스트리밍·툴콜링이 실제로 진행 중인데 경과 시간만으로 요청이 끊기면, 정상적으로 응답을 생성하던 고가 요청이 낭비되고 원인도 알 수 없다 | 기본값을 무제한/null로 바꾸고 통신 실패는 upstream provider 자체 timeout/error로만 종료되게 하며, `/admin` 콘솔에 모델별 타임아웃 view/set/clear/restore(단위, 우선순위, 상속, 입력 검증, 감사 추적)와 `/api/v1/*` 계약, 취소-사유 귀속 필드를 추가한다. 소유 저장소는 `contextual-orchestrator`다 | | G-19 | 반복 웹 페이지 E2E 성능에 대해 예외 없는 p95 ≤20ms 하드 게이트와 표본 축소·느린 측정 배제·비현실적 캐시 예열 금지 조항이 어떤 UI 소유 저장소에도 k6/Playwright 등 executed 증거로 존재하는지 미확인이다 | 실측 없이 "빠르다"고 주장하면 실제 고객이 체감하는 지연이 방치된다 | UI 소유 저장소별로 페이지 단위 k6/Lighthouse-CI p95 측정을 CI 필수 증거로 추가하고, 위반 시 원인이 JS 번들 크기·힙·DOM·hydration·메인스레드 블로킹·GC 등 구조적이면 최적화가 아니라 프론트엔드 스택 교체를 ADR로 기록한다. Figma File ID N/A인 이 저장소는 게이트 정의만 문서화하고, 실측/교체는 각 UI repo 소유다 | | G-20 | 번역(i18n)이 버전관리되는 DB 자원으로 관리되고, 서버/네이티브가 화면별 필요한 키만 캐싱해 가져오며, 전체 카탈로그를 브라우저에 내려보내지 않는 아키텍처가 어느 소비 저장소에도 확인되지 않았다. 번역 리뷰/승인/배포/롤백 API와 관리 UI를 소유하는 저장소도 없다 | 번역 파일/JS 번들 방식은 배포 없이 문구를 고칠 수 없고, 전체 카탈로그 다운로드는 SPA를 가정하지 않는 서버/네이티브 화면에서 낭비와 불일치를 만든다 | 기존 저장소 중 적합한 곳이 없으면 전용 신규 저장소(번역 DB, 화면별 key 캐시 API, 리뷰/승인/배포/롤백 API+관리 UI)를 신설하고 §2.4 ownership map에 추가한다. Keyverse는 인증 백엔드로만 유지하고 로그인/가입/복구 UI는 각 제품이 자체 구축한다 | @@ -2619,7 +2619,7 @@ Higgins, S. S., Crepalde, N., & Fernandes, L. (2021). Segmented multiplexity: A **Residual.** This closes the specific floating-image contribution from these three central workflows; it does not by itself guarantee the organization-wide Actions queue is fully drained, since other repositories' own workflows and any remaining unpinned central workflows may still request the floating image. Worth a follow-up sweep across the rest of `.github/workflows/` and sibling-repo workflows if queuing persists after this lands. -## 2026-09-02 provider-group-name hardcoding and routing-config naming audit: contextual-orchestrator#1017 +## 2026-09-02 provider-group-name hardcoding and routing-config naming audit: ContextualWisdomLab/contextual-orchestrator#1017 **Observed gap (now G-17).** An adversarial 5-agent audit of the "provider GROUP 명을 라우팅/선택/failover 조건으로 하드코딩하지 않는다" policy across `.github`, `noema`, and `contextual-orchestrator` confirmed one real, production-affecting violation: `contextual_orchestrator/orchestrator.py`'s `proxy_capability()` rewrote the image-generation endpoint path by comparing `agent.provider_name == "openrouter"` literally, in both its immediate-race (`_equivalent_race_members`) and sequential-failover call sites. Provider identity was doing routing work it is not supposed to do — it is a display/admin alias only. The same audit independently checked two adjacent suspects and found them **not** the same anti-pattern: `scripts/ci/zdr_policy.py`'s `PROVIDER_ZDR_SCOPE` is a legitimate, ADR-documented, intentionally fail-closed (`KeyError`-on-unknown-provider) compliance-attestation ledger — ZDR status is an inherent legal fact about a named vendor, not a discoverable technical capability, so a vendor key here is correct, not a violation. `scripts/ci/run_opencode_review_model_pool.sh`'s `is_nvidia_nim_candidate()` **is** a real instance of the same pattern, but is left unfixed here because it is already superseded by the separately tracked NIM-direct-communication removal migration (§8 of the standing directive; `orchestrator/free` pin work). @@ -2627,7 +2627,7 @@ Higgins, S. S., Crepalde, N., & Fernandes, L. (2021). Segmented multiplexity: A **Adjacent fix bundled in the same PR (KV naming convention), corrected after human review.** The same PR also fixes an unrelated but independently discovered naming-convention violation: `_ROUTING_CATEGORY`/`_EMBEDDING_CONFIG_CATEGORY` (both the single-word `"routing"`) in `batch_routing.py`/`cost_router.py`, plus a matching literal in `batch_job_registry.py`, violated the two-or-more-semantic-word KV category naming convention. A full-repo grep found **three** real production call sites (not the two an initial narrower pass found) plus three test files sharing the one category — splitting it (the naming fix an isolated look would suggest) would have silently orphaned already-persisted config across two categories instead of one. This entry originally claimed the rename to one unified `"routing_config"` name carried "zero orphaning risk"; PR reviewer `seonghobae` correctly identified that claim as false for the Postgres-backed production boundary — `pg_llm_batch.PostgresConfigStore` keys `com_config` by the literal `f"{category}.{key}"` SQL primary key, so the call-site rename alone *does* orphan any row a prior deployment already persisted under `routing.`: readers now asking for `routing_config.` get an exact miss and silently fall back to their hardcoded default instead of the operator's configured value. Fixed with an idempotent, additive-only backfill migration (`kv_config._migrate_legacy_categories`, run at every `get_config_store()` boot for the seven known keys) that copies a legacy `routing.` value forward only when no `routing_config.` value exists yet — an explicit new-category value always wins and is never overwritten, so an operator's post-backfill reconfiguration survives a later restart. Evidence: `tests/test_kv_config_store.py` gained four tests (backfill-from-legacy, new-value-precedence, idempotent-across-reconnects, in-memory-seed-path), three of which were confirmed to genuinely fail without the migration wired in (RED-before-GREEN, verified by temporarily disabling the migration call and re-running). A third, unrelated pre-existing regression (a hard top-level `import numpy` in `tests/test_psychometric_routing.py` breaking collection for the entire suite, since numpy/fast_mlsirm are genuinely optional lazy-imported dependencies of the production module they test) was fixed in the same PR as a side effect of full-suite validation, scoped via `pytest.importorskip` to the one test function that needs them. -**Status.** PR opened as draft, `subscribe_pr_activity` armed; full suite green modulo two independently verified pre-existing/unrelated failures (a load-induced timing flake and an unrelated `test_spend_analytics.py` failure, both reproduced identically against unmodified `main` with this PR's changes stashed). Not yet merged — G-17's priority action (residual provider-name-string-comparison regression test across the ownership map's LLM-gateway consumers, and the `run_opencode_review_model_pool.sh` cleanup bundled into the NIM-removal PR) remains open until #1017 merges and a follow-up sweep runs. +**Status.** PR opened as draft, `subscribe_pr_activity` armed; full suite green modulo two independently verified pre-existing/unrelated failures (a load-induced timing flake and an unrelated `test_spend_analytics.py` failure, both reproduced identically against unmodified `main` with this PR's changes stashed). Not yet merged — G-17's priority action (residual provider-name-string-comparison regression test across the ownership map's LLM-gateway consumers, and the `run_opencode_review_model_pool.sh` cleanup bundled into the NIM-removal PR) remains open until `ContextualWisdomLab/contextual-orchestrator#1017` merges and a follow-up sweep runs. **New Gap rows.** This pass also added G-18 (LLM model-timeout admin console — confirmed entirely missing, not merely buggy), G-19 (p95 ≤20ms E2E performance gate — no executed k6/Lighthouse-CI evidence found in any UI-owning repo), G-20 (i18n as a versioned DB resource — no such architecture found; may need a new dedicated repo), G-21 (Rust-preference tightening — `contextual_orchestrator/orchestrator.py` and siblings remain Python with no per-exception ADR), and G-22 (two confirmed DB column-naming violations in `contextual_orchestrator`'s `agent_pool`/`orchestration_records` tables, invisible to the existing table/index/view/sequence/constraint-only static-analysis test) to §3, and a new §2.4 ecosystem canonical-owner map transcribing the standing directive's ~25-repository ownership assignment, so future work chooses a repository by product-responsibility boundary rather than by name. From 44c2117c411abc3fe7f65b3bda6cd05addb278df Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 07:59:13 +0000 Subject: [PATCH 16/24] docs: delink cross-repo refs from inline code, refine ownership map categories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devin Review correctly noted that wrapping ContextualWisdomLab/ contextual-orchestrator#1017 in backticks prevents GitHub's cross-repo autolinking even after qualifying it with the owner -- inline code spans are never autolinked. Removes the backtick wrapping from all three occurrences (G-17's observation and priority-action cells, the dated entry's Status paragraph) plus the Fix paragraph's occurrence for consistency, while leaving every other backtick-wrapped identifier (module/function/class names) untouched. Also refines §2.4's ecosystem canonical-owner map to match the standing directive's newer, more precisely-categorized breakdown: previously grouped pairs (enterprise-architecture-core+context-graph-contracts, ConceptWeave+semantic-data-portal, contextual-orchestrator+noema, appguardrail+wardnet) are now listed as distinct rows with their actual individually-scoped responsibilities, organized under five explicit categories (조직·계약, 의미·데이터, AI·운영, Identity·보안·runtime, 재사용 기능) plus the existing domain-product-consumer row, matching the "core foundation is a selective control plane per responsibility, not a shared installation" framing. Verified: tests/test_product_technical_gap_baseline.py passes (5 passed). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KPmJErfkcHer4UVEgrQxUX --- docs/product-technical-gap-baseline.md | 51 +++++++++++++++++--------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b6e5028d68..4607615b55 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -76,21 +76,36 @@ flowchart LR 각 core 기능은 정확히 하나의 canonical-owner 저장소가 소유하며, 소비 저장소는 해당 기능을 복제·우회·배제하지 않는다(§5의 "no duplicating immature core in consumers" 원칙). 미성숙한 core가 필요하면 소비 저장소는 오너 저장소에 RED 테스트 → 수정/기능/문서/릴리스를 개발해 통합 CI가 GREEN이 될 때까지 진행한 뒤 소비측 고정 버전을 올린다. 배제는 경계가 실제로 잘못되었거나 공통 수요가 없음을 ADR로 정당화할 때만 허용된다. -| Canonical owner | 소유 core 기능 | -|---|---| -| `.github` | 중앙 CI·PR 리뷰·보안 스캔·머지 자동화 거버넌스 | -| `enterprise-architecture-core` + `context-graph-contracts` | 조직 전체 아키텍처·컨텍스트 그래프 계약 | -| `ConceptWeave` + `semantic-data-portal` | 의미 데이터 포털 | -| `contextual-orchestrator` + `noema` | LLM 게이트웨이(오케스트레이션·라우팅·비용)·리뷰 봇 | -| `keyverse` | 유일한 identity ledger(Keycloak 기반 인증 백엔드) | -| `EgressWeave` / `OriginWeave` / `pingora-gateway` / `quarantine-sandbox-runtime` | egress·게이트웨이·샌드박스 | -| `pg-llm-batch` / `EmbedRelay` | 배치·임베딩 | -| `fast-mlsirm` / `TEPP` | psychometrics 연산(Rust 산술) | -| `RankWeave` / `ThreadWeave` | retrieval fusion·이메일 threading | -| `inkspan` / `DiagramWeave` | 다이어그램 | -| `mhtml-etl-gateway` | ETL | -| `appguardrail` / `wardnet` | 보안 게이트웨이(Rust-first) | -| `naruon` / `LineageWeave` / `psychometrics-commons` / `disksage` / `PolicyWeave` / `CalendarWeave` / `supply-chain-control-plane` | 도메인 제품 소비 저장소 | +core foundation은 전 제품의 공통 설치물이 아니라, 여러 제품에서 반복되는 책임 하나를 한 저장소가 canonical owner로서 독립 배포·versioned contract로 제공하는 선택형 control plane·service·library다. 보호 브랜치의 문서·API/schema·release evidence로 역할·성숙도를 확인하며, open PR은 아직 Proposed 상태로 취급한다. + +| 분류 | Canonical owner | 소유 core 기능 | +|---|---|---| +| 조직·계약 | `.github` | 공통 CI·review·security·release | +| 조직·계약 | `enterprise-architecture-core` | 전사 Context Map·architecture decision | +| 조직·계약 | `context-graph-contracts` | assertion·event·schema·fixture·conformance (domain truth·Ubiquitous Language는 제품에 남긴다) | +| 의미·데이터 | `ConceptWeave` | ontology·semantic-layer 생성·검증·release | +| 의미·데이터 | `semantic-data-portal` | catalog·governance·검색·제공 | +| 의미·데이터 | `EmbedRelay` | embedding identity·migration | +| 의미·데이터 | `mhtml-etl-gateway` | MHTML 검사·schema proposal·load lineage | +| AI·운영 | `contextual-orchestrator` | provider discovery·model capability·routing/delegation/verification·admin | +| AI·운영 | `noema` | GitHub Actions OIDC 단기 repository capability·exact-revision evidence | +| AI·운영 | `pg-llm-batch` | DB token count·batch 처리 | +| Identity·보안·runtime | `keyverse` | identity·federation·token (유일한 identity ledger; Keycloak 기반 인증 백엔드) | +| Identity·보안·runtime | `EgressWeave` | 안전한 outbound HTTP | +| Identity·보안·runtime | `OriginWeave` | governed browser | +| Identity·보안·runtime | `pingora-gateway` | Rust edge | +| Identity·보안·runtime | `quarantine-sandbox-runtime` | 격리 | +| Identity·보안·runtime | `appguardrail` | scan·SARIF·remediation | +| Identity·보안·runtime | `wardnet` | gateway·WAF·IDS·SOC | +| 재사용 기능 | `fast-mlsirm` | IRT·MLSIRM | +| 재사용 기능 | `TEPP` | 다국어·시간·event·relation 측정 | +| 재사용 기능 | `RankWeave` | retrieval fusion·evaluation·통계 비교·tuning·TREC | +| 재사용 기능 | `ThreadWeave` | JWZ/RFC 5256 threading | +| 재사용 기능 | `inkspan` | editor·serialization·문서 변환 | +| 재사용 기능 | `DiagramWeave` | diagram patch·render·CLI·LSP | +| 도메인 제품 소비 | `naruon` / `LineageWeave` / `psychometrics-commons` / `disksage` / `PolicyWeave` / `CalendarWeave` / `supply-chain-control-plane` | core foundation을 소비하는 도메인 제품 저장소; domain truth·Ubiquitous Language는 여기 남고 위 core로 옮기지 않는다 | + +owner가 미성숙하거나 API가 없어도 소비 저장소는 복제·우회하지 않는다. owner 저장소에서 RED test → 기능/문서/release를 개발해 CI GREEN과 immutable version을 낸 뒤 소비측이 채택한다. 그 전에는 port·ACL·feature flag·test double로 경계를 지키고 owner의 source·DB·임시 branch를 직접 읽지 않는다. 이 지도는 저장소 신설·기능 배치 결정의 기준이며, 이름이 아니라 제품 책임·재사용 경계·문서·구현·소비 관계로 저장소를 선택한다(§1). 표에 없는 신규 core 필요가 확인되면 이 표에 행을 추가하고 해당 오너 저장소에 ADR을 남긴다. @@ -116,7 +131,7 @@ flowchart LR | G-14 | release/changelog/version 증거가 각 PR에 분산되고 현재 central repo 보호 main의 release candidate가 명확하지 않다 | 운영자는 어떤 기능이 supportable release인지 확인할 수 없다 | merge 후 release readiness ledger, CHANGELOG, semantic version/tag, rollback/operability evidence를 함께 갱신한다 | | G-15 | 첨부파일 처리 경계가 제품별로 다르고, 1MB 상한은 업무 데이터와 맞지 않으며 미지원 MIME/컨테이너가 parser registry에서 명시적으로 pending/quarantine 되는지 확인되지 않았다. 현재 20MB 초과 파일 가능성과 PDF/HWP/HWPX·이미지·압축파일의 parse/sidecar 흐름을 하나의 exact contract로 묶지 못했다 | 큰 업무 첨부를 거부하거나 파싱 실패를 조용히 잃으면 고객의 메일·문서 업무가 중단된다 | naruon/newsdom-api 소유 PR에서 streaming upload, configurable bounded limit above 20MB, MIME sniffing, parser capability registry, quarantine/retry, source-position provenance, and ADR를 추가하고 size/unsupported-type/zip-bomb tests를 required evidence로 만든다 | | G-16 | Required Pingora policy treated a changed documentation PNG screenshot as UTF-8 runtime evidence | Valid UI evidence blocked otherwise valid product PRs before policy evaluation | This branch verifies bounded PNG magic before exemption while runtime paths and malformed assets continue to fail closed; protected-main delivery remains the release gate | -| G-17 | `contextual-orchestrator`의 `proxy_capability()`가 이미지-생성 엔드포인트를 `agent.provider_name == "openrouter"` 리터럴 비교로 재작성했다(provider 식별자를 라우팅 조건으로 하드코딩 — 확인·수정됨: `ContextualWisdomLab/contextual-orchestrator#1017`, `ModelAgent.image_generation_endpoint` 선언적 capability 필드로 교체). `scripts/ci/run_opencode_review_model_pool.sh`의 `is_nvidia_nim_candidate()`도 provider-prefix 문자열 비교로 같은 패턴을 갖고 있으나, 이는 NIM 직접 통신 제거 마이그레이션(§8 orchestrator/free 고정)으로 대체될 예정이라 별도 fix 대상에서 제외했다 | provider GROUP명이 라우팅/선택/failover 조건에 남아 있으면 신규 provider 추가·제거 시 코드 변경이 필요해지고, "표시/관리자 별칭"이라는 정책이 실제로 지켜지지 않는다 | `ContextualWisdomLab/contextual-orchestrator#1017` 병합 후, 조직 전체(§2.4 ownership map의 LLM 게이트웨이 소비 저장소 포함)에서 provider 이름 문자열 비교로 라우팅/선택/failover를 분기하는 잔여 코드를 grep-detect 회귀 테스트로 고정하고, `run_opencode_review_model_pool.sh`는 NIM 제거 PR에서 함께 정리한다 | +| G-17 | `contextual-orchestrator`의 `proxy_capability()`가 이미지-생성 엔드포인트를 `agent.provider_name == "openrouter"` 리터럴 비교로 재작성했다(provider 식별자를 라우팅 조건으로 하드코딩 — 확인·수정됨: ContextualWisdomLab/contextual-orchestrator#1017, `ModelAgent.image_generation_endpoint` 선언적 capability 필드로 교체). `scripts/ci/run_opencode_review_model_pool.sh`의 `is_nvidia_nim_candidate()`도 provider-prefix 문자열 비교로 같은 패턴을 갖고 있으나, 이는 NIM 직접 통신 제거 마이그레이션(§8 orchestrator/free 고정)으로 대체될 예정이라 별도 fix 대상에서 제외했다 | provider GROUP명이 라우팅/선택/failover 조건에 남아 있으면 신규 provider 추가·제거 시 코드 변경이 필요해지고, "표시/관리자 별칭"이라는 정책이 실제로 지켜지지 않는다 | ContextualWisdomLab/contextual-orchestrator#1017 병합 후, 조직 전체(§2.4 ownership map의 LLM 게이트웨이 소비 저장소 포함)에서 provider 이름 문자열 비교로 라우팅/선택/failover를 분기하는 잔여 코드를 grep-detect 회귀 테스트로 고정하고, `run_opencode_review_model_pool.sh`는 NIM 제거 PR에서 함께 정리한다 | | G-18 | LLM 모델 타임아웃에 앱/에이전트/게이트웨이 전역 우선순위 상한이 존재하며, 모델별 조회/설정/해제/복원을 제공하는 관리자 웹 콘솔이 `contextual-orchestrator`에 없다. 취소 사유(사용자 취소/provider 종료/관리자 설정 타임아웃)를 구분해 귀속하는 계약도 없다 | 추론·스트리밍·툴콜링이 실제로 진행 중인데 경과 시간만으로 요청이 끊기면, 정상적으로 응답을 생성하던 고가 요청이 낭비되고 원인도 알 수 없다 | 기본값을 무제한/null로 바꾸고 통신 실패는 upstream provider 자체 timeout/error로만 종료되게 하며, `/admin` 콘솔에 모델별 타임아웃 view/set/clear/restore(단위, 우선순위, 상속, 입력 검증, 감사 추적)와 `/api/v1/*` 계약, 취소-사유 귀속 필드를 추가한다. 소유 저장소는 `contextual-orchestrator`다 | | G-19 | 반복 웹 페이지 E2E 성능에 대해 예외 없는 p95 ≤20ms 하드 게이트와 표본 축소·느린 측정 배제·비현실적 캐시 예열 금지 조항이 어떤 UI 소유 저장소에도 k6/Playwright 등 executed 증거로 존재하는지 미확인이다 | 실측 없이 "빠르다"고 주장하면 실제 고객이 체감하는 지연이 방치된다 | UI 소유 저장소별로 페이지 단위 k6/Lighthouse-CI p95 측정을 CI 필수 증거로 추가하고, 위반 시 원인이 JS 번들 크기·힙·DOM·hydration·메인스레드 블로킹·GC 등 구조적이면 최적화가 아니라 프론트엔드 스택 교체를 ADR로 기록한다. Figma File ID N/A인 이 저장소는 게이트 정의만 문서화하고, 실측/교체는 각 UI repo 소유다 | | G-20 | 번역(i18n)이 버전관리되는 DB 자원으로 관리되고, 서버/네이티브가 화면별 필요한 키만 캐싱해 가져오며, 전체 카탈로그를 브라우저에 내려보내지 않는 아키텍처가 어느 소비 저장소에도 확인되지 않았다. 번역 리뷰/승인/배포/롤백 API와 관리 UI를 소유하는 저장소도 없다 | 번역 파일/JS 번들 방식은 배포 없이 문구를 고칠 수 없고, 전체 카탈로그 다운로드는 SPA를 가정하지 않는 서버/네이티브 화면에서 낭비와 불일치를 만든다 | 기존 저장소 중 적합한 곳이 없으면 전용 신규 저장소(번역 DB, 화면별 key 캐시 API, 리뷰/승인/배포/롤백 API+관리 UI)를 신설하고 §2.4 ownership map에 추가한다. Keyverse는 인증 백엔드로만 유지하고 로그인/가입/복구 UI는 각 제품이 자체 구축한다 | @@ -2623,11 +2638,11 @@ Higgins, S. S., Crepalde, N., & Fernandes, L. (2021). Segmented multiplexity: A **Observed gap (now G-17).** An adversarial 5-agent audit of the "provider GROUP 명을 라우팅/선택/failover 조건으로 하드코딩하지 않는다" policy across `.github`, `noema`, and `contextual-orchestrator` confirmed one real, production-affecting violation: `contextual_orchestrator/orchestrator.py`'s `proxy_capability()` rewrote the image-generation endpoint path by comparing `agent.provider_name == "openrouter"` literally, in both its immediate-race (`_equivalent_race_members`) and sequential-failover call sites. Provider identity was doing routing work it is not supposed to do — it is a display/admin alias only. The same audit independently checked two adjacent suspects and found them **not** the same anti-pattern: `scripts/ci/zdr_policy.py`'s `PROVIDER_ZDR_SCOPE` is a legitimate, ADR-documented, intentionally fail-closed (`KeyError`-on-unknown-provider) compliance-attestation ledger — ZDR status is an inherent legal fact about a named vendor, not a discoverable technical capability, so a vendor key here is correct, not a violation. `scripts/ci/run_opencode_review_model_pool.sh`'s `is_nvidia_nim_candidate()` **is** a real instance of the same pattern, but is left unfixed here because it is already superseded by the separately tracked NIM-direct-communication removal migration (§8 of the standing directive; `orchestrator/free` pin work). -**Fix.** `ContextualWisdomLab/contextual-orchestrator#1017` (branch `fix/provider-endpoint-hardcoding-and-routing-config-20260902`, exact head `263cf0c9`) replaces the provider-name comparison with a declared `ModelAgent.image_generation_endpoint: str | None = None` capability field, round-tripped through `to_config()`/`from_dict()`, set explicitly via agent-pool config or discovery metadata rather than inferred from `provider_name` at request time — zero behavior change for any currently-configured agent, since the field must be set explicitly to opt into the dedicated endpoint. `test_provider_name_alone_never_rewrites_the_image_endpoint` locks the regression: an agent named `"openrouter"` with no declared field routes to the caller's requested endpoint unchanged. +**Fix.** ContextualWisdomLab/contextual-orchestrator#1017 (branch `fix/provider-endpoint-hardcoding-and-routing-config-20260902`, exact head `263cf0c9`) replaces the provider-name comparison with a declared `ModelAgent.image_generation_endpoint: str | None = None` capability field, round-tripped through `to_config()`/`from_dict()`, set explicitly via agent-pool config or discovery metadata rather than inferred from `provider_name` at request time — zero behavior change for any currently-configured agent, since the field must be set explicitly to opt into the dedicated endpoint. `test_provider_name_alone_never_rewrites_the_image_endpoint` locks the regression: an agent named `"openrouter"` with no declared field routes to the caller's requested endpoint unchanged. **Adjacent fix bundled in the same PR (KV naming convention), corrected after human review.** The same PR also fixes an unrelated but independently discovered naming-convention violation: `_ROUTING_CATEGORY`/`_EMBEDDING_CONFIG_CATEGORY` (both the single-word `"routing"`) in `batch_routing.py`/`cost_router.py`, plus a matching literal in `batch_job_registry.py`, violated the two-or-more-semantic-word KV category naming convention. A full-repo grep found **three** real production call sites (not the two an initial narrower pass found) plus three test files sharing the one category — splitting it (the naming fix an isolated look would suggest) would have silently orphaned already-persisted config across two categories instead of one. This entry originally claimed the rename to one unified `"routing_config"` name carried "zero orphaning risk"; PR reviewer `seonghobae` correctly identified that claim as false for the Postgres-backed production boundary — `pg_llm_batch.PostgresConfigStore` keys `com_config` by the literal `f"{category}.{key}"` SQL primary key, so the call-site rename alone *does* orphan any row a prior deployment already persisted under `routing.`: readers now asking for `routing_config.` get an exact miss and silently fall back to their hardcoded default instead of the operator's configured value. Fixed with an idempotent, additive-only backfill migration (`kv_config._migrate_legacy_categories`, run at every `get_config_store()` boot for the seven known keys) that copies a legacy `routing.` value forward only when no `routing_config.` value exists yet — an explicit new-category value always wins and is never overwritten, so an operator's post-backfill reconfiguration survives a later restart. Evidence: `tests/test_kv_config_store.py` gained four tests (backfill-from-legacy, new-value-precedence, idempotent-across-reconnects, in-memory-seed-path), three of which were confirmed to genuinely fail without the migration wired in (RED-before-GREEN, verified by temporarily disabling the migration call and re-running). A third, unrelated pre-existing regression (a hard top-level `import numpy` in `tests/test_psychometric_routing.py` breaking collection for the entire suite, since numpy/fast_mlsirm are genuinely optional lazy-imported dependencies of the production module they test) was fixed in the same PR as a side effect of full-suite validation, scoped via `pytest.importorskip` to the one test function that needs them. -**Status.** PR opened as draft, `subscribe_pr_activity` armed; full suite green modulo two independently verified pre-existing/unrelated failures (a load-induced timing flake and an unrelated `test_spend_analytics.py` failure, both reproduced identically against unmodified `main` with this PR's changes stashed). Not yet merged — G-17's priority action (residual provider-name-string-comparison regression test across the ownership map's LLM-gateway consumers, and the `run_opencode_review_model_pool.sh` cleanup bundled into the NIM-removal PR) remains open until `ContextualWisdomLab/contextual-orchestrator#1017` merges and a follow-up sweep runs. +**Status.** PR opened as draft, `subscribe_pr_activity` armed; full suite green modulo two independently verified pre-existing/unrelated failures (a load-induced timing flake and an unrelated `test_spend_analytics.py` failure, both reproduced identically against unmodified `main` with this PR's changes stashed). Not yet merged — G-17's priority action (residual provider-name-string-comparison regression test across the ownership map's LLM-gateway consumers, and the `run_opencode_review_model_pool.sh` cleanup bundled into the NIM-removal PR) remains open until ContextualWisdomLab/contextual-orchestrator#1017 merges and a follow-up sweep runs. **New Gap rows.** This pass also added G-18 (LLM model-timeout admin console — confirmed entirely missing, not merely buggy), G-19 (p95 ≤20ms E2E performance gate — no executed k6/Lighthouse-CI evidence found in any UI-owning repo), G-20 (i18n as a versioned DB resource — no such architecture found; may need a new dedicated repo), G-21 (Rust-preference tightening — `contextual_orchestrator/orchestrator.py` and siblings remain Python with no per-exception ADR), and G-22 (two confirmed DB column-naming violations in `contextual_orchestrator`'s `agent_pool`/`orchestration_records` tables, invisible to the existing table/index/view/sequence/constraint-only static-analysis test) to §3, and a new §2.4 ecosystem canonical-owner map transcribing the standing directive's ~25-repository ownership assignment, so future work chooses a repository by product-responsibility boundary rather than by name. From b7cbfc246deee2f5adbb64c878c2b312690c105b Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:20:43 +0000 Subject: [PATCH 17/24] =?UTF-8?q?docs:=20fix=20=C2=A72.4=20cross-reference?= =?UTF-8?q?=20and=20restore=20noema's=20shared-runtime=20role?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devin Review findings on PR #1696: - The "no duplicating immature core in consumers" principle was cited as living in this document's own §5, but §5 is "실행 루프와 고객의 다음 행동" (the execution loop) and does not discuss duplication at all -- a dangling internal reference. The principle is actually defined right here in §2.4 itself; the citation now says so and points out §5 is unrelated, instead of pointing at the wrong section. - The ownership-map row for `noema` listed only its GitHub Actions OIDC token-exchange role, dropping the established "공유 agent runtime· GitHub review agent" (shared agent runtime / GitHub review agent) role documented in docs/CWL-MASTER-CONTEXT.md:36. Restored both responsibilities in the row so the map doesn't leave that existing capability without a stated owner. Verified: tests/test_product_technical_gap_baseline.py passes (5/5). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KPmJErfkcHer4UVEgrQxUX --- docs/product-technical-gap-baseline.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 4607615b55..481256dada 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -74,7 +74,7 @@ flowchart LR ### 2.4 Ecosystem canonical-owner map -각 core 기능은 정확히 하나의 canonical-owner 저장소가 소유하며, 소비 저장소는 해당 기능을 복제·우회·배제하지 않는다(§5의 "no duplicating immature core in consumers" 원칙). 미성숙한 core가 필요하면 소비 저장소는 오너 저장소에 RED 테스트 → 수정/기능/문서/릴리스를 개발해 통합 CI가 GREEN이 될 때까지 진행한 뒤 소비측 고정 버전을 올린다. 배제는 경계가 실제로 잘못되었거나 공통 수요가 없음을 ADR로 정당화할 때만 허용된다. +각 core 기능은 정확히 하나의 canonical-owner 저장소가 소유하며, 소비 저장소는 해당 기능을 복제·우회·배제하지 않는다 ("no duplicating immature core in consumers" 원칙 — 이 섹션(§2.4)이 정의하는 소유권 규칙이며, 실행 루프를 다루는 §5와는 별개다). 미성숙한 core가 필요하면 소비 저장소는 오너 저장소에 RED 테스트 → 수정/기능/문서/릴리스를 개발해 통합 CI가 GREEN이 될 때까지 진행한 뒤 소비측 고정 버전을 올린다. 배제는 경계가 실제로 잘못되었거나 공통 수요가 없음을 ADR로 정당화할 때만 허용된다. core foundation은 전 제품의 공통 설치물이 아니라, 여러 제품에서 반복되는 책임 하나를 한 저장소가 canonical owner로서 독립 배포·versioned contract로 제공하는 선택형 control plane·service·library다. 보호 브랜치의 문서·API/schema·release evidence로 역할·성숙도를 확인하며, open PR은 아직 Proposed 상태로 취급한다. @@ -88,7 +88,7 @@ core foundation은 전 제품의 공통 설치물이 아니라, 여러 제품에 | 의미·데이터 | `EmbedRelay` | embedding identity·migration | | 의미·데이터 | `mhtml-etl-gateway` | MHTML 검사·schema proposal·load lineage | | AI·운영 | `contextual-orchestrator` | provider discovery·model capability·routing/delegation/verification·admin | -| AI·운영 | `noema` | GitHub Actions OIDC 단기 repository capability·exact-revision evidence | +| AI·운영 | `noema` | 공유 agent runtime·GitHub review agent·GitHub Actions OIDC 단기 repository capability·exact-revision evidence | | AI·운영 | `pg-llm-batch` | DB token count·batch 처리 | | Identity·보안·runtime | `keyverse` | identity·federation·token (유일한 identity ledger; Keycloak 기반 인증 백엔드) | | Identity·보안·runtime | `EgressWeave` | 안전한 outbound HTTP | From 2ec20ecad43b618284f88585d7c50d668f604695 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:25:49 +0900 Subject: [PATCH 18/24] docs: add exact-head evidence for G-17 through G-22 --- ...ap-baseline-g17-g22-evidence-2026-09-02.md | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md diff --git a/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md b/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md new file mode 100644 index 0000000000..308f0d5f1e --- /dev/null +++ b/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md @@ -0,0 +1,65 @@ +# G-17 through G-22 evidence and decision trace + +Status: Proposed evidence for PR #1696. This note is not production authority until the PR merges to protected `main`. + +## Scope + +This doctoring note records the evidence boundary behind G-17 through G-22 in `docs/product-technical-gap-baseline.md`. It distinguishes observed repository state from organization-level engineering requirements so that a later Agent can revalidate each claim without treating an open PR as released authority. + +## Exact-head evidence snapshot + +- `ContextualWisdomLab/.github` protected `main`: `acbb8e7ceef6d1fc0fee67d553a622ac5d707a9b` after PR #1708. Branch protection still requires the established security, coverage, Noema, and OpenCode contexts. +- `ContextualWisdomLab/contextual-orchestrator` protected `main`: `8839081659df587b19642be17b9114f9dee8b666`. +- `ContextualWisdomLab/contextual-orchestrator#1017`: open, not merged, exact head `fe043f4e6db8b24a6ab719fc5801bbbf40e046ae` at this audit. Its provider-name endpoint repair therefore remains **Proposed** and must not be described as protected-main production authority. The open PR also contains adjacent routing-category/naming work; consumers must wait for an immutable released owner version rather than copying its source. +- Current protected-main search still finds provider identity used in provider-specific telemetry/discovery code such as `contextual_orchestrator/openrouter_uptime.py`. That is not automatically a routing-policy violation: the violation criterion is provider identity controlling selection, endpoint rewrite, or failover where a declared capability should do so. Each match must be classified at its actual responsibility boundary. +- Protected-main persistence evidence still includes legacy one-word schema vocabulary in the orchestration persistence fixtures (`seq`, `kind`, `key`, `payload`) and the agent-pool contract still exposes one-word fields such as `priority`/`disabled`. G-22 is therefore a migration/contract gap, not permission to rename storage destructively. + +## G-18 — model execution timeout versus transport failure + +CWL DEVELOPMENT PHILOSOPHY v2026-09-02B requires the default **model execution timeout** across application, Agent, and Gateway to be `null`; a reasoning, streaming, or tool-call operation must not be terminated merely because elapsed model time crossed a generic ceiling. It separately requires provider communication failure to terminate upstream and requires attribution among user cancellation, provider termination, and an explicitly configured administrator timeout. + +These are different failure domains. A `null` model-execution deadline does **not** require retaining a dead socket forever. Transport implementations must observe provider/connection termination and propagate communication failures; connection lifecycle and liveness handling remain transport responsibilities. RFC 9112 explicitly separates HTTP connection failures/timeouts and graceful connection closure from application semantics, and does not require either endpoint to have a fixed persistent-connection timeout. Consequently, the repair criterion is: + +1. no implicit elapsed-time ceiling for a healthy, progressing model operation; +2. provider/network termination or communication failure propagates immediately and releases resources; +3. an administrator may configure a model-specific timeout, with get/set/clear/restore, units, priority/inheritance, validation, and audit; +4. cancellation cause is observable as user cancel, provider end/failure, or configured administrator timeout; +5. clearing an administrator timeout restores the inherited/null model-execution policy rather than inventing a paid or hidden fallback. + +This resolves the apparent contradiction between long-running inference and resource safety without weakening the governing no-elapsed-time-termination rule. + +## G-19 — p95 <= 20 ms is an internal SLO, not an external universal threshold + +The `p95 <= 20 ms` requirement is an explicit ContextualWisdomLab engineering SLO from CWL DEVELOPMENT PHILOSOPHY v2026-09-02B. It is **not** claimed to be a universal HCI standard or a threshold derived from the cited papers. Peer-reviewed latency research instead supports the narrower premise that interaction latency below the traditional 100 ms guideline can still be perceptible and affect interaction; Forch et al. measured approximately 60 ms perception thresholds in a simple mouse task, while Attig et al. reviewed evidence that sub-100 ms latency can matter. + +Accordingly, G-19 requires each UI-owning product to define the measured page/action boundary, workload, sample design, environment, cold/warm-cache policy, and failure denominator, then prove the organization SLO with executed k6/E2E evidence. The current central baseline records the absence of such evidence **in this audit ledger**; it is not an exhaustive proof that no repository anywhere has ever run a latency test. A product that has current executed evidence should link its exact head/run and make the gap row narrower rather than suppress the SLO. + +## G-20 — i18n topology is a governance requirement + +DB-backed, versioned translation resources; screen-key-scoped fetch/cache; separation of UI translations from ontology labels; and review/approval/deploy/rollback authority are organization architecture requirements from CWL DEVELOPMENT PHILOSOPHY v2026-09-02B. They are not presented as a W3C mandate. The gap is that this central baseline currently has no verified canonical-owner release/API evidence for that shared responsibility. Until an owner is verified and released, products preserve the boundary with ports/ACLs/test doubles and do not copy an unreleased owner source tree or download a full browser catalog as a workaround. + +## G-21 — Rust-first scope is hot-path and risk based + +The Rust-first rule does not authorize a wholesale rewrite of every Python orchestration module. The governing scope is mathematical/psychometric/EDA/data-science core and performance/security-critical runtime, including vector/matrix algebra, token size, CPU multithreading, GPU work, and other measured hot paths. Python remains allowed only for a validated Python-only ML runtime without practical Rust parity, with an ADR that records evidence, bounded scope, and removal conditions. G-21 therefore calls for profiling and boundary identification before migration; an unmeasured `orchestrator.py` rewrite would itself violate the policy. + +## G-22 — schema migration safety + +The two-semantic-word naming rule applies to organization-owned DB objects and fields, but migration must preserve persisted data and released consumer contracts. Repair therefore requires a RED naming/migration contract first, an item-safe migration or compatibility layer, GREEN owner CI, and only then an immutable owner release and consumer bump. Existing one-word external/released boundary names are translated at the anti-corruption boundary until the owner version changes; they are not silently rewritten in consumers. + +## Revalidation checklist + +Before merging or later marking any row complete: + +1. Re-fetch protected `main` for both `.github` and each canonical owner. +2. Re-fetch the exact PR head, reviews/threads, required checks, and release/tag evidence; an open PR remains Proposed. +3. Re-run the repository/code/API search used by the row and record the exact head/module or remove the claim if it no longer reproduces. +4. For G-19/G-20, replace central "evidence not recorded" wording with concrete owner evidence as soon as a current run/release exists. +5. For G-18/G-21/G-22, land owner RED -> fix -> integrated GREEN -> immutable release -> consumer version bump; do not copy branch source into consumers. + +## References + +Attig, C., Rauh, N., Franke, T., & Krems, J. F. (2017). System latency guidelines then and now—Is zero latency really considered necessary? In D. Harris (Ed.), *Engineering psychology and cognitive ergonomics: Cognition and design* (Lecture Notes in Computer Science, Vol. 10276, pp. 3–14). Springer. https://doi.org/10.1007/978-3-319-58475-1_1 + +Fielding, R., Nottingham, M., & Reschke, J. (Eds.). (2022). *HTTP/1.1* (RFC 9112). Internet Engineering Task Force. https://www.rfc-editor.org/rfc/rfc9112.html + +Forch, V., Franke, T., Rauh, N., & Krems, J. F. (2017). Are 100 ms fast enough? Characterizing latency perception thresholds in mouse-based interaction. In D. Harris (Ed.), *Engineering psychology and cognitive ergonomics: Cognition and design* (Lecture Notes in Computer Science, Vol. 10276, pp. 45–56). Springer. https://doi.org/10.1007/978-3-319-58475-1_4 From b281f7e11b142955f388ee98a6c26a366048b292 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:30:10 +0900 Subject: [PATCH 19/24] docs: codify CWL DEVELOPMENT PHILOSOPHY v2026-09-02B --- docs/CWL-DEVELOPMENT-PHILOSOPHY.md | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/CWL-DEVELOPMENT-PHILOSOPHY.md diff --git a/docs/CWL-DEVELOPMENT-PHILOSOPHY.md b/docs/CWL-DEVELOPMENT-PHILOSOPHY.md new file mode 100644 index 0000000000..75ef8261ce --- /dev/null +++ b/docs/CWL-DEVELOPMENT-PHILOSOPHY.md @@ -0,0 +1,47 @@ +# CWL DEVELOPMENT PHILOSOPHY v2026-09-02B + +Status: Governing development policy for ContextualWisdomLab. This version overrides looser wording; stricter safety and governance remain in force. Preserve exact ContextualWisdomLab/repository/PRD capitalization. + +## 1. Loop and goal + +Every open PR cycles review → repair → exact-current-head Checks → ordinary merge/auto-merge → next development. PRD may revise Goal/Loop. PR count reaches zero only by merge or verified complete successor transfer of every valid delta, never simple Close. Target USD 20B sale quality and buyer-visible gap removal. Derive/update PRD, TRD, UML/ERD/Context Map, Gap, and Action/status from ADR/current evidence/PRs in `docs/product-technical-gap-baseline.md`. After substantive PR/Issue exhaustion continue gap development, merges, ContextualWisdomLab ecosystem/Connector integration and releases. Reviews/checks/deploy waits are non-blocking; RCA failures from exact logs, fix, rerun, continue other safe lanes, revisit. Select repositories by responsibility/reuse/implementation/consumption boundaries; update ADR/Goal/Loop. + +## 2. PR, concurrency, and root cause + +Never infer conflict from normal concurrent Commit/Push; re-fetch and preserve intent. No Force Push/destructive rebase. Record rationale before merge/delete consolidation. Remove completed Self-modifying/Source-fix/one-shot workflows after proving no live caller. Stack PRs to merge-ready; if stacked review is missing repair `.github`; use Agent dialogue/decomposition/spawn as accelerators, never as substitutes for a writable repair. single-writer/DDD violation, wrong base/conflict, ADR-number collision, premature Accepted, unprotected dependency, missing test/fixture/contract are repair findings. Move not-ready PR to Draft and ADR/claims to Proposed; non-force restack/retarget into canonical owner stack and repair boundary/number/status/tests/fixtures/contracts. single-writer means delta integration, not disposal. If direct repair is impossible, successor must completely carry valid commits/diff/requirements with verified equivalence before predecessor retirement. Finish missing prerequisite/foundation and keep dependents alive. Reopen wrong closures or create verified successors. Close only by explicit user request, no valid delta, malicious change, or proven complete merged/successor carryover; Proposed/blocked/evidence-preserved/retire/defer labels are not completion. Codify manual workarounds. RCA `PYTHONPATH=.`, Actions/runtime errors. Fix internal defects at canonical owner/original supplier via RED test/contract/feature/docs → integrated CI GREEN → immutable versioned release → consumer version bump; exclude only when ADR proves boundary/common demand absent. Use ponytail, Superpowers ignoring unconditional-question rules, code-review-graph/codegraph indexing. Korean copy/docs/translation applies epoko77-ai/im-not-ai when available while preserving meaning/facts/numbers/proper nouns. + +## 3. Research and docs + +Research authoritative standards/primary sources/peer-reviewed work; APA 7th in doctoring. Use Local Zotero API/OA when available. Link evidence to exact head, PR, module, API, log, experiment; repair contradictions. Maintain `AGENTS.md`, `CLAUDE.md`, `ARCHITECTURE.md`, `CHANGELOG.md`, ADR, ERD/UML, PRD/TRD, UX, security/test/operability. When releasable bump version/CHANGELOG and actually publish before mentioning GitHub.io/Pages. Decisions record enough problem/constraints/alternatives/selection-rejection reasons/evidence/risks/effects/follow-up and concrete user/operations/failure scenarios for a new Agent to reconstruct and continue. + +## 4. UX, UI, and i18n + +Use Figma, Storybook, ui-ux-pro-max, Anti-Slop-UI. UI is reusable objects/components; pages compose them. Record tokens/Figma IDs in ADR. Storybook covers normal/loading/empty/error/permission/responsive/interaction states and screenshots/E2E audit the full ui-ux-pro-max scope. shadcn/ui is product-owned component source; Storybook is validation. Choose frontend stack by security/maintainability/standards/accessibility/measured performance. Hide internal boundaries and guide next action. Keyverse stays auth backend (Direct Grant/ROPC or Keycloak REST API where appropriate); product owns login/signup/recovery forms; verify token CSS/Action Edge/Interaction UX. Support ko/en/ja/zh/vi/es/de/fr with size/wrapping/CJK/text expansion/font fallback/locale Storybook+E2E. Translation authority is DB-backed versioned resources; server/native fetch/cache screen keys only; no full browser catalog, heavy i18n JS or SPA assumption. If shared management is absent create a bounded owner repository with per-product translation/review/approval/deploy/rollback APIs/admin UI. UI translation and ontology labels stay separate. + +## 5. Architecture, ontology, naming, and DB + +Align DDD Subdomain/Bounded Context/Context Map/Ubiquitous Language, Aggregate/Entity/Value Object/Domain Service/Repository/Event/Invariant across ADR/code/API/DB/tests. Aggregates are minimal transaction boundaries; external/legacy uses ACL; Shared Kernel minimal; split oversized monoliths by responsibility and repair stale names. Keep ontology generation/publish, catalog/consumption, interoperability contracts and EA decisions in distinct owners; product domain truth/UL stays with product. Releases carry evidence/provenance/validity/confidence/status/locale. Consumers use released contracts+ACL only; no file copies, cross-service SQL or unapproved publication. Organization-owned variables/constants/args/fields/functions/methods/classes/types/modules/packages/APIs/DB objects/files/directories use at least two semantic words; snake_case preferred, idiomatic camelCase/PascalCase/external conventions translated at boundaries. DB 3NF, hot-partition planning, locks, read/write split when justified, item-level UPSERT. Replace placeholder Buyer. Design toward CSAP/SOC2 without false certification; if PII masking breaks work design a compliant non-masking alternative; anonymize real names/institutions in tests/docs and account for PYPI/API-key/public-release threat models. + +## 6. Language, computation, and measurement + +Require 100% Docstring/public-doc, Test and meaningful Edge Case Coverage on owned production surfaces. Rust is default for mathematical science, Psychometrics, EDA/data-science core and performance/security runtime including vector/linear/matrix algebra, token size, CPU multithreading and GPU. Python is disfavored and never chosen for LLM convenience; use only for validated Python-only ML runtime without practical Rust parity, document scope/evidence/removal conditions in ADR and keep hot path Rust. Probability sampling states design/error target/failure denominator; model multilevel/multiple-membership/time to avoid atomistic fallacy. Weights come from research-backed fast-mlsirm/TEPP or equivalent; heuristics forbidden. Resolve uncertainty with explicit inference/SOLID or fail closed. Fix Deprecation Warnings at root; synthetic data Unit-test-only. Unavoidable Python web server is multithreaded and GIL bottleneck moves to Python 3.14/Rust. + +## 7. Validation and runtime + +Use realistic cases/product-specific accuracy; Psychometrics true-parameter RMSE/reproducibility, music real-audio expected values. Async web + realistic k6 E2E; every page p95 ≤20ms. Profile/fix algorithm/query/I/O/render/runtime; never shrink samples/exclude measures/unrealistic warm caches. If runtime/language/framework or JS bundle/heap/DOM/hydration/main-thread/GC is causal, preserve contracts/accuracy and replace dependency/rendering/frontend stack or move hot paths Rust-first. Verify `close_connection`. Docker substitutable by Podman/Colima; tune `shm_size`/PostgreSQL to hardware; compose k8s-portable; project-name override only for test isolation. Record MLX/CPU/CUDA/OpenCL in ADR; split Native Modules into services when warranted. + +## 8. LLM, orchestration, and embedding + +LLM work is contextual-orchestrator (CO) Agents. Auto-discover configured `BYTEZ_API_KEY`, `NVIDIA_NIM_API_KEY`, `NVIDIA_NIM_API_KEY_SUB`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY`; support embedding/responses/completions/audio/video/image/omni-modal via released API/client/schema. CI is `.github` reusable workflows + thin callers; on owner PR/release/consumer change verify exact-SHA build, API/schema contract, E2E, model behavior, security, SBOM, provenance. Owner defects RED → fix → GREEN → release → consumer version bump. Forbid mutable heads, branch URLs, cross-repo source reads, workflow copies; bridges need owner issue/expiry/delete. Every GitHub Actions model-backed workflow is fixed to `orchestrator/free`; free candidate discovery/routing/fallback happens only inside CO. Workflow must not specify provider/model/provider-group/paid fallback and uses only gateway token. If capability is absent, fail closed without paid bypass and improve free pool/contract/CI. Provider group names are aliases, never hard-coded policy; CO selects from verified modality/context/reasoning/tools/structured output/streaming/price/latency/availability/accuracy. Default model timeout across application/Agent/Gateway is `null`; provider communication failure terminates upstream. Admin Web supports per-model get/set/clear/restore, units, priority, inheritance, validation, audit, API; only configured models are limited. Never terminate reasoning/streaming/tool calls by elapsed time alone; distinguish user cancel/provider end/admin timeout. Use Fugu/Conductor/TRINITY for test-time-compute allocation/ablation; accuracy first; allow at least 2h/model for OpenCode/Strix/Noema. Chat supports completions/responses/json_object/json_schema. Embeddings use semantic units and preserve base64-image recognition/search/insertion position/context. + +## 9. Core foundation + +Use Superpowers/GitHub/Figma/Visualize/Context7/Product Design/Consensus when material. Core foundation is NOT mandatory infrastructure in every product; it is an optional canonical-owner control plane/service/library for responsibility repeated across multiple products, independently deployed behind a versioned contract. Verify role/maturity from protected-branch docs, API/schema and release evidence; open PR is Proposed, never production authority. + +Canonical responsibilities: `.github` common CI/review/security/release; `enterprise-architecture-core` enterprise Context Map/decisions; `context-graph-contracts` assertion/event/schema/fixture/conformance with domain truth remaining in products; `ConceptWeave` ontology/semantic-layer generate/validate/release; `semantic-data-portal` catalog/governance/search/serving; `EmbedRelay` embedding identity/migration; `mhtml-etl-gateway` MHTML inspection/schema proposal/load lineage; CO provider discovery/model capability/routing/delegation/verification/admin; `noema` GitHub Actions OIDC short-lived repository capability/exact-revision evidence; `pg-llm-batch` DB token count/batch; `keyverse` identity/federation/token; `EgressWeave` safe outbound HTTP; `OriginWeave` governed browser; `pingora-gateway` Rust edge; `quarantine-sandbox-runtime` isolation; `appguardrail` scan/SARIF/remediation; `wardnet` gateway/WAF/IDS/SOC; `fast-mlsirm` IRT/MLSIRM; `TEPP` multilingual/time/event/relation measurement; `RankWeave` retrieval fusion/evaluation/statistical comparison/tuning/TREC; `ThreadWeave` JWZ/RFC5256 threading; `inkspan` editor/serialization/document conversion; `DiagramWeave` diagram patch/render/CLI/LSP. + +If owner is immature or lacks API, consumer still does not copy/bypass: develop owner RED → feature/docs → CI GREEN → immutable versioned release, then adopt. Until release preserve boundary via port/ACL/feature flag/test double; never read owner source/DB/temp branch directly. + +## Specialized mission for ContextualWisdomLab/.github + +Run ContextualWisdomLab/.github commercialization/control-plane repair from fresh protected main and exact open PR heads/reviews/threads/workflow inventory/rulesets/PRD/ADR/ARCHITECTURE/CHANGELOG/product-gap baseline. Diagnosis/comment/RED-only/queued review is never completion when a repair is writable. Fix control-plane causes test-first, regenerate exact-head evidence, merge through ordinary protection. Treat PR push/synchronize stale-run retirement, PR-stable concurrency and live-head revalidation as executable contracts; long semantic reviews may use trusted stale-head revalidation instead of blind cancellation, with minimum `actions: write` and repository/PR/head validation. Remove completed repair workflows/drivers/fixtures after proving no callers. Use bypass only for freshly proven circular/`QUEUE_SATURATION_CHICKEN_EGG` with exact mechanically mergeable independently verified head, no substantive unresolved review/security/test/policy/provenance failure, live authorization, and sole blocker being impossible pre-landing evidence; prefer ordinary merge, protect with `expected_head_sha`, record evidence and immediately revalidate all affected PRs. Never bypass substantive defects. After backlog drains, implement the highest-leverage control-plane/product gap and continue. From d417d575dacd8f2202ef55797dad4731c6bcd3e3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:32:23 +0900 Subject: [PATCH 20/24] docs: link G-17..G-22 evidence to governing policy --- .../gap-baseline-g17-g22-evidence-2026-09-02.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md b/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md index 308f0d5f1e..bc16191242 100644 --- a/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md +++ b/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md @@ -6,6 +6,8 @@ Status: Proposed evidence for PR #1696. This note is not production authority un This doctoring note records the evidence boundary behind G-17 through G-22 in `docs/product-technical-gap-baseline.md`. It distinguishes observed repository state from organization-level engineering requirements so that a later Agent can revalidate each claim without treating an open PR as released authority. +The governing policy source is [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md). The repository copy is versioned with this PR so subsequent audits can resolve every policy-attributed requirement to a stable repository path instead of relying on conversation state. + ## Exact-head evidence snapshot - `ContextualWisdomLab/.github` protected `main`: `acbb8e7ceef6d1fc0fee67d553a622ac5d707a9b` after PR #1708. Branch protection still requires the established security, coverage, Noema, and OpenCode contexts. @@ -16,7 +18,7 @@ This doctoring note records the evidence boundary behind G-17 through G-22 in `d ## G-18 — model execution timeout versus transport failure -CWL DEVELOPMENT PHILOSOPHY v2026-09-02B requires the default **model execution timeout** across application, Agent, and Gateway to be `null`; a reasoning, streaming, or tool-call operation must not be terminated merely because elapsed model time crossed a generic ceiling. It separately requires provider communication failure to terminate upstream and requires attribution among user cancellation, provider termination, and an explicitly configured administrator timeout. +[CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md) requires the default **model execution timeout** across application, Agent, and Gateway to be `null`; a reasoning, streaming, or tool-call operation must not be terminated merely because elapsed model time crossed a generic ceiling. It separately requires provider communication failure to terminate upstream and requires attribution among user cancellation, provider termination, and an explicitly configured administrator timeout. These are different failure domains. A `null` model-execution deadline does **not** require retaining a dead socket forever. Transport implementations must observe provider/connection termination and propagate communication failures; connection lifecycle and liveness handling remain transport responsibilities. RFC 9112 explicitly separates HTTP connection failures/timeouts and graceful connection closure from application semantics, and does not require either endpoint to have a fixed persistent-connection timeout. Consequently, the repair criterion is: @@ -30,21 +32,21 @@ This resolves the apparent contradiction between long-running inference and reso ## G-19 — p95 <= 20 ms is an internal SLO, not an external universal threshold -The `p95 <= 20 ms` requirement is an explicit ContextualWisdomLab engineering SLO from CWL DEVELOPMENT PHILOSOPHY v2026-09-02B. It is **not** claimed to be a universal HCI standard or a threshold derived from the cited papers. Peer-reviewed latency research instead supports the narrower premise that interaction latency below the traditional 100 ms guideline can still be perceptible and affect interaction; Forch et al. measured approximately 60 ms perception thresholds in a simple mouse task, while Attig et al. reviewed evidence that sub-100 ms latency can matter. +The `p95 <= 20 ms` requirement is an explicit ContextualWisdomLab engineering SLO in [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md). It is **not** claimed to be a universal HCI standard or a threshold derived from the cited papers. Peer-reviewed latency research instead supports the narrower premise that interaction latency below the traditional 100 ms guideline can still be perceptible and affect interaction; Forch et al. measured approximately 60 ms perception thresholds in a simple mouse task, while Attig et al. reviewed evidence that sub-100 ms latency can matter. Accordingly, G-19 requires each UI-owning product to define the measured page/action boundary, workload, sample design, environment, cold/warm-cache policy, and failure denominator, then prove the organization SLO with executed k6/E2E evidence. The current central baseline records the absence of such evidence **in this audit ledger**; it is not an exhaustive proof that no repository anywhere has ever run a latency test. A product that has current executed evidence should link its exact head/run and make the gap row narrower rather than suppress the SLO. ## G-20 — i18n topology is a governance requirement -DB-backed, versioned translation resources; screen-key-scoped fetch/cache; separation of UI translations from ontology labels; and review/approval/deploy/rollback authority are organization architecture requirements from CWL DEVELOPMENT PHILOSOPHY v2026-09-02B. They are not presented as a W3C mandate. The gap is that this central baseline currently has no verified canonical-owner release/API evidence for that shared responsibility. Until an owner is verified and released, products preserve the boundary with ports/ACLs/test doubles and do not copy an unreleased owner source tree or download a full browser catalog as a workaround. +DB-backed, versioned translation resources; screen-key-scoped fetch/cache; separation of UI translations from ontology labels; and review/approval/deploy/rollback authority are organization architecture requirements in [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md). They are not presented as a W3C mandate. The gap is that this central baseline currently has no verified canonical-owner release/API evidence for that shared responsibility. Until an owner is verified and released, products preserve the boundary with ports/ACLs/test doubles and do not copy an unreleased owner source tree or download a full browser catalog as a workaround. ## G-21 — Rust-first scope is hot-path and risk based -The Rust-first rule does not authorize a wholesale rewrite of every Python orchestration module. The governing scope is mathematical/psychometric/EDA/data-science core and performance/security-critical runtime, including vector/matrix algebra, token size, CPU multithreading, GPU work, and other measured hot paths. Python remains allowed only for a validated Python-only ML runtime without practical Rust parity, with an ADR that records evidence, bounded scope, and removal conditions. G-21 therefore calls for profiling and boundary identification before migration; an unmeasured `orchestrator.py` rewrite would itself violate the policy. +The Rust-first rule in [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md) does not authorize a wholesale rewrite of every Python orchestration module. The governing scope is mathematical/psychometric/EDA/data-science core and performance/security-critical runtime, including vector/matrix algebra, token size, CPU multithreading, GPU work, and other measured hot paths. Python remains allowed only for a validated Python-only ML runtime without practical Rust parity, with an ADR that records evidence, bounded scope, and removal conditions. G-21 therefore calls for profiling and boundary identification before migration; an unmeasured `orchestrator.py` rewrite would itself violate the policy. ## G-22 — schema migration safety -The two-semantic-word naming rule applies to organization-owned DB objects and fields, but migration must preserve persisted data and released consumer contracts. Repair therefore requires a RED naming/migration contract first, an item-safe migration or compatibility layer, GREEN owner CI, and only then an immutable owner release and consumer bump. Existing one-word external/released boundary names are translated at the anti-corruption boundary until the owner version changes; they are not silently rewritten in consumers. +The two-semantic-word naming rule in [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md) applies to organization-owned DB objects and fields, but migration must preserve persisted data and released consumer contracts. Repair therefore requires a RED naming/migration contract first, an item-safe migration or compatibility layer, GREEN owner CI, and only then an immutable owner release and consumer bump. Existing one-word external/released boundary names are translated at the anti-corruption boundary until the owner version changes; they are not silently rewritten in consumers. ## Revalidation checklist From a3be3a969c8f5bd5d2584dd0407cbd5f77c13b07 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 19:34:27 +0900 Subject: [PATCH 21/24] docs(gap): bind governance evidence to canonical single writer --- ...ap-baseline-g17-g22-evidence-2026-09-02.md | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md b/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md index bc16191242..067f893d9a 100644 --- a/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md +++ b/docs/doctoring/gap-baseline-g17-g22-evidence-2026-09-02.md @@ -6,19 +6,20 @@ Status: Proposed evidence for PR #1696. This note is not production authority un This doctoring note records the evidence boundary behind G-17 through G-22 in `docs/product-technical-gap-baseline.md`. It distinguishes observed repository state from organization-level engineering requirements so that a later Agent can revalidate each claim without treating an open PR as released authority. -The governing policy source is [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md). The repository copy is versioned with this PR so subsequent audits can resolve every policy-attributed requirement to a stable repository path instead of relying on conversation state. +The canonical repository policy path is [`docs/product-goal-directive.md`](../product-goal-directive.md). `ContextualWisdomLab/.github#1692` is the single-writer Draft that carries **CWL DEVELOPMENT PHILOSOPHY v2026-09-02B** into that canonical path and its doctoring record; until #1692 merges, that revision remains Proposed rather than protected-main production authority. PR #1696 therefore does not create or retain a second governing-policy file. Its G-17 through G-22 evidence remains Draft/Proposed and must not merge ahead of the canonical policy prerequisite if a row depends on v2026-09-02B wording that is not yet present on protected `main`. ## Exact-head evidence snapshot -- `ContextualWisdomLab/.github` protected `main`: `acbb8e7ceef6d1fc0fee67d553a622ac5d707a9b` after PR #1708. Branch protection still requires the established security, coverage, Noema, and OpenCode contexts. +- `ContextualWisdomLab/.github` protected `main`: `5935c8153722fe6b53bafd579b74f8f097303959` after PR #1715 at this repair pass. Branch protection still requires the established security, coverage, Noema, and OpenCode contexts. +- Canonical policy single writer: `ContextualWisdomLab/.github#1692`, Draft, exact head `4430864470a4ddb7a8c1692e3ad28708e37d47b5` at this repair pass. It changes `docs/product-goal-directive.md` plus `docs/doctoring/product-goal-directive.md` and explicitly carries the 2026-09-02B revision without introducing a competing authority path. - `ContextualWisdomLab/contextual-orchestrator` protected `main`: `8839081659df587b19642be17b9114f9dee8b666`. -- `ContextualWisdomLab/contextual-orchestrator#1017`: open, not merged, exact head `fe043f4e6db8b24a6ab719fc5801bbbf40e046ae` at this audit. Its provider-name endpoint repair therefore remains **Proposed** and must not be described as protected-main production authority. The open PR also contains adjacent routing-category/naming work; consumers must wait for an immutable released owner version rather than copying its source. +- `ContextualWisdomLab/contextual-orchestrator#1017`: open, not merged, exact head `fe043f4e6db8b24a6ab719fc5801bbbf40e046ae` at the prior owner audit. Its provider-name endpoint repair therefore remains **Proposed** and must not be described as protected-main production authority. The open PR also contains adjacent routing-category/naming work; consumers must wait for an immutable released owner version rather than copying its source. - Current protected-main search still finds provider identity used in provider-specific telemetry/discovery code such as `contextual_orchestrator/openrouter_uptime.py`. That is not automatically a routing-policy violation: the violation criterion is provider identity controlling selection, endpoint rewrite, or failover where a declared capability should do so. Each match must be classified at its actual responsibility boundary. - Protected-main persistence evidence still includes legacy one-word schema vocabulary in the orchestration persistence fixtures (`seq`, `kind`, `key`, `payload`) and the agent-pool contract still exposes one-word fields such as `priority`/`disabled`. G-22 is therefore a migration/contract gap, not permission to rename storage destructively. ## G-18 — model execution timeout versus transport failure -[CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md) requires the default **model execution timeout** across application, Agent, and Gateway to be `null`; a reasoning, streaming, or tool-call operation must not be terminated merely because elapsed model time crossed a generic ceiling. It separately requires provider communication failure to terminate upstream and requires attribution among user cancellation, provider termination, and an explicitly configured administrator timeout. +CWL DEVELOPMENT PHILOSOPHY v2026-09-02B, being integrated through the canonical [`docs/product-goal-directive.md`](../product-goal-directive.md) single-writer PR #1692, requires the default **model execution timeout** across application, Agent, and Gateway to be `null`; a reasoning, streaming, or tool-call operation must not be terminated merely because elapsed model time crossed a generic ceiling. It separately requires provider communication failure to terminate upstream and requires attribution among user cancellation, provider termination, and an explicitly configured administrator timeout. These are different failure domains. A `null` model-execution deadline does **not** require retaining a dead socket forever. Transport implementations must observe provider/connection termination and propagate communication failures; connection lifecycle and liveness handling remain transport responsibilities. RFC 9112 explicitly separates HTTP connection failures/timeouts and graceful connection closure from application semantics, and does not require either endpoint to have a fixed persistent-connection timeout. Consequently, the repair criterion is: @@ -32,21 +33,21 @@ This resolves the apparent contradiction between long-running inference and reso ## G-19 — p95 <= 20 ms is an internal SLO, not an external universal threshold -The `p95 <= 20 ms` requirement is an explicit ContextualWisdomLab engineering SLO in [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md). It is **not** claimed to be a universal HCI standard or a threshold derived from the cited papers. Peer-reviewed latency research instead supports the narrower premise that interaction latency below the traditional 100 ms guideline can still be perceptible and affect interaction; Forch et al. measured approximately 60 ms perception thresholds in a simple mouse task, while Attig et al. reviewed evidence that sub-100 ms latency can matter. +The `p95 <= 20 ms` requirement is an explicit ContextualWisdomLab engineering SLO in CWL DEVELOPMENT PHILOSOPHY v2026-09-02B, whose canonical repository integration is `ContextualWisdomLab/.github#1692` at [`docs/product-goal-directive.md`](../product-goal-directive.md). It is **not** claimed to be a universal HCI standard or a threshold derived from the cited papers. Peer-reviewed latency research instead supports the narrower premise that interaction latency below the traditional 100 ms guideline can still be perceptible and affect interaction; Forch et al. measured approximately 60 ms perception thresholds in a simple mouse task, while Attig et al. reviewed evidence that sub-100 ms latency can matter. Accordingly, G-19 requires each UI-owning product to define the measured page/action boundary, workload, sample design, environment, cold/warm-cache policy, and failure denominator, then prove the organization SLO with executed k6/E2E evidence. The current central baseline records the absence of such evidence **in this audit ledger**; it is not an exhaustive proof that no repository anywhere has ever run a latency test. A product that has current executed evidence should link its exact head/run and make the gap row narrower rather than suppress the SLO. ## G-20 — i18n topology is a governance requirement -DB-backed, versioned translation resources; screen-key-scoped fetch/cache; separation of UI translations from ontology labels; and review/approval/deploy/rollback authority are organization architecture requirements in [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md). They are not presented as a W3C mandate. The gap is that this central baseline currently has no verified canonical-owner release/API evidence for that shared responsibility. Until an owner is verified and released, products preserve the boundary with ports/ACLs/test doubles and do not copy an unreleased owner source tree or download a full browser catalog as a workaround. +DB-backed, versioned translation resources; screen-key-scoped fetch/cache; separation of UI translations from ontology labels; and review/approval/deploy/rollback authority are organization architecture requirements in CWL DEVELOPMENT PHILOSOPHY v2026-09-02B, whose canonical repository integration is `ContextualWisdomLab/.github#1692` at [`docs/product-goal-directive.md`](../product-goal-directive.md). They are not presented as a W3C mandate. The gap is that this central baseline currently has no verified canonical-owner release/API evidence for that shared responsibility. Until an owner is verified and released, products preserve the boundary with ports/ACLs/test doubles and do not copy an unreleased owner source tree or download a full browser catalog as a workaround. ## G-21 — Rust-first scope is hot-path and risk based -The Rust-first rule in [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md) does not authorize a wholesale rewrite of every Python orchestration module. The governing scope is mathematical/psychometric/EDA/data-science core and performance/security-critical runtime, including vector/matrix algebra, token size, CPU multithreading, GPU work, and other measured hot paths. Python remains allowed only for a validated Python-only ML runtime without practical Rust parity, with an ADR that records evidence, bounded scope, and removal conditions. G-21 therefore calls for profiling and boundary identification before migration; an unmeasured `orchestrator.py` rewrite would itself violate the policy. +The Rust-first rule in CWL DEVELOPMENT PHILOSOPHY v2026-09-02B, whose canonical repository integration is `ContextualWisdomLab/.github#1692` at [`docs/product-goal-directive.md`](../product-goal-directive.md), does not authorize a wholesale rewrite of every Python orchestration module. The governing scope is mathematical/psychometric/EDA/data-science core and performance/security-critical runtime, including vector/matrix algebra, token size, CPU multithreading, GPU work, and other measured hot paths. Python remains allowed only for a validated Python-only ML runtime without practical Rust parity, with an ADR that records evidence, bounded scope, and removal conditions. G-21 therefore calls for profiling and boundary identification before migration; an unmeasured `orchestrator.py` rewrite would itself violate the policy. ## G-22 — schema migration safety -The two-semantic-word naming rule in [CWL DEVELOPMENT PHILOSOPHY v2026-09-02B](../CWL-DEVELOPMENT-PHILOSOPHY.md) applies to organization-owned DB objects and fields, but migration must preserve persisted data and released consumer contracts. Repair therefore requires a RED naming/migration contract first, an item-safe migration or compatibility layer, GREEN owner CI, and only then an immutable owner release and consumer bump. Existing one-word external/released boundary names are translated at the anti-corruption boundary until the owner version changes; they are not silently rewritten in consumers. +The two-semantic-word naming rule in CWL DEVELOPMENT PHILOSOPHY v2026-09-02B, whose canonical repository integration is `ContextualWisdomLab/.github#1692` at [`docs/product-goal-directive.md`](../product-goal-directive.md), applies to organization-owned DB objects and fields, but migration must preserve persisted data and released consumer contracts. Repair therefore requires a RED naming/migration contract first, an item-safe migration or compatibility layer, GREEN owner CI, and only then an immutable owner release and consumer bump. Existing one-word external/released boundary names are translated at the anti-corruption boundary until the owner version changes; they are not silently rewritten in consumers. ## Revalidation checklist @@ -54,9 +55,10 @@ Before merging or later marking any row complete: 1. Re-fetch protected `main` for both `.github` and each canonical owner. 2. Re-fetch the exact PR head, reviews/threads, required checks, and release/tag evidence; an open PR remains Proposed. -3. Re-run the repository/code/API search used by the row and record the exact head/module or remove the claim if it no longer reproduces. -4. For G-19/G-20, replace central "evidence not recorded" wording with concrete owner evidence as soon as a current run/release exists. -5. For G-18/G-21/G-22, land owner RED -> fix -> integrated GREEN -> immutable release -> consumer version bump; do not copy branch source into consumers. +3. Verify `ContextualWisdomLab/.github#1692` has merged the 2026-09-02B text into canonical `docs/product-goal-directive.md` before merging any #1696 row whose requirement depends on that revision. +4. Re-run the repository/code/API search used by the row and record the exact head/module or remove the claim if it no longer reproduces. +5. For G-19/G-20, replace central "evidence not recorded" wording with concrete owner evidence as soon as a current run/release exists. +6. For G-18/G-21/G-22, land owner RED -> fix -> integrated GREEN -> immutable release -> consumer version bump; do not copy branch source into consumers. ## References From 2cb5952f8a40a2bc8a7318707574d3b6d460fa3a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 19:34:33 +0900 Subject: [PATCH 22/24] docs(gap): remove competing governance authority copy --- docs/CWL-DEVELOPMENT-PHILOSOPHY.md | 47 ------------------------------ 1 file changed, 47 deletions(-) delete mode 100644 docs/CWL-DEVELOPMENT-PHILOSOPHY.md diff --git a/docs/CWL-DEVELOPMENT-PHILOSOPHY.md b/docs/CWL-DEVELOPMENT-PHILOSOPHY.md deleted file mode 100644 index 75ef8261ce..0000000000 --- a/docs/CWL-DEVELOPMENT-PHILOSOPHY.md +++ /dev/null @@ -1,47 +0,0 @@ -# CWL DEVELOPMENT PHILOSOPHY v2026-09-02B - -Status: Governing development policy for ContextualWisdomLab. This version overrides looser wording; stricter safety and governance remain in force. Preserve exact ContextualWisdomLab/repository/PRD capitalization. - -## 1. Loop and goal - -Every open PR cycles review → repair → exact-current-head Checks → ordinary merge/auto-merge → next development. PRD may revise Goal/Loop. PR count reaches zero only by merge or verified complete successor transfer of every valid delta, never simple Close. Target USD 20B sale quality and buyer-visible gap removal. Derive/update PRD, TRD, UML/ERD/Context Map, Gap, and Action/status from ADR/current evidence/PRs in `docs/product-technical-gap-baseline.md`. After substantive PR/Issue exhaustion continue gap development, merges, ContextualWisdomLab ecosystem/Connector integration and releases. Reviews/checks/deploy waits are non-blocking; RCA failures from exact logs, fix, rerun, continue other safe lanes, revisit. Select repositories by responsibility/reuse/implementation/consumption boundaries; update ADR/Goal/Loop. - -## 2. PR, concurrency, and root cause - -Never infer conflict from normal concurrent Commit/Push; re-fetch and preserve intent. No Force Push/destructive rebase. Record rationale before merge/delete consolidation. Remove completed Self-modifying/Source-fix/one-shot workflows after proving no live caller. Stack PRs to merge-ready; if stacked review is missing repair `.github`; use Agent dialogue/decomposition/spawn as accelerators, never as substitutes for a writable repair. single-writer/DDD violation, wrong base/conflict, ADR-number collision, premature Accepted, unprotected dependency, missing test/fixture/contract are repair findings. Move not-ready PR to Draft and ADR/claims to Proposed; non-force restack/retarget into canonical owner stack and repair boundary/number/status/tests/fixtures/contracts. single-writer means delta integration, not disposal. If direct repair is impossible, successor must completely carry valid commits/diff/requirements with verified equivalence before predecessor retirement. Finish missing prerequisite/foundation and keep dependents alive. Reopen wrong closures or create verified successors. Close only by explicit user request, no valid delta, malicious change, or proven complete merged/successor carryover; Proposed/blocked/evidence-preserved/retire/defer labels are not completion. Codify manual workarounds. RCA `PYTHONPATH=.`, Actions/runtime errors. Fix internal defects at canonical owner/original supplier via RED test/contract/feature/docs → integrated CI GREEN → immutable versioned release → consumer version bump; exclude only when ADR proves boundary/common demand absent. Use ponytail, Superpowers ignoring unconditional-question rules, code-review-graph/codegraph indexing. Korean copy/docs/translation applies epoko77-ai/im-not-ai when available while preserving meaning/facts/numbers/proper nouns. - -## 3. Research and docs - -Research authoritative standards/primary sources/peer-reviewed work; APA 7th in doctoring. Use Local Zotero API/OA when available. Link evidence to exact head, PR, module, API, log, experiment; repair contradictions. Maintain `AGENTS.md`, `CLAUDE.md`, `ARCHITECTURE.md`, `CHANGELOG.md`, ADR, ERD/UML, PRD/TRD, UX, security/test/operability. When releasable bump version/CHANGELOG and actually publish before mentioning GitHub.io/Pages. Decisions record enough problem/constraints/alternatives/selection-rejection reasons/evidence/risks/effects/follow-up and concrete user/operations/failure scenarios for a new Agent to reconstruct and continue. - -## 4. UX, UI, and i18n - -Use Figma, Storybook, ui-ux-pro-max, Anti-Slop-UI. UI is reusable objects/components; pages compose them. Record tokens/Figma IDs in ADR. Storybook covers normal/loading/empty/error/permission/responsive/interaction states and screenshots/E2E audit the full ui-ux-pro-max scope. shadcn/ui is product-owned component source; Storybook is validation. Choose frontend stack by security/maintainability/standards/accessibility/measured performance. Hide internal boundaries and guide next action. Keyverse stays auth backend (Direct Grant/ROPC or Keycloak REST API where appropriate); product owns login/signup/recovery forms; verify token CSS/Action Edge/Interaction UX. Support ko/en/ja/zh/vi/es/de/fr with size/wrapping/CJK/text expansion/font fallback/locale Storybook+E2E. Translation authority is DB-backed versioned resources; server/native fetch/cache screen keys only; no full browser catalog, heavy i18n JS or SPA assumption. If shared management is absent create a bounded owner repository with per-product translation/review/approval/deploy/rollback APIs/admin UI. UI translation and ontology labels stay separate. - -## 5. Architecture, ontology, naming, and DB - -Align DDD Subdomain/Bounded Context/Context Map/Ubiquitous Language, Aggregate/Entity/Value Object/Domain Service/Repository/Event/Invariant across ADR/code/API/DB/tests. Aggregates are minimal transaction boundaries; external/legacy uses ACL; Shared Kernel minimal; split oversized monoliths by responsibility and repair stale names. Keep ontology generation/publish, catalog/consumption, interoperability contracts and EA decisions in distinct owners; product domain truth/UL stays with product. Releases carry evidence/provenance/validity/confidence/status/locale. Consumers use released contracts+ACL only; no file copies, cross-service SQL or unapproved publication. Organization-owned variables/constants/args/fields/functions/methods/classes/types/modules/packages/APIs/DB objects/files/directories use at least two semantic words; snake_case preferred, idiomatic camelCase/PascalCase/external conventions translated at boundaries. DB 3NF, hot-partition planning, locks, read/write split when justified, item-level UPSERT. Replace placeholder Buyer. Design toward CSAP/SOC2 without false certification; if PII masking breaks work design a compliant non-masking alternative; anonymize real names/institutions in tests/docs and account for PYPI/API-key/public-release threat models. - -## 6. Language, computation, and measurement - -Require 100% Docstring/public-doc, Test and meaningful Edge Case Coverage on owned production surfaces. Rust is default for mathematical science, Psychometrics, EDA/data-science core and performance/security runtime including vector/linear/matrix algebra, token size, CPU multithreading and GPU. Python is disfavored and never chosen for LLM convenience; use only for validated Python-only ML runtime without practical Rust parity, document scope/evidence/removal conditions in ADR and keep hot path Rust. Probability sampling states design/error target/failure denominator; model multilevel/multiple-membership/time to avoid atomistic fallacy. Weights come from research-backed fast-mlsirm/TEPP or equivalent; heuristics forbidden. Resolve uncertainty with explicit inference/SOLID or fail closed. Fix Deprecation Warnings at root; synthetic data Unit-test-only. Unavoidable Python web server is multithreaded and GIL bottleneck moves to Python 3.14/Rust. - -## 7. Validation and runtime - -Use realistic cases/product-specific accuracy; Psychometrics true-parameter RMSE/reproducibility, music real-audio expected values. Async web + realistic k6 E2E; every page p95 ≤20ms. Profile/fix algorithm/query/I/O/render/runtime; never shrink samples/exclude measures/unrealistic warm caches. If runtime/language/framework or JS bundle/heap/DOM/hydration/main-thread/GC is causal, preserve contracts/accuracy and replace dependency/rendering/frontend stack or move hot paths Rust-first. Verify `close_connection`. Docker substitutable by Podman/Colima; tune `shm_size`/PostgreSQL to hardware; compose k8s-portable; project-name override only for test isolation. Record MLX/CPU/CUDA/OpenCL in ADR; split Native Modules into services when warranted. - -## 8. LLM, orchestration, and embedding - -LLM work is contextual-orchestrator (CO) Agents. Auto-discover configured `BYTEZ_API_KEY`, `NVIDIA_NIM_API_KEY`, `NVIDIA_NIM_API_KEY_SUB`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY`; support embedding/responses/completions/audio/video/image/omni-modal via released API/client/schema. CI is `.github` reusable workflows + thin callers; on owner PR/release/consumer change verify exact-SHA build, API/schema contract, E2E, model behavior, security, SBOM, provenance. Owner defects RED → fix → GREEN → release → consumer version bump. Forbid mutable heads, branch URLs, cross-repo source reads, workflow copies; bridges need owner issue/expiry/delete. Every GitHub Actions model-backed workflow is fixed to `orchestrator/free`; free candidate discovery/routing/fallback happens only inside CO. Workflow must not specify provider/model/provider-group/paid fallback and uses only gateway token. If capability is absent, fail closed without paid bypass and improve free pool/contract/CI. Provider group names are aliases, never hard-coded policy; CO selects from verified modality/context/reasoning/tools/structured output/streaming/price/latency/availability/accuracy. Default model timeout across application/Agent/Gateway is `null`; provider communication failure terminates upstream. Admin Web supports per-model get/set/clear/restore, units, priority, inheritance, validation, audit, API; only configured models are limited. Never terminate reasoning/streaming/tool calls by elapsed time alone; distinguish user cancel/provider end/admin timeout. Use Fugu/Conductor/TRINITY for test-time-compute allocation/ablation; accuracy first; allow at least 2h/model for OpenCode/Strix/Noema. Chat supports completions/responses/json_object/json_schema. Embeddings use semantic units and preserve base64-image recognition/search/insertion position/context. - -## 9. Core foundation - -Use Superpowers/GitHub/Figma/Visualize/Context7/Product Design/Consensus when material. Core foundation is NOT mandatory infrastructure in every product; it is an optional canonical-owner control plane/service/library for responsibility repeated across multiple products, independently deployed behind a versioned contract. Verify role/maturity from protected-branch docs, API/schema and release evidence; open PR is Proposed, never production authority. - -Canonical responsibilities: `.github` common CI/review/security/release; `enterprise-architecture-core` enterprise Context Map/decisions; `context-graph-contracts` assertion/event/schema/fixture/conformance with domain truth remaining in products; `ConceptWeave` ontology/semantic-layer generate/validate/release; `semantic-data-portal` catalog/governance/search/serving; `EmbedRelay` embedding identity/migration; `mhtml-etl-gateway` MHTML inspection/schema proposal/load lineage; CO provider discovery/model capability/routing/delegation/verification/admin; `noema` GitHub Actions OIDC short-lived repository capability/exact-revision evidence; `pg-llm-batch` DB token count/batch; `keyverse` identity/federation/token; `EgressWeave` safe outbound HTTP; `OriginWeave` governed browser; `pingora-gateway` Rust edge; `quarantine-sandbox-runtime` isolation; `appguardrail` scan/SARIF/remediation; `wardnet` gateway/WAF/IDS/SOC; `fast-mlsirm` IRT/MLSIRM; `TEPP` multilingual/time/event/relation measurement; `RankWeave` retrieval fusion/evaluation/statistical comparison/tuning/TREC; `ThreadWeave` JWZ/RFC5256 threading; `inkspan` editor/serialization/document conversion; `DiagramWeave` diagram patch/render/CLI/LSP. - -If owner is immature or lacks API, consumer still does not copy/bypass: develop owner RED → feature/docs → CI GREEN → immutable versioned release, then adopt. Until release preserve boundary via port/ACL/feature flag/test double; never read owner source/DB/temp branch directly. - -## Specialized mission for ContextualWisdomLab/.github - -Run ContextualWisdomLab/.github commercialization/control-plane repair from fresh protected main and exact open PR heads/reviews/threads/workflow inventory/rulesets/PRD/ADR/ARCHITECTURE/CHANGELOG/product-gap baseline. Diagnosis/comment/RED-only/queued review is never completion when a repair is writable. Fix control-plane causes test-first, regenerate exact-head evidence, merge through ordinary protection. Treat PR push/synchronize stale-run retirement, PR-stable concurrency and live-head revalidation as executable contracts; long semantic reviews may use trusted stale-head revalidation instead of blind cancellation, with minimum `actions: write` and repository/PR/head validation. Remove completed repair workflows/drivers/fixtures after proving no callers. Use bypass only for freshly proven circular/`QUEUE_SATURATION_CHICKEN_EGG` with exact mechanically mergeable independently verified head, no substantive unresolved review/security/test/policy/provenance failure, live authorization, and sole blocker being impossible pre-landing evidence; prefer ordinary merge, protect with `expected_head_sha`, record evidence and immediately revalidate all affected PRs. Never bypass substantive defects. After backlog drains, implement the highest-leverage control-plane/product gap and continue. From 750f02ab6980fee59b9865658a9d39378c422cee Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 10:39:38 +0000 Subject: [PATCH 23/24] docs: flag sandbox-isolation ownership conflict, defer resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devin Review on PR #1696 (based_on_repo_rules: true): the §2.4 ownership map assigns isolation to quarantine-sandbox-runtime as a single-responsibility owner, but the mandatory docs/CWL-MASTER-CONTEXT.md:36 describes noema as "agent runtime... + the lightweight quarantine sandbox" -- the same responsibility assigned to a different repository. Not resolving this unilaterally: deciding which source is authoritative (or whether these are genuinely distinct tiers -- noema's own lightweight embedded sandbox vs. a dedicated org-wide isolation service) is an architectural decision this doc has no authority to make on its own. Added a footnote on the quarantine-sandbox-runtime row documenting the conflict, the two plausible resolutions, and the three concrete guardrails consumers should follow until an ADR resolves it (don't pick one arbitrarily and build a parallel implementation; the real owner records the noema/wardnet/naruon/quarantine-sandbox-runtime relationship in an ADR; CWL-MASTER-CONTEXT.md and this table get updated together once resolved). Verified: tests/test_product_technical_gap_baseline.py passes (5/5). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KPmJErfkcHer4UVEgrQxUX --- docs/product-technical-gap-baseline.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 481256dada..7fee51c3bc 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -94,7 +94,7 @@ core foundation은 전 제품의 공통 설치물이 아니라, 여러 제품에 | Identity·보안·runtime | `EgressWeave` | 안전한 outbound HTTP | | Identity·보안·runtime | `OriginWeave` | governed browser | | Identity·보안·runtime | `pingora-gateway` | Rust edge | -| Identity·보안·runtime | `quarantine-sandbox-runtime` | 격리 | +| Identity·보안·runtime | `quarantine-sandbox-runtime` | 격리[^sandbox-ownership] | | Identity·보안·runtime | `appguardrail` | scan·SARIF·remediation | | Identity·보안·runtime | `wardnet` | gateway·WAF·IDS·SOC | | 재사용 기능 | `fast-mlsirm` | IRT·MLSIRM | @@ -109,6 +109,8 @@ owner가 미성숙하거나 API가 없어도 소비 저장소는 복제·우회 이 지도는 저장소 신설·기능 배치 결정의 기준이며, 이름이 아니라 제품 책임·재사용 경계·문서·구현·소비 관계로 저장소를 선택한다(§1). 표에 없는 신규 core 필요가 확인되면 이 표에 행을 추가하고 해당 오너 저장소에 ADR을 남긴다. +[^sandbox-ownership]: **미해결 소유권 충돌 (Devin Review, based_on_repo_rules).** 이 표는 격리를 `quarantine-sandbox-runtime`의 단일 책임으로 배정하지만, mandatory master context [`docs/CWL-MASTER-CONTEXT.md:36`](https://github.com/ContextualWisdomLab/.github/blob/main/docs/CWL-MASTER-CONTEXT.md)은 noema를 "agent runtime... + the lightweight quarantine sandbox"로 설명해 동일 책임을 다른 저장소에도 배정한다. 두 출처 중 하나가 오래됐거나, noema의 것은 자체 실행 경로용 경량 내장 격리이고 `quarantine-sandbox-runtime`은 조직 전체가 소비하는 전용 격리 서비스라는 실제 계층 분리가 있을 수 있다 — 이 문서는 그 구분을 확인할 권한이 없으므로 단정하지 않는다. 해결 전까지: (1) 새 소비자는 두 구현 중 하나를 임의로 골라 병행 구현하지 않는다, (2) 실제 소유자와 noema·wardnet·naruon·quarantine-sandbox-runtime 간 관계(추출·release된 contract 여부)를 확정하는 ADR을 오너 저장소에 남긴다, (3) 확정 후 `docs/CWL-MASTER-CONTEXT.md`와 이 표를 동일 PR에서 함께 갱신한다. + ## 3. Gap register 우선순위는 구매자 체감, 보안/증거 위험, 선행 의존성 순서다. From 8bff7e7fef25480e5119af511acb08c2dfb69ad3 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 10:42:57 +0000 Subject: [PATCH 24/24] =?UTF-8?q?docs:=20make=20=C2=A72.4=20ownership-map?= =?UTF-8?q?=20entries=20navigable=20owner/repo=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devin Review on PR #1696 (analysis): the ownership table used bare repository names instead of owner/repo references or URLs, so readers could not directly verify each claimed canonical owner -- also at odds with this repo's own binding convention (CLAUDE.md / CWL-MASTER-CONTEXT.md §7: "cross-repo references as owner/repo#num or full URLs"). Converted every Canonical owner cell to a markdown link (`ContextualWisdomLab/` -> https://github.com/ContextualWisdomLab/). Mechanical formatting change only; no ownership assignment changed. Verified: tests/test_product_technical_gap_baseline.py passes (5/5). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KPmJErfkcHer4UVEgrQxUX --- docs/product-technical-gap-baseline.md | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 7fee51c3bc..96a04291c2 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -80,30 +80,30 @@ core foundation은 전 제품의 공통 설치물이 아니라, 여러 제품에 | 분류 | Canonical owner | 소유 core 기능 | |---|---|---| -| 조직·계약 | `.github` | 공통 CI·review·security·release | -| 조직·계약 | `enterprise-architecture-core` | 전사 Context Map·architecture decision | -| 조직·계약 | `context-graph-contracts` | assertion·event·schema·fixture·conformance (domain truth·Ubiquitous Language는 제품에 남긴다) | -| 의미·데이터 | `ConceptWeave` | ontology·semantic-layer 생성·검증·release | -| 의미·데이터 | `semantic-data-portal` | catalog·governance·검색·제공 | -| 의미·데이터 | `EmbedRelay` | embedding identity·migration | -| 의미·데이터 | `mhtml-etl-gateway` | MHTML 검사·schema proposal·load lineage | -| AI·운영 | `contextual-orchestrator` | provider discovery·model capability·routing/delegation/verification·admin | -| AI·운영 | `noema` | 공유 agent runtime·GitHub review agent·GitHub Actions OIDC 단기 repository capability·exact-revision evidence | -| AI·운영 | `pg-llm-batch` | DB token count·batch 처리 | -| Identity·보안·runtime | `keyverse` | identity·federation·token (유일한 identity ledger; Keycloak 기반 인증 백엔드) | -| Identity·보안·runtime | `EgressWeave` | 안전한 outbound HTTP | -| Identity·보안·runtime | `OriginWeave` | governed browser | -| Identity·보안·runtime | `pingora-gateway` | Rust edge | -| Identity·보안·runtime | `quarantine-sandbox-runtime` | 격리[^sandbox-ownership] | -| Identity·보안·runtime | `appguardrail` | scan·SARIF·remediation | -| Identity·보안·runtime | `wardnet` | gateway·WAF·IDS·SOC | -| 재사용 기능 | `fast-mlsirm` | IRT·MLSIRM | -| 재사용 기능 | `TEPP` | 다국어·시간·event·relation 측정 | -| 재사용 기능 | `RankWeave` | retrieval fusion·evaluation·통계 비교·tuning·TREC | -| 재사용 기능 | `ThreadWeave` | JWZ/RFC 5256 threading | -| 재사용 기능 | `inkspan` | editor·serialization·문서 변환 | -| 재사용 기능 | `DiagramWeave` | diagram patch·render·CLI·LSP | -| 도메인 제품 소비 | `naruon` / `LineageWeave` / `psychometrics-commons` / `disksage` / `PolicyWeave` / `CalendarWeave` / `supply-chain-control-plane` | core foundation을 소비하는 도메인 제품 저장소; domain truth·Ubiquitous Language는 여기 남고 위 core로 옮기지 않는다 | +| 조직·계약 | [`ContextualWisdomLab/.github`](https://github.com/ContextualWisdomLab/.github) | 공통 CI·review·security·release | +| 조직·계약 | [`ContextualWisdomLab/enterprise-architecture-core`](https://github.com/ContextualWisdomLab/enterprise-architecture-core) | 전사 Context Map·architecture decision | +| 조직·계약 | [`ContextualWisdomLab/context-graph-contracts`](https://github.com/ContextualWisdomLab/context-graph-contracts) | assertion·event·schema·fixture·conformance (domain truth·Ubiquitous Language는 제품에 남긴다) | +| 의미·데이터 | [`ContextualWisdomLab/ConceptWeave`](https://github.com/ContextualWisdomLab/ConceptWeave) | ontology·semantic-layer 생성·검증·release | +| 의미·데이터 | [`ContextualWisdomLab/semantic-data-portal`](https://github.com/ContextualWisdomLab/semantic-data-portal) | catalog·governance·검색·제공 | +| 의미·데이터 | [`ContextualWisdomLab/EmbedRelay`](https://github.com/ContextualWisdomLab/EmbedRelay) | embedding identity·migration | +| 의미·데이터 | [`ContextualWisdomLab/mhtml-etl-gateway`](https://github.com/ContextualWisdomLab/mhtml-etl-gateway) | MHTML 검사·schema proposal·load lineage | +| AI·운영 | [`ContextualWisdomLab/contextual-orchestrator`](https://github.com/ContextualWisdomLab/contextual-orchestrator) | provider discovery·model capability·routing/delegation/verification·admin | +| AI·운영 | [`ContextualWisdomLab/noema`](https://github.com/ContextualWisdomLab/noema) | 공유 agent runtime·GitHub review agent·GitHub Actions OIDC 단기 repository capability·exact-revision evidence | +| AI·운영 | [`ContextualWisdomLab/pg-llm-batch`](https://github.com/ContextualWisdomLab/pg-llm-batch) | DB token count·batch 처리 | +| Identity·보안·runtime | [`ContextualWisdomLab/keyverse`](https://github.com/ContextualWisdomLab/keyverse) | identity·federation·token (유일한 identity ledger; Keycloak 기반 인증 백엔드) | +| Identity·보안·runtime | [`ContextualWisdomLab/EgressWeave`](https://github.com/ContextualWisdomLab/EgressWeave) | 안전한 outbound HTTP | +| Identity·보안·runtime | [`ContextualWisdomLab/OriginWeave`](https://github.com/ContextualWisdomLab/OriginWeave) | governed browser | +| Identity·보안·runtime | [`ContextualWisdomLab/pingora-gateway`](https://github.com/ContextualWisdomLab/pingora-gateway) | Rust edge | +| Identity·보안·runtime | [`ContextualWisdomLab/quarantine-sandbox-runtime`](https://github.com/ContextualWisdomLab/quarantine-sandbox-runtime) | 격리[^sandbox-ownership] | +| Identity·보안·runtime | [`ContextualWisdomLab/appguardrail`](https://github.com/ContextualWisdomLab/appguardrail) | scan·SARIF·remediation | +| Identity·보안·runtime | [`ContextualWisdomLab/wardnet`](https://github.com/ContextualWisdomLab/wardnet) | gateway·WAF·IDS·SOC | +| 재사용 기능 | [`ContextualWisdomLab/fast-mlsirm`](https://github.com/ContextualWisdomLab/fast-mlsirm) | IRT·MLSIRM | +| 재사용 기능 | [`ContextualWisdomLab/TEPP`](https://github.com/ContextualWisdomLab/TEPP) | 다국어·시간·event·relation 측정 | +| 재사용 기능 | [`ContextualWisdomLab/RankWeave`](https://github.com/ContextualWisdomLab/RankWeave) | retrieval fusion·evaluation·통계 비교·tuning·TREC | +| 재사용 기능 | [`ContextualWisdomLab/ThreadWeave`](https://github.com/ContextualWisdomLab/ThreadWeave) | JWZ/RFC 5256 threading | +| 재사용 기능 | [`ContextualWisdomLab/inkspan`](https://github.com/ContextualWisdomLab/inkspan) | editor·serialization·문서 변환 | +| 재사용 기능 | [`ContextualWisdomLab/DiagramWeave`](https://github.com/ContextualWisdomLab/DiagramWeave) | diagram patch·render·CLI·LSP | +| 도메인 제품 소비 | [`naruon`](https://github.com/ContextualWisdomLab/naruon) / [`LineageWeave`](https://github.com/ContextualWisdomLab/LineageWeave) / [`psychometrics-commons`](https://github.com/ContextualWisdomLab/psychometrics-commons) / [`disksage`](https://github.com/ContextualWisdomLab/disksage) / [`PolicyWeave`](https://github.com/ContextualWisdomLab/PolicyWeave) / [`CalendarWeave`](https://github.com/ContextualWisdomLab/CalendarWeave) / [`supply-chain-control-plane`](https://github.com/ContextualWisdomLab/supply-chain-control-plane) | core foundation을 소비하는 도메인 제품 저장소; domain truth·Ubiquitous Language는 여기 남고 위 core로 옮기지 않는다 | owner가 미성숙하거나 API가 없어도 소비 저장소는 복제·우회하지 않는다. owner 저장소에서 RED test → 기능/문서/release를 개발해 CI GREEN과 immutable version을 낸 뒤 소비측이 채택한다. 그 전에는 port·ACL·feature flag·test double로 경계를 지키고 owner의 source·DB·임시 branch를 직접 읽지 않는다.