Merge pull request #7 from pewdiepie-archdaemon/fix/maintainer-harness-ci-reproducibility-v1

fix(ci): make maintainer harness and lab workflow portable
This commit is contained in:
Alexandre Teixeira
2026-09-22 12:44:20 +01:00
committed by GitHub
6 changed files with 125 additions and 32 deletions
+8 -4
View File
@@ -4,12 +4,16 @@
## Target branch ## Target branch
- [ ] This PR targets **`dev`**, not `main`. All PRs land in `dev`; `main` is curated by the maintainer at each release. If your PR is on `main` by accident, click "Edit" on this PR and change the base. - [ ] This PR targets the correct integration branch: **`lab`** in the private maintainer-preview repository, or **`dev`** in the public repository. `main` remains release-curated.
## Linked Issue ## Linked Issue
<!-- Every PR should be linked to an issue. <!-- Public-repository PRs must link an issue:
Use one of: Fixes #NNN | Part of #NNN | Closes #NNN --> Fixes #NNN | Part of #NNN | Closes #NNN
Private maintainer-preview PRs may instead use:
N/A — maintainer integration work
-->
Fixes # Fixes #
@@ -25,7 +29,7 @@ Fixes #
## Checklist ## Checklist
- [ ] I searched [open issues](https://github.com/odysseus-dev/odysseus/issues) and [open PRs](https://github.com/odysseus-dev/odysseus/pulls) — this is not a duplicate. - [ ] I searched [open issues](https://github.com/odysseus-dev/odysseus/issues) and [open PRs](https://github.com/odysseus-dev/odysseus/pulls) — this is not a duplicate.
- [ ] This PR targets `dev` - [ ] This PR targets the correct integration branch (`lab` in maintainer-preview; `dev` in the public repository)
- [ ] My changes are limited to the scope described above — no unrelated refactors or whitespace changes mixed in. - [ ] My changes are limited to the scope described above — no unrelated refactors or whitespace changes mixed in.
- [ ] I actually ran the app (`docker compose up` or `uvicorn app:app`) and verified the change works end-to-end. Type-checks and unit tests are not enough. - [ ] I actually ran the app (`docker compose up` or `uvicorn app:app`) and verified the change works end-to-end. Type-checks and unit tests are not enough.
- [ ] I did not run the app/runtime validation and stated that gap in **How to Test**. Leave this unchecked when the app-run box above is checked. - [ ] I did not run the app/runtime validation and stated that gap in **How to Test**. Leave this unchecked when the app-run box above is checked.
+25 -5
View File
@@ -8,6 +8,9 @@ module.exports = async ({ github, context, core }) => {
const MARKER = '<!-- pr-description-check-bot -->'; const MARKER = '<!-- pr-description-check-bot -->';
const owner = context.repo.owner; const owner = context.repo.owner;
const repo = context.repo.repo; const repo = context.repo.repo;
const isMaintainerPreview =
owner === 'pewdiepie-archdaemon'
&& repo === 'odysseus-maintainer-preview';
// Strip HTML comments so placeholder text does not count as content. // Strip HTML comments so placeholder text does not count as content.
function strip(text) { function strip(text) {
@@ -28,13 +31,30 @@ module.exports = async ({ github, context, core }) => {
descriptionProblems.push('**Summary** is empty or too short — describe what changed and why.'); descriptionProblems.push('**Summary** is empty or too short — describe what changed and why.');
} }
// 2. Linked Issue must reference a real issue. Accept a bare #NNN, a closing // 2. Public contributor PRs must reference a real issue. The private
// keyword + #NNN, or a full issue URL (e.g. .../issues/123) — the strict // maintainer-preview repository may explicitly opt out for fast maintainer
// keyword-prefixed form previously false-flagged correctly-linked PRs. // integration work while still requiring the section to state that intent.
const linkedSection = section('Linked Issue'); const linkedSection = section('Linked Issue');
const hasIssueRef = /#\d+\b/.test(linkedSection) || /\/issues\/\d+/.test(linkedSection); const hasIssueRef = /#\d+\b/.test(linkedSection) || /\/issues\/\d+/.test(linkedSection);
if (!linkedSection || !hasIssueRef) { const hasMaintainerNA = /^N\/A\b/i.test(linkedSection);
descriptionProblems.push('**Linked Issue** — add a reference like `Fixes #NNN`, a bare `#NNN`, or a link to the issue.');
if (!linkedSection) {
descriptionProblems.push(
'**Linked Issue** — fill this section. Public PRs require an issue reference; ' +
'maintainer-preview PRs may use `N/A — maintainer integration work`.'
);
} else if (isMaintainerPreview) {
if (!hasIssueRef && !hasMaintainerNA) {
descriptionProblems.push(
'**Linked Issue** — use an issue reference or `N/A — maintainer integration work` ' +
'in the private maintainer-preview repository.'
);
}
} else if (!hasIssueRef) {
descriptionProblems.push(
'**Linked Issue** — add a reference like `Fixes #NNN`, a bare `#NNN`, ' +
'or a link to the issue.'
);
} }
// 3. At least one Type of Change box must be checked. // 3. At least one Type of Change box must be checked.
+4 -1
View File
@@ -30,7 +30,10 @@ jobs:
dependency-review: dependency-review:
name: dependency-review (PR gate) name: dependency-review (PR gate)
# Only meaningful on a pull request -- it needs a base..head diff to review. # Only meaningful on a pull request -- it needs a base..head diff to review.
if: github.event_name == 'pull_request' # dependency-review-action requires GitHub dependency-review support.
# Keep the blocking gate on the canonical repository; forks and maintainer
# preview mirrors still run the advisory pip-audit job below.
if: github.event_name == 'pull_request' && github.repository == 'odysseus-dev/odysseus'
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: read
+12 -3
View File
@@ -9,6 +9,7 @@ import argparse
import copy import copy
import hashlib import hashlib
import json import json
import os
import sys import sys
import time import time
from pathlib import Path from pathlib import Path
@@ -19,9 +20,17 @@ import jsonschema
sys.path.insert(0, str(Path(__file__).resolve().parents[1])) sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from src.tool_schemas import FUNCTION_TOOL_SCHEMAS from src.tool_schemas import FUNCTION_TOOL_SCHEMAS
from src.turn_contract import FAMILY_TOOLS, requested_capabilities from src.turn_contract import FAMILY_TOOLS, requested_capabilities
CONTRACT_SOURCE = Path(str(Path(__file__).resolve().parents[1] / "scripts")) CONTRACT_SOURCE = Path(os.environ.get("ODYSSEUS_TOOL_CONTRACT_ROOT", str(Path(__file__).resolve().parents[1] / "scripts")))
sys.path.insert(0, str(CONTRACT_SOURCE)) if (CONTRACT_SOURCE / 'eval_alltools_unseen_compare.py').is_file():
from eval_alltools_unseen_compare import tools_for_mode sys.path.insert(0, str(CONTRACT_SOURCE))
try:
from eval_alltools_unseen_compare import tools_for_mode
finally:
if str(CONTRACT_SOURCE) in sys.path:
sys.path.remove(str(CONTRACT_SOURCE))
else:
from src.clean_agent_preview import contract_builder
tools_for_mode = contract_builder()
FAMILIES = tuple(FAMILY_TOOLS)[:10] FAMILIES = tuple(FAMILY_TOOLS)[:10]
TRAINED_NAMES = set().union(*(FAMILY_TOOLS[f] for f in FAMILIES)) TRAINED_NAMES = set().union(*(FAMILY_TOOLS[f] for f in FAMILIES))
+18 -15
View File
@@ -1943,6 +1943,10 @@ def authorized_write_families(user_text):
return frozenset(families) return frozenset(families)
def canonical_tools_for_mode(tools, mode):
return copy.deepcopy(tools)
@lru_cache(maxsize=1) @lru_cache(maxsize=1)
def contract_builder(): def contract_builder():
root = Path(os.environ.get( root = Path(os.environ.get(
@@ -1950,21 +1954,20 @@ def contract_builder():
str(Path(__file__).resolve().parents[1] / "scripts"), str(Path(__file__).resolve().parents[1] / "scripts"),
)).resolve() )).resolve()
contract_path = root / 'eval_alltools_unseen_compare.py' contract_path = root / 'eval_alltools_unseen_compare.py'
if not contract_path.is_file(): if contract_path.is_file():
raise FileNotFoundError( # Load the original promotion protocol, not the description-stripping UI helper.
f'Compact-v5 tool contract is missing: {contract_path}' sys.path.insert(0, str(root))
) try:
# Load the original promotion protocol, not the description-stripping UI helper. spec = importlib.util.spec_from_file_location(
sys.path.insert(0, str(root)) 'odysseus_preview_v3_contract', contract_path
try: )
spec = importlib.util.spec_from_file_location( module = importlib.util.module_from_spec(spec)
'odysseus_preview_v3_contract', contract_path spec.loader.exec_module(module)
) return module.tools_for_mode
module = importlib.util.module_from_spec(spec) finally:
spec.loader.exec_module(module) if str(root) in sys.path:
return module.tools_for_mode sys.path.remove(str(root))
finally: return canonical_tools_for_mode
sys.path.remove(str(root))
def compact_schemas(schemas): def compact_schemas(schemas):
+58 -4
View File
@@ -14,14 +14,21 @@ _WORKFLOW = _REPO / ".github" / "workflows" / "pr-description-check.yml"
pytestmark = pytest.mark.skipif(not shutil.which("node"), reason="node not on PATH") pytestmark = pytest.mark.skipif(not shutil.which("node"), reason="node not on PATH")
def _body(*, app_ran=False, app_not_run=False, screenshot=False, media=""): def _body(
*,
app_ran=False,
app_not_run=False,
screenshot=False,
media="",
linked_issue="Fixes #5934",
):
return f"""## Summary return f"""## Summary
This focused change has enough concrete summary detail for the checker. This focused change has enough concrete summary detail for the checker.
## Linked Issue ## Linked Issue
Fixes #5934 {linked_issue}
## Type of Change ## Type of Change
@@ -47,7 +54,15 @@ Run the focused checker regression tests and inspect their exact assertions.
""" """
def _run_checker(files, body, *, missing_labels=(), draft=False): def _run_checker(
files,
body,
*,
missing_labels=(),
draft=False,
owner="odysseus-dev",
repo="odysseus",
):
harness = r""" harness = r"""
const checkPrDescription = require(process.argv[1]); const checkPrDescription = require(process.argv[1]);
const input = JSON.parse(process.argv[2]); const input = JSON.parse(process.argv[2]);
@@ -89,7 +104,7 @@ const context = {
draft: input.draft, draft: input.draft,
}, },
}, },
repo: { owner: 'odysseus-dev', repo: 'odysseus' }, repo: { owner: input.owner, repo: input.repo },
}; };
const core = { const core = {
warning: (message) => calls.push({ method: 'warning', message }), warning: (message) => calls.push({ method: 'warning', message }),
@@ -109,6 +124,8 @@ checkPrDescription({ github, context, core })
"body": body, "body": body,
"missingLabels": list(missing_labels), "missingLabels": list(missing_labels),
"draft": draft, "draft": draft,
"owner": owner,
"repo": repo,
} }
) )
proc = subprocess.run( proc = subprocess.run(
@@ -158,6 +175,43 @@ def test_complete_expected_state_is_ready(files, body):
assert not any(call["method"] == "setFailed" for call in calls) assert not any(call["method"] == "setFailed" for call in calls)
def test_public_repo_still_requires_linked_issue():
calls = _run_checker(
["README.md"],
_body(linked_issue="N/A — maintainer integration work"),
)
assert any(call["method"] == "setFailed" for call in calls)
assert "**Linked Issue**" in _comment(calls)
assert "ready for review" not in _added_labels(calls)
def test_maintainer_preview_accepts_explicit_na_linked_issue():
calls = _run_checker(
["README.md"],
_body(linked_issue="N/A — maintainer integration work"),
owner="pewdiepie-archdaemon",
repo="odysseus-maintainer-preview",
)
assert _added_labels(calls) == {"ready for review"}
assert not _comment(calls)
assert not any(call["method"] == "setFailed" for call in calls)
def test_maintainer_preview_rejects_ambiguous_non_issue_text():
calls = _run_checker(
["README.md"],
_body(linked_issue="No tracking needed"),
owner="pewdiepie-archdaemon",
repo="odysseus-maintainer-preview",
)
assert any(call["method"] == "setFailed" for call in calls)
assert "**Linked Issue**" in _comment(calls)
assert "ready for review" not in _added_labels(calls)
def test_ui_checkbox_without_media_still_needs_visual_evidence(): def test_ui_checkbox_without_media_still_needs_visual_evidence():
calls = _run_checker( calls = _run_checker(
["static/js/example.js"], ["static/js/example.js"],