From 03b2c6297cfe1a596d4be3868fce9b004d143218 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 1 Mar 2026 00:23:12 +0000 Subject: [PATCH] chore: sync workflow templates from Workflows repo Automated sync from stranske/Workflows Template hash: 0896ae6b2b2f Changes synced from sync-manifest.yml --- .github/scripts/agents_pr_meta_update_body.js | 20 +++++++++++++- CLAUDE.md | 26 ------------------- scripts/langchain/capability_check.py | 4 +-- scripts/langchain/issue_optimizer.py | 4 +-- tools/langchain_client.py | 23 ---------------- 5 files changed, 21 insertions(+), 56 deletions(-) diff --git a/.github/scripts/agents_pr_meta_update_body.js b/.github/scripts/agents_pr_meta_update_body.js index 3e987c10c..8d0bed771 100644 --- a/.github/scripts/agents_pr_meta_update_body.js +++ b/.github/scripts/agents_pr_meta_update_body.js @@ -706,7 +706,25 @@ function upsertBlock(body, marker, replacement) { const startIndex = body.indexOf(start); const endIndex = body.indexOf(end); if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) { - return `${body.slice(0, startIndex)}${replacement}${body.slice(endIndex + end.length)}`; + // Replace the first marker pair in place + let result = `${body.slice(0, startIndex)}${replacement}${body.slice(endIndex + end.length)}`; + + // Remove any duplicate marker pairs left by concurrent writers + let hadDuplicates = false; + let limit = 10; + while (limit-- > 0) { + const dupStart = result.indexOf(start, startIndex + replacement.length); + const dupEnd = result.indexOf(end, dupStart + start.length); + if (dupStart !== -1 && dupEnd !== -1 && dupEnd > dupStart) { + result = `${result.slice(0, dupStart)}${result.slice(dupEnd + end.length)}`; + hadDuplicates = true; + } else { + break; + } + } + + // Collapse triple+ newlines left by removed blocks + return hadDuplicates ? result.replace(/\n{3,}/g, '\n\n') : result; } const trimmed = body.trimEnd(); diff --git a/CLAUDE.md b/CLAUDE.md index 1010de58c..685aac408 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -87,32 +87,6 @@ See `docs/INTEGRATION_GUIDE.md` in Workflows repo. - Fix in Workflows repo → sync will propagate here - Or request manual sync: `gh workflow run maint-68-sync-consumer-repos.yml --repo stranske/Workflows` -## Slow Test Strategy - -This repo uses a `slow` pytest marker to keep PR Gate fast (~4 min) while -ensuring heavyweight tests still run on Main CI. - -**How it works:** - -- `pyproject.toml` registers the `slow` marker. -- `pr-00-gate.yml` passes `pytest_markers: "not release and not slow"` to - exclude slow tests from PR feedback. -- `ci.yml` (Main CI) runs the **full** suite including slow tests. -- Locally, `make test` also excludes slow tests for fast iteration. - -**Currently marked slow:** - -- `tests/pipeline/test_run_pipeline.py` — auto-marked by - `tests/pipeline/conftest.py` (each test runs the full pipeline with - real Excel fixtures, 100-170 s each). -- `tests/spec/test_macro_spec_fixtures.py` — module-level - `pytestmark = pytest.mark.slow` (session fixture parses three NISA - workbooks, ~85 s). - -**Rule for agents:** any new test that parses real workbooks or calls -`run_pipeline()` **must** be marked `@pytest.mark.slow`. Omitting the -marker will silently regress Gate duration for every open PR. - ## Reference Implementation **Travel-Plan-Permission** is the reference consumer repo. When debugging: diff --git a/scripts/langchain/capability_check.py b/scripts/langchain/capability_check.py index 61269c690..ef64b889a 100755 --- a/scripts/langchain/capability_check.py +++ b/scripts/langchain/capability_check.py @@ -139,9 +139,7 @@ def _build_llm_config( issue_or_pr = ( str(issue_number) if issue_number is not None - else env_issue - if env_issue.isdigit() - else "unknown" + else env_issue if env_issue.isdigit() else "unknown" ) metadata = { "repo": repo, diff --git a/scripts/langchain/issue_optimizer.py b/scripts/langchain/issue_optimizer.py index 3a7d6b5ed..12d74802e 100755 --- a/scripts/langchain/issue_optimizer.py +++ b/scripts/langchain/issue_optimizer.py @@ -319,9 +319,7 @@ def _build_llm_config( issue_or_pr = ( str(issue_number) if issue_number is not None - else env_issue - if env_issue.isdigit() - else "unknown" + else env_issue if env_issue.isdigit() else "unknown" ) metadata = { "repo": repo, diff --git a/tools/langchain_client.py b/tools/langchain_client.py index 2e8ee842c..c80d31d93 100644 --- a/tools/langchain_client.py +++ b/tools/langchain_client.py @@ -148,29 +148,6 @@ def _resolve_slots() -> list[SlotDefinition]: return _apply_slot_env_overrides(_load_slot_config()) -def list_slot_definitions() -> list[SlotDefinition]: - """Return configured LLM slot definitions after env overrides.""" - - return list(_resolve_slots()) - - -def get_provider_model_catalog() -> dict[str, set[str]]: - """Return provider->model mappings from configured slots.""" - - catalog: dict[str, set[str]] = { - PROVIDER_OPENAI: set(), - PROVIDER_ANTHROPIC: set(), - PROVIDER_GITHUB: set(), - } - for slot in _resolve_slots(): - catalog.setdefault(slot.provider, set()).add(slot.model) - - if not any(catalog.values()): - for slot in _default_slots(): - catalog.setdefault(slot.provider, set()).add(slot.model) - return catalog - - def _is_reasoning_model(model: str) -> bool: """Return True if the model is an OpenAI reasoning model that rejects temperature.