Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion .github/scripts/agents_pr_meta_update_body.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
22 changes: 2 additions & 20 deletions .github/scripts/agents_verifier_context.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,28 +378,10 @@ async function buildVerifierContext({ github, context, core, ciWorkflows }) {
};
}

const baseRef = pr.base?.ref || '';
const defaultBranch = context.payload?.repository?.default_branch || DEFAULT_BRANCH;
if (baseRef && baseRef !== defaultBranch) {
const skipReason = `Pull request base ref ${baseRef} does not match default branch ${defaultBranch}; skipping verifier.`;
core?.notice?.(skipReason);
core?.setOutput?.('should_run', 'false');
core?.setOutput?.('skip_reason', skipReason);
core?.setOutput?.('pr_number', String(pr.number || ''));
core?.setOutput?.('issue_numbers', '[]');
core?.setOutput?.('pr_html_url', pr.html_url || '');
core?.setOutput?.('target_sha', pr.merge_commit_sha || pr.head?.sha || context.sha || '');
core?.setOutput?.('context_path', '');
core?.setOutput?.('acceptance_count', '0');
core?.setOutput?.('ci_results', '[]');
core?.setOutput?.('diff_summary_path', '');
core?.setOutput?.('diff_path', '');
core?.setOutput?.('chain_depth', '0');
return { shouldRun: false, reason: skipReason, ciResults: [] };
}

const prDetails = await github.rest.pulls.get({ owner, repo, pull_number: pr.number });
const pull = prDetails?.data || pr;
const baseRef = pull.base?.ref || pr.base?.ref || '';
const defaultBranch = context.payload?.repository?.default_branch || DEFAULT_BRANCH;

if (isForkPullRequest(pull)) {
const skipReason = 'Pull request is from a fork; skipping verifier.';
Expand Down
26 changes: 0 additions & 26 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 1 addition & 3 deletions scripts/langchain/capability_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 1 addition & 3 deletions scripts/langchain/issue_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
23 changes: 0 additions & 23 deletions tools/langchain_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,29 +148,6 @@ def _resolve_slots() -> list[SlotDefinition]:
return _apply_slot_env_overrides(_load_slot_config())


Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_provider_model_catalog() (and list_slot_definitions()) were removed here, but src/counter_risk/chat/providers/base.py imports and calls get_provider_model_catalog(). This will raise an ImportError at runtime and break tests/test_chat_provider_clients.py. Please restore/re-export get_provider_model_catalog() (and keep its previous behavior of falling back to _default_slots() when the configured catalog is empty), or update call sites to use the new API in a way that preserves the same semantics.

Suggested change
def list_slot_definitions() -> list[SlotDefinition]:
"""Return the configured slot definitions, falling back to defaults if empty.
This preserves the historical behavior where an empty configured catalog
is treated as "no catalog", and the built-in default slots are used instead.
"""
slots = _resolve_slots()
if not slots:
slots = _default_slots()
return slots
def get_provider_model_catalog() -> dict[str, dict[str, str]]:
"""Return a catalog of provider/model pairs keyed by slot name.
The catalog is derived from the current slot definitions, with the same
empty-catalog fallback behavior as :func:`list_slot_definitions`.
"""
catalog: dict[str, dict[str, str]] = {}
for slot in list_slot_definitions():
catalog[slot.name] = {"provider": slot.provider, "model": slot.model}
return catalog

Copilot uses AI. Check for mistakes.
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.

Expand Down
Loading